r193383 - Refactor: Extract specializing the generic lambda call operator during conversion to fptr deduction into its own function.
Faisal Vali
faisalv at yahoo.com
Thu Oct 24 16:40:03 PDT 2013
Author: faisalv
Date: Thu Oct 24 18:40:02 2013
New Revision: 193383
URL: http://llvm.org/viewvc/llvm-project?rev=193383&view=rev
Log:
Refactor: Extract specializing the generic lambda call operator during conversion to fptr deduction into its own function.
No functionality change.
All clang regression tests pass.
Thanks!
Modified:
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=193383&r1=193382&r2=193383&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Oct 24 18:40:02 2013
@@ -3609,21 +3609,113 @@ Sema::DeduceTemplateArguments(FunctionTe
/// \brief Given a function declaration (e.g. a generic lambda conversion
/// function) that contains an 'auto' in its result type, substitute it
-/// with the same Deduced type that the TypeToReplaceAutoWith was deduced
-/// with.
+/// with TypeToReplaceAutoWith. Be careful to pass in the type you want
+/// to replace 'auto' with and not the actual result type you want
+/// to set the function to.
static inline void
-ReplaceAutoWithinFunctionReturnType(FunctionDecl *F,
+SubstAutoWithinFunctionReturnType(FunctionDecl *F,
QualType TypeToReplaceAutoWith, Sema &S) {
- if (TypeToReplaceAutoWith->getContainedAutoType())
- TypeToReplaceAutoWith = TypeToReplaceAutoWith->
- getContainedAutoType()->getDeducedType();
-
+ assert(!TypeToReplaceAutoWith->getContainedAutoType());
QualType AutoResultType = F->getResultType();
assert(AutoResultType->getContainedAutoType());
QualType DeducedResultType = S.SubstAutoType(AutoResultType,
TypeToReplaceAutoWith);
S.Context.adjustDeducedFunctionResultType(F, DeducedResultType);
}
+
+/// \brief Given a specialized conversion operator of a generic lambda
+/// create the corresponding specializations of the call operator and
+/// the static-invoker. If the return type of the call operator is auto,
+/// deduce its return type and check if that matches the
+/// return type of the destination function ptr.
+
+static inline Sema::TemplateDeductionResult
+SpecializeCorrespondingLambdaCallOperatorAndInvoker(
+ CXXConversionDecl *ConversionSpecialized,
+ SmallVectorImpl<DeducedTemplateArgument> &DeducedArguments,
+ QualType ReturnTypeOfDestFunctionPtr,
+ TemplateDeductionInfo &TDInfo,
+ Sema &S) {
+
+ CXXRecordDecl *LambdaClass = ConversionSpecialized->getParent();
+ assert(LambdaClass && LambdaClass->isGenericLambda());
+
+ CXXMethodDecl *CallOpGeneric = LambdaClass->getLambdaCallOperator();
+ QualType CallOpResultType = CallOpGeneric->getResultType();
+ const bool GenericLambdaCallOperatorHasDeducedReturnType =
+ CallOpResultType->getContainedAutoType();
+
+ FunctionTemplateDecl *CallOpTemplate =
+ CallOpGeneric->getDescribedFunctionTemplate();
+
+ FunctionDecl *CallOpSpecialized = 0;
+ // Use the deduced arguments of the conversion function, to specialize our
+ // generic lambda's call operator.
+ if (Sema::TemplateDeductionResult Result
+ = S.FinishTemplateArgumentDeduction(CallOpTemplate,
+ DeducedArguments,
+ 0, CallOpSpecialized, TDInfo))
+ return Result;
+
+ // If we need to deduce the return type, do so (instantiates the callop).
+ if (GenericLambdaCallOperatorHasDeducedReturnType &&
+ CallOpSpecialized->getResultType()->isUndeducedType())
+ S.DeduceReturnType(CallOpSpecialized,
+ CallOpSpecialized->getPointOfInstantiation(),
+ /*Diagnose*/ true);
+
+ // Check to see if the return type of the destination ptr-to-function
+ // matches the return type of the call operator.
+ if (!S.Context.hasSameType(CallOpSpecialized->getResultType(),
+ ReturnTypeOfDestFunctionPtr))
+ return Sema::TDK_NonDeducedMismatch;
+ // Since we have succeeded in matching the source and destination
+ // ptr-to-functions (now including return type), and have successfully
+ // specialized our corresponding call operator, we are ready to
+ // specialize the static invoker with the deduced arguments of our
+ // ptr-to-function.
+ FunctionDecl *InvokerSpecialized = 0;
+ FunctionTemplateDecl *InvokerTemplate = LambdaClass->
+ getLambdaStaticInvoker()->getDescribedFunctionTemplate();
+
+ Sema::TemplateDeductionResult LLVM_ATTRIBUTE_UNUSED Result
+ = S.FinishTemplateArgumentDeduction(InvokerTemplate, DeducedArguments, 0,
+ InvokerSpecialized, TDInfo);
+ assert(Result == Sema::TDK_Success &&
+ "If the call operator succeeded so should the invoker!");
+ // Set the result type to match the corresponding call operator
+ // specialization's result type.
+ if (GenericLambdaCallOperatorHasDeducedReturnType &&
+ InvokerSpecialized->getResultType()->isUndeducedType()) {
+ // Be sure to get the type to replace 'auto' with and not
+ // the full result type of the call op specialization
+ // to substitute into the 'auto' of the invoker and conversion
+ // function.
+ // For e.g.
+ // int* (*fp)(int*) = [](auto* a) -> auto* { return a; };
+ // We don't want to subst 'int*' into 'auto' to get int**.
+
+ QualType TypeToReplaceAutoWith =
+ CallOpSpecialized->getResultType()->
+ getContainedAutoType()->getDeducedType();
+ SubstAutoWithinFunctionReturnType(InvokerSpecialized,
+ TypeToReplaceAutoWith, S);
+ SubstAutoWithinFunctionReturnType(ConversionSpecialized,
+ TypeToReplaceAutoWith, S);
+ }
+
+ // Ensure that static invoker doesn't have a const qualifier.
+ // FIXME: When creating the InvokerTemplate in SemaLambda.cpp
+ // do not use the CallOperator's TypeSourceInfo which allows
+ // the const qualifier to leak through.
+ const FunctionProtoType *InvokerFPT = InvokerSpecialized->
+ getType().getTypePtr()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo();
+ EPI.TypeQuals = 0;
+ InvokerSpecialized->setType(S.Context.getFunctionType(
+ InvokerFPT->getResultType(), InvokerFPT->getArgTypes(),EPI));
+ return Sema::TDK_Success;
+}
/// \brief Deduce template arguments for a templated conversion
/// function (C++ [temp.deduct.conv]) and, if successful, produce a
/// conversion function template specialization.
@@ -3635,10 +3727,10 @@ Sema::DeduceTemplateArguments(FunctionTe
if (ConversionTemplate->isInvalidDecl())
return TDK_Invalid;
- CXXConversionDecl *Conv
+ CXXConversionDecl *ConversionGeneric
= cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());
- QualType FromType = Conv->getConversionType();
+ QualType FromType = ConversionGeneric->getConversionType();
// Canonicalize the types for deduction.
QualType P = Context.getCanonicalType(FromType);
@@ -3724,141 +3816,41 @@ Sema::DeduceTemplateArguments(FunctionTe
// Create an Instantiation Scope for finalizing the operator.
LocalInstantiationScope InstScope(*this);
-
- CXXMethodDecl *LambdaCallOpSpec = 0;
- bool GenericLambdaCallOperatorHasDeducedReturnType = false;
-
- // Having successfully deduced and matched the type of the conversion
- // function against the destination type, if the destination type
- // is a ptr-to-function and the source type is a generic lambda conversion
- // to ptr-to-function, we know that the parameters of the destination
- // ptr-to-function have matched successfully against those of our
- // lambda's conversion function.
- // For instance:
- // int (*fp)(int) = [](auto a) { return a; };
- // [template<class T> operator id<auto(*)(T)>() const]
- // If it is indeed the conversion operator of a generic lambda then if
- // not already done, create the corresponding specializations of the call
- // operator and the static-invoker; and if the return type is auto,
- // deduce the return type, and then check and see if it matches the ToType.
-
- const bool IsGenericLambdaConversionOperator =
- isLambdaConversionOperator(Conv);
- if (IsGenericLambdaConversionOperator) {
- const Type *ToTypePtr = A.getTypePtr();
-
- assert(A->isPointerType());
- ToTypePtr = A->getPointeeType().getTypePtr();
-
- CXXRecordDecl *LambdaClass = Conv->getParent();
- assert(LambdaClass && LambdaClass->isGenericLambda());
-
- const FunctionType *ToFunType = ToTypePtr->getAs<FunctionType>();
-
- // The specialization of the Generic Lambda Call Op, instantiated
- // using the deduced parameters from the conversion function
- // i.e.
- // auto L = [](auto a) { return f(a); };
- // int (*fp)(int) = L;
- //
-
- CXXMethodDecl *CallOp = LambdaClass->getLambdaCallOperator();
- QualType CallOpResultType = CallOp->getResultType();
- GenericLambdaCallOperatorHasDeducedReturnType =
- CallOpResultType->getContainedAutoType();
- FunctionTemplateDecl *CallOpTemplate =
- CallOp->getDescribedFunctionTemplate();
-
- TemplateDeductionInfo OpInfo(Info.getLocation());
- FunctionDecl *CallOpSpec = 0;
- // Use the deduced arguments so far, to specialize our generic
- // lambda's call operator.
- if (TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(CallOpTemplate, Deduced,
- 0, CallOpSpec, OpInfo))
- return Result;
-
- // bool HadToDeduceReturnTypeDuringCurrentCall = false;
- // If we need to deduce the return type, do so (instantiates the callop).
- if (GenericLambdaCallOperatorHasDeducedReturnType &&
- CallOpSpec->getResultType()->isUndeducedType()) {
- // HadToDeduceReturnTypeDuringCurrentCall = true;
- DeduceReturnType(CallOpSpec, CallOpSpec->getPointOfInstantiation(),
- /*Diagnose*/ true);
- }
-
- LambdaCallOpSpec = cast<CXXMethodDecl>(CallOpSpec);
-
- // Check to see if the return type of the destination ptr-to-function
- // matches the return type of the call operator.
- if (!Context.hasSameType(LambdaCallOpSpec->getResultType(),
- ToFunType->getResultType()))
- return TDK_NonDeducedMismatch;
- // Since we have succeeded in matching the source and destination
- // ptr-to-functions (now including return type), and have successfully
- // specialized our corresponding call operator, we are ready to
- // specialize the static invoker with the deduced arguments of our
- // ptr-to-function.
- FunctionDecl *InvokerSpecialization = 0;
- FunctionTemplateDecl *InvokerTemplate = LambdaClass->
- getLambdaStaticInvoker()->getDescribedFunctionTemplate();
-
- TemplateDeductionResult LLVM_ATTRIBUTE_UNUSED Result
- = FinishTemplateArgumentDeduction(InvokerTemplate, Deduced, 0,
- InvokerSpecialization, Info);
- assert(Result == TDK_Success);
- // Set the result type to match the corresponding call operator
- // specialization's result type.
- if (GenericLambdaCallOperatorHasDeducedReturnType &&
- InvokerSpecialization->getResultType()->isUndeducedType())
- ReplaceAutoWithinFunctionReturnType(InvokerSpecialization,
- LambdaCallOpSpec->getResultType(), *this);
+ // Finish template argument deduction.
+ FunctionDecl *ConversionSpecialized = 0;
+ TemplateDeductionResult Result
+ = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
+ ConversionSpecialized, Info);
+ Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
+
+ // If the conversion operator is being invoked on a lambda closure to convert
+ // to a ptr-to-function, use the deduced arguments from the conversion function
+ // to specialize the corresponding call operator.
+ // e.g., int (*fp)(int) = [](auto a) { return a; };
+ if (Result == TDK_Success && isLambdaConversionOperator(ConversionGeneric)) {
- // Ensure that static invoker doesn't have a const qualifier.
- // FIXME: When creating the InvokerTemplate in SemaLambda.cpp
- // do not use the CallOperator's TypeSourceInfo which allows
- // the const qualifier to leak through.
- const FunctionProtoType *InvokerFPT = InvokerSpecialization->
- getType().getTypePtr()->castAs<FunctionProtoType>();
- FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo();
- EPI.TypeQuals = 0;
- InvokerSpecialization->setType(Context.getFunctionType(
- InvokerFPT->getResultType(), InvokerFPT->getArgTypes(),EPI));
+ // Get the return type of the destination ptr-to-function we are converting
+ // to. This is necessary for matching the lambda call operator's return
+ // type to that of the destination ptr-to-function's return type.
+ assert(A->isPointerType() &&
+ "Can only convert from lambda to ptr-to-function");
+ const FunctionType *ToFunType =
+ A->getPointeeType().getTypePtr()->getAs<FunctionType>();
+ const QualType DestFunctionPtrReturnType = ToFunType->getResultType();
- // Since the original conversion operator's parameters are the same
- // entities as the lambda's call operator's, we introduce a mapping
- // from the generic to the specialized parameters of the call operators.
- // This only needs to be done in the absence of return type deduction,
- // since deducing the return type entails instantiation which adds
- // the parameter mapping to the CurrentInstantiationScope.
- // This is necessary when transforming nested lambdas that do not
- // capture.
- // FIXME: This will be fixed once nested lambdas and capturing
- // is implemented since it does require handling parameter
- // packs correctly which might require careful calls to
- // SemaTemplateInstantiate::addInstantiatedParametersToScope.
- // if (!HadToDeduceReturnTypeDuringCurrentCall) { ... }
+ // Create the corresponding specializations of the call operator and
+ // the static-invoker; and if the return type is auto,
+ // deduce the return type and check if it matches the
+ // DestFunctionPtrReturnType.
+ // For instance:
+ // auto L = [](auto a) { return f(a); };
+ // int (*fp)(int) = L;
+ // char (*fp2)(int) = L; <-- Not OK.
+
+ Result = SpecializeCorrespondingLambdaCallOperatorAndInvoker(
+ Specialization, Deduced, DestFunctionPtrReturnType,
+ Info, *this);
}
-
-
- // Finish template argument deduction.
- FunctionDecl *ConversionSpec = 0;
- TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
- ConversionSpec, Info);
- Specialization = cast_or_null<CXXConversionDecl>(ConversionSpec);
- if (Result == TDK_Success && GenericLambdaCallOperatorHasDeducedReturnType) {
- // Set the return type of the conversion specialization, since even
- // though we have ensured that the return types are compatible, if
- // there is an auto in the return type of this conversion function,
- // replace it permanently with the return type of the deduced lambda
- // so we don't try and deduce against it.
- assert(LambdaCallOpSpec);
- if (ConversionSpec->getResultType()->isUndeducedType())
- ReplaceAutoWithinFunctionReturnType(ConversionSpec,
- LambdaCallOpSpec->getResultType(),
- *this);
- }
return Result;
}
Modified: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=193383&r1=193382&r2=193383&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Thu Oct 24 18:40:02 2013
@@ -53,7 +53,10 @@ int test() {
char (*fc)(char) = L; //expected-error{{no viable conversion}}
double (*fd)(double) = L; //expected-error{{no viable conversion}}
}
-
+{
+ int* (*fp)(int*) = [](auto *a) -> auto* { return a; };
+ fp(0);
+}
}
namespace more_converion_to_ptr_to_function_tests {
More information about the cfe-commits
mailing list