]> granicus.if.org Git - clang/commitdiff
Fix nested lifetime extension when a std::initializer_list member is
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 27 Jun 2013 22:54:33 +0000 (22:54 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 27 Jun 2013 22:54:33 +0000 (22:54 +0000)
initialized during aggregate initialization of the surrounding structure.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@185117 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaInit.cpp
test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp

index 9370287bee9613f8d1fe8e701e90457148f3c878..f59571a4865908cc4a33315b40a2acc82e8ea082 100644 (file)
@@ -5348,13 +5348,15 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
              I != E; ++I) {
           if (I->isUnnamedBitfield())
             continue;
+          Expr *SubInit = ILE->getInit(Index);
           if (I->getType()->isReferenceType())
-            performReferenceExtension(ILE->getInit(Index), ExtendingD);
-          else if (isa<InitListExpr>(ILE->getInit(Index)))
+            performReferenceExtension(SubInit, ExtendingD);
+          else if (isa<InitListExpr>(SubInit) ||
+                   isa<CXXStdInitializerListExpr>(SubInit))
             // This may be either aggregate-initialization of a member or
             // initialization of a std::initializer_list object. Either way,
             // we should recursively lifetime-extend that initializer.
-            performLifetimeExtension(ILE->getInit(Index), ExtendingD);
+            performLifetimeExtension(SubInit, ExtendingD);
           ++Index;
         }
       }
index 8adb887b9a8f207d4bb7b940523b870a316c7b0f..8dbb05711d2e338a5f47caed6610b38e4233abeb 100644 (file)
@@ -395,3 +395,39 @@ namespace partly_constant {
   // 'il' reference.
   // CHECK: store {{.*}}* @[[PARTLY_CONSTANT_OUTER]], {{.*}}** @_ZN15partly_constant2ilE, align 8
 }
+
+namespace nested {
+  struct A { A(); ~A(); };
+  struct B { const A &a; ~B(); };
+  struct C { std::initializer_list<B> b; ~C(); };
+  void f();
+  // CHECK: define void @_ZN6nested1gEv(
+  void g() {
+    // CHECK: call void @_ZN6nested1AC1Ev(
+    // CHECK-NOT: call
+    // CHECK: call void @_ZN6nested1AC1Ev(
+    // CHECK-NOT: call
+    const C &c { { { A() }, { A() } } };
+
+    // CHECK: call void @_ZN6nested1fEv(
+    // CHECK-NOT: call
+    f();
+
+    // CHECK: call void @_ZN6nested1CD1Ev(
+    // CHECK-NOT: call
+
+    // Destroy B[2] array.
+    // FIXME: This isn't technically correct: reverse construction order would
+    // destroy the second B then the second A then the first B then the first A.
+    // CHECK: call void @_ZN6nested1BD1Ev(
+    // CHECK-NOT: call
+    // CHECK: br
+
+    // CHECK-NOT: call
+    // CHECK: call void @_ZN6nested1AD1Ev(
+    // CHECK-NOT: call
+    // CHECK: call void @_ZN6nested1AD1Ev(
+    // CHECK-NOT: call
+    // CHECK: }
+  }
+}