diff options
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 97 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 46 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 57 |
3 files changed, 162 insertions, 38 deletions
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2c00b9bf06..af0af7fbef 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -205,11 +205,21 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, 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 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, // 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 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, 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); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index ede2302403..a43f451109 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -1985,6 +1985,21 @@ namespace { CallReleaseForObject(QualType type, llvm::Value *addr, bool precise) : ObjCReleasingCleanup(type, addr), precise(precise) {} + using ObjCReleasingCleanup::Emit; + static void Emit(CodeGenFunction &CGF, bool IsForEH, + QualType type, llvm::Value *addr, bool precise) { + // EHScopeStack::Cleanup objects can never have their destructors called, + // so use placement new to construct our temporary object. + union { + void* align; + char data[sizeof(CallReleaseForObject)]; + }; + + CallReleaseForObject *Object + = new (&align) CallReleaseForObject(type, addr, precise); + Object->Emit(CGF, IsForEH); + } + void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) { llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "tmp"); CGF.EmitARCRelease(ptr, precise); @@ -2033,6 +2048,21 @@ namespace { CallWeakReleaseForObject(QualType type, llvm::Value *addr) : ObjCReleasingCleanup(type, addr) {} + using ObjCReleasingCleanup::Emit; + static void Emit(CodeGenFunction &CGF, bool IsForEH, + QualType type, llvm::Value *addr) { + // EHScopeStack::Cleanup objects can never have their destructors called, + // so use placement new to construct our temporary object. + union { + void* align; + char data[sizeof(CallWeakReleaseForObject)]; + }; + + CallWeakReleaseForObject *Object + = new (&align) CallWeakReleaseForObject(type, addr); + Object->Emit(CGF, IsForEH); + } + void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) { CGF.EmitARCDestroyWeak(addr); } @@ -2099,16 +2129,24 @@ void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) { void CodeGenFunction::PushARCReleaseCleanup(CleanupKind cleanupKind, QualType type, llvm::Value *addr, - bool precise) { - EHStack.pushCleanup<CallReleaseForObject>(cleanupKind, type, addr, precise); + bool precise, + bool forFullExpr) { + if (forFullExpr) + pushFullExprCleanup<CallReleaseForObject>(cleanupKind, type, addr, precise); + else + EHStack.pushCleanup<CallReleaseForObject>(cleanupKind, type, addr, precise); } /// PushARCWeakReleaseCleanup - Enter a cleanup to perform a weak /// release on the given object or array of objects. void CodeGenFunction::PushARCWeakReleaseCleanup(CleanupKind cleanupKind, QualType type, - llvm::Value *addr) { - EHStack.pushCleanup<CallWeakReleaseForObject>(cleanupKind, type, addr); + llvm::Value *addr, + bool forFullExpr) { + if (forFullExpr) + pushFullExprCleanup<CallWeakReleaseForObject>(cleanupKind, type, addr); + else + EHStack.pushCleanup<CallWeakReleaseForObject>(cleanupKind, type, addr); } /// PushARCReleaseCleanup - Enter a cleanup to perform a release on a diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 1aaa700f7e..0b24525029 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -223,6 +223,16 @@ public: } }; + template <class T, class A0, class A1, class A2> + class UnconditionalCleanup3 : public Cleanup { + A0 a0; A1 a1; A2 a2; + public: + UnconditionalCleanup3(A0 a0, A1 a1, A2 a2) : a0(a0), a1(a1), a2(a2) {} + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { + T::Emit(CGF, IsForEHCleanup, a0, a1, a2); + } + }; + /// ConditionalCleanupN stores the saved form of its N parameters, /// then restores them and performs the cleanup. template <class T, class A0> @@ -258,6 +268,27 @@ public: : a0_saved(a0), a1_saved(a1) {} }; + template <class T, class A0, class A1, class A2> + class ConditionalCleanup3 : public Cleanup { + typedef typename DominatingValue<A0>::saved_type A0_saved; + typedef typename DominatingValue<A1>::saved_type A1_saved; + typedef typename DominatingValue<A2>::saved_type A2_saved; + A0_saved a0_saved; + A1_saved a1_saved; + A2_saved a2_saved; + + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { + A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); + A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved); + A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved); + T::Emit(CGF, IsForEHCleanup, a0, a1, a2); + } + + public: + ConditionalCleanup3(A0_saved a0, A1_saved a1, A2_saved a2) + : a0_saved(a0), a1_saved(a1), a2_saved(a2) {} + }; + private: // The implementation for this class is in CGException.h and // CGException.cpp; the definition is here because it's used as a @@ -697,6 +728,27 @@ public: initFullExprCleanup(); } + /// pushFullExprCleanup - Push a cleanup to be run at the end of the + /// current full-expression. Safe against the possibility that + /// we're currently inside a conditionally-evaluated expression. + template <class T, class A0, class A1, class A2> + void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1, A2 a2) { + // If we're not in a conditional branch, or if none of the + // arguments requires saving, then use the unconditional cleanup. + if (!isInConditionalBranch()) { + typedef EHScopeStack::UnconditionalCleanup3<T, A0, A1, A2> CleanupType; + return EHStack.pushCleanup<CleanupType>(kind, a0, a1, a2); + } + + typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0); + typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1); + typename DominatingValue<A2>::saved_type a2_saved = saveValueInCond(a2); + + typedef EHScopeStack::ConditionalCleanup3<T, A0, A1, A2> CleanupType; + EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved, a2_saved); + initFullExprCleanup(); + } + /// PushDestructorCleanup - Push a cleanup to call the /// complete-object destructor of an object of the given type at the /// given address. Does nothing if T is not a C++ class type with a @@ -2036,9 +2088,10 @@ public: llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr); void PushARCReleaseCleanup(CleanupKind kind, QualType type, - llvm::Value *addr, bool precise); + llvm::Value *addr, bool precise, + bool forFullExpr = false); void PushARCWeakReleaseCleanup(CleanupKind kind, QualType type, - llvm::Value *addr); + llvm::Value *addr, bool forFullExpr = false); void PushARCFieldReleaseCleanup(CleanupKind cleanupKind, const FieldDecl *Field); void PushARCFieldWeakReleaseCleanup(CleanupKind cleanupKind, |