From e81ac69c5da9fadfac33ee76e98d5fb558c4e389 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 22 Mar 2011 07:05:39 +0000 Subject: [PATCH] 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 --- lib/CodeGen/CGObjC.cpp | 133 ++++++++++++++++++++--------- lib/CodeGen/CodeGenModule.cpp | 45 ++++++---- test/CodeGenObjCXX/ivar-objects.mm | 18 ++++ test/PCH/objcxx-ivar-class.h | 1 + 4 files changed, 142 insertions(+), 55 deletions(-) diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 2bfa496625..cf1ff23000 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -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(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(NormalAndEHCleanup, + ivar, self); + else + CGF.EHStack.pushCleanup(NormalAndEHCleanup, + ivar, self); + break; + } + } + + assert(scope.requiresCleanups() && "nothing to do in .cxx_destruct?"); +} + void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, ObjCMethodDecl *MD, bool ctor) { - llvm::SmallVector 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 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(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(Field); - LValue LV = EmitLValueForIvar(TypeOfSelfObject(), - LoadObjCSelf(), Ivar, 0); - const RecordType *RT = FieldType->getAs(); - CXXRecordDecl *FieldClassDecl = cast(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(); } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index ea74abff54..a528d2ede7 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1937,37 +1937,48 @@ void CodeGenModule::EmitObjCPropertyImplementations(const } } +static bool needsDestructMethod(ObjCImplementationDecl *impl) { + ObjCInterfaceDecl *iface + = const_cast(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(dyn_cast(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. diff --git a/test/CodeGenObjCXX/ivar-objects.mm b/test/CodeGenObjCXX/ivar-objects.mm index d0432edf2b..d05763b3fc 100644 --- a/test/CodeGenObjCXX/ivar-objects.mm +++ b/test/CodeGenObjCXX/ivar-objects.mm @@ -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 diff --git a/test/PCH/objcxx-ivar-class.h b/test/PCH/objcxx-ivar-class.h index 50ebda709d..5e5565864d 100644 --- a/test/PCH/objcxx-ivar-class.h +++ b/test/PCH/objcxx-ivar-class.h @@ -1,6 +1,7 @@ struct S { S(); S(const S&); + ~S(); S& operator= (const S&); };