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