Patch to instantiate destructors used to destruct
base and data members when they are needed.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80967 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 766d18b..746c28a 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2191,6 +2191,12 @@
                               llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
                               llvm::SmallVectorImpl<FieldDecl *>&Members);
   
+  /// computeBaseOrMembersToDestroy - Compute information in current 
+  /// destructor decl's AST of bases and non-static data members which will be 
+  /// implicitly destroyed. We are storing the destruction in the order that
+  /// they should occur (which is the reverse of construction order).
+  void computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor);
+  
   void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
 
   virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, 
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e7a3278..abf9528 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3758,7 +3758,7 @@
     DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
   
   if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
-    Destructor->computeBaseOrMembersToDestroy(Context);
+    computeBaseOrMembersToDestroy(Destructor);
   return D;
 }
 
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 075c945..e5a4c6f 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1284,6 +1284,81 @@
   }
 }
 
+void
+Sema::computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor) {
+  CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext());
+  llvm::SmallVector<uintptr_t, 32> AllToDestruct;
+  
+  for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
+       E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+    if (VBase->getType()->isDependentType())
+      continue;
+    // Skip over virtual bases which have trivial destructors.
+    CXXRecordDecl *BaseClassDecl
+      = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+    if (BaseClassDecl->hasTrivialDestructor())
+      continue;
+    if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context))
+      MarkDeclarationReferenced(Destructor->getLocation(), 
+                                const_cast<CXXDestructorDecl*>(Dtor));
+    
+    uintptr_t Member = 
+    reinterpret_cast<uintptr_t>(VBase->getType().getTypePtr()) 
+      | CXXDestructorDecl::VBASE;
+    AllToDestruct.push_back(Member);
+  }
+  for (CXXRecordDecl::base_class_iterator Base =
+       ClassDecl->bases_begin(),
+       E = ClassDecl->bases_end(); Base != E; ++Base) {
+    if (Base->isVirtual())
+      continue;
+    if (Base->getType()->isDependentType())
+      continue;
+    // Skip over virtual bases which have trivial destructors.
+    CXXRecordDecl *BaseClassDecl
+    = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+    if (BaseClassDecl->hasTrivialDestructor())
+      continue;
+    if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context))
+      MarkDeclarationReferenced(Destructor->getLocation(), 
+                                const_cast<CXXDestructorDecl*>(Dtor));
+    uintptr_t Member = 
+    reinterpret_cast<uintptr_t>(Base->getType().getTypePtr()) 
+      | CXXDestructorDecl::DRCTNONVBASE;
+    AllToDestruct.push_back(Member);
+  }
+  
+  // non-static data members.
+  for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+       E = ClassDecl->field_end(); Field != E; ++Field) {
+    QualType FieldType = Context.getBaseElementType((*Field)->getType());
+    
+    if (const RecordType* RT = FieldType->getAs<RecordType>()) {
+      // Skip over virtual bases which have trivial destructors.
+      CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+      if (FieldClassDecl->hasTrivialDestructor())
+        continue;
+      if (const CXXDestructorDecl *Dtor = 
+            FieldClassDecl->getDestructor(Context))
+        MarkDeclarationReferenced(Destructor->getLocation(), 
+                                  const_cast<CXXDestructorDecl*>(Dtor));
+      uintptr_t Member = reinterpret_cast<uintptr_t>(*Field);
+      AllToDestruct.push_back(Member);
+    }
+  }
+  
+  unsigned NumDestructions = AllToDestruct.size();
+  if (NumDestructions > 0) {
+    Destructor->setNumBaseOrMemberDestructions(NumDestructions);
+    uintptr_t *BaseOrMemberDestructions = 
+      new (Context) uintptr_t [NumDestructions];
+    // Insert in reverse order.
+    for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx)
+      BaseOrMemberDestructions[i++] = AllToDestruct[Idx];
+    Destructor->setBaseOrMemberDestructions(BaseOrMemberDestructions);
+  }
+}
+
 void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
   if (!CDtorDecl)
     return;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index b88ee89..c62159d 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -757,6 +757,10 @@
                                  &DeleteArg, 1, Record, /*AllowMissing=*/true,
                                  OperatorDelete))
         return ExprError();
+      if (!Record->hasTrivialDestructor())
+        if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context))
+          MarkDeclarationReferenced(StartLoc, 
+                                    const_cast<CXXDestructorDecl*>(Dtor));
     }
     
     if (!OperatorDelete) {