[cfe-commits] r149718 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/ScopeInfo.h include/clang/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaExprObjC.cpp test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp test/SemaCXX/lambda-expressions.cpp

Eli Friedman eli.friedman at gmail.com
Fri Feb 3 14:47:37 PST 2012


Author: efriedma
Date: Fri Feb  3 16:47:37 2012
New Revision: 149718

URL: http://llvm.org/viewvc/llvm-project?rev=149718&view=rev
Log:
Implement implicit capture for lambda expressions.

Still left: explicit captures in lambdas need to cause implicit capture, and I need to take a look at the diagnostics for some cases.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/ScopeInfo.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp
    cfe/trunk/test/SemaCXX/lambda-expressions.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=149718&r1=149717&r2=149718&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb  3 16:47:37 2012
@@ -4094,8 +4094,18 @@
 def err_this_capture : Error<
   "'this' cannot be %select{implicitly |}0captured in this context">;
 def err_lambda_capture_block : Error<
-  "__block variable %0 cannot be captured in a lambda">;
-  
+  "__block variable %0 cannot be captured in a lambda expression">;
+def err_lambda_capture_anonymous_var : Error<
+  "unnamed variable cannot be implicitly captured in a lambda expression">;
+def err_lambda_capture_vm_type : Error<
+  "variable %0 with variably modified type cannot be captured in "
+  "a lambda expression">;
+def err_lambda_impcap : Error<
+  "variable %0 cannot be implicitly captured in a lambda with no "
+  "capture-default specified">;
+def note_lambda_decl : Note<"lambda expression begins here">;
+
+
 def err_operator_arrow_circular : Error<
   "circular pointer delegation detected">;
 def err_pseudo_dtor_base_not_scalar : Error<

Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=149718&r1=149717&r2=149718&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Fri Feb  3 16:47:37 2012
@@ -125,8 +125,15 @@
   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.
     enum CaptureKind {
-      Cap_This, Cap_ByVal, Cap_ByRef
+      Cap_This, Cap_ByCopy, Cap_ByRef, Cap_Block
     };
 
     // The variable being captured (if we are not capturing 'this'),
@@ -143,9 +150,9 @@
     SourceLocation Loc;
     
   public:
-    Capture(VarDecl *Var, bool isByref, bool isNested, SourceLocation Loc,
-            Expr *Cpy)
-      : VarAndKind(Var, isByref ? Cap_ByRef : Cap_ByVal),
+    Capture(VarDecl *Var, bool block, bool byRef, bool isNested, 
+            SourceLocation Loc, Expr *Cpy)
+      : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy),
         CopyExprAndNested(Cpy, isNested) {}
 
     enum IsThisCapture { ThisCapture };
@@ -155,8 +162,9 @@
 
     bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; }
     bool isVariableCapture() const { return !isThisCapture(); }
-    bool isCopyCapture() const { return VarAndKind.getInt() == Cap_ByVal; }
+    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(); }
 
     VarDecl *getVariable() const {
@@ -194,9 +202,9 @@
   /// or null if unknown.
   QualType ReturnType;
 
-  void AddCapture(VarDecl *Var, bool isByref, bool isNested, SourceLocation Loc,
-                  Expr *Cpy) {
-    Captures.push_back(Capture(Var, isByref, isNested, Loc, Cpy));
+  void AddCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
+                  SourceLocation Loc, Expr *Cpy) {
+    Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, Cpy));
     CaptureMap[Var] = Captures.size();
   }
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=149718&r1=149717&r2=149718&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Feb  3 16:47:37 2012
@@ -2284,6 +2284,7 @@
   void UpdateMarkingForLValueToRValue(Expr *E);
   void CleanupVarDeclMarking();
 
+  void TryCaptureVar(VarDecl *var, SourceLocation loc);
 
   void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
   void MarkDeclarationsReferencedInExpr(Expr *E);
@@ -5466,7 +5467,7 @@
                             SourceLocation receiverNameLoc,
                             SourceLocation propertyNameLoc);
 
-  ObjCMethodDecl *tryCaptureObjCSelf();
+  ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc);
 
   /// \brief Describes the kind of message expression indicated by a message
   /// send that starts with an identifier.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=149718&r1=149717&r2=149718&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Feb  3 16:47:37 2012
@@ -8747,7 +8747,7 @@
     CapturingScopeInfo::Capture &Cap = BSI->Captures[i];
     if (Cap.isThisCapture())
       continue;
-    BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isReferenceCapture(),
+    BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(),
                               Cap.isNested(), Cap.getCopyExpr());
     Captures.push_back(NewCap);
   }
@@ -9440,10 +9440,21 @@
     << var->getIdentifier();
 }
 
-static void tryCaptureVar(Sema &S, VarDecl *var,
-                          SourceLocation loc) {
-  // Check if the variable needs to be captured.
-  DeclContext *DC = S.CurContext;
+static bool shouldAddConstForScope(CapturingScopeInfo *CSI, VarDecl *VD) {
+  if (VD->hasAttr<BlocksAttr>())
+    return false;
+  if (isa<BlockScopeInfo>(CSI))
+    return true;
+  if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI))
+    return !LSI->Mutable;
+  return false;
+}
+
+// Check if the variable needs to be captured; if so, try to perform
+// the capture.
+// FIXME: Add support for explicit captures.
+void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc) {
+  DeclContext *DC = CurContext;
   if (var->getDeclContext() == DC) return;
   if (!var->hasLocalStorage()) return;
 
@@ -9451,87 +9462,144 @@
   QualType type = var->getType();
   bool Nested = false;
 
-  unsigned functionScopesIndex = S.FunctionScopes.size() - 1;
+  unsigned functionScopesIndex = FunctionScopes.size() - 1;
   do {
-    // Only blocks (and eventually C++0x closures) can capture; other
+    // Only block literals and lambda expressions can capture; other
     // scopes don't work.
-    // FIXME: Make this function support lambdas!
-    if (!isa<BlockDecl>(DC))
-      return diagnoseUncapturableValueReference(S, loc, var, DC);
-
-    BlockScopeInfo *blockScope =
-      cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
-    assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC));
+    DeclContext *ParentDC;
+    if (isa<BlockDecl>(DC))
+      ParentDC = DC->getParent();
+    else if (isa<CXXMethodDecl>(DC) &&
+             cast<CXXRecordDecl>(DC->getParent())->isLambda())
+      ParentDC = DC->getParent()->getParent();
+    else
+      return diagnoseUncapturableValueReference(*this, loc, var, DC);
 
-    // Check whether we've already captured it in this block.
-    if (blockScope->CaptureMap.count(var)) {
+    CapturingScopeInfo *CSI =
+      cast<CapturingScopeInfo>(FunctionScopes[functionScopesIndex]);
+
+    // Check whether we've already captured it.
+    if (CSI->CaptureMap.count(var)) {
+      // If we found a capture, any subcaptures are nested
       Nested = true;
+
+      if (shouldAddConstForScope(CSI, var))
+        type.addConst();
       break;
     }
 
     functionScopesIndex--;
-    DC = cast<BlockDecl>(DC)->getDeclContext();
+    DC = ParentDC;
   } while (var->getDeclContext() != DC);
 
-  bool byRef = var->hasAttr<BlocksAttr>();
+  bool hasBlocksAttr = var->hasAttr<BlocksAttr>();
 
   for (unsigned i = functionScopesIndex + 1,
-                e = S.FunctionScopes.size(); i != e; ++i) {
-    // Prohibit variably-modified types.
+                e = FunctionScopes.size(); i != e; ++i) {
+    CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[i]);
+    bool isBlock = isa<BlockScopeInfo>(CSI);
+    bool isLambda = isa<LambdaScopeInfo>(CSI);
+
+    // Lambdas are not allowed to capture unnamed variables
+    // (e.g. anonymous unions).
+    // FIXME: The C++11 rule don't actually state this explicitly, but I'm
+    // assuming that's the intent.
+    if (isLambda && !var->getDeclName()) {
+      Diag(loc, diag::err_lambda_capture_anonymous_var);
+      Diag(var->getLocation(), diag::note_declared_at);
+      return;
+    }
+
+    // Prohibit variably-modified types; they're difficult to deal with.
     if (type->isVariablyModifiedType()) {
-      S.Diag(loc, diag::err_ref_vm_type);
-      S.Diag(var->getLocation(), diag::note_declared_at);
+      if (isBlock)
+        Diag(loc, diag::err_ref_vm_type);
+      else
+        Diag(loc, diag::err_lambda_capture_vm_type) << var->getDeclName();
+      Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName();
+      return;
+    }
+
+    // Blocks are not allowed to capture arrays.
+    if (isBlock && type->isArrayType()) {
+      Diag(loc, diag::err_ref_array_type);
+      Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName();
       return;
     }
 
-    // Prohibit arrays, even in __block variables, but not references to
-    // them.
-    if (type->isArrayType()) {
-      S.Diag(loc, diag::err_ref_array_type);
-      S.Diag(var->getLocation(), diag::note_declared_at);
+    // Lambdas are not allowed to capture __block variables; they don't
+    // support the expected semantics.
+    if (isLambda && hasBlocksAttr) {
+      Diag(loc, diag::err_lambda_capture_block) << var->getDeclName();
+      Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName();
       return;
     }
 
-    // Build a copy expression.
+    bool byRef;
+    if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
+      // No capture-default
+      Diag(loc, diag::err_lambda_impcap) << var->getDeclName();
+      Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName();
+      Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
+           diag::note_lambda_decl);
+      return;
+    } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval) {
+      // capture-default '='
+      byRef = false;
+    } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref) {
+      // capture-default '&'
+      byRef = true;
+    } else {
+      // A block captures __block variables in a special __block fashion, 
+      // variables of reference type by reference (in the sense of
+      // [expr.prim.lambda]), and other non-__block variables by copy.
+      assert(CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block);
+      byRef = hasBlocksAttr || type->isReferenceType();
+    }
+
+    // Build a copy expression if we are capturing by copy and the copy
+    // might be non-trivial.
     Expr *copyExpr = 0;
     const RecordType *rtype;
-    if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() &&
-        (rtype = type->getAs<RecordType>())) {
-
+    if (!byRef && getLangOptions().CPlusPlus &&
+        (rtype = type.getNonReferenceType()->getAs<RecordType>())) {
       // The capture logic needs the destructor, so make sure we mark it.
       // Usually this is unnecessary because most local variables have
       // their destructors marked at declaration time, but parameters are
       // an exception because it's technically only the call site that
       // actually requires the destructor.
       if (isa<ParmVarDecl>(var))
-        S.FinalizeVarWithDestructor(var, rtype);
+        FinalizeVarWithDestructor(var, rtype);
 
       // According to the blocks spec, the capture of a variable from
       // the stack requires a const copy constructor.  This is not true
       // of the copy/move done to move a __block variable to the heap.
-      type.addConst();
+      // There is no equivalent language in the C++11 specification of lambdas.
+      if (isBlock)
+        type.addConst();
 
-      Expr *declRef = new (S.Context) DeclRefExpr(var, type, VK_LValue, loc);
+      Expr *declRef = new (Context) DeclRefExpr(var, type, VK_LValue, loc);
       ExprResult result =
-        S.PerformCopyInitialization(
+        PerformCopyInitialization(
                         InitializedEntity::InitializeBlock(var->getLocation(),
                                                            type, false),
-                                    loc, S.Owned(declRef));
+                                    loc, Owned(declRef));
 
       // Build a full-expression copy expression if initialization
       // succeeded and used a non-trivial constructor.  Recover from
       // errors by pretending that the copy isn't necessary.
       if (!result.isInvalid() &&
           !cast<CXXConstructExpr>(result.get())->getConstructor()->isTrivial()) {
-        result = S.MaybeCreateExprWithCleanups(result);
+        result = MaybeCreateExprWithCleanups(result);
         copyExpr = result.take();
       }
     }
 
-    BlockScopeInfo *blockScope = cast<BlockScopeInfo>(S.FunctionScopes[i]);
-    blockScope->AddCapture(var, byRef, Nested, loc, copyExpr);
+    CSI->AddCapture(var, hasBlocksAttr, byRef, Nested, loc, copyExpr);
 
     Nested = true;
+    if (shouldAddConstForScope(CSI, var))
+      type.addConst();
   }
 }
 
@@ -9544,7 +9612,7 @@
     if (old.isInvalid()) old = Loc;
   }
 
-  tryCaptureVar(SemaRef, Var, Loc);
+  SemaRef.TryCaptureVar(Var, Loc);
 
   Var->setUsed(true);
 }

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=149718&r1=149717&r2=149718&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Feb  3 16:47:37 2012
@@ -5051,7 +5051,8 @@
     // the variable.
     // FIXME: Unify with normal capture path, so we get all of the necessary
     // nested captures.
-    LSI->AddCapture(Var, C->Kind == LCK_ByRef, /*isNested=*/false, C->Loc, 0);
+    LSI->AddCapture(Var, /*isBlock*/false, C->Kind == LCK_ByRef,
+                    /*isNested=*/false, C->Loc, 0);
   }
   LSI->finishedExplicitCaptures();
 

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=149718&r1=149717&r2=149718&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Fri Feb  3 16:47:37 2012
@@ -237,14 +237,8 @@
 }
 
 /// Try to capture an implicit reference to 'self'.
-ObjCMethodDecl *Sema::tryCaptureObjCSelf() {
-  // Ignore block scopes: we can capture through them.
-  DeclContext *DC = CurContext;
-  while (true) {
-    if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
-    else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
-    else break;
-  }
+ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) {
+  DeclContext *DC = getFunctionLevelDeclContext();
 
   // If we're not in an ObjC method, error out.  Note that, unlike the
   // C++ case, we don't require an instance method --- class methods
@@ -253,22 +247,7 @@
   if (!method)
     return 0;
 
-  ImplicitParamDecl *self = method->getSelfDecl();
-  assert(self && "capturing 'self' in non-definition?");
-
-  // Mark that we're closing on 'this' in all the block scopes, if applicable.
-  for (unsigned idx = FunctionScopes.size() - 1;
-       isa<BlockScopeInfo>(FunctionScopes[idx]);
-       --idx) {
-    BlockScopeInfo *blockScope = cast<BlockScopeInfo>(FunctionScopes[idx]);
-    unsigned &captureIndex = blockScope->CaptureMap[self];
-    if (captureIndex) break;
-
-    bool nested = isa<BlockScopeInfo>(FunctionScopes[idx-1]);
-    blockScope->AddCapture(self, /*byref*/ false, nested, self->getLocation(),
-                           /*copy*/ 0);
-    captureIndex = blockScope->Captures.size(); // +1
-  }
+  TryCaptureVar(method->getSelfDecl(), Loc);
 
   return method;
 }
@@ -763,7 +742,7 @@
     if (receiverNamePtr->isStr("super")) {
       IsSuper = true;
 
-      if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) {
+      if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) {
         if (CurMethod->isInstanceMethod()) {
           QualType T = 
             Context.getObjCInterfaceType(CurMethod->getClassInterface());
@@ -975,7 +954,7 @@
                                    SourceLocation RBracLoc,
                                    MultiExprArg Args) {
   // Determine whether we are inside a method or not.
-  ObjCMethodDecl *Method = tryCaptureObjCSelf();
+  ObjCMethodDecl *Method = tryCaptureObjCSelf(SuperLoc);
   if (!Method) {
     Diag(SuperLoc, diag::err_invalid_receiver_to_message_super);
     return ExprError();

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp?rev=149718&r1=149717&r2=149718&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp Fri Feb  3 16:47:37 2012
@@ -5,7 +5,6 @@
   (void)[var] { }; // expected-error{{__block variable 'var' cannot be captured in a lambda}} \
   // expected-error{{lambda expressions are not supported yet}}
 
-  // FIXME: this should produce the same error as above
-  (void)[=] { var = 17; }; // expected-error{{reference to local variable 'var' declared in enclosed function 'block_capture_errors'}} \
+  (void)[=] { var = 17; }; // expected-error{{__block variable 'var' cannot be captured in a lambda}} \
   // expected-error{{lambda expressions are not supported yet}}
 }

Modified: cfe/trunk/test/SemaCXX/lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/lambda-expressions.cpp?rev=149718&r1=149717&r2=149718&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/lambda-expressions.cpp (original)
+++ cfe/trunk/test/SemaCXX/lambda-expressions.cpp Fri Feb  3 16:47:37 2012
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -fblocks %s
 
 namespace std { class type_info; };
 
@@ -42,3 +42,39 @@
     [](){ return 1; return 1; }; // expected-error {{not supported yet}}
   }
 }
+
+namespace ImplicitCapture {
+  void test() {
+    int a = 0; // expected-note 3 {{declared}}
+    []() { return a; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{begins here}} expected-error {{not supported yet}} 
+    [&]() { return a; }; // expected-error {{not supported yet}}
+    [=]() { return a; }; // expected-error {{not supported yet}}
+    [=]() { int* b = &a; }; // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'}} expected-error {{not supported yet}}
+    [=]() { return [&]() { return a; }; }; // expected-error 2 {{not supported yet}}
+    []() { return [&]() { return a; }; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-error 2 {{not supported yet}}
+    []() { return ^{ return a; }; };// expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-error {{not supported yet}}
+
+    const int b = 2;
+    []() { return b; }; // expected-error {{not supported yet}}
+
+    union { // expected-note {{declared}}
+      int c;
+      float d;
+    };
+    d = 3;
+    [=]() { return c; }; // expected-error {{unnamed variable cannot be implicitly captured in a lambda expression}} expected-error {{not supported yet}}
+
+    __block int e; // expected-note {{declared}}
+    [&]() { return e; }; // expected-error {{__block variable 'e' cannot be captured in a lambda expression}} expected-error {{not supported yet}}
+
+    int f[10]; // expected-note {{declared}}
+    [&]() { return f[2]; };  // expected-error {{not supported yet}}
+    (void) ^{ return []() { return f[2]; }; }; // expected-error {{cannot refer to declaration with an array type inside block}} expected-error {{not supported yet}}
+
+    struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}}
+    G g;
+    [=]() { const G* gg = &g; return gg->a; }; // expected-error {{not supported yet}}
+    [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'const ImplicitCapture::G'}} expected-error 2 {{not supported yet}}
+    (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const ImplicitCapture::G'}} expected-error {{not supported yet}}
+  }
+}





More information about the cfe-commits mailing list