forked from OSchip/llvm-project
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:
parent
fffbc0c5d9
commit
f98849eb8a
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
Loading…
Reference in New Issue