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
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 98880e9..2b48efb 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -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);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 76b726f..5a7d006 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -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");
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 7df86ee..4db769b 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 @@
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.
+}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index f5f712a..148dc63 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -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;