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);