зеркало из https://github.com/microsoft/clang.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128074 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
78951941f3
Коммит
e81ac69c5d
|
@ -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);
|
||||
|
||||
// Emit .cxx_destruct.
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
emitCXXDestructMethod(*this, IMP);
|
||||
}
|
||||
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
|
||||
/// 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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
struct S {
|
||||
S();
|
||||
S(const S&);
|
||||
~S();
|
||||
S& operator= (const S&);
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче