diff options
author | Anders Carlsson <andersca@mac.com> | 2009-12-02 17:15:43 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-12-02 17:15:43 +0000 |
commit | 5ec02ae147760c32ad5b6fb0fec30ab3b3696778 (patch) | |
tree | 736264c2e86ceee0eb74e0904281a7a9df25cb9a | |
parent | f59ef9668d9ac7ae319d751a7cd4ed671525abfe (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90327 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclCXX.h | 2 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 5 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 37 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 5 | ||||
-rw-r--r-- | test/SemaCXX/implicit-virtual-member-functions.cpp | 29 |
8 files changed, 84 insertions, 18 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 10ed99a189..87a47fec6b 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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. diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index d850e4fd0a..c98b3f078b 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 326a1dcd27..3a1e248dbc 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -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; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 98880e9d5f..2b48efb495 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 76b726fe33..5a7d006043 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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"); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 7df86ee66c..4db769bd91 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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. +} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index f5f712a0a5..148dc63944 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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; diff --git a/test/SemaCXX/implicit-virtual-member-functions.cpp b/test/SemaCXX/implicit-virtual-member-functions.cpp new file mode 100644 index 0000000000..30fe2786ba --- /dev/null +++ b/test/SemaCXX/implicit-virtual-member-functions.cpp @@ -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}} +} + |