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: include/clang/Sema/ScopeInfo.h =================================================================== --- include/clang/Sema/ScopeInfo.h +++ include/clang/Sema/ScopeInfo.h @@ -622,6 +622,9 @@ /// its list of array index variables. SmallVector ArrayIndexStarts; + /// \brief Expressions used in declarations of VLA types. + SmallVector VLAUsedExprs; + /// \brief If this is a generic lambda, use this as the depth of /// each 'auto' parameter, during initial AST construction. unsigned AutoTemplateParameterDepth; @@ -781,6 +784,9 @@ PotentialThisCaptureLocation.isValid(); } + ArrayRef getVLAUsedExpressions() const { return VLAUsedExprs; } + void clearVLAUsedExpressions() { VLAUsedExprs.clear(); } + // When passed the index, returns the VarDecl and Expr associated // with the index. void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -596,6 +596,23 @@ } }; + bool CaptureVLAUsedVars; + /// \brief RAII for capturing non odr-used variables in VLA. + class RAIICaptureVLAUsedVarsTy { + Sema &S; + bool PrevCaptureVLAUsedVars; + + public: + RAIICaptureVLAUsedVarsTy(Sema &S) + : S(S), PrevCaptureVLAUsedVars(S.CaptureVLAUsedVars) { + S.CaptureVLAUsedVars = true; + } + + ~RAIICaptureVLAUsedVarsTy() { + S.CaptureVLAUsedVars = PrevCaptureVLAUsedVars; + } + }; + /// WeakUndeclaredIdentifiers - Identifiers contained in /// \#pragma weak before declared. rare. may alias another /// identifier, declared or undeclared Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -522,6 +522,22 @@ return false; } +static void InitVLACaptures(CodeGenFunction &CGF, const CXXRecordDecl *D) { + for (auto &C : D->captures()) { + if (C.capturesVariable()) { + QualType QTy; + auto VD = C.getCapturedVar(); + if (const ParmVarDecl *PVD = dyn_cast(VD)) + QTy = PVD->getOriginalType(); + else + QTy = VD->getType(); + if (QTy->isVariablyModifiedType()) { + CGF.EmitVariablyModifiedType(QTy); + } + } + } +} + void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, @@ -668,6 +684,7 @@ CXXThisValue = EmitLoadOfLValue(ThisLValue, SourceLocation()).getScalarVal(); } + InitVLACaptures(*this, MD->getParent()); } 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/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -74,38 +74,33 @@ } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, - TranslationUnitKind TUKind, - CodeCompleteConsumer *CodeCompleter) - : ExternalSource(nullptr), - isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()), - LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), - Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - CollectStats(false), CodeCompleter(CodeCompleter), - CurContext(nullptr), OriginalLexicalContext(nullptr), - PackContext(nullptr), MSStructPragmaOn(false), - MSPointerToMemberRepresentationMethod( - LangOpts.getMSPointerToMemberRepresentationMethod()), - VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), - DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), - CodeSegStack(nullptr), VisContext(nullptr), - IsBuildingRecoveryCallExpr(false), - ExprNeedsCleanups(false), LateTemplateParser(nullptr), - OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr), - CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), - NSNumberDecl(nullptr), - NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), - NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr), - NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr), - GlobalNewDeleteDeclared(false), - TUKind(TUKind), - NumSFINAEErrors(0), - AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), - NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), - CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), - TyposCorrected(0), AnalysisWarnings(*this), - VarDataSharingAttributesStack(nullptr), CurScope(nullptr), - Ident_super(nullptr), Ident___float128(nullptr) -{ + TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) + : ExternalSource(nullptr), isMultiplexExternalSource(false), + FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), + Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), + SourceMgr(PP.getSourceManager()), CollectStats(false), + CodeCompleter(CodeCompleter), CurContext(nullptr), + OriginalLexicalContext(nullptr), PackContext(nullptr), + MSStructPragmaOn(false), + MSPointerToMemberRepresentationMethod( + LangOpts.getMSPointerToMemberRepresentationMethod()), + VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), + DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), + CodeSegStack(nullptr), VisContext(nullptr), + IsBuildingRecoveryCallExpr(false), ExprNeedsCleanups(false), + LateTemplateParser(nullptr), OpaqueParser(nullptr), + CaptureVLAUsedVars(false), IdResolver(pp), StdInitializerList(nullptr), + CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), + NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), + NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr), + NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr), + GlobalNewDeleteDeclared(false), TUKind(TUKind), NumSFINAEErrors(0), + AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), + NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), + CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), + TyposCorrected(0), AnalysisWarnings(*this), + VarDataSharingAttributesStack(nullptr), CurScope(nullptr), + Ident_super(nullptr), Ident___float128(nullptr) { TUScope = nullptr; LoadedExternalKnownNamespaces = false; 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(); } @@ -11989,6 +11986,7 @@ } else { ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref); } + ByRef |= S.CaptureVLAUsedVars; // Compute the type of the field that will capture this variable. if (ByRef) { @@ -12139,7 +12137,7 @@ // during either a lambdas transformation or initial parsing // should be used. if (isGenericLambdaCallOperatorSpecialization(DC)) { - if (BuildAndDiagnose) { + if (BuildAndDiagnose && !CaptureVLAUsedVars) { LambdaScopeInfo *LSI = cast(CSI); if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) { Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName(); @@ -12218,8 +12216,15 @@ // 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(CSI)) + // Use late var capturing for lambdas to give a chance to capture + // variables explicitly or by default. + LSI->VLAUsedExprs.push_back(Size); + else + // Immediately mark all referenced vars for CapturedStatements, + // they all are captured by reference. + MarkDeclarationsReferencedInExpr(Size); } QTy = Vat->getElementType(); break; @@ -12256,7 +12261,8 @@ } while (!QTy.isNull() && QTy->isVariablyModifiedType()); } - if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) { + if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit && + !CaptureVLAUsedVars) { // No capture-default, and this is not an explicit capture // so cannot capture this variable. if (BuildAndDiagnose) { Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -1389,6 +1389,12 @@ SmallVector ArrayIndexStarts; { LambdaScopeInfo *LSI = getCurLambda(); + { + RAIICaptureVLAUsedVarsTy RAII(*this); + for (auto E : LSI->getVLAUsedExpressions()) + this->MarkDeclarationsReferencedInExpr(E); + LSI->clearVLAUsedExpressions(); + } CallOperator = LSI->CallOperator; Class = LSI->Lambda; IntroducerRange = LSI->IntroducerRange; Index: test/CodeGenCXX/instantiate-typeof-vla.cpp =================================================================== --- test/CodeGenCXX/instantiate-typeof-vla.cpp +++ test/CodeGenCXX/instantiate-typeof-vla.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s + +typedef __INTPTR_TYPE__ intptr_t; + +// CHECK-DAG: [[CAP_TYPE1:%.+]] = type { [[INTPTR_T:i.+]], [[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: [[CAP_N_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0 +// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR]] +// CHECK: store [[INTPTR_T]] [[N]], [[INTPTR_T]]* [[CAP_N_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: call void [[G_LAMBDA:@.+]]([[CAP_TYPE1]]* [[CAP_ARG]]) +// CHECK: ret void +void g(intptr_t n) { + intptr_t buffer[n]; + [n, &buffer]() { + __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 void f(T n) { + intptr_t buffer[n]; + [&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) + f((intptr_t)1); +// CHECK: ret i32 0 + return 0; +} + +// CHECK: void [[F_INT]]([[INTPTR_T]] +// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR:%.+]], +// CHECK: call i{{.+}}* @llvm.stacksave() +// CHECK: [[BUFFER_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]] [[N]] +// CHECK: [[CAP_BUFFER_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store [[INTPTR_T]]* [[BUFFER_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER_ADDR_REF]] +// CHECK: [[CAP_N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1 +// CHECK: store [[INTPTR_T]]* [[N_ADDR]], [[INTPTR_T]]** [[CAP_N_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: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[THIS]], i{{.+}} 0, i{{.+}} 1 +// CHECK: [[N_REF:%.+]] = load [[INTPTR_T]]** [[N_ADDR_REF]] +// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_REF]] +// CHECK: call i{{.+}}* @llvm.stacksave() +// CHECK: alloca [[INTPTR_T]], [[INTPTR_T]] [[N]] +// CHECK: call void @llvm.stackrestore( +// CHECK: ret void 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 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(1); // expected-note {{in instantiation}} + f(1); }