From dee9a3020466eb1f038477a2fb827ce5750b4730 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Tue, 17 Nov 2009 04:44:12 +0000 Subject: [PATCH] Unify the way destructor epilogues are generated for synthesized and regular destructors. Also fix PR5529. llvm-svn: 89034 --- clang/include/clang/AST/DeclCXX.h | 111 +------------- clang/lib/AST/DeclCXX.cpp | 6 - clang/lib/AST/DeclPrinter.cpp | 31 ---- clang/lib/CodeGen/CGCXX.cpp | 202 ++++++++++++-------------- clang/lib/Sema/Sema.h | 9 +- clang/lib/Sema/SemaDecl.cpp | 2 +- clang/lib/Sema/SemaDeclCXX.cpp | 114 +++++++-------- clang/test/CodeGenCXX/destructors.cpp | 14 ++ 8 files changed, 159 insertions(+), 330 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 6ede5dee1e1e..17dbd61aecf4 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -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(Base & ~0x03); - return 0; - } - /// getMemberToDestroy - Get the member for the given object. - FieldDecl *getMemberToDestroy(uintptr_t Member) const { - if (isMemberToDestroy(Member)) - return reinterpret_cast(Member); - return 0; - } - /// getVbaseClassToDestroy - Get the virtual base. - Type *getVbaseClassToDestroy(uintptr_t Vbase) const { - if (isVbaseToDestroy(Vbase)) - return reinterpret_cast(Vbase & ~0x01); - return 0; - } - /// getDirectNonVBaseClassToDestroy - Get the virtual base. - Type *getDirectNonVBaseClassToDestroy(uintptr_t Base) const { - if (isDirectNonVBaseToDestroy(Base)) - return reinterpret_cast(Base & ~0x02); - return 0; - } - // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == CXXDestructor; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index bfa338b36592..3768796627dd 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -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); diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index d9d195016bf3..b88a971f1ec6 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -401,37 +401,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } } } - else if (CXXDestructorDecl *DDecl = dyn_cast(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()) { - const CXXRecordDecl *BaseDecl = - cast(RT->getDecl()); - Proto += "~"; - Proto += BaseDecl->getNameAsString(); - } - Proto += "()"; - } - Proto += " */"; - } - } else AFT->getResultType().getAsStringInternal(Proto, Policy); } else { diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 97e1868f55f5..82f3cfefcabe 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -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(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(); - CXXRecordDecl *FieldClassDecl = cast(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(); - CXXRecordDecl *BaseClassDecl = cast(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 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()) { - CXXRecordDecl *FieldClassDecl = cast(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(); - CXXRecordDecl *FieldClassDecl = cast(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 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 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(); + if (!RT) continue; - - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->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(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(); + CXXRecordDecl *FieldClassDecl = cast(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(Base.getType()->getAs()->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()); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index e6772dbe68e0..acf52c97fde7 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ecea71d7ed96..2228b41b3311 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4052,7 +4052,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, DiagnoseReturnInConstructorExceptionHandler(cast(Body)); if (CXXDestructorDecl *Destructor = dyn_cast(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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 18e62291e56c..9ba03a90fc03 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1633,77 +1633,63 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, } void -Sema::computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor) { - CXXRecordDecl *ClassDecl = cast(Destructor->getDeclContext()); - llvm::SmallVector 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(); + if (!RT) + continue; + + CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) + continue; + + const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context); + MarkDeclarationReferenced(Destructor->getLocation(), + const_cast(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(Base->getType()->getAs()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + + const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + MarkDeclarationReferenced(Destructor->getLocation(), + const_cast(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(VBase->getType()->getAs()->getDecl()); if (BaseClassDecl->hasTrivialDestructor()) continue; - if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context)) - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast(Dtor)); - - uintptr_t Member = - reinterpret_cast(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(Base->getType()->getAs()->getDecl()); - if (BaseClassDecl->hasTrivialDestructor()) - continue; - if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context)) - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast(Dtor)); - uintptr_t Member = - reinterpret_cast(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()) { - // Skip over virtual bases which have trivial destructors. - CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); - if (FieldClassDecl->hasTrivialDestructor()) - continue; - if (const CXXDestructorDecl *Dtor = - FieldClassDecl->getDestructor(Context)) - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast(Dtor)); - uintptr_t Member = reinterpret_cast(*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(Dtor)); } } diff --git a/clang/test/CodeGenCXX/destructors.cpp b/clang/test/CodeGenCXX/destructors.cpp index 44d2b2936864..a196c13f8f42 100644 --- a/clang/test/CodeGenCXX/destructors.cpp +++ b/clang/test/CodeGenCXX/destructors.cpp @@ -28,3 +28,17 @@ class A1 { }; template<> A1::~A1(); + +// PR5529 +namespace PR5529 { + struct A { + ~A(); + }; + + A::~A() { } + struct B : A { + virtual ~B(); + }; + + B::~B() {} +}