1 // RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t
2 
3 // RUN: FileCheck --check-prefix=VTABLE-C %s < %t
4 // RUN: FileCheck --check-prefix=VTABLE-D %s < %t
5 // RUN: FileCheck --check-prefix=TEST1 %s < %t
6 // RUN: FileCheck --check-prefix=TEST2 %s < %t
7 // RUN: FileCheck --check-prefix=TEST3 %s < %t
8 // RUN: FileCheck --check-prefix=TEST4 %s < %t
9 // RUN: FileCheck --check-prefix=TEST5 %s < %t
10 // RUN: FileCheck --check-prefix=TEST6 %s < %t
11 // RUN: FileCheck --check-prefix=TEST7 %s < %t
12 // RUN: FileCheck --check-prefix=TEST8-X %s < %t
13 // RUN: FileCheck --check-prefix=TEST8-Z %s < %t
14 // RUN: FileCheck --check-prefix=TEST9-Y %s < %t
15 // RUN: FileCheck --check-prefix=TEST9-Z %s < %t
16 // RUN: FileCheck --check-prefix=TEST9-W %s < %t
17 // RUN: FileCheck --check-prefix=TEST9-T %s < %t
18 // RUN: FileCheck --check-prefix=TEST10 %s < %t
19 // RUN: FileCheck --check-prefix=VDTORS-Y %s < %t
20 // RUN: FileCheck --check-prefix=VDTORS-U %s < %t
21 // RUN: FileCheck --check-prefix=VDTORS-V %s < %t
22 // RUN: FileCheck --check-prefix=VDTORS-P %s < %t
23 // RUN: FileCheck --check-prefix=RET-W %s < %t
24 // RUN: FileCheck --check-prefix=RET-T %s < %t
25 // RUN: FileCheck --check-prefix=RET-V %s < %t
26 
27 // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
28 
29 struct Empty { };
30 
31 struct A {
32   virtual void f();
33   virtual void z();  // Useful to check there are no thunks for f() when appropriate.
34 };
35 
36 struct B {
37   virtual void g();
38 };
39 
40 struct C: virtual A {
41   // VTABLE-C: VFTable for 'A' in 'C' (2 entries)
42   // VTABLE-C-NEXT: 0 | void C::f()
43   // VTABLE-C-NEXT: 1 | void A::z()
44 
45   // VTABLE-C: VFTable indices for 'C' (1 entries)
46   // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0
47   // VTABLE-C-NEXT: 0 | void C::f()
48 
49   // MANGLING-DAG: @"\01??_7C@@6B@"
50 
51   virtual void f();
52 };
53 
54 C c;
55 
56 struct D: virtual A {
57   // VTABLE-D: VFTable for 'D' (1 entries).
58   // VTABLE-D-NEXT: 0 | void D::h()
59 
60   // VTABLE-D: VFTable for 'A' in 'D' (2 entries).
61   // VTABLE-D-NEXT: 0 | void D::f()
62   // VTABLE-D-NEXT: 1 | void A::z()
63 
64   // VTABLE-D: VFTable indices for 'D' (2 entries).
65   // VTABLE-D-NEXT: via vfptr at offset 0
66   // VTABLE-D-NEXT: 0 | void D::h()
67   // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0
68   // VTABLE-D-NEXT: 0 | void D::f()
69 
70   // MANGLING-DAG: @"\01??_7D@@6B0@@"
71   // MANGLING-DAG: @"\01??_7D@@6BA@@@"
72 
73   virtual void f();
74   virtual void h();
75 };
76 
77 void D::h() {}
78 D d;
79 
80 namespace Test1 {
81 
82 struct X { int x; };
83 
84 // X and A get reordered in the layout since X doesn't have a vfptr while A has.
85 struct Y : X, A { };
86 // MANGLING-DAG: @"\01??_7Y@Test1@@6B@"
87 
88 struct Z : virtual Y {
89   // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries).
90   // TEST1-NEXT: 0 | void A::f()
91   // TEST1-NEXT: 1 | void A::z()
92 
93   // TEST1-NOT: VFTable indices for 'Test1::Z'
94 
95   // MANGLING-DAG: @"\01??_7Z@Test1@@6B@"
96 };
97 
98 Z z;
99 }
100 
101 namespace Test2 {
102 
103 struct X: virtual A, virtual B {
104   // TEST2: VFTable for 'Test2::X' (1 entries).
105   // TEST2-NEXT: 0 | void Test2::X::h()
106 
107   // TEST2: VFTable for 'A' in 'Test2::X' (2 entries).
108   // TEST2-NEXT: 0 | void A::f()
109   // TEST2-NEXT: 1 | void A::z()
110 
111   // TEST2: VFTable for 'B' in 'Test2::X' (1 entries).
112   // TEST2-NEXT: 0 | void B::g()
113 
114   // TEST2: VFTable indices for 'Test2::X' (1 entries).
115   // TEST2-NEXT: 0 | void Test2::X::h()
116 
117   // MANGLING-DAG: @"\01??_7X@Test2@@6B01@@"
118   // MANGLING-DAG: @"\01??_7X@Test2@@6BA@@@"
119   // MANGLING-DAG: @"\01??_7X@Test2@@6BB@@@"
120 
121   virtual void h();
122 };
123 
124 X x;
125 }
126 
127 namespace Test3 {
128 
129 struct X : virtual A {
130   // MANGLING-DAG: @"\01??_7X@Test3@@6B@"
131 };
132 
133 struct Y: virtual X {
134   // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries).
135   // TEST3-NEXT: 0 | void A::f()
136   // TEST3-NEXT: 1 | void A::z()
137 
138   // TEST3-NOT: VFTable indices for 'Test3::Y'
139 
140   // MANGLING-DAG: @"\01??_7Y@Test3@@6B@"
141 };
142 
143 Y y;
144 }
145 
146 namespace Test4 {
147 
148 struct X: virtual C {
149   // This one's interesting. C::f expects (A*) to be passed as 'this' and does
150   // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk
151   // should pass a pointer to the end of X in order
152   // for ECX-=4 to point at the C part.
153 
154   // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries).
155   // TEST4-NEXT: 0 | void C::f()
156   // TEST4-NEXT:     [this adjustment: 8 non-virtual]
157   // TEST4-NEXT: 1 | void A::z()
158 
159   // TEST4-NOT: VFTable indices for 'Test4::X'
160 
161   // MANGLING-DAG: @"\01??_7X@Test4@@6B@"
162 
163   // Also check the mangling of the thunk.
164   // MANGLING-DAG: define weak x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ"
165 };
166 
167 X x;
168 }
169 
170 namespace Test5 {
171 
172 // New methods are added to the base's vftable.
173 struct X : A {
174   // MANGLING-DAG: @"\01??_7X@Test5@@6B@"
175   virtual void g();
176 };
177 
178 struct Y : virtual X {
179   // TEST5: VFTable for 'Test5::Y' (1 entries).
180   // TEST5-NEXT: 0 | void Test5::Y::h()
181 
182   // TEST5: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries).
183   // TEST5-NEXT: 0 | void A::f()
184   // TEST5-NEXT: 1 | void A::z()
185   // TEST5-NEXT: 2 | void Test5::X::g()
186 
187   // TEST5: VFTable indices for 'Test5::Y' (1 entries).
188   // TEST5-NEXT: 0 | void Test5::Y::h()
189 
190   // MANGLING-DAG: @"\01??_7Y@Test5@@6B01@@"
191   // MANGLING-DAG: @"\01??_7Y@Test5@@6BX@1@@"
192 
193   virtual void h();
194 };
195 
196 Y y;
197 }
198 
199 namespace Test6 {
200 
201 struct X : A, virtual Empty {
202   // TEST6: VFTable for 'A' in 'Test6::X' (2 entries).
203   // TEST6-NEXT: 0 | void A::f()
204   // TEST6-NEXT: 1 | void A::z()
205 
206   // TEST6-NOT: VFTable indices for 'Test6::X'
207 
208   // MANGLING-DAG: @"\01??_7X@Test6@@6B@"
209 };
210 
211 X x;
212 }
213 
214 namespace Test7 {
215 
216 struct X : C {
217   // MANGLING-DAG: @"\01??_7X@Test7@@6B@"
218 };
219 
220 struct Y : virtual X {
221   // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries).
222   // TEST7-NEXT: 0 | void C::f()
223   // TEST7-NEXT:     [this adjustment: 8 non-virtual]
224   // TEST7-NEXT: 1 | void A::z()
225 
226   // TEST7: Thunks for 'void C::f()' (1 entry).
227   // TEST7-NEXT: 0 | [this adjustment: 8 non-virtual]
228 
229   // TEST7-NOT: VFTable indices for 'Test7::Y'
230 
231   // MANGLING-DAG: @"\01??_7Y@Test7@@6B@"
232 };
233 
234 Y y;
235 }
236 
237 namespace Test8 {
238 
239 // This is a typical diamond inheritance with a shared 'A' vbase.
240 struct X : D, C {
241   // TEST8-X: VFTable for 'D' in 'Test8::X' (1 entries).
242   // TEST8-X-NEXT: 0 | void D::h()
243 
244   // TEST8-X: VFTable for 'A' in 'D' in 'Test8::X' (2 entries).
245   // TEST8-X-NEXT: 0 | void Test8::X::f()
246   // TEST8-X-NEXT: 1 | void A::z()
247 
248   // TEST8-X: VFTable indices for 'Test8::X' (1 entries).
249   // TEST8-X-NEXT: via vbtable index 1, vfptr at offset 0
250   // TEST8-X-NEXT: 0 | void Test8::X::f()
251 
252   // MANGLING-DAG: @"\01??_7X@Test8@@6BA@@@"
253   // MANGLING-DAG: @"\01??_7X@Test8@@6BD@@@"
254 
255   virtual void f();
256 };
257 
258 X x;
259 
260 // Another diamond inheritance which led to AST crashes.
261 struct Y : virtual A {};
262 
263 class Z : Y, C {
264   // TEST8-Z: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries).
265   // TEST8-Z-NEXT: 0 | void Test8::Z::f()
266   // TEST8-Z-NEXT: 1 | void A::z()
267 
268   // TEST8-Z: VFTable indices for 'Test8::Z' (1 entries).
269   // TEST8-Z-NEXT: via vbtable index 1, vfptr at offset 0
270   // TEST8-Z-NEXT: 0 | void Test8::Z::f()
271   virtual void f();
272 };
273 Z z;
274 }
275 
276 namespace Test9 {
277 
278 struct X : A { };
279 
280 struct Y : virtual X {
281   // TEST9-Y: VFTable for 'Test9::Y' (1 entries).
282   // TEST9-Y-NEXT: 0 | void Test9::Y::h()
283 
284   // TEST9-Y: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries).
285   // TEST9-Y-NEXT: 0 | void A::f()
286   // TEST9-Y-NEXT: 1 | void A::z()
287 
288   // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries).
289   // TEST9-Y-NEXT: 0 | void Test9::Y::h()
290 
291   // MANGLING-DAG: @"\01??_7Y@Test9@@6B01@@"
292   // MANGLING-DAG: @"\01??_7Y@Test9@@6BX@1@@"
293 
294   virtual void h();
295 };
296 
297 Y y;
298 
299 struct Z : Y, virtual B {
300   // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entries).
301   // TEST9-Z-NEXT: 0 | void Test9::Y::h()
302 
303   // TEST9-Z: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries).
304   // TEST9-Z-NEXT: 0 | void A::f()
305   // TEST9-Z-NEXT: 1 | void A::z()
306 
307   // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entries).
308   // TEST9-Z-NEXT: 0 | void B::g()
309 
310   // TEST9-Z-NOT: VFTable indices for 'Test9::Z'
311 
312   // MANGLING-DAG: @"\01??_7Z@Test9@@6BX@1@@"
313   // MANGLING-DAG: @"\01??_7Z@Test9@@6BY@1@@"
314 
315   // FIXME this one is wrong:
316   // INCORRECT MANGLING-DAG: @"\01??_7Z@Test9@@6BB@@@"
317   // MANGLING-DAG-SHOULD-BE: @"\01??_7Z@Test9@@6B@"
318 };
319 
320 Z z;
321 
322 struct W : Z, D, virtual A, virtual B {
323   // TEST9-W: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entries).
324   // TEST9-W-NEXT: 0 | void Test9::Y::h()
325 
326   // TEST9-W: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries).
327   // TEST9-W-NEXT: 0 | void A::f()
328   // TEST9-W-NEXT: 1 | void A::z()
329 
330   // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entries).
331   // TEST9-W-NEXT: 0 | void B::g()
332 
333   // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entries).
334   // TEST9-W-NEXT: 0 | void D::h()
335 
336   // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries).
337   // TEST9-W-NEXT: 0 | void D::f()
338   // TEST9-W-NEXT:     [this adjustment: -8 non-virtual]
339   // TEST9-W-NEXT: 1 | void A::z()
340 
341   // TEST9-W: Thunks for 'void D::f()' (1 entry).
342   // TEST9-W-NEXT: 0 | [this adjustment: -8 non-virtual]
343 
344   // TEST9-W-NOT: VFTable indices for 'Test9::W'
345 
346   // MANGLING-DAG: @"\01??_7W@Test9@@6BA@@@"
347   // MANGLING-DAG: @"\01??_7W@Test9@@6BD@@@"
348   // MANGLING-DAG: @"\01??_7W@Test9@@6BX@1@@"
349 
350   // FIXME: these two are wrong:
351   // INCORRECT MANGLING-DAG: @"\01??_7W@Test9@@6BB@@@"
352   // MANGLING-DAG-SHOULD-BE: @"\01??_7W@Test9@@6B@"
353   // INCORRECT MANGLING-DAG: @"\01??_7W@Test9@@6BY@1@Z@1@@"
354   // MANGLING-DAG-SHOULD-BE: @"\01??_7W@Test9@@6BY@1@@"
355 };
356 
357 W w;
358 
359 struct T : Z, D, virtual A, virtual B {
360   // TEST9-T: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entries).
361   // TEST9-T-NEXT: 0 | void Test9::T::h()
362 
363   // TEST9-T: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries).
364   // TEST9-T-NEXT: 0 | void Test9::T::f()
365   // TEST9-T-NEXT: 1 | void Test9::T::z()
366 
367   // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entries).
368   // TEST9-T-NEXT: 0 | void Test9::T::g()
369 
370   // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entries).
371   // TEST9-T-NEXT: 0 | void Test9::T::h()
372   // TEST9-T-NEXT:     [this adjustment: -8 non-virtual]
373 
374   // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry).
375   // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
376 
377   // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries).
378   // TEST9-T-NEXT: 0 | void Test9::T::f()
379   // TEST9-T-NEXT:     [this adjustment: -8 non-virtual]
380   // TEST9-T-NEXT: 1 | void Test9::T::z()
381   // TEST9-T-NEXT:     [this adjustment: -8 non-virtual]
382 
383   // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry).
384   // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
385 
386   // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry).
387   // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
388 
389   // TEST9-T: VFTable indices for 'Test9::T' (4 entries).
390   // TEST9-T-NEXT: via vfptr at offset 0
391   // TEST9-T-NEXT: 0 | void Test9::T::h()
392   // TEST9-T-NEXT: via vbtable index 1, vfptr at offset 0
393   // TEST9-T-NEXT: 0 | void Test9::T::f()
394   // TEST9-T-NEXT: 1 | void Test9::T::z()
395   // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0
396   // TEST9-T-NEXT: 0 | void Test9::T::g()
397 
398   // MANGLING-DAG: @"\01??_7T@Test9@@6BA@@@"
399   // MANGLING-DAG: @"\01??_7T@Test9@@6BD@@@"
400   // MANGLING-DAG: @"\01??_7T@Test9@@6BX@1@@"
401 
402   // FIXME: these two are wrong:
403   // INCORRECT MANGLING-DAG: @"\01??_7T@Test9@@6BB@@@"
404   // MANGLING-DAG-SHOULD-BE: @"\01??_7T@Test9@@6B@"
405   // INCORRECT MANGLING-DAG: @"\01??_7T@Test9@@6BY@1@Z@1@@"
406   // MANGLING-DAG-SHOULD-BE: @"\01??_7T@Test9@@6BY@1@@"
407 
408   virtual void f();
409   virtual void g();
410   virtual void h();
411   virtual void z();
412 };
413 
414 T t;
415 }
416 
417 namespace Test10 {
418 struct X : virtual C, virtual A {
419   // TEST10: VFTable for 'A' in 'C' in 'Test10::X' (2 entries).
420   // TEST10-NEXT: 0 | void Test10::X::f()
421   // TEST10-NEXT: 1 | void A::z()
422 
423   // TEST10: VFTable indices for 'Test10::X' (1 entries).
424   // TEST10-NEXT: via vbtable index 1, vfptr at offset 0
425   // TEST10-NEXT: 0 | void Test10::X::f()
426   virtual void f();
427 };
428 
429 void X::f() {}
430 X x;
431 }
432 
433 namespace Test11 {
434 struct X : virtual A {};
435 struct Y { virtual void g(); };
436 
437 struct Z : virtual X, Y {
438   // MANGLING-DAG: @"\01??_7Z@Test11@@6BY@1@@"
439 
440   // FIXME this one is wrong:
441   // MANGLING-DAG-SHOULD-BE: @"\01??_7Z@Test11@@6BX@1@@"
442   // INCORRECT MANGLING-DAG: @"\01??_7Z@Test11@@6BA@@@"
443 };
444 
445 Z z;
446 
447 struct W : virtual X, A {};
448 
449 // PR17748 FIXME this one hits UNREACHABLE:
450 // W w;
451 }
452 
453 namespace vdtors {
454 struct X {
455   virtual ~X();
456   virtual void zzz();
457 };
458 
459 struct Y : virtual X {
460   // VDTORS-Y: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries).
461   // VDTORS-Y-NEXT: 0 | vdtors::Y::~Y() [scalar deleting]
462   // VDTORS-Y-NEXT: 1 | void vdtors::X::zzz()
463 
464   // VDTORS-Y-NOT: Thunks for 'vdtors::Y::~Y()'
465   virtual ~Y();
466 };
467 
468 Y y;
469 
470 struct Z {
471   virtual void z();
472 };
473 
474 struct W : Z, X {
475   // Implicit virtual dtor.
476 };
477 
478 struct U : virtual W {
479   // VDTORS-U: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entries).
480   // VDTORS-U-NEXT: 0 | void vdtors::Z::z()
481 
482   // VDTORS-U: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries).
483   // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting]
484   // VDTORS-U-NEXT:     [this adjustment: -4 non-virtual]
485   // VDTORS-U-NEXT: 1 | void vdtors::X::zzz()
486 
487   // VDTORS-U: Thunks for 'vdtors::W::~W()' (1 entry).
488   // VDTORS-U-NEXT: 0 | [this adjustment: -4 non-virtual]
489 
490   // VDTORS-U: VFTable indices for 'vdtors::U' (1 entries).
491   // VDTORS-U-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
492   // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting]
493   virtual ~U();
494 };
495 
496 U u;
497 
498 struct V : virtual W {
499   // VDTORS-V: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entries).
500   // VDTORS-V-NEXT: 0 | void vdtors::Z::z()
501 
502   // VDTORS-V: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries).
503   // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting]
504   // VDTORS-V-NEXT:     [this adjustment: -4 non-virtual]
505   // VDTORS-V-NEXT: 1 | void vdtors::X::zzz()
506 
507   // VDTORS-V: Thunks for 'vdtors::W::~W()' (1 entry).
508   // VDTORS-V-NEXT: 0 | [this adjustment: -4 non-virtual]
509 
510   // VDTORS-V: VFTable indices for 'vdtors::V' (1 entries).
511   // VDTORS-V-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
512   // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting]
513 };
514 
515 V v;
516 
517 struct T : virtual X {
518   virtual ~T();
519 };
520 
521 struct P : T, Y {
522   // VDTORS-P: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries).
523   // VDTORS-P-NEXT: 0 | vdtors::P::~P() [scalar deleting]
524   // VDTORS-P-NEXT: 1 | void vdtors::X::zzz()
525 
526   // VDTORS-P-NOT: Thunks for 'vdtors::P::~P()'
527   virtual ~P();
528 };
529 
530 P p;
531 
532 }
533 
534 namespace return_adjustment {
535 
536 struct X : virtual A {
537   virtual void f();
538 };
539 
540 struct Y : virtual A, virtual X {
541   virtual void f();
542 };
543 
544 struct Z {
545   virtual A* foo();
546 };
547 
548 struct W : Z {
549   // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries).
550   // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo()
551   // RET-W-NEXT:     [return adjustment: vbase #1, 0 non-virtual]
552   // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
553 
554   // RET-W: VFTable indices for 'return_adjustment::W' (1 entries).
555   // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
556 
557   virtual X* foo();
558 };
559 
560 W y;
561 
562 struct T : W {
563   // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries).
564   // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo()
565   // RET-T-NEXT:     [return adjustment: vbase #1, 0 non-virtual]
566   // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo()
567   // RET-T-NEXT:     [return adjustment: vbase #2, 0 non-virtual]
568   // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
569 
570   // RET-T: VFTable indices for 'return_adjustment::T' (1 entries).
571   // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
572 
573   virtual Y* foo();
574 };
575 
576 T t;
577 
578 struct U : virtual A {
579   virtual void g();  // adds a vfptr
580 };
581 
582 struct V : Z {
583   // RET-V: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries).
584   // RET-V-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo()
585   // RET-V-NEXT:     [return adjustment: vbptr at offset 4, vbase #1, 0 non-virtual]
586   // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
587 
588   // RET-V: VFTable indices for 'return_adjustment::V' (1 entries).
589   // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
590 
591   virtual U* foo();
592 };
593 
594 V v;
595 }
596