[cfe-commits] r90327 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/AST/RecordLayoutBuilder.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/implicit-virtual-member-functions.cpp
Anders Carlsson
andersca at mac.com
Wed Dec 2 09:15:43 PST 2009
Author: andersca
Date: Wed Dec 2 11:15:43 2009
New Revision: 90327
URL: http://llvm.org/viewvc/llvm-project?rev=90327&view=rev
Log:
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.
Added:
cfe/trunk/test/SemaCXX/implicit-virtual-member-functions.cpp
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=90327&r1=90326&r2=90327&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Dec 2 11:15:43 2009
@@ -660,7 +660,7 @@
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.
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=90327&r1=90326&r2=90327&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Dec 2 11:15:43 2009
@@ -507,8 +507,7 @@
return 0;
}
-const CXXDestructorDecl *
-CXXRecordDecl::getDestructor(ASTContext &Context) {
+CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) {
QualType ClassType = Context.getTypeDeclType(this);
DeclarationName Name
@@ -519,7 +518,7 @@
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;
Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=90327&r1=90326&r2=90327&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Wed Dec 2 11:15:43 2009
@@ -677,6 +677,11 @@
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;
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=90327&r1=90326&r2=90327&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Dec 2 11:15:43 2009
@@ -1932,8 +1932,7 @@
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 @@
/// 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 @@
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);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=90327&r1=90326&r2=90327&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Dec 2 11:15:43 2009
@@ -4085,12 +4085,14 @@
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");
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=90327&r1=90326&r2=90327&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Dec 2 11:15:43 2009
@@ -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 @@
ClassDecl->addDecl(Destructor);
AddOverriddenMethods(ClassDecl, Destructor);
- CheckDestructor(Destructor, false);
}
}
@@ -2371,7 +2371,7 @@
/// 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 @@
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 @@
} else {
Constructor->setUsed();
}
- return;
+
+ MaybeMarkVirtualImplicitMembersReferenced(CurrentLocation, Constructor);
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -4994,3 +4995,31 @@
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.
+}
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=90327&r1=90326&r2=90327&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Dec 2 11:15:43 2009
@@ -775,8 +775,7 @@
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 @@
// 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;
Added: cfe/trunk/test/SemaCXX/implicit-virtual-member-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-virtual-member-functions.cpp?rev=90327&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/implicit-virtual-member-functions.cpp (added)
+++ cfe/trunk/test/SemaCXX/implicit-virtual-member-functions.cpp Wed Dec 2 11:15:43 2009
@@ -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}}
+}
+
More information about the cfe-commits
mailing list