[cfe-commits] r150417 - in /cfe/trunk: include/clang/AST/ExprCXX.h include/clang/Sema/Sema.h lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaLambda.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/TreeTransform.h test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 13 14:00:16 PST 2012


Author: dgregor
Date: Mon Feb 13 16:00:16 2012
New Revision: 150417

URL: http://llvm.org/viewvc/llvm-project?rev=150417&view=rev
Log:
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.

Added:
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/TreeTransform.h

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Mon Feb 13 16:00:16 2012
@@ -1059,6 +1059,11 @@
   /// 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 @@
              LambdaCaptureDefault CaptureDefault,
              ArrayRef<Capture> Captures,
              bool ExplicitParams,
+             bool ExplicitResultType,
              ArrayRef<Expr *> CaptureInits,
              ArrayRef<VarDecl *> ArrayIndexVars,
              ArrayRef<unsigned> ArrayIndexStarts,
@@ -1186,6 +1192,7 @@
                             LambdaCaptureDefault CaptureDefault,
                             ArrayRef<Capture> Captures,
                             bool ExplicitParams,
+                            bool ExplicitResultType,
                             ArrayRef<Expr *> CaptureInits,
                             ArrayRef<VarDecl *> ArrayIndexVars,
                             ArrayRef<unsigned> ArrayIndexStarts,
@@ -1276,6 +1283,9 @@
   /// 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;
   }

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Feb 13 16:00:16 2012
@@ -3467,6 +3467,31 @@
   /// 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 @@
 
   /// 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,

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Mon Feb 13 16:00:16 2012
@@ -752,6 +752,7 @@
                        LambdaCaptureDefault CaptureDefault,
                        ArrayRef<Capture> Captures, 
                        bool ExplicitParams,
+                       bool ExplicitResultType,
                        ArrayRef<Expr *> CaptureInits,
                        ArrayRef<VarDecl *> ArrayIndexVars,
                        ArrayRef<unsigned> ArrayIndexStarts,
@@ -763,6 +764,7 @@
     NumCaptures(Captures.size()),
     CaptureDefault(CaptureDefault),
     ExplicitParams(ExplicitParams),
+    ExplicitResultType(ExplicitResultType),
     ClosingBrace(ClosingBrace)
 {
   assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments");
@@ -810,6 +812,7 @@
                                LambdaCaptureDefault CaptureDefault,
                                ArrayRef<Capture> Captures, 
                                bool ExplicitParams,
+                               bool ExplicitResultType,
                                ArrayRef<Expr *> CaptureInits,
                                ArrayRef<VarDecl *> ArrayIndexVars,
                                ArrayRef<unsigned> ArrayIndexStarts,
@@ -824,8 +827,8 @@
           + 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);
 }
 

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Mon Feb 13 16:00:16 2012
@@ -1344,9 +1344,9 @@
 
     // 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.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Feb 13 16:00:16 2012
@@ -9283,8 +9283,6 @@
       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;

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Mon Feb 13 16:00:16 2012
@@ -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 @@
     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 @@
     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 @@
   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 @@
                                                  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 @@
   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 @@
   CXXMethodDecl *CallOperator;
   SourceRange IntroducerRange;
   bool ExplicitParams;
+  bool ExplicitResultType;
   bool LambdaExprNeedsCleanups;
   llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
   llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
@@ -314,6 +357,7 @@
     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 @@
     // 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 @@
 
   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

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Feb 13 16:00:16 2012
@@ -6842,6 +6842,11 @@
       this->Loc = Loc;
       this->Entity = Entity;
     }
+      
+    ExprResult TransformLambdaExpr(LambdaExpr *E) {
+      // Lambdas never need to be transformed.
+      return E;
+    }
   };
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Feb 13 16:00:16 2012
@@ -3379,6 +3379,11 @@
         return Result;
       }
     }
+
+    ExprResult TransformLambdaExpr(LambdaExpr *E) {
+      // Lambdas never need to be transformed.
+      return E;
+    }
   };
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Feb 13 16:00:16 2012
@@ -732,6 +732,14 @@
     /// 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);

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Feb 13 16:00:16 2012
@@ -112,6 +112,11 @@
 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 @@
   /// \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 @@
 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>

Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp?rev=150417&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp Mon Feb 13 16:00:16 2012
@@ -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}}
+





More information about the cfe-commits mailing list