<div dir="ltr">This change caused a regression with range-based for loops:<div><div>$ cat t2.cc</div><div>#include <map></div><div>#include <string></div><div><br></div><div>struct E {</div><div>  std::string x;</div>
<div>};</div><div><br></div><div>int main() {</div><div>  std::map<int, E> m;</div><div>  m[42].x = "grrrrrr";</div><div><br></div><div>  for (const std::pair<int, E>& e : m) {</div><div>  }</div>
<div>}</div></div><div><br></div><div style>Valgrind finds:</div><div><div>==25512== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1</div><div>==25512==    at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)</div>
<div>==25512==    by 0x4ED0A88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)</div><div>==25512==    by 0x4ED0C79: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)</div>
<div>==25512==    by 0x4ED0E1B: std::string::_M_replace_safe(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)</div><div>==25512==    by 0x400D8A: main (in /tmp/t)</div>
</div><div><br></div><div style>This does not leak before the change. Replacing the pair type so there is no temporary fixes the issue. </div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Jun 11, 2013 at 4:41 AM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk" target="_blank">richard-llvm@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Mon Jun 10 21:41:00 2013<br>
New Revision: 183721<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=183721&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=183721&view=rev</a><br>
Log:<br>
Rework IR emission for lifetime-extended temporaries. Instead of trying to walk<br>
into the expression and dig out a single lifetime-extended entity and manually<br>
pull its cleanup outside the expression, instead keep a list of the cleanups<br>
which we'll need to emit when we get to the end of the full-expression. Also<br>
emit those cleanups early, as EH-only cleanups, to cover the case that the<br>
full-expression does not terminate normally. This allows IR generation to<br>
properly model temporary lifetime when multiple temporaries are extended by the<br>
same declaration.<br>
<br>
We have a pre-existing bug where an exception thrown from a temporary's<br>
destructor does not clean up lifetime-extended temporaries created in the same<br>
expression and extended to automatic storage duration; that is not fixed by<br>
this patch.<br>
<br>
Modified:<br>
    cfe/trunk/lib/CodeGen/CGCleanup.cpp<br>
    cfe/trunk/lib/CodeGen/CGCleanup.h<br>
    cfe/trunk/lib/CodeGen/CGDecl.cpp<br>
    cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
    cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
    cfe/trunk/lib/Sema/SemaInit.cpp<br>
    cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp<br>
    cfe/trunk/test/CodeGenCXX/temporaries.cpp<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGCleanup.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.cpp?rev=183721&r1=183720&r2=183721&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.cpp?rev=183721&r1=183720&r2=183721&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGCleanup.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGCleanup.cpp Mon Jun 10 21:41:00 2013<br>
@@ -387,6 +387,33 @@ void CodeGenFunction::PopCleanupBlocks(E<br>
   }<br>
 }<br>
<br>
+/// Pops cleanup blocks until the given savepoint is reached, then add the<br>
+/// cleanups from the given savepoint in the lifetime-extended cleanups stack.<br>
+void<br>
+CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old,<br>
+                                  size_t OldLifetimeExtendedSize) {<br>
+  PopCleanupBlocks(Old);<br>
+<br>
+  // Move our deferred cleanups onto the EH stack.<br>
+  for (size_t I = OldLifetimeExtendedSize,<br>
+              E = LifetimeExtendedCleanupStack.size(); I != E; /**/) {<br>
+    // Alignment should be guaranteed by the vptrs in the individual cleanups.<br>
+    assert((I % llvm::alignOf<LifetimeExtendedCleanupHeader>() == 0) &&<br>
+           "misaligned cleanup stack entry");<br>
+<br>
+    LifetimeExtendedCleanupHeader &Header =<br>
+        reinterpret_cast<LifetimeExtendedCleanupHeader&>(<br>
+            LifetimeExtendedCleanupStack[I]);<br>
+    I += sizeof(Header);<br>
+<br>
+    EHStack.pushCopyOfCleanup(Header.getKind(),<br>
+                              &LifetimeExtendedCleanupStack[I],<br>
+                              Header.getSize());<br>
+    I += Header.getSize();<br>
+  }<br>
+  LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize);<br>
+}<br>
+<br>
 static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF,<br>
                                            EHCleanupScope &Scope) {<br>
   assert(Scope.isNormalCleanup());<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGCleanup.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.h?rev=183721&r1=183720&r2=183721&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.h?rev=183721&r1=183720&r2=183721&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGCleanup.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CGCleanup.h Mon Jun 10 21:41:00 2013<br>
@@ -374,6 +374,11 @@ public:<br>
     return new (Buffer) T(N, a0, a1, a2);<br>
   }<br>
<br>
+  void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) {<br>
+    void *Buffer = pushCleanup(Kind, Size);<br>
+    std::memcpy(Buffer, Cleanup, Size);<br>
+  }<br>
+<br>
   /// Pops a cleanup scope off the stack.  This is private to CGCleanup.cpp.<br>
   void popCleanup();<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=183721&r1=183720&r2=183721&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=183721&r1=183720&r2=183721&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Mon Jun 10 21:41:00 2013<br>
@@ -1340,6 +1340,26 @@ void CodeGenFunction::pushDestroy(Cleanu<br>
                                      destroyer, useEHCleanupForArray);<br>
 }<br>
<br>
+void CodeGenFunction::pushLifetimeExtendedDestroy(<br>
+    CleanupKind cleanupKind, llvm::Value *addr, QualType type,<br>
+    Destroyer *destroyer, bool useEHCleanupForArray) {<br>
+  assert(!isInConditionalBranch() &&<br>
+         "performing lifetime extension from within conditional");<br>
+<br>
+  // Push an EH-only cleanup for the object now.<br>
+  // FIXME: When popping normal cleanups, we need to keep this EH cleanup<br>
+  // around in case a temporary's destructor throws an exception.<br>
+  if (cleanupKind & EHCleanup)<br>
+    EHStack.pushCleanup<DestroyObject>(<br>
+        static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), addr, type,<br>
+        destroyer, useEHCleanupForArray);<br>
+<br>
+  // Remember that we need to push a full cleanup for the object at the<br>
+  // end of the full-expression.<br>
+  pushCleanupAfterFullExpr<DestroyObject>(<br>
+      cleanupKind, addr, type, destroyer, useEHCleanupForArray);<br>
+}<br>
+<br>
 /// emitDestroy - Immediately perform the destruction of the given<br>
 /// object.<br>
 ///<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=183721&r1=183720&r2=183721&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=183721&r1=183720&r2=183721&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Mon Jun 10 21:41:00 2013<br>
@@ -171,128 +171,186 @@ void CodeGenFunction::EmitAnyExprToMem(c<br>
   llvm_unreachable("bad evaluation kind");<br>
 }<br>
<br>
-static llvm::Value *<br>
-CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type,<br>
-                         const NamedDecl *InitializedDecl) {<br>
-  if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {<br>
-    if (VD->hasGlobalStorage()) {<br>
-      SmallString<256> Name;<br>
-      llvm::raw_svector_ostream Out(Name);<br>
-      CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);<br>
-      Out.flush();<br>
-<br>
-      llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type);<br>
-<br>
-      // Create the reference temporary.<br>
-      llvm::GlobalVariable *RefTemp =<br>
-        new llvm::GlobalVariable(CGF.CGM.getModule(),<br>
-                                 RefTempTy, /*isConstant=*/false,<br>
-                                 llvm::GlobalValue::InternalLinkage,<br>
-                                 llvm::Constant::getNullValue(RefTempTy),<br>
-                                 Name.str());<br>
-      // If we're binding to a thread_local variable, the temporary is also<br>
-      // thread local.<br>
-      if (VD->getTLSKind())<br>
-        CGF.CGM.setTLSMode(RefTemp, *VD);<br>
-      return RefTemp;<br>
+static void<br>
+pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,<br>
+                     const Expr *E, llvm::Value *ReferenceTemporary) {<br>
+  // Objective-C++ ARC:<br>
+  //   If we are binding a reference to a temporary that has ownership, we<br>
+  //   need to perform retain/release operations on the temporary.<br>
+  //<br>
+  // FIXME: This should be looking at E, not M.<br>
+  if (CGF.getLangOpts().ObjCAutoRefCount &&<br>
+      M->getType()->isObjCLifetimeType()) {<br>
+    QualType ObjCARCReferenceLifetimeType = M->getType();<br>
+    switch (Qualifiers::ObjCLifetime Lifetime =<br>
+                ObjCARCReferenceLifetimeType.getObjCLifetime()) {<br>
+    case Qualifiers::OCL_None:<br>
+    case Qualifiers::OCL_ExplicitNone:<br>
+      // Carry on to normal cleanup handling.<br>
+      break;<br>
+<br>
+    case Qualifiers::OCL_Autoreleasing:<br>
+      // Nothing to do; cleaned up by an autorelease pool.<br>
+      return;<br>
+<br>
+    case Qualifiers::OCL_Strong:<br>
+    case Qualifiers::OCL_Weak:<br>
+      switch (StorageDuration Duration = M->getStorageDuration()) {<br>
+      case SD_Static:<br>
+        // Note: we intentionally do not register a cleanup to release<br>
+        // the object on program termination.<br>
+        return;<br>
+<br>
+      case SD_Thread:<br>
+        // FIXME: We should probably register a cleanup in this case.<br>
+        return;<br>
+<br>
+      case SD_Automatic:<br>
+      case SD_FullExpression:<br>
+        assert(!ObjCARCReferenceLifetimeType->isArrayType());<br>
+        CodeGenFunction::Destroyer *Destroy;<br>
+        CleanupKind CleanupKind;<br>
+        if (Lifetime == Qualifiers::OCL_Strong) {<br>
+          const ValueDecl *VD = M->getExtendingDecl();<br>
+          bool Precise =<br>
+              VD && isa<VarDecl>(VD) && VD->hasAttr<ObjCPreciseLifetimeAttr>();<br>
+          CleanupKind = CGF.getARCCleanupKind();<br>
+          Destroy = Precise ? &CodeGenFunction::destroyARCStrongPrecise<br>
+                            : &CodeGenFunction::destroyARCStrongImprecise;<br>
+        } else {<br>
+          // __weak objects always get EH cleanups; otherwise, exceptions<br>
+          // could cause really nasty crashes instead of mere leaks.<br>
+          CleanupKind = NormalAndEHCleanup;<br>
+          Destroy = &CodeGenFunction::destroyARCWeak;<br>
+        }<br>
+        if (Duration == SD_FullExpression)<br>
+          CGF.pushDestroy(CleanupKind, ReferenceTemporary,<br>
+                          ObjCARCReferenceLifetimeType, *Destroy,<br>
+                          CleanupKind & EHCleanup);<br>
+        else<br>
+          CGF.pushLifetimeExtendedDestroy(CleanupKind, ReferenceTemporary,<br>
+                                          ObjCARCReferenceLifetimeType,<br>
+                                          *Destroy, CleanupKind & EHCleanup);<br>
+        return;<br>
+<br>
+      case SD_Dynamic:<br>
+        llvm_unreachable("temporary cannot have dynamic storage duration");<br>
+      }<br>
+      llvm_unreachable("unknown storage duration");<br>
+    }<br>
+  }<br>
+<br>
+  if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {<br>
+    if (ILE->initializesStdInitializerList()) {<br>
+      // FIXME: This is wrong if the temporary has static or thread storage<br>
+      // duration.<br>
+      CGF.EmitStdInitializerListCleanup(ReferenceTemporary, ILE);<br>
+      return;<br>
+    }<br>
+  }<br>
+<br>
+  CXXDestructorDecl *ReferenceTemporaryDtor = 0;<br>
+  if (const RecordType *RT =<br>
+          E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {<br>
+    // Get the destructor for the reference temporary.<br>
+    CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());<br>
+    if (!ClassDecl->hasTrivialDestructor())<br>
+      ReferenceTemporaryDtor = ClassDecl->getDestructor();<br>
+  }<br>
+<br>
+  if (!ReferenceTemporaryDtor)<br>
+    return;<br>
+<br>
+  // Call the destructor for the temporary.<br>
+  switch (M->getStorageDuration()) {<br>
+  case SD_Static:<br>
+  case SD_Thread: {<br>
+    llvm::Constant *CleanupFn;<br>
+    llvm::Constant *CleanupArg;<br>
+    if (E->getType()->isArrayType()) {<br>
+      CleanupFn = CodeGenFunction(CGF.CGM).generateDestroyHelper(<br>
+          cast<llvm::Constant>(ReferenceTemporary), E->getType(),<br>
+          CodeGenFunction::destroyCXXObject, CGF.getLangOpts().Exceptions);<br>
+      CleanupArg = llvm::Constant::getNullValue(CGF.Int8PtrTy);<br>
+    } else {<br>
+      CleanupFn =<br>
+        CGF.CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);<br>
+      CleanupArg = cast<llvm::Constant>(ReferenceTemporary);<br>
     }<br>
+    CGF.CGM.getCXXABI().registerGlobalDtor(<br>
+        CGF, *cast<VarDecl>(M->getExtendingDecl()), CleanupFn, CleanupArg);<br>
+    break;<br>
   }<br>
<br>
-  return CGF.CreateMemTemp(Type, "ref.tmp");<br>
+  case SD_FullExpression:<br>
+    CGF.pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),<br>
+                    CodeGenFunction::destroyCXXObject,<br>
+                    CGF.getLangOpts().Exceptions);<br>
+    break;<br>
+<br>
+  case SD_Automatic:<br>
+    CGF.pushLifetimeExtendedDestroy(NormalAndEHCleanup,<br>
+                                    ReferenceTemporary, E->getType(),<br>
+                                    CodeGenFunction::destroyCXXObject,<br>
+                                    CGF.getLangOpts().Exceptions);<br>
+    break;<br>
+<br>
+  case SD_Dynamic:<br>
+    llvm_unreachable("temporary cannot have dynamic storage duration");<br>
+  }<br>
 }<br>
<br>
 static llvm::Value *<br>
-EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,<br>
-                            llvm::Value *&ReferenceTemporary,<br>
-                            const CXXDestructorDecl *&ReferenceTemporaryDtor,<br>
-                            const InitListExpr *&ReferenceInitializerList,<br>
-                            QualType &ObjCARCReferenceLifetimeType,<br>
-                            const NamedDecl *InitializedDecl) {<br>
-  const MaterializeTemporaryExpr *M = NULL;<br>
-  E = E->findMaterializedTemporary(M);<br>
-  // Objective-C++ ARC:<br>
-  //   If we are binding a reference to a temporary that has ownership, we<br>
-  //   need to perform retain/release operations on the temporary.<br>
-  if (M && CGF.getLangOpts().ObjCAutoRefCount &&<br>
-      M->getType()->isObjCLifetimeType() &&<br>
-      (M->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||<br>
-       M->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||<br>
-       M->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))<br>
-    ObjCARCReferenceLifetimeType = M->getType();<br>
+createReferenceTemporary(CodeGenFunction &CGF,<br>
+                         const MaterializeTemporaryExpr *M, const Expr *Inner) {<br>
+  switch (M->getStorageDuration()) {<br>
+  case SD_FullExpression:<br>
+  case SD_Automatic:<br>
+    return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");<br>
+<br>
+  case SD_Thread:<br>
+  case SD_Static:<br>
+    return CGF.CGM.GetAddrOfGlobalTemporary(M, Inner);<br>
+<br>
+  case SD_Dynamic:<br>
+    llvm_unreachable("temporary can't have dynamic storage duration");<br>
+  }<br>
+}<br>
<br>
+static llvm::Value *<br>
+emitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,<br>
+                            const NamedDecl *InitializedDecl) {<br>
   if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) {<br>
     CGF.enterFullExpression(EWC);<br>
     CodeGenFunction::RunCleanupsScope Scope(CGF);<br>
-<br>
-    return EmitExprForReferenceBinding(CGF, EWC->getSubExpr(),<br>
-                                       ReferenceTemporary,<br>
-                                       ReferenceTemporaryDtor,<br>
-                                       ReferenceInitializerList,<br>
-                                       ObjCARCReferenceLifetimeType,<br>
-                                       InitializedDecl);<br>
+    return emitExprForReferenceBinding(CGF, EWC->getSubExpr(), InitializedDecl);<br>
   }<br>
<br>
+  const MaterializeTemporaryExpr *M = 0;<br>
+  E = E->findMaterializedTemporary(M);<br>
+<br>
   if (E->isGLValue()) {<br>
     // Emit the expression as an lvalue.<br>
     LValue LV = CGF.EmitLValue(E);<br>
     assert(LV.isSimple());<br>
     return LV.getAddress();<br>
   }<br>
-<br>
-  if (!ObjCARCReferenceLifetimeType.isNull()) {<br>
-    ReferenceTemporary = CreateReferenceTemporary(CGF,<br>
-                                                ObjCARCReferenceLifetimeType,<br>
-                                                  InitializedDecl);<br>
-<br>
-<br>
-    LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary,<br>
-                                           ObjCARCReferenceLifetimeType);<br>
+<br>
+  assert(M && "prvalue reference initializer but not a materialized temporary");<br>
+<br>
+  if (CGF.getLangOpts().ObjCAutoRefCount &&<br>
+      M->getType()->isObjCLifetimeType() &&<br>
+      M->getType().getObjCLifetime() != Qualifiers::OCL_None &&<br>
+      M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {<br>
+    // FIXME: Fold this into the general case below.<br>
+    llvm::Value *Object = createReferenceTemporary(CGF, M, E);<br>
+    LValue RefTempDst = CGF.MakeAddrLValue(Object, M->getType());<br>
<br>
     CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl),<br>
                        RefTempDst, false);<br>
-<br>
-    bool ExtendsLifeOfTemporary = false;<br>
-    if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) {<br>
-      if (Var->extendsLifetimeOfTemporary())<br>
-        ExtendsLifeOfTemporary = true;<br>
-    } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) {<br>
-      ExtendsLifeOfTemporary = true;<br>
-    }<br>
-<br>
-    if (!ExtendsLifeOfTemporary) {<br>
-      // Since the lifetime of this temporary isn't going to be extended,<br>
-      // we need to clean it up ourselves at the end of the full expression.<br>
-      switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {<br>
-      case Qualifiers::OCL_None:<br>
-      case Qualifiers::OCL_ExplicitNone:<br>
-      case Qualifiers::OCL_Autoreleasing:<br>
-        break;<br>
-<br>
-      case Qualifiers::OCL_Strong: {<br>
-        assert(!ObjCARCReferenceLifetimeType->isArrayType());<br>
-        CleanupKind cleanupKind = CGF.getARCCleanupKind();<br>
-        CGF.pushDestroy(cleanupKind,<br>
-                        ReferenceTemporary,<br>
-                        ObjCARCReferenceLifetimeType,<br>
-                        CodeGenFunction::destroyARCStrongImprecise,<br>
-                        cleanupKind & EHCleanup);<br>
-        break;<br>
-      }<br>
-<br>
-      case Qualifiers::OCL_Weak:<br>
-        assert(!ObjCARCReferenceLifetimeType->isArrayType());<br>
-        CGF.pushDestroy(NormalAndEHCleanup,<br>
-                        ReferenceTemporary,<br>
-                        ObjCARCReferenceLifetimeType,<br>
-                        CodeGenFunction::destroyARCWeak,<br>
-                        /*useEHCleanupForArray*/ true);<br>
-        break;<br>
-      }<br>
-<br>
-      ObjCARCReferenceLifetimeType = QualType();<br>
-    }<br>
-<br>
-    return ReferenceTemporary;<br>
+<br>
+    pushTemporaryCleanup(CGF, M, E, Object);<br>
+    return Object;<br>
   }<br>
<br>
   SmallVector<const Expr *, 2> CommaLHSs;<br>
@@ -302,112 +360,59 @@ EmitExprForReferenceBinding(CodeGenFunct<br>
   for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)<br>
     CGF.EmitIgnoredExpr(CommaLHSs[I]);<br>
<br>
-  if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))<br>
-    if (opaque->getType()->isRecordType())<br>
+  if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) {<br>
+    if (opaque->getType()->isRecordType()) {<br>
+      assert(Adjustments.empty());<br>
       return CGF.EmitOpaqueValueLValue(opaque).getAddress();<br>
-<br>
-  // Create a reference temporary if necessary.<br>
-  AggValueSlot AggSlot = AggValueSlot::ignored();<br>
-  if (CGF.hasAggregateEvaluationKind(E->getType())) {<br>
-    ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),<br>
-                                                  InitializedDecl);<br>
-    CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType());<br>
-    AggValueSlot::IsDestructed_t isDestructed<br>
-      = AggValueSlot::IsDestructed_t(InitializedDecl != 0);<br>
-    AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment,<br>
-                                    Qualifiers(), isDestructed,<br>
-                                    AggValueSlot::DoesNotNeedGCBarriers,<br>
-                                    AggValueSlot::IsNotAliased);<br>
-  }<br>
-<br>
-  if (InitializedDecl) {<br>
-    if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {<br>
-      if (ILE->initializesStdInitializerList()) {<br>
-        ReferenceInitializerList = ILE;<br>
-      }<br>
-    }<br>
-    else if (const RecordType *RT =<br>
-               E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()){<br>
-      // Get the destructor for the reference temporary.<br>
-      CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());<br>
-      if (!ClassDecl->hasTrivialDestructor())<br>
-        ReferenceTemporaryDtor = ClassDecl->getDestructor();<br>
     }<br>
   }<br>
<br>
-  RValue RV = CGF.EmitAnyExpr(E, AggSlot);<br>
-<br>
-  // FIXME: This is wrong. We need to register the destructor for the temporary<br>
-  // now, *before* we perform the adjustments, because in the case of a<br>
-  // pointer-to-member adjustment, the adjustment might throw.<br>
-<br>
-  // Check if need to perform derived-to-base casts and/or field accesses, to<br>
-  // get from the temporary object we created (and, potentially, for which we<br>
-  // extended the lifetime) to the subobject we're binding the reference to.<br>
-  if (!Adjustments.empty()) {<br>
-    llvm::Value *Object = RV.getAggregateAddr();<br>
-    for (unsigned I = Adjustments.size(); I != 0; --I) {<br>
-      SubobjectAdjustment &Adjustment = Adjustments[I-1];<br>
-      switch (Adjustment.Kind) {<br>
-      case SubobjectAdjustment::DerivedToBaseAdjustment:<br>
-        Object =<br>
-            CGF.GetAddressOfBaseClass(Object,<br>
-                                      Adjustment.DerivedToBase.DerivedClass,<br>
-                            Adjustment.DerivedToBase.BasePath->path_begin(),<br>
-                            Adjustment.DerivedToBase.BasePath->path_end(),<br>
-                                      /*NullCheckValue=*/false);<br>
-        break;<br>
-<br>
-      case SubobjectAdjustment::FieldAdjustment: {<br>
-        LValue LV = CGF.MakeAddrLValue(Object, E->getType());<br>
-        LV = CGF.EmitLValueForField(LV, Adjustment.Field);<br>
-        assert(LV.isSimple() &&<br>
-               "materialized temporary field is not a simple lvalue");<br>
-        Object = LV.getAddress();<br>
-        break;<br>
-      }<br>
+  // Create and initialize the reference temporary.<br>
+  llvm::Value *Object = createReferenceTemporary(CGF, M, E);<br>
+  CGF.EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);<br>
+  pushTemporaryCleanup(CGF, M, E, Object);<br>
+<br>
+  // Perform derived-to-base casts and/or field accesses, to get from the<br>
+  // temporary object we created (and, potentially, for which we extended<br>
+  // the lifetime) to the subobject we're binding the reference to.<br>
+  for (unsigned I = Adjustments.size(); I != 0; --I) {<br>
+    SubobjectAdjustment &Adjustment = Adjustments[I-1];<br>
+    switch (Adjustment.Kind) {<br>
+    case SubobjectAdjustment::DerivedToBaseAdjustment:<br>
+      Object =<br>
+          CGF.GetAddressOfBaseClass(Object,<br>
+                                    Adjustment.DerivedToBase.DerivedClass,<br>
+                          Adjustment.DerivedToBase.BasePath->path_begin(),<br>
+                          Adjustment.DerivedToBase.BasePath->path_end(),<br>
+                                    /*NullCheckValue=*/false);<br>
+      break;<br>
<br>
-      case SubobjectAdjustment::MemberPointerAdjustment: {<br>
-        llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);<br>
-        Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(<br>
-                      CGF, Object, Ptr, Adjustment.Ptr.MPT);<br>
-        break;<br>
-      }<br>
-      }<br>
+    case SubobjectAdjustment::FieldAdjustment: {<br>
+      LValue LV = CGF.MakeAddrLValue(Object, E->getType());<br>
+      LV = CGF.EmitLValueForField(LV, Adjustment.Field);<br>
+      assert(LV.isSimple() &&<br>
+             "materialized temporary field is not a simple lvalue");<br>
+      Object = LV.getAddress();<br>
+      break;<br>
     }<br>
<br>
-    return Object;<br>
+    case SubobjectAdjustment::MemberPointerAdjustment: {<br>
+      llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);<br>
+      Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(<br>
+                    CGF, Object, Ptr, Adjustment.Ptr.MPT);<br>
+      break;<br>
+    }<br>
+    }<br>
   }<br>
<br>
-  if (RV.isAggregate())<br>
-    return RV.getAggregateAddr();<br>
-<br>
-  // Create a temporary variable that we can bind the reference to.<br>
-  ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),<br>
-                                                InitializedDecl);<br>
-<br>
-<br>
-  LValue tempLV = CGF.MakeNaturalAlignAddrLValue(ReferenceTemporary,<br>
-                                                 E->getType());<br>
-  if (RV.isScalar())<br>
-    CGF.EmitStoreOfScalar(RV.getScalarVal(), tempLV, /*init*/ true);<br>
-  else<br>
-    CGF.EmitStoreOfComplex(RV.getComplexVal(), tempLV, /*init*/ true);<br>
-  return ReferenceTemporary;<br>
+  return Object;<br>
 }<br>
<br>
 RValue<br>
 CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,<br>
                                             const NamedDecl *InitializedDecl) {<br>
-  llvm::Value *ReferenceTemporary = 0;<br>
-  const CXXDestructorDecl *ReferenceTemporaryDtor = 0;<br>
-  const InitListExpr *ReferenceInitializerList = 0;<br>
-  QualType ObjCARCReferenceLifetimeType;<br>
-  llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary,<br>
-                                                   ReferenceTemporaryDtor,<br>
-                                                   ReferenceInitializerList,<br>
-                                                   ObjCARCReferenceLifetimeType,<br>
-                                                   InitializedDecl);<br>
+  llvm::Value *Value = emitExprForReferenceBinding(*this, E, InitializedDecl);<br>
+<br>
   if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) {<br>
     // C++11 [dcl.ref]p5 (as amended by core issue 453):<br>
     //   If a glvalue to which a reference is directly bound designates neither<br>
@@ -417,80 +422,7 @@ CodeGenFunction::EmitReferenceBindingToE<br>
     QualType Ty = E->getType();<br>
     EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty);<br>
   }<br>
-  if (!ReferenceTemporaryDtor && !ReferenceInitializerList &&<br>
-      ObjCARCReferenceLifetimeType.isNull())<br>
-    return RValue::get(Value);<br>
-<br>
-  // Make sure to call the destructor for the reference temporary.<br>
-  const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);<br>
-  if (VD && VD->hasGlobalStorage()) {<br>
-    if (ReferenceTemporaryDtor) {<br>
-      llvm::Constant *CleanupFn;<br>
-      llvm::Constant *CleanupArg;<br>
-      if (E->getType()->isArrayType()) {<br>
-        CleanupFn = CodeGenFunction(CGM).generateDestroyHelper(<br>
-            cast<llvm::Constant>(ReferenceTemporary), E->getType(),<br>
-            destroyCXXObject, getLangOpts().Exceptions);<br>
-        CleanupArg = llvm::Constant::getNullValue(Int8PtrTy);<br>
-      } else {<br>
-        CleanupFn =<br>
-          CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);<br>
-        CleanupArg = cast<llvm::Constant>(ReferenceTemporary);<br>
-      }<br>
-      CGM.getCXXABI().registerGlobalDtor(*this, *VD, CleanupFn, CleanupArg);<br>
-    } else if (ReferenceInitializerList) {<br>
-      // FIXME: This is wrong. We need to register a global destructor to clean<br>
-      // up the initializer_list object, rather than adding it as a local<br>
-      // cleanup.<br>
-      EmitStdInitializerListCleanup(ReferenceTemporary,<br>
-                                    ReferenceInitializerList);<br>
-    } else {<br>
-      assert(!ObjCARCReferenceLifetimeType.isNull() && !VD->getTLSKind());<br>
-      // Note: We intentionally do not register a global "destructor" to<br>
-      // release the object.<br>
-    }<br>
-<br>
-    return RValue::get(Value);<br>
-  }<br>
<br>
-  if (ReferenceTemporaryDtor) {<br>
-    if (E->getType()->isArrayType())<br>
-      pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),<br>
-                  destroyCXXObject, getLangOpts().Exceptions);<br>
-    else<br>
-      PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);<br>
-  } else if (ReferenceInitializerList) {<br>
-    EmitStdInitializerListCleanup(ReferenceTemporary,<br>
-                                  ReferenceInitializerList);<br>
-  } else {<br>
-    switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {<br>
-    case Qualifiers::OCL_None:<br>
-      llvm_unreachable(<br>
-                      "Not a reference temporary that needs to be deallocated");<br>
-    case Qualifiers::OCL_ExplicitNone:<br>
-    case Qualifiers::OCL_Autoreleasing:<br>
-      // Nothing to do.<br>
-      break;<br>
-<br>
-    case Qualifiers::OCL_Strong: {<br>
-      bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>();<br>
-      CleanupKind cleanupKind = getARCCleanupKind();<br>
-      pushDestroy(cleanupKind, ReferenceTemporary, ObjCARCReferenceLifetimeType,<br>
-                  precise ? destroyARCStrongPrecise : destroyARCStrongImprecise,<br>
-                  cleanupKind & EHCleanup);<br>
-      break;<br>
-    }<br>
-<br>
-    case Qualifiers::OCL_Weak: {<br>
-      // __weak objects always get EH cleanups; otherwise, exceptions<br>
-      // could cause really nasty crashes instead of mere leaks.<br>
-      pushDestroy(NormalAndEHCleanup, ReferenceTemporary,<br>
-                  ObjCARCReferenceLifetimeType, destroyARCWeak, true);<br>
-      break;<br>
-    }<br>
-    }<br>
-  }<br>
-<br>
   return RValue::get(Value);<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=183721&r1=183720&r2=183721&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=183721&r1=183720&r2=183721&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Jun 10 21:41:00 2013<br>
@@ -241,6 +241,18 @@ public:<br>
   llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;<br>
<br>
   EHScopeStack EHStack;<br>
+  llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;<br>
+<br>
+  /// Header for data within LifetimeExtendedCleanupStack.<br>
+  struct LifetimeExtendedCleanupHeader {<br>
+    /// The size of the following cleanup object.<br>
+    size_t Size : 29;<br>
+    /// The kind of cleanup to push: a value from the CleanupKind enumeration.<br>
+    unsigned Kind : 3;<br>
+<br>
+    size_t getSize() const { return Size; }<br>
+    CleanupKind getKind() const { return static_cast<CleanupKind>(Kind); }<br>
+  };<br>
<br>
   /// i32s containing the indexes of the cleanup destinations.<br>
   llvm::AllocaInst *NormalCleanupDest;<br>
@@ -376,6 +388,23 @@ public:<br>
     initFullExprCleanup();<br>
   }<br>
<br>
+  /// \brief Queue a cleanup to be pushed after finishing the current<br>
+  /// full-expression.<br>
+  template <class T, class A0, class A1, class A2, class A3><br>
+  void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {<br>
+    assert(!isInConditionalBranch() && "can't defer conditional cleanup");<br>
+<br>
+    LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind };<br>
+<br>
+    size_t OldSize = LifetimeExtendedCleanupStack.size();<br>
+    LifetimeExtendedCleanupStack.resize(<br>
+        LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size);<br>
+<br>
+    char *Buffer = &LifetimeExtendedCleanupStack[OldSize];<br>
+    new (Buffer) LifetimeExtendedCleanupHeader(Header);<br>
+    new (Buffer + sizeof(Header)) T(a0, a1, a2, a3);<br>
+  }<br>
+<br>
   /// Set up the last cleaup that was pushed as a conditional<br>
   /// full-expression cleanup.<br>
   void initFullExprCleanup();<br>
@@ -421,6 +450,7 @@ public:<br>
   /// will be executed once the scope is exited.<br>
   class RunCleanupsScope {<br>
     EHScopeStack::stable_iterator CleanupStackDepth;<br>
+    size_t LifetimeExtendedCleanupStackSize;<br>
     bool OldDidCallStackSave;<br>
   protected:<br>
     bool PerformCleanup;<br>
@@ -438,6 +468,8 @@ public:<br>
       : PerformCleanup(true), CGF(CGF)<br>
     {<br>
       CleanupStackDepth = CGF.EHStack.stable_begin();<br>
+      LifetimeExtendedCleanupStackSize =<br>
+          CGF.LifetimeExtendedCleanupStack.size();<br>
       OldDidCallStackSave = CGF.DidCallStackSave;<br>
       CGF.DidCallStackSave = false;<br>
     }<br>
@@ -447,7 +479,8 @@ public:<br>
     ~RunCleanupsScope() {<br>
       if (PerformCleanup) {<br>
         CGF.DidCallStackSave = OldDidCallStackSave;<br>
-        CGF.PopCleanupBlocks(CleanupStackDepth);<br>
+        CGF.PopCleanupBlocks(CleanupStackDepth,<br>
+                             LifetimeExtendedCleanupStackSize);<br>
       }<br>
     }<br>
<br>
@@ -461,7 +494,8 @@ public:<br>
     void ForceCleanup() {<br>
       assert(PerformCleanup && "Already forced cleanup");<br>
       CGF.DidCallStackSave = OldDidCallStackSave;<br>
-      CGF.PopCleanupBlocks(CleanupStackDepth);<br>
+      CGF.PopCleanupBlocks(CleanupStackDepth,<br>
+                           LifetimeExtendedCleanupStackSize);<br>
       PerformCleanup = false;<br>
     }<br>
   };<br>
@@ -513,10 +547,16 @@ public:<br>
   };<br>
<br>
<br>
-  /// PopCleanupBlocks - Takes the old cleanup stack size and emits<br>
-  /// the cleanup blocks that have been added.<br>
+  /// \brief Takes the old cleanup stack size and emits the cleanup blocks<br>
+  /// that have been added.<br>
   void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize);<br>
<br>
+  /// \brief Takes the old cleanup stack size and emits the cleanup blocks<br>
+  /// that have been added, then adds all lifetime-extended cleanups from<br>
+  /// the given position to the stack.<br>
+  void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,<br>
+                        size_t OldLifetimeExtendedStackSize);<br>
+<br>
   void ResolveBranchFixups(llvm::BasicBlock *Target);<br>
<br>
   /// The given basic block lies in the current EH scope, but may be a<br>
@@ -988,6 +1028,9 @@ public:<br>
                      llvm::Value *addr, QualType type);<br>
   void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,<br>
                    Destroyer *destroyer, bool useEHCleanupForArray);<br>
+  void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr,<br>
+                                   QualType type, Destroyer *destroyer,<br>
+                                   bool useEHCleanupForArray);<br>
   void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,<br>
                    bool useEHCleanupForArray);<br>
   llvm::Function *generateDestroyHelper(llvm::Constant *addr,<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaInit.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=183721&r1=183720&r2=183721&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=183721&r1=183720&r2=183721&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Jun 10 21:41:00 2013<br>
@@ -5214,6 +5214,9 @@ static void performLifetimeExtension(Exp<br>
   Init = const_cast<Expr *>(<br>
       Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));<br>
<br>
+  if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))<br>
+    Init = BTE->getSubExpr();<br>
+<br>
   if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {<br>
     if (ILE->initializesStdInitializerList() || ILE->getType()->isArrayType()) {<br>
       // FIXME: If this is an InitListExpr which creates a std::initializer_list<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp?rev=183721&r1=183720&r2=183721&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp?rev=183721&r1=183720&r2=183721&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp Mon Jun 10 21:41:00 2013<br>
@@ -35,7 +35,7 @@ int e = V<int>::m;<br>
<br>
 // CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global<br>
 // CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0<br>
-// CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global<br>
+// CHECK: @_ZGRZ8tls_dtorvE1u = private thread_local global<br>
<br>
 // CHECK: @_ZGVN1VIiE1mE = weak_odr thread_local global i64 0<br>
<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/temporaries.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/temporaries.cpp?rev=183721&r1=183720&r2=183721&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/temporaries.cpp?rev=183721&r1=183720&r2=183721&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/temporaries.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/temporaries.cpp Mon Jun 10 21:41:00 2013<br>
@@ -584,11 +584,9 @@ namespace BindToSubobject {<br>
   // CHECK: call void @_ZN15BindToSubobject1fEv()<br>
   // CHECK: call void @_ZN15BindToSubobject1gEv()<br>
   // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1cE)<br>
-  // FIXME: This is wrong. We should emit the call to __cxa_atexit prior to<br>
-  // calling h(), in case h() throws.<br>
+  // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle)<br>
   // CHECK: call {{.*}} @_ZN15BindToSubobject1hE<br>
   // CHECK: getelementptr<br>
-  // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle)<br>
   // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1cE, align 8<br>
   int &&c = (f(), (g(), A().*h()));<br>
<br>
@@ -598,9 +596,9 @@ namespace BindToSubobject {<br>
   };<br>
<br>
   // CHECK: call void @_ZN15BindToSubobject1BC1Ev({{.*}} @_ZGRN15BindToSubobject1dE)<br>
+  // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle)<br>
   // CHECK: call {{.*}} @_ZN15BindToSubobject1hE<br>
   // CHECK: getelementptr {{.*}} getelementptr<br>
-  // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle)<br>
   // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1dE, align 8<br>
   int &&d = (B().a).*h();<br>
 }<br>
@@ -611,7 +609,7 @@ namespace Bitfield {<br>
   // Do not lifetime extend the S() temporary here.<br>
   // CHECK: alloca<br>
   // CHECK: call {{.*}}memset<br>
-  // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE, align 4<br>
+  // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE<br>
   // CHECK: call void @_ZN8Bitfield1SD1<br>
   // CHECK: store i32* @_ZGRN8Bitfield1rE, i32** @_ZN8Bitfield1rE, align 8<br>
   int &&r = S().a;<br>
@@ -626,15 +624,91 @@ namespace Vector {<br>
   };<br>
   // CHECK: alloca<br>
   // CHECK: extractelement<br>
-  // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE,<br>
+  // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE<br>
   // CHECK: store i32* @_ZGRN6Vector1rE, i32** @_ZN6Vector1rE,<br>
   int &&r = S().v[1];<br>
<br>
   // CHECK: alloca<br>
   // CHECK: extractelement<br>
-  // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE,<br>
+  // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE<br>
   // CHECK: store i32* @_ZGRN6Vector1sE, i32** @_ZN6Vector1sE,<br>
   int &&s = S().w[1];<br>
   // FIXME PR16204: The following code leads to an assertion in Sema.<br>
   //int &&s = S().w.y;<br>
 }<br>
+<br>
+namespace MultipleExtension {<br>
+  struct A { A(); ~A(); };<br>
+  struct B { B(); ~B(); };<br>
+  struct C { C(); ~C(); };<br>
+  struct D { D(); ~D(); int n; C c; };<br>
+  struct E { const A &a; B b; const C &c; ~E(); };<br>
+<br>
+  E &&e1 = { A(), B(), D().c };<br>
+<br>
+  // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e1E.*]])<br>
+  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]]<br>
+  // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE:_ZGRN17MultipleExtension2e1E.*]], i32 0, i32 0)<br>
+<br>
+  // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 1))<br>
+<br>
+  // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e1E.*]])<br>
+  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]]<br>
+  // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 2)<br>
+  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[TEMPE]]<br>
+  // CHECK: store {{.*}} @[[TEMPE]], %"struct.MultipleExtension::E"** @_ZN17MultipleExtension2e1E, align 8<br>
+<br>
+  E e2 = { A(), B(), D().c };<br>
+<br>
+  // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e2E.*]])<br>
+  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]]<br>
+  // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[E:_ZN17MultipleExtension2e2E]], i32 0, i32 0)<br>
+<br>
+  // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 1))<br>
+<br>
+  // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e2E.*]])<br>
+  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]]<br>
+  // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 2)<br>
+  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[E]]<br>
+<br>
+<br>
+  void g();<br>
+  // CHECK: define void @[[NS:_ZN17MultipleExtension]]1fEv(<br>
+  void f() {<br>
+    E &&e1 = { A(), B(), D().c };<br>
+    // CHECK: %[[TEMPE1_A:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1:.*]], i32 0, i32 0<br>
+    // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA1:.*]])<br>
+    // CHECK: store {{.*}} %[[TEMPA1]], {{.*}} %[[TEMPE1_A]]<br>
+    // CHECK: %[[TEMPE1_B:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 1<br>
+    // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE1_B]])<br>
+    // CHECK: %[[TEMPE1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 2<br>
+    // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD1:.*]])<br>
+    // CHECK: %[[TEMPD1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD1]], i32 0, i32 1<br>
+    // CHECK: store {{.*}} %[[TEMPD1_C]], {{.*}} %[[TEMPE1_C]]<br>
+    // CHECK: store {{.*}} %[[TEMPE1]], {{.*}} %[[E1:.*]]<br>
+<br>
+    g();<br>
+    // CHECK: call void @[[NS]]1gEv()<br>
+<br>
+    E e2 = { A(), B(), D().c };<br>
+    // CHECK: %[[TEMPE2_A:.*]] = getelementptr inbounds {{.*}} %[[E2:.*]], i32 0, i32 0<br>
+    // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA2:.*]])<br>
+    // CHECK: store {{.*}} %[[TEMPA2]], {{.*}} %[[TEMPE2_A]]<br>
+    // CHECK: %[[TEMPE2_B:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 1<br>
+    // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE2_B]])<br>
+    // CHECK: %[[TEMPE2_C:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 2<br>
+    // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD2:.*]])<br>
+    // CHECK: %[[TEMPD2_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD2]], i32 0, i32 1<br>
+    // CHECK: store {{.*}} %[[TEMPD2_C]], {{.*}}* %[[TEMPE2_C]]<br>
+<br>
+    g();<br>
+    // CHECK: call void @[[NS]]1gEv()<br>
+<br>
+    // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[E2]])<br>
+    // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD2]])<br>
+    // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA2]])<br>
+    // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[TEMPE1]])<br>
+    // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD1]])<br>
+    // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA1]])<br>
+  }<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>