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 -emit-llvm -o - -O1 -disable-llvm-optzns | FileCheck %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-LABEL: define void @_ZThn8_N5Test11C1fEv(
f()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-LABEL: define void @_ZTv0_n24_N5Test21B1fEv(
f()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(
f()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-LABEL: define protected void @_ZThn8_N5Test41C1fEv(
f()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 }
c()106 void C::c() {}
f()107 void C::f() {}
108
109 // Force C::f to be used.
f()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 {
fTest5::B124 virtual void f() { }
125 };
126
f(B b)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
fTest6::Base1153 virtual X f() { return X(); }
154 };
155
156 struct Base2 {
157 float real;
158
fTest6::Base2159 virtual X f() { return X(); }
160 };
161
162 struct Thunks : Base1, Base2 {
163 long l;
164
165 virtual X f();
166 };
167
168 // CHECK-LABEL: define void @_ZThn16_N5Test66Thunks1fEv
169 // CHECK-NOT: memcpy
170 // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}}
171 // CHECK: ret void
f()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
foo()207 void foo() {}
bar()208 void bar() {}
209 void baz(X, X&, _Complex float, Small, Small&, Large);
210 };
211
baz(X,X &,_Complex float,Small,Small &,Large)212 void D::baz(X, X&, _Complex float, Small, Small&, Large) { }
213
214 // CHECK-LABEL: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE(
215 // CHECK-NOT: memcpy
216 // CHECK: ret void
testD()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:%.*]]*
helper(NonPOD var)227 void C::helper(NonPOD var) {}
228
229 // CHECK-LABEL: define void @_ZThn8_N5Test81C3barENS_6NonPODE(
230 // CHECK-NOT: load [[NONPODTYPE]]*
231 // CHECK-NOT: memcpy
232 // CHECK: ret void
bar(NonPOD var)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 {
~ATest9::A239 struct A { virtual ~A() { } };
testTest9::B240 struct B : A { virtual void test() const {} };
241 struct C : B { C(); ~C(); };
DTest9::D242 struct D : C { D() {} };
test()243 void test() {
244 D d;
245 }
246 }
247
248 namespace Test10 {
249 struct A { virtual void foo(); };
250 struct B { virtual void foo(); };
fooTest10::C251 struct C : A, B { void foo() {} };
252
253 // Test later.
test()254 void test() {
255 C c;
256 }
257 }
258
259 // PR7611
260 namespace Test11 {
261 struct A { virtual A* f(); };
262 struct B : virtual A { virtual A* f(); };
263 struct C : B { virtual C* f(); };
f()264 C* C::f() { return 0; }
265
266 // C::f itself.
267 // CHECK: define {{.*}} @_ZN6Test111C1fEv(
268
269 // The this-adjustment and return-adjustment thunk required when
270 // C::f appears in a vtable where A is at a nonzero offset from C.
271 // CHECK: define {{.*}} @_ZTcv0_n24_v0_n32_N6Test111C1fEv(
272
273 // The return-adjustment thunk required when C::f appears in a vtable
274 // where A is at a zero offset from C.
275 // CHECK: define {{.*}} @_ZTch0_v0_n32_N6Test111C1fEv(
276 }
277
278 // Varargs thunk test.
279 namespace Test12 {
280 struct A {
281 virtual A* f(int x, ...);
282 };
283 struct B {
284 virtual B* f(int x, ...);
285 };
286 struct C : A, B {
287 virtual void c();
288 virtual C* f(int x, ...);
289 };
f(int x,...)290 C* C::f(int x, ...) { return this; }
291
292 // C::f
293 // CHECK: define {{.*}} @_ZN6Test121C1fEiz
294
295 // Varargs thunk; check that both the this and covariant adjustments
296 // are generated.
297 // CHECK: define {{.*}} @_ZTchn8_h8_N6Test121C1fEiz
298 // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
299 // CHECK: getelementptr inbounds i8* {{.*}}, i64 8
300 }
301
302 // PR13832
303 namespace Test13 {
304 struct B1 {
305 virtual B1 &foo1();
306 };
307 struct Pad1 {
308 virtual ~Pad1();
309 };
310 struct Proxy1 : Pad1, B1 {
311 virtual ~Proxy1();
312 };
313 struct D : virtual Proxy1 {
314 virtual ~D();
315 virtual D &foo1();
316 };
foo1()317 D& D::foo1() {
318 return *this;
319 }
320 // CHECK: define {{.*}} @_ZTcvn8_n32_v8_n24_N6Test131D4foo1Ev
321 // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
322 // CHECK: getelementptr inbounds i8* {{.*}}, i64 -32
323 // CHECK: getelementptr inbounds i8* {{.*}}, i64 -24
324 // CHECK: getelementptr inbounds i8* {{.*}}, i64 8
325 // CHECK: ret %"struct.Test13::D"*
326 }
327
328 namespace Test14 {
329 class A {
330 virtual void f();
331 };
332 class B {
333 virtual void f();
334 };
335 class C : public A, public B {
336 virtual void f();
337 };
f()338 void C::f() {
339 }
340 // CHECK: define void @_ZThn8_N6Test141C1fEv({{.*}}) unnamed_addr [[NUW:#[0-9]+]]
341 }
342
343 // Varargs non-covariant thunk test.
344 // PR18098
345 namespace Test15 {
346 struct A {
347 virtual ~A();
348 };
349 struct B {
350 virtual void f(int x, ...);
351 };
352 struct C : A, B {
353 virtual void c();
354 virtual void f(int x, ...);
355 };
c()356 void C::c() {}
357
358 // C::c
359 // CHECK: declare void @_ZN6Test151C1fEiz
360 // non-virtual thunk to C::f
361 // CHECK: declare void @_ZThn8_N6Test151C1fEiz
362 }
363
364 /**** The following has to go at the end of the file ****/
365
366 // This is from Test10:
367 // CHECK-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv
368 // CHECK-LABEL: define linkonce_odr void @_ZThn8_N6Test101C3fooEv
369
370 // This is from Test5:
371 // CHECK-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
372 // CHECK-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(
373
374 // CHECK: attributes [[NUW]] = { nounwind uwtable{{.*}} }
375