]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | // RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - | FileCheck %s |
2 | // RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=HIDDEN %s | |
3 | ||
4 | namespace Test1 { | |
5 | ||
6 | // Check that we emit a non-virtual thunk for C::f. | |
7 | ||
8 | struct A { | |
9 | virtual void f(); | |
10 | }; | |
11 | ||
12 | struct B { | |
13 | virtual void f(); | |
14 | }; | |
15 | ||
16 | struct C : A, B { | |
17 | virtual void c(); | |
18 | ||
19 | virtual void f(); | |
20 | }; | |
21 | ||
22 | // CHECK: define void @_ZThn8_N5Test11C1fEv( | |
23 | void C::f() { } | |
24 | ||
25 | } | |
26 | ||
27 | namespace Test2 { | |
28 | ||
29 | // Check that we emit a thunk for B::f since it's overriding a virtual base. | |
30 | ||
31 | struct A { | |
32 | virtual void f(); | |
33 | }; | |
34 | ||
35 | struct B : virtual A { | |
36 | virtual void b(); | |
37 | virtual void f(); | |
38 | }; | |
39 | ||
40 | // CHECK: define void @_ZTv0_n24_N5Test21B1fEv( | |
41 | void B::f() { } | |
42 | ||
43 | } | |
44 | ||
45 | namespace Test3 { | |
46 | ||
47 | // Check that we emit a covariant thunk for B::f. | |
48 | ||
49 | struct V1 { }; | |
50 | struct V2 : virtual V1 { }; | |
51 | ||
52 | struct A { | |
53 | virtual V1 *f(); | |
54 | }; | |
55 | ||
56 | struct B : A { | |
57 | virtual void b(); | |
58 | ||
59 | virtual V2 *f(); | |
60 | }; | |
61 | ||
62 | // CHECK: define %{{.*}}* @_ZTch0_v0_n24_N5Test31B1fEv( | |
63 | V2 *B::f() { return 0; } | |
64 | ||
65 | } | |
66 | ||
67 | namespace Test4 { | |
68 | ||
69 | // Check that the thunk for 'C::f' has the same visibility as the function itself. | |
70 | ||
71 | struct A { | |
72 | virtual void f(); | |
73 | }; | |
74 | ||
75 | struct B { | |
76 | virtual void f(); | |
77 | }; | |
78 | ||
79 | struct __attribute__((visibility("protected"))) C : A, B { | |
80 | virtual void c(); | |
81 | ||
82 | virtual void f(); | |
83 | }; | |
84 | ||
85 | // CHECK: define protected void @_ZThn8_N5Test41C1fEv( | |
86 | void C::f() { } | |
87 | ||
88 | } | |
89 | ||
90 | // Check that the thunk gets internal linkage. | |
91 | namespace Test4B { | |
92 | struct A { | |
93 | virtual void f(); | |
94 | }; | |
95 | ||
96 | struct B { | |
97 | virtual void f(); | |
98 | }; | |
99 | ||
100 | namespace { | |
101 | struct C : A, B { | |
102 | virtual void c(); | |
103 | virtual void f(); | |
104 | }; | |
105 | } | |
106 | void C::c() {} | |
107 | void C::f() {} | |
108 | ||
109 | // Force C::f to be used. | |
110 | void f() { | |
111 | C c; | |
112 | c.f(); | |
113 | } | |
114 | } | |
115 | ||
116 | namespace Test5 { | |
117 | ||
118 | // Check that the thunk for 'B::f' gets the same linkage as the function itself. | |
119 | struct A { | |
120 | virtual void f(); | |
121 | }; | |
122 | ||
123 | struct B : virtual A { | |
124 | virtual void f() { } | |
125 | }; | |
126 | ||
127 | void f(B b) { | |
128 | b.f(); | |
129 | } | |
130 | } | |
131 | ||
132 | namespace Test6 { | |
133 | struct X { | |
134 | X(); | |
135 | X(const X&); | |
136 | X &operator=(const X&); | |
137 | ~X(); | |
138 | }; | |
139 | ||
140 | struct P { | |
141 | P(); | |
142 | P(const P&); | |
143 | ~P(); | |
144 | X first; | |
145 | X second; | |
146 | }; | |
147 | ||
148 | P getP(); | |
149 | ||
150 | struct Base1 { | |
151 | int i; | |
152 | ||
153 | virtual X f() { return X(); } | |
154 | }; | |
155 | ||
156 | struct Base2 { | |
157 | float real; | |
158 | ||
159 | virtual X f() { return X(); } | |
160 | }; | |
161 | ||
162 | struct Thunks : Base1, Base2 { | |
163 | long l; | |
164 | ||
165 | virtual X f(); | |
166 | }; | |
167 | ||
168 | // CHECK: define void @_ZThn16_N5Test66Thunks1fEv | |
169 | // CHECK-NOT: memcpy | |
170 | // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}} | |
171 | // CHECK: ret void | |
172 | X Thunks::f() { return X(); } | |
173 | } | |
174 | ||
175 | namespace Test7 { | |
176 | // PR7188 | |
177 | struct X { | |
178 | X(); | |
179 | X(const X&); | |
180 | X &operator=(const X&); | |
181 | ~X(); | |
182 | }; | |
183 | ||
184 | struct Small { short s; }; | |
185 | struct Large { | |
186 | char array[1024]; | |
187 | }; | |
188 | ||
189 | class A { | |
190 | protected: | |
191 | virtual void foo() = 0; | |
192 | }; | |
193 | ||
194 | class B : public A { | |
195 | protected: | |
196 | virtual void bar() = 0; | |
197 | }; | |
198 | ||
199 | class C : public A { | |
200 | protected: | |
201 | virtual void baz(X, X&, _Complex float, Small, Small&, Large) = 0; | |
202 | }; | |
203 | ||
204 | class D : public B, | |
205 | public C { | |
206 | ||
207 | void foo() {} | |
208 | void bar() {} | |
209 | void baz(X, X&, _Complex float, Small, Small&, Large); | |
210 | }; | |
211 | ||
212 | void D::baz(X, X&, _Complex float, Small, Small&, Large) { } | |
213 | ||
214 | // CHECK: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE( | |
215 | // CHECK-NOT: memcpy | |
216 | // CHECK: ret void | |
217 | void testD() { D d; } | |
218 | } | |
219 | ||
220 | namespace Test8 { | |
221 | struct NonPOD { ~NonPOD(); int x, y, z; }; | |
222 | struct A { virtual void foo(); }; | |
223 | struct B { virtual void bar(NonPOD); }; | |
224 | struct C : A, B { virtual void bar(NonPOD); static void helper(NonPOD); }; | |
225 | ||
226 | // CHECK: define void @_ZN5Test81C6helperENS_6NonPODE([[NONPODTYPE:%.*]]* | |
227 | void C::helper(NonPOD var) {} | |
228 | ||
229 | // CHECK: define void @_ZThn8_N5Test81C3barENS_6NonPODE( | |
230 | // CHECK-NOT: load [[NONPODTYPE]]* | |
231 | // CHECK-NOT: memcpy | |
232 | // CHECK: ret void | |
233 | void C::bar(NonPOD var) {} | |
234 | } | |
235 | ||
236 | // PR7241: Emitting thunks for a method shouldn't require the vtable for | |
237 | // that class to be emitted. | |
238 | namespace Test9 { | |
239 | struct A { virtual ~A() { } }; | |
240 | struct B : A { virtual void test() const {} }; | |
241 | struct C : B { C(); ~C(); }; | |
242 | struct D : C { D() {} }; | |
243 | void test() { | |
244 | D d; | |
245 | } | |
246 | } | |
247 | ||
248 | namespace Test10 { | |
249 | struct A { virtual void foo(); }; | |
250 | struct B { virtual void foo(); }; | |
251 | struct C : A, B { void foo() {} }; | |
252 | ||
253 | // CHECK-HIDDEN: define linkonce_odr void @_ZN6Test101C3fooEv | |
254 | // CHECK-HIDDEN: define linkonce_odr hidden void @_ZThn8_N6Test101C3fooEv | |
255 | ||
256 | void test() { | |
257 | C c; | |
258 | } | |
259 | } | |
260 | ||
261 | // PR7611 | |
262 | namespace Test11 { | |
263 | struct A { virtual A* f(); }; | |
264 | struct B : virtual A { virtual A* f(); }; | |
265 | struct C : B { virtual C* f(); }; | |
266 | C* C::f() { return 0; } | |
267 | ||
268 | // C::f itself. | |
269 | // CHECK: define {{.*}} @_ZN6Test111C1fEv( | |
270 | ||
271 | // The this-adjustment and return-adjustment thunk required when | |
272 | // C::f appears in a vtable where A is at a nonzero offset from C. | |
273 | // CHECK: define {{.*}} @_ZTcv0_n24_v0_n32_N6Test111C1fEv( | |
274 | ||
275 | // The return-adjustment thunk required when C::f appears in a vtable | |
276 | // where A is at a zero offset from C. | |
277 | // CHECK: define {{.*}} @_ZTch0_v0_n32_N6Test111C1fEv( | |
278 | } | |
279 | ||
280 | // Varargs thunk test. | |
281 | namespace Test12 { | |
282 | struct A { | |
283 | virtual A* f(int x, ...); | |
284 | }; | |
285 | struct B { | |
286 | virtual B* f(int x, ...); | |
287 | }; | |
288 | struct C : A, B { | |
289 | virtual void c(); | |
290 | virtual C* f(int x, ...); | |
291 | }; | |
292 | C* C::f(int x, ...) { return this; } | |
293 | ||
294 | // C::f | |
295 | // CHECK: define {{.*}} @_ZN6Test121C1fEiz | |
296 | ||
297 | // Varargs thunk; check that both the this and covariant adjustments | |
298 | // are generated. | |
299 | // CHECK: define {{.*}} @_ZTchn8_h8_N6Test121C1fEiz | |
300 | // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 | |
301 | // CHECK: getelementptr inbounds i8* {{.*}}, i64 8 | |
302 | } | |
303 | ||
304 | // PR13832 | |
305 | namespace Test13 { | |
306 | struct B1 { | |
307 | virtual B1 &foo1(); | |
308 | }; | |
309 | struct Pad1 { | |
310 | virtual ~Pad1(); | |
311 | }; | |
312 | struct Proxy1 : Pad1, B1 { | |
313 | virtual ~Proxy1(); | |
314 | }; | |
315 | struct D : virtual Proxy1 { | |
316 | virtual ~D(); | |
317 | virtual D &foo1(); | |
318 | }; | |
319 | D& D::foo1() { | |
320 | return *this; | |
321 | } | |
322 | // CHECK: define {{.*}} @_ZTcvn8_n32_v8_n24_N6Test131D4foo1Ev | |
323 | // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 | |
324 | // CHECK: getelementptr inbounds i8* {{.*}}, i64 -32 | |
325 | // CHECK: getelementptr inbounds i8* {{.*}}, i64 -24 | |
326 | // CHECK: getelementptr inbounds i8* {{.*}}, i64 8 | |
327 | // CHECK: ret %"struct.Test13::D"* | |
328 | } | |
329 | ||
330 | namespace Test14 { | |
331 | class A { | |
332 | virtual void f(); | |
333 | }; | |
334 | class B { | |
335 | virtual void f(); | |
336 | }; | |
337 | class C : public A, public B { | |
338 | virtual void f(); | |
339 | }; | |
340 | void C::f() { | |
341 | } | |
342 | // CHECK: define void @_ZThn8_N6Test141C1fEv({{.*}}) {{.*}} uwtable | |
343 | } | |
344 | ||
345 | /**** The following has to go at the end of the file ****/ | |
346 | ||
347 | // This is from Test5: | |
348 | // CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv | |
349 | // CHECK: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv( |