]> granicus.if.org Git - clang/commitdiff
The emission of an Objective-C++'s class .cxx_destruct method should be
authorJohn McCall <rjmccall@apple.com>
Tue, 22 Mar 2011 07:05:39 +0000 (07:05 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 22 Mar 2011 07:05:39 +0000 (07:05 +0000)
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
lib/CodeGen/CodeGenModule.cpp
test/CodeGenObjCXX/ivar-objects.mm
test/PCH/objcxx-ivar-class.h

index 2bfa49662576b77823d012bad4345a971359143a..cf1ff23000d373e741b9ff4a04e4f9fc4dbf96c8 100644 (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);
+
+  // 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();
 }
index ea74abff54053b17b4a155d1d4b68cb3985a73f0..a528d2ede7afda482e8df9e7fbffd35df280f3c9 100644 (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.
index d0432edf2b2901e835c90f0367d8579384f1d13c..d05763b3fcf8df114ea46e54db18cb5829bb567f 100644 (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
index 50ebda709db0e460e50be2dc1cce148863e317b3..5e5565864d8793a48e2bc36a571da6b1c06e7cac 100644 (file)
@@ -1,6 +1,7 @@
 struct S {
     S();
     S(const S&);
+    ~S();
     S& operator= (const S&);
 };