diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-13 22:00:16 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-13 22:00:16 +0000 |
commit | dfca6f53ab97d28d43e3fa2564209df08f3d282c (patch) | |
tree | 1e1a5459162a72d9f5d1306def0035c13cae51ec | |
parent | 07e5288c6532c8a61278fab4e0ae058ec81a0f5c (diff) |
Introduce support for template instantiation of lambda
expressions. This is mostly a simple refact, splitting the main "start
a lambda expression" function into smaller chunks that are driven
either from the parser (Sema::ActOnLambdaExpr) or during AST
transformation (TreeTransform::TransformLambdaExpr). A few minor
interesting points:
- Added new entry points for TreeTransform, so that we can
explicitly establish the link between the lambda closure type in the
template and the lambda closure type in the instantiation.
- Added a bit into LambdaExpr specifying whether it had an explicit
result type or not. We should have had this anyway.
This code is 'lightly' tested.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150417 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ExprCXX.h | 10 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 30 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 7 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 218 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 140 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp | 45 |
11 files changed, 376 insertions, 100 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 7f68b2667f..ba2233d23b 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1059,6 +1059,11 @@ class LambdaExpr : public Expr { /// implicit (and empty) parameter list. unsigned ExplicitParams : 1; + /// \brief Whether this lambda had the result type explicitly specified. + unsigned ExplicitResultType : 1; + + /// \brief Whether there are any array index variables stored at the end of + /// this lambda expression. unsigned HasArrayIndexVars : 1; /// \brief The location of the closing brace ('}') that completes @@ -1157,6 +1162,7 @@ private: LambdaCaptureDefault CaptureDefault, ArrayRef<Capture> Captures, bool ExplicitParams, + bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars, ArrayRef<unsigned> ArrayIndexStarts, @@ -1186,6 +1192,7 @@ public: LambdaCaptureDefault CaptureDefault, ArrayRef<Capture> Captures, bool ExplicitParams, + bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars, ArrayRef<unsigned> ArrayIndexStarts, @@ -1276,6 +1283,9 @@ public: /// list vs. an implicit (empty) parameter list. bool hasExplicitParameters() const { return ExplicitParams; } + /// \brief Whether this lambda had its result type explicitly specified. + bool hasExplicitResultType() const { return ExplicitResultType; } + static bool classof(const Stmt *T) { return T->getStmtClass() == LambdaExprClass; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 2e5f8750db..6014fefe1b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3467,6 +3467,31 @@ public: /// initializer for the declaration 'Dcl'. void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); + /// \brief Create a new lambda closure type. + CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange); + + /// \brief Start the definition of a lambda expression. + CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, + SourceRange IntroducerRange, + TypeSourceInfo *MethodType, + SourceLocation EndLoc); + + /// \brief Introduce the scope for a lambda expression. + sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + bool ExplicitParams, + bool ExplicitResultType, + bool Mutable); + + /// \brief Note that we have finished the explicit captures for the + /// given lambda. + void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); + + /// \brief Introduce the lambda parameters into scope. + void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope, + llvm::ArrayRef<ParmVarDecl *> Params); + /// ActOnStartOfLambdaDefinition - This is called just before we start /// parsing the body of a lambda; it analyzes the explicit captures and /// arguments, and sets up various data-structures for the body of the @@ -3476,12 +3501,13 @@ public: /// ActOnLambdaError - If there is an error parsing a lambda, this callback /// is invoked to pop the information about the lambda. - void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope); + void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, + bool IsInstantiation = false); /// ActOnLambdaExpr - This is called when the body of a lambda expression /// was successfully completed. ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, - Scope *CurScope); + Scope *CurScope, bool IsInstantiation = false); // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 4d9f05a028..6825390772 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -752,6 +752,7 @@ LambdaExpr::LambdaExpr(QualType T, LambdaCaptureDefault CaptureDefault, ArrayRef<Capture> Captures, bool ExplicitParams, + bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars, ArrayRef<unsigned> ArrayIndexStarts, @@ -763,6 +764,7 @@ LambdaExpr::LambdaExpr(QualType T, NumCaptures(Captures.size()), CaptureDefault(CaptureDefault), ExplicitParams(ExplicitParams), + ExplicitResultType(ExplicitResultType), ClosingBrace(ClosingBrace) { assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments"); @@ -810,6 +812,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, LambdaCaptureDefault CaptureDefault, ArrayRef<Capture> Captures, bool ExplicitParams, + bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars, ArrayRef<unsigned> ArrayIndexStarts, @@ -824,8 +827,8 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, + sizeof(unsigned) * (Captures.size() + 1); void *Mem = Context.Allocate(Size); return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, - Captures, ExplicitParams, CaptureInits, - ArrayIndexVars, ArrayIndexStarts, + Captures, ExplicitParams, ExplicitResultType, + CaptureInits, ArrayIndexVars, ArrayIndexStarts, ClosingBrace); } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 292d593c7a..746049b166 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1344,9 +1344,9 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { // FIXME: Attributes - // FIXME: Suppress trailing return type if it wasn't specified in - // the source. - OS << " -> " << Proto->getResultType().getAsString(Policy); + // Print the trailing return type if it was specified in the source. + if (Node->hasExplicitResultType()) + OS << " -> " << Proto->getResultType().getAsString(Policy); } // Print the body. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0d43afcd81..a67bcf413c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9283,8 +9283,6 @@ namespace { return BaseTransform::TransformUnaryOperator(E); } - /// \brief Transform the capture expressions in the lambda - /// expression. ExprResult TransformLambdaExpr(LambdaExpr *E) { // Lambdas never need to be transformed. return E; diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index f91b93f957..f97b5232ac 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -20,23 +20,115 @@ using namespace clang; using namespace sema; -void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, - Declarator &ParamInfo, - Scope *CurScope) { +CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange) { DeclContext *DC = CurContext; while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext())) DC = DC->getParent(); - + // Start constructing the lambda class. CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, - Intro.Range.getBegin()); + IntroducerRange.getBegin()); CurContext->addDecl(Class); + + return Class; +} - // Build the call operator; we don't really have all the relevant information - // at this point, but we need something to attach child declarations to. - QualType MethodTy; +CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, + SourceRange IntroducerRange, + TypeSourceInfo *MethodType, + SourceLocation EndLoc) { + // C++11 [expr.prim.lambda]p5: + // The closure type for a lambda-expression has a public inline function + // call operator (13.5.4) whose parameters and return type are described by + // the lambda-expression's parameter-declaration-clause and + // trailing-return-type respectively. + DeclarationName MethodName + = Context.DeclarationNames.getCXXOperatorName(OO_Call); + DeclarationNameLoc MethodNameLoc; + MethodNameLoc.CXXOperatorName.BeginOpNameLoc + = IntroducerRange.getBegin().getRawEncoding(); + MethodNameLoc.CXXOperatorName.EndOpNameLoc + = IntroducerRange.getEnd().getRawEncoding(); + CXXMethodDecl *Method + = CXXMethodDecl::Create(Context, Class, EndLoc, + DeclarationNameInfo(MethodName, + IntroducerRange.getBegin(), + MethodNameLoc), + MethodType->getType(), MethodType, + /*isStatic=*/false, + SC_None, + /*isInline=*/true, + /*isConstExpr=*/false, + EndLoc); + Method->setAccess(AS_public); + + // Temporarily set the lexical declaration context to the current + // context, so that the Scope stack matches the lexical nesting. + Method->setLexicalDeclContext(Class->getDeclContext()); + + return Method; +} + +LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + bool ExplicitParams, + bool ExplicitResultType, + bool Mutable) { + PushLambdaScope(CallOperator->getParent(), CallOperator); + LambdaScopeInfo *LSI = getCurLambda(); + if (CaptureDefault == LCD_ByCopy) + LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval; + else if (CaptureDefault == LCD_ByRef) + LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref; + LSI->IntroducerRange = IntroducerRange; + LSI->ExplicitParams = ExplicitParams; + LSI->Mutable = Mutable; + + if (ExplicitResultType) { + LSI->ReturnType = CallOperator->getResultType(); + } else { + LSI->HasImplicitReturnType = true; + } + + return LSI; +} + +void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) { + LSI->finishedExplicitCaptures(); +} + +void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope, + llvm::ArrayRef<ParmVarDecl *> Params) { + CallOperator->setParams(Params); + CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()), + const_cast<ParmVarDecl **>(Params.end()), + /*CheckParameterNames=*/false); + + // Introduce our parameters into the function scope + for (unsigned p = 0, NumParams = CallOperator->getNumParams(); + p < NumParams; ++p) { + ParmVarDecl *Param = CallOperator->getParamDecl(p); + Param->setOwningFunction(CallOperator); + + // If this has an identifier, add it to the scope stack. + if (CurScope && Param->getIdentifier()) { + CheckShadow(CurScope, Param); + + PushOnScopeChains(Param, CurScope); + } + } +} + +void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, + Declarator &ParamInfo, + Scope *CurScope) { + CXXRecordDecl *Class = createLambdaClosureType(Intro.Range); + + // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; bool ExplicitParams = true; + bool ExplicitResultType = true; SourceLocation EndLoc; if (ParamInfo.getNumTypeObjects() == 0) { // C++11 [expr.prim.lambda]p4: @@ -45,10 +137,11 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = true; EPI.TypeQuals |= DeclSpec::TQ_const; - MethodTy = Context.getFunctionType(Context.DependentTy, - /*Args=*/0, /*NumArgs=*/0, EPI); + QualType MethodTy = Context.getFunctionType(Context.DependentTy, + /*Args=*/0, /*NumArgs=*/0, EPI); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); ExplicitParams = false; + ExplicitResultType = false; EndLoc = Intro.Range.getEnd(); } else { assert(ParamInfo.isFunctionDeclarator() && @@ -70,40 +163,16 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); // FIXME: Can these asserts actually fail? assert(MethodTyInfo && "no type from lambda-declarator"); - MethodTy = MethodTyInfo->getType(); - assert(!MethodTy.isNull() && "no type from lambda declarator"); EndLoc = ParamInfo.getSourceRange().getEnd(); + + ExplicitResultType + = MethodTyInfo->getType()->getAs<FunctionType>()->getResultType() + != Context.DependentTy; } - // C++11 [expr.prim.lambda]p5: - // The closure type for a lambda-expression has a public inline function - // call operator (13.5.4) whose parameters and return type are described by - // the lambda-expression's parameter-declaration-clause and - // trailing-return-type respectively. - DeclarationName MethodName - = Context.DeclarationNames.getCXXOperatorName(OO_Call); - DeclarationNameLoc MethodNameLoc; - MethodNameLoc.CXXOperatorName.BeginOpNameLoc - = Intro.Range.getBegin().getRawEncoding(); - MethodNameLoc.CXXOperatorName.EndOpNameLoc - = Intro.Range.getEnd().getRawEncoding(); - CXXMethodDecl *Method - = CXXMethodDecl::Create(Context, Class, EndLoc, - DeclarationNameInfo(MethodName, - Intro.Range.getBegin(), - MethodNameLoc), - MethodTy, MethodTyInfo, - /*isStatic=*/false, - SC_None, - /*isInline=*/true, - /*isConstExpr=*/false, - EndLoc); - Method->setAccess(AS_public); - - // Temporarily set the lexical declaration context to the current - // context, so that the Scope stack matches the lexical nesting. - Method->setLexicalDeclContext(DC); - + CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, + MethodTyInfo, EndLoc); + // Attributes on the lambda apply to the method. ProcessDeclAttributes(CurScope, Method, ParamInfo); @@ -111,15 +180,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, PushDeclContext(CurScope, Method); // Introduce the lambda scope. - PushLambdaScope(Class, Method); - LambdaScopeInfo *LSI = getCurLambda(); - if (Intro.Default == LCD_ByCopy) - LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval; - else if (Intro.Default == LCD_ByRef) - LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref; - LSI->IntroducerRange = Intro.Range; - LSI->ExplicitParams = ExplicitParams; - LSI->Mutable = (Method->getTypeQualifiers() & Qualifiers::Const) == 0; + LambdaScopeInfo *LSI + = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams, + ExplicitResultType, + (Method->getTypeQualifiers() & Qualifiers::Const) == 0); // Handle explicit captures. SourceLocation PrevCaptureLoc @@ -231,53 +295,31 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, TryCapture_ExplicitByVal; TryCaptureVar(Var, C->Loc, Kind); } - LSI->finishedExplicitCaptures(); + finishLambdaExplicitCaptures(LSI); // Set the parameters on the decl, if specified. if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) { - FunctionProtoTypeLoc Proto = - cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc()); - Method->setParams(Proto.getParams()); - CheckParmsForFunctionDef(Method->param_begin(), - Method->param_end(), - /*CheckParameterNames=*/false); - - // Introduce our parameters into the function scope - for (unsigned p = 0, NumParams = Method->getNumParams(); p < NumParams; ++p) { - ParmVarDecl *Param = Method->getParamDecl(p); - Param->setOwningFunction(Method); - - // If this has an identifier, add it to the scope stack. - if (Param->getIdentifier()) { - CheckShadow(CurScope, Param); - - PushOnScopeChains(Param, CurScope); - } - } - } - - const FunctionType *Fn = MethodTy->getAs<FunctionType>(); - QualType RetTy = Fn->getResultType(); - if (RetTy != Context.DependentTy) { - LSI->ReturnType = RetTy; - } else { - LSI->HasImplicitReturnType = true; + FunctionProtoTypeLoc Proto + = cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc()); + addLambdaParameters(Method, CurScope, Proto.getParams()); } // FIXME: Check return type is complete, !isObjCObjectType - // Enter a new evaluation context to insulate the block from any + // Enter a new evaluation context to insulate the lambda from any // cleanups from the enclosing full-expression. PushExpressionEvaluationContext(PotentiallyEvaluated); } -void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) { +void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, + bool IsInstantiation) { // Leave the expression-evaluation context. DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); // Leave the context of the lambda. - PopDeclContext(); + if (!IsInstantiation) + PopDeclContext(); // Finalize the lambda. LambdaScopeInfo *LSI = getCurLambda(); @@ -291,8 +333,8 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) { PopFunctionScopeInfo(); } -ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, - Stmt *Body, Scope *CurScope) { +ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, + Scope *CurScope, bool IsInstantiation) { // Leave the expression-evaluation context. DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); @@ -305,6 +347,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, CXXMethodDecl *CallOperator; SourceRange IntroducerRange; bool ExplicitParams; + bool ExplicitResultType; bool LambdaExprNeedsCleanups; llvm::SmallVector<VarDecl *, 4> ArrayIndexVars; llvm::SmallVector<unsigned, 4> ArrayIndexStarts; @@ -314,6 +357,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Class = LSI->Lambda; IntroducerRange = LSI->IntroducerRange; ExplicitParams = LSI->ExplicitParams; + ExplicitResultType = !LSI->HasImplicitReturnType; LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups; ArrayIndexVars.swap(LSI->ArrayIndexVars); ArrayIndexStarts.swap(LSI->ArrayIndexStarts); @@ -409,7 +453,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, // C++ [expr.prim.lambda]p7: // The lambda-expression's compound-statement yields the // function-body (8.4) of the function call operator [...]. - ActOnFinishFunctionBody(CallOperator, Body, /*IsInstantation=*/false); + ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation); CallOperator->setLexicalDeclContext(Class); Class->addDecl(CallOperator); @@ -470,9 +514,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, Captures, - ExplicitParams, CaptureInits, - ArrayIndexVars, ArrayIndexStarts, - Body->getLocEnd()); + ExplicitParams, ExplicitResultType, + CaptureInits, ArrayIndexVars, + ArrayIndexStarts, Body->getLocEnd()); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index af2c6efdff..17bdd69ec2 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -6842,6 +6842,11 @@ namespace { this->Loc = Loc; this->Entity = Entity; } + + ExprResult TransformLambdaExpr(LambdaExpr *E) { + // Lambdas never need to be transformed. + return E; + } }; } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 1d84ce31b2..fa66a5a179 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -3379,6 +3379,11 @@ namespace { return Result; } } + + ExprResult TransformLambdaExpr(LambdaExpr *E) { + // Lambdas never need to be transformed. + return E; + } }; } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index bd5a1ed3d0..073d64407a 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -732,6 +732,14 @@ namespace { /// this declaration. Decl *TransformDecl(SourceLocation Loc, Decl *D); + void transformAttrs(Decl *Old, Decl *New) { + SemaRef.InstantiateAttrs(TemplateArgs, Old, New); + } + + void transformedLocalDecl(Decl *Old, Decl *New) { + SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New); + } + /// \brief Transform the definition of the given declaration by /// instantiating it. Decl *TransformDefinition(SourceLocation Loc, Decl *D); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 8744f413a1..ba6ec82c81 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -112,6 +112,11 @@ class TreeTransform { protected: Sema &SemaRef; + /// \brief The set of local declarations that have been transformed, for + /// cases where we are forced to build new declarations within the transformer + /// rather than in the subclass (e.g., lambda closure types). + llvm::DenseMap<Decl *, Decl *> TransformedLocalDecls; + public: /// \brief Initializes a new tree transformer. TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } @@ -351,10 +356,36 @@ public: /// \brief Transform the given declaration, which is referenced from a type /// or expression. /// - /// By default, acts as the identity function on declarations. Subclasses + /// By default, acts as the identity function on declarations, unless the + /// transformer has had to transform the declaration itself. Subclasses /// may override this function to provide alternate behavior. - Decl *TransformDecl(SourceLocation Loc, Decl *D) { return D; } + Decl *TransformDecl(SourceLocation Loc, Decl *D) { + llvm::DenseMap<Decl *, Decl *>::iterator Known + = TransformedLocalDecls.find(D); + if (Known != TransformedLocalDecls.end()) + return Known->second; + + return D; + } + /// \brief Transform the attributes associated with the given declaration and + /// place them on the new declaration. + /// + /// By default, this operation does nothing. Subclasses may override this + /// behavior to transform attributes. + void transformAttrs(Decl *Old, Decl *New) { } + + /// \brief Note that a local declaration has been transformed by this + /// transformer. + /// + /// Local declarations are typically transformed via a call to + /// TransformDefinition. However, in some cases (e.g., lambda expressions), + /// the transformer itself has to transform the declarations. This routine + /// can be overridden by a subclass that keeps track of such mappings. + void transformedLocalDecl(Decl *Old, Decl *New) { + TransformedLocalDecls[Old] = New; + } + /// \brief Transform the definition of the given declaration. /// /// By default, invokes TransformDecl() to transform the declaration. @@ -7622,8 +7653,109 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( template<typename Derived> ExprResult TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { - assert(false && "Lambda expressions cannot be instantiated (yet)"); - return ExprError(); + // Create the local class that will describe the lambda. + CXXRecordDecl *Class + = getSema().createLambdaClosureType(E->getIntroducerRange()); + getDerived().transformedLocalDecl(E->getLambdaClass(), Class); + + // Transform the type of the lambda parameters and start the definition of + // the lambda itself. + TypeSourceInfo *MethodTy + = TransformType(E->getCallOperator()->getTypeSourceInfo()); + if (!MethodTy) + return ExprError(); + + // Build the call operator. + CXXMethodDecl *CallOperator + = getSema().startLambdaDefinition(Class, E->getIntroducerRange(), + MethodTy, + E->getCallOperator()->getLocEnd()); + getDerived().transformAttrs(E->getCallOperator(), CallOperator); + + // Enter the scope of the lambda. + sema::LambdaScopeInfo *LSI + = getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(), + E->getCaptureDefault(), + E->hasExplicitParameters(), + E->hasExplicitResultType(), + E->isMutable()); + + // Transform captures. + bool Invalid = false; + bool FinishedExplicitCaptures = false; + for (LambdaExpr::capture_iterator C = E->capture_begin(), + CEnd = E->capture_end(); + C != CEnd; ++C) { + // When we hit the first implicit capture, tell Sema that we've finished + // the list of explicit captures. + if (!FinishedExplicitCaptures && C->isImplicit()) { + getSema().finishLambdaExplicitCaptures(LSI); + FinishedExplicitCaptures = true; + } + + // Capturing 'this' is trivial. + if (C->capturesThis()) { + getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit()); + continue; + } + + // Transform the captured variable. + VarDecl *CapturedVar + = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(), + C->getCapturedVar())); + if (!CapturedVar) { + Invalid = true; + continue; + } + + // Capture the transformed variable. + getSema().TryCaptureVar(CapturedVar, C->getLocation(), + C->isImplicit()? Sema::TryCapture_Implicit + : C->getCaptureKind() == LCK_ByCopy + ? Sema::TryCapture_ExplicitByVal + : Sema::TryCapture_ExplicitByRef); + } + if (!FinishedExplicitCaptures) + getSema().finishLambdaExplicitCaptures(LSI); + + // Transform lambda parameters. + llvm::SmallVector<QualType, 4> ParamTypes; + llvm::SmallVector<ParmVarDecl *, 4> Params; + if (!getDerived().TransformFunctionTypeParams(E->getLocStart(), + E->getCallOperator()->param_begin(), + E->getCallOperator()->param_size(), + 0, ParamTypes, &Params)) + getSema().addLambdaParameters(CallOperator, /*CurScope=*/0, Params); + else + Invalid = true; + + + // Enter a new evaluation context to insulate the lambda from any + // cleanups from the enclosing full-expression. + getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + + if (Invalid) { + getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0, + /*IsInstantiation=*/true); + return ExprError(); + } + + // Instantiate the body of the lambda expression. + StmtResult Body; + { + Sema::ContextRAII SavedContext(getSema(), CallOperator); + + Body = getDerived().TransformStmt(E->getBody()); + if (Body.isInvalid()) { + getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0, + /*IsInstantiation=*/true); + return ExprError(); + } + } + + return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(), + /*CurScope=*/0, + /*IsInstantiation=*/true); } template<typename Derived> diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp new file mode 100644 index 0000000000..4126dd96b9 --- /dev/null +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Winvalid-noreturn %s -verify + +template<typename T> +void test_attributes() { + auto nrl = []() [[noreturn]] {}; // expected-warning{{function declared 'noreturn' should not return}} +} + +template void test_attributes<int>(); // expected-note{{in instantiation of function}} + +template<typename T> +void call_with_zero() { + [](T *ptr) -> T& { return *ptr; }(0); +} + +template void call_with_zero<int>(); + +template<typename T> +T captures(T x, T y) { + auto lambda = [=, &y] () -> T { + T i = x; + return i + y; + }; + + return lambda(); +} + +struct X { + X(const X&); +}; + +X operator+(X, X); +X operator-(X, X); + +template int captures(int, int); +template X captures(X, X); + +template<typename T> +int infer_result(T x, T y) { + auto lambda = [=](bool b) { return x + y; }; + return lambda(true); // expected-error{{no viable conversion from 'X' to 'int'}} +} + +template int infer_result(int, int); +template int infer_result(X, X); // expected-note{{in instantiation of function template specialization 'infer_result<X>' requested here}} + |