Cosmetic update per Richard Smith comments.
http://reviews.llvm.org/D4368
Files:
include/clang/AST/Decl.h
include/clang/AST/LambdaCapture.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/Decl.cpp
lib/AST/Expr.cpp
lib/AST/ExprCXX.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/CGExprCXX.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/TreeTransform.h
test/CodeGenCXX/instantiate-typeof-vla.cpp
test/SemaTemplate/instantiate-typeof.cpp
tools/libclang/IndexBody.cpp
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -2156,8 +2156,9 @@
mutable unsigned CachedFieldIndex : 31;
/// \brief An InClassInitStyle value, and either a bit width expression (if
- /// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class
- /// initializer for this field (otherwise).
+ /// the InClassInitStyle value is ICIS_NoInit) in struct/class, or a captured
+ /// variable length array bound in a lambda expression, or a pointer to the
+ /// in-class initializer for this field (otherwise).
///
/// We can safely combine these two because in-class initializers are not
/// permitted for bit-fields.
@@ -2193,11 +2194,8 @@
/// isMutable - Determines whether this field is mutable (C++ only).
bool isMutable() const { return Mutable; }
- /// isBitfield - Determines whether this field is a bitfield.
- bool isBitField() const {
- return getInClassInitStyle() == ICIS_NoInit &&
- InitializerOrBitWidth.getPointer();
- }
+ /// \brief Determines whether this field is a bitfield.
+ bool isBitField() const;
/// @brief Determines whether this is an unnamed bitfield.
bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
@@ -2253,6 +2251,18 @@
InitializerOrBitWidth.setInt(ICIS_NoInit);
}
+ /// \brief Determine whether this member captures the expression for variable
+ /// length arrays bounds.
+ bool hasCapturedVLABoundExpr() const;
+ /// \brief Get the captured variable length array bound expression.
+ Expr *getCapturedVLABoundExpr() const {
+ return hasCapturedVLABoundExpr() ? InitializerOrBitWidth.getPointer()
+ : nullptr;
+ }
+ /// \brief Set the captured variable length array bound expression for this
+ /// field.
+ void setCapturedVLABoundExpr(Expr *CapturedExpr);
+
/// getParent - Returns the parent of this field declaration, which
/// is the struct in which this method is defined.
const RecordDecl *getParent() const {
Index: include/clang/AST/LambdaCapture.h
===================================================================
--- include/clang/AST/LambdaCapture.h
+++ include/clang/AST/LambdaCapture.h
@@ -68,13 +68,23 @@
/// \brief Determine whether this capture handles the C++ \c this
/// pointer.
- bool capturesThis() const { return DeclAndBits.getPointer() == nullptr; }
+ bool capturesThis() const {
+ return (DeclAndBits.getPointer() == nullptr) &&
+ !(DeclAndBits.getInt() & Capture_ByCopy);
+ }
/// \brief Determine whether this capture handles a variable.
bool capturesVariable() const {
return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer());
}
+ /// \brief Determine whether this captures a variable length array bound
+ /// expression.
+ bool capturesVLABoundExpression() const {
+ return (DeclAndBits.getPointer() == nullptr) &&
+ (DeclAndBits.getInt() & Capture_ByCopy);
+ }
+
/// \brief Determine whether this is an init-capture.
bool isInitCapture() const {
return capturesVariable() && getCapturedVar()->isInitCapture();
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -5319,9 +5319,6 @@
"'this' cannot be %select{implicitly |}0captured in this context">;
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_capture_flexarray_type : Error<
"variable %0 with flexible array member cannot be captured in "
"a lambda expression">;
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3259,6 +3259,19 @@
return false;
}
+bool FieldDecl::isBitField() const {
+ if (getInClassInitStyle() == ICIS_NoInit &&
+ InitializerOrBitWidth.getPointer()) {
+ if (getDeclContext() && getDeclContext()->isRecord()) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(getParent())) {
+ return !RD->isLambda();
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
assert(isBitField() && "not a bitfield");
Expr *BitWidth = InitializerOrBitWidth.getPointer();
@@ -3291,16 +3304,35 @@
void FieldDecl::setBitWidth(Expr *Width) {
assert(!InitializerOrBitWidth.getPointer() && !hasInClassInitializer() &&
- "bit width or initializer already set");
+ "bit width, initializer or captured expr already set");
InitializerOrBitWidth.setPointer(Width);
}
void FieldDecl::setInClassInitializer(Expr *Init) {
assert(!InitializerOrBitWidth.getPointer() && hasInClassInitializer() &&
- "bit width or initializer already set");
+ "bit width, initializer or captured expr already set");
InitializerOrBitWidth.setPointer(Init);
}
+bool FieldDecl::hasCapturedVLABoundExpr() const {
+ if (getDeclContext() && getDeclContext()->isRecord()) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(getParent())) {
+ return RD->isLambda() && getInClassInitStyle() == ICIS_NoInit &&
+ InitializerOrBitWidth.getPointer();
+ }
+ }
+ return false;
+}
+
+void FieldDecl::setCapturedVLABoundExpr(Expr *CapturedExpr) {
+ assert(isa<CXXRecordDecl>(getParent()) &&
+ cast<CXXRecordDecl>(getParent())->isLambda() &&
+ "capturing expression in non-lambda.");
+ assert(!InitializerOrBitWidth.getPointer() && !hasInClassInitializer() &&
+ "bit width, initializer or captured expr already set");
+ InitializerOrBitWidth.setPointer(CapturedExpr);
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -2989,7 +2989,7 @@
const LambdaExpr *LE = cast<LambdaExpr>(this);
for (LambdaExpr::capture_iterator I = LE->capture_begin(),
E = LE->capture_end(); I != E; ++I)
- if (I->getCaptureKind() == LCK_ByCopy)
+ if (I->getCaptureKind() == LCK_ByCopy && I->capturesVariable())
// FIXME: Only has a side-effect if the variable is volatile or if
// the copy would invoke a non-trivial copy constructor.
return true;
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp
+++ lib/AST/ExprCXX.cpp
@@ -901,7 +901,7 @@
case LCK_ByCopy:
Bits |= Capture_ByCopy;
- // Fall through
+ break;
case LCK_ByRef:
assert(Var && "capture must have a variable!");
break;
@@ -911,7 +911,8 @@
LambdaCaptureKind LambdaCapture::getCaptureKind() const {
Decl *D = DeclAndBits.getPointer();
- if (!D)
+ bool CapByCopy = DeclAndBits.getInt() & Capture_ByCopy;
+ if (!D && !CapByCopy)
return LCK_This;
return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef;
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1623,6 +1623,8 @@
CEnd = Node->explicit_capture_end();
C != CEnd;
++C) {
+ if (C->capturesVLABoundExpression())
+ continue;
if (NeedComma)
OS << ", ";
NeedComma = true;
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -954,6 +954,8 @@
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
CEnd = S->explicit_capture_end();
C != CEnd; ++C) {
+ if (C->capturesVLABoundExpression())
+ continue;
ID.AddInteger(C->getCaptureKind());
switch (C->getCaptureKind()) {
case LCK_This:
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -850,12 +850,11 @@
C.getLocation(), Field->getAccess(),
layout.getFieldOffset(fieldno), VUnit, RecordTy);
elements.push_back(fieldType);
- } else {
+ } else if (C.capturesThis()) {
// TODO: Need to handle 'this' in some way by probably renaming the
// this of the lambda class and having a field member of 'this' or
// by using AT_object_pointer for the function and having that be
// used as 'this' for semantic references.
- assert(C.capturesThis() && "Field that isn't captured and isn't this?");
FieldDecl *f = *Field;
llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
QualType type = f->getType();
Index: lib/CodeGen/CGExprCXX.cpp
===================================================================
--- lib/CodeGen/CGExprCXX.cpp
+++ lib/CodeGen/CGExprCXX.cpp
@@ -1768,19 +1768,29 @@
void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) {
RunCleanupsScope Scope(*this);
- LValue SlotLV = MakeAddrLValue(Slot.getAddr(), E->getType(),
- Slot.getAlignment());
+ LValue SlotLV =
+ MakeAddrLValue(Slot.getAddr(), E->getType(), Slot.getAlignment());
CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
for (LambdaExpr::capture_init_iterator i = E->capture_init_begin(),
e = E->capture_init_end();
i != e; ++i, ++CurField) {
// Emit initialization
-
LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
- ArrayRef<VarDecl *> ArrayIndexes;
- if (CurField->getType()->isArrayType())
- ArrayIndexes = E->getCaptureInitIndexVars(i);
- EmitInitializerForField(*CurField, LV, *i, ArrayIndexes);
+ if (CurField->hasCapturedVLABoundExpr()) {
+ assert(isa<BinaryOperator>(*i) &&
+ "Captured expression is not a binary operator.");
+ auto QArrayType = cast<VariableArrayType>(cast<BinaryOperator>(*i)
+ ->getLHS()
+ ->getType()
+ ->getAsArrayTypeUnsafe());
+ EmitStoreThroughLValue(RValue::get(VLASizeMap[QArrayType->getSizeExpr()]),
+ LV);
+ } else {
+ ArrayRef<VarDecl *> ArrayIndexes;
+ if (CurField->getType()->isArrayType())
+ ArrayIndexes = E->getCaptureInitIndexVars(i);
+ EmitInitializerForField(*CurField, LV, *i, ArrayIndexes);
+ }
}
}
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -668,6 +668,20 @@
CXXThisValue = EmitLoadOfLValue(ThisLValue,
SourceLocation()).getScalarVal();
}
+ for (auto *FD : MD->getParent()->fields()) {
+ if (FD->hasCapturedVLABoundExpr()) {
+ auto *ExprArg = EmitLoadOfLValue(EmitLValueForLambdaField(FD),
+ SourceLocation()).getScalarVal();
+ assert(isa<BinaryOperator>(FD->getCapturedVLABoundExpr()) &&
+ "Captured expression is not a binary operator.");
+ auto QArrayType = cast<VariableArrayType>(
+ cast<BinaryOperator>(FD->getCapturedVLABoundExpr())
+ ->getLHS()
+ ->getType()
+ ->getAsArrayTypeUnsafe());
+ VLASizeMap[QArrayType->getSizeExpr()] = ExprArg;
+ }
+ }
} else {
// Not in a lambda; just use 'this' from the method.
// FIXME: Should we generate a new load for each use of 'this'? The
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -9749,6 +9749,7 @@
// Add the captures to the LSI so they can be noted as already
// captured within tryCaptureVar.
+ auto I = LambdaClass->field_begin();
for (const auto &C : LambdaClass->captures()) {
if (C.capturesVariable()) {
VarDecl *VD = C.getCapturedVar();
@@ -9765,7 +9766,14 @@
} else if (C.capturesThis()) {
LSI->addThisCapture(/*Nested*/ false, C.getLocation(),
S.getCurrentThisType(), /*Expr*/ nullptr);
+ } else {
+ LSI->addCapture(nullptr, /*IsBlock*/ false, /*ByRef*/ false,
+ /*RefersToEnclosingLocal*/ false, C.getLocation(),
+ /*EllipsisLoc*/ C.isPackExpansion() ? C.getEllipsisLoc()
+ : SourceLocation(),
+ I->getType(), I->getCapturedVLABoundExpr());
}
+ ++I;
}
}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11668,12 +11668,9 @@
}
// Prohibit variably-modified types; they're difficult to deal with.
- if (Var->getType()->isVariablyModifiedType() && (IsBlock || IsLambda)) {
+ if (Var->getType()->isVariablyModifiedType() && IsBlock) {
if (Diagnose) {
- if (IsBlock)
- S.Diag(Loc, diag::err_ref_vm_type);
- else
- S.Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName();
+ S.Diag(Loc, diag::err_ref_vm_type);
S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
}
@@ -12218,8 +12215,43 @@
// Unknown size indication requires no size computation.
// Otherwise, evaluate and record it.
- if (Expr *Size = Vat->getSizeExpr()) {
- MarkDeclarationsReferencedInExpr(Size);
+ if (auto Size = Vat->getSizeExpr()) {
+ if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
+ auto Loc = Size->getExprLoc();
+ auto QType = Size->getType();
+ auto QArrayType = QualType(Vat, 0);
+ auto TInfo = Context.getTrivialTypeSourceInfo(QType, Loc);
+ auto QArrayTInfo =
+ Context.getTrivialTypeSourceInfo(QArrayType, Loc);
+ auto VD = VarDecl::Create(Context, getFunctionLevelDeclContext(),
+ SourceLocation(), SourceLocation(),
+ &Context.Idents.get(".captured_expr."),
+ QArrayType, QArrayTInfo, SC_Auto);
+ auto DRE =
+ new (Context) DeclRefExpr(VD, /*refersToEnclosingLocal*/ true,
+ QArrayType, VK_LValue, Loc);
+ auto BinExpr = new (Context) BinaryOperator(
+ DRE, Size, BO_Comma, QType, Size->getValueKind(), OK_Ordinary,
+ Loc, /*fpContractable*/ false);
+ auto Lambda = LSI->Lambda;
+
+ // Build the non-static data member.
+ FieldDecl *Field = FieldDecl::Create(Context, Lambda, Loc, Loc,
+ /*Id*/ nullptr, QType, TInfo,
+ BinExpr, /*Mutable*/ false,
+ /*InitStyle*/ ICIS_NoInit);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ Lambda->addDecl(Field);
+
+ LSI->addCapture(/*Var=*/nullptr, /*IsBlock=*/false,
+ /*isByref=*/false, /*isNested=*/false, Loc, Loc,
+ QType, BinExpr);
+ } else {
+ // Immediately mark all referenced vars for CapturedStatements,
+ // they all are captured by reference.
+ MarkDeclarationsReferencedInExpr(Size);
+ }
}
QTy = Vat->getElementType();
break;
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -8760,6 +8760,10 @@
getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit());
continue;
}
+ // Captured expression will be recaptured during captured variables
+ // rebuilding.
+ if (C->capturesVLABoundExpression())
+ continue;
// Rebuild init-captures, including the implied field declaration.
if (C->isInitCapture()) {
Index: test/CodeGenCXX/instantiate-typeof-vla.cpp
===================================================================
--- test/CodeGenCXX/instantiate-typeof-vla.cpp
+++ test/CodeGenCXX/instantiate-typeof-vla.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -emit-pch -o %t
+// RUN: %clang_cc1 %s -std=c++11 -include-pch %t -emit-llvm -o - | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+// CHECK-DAG: [[CAP_TYPE1:%.+]] = type { [[INTPTR_T:i.+]], [[INTPTR_T]]*, [[INTPTR_T]]* }
+// CHECK-DAG: [[CAP_TYPE2:%.+]] = type { [[INTPTR_T]], [[INTPTR_T]]* }
+
+
+
+// CHECK: define void [[G:@.+]](
+// CHECK: [[N_ADDR:%.+]] = alloca [[INTPTR_T]]
+// CHECK: store [[INTPTR_T]] %{{.+}}, [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[N_VAL:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[CAP_EXPR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK: store [[INTPTR_T]] [[N_VAL]], [[INTPTR_T]]* [[CAP_EXPR_REF]]
+// CHECK: [[CAP_BUFFER_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK: store [[INTPTR_T]]* %{{.+}}, [[INTPTR_T]]** [[CAP_BUFFER_ADDR]]
+// CHECK: [[CAP_N_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 2
+// CHECK: store [[INTPTR_T]]* [[N_ADDR]], [[INTPTR_T]]** [[CAP_N_REF]]
+// CHECK: call void [[G_LAMBDA:@.+]]([[CAP_TYPE1]]* [[CAP_ARG]])
+// CHECK: ret void
+void g(intptr_t n) {
+ intptr_t buffer[n];
+ [&buffer, &n]() {
+ __typeof(buffer) x;
+ }();
+}
+
+// CHECK: void [[G_LAMBDA]]([[CAP_TYPE1]]*
+// CHECK: [[THIS:%.+]] = load [[CAP_TYPE1]]**
+// CHECK: [[N_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[THIS]], i{{.+}} 0, i{{.+}} 0
+// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[BUFFER_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[THIS]], i{{.+}} 0, i{{.+}} 1
+// CHECK: [[BUFFER:%.+]] = load [[INTPTR_T]]** [[BUFFER_ADDR]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: alloca [[INTPTR_T]], [[INTPTR_T]] [[N]]
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+
+template <typename T> void f(T n, T m) {
+ intptr_t buffer[n + m];
+ [&buffer]() {
+ __typeof(buffer) x;
+ }();
+}
+
+// CHECK-LABEL: @main
+int main() {
+// CHECK: call void [[G]]([[INTPTR_T]] 1)
+ g((intptr_t)1);
+// CHECK: call void [[F_INT:@.+]]([[INTPTR_T]] 1, [[INTPTR_T]] 2)
+ f((intptr_t)1, (intptr_t)2);
+// CHECK: ret i32 0
+ return 0;
+}
+
+// CHECK: void [[F_INT]]([[INTPTR_T]]
+// CHECK: [[SIZE:%.+]] = add
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: [[BUFFER_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]] [[SIZE]]
+// CHECK: [[CAP_SIZE_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK: store [[INTPTR_T]] [[SIZE]], [[INTPTR_T]]* [[CAP_SIZE_REF]]
+// CHECK: [[CAP_BUFFER_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK: store [[INTPTR_T]]* [[BUFFER_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER_ADDR_REF]]
+// CHECK: call void [[F_INT_LAMBDA:@.+]]([[CAP_TYPE2]]* [[CAP_ARG]])
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+
+// CHECK: void [[F_INT_LAMBDA]]([[CAP_TYPE2]]*
+// CHECK: [[THIS:%.+]] = load [[CAP_TYPE2]]**
+// CHECK: [[SIZE_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[THIS]], i{{.+}} 0, i{{.+}} 0
+// CHECK: [[SIZE:%.+]] = load [[INTPTR_T]]* [[SIZE_REF]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: alloca [[INTPTR_T]], [[INTPTR_T]] [[SIZE]]
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+#endif
Index: test/SemaTemplate/instantiate-typeof.cpp
===================================================================
--- test/SemaTemplate/instantiate-typeof.cpp
+++ test/SemaTemplate/instantiate-typeof.cpp
@@ -1,10 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
// Make sure we correctly treat __typeof as potentially-evaluated when appropriate
template<typename T> void f(T n) {
- int buffer[n]; // expected-note {{declared here}}
- [] { __typeof(buffer) x; }(); // expected-error {{variable 'buffer' with variably modified type cannot be captured in a lambda expression}}
+ int buffer[n];
+ [&buffer] { __typeof(buffer) x; }();
}
int main() {
- f<int>(1); // expected-note {{in instantiation}}
+ f<int>(1);
}
Index: tools/libclang/IndexBody.cpp
===================================================================
--- tools/libclang/IndexBody.cpp
+++ tools/libclang/IndexBody.cpp
@@ -150,7 +150,7 @@
}
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) {
- if (C->capturesThis())
+ if (C->capturesThis() || C->capturesVLABoundExpression())
return true;
if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits