Lazily declare the implicitly-declared destructor in a C++ class.

llvm-svn: 107510
This commit is contained in:
Douglas Gregor 2010-07-02 20:37:36 +00:00
parent 0ce84486c3
commit 7454c563f1
10 changed files with 111 additions and 6 deletions

View File

@ -1322,6 +1322,17 @@ public:
/// \brief Data Pointer data that will be provided to the callback function
/// when it is called.
void AddDeallocation(void (*Callback)(void*), void *Data);
//===--------------------------------------------------------------------===//
// Statistics
//===--------------------------------------------------------------------===//
/// \brief The number of implicitly-declared destructors.
static unsigned NumImplicitDestructors;
/// \brief The number of implicitly-declared destructors for which
/// declarations were built.
static unsigned NumImplicitDestructorsDeclared;
private:
ASTContext(const ASTContext&); // DO NOT IMPLEMENT

View File

@ -319,6 +319,9 @@ class CXXRecordDecl : public RecordDecl {
/// already computed and are available.
bool ComputedVisibleConversions : 1;
/// \brief Whether we have already declared a destructor within the class.
bool DeclaredDestructor : 1;
/// Bases - Base classes of this class.
/// FIXME: This is wasted space for a union.
CXXBaseSpecifier *Bases;
@ -600,8 +603,21 @@ public:
/// fully defined, a destructor will be implicitly declared.
void setUserDeclaredDestructor(bool UCD) {
data().UserDeclaredDestructor = UCD;
if (UCD)
data().DeclaredDestructor = true;
}
/// \brief Determine whether this class has had its destructor declared,
/// either via the user or via an implicit declaration.
///
/// This value is used for lazy creation of destructors.
bool hasDeclaredDestructor() const { return data().DeclaredDestructor; }
/// \brief Note whether this class has already had its destructor declared.
void setDeclaredDestructor(bool DD) {
data().DeclaredDestructor = DD;
}
/// getConversions - Retrieve the overload set containing all of the
/// conversion functions in this class.
UnresolvedSetImpl *getConversionFunctions() {

View File

@ -31,6 +31,9 @@
using namespace clang;
unsigned ASTContext::NumImplicitDestructors;
unsigned ASTContext::NumImplicitDestructorsDeclared;
enum FloatingRank {
FloatRank, DoubleRank, LongDoubleRank
};
@ -253,6 +256,10 @@ void ASTContext::PrintStats() const {
fprintf(stderr, "Total bytes = %d\n", int(TotalBytes));
// Implicit special member functions.
fprintf(stderr, " %u/%u implicit destructors created\n",
NumImplicitDestructorsDeclared, NumImplicitDestructors);
if (ExternalSource.get()) {
fprintf(stderr, "\n");
ExternalSource->PrintStats();

View File

@ -32,6 +32,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
Abstract(false), HasTrivialConstructor(true),
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialDestructor(true), ComputedVisibleConversions(false),
DeclaredDestructor(false),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
Definition(D), FirstFriend(0) {
}

View File

@ -668,6 +668,7 @@ void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
Data.HasTrivialCopyAssignment = Record[Idx++];
Data.HasTrivialDestructor = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
Data.DeclaredDestructor = Record[Idx++];
// setBases() is unsuitable since it may try to iterate the bases of an
// unitialized base.

View File

@ -664,6 +664,7 @@ void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Record.push_back(Data.HasTrivialCopyAssignment);
Record.push_back(Data.HasTrivialDestructor);
Record.push_back(Data.ComputedVisibleConversions);
Record.push_back(Data.DeclaredDestructor);
Record.push_back(D->getNumBases());
for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),

View File

@ -2282,6 +2282,10 @@ public:
void DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *MethodDecl);
/// \brief Force the declaration of any implicitly-declared members of this
/// class.
void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class);
/// MaybeBindToTemporary - If the passed in expression has a record type with
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
/// it simply returns the passed in expression.

View File

@ -3676,7 +3676,7 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
CXXRecordDecl *Record = Destructor->getParent();
QualType ClassType = Context.getTypeDeclType(Record);
// FIXME: Shouldn't we be able to perform thisc heck even when the class
// FIXME: Shouldn't we be able to perform this check even when the class
// type is dependent? Both gcc and edg can handle that.
if (!ClassType->isDependentType()) {
DeclarationName Name

View File

@ -2662,8 +2662,16 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
if (!ClassDecl->hasUserDeclaredCopyAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
if (!ClassDecl->hasUserDeclaredDestructor())
DeclareImplicitDestructor(ClassDecl);
if (!ClassDecl->hasUserDeclaredDestructor()) {
++ASTContext::NumImplicitDestructors;
// If we have a dynamic class, then the destructor may be virtual, so we
// have to declare the destructor immediately. This ensures that, e.g., it
// shows up in the right place in the vtable and that we diagnose problems
// with the implicit exception specification.
if (ClassDecl->isDynamicClass())
DeclareImplicitDestructor(ClassDecl);
}
}
void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
@ -4274,6 +4282,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
}
// Create the actual destructor declaration.
QualType Ty = Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
ExceptSpec.hasExceptionSpecification(),
@ -4294,15 +4303,21 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
// Note that we have declared this destructor.
ClassDecl->setDeclaredDestructor(true);
++ASTContext::NumImplicitDestructorsDeclared;
// Introduce this destructor into its scope.
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(Destructor, S, true);
else
ClassDecl->addDecl(Destructor);
PushOnScopeChains(Destructor, S, false);
ClassDecl->addDecl(Destructor);
// This could be uniqued if it ever proves significant.
Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
AddOverriddenMethods(ClassDecl, Destructor);
return Destructor;
}

View File

@ -447,11 +447,52 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
return false;
}
/// \brief Determine whether we can declare a special member function within
/// the class at this point.
static bool CanDeclareSpecialMemberFunction(ASTContext &Context,
const CXXRecordDecl *Class) {
// We need to have a definition for the class.
if (!Class->getDefinition() || Class->isDependentContext())
return false;
// We can't be in the middle of defining the class.
if (const RecordType *RecordTy
= Context.getTypeDeclType(Class)->getAs<RecordType>())
return !RecordTy->isBeingDefined();
return false;
}
void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
// If the destructor has not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Context, Class) &&
!Class->hasDeclaredDestructor())
DeclareImplicitDestructor(Class);
}
// Adds all qualifying matches for a name within a decl context to the
// given lookup result. Returns true if any matches were found.
static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
bool Found = false;
// Lazily declare C++ special member functions.
if (S.getLangOptions().CPlusPlus) {
switch (R.getLookupName().getNameKind()) {
case DeclarationName::CXXDestructorName:
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
if (Record->getDefinition() && !Record->hasDeclaredDestructor() &&
CanDeclareSpecialMemberFunction(S.Context, Record))
S.DeclareImplicitDestructor(const_cast<CXXRecordDecl *>(Record));
break;
default:
break;
}
}
// Perform lookup into this declaration context.
DeclContext::lookup_const_iterator I, E;
for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
NamedDecl *D = *I;
@ -1904,6 +1945,11 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
///
/// \returns The destructor for this class.
CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
// If the destructor has not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Context, Class) &&
!Class->hasDeclaredDestructor())
DeclareImplicitDestructor(Class);
return Class->getDestructor();
}
@ -2205,6 +2251,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
if (Visited.visitedContext(Ctx->getPrimaryContext()))
return;
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
// Enumerate all of the results in this context.
for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
CurCtx = CurCtx->getNextContext()) {