From: Richard Smith Date: Thu, 27 Jun 2013 22:54:33 +0000 (+0000) Subject: Fix nested lifetime extension when a std::initializer_list member is X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5771aab8027e317de1e3f2f67b5dae67b3d895f8;p=clang Fix nested lifetime extension when a std::initializer_list member is 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 --- diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 9370287bee..f59571a486 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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(ILE->getInit(Index))) + performReferenceExtension(SubInit, ExtendingD); + else if (isa(SubInit) || + isa(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; } } diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp index 8adb887b9a..8dbb05711d 100644 --- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -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; ~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: } + } +}