Hi doug.gregor, rsmith, gribozavr, hfinkel,
http://reviews.llvm.org/D4368
Files:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
lib/CodeGen/CodeGenFunction.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLambda.cpp
test/CodeGenCXX/instantiate-typeof-vla.cpp
test/SemaTemplate/instantiate-typeof.cpp
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<unsigned, 4> ArrayIndexStarts;
+ /// \brief Expressions used in declarations of VLA types.
+ SmallVector<Expr *, 4> 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<Expr *> 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<ParmVarDecl>(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<LambdaScopeInfo>(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<LambdaScopeInfo>(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<unsigned, 4> 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 <typename T> 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<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);
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits