]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):
[FreeBSD/FreeBSD.git] / test / CodeGenCXX / microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
1 // RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
2
3 // RUN: FileCheck --check-prefix=NO-THUNKS-Test1 %s < %t
4 // RUN: FileCheck --check-prefix=NO-THUNKS-Test2 %s < %t
5 // RUN: FileCheck --check-prefix=NO-THUNKS-Test3 %s < %t
6 // RUN: FileCheck --check-prefix=NO-THUNKS-Test4 %s < %t
7 // RUN: FileCheck --check-prefix=NO-THUNKS-Test5 %s < %t
8 // RUN: FileCheck --check-prefix=NO-THUNKS-Test6 %s < %t
9 // RUN: FileCheck --check-prefix=NO-THUNKS-Test7 %s < %t
10 // RUN: FileCheck --check-prefix=NO-THUNKS-Test8 %s < %t
11 // RUN: FileCheck --check-prefix=NO-THUNKS-Test9 %s < %t
12 // RUN: FileCheck --check-prefix=PURE-VIRTUAL-Test1 %s < %t
13 // RUN: FileCheck --check-prefix=THIS-THUNKS-Test1 %s < %t
14 // RUN: FileCheck --check-prefix=THIS-THUNKS-Test2 %s < %t
15 // RUN: FileCheck --check-prefix=THIS-THUNKS-Test3 %s < %t
16 // RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test3 %s < %t
17 // RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test5 %s < %t
18 // RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test6 %s < %t
19 // RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test7 %s < %t
20 // RUN: FileCheck --check-prefix=RET-THUNKS-Test1 %s < %t
21 // RUN: FileCheck --check-prefix=RET-THUNKS-Test2 %s < %t
22 // RUN: FileCheck --check-prefix=RET-THUNKS-Test3 %s < %t
23 // RUN: FileCheck --check-prefix=RET-THUNKS-Test4 %s < %t
24 // RUN: FileCheck --check-prefix=RET-THUNKS-Test5 %s < %t
25 // RUN: FileCheck --check-prefix=RET-THUNKS-Test6 %s < %t
26
27 // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
28
29 struct Empty {
30   // Doesn't have a vftable!
31 };
32
33 struct A {
34   virtual void f();
35 };
36
37 struct B {
38   virtual void g();
39   // Add an extra virtual method so it's easier to check for the absence of thunks.
40   virtual void h();
41 };
42
43 struct C {
44   virtual void g();  // Might "collide" with B::g if both are bases of some class.
45 };
46
47
48 namespace no_thunks {
49
50 struct Test1: A, B {
51   // NO-THUNKS-Test1: VFTable for 'A' in 'no_thunks::Test1' (1 entries)
52   // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f()
53
54   // NO-THUNKS-Test1: VFTable for 'B' in 'no_thunks::Test1' (2 entries)
55   // NO-THUNKS-Test1-NEXT: 0 | void B::g()
56   // NO-THUNKS-Test1-NEXT: 1 | void B::h()
57
58   // NO-THUNKS-Test1: VFTable indices for 'no_thunks::Test1' (1 entries)
59   // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f()
60
61   // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BA@@@"
62   // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BB@@@"
63
64   // Overrides only the left child's method (A::f), needs no thunks.
65   virtual void f();
66 };
67
68 Test1 t1;
69
70 struct Test2: A, B {
71   // NO-THUNKS-Test2: VFTable for 'A' in 'no_thunks::Test2' (1 entries)
72   // NO-THUNKS-Test2-NEXT: 0 | void A::f()
73
74   // NO-THUNKS-Test2: VFTable for 'B' in 'no_thunks::Test2' (2 entries)
75   // NO-THUNKS-Test2-NEXT: 0 | void no_thunks::Test2::g()
76   // NO-THUNKS-Test2-NEXT: 1 | void B::h()
77
78   // NO-THUNKS-Test2: VFTable indices for 'no_thunks::Test2' (1 entries).
79   // NO-THUNKS-Test2-NEXT: via vfptr at offset 4
80   // NO-THUNKS-Test2-NEXT: 0 | void no_thunks::Test2::g()
81
82   // Overrides only the right child's method (B::g), needs this adjustment but
83   // not thunks.
84   virtual void g();
85 };
86
87 Test2 t2;
88
89 struct Test3: A, B {
90   // NO-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test3' (2 entries)
91   // NO-THUNKS-Test3-NEXT: 0 | void A::f()
92   // NO-THUNKS-Test3-NEXT: 1 | void no_thunks::Test3::i()
93
94   // NO-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test3' (2 entries)
95   // NO-THUNKS-Test3-NEXT: 0 | void B::g()
96   // NO-THUNKS-Test3-NEXT: 1 | void B::h()
97
98   // NO-THUNKS-Test3: VFTable indices for 'no_thunks::Test3' (1 entries).
99   // NO-THUNKS-Test3-NEXT: 1 | void no_thunks::Test3::i()
100
101   // Only adds a new method.
102   virtual void i();
103 };
104
105 Test3 t3;
106
107 // Only the right base has a vftable, so it's laid out before the left one!
108 struct Test4 : Empty, A {
109   // NO-THUNKS-Test4: VFTable for 'A' in 'no_thunks::Test4' (1 entries)
110   // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f()
111
112   // NO-THUNKS-Test4: VFTable indices for 'no_thunks::Test4' (1 entries).
113   // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f()
114
115   // MANGLING-DAG: @"\01??_7Test4@no_thunks@@6B@"
116
117   virtual void f();
118 };
119
120 Test4 t4;
121
122 // 2-level structure with repeating subobject types, but no thunks needed.
123 struct Test5: Test1, Test2 {
124   // NO-THUNKS-Test5: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries)
125   // NO-THUNKS-Test5-NEXT: 0 | void no_thunks::Test1::f()
126   // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z()
127
128   // NO-THUNKS-Test5: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries)
129   // NO-THUNKS-Test5-NEXT: 0 | void B::g()
130   // NO-THUNKS-Test5-NEXT: 1 | void B::h()
131
132   // NO-THUNKS-Test5: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test5' (1 entries)
133   // NO-THUNKS-Test5-NEXT: 0 | void A::f()
134
135   // NO-THUNKS-Test5: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test5' (2 entries)
136   // NO-THUNKS-Test5-NEXT: 0 | void no_thunks::Test2::g()
137   // NO-THUNKS-Test5-NEXT: 1 | void B::h()
138
139   // NO-THUNKS-Test5: VFTable indices for 'no_thunks::Test5' (1 entries).
140   // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z()
141
142   // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test1@1@@"
143   // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test2@1@@"
144   // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test1@1@@"
145   // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test2@1@@"
146
147   virtual void z();
148 };
149
150 Test5 t5;
151
152 struct Test6: Test1 {
153   // NO-THUNKS-Test6: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test6' (1 entries).
154   // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f()
155
156   // NO-THUNKS-Test6: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test6' (2 entries).
157   // NO-THUNKS-Test6-NEXT: 0 | void B::g()
158   // NO-THUNKS-Test6-NEXT: 1 | void B::h()
159
160   // NO-THUNKS-Test6: VFTable indices for 'no_thunks::Test6' (1 entries).
161   // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f()
162
163   // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BA@@@"
164   // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BB@@@"
165
166   // Overrides both no_thunks::Test1::f and A::f.
167   virtual void f();
168 };
169
170 Test6 t6;
171
172 struct Test7: Test2 {
173   // NO-THUNKS-Test7: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test7' (1 entries).
174   // NO-THUNKS-Test7-NEXT: 0 | void A::f()
175
176   // NO-THUNKS-Test7: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test7' (2 entries).
177   // NO-THUNKS-Test7-NEXT: 0 | void no_thunks::Test7::g()
178   // NO-THUNKS-Test7-NEXT: 1 | void B::h()
179
180   // NO-THUNKS-Test7: VFTable indices for 'no_thunks::Test7' (1 entries).
181   // NO-THUNKS-Test7-NEXT: via vfptr at offset 4
182   // NO-THUNKS-Test7-NEXT: 0 | void no_thunks::Test7::g()
183
184   // Overrides both no_thunks::Test2::g and B::g.
185   virtual void g();
186 };
187
188 Test7 t7;
189
190 struct Test8: Test3 {
191   // NO-THUNKS-Test8: VFTable for 'A' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries).
192   // NO-THUNKS-Test8-NEXT: 0 | void A::f()
193   // NO-THUNKS-Test8-NEXT: 1 | void no_thunks::Test3::i()
194
195   // NO-THUNKS-Test8: VFTable for 'B' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries).
196   // NO-THUNKS-Test8-NEXT: 0 | void no_thunks::Test8::g()
197   // NO-THUNKS-Test8-NEXT: 1 | void B::h()
198
199   // NO-THUNKS-Test8: VFTable indices for 'no_thunks::Test8' (1 entries).
200   // NO-THUNKS-Test8-NEXT: via vfptr at offset 4
201   // NO-THUNKS-Test8-NEXT: 0 | void no_thunks::Test8::g()
202
203   // Overrides grandparent's B::g.
204   virtual void g();
205 };
206
207 Test8 t8;
208
209 struct D : A {
210   virtual void g();
211 };
212
213 // Repeating subobject.
214 struct Test9: A, D {
215   // NO-THUNKS-Test9: VFTable for 'A' in 'no_thunks::Test9' (2 entries).
216   // NO-THUNKS-Test9-NEXT: 0 | void A::f()
217   // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h()
218
219   // NO-THUNKS-Test9: VFTable for 'A' in 'no_thunks::D' in 'no_thunks::Test9' (2 entries).
220   // NO-THUNKS-Test9-NEXT: 0 | void A::f()
221   // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::D::g()
222
223   // NO-THUNKS-Test9: VFTable indices for 'no_thunks::Test9' (1 entries).
224   // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h()
225
226   // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BA@@@"
227   // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BD@1@@"
228
229   virtual void h();
230 };
231
232 Test9 t9;
233 }
234
235 namespace pure_virtual {
236 struct D {
237   virtual void g() = 0;
238   virtual void h();
239 };
240
241
242 struct Test1: A, D {
243   // PURE-VIRTUAL-Test1: VFTable for 'A' in 'pure_virtual::Test1' (1 entries)
244   // PURE-VIRTUAL-Test1-NEXT: 0 | void A::f()
245
246   // PURE-VIRTUAL-Test1: VFTable for 'pure_virtual::D' in 'pure_virtual::Test1' (2 entries)
247   // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g()
248   // PURE-VIRTUAL-Test1-NEXT: 1 | void pure_virtual::D::h()
249
250   // PURE-VIRTUAL-Test1: VFTable indices for 'pure_virtual::Test1' (1 entries).
251   // PURE-VIRTUAL-Test1-NEXT: via vfptr at offset 4
252   // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g()
253
254   // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BA@@@"
255   // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BD@1@@"
256
257   // Overrides only the right child's method (pure_virtual::D::g), needs this adjustment but
258   // not thunks.
259   virtual void g();
260 };
261
262 Test1 t1;
263 }
264
265 namespace this_adjustment {
266
267 // Overrides methods of two bases at the same time, thus needing thunks.
268 struct Test1 : B, C {
269   // THIS-THUNKS-Test1: VFTable for 'B' in 'this_adjustment::Test1' (2 entries).
270   // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
271   // THIS-THUNKS-Test1-NEXT: 1 | void B::h()
272
273   // THIS-THUNKS-Test1: VFTable for 'C' in 'this_adjustment::Test1' (1 entries).
274   // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
275   // THIS-THUNKS-Test1-NEXT:     [this adjustment: -4 non-virtual]
276
277   // THIS-THUNKS-Test1: Thunks for 'void this_adjustment::Test1::g()' (1 entry).
278   // THIS-THUNKS-Test1-NEXT: 0 | [this adjustment: -4 non-virtual]
279
280   // THIS-THUNKS-Test1: VFTable indices for 'this_adjustment::Test1' (1 entries).
281   // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
282
283   // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BB@@@"
284   // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BC@@@"
285
286   virtual void g();
287 };
288
289 Test1 t1;
290
291 struct Test2 : A, B, C {
292   // THIS-THUNKS-Test2: VFTable for 'A' in 'this_adjustment::Test2' (1 entries).
293   // THIS-THUNKS-Test2-NEXT: 0 | void A::f()
294
295   // THIS-THUNKS-Test2: VFTable for 'B' in 'this_adjustment::Test2' (2 entries).
296   // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
297   // THIS-THUNKS-Test2-NEXT: 1 | void B::h()
298
299   // THIS-THUNKS-Test2: VFTable for 'C' in 'this_adjustment::Test2' (1 entries).
300   // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
301   // THIS-THUNKS-Test2-NEXT:     [this adjustment: -4 non-virtual]
302
303   // THIS-THUNKS-Test2: Thunks for 'void this_adjustment::Test2::g()' (1 entry).
304   // THIS-THUNKS-Test2-NEXT: 0 | [this adjustment: -4 non-virtual]
305
306   // THIS-THUNKS-Test2: VFTable indices for 'this_adjustment::Test2' (1 entries).
307   // THIS-THUNKS-Test2-NEXT: via vfptr at offset 4
308   // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
309
310   // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BA@@@"
311   // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BB@@@"
312   // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BC@@@"
313
314   virtual void g();
315 };
316
317 Test2 t2;
318
319 // Overrides methods of two bases at the same time, thus needing thunks.
320 struct Test3: no_thunks::Test1, no_thunks::Test2 {
321   // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test1' in 'this_adjustment::Test3' (1 entries).
322   // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
323
324   // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test1' in 'this_adjustment::Test3' (2 entries).
325   // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
326   // THIS-THUNKS-Test3-NEXT: 1 | void B::h()
327
328   // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test2' in 'this_adjustment::Test3' (1 entries).
329   // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
330   // THIS-THUNKS-Test3-NEXT:     [this adjustment: -8 non-virtual]
331
332   // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::f()' (1 entry).
333   // THIS-THUNKS-Test3-NEXT: 0 | [this adjustment: -8 non-virtual]
334
335   // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test2' in 'this_adjustment::Test3' (2 entries).
336   // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
337   // THIS-THUNKS-Test3-NEXT:     [this adjustment: -8 non-virtual]
338   // THIS-THUNKS-Test3-NEXT: 1 | void B::h()
339
340   // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::g()' (1 entry).
341   // THIS-THUNKS-Test3-NEXT: 0 | [this adjustment: -8 non-virtual]
342
343   // THIS-THUNKS-Test3: VFTable indices for 'this_adjustment::Test3' (2 entries).
344   // THIS-THUNKS-Test3-NEXT: via vfptr at offset 0
345   // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
346   // THIS-THUNKS-Test3-NEXT: via vfptr at offset 4
347   // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
348
349   virtual void f();
350   virtual void g();
351 };
352
353 Test3 t3;
354 }
355
356 namespace vdtor {
357 struct Test1 {
358   virtual ~Test1();
359   virtual void z1();
360 };
361
362 struct Test2 {
363   virtual ~Test2();
364 };
365
366 struct Test3 : Test1, Test2 {
367   // VDTOR-THUNKS-Test3: VFTable for 'vdtor::Test1' in 'vdtor::Test3' (2 entries).
368   // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
369   // VDTOR-THUNKS-Test3-NEXT: 1 | void vdtor::Test1::z1()
370
371   // VDTOR-THUNKS-Test3: VFTable for 'vdtor::Test2' in 'vdtor::Test3' (1 entries).
372   // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
373   // VDTOR-THUNKS-Test3-NEXT:     [this adjustment: -4 non-virtual]
374
375   // VDTOR-THUNKS-Test3: Thunks for 'vdtor::Test3::~Test3()' (1 entry).
376   // VDTOR-THUNKS-Test3-NEXT: 0 | [this adjustment: -4 non-virtual]
377
378   // VDTOR-THUNKS-Test3: VFTable indices for 'vdtor::Test3' (1 entries).
379   // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
380   virtual ~Test3();
381 };
382
383 Test3 t3;
384
385 struct Test4 {
386   // No virtual destructor here!
387   virtual void z4();
388 };
389
390 struct Test5 : Test4, Test2 {
391   // Implicit virtual dtor here!
392
393   // VDTOR-THUNKS-Test5: VFTable for 'vdtor::Test4' in 'vdtor::Test5' (1 entries).
394   // VDTOR-THUNKS-Test5-NEXT: 0 | void vdtor::Test4::z4()
395
396   // VDTOR-THUNKS-Test5: VFTable for 'vdtor::Test2' in 'vdtor::Test5' (1 entries).
397   // VDTOR-THUNKS-Test5-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting]
398   // VDTOR-THUNKS-Test5-NEXT:     [this adjustment: -4 non-virtual]
399
400   // VDTOR-THUNKS-Test5: Thunks for 'vdtor::Test5::~Test5()' (1 entry).
401   // VDTOR-THUNKS-Test5-NEXT: 0 | [this adjustment: -4 non-virtual]
402
403   // VDTOR-THUNKS-Test5: VFTable indices for 'vdtor::Test5' (1 entries).
404   // VDTOR-THUNKS-Test5-NEXT: -- accessible via vfptr at offset 4 --
405   // VDTOR-THUNKS-Test5-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting]
406 };
407
408 Test5 t5;
409
410 struct Test6 : Test4, Test2 {
411   // Implicit virtual dtor here!
412
413   // VDTOR-THUNKS-Test6: VFTable for 'vdtor::Test4' in 'vdtor::Test6' (1 entries).
414   // VDTOR-THUNKS-Test6-NEXT: 0 | void vdtor::Test4::z4()
415
416   // VDTOR-THUNKS-Test6: VFTable for 'vdtor::Test2' in 'vdtor::Test6' (1 entries).
417   // VDTOR-THUNKS-Test6-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting]
418   // VDTOR-THUNKS-Test6-NEXT:     [this adjustment: -4 non-virtual]
419
420   // VDTOR-THUNKS-Test6: Thunks for 'vdtor::Test6::~Test6()' (1 entry).
421   // VDTOR-THUNKS-Test6-NEXT: 0 | [this adjustment: -4 non-virtual]
422
423   // VDTOR-THUNKS-Test6: VFTable indices for 'vdtor::Test6' (1 entries).
424   // VDTOR-THUNKS-Test6-NEXT: -- accessible via vfptr at offset 4 --
425   // VDTOR-THUNKS-Test6-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting]
426 };
427
428 Test6 t6;
429
430 struct Test7 : Test5 {
431   // VDTOR-THUNKS-Test7: VFTable for 'vdtor::Test4' in 'vdtor::Test5' in 'vdtor::Test7' (1 entries).
432   // VDTOR-THUNKS-Test7-NEXT: 0 | void vdtor::Test4::z4()
433
434   // VDTOR-THUNKS-Test7: VFTable for 'vdtor::Test2' in 'vdtor::Test5' in 'vdtor::Test7' (1 entries).
435   // VDTOR-THUNKS-Test7-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting]
436   // VDTOR-THUNKS-Test7-NEXT:     [this adjustment: -4 non-virtual]
437
438   // VDTOR-THUNKS-Test7: Thunks for 'vdtor::Test7::~Test7()' (1 entry).
439   // VDTOR-THUNKS-Test7-NEXT: 0 | [this adjustment: -4 non-virtual]
440
441   // VDTOR-THUNKS-Test7: VFTable indices for 'vdtor::Test7' (1 entries).
442   // VDTOR-THUNKS-Test7-NEXT: -- accessible via vfptr at offset 4 --
443   // VDTOR-THUNKS-Test7-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting]
444   virtual ~Test7();
445 };
446
447 Test7 t7;
448
449 }
450
451 namespace return_adjustment {
452
453 struct Ret1 {
454   virtual C* foo();
455   virtual void z();
456 };
457
458 struct Test1 : Ret1 {
459   // RET-THUNKS-Test1: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' (3 entries).
460   // RET-THUNKS-Test1-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test1::foo()
461   // RET-THUNKS-Test1-NEXT:     [return adjustment: 4 non-virtual]
462   // RET-THUNKS-Test1-NEXT: 1 | void return_adjustment::Ret1::z()
463   // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
464
465   // RET-THUNKS-Test1: VFTable indices for 'return_adjustment::Test1' (1 entries).
466   // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
467
468   // MANGLING-DAG: @"\01??_7Test1@return_adjustment@@6B@"
469
470   virtual this_adjustment::Test1* foo();
471 };
472
473 Test1 t1;
474
475 struct Ret2 : B, this_adjustment::Test1 { };
476
477 struct Test2 : Test1 {
478   // RET-THUNKS-Test2: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test2' (4 entries).
479   // RET-THUNKS-Test2-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
480   // RET-THUNKS-Test2-NEXT:     [return adjustment: 8 non-virtual]
481   // RET-THUNKS-Test2-NEXT: 1 | void return_adjustment::Ret1::z()
482   // RET-THUNKS-Test2-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
483   // RET-THUNKS-Test2-NEXT:     [return adjustment: 4 non-virtual]
484   // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
485
486   // RET-THUNKS-Test2: VFTable indices for 'return_adjustment::Test2' (1 entries).
487   // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
488
489   virtual Ret2* foo();
490 };
491
492 Test2 t2;
493
494 struct Test3: B, Ret1 {
495   // RET-THUNKS-Test3: VFTable for 'B' in 'return_adjustment::Test3' (2 entries).
496   // RET-THUNKS-Test3-NEXT: 0 | void B::g()
497   // RET-THUNKS-Test3-NEXT: 1 | void B::h()
498
499   // RET-THUNKS-Test3: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' (3 entries).
500   // RET-THUNKS-Test3-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test3::foo()
501   // RET-THUNKS-Test3-NEXT:     [return adjustment: 4 non-virtual]
502   // RET-THUNKS-Test3-NEXT: 1 | void return_adjustment::Ret1::z()
503   // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
504
505   // RET-THUNKS-Test3: VFTable indices for 'return_adjustment::Test3' (1 entries).
506   // RET-THUNKS-Test3-NEXT: via vfptr at offset 4
507   // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
508
509   virtual this_adjustment::Test1* foo();
510 };
511
512 Test3 t3;
513
514 struct Test4 : Test3 {
515   // RET-THUNKS-Test4: VFTable for 'B' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (2 entries).
516   // RET-THUNKS-Test4-NEXT: 0 | void B::g()
517   // RET-THUNKS-Test4-NEXT: 1 | void B::h()
518
519   // RET-THUNKS-Test4: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (4 entries).
520   // RET-THUNKS-Test4-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
521   // RET-THUNKS-Test4-NEXT:     [return adjustment: 8 non-virtual]
522   // RET-THUNKS-Test4-NEXT: 1 | void return_adjustment::Ret1::z()
523   // RET-THUNKS-Test4-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
524   // RET-THUNKS-Test4-NEXT:     [return adjustment: 4 non-virtual]
525   // RET-THUNKS-Test4-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
526
527   // RET-THUNKS-Test4: VFTable indices for 'return_adjustment::Test4' (1 entries).
528   // RET-THUNKS-Test4-NEXT: -- accessible via vfptr at offset 4 --
529   // RET-THUNKS-Test4-NEXT:   3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
530
531   virtual Ret2* foo();
532 };
533
534 Test4 t4;
535
536 struct Test5 : Ret1, Test1 {
537   // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test5' (3 entries).
538   // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
539   // RET-THUNKS-Test5-NEXT:     [return adjustment: 8 non-virtual]
540   // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z()
541   // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
542
543   // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in  'return_adjustment::Test1' in 'return_adjustment::Test5' (4 entries).
544   // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
545   // RET-THUNKS-Test5-NEXT:     [return adjustment: 8 non-virtual]
546   // RET-THUNKS-Test5-NEXT:     [this adjustment: -4 non-virtual]
547   // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z()
548   // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
549   // RET-THUNKS-Test5-NEXT:     [return adjustment: 4 non-virtual]
550   // RET-THUNKS-Test5-NEXT:     [this adjustment: -4 non-virtual]
551   // RET-THUNKS-Test5-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
552   // RET-THUNKS-Test5-NEXT:     [this adjustment: -4 non-virtual]
553
554   // RET-THUNKS-Test5: VFTable indices for 'return_adjustment::Test5' (1 entries).
555   // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
556
557   virtual Ret2* foo();
558 };
559
560 Test5 t5;
561
562 struct Ret3 : this_adjustment::Test1 { };
563
564 struct Test6 : Test1 {
565   virtual Ret3* foo();
566   // RET-THUNKS-Test6: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test6' (4 entries).
567   // RET-THUNKS-Test6-NEXT: 0 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
568   // RET-THUNKS-Test6-NEXT:     [return adjustment: 4 non-virtual]
569   // RET-THUNKS-Test6-NEXT: 1 | void return_adjustment::Ret1::z()
570   // RET-THUNKS-Test6-NEXT: 2 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
571   // RET-THUNKS-Test6-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
572
573   // RET-THUNKS-Test6: VFTable indices for 'return_adjustment::Test6' (1 entries).
574   // RET-THUNKS-Test6-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
575 };
576
577 Test6 t6;
578
579 }