In Sema, whenever we think that a function is going to cause a vtable to be generated, we mark any virtual implicit member functions as referenced.

llvm-svn: 90327
This commit is contained in:
Anders Carlsson 2009-12-02 17:15:43 +00:00
parent fffbc0c5d9
commit f98849eb8a
8 changed files with 84 additions and 18 deletions

View File

@ -660,7 +660,7 @@ public:
CXXConstructorDecl *getDefaultConstructor(ASTContext &Context);
/// getDestructor - Returns the destructor decl for this class.
const CXXDestructorDecl *getDestructor(ASTContext &Context);
CXXDestructorDecl *getDestructor(ASTContext &Context);
/// isLocalClass - If the class is a local class [class.local], returns
/// the enclosing function declaration.

View File

@ -507,8 +507,7 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
return 0;
}
const CXXDestructorDecl *
CXXRecordDecl::getDestructor(ASTContext &Context) {
CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) {
QualType ClassType = Context.getTypeDeclType(this);
DeclarationName Name
@ -519,7 +518,7 @@ CXXRecordDecl::getDestructor(ASTContext &Context) {
llvm::tie(I, E) = lookup(Name);
assert(I != E && "Did not find a destructor!");
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
assert(++I == E && "Found more than one destructor!");
return Dtor;

View File

@ -677,6 +677,11 @@ static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) {
if (MD->isPure())
continue;
// Ignore implicit member functions, they are always marked as inline, but
// they don't have a body until they're defined.
if (MD->isImplicit())
continue;
const FunctionDecl *fn;
if (MD->getBody(fn) && !fn->isOutOfLine())
continue;

View File

@ -1932,8 +1932,7 @@ public:
QualType Argument);
bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name, FunctionDecl* &Operator,
bool Diagnose=true);
DeclarationName Name, FunctionDecl* &Operator);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
@ -2128,6 +2127,12 @@ public:
/// as referenced.
void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor);
/// MaybeMarkVirtualImplicitMembersReferenced - If the passed in method is the
/// key function of the record decl, will mark virtual member functions as
/// referenced.
void MaybeMarkVirtualImplicitMembersReferenced(SourceLocation Loc,
CXXMethodDecl *MD);
void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
@ -2160,7 +2165,7 @@ public:
void CheckConstructor(CXXConstructorDecl *Constructor);
QualType CheckDestructorDeclarator(Declarator &D,
FunctionDecl::StorageClass& SC);
bool CheckDestructor(CXXDestructorDecl *Destructor, bool Diagnose=true);
bool CheckDestructor(CXXDestructorDecl *Destructor);
void CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);

View File

@ -4085,12 +4085,14 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
// C++ [basic.def.odr]p2:
// [...] A virtual member function is used if it is not pure. [...]
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) {
// C++ [basic.def.odr]p2:
// [...] A virtual member function is used if it is not pure. [...]
if (Method->isVirtual() && !Method->isPure())
MarkDeclarationReferenced(Method->getLocation(), Method);
MaybeMarkVirtualImplicitMembersReferenced(Method->getLocation(), Method);
}
assert(FD == getCurFunctionDecl() && "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");

View File

@ -15,6 +15,7 @@
#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeOrdering.h"
@ -2172,7 +2173,6 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->addDecl(Destructor);
AddOverriddenMethods(ClassDecl, Destructor);
CheckDestructor(Destructor, false);
}
}
@ -2371,7 +2371,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
/// CheckDestructor - Checks a fully-formed destructor for well-formedness,
/// issuing any diagnostics required. Returns true on error.
bool Sema::CheckDestructor(CXXDestructorDecl *Destructor, bool Diagnose) {
bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
CXXRecordDecl *RD = Destructor->getParent();
if (Destructor->isVirtual()) {
@ -2386,7 +2386,7 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor, bool Diagnose) {
FunctionDecl *OperatorDelete = 0;
DeclarationName Name =
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete, Diagnose))
if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
return true;
Destructor->setOperatorDelete(OperatorDelete);
@ -3083,7 +3083,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
} else {
Constructor->setUsed();
}
return;
MaybeMarkVirtualImplicitMembersReferenced(CurrentLocation, Constructor);
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@ -4994,3 +4995,31 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
VD->setDeclaredInCondition(true);
return Dcl;
}
void Sema::MaybeMarkVirtualImplicitMembersReferenced(SourceLocation Loc,
CXXMethodDecl *MD) {
// Ignore dependent types.
if (MD->isDependentContext())
return;
CXXRecordDecl *RD = MD->getParent();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
const CXXMethodDecl *KeyFunction = Layout.getKeyFunction();
if (!KeyFunction) {
// This record does not have a key function, so we assume that the vtable
// will be emitted when it's used by the constructor.
if (!isa<CXXConstructorDecl>(MD))
return;
} else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) {
// We don't have the right key function.
return;
}
if (CXXDestructorDecl *Dtor = RD->getDestructor(Context)) {
if (Dtor->isImplicit() && Dtor->isVirtual())
MarkDeclarationReferenced(Loc, Dtor);
}
// FIXME: Need to handle the virtual assignment operator here too.
}

View File

@ -775,8 +775,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
FunctionDecl* &Operator,
bool Diagnose) {
FunctionDecl* &Operator) {
LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName);
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, RD);
@ -796,8 +795,6 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
// We did find operator delete/operator delete[] declarations, but
// none of them were suitable.
if (!Found.empty()) {
if (!Diagnose)
return true;
Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
<< Name << RD;

View File

@ -0,0 +1,29 @@
// RUN: clang-cc -fsyntax-only -verify %s
struct A {
virtual ~A();
};
struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}}
virtual void f();
void operator delete (void *, int); // expected-note {{'operator delete' declared here}}
};
void B::f() { // expected-note {{implicit default destructor for 'struct B' first required here}}
}
struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
C();
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
};
C::C() { } // expected-note {{implicit default destructor for 'struct C' first required here}}
struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
};
void f() {
new D; // expected-note {{implicit default destructor for 'struct D' first required here}}
}