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/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());