[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