]> granicus.if.org Git - clang/commitdiff
Patch to 1) synthesizing non-trivial default destructor when
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 17 Aug 2009 19:04:50 +0000 (19:04 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 17 Aug 2009 19:04:50 +0000 (19:04 +0000)
one is not provided by user. 2) More complete
emission of ctor prologue when it has no initializer
list or when it is synthesized.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79269 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGenCXX/default-destructor-synthesis.cpp [new file with mode: 0644]

index 61ff4807b2b4e859544d7133a3b1b6b9f9b07de6..655f6f808d1b355a27d991e8e6defc90fa146bb3 100644 (file)
@@ -1193,9 +1193,30 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD) {
     }
   }
 
-  if (!CD->isTrivial() && CD->getNumBaseOrMemberInitializers() == 0)
+  if (!CD->getNumBaseOrMemberInitializers() && !CD->isTrivial()) {
     // Nontrivial default constructor with no initializer list. It may still
-    // contain non-static data members which require construction.
+    // have bases classes and/or contain non-static data members which require 
+    // construction.
+    for (CXXRecordDecl::base_class_const_iterator Base = 
+          ClassDecl->bases_begin();
+          Base != ClassDecl->bases_end(); ++Base) {
+      // FIXME. copy assignment of virtual base NYI
+      if (Base->isVirtual())
+        continue;
+    
+      CXXRecordDecl *BaseClassDecl
+        = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+      if (BaseClassDecl->hasTrivialConstructor())
+        continue;
+      if (CXXConstructorDecl *BaseCX = 
+            BaseClassDecl->getDefaultConstructor(getContext())) {
+        LoadOfThis = LoadCXXThis();
+        llvm::Value *V = AddressCXXOfBaseClass(LoadOfThis, ClassDecl,
+                                               BaseClassDecl);
+        EmitCXXConstructorCall(BaseCX, Ctor_Complete, V, 0, 0);
+      }
+    }
+  
     for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
          FieldEnd = ClassDecl->field_end();
          Field != FieldEnd; ++Field) {
@@ -1203,19 +1224,19 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD) {
       if (!FieldType->getAs<RecordType>() || Field->isAnonymousStructOrUnion())
         continue;
       const RecordType *ClassRec = FieldType->getAs<RecordType>();
-      if (CXXRecordDecl *MemberClassDecl = 
-            dyn_cast<CXXRecordDecl>(ClassRec->getDecl())) {
-        if (MemberClassDecl->hasTrivialConstructor())
-          continue;
-        if (CXXConstructorDecl *MamberCX = 
-              MemberClassDecl->getDefaultConstructor(getContext())) {
-          LoadOfThis = LoadCXXThis();
-          LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
-          EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(), 0, 0);
-        }
+      CXXRecordDecl *MemberClassDecl = 
+        dyn_cast<CXXRecordDecl>(ClassRec->getDecl());
+      if (!MemberClassDecl || MemberClassDecl->hasTrivialConstructor())
+        continue;
+      if (CXXConstructorDecl *MamberCX = 
+            MemberClassDecl->getDefaultConstructor(getContext())) {
+        LoadOfThis = LoadCXXThis();
+        LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
+        EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(), 0, 0);
       }
     }
-
+  }
+  
   // Initialize the vtable pointer
   if (ClassDecl->isDynamicClass()) {
     if (!LoadOfThis)
@@ -1267,4 +1288,72 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD) {
                             Dtor_Complete, V);
     }
   }
+  if (DD->getNumBaseOrMemberDestructions() || DD->isTrivial())
+    return;
+  // Case of destructor synthesis with fields and base classes
+  // which have non-trivial destructors. They must be destructed in 
+  // reverse order of their construction.
+  llvm::SmallVector<FieldDecl *, 16> DestructedFields;
+  
+  for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+       FieldEnd = ClassDecl->field_end();
+       Field != FieldEnd; ++Field) {
+    QualType FieldType = getContext().getCanonicalType((*Field)->getType());
+    // FIXME. Assert on arrays for now.
+    if (const RecordType *RT = FieldType->getAs<RecordType>()) {
+      CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+      if (FieldClassDecl->hasTrivialDestructor())
+        continue;
+      DestructedFields.push_back(*Field);
+    }
+  }
+  if (!DestructedFields.empty())
+    for (int i = DestructedFields.size() -1; i >= 0; --i) {
+      FieldDecl *Field = DestructedFields[i];
+      QualType FieldType = Field->getType();
+      const RecordType *RT = FieldType->getAs<RecordType>();
+      CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+      llvm::Value *LoadOfThis = LoadCXXThis();
+      LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+      EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
+                            Dtor_Complete, LHS.getAddress());
+    }
+  
+  llvm::SmallVector<CXXRecordDecl*, 4> DestructedBases;
+  for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+       Base != ClassDecl->bases_end(); ++Base) {
+    // FIXME. copy assignment of virtual base NYI
+    if (Base->isVirtual())
+      continue;
+    
+    CXXRecordDecl *BaseClassDecl
+      = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+    if (BaseClassDecl->hasTrivialDestructor())
+      continue;
+    DestructedBases.push_back(BaseClassDecl);
+  }
+  if (DestructedBases.empty())
+    return;
+  for (int i = DestructedBases.size() -1; i >= 0; --i) {
+    CXXRecordDecl *BaseClassDecl = DestructedBases[i];
+    llvm::Value *V = AddressCXXOfBaseClass(LoadCXXThis(), 
+                                           ClassDecl,BaseClassDecl);
+    EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
+                          Dtor_Complete, V);
+  }
 }
+
+void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *CD,
+                                                  const FunctionDecl *FD,
+                                                  llvm::Function *Fn,
+                                                  const FunctionArgList &Args) {
+  
+  const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
+  assert(!ClassDecl->hasUserDeclaredDestructor() &&
+         "SynthesizeDefaultDestructor - destructor has user declaration");
+  (void) ClassDecl;
+  
+  StartFunction(FD, FD->getResultType(), Fn, Args, SourceLocation());
+  EmitDtorEpilogue(CD);
+  FinishFunction();
+}  
index 1e8d05261db2d861a4e740247b49c43b9138ce9b..d0c722ecfb21890f0aad8475f2a9e24f832f9d51 100644 (file)
@@ -254,6 +254,8 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD,
         SynthesizeDefaultConstructor(CD, FD, Fn, Args);
       }
     }
+  else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
+         SynthesizeDefaultDestructor(DD, FD, Fn, Args);
   else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
          if (MD->isCopyAssignment())
            SynthesizeCXXCopyAssignment(MD, FD, Fn, Args);
index c41af94e20bc0a265a73bc90a68fc5e7b84e2ae4..e2aba1b2baa8f32299aec38f5f0d8435103aa95a 100644 (file)
@@ -403,6 +403,11 @@ public:
                                     llvm::Function *Fn,
                                     const FunctionArgList &Args);
   
+  void SynthesizeDefaultDestructor(const CXXDestructorDecl *CD,
+                                    const FunctionDecl *FD,
+                                    llvm::Function *Fn,
+                                    const FunctionArgList &Args);
+  
   /// EmitDtorEpilogue - Emit all code that comes at the end of class's
   /// destructor. This is to call destructors on members and base classes 
   /// in reverse order of their construction.
diff --git a/test/CodeGenCXX/default-destructor-synthesis.cpp b/test/CodeGenCXX/default-destructor-synthesis.cpp
new file mode 100644 (file)
index 0000000..0f6849c
--- /dev/null
@@ -0,0 +1,54 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -O0 -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -O0 -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 -input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+struct S {
+  S() : iS(1), fS(1.23) {};
+  ~S(){printf("S::~S(%d, %f)\n", iS, fS); };
+  int iS;
+  float fS;
+};
+
+struct Q {
+  Q() : iQ(2), dQ(2.34) {};
+  ~Q(){printf("Q::~Q(%d, %f)\n", iQ, dQ); };
+  int iQ;
+  double dQ;
+};
+
+struct P {
+  P() : fP(3.45) , iP(3) {};
+  ~P(){printf("P::~P(%d, %f)\n", iP, fP); };
+  float fP;
+  int iP;
+};
+
+struct M  : Q, P {
+  S s;
+
+  Q q;
+
+  P p; 
+
+};
+
+M gm;
+
+int main() {M m1;}
+
+// CHECK-LP64:  call   __ZN1MC1Ev
+// CHECK-LP64:  call   __ZN1MD1Ev
+// CHECK-LP64:  .globl __ZN1MD1Ev
+// CHECK-LP64-NEXT:  .weak_definition __ZN1MD1Ev
+// CHECK-LP64-NEXT:  __ZN1MD1Ev:
+
+
+// CHECK-LP32:  call   L__ZN1MC1Ev
+// CHECK-LP32:  call   L__ZN1MD1Ev
+// CHECK-LP32:  .globl __ZN1MD1Ev
+// CHECK-LP32-NEXT:  .weak_definition __ZN1MD1Ev
+// CHECK-LP32-NEXT:  __ZN1MD1Ev: