forked from OSchip/llvm-project
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:
parent
8f9a42971e
commit
6a4fa52b37
|
@ -458,20 +458,104 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
|
||||||
FinishFunction();
|
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,
|
void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
|
||||||
ObjCMethodDecl *MD,
|
ObjCMethodDecl *MD,
|
||||||
bool ctor) {
|
bool ctor) {
|
||||||
llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
|
|
||||||
MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
|
MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
|
||||||
StartObjCMethod(MD, IMP->getClassInterface());
|
StartObjCMethod(MD, IMP->getClassInterface());
|
||||||
for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
|
|
||||||
E = IMP->init_end(); B != E; ++B) {
|
// Emit .cxx_construct.
|
||||||
CXXCtorInitializer *Member = (*B);
|
|
||||||
IvarInitializers.push_back(Member);
|
|
||||||
}
|
|
||||||
if (ctor) {
|
if (ctor) {
|
||||||
for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) {
|
llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
|
||||||
CXXCtorInitializer *IvarInit = IvarInitializers[I];
|
for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
|
||||||
|
E = IMP->init_end(); B != E; ++B) {
|
||||||
|
CXXCtorInitializer *IvarInit = (*B);
|
||||||
FieldDecl *Field = IvarInit->getAnyMember();
|
FieldDecl *Field = IvarInit->getAnyMember();
|
||||||
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
|
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
|
||||||
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
|
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
|
||||||
|
@ -484,37 +568,10 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
|
||||||
llvm::Value *SelfAsId =
|
llvm::Value *SelfAsId =
|
||||||
Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
|
Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
|
||||||
EmitReturnOfRValue(RValue::get(SelfAsId), 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);
|
// Emit .cxx_destruct.
|
||||||
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
|
} else {
|
||||||
LoadObjCSelf(), Ivar, 0);
|
emitCXXDestructMethod(*this, IMP);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
FinishFunction();
|
FinishFunction();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
/// EmitObjCIvarInitializations - Emit information for ivar initialization
|
||||||
/// for an implementation.
|
/// for an implementation.
|
||||||
void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
|
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)
|
if (D->getNumIvarInitializers() == 0)
|
||||||
return;
|
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");
|
IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
|
||||||
cxxSelector = getContext().Selectors.getSelector(0, &II);
|
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
|
||||||
// The constructor returns 'self'.
|
// The constructor returns 'self'.
|
||||||
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
|
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
|
||||||
D->getLocation(),
|
D->getLocation(),
|
||||||
D->getLocation(), cxxSelector,
|
D->getLocation(), cxxSelector,
|
||||||
getContext().getObjCIdType(), 0,
|
getContext().getObjCIdType(), 0,
|
||||||
DC, true, false, true, false,
|
D, true, false, true, false,
|
||||||
ObjCMethodDecl::Required);
|
ObjCMethodDecl::Required);
|
||||||
D->addInstanceMethod(CTORMethod);
|
D->addInstanceMethod(CTORMethod);
|
||||||
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
|
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// EmitNamespace - Emit all declarations in a namespace.
|
/// EmitNamespace - Emit all declarations in a namespace.
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
|
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
|
||||||
// CHECK: -[A .cxx_construct]
|
// CHECK: -[A .cxx_construct]
|
||||||
// CHECK: -[A .cxx_destruct]
|
// CHECK: -[A .cxx_destruct]
|
||||||
|
// CHECK: -[B .cxx_construct]
|
||||||
|
// CHECK-NOT: -[B .cxx_destruct]
|
||||||
|
// CHECK-NOT: -[C .cxx_construct]
|
||||||
|
// CHECK: -[C .cxx_destruct]
|
||||||
|
|
||||||
@interface NSObject
|
@interface NSObject
|
||||||
- alloc;
|
- alloc;
|
||||||
|
@ -84,3 +88,17 @@ public:
|
||||||
@implementation I
|
@implementation I
|
||||||
@synthesize position;
|
@synthesize position;
|
||||||
@end
|
@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
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
struct S {
|
struct S {
|
||||||
S();
|
S();
|
||||||
S(const S&);
|
S(const S&);
|
||||||
|
~S();
|
||||||
S& operator= (const S&);
|
S& operator= (const S&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue