Hi rsmith, doug.gregor,


Currently clang does not seem to get capturing of init-captures correctly.

Consider the following code:
    void test() {
       const int x = 10;
       const int y = 12;
       auto L = [&k = x, j = x](int a) {
           return [&l = x, m = y] (int b) { };
       };  
    }

The outer lambda needs to capture 'x' but not 'y'.  And the inner lambda should 
not capture either x or y.  

This patch fixes this by:
  - moving up the checking of the init capture before its lambda call 
operator's declcontext, scope, scopeinfo are pushed on (so that 
lvalue-to-rvalue conversions can be checked for const variables in the 
init-expr)
  - using the declcontext of the enclosing scope temporarily when the 
init-variable is created, and then fixing it once its call-operator has been 
created.  (this does require fixing the linkage computation of init-vars to 
return none, so that it isn't perceived as ever being declared at namespace 
scope).
  
Tests added - and regressions tests all seem to pass.

Certain aspects of this patch might emanate a bad smell - lets see if anyone 
else feels the same ;)

Thanks!

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

Files:
  include/clang/AST/Decl.h
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Sema.h
  lib/AST/Decl.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateVariadic.cpp
  lib/Sema/TreeTransform.h
  test/SemaCXX/cxx1y-init-captures.cpp
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -884,8 +884,11 @@
   bool isLocalVarDecl() const {
     if (getKind() != Decl::Var)
       return false;
+    // Lambda init-captures behave as if declared within the body of lambdas.
+    if (isInitCapture()) return true;
     if (const DeclContext *DC = getLexicalDeclContext())
       return DC->getRedeclContext()->isFunctionOrMethod();
+    
     return false;
   }
 
@@ -909,7 +912,8 @@
   /// \endcode
   bool isStaticDataMember() const {
     // If it wasn't static, it would be a FieldDecl.
-    return getKind() != Decl::ParmVar && getDeclContext()->isRecord();
+    return getKind() != Decl::ParmVar && !isInitCapture() &&
+        getDeclContext()->isRecord();
   }
 
   virtual VarDecl *getCanonicalDecl();
Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h
+++ include/clang/Sema/DeclSpec.h
@@ -50,6 +50,7 @@
   class Sema;
   class Declarator;
   struct TemplateIdAnnotation;
+  class VarDecl;
 
 /// \brief Represents a C++ nested-name-specifier or a global scope specifier.
 ///
@@ -2143,12 +2144,13 @@
   IdentifierInfo *Id;
   SourceLocation EllipsisLoc;
   ExprResult Init;
-
+  VarDecl *InitVar;
   LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
                 IdentifierInfo* Id = 0,
                 SourceLocation EllipsisLoc = SourceLocation(),
                 ExprResult Init = ExprResult())
-    : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), Init(Init)
+    : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), Init(Init), 
+        InitVar(0)
   {}
 };
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -281,8 +281,36 @@
   /// element type here is ExprWithCleanups::Object.
   SmallVector<BlockDecl*, 8> ExprCleanupObjects;
 
+  /// \brief When non-zero, this represents a lambda's init-capture
+  ///  being processed after initial parsing, or during template 
+  ///  transformation.  This is set in Sema::checkInitCapture and
+  ///  updated in Sema::AddInitializerToDecl. It is used mainly
+  ///  to inform SemaTemplateVariadic that we are in a lambda and
+  ///  its ok to allow an unexpanded parameter pack here.
+  const Expr *CurLambdaInitCapture;
+
+  /// \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;
+  
+  typedef SmallVector<llvm::SmallPtrSet<Expr*, 2>, 4> MaybeODRUseExprsStackTy;
+  
+  /// \brief A stack to push and pop off the current MaybeODRUseExprs set. 
+  MaybeODRUseExprsStackTy MaybeODRUseExprsStack;
 
+  void SaveMaybeODRUseExprs()  {
+    MaybeODRUseExprsStack.push_back(MaybeODRUseExprsStackTy::value_type());
+    MaybeODRUseExprs.swap(MaybeODRUseExprsStack.back());
+  }
+  void RestoreMaybeODRUseExprs() {
+    MaybeODRUseExprs.swap(MaybeODRUseExprsStack.back()); 
+    MaybeODRUseExprsStack.pop_back();
+  }
+
   /// \brief Stack containing information about each of the nested
   /// function, block, and method scopes that are currently active.
   ///
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1141,7 +1141,18 @@
     case Decl::ObjCPropertyImpl:
     case Decl::ObjCProtocol:
       return LinkageInfo::external();
-      
+    case Decl::Var:
+      // Lambda init-capture dummy VarDecls behave as if the variable 
+      // was declared locally in its lambda's call-operator's body.
+      // When they are initially created, their corresponding call-operator 
+      // has not been.  So the DeclContext is not always correct, and may 
+      // temporarily incorrectly refer to the enclosing DeclContext - which 
+      // can result in incorrect linkage computations for lambdas with 
+      // init-captures at namespace scope. So nip this in the bud and always
+      // return no linkage. 
+      if (cast<VarDecl>(D)->isInitCapture())
+        return LinkageInfo::none();
+      break;  
     case Decl::CXXRecord: {
       const CXXRecordDecl *Record = cast<CXXRecordDecl>(D);
       if (Record->isLambda()) {
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -590,7 +590,71 @@
   return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name,
                                    Tok.is(tok::l_paren), isAddressOfOperand);
 }
+namespace {
 
+// 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).
+// So the init-variables (i, j, k) above are created temporarily
+// in their enclosing DeclContext. 
+// 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.
+//  
+struct InitCaptureCheckerAndBuilder {
+  LambdaIntroducer &Intro;
+  Sema &Actions;
+  InitCaptureCheckerAndBuilder(LambdaIntroducer &Intro, Sema &S) :
+    Intro(Intro), Actions(S) {
+      // Each lambda init-capture forms its own full expression, which clears
+      // MaybeODRUseExprs. So save it on the stack, and avoid clobbering by a 
+      // premature 'clear'.
+      Actions.SaveMaybeODRUseExprs();
+  }
+  ~InitCaptureCheckerAndBuilder() {
+    // 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.
+    for (SmallVectorImpl<LambdaCapture>::iterator
+      C = Intro.Captures.begin(),
+      E = Intro.Captures.end();
+    C != E; ++C) {
+      if (C->Init.isUsable()) {
+        // This also performs any lvalue-to-rvalue conversions if necessary.
+        VarDecl *Var = Actions.checkInitCapture(C->Loc, C->Kind == LCK_ByRef,
+          C->Id, C->Init.take());
+        C->InitVar = Var;
+      }   
+
+    }
+    Actions.RestoreMaybeODRUseExprs(); 
+  }
+};
+}
 /// ParseLambdaExpression - Parse a C++11 lambda expression.
 ///
 ///       lambda-expression:
@@ -633,8 +697,13 @@
 ExprResult Parser::ParseLambdaExpression() {
   // Parse lambda-introducer.
   LambdaIntroducer Intro;
-
-  Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+  Optional<unsigned> DiagID;
+  // Use a new block to ensure that ~ICAB gets called
+  // appropriately.
+  {
+    InitCaptureCheckerAndBuilder ICAB(Intro, Actions);
+    DiagID = ParseLambdaIntroducer(Intro);
+  }
   if (DiagID) {
     Diag(Tok, DiagID.getValue());
     SkipUntil(tok::r_square);
@@ -674,7 +743,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
@@ -682,8 +751,11 @@
   // a lambda introducer first, and fall back if that fails.
   // (TryParseLambdaIntroducer never produces any diagnostic output.)
   LambdaIntroducer Intro;
-  if (TryParseLambdaIntroducer(Intro))
-    return ExprEmpty();
+  {
+    InitCaptureCheckerAndBuilder ICAB(Intro, Actions);
+    if (TryParseLambdaIntroducer(Intro)) 
+      return ExprEmpty();
+  }
   return ParseLambdaExpressionAfterIntroducer(Intro);
 }
 
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -78,7 +78,8 @@
     CurContext(0), OriginalLexicalContext(0),
     PackContext(0), MSStructPragmaOn(false), VisContext(0),
     IsBuildingRecoveryCallExpr(false),
-    ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
+    ExprNeedsCleanups(false),  CurLambdaInitCapture(0), 
+    LateTemplateParser(0), OpaqueParser(0),
     IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
     NSNumberDecl(0),
     NSStringDecl(0), StringWithUTF8StringMethod(0),
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -7996,11 +7996,31 @@
   }
 }
 
+// Intercept assignment of the InitExpr so that we can update 
+// CurLambdaInitCapture at the same time.
+class AssignmentInterceptorProxyForInitExpr {
+  Expr *&Init;
+  Sema &S;
+  const bool IsInitCapture;
+public:
+  AssignmentInterceptorProxyForInitExpr(Expr *&Init, Sema &S) 
+      : Init(Init), S(S), IsInitCapture(Init == S.CurLambdaInitCapture) 
+      { }
+  void operator=(Expr *E) {
+    Init = E;
+    if (IsInitCapture)
+      S.CurLambdaInitCapture = E;
+  }
+  operator Expr*() const { return Init; }
+  Expr* operator->() const { return Init; }
+  Expr*& get() { return Init; } 
+};
 /// AddInitializerToDecl - Adds the initializer Init to the
 /// declaration dcl. If DirectInit is true, this is C++ direct
 /// initialization rather than copy initialization.
-void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
+void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *InitExpr,
                                 bool DirectInit, bool TypeMayContainAuto) {
+  AssignmentInterceptorProxyForInitExpr Init(InitExpr, *this);
   // If there is no declaration, there was an error parsing it.  Just ignore
   // the initializer.
   if (RealDecl == 0 || RealDecl->isInvalidDecl())
@@ -8011,7 +8031,7 @@
     // distinguish between a normal initializer and a pure-specifier.
     // Thus this grotesque test.
     IntegerLiteral *IL;
-    if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
+    if ((IL = dyn_cast<IntegerLiteral>(Init.get())) && IL->getValue() == 0 &&
         Context.getCanonicalType(IL->getType()) == Context.IntTy)
       CheckPureMethod(Method, Init->getSourceRange());
     else {
@@ -8029,7 +8049,7 @@
     RealDecl->setInvalidDecl();
     return;
   }
-  ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+  ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init.get());
 
   // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
   if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) {
@@ -8218,7 +8238,7 @@
                    : InitializationKind::CreateCopy(VDecl->getLocation(),
                                                     Init->getLocStart());
 
-    MultiExprArg Args = Init;
+    MultiExprArg Args = Init.get();
     if (CXXDirectInit)
       Args = MultiExprArg(CXXDirectInit->getExprs(),
                           CXXDirectInit->getNumExprs());
@@ -8305,7 +8325,7 @@
       // for an object that has aggregate or union type shall be
       // constant expressions.
       else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() &&
-               isa<InitListExpr>(Init) &&
+               isa<InitListExpr>(Init.get()) &&
                !Init->isConstantInitializer(Context, false))
         Diag(Init->getExprLoc(),
              diag::ext_aggregate_init_not_constant)
@@ -8744,7 +8764,7 @@
 
 void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
   if (var->isInvalidDecl()) return;
-
+  
   // In ARC, don't allow jumps past the implicit initialization of a
   // local retaining variable.
   if (getLangOpts().ObjCAutoRefCount &&
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -508,6 +508,8 @@
   //   An init-capture behaves as if it declares and explicitly captures
   //   a variable of the form
   //     "auto init-capture;"
+  const Expr *const PreviousLambdaInitCapture = CurLambdaInitCapture;
+  CurLambdaInitCapture = Init;
   QualType DeductType = Context.getAutoDeductType();
   TypeLocBuilder TLB;
   TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
@@ -522,7 +524,7 @@
   // 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,
+  VarDecl *NewVD = VarDecl::Create(Context, CurContext /*CurContext*/, Loc,
                                    Loc, Id, TSI->getType(), TSI, SC_Auto);
   NewVD->setInitCapture(true);
   NewVD->setReferenced(true);
@@ -535,6 +537,7 @@
   // FIXME: We should model whether an '=' was present.
   bool DirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
   AddInitializerToDecl(NewVD, Init, DirectInit, /*ContainsAuto*/true);
+  CurLambdaInitCapture = PreviousLambdaInitCapture;
   return NewVD;
 }
 
@@ -718,14 +721,16 @@
       if (C->Init.get()->containsUnexpandedParameterPack())
         ContainsUnexpandedParameterPack = true;
 
-      Var = checkInitCapture(C->Loc, C->Kind == LCK_ByRef,
-                             C->Id, C->Init.take());
+      Var = C->InitVar;
       // C++1y [expr.prim.lambda]p11:
       //   An init-capture behaves as if it declares and explicitly
       //   captures a variable [...] whose declarative region is the
       //   lambda-expression's compound-statement
-      if (Var)
+     
+      if (Var) {
+        Var->setDeclContext(Method);        
         PushOnScopeChains(Var, CurScope, false);
+      }      
     } else {
       // C++11 [expr.prim.lambda]p8:
       //   If a lambda-capture includes a capture-default that 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<InitExprVarPairTy> InitCaptureExprsAndVars) {
       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, 
+          InitCaptureExprsAndVars);
     }
     TemplateParameterList *TransformTemplateParameterList(
                               TemplateParameterList *OrigTPL)  {
Index: lib/Sema/SemaTemplateVariadic.cpp
===================================================================
--- lib/Sema/SemaTemplateVariadic.cpp
+++ lib/Sema/SemaTemplateVariadic.cpp
@@ -275,6 +275,14 @@
   //   ill-formed.
   if (!E->containsUnexpandedParameterPack())
     return false;
+  // If we are an init-expression in a lambdas init-capture, we are done.
+  // template<class ... Ts> void test(Ts ... t) {
+  //   test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now.
+  //     return a;
+  //   }() ...);
+  // }
+  if (E == CurLambdaInitCapture)
+    return false;
 
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
   CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -589,9 +589,10 @@
 
   StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
   ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
-
+  typedef std::pair<ExprResult, VarDecl*> InitExprVarPairTy;
   /// \brief Transform the captures and body of a lambda expression.
-  ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+  ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator, 
+       ArrayRef<InitExprVarPairTy> InitCaptureExprsAndVars);
 
   TemplateParameterList *TransformTemplateParameterList(
         TemplateParameterList *TPL) {
@@ -8272,6 +8273,32 @@
 ExprResult
 TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
  
+  // Transform any init-capture expressions before entering the scope of the
+  // lambda to avoid confusing tryCaptureVar during the transformation.
+  SmallVector<InitExprVarPairTy, 8> InitCaptureExprsAndVars;
+  InitCaptureExprsAndVars.resize(E->explicit_capture_end() -
+      E->explicit_capture_begin());
+  getSema().SaveMaybeODRUseExprs();
+  for (LambdaExpr::capture_iterator C = E->capture_begin(),
+      CEnd = E->capture_end();
+      C != CEnd; ++C) {
+    if (!C->isInitCapture())
+      continue;
+      
+    ExprResult NewExprInit = getDerived().TransformInitializer(
+        C->getCapturedVar()->getInit(),
+        C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
+    VarDecl *OldVD = C->getCapturedVar();
+    VarDecl *NewVD = getSema().checkInitCapture(
+        C->getLocation(), OldVD->getType()->isReferenceType(),
+        OldVD->getIdentifier(), NewExprInit.take());
+
+    InitCaptureExprsAndVars[C - E->capture_begin()] =
+        std::make_pair(NewExprInit, NewVD);
+
+  }
+  getSema().RestoreMaybeODRUseExprs();
+
   getSema().PushLambdaScope();
   LambdaScopeInfo *LSI = getSema().getCurLambda();
   // Transform the template parameters, and add them to the current
@@ -8367,31 +8394,17 @@
 
   getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
 
-  return getDerived().TransformLambdaScope(E, NewCallOperator);
+  return getDerived().TransformLambdaScope(E, NewCallOperator, 
+      InitCaptureExprsAndVars);
 }
 
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
-                                             CXXMethodDecl *CallOperator) {
+    CXXMethodDecl *CallOperator, 
+    ArrayRef<InitExprVarPairTy> InitCaptureExprsAndVars) {
   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);
 
@@ -8424,19 +8437,22 @@
 
     // Rebuild init-captures, including the implied field declaration.
     if (C->isInitCapture()) {
-      ExprResult Init = InitCaptureExprs[C - E->capture_begin()];
+      
+      InitExprVarPairTy InitExprVarPair = 
+          InitCaptureExprsAndVars[C - E->capture_begin()];
+      ExprResult Init = InitExprVarPair.first;
       if (Init.isInvalid()) {
         Invalid = true;
         continue;
       }
       VarDecl *OldVD = C->getCapturedVar();
-      VarDecl *NewVD = getSema().checkInitCapture(
-          C->getLocation(), OldVD->getType()->isReferenceType(),
-          OldVD->getIdentifier(), Init.take());
+      VarDecl *NewVD = InitExprVarPair.second;
       if (!NewVD)
         Invalid = true;
-      else
+      else {
+        NewVD->setDeclContext(CallOperator);
         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-note2{{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-note2{{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 2{{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 {{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;
+    };     
+  }
+  {
+    // 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