Patch to instantiate destructors used to destruct

base and data members when they are needed.

llvm-svn: 80967
This commit is contained in:
Fariborz Jahanian 2009-09-03 23:18:17 +00:00
parent 92291f6ad0
commit 37d065680b
7 changed files with 109 additions and 71 deletions

View File

@ -1095,12 +1095,13 @@ 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
@ -1181,12 +1182,24 @@ public:
return NumBaseOrMemberDestructions;
}
/// getBaseOrMember - get the generic 'member' representing either the field
/// or a base class.
/// 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;
@ -1229,12 +1242,6 @@ public:
return reinterpret_cast<Type*>(Base & ~0x02);
return 0;
}
/// 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(ASTContext &C);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {

View File

@ -522,67 +522,6 @@ CXXDestructorDecl::Destroy(ASTContext& C) {
CXXMethodDecl::Destroy(C);
}
void
CXXDestructorDecl::computeBaseOrMembersToDestroy(ASTContext &C) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(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;
uintptr_t Member =
reinterpret_cast<uintptr_t>(VBase->getType().getTypePtr()) | 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;
uintptr_t Member =
reinterpret_cast<uintptr_t>(Base->getType().getTypePtr()) | 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 = C.getBaseElementType((*Field)->getType());
if (const RecordType* RT = FieldType->getAs<RecordType>()) {
// Skip over virtual bases which have trivial destructors.
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (BaseClassDecl->hasTrivialDestructor())
continue;
uintptr_t Member = reinterpret_cast<uintptr_t>(*Field);
AllToDestruct.push_back(Member);
}
}
unsigned NumDestructions = AllToDestruct.size();
if (NumDestructions > 0) {
NumBaseOrMemberDestructions = NumDestructions;
BaseOrMemberDestructions = new (C) uintptr_t [NumDestructions];
// Insert in reverse order.
for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx)
BaseOrMemberDestructions[i++] = AllToDestruct[Idx];
}
}
void
CXXConstructorDecl::Destroy(ASTContext& C) {
C.Deallocate(BaseOrMemberInitializers);

View File

@ -2191,6 +2191,12 @@ public:
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,

View File

@ -3758,7 +3758,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
Destructor->computeBaseOrMembersToDestroy(Context);
computeBaseOrMembersToDestroy(Destructor);
return D;
}

View File

@ -1284,6 +1284,81 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
}
}
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;

View File

@ -757,6 +757,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
&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) {

View File

@ -22,12 +22,14 @@ struct B {
template <typename T> class List {
public:
List(){ } // List<BinomialNode<int>*>::List() remains undefined.
~List() {}
};
template <typename T> class Node {
int i;
public:
Node(){ } // Node<BinomialNode<int>*>::Node() remains undefined.
~Node() {}
};
@ -40,10 +42,15 @@ public:
int main() {
B<int> *n = new B<int>(4);
BinomialNode<int> *node = new BinomialNode<int>(1);
delete node;
}
// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED1Ev:
// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED2Ev:
// CHECK-LP64: __ZN4NodeIP12BinomialNodeIiEEC1Ev:
// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEEC1Ev:
// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED1Ev:
// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED2Ev:
// CHECK-LP32: __ZN4NodeIP12BinomialNodeIiEEC1Ev:
// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEEC1Ev: