Unify the way destructor epilogues are generated for synthesized and regular destructors. Also fix PR5529.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89034 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index bfa338b..3768796 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -791,12 +791,6 @@
}
void
-CXXDestructorDecl::Destroy(ASTContext& C) {
- C.Deallocate(BaseOrMemberDestructions);
- CXXMethodDecl::Destroy(C);
-}
-
-void
CXXConstructorDecl::Destroy(ASTContext& C) {
C.Deallocate(BaseOrMemberInitializers);
CXXMethodDecl::Destroy(C);
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d9d1950..b88a971 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -401,37 +401,6 @@
}
}
}
- else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(D)) {
- if (DDecl->getNumBaseOrMemberDestructions() > 0) {
- // List order of base/member destruction for visualization purposes.
- assert (D->isThisDeclarationADefinition() && "Destructor with dtor-list");
- Proto += "/* : ";
- for (CXXDestructorDecl::destr_const_iterator *B = DDecl->destr_begin(),
- *E = DDecl->destr_end();
- B != E; ++B) {
- uintptr_t BaseOrMember = (*B);
- if (B != DDecl->destr_begin())
- Proto += ", ";
-
- if (DDecl->isMemberToDestroy(BaseOrMember)) {
- FieldDecl *FD = DDecl->getMemberToDestroy(BaseOrMember);
- Proto += "~";
- Proto += FD->getNameAsString();
- }
- else // FIXME. skip dependent types for now.
- if (const RecordType *RT =
- DDecl->getAnyBaseClassToDestroy(BaseOrMember)
- ->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(RT->getDecl());
- Proto += "~";
- Proto += BaseDecl->getNameAsString();
- }
- Proto += "()";
- }
- Proto += " */";
- }
- }
else
AFT->getResultType().getAsStringInternal(Proto, Policy);
} else {
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 97e1868..82f3cfe 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -1643,119 +1643,97 @@
/// FIXME: This needs to take a CXXDtorType.
void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
CXXDtorType DtorType) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext());
- assert(!ClassDecl->getNumVBases() &&
- "FIXME: Destruction of virtual bases not supported");
- (void)ClassDecl; // prevent warning.
+ assert(!DD->isTrivial() &&
+ "Should not emit dtor epilogue for trivial dtor!");
- for (CXXDestructorDecl::destr_const_iterator *B = DD->destr_begin(),
- *E = DD->destr_end(); B != E; ++B) {
- uintptr_t BaseOrMember = (*B);
- if (DD->isMemberToDestroy(BaseOrMember)) {
- FieldDecl *FD = DD->getMemberToDestroy(BaseOrMember);
- QualType FieldType = getContext().getCanonicalType((FD)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
- const RecordType *RT = FieldType->getAs<RecordType>();
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
- continue;
- llvm::Value *LoadOfThis = LoadCXXThis();
- LValue LHS = EmitLValueForField(LoadOfThis, FD, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Array, BaseAddrPtr);
- }
- else
- EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Dtor_Complete, LHS.getAddress());
- } else {
- const RecordType *RT =
- DD->getAnyBaseClassToDestroy(BaseOrMember)->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
- DtorType, 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;
+ const CXXRecordDecl *ClassDecl = DD->getParent();
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
- if (getContext().getAsConstantArrayType(FieldType))
- FieldType = getContext().getBaseElementType(FieldType);
- 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 ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
- const RecordType *RT = FieldType->getAs<RecordType>();
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- llvm::Value *LoadOfThis = LoadCXXThis();
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Array, BaseAddrPtr);
- }
- else
- 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())
+ // Collect the fields.
+ llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ QualType FieldType = getContext().getCanonicalType(Field->getType());
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ if (!RT)
continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
- DestructedBases.push_back(BaseClassDecl);
- }
-
- for (int i = DestructedBases.size(); i > 0; --i) {
- CXXRecordDecl *BaseClassDecl = DestructedBases[i - 1];
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
- ClassDecl,BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
- Dtor_Complete, V);
+
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
+ continue;
+
+ FieldDecls.push_back(Field);
}
+ // Now destroy the fields.
+ for (size_t i = FieldDecls.size(); i > 0; --i) {
+ const FieldDecl *Field = FieldDecls[i - 1];
+
+ QualType FieldType = Field->getType();
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+ llvm::Value *ThisPtr = LoadCXXThis();
+
+ LValue LHS = EmitLValueForField(ThisPtr, Field,
+ /*isUnion=*/false,
+ // FIXME: Qualifiers?
+ /*CVRQualifiers=*/0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Array, BaseAddrPtr);
+ } else
+ EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Dtor_Complete, LHS.getAddress());
+ }
+
+ // Destroy non-virtual bases.
+ for (CXXRecordDecl::reverse_base_class_const_iterator I =
+ ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+
+ // Ignore virtual bases.
+ if (Base.isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore trivial destructors.
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+
+ llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
+ Dtor_Base, V);
+ }
+
+ // If we're emitting a base destructor, we don't want to emit calls to the
+ // virtual bases.
+ if (DtorType == Dtor_Base)
+ return;
+
+ // FIXME: Handle virtual bases.
+ for (CXXRecordDecl::reverse_base_class_const_iterator I =
+ ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
+ assert(false && "FIXME: Handle virtual bases.");
+ }
+
+ // If we have a deleting destructor, emit a call to the delete operator.
if (DtorType == Dtor_Deleting) {
const FunctionDecl *DeleteFD = DD->getOperatorDelete();
assert(DeleteFD && "deleting dtor did not have a delete operator!");
@@ -1782,19 +1760,17 @@
CXXDtorType DtorType,
llvm::Function *Fn,
const FunctionArgList &Args) {
-
- const CXXRecordDecl *ClassDecl = Dtor->getParent();
- assert(!ClassDecl->hasUserDeclaredDestructor() &&
+ assert(!Dtor->getParent()->hasUserDeclaredDestructor() &&
"SynthesizeDefaultDestructor - destructor has user declaration");
- (void) ClassDecl;
StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args,
SourceLocation());
+
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
-// FIXME: Move this to CGCXXStmt.cpp
+// FIXME: Move this to CGStmtCXX.cpp
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
// FIXME: We need to do more here.
EmitStmt(S.getTryBlock());
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index e6772db..acf52c9 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2407,11 +2407,10 @@
unsigned NumInitializers,
bool IsImplicitConstructor);
- /// 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);
+ /// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl,
+ /// mark all its non-trivial member and base destructor declarations
+ /// as referenced.
+ void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor);
void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index ecea71d..2228b41 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4052,7 +4052,7 @@
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
- computeBaseOrMembersToDestroy(Destructor);
+ MarkBaseAndMemberDestructorsReferenced(Destructor);
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 18e6229..9ba03a9 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1633,77 +1633,63 @@
}
void
-Sema::computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor) {
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext());
- llvm::SmallVector<uintptr_t, 32> AllToDestruct;
+Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
+ // Ignore dependent destructors.
+ if (Destructor->isDependentContext())
+ return;
+
+ CXXRecordDecl *ClassDecl = Destructor->getParent();
+ // Non-static data members.
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ FieldDecl *Field = *I;
+
+ QualType FieldType = Context.getBaseElementType(Field->getType());
+
+ const RecordType* RT = FieldType->getAs<RecordType>();
+ if (!RT)
+ continue;
+
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
+ continue;
+
+ const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
+ }
+
+ // Bases.
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Ignore virtual bases.
+ if (Base->isVirtual())
+ continue;
+
+ // Ignore trivial destructors.
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+
+ const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
+ }
+
+ // Virtual bases.
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.
+ // Ignore 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);
+
+ const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
}
}