[cfe-commits] r128074 - in /cfe/trunk: lib/CodeGen/CGObjC.cpp lib/CodeGen/CodeGenModule.cpp test/CodeGenObjCXX/ivar-objects.mm test/PCH/objcxx-ivar-class.h

John McCall rjmccall at apple.com
Tue Mar 22 00:05:39 PDT 2011


Author: rjmccall
Date: Tue Mar 22 02:05:39 2011
New Revision: 128074

URL: http://llvm.org/viewvc/llvm-project?rev=128074&view=rev
Log:
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.


Modified:
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/test/CodeGenObjCXX/ivar-objects.mm
    cfe/trunk/test/PCH/objcxx-ivar-class.h

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=128074&r1=128073&r2=128074&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Tue Mar 22 02:05:39 2011
@@ -458,20 +458,104 @@
   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 @@
     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();
 }

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=128074&r1=128073&r2=128074&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Mar 22 02:05:39 2011
@@ -1937,37 +1937,48 @@
   }
 }
 
+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.

Modified: cfe/trunk/test/CodeGenObjCXX/ivar-objects.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/ivar-objects.mm?rev=128074&r1=128073&r2=128074&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/ivar-objects.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/ivar-objects.mm Tue Mar 22 02:05:39 2011
@@ -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 @@
 @implementation I
 	@synthesize position;
 @end
+
+// This class should have a .cxx_construct but no .cxx_destruct.
+namespace test3 { struct S { S(); }; }
+ at implementation B {
+  test3::S s;
+}
+ at end
+
+// This class should have a .cxx_destruct but no .cxx_construct.
+namespace test4 { struct S { ~S(); }; }
+ at implementation C {
+  test4::S s;
+}
+ at end

Modified: cfe/trunk/test/PCH/objcxx-ivar-class.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objcxx-ivar-class.h?rev=128074&r1=128073&r2=128074&view=diff
==============================================================================
--- cfe/trunk/test/PCH/objcxx-ivar-class.h (original)
+++ cfe/trunk/test/PCH/objcxx-ivar-class.h Tue Mar 22 02:05:39 2011
@@ -1,6 +1,7 @@
 struct S {
     S();
     S(const S&);
+    ~S();
     S& operator= (const S&);
 };
 





More information about the cfe-commits mailing list