summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/AST/ASTLambda.h27
-rw-r--r--clang/lib/AST/DeclCXX.cpp21
-rw-r--r--clang/lib/CodeGen/CGClass.cpp33
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h2
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp111
-rw-r--r--clang/lib/Sema/SemaLambda.cpp48
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp175
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp43
-rw-r--r--clang/test/SemaCXX/cxx1y-generic-lambdas.cpp116
9 files changed, 478 insertions, 98 deletions
diff --git a/clang/include/clang/AST/ASTLambda.h b/clang/include/clang/AST/ASTLambda.h
index 814beb34e17..9044878e35d 100644
--- a/clang/include/clang/AST/ASTLambda.h
+++ b/clang/include/clang/AST/ASTLambda.h
@@ -31,7 +31,13 @@ inline bool isLambdaCallOperator(const CXXMethodDecl *MD) {
return MD->getOverloadedOperator() == OO_Call;
}
+inline bool isLambdaCallOperator(const DeclContext *DC) {
+ if (!DC || !isa<CXXMethodDecl>(DC)) return false;
+ return isLambdaCallOperator(cast<CXXMethodDecl>(DC));
+}
+
inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
+ if (!MD) return false;
CXXRecordDecl *LambdaClass = MD->getParent();
if (LambdaClass && LambdaClass->isGenericLambda())
return isLambdaCallOperator(MD) &&
@@ -44,6 +50,27 @@ inline bool isGenericLambdaCallOperatorSpecialization(Decl *D) {
return isGenericLambdaCallOperatorSpecialization(
cast<CXXMethodDecl>(D));
}
+
+inline bool isLambdaConversionOperator(CXXConversionDecl *C) {
+ return C ? C->getParent()->isLambda() : false;
+}
+
+inline bool isLambdaConversionOperator(Decl *D) {
+ if (!D) return false;
+ if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D))
+ return isLambdaConversionOperator(Conv);
+ if (FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(D))
+ if (CXXConversionDecl *Conv =
+ dyn_cast_or_null<CXXConversionDecl>(F->getTemplatedDecl()))
+ return isLambdaConversionOperator(Conv);
+ return false;
+}
+
+inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) {
+ return isGenericLambdaCallOperatorSpecialization(
+ dyn_cast<CXXMethodDecl>(DC));
+}
+
} // clang
#endif // LLVM_CLANG_AST_LAMBDA_H
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 33c7ff99b0e..146853586ac 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -972,9 +972,12 @@ CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
DeclContext::lookup_const_result Invoker = lookup(Name);
if (Invoker.empty()) return 0;
assert(Invoker.size() == 1 && "More than one static invoker operator!");
- CXXMethodDecl *Result = cast<CXXMethodDecl>(Invoker.front());
- return Result;
-
+ NamedDecl *InvokerFun = Invoker.front();
+ if (FunctionTemplateDecl *InvokerTemplate =
+ dyn_cast<FunctionTemplateDecl>(InvokerFun))
+ return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());
+
+ return cast<CXXMethodDecl>(InvokerFun);
}
void CXXRecordDecl::getCaptureFields(
@@ -1552,11 +1555,17 @@ bool CXXMethodDecl::hasInlineBody() const {
}
bool CXXMethodDecl::isLambdaStaticInvoker() const {
- return getParent()->isLambda() &&
- getParent()->getLambdaStaticInvoker() == this;
+ const CXXRecordDecl *P = getParent();
+ if (P->isLambda()) {
+ if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) {
+ if (StaticInvoker == this) return true;
+ if (P->isGenericLambda() && this->isFunctionTemplateSpecialization())
+ return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl();
+ }
+ }
+ return false;
}
-
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init,
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index c1226d5681c..4db5b09afe1 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -17,6 +17,7 @@
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
@@ -2104,14 +2105,9 @@ CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
return CGM.GetAddrOfFunction(MD, fnType);
}
-void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
- CallArgList &callArgs) {
- // Lookup the call operator
- DeclarationName operatorName
- = getContext().DeclarationNames.getCXXOperatorName(OO_Call);
- CXXMethodDecl *callOperator =
- cast<CXXMethodDecl>(lambda->lookup(operatorName).front());
-
+void CodeGenFunction::EmitForwardingCallToLambda(
+ const CXXMethodDecl *callOperator,
+ CallArgList &callArgs) {
// Get the address of the call operator.
const CGFunctionInfo &calleeFnInfo =
CGM.getTypes().arrangeCXXMethodDeclaration(callOperator);
@@ -2162,8 +2158,9 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
ParmVarDecl *param = *I;
EmitDelegateCallArg(CallArgs, param);
}
-
- EmitForwardingCallToLambda(Lambda, CallArgs);
+ assert(!Lambda->isGenericLambda() &&
+ "generic lambda interconversion to block not implemented");
+ EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs);
}
void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
@@ -2193,8 +2190,20 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
ParmVarDecl *param = *I;
EmitDelegateCallArg(CallArgs, param);
}
-
- EmitForwardingCallToLambda(Lambda, CallArgs);
+ const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
+ // For a generic lambda, find the corresponding call operator specialization
+ // to which the call to the static-invoker shall be forwarded.
+ if (Lambda->isGenericLambda()) {
+ assert(MD->isFunctionTemplateSpecialization());
+ const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
+ FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate();
+ void *InsertPos = 0;
+ FunctionDecl *CorrespondingCallOpSpecialization =
+ CallOpTemplate->findSpecialization(TAL->data(), TAL->size(), InsertPos);
+ assert(CorrespondingCallOpSpecialization);
+ CallOp = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
+ }
+ EmitForwardingCallToLambda(CallOp, CallArgs);
}
void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 5889d058606..080d0b7b6f3 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1138,7 +1138,7 @@ public:
void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
void EmitFunctionBody(FunctionArgList &Args);
- void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,
+ void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
CallArgList &CallArgs);
void EmitLambdaToBlockPointerBody(FunctionArgList &Args);
void EmitLambdaBlockInvokeBody();
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 6e1751aebd9..4aa53e0a8e8 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -10351,57 +10351,92 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
return FD->isDeleted() && FD->isDefaulted() && isa<CXXMethodDecl>(FD);
}
-/// \brief Mark the call operator of the given lambda closure type as "used".
-static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
- CXXMethodDecl *CallOperator
- = cast<CXXMethodDecl>(
- Lambda->lookup(
- S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
- CallOperator->setReferenced();
- CallOperator->markUsed(S.Context);
-}
-
void Sema::DefineImplicitLambdaToFunctionPointerConversion(
- SourceLocation CurrentLocation,
- CXXConversionDecl *Conv)
-{
- CXXRecordDecl *LambdaClass = Conv->getParent();
-
- // Make sure that the lambda call operator is marked used.
- markLambdaCallOperatorUsed(*this, LambdaClass);
-
- Conv->markUsed(Context);
+ SourceLocation CurrentLocation,
+ CXXConversionDecl *Conv) {
+ 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 = 0;
+
+ // Retrieve the corresponding call-operator specialization.
+ if (Lambda->isGenericLambda()) {
+ assert(Conv->isFunctionTemplateSpecialization());
+ FunctionTemplateDecl *CallOpTemplate =
+ CallOp->getDescribedFunctionTemplate();
+ DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();
+ void *InsertPos = 0;
+ FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(
+ DeducedTemplateArgs->data(),
+ DeducedTemplateArgs->size(),
+ InsertPos);
+ assert(CallOpSpec &&
+ "Conversion operator must have a corresponding call operator");
+ CallOp = cast<CXXMethodDecl>(CallOpSpec);
+ }
+ // Mark the call operator referenced (and add to pending instantiations
+ // if necessary).
+ // For both the conversion and static-invoker template specializations
+ // we construct their body's in this function, so no need to add them
+ // to the PendingInstantiations.
+ MarkFunctionReferenced(CurrentLocation, CallOp);
+
SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
+
+ // Retreive 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 = 0;
+ FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(
+ DeducedTemplateArgs->data(),
+ DeducedTemplateArgs->size(),
+ InsertPos);
+ assert(InvokeSpec &&
+ "Must have a corresponding static invoker specialization");
+ Invoker = cast<CXXMethodDecl>(InvokeSpec);
+ }
+ // Construct the body of the conversion function { return __invoke; }.
+ Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
+ VK_LValue, Conv->getLocation()).take();
+ assert(FunctionRef && "Can't refer to __invoke function?");
+ Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
+ Conv->setBody(new (Context) CompoundStmt(Context, Return,
+ Conv->getLocation(),
+ Conv->getLocation()));
+
+ Conv->markUsed(Context);
+ Conv->setReferenced();
- // Return the address of the __invoke function.
-
- CXXMethodDecl *Invoke = LambdaClass->getLambdaStaticInvoker();
- Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
- VK_LValue, Conv->getLocation()).take();
- assert(FunctionRef && "Can't refer to lambda static invoker function?");
- Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
- Conv->setBody(new (Context) CompoundStmt(Context, Return,
- Conv->getLocation(),
- Conv->getLocation()));
-
- // Fill in the static invoker function with a dummy implementation.
- // IR generation will fill in the actual details.
- Invoke->markUsed(Context);
- Invoke->setReferenced();
- Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));
-
+ // 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(Invoke);
- }
+ L->CompletedImplicitDefinition(Invoker);
+ }
}
+
+
void Sema::DefineImplicitLambdaToBlockPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv)
{
+ assert(!Conv->getParent()->isGenericLambda());
+
Conv->markUsed(Context);
SynthesizedFunctionScope Scope(*this, Conv);
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index fa46a282991..32a385caaa5 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -857,8 +857,6 @@ static void addFunctionPointerConversion(Sema &S,
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
- // FIXME: The conversion operator needs to be fixed for generic lambdas.
- if (Class->isGenericLambda()) return;
// Add the conversion to function pointer.
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
@@ -898,10 +896,34 @@ static void addFunctionPointerConversion(Sema &S,
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
- Class->addDecl(Conversion);
+
+ if (Class->isGenericLambda()) {
+ // Create a template version of the conversion operator, using the template
+ // parameter list of the function call operator.
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *ConversionTemplate =
+ FunctionTemplateDecl::Create(S.Context, Class,
+ Loc, Name,
+ TemplateCallOperator->getTemplateParameters(),
+ Conversion);
+ ConversionTemplate->setAccess(AS_public);
+ ConversionTemplate->setImplicit(true);
+ Conversion->setDescribedFunctionTemplate(ConversionTemplate);
+ Class->addDecl(ConversionTemplate);
+ } else
+ Class->addDecl(Conversion);
// Add a non-static member function that will be the result of
// the conversion with a certain unique ID.
Name = &S.Context.Idents.get(getLambdaStaticInvokerName());
+ // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
+ // we should get a prebuilt TrivialTypeSourceInfo from Context
+ // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
+ // then rewire the parameters accordingly, by hoisting up the InvokeParams
+ // loop below and then use its Params to set Invoke->setParams(...) below.
+ // This would avoid the 'const' qualifier of the calloperator from
+ // contaminating the type of the invoker, which is currently adjusted
+ // in SemaTemplateDeduction.cpp:DeduceTemplateArguments.
CXXMethodDecl *Invoke
= CXXMethodDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc), FunctionTy,
@@ -924,7 +946,19 @@ static void addFunctionPointerConversion(Sema &S,
Invoke->setParams(InvokeParams);
Invoke->setAccess(AS_private);
Invoke->setImplicit(true);
- Class->addDecl(Invoke);
+ if (Class->isGenericLambda()) {
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
+ S.Context, Class, Loc, Name,
+ TemplateCallOperator->getTemplateParameters(),
+ Invoke);
+ StaticInvokerTemplate->setAccess(AS_private);
+ StaticInvokerTemplate->setImplicit(true);
+ Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
+ Class->addDecl(StaticInvokerTemplate);
+ } else
+ Class->addDecl(Invoke);
}
/// \brief Add a lambda's conversion to block pointer.
@@ -1096,7 +1130,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// non-explicit const conversion function to a block pointer having the
// same parameter and return types as the closure type's function call
// operator.
- if (getLangOpts().Blocks && getLangOpts().ObjC1)
+ // FIXME: Fix generic lambda to block conversions.
+ if (getLangOpts().Blocks && getLangOpts().ObjC1 &&
+ !Class->isGenericLambda())
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
@@ -1141,7 +1177,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
}
// TODO: Implement capturing.
if (Lambda->isGenericLambda()) {
- if (Lambda->getCaptureDefault() != LCD_None) {
+ if (!Captures.empty() || Lambda->getCaptureDefault() != LCD_None) {
Diag(Lambda->getIntroducerRange().getBegin(),
diag::err_glambda_not_fully_implemented)
<< " capturing not implemented yet";
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index b71aafe868a..4c73fddbb53 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/TemplateDeduction.h"
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -26,7 +27,6 @@
namespace clang {
using namespace sema;
-
/// \brief Various flags that control template argument deduction.
///
/// These flags can be bitwise-OR'd together.
@@ -3607,19 +3607,37 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
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 the same Deduced type that the TypeToReplaceAutoWith was deduced
+/// with.
+static inline void
+ReplaceAutoWithinFunctionReturnType(FunctionDecl *F,
+ QualType TypeToReplaceAutoWith, Sema &S) {
+ if (TypeToReplaceAutoWith->getContainedAutoType())
+ TypeToReplaceAutoWith = TypeToReplaceAutoWith->
+ getContainedAutoType()->getDeducedType();
+
+ QualType AutoResultType = F->getResultType();
+ assert(AutoResultType->getContainedAutoType());
+ QualType DeducedResultType = S.SubstAutoType(AutoResultType,
+ TypeToReplaceAutoWith);
+ S.Context.adjustDeducedFunctionResultType(F, DeducedResultType);
+}
/// \brief Deduce template arguments for a templated conversion
/// function (C++ [temp.deduct.conv]) and, if successful, produce a
/// conversion function template specialization.
Sema::TemplateDeductionResult
-Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
QualType ToType,
CXXConversionDecl *&Specialization,
TemplateDeductionInfo &Info) {
- if (FunctionTemplate->isInvalidDecl())
+ if (ConversionTemplate->isInvalidDecl())
return TDK_Invalid;
CXXConversionDecl *Conv
- = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
+ = cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());
+
QualType FromType = Conv->getConversionType();
// Canonicalize the types for deduction.
@@ -3675,7 +3693,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// type that is required as the result of the conversion (call it
// A) as described in 14.8.2.4.
TemplateParameterList *TemplateParams
- = FunctionTemplate->getTemplateParameters();
+ = ConversionTemplate->getTemplateParameters();
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
@@ -3703,14 +3721,147 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
P, A, Info, Deduced, TDF))
return Result;
-
+
+ // 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 *FromTypePtr = P.getTypePtr();
+ const Type *ToTypePtr = A.getTypePtr();
+
+ assert(P->isPointerType());
+ FromTypePtr = P->getPointeeType().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 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);
+
+ // 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));
+
+ // 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) { ... }
+ }
+
+
// Finish template argument deduction.
- LocalInstantiationScope InstScope(*this);
- FunctionDecl *Spec = 0;
- TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec,
- Info);
- Specialization = cast_or_null<CXXConversionDecl>(Spec);
+ 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;
}
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
index 7773aedb4ee..a43a98bb18f 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
@@ -1,20 +1,30 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
-namespace return_type_deduction_ok {
- auto l = [](auto a) ->auto { return a; }(2);
- auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
- auto l3 = [](auto a) { return a; }(2);
-
-}
namespace lambda_capturing {
// FIXME: Once return type deduction is implemented for generic lambdas
// this will need to be updated.
void test() {
int i = 10;
- auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
- return i + a;
- };
- L(3);
+ {
+ auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
+ return i + a;
+ };
+ L(3);
+ }
+ {
+ auto L = [i](auto a) -> int { //expected-error{{unimplemented}}
+ return i + a;
+ };
+ L(3);
+ }
+ {
+ auto L = [i = i](auto a) -> int { //expected-error{{unimplemented}}
+ return i + a;
+ };
+ L(3);
+ }
+
+
}
}
@@ -35,17 +45,4 @@ template<class T> void foo(T) {
template void foo(int); //expected-note{{in instantiation of}}
}
-namespace conversion_operator {
-void test() {
- auto L = [](auto a) -> int { return a; };
- int (*fp)(int) = L; //expected-error{{no viable conversion}}
- }
-}
-
-namespace generic_lambda_as_default_argument_ok {
- void test(int i = [](auto a)->int { return a; }(3)) {
-
- }
-
-}
diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
new file mode 100644
index 00000000000..b66825a536d
--- /dev/null
+++ b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %s
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
+
+namespace explicit_call {
+int test() {
+ auto L = [](auto a) { return a; };
+ L.operator()(3);
+ L.operator()<char>(3.14); //expected-warning{{implicit conversion}}
+ return 0;
+}
+} //end ns
+
+namespace test_conversion_to_fptr {
+
+void f1(int (*)(int)) { }
+void f2(char (*)(int)) { } // expected-note{{candidate}}
+void g(int (*)(int)) { } // #1 expected-note{{candidate}}
+void g(char (*)(char)) { } // #2 expected-note{{candidate}}
+void h(int (*)(int)) { } // #3
+void h(char (*)(int)) { } // #4
+
+int test() {
+{
+ auto glambda = [](auto a) { return a; };
+ glambda(1);
+ f1(glambda); // OK
+ f2(glambda); // expected-error{{no matching function}}
+ g(glambda); // expected-error{{call to 'g' is ambiguous}}
+ h(glambda); // OK: calls #3 since it is convertible from ID
+
+ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
+
+}
+{
+
+ auto L = [](auto a) { return a; };
+ int (*fp)(int) = L;
+ fp(5);
+ L(3);
+ char (*fc)(char) = L;
+ fc('b');
+ L('c');
+ double (*fd)(double) = L;
+ fd(3.14);
+ fd(6.26);
+ L(4.25);
+}
+{
+ auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
+ int (*fp)(int) = L;
+ char (*fc)(char) = L; //expected-error{{no viable conversion}}
+ double (*fd)(double) = L; //expected-error{{no viable conversion}}
+}
+
+}
+
+namespace more_converion_to_ptr_to_function_tests {
+
+
+int test() {
+ {
+ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
+ 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}}
+ char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\
+ //expected-note{{candidate template ignored}}
+
+ fp2(3);
+ fp3('\n');
+ fp3('a');
+ return 0;
+ }
+} // end test()
+
+template<class ... Ts> void vfun(Ts ... ) { }
+
+int variadic_test() {
+
+ int (*fp)(int, char, double) = [](auto ... a) -> int { vfun(a...); return 4; };
+ fp(3, '4', 3.14);
+
+ int (*fp2)(int, char, double) = [](auto ... a) { vfun(a...); return 4; };
+ fp(3, '4', 3.14);
+ return 2;
+}
+
+} // end ns
+
+namespace conversion_operator {
+void test() {
+ auto L = [](auto a) -> int { return a; };
+ 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}}
+ }
+}
+
+}
+
+
+namespace return_type_deduction_ok {
+ auto l = [](auto a) ->auto { return a; }(2);
+ auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
+ auto l3 = [](auto a) { return a; }(2);
+
+}
+
+namespace generic_lambda_as_default_argument_ok {
+ void test(int i = [](auto a)->int { return a; }(3)) {
+ }
+}
OpenPOWER on IntegriCloud