Skip to content

Commit 47f81a8

Browse files
committed
[Cygwin][MinGW] Internal class in explicitly-instantiation-declarated template should be instantiated
In-code comment says "explicit instantiation decl of the outer class doesn't affect the inner class" but this behavior seems MSVC specific, MinGW-GCC and Cygwin-GCC does not. Clang should honor gcc's behavior. This change fixes std::string compatibilty and resolves strange link error (statically linked), strange crash (dynamically linked) using libstdc++ on Cygwin.
1 parent e5f8998 commit 47f81a8

File tree

2 files changed

+93
-17
lines changed

2 files changed

+93
-17
lines changed

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4247,6 +4247,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
42474247
continue;
42484248

42494249
if (Context.getTargetInfo().getTriple().isOSWindows() &&
4250+
!Context.getTargetInfo().getTriple().isOSCygMing() &&
42504251
TSK == TSK_ExplicitInstantiationDeclaration) {
42514252
// On Windows, explicit instantiation decl of the outer class doesn't
42524253
// affect the inner class. Typically extern template declarations are

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

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,121 @@
66
#define JOIN2(x, y) x##y
77
#define JOIN(x, y) JOIN2(x, y)
88
#define UNIQ(name) JOIN(name, __LINE__)
9-
#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; }
9+
#define USEMEMFUNC(class, func) auto UNIQ(use) = &class::func;
1010

1111
template <class T>
1212
class c {
13+
// MinGW-GCC does not apply 'dllexport' to inline member function in dll-exported template but clang does from long ago.
1314
void f() {}
15+
void g();
16+
inline static int u = 0;
17+
static int v;
1418
};
19+
template <class T> void c<T>::g() {}
20+
template <class T> int c<T>::v = 0;
1521

22+
// #1
1623
template class __declspec(dllexport) c<int>;
1724

18-
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
19-
25+
// #2
2026
extern template class __declspec(dllexport) c<char>;
2127
template class c<char>;
2228

23-
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
24-
29+
// #3
2530
extern template class c<double>;
26-
template class __declspec(dllexport) c<double>;
31+
template class __declspec(dllexport) c<double>; // expected-warning {{ 'dllexport' attribute ignored on explicit instantiation definition }}
2732

28-
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
2933

3034
template <class T>
3135
struct outer {
32-
void f();
36+
void f() {}
37+
void g();
38+
inline static int u = 0;
39+
static int v;
40+
// MinGW-GCC and Clang does not apply 'dllexport' to inner type and its sub-elements in template class.
3341
struct inner {
34-
void f();
42+
void f() {}
43+
void g();
44+
inline static int u = 0;
45+
static int v;
3546
};
3647
};
3748

38-
template <class T> void outer<T>::f() {}
39-
template <class T> void outer<T>::inner::f() {}
49+
template <class T> void outer<T>::g() {}
50+
template <class T> void outer<T>::inner::g() {}
51+
template <class T> int outer<T>::v = 0;
52+
template <class T> int outer<T>::inner::v = 0;
4053

41-
template class __declspec(dllexport) outer<int>;
54+
// #4
55+
template struct __declspec(dllexport) outer<int>;
4256

43-
// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
44-
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv
45-
46-
extern template class __declspec(dllimport) outer<char>;
57+
// #5
58+
extern template struct __declspec(dllimport) outer<char>;
4759
USEMEMFUNC(outer<char>, f)
60+
USEMEMFUNC(outer<char>, g)
61+
USEMEMFUNC(outer<char>, u)
62+
USEMEMFUNC(outer<char>, v)
4863
USEMEMFUNC(outer<char>::inner, f)
64+
USEMEMFUNC(outer<char>::inner, g)
65+
USEMEMFUNC(outer<char>::inner, u)
66+
USEMEMFUNC(outer<char>::inner, v)
67+
68+
69+
// #1 variables
70+
// CHECK: @_ZN1cIiE1uE = {{.*}} dllexport {{.*}}
71+
// CHECK: @_ZN1cIiE1vE = {{.*}} dllexport {{.*}}
72+
73+
// #2 variables
74+
// CHECK: @_ZN1cIcE1uE = {{.*}} dllexport {{.*}}
75+
// CHECK: @_ZN1cIcE1vE = {{.*}} dllexport {{.*}}
76+
77+
// #3 variables
78+
// CHECK: @_ZN1cIdE1uE = {{.*}}
79+
// CHECK-NOT: @_ZN1cIcE1uE = {{.*}} dllexport {{.*}}
80+
// CHECK: @_ZN1cIdE1vE = {{.*}}
81+
// CHECK-NOT: @_ZN1cIcE1vE = {{.*}} dllexport {{.*}}
82+
83+
// #4 variables
84+
// CHECK: @_ZN5outerIiE1uE = {{.*}} dllexport {{.*}}
85+
// CHECK: @_ZN5outerIiE1vE = {{.*}} dllexport {{.*}}
86+
// CHECK: @_ZN5outerIiE5inner1uE = {{.*}}
87+
// CHECK-NOT: @_ZN5outerIiE5inner1uE = {{.*}} dllexport {{.*}}
88+
// CHECK: @_ZN5outerIiE5inner1vE = {{.*}}
89+
// CHECK-NOT: @_ZN5outerIiE5inner1vE = {{.*}} dllexport {{.*}}
90+
91+
// #5 variables
92+
// CHECK: @_ZN5outerIcE1uE = external dllimport {{.*}}
93+
// CHECK: @_ZN5outerIcE1vE = external dllimport {{.*}}
94+
// CHECK-NOT: @_ZN5outerIcE5inner1uE = dllimport {{.*}}
95+
// CHECK-NOT: @_ZN5outerIcE5inner1vE = dllimport {{.*}}
96+
// CHECK: @_ZN5outerIcE5inner1uE = external {{.*}}
97+
// CHECK: @_ZN5outerIcE5inner1vE = external {{.*}}
98+
99+
100+
// #1 functions
101+
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
102+
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1gEv
103+
104+
// #2 functions
105+
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
106+
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1gEv
107+
108+
// #3 functions
109+
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
110+
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1gEv
111+
112+
// #4 functions
113+
// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
114+
// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1gEv
115+
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv
116+
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1gEv
49117

118+
// #5 functions
50119
// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv
51-
// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv
120+
// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1gEv
121+
// CHECK-NOT: declare dllimport {{.*}} @_ZN5outerIcE5inner1fEv
122+
// CHECK-NOT: declare dllimport {{.*}} @_ZN5outerIcE5inner1gEv
123+
// CHECK-NOT: define {{.*}} @_ZN5outerIcE1fEv
124+
// CHECK-NOT: define {{.*}} @_ZN5outerIcE5inner1fEv
125+
// CHECK-NOT: define {{.*}} @_ZN5outerIcE1gEv
126+
// CHECK-NOT: define {{.*}} @_ZN5outerIcE5inner1gEv

0 commit comments

Comments
 (0)