Skip to content

Commit da93dec

Browse files
committed
[MinGW] Don't let template instantiation declarations cover nested classes
An explicit template instantiation declaration used to let callers assume both outer and nested classes instantiations were defined in a different translation unit. If the instantiation is marked dllexport, only the outer class is exported, but the caller will try to reference the instantiation of both outer and inner classes. This makes MinGW mode match both MSVC and Windows Itanium, by having instantations only cover the outer class, and locally emitting definitions of the nested classes. Windows Itanium was changed to use this behavious in SVN r300804. This deviates from what GCC does, but should be safe (and only inflate the object file size a bit, but MSVC and Windows Itanium modes do the same), and fixes cases where inner classes aren't dllexported. This fixes missing references in combination with dllexported/imported template intantiations. GCC suffers from the same issue, reported at [1], but the issue is still unresolved there. The issue can probably be solved either by making dllexport cover all nested classes as well, or this way (matching MSVC). [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89087 Differential Revision: https://reviews.llvm.org/D61175 llvm-svn: 359342
1 parent c03fe73 commit da93dec

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2685,10 +2685,14 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
26852685
continue;
26862686

26872687
if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
2688-
Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) &&
2688+
Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment() ||
2689+
Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) &&
26892690
TSK == TSK_ExplicitInstantiationDeclaration) {
26902691
// In MSVC and Windows Itanium mode, explicit instantiation decl of the
26912692
// outer class doesn't affect the inner class.
2693+
// In GNU mode, inner classes aren't dllexported. Don't let the
2694+
// instantiation cover the inner class, to avoid undefined references
2695+
// to inner classes that weren't exported.
26922696
continue;
26932697
}
26942698

clang/test/CodeGenCXX/mingw-template-dllexport.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
// RUN: %clang_cc1 -emit-llvm -triple i686-mingw32 %s -o - | FileCheck %s
22

3+
#define JOIN2(x, y) x##y
4+
#define JOIN(x, y) JOIN2(x, y)
5+
#define UNIQ(name) JOIN(name, __LINE__)
6+
#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; }
7+
38
template <class T>
49
class c {
510
void f();
@@ -36,3 +41,10 @@ template class __declspec(dllexport) outer<int>;
3641

3742
// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
3843
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv
44+
45+
extern template class __declspec(dllimport) outer<char>;
46+
USEMEMFUNC(outer<char>, f)
47+
USEMEMFUNC(outer<char>::inner, f)
48+
49+
// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv
50+
// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv

0 commit comments

Comments
 (0)