From: Douglas Gregor Date: Thu, 9 Feb 2012 02:45:47 +0000 (+0000) Subject: Implement capture-by-copy for arrays in lambdas. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=18fe084d72392a5ceaa1fab7d3f3f0d0f2538069;p=clang 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 --- 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 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 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 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 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}} }