- moved EnterExpressionEvaluationContext and semantic processing of the 
init-expr into ParseLambdaIntroducer
  - added a FIXME regarding the better variadic expansion fix for init-captures
  - fixed various comments and names per your suggestion

  This should address all the previous comments.

  Thanks!

Hi rsmith, doug.gregor,

http://llvm-reviews.chandlerc.com/D2092

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D2092?vs=5433&id=5696#toc

Files:
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Initialization.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseExprCXX.cpp
  lib/Sema/SemaAccess.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaInit.cpp
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/TreeTransform.h
  test/SemaCXX/cxx1y-init-captures.cpp
Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h
+++ include/clang/Sema/DeclSpec.h
@@ -2166,12 +2166,13 @@
   IdentifierInfo *Id;
   SourceLocation EllipsisLoc;
   ExprResult Init;
-
+  ParsedType InitCaptureType;
   LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
-                IdentifierInfo* Id = 0,
-                SourceLocation EllipsisLoc = SourceLocation(),
-                ExprResult Init = ExprResult())
-    : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), Init(Init)
+                IdentifierInfo* Id,
+                SourceLocation EllipsisLoc,
+                ExprResult Init, ParsedType InitCaptureType)
+    : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), Init(Init),
+        InitCaptureType(InitCaptureType)
   {}
 };
 
@@ -2188,10 +2189,12 @@
   /// \brief Append a capture in a lambda introducer.
   void addCapture(LambdaCaptureKind Kind,
                   SourceLocation Loc,
-                  IdentifierInfo* Id = 0,
-                  SourceLocation EllipsisLoc = SourceLocation(),
-                  ExprResult Init = ExprResult()) {
-    Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, Init));
+                  IdentifierInfo* Id,
+                  SourceLocation EllipsisLoc,
+                  ExprResult Init, 
+                  ParsedType InitCaptureType) {
+    Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, Init, 
+        InitCaptureType));
   }
 };
 
Index: include/clang/Sema/Initialization.h
===================================================================
--- include/clang/Sema/Initialization.h
+++ include/clang/Sema/Initialization.h
@@ -116,8 +116,8 @@
   };
 
   struct C {
-    /// \brief The variable being captured by an EK_LambdaCapture.
-    VarDecl *Var;
+    /// \brief The name of the variable being captured by an EK_LambdaCapture.
+    IdentifierInfo *VarID;
 
     /// \brief The source location at which the capture occurs.
     unsigned Location;
@@ -183,10 +183,10 @@
                     const InitializedEntity &Parent);
 
   /// \brief Create the initialization entity for a lambda capture.
-  InitializedEntity(VarDecl *Var, FieldDecl *Field, SourceLocation Loc)
-    : Kind(EK_LambdaCapture), Parent(0), Type(Field->getType()) 
+  InitializedEntity(IdentifierInfo *VarID, QualType FieldType, SourceLocation Loc)
+    : Kind(EK_LambdaCapture), Parent(0), Type(FieldType) 
   {
-    Capture.Var = Var;
+    Capture.VarID = VarID;
     Capture.Location = Loc.getRawEncoding();
   }
   
@@ -309,10 +309,10 @@
   }
 
   /// \brief Create the initialization entity for a lambda capture.
-  static InitializedEntity InitializeLambdaCapture(VarDecl *Var,
-                                                   FieldDecl *Field,
+  static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID,
+                                                   QualType FieldType,
                                                    SourceLocation Loc) {
-    return InitializedEntity(Var, Field, Loc);
+    return InitializedEntity(VarID, FieldType, Loc);
   }
 
   /// \brief Create the entity for a compound literal initializer.
@@ -402,13 +402,11 @@
            getKind() == EK_ComplexElement);
     this->Index = Index;
   }
-
-  /// \brief Retrieve the variable for a captured variable in a lambda.
-  VarDecl *getCapturedVar() const {
+  /// \brief For a lambda capture, return the capture's name.
+  StringRef getCapturedVarName() const {
     assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
-    return Capture.Var;
+    return Capture.VarID->getName();
   }
-  
   /// \brief Determine the location of the capture when initializing
   /// field from a captured variable in a lambda.
   SourceLocation getCaptureLoc() const {
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -281,6 +281,12 @@
   /// element type here is ExprWithCleanups::Object.
   SmallVector<BlockDecl*, 8> ExprCleanupObjects;
 
+  /// \brief Store a list of either DeclRefExprs or MemberExprs
+  ///  that contain a reference to a variable (constant) that may or may not
+  ///  be odr-used in this Expr, and we won't know until all lvalue-to-rvalue
+  ///  and discarded value conversions have been applied to all subexpressions 
+  ///  of the enclosing full expression.  This is cleared at the end of each 
+  ///  full expression. 
   llvm::SmallPtrSet<Expr*, 2> MaybeODRUseExprs;
 
   /// \brief Stack containing information about each of the nested
@@ -4311,7 +4317,8 @@
   }
   ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC,
                                  bool DiscardedValue = false,
-                                 bool IsConstexpr = false);
+                                 bool IsConstexpr = false,
+                                 bool IsLambdaInitCaptureInitializer = false);
   StmtResult ActOnFinishFullStmt(Stmt *Stmt);
 
   // Marks SS invalid if it represents an incomplete type.
@@ -4506,10 +4513,18 @@
                         bool ExplicitResultType,
                         bool Mutable);
 
-  /// \brief Check an init-capture and build the implied variable declaration
-  /// with the specified name and initializer.
-  VarDecl *checkInitCapture(SourceLocation Loc, bool ByRef,
-                            IdentifierInfo *Id, Expr *Init);
+  /// \brief Perform initialization analysis of the init-capture and perform
+  /// any implicit conversions such as an lvalue-to-rvalue conversion if
+  /// not being used to initialize a reference.
+  QualType performLambdaInitCaptureInitialization(SourceLocation Loc, 
+      bool ByRef, IdentifierInfo *Id, Expr *&Init);
+  /// \brief Create a dummy variable within the declcontext of the lambda's
+  ///  call operator, for name lookup purposes for a lambda init capture.
+  ///  
+  ///  CodeGen handles emission of lambda captures, ignoring these dummy
+  ///  variables appropriately.
+  VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc, 
+    QualType InitCaptureType, IdentifierInfo *Id, Expr *Init);
 
   /// \brief Build the implicit field for an init-capture.
   FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var);
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -633,8 +633,7 @@
 ExprResult Parser::ParseLambdaExpression() {
   // Parse lambda-introducer.
   LambdaIntroducer Intro;
-
-  Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+  Optional<unsigned> DiagID = ParseLambdaIntroducer(Intro);
   if (DiagID) {
     Diag(Tok, DiagID.getValue());
     SkipUntil(tok::r_square, StopAtSemi);
@@ -674,7 +673,7 @@
   if (Next.is(tok::identifier) && After.is(tok::identifier)) {
     return ExprEmpty();
   }
-
+ 
   // Here, we're stuck: lambda introducers and Objective-C message sends are
   // unambiguous, but it requires arbitrary lookhead.  [a,b,c,d,e,f,g] is a
   // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send.  Instead of
@@ -684,6 +683,7 @@
   LambdaIntroducer Intro;
   if (TryParseLambdaIntroducer(Intro))
     return ExprEmpty();
+
   return ParseLambdaExpressionAfterIntroducer(Intro);
 }
 
@@ -699,6 +699,10 @@
 Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
                                                  bool *SkippedInits) {
   typedef Optional<unsigned> DiagResult;
+  // Each lambda init-capture forms its own full expression, which clears
+  // Actions.MaybeODRUseExprs. So create an expression evaluation context to
+  // save the necessary state, and restore it later.
+  EnterExpressionEvaluationContext EC(Actions, Sema::PotentiallyEvaluated);
 
   assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
   BalancedDelimiterTracker T(*this, tok::l_square);
@@ -862,13 +866,61 @@
       } else if (Tok.is(tok::ellipsis))
         EllipsisLoc = ConsumeToken();
     }
+    // If this is an init capture, process the initialization expression
+    // right away.  For lambda init-captures such as the following:
+    // const int x = 10;
+    //  auto L = [i = x+1](int a) {
+    //    return [j = x+2,
+    //           &k = x](char b) { };
+    //  };
+    // keep in mind that each lambda init-capture has to have:
+    //  - its initialization expression executed in the context
+    //    of the enclosing/parent decl-context.
+    //  - but the variable itself has to be 'injected' into the
+    //    decl-context of its lambda's call-operator (which has
+    //    not yet been created).
+    // Each init-expression is a full-expression that has to get
+    // Sema-analyzed (for capturing etc.) before its lambda's
+    // call-operator's decl-context, scope & scopeinfo are pushed on their
+    // respective stacks.  Thus if any variable is odr-used in the init-capture
+    // it will correctly get captured in the enclosing lambda, if one exists.
+    // The init-variables above are created later once the lambdascope and
+    // call-operators decl-context is pushed onto its respective stack.
 
-    Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init);
+    // Since the lambda init-capture's initializer expression occurs in the
+    // context of the enclosing function or lambda, therefore we can not wait
+    // till a lambda scope has been pushed on before deciding whether the
+    // variable needs to be captured.  We also need to process all
+    // lvalue-to-rvalue conversions and discarded-value conversions,
+    // so that we can avoid capturing certain constant variables.
+    // For e.g.,
+    //  void test() {
+    //   const int x = 10;
+    //   auto L = [&z = x](char a) { <-- don't capture by the current lambda
+    //     return [y = x](int i) { <-- don't capture by enclosing lambda
+    //          return y;
+    //     }
+    //   };
+    // If x was not const, the second use would require 'L' to capture, and
+    // that would be an error.
+
+    ParsedType InitCaptureParsedType;
+    if (Init.isUsable()) {
+      // Get the pointer and store it in an lvalue, so we can use it as an
+      // out argument.
+      Expr *InitExpr = Init.get();
+      // This performs any lvalue-to-rvalue conversions if necessary, which
+      // can affect what gets captured in the containing decl-context.
+      QualType InitCaptureType = Actions.performLambdaInitCaptureInitialization(
+        Loc, Kind == LCK_ByRef, Id, InitExpr);
+      Init = InitExpr;
+      InitCaptureParsedType.set(InitCaptureType);
+    }
+    Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init, InitCaptureParsedType);
   }
 
   T.consumeClose();
   Intro.Range.setEnd(T.getCloseLocation());
-
   return DiagResult();
 }
 
Index: lib/Sema/SemaAccess.cpp
===================================================================
--- lib/Sema/SemaAccess.cpp
+++ lib/Sema/SemaAccess.cpp
@@ -1650,9 +1650,9 @@
   }
 
   case InitializedEntity::EK_LambdaCapture: {
-    const VarDecl *Var = Entity.getCapturedVar();
+    StringRef VarName = Entity.getCapturedVarName();
     PD = PDiag(diag::err_access_lambda_capture);
-    PD << Var->getName() << Entity.getType() << getSpecialMember(Constructor);
+    PD << VarName << Entity.getType() << getSpecialMember(Constructor);
     break;
   }
 
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11687,7 +11687,8 @@
   SmallVector<InitializedEntity, 4> Entities;
   Entities.reserve(1 + IndexVariables.size());
   Entities.push_back(
-    InitializedEntity::InitializeLambdaCapture(Var, Field, Loc));
+    InitializedEntity::InitializeLambdaCapture(Var->getIdentifier(), 
+        Field->getType(), Loc));
   for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
     Entities.push_back(InitializedEntity::InitializeElement(S.Context,
                                                             0,
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5929,13 +5929,30 @@
 
 ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
                                      bool DiscardedValue,
-                                     bool IsConstexpr) {
+                                     bool IsConstexpr, 
+                                     bool IsLambdaInitCaptureInitializer) {
   ExprResult FullExpr = Owned(FE);
 
   if (!FullExpr.get())
     return ExprError();
-
-  if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
+ 
+  // If we are an init-expression in a lambdas init-capture, we should not 
+  // diagnose an unexpanded pack now (will be diagnosed once lambda-expr 
+  // containing full-expression is done).
+  // template<class ... Ts> void test(Ts ... t) {
+  //   test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now.
+  //     return a;
+  //   }() ...);
+  // }
+  // FIXME: This is a hack. It would be better if we pushed the lambda scope
+  // when we parse the lambda introducer, and teach capturing (but not
+  // unexpanded pack detection) to walk over LambdaScopeInfos which don't have a
+  // corresponding class yet (that is, have LambdaScopeInfo either represent a
+  // lambda where we've entered the introducer but not the body, or represent a
+  // lambda where we've entered the body, depending on where the
+  // parser/instantiation has got to).
+  if (!IsLambdaInitCaptureInitializer && 
+      DiagnoseUnexpandedParameterPack(FullExpr.get()))
     return ExprError();
 
   // Top-level expressions default to 'id' when we're in a debugger.
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -2508,7 +2508,7 @@
     return VariableOrMember->getDeclName();
 
   case EK_LambdaCapture:
-    return Capture.Var->getDeclName();
+    return DeclarationName(Capture.VarID);
       
   case EK_Result:
   case EK_Exception:
@@ -2610,7 +2610,7 @@
   case EK_BlockElement: OS << "Block"; break;
   case EK_LambdaCapture:
     OS << "LambdaCapture ";
-    getCapturedVar()->printName(OS);
+    OS << DeclarationName(Capture.VarID);
     break;
   }
 
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -609,12 +609,15 @@
   }
 }
 
-VarDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
-                                IdentifierInfo *Id, Expr *Init) {
-  // C++1y [expr.prim.lambda]p11:
-  //   An init-capture behaves as if it declares and explicitly captures
-  //   a variable of the form
-  //     "auto init-capture;"
+QualType Sema::performLambdaInitCaptureInitialization(SourceLocation Loc,
+                                                      bool ByRef,
+                                                      IdentifierInfo *Id,
+                                                      Expr *&Init) {
+
+  const bool IsDirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
+
+  // Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
+  // deduce against.
   QualType DeductType = Context.getAutoDeductType();
   TypeLocBuilder TLB;
   TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
@@ -625,24 +628,102 @@
   }
   TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
 
+  // Are we a non-list direct initialization?
+  ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+
+  Expr *DeduceInit = Init;
+  // Initializer could be a C++ direct-initializer. Deduction only works if it
+  // contains exactly one expression.
+  if (CXXDirectInit) {
+    if (CXXDirectInit->getNumExprs() == 0) {
+      // It isn't possible to write this directly, but it is possible to
+      // end up in this situation with "x(some_pack...);"
+      Diag(CXXDirectInit->getLocStart(), diag::err_init_capture_no_expression)
+          << DeclarationName(Id) << TSI->getType() << Loc;
+      return QualType();
+    } else if (CXXDirectInit->getNumExprs() > 1) {
+      Diag(CXXDirectInit->getExpr(1)->getLocStart(),
+           diag::err_init_capture_multiple_expressions)
+          << DeclarationName(Id) << TSI->getType() << Loc;
+      return QualType();
+    } else {
+      DeduceInit = CXXDirectInit->getExpr(0);
+    }
+  }
+
+  // Now deduce against the initialization expression and store the deduced
+  // type below.
+  QualType DeducedType;
+  if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
+    if (isa<InitListExpr>(Init))
+      Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list)
+          << DeclarationName(Id)
+          << (DeduceInit->getType().isNull() ? TSI->getType()
+                                             : DeduceInit->getType())
+          << DeduceInit->getSourceRange();
+    else
+      Diag(Loc, diag::err_init_capture_deduction_failure)
+          << DeclarationName(Id) << TSI->getType()
+          << (DeduceInit->getType().isNull() ? TSI->getType()
+                                             : DeduceInit->getType())
+          << DeduceInit->getSourceRange();
+  }
+  if (DeducedType.isNull())
+    return QualType();
+
+  // Perform initialization analysis and ensure any implicit conversions
+  // (such as lvalue-to-rvalue) are enforced.
+  InitializedEntity Entity =
+      InitializedEntity::InitializeLambdaCapture(Id, DeducedType, Loc);
+  InitializationKind Kind =
+      IsDirectInit
+          ? (CXXDirectInit ? InitializationKind::CreateDirect(
+                                 Loc, Init->getLocStart(), Init->getLocEnd())
+                           : InitializationKind::CreateDirectList(Loc))
+          : InitializationKind::CreateCopy(Loc, Init->getLocStart());
+
+  MultiExprArg Args = Init;
+  if (CXXDirectInit)
+    Args =
+        MultiExprArg(CXXDirectInit->getExprs(), CXXDirectInit->getNumExprs());
+  QualType DclT;
+  InitializationSequence InitSeq(*this, Entity, Kind, Args);
+  ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
+
+  if (Result.isInvalid())
+    return QualType();
+  Init = Result.takeAs<Expr>();
+
+  // The init-capture initialization is a full-expression that must be
+  // processed as one before we enter the declcontext of the lambda's
+  // call-operator.
+  Result = ActOnFinishFullExpr(Init, Loc, /*DiscardedValue*/ false,
+                               /*IsConstexpr*/ false,
+                               /*IsLambdaInitCaptureInitalizer*/ true);
+  if (Result.isInvalid())
+    return QualType();
+
+  Init = Result.takeAs<Expr>();
+  return DeducedType;
+}
+
+VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, 
+    QualType InitCaptureType, IdentifierInfo *Id, Expr *Init) {
+
+  TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType,
+      Loc);
   // Create a dummy variable representing the init-capture. This is not actually
   // used as a variable, and only exists as a way to name and refer to the
   // init-capture.
   // FIXME: Pass in separate source locations for '&' and identifier.
   VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc,
-                                   Loc, Id, TSI->getType(), TSI, SC_Auto);
+                                   Loc, Id, InitCaptureType, TSI, SC_Auto);
   NewVD->setInitCapture(true);
   NewVD->setReferenced(true);
   NewVD->markUsed(Context);
+  NewVD->setInit(Init);
+  return NewVD;
 
-  // 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.
-  bool DirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
-  AddInitializerToDecl(NewVD, Init, DirectInit, /*ContainsAuto*/true);
-  return NewVD;
 }
 
 FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
@@ -816,7 +897,7 @@
     if (C->Init.isInvalid())
       continue;
 
-    VarDecl *Var;
+    VarDecl *Var = 0;
     if (C->Init.isUsable()) {
       Diag(C->Loc, getLangOpts().CPlusPlus1y
                        ? diag::warn_cxx11_compat_init_capture
@@ -824,9 +905,13 @@
 
       if (C->Init.get()->containsUnexpandedParameterPack())
         ContainsUnexpandedParameterPack = true;
-
-      Var = checkInitCapture(C->Loc, C->Kind == LCK_ByRef,
-                             C->Id, C->Init.take());
+      // If the initializer expression is usable, but the InitCaptureType
+      // is not then an error has occured - so ignore the capture for now.
+      // for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
+      if (C->InitCaptureType.get().isNull()) 
+        continue;
+      Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(), 
+            C->Id, C->Init.take());
       // C++1y [expr.prim.lambda]p11:
       //   An init-capture behaves as if it declares and explicitly
       //   captures a variable [...] whose declarative region is the
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -917,7 +917,8 @@
     }
 
     ExprResult TransformLambdaScope(LambdaExpr *E,
-                                    CXXMethodDecl *NewCallOperator) {
+        CXXMethodDecl *NewCallOperator, 
+        ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) {
       CXXMethodDecl *const OldCallOperator = E->getCallOperator();   
       // In the generic lambda case, we set the NewTemplate to be considered
       // an "instantiation" of the OldTemplate.
@@ -936,7 +937,8 @@
         NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,
                                                     TSK_ImplicitInstantiation);
       
-      return inherited::TransformLambdaScope(E, NewCallOperator);
+      return inherited::TransformLambdaScope(E, NewCallOperator, 
+          InitCaptureExprsAndTypes);
     }
     TemplateParameterList *TransformTemplateParameterList(
                               TemplateParameterList *OrigTPL)  {
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -593,9 +593,11 @@
 
   StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
   ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
-
+  
+  typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
   /// \brief Transform the captures and body of a lambda expression.
-  ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+  ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator, 
+       ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes);
 
   TemplateParameterList *TransformTemplateParameterList(
         TemplateParameterList *TPL) {
@@ -8275,7 +8277,40 @@
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
- 
+   
+  // Transform any init-capture expressions before entering the scope of the 
+  // lambda body, because they are not semantically within that scope.
+  SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes;
+  InitCaptureExprsAndTypes.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;
+    EnterExpressionEvaluationContext  EEEC(getSema(), 
+        Sema::PotentiallyEvaluated);    
+    ExprResult NewExprInitResult = getDerived().TransformInitializer(
+        C->getCapturedVar()->getInit(),
+        C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
+    
+    if (NewExprInitResult.isInvalid())
+      return ExprError();
+    Expr *NewExprInit = NewExprInitResult.get();
+      
+    VarDecl *OldVD = C->getCapturedVar();
+    QualType NewInitCaptureType = 
+        getSema().performLambdaInitCaptureInitialization(C->getLocation(), 
+            OldVD->getType()->isReferenceType(), OldVD->getIdentifier(), 
+            NewExprInit);
+    NewExprInitResult = NewExprInit;
+    VarDecl *NewVD = 0;
+    InitCaptureExprsAndTypes[C - E->capture_begin()] =
+        std::make_pair(NewExprInitResult, NewInitCaptureType);
+
+  }
+
   LambdaScopeInfo *LSI = getSema().PushLambdaScope();
   // Transform the template parameters, and add them to the current
   // instantiation scope. The null case is handled correctly.
@@ -8370,31 +8405,17 @@
 
   getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
 
-  return getDerived().TransformLambdaScope(E, NewCallOperator);
+  return getDerived().TransformLambdaScope(E, NewCallOperator, 
+      InitCaptureExprsAndTypes);
 }
 
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
-                                             CXXMethodDecl *CallOperator) {
+    CXXMethodDecl *CallOperator, 
+    ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) {
   bool Invalid = false;
 
-  // Transform any init-capture expressions before entering the scope of the
-  // lambda.
-  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().TransformInitializer(
-            C->getCapturedVar()->getInit(),
-            C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
-  }
-
   // Introduce the context of the call operator.
   Sema::ContextRAII SavedContext(getSema(), CallOperator);
 
@@ -8427,19 +8448,24 @@
 
     // Rebuild init-captures, including the implied field declaration.
     if (C->isInitCapture()) {
-      ExprResult Init = InitCaptureExprs[C - E->capture_begin()];
-      if (Init.isInvalid()) {
+      
+      InitCaptureInfoTy InitExprTypePair = 
+          InitCaptureExprsAndTypes[C - E->capture_begin()];
+      ExprResult Init = InitExprTypePair.first;
+      QualType InitQualType = InitExprTypePair.second;
+      if (Init.isInvalid() || InitQualType.isNull()) {
         Invalid = true;
         continue;
       }
       VarDecl *OldVD = C->getCapturedVar();
-      VarDecl *NewVD = getSema().checkInitCapture(
-          C->getLocation(), OldVD->getType()->isReferenceType(),
-          OldVD->getIdentifier(), Init.take());
+      VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
+          OldVD->getLocation(), InitExprTypePair.second, 
+          OldVD->getIdentifier(), Init.get());
       if (!NewVD)
         Invalid = true;
-      else
+      else {
         getDerived().transformedLocalDecl(OldVD, NewVD);
+      }
       getSema().buildInitCaptureField(LSI, NewVD);
       continue;
     }
Index: test/SemaCXX/cxx1y-init-captures.cpp
===================================================================
--- test/SemaCXX/cxx1y-init-captures.cpp
+++ test/SemaCXX/cxx1y-init-captures.cpp
@@ -1,14 +1,169 @@
-// RUN: %clang_cc1 -std=c++1y %s -verify
+// RUN: %clang_cc1 -std=c++1y %s -verify -emit-llvm-only
 
-// expected-no-diagnostics
 namespace variadic_expansion {
-  void f(int &, char &);
-
-  template <typename ... T> void g(T &... t) {
+  int f(int &, char &) { return 0; }
+  template<class ... Ts> char fv(Ts ... ts) { return 0; }
+  // FIXME: why do we get 2 error messages
+  template <typename ... T> void g(T &... t) { //expected-note3{{declared here}}
     f([&a(t)]()->decltype(auto) {
       return a;
     }() ...);
+    
+    auto L = [x = f([&a(t)]()->decltype(auto) { return a; }()...)]() { return x; };
+    const int y = 10;
+    auto M = [x = y, 
+                &z = y](T& ... t) { }; 
+    auto N = [x = y, 
+                &z = y, n = f(t...), 
+                o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...), t...](T& ... s) { 
+                  fv([&a(t)]()->decltype(auto) { 
+                    return a;
+                  }() ...);
+                };                 
+    auto N2 = [x = y,                     //expected-note3{{begins here}}
+                &z = y, n = f(t...), 
+                o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) { 
+                  fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
+                    return a;
+                  }() ...);
+                };                 
+
   }
 
-  void h(int i, char c) { g(i, c); }
+  void h(int i, char c) { g(i, c); } //expected-note{{in instantiation}}
 }
+
+namespace odr_use_within_init_capture {
+
+int test() {
+
+  { // no captures
+    const int x = 10;
+    auto L = [z = x + 2](int a) {
+      auto M = [y = x - 2](char b) {
+        return y;
+      };
+      return M;
+    };
+        
+  }
+  { // should not capture
+    const int x = 10;
+    auto L = [&z = x](int a) {
+      return a;;
+    };
+        
+  }
+  {
+    const int x = 10;
+    auto L = [k = x](char a) { //expected-note {{declared}}
+      return [](int b) { //expected-note {{begins}}
+        return [j = k](int c) { //expected-error {{cannot be implicitly captured}}
+          return c;
+        };
+      };
+    };
+  }
+  {
+    const int x = 10;
+    auto L = [k = x](char a) { 
+      return [=](int b) { 
+        return [j = k](int c) { 
+          return c;
+        };
+      };
+    };
+  }
+  {
+    const int x = 10;
+    auto L = [k = x](char a) { 
+      return [k](int b) { 
+        return [j = k](int c) { 
+          return c;
+        };
+      };
+    };
+  }
+
+  return 0;
+}
+
+int run = test();
+
+}
+
+namespace odr_use_within_init_capture_template {
+
+template<class T = int>
+int test(T t = T{}) {
+
+  { // no captures
+    const T x = 10;
+    auto L = [z = x](char a) {
+      auto M = [y = x](T b) {
+        return y;
+      };
+      return M;
+    };
+        
+  }
+  { // should not capture
+    const T x = 10;
+    auto L = [&z = x](T a) {
+      return a;;
+    };
+        
+  }
+  { // will need to capture x in outer lambda
+    const T x = 10; //expected-note {{declared}}
+    auto L = [z = x](char a) { //expected-note {{begins}}
+      auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
+        return y;
+      };
+      return M;
+    };
+        
+  }
+  { // will need to capture x in outer lambda
+    const T x = 10; 
+    auto L = [=,z = x](char a) { 
+      auto M = [&y = x](T b) { 
+        return y;
+      };
+      return M;
+    };
+        
+  }
+  { // will need to capture x in outer lambda
+    const T x = 10; 
+    auto L = [x, z = x](char a) { 
+      auto M = [&y = x](T b) { 
+        return y;
+      };
+      return M;
+    };
+  }
+  { // will need to capture x in outer lambda
+    const int x = 10; //expected-note 2{{declared}}
+    auto L = [z = x](char a) { //expected-note 2{{begins}}
+      auto M = [&y = x](T b) { //expected-error 2{{cannot be implicitly captured}}
+        return y;
+      };
+      return M;
+    };     
+  }
+  {
+    // no captures
+    const T x = 10;
+    auto L = [z = 
+                  [z = x, &y = x](char a) { return z + y; }('a')](char a) 
+      { return z; };
+  
+  }
+  
+  return 0;
+}
+
+int run = test(); //expected-note {{instantiation}}
+
+}
\ No newline at end of file
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to