1 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=1 -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-IMPORT,CHECK-NO-NS,CHECK-IMPORT-NO-NS --implicit-check-not=unused |
2 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=1 -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-IMPORT,CHECK-NS,CHECK-IMPORT-NS --implicit-check-not=unused |
3 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=2 -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-NS --implicit-check-not=unused |
4 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=2 -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NS --implicit-check-not=unused |
5 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-NS --implicit-check-not=unused |
6 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NS --implicit-check-not=unused |
7 | |
8 | // Check that we behave sensibly when importing a header containing strong and |
9 | // weak, ordered and unordered global initializers. |
10 | // |
11 | // Our behavior is as follows: |
12 | // |
13 | // -- for variables with one or more specific points of initialization |
14 | // (non-template variables, whether or not they are inline or thread_local), |
15 | // emit them if (and only if) a header containing a point of initialization |
16 | // is transitively #included / imported. |
17 | // |
18 | // -- for variables with unordered initialization (any kind of templated |
19 | // variable -- excluding explicit specializations), emit them if any part |
20 | // of any module that triggers an instantiation is imported. |
21 | // |
22 | // The intent is to: |
23 | // |
24 | // 1) preserve order of initialization guarantees |
25 | // 2) preserve the behavior of globals with ctors in headers, and specifically |
26 | // of std::ios_base::Init (do not run the iostreams initializer nor force |
27 | // linking in the iostreams portion of the static library unless <iostream> |
28 | // is included) |
29 | // 3) behave conservatively-correctly with regard to unordered initializers: we |
30 | // might run them in cases where a traditional compilation would not, but |
31 | // will never fail to run them in cases where a traditional compilation |
32 | // would do so |
33 | // |
34 | // Perfect handling of unordered initializers would require tracking all |
35 | // submodules containing points of instantiation, which is very hard when those |
36 | // points of instantiation are within definitions that we skip because we |
37 | // already have a (non-visible) definition for the entity: |
38 | // |
39 | // // a.h |
40 | // template<typename> int v = f(); |
41 | // inline int get() { return v<int>; } |
42 | // |
43 | // // b.h |
44 | // template<typename> int v = f(); |
45 | // inline int get() { return v<int>; } |
46 | // |
47 | // If a.h and b.h are built as a module, we will only have a point of |
48 | // instantiation for v<int> in one of the two headers, because we will only |
49 | // parse one of the two get() functions. |
50 | |
51 | #pragma clang module build m |
52 | module m { |
53 | module a { |
54 | header "foo.h" { size 123 mtime 456789 } |
55 | } |
56 | module b {} |
57 | } |
58 | |
59 | #pragma clang module contents |
60 | #pragma clang module begin m.a |
61 | inline int non_trivial() { return 3; } |
62 | |
63 | #ifdef NS |
64 | namespace ns { |
65 | #endif |
66 | |
67 | int a = non_trivial(); |
68 | inline int b = non_trivial(); |
69 | thread_local int c = non_trivial(); |
70 | inline thread_local int d = non_trivial(); |
71 | |
72 | template<typename U> int e = non_trivial(); |
73 | template<typename U> inline int f = non_trivial(); |
74 | template<typename U> thread_local int g = non_trivial(); |
75 | template<typename U> inline thread_local int h = non_trivial(); |
76 | |
77 | inline int unused = 123; // should not be emitted |
78 | |
79 | template<typename T> struct X { |
80 | static int a; |
81 | static inline int b = non_trivial(); |
82 | static thread_local int c; |
83 | static inline thread_local int d = non_trivial(); |
84 | |
85 | template<typename U> static int e; |
86 | template<typename U> static inline int f = non_trivial(); |
87 | template<typename U> static thread_local int g; |
88 | template<typename U> static inline thread_local int h = non_trivial(); |
89 | |
90 | static inline int unused = 123; // should not be emitted |
91 | }; |
92 | |
93 | template<typename T> int X<T>::a = non_trivial(); |
94 | template<typename T> thread_local int X<T>::c = non_trivial(); |
95 | template<typename T> template<typename U> int X<T>::e = non_trivial(); |
96 | template<typename T> template<typename U> thread_local int X<T>::g = non_trivial(); |
97 | |
98 | inline void use(bool b, ...) { |
99 | if (b) return; |
100 | use(true, e<int>, f<int>, g<int>, h<int>, |
101 | X<int>::a, X<int>::b, X<int>::c, X<int>::d, |
102 | X<int>::e<int>, X<int>::f<int>, X<int>::g<int>, X<int>::h<int>); |
103 | } |
104 | |
105 | #ifdef NS |
106 | } |
107 | #endif |
108 | |
109 | #pragma clang module end |
110 | #pragma clang module endbuild |
111 | |
112 | #if IMPORT == 1 |
113 | // Import the module and the m.a submodule; runs the ordered initializers and |
114 | // the unordered initializers. |
115 | #pragma clang module import m.a |
116 | #elif IMPORT == 2 |
117 | // Import the module but not the m.a submodule; runs only the unordered |
118 | // initializers. |
119 | #pragma clang module import m.b |
120 | #else |
121 | // Load the module but do not import any submodules; runs only the unordered |
122 | // initializers. FIXME: Should this skip all of them? |
123 | #pragma clang module load m |
124 | #endif |
125 | |
126 | // CHECK-IMPORT-NO-NS-DAG: @[[A:a]] = global i32 0, align 4 |
127 | // CHECK-IMPORT-NO-NS-DAG: @[[B:b]] = linkonce_odr global i32 0, comdat, align 4 |
128 | // CHECK-IMPORT-NO-NS-DAG: @[[C:c]] = thread_local global i32 0, align 4 |
129 | // CHECK-IMPORT-NO-NS-DAG: @[[D:d]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
130 | // CHECK-NO-NS-DAG: @[[E:_Z1eIiE]] = linkonce_odr global i32 0, comdat, align 4 |
131 | // CHECK-NO-NS-DAG: @[[F:_Z1fIiE]] = linkonce_odr global i32 0, comdat, align 4 |
132 | // CHECK-NO-NS-DAG: @[[G:_Z1gIiE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
133 | // CHECK-NO-NS-DAG: @[[H:_Z1hIiE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
134 | |
135 | // CHECK-IMPORT-NS-DAG: @[[A:_ZN2ns1aE]] = global i32 0, align 4 |
136 | // CHECK-IMPORT-NS-DAG: @[[B:_ZN2ns1bE]] = linkonce_odr global i32 0, comdat, align 4 |
137 | // CHECK-IMPORT-NS-DAG: @[[BG:_ZGVN2ns1bE]] = linkonce_odr global i64 0, comdat($[[B]]), align 8 |
138 | // CHECK-IMPORT-NS-DAG: @[[C:_ZN2ns1cE]] = thread_local global i32 0, align 4 |
139 | // CHECK-IMPORT-NS-DAG: @[[D:_ZN2ns1dE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
140 | // CHECK-IMPORT-NS-DAG: @[[DG:_ZGVN2ns1dE]] = linkonce_odr thread_local global i64 0, comdat($[[D]]), align 8 |
141 | // CHECK-NS-DAG: @[[E:_ZN2ns1eIiEE]] = linkonce_odr global i32 0, comdat, align 4 |
142 | // CHECK-NS-DAG: @[[F:_ZN2ns1fIiEE]] = linkonce_odr global i32 0, comdat, align 4 |
143 | // CHECK-NS-DAG: @[[G:_ZN2ns1gIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
144 | // CHECK-NS-DAG: @[[H:_ZN2ns1hIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
145 | |
146 | // CHECK-DAG: @[[XA:_ZN(2ns)?1XIiE1aE]] = linkonce_odr global i32 0, comdat, align 4 |
147 | // CHECK-DAG: @[[XB:_ZN(2ns)?1XIiE1bE]] = linkonce_odr global i32 0, comdat, align 4 |
148 | // CHECK-DAG: @[[XC:_ZN(2ns)?1XIiE1cE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
149 | // CHECK-DAG: @[[XD:_ZN(2ns)?1XIiE1dE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
150 | // CHECK-DAG: @[[XE:_ZN(2ns)?1XIiE1eIiEE]] = linkonce_odr global i32 0, comdat, align 4 |
151 | // CHECK-DAG: @[[XF:_ZN(2ns)?1XIiE1fIiEE]] = linkonce_odr global i32 0, comdat, align 4 |
152 | // CHECK-DAG: @[[XG:_ZN(2ns)?1XIiE1gIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
153 | // CHECK-DAG: @[[XH:_ZN(2ns)?1XIiE1hIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
154 | |
155 | // It's OK if the order of the first 6 of these changes. |
156 | // CHECK: @llvm.global_ctors = appending global |
157 | // CHECK-SAME: @[[E_INIT:[^,]*]], {{[^@]*}} @[[E]] |
158 | // CHECK-SAME: @[[F_INIT:[^,]*]], {{[^@]*}} @[[F]] |
159 | // CHECK-SAME: @[[XA_INIT:[^,]*]], {{[^@]*}} @[[XA]] |
160 | // CHECK-SAME: @[[XE_INIT:[^,]*]], {{[^@]*}} @[[XE]] |
161 | // CHECK-SAME: @[[XF_INIT:[^,]*]], {{[^@]*}} @[[XF]] |
162 | // CHECK-SAME: @[[XB_INIT:[^,]*]], {{[^@]*}} @[[XB]] |
163 | // CHECK-IMPORT-SAME: @[[TU_INIT:[^,]*]], i8* null }] |
164 | |
165 | // FIXME: Should this use __cxa_guard_acquire? |
166 | // CHECK: define {{.*}} @[[E_INIT]]() |
167 | // CHECK: load {{.*}} (i64* @_ZGV |
168 | // CHECK: store {{.*}}, i32* @[[E]], |
169 | |
170 | // FIXME: Should this use __cxa_guard_acquire? |
171 | // CHECK: define {{.*}} @[[F_INIT]]() |
172 | // CHECK: load {{.*}} (i64* @_ZGV |
173 | // CHECK: store {{.*}}, i32* @[[F]], |
174 | |
175 | // CHECK: define {{.*}} @[[G_INIT:__cxx_global.*]]() |
176 | // CHECK: load {{.*}} (i64* @_ZGV |
177 | // CHECK: store {{.*}}, i32* @[[G]], |
178 | |
179 | // CHECK: define {{.*}} @[[H_INIT:__cxx_global.*]]() |
180 | // CHECK: load {{.*}} (i64* @_ZGV |
181 | // CHECK: store {{.*}}, i32* @[[H]], |
182 | |
183 | // FIXME: Should this use __cxa_guard_acquire? |
184 | // CHECK: define {{.*}} @[[XA_INIT]]() |
185 | // CHECK: load {{.*}} (i64* @_ZGV |
186 | // CHECK: store {{.*}}, i32* @[[XA]], |
187 | |
188 | // CHECK: define {{.*}} @[[XC_INIT:__cxx_global.*]]() |
189 | // CHECK: load {{.*}} (i64* @_ZGV |
190 | // CHECK: store {{.*}}, i32* @[[XC]], |
191 | |
192 | // FIXME: Should this use __cxa_guard_acquire? |
193 | // CHECK: define {{.*}} @[[XE_INIT]]() |
194 | // CHECK: load {{.*}} (i64* @_ZGV |
195 | // CHECK: store {{.*}}, i32* @[[XE]], |
196 | |
197 | // CHECK: define {{.*}} @[[XG_INIT:__cxx_global.*]]() |
198 | // CHECK: load {{.*}} (i64* @_ZGV |
199 | // CHECK: store {{.*}}, i32* @[[XG]], |
200 | |
201 | // CHECK: define {{.*}} @[[XH_INIT:__cxx_global.*]]() |
202 | // CHECK: load {{.*}} (i64* @_ZGV |
203 | // CHECK: store {{.*}}, i32* @[[XH]], |
204 | |
205 | // FIXME: Should this use __cxa_guard_acquire? |
206 | // CHECK: define {{.*}} @[[XF_INIT]]() |
207 | // CHECK: load {{.*}} (i64* @_ZGV |
208 | // CHECK: store {{.*}}, i32* @[[XF]], |
209 | |
210 | // CHECK: define {{.*}} @[[XD_INIT:__cxx_global.*]]() |
211 | // CHECK: load {{.*}} (i64* @_ZGV |
212 | // CHECK: store {{.*}}, i32* @[[XD]], |
213 | |
214 | // FIXME: Should this use __cxa_guard_acquire? |
215 | // CHECK: define {{.*}} @[[XB_INIT]]() |
216 | // CHECK: load {{.*}} (i64* @_ZGV |
217 | // CHECK: store {{.*}}, i32* @[[XB]], |
218 | |
219 | // CHECK-IMPORT: define {{.*}} @[[A_INIT:__cxx_global.*]]() |
220 | // CHECK-IMPORT: call i32 @_Z11non_trivialv( |
221 | // CHECK-IMPORT: store {{.*}}, i32* @[[A]], |
222 | |
223 | // CHECK-IMPORT: define {{.*}} @[[B_INIT:__cxx_global.*]]() |
224 | // CHECK-IMPORT: call i32 @__cxa_guard_acquire(i64* @_ZGV |
225 | // CHECK-IMPORT: store {{.*}}, i32* @[[B]], |
226 | |
227 | // CHECK-IMPORT: define {{.*}} @[[C_INIT:__cxx_global.*]]() |
228 | // CHECK-IMPORT: call i32 @_Z11non_trivialv( |
229 | // CHECK-IMPORT: store {{.*}}, i32* @[[C]], |
230 | |
231 | // CHECK-IMPORT: define {{.*}} @[[D_INIT:__cxx_global.*]]() |
232 | // CHECK-IMPORT: load {{.*}} (i64* @_ZGV |
233 | // CHECK-IMPORT: store {{.*}}, i32* @[[D]], |
234 | |
235 | |
236 | // CHECK-IMPORT: define {{.*}} @[[TU_INIT]]() |
237 | // CHECK-IMPORT: call void @[[A_INIT]]() |
238 | // CHECK-IMPORT: call void @[[B_INIT]]() |
239 | |
240 | // CHECK-IMPORT: define {{.*}} @__tls_init() |
241 | // CHECK-IMPORT: call void @[[C_INIT]]() |
242 | // CHECK-IMPORT: call void @[[D_INIT]]() |
243 | |