At a high level there are two things we have to decide about templates
and vtables
*) When do we *must* produce a vtable
*) When we don't have too, how much effort do we want to put to avoid it
On a IRC discussion we agreed that for
template<typename T>
class C {
virtual ~C() { }
void foo();
};
template<>
void C<char>::foo() {
}
we should produce a vtable, otherwise we would force the user to use
an explicit template instantiation definition (as gcc effectively
does).
Given the above decision it is interesting to consider what we should
do when the above example is followed by
extern template C<char>;
* Should we change our mind and not produce a vtable?
* If producing a vtable, should we also irgen the methods?
Currently we produce the vtable and *some* methods. The reason we
produce some is a bug in how we handle implicit methods.
On the first item, I think that we *should* emit the vtable, otherwise
things would get really complicated. For example, we would have to
force vtable emission on explicit template instantiation declarations.
On the second item, we are already delaying the vtable emission
anyway, I think we should use the opportunity to avoid emitting
functions we don't need. The attached patch fixes that for implicit
methods. The patch has 3 parts (other than the test)
* Propagate the fact that we have seen the extern template
(Sema::ActOnExplicitInstantiation)
* Don't get eager in the codegen when we see a
TSK_ExplicitInstantiationDeclaration (CGVtableInfo::MaybeEmitVtable).
* Correctly handle implicitly declare methods in GetLinkageForFunction.
The patch is clean on "make test". Is it OK if it also passes a bootstrap?
Cheers,
--
Rafael Ávila de Espíndola
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 49dbd29..9287e10 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -3804,7 +3804,17 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
return;
TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
- if (kind == TSK_ImplicitInstantiation)
+
+
+ // The reason we have TSK_ExplicitInstantiationDeclaration in here (but not
+ // in Sema::MaybeMarkVirtualMembersReferenced) is for the case
+ // template<> void stdio_sync_filebuf<wchar_t>::xsgetn() {
+ // }
+ // extern template class stdio_sync_filebuf<wchar_t>;
+ // Since we are called after the extern declaration is seen.
+
+ if (kind == TSK_ImplicitInstantiation ||
+ kind == TSK_ExplicitInstantiationDeclaration)
CGM.DeferredVtables.push_back(RD);
else
GenerateClassData(CGM.getVtableLinkage(RD), RD);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index b4b5bbd..9879d31 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -310,8 +310,16 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
// instantiated when used so that the body can be considered for
// inlining, but that no out-of-line copy of the inline function would be
// generated in the translation unit. -- end note ]
- if (FD->getTemplateSpecializationKind()
- == TSK_ExplicitInstantiationDeclaration)
+
+ // We check the specialization kind of the class so that we do the correct thing
+ // for implicit methods. They have a TSK_Undeclared kind.
+ TemplateSpecializationKind TSK;
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ TSK = MD->getParent()->getTemplateSpecializationKind();
+ else
+ TSK = FD->getTemplateSpecializationKind();
+
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
return CodeGenModule::GVA_C99Inline;
return CodeGenModule::GVA_CXXInline;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index abe9363..d7b613e 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4389,13 +4389,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Def = cast_or_null<ClassTemplateSpecializationDecl>(
Specialization->getDefinition());
if (Def) {
- TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind();
-
- // Fix a TSK_ExplicitInstantiationDeclaration followed by a
- // TSK_ExplicitInstantiationDefinition
- if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
- TSK == TSK_ExplicitInstantiationDefinition)
- Def->setTemplateSpecializationKind(TSK);
+ Def->setTemplateSpecializationKind(TSK);
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
}
diff --git a/test/CodeGenCXX/PR6677.cpp b/test/CodeGenCXX/PR6677.cpp
index 8d168f1..d649867 100644
--- a/test/CodeGenCXX/PR6677.cpp
+++ b/test/CodeGenCXX/PR6677.cpp
@@ -13,7 +13,12 @@ namespace test0 {
};
// This specialization should cause the vtable to be emitted, even with
- // the following extern template declaration.
+ // the following extern template declaration (test at the top).
+
+ // The existance of the extern template declaration should prevent us from emitting
+ // destructors.
+ // CHECK: define available_externally void @_ZN5test018stdio_sync_filebufIwED0Ev
+ // CHECK: define available_externally void @_ZN5test018stdio_sync_filebufIwED2Ev
template<> void stdio_sync_filebuf<wchar_t>::xsgetn() {
}
extern template class stdio_sync_filebuf<wchar_t>;
@@ -28,6 +33,6 @@ namespace test1 {
virtual void xsgetn();
};
- // Just a declaration should not force the vtable to be emitted.
+ // Just a declaration should not force the vtable to be emitted (test at the top).
template<> void stdio_sync_filebuf<wchar_t>::xsgetn();
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits