Improve key-function computation for templates. In particular:
- All classes can have a key function; templates don't change that.
non-template classes when computing the key function.
- We always mark all of the virtual member functions of class
template instantiations.
- The vtable for an instantiation of a class template has weak
linkage.
We could probably use available_externally linkage for vtables of
classes instantiated by explicit instantiation declarations (extern
templates), but GCC doesn't do this and I'm not 100% that the ABI
permits it.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92753 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index bbbb19a..b30d335 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -643,23 +643,15 @@
return C.getPointerType(ClassTy);
}
-static bool MethodHasBody(const CXXMethodDecl *MD, const FunctionDecl *&fn) {
- // Simple case: function has a body
- if (MD->getBody(fn))
- return true;
-
- // Complex case: function is an instantiation of a function which has a
- // body, but the definition hasn't been instantiated.
- const FunctionDecl *PatternDecl = MD->getTemplateInstantiationPattern();
- if (PatternDecl && PatternDecl->getBody(fn))
- return true;
-
- return false;
-}
-
bool CXXMethodDecl::hasInlineBody() const {
+ // If this function is a template instantiation, look at the template from
+ // which it was instantiated.
+ const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
+ if (!CheckFn)
+ CheckFn = this;
+
const FunctionDecl *fn;
- return MethodHasBody(this, fn) && !fn->isOutOfLine();
+ return CheckFn->getBody(fn) && !fn->isOutOfLine();
}
CXXBaseOrMemberInitializer::
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index c914f3f..cfd89ea 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -719,11 +719,6 @@
// If a class isnt' polymorphic it doesn't have a key function.
if (!RD->isPolymorphic())
return 0;
-
- // A class template specialization or instantation does not have a key
- // function.
- if (RD->getTemplateSpecializationKind() != TSK_Undeclared)
- return 0;
// A class inside an anonymous namespace doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
@@ -741,13 +736,13 @@
if (MD->isPure())
continue;
- if (MD->isInlineSpecified())
- 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;
+
+ if (MD->isInlineSpecified())
+ continue;
if (MD->hasInlineBody())
continue;
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index ba5a0c3..ca148da 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -1493,8 +1493,22 @@
llvm::GlobalVariable::LinkageTypes Linkage;
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
Linkage = llvm::GlobalVariable::InternalLinkage;
- else if (KeyFunction && !MD->isInlined())
- Linkage = llvm::GlobalVariable::ExternalLinkage;
+ else if (KeyFunction && !MD->isInlined()) {
+ switch (MD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ Linkage = llvm::GlobalVariable::ExternalLinkage;
+ break;
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ // FIXME: could an explicit instantiation declaration imply
+ // available_externally linkage?
+ case TSK_ExplicitInstantiationDefinition:
+ Linkage = llvm::GlobalVariable::WeakODRLinkage;
+ break;
+ }
+ }
else
Linkage = llvm::GlobalVariable::WeakODRLinkage;
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 16a01cf..85d57e7 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -547,7 +547,8 @@
const CXXRecordDecl *RD = MD->getParent();
if (MD->isOutOfLine() && RD->isDynamicClass()) {
const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD);
- if (KeyFunction == MD->getCanonicalDecl())
+ if (KeyFunction &&
+ KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
return false;
}
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a15c5fe..0fc61e3 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3749,7 +3749,7 @@
if (getLangOptions().CPlusPlus) {
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
- if (const ArrayType *Array = Context.getAsArrayType(InitType))
+ while (const ArrayType *Array = Context.getAsArrayType(InitType))
InitType = Context.getBaseElementType(Array);
if (InitType->isRecordType())
FinalizeVarWithDestructor(VDecl, InitType);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 204d776..ecf95d7 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -5702,19 +5702,31 @@
ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc));
return;
}
-
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
- 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))
+ switch (RD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization: {
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
+
+ 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;
- } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) {
- // We don't have the right key function.
- return;
+ }
+ break;
}
-
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ // Always mark the virtual members of an instantiated template.
+ break;
+ }
+
// Mark the members as referenced.
MarkVirtualMembersReferenced(Loc, RD);
ClassesWithUnmarkedVirtualMembers.erase(RD);