When binding a reference to an Automatic Reference Counting temporary,
retain/release the temporary object appropriately. Previously, we
would only perform the retain/release operations when the reference
would extend the lifetime of the temporary, but this does the wrong
thing across calls.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133620 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 2c00b9b..af0af7f 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -205,11 +205,21 @@
                             const CXXDestructorDecl *&ReferenceTemporaryDtor,
                             QualType &ObjCARCReferenceLifetimeType,
                             const NamedDecl *InitializedDecl) {
-  ObjCARCReferenceLifetimeType = QualType();
-  
   // Look through expressions for materialized temporaries (for now).
-  if (isa<MaterializeTemporaryExpr>(E))
-    E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+  if (const MaterializeTemporaryExpr *M 
+                                      = dyn_cast<MaterializeTemporaryExpr>(E)) {
+    // Objective-C++ ARC:
+    //   If we are binding a reference to a temporary that has ownership, we 
+    //   need to perform retain/release operations on the temporary.
+    if (CGF.getContext().getLangOptions().ObjCAutoRefCount &&        
+        E->getType()->isObjCLifetimeType() &&
+        (E->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
+         E->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
+         E->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))
+      ObjCARCReferenceLifetimeType = E->getType();
+    
+    E = M->GetTemporaryExpr();
+  }
 
   if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
     E = DAE->getExpr();
@@ -243,6 +253,57 @@
     // We have to load the lvalue.
     RV = CGF.EmitLoadOfLValue(LV, E->getType());
   } else {
+    if (!ObjCARCReferenceLifetimeType.isNull()) {
+      ReferenceTemporary = CreateReferenceTemporary(CGF, 
+                                                  ObjCARCReferenceLifetimeType, 
+                                                    InitializedDecl);
+      
+      
+      LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary, 
+                                             ObjCARCReferenceLifetimeType);
+
+      CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl),
+                         RefTempDst, false);
+      
+      bool ExtendsLifeOfTemporary = false;
+      if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
+        if (Var->extendsLifetimeOfTemporary())
+          ExtendsLifeOfTemporary = true;
+      } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) {
+        ExtendsLifeOfTemporary = true;
+      }
+      
+      if (!ExtendsLifeOfTemporary) {
+        // Since the lifetime of this temporary isn't going to be extended,
+        // we need to clean it up ourselves at the end of the full expression.
+        switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
+        case Qualifiers::OCL_None:
+        case Qualifiers::OCL_ExplicitNone:
+        case Qualifiers::OCL_Autoreleasing:
+          break;
+            
+        case Qualifiers::OCL_Strong:
+          CGF.PushARCReleaseCleanup(CGF.getARCCleanupKind(), 
+                                    ObjCARCReferenceLifetimeType, 
+                                    ReferenceTemporary,
+                                    /*Precise lifetime=*/false, 
+                                    /*For full expression=*/true);
+          break;
+          
+        case Qualifiers::OCL_Weak:
+          CGF.PushARCWeakReleaseCleanup(NormalAndEHCleanup, 
+                                        ObjCARCReferenceLifetimeType, 
+                                        ReferenceTemporary,
+                                        /*For full expression=*/true);
+          break;
+        }
+        
+        ObjCARCReferenceLifetimeType = QualType();
+      }
+      
+      return ReferenceTemporary;
+    }
+    
     llvm::SmallVector<SubobjectAdjustment, 2> Adjustments;
     while (true) {
       E = E->IgnoreParens();
@@ -298,34 +359,6 @@
         if (!ClassDecl->hasTrivialDestructor())
           ReferenceTemporaryDtor = ClassDecl->getDestructor();
       }
-      else if (CGF.getContext().getLangOptions().ObjCAutoRefCount) {
-        if (const ValueDecl *InitVD = dyn_cast<ValueDecl>(InitializedDecl)) {
-          if (const ReferenceType *RefType
-                                  = InitVD->getType()->getAs<ReferenceType>()) {
-            QualType PointeeType = RefType->getPointeeType();
-            if (PointeeType->isObjCLifetimeType() &&
-                PointeeType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
-              // Objective-C++ ARC: We're binding a reference to 
-              // lifetime-qualified type to a temporary, so we need to extend 
-              // the lifetime of the temporary with appropriate retain/release/
-              // autorelease calls.
-              ObjCARCReferenceLifetimeType = PointeeType;
-              
-              // Create a temporary variable that we can bind the reference to.
-              ReferenceTemporary = CreateReferenceTemporary(CGF, PointeeType, 
-                                                            InitializedDecl);
-
-              unsigned Alignment =
-                CGF.getContext().getTypeAlignInChars(PointeeType).getQuantity();
-              LValue lvalue =
-                CGF.MakeAddrLValue(ReferenceTemporary, PointeeType, Alignment);
-
-              CGF.EmitScalarInit(E, InitVD, lvalue, false);
-              return ReferenceTemporary;
-            }
-          }
-        }
-      }
     }
 
     RV = CGF.EmitAnyExpr(E, AggSlot);