The emission of an Objective-C++'s class .cxx_destruct method should be

conditioned on whether it has any destructible ivars, not on whether
it has any non-trivial class-object initializers.

llvm-svn: 128074
This commit is contained in:
John McCall 2011-03-22 07:05:39 +00:00
parent 8f9a42971e
commit 6a4fa52b37
4 changed files with 142 additions and 55 deletions

View File

@ -458,20 +458,104 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
FinishFunction();
}
// FIXME: these are stolen from CGClass.cpp, which is lame.
namespace {
struct CallArrayIvarDtor : EHScopeStack::Cleanup {
const ObjCIvarDecl *ivar;
llvm::Value *self;
CallArrayIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self)
: ivar(ivar), self(self) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
LValue lvalue =
CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0);
QualType type = ivar->getType();
const ConstantArrayType *arrayType
= CGF.getContext().getAsConstantArrayType(type);
QualType baseType = CGF.getContext().getBaseElementType(arrayType);
const CXXRecordDecl *classDecl = baseType->getAsCXXRecordDecl();
llvm::Value *base
= CGF.Builder.CreateBitCast(lvalue.getAddress(),
CGF.ConvertType(baseType)->getPointerTo());
CGF.EmitCXXAggrDestructorCall(classDecl->getDestructor(),
arrayType, base);
}
};
struct CallIvarDtor : EHScopeStack::Cleanup {
const ObjCIvarDecl *ivar;
llvm::Value *self;
CallIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self)
: ivar(ivar), self(self) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
LValue lvalue =
CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0);
QualType type = ivar->getType();
const CXXRecordDecl *classDecl = type->getAsCXXRecordDecl();
CGF.EmitCXXDestructorCall(classDecl->getDestructor(),
Dtor_Complete, /*ForVirtualBase=*/false,
lvalue.getAddress());
}
};
}
static void emitCXXDestructMethod(CodeGenFunction &CGF,
ObjCImplementationDecl *impl) {
CodeGenFunction::RunCleanupsScope scope(CGF);
llvm::Value *self = CGF.LoadObjCSelf();
ObjCInterfaceDecl *iface
= const_cast<ObjCInterfaceDecl*>(impl->getClassInterface());
for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
ivar; ivar = ivar->getNextIvar()) {
QualType type = ivar->getType();
// Drill down to the base element type.
QualType baseType = type;
const ConstantArrayType *arrayType =
CGF.getContext().getAsConstantArrayType(baseType);
if (arrayType) baseType = CGF.getContext().getBaseElementType(arrayType);
// Check whether the ivar is a destructible type.
QualType::DestructionKind destructKind = baseType.isDestructedType();
assert(destructKind == type.isDestructedType());
switch (destructKind) {
case QualType::DK_none:
continue;
case QualType::DK_cxx_destructor:
if (arrayType)
CGF.EHStack.pushCleanup<CallArrayIvarDtor>(NormalAndEHCleanup,
ivar, self);
else
CGF.EHStack.pushCleanup<CallIvarDtor>(NormalAndEHCleanup,
ivar, self);
break;
}
}
assert(scope.requiresCleanups() && "nothing to do in .cxx_destruct?");
}
void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCMethodDecl *MD,
bool ctor) {
llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
StartObjCMethod(MD, IMP->getClassInterface());
for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
E = IMP->init_end(); B != E; ++B) {
CXXCtorInitializer *Member = (*B);
IvarInitializers.push_back(Member);
}
// Emit .cxx_construct.
if (ctor) {
for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) {
CXXCtorInitializer *IvarInit = IvarInitializers[I];
llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
E = IMP->init_end(); B != E; ++B) {
CXXCtorInitializer *IvarInit = (*B);
FieldDecl *Field = IvarInit->getAnyMember();
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
@ -484,37 +568,10 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
llvm::Value *SelfAsId =
Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
EmitReturnOfRValue(RValue::get(SelfAsId), IdTy);
} else {
// dtor
for (size_t i = IvarInitializers.size(); i > 0; --i) {
FieldDecl *Field = IvarInitializers[i - 1]->getAnyMember();
QualType FieldType = Field->getType();
const ConstantArrayType *Array =
getContext().getAsConstantArrayType(FieldType);
if (Array)
FieldType = getContext().getBaseElementType(FieldType);
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
LoadObjCSelf(), Ivar, 0);
const RecordType *RT = FieldType->getAs<RecordType>();
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor();
if (!Dtor->isTrivial()) {
if (Array) {
const llvm::Type *BasePtr = ConvertType(FieldType);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(LV.getAddress(), BasePtr);
EmitCXXAggrDestructorCall(Dtor,
Array, BaseAddrPtr);
} else {
EmitCXXDestructorCall(Dtor,
Dtor_Complete, /*ForVirtualBase=*/false,
LV.getAddress());
}
}
}
// Emit .cxx_destruct.
} else {
emitCXXDestructMethod(*this, IMP);
}
FinishFunction();
}

View File

@ -1937,37 +1937,48 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
}
}
static bool needsDestructMethod(ObjCImplementationDecl *impl) {
ObjCInterfaceDecl *iface
= const_cast<ObjCInterfaceDecl*>(impl->getClassInterface());
for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
ivar; ivar = ivar->getNextIvar())
if (ivar->getType().isDestructedType())
return true;
return false;
}
/// EmitObjCIvarInitializations - Emit information for ivar initialization
/// for an implementation.
void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
// We might need a .cxx_destruct even if we don't have any ivar initializers.
if (needsDestructMethod(D)) {
IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
ObjCMethodDecl *DTORMethod =
ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
cxxSelector, getContext().VoidTy, 0, D, true,
false, true, false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
}
// If the implementation doesn't have any ivar initializers, we don't need
// a .cxx_construct.
if (D->getNumIvarInitializers() == 0)
return;
DeclContext* DC = const_cast<DeclContext*>(dyn_cast<DeclContext>(D));
assert(DC && "EmitObjCIvarInitializations - null DeclContext");
IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(),
D->getLocation(),
D->getLocation(), cxxSelector,
getContext().VoidTy, 0,
DC, true, false, true, false,
ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
II = &getContext().Idents.get(".cxx_construct");
cxxSelector = getContext().Selectors.getSelector(0, &II);
IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
// The constructor returns 'self'.
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
D->getLocation(),
D->getLocation(), cxxSelector,
getContext().getObjCIdType(), 0,
DC, true, false, true, false,
D, true, false, true, false,
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
}
/// EmitNamespace - Emit all declarations in a namespace.

View File

@ -1,6 +1,10 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// CHECK: -[A .cxx_construct]
// CHECK: -[A .cxx_destruct]
// CHECK: -[B .cxx_construct]
// CHECK-NOT: -[B .cxx_destruct]
// CHECK-NOT: -[C .cxx_construct]
// CHECK: -[C .cxx_destruct]
@interface NSObject
- alloc;
@ -84,3 +88,17 @@ public:
@implementation I
@synthesize position;
@end
// This class should have a .cxx_construct but no .cxx_destruct.
namespace test3 { struct S { S(); }; }
@implementation B {
test3::S s;
}
@end
// This class should have a .cxx_destruct but no .cxx_construct.
namespace test4 { struct S { ~S(); }; }
@implementation C {
test4::S s;
}
@end

View File

@ -1,6 +1,7 @@
struct S {
S();
S(const S&);
~S();
S& operator= (const S&);
};