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