aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-02-09 02:45:47 +0000
committerDouglas Gregor <dgregor@apple.com>2012-02-09 02:45:47 +0000
commit18fe084d72392a5ceaa1fab7d3f3f0d0f2538069 (patch)
tree978b9bb31cb6e413aa4c372d3dcce1ab0051a88f
parent4bbb8501d9db2ae72b1e39afaafa5795d67ffe03 (diff)
Implement capture-by-copy for arrays in lambdas.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150138 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaExpr.cpp73
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp17
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp2
3 files changed, 82 insertions, 10 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4db266b2ed..36bbae03f8 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -9588,7 +9588,6 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
// which the non-static data members are declared.
//
// FIXME: Introduce an initialization entity for lambda captures.
- // FIXME: Totally broken for arrays.
// Introduce a new evaluation context for the initialization, so that
// temporaries introduced as part of the capture
@@ -9596,14 +9595,74 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
Expr *Ref = new (S.Context) DeclRefExpr(Var, Type.getNonReferenceType(),
VK_LValue, Loc);
- InitializedEntity InitEntity
- = InitializedEntity::InitializeMember(Field, /*Parent=*/0);
+
+ // When the field has array type, create index variables for each
+ // dimension of the array. We use these index variables to subscript
+ // the source array, and other clients (e.g., CodeGen) will perform
+ // the necessary iteration with these index variables.
+ SmallVector<VarDecl *, 4> IndexVariables;
+ bool InitializingArray = false;
+ QualType BaseType = FieldType;
+ QualType SizeType = S.Context.getSizeType();
+ while (const ConstantArrayType *Array
+ = S.Context.getAsConstantArrayType(BaseType)) {
+ InitializingArray = true;
+
+ // Create the iteration variable for this array index.
+ IdentifierInfo *IterationVarName = 0;
+ {
+ SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << IndexVariables.size();
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar
+ = VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
+ IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
+ SC_None, SC_None);
+ IndexVariables.push_back(IterationVar);
+
+ // Create a reference to the iteration variable.
+ ExprResult IterationVarRef
+ = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
+ assert(!IterationVarRef.isInvalid() &&
+ "Reference to invented variable cannot fail!");
+ IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.take());
+ assert(!IterationVarRef.isInvalid() &&
+ "Conversion of invented variable cannot fail!");
+
+ // Subscript the array with this iteration variable.
+ ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr(
+ Ref, Loc, IterationVarRef.take(), Loc);
+ if (Subscript.isInvalid()) {
+ S.CleanupVarDeclMarking();
+ S.DiscardCleanupsInEvaluationContext();
+ S.PopExpressionEvaluationContext();
+ return ExprError();
+ }
+
+ Ref = Subscript.take();
+ BaseType = Array->getElementType();
+ }
+
+ // Construct the entity that we will be initializing. For an array, this
+ // will be first element in the array, which may require several levels
+ // of array-subscript entities.
+ SmallVector<InitializedEntity, 4> Entities;
+ Entities.reserve(1 + IndexVariables.size());
+ Entities.push_back(InitializedEntity::InitializeMember(Field));
+ for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
+ Entities.push_back(InitializedEntity::InitializeElement(S.Context,
+ 0,
+ Entities.back()));
+
InitializationKind InitKind
= InitializationKind::CreateDirect(Loc, Loc, Loc);
- InitializationSequence Init(S, InitEntity, InitKind, &Ref, 1);
+ InitializationSequence Init(S, Entities.back(), InitKind, &Ref, 1);
ExprResult Result(true);
- if (!Init.Diagnose(S, InitEntity, InitKind, &Ref, 1))
- Result = Init.Perform(S, InitEntity, InitKind,
+ if (!Init.Diagnose(S, Entities.back(), InitKind, &Ref, 1))
+ Result = Init.Perform(S, Entities.back(), InitKind,
MultiExprArg(S, &Ref, 1));
// If this initialization requires any cleanups (e.g., due to a
@@ -9617,7 +9676,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
S.DiscardCleanupsInEvaluationContext();
S.PopExpressionEvaluationContext();
return Result;
-}
+}
// Check if the variable needs to be captured; if so, try to perform
// the capture.
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
index 10d1e927bf..2dcaa5ddf6 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+template<typename T> void capture(const T&);
+
class NonCopyable {
NonCopyable(const NonCopyable&); // expected-note 2 {{implicitly declared private here}}
};
@@ -19,6 +21,7 @@ struct NonTrivial {
};
struct CopyCtorDefault {
+ CopyCtorDefault();
CopyCtorDefault(const CopyCtorDefault&, NonTrivial nt = NonTrivial());
void foo() const;
@@ -28,7 +31,17 @@ void capture_with_default_args(CopyCtorDefault cct) {
(void)[=] () -> void { cct.foo(); }; // expected-error{{lambda expressions are not supported yet}}
}
-// FIXME: arrays!
+struct ExpectedArrayLayout {
+ CopyCtorDefault array[3];
+};
+
+void capture_array() {
+ CopyCtorDefault array[3];
+ auto x = [=]() -> void { // expected-error{{lambda expressions are not supported yet}}
+ capture(array[0]);
+ };
+ static_assert(sizeof(x) == sizeof(ExpectedArrayLayout), "layout mismatch");
+}
// Check for the expected non-static data members.
@@ -37,8 +50,6 @@ struct ExpectedLayout {
short b;
};
-template<typename T> void capture(const T&);
-
void test_layout(char a, short b) {
auto x = [=] () -> void { // expected-error{{lambda expressions are not supported yet}}
capture(a);
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp
index e17d8b5101..605265b80a 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp
@@ -5,6 +5,8 @@ class NonCopyable {
};
void capture_by_ref(NonCopyable nc, NonCopyable &ncr) {
+ int array[3];
(void)[&nc] () -> void {}; // expected-error{{lambda expressions are not supported yet}}
(void)[&ncr] () -> void {}; // expected-error{{lambda expressions are not supported yet}}
+ (void)[&array] () -> void {}; // expected-error{{lambda expressions are not supported yet}}
}