r181985 - First pass of semantic analysis for init-captures: check the initializer, build

Richard Smith richard-llvm at metafoo.co.uk
Wed May 15 23:20:58 PDT 2013


Author: rsmith
Date: Thu May 16 01:20:58 2013
New Revision: 181985

URL: http://llvm.org/viewvc/llvm-project?rev=181985&view=rev
Log:
First pass of semantic analysis for init-captures: check the initializer, build
a FieldDecl from it, and propagate both into the closure type and the
LambdaExpr.

You can't do much useful with them yet -- you can't use them within the body
of the lambda, because we don't have a representation for "the this of the
lambda, not the this of the enclosing context". We also don't have support or a
representation for a nested capture of an init-capture yet, which was intended
to work despite not being allowed by the current standard wording.

Added:
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/Lambda.h
    cfe/trunk/include/clang/Sema/ScopeInfo.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/Stmt.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
    cfe/trunk/test/PCH/cxx11-lambdas.mm
    cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp
    cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/IndexBody.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu May 16 01:20:58 2013
@@ -988,6 +988,8 @@ public:
   ///
   /// \param ThisCapture Will be set to the field declaration for the
   /// 'this' capture.
+  ///
+  /// \note No entries will be added for init-captures.
   void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
                         FieldDecl *&ThisCapture) const;
 

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Thu May 16 01:20:58 2013
@@ -1256,7 +1256,7 @@ class LambdaExpr : public Expr {
     /// capture was implicit.
     Capture_Implicit = 0x01,
 
-    /// \brief Flag used by the Capture class to indciate that the
+    /// \brief Flag used by the Capture class to indicate that the
     /// given capture was by-copy.
     Capture_ByCopy = 0x02
   };
@@ -1299,7 +1299,7 @@ class LambdaExpr : public Expr {
 public:
   /// \brief Describes the capture of either a variable or 'this'.
   class Capture {
-    llvm::PointerIntPair<VarDecl *, 2> VarAndBits;
+    llvm::PointerIntPair<Decl *, 2> DeclAndBits;
     SourceLocation Loc;
     SourceLocation EllipsisLoc;
     
@@ -1315,7 +1315,8 @@ public:
     ///
     /// \param Implicit Whether the capture was implicit or explicit.
     ///
-    /// \param Var The local variable being captured, or null if capturing this.
+    /// \param Var The local variable being captured, or null if capturing this
+    ///        or if this is an init-capture.
     ///
     /// \param EllipsisLoc The location of the ellipsis (...) for a
     /// capture that is a pack expansion, or an invalid source
@@ -1324,29 +1325,43 @@ public:
             LambdaCaptureKind Kind, VarDecl *Var = 0,
             SourceLocation EllipsisLoc = SourceLocation());
 
+    /// \brief Create a new init-capture.
+    Capture(FieldDecl *Field);
+
     /// \brief Determine the kind of capture.
     LambdaCaptureKind getCaptureKind() const;
 
     /// \brief Determine whether this capture handles the C++ 'this'
     /// pointer.
-    bool capturesThis() const { return VarAndBits.getPointer() == 0; }
+    bool capturesThis() const { return DeclAndBits.getPointer() == 0; }
 
     /// \brief Determine whether this capture handles a variable.
-    bool capturesVariable() const { return VarAndBits.getPointer() != 0; }
+    bool capturesVariable() const {
+      return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer());
+    }
+
+    /// \brief Determines whether this is an init-capture.
+    bool isInitCapture() const { return getCaptureKind() == LCK_Init; }
 
     /// \brief Retrieve the declaration of the local variable being
     /// captured.
     ///
-    /// This operation is only valid if this capture does not capture
-    /// 'this'.
-    VarDecl *getCapturedVar() const { 
-      assert(!capturesThis() && "No variable available for 'this' capture");
-      return VarAndBits.getPointer();
+    /// This operation is only valid if this capture is a variable capture
+    /// (other than a capture of 'this').
+    VarDecl *getCapturedVar() const {
+      assert(capturesVariable() && "No variable available for 'this' capture");
+      return cast<VarDecl>(DeclAndBits.getPointer());
+    }
+
+    /// \brief Retrieve the field for an init-capture.
+    FieldDecl *getInitCaptureField() const {
+      assert(getCaptureKind() == LCK_Init && "no field for non-init-capture");
+      return cast<FieldDecl>(DeclAndBits.getPointer());
     }
 
     /// \brief Determine whether this was an implicit capture (not
     /// written between the square brackets introducing the lambda).
-    bool isImplicit() const { return VarAndBits.getInt() & Capture_Implicit; }
+    bool isImplicit() const { return DeclAndBits.getInt() & Capture_Implicit; }
 
     /// \brief Determine whether this was an explicit capture, written
     /// between the square brackets introducing the lambda.
@@ -1483,6 +1498,16 @@ public:
     return capture_init_begin() + NumCaptures;    
   }
 
+  /// \brief Retrieve the initializer for an init-capture.
+  Expr *getInitCaptureInit(capture_iterator Capture) {
+    assert(Capture >= explicit_capture_begin() &&
+           Capture <= explicit_capture_end() && Capture->isInitCapture());
+    return capture_init_begin()[Capture - capture_begin()];
+  }
+  const Expr *getInitCaptureInit(capture_iterator Capture) const {
+    return const_cast<LambdaExpr*>(this)->getInitCaptureInit(Capture);
+  }
+
   /// \brief Retrieve the set of index variables used in the capture 
   /// initializer of an array captured by copy.
   ///

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Thu May 16 01:20:58 2013
@@ -243,7 +243,7 @@ public:
   /// \brief Recursively visit a lambda capture.
   ///
   /// \returns false if the visitation was terminated early, true otherwise.
-  bool TraverseLambdaCapture(LambdaExpr::Capture C);
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaExpr::Capture *C);
   
   // ---- Methods on Stmts ----
 
@@ -802,7 +802,10 @@ bool RecursiveASTVisitor<Derived>::Trave
 }
 
 template<typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){
+bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(
+    LambdaExpr *LE, const LambdaExpr::Capture *C) {
+  if (C->isInitCapture())
+    TRY_TO(TraverseStmt(LE->getInitCaptureInit(C)));
   return true;
 }
 
@@ -2120,7 +2123,7 @@ bool RecursiveASTVisitor<Derived>::Trave
   for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
                                  CEnd = S->explicit_capture_end();
        C != CEnd; ++C) {
-    TRY_TO(TraverseLambdaCapture(*C));
+    TRY_TO(TraverseLambdaCapture(S, C));
   }
 
   if (S->hasExplicitParameters() || S->hasExplicitResultType()) {

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu May 16 01:20:58 2013
@@ -4895,8 +4895,16 @@ let CategoryName = "Lambda Issue" in {
   def note_lambda_to_block_conv : Note<
     "implicit capture of lambda object due to conversion to block pointer "
     "here">;
-  def err_lambda_init_capture_unsupported : Error<
-    "sorry, initialized lambda-captures are not supported yet">;
+
+  // C++1y lambda init-captures.
+  def err_init_capture_no_expression : Error<
+    "initializer missing for lambda capture %0">;
+  def err_init_capture_multiple_expressions : Error<
+    "initializer for lambda capture %0 contains multiple expressions">;
+  def err_init_capture_deduction_failure : Error<
+    "cannot deduce type for lambda capture %0 from initializer of type %1">;
+  def err_init_capture_deduction_failure_from_init_list : Error<
+    "cannot deduce type for lambda capture %0 from initializer list">;
 }
 
 def err_return_in_captured_stmt : Error<

Modified: cfe/trunk/include/clang/Basic/Lambda.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Lambda.h?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Lambda.h (original)
+++ cfe/trunk/include/clang/Basic/Lambda.h Thu May 16 01:20:58 2013
@@ -31,7 +31,8 @@ enum LambdaCaptureDefault {
 enum LambdaCaptureKind {
   LCK_This,
   LCK_ByCopy,
-  LCK_ByRef
+  LCK_ByRef,
+  LCK_Init
 };
 
 } // end namespace clang

Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Thu May 16 01:20:58 2013
@@ -27,6 +27,7 @@ class Decl;
 class BlockDecl;
 class CapturedDecl;
 class CXXMethodDecl;
+class FieldDecl;
 class ObjCPropertyDecl;
 class IdentifierInfo;
 class ImplicitParamDecl;
@@ -330,60 +331,93 @@ public:
   ImplicitCaptureStyle ImpCaptureStyle;
 
   class Capture {
-    // There are two categories of capture: capturing 'this', and capturing
-    // local variables.  There are three ways to capture a local variable:
-    // capture by copy in the C++11 sense, capture by reference
-    // in the C++11 sense, and __block capture.  Lambdas explicitly specify
-    // capture by copy or capture by reference.  For blocks, __block capture
-    // applies to variables with that annotation, variables of reference type
-    // are captured by reference, and other variables are captured by copy.
+    // There are three categories of capture: capturing 'this', capturing
+    // local variables, and C++1y initialized captures (which can have an
+    // arbitrary initializer, and don't really capture in the traditional
+    // sense at all).
+    //
+    // There are three ways to capture a local variable:
+    //  - capture by copy in the C++11 sense,
+    //  - capture by reference in the C++11 sense, and
+    //  - __block capture.
+    // Lambdas explicitly specify capture by copy or capture by reference.
+    // For blocks, __block capture applies to variables with that annotation,
+    // variables of reference type are captured by reference, and other
+    // variables are captured by copy.
     enum CaptureKind {
-      Cap_This, Cap_ByCopy, Cap_ByRef, Cap_Block
+      Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_ThisOrInit
     };
 
-    // The variable being captured (if we are not capturing 'this'),
-    // and misc bits descibing the capture.
-    llvm::PointerIntPair<VarDecl*, 2, CaptureKind> VarAndKind;
-
-    // Expression to initialize a field of the given type, and whether this
-    // is a nested capture; the expression is only required if we are
-    // capturing ByVal and the variable's type has a non-trivial
-    // copy constructor.
-    llvm::PointerIntPair<Expr*, 1, bool> CopyExprAndNested;
+    // The variable being captured (if we are not capturing 'this', and whether
+    // this is a nested capture; the expression is only required if we are
+    // capturing ByVal and the variable's type has a non-trivial copy
+    // constructor, or for an initialized capture.
+    typedef llvm::PointerIntPair<VarDecl*, 1, bool> VarAndNested;
+
+    // The variable being captured, or the implicitly-generated field for
+    // an init-capture.
+    llvm::PointerUnion<VarAndNested, FieldDecl*> VarOrField;
+
+    // Expression to initialize a field of the given type, and the kind of
+    // capture (if this is a capture and not an init-capture).
+    llvm::PointerIntPair<Expr*, 2, CaptureKind> InitExprAndCaptureKind;
 
-    /// \brief The source location at which the first capture occurred..
+    /// \brief The source location at which the first capture occurred.
     SourceLocation Loc;
-    
+
     /// \brief The location of the ellipsis that expands a parameter pack.
     SourceLocation EllipsisLoc;
-    
+
     /// \brief The type as it was captured, which is in effect the type of the
     /// non-static data member that would hold the capture.
     QualType CaptureType;
-    
+
   public:
-    Capture(VarDecl *Var, bool block, bool byRef, bool isNested, 
-            SourceLocation Loc, SourceLocation EllipsisLoc, 
+    Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
+            SourceLocation Loc, SourceLocation EllipsisLoc,
             QualType CaptureType, Expr *Cpy)
-      : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy),
-        CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc),
-        CaptureType(CaptureType){}
+        : VarOrField(VarAndNested(Var, IsNested)),
+          InitExprAndCaptureKind(Cpy, Block ? Cap_Block :
+                                      ByRef ? Cap_ByRef : Cap_ByCopy),
+          Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}
 
     enum IsThisCapture { ThisCapture };
-    Capture(IsThisCapture, bool isNested, SourceLocation Loc, 
+    Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
             QualType CaptureType, Expr *Cpy)
-      : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc),
-        EllipsisLoc(), CaptureType(CaptureType) { }
-
-    bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; }
-    bool isVariableCapture() const { return !isThisCapture(); }
-    bool isCopyCapture() const { return VarAndKind.getInt() == Cap_ByCopy; }
-    bool isReferenceCapture() const { return VarAndKind.getInt() == Cap_ByRef; }
-    bool isBlockCapture() const { return VarAndKind.getInt() == Cap_Block; }
-    bool isNested() { return CopyExprAndNested.getInt(); }
+        : VarOrField(VarAndNested(0, IsNested)),
+          InitExprAndCaptureKind(Cpy, Cap_ThisOrInit),
+          Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}
+
+    Capture(FieldDecl *Field, Expr *Init)
+        : VarOrField(Field), InitExprAndCaptureKind(Init, Cap_ThisOrInit),
+          Loc(), EllipsisLoc(), CaptureType() {}
+
+    bool isThisCapture() const {
+      return InitExprAndCaptureKind.getInt() == Cap_ThisOrInit &&
+             VarOrField.is<VarAndNested>();
+    }
+    bool isVariableCapture() const {
+      return InitExprAndCaptureKind.getInt() != Cap_ThisOrInit;
+    }
+    bool isInitCapture() const {
+      return VarOrField.is<FieldDecl*>();
+    }
+    bool isCopyCapture() const {
+      return InitExprAndCaptureKind.getInt() == Cap_ByCopy;
+    }
+    bool isReferenceCapture() const {
+      return InitExprAndCaptureKind.getInt() == Cap_ByRef;
+    }
+    bool isBlockCapture() const {
+      return InitExprAndCaptureKind.getInt() == Cap_Block;
+    }
+    bool isNested() { return VarOrField.dyn_cast<VarAndNested>().getInt(); }
 
     VarDecl *getVariable() const {
-      return VarAndKind.getPointer();
+      return VarOrField.dyn_cast<VarAndNested>().getPointer();
+    }
+    FieldDecl *getInitCaptureField() const {
+      return VarOrField.dyn_cast<FieldDecl*>();
     }
     
     /// \brief Retrieve the location at which this variable was captured.
@@ -398,8 +432,8 @@ public:
     /// that would store this capture.
     QualType getCaptureType() const { return CaptureType; }
     
-    Expr *getCopyExpr() const {
-      return CopyExprAndNested.getPointer();
+    Expr *getInitExpr() const {
+      return InitExprAndCaptureKind.getPointer();
     }
   };
 
@@ -437,6 +471,10 @@ public:
   void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
                       Expr *Cpy);
 
+  void addInitCapture(FieldDecl *Field, Expr *Init) {
+    Captures.push_back(Capture(Field, Init));
+  }
+
   /// \brief Determine whether the C++ 'this' is captured.
   bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; }
   

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu May 16 01:20:58 2013
@@ -4313,6 +4313,11 @@ public:
                                           bool ExplicitResultType,
                                           bool Mutable);
 
+  /// \brief Check and build an init-capture with the specified name and
+  /// initializer.
+  FieldDecl *checkInitCapture(SourceLocation Loc, bool ByRef,
+                              IdentifierInfo *Id, Expr *Init);
+
   /// \brief Note that we have finished the explicit captures for the
   /// given lambda.
   void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu May 16 01:20:58 2013
@@ -940,12 +940,10 @@ void CXXRecordDecl::getCaptureFields(
   RecordDecl::field_iterator Field = field_begin();
   for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
        C != CEnd; ++C, ++Field) {
-    if (C->capturesThis()) {
+    if (C->capturesThis())
       ThisCapture = *Field;
-      continue;
-    }
-
-    Captures[C->getCapturedVar()] = *Field;
+    else if (C->capturesVariable())
+      Captures[C->getCapturedVar()] = *Field;
   }
 }
 

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Thu May 16 01:20:58 2013
@@ -811,7 +811,7 @@ CXXConstructExpr::CXXConstructExpr(ASTCo
 LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
                              LambdaCaptureKind Kind, VarDecl *Var,
                              SourceLocation EllipsisLoc)
-  : VarAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
+  : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
 {
   unsigned Bits = 0;
   if (Implicit)
@@ -828,15 +828,27 @@ LambdaExpr::Capture::Capture(SourceLocat
   case LCK_ByRef:
     assert(Var && "capture must have a variable!");
     break;
+
+  case LCK_Init:
+    llvm_unreachable("don't use this constructor for an init-capture");
   }
-  VarAndBits.setInt(Bits);
+  DeclAndBits.setInt(Bits);
 }
 
+LambdaExpr::Capture::Capture(FieldDecl *Field)
+    : DeclAndBits(Field,
+                  Field->getType()->isReferenceType() ? 0 : Capture_ByCopy),
+      Loc(Field->getLocation()), EllipsisLoc() {}
+
 LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const {
-  if (capturesThis())
+  Decl *D = DeclAndBits.getPointer();
+  if (!D)
     return LCK_This;
 
-  return (VarAndBits.getInt() & Capture_ByCopy)? LCK_ByCopy : LCK_ByRef;
+  if (isa<FieldDecl>(D))
+    return LCK_Init;
+
+  return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef;
 }
 
 LambdaExpr::LambdaExpr(QualType T, 

Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Thu May 16 01:20:58 2013
@@ -1128,7 +1128,7 @@ Stmt::child_range CapturedStmt::children
 bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
   for (const_capture_iterator I = capture_begin(),
                               E = capture_end(); I != E; ++I) {
-    if (I->capturesThis())
+    if (!I->capturesVariable())
       continue;
 
     // This does not handle variable redeclarations. This should be

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Thu May 16 01:20:58 2013
@@ -1387,6 +1387,13 @@ void StmtPrinter::VisitLambdaExpr(Lambda
         OS << '=';
       OS << C->getCapturedVar()->getName();
       break;
+
+    case LCK_Init:
+      if (C->getInitCaptureField()->getType()->isReferenceType())
+        OS << '&';
+      OS << C->getInitCaptureField()->getName();
+      PrintExpr(Node->getInitCaptureInit(C));
+      break;
     }
   }
   OS << ']';

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Thu May 16 01:20:58 2013
@@ -822,9 +822,17 @@ StmtProfiler::VisitLambdaExpr(const Lamb
                                  CEnd = S->explicit_capture_end();
        C != CEnd; ++C) {
     ID.AddInteger(C->getCaptureKind());
-    if (C->capturesVariable()) {
+    switch (C->getCaptureKind()) {
+    case LCK_This:
+      break;
+    case LCK_ByRef:
+    case LCK_ByCopy:
       VisitDecl(C->getCapturedVar());
       ID.AddBoolean(C->isPackExpansion());
+      break;
+    case LCK_Init:
+      VisitDecl(C->getInitCaptureField());
+      break;
     }
   }
   // Note: If we actually needed to be able to match lambda

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu May 16 01:20:58 2013
@@ -766,9 +766,6 @@ Optional<unsigned> Parser::ParseLambdaIn
       if (Tok.is(tok::identifier)) {
         Id = Tok.getIdentifierInfo();
         Loc = ConsumeToken();
-        
-        if (Tok.is(tok::ellipsis))
-          EllipsisLoc = ConsumeToken();
       } else if (Tok.is(tok::kw_this)) {
         // FIXME: If we want to suggest a fixit here, will need to return more
         // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be
@@ -798,7 +795,8 @@ Optional<unsigned> Parser::ParseLambdaIn
           ConsumeToken();
 
         Init = ParseInitializer();
-      }
+      } else if (Tok.is(tok::ellipsis))
+        EllipsisLoc = ConsumeToken();
     }
 
     Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init);

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu May 16 01:20:58 2013
@@ -9932,7 +9932,7 @@ ExprResult Sema::ActOnBlockStmtExpr(Sour
     if (Cap.isThisCapture())
       continue;
     BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(),
-                              Cap.isNested(), Cap.getCopyExpr());
+                              Cap.isNested(), Cap.getInitExpr());
     Captures.push_back(NewCap);
   }
   BSI->TheDecl->setCaptures(Context, Captures.begin(), Captures.end(),
@@ -11144,17 +11144,18 @@ bool Sema::tryCaptureVariable(VarDecl *V
       cast<CapturingScopeInfo>(FunctionScopes[FunctionScopesIndex]);
 
     // Check whether we've already captured it.
-    if (CSI->CaptureMap.count(Var)) {
+    if (CSI->isCaptured(Var)) {
+      const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var);
+
       // If we found a capture, any subcaptures are nested.
       Nested = true;
       
       // Retrieve the capture type for this variable.
-      CaptureType = CSI->getCapture(Var).getCaptureType();
+      CaptureType = Cap.getCaptureType();
       
       // Compute the type of an expression that refers to this variable.
       DeclRefType = CaptureType.getNonReferenceType();
       
-      const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var);
       if (Cap.isCopyCapture() &&
           !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable))
         DeclRefType.addConst();

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Thu May 16 01:20:58 2013
@@ -18,6 +18,7 @@
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
+#include "TypeLocBuilder.h"
 using namespace clang;
 using namespace sema;
 
@@ -429,6 +430,88 @@ void Sema::deduceClosureReturnType(Captu
   }
 }
 
+FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
+                                  IdentifierInfo *Id, Expr *InitExpr) {
+  LambdaScopeInfo *LSI = getCurLambda();
+
+  // C++1y [expr.prim.lambda]p11:
+  //   The type of [the] member corresponds to the type of a hypothetical
+  //   variable declaration of the form "auto init-capture;"
+  QualType DeductType = Context.getAutoDeductType();
+  TypeLocBuilder TLB;
+  TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
+  if (ByRef) {
+    DeductType = BuildReferenceType(DeductType, true, Loc, Id);
+    assert(!DeductType.isNull() && "can't build reference to auto");
+    TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc);
+  }
+
+  InitializationKind InitKind = InitializationKind::CreateDefault(Loc);
+  Expr *Init = InitExpr;
+  if (ParenListExpr *Parens = dyn_cast<ParenListExpr>(Init)) {
+    if (Parens->getNumExprs() == 1) {
+      Init = Parens->getExpr(0);
+      InitKind = InitializationKind::CreateDirect(
+          Loc, Parens->getLParenLoc(), Parens->getRParenLoc());
+    } else {
+      // C++1y [dcl.spec.auto]p3:
+      //   In an initializer of the form ( expression-list ), the
+      //   expression-list shall be a single assignment-expression.
+      if (Parens->getNumExprs() == 0)
+        Diag(Parens->getLocStart(), diag::err_init_capture_no_expression)
+          << Id;
+      else if (Parens->getNumExprs() > 1)
+        Diag(Parens->getExpr(1)->getLocStart(),
+             diag::err_init_capture_multiple_expressions)
+          << Id;
+      return 0;
+    }
+  } else if (isa<InitListExpr>(Init))
+    // We do not need to distinguish between direct-list-initialization
+    // and copy-list-initialization here, because we will always deduce
+    // std::initializer_list<T>, and direct- and copy-list-initialization
+    // always behave the same for such a type.
+    // FIXME: We should model whether an '=' was present.
+    InitKind = InitializationKind::CreateDirectList(Loc);
+  else
+    InitKind = InitializationKind::CreateCopy(Loc, Loc);
+  QualType DeducedType;
+  if (DeduceAutoType(TLB.getTemporaryTypeLoc(DeductType),
+                     Init, DeducedType) == DAR_Failed) {
+    if (isa<InitListExpr>(Init))
+      Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list)
+          << Id << Init->getSourceRange();
+    else
+      Diag(Loc, diag::err_init_capture_deduction_failure)
+          << Id << Init->getType() << Init->getSourceRange();
+  }
+  if (DeducedType.isNull())
+    return 0;
+
+  //   [...] a non-static data member named by the identifier is declared in
+  //   the closure type. This member is not a bit-field and not mutable.
+  // Core issue: the member is (probably...) public.
+  FieldDecl *NewFD = CheckFieldDecl(
+      Id, DeducedType, TLB.getTypeSourceInfo(Context, DeductType), LSI->Lambda,
+      Loc, /*Mutable*/ false, /*BitWidth*/ 0, ICIS_NoInit,
+      Loc, AS_public, /*PrevDecl*/ 0, /*Declarator*/ 0);
+  LSI->Lambda->addDecl(NewFD);
+
+  if (CurContext->isDependentContext()) {
+    LSI->addInitCapture(NewFD, InitExpr);
+  } else {
+    InitializedEntity Entity = InitializedEntity::InitializeMember(NewFD);
+    InitializationSequence InitSeq(*this, Entity, InitKind, Init);
+    if (!InitSeq.Diagnose(*this, Entity, InitKind, Init)) {
+      ExprResult InitResult = InitSeq.Perform(*this, Entity, InitKind, Init);
+      if (!InitResult.isInvalid())
+        LSI->addInitCapture(NewFD, InitResult.take());
+    }
+  }
+
+  return NewFD;
+}
+
 void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
                                         Declarator &ParamInfo,
                                         Scope *CurScope) {
@@ -514,7 +597,10 @@ void Sema::ActOnStartOfLambdaDefinition(
     = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams,
                        ExplicitResultType,
                        !Method->isConst());
- 
+
+  // Distinct capture names, for diagnostics.
+  llvm::SmallSet<IdentifierInfo*, 8> CaptureNames;
+
   // Handle explicit captures.
   SourceLocation PrevCaptureLoc
     = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
@@ -559,16 +645,32 @@ void Sema::ActOnStartOfLambdaDefinition(
       continue;
     }
 
-    // FIXME: C++1y [expr.prim.lambda]p11
+    assert(C->Id && "missing identifier for capture");
+
     if (C->Init.isInvalid())
       continue;
     if (C->Init.isUsable()) {
-      Diag(C->Loc, diag::err_lambda_init_capture_unsupported);
+      // C++11 [expr.prim.lambda]p8:
+      //   An identifier or this shall not appear more than once in a
+      //   lambda-capture.
+      if (!CaptureNames.insert(C->Id))
+        Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
+
+      if (C->Init.get()->containsUnexpandedParameterPack())
+        ContainsUnexpandedParameterPack = true;
+
+      FieldDecl *NewFD = checkInitCapture(C->Loc, C->Kind == LCK_ByRef,
+                                          C->Id, C->Init.take());
+      // C++1y [expr.prim.lambda]p11:
+      //   Within the lambda-expression's lambda-declarator and
+      //   compound-statement, the identifier in the init-capture
+      //   hides any declaration of the same name in scopes enclosing
+      //   the lambda-expression.
+      if (NewFD)
+        PushOnScopeChains(NewFD, CurScope, false);
       continue;
     }
 
-    assert(C->Id && "missing identifier for capture");
-
     // C++11 [expr.prim.lambda]p8:
     //   If a lambda-capture includes a capture-default that is &, the 
     //   identifiers in the lambda-capture shall not be preceded by &.
@@ -586,6 +688,9 @@ void Sema::ActOnStartOfLambdaDefinition(
       continue;
     }
 
+    // C++11 [expr.prim.lambda]p10:
+    //   The identifiers in a capture-list are looked up using the usual
+    //   rules for unqualified name lookup (3.4.1)
     DeclarationNameInfo Name(C->Id, C->Loc);
     LookupResult R(*this, Name, LookupOrdinaryName);
     LookupName(R, CurScope);
@@ -599,14 +704,27 @@ void Sema::ActOnStartOfLambdaDefinition(
         continue;
     }
 
+    VarDecl *Var = R.getAsSingle<VarDecl>();
+
+    // C++11 [expr.prim.lambda]p8:
+    //   An identifier or this shall not appear more than once in a
+    //   lambda-capture.
+    if (!CaptureNames.insert(C->Id)) {
+      if (Var && LSI->isCaptured(Var)) {
+        Diag(C->Loc, diag::err_capture_more_than_once)
+          << C->Id << SourceRange(LSI->getCapture(Var).getLocation())
+          << FixItHint::CreateRemoval(
+               SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+      } else
+        // Previous capture was an init-capture: no fixit.
+        Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
+      continue;
+    }
+
     // C++11 [expr.prim.lambda]p10:
-    //   The identifiers in a capture-list are looked up using the usual rules
-    //   for unqualified name lookup (3.4.1); each such lookup shall find a 
-    //   variable with automatic storage duration declared in the reaching 
-    //   scope of the local lambda expression.
-    // 
+    //   [...] each such lookup shall find a variable with automatic storage
+    //   duration declared in the reaching scope of the local lambda expression.
     // Note that the 'reaching scope' check happens in tryCaptureVariable().
-    VarDecl *Var = R.getAsSingle<VarDecl>();
     if (!Var) {
       Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
       continue;
@@ -622,18 +740,6 @@ void Sema::ActOnStartOfLambdaDefinition(
       continue;
     }
 
-    // C++11 [expr.prim.lambda]p8:
-    //   An identifier or this shall not appear more than once in a 
-    //   lambda-capture.
-    if (LSI->isCaptured(Var)) {
-      Diag(C->Loc, diag::err_capture_more_than_once) 
-        << C->Id
-        << SourceRange(LSI->getCapture(Var).getLocation())
-        << FixItHint::CreateRemoval(
-             SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
-      continue;
-    }
-
     // C++11 [expr.prim.lambda]p23:
     //   A capture followed by an ellipsis is a pack expansion (14.5.3).
     SourceLocation EllipsisLoc;
@@ -853,11 +959,17 @@ ExprResult Sema::ActOnLambdaExpr(SourceL
         continue;
       }
 
+      if (From.isInitCapture()) {
+        Captures.push_back(LambdaExpr::Capture(From.getInitCaptureField()));
+        CaptureInits.push_back(From.getInitExpr());
+        continue;
+      }
+
       VarDecl *Var = From.getVariable();
       LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
       Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, 
                                              Kind, Var, From.getEllipsisLoc()));
-      CaptureInits.push_back(From.getCopyExpr());
+      CaptureInits.push_back(From.getInitExpr());
     }
 
     switch (LSI->ImpCaptureStyle) {

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu May 16 01:20:58 2013
@@ -3063,7 +3063,7 @@ static void buildCapturedStmtCaptureList
     if (Cap->isThisCapture()) {
       Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
                                                CapturedStmt::VCK_This));
-      CaptureInits.push_back(Cap->getCopyExpr());
+      CaptureInits.push_back(Cap->getInitExpr());
       continue;
     }
 
@@ -3073,7 +3073,7 @@ static void buildCapturedStmtCaptureList
     Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
                                              CapturedStmt::VCK_ByRef,
                                              Cap->getVariable()));
-    CaptureInits.push_back(Cap->getCopyExpr());
+    CaptureInits.push_back(Cap->getInitExpr());
   }
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Thu May 16 01:20:58 2013
@@ -179,10 +179,14 @@ namespace {
       // If any capture names a function parameter pack, that pack is expanded
       // when the lambda is expanded.
       for (LambdaExpr::capture_iterator I = Lambda->capture_begin(),
-                                        E = Lambda->capture_end(); I != E; ++I)
-        if (VarDecl *VD = I->getCapturedVar())
+                                        E = Lambda->capture_end();
+           I != E; ++I) {
+        if (I->capturesVariable()) {
+          VarDecl *VD = I->getCapturedVar();
           if (VD->isParameterPack())
             Unexpanded.push_back(std::make_pair(VD, I->getLocation()));
+        }
+      }
 
       inherited::TraverseLambdaExpr(Lambda);
 

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu May 16 01:20:58 2013
@@ -8074,6 +8074,22 @@ template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
                                              CXXMethodDecl *CallOperator) {
+  bool Invalid = false;
+
+  // Transform any init-capture expressions before entering the scope of the
+  // lambda.
+  llvm::SmallVector<ExprResult, 8> InitCaptureExprs;
+  InitCaptureExprs.resize(E->explicit_capture_end() -
+                          E->explicit_capture_begin());
+  for (LambdaExpr::capture_iterator C = E->capture_begin(),
+                                 CEnd = E->capture_end();
+       C != CEnd; ++C) {
+    if (!C->isInitCapture())
+      continue;
+    InitCaptureExprs[C - E->capture_begin()] =
+        getDerived().TransformExpr(E->getInitCaptureInit(C));
+  }
+
   // Introduce the context of the call operator.
   Sema::ContextRAII SavedContext(getSema(), CallOperator);
 
@@ -8086,7 +8102,6 @@ TreeTransform<Derived>::TransformLambdaS
                                  E->isMutable());
 
   // Transform captures.
-  bool Invalid = false;
   bool FinishedExplicitCaptures = false;
   for (LambdaExpr::capture_iterator C = E->capture_begin(),
                                  CEnd = E->capture_end();
@@ -8104,6 +8119,26 @@ TreeTransform<Derived>::TransformLambdaS
       continue;
     }
 
+    // Rebuild init-captures, including the implied field declaration.
+    if (C->isInitCapture()) {
+      ExprResult Init = InitCaptureExprs[C - E->capture_begin()];
+      if (Init.isInvalid()) {
+        Invalid = true;
+        continue;
+      }
+      FieldDecl *OldFD = C->getInitCaptureField();
+      FieldDecl *NewFD = getSema().checkInitCapture(
+          C->getLocation(), OldFD->getType()->isReferenceType(),
+          OldFD->getIdentifier(), Init.take());
+      if (!NewFD)
+        Invalid = true;
+      else
+        getDerived().transformedLocalDecl(OldFD, NewFD);
+      continue;
+    }
+
+    assert(C->capturesVariable() && "unexpected kind of lambda capture");
+
     // Determine the capture kind for Sema.
     Sema::TryCaptureKind Kind
       = C->isImplicit()? Sema::TryCapture_Implicit
@@ -8120,8 +8155,10 @@ TreeTransform<Derived>::TransformLambdaS
                                                C->getLocation(),
                                                Unexpanded,
                                                ShouldExpand, RetainExpansion,
-                                               NumExpansions))
-        return ExprError();
+                                               NumExpansions)) {
+        Invalid = true;
+        continue;
+      }
 
       if (ShouldExpand) {
         // The transform has determined that we should perform an expansion;

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Thu May 16 01:20:58 2013
@@ -1160,9 +1160,22 @@ void ASTDeclReader::ReadCXXDefinitionDat
       SourceLocation Loc = ReadSourceLocation(Record, Idx);
       bool IsImplicit = Record[Idx++];
       LambdaCaptureKind Kind = static_cast<LambdaCaptureKind>(Record[Idx++]);
-      VarDecl *Var = ReadDeclAs<VarDecl>(Record, Idx);
-      SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx);
-      *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc);
+      switch (Kind) {
+      case LCK_This:
+        *ToCapture++ = Capture(Loc, IsImplicit, Kind, 0, SourceLocation());
+        break;
+      case LCK_ByCopy:
+      case LCK_ByRef: {
+        VarDecl *Var = ReadDeclAs<VarDecl>(Record, Idx);
+        SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx);
+        *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc);
+        break;
+      }
+      case LCK_Init:
+        FieldDecl *Field = ReadDeclAs<FieldDecl>(Record, Idx);
+        *ToCapture++ = Capture(Field);
+        break;
+      }
     }
   }
 }

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu May 16 01:20:58 2013
@@ -5047,12 +5047,25 @@ void ASTWriter::AddCXXDefinitionData(con
       LambdaExpr::Capture &Capture = Lambda.Captures[I];
       AddSourceLocation(Capture.getLocation(), Record);
       Record.push_back(Capture.isImplicit());
-      Record.push_back(Capture.getCaptureKind()); // FIXME: stable!
-      VarDecl *Var = Capture.capturesVariable()? Capture.getCapturedVar() : 0;
-      AddDeclRef(Var, Record);
-      AddSourceLocation(Capture.isPackExpansion()? Capture.getEllipsisLoc()
-                                                 : SourceLocation(), 
-                        Record);
+      Record.push_back(Capture.getCaptureKind());
+      switch (Capture.getCaptureKind()) {
+      case LCK_This:
+        break;
+      case LCK_ByCopy:
+      case LCK_ByRef: {
+        VarDecl *Var =
+            Capture.capturesVariable() ? Capture.getCapturedVar() : 0;
+        AddDeclRef(Var, Record);
+        AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc()
+                                                    : SourceLocation(),
+                          Record);
+        break;
+      }
+      case LCK_Init:
+        FieldDecl *Field = Capture.getInitCaptureField();
+        AddDeclRef(Field, Record);
+        break;
+      }
     }
   }
 }

Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp?rev=181985&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp Thu May 16 01:20:58 2013
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -std=c++1y %s -verify
+
+// For every init-capture a non-static data member named by the identifier of
+// the init-capture is declared in the closure type.
+const char *has_member_x = [x("hello")] {}.x;
+// This member is not a bit-field...
+auto capturing_lambda = [n(0)] {};
+int decltype(capturing_lambda)::*mem_ptr = &decltype(capturing_lambda)::n;
+// ... and not mutable.
+const auto capturing_lambda_copy = capturing_lambda;
+int &n = capturing_lambda_copy.n; // expected-error {{drops qualifiers}}
+
+// The type of that member [...is that of a...] variable declaration of the form
+// "auto init-capture ;"...
+auto with_float = [f(1.0f)] {};
+float &f = with_float.f;
+// ... except that the variable name is replaced by a unique identifier.
+auto with_float_2 = [&f(f)] {}; // ok, refers to outer f
+float &f2 = with_float_2.f;
+
+// Within the lambda-expression's lambda-declarator (FIXME) and
+// compound-statement, the identifier in the init-capture hides any declaration
+// of the same name in scopes enclosing the lambda-expression.
+void hiding() {
+  char c;
+  (void) [c("foo")] {
+    static_assert(sizeof(c) == sizeof(const char*), "");
+  };
+  (void) [c("bar")] () -> decltype(c) {
+    // FIXME: the 'c' in the return type should be the init-capture, not the
+    // outer c.
+    return "baz"; // expected-error {{cannot initialize}}
+  };
+}
+
+struct ExplicitCopy {
+  ExplicitCopy(); // expected-note 2{{not viable}}
+  explicit ExplicitCopy(const ExplicitCopy&);
+};
+auto init_kind_1 = [ec(ExplicitCopy())] {};
+auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching constructor}}
+
+template<typename T> void init_kind_template() {
+  auto init_kind_1 = [ec(T())] {};
+  auto init_kind_2 = [ec = T()] {}; // expected-error {{no matching constructor}}
+}
+template void init_kind_template<int>();
+template void init_kind_template<ExplicitCopy>(); // expected-note {{instantiation of}}
+
+void void_fn();
+int overload_fn();
+int overload_fn(int);
+
+auto bad_init_1 = [a()] {}; // expected-error {{expected expression}}
+auto bad_init_2 = [a(1, 2)] {}; // expected-error {{initializer for lambda capture 'a' contains multiple expressions}}
+auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}}
+auto bad_init_4 = [a(void_fn())] {}; // expected-error {{field has incomplete type 'void'}}
+auto bad_init_5 = [a(overload_fn)] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer of type '<overloaded function}}
+auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer list}}
+
+template<typename...T> void pack_1(T...t) { [a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}}
+template void pack_1<>(); // expected-note {{instantiation of}}
+
+auto multi_return(int a, int b) {
+  return [n(a + 2*b), m(a - 2*b)] {};
+}
+auto use_multi_return() {
+  auto nm = multi_return(5, 9);
+  return nm.n + nm.m;
+}
+
+auto a = [a(4), b = 5, &c = static_cast<const int&&>(0)] {
+  static_assert(sizeof(a) == sizeof(int), "");
+  static_assert(sizeof(b) == sizeof(int), "");
+  using T = decltype(c);
+  using T = const int &;
+};
+auto b = [a{0}] {}; // expected-error {{include <initializer_list>}}
+
+struct S { S(); S(S&&); };
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+template<typename T> decltype(auto) move(T &&t) { return static_cast<typename remove_reference<T>::type&&>(t); }
+auto s = [s(move(S()))] {};

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp Thu May 16 01:20:58 2013
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
 
 void print();
 
@@ -56,3 +57,25 @@ void variadic_lambda(Args... args) {
 }
 
 template void variadic_lambda(int*, float*, double*);
+
+template<typename ...Args>
+void init_capture_pack_err(Args ...args) {
+  [as(args)...] {} (); // expected-error {{expected ','}}
+  [as...(args)]{} (); // expected-error {{expected ','}}
+}
+
+template<typename ...Args>
+void init_capture_pack_multi(Args ...args) {
+  [as(args...)] {} (); // expected-error {{initializer missing}} expected-error {{multiple}}
+}
+template void init_capture_pack_multi(); // expected-note {{instantiation}}
+template void init_capture_pack_multi(int);
+template void init_capture_pack_multi(int, int); // expected-note {{instantiation}}
+
+template<typename ...Args>
+void init_capture_pack_outer(Args ...args) {
+  print([as(args)] { return sizeof(as); } () ...);
+}
+template void init_capture_pack_outer();
+template void init_capture_pack_outer(int);
+template void init_capture_pack_outer(int, int);

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp Thu May 16 01:20:58 2013
@@ -26,4 +26,7 @@ void S2::f(int i) {
   (void)[=, this]{ }; // expected-error{{'this' cannot be explicitly captured}}
   (void)[=]{ this->g(i); };
   (void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
+  (void)[i(0), i(1)]{ }; // expected-error{{'i' can appear only once in a capture list}}
+  (void)[i, i(1)]{ }; // expected-error{{'i' can appear only once in a capture list}}
+  (void)[i(0), i]{ }; // expected-error{{'i' can appear only once in a capture list}}
 }

Modified: cfe/trunk/test/PCH/cxx11-lambdas.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx11-lambdas.mm?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx11-lambdas.mm (original)
+++ cfe/trunk/test/PCH/cxx11-lambdas.mm Thu May 16 01:20:58 2013
@@ -33,6 +33,11 @@ inline int to_block_pointer(int n) {
   return block(17);
 }
 
+template<typename T>
+int init_capture(T t) {
+  return [&, x(t)] { return sizeof(x); };
+}
+
 #else
 
 // CHECK-PRINT: T add_slowly
@@ -45,4 +50,8 @@ int add(int x, int y) {
 
 // CHECK-PRINT: inline int add_int_slowly_twice 
 // CHECK-PRINT: lambda = [&] (int z)
+
+// CHECK-PRINT: init_capture
+// CHECK-PRINT: [&, x( t )]
+
 #endif

Modified: cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp (original)
+++ cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp Thu May 16 01:20:58 2013
@@ -54,16 +54,16 @@ class C {
   void init_capture() {
     // FIXME: These diagnostics should all disappear once semantic analysis
     // for init-captures is complete.
-    [n(0)] () -> int { return ++n; }; // expected-error {{not supported}} expected-error {{undeclared}}
-    [n{0}] { return; }; // expected-error {{not supported}}
-    [n = 0] { return ++n; }; // expected-error {{not supported}} expected-error {{undeclared}}
-    [n = {0}] { return; }; // expected-error {{not supported}}
-    [a([&b = z]{})](){}; // expected-error 2{{not supported}}
+    [n(0)] () -> int { return ++n; }; // expected-error {{non-static data member}}
+    [n{0}] { return; }; // expected-error {{<initializer_list>}}
+    [n = 0] { return ++n; }; // expected-error {{non-static data member}}
+    [n = {0}] { return; }; // expected-error {{<initializer_list>}}
+    [a([&b = z]{})](){};
 
-    int x = 4; // expected-note {{here}}
-    auto y = [&r = x, x = x + 1]() -> int { // expected-error 2{{not supported}} expected-note {{here}}
-      r += 2; // expected-error {{undeclared}}
-      return x + 2; // expected-error {{implicitly captured}}
+    int x = 4;
+    auto y = [&r = x, x = x + 1]() -> int {
+      r += 2; // expected-error {{non-static data member}}
+      return x + 2; // expected-error {{non-static data member}}
     } ();
   }
 };

Modified: cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm (original)
+++ cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm Thu May 16 01:20:58 2013
@@ -18,10 +18,10 @@ class C {
     [=,&foo] () {}; 
     [this] () {}; 
 
-    [foo(bar)] () {}; // expected-error {{not supported}}
-    [foo = bar] () {}; // expected-error {{not supported}}
-    [foo{bar}] () {}; // expected-error {{not supported}}
-    [foo = {bar}] () {}; // expected-error {{not supported}}
+    [foo(bar)] () {};
+    [foo = bar] () {};
+    [foo{bar}] () {}; // expected-error {{<initializer_list>}}
+    [foo = {bar}] () {}; // expected-error {{<initializer_list>}}
 
     [foo(bar) baz] () {}; // expected-error {{called object type 'int' is not a function}}
 

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Thu May 16 01:20:58 2013
@@ -2366,9 +2366,10 @@ bool CursorVisitor::RunVisitorWorkList(V
         for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
                                        CEnd = E->explicit_capture_end();
              C != CEnd; ++C) {
-          if (C->capturesThis())
+          // FIXME: Lambda init-captures.
+          if (!C->capturesVariable())
             continue;
-          
+
           if (Visit(MakeCursorVariableRef(C->getCapturedVar(),
                                           C->getLocation(),
                                           TU)))

Modified: cfe/trunk/tools/libclang/IndexBody.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/IndexBody.cpp?rev=181985&r1=181984&r2=181985&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/IndexBody.cpp (original)
+++ cfe/trunk/tools/libclang/IndexBody.cpp Thu May 16 01:20:58 2013
@@ -153,9 +153,11 @@ public:
     if (C.capturesThis())
       return true;
 
-    if (IndexCtx.shouldIndexFunctionLocalSymbols())
+    if (C.capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())
       IndexCtx.handleReference(C.getCapturedVar(), C.getLocation(),
                                Parent, ParentDC);
+
+    // FIXME: Lambda init-captures.
     return true;
   }
 





More information about the cfe-commits mailing list