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