ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
sema::LambdaScopeInfo *LSI);
+ /// Get the return type to use for a lambda's conversion function(s) to
+ /// function pointer type, given the type of the call operator.
+ QualType
+ getLambdaConversionFunctionResultType(const FunctionProtoType *CallOpType);
+
/// \brief Define the "body" of the conversion from a lambda object to a
/// function pointer.
///
void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionDecl *Function);
+ FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
+ const TemplateArgumentList *Args,
+ SourceLocation Loc);
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive = false,
SourceLocation CurrentLocation,
CXXConversionDecl *Conv) {
SynthesizedFunctionScope Scope(*this, Conv);
+ assert(!Conv->getReturnType()->isUndeducedType());
CXXRecordDecl *Lambda = Conv->getParent();
- CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
- // If we are defining a specialization of a conversion to function-ptr
- // cache the deduced template arguments for this specialization
- // so that we can use them to retrieve the corresponding call-operator
- // and static-invoker.
- const TemplateArgumentList *DeducedTemplateArgs = nullptr;
-
- // Retrieve the corresponding call-operator specialization.
- if (Lambda->isGenericLambda()) {
- assert(Conv->isFunctionTemplateSpecialization());
- FunctionTemplateDecl *CallOpTemplate =
- CallOp->getDescribedFunctionTemplate();
- DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();
- void *InsertPos = nullptr;
- FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(
- DeducedTemplateArgs->asArray(),
- InsertPos);
- assert(CallOpSpec &&
- "Conversion operator must have a corresponding call operator");
- CallOp = cast<CXXMethodDecl>(CallOpSpec);
+ FunctionDecl *CallOp = Lambda->getLambdaCallOperator();
+ FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker();
+
+ if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) {
+ CallOp = InstantiateFunctionDeclaration(
+ CallOp->getDescribedFunctionTemplate(), TemplateArgs, CurrentLocation);
+ if (!CallOp)
+ return;
+
+ Invoker = InstantiateFunctionDeclaration(
+ Invoker->getDescribedFunctionTemplate(), TemplateArgs, CurrentLocation);
+ if (!Invoker)
+ return;
}
+ if (CallOp->isInvalidDecl())
+ return;
+
// Mark the call operator referenced (and add to pending instantiations
// if necessary).
// For both the conversion and static-invoker template specializations
// to the PendingInstantiations.
MarkFunctionReferenced(CurrentLocation, CallOp);
- // Retrieve the static invoker...
- CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
- // ... and get the corresponding specialization for a generic lambda.
- if (Lambda->isGenericLambda()) {
- assert(DeducedTemplateArgs &&
- "Must have deduced template arguments from Conversion Operator");
- FunctionTemplateDecl *InvokeTemplate =
- Invoker->getDescribedFunctionTemplate();
- void *InsertPos = nullptr;
- FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(
- DeducedTemplateArgs->asArray(),
- InsertPos);
- assert(InvokeSpec &&
- "Must have a corresponding static invoker specialization");
- Invoker = cast<CXXMethodDecl>(InvokeSpec);
- }
+ // Fill in the __invoke function with a dummy implementation. IR generation
+ // will fill in the actual details. Update its type in case it contained
+ // an 'auto'.
+ Invoker->markUsed(Context);
+ Invoker->setReferenced();
+ Invoker->setType(Conv->getReturnType()->getPointeeType());
+ Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+
// Construct the body of the conversion function { return __invoke; }.
Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
- VK_LValue, Conv->getLocation()).get();
+ VK_LValue, Conv->getLocation()).get();
assert(FunctionRef && "Can't refer to __invoke function?");
Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(),
Conv->getLocation()));
-
Conv->markUsed(Context);
Conv->setReferenced();
- // Fill in the __invoke function with a dummy implementation. IR generation
- // will fill in the actual details.
- Invoker->markUsed(Context);
- Invoker->setReferenced();
- Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
-
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
L->CompletedImplicitDefinition(Invoker);
PopFunctionScopeInfo();
}
+QualType Sema::getLambdaConversionFunctionResultType(
+ const FunctionProtoType *CallOpProto) {
+ // The function type inside the pointer type is the same as the call
+ // operator with some tweaks. The calling convention is the default free
+ // function convention, and the type qualifications are lost.
+ const FunctionProtoType::ExtProtoInfo CallOpExtInfo =
+ CallOpProto->getExtProtoInfo();
+ FunctionProtoType::ExtProtoInfo InvokerExtInfo = CallOpExtInfo;
+ CallingConv CC = Context.getDefaultCallingConvention(
+ CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
+ InvokerExtInfo.ExtInfo = InvokerExtInfo.ExtInfo.withCallingConv(CC);
+ InvokerExtInfo.TypeQuals = 0;
+ assert(InvokerExtInfo.RefQualifier == RQ_None &&
+ "Lambda's call operator should not have a reference qualifier");
+ return Context.getFunctionType(CallOpProto->getReturnType(),
+ CallOpProto->getParamTypes(), InvokerExtInfo);
+}
+
/// \brief Add a lambda's conversion to function pointer, as described in
/// C++11 [expr.prim.lambda]p6.
static void addFunctionPointerConversion(Sema &S,
return;
// Add the conversion to function pointer.
- const FunctionProtoType *CallOpProto =
- CallOperator->getType()->getAs<FunctionProtoType>();
- const FunctionProtoType::ExtProtoInfo CallOpExtInfo =
- CallOpProto->getExtProtoInfo();
- QualType PtrToFunctionTy;
- QualType InvokerFunctionTy;
- {
- FunctionProtoType::ExtProtoInfo InvokerExtInfo = CallOpExtInfo;
- CallingConv CC = S.Context.getDefaultCallingConvention(
- CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
- InvokerExtInfo.ExtInfo = InvokerExtInfo.ExtInfo.withCallingConv(CC);
- InvokerExtInfo.TypeQuals = 0;
- assert(InvokerExtInfo.RefQualifier == RQ_None &&
- "Lambda's call operator should not have a reference qualifier");
- InvokerFunctionTy =
- S.Context.getFunctionType(CallOpProto->getReturnType(),
- CallOpProto->getParamTypes(), InvokerExtInfo);
- PtrToFunctionTy = S.Context.getPointerType(InvokerFunctionTy);
- }
+ QualType InvokerFunctionTy = S.getLambdaConversionFunctionResultType(
+ CallOperator->getType()->castAs<FunctionProtoType>());
+ QualType PtrToFunctionTy = S.Context.getPointerType(InvokerFunctionTy);
// Create the type of the conversion function.
FunctionProtoType::ExtProtoInfo ConvExtInfo(
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
- const FunctionProtoType *Proto =
- CallOperator->getType()->getAs<FunctionProtoType>();
-
- // The function type inside the block pointer type is the same as the call
- // operator with some tweaks. The calling convention is the default free
- // function convention, and the type qualifications are lost.
- FunctionProtoType::ExtProtoInfo BlockEPI = Proto->getExtProtoInfo();
- BlockEPI.ExtInfo =
- BlockEPI.ExtInfo.withCallingConv(S.Context.getDefaultCallingConvention(
- Proto->isVariadic(), /*IsCXXMethod=*/false));
- BlockEPI.TypeQuals = 0;
- QualType FunctionTy = S.Context.getFunctionType(
- Proto->getReturnType(), Proto->getParamTypes(), BlockEPI);
+ QualType FunctionTy = S.getLambdaConversionFunctionResultType(
+ CallOperator->getType()->castAs<FunctionProtoType>());
QualType BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
FunctionProtoType::ExtProtoInfo ConversionEPI(
return Matched;
}
-
-
-
// Resolve and fix an overloaded expression that can be resolved
// because it identifies a single function template specialization.
//
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
SourceLocation ReturnLoc,
Expr *&RetExpr,
AutoType *AT) {
+ // If this is the conversion function for a lambda, we choose to deduce it
+ // type from the corresponding call operator, not from the synthesized return
+ // statement within it. See Sema::DeduceReturnType.
+ if (isLambdaConversionOperator(FD))
+ return false;
+
TypeLoc OrigResultType = getReturnTypeLoc(FD);
QualType Deduced;
return TDK_Success;
}
-/// \brief Given a function declaration (e.g. a generic lambda conversion
-/// function) that contains an 'auto' in its result type, substitute it
-/// 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
-SubstAutoWithinFunctionReturnType(FunctionDecl *F,
- QualType TypeToReplaceAutoWith, Sema &S) {
- assert(!TypeToReplaceAutoWith->getContainedAutoType());
- QualType AutoResultType = F->getReturnType();
- 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->getReturnType();
- const bool GenericLambdaCallOperatorHasDeducedReturnType =
- CallOpResultType->getContainedAutoType();
-
- FunctionTemplateDecl *CallOpTemplate =
- CallOpGeneric->getDescribedFunctionTemplate();
-
- FunctionDecl *CallOpSpecialized = nullptr;
- // 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->getReturnType()->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->getReturnType(),
- 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 = nullptr;
- FunctionTemplateDecl *InvokerTemplate = LambdaClass->
- getLambdaStaticInvoker()->getDescribedFunctionTemplate();
-
-#ifndef NDEBUG
- Sema::TemplateDeductionResult LLVM_ATTRIBUTE_UNUSED Result =
-#endif
- 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->getReturnType()->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->getReturnType()
- ->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->getReturnType(), InvokerFPT->getParamTypes(), 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.
= 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)) {
-
- // 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->getReturnType();
-
- // 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);
- }
return Result;
}
bool Diagnose) {
assert(FD->getReturnType()->isUndeducedType());
+ // For a lambda's conversion operator, deduce any 'auto' or 'decltype(auto)'
+ // within the return type from the call operator's type.
+ if (isLambdaConversionOperator(FD)) {
+ CXXRecordDecl *Lambda = cast<CXXMethodDecl>(FD)->getParent();
+ FunctionDecl *CallOp = Lambda->getLambdaCallOperator();
+
+ // For a generic lambda, instantiate the call operator if needed.
+ if (auto *Args = FD->getTemplateSpecializationArgs()) {
+ CallOp = InstantiateFunctionDeclaration(
+ CallOp->getDescribedFunctionTemplate(), Args, Loc);
+ if (!CallOp || CallOp->isInvalidDecl())
+ return true;
+
+ // We might need to deduce the return type by instantiating the definition
+ // of the operator() function.
+ if (CallOp->getReturnType()->isUndeducedType())
+ InstantiateFunctionDefinition(Loc, CallOp);
+ }
+
+ if (CallOp->isInvalidDecl())
+ return true;
+ assert(!CallOp->getReturnType()->isUndeducedType() &&
+ "failed to deduce lambda return type");
+
+ // Build the new return type from scratch.
+ QualType RetType = getLambdaConversionFunctionResultType(
+ CallOp->getType()->castAs<FunctionProtoType>());
+ if (FD->getReturnType()->getAs<PointerType>())
+ RetType = Context.getPointerType(RetType);
+ else {
+ assert(FD->getReturnType()->getAs<BlockPointerType>());
+ RetType = Context.getBlockPointerType(RetType);
+ }
+ Context.adjustDeducedFunctionResultType(FD, RetType);
+ return false;
+ }
+
if (FD->getTemplateInstantiationPattern())
InstantiateFunctionDefinition(Loc, FD);
return false;
}
+/// Instantiate (or find existing instantiation of) a function template with a
+/// given set of template arguments.
+///
+/// Usually this should not be used, and template argument deduction should be
+/// used in its place.
+FunctionDecl *
+Sema::InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
+ const TemplateArgumentList *Args,
+ SourceLocation Loc) {
+ FunctionDecl *FD = FTD->getTemplatedDecl();
+
+ sema::TemplateDeductionInfo Info(Loc);
+ InstantiatingTemplate Inst(
+ *this, Loc, FTD, Args->asArray(),
+ CodeSynthesisContext::ExplicitTemplateArgumentSubstitution, Info);
+ if (Inst.isInvalid())
+ return nullptr;
+
+ ContextRAII SavedContext(*this, FD);
+ MultiLevelTemplateArgumentList MArgs(*Args);
+
+ return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
+}
+
/// In the MS ABI, we need to instantiate default arguments of dllexported
/// default constructors along with the constructor definition. This allows IR
/// gen to emit a constructor closure which calls the default constructor with
int (*fp2)(int) = [](auto b) -> int { return b; };
int (*fp3)(char) = [](auto c) -> int { return c; };
char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\
- //expected-note{{candidate template ignored}}
+ //expected-note{{candidate function[with $0 = int]}}
char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\
//expected-note{{candidate template ignored}}
} // end ns
namespace conversion_operator {
-void test() {
- auto L = [](auto a) -> int { return a; };
+ void test() {
+ auto L = [](auto a) -> int { return a; }; // expected-error {{cannot initialize}}
int (*fp)(int) = L;
int (&fp2)(int) = [](auto a) { return a; }; // expected-error{{non-const lvalue}}
int (&&fp3)(int) = [](auto a) { return a; }; // expected-error{{no viable conversion}}\
//expected-note{{candidate}}
+
+ using F = int(int);
+ using G = int(void*);
+ L.operator F*();
+ L.operator G*(); // expected-note-re {{instantiation of function template specialization '{{.*}}::operator()<void *>'}}
+
+ // Here, the conversion function is named 'operator auto (*)(int)', and
+ // there is no way to write that name in valid C++.
+ auto M = [](auto a) -> auto { return a; };
+ M.operator F*(); // expected-error {{no member named 'operator int (*)(int)'}}
}
}
}
void test() {
[](auto x) noexcept(noexcept(x)) { } (0);
}
-}
\ No newline at end of file
+}
(void) [] { X<N> x; };
}
}
+
+namespace ConversionOperatorDoesNotHaveDeducedReturnType {
+ auto x = [](int){};
+ auto y = [](auto) -> void {};
+ using T = decltype(x);
+ using U = decltype(y);
+ using ExpectedTypeT = void (*)(int);
+ template<typename T>
+ using ExpectedTypeU = void (*)(T);
+
+ struct X {
+ friend T::operator ExpectedTypeT() const;
+
+ // Formally, this is invalid, because the return type of the conversion
+ // function for a generic lambda expression is an unspecified decltype
+ // type, which this should not match. However, this declaration is
+ // functionally equivalent to that one, so we're permitted to choose to
+ // accept this.
+ template<typename T>
+ friend U::operator ExpectedTypeU<T>() const;
+ };
+
+ // This used to crash in return type deduction for the conversion opreator.
+ struct A { int n; void f() { +[](decltype(n)) {}; } };
+}