r183776 - Revert r183721. It caused cleanups to be delayed too long in some cases.
Richard Smith
richard-llvm at metafoo.co.uk
Tue Jun 11 12:14:25 PDT 2013
Author: rsmith
Date: Tue Jun 11 14:14:25 2013
New Revision: 183776
URL: http://llvm.org/viewvc/llvm-project?rev=183776&view=rev
Log:
Revert r183721. It caused cleanups to be delayed too long in some cases.
Testcase to follow.
Modified:
cfe/trunk/lib/CodeGen/CGCleanup.cpp
cfe/trunk/lib/CodeGen/CGCleanup.h
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
cfe/trunk/test/CodeGenCXX/temporaries.cpp
Modified: cfe/trunk/lib/CodeGen/CGCleanup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.cpp?rev=183776&r1=183775&r2=183776&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCleanup.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCleanup.cpp Tue Jun 11 14:14:25 2013
@@ -387,33 +387,6 @@ void CodeGenFunction::PopCleanupBlocks(E
}
}
-/// Pops cleanup blocks until the given savepoint is reached, then add the
-/// cleanups from the given savepoint in the lifetime-extended cleanups stack.
-void
-CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old,
- size_t OldLifetimeExtendedSize) {
- PopCleanupBlocks(Old);
-
- // Move our deferred cleanups onto the EH stack.
- for (size_t I = OldLifetimeExtendedSize,
- E = LifetimeExtendedCleanupStack.size(); I != E; /**/) {
- // Alignment should be guaranteed by the vptrs in the individual cleanups.
- assert((I % llvm::alignOf<LifetimeExtendedCleanupHeader>() == 0) &&
- "misaligned cleanup stack entry");
-
- LifetimeExtendedCleanupHeader &Header =
- reinterpret_cast<LifetimeExtendedCleanupHeader&>(
- LifetimeExtendedCleanupStack[I]);
- I += sizeof(Header);
-
- EHStack.pushCopyOfCleanup(Header.getKind(),
- &LifetimeExtendedCleanupStack[I],
- Header.getSize());
- I += Header.getSize();
- }
- LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize);
-}
-
static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF,
EHCleanupScope &Scope) {
assert(Scope.isNormalCleanup());
Modified: cfe/trunk/lib/CodeGen/CGCleanup.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.h?rev=183776&r1=183775&r2=183776&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCleanup.h (original)
+++ cfe/trunk/lib/CodeGen/CGCleanup.h Tue Jun 11 14:14:25 2013
@@ -374,11 +374,6 @@ public:
return new (Buffer) T(N, a0, a1, a2);
}
- void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) {
- void *Buffer = pushCleanup(Kind, Size);
- std::memcpy(Buffer, Cleanup, Size);
- }
-
/// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp.
void popCleanup();
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=183776&r1=183775&r2=183776&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Tue Jun 11 14:14:25 2013
@@ -1340,26 +1340,6 @@ void CodeGenFunction::pushDestroy(Cleanu
destroyer, useEHCleanupForArray);
}
-void CodeGenFunction::pushLifetimeExtendedDestroy(
- CleanupKind cleanupKind, llvm::Value *addr, QualType type,
- Destroyer *destroyer, bool useEHCleanupForArray) {
- assert(!isInConditionalBranch() &&
- "performing lifetime extension from within conditional");
-
- // Push an EH-only cleanup for the object now.
- // FIXME: When popping normal cleanups, we need to keep this EH cleanup
- // around in case a temporary's destructor throws an exception.
- if (cleanupKind & EHCleanup)
- EHStack.pushCleanup<DestroyObject>(
- static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), addr, type,
- destroyer, useEHCleanupForArray);
-
- // Remember that we need to push a full cleanup for the object at the
- // end of the full-expression.
- pushCleanupAfterFullExpr<DestroyObject>(
- cleanupKind, addr, type, destroyer, useEHCleanupForArray);
-}
-
/// emitDestroy - Immediately perform the destruction of the given
/// object.
///
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=183776&r1=183775&r2=183776&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Jun 11 14:14:25 2013
@@ -171,164 +171,66 @@ void CodeGenFunction::EmitAnyExprToMem(c
llvm_unreachable("bad evaluation kind");
}
-static void
-pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
- const Expr *E, llvm::Value *ReferenceTemporary) {
- // 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.
- //
- // FIXME: This should be looking at E, not M.
- if (CGF.getLangOpts().ObjCAutoRefCount &&
- M->getType()->isObjCLifetimeType()) {
- QualType ObjCARCReferenceLifetimeType = M->getType();
- switch (Qualifiers::ObjCLifetime Lifetime =
- ObjCARCReferenceLifetimeType.getObjCLifetime()) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- // Carry on to normal cleanup handling.
- break;
-
- case Qualifiers::OCL_Autoreleasing:
- // Nothing to do; cleaned up by an autorelease pool.
- return;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- switch (StorageDuration Duration = M->getStorageDuration()) {
- case SD_Static:
- // Note: we intentionally do not register a cleanup to release
- // the object on program termination.
- return;
-
- case SD_Thread:
- // FIXME: We should probably register a cleanup in this case.
- return;
-
- case SD_Automatic:
- case SD_FullExpression:
- assert(!ObjCARCReferenceLifetimeType->isArrayType());
- CodeGenFunction::Destroyer *Destroy;
- CleanupKind CleanupKind;
- if (Lifetime == Qualifiers::OCL_Strong) {
- const ValueDecl *VD = M->getExtendingDecl();
- bool Precise =
- VD && isa<VarDecl>(VD) && VD->hasAttr<ObjCPreciseLifetimeAttr>();
- CleanupKind = CGF.getARCCleanupKind();
- Destroy = Precise ? &CodeGenFunction::destroyARCStrongPrecise
- : &CodeGenFunction::destroyARCStrongImprecise;
- } else {
- // __weak objects always get EH cleanups; otherwise, exceptions
- // could cause really nasty crashes instead of mere leaks.
- CleanupKind = NormalAndEHCleanup;
- Destroy = &CodeGenFunction::destroyARCWeak;
- }
- if (Duration == SD_FullExpression)
- CGF.pushDestroy(CleanupKind, ReferenceTemporary,
- ObjCARCReferenceLifetimeType, *Destroy,
- CleanupKind & EHCleanup);
- else
- CGF.pushLifetimeExtendedDestroy(CleanupKind, ReferenceTemporary,
- ObjCARCReferenceLifetimeType,
- *Destroy, CleanupKind & EHCleanup);
- return;
-
- case SD_Dynamic:
- llvm_unreachable("temporary cannot have dynamic storage duration");
- }
- llvm_unreachable("unknown storage duration");
- }
- }
-
- if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
- if (ILE->initializesStdInitializerList()) {
- // FIXME: This is wrong if the temporary has static or thread storage
- // duration.
- CGF.EmitStdInitializerListCleanup(ReferenceTemporary, ILE);
- return;
- }
- }
-
- CXXDestructorDecl *ReferenceTemporaryDtor = 0;
- if (const RecordType *RT =
- E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
- // Get the destructor for the reference temporary.
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (!ClassDecl->hasTrivialDestructor())
- ReferenceTemporaryDtor = ClassDecl->getDestructor();
- }
-
- if (!ReferenceTemporaryDtor)
- return;
-
- // Call the destructor for the temporary.
- switch (M->getStorageDuration()) {
- case SD_Static:
- case SD_Thread: {
- llvm::Constant *CleanupFn;
- llvm::Constant *CleanupArg;
- if (E->getType()->isArrayType()) {
- CleanupFn = CodeGenFunction(CGF.CGM).generateDestroyHelper(
- cast<llvm::Constant>(ReferenceTemporary), E->getType(),
- CodeGenFunction::destroyCXXObject, CGF.getLangOpts().Exceptions);
- CleanupArg = llvm::Constant::getNullValue(CGF.Int8PtrTy);
- } else {
- CleanupFn =
- CGF.CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
- CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
+static llvm::Value *
+CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type,
+ const NamedDecl *InitializedDecl) {
+ if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
+ if (VD->hasGlobalStorage()) {
+ SmallString<256> Name;
+ llvm::raw_svector_ostream Out(Name);
+ CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
+ Out.flush();
+
+ llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type);
+
+ // Create the reference temporary.
+ llvm::GlobalVariable *RefTemp =
+ new llvm::GlobalVariable(CGF.CGM.getModule(),
+ RefTempTy, /*isConstant=*/false,
+ llvm::GlobalValue::InternalLinkage,
+ llvm::Constant::getNullValue(RefTempTy),
+ Name.str());
+ // If we're binding to a thread_local variable, the temporary is also
+ // thread local.
+ if (VD->getTLSKind())
+ CGF.CGM.setTLSMode(RefTemp, *VD);
+ return RefTemp;
}
- CGF.CGM.getCXXABI().registerGlobalDtor(
- CGF, *cast<VarDecl>(M->getExtendingDecl()), CleanupFn, CleanupArg);
- break;
- }
-
- case SD_FullExpression:
- CGF.pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
- CodeGenFunction::destroyCXXObject,
- CGF.getLangOpts().Exceptions);
- break;
-
- case SD_Automatic:
- CGF.pushLifetimeExtendedDestroy(NormalAndEHCleanup,
- ReferenceTemporary, E->getType(),
- CodeGenFunction::destroyCXXObject,
- CGF.getLangOpts().Exceptions);
- break;
-
- case SD_Dynamic:
- llvm_unreachable("temporary cannot have dynamic storage duration");
}
-}
-
-static llvm::Value *
-createReferenceTemporary(CodeGenFunction &CGF,
- const MaterializeTemporaryExpr *M, const Expr *Inner) {
- switch (M->getStorageDuration()) {
- case SD_FullExpression:
- case SD_Automatic:
- return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");
-
- case SD_Thread:
- case SD_Static:
- return CGF.CGM.GetAddrOfGlobalTemporary(M, Inner);
- case SD_Dynamic:
- llvm_unreachable("temporary can't have dynamic storage duration");
- }
- llvm_unreachable("unknown storage duration");
+ return CGF.CreateMemTemp(Type, "ref.tmp");
}
static llvm::Value *
-emitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
+EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *&ReferenceTemporary,
+ const CXXDestructorDecl *&ReferenceTemporaryDtor,
+ const InitListExpr *&ReferenceInitializerList,
+ QualType &ObjCARCReferenceLifetimeType,
const NamedDecl *InitializedDecl) {
+ const MaterializeTemporaryExpr *M = NULL;
+ E = E->findMaterializedTemporary(M);
+ // 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 (M && CGF.getLangOpts().ObjCAutoRefCount &&
+ M->getType()->isObjCLifetimeType() &&
+ (M->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
+ M->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
+ M->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))
+ ObjCARCReferenceLifetimeType = M->getType();
+
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) {
CGF.enterFullExpression(EWC);
CodeGenFunction::RunCleanupsScope Scope(CGF);
- return emitExprForReferenceBinding(CGF, EWC->getSubExpr(), InitializedDecl);
- }
- const MaterializeTemporaryExpr *M = 0;
- E = E->findMaterializedTemporary(M);
+ return EmitExprForReferenceBinding(CGF, EWC->getSubExpr(),
+ ReferenceTemporary,
+ ReferenceTemporaryDtor,
+ ReferenceInitializerList,
+ ObjCARCReferenceLifetimeType,
+ InitializedDecl);
+ }
if (E->isGLValue()) {
// Emit the expression as an lvalue.
@@ -336,22 +238,61 @@ emitExprForReferenceBinding(CodeGenFunct
assert(LV.isSimple());
return LV.getAddress();
}
-
- assert(M && "prvalue reference initializer but not a materialized temporary");
-
- if (CGF.getLangOpts().ObjCAutoRefCount &&
- M->getType()->isObjCLifetimeType() &&
- M->getType().getObjCLifetime() != Qualifiers::OCL_None &&
- M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
- // FIXME: Fold this into the general case below.
- llvm::Value *Object = createReferenceTemporary(CGF, M, E);
- LValue RefTempDst = CGF.MakeAddrLValue(Object, M->getType());
+
+ 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);
-
- pushTemporaryCleanup(CGF, M, E, Object);
- return Object;
+
+ 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: {
+ assert(!ObjCARCReferenceLifetimeType->isArrayType());
+ CleanupKind cleanupKind = CGF.getARCCleanupKind();
+ CGF.pushDestroy(cleanupKind,
+ ReferenceTemporary,
+ ObjCARCReferenceLifetimeType,
+ CodeGenFunction::destroyARCStrongImprecise,
+ cleanupKind & EHCleanup);
+ break;
+ }
+
+ case Qualifiers::OCL_Weak:
+ assert(!ObjCARCReferenceLifetimeType->isArrayType());
+ CGF.pushDestroy(NormalAndEHCleanup,
+ ReferenceTemporary,
+ ObjCARCReferenceLifetimeType,
+ CodeGenFunction::destroyARCWeak,
+ /*useEHCleanupForArray*/ true);
+ break;
+ }
+
+ ObjCARCReferenceLifetimeType = QualType();
+ }
+
+ return ReferenceTemporary;
}
SmallVector<const Expr *, 2> CommaLHSs;
@@ -361,59 +302,112 @@ emitExprForReferenceBinding(CodeGenFunct
for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
CGF.EmitIgnoredExpr(CommaLHSs[I]);
- if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) {
- if (opaque->getType()->isRecordType()) {
- assert(Adjustments.empty());
+ if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))
+ if (opaque->getType()->isRecordType())
return CGF.EmitOpaqueValueLValue(opaque).getAddress();
+
+ // Create a reference temporary if necessary.
+ AggValueSlot AggSlot = AggValueSlot::ignored();
+ if (CGF.hasAggregateEvaluationKind(E->getType())) {
+ ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
+ InitializedDecl);
+ CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType());
+ AggValueSlot::IsDestructed_t isDestructed
+ = AggValueSlot::IsDestructed_t(InitializedDecl != 0);
+ AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment,
+ Qualifiers(), isDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+ }
+
+ if (InitializedDecl) {
+ if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->initializesStdInitializerList()) {
+ ReferenceInitializerList = ILE;
+ }
+ }
+ else if (const RecordType *RT =
+ E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()){
+ // Get the destructor for the reference temporary.
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (!ClassDecl->hasTrivialDestructor())
+ ReferenceTemporaryDtor = ClassDecl->getDestructor();
}
}
- // Create and initialize the reference temporary.
- llvm::Value *Object = createReferenceTemporary(CGF, M, E);
- CGF.EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
- pushTemporaryCleanup(CGF, M, E, Object);
-
- // Perform derived-to-base casts and/or field accesses, to get from the
- // temporary object we created (and, potentially, for which we extended
- // the lifetime) to the subobject we're binding the reference to.
- for (unsigned I = Adjustments.size(); I != 0; --I) {
- SubobjectAdjustment &Adjustment = Adjustments[I-1];
- switch (Adjustment.Kind) {
- case SubobjectAdjustment::DerivedToBaseAdjustment:
- Object =
- CGF.GetAddressOfBaseClass(Object,
- Adjustment.DerivedToBase.DerivedClass,
- Adjustment.DerivedToBase.BasePath->path_begin(),
- Adjustment.DerivedToBase.BasePath->path_end(),
- /*NullCheckValue=*/false);
- break;
+ RValue RV = CGF.EmitAnyExpr(E, AggSlot);
- case SubobjectAdjustment::FieldAdjustment: {
- LValue LV = CGF.MakeAddrLValue(Object, E->getType());
- LV = CGF.EmitLValueForField(LV, Adjustment.Field);
- assert(LV.isSimple() &&
- "materialized temporary field is not a simple lvalue");
- Object = LV.getAddress();
- break;
- }
+ // FIXME: This is wrong. We need to register the destructor for the temporary
+ // now, *before* we perform the adjustments, because in the case of a
+ // pointer-to-member adjustment, the adjustment might throw.
+
+ // Check if need to perform derived-to-base casts and/or field accesses, to
+ // get from the temporary object we created (and, potentially, for which we
+ // extended the lifetime) to the subobject we're binding the reference to.
+ if (!Adjustments.empty()) {
+ llvm::Value *Object = RV.getAggregateAddr();
+ for (unsigned I = Adjustments.size(); I != 0; --I) {
+ SubobjectAdjustment &Adjustment = Adjustments[I-1];
+ switch (Adjustment.Kind) {
+ case SubobjectAdjustment::DerivedToBaseAdjustment:
+ Object =
+ CGF.GetAddressOfBaseClass(Object,
+ Adjustment.DerivedToBase.DerivedClass,
+ Adjustment.DerivedToBase.BasePath->path_begin(),
+ Adjustment.DerivedToBase.BasePath->path_end(),
+ /*NullCheckValue=*/false);
+ break;
+
+ case SubobjectAdjustment::FieldAdjustment: {
+ LValue LV = CGF.MakeAddrLValue(Object, E->getType());
+ LV = CGF.EmitLValueForField(LV, Adjustment.Field);
+ assert(LV.isSimple() &&
+ "materialized temporary field is not a simple lvalue");
+ Object = LV.getAddress();
+ break;
+ }
- case SubobjectAdjustment::MemberPointerAdjustment: {
- llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);
- Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(
- CGF, Object, Ptr, Adjustment.Ptr.MPT);
- break;
- }
+ case SubobjectAdjustment::MemberPointerAdjustment: {
+ llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);
+ Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(
+ CGF, Object, Ptr, Adjustment.Ptr.MPT);
+ break;
+ }
+ }
}
+
+ return Object;
}
- return Object;
+ if (RV.isAggregate())
+ return RV.getAggregateAddr();
+
+ // Create a temporary variable that we can bind the reference to.
+ ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
+ InitializedDecl);
+
+
+ LValue tempLV = CGF.MakeNaturalAlignAddrLValue(ReferenceTemporary,
+ E->getType());
+ if (RV.isScalar())
+ CGF.EmitStoreOfScalar(RV.getScalarVal(), tempLV, /*init*/ true);
+ else
+ CGF.EmitStoreOfComplex(RV.getComplexVal(), tempLV, /*init*/ true);
+ return ReferenceTemporary;
}
RValue
CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
const NamedDecl *InitializedDecl) {
- llvm::Value *Value = emitExprForReferenceBinding(*this, E, InitializedDecl);
-
+ llvm::Value *ReferenceTemporary = 0;
+ const CXXDestructorDecl *ReferenceTemporaryDtor = 0;
+ const InitListExpr *ReferenceInitializerList = 0;
+ QualType ObjCARCReferenceLifetimeType;
+ llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary,
+ ReferenceTemporaryDtor,
+ ReferenceInitializerList,
+ ObjCARCReferenceLifetimeType,
+ InitializedDecl);
if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) {
// C++11 [dcl.ref]p5 (as amended by core issue 453):
// If a glvalue to which a reference is directly bound designates neither
@@ -423,7 +417,80 @@ CodeGenFunction::EmitReferenceBindingToE
QualType Ty = E->getType();
EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty);
}
+ if (!ReferenceTemporaryDtor && !ReferenceInitializerList &&
+ ObjCARCReferenceLifetimeType.isNull())
+ return RValue::get(Value);
+
+ // Make sure to call the destructor for the reference temporary.
+ const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);
+ if (VD && VD->hasGlobalStorage()) {
+ if (ReferenceTemporaryDtor) {
+ llvm::Constant *CleanupFn;
+ llvm::Constant *CleanupArg;
+ if (E->getType()->isArrayType()) {
+ CleanupFn = CodeGenFunction(CGM).generateDestroyHelper(
+ cast<llvm::Constant>(ReferenceTemporary), E->getType(),
+ destroyCXXObject, getLangOpts().Exceptions);
+ CleanupArg = llvm::Constant::getNullValue(Int8PtrTy);
+ } else {
+ CleanupFn =
+ CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
+ CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
+ }
+ CGM.getCXXABI().registerGlobalDtor(*this, *VD, CleanupFn, CleanupArg);
+ } else if (ReferenceInitializerList) {
+ // FIXME: This is wrong. We need to register a global destructor to clean
+ // up the initializer_list object, rather than adding it as a local
+ // cleanup.
+ EmitStdInitializerListCleanup(ReferenceTemporary,
+ ReferenceInitializerList);
+ } else {
+ assert(!ObjCARCReferenceLifetimeType.isNull() && !VD->getTLSKind());
+ // Note: We intentionally do not register a global "destructor" to
+ // release the object.
+ }
+
+ return RValue::get(Value);
+ }
+ if (ReferenceTemporaryDtor) {
+ if (E->getType()->isArrayType())
+ pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
+ destroyCXXObject, getLangOpts().Exceptions);
+ else
+ PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
+ } else if (ReferenceInitializerList) {
+ EmitStdInitializerListCleanup(ReferenceTemporary,
+ ReferenceInitializerList);
+ } else {
+ switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ llvm_unreachable(
+ "Not a reference temporary that needs to be deallocated");
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ // Nothing to do.
+ break;
+
+ case Qualifiers::OCL_Strong: {
+ bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>();
+ CleanupKind cleanupKind = getARCCleanupKind();
+ pushDestroy(cleanupKind, ReferenceTemporary, ObjCARCReferenceLifetimeType,
+ precise ? destroyARCStrongPrecise : destroyARCStrongImprecise,
+ cleanupKind & EHCleanup);
+ break;
+ }
+
+ case Qualifiers::OCL_Weak: {
+ // __weak objects always get EH cleanups; otherwise, exceptions
+ // could cause really nasty crashes instead of mere leaks.
+ pushDestroy(NormalAndEHCleanup, ReferenceTemporary,
+ ObjCARCReferenceLifetimeType, destroyARCWeak, true);
+ break;
+ }
+ }
+ }
+
return RValue::get(Value);
}
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=183776&r1=183775&r2=183776&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Jun 11 14:14:25 2013
@@ -241,18 +241,6 @@ public:
llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;
EHScopeStack EHStack;
- llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;
-
- /// Header for data within LifetimeExtendedCleanupStack.
- struct LifetimeExtendedCleanupHeader {
- /// The size of the following cleanup object.
- size_t Size : 29;
- /// The kind of cleanup to push: a value from the CleanupKind enumeration.
- unsigned Kind : 3;
-
- size_t getSize() const { return Size; }
- CleanupKind getKind() const { return static_cast<CleanupKind>(Kind); }
- };
/// i32s containing the indexes of the cleanup destinations.
llvm::AllocaInst *NormalCleanupDest;
@@ -388,23 +376,6 @@ public:
initFullExprCleanup();
}
- /// \brief Queue a cleanup to be pushed after finishing the current
- /// full-expression.
- template <class T, class A0, class A1, class A2, class A3>
- void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {
- assert(!isInConditionalBranch() && "can't defer conditional cleanup");
-
- LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind };
-
- size_t OldSize = LifetimeExtendedCleanupStack.size();
- LifetimeExtendedCleanupStack.resize(
- LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size);
-
- char *Buffer = &LifetimeExtendedCleanupStack[OldSize];
- new (Buffer) LifetimeExtendedCleanupHeader(Header);
- new (Buffer + sizeof(Header)) T(a0, a1, a2, a3);
- }
-
/// Set up the last cleaup that was pushed as a conditional
/// full-expression cleanup.
void initFullExprCleanup();
@@ -450,7 +421,6 @@ public:
/// will be executed once the scope is exited.
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth;
- size_t LifetimeExtendedCleanupStackSize;
bool OldDidCallStackSave;
protected:
bool PerformCleanup;
@@ -468,8 +438,6 @@ public:
: PerformCleanup(true), CGF(CGF)
{
CleanupStackDepth = CGF.EHStack.stable_begin();
- LifetimeExtendedCleanupStackSize =
- CGF.LifetimeExtendedCleanupStack.size();
OldDidCallStackSave = CGF.DidCallStackSave;
CGF.DidCallStackSave = false;
}
@@ -479,8 +447,7 @@ public:
~RunCleanupsScope() {
if (PerformCleanup) {
CGF.DidCallStackSave = OldDidCallStackSave;
- CGF.PopCleanupBlocks(CleanupStackDepth,
- LifetimeExtendedCleanupStackSize);
+ CGF.PopCleanupBlocks(CleanupStackDepth);
}
}
@@ -494,8 +461,7 @@ public:
void ForceCleanup() {
assert(PerformCleanup && "Already forced cleanup");
CGF.DidCallStackSave = OldDidCallStackSave;
- CGF.PopCleanupBlocks(CleanupStackDepth,
- LifetimeExtendedCleanupStackSize);
+ CGF.PopCleanupBlocks(CleanupStackDepth);
PerformCleanup = false;
}
};
@@ -547,16 +513,10 @@ public:
};
- /// \brief Takes the old cleanup stack size and emits the cleanup blocks
- /// that have been added.
+ /// PopCleanupBlocks - Takes the old cleanup stack size and emits
+ /// the cleanup blocks that have been added.
void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize);
- /// \brief Takes the old cleanup stack size and emits the cleanup blocks
- /// that have been added, then adds all lifetime-extended cleanups from
- /// the given position to the stack.
- void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,
- size_t OldLifetimeExtendedStackSize);
-
void ResolveBranchFixups(llvm::BasicBlock *Target);
/// The given basic block lies in the current EH scope, but may be a
@@ -1028,9 +988,6 @@ public:
llvm::Value *addr, QualType type);
void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray);
- void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr,
- QualType type, Destroyer *destroyer,
- bool useEHCleanupForArray);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
llvm::Function *generateDestroyHelper(llvm::Constant *addr,
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=183776&r1=183775&r2=183776&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Jun 11 14:14:25 2013
@@ -5214,9 +5214,6 @@ static void performLifetimeExtension(Exp
Init = const_cast<Expr *>(
Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
- if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
- Init = BTE->getSubExpr();
-
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
if (ILE->initializesStdInitializerList() || ILE->getType()->isArrayType()) {
// FIXME: If this is an InitListExpr which creates a std::initializer_list
Modified: cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp?rev=183776&r1=183775&r2=183776&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp Tue Jun 11 14:14:25 2013
@@ -35,7 +35,7 @@ int e = V<int>::m;
// CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global
// CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0
-// CHECK: @_ZGRZ8tls_dtorvE1u = private thread_local global
+// CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global
// CHECK: @_ZGVN1VIiE1mE = weak_odr thread_local global i64 0
Modified: cfe/trunk/test/CodeGenCXX/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/temporaries.cpp?rev=183776&r1=183775&r2=183776&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/temporaries.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/temporaries.cpp Tue Jun 11 14:14:25 2013
@@ -584,9 +584,11 @@ namespace BindToSubobject {
// CHECK: call void @_ZN15BindToSubobject1fEv()
// CHECK: call void @_ZN15BindToSubobject1gEv()
// CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1cE)
- // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle)
+ // FIXME: This is wrong. We should emit the call to __cxa_atexit prior to
+ // calling h(), in case h() throws.
// CHECK: call {{.*}} @_ZN15BindToSubobject1hE
// CHECK: getelementptr
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle)
// CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1cE, align 8
int &&c = (f(), (g(), A().*h()));
@@ -596,9 +598,9 @@ namespace BindToSubobject {
};
// CHECK: call void @_ZN15BindToSubobject1BC1Ev({{.*}} @_ZGRN15BindToSubobject1dE)
- // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle)
// CHECK: call {{.*}} @_ZN15BindToSubobject1hE
// CHECK: getelementptr {{.*}} getelementptr
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle)
// CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1dE, align 8
int &&d = (B().a).*h();
}
@@ -609,7 +611,7 @@ namespace Bitfield {
// Do not lifetime extend the S() temporary here.
// CHECK: alloca
// CHECK: call {{.*}}memset
- // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE
+ // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE, align 4
// CHECK: call void @_ZN8Bitfield1SD1
// CHECK: store i32* @_ZGRN8Bitfield1rE, i32** @_ZN8Bitfield1rE, align 8
int &&r = S().a;
@@ -624,91 +626,15 @@ namespace Vector {
};
// CHECK: alloca
// CHECK: extractelement
- // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE
+ // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE,
// CHECK: store i32* @_ZGRN6Vector1rE, i32** @_ZN6Vector1rE,
int &&r = S().v[1];
// CHECK: alloca
// CHECK: extractelement
- // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE
+ // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE,
// CHECK: store i32* @_ZGRN6Vector1sE, i32** @_ZN6Vector1sE,
int &&s = S().w[1];
// FIXME PR16204: The following code leads to an assertion in Sema.
//int &&s = S().w.y;
}
-
-namespace MultipleExtension {
- struct A { A(); ~A(); };
- struct B { B(); ~B(); };
- struct C { C(); ~C(); };
- struct D { D(); ~D(); int n; C c; };
- struct E { const A &a; B b; const C &c; ~E(); };
-
- E &&e1 = { A(), B(), D().c };
-
- // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e1E.*]])
- // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]]
- // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE:_ZGRN17MultipleExtension2e1E.*]], i32 0, i32 0)
-
- // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 1))
-
- // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e1E.*]])
- // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]]
- // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 2)
- // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[TEMPE]]
- // CHECK: store {{.*}} @[[TEMPE]], %"struct.MultipleExtension::E"** @_ZN17MultipleExtension2e1E, align 8
-
- E e2 = { A(), B(), D().c };
-
- // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e2E.*]])
- // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]]
- // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[E:_ZN17MultipleExtension2e2E]], i32 0, i32 0)
-
- // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 1))
-
- // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e2E.*]])
- // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]]
- // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 2)
- // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[E]]
-
-
- void g();
- // CHECK: define void @[[NS:_ZN17MultipleExtension]]1fEv(
- void f() {
- E &&e1 = { A(), B(), D().c };
- // CHECK: %[[TEMPE1_A:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1:.*]], i32 0, i32 0
- // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA1:.*]])
- // CHECK: store {{.*}} %[[TEMPA1]], {{.*}} %[[TEMPE1_A]]
- // CHECK: %[[TEMPE1_B:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 1
- // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE1_B]])
- // CHECK: %[[TEMPE1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 2
- // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD1:.*]])
- // CHECK: %[[TEMPD1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD1]], i32 0, i32 1
- // CHECK: store {{.*}} %[[TEMPD1_C]], {{.*}} %[[TEMPE1_C]]
- // CHECK: store {{.*}} %[[TEMPE1]], {{.*}} %[[E1:.*]]
-
- g();
- // CHECK: call void @[[NS]]1gEv()
-
- E e2 = { A(), B(), D().c };
- // CHECK: %[[TEMPE2_A:.*]] = getelementptr inbounds {{.*}} %[[E2:.*]], i32 0, i32 0
- // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA2:.*]])
- // CHECK: store {{.*}} %[[TEMPA2]], {{.*}} %[[TEMPE2_A]]
- // CHECK: %[[TEMPE2_B:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 1
- // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE2_B]])
- // CHECK: %[[TEMPE2_C:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 2
- // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD2:.*]])
- // CHECK: %[[TEMPD2_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD2]], i32 0, i32 1
- // CHECK: store {{.*}} %[[TEMPD2_C]], {{.*}}* %[[TEMPE2_C]]
-
- g();
- // CHECK: call void @[[NS]]1gEv()
-
- // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[E2]])
- // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD2]])
- // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA2]])
- // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[TEMPE1]])
- // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD1]])
- // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA1]])
- }
-}
More information about the cfe-commits
mailing list