forked from OSchip/llvm-project
Lazily declare the implicitly-declared destructor in a C++ class.
llvm-svn: 107510
This commit is contained in:
parent
0ce84486c3
commit
7454c563f1
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Reference in New Issue