• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(
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: 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: 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: 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: 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: 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   // CHECK-HIDDEN: define linkonce_odr void @_ZN6Test101C3fooEv
254   // CHECK-HIDDEN: define linkonce_odr hidden void @_ZThn8_N6Test101C3fooEv
255 
test()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(); };
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   };
f(int x,...)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   };
foo1()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   };
f()340   void C::f() {
341   }
342   // CHECK: define void @_ZThn8_N6Test141C1fEv({{.*}}) unnamed_addr [[NUW:#[0-9]+]]
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(
350 
351 // CHECK: attributes [[NUW]] = { nounwind uwtable{{.*}} }
352