forked from OSchip/llvm-project
Unify the way destructor epilogues are generated for synthesized and regular destructors. Also fix PR5529.
llvm-svn: 89034
This commit is contained in:
parent
cfd3012756
commit
dee9a30204
|
@ -1269,13 +1269,6 @@ public:
|
|||
/// };
|
||||
/// @endcode
|
||||
class CXXDestructorDecl : public CXXMethodDecl {
|
||||
public:
|
||||
enum KindOfObjectToDestroy {
|
||||
VBASE = 0x1,
|
||||
DRCTNONVBASE = 0x2,
|
||||
ANYBASE = 0x3
|
||||
};
|
||||
private:
|
||||
/// ImplicitlyDefined - Whether this destructor was implicitly
|
||||
/// defined by the compiler. When false, the destructor was defined
|
||||
/// by the user. In C++03, this flag will have the same value as
|
||||
|
@ -1284,27 +1277,15 @@ private:
|
|||
/// @c !Implicit && ImplicitlyDefined.
|
||||
bool ImplicitlyDefined : 1;
|
||||
|
||||
/// Support for base and member destruction.
|
||||
/// BaseOrMemberDestructions - The arguments used to destruct the base
|
||||
/// or member. Each uintptr_t value represents one of base classes (either
|
||||
/// virtual or direct non-virtual base), or non-static data member
|
||||
/// to be destroyed. The low two bits encode the kind of object
|
||||
/// being destroyed.
|
||||
uintptr_t *BaseOrMemberDestructions;
|
||||
unsigned NumBaseOrMemberDestructions;
|
||||
|
||||
FunctionDecl *OperatorDelete;
|
||||
|
||||
CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXDestructor, RD, L, N, T, /*DInfo=*/0, false, isInline),
|
||||
ImplicitlyDefined(false),
|
||||
BaseOrMemberDestructions(0), NumBaseOrMemberDestructions(0),
|
||||
OperatorDelete(0) {
|
||||
ImplicitlyDefined(false), OperatorDelete(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
public:
|
||||
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
|
@ -1333,96 +1314,6 @@ public:
|
|||
void setOperatorDelete(FunctionDecl *OD) { OperatorDelete = OD; }
|
||||
const FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
|
||||
|
||||
/// destr_iterator - Iterates through the member/base destruction list.
|
||||
|
||||
/// destr_const_iterator - Iterates through the member/base destruction list.
|
||||
typedef uintptr_t const destr_const_iterator;
|
||||
|
||||
/// destr_begin() - Retrieve an iterator to the first destructed member/base.
|
||||
uintptr_t* destr_begin() {
|
||||
return BaseOrMemberDestructions;
|
||||
}
|
||||
/// destr_begin() - Retrieve an iterator to the first destructed member/base.
|
||||
uintptr_t* destr_begin() const {
|
||||
return BaseOrMemberDestructions;
|
||||
}
|
||||
|
||||
/// destr_end() - Retrieve an iterator past the last destructed member/base.
|
||||
uintptr_t* destr_end() {
|
||||
return BaseOrMemberDestructions + NumBaseOrMemberDestructions;
|
||||
}
|
||||
/// destr_end() - Retrieve an iterator past the last destructed member/base.
|
||||
uintptr_t* destr_end() const {
|
||||
return BaseOrMemberDestructions + NumBaseOrMemberDestructions;
|
||||
}
|
||||
|
||||
/// getNumBaseOrMemberDestructions - Number of base and non-static members
|
||||
/// to destroy.
|
||||
unsigned getNumBaseOrMemberDestructions() const {
|
||||
return NumBaseOrMemberDestructions;
|
||||
}
|
||||
|
||||
/// setNumBaseOrMemberDestructions - Set number of base and non-static members
|
||||
/// to destroy.
|
||||
void setNumBaseOrMemberDestructions(unsigned numBaseOrMemberDestructions) {
|
||||
NumBaseOrMemberDestructions = numBaseOrMemberDestructions;
|
||||
}
|
||||
|
||||
/// getBaseOrMemberToDestroy - get the generic 'member' representing either
|
||||
/// the field or a base class.
|
||||
uintptr_t* getBaseOrMemberToDestroy() const {
|
||||
return BaseOrMemberDestructions;
|
||||
}
|
||||
|
||||
/// setBaseOrMemberToDestroy - set the generic 'member' representing either
|
||||
/// the field or a base class.
|
||||
void setBaseOrMemberDestructions(uintptr_t* baseOrMemberDestructions) {
|
||||
BaseOrMemberDestructions = baseOrMemberDestructions;
|
||||
}
|
||||
|
||||
/// isVbaseToDestroy - returns true, if object is virtual base.
|
||||
bool isVbaseToDestroy(uintptr_t Vbase) const {
|
||||
return (Vbase & VBASE) != 0;
|
||||
}
|
||||
/// isDirectNonVBaseToDestroy - returns true, if object is direct non-virtual
|
||||
/// base.
|
||||
bool isDirectNonVBaseToDestroy(uintptr_t DrctNonVbase) const {
|
||||
return (DrctNonVbase & DRCTNONVBASE) != 0;
|
||||
}
|
||||
/// isAnyBaseToDestroy - returns true, if object is any base (virtual or
|
||||
/// direct non-virtual)
|
||||
bool isAnyBaseToDestroy(uintptr_t AnyBase) const {
|
||||
return (AnyBase & ANYBASE) != 0;
|
||||
}
|
||||
/// isMemberToDestroy - returns true if object is a non-static data member.
|
||||
bool isMemberToDestroy(uintptr_t Member) const {
|
||||
return (Member & ANYBASE) == 0;
|
||||
}
|
||||
/// getAnyBaseClassToDestroy - Get the type for the given base class object.
|
||||
Type *getAnyBaseClassToDestroy(uintptr_t Base) const {
|
||||
if (isAnyBaseToDestroy(Base))
|
||||
return reinterpret_cast<Type*>(Base & ~0x03);
|
||||
return 0;
|
||||
}
|
||||
/// getMemberToDestroy - Get the member for the given object.
|
||||
FieldDecl *getMemberToDestroy(uintptr_t Member) const {
|
||||
if (isMemberToDestroy(Member))
|
||||
return reinterpret_cast<FieldDecl *>(Member);
|
||||
return 0;
|
||||
}
|
||||
/// getVbaseClassToDestroy - Get the virtual base.
|
||||
Type *getVbaseClassToDestroy(uintptr_t Vbase) const {
|
||||
if (isVbaseToDestroy(Vbase))
|
||||
return reinterpret_cast<Type*>(Vbase & ~0x01);
|
||||
return 0;
|
||||
}
|
||||
/// getDirectNonVBaseClassToDestroy - Get the virtual base.
|
||||
Type *getDirectNonVBaseClassToDestroy(uintptr_t Base) const {
|
||||
if (isDirectNonVBaseToDestroy(Base))
|
||||
return reinterpret_cast<Type*>(Base & ~0x02);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == CXXDestructor;
|
||||
|
|
|
@ -790,12 +790,6 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
|||
isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
void
|
||||
CXXDestructorDecl::Destroy(ASTContext& C) {
|
||||
C.Deallocate(BaseOrMemberDestructions);
|
||||
CXXMethodDecl::Destroy(C);
|
||||
}
|
||||
|
||||
void
|
||||
CXXConstructorDecl::Destroy(ASTContext& C) {
|
||||
C.Deallocate(BaseOrMemberInitializers);
|
||||
|
|
|
@ -401,37 +401,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
|
|||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
|
|
@ -1643,119 +1643,97 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
|
|||
/// 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 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
|
|||
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());
|
||||
|
|
|
@ -2407,11 +2407,10 @@ public:
|
|||
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);
|
||||
|
||||
|
|
|
@ -4052,7 +4052,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
|
|||
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
|
||||
|
|
|
@ -1633,77 +1633,63 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
|
|||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,3 +28,17 @@ class A1 {
|
|||
};
|
||||
|
||||
template<> A1<char>::~A1();
|
||||
|
||||
// PR5529
|
||||
namespace PR5529 {
|
||||
struct A {
|
||||
~A();
|
||||
};
|
||||
|
||||
A::~A() { }
|
||||
struct B : A {
|
||||
virtual ~B();
|
||||
};
|
||||
|
||||
B::~B() {}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue