Use function pointers, rather than references, to pass Destroyers

around, in the process cleaning up the various gcc/msvc compiler
workarounds.

llvm-svn: 149036
This commit is contained in:
Peter Collingbourne 2012-01-26 03:33:36 +00:00
parent e67bb67a9b
commit 1425b4556a
8 changed files with 41 additions and 55 deletions

View File

@ -535,9 +535,9 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
// Block captures count as local values and have imprecise semantics. // Block captures count as local values and have imprecise semantics.
// They also can't be arrays, so need to worry about that. // They also can't be arrays, so need to worry about that.
if (dtorKind == QualType::DK_objc_strong_lifetime) { if (dtorKind == QualType::DK_objc_strong_lifetime) {
destroyer = &CodeGenFunction::destroyARCStrongImprecise; destroyer = CodeGenFunction::destroyARCStrongImprecise;
} else { } else {
destroyer = &CGF.getDestroyer(dtorKind); destroyer = CGF.getDestroyer(dtorKind);
} }
// GEP down to the address. // GEP down to the address.
@ -554,7 +554,7 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
cleanupKind = InactiveNormalAndEHCleanup; cleanupKind = InactiveNormalAndEHCleanup;
CGF.pushDestroy(cleanupKind, addr, variable->getType(), CGF.pushDestroy(cleanupKind, addr, variable->getType(),
*destroyer, useArrayEHCleanup); destroyer, useArrayEHCleanup);
// Remember where that cleanup was. // Remember where that cleanup was.
capture.setCleanup(CGF.EHStack.stable_begin()); capture.setCleanup(CGF.EHStack.stable_begin());

View File

@ -945,13 +945,13 @@ namespace {
class DestroyField : public EHScopeStack::Cleanup { class DestroyField : public EHScopeStack::Cleanup {
const FieldDecl *field; const FieldDecl *field;
CodeGenFunction::Destroyer &destroyer; CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray; bool useEHCleanupForArray;
public: public:
DestroyField(const FieldDecl *field, CodeGenFunction::Destroyer *destroyer, DestroyField(const FieldDecl *field, CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray) bool useEHCleanupForArray)
: field(field), destroyer(*destroyer), : field(field), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {} useEHCleanupForArray(useEHCleanupForArray) {}
void Emit(CodeGenFunction &CGF, Flags flags) { void Emit(CodeGenFunction &CGF, Flags flags) {

View File

@ -1098,8 +1098,6 @@ llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() {
void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary, void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
QualType TempType, QualType TempType,
llvm::Value *Ptr) { llvm::Value *Ptr) {
// This local is a GCC and MSVC compiler workaround. pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
Destroyer *destroyer = &destroyCXXObject;
pushDestroy(NormalAndEHCleanup, Ptr, TempType, *destroyer,
/*useEHCleanup*/ true); /*useEHCleanup*/ true);
} }

View File

@ -310,12 +310,12 @@ namespace {
DestroyObject(llvm::Value *addr, QualType type, DestroyObject(llvm::Value *addr, QualType type,
CodeGenFunction::Destroyer *destroyer, CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray) bool useEHCleanupForArray)
: addr(addr), type(type), destroyer(*destroyer), : addr(addr), type(type), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {} useEHCleanupForArray(useEHCleanupForArray) {}
llvm::Value *addr; llvm::Value *addr;
QualType type; QualType type;
CodeGenFunction::Destroyer &destroyer; CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray; bool useEHCleanupForArray;
void Emit(CodeGenFunction &CGF, Flags flags) { void Emit(CodeGenFunction &CGF, Flags flags) {
@ -430,7 +430,7 @@ static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
break; break;
case Qualifiers::OCL_Strong: { case Qualifiers::OCL_Strong: {
CodeGenFunction::Destroyer &destroyer = CodeGenFunction::Destroyer *destroyer =
(var.hasAttr<ObjCPreciseLifetimeAttr>() (var.hasAttr<ObjCPreciseLifetimeAttr>()
? CodeGenFunction::destroyARCStrongPrecise ? CodeGenFunction::destroyARCStrongPrecise
: CodeGenFunction::destroyARCStrongImprecise); : CodeGenFunction::destroyARCStrongImprecise);
@ -1111,7 +1111,7 @@ void CodeGenFunction::emitAutoVarTypeCleanup(
} }
// If we haven't chosen a more specific destroyer, use the default. // If we haven't chosen a more specific destroyer, use the default.
if (!destroyer) destroyer = &getDestroyer(dtorKind); if (!destroyer) destroyer = getDestroyer(dtorKind);
// Use an EH cleanup in array destructors iff the destructor itself // Use an EH cleanup in array destructors iff the destructor itself
// is being pushed as an EH cleanup. // is being pushed as an EH cleanup.
@ -1155,25 +1155,17 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
enterByrefCleanup(emission); enterByrefCleanup(emission);
} }
CodeGenFunction::Destroyer & CodeGenFunction::Destroyer *
CodeGenFunction::getDestroyer(QualType::DestructionKind kind) { CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
// This is surprisingly compiler-dependent. GCC 4.2 can't bind
// references to functions directly in returns, and using '*&foo'
// confuses MSVC. Luckily, the following code pattern works in both.
Destroyer *destroyer = 0;
switch (kind) { switch (kind) {
case QualType::DK_none: llvm_unreachable("no destroyer for trivial dtor"); case QualType::DK_none: llvm_unreachable("no destroyer for trivial dtor");
case QualType::DK_cxx_destructor: case QualType::DK_cxx_destructor:
destroyer = &destroyCXXObject; return destroyCXXObject;
break;
case QualType::DK_objc_strong_lifetime: case QualType::DK_objc_strong_lifetime:
destroyer = &destroyARCStrongPrecise; return destroyARCStrongPrecise;
break;
case QualType::DK_objc_weak_lifetime: case QualType::DK_objc_weak_lifetime:
destroyer = &destroyARCWeak; return destroyARCWeak;
break;
} }
return *destroyer;
} }
/// pushDestroy - Push the standard destructor for the given type. /// pushDestroy - Push the standard destructor for the given type.
@ -1187,7 +1179,7 @@ void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
} }
void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr, void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
QualType type, Destroyer &destroyer, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray) { bool useEHCleanupForArray) {
pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type,
destroyer, useEHCleanupForArray); destroyer, useEHCleanupForArray);
@ -1205,7 +1197,7 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
/// used when destroying array elements, in case one of the /// used when destroying array elements, in case one of the
/// destructions throws an exception /// destructions throws an exception
void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type, void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type,
Destroyer &destroyer, Destroyer *destroyer,
bool useEHCleanupForArray) { bool useEHCleanupForArray) {
const ArrayType *arrayType = getContext().getAsArrayType(type); const ArrayType *arrayType = getContext().getAsArrayType(type);
if (!arrayType) if (!arrayType)
@ -1242,7 +1234,7 @@ void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type,
void CodeGenFunction::emitArrayDestroy(llvm::Value *begin, void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
llvm::Value *end, llvm::Value *end,
QualType type, QualType type,
Destroyer &destroyer, Destroyer *destroyer,
bool checkZeroLength, bool checkZeroLength,
bool useEHCleanup) { bool useEHCleanup) {
assert(!type->isArrayType()); assert(!type->isArrayType());
@ -1293,7 +1285,7 @@ void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
static void emitPartialArrayDestroy(CodeGenFunction &CGF, static void emitPartialArrayDestroy(CodeGenFunction &CGF,
llvm::Value *begin, llvm::Value *end, llvm::Value *begin, llvm::Value *end,
QualType type, QualType type,
CodeGenFunction::Destroyer &destroyer) { CodeGenFunction::Destroyer *destroyer) {
// If the element type is itself an array, drill down. // If the element type is itself an array, drill down.
unsigned arrayDepth = 0; unsigned arrayDepth = 0;
while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) { while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) {
@ -1326,13 +1318,13 @@ namespace {
llvm::Value *ArrayBegin; llvm::Value *ArrayBegin;
llvm::Value *ArrayEnd; llvm::Value *ArrayEnd;
QualType ElementType; QualType ElementType;
CodeGenFunction::Destroyer &Destroyer; CodeGenFunction::Destroyer *Destroyer;
public: public:
RegularPartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEnd, RegularPartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEnd,
QualType elementType, QualType elementType,
CodeGenFunction::Destroyer *destroyer) CodeGenFunction::Destroyer *destroyer)
: ArrayBegin(arrayBegin), ArrayEnd(arrayEnd), : ArrayBegin(arrayBegin), ArrayEnd(arrayEnd),
ElementType(elementType), Destroyer(*destroyer) {} ElementType(elementType), Destroyer(destroyer) {}
void Emit(CodeGenFunction &CGF, Flags flags) { void Emit(CodeGenFunction &CGF, Flags flags) {
emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd, emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd,
@ -1347,14 +1339,14 @@ namespace {
llvm::Value *ArrayBegin; llvm::Value *ArrayBegin;
llvm::Value *ArrayEndPointer; llvm::Value *ArrayEndPointer;
QualType ElementType; QualType ElementType;
CodeGenFunction::Destroyer &Destroyer; CodeGenFunction::Destroyer *Destroyer;
public: public:
IrregularPartialArrayDestroy(llvm::Value *arrayBegin, IrregularPartialArrayDestroy(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer, llvm::Value *arrayEndPointer,
QualType elementType, QualType elementType,
CodeGenFunction::Destroyer *destroyer) CodeGenFunction::Destroyer *destroyer)
: ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer), : ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer),
ElementType(elementType), Destroyer(*destroyer) {} ElementType(elementType), Destroyer(destroyer) {}
void Emit(CodeGenFunction &CGF, Flags flags) { void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer); llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer);
@ -1377,10 +1369,10 @@ namespace {
void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin, void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer, llvm::Value *arrayEndPointer,
QualType elementType, QualType elementType,
Destroyer &destroyer) { Destroyer *destroyer) {
pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup, pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEndPointer, arrayBegin, arrayEndPointer,
elementType, &destroyer); elementType, destroyer);
} }
/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy /// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
@ -1396,10 +1388,10 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin, void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEnd, llvm::Value *arrayEnd,
QualType elementType, QualType elementType,
Destroyer &destroyer) { Destroyer *destroyer) {
pushFullExprCleanup<RegularPartialArrayDestroy>(EHCleanup, pushFullExprCleanup<RegularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEnd, arrayBegin, arrayEnd,
elementType, &destroyer); elementType, destroyer);
} }
namespace { namespace {

View File

@ -343,7 +343,7 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
llvm::Function * llvm::Function *
CodeGenFunction::generateDestroyHelper(llvm::Constant *addr, CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
QualType type, QualType type,
Destroyer &destroyer, Destroyer *destroyer,
bool useEHCleanupForArray) { bool useEHCleanupForArray) {
FunctionArgList args; FunctionArgList args;
ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy); ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy);

View File

@ -487,21 +487,17 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
case Qualifiers::OCL_Strong: { case Qualifiers::OCL_Strong: {
bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>(); bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>();
CleanupKind cleanupKind = getARCCleanupKind(); CleanupKind cleanupKind = getARCCleanupKind();
// This local is a GCC and MSVC compiler workaround.
Destroyer *destroyer = precise ? &destroyARCStrongPrecise :
&destroyARCStrongImprecise;
pushDestroy(cleanupKind, ReferenceTemporary, ObjCARCReferenceLifetimeType, pushDestroy(cleanupKind, ReferenceTemporary, ObjCARCReferenceLifetimeType,
*destroyer, cleanupKind & EHCleanup); precise ? destroyARCStrongPrecise : destroyARCStrongImprecise,
cleanupKind & EHCleanup);
break; break;
} }
case Qualifiers::OCL_Weak: { case Qualifiers::OCL_Weak: {
// This local is a GCC and MSVC compiler workaround.
Destroyer *destroyer = &destroyARCWeak;
// __weak objects always get EH cleanups; otherwise, exceptions // __weak objects always get EH cleanups; otherwise, exceptions
// could cause really nasty crashes instead of mere leaks. // could cause really nasty crashes instead of mere leaks.
pushDestroy(NormalAndEHCleanup, ReferenceTemporary, pushDestroy(NormalAndEHCleanup, ReferenceTemporary,
ObjCARCReferenceLifetimeType, *destroyer, true); ObjCARCReferenceLifetimeType, destroyARCWeak, true);
break; break;
} }
} }

View File

@ -1047,13 +1047,13 @@ namespace {
private: private:
llvm::Value *addr; llvm::Value *addr;
const ObjCIvarDecl *ivar; const ObjCIvarDecl *ivar;
CodeGenFunction::Destroyer &destroyer; CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray; bool useEHCleanupForArray;
public: public:
DestroyIvar(llvm::Value *addr, const ObjCIvarDecl *ivar, DestroyIvar(llvm::Value *addr, const ObjCIvarDecl *ivar,
CodeGenFunction::Destroyer *destroyer, CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray) bool useEHCleanupForArray)
: addr(addr), ivar(ivar), destroyer(*destroyer), : addr(addr), ivar(ivar), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {} useEHCleanupForArray(useEHCleanupForArray) {}
void Emit(CodeGenFunction &CGF, Flags flags) { void Emit(CodeGenFunction &CGF, Flags flags) {
@ -1093,11 +1093,11 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF,
// Use a call to objc_storeStrong to destroy strong ivars, for the // Use a call to objc_storeStrong to destroy strong ivars, for the
// general benefit of the tools. // general benefit of the tools.
if (dtorKind == QualType::DK_objc_strong_lifetime) { if (dtorKind == QualType::DK_objc_strong_lifetime) {
destroyer = &destroyARCStrongWithStore; destroyer = destroyARCStrongWithStore;
// Otherwise use the default for the destruction kind. // Otherwise use the default for the destruction kind.
} else { } else {
destroyer = &CGF.getDestroyer(dtorKind); destroyer = CGF.getDestroyer(dtorKind);
} }
CleanupKind cleanupKind = CGF.getCleanupKind(dtorKind); CleanupKind cleanupKind = CGF.getCleanupKind(dtorKind);

View File

@ -1244,27 +1244,27 @@ public:
void pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin, void pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer, llvm::Value *arrayEndPointer,
QualType elementType, QualType elementType,
Destroyer &destroyer); Destroyer *destroyer);
void pushRegularPartialArrayCleanup(llvm::Value *arrayBegin, void pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEnd, llvm::Value *arrayEnd,
QualType elementType, QualType elementType,
Destroyer &destroyer); Destroyer *destroyer);
void pushDestroy(QualType::DestructionKind dtorKind, void pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type); llvm::Value *addr, QualType type);
void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type, void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
Destroyer &destroyer, bool useEHCleanupForArray); Destroyer *destroyer, bool useEHCleanupForArray);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer &destroyer, void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray); bool useEHCleanupForArray);
llvm::Function *generateDestroyHelper(llvm::Constant *addr, llvm::Function *generateDestroyHelper(llvm::Constant *addr,
QualType type, QualType type,
Destroyer &destroyer, Destroyer *destroyer,
bool useEHCleanupForArray); bool useEHCleanupForArray);
void emitArrayDestroy(llvm::Value *begin, llvm::Value *end, void emitArrayDestroy(llvm::Value *begin, llvm::Value *end,
QualType type, Destroyer &destroyer, QualType type, Destroyer *destroyer,
bool checkZeroLength, bool useEHCleanup); bool checkZeroLength, bool useEHCleanup);
Destroyer &getDestroyer(QualType::DestructionKind destructionKind); Destroyer *getDestroyer(QualType::DestructionKind destructionKind);
/// Determines whether an EH cleanup is required to destroy a type /// Determines whether an EH cleanup is required to destroy a type
/// with the given destruction kind. /// with the given destruction kind.