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
4namespace Test1 {
5
6// Check that we emit a non-virtual thunk for C::f.
7
8struct A {
9  virtual void f();
10};
11
12struct B {
13  virtual void f();
14};
15
16struct C : A, B {
17  virtual void c();
18
19  virtual void f();
20};
21
22// CHECK-LABEL: define void @_ZThn8_N5Test11C1fEv(
23void C::f() { }
24
25}
26
27namespace Test2 {
28
29// Check that we emit a thunk for B::f since it's overriding a virtual base.
30
31struct A {
32  virtual void f();
33};
34
35struct B : virtual A {
36  virtual void b();
37  virtual void f();
38};
39
40// CHECK-LABEL: define void @_ZTv0_n24_N5Test21B1fEv(
41void B::f() { }
42
43}
44
45namespace Test3 {
46
47// Check that we emit a covariant thunk for B::f.
48
49struct V1 { };
50struct V2 : virtual V1 { };
51
52struct A {
53  virtual V1 *f();
54};
55
56struct B : A {
57  virtual void b();
58
59  virtual V2 *f();
60};
61
62// CHECK: define %{{.*}}* @_ZTch0_v0_n24_N5Test31B1fEv(
63V2 *B::f() { return 0; }
64
65}
66
67namespace Test4 {
68
69// Check that the thunk for 'C::f' has the same visibility as the function itself.
70
71struct A {
72  virtual void f();
73};
74
75struct B {
76  virtual void f();
77};
78
79struct __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(
86void C::f() { }
87
88}
89
90// Check that the thunk gets internal linkage.
91namespace 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
116namespace Test5 {
117
118// Check that the thunk for 'B::f' gets the same linkage as the function itself.
119struct A {
120  virtual void f();
121};
122
123struct B : virtual A {
124  virtual void f() { }
125};
126
127void f(B b) {
128  b.f();
129}
130}
131
132namespace 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-LABEL: 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
175namespace 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-LABEL: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE(
215  // CHECK-NOT: memcpy
216  // CHECK: ret void
217  void testD() { D d; }
218}
219
220namespace 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-LABEL: 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.
238namespace 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
248namespace Test10 {
249  struct A { virtual void foo(); };
250  struct B { virtual void foo(); };
251  struct C : A, B { void foo() {} };
252
253  // Test later.
254  void test() {
255    C c;
256  }
257}
258
259// PR7611
260namespace Test11 {
261  struct A {             virtual A* f(); };
262  struct B : virtual A { virtual A* f(); };
263  struct C : B         { virtual C* 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.
279namespace 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  };
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
303namespace 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  };
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
328namespace 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  };
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
345namespace 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  };
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