]> granicus.if.org Git - clang/commitdiff
Implement capture-by-copy for arrays in lambdas.
authorDouglas Gregor <dgregor@apple.com>
Thu, 9 Feb 2012 02:45:47 +0000 (02:45 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 9 Feb 2012 02:45:47 +0000 (02:45 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150138 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExpr.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp

index 4db266b2edf4e8cdfbcc525de4e8dc7668fb0c46..36bbae03f8bea919a33acfb0d7a5e53722bcbbe9 100644 (file)
@@ -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.
index 10d1e927bfea5d958328bcff594c65d0d6c2147d..2dcaa5ddf634689c1a5176dbc72b24611da60bb2 100644 (file)
@@ -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);
index e17d8b5101a1d876c51d8179484bc3709d4a968d..605265b80a08825ee1f80f5a49dfaa072c2d7238 100644 (file)
@@ -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}}
 }