]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
Vendor import of clang trunk r338150:
[FreeBSD/FreeBSD.git] / test / CodeGenCXX / microsoft-abi-vtables-virtual-inheritance.cpp
1 // RUN: %clang_cc1 -std=c++11 -fms-extensions -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t
2 // RUN: FileCheck %s < %t
3 // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
4
5 struct Empty { };
6
7 struct A {
8   virtual void f();
9   virtual void z();  // Useful to check there are no thunks for f() when appropriate.
10 };
11
12 struct B {
13   virtual void g();
14 };
15
16 struct C: virtual A {
17   // CHECK-LABEL: VFTable for 'A' in 'C' (2 entries)
18   // CHECK-NEXT: 0 | void C::f()
19   // CHECK-NEXT: 1 | void A::z()
20
21   // CHECK-LABEL: VFTable indices for 'C' (1 entry)
22   // CHECK-NEXT: vbtable index 1, vfptr at offset 0
23   // CHECK-NEXT: 0 | void C::f()
24
25   // MANGLING-DAG: @"??_7C@@6B@"
26
27   virtual void f() {}
28 };
29
30 C c;
31 void use(C *obj) { obj->f(); }
32
33 struct D: virtual A {
34   // CHECK-LABEL: VFTable for 'D' (1 entry).
35   // CHECK-NEXT: 0 | void D::h()
36
37   // CHECK-LABEL: VFTable for 'A' in 'D' (2 entries).
38   // CHECK-NEXT: 0 | void D::f()
39   // CHECK-NEXT: 1 | void A::z()
40
41   // CHECK-LABEL: VFTable indices for 'D' (2 entries).
42   // CHECK-NEXT: via vfptr at offset 0
43   // CHECK-NEXT: 0 | void D::h()
44   // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
45   // CHECK-NEXT: 0 | void D::f()
46
47   // MANGLING-DAG: @"??_7D@@6B0@@"
48   // MANGLING-DAG: @"??_7D@@6BA@@@"
49
50   virtual void f();
51   virtual void h();
52 };
53
54 D d;
55 void use(D *obj) { obj->h(); }
56
57 namespace Test1 {
58
59 struct X { int x; };
60
61 // X and A get reordered in the layout since X doesn't have a vfptr while A has.
62 struct Y : X, A { };
63 // MANGLING-DAG: @"??_7Y@Test1@@6B@"
64
65 struct Z : virtual Y {
66   Z();
67   // CHECK-LABEL: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries).
68   // CHECK-NEXT: 0 | void A::f()
69   // CHECK-NEXT: 1 | void A::z()
70
71   // CHECK-NOT: VFTable indices for 'Test1::Z'
72
73   // MANGLING-DAG: @"??_7Z@Test1@@6B@"
74 };
75
76 Z::Z() {}
77 }
78
79 namespace Test2 {
80
81 struct X: virtual A, virtual B {
82   // CHECK-LABEL: VFTable for 'Test2::X' (1 entry).
83   // CHECK-NEXT: 0 | void Test2::X::h()
84
85   // CHECK-LABEL: VFTable for 'A' in 'Test2::X' (2 entries).
86   // CHECK-NEXT: 0 | void A::f()
87   // CHECK-NEXT: 1 | void A::z()
88
89   // CHECK-LABEL: VFTable for 'B' in 'Test2::X' (1 entry).
90   // CHECK-NEXT: 0 | void B::g()
91
92   // CHECK-LABEL: VFTable indices for 'Test2::X' (1 entry).
93   // CHECK-NEXT: 0 | void Test2::X::h()
94
95   // MANGLING-DAG: @"??_7X@Test2@@6B01@@"
96   // MANGLING-DAG: @"??_7X@Test2@@6BA@@@"
97   // MANGLING-DAG: @"??_7X@Test2@@6BB@@@"
98
99   virtual void h();
100 };
101
102 X x;
103 void use(X *obj) { obj->h(); }
104 }
105
106 namespace Test3 {
107
108 struct X : virtual A {
109   // MANGLING-DAG: @"??_7X@Test3@@6B@"
110 };
111
112 struct Y: virtual X {
113   Y();
114   // CHECK-LABEL: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries).
115   // CHECK-NEXT: 0 | void A::f()
116   // CHECK-NEXT: 1 | void A::z()
117
118   // CHECK-NOT: VFTable indices for 'Test3::Y'
119
120   // MANGLING-DAG: @"??_7Y@Test3@@6B@"
121 };
122
123 Y::Y() {}
124 }
125
126 namespace Test4 {
127
128 struct X: virtual C {
129   X();
130   // This one's interesting. C::f expects (A*) to be passed as 'this' and does
131   // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk
132   // should pass a pointer to the end of X in order
133   // for ECX-=4 to point at the C part.
134
135   // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test4::X' (2 entries).
136   // CHECK-NEXT: 0 | void C::f()
137   // CHECK-NEXT:     [this adjustment: 8 non-virtual]
138   // CHECK-NEXT: 1 | void A::z()
139
140   // CHECK-LABEL: Thunks for 'void C::f()' (1 entry).
141   // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual]
142
143   // CHECK-NOT: VFTable indices for 'Test4::X'
144
145   // MANGLING-DAG: @"??_7X@Test4@@6B@"
146
147   // Also check the mangling of the thunk.
148   // MANGLING-DAG: define linkonce_odr dso_local x86_thiscallcc void @"?f@C@@WPPPPPPPI@AEXXZ"
149 };
150
151 X::X() {}
152 }
153
154 namespace Test5 {
155
156 // New methods are added to the base's vftable.
157 struct X : A {
158   // MANGLING-DAG: @"??_7X@Test5@@6B@"
159   virtual void g();
160 };
161
162 struct Y : virtual X {
163   // CHECK-LABEL: VFTable for 'Test5::Y' (1 entry).
164   // CHECK-NEXT: 0 | void Test5::Y::h()
165
166   // CHECK-LABEL: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries).
167   // CHECK-NEXT: 0 | void A::f()
168   // CHECK-NEXT: 1 | void A::z()
169   // CHECK-NEXT: 2 | void Test5::X::g()
170
171   // CHECK-LABEL: VFTable indices for 'Test5::Y' (1 entry).
172   // CHECK-NEXT: 0 | void Test5::Y::h()
173
174   // MANGLING-DAG: @"??_7Y@Test5@@6B01@@"
175   // MANGLING-DAG: @"??_7Y@Test5@@6BX@1@@"
176
177   virtual void h();
178 };
179
180 Y y;
181 void use(Y *obj) { obj->h(); }
182 }
183
184 namespace Test6 {
185
186 struct X : A, virtual Empty {
187   X();
188   // CHECK-LABEL: VFTable for 'A' in 'Test6::X' (2 entries).
189   // CHECK-NEXT: 0 | void A::f()
190   // CHECK-NEXT: 1 | void A::z()
191
192   // CHECK-NOT: VFTable indices for 'Test6::X'
193
194   // MANGLING-DAG: @"??_7X@Test6@@6B@"
195 };
196
197 X::X() {}
198 }
199
200 namespace Test7 {
201
202 struct X : C {
203   // MANGLING-DAG: @"??_7X@Test7@@6B@"
204 };
205
206 struct Y : virtual X {
207   Y();
208   // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries).
209   // CHECK-NEXT: 0 | void C::f()
210   // CHECK-NEXT:     [this adjustment: 8 non-virtual]
211   // CHECK-NEXT: 1 | void A::z()
212
213   // CHECK-LABEL: Thunks for 'void C::f()' (1 entry).
214   // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual]
215
216   // CHECK-NOT: VFTable indices for 'Test7::Y'
217
218   // MANGLING-DAG: @"??_7Y@Test7@@6B@"
219 };
220
221 Y::Y() {}
222 }
223
224 namespace Test8 {
225
226 // This is a typical diamond inheritance with a shared 'A' vbase.
227 struct X : D, C {
228   // CHECK-LABEL: VFTable for 'D' in 'Test8::X' (1 entry).
229   // CHECK-NEXT: 0 | void D::h()
230
231   // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test8::X' (2 entries).
232   // CHECK-NEXT: 0 | void Test8::X::f()
233   // CHECK-NEXT: 1 | void A::z()
234
235   // CHECK-LABEL: VFTable indices for 'Test8::X' (1 entry).
236   // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
237   // CHECK-NEXT: 0 | void Test8::X::f()
238
239   // MANGLING-DAG: @"??_7X@Test8@@6BA@@@"
240   // MANGLING-DAG: @"??_7X@Test8@@6BD@@@"
241
242   virtual void f();
243 };
244
245 X x;
246 void use(X *obj) { obj->f(); }
247
248 // Another diamond inheritance which led to AST crashes.
249 struct Y : virtual A {};
250
251 struct Z : Y, C {
252   // CHECK-LABEL: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries).
253   // CHECK-NEXT: 0 | void Test8::Z::f()
254   // CHECK-NEXT: 1 | void A::z()
255
256   // CHECK-LABEL: VFTable indices for 'Test8::Z' (1 entry).
257   // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
258   // CHECK-NEXT: 0 | void Test8::Z::f()
259   virtual void f();
260 };
261 Z z;
262 void use(Z *obj) { obj->f(); }
263
264 // Another diamond inheritance which we miscompiled (PR18967).
265 struct W : virtual A {
266   virtual void bar();
267 };
268
269 struct T : W, C {
270   // CHECK-LABEL: VFTable for 'Test8::W' in 'Test8::T' (1 entry)
271   // CHECK-NEXT: 0 | void Test8::T::bar()
272
273   // CHECK-LABEL: VFTable for 'A' in 'Test8::W' in 'Test8::T' (2 entries)
274   // CHECK-NEXT: 0 | void C::f()
275   // CHECK-NEXT:     [this adjustment: -4 non-virtual]
276   // CHECK-NEXT: 1 | void A::z()
277
278   // CHECK-LABEL: Thunks for 'void C::f()' (1 entry).
279   // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
280   virtual void bar();
281   int field;
282 };
283 T t;
284 void use(T *obj) { obj->bar(); }
285 }
286
287 namespace Test9 {
288
289 struct X : A { };
290
291 struct Y : virtual X {
292   // CHECK-LABEL: VFTable for 'Test9::Y' (1 entry).
293   // CHECK-NEXT: 0 | void Test9::Y::h()
294
295   // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries).
296   // CHECK-NEXT: 0 | void A::f()
297   // CHECK-NEXT: 1 | void A::z()
298
299   // CHECK-LABEL: VFTable indices for 'Test9::Y' (1 entry).
300   // CHECK-NEXT: 0 | void Test9::Y::h()
301
302   // MANGLING-DAG: @"??_7Y@Test9@@6B01@@"
303   // MANGLING-DAG: @"??_7Y@Test9@@6BX@1@@"
304
305   virtual void h();
306 };
307
308 Y y;
309 void use(Y *obj) { obj->h(); }
310
311 struct Z : Y, virtual B {
312   Z();
313   // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' (1 entry).
314   // CHECK-NEXT: 0 | void Test9::Y::h()
315
316   // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries).
317   // CHECK-NEXT: 0 | void A::f()
318   // CHECK-NEXT: 1 | void A::z()
319
320   // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' (1 entry).
321   // CHECK-NEXT: 0 | void B::g()
322
323   // CHECK-NOT: VFTable indices for 'Test9::Z'
324
325   // MANGLING-DAG: @"??_7Z@Test9@@6BX@1@@"
326   // MANGLING-DAG: @"??_7Z@Test9@@6BY@1@@"
327
328   // MANGLING-DAG: @"??_7Z@Test9@@6B@"
329 };
330
331 Z::Z() {}
332
333 struct W : Z, D, virtual A, virtual B {
334   W();
335   // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entry).
336   // CHECK-NEXT: 0 | void Test9::Y::h()
337
338   // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries).
339   // CHECK-NEXT: 0 | void A::f()
340   // CHECK-NEXT: 1 | void A::z()
341
342   // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entry).
343   // CHECK-NEXT: 0 | void B::g()
344
345   // CHECK-LABEL: VFTable for 'D' in 'Test9::W' (1 entry).
346   // CHECK-NEXT: 0 | void D::h()
347
348   // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::W' (2 entries).
349   // CHECK-NEXT: 0 | void D::f()
350   // CHECK-NEXT:     [this adjustment: -8 non-virtual]
351   // CHECK-NEXT: 1 | void A::z()
352
353   // CHECK-LABEL: Thunks for 'void D::f()' (1 entry).
354   // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
355
356   // CHECK-NOT: VFTable indices for 'Test9::W'
357
358   // MANGLING-DAG: @"??_7W@Test9@@6BA@@@"
359   // MANGLING-DAG: @"??_7W@Test9@@6BD@@@"
360   // MANGLING-DAG: @"??_7W@Test9@@6BX@1@@"
361
362   // MANGLING-DAG: @"??_7W@Test9@@6B@"
363   // MANGLING-DAG: @"??_7W@Test9@@6BY@1@@"
364 };
365
366 W::W() {}
367
368 struct T : Z, D, virtual A, virtual B {
369   // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entry).
370   // CHECK-NEXT: 0 | void Test9::T::h()
371
372   // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries).
373   // CHECK-NEXT: 0 | void Test9::T::f()
374   // CHECK-NEXT: 1 | void Test9::T::z()
375
376   // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entry).
377   // CHECK-NEXT: 0 | void Test9::T::g()
378
379   // CHECK-LABEL: VFTable for 'D' in 'Test9::T' (1 entry).
380   // CHECK-NEXT: 0 | void Test9::T::h()
381   // CHECK-NEXT:     [this adjustment: -8 non-virtual]
382
383   // CHECK-LABEL: Thunks for 'void Test9::T::h()' (1 entry).
384   // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
385
386   // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::T' (2 entries).
387   // CHECK-NEXT: 0 | void Test9::T::f()
388   // CHECK-NEXT:     [this adjustment: -8 non-virtual]
389   // CHECK-NEXT: 1 | void Test9::T::z()
390   // CHECK-NEXT:     [this adjustment: -8 non-virtual]
391
392   // CHECK-LABEL: Thunks for 'void Test9::T::f()' (1 entry).
393   // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
394
395   // CHECK-LABEL: Thunks for 'void Test9::T::z()' (1 entry).
396   // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
397
398   // CHECK-LABEL: VFTable indices for 'Test9::T' (4 entries).
399   // CHECK-NEXT: via vfptr at offset 0
400   // CHECK-NEXT: 0 | void Test9::T::h()
401   // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
402   // CHECK-NEXT: 0 | void Test9::T::f()
403   // CHECK-NEXT: 1 | void Test9::T::z()
404   // CHECK-NEXT: via vbtable index 2, vfptr at offset 0
405   // CHECK-NEXT: 0 | void Test9::T::g()
406
407   // MANGLING-DAG: @"??_7T@Test9@@6BA@@@"
408   // MANGLING-DAG: @"??_7T@Test9@@6BD@@@"
409   // MANGLING-DAG: @"??_7T@Test9@@6BX@1@@"
410
411   // MANGLING-DAG: @"??_7T@Test9@@6B@"
412   // MANGLING-DAG: @"??_7T@Test9@@6BY@1@@"
413
414   virtual void f();
415   virtual void g();
416   virtual void h();
417   virtual void z();
418 };
419
420 T t;
421 void use(T *obj) { obj->f(); }
422 }
423
424 namespace Test10 {
425 struct X : virtual C, virtual A {
426   // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test10::X' (2 entries).
427   // CHECK-NEXT: 0 | void Test10::X::f()
428   // CHECK-NEXT: 1 | void A::z()
429
430   // CHECK-LABEL: VFTable indices for 'Test10::X' (1 entry).
431   // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
432   // CHECK-NEXT: 0 | void Test10::X::f()
433   virtual void f();
434 };
435
436 void X::f() {}
437 X x;
438 void use(X *obj) { obj->f(); }
439 }
440
441 namespace Test11 {
442 struct X : virtual A {};
443 struct Y { virtual void g(); };
444
445 struct Z : virtual X, Y {
446   // MANGLING-DAG: @"??_7Z@Test11@@6BY@1@@"
447   // MANGLING-DAG: @"??_7Z@Test11@@6BX@1@@"
448 };
449
450 Z z;
451
452 struct W : virtual X, A {};
453
454 // Used to crash, PR17748.
455 W w;
456 }
457
458 namespace Test12 {
459 struct X : B, A { };
460
461 struct Y : X {
462   virtual void f();  // Overrides A::f.
463 };
464
465 struct Z : virtual Y {
466   // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' (2 entries).
467   // CHECK-NEXT:   0 | void Test12::Y::f()
468   // CHECK-NEXT:   1 | void A::z()
469
470   int z;
471   // MANGLING-DAG: @"??_7Z@Test12@@6BA@@@" = {{.*}}@"?f@Y@Test12@@UAEXXZ"
472 };
473
474 struct W : Z {
475   // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' in 'Test12::W' (2 entries).
476   // CHECK-NEXT:   0 | void Test12::Y::f()
477   // CHECK-NEXT:   1 | void A::z()
478   W();
479
480   int w;
481   // MANGLING-DAG: @"??_7W@Test12@@6BA@@@" = {{.*}}@"?f@Y@Test12@@UAEXXZ"
482 };
483
484 W::W() {}
485 }
486
487 namespace vdtors {
488 struct X {
489   virtual ~X();
490   virtual void zzz();
491 };
492
493 struct Y : virtual X {
494   // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries).
495   // CHECK-NEXT: 0 | vdtors::Y::~Y() [scalar deleting]
496   // CHECK-NEXT: 1 | void vdtors::X::zzz()
497
498   // CHECK-NOT: Thunks for 'vdtors::Y::~Y()'
499   virtual ~Y();
500 };
501
502 Y y;
503 void use(Y *obj) { delete obj; }
504
505 struct Z {
506   virtual void z();
507 };
508
509 struct W : Z, X {
510   // Implicit virtual dtor.
511 };
512
513 struct U : virtual W {
514   // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entry).
515   // CHECK-NEXT: 0 | void vdtors::Z::z()
516
517   // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries).
518   // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting]
519   // CHECK-NEXT:     [this adjustment: -4 non-virtual]
520   // CHECK-NEXT: 1 | void vdtors::X::zzz()
521
522   // CHECK-LABEL: Thunks for 'vdtors::U::~U()' (1 entry).
523   // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
524
525   // CHECK-LABEL: VFTable indices for 'vdtors::U' (1 entry).
526   // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
527   // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting]
528   virtual ~U();
529 };
530
531 U u;
532 void use(U *obj) { delete obj; }
533
534 struct V : virtual W {
535   // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entry).
536   // CHECK-NEXT: 0 | void vdtors::Z::z()
537
538   // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries).
539   // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting]
540   // CHECK-NEXT:     [this adjustment: -4 non-virtual]
541   // CHECK-NEXT: 1 | void vdtors::X::zzz()
542
543   // CHECK-LABEL: Thunks for 'vdtors::V::~V()' (1 entry).
544   // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
545
546   // CHECK-LABEL: VFTable indices for 'vdtors::V' (1 entry).
547   // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
548   // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting]
549 };
550
551 V v;
552 void use(V *obj) { delete obj; }
553
554 struct T : virtual X {
555   virtual ~T();
556 };
557
558 struct P : T, Y {
559   // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries).
560   // CHECK-NEXT: 0 | vdtors::P::~P() [scalar deleting]
561   // CHECK-NEXT: 1 | void vdtors::X::zzz()
562
563   // CHECK-NOT: Thunks for 'vdtors::P::~P()'
564   virtual ~P();
565 };
566
567 P p;
568 void use(P *obj) { delete obj; }
569
570 struct Q {
571   virtual ~Q();
572 };
573
574 // PR19172: Yet another diamond we miscompiled.
575 struct R : virtual Q, X {
576   // CHECK-LABEL: VFTable for 'vdtors::Q' in 'vdtors::R' (1 entry).
577   // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting]
578   // CHECK-NEXT:     [this adjustment: -8 non-virtual]
579
580   // CHECK-LABEL: Thunks for 'vdtors::R::~R()' (1 entry).
581   // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
582
583   // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries).
584   // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting]
585   // CHECK-NEXT: 1 | void vdtors::X::zzz()
586
587   // CHECK-LABEL: VFTable indices for 'vdtors::R' (1 entry).
588   // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting]
589   virtual ~R();
590 };
591
592 R r;
593 void use(R *obj) { delete obj; }
594 }
595
596 namespace return_adjustment {
597
598 struct X : virtual A {
599   virtual void f();
600 };
601
602 struct Y : virtual A, virtual X {
603   virtual void f();
604 };
605
606 struct Z {
607   virtual A* foo();
608 };
609
610 struct W : Z {
611   // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries).
612   // CHECK-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo()
613   // CHECK-NEXT:     [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]
614   // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
615
616   // CHECK-LABEL: Thunks for 'return_adjustment::X *return_adjustment::W::foo()' (1 entry).
617   // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]
618
619   // CHECK-LABEL: VFTable indices for 'return_adjustment::W' (1 entry).
620   // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
621
622   virtual X* foo();
623 };
624
625 W w;
626 void use(W *obj) { obj->foo(); }
627
628 struct T : W {
629   // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries).
630   // CHECK-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo()
631   // CHECK-NEXT:     [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]
632   // CHECK-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo()
633   // CHECK-NEXT:     [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual]
634   // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
635
636   // CHECK-LABEL: Thunks for 'return_adjustment::Y *return_adjustment::T::foo()' (2 entries).
637   // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]
638   // CHECK-NEXT: 1 | [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual]
639
640   // CHECK-LABEL: VFTable indices for 'return_adjustment::T' (1 entry).
641   // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
642
643   virtual Y* foo();
644 };
645
646 T t;
647 void use(T *obj) { obj->foo(); }
648
649 struct U : virtual A {
650   virtual void g();  // adds a vfptr
651 };
652
653 struct V : Z {
654   // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries).
655   // CHECK-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo()
656   // CHECK-NEXT:     [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual]
657   // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
658
659   // CHECK-LABEL: Thunks for 'return_adjustment::U *return_adjustment::V::foo()' (1 entry).
660   // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual]
661
662   // CHECK-LABEL: VFTable indices for 'return_adjustment::V' (1 entry).
663   // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
664
665   virtual U* foo();
666 };
667
668 V v;
669 void use(V *obj) { obj->foo(); }
670 }
671
672 namespace pr17748 {
673 struct A {
674   virtual void f() {}
675 };
676
677 struct B : virtual A {
678   B() {}
679 };
680
681 struct C : virtual B, A {
682   C() {}
683 };
684 C c;
685
686 // MANGLING-DAG: @"??_7A@pr17748@@6B@"
687 // MANGLING-DAG: @"??_7B@pr17748@@6B@"
688 // MANGLING-DAG: @"??_7C@pr17748@@6BA@1@@"
689 // MANGLING-DAG: @"??_7C@pr17748@@6BB@1@@"
690 }
691
692 namespace pr19066 {
693 struct X : virtual B {};
694
695 struct Y : virtual X, B {
696   Y();
697   // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry).
698   // CHECK-NEXT:  0 | void B::g()
699
700   // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry).
701   // CHECK-NEXT:  0 | void B::g()
702 };
703
704 Y::Y() {}
705 }
706
707 namespace pr19240 {
708 struct A {
709   virtual void c();
710 };
711
712 struct B : virtual A {
713   virtual void c();
714 };
715
716 struct C { };
717
718 struct D : virtual A, virtual C, B {};
719
720 D obj;
721
722 // Each MDC only has one vftable.
723
724 // MANGLING-DAG: @"??_7D@pr19240@@6B@"
725 // MANGLING-DAG: @"??_7A@pr19240@@6B@"
726 // MANGLING-DAG: @"??_7B@pr19240@@6B@"
727
728 }
729
730 namespace pr19408 {
731 // This test is a non-vtordisp version of the reproducer for PR19408.
732 struct X : virtual A {
733   int x;
734 };
735
736 struct Y : X {
737   virtual void f();
738   int y;
739 };
740
741 struct Z : Y {
742   // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::Z' (2 entries).
743   // CHECK-NEXT:   0 | void pr19408::Y::f()
744   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
745   // CHECK-NEXT:   1 | void A::z()
746
747   Z();
748   int z;
749   // MANGLING-DAG: @"??_7Z@pr19408@@6B@" = {{.*}}@"?f@Y@pr19408@@W3AEXXZ"
750 };
751
752 Z::Z() {}
753
754 struct W : B, Y {
755   // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::W' (2 entries).
756   // CHECK-NEXT:   0 | void pr19408::Y::f()
757   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
758   // CHECK-NEXT:   1 | void A::z()
759
760   W();
761   int w;
762   // MANGLING-DAG: @"??_7W@pr19408@@6BY@1@@" = {{.*}}@"?f@Y@pr19408@@W3AEXXZ"
763 };
764
765 W::W() {}
766 }
767
768 namespace Test13 {
769 struct A {
770   virtual void f();
771 };
772 struct __declspec(dllexport) B : virtual A {
773   virtual void f() = 0;
774   // MANGLING-DAG: @"??_7B@Test13@@6B@" = weak_odr dllexport unnamed_addr constant { [1 x i8*] } { [1 x i8*] [i8* bitcast (void ()* @_purecall to i8*)] }
775 };
776 }
777
778 namespace pr21031_1 {
779 // This ordering of base specifiers regressed in r202425.
780 struct A { virtual void f(void); };
781 struct B : virtual A { virtual void g(void); };
782 struct C : virtual A, B { C(); };
783 C::C() {}
784
785 // CHECK-LABEL: VFTable for 'pr21031_1::A' in 'pr21031_1::B' in 'pr21031_1::C' (1 entry)
786 // CHECK-NEXT:   0 | void pr21031_1::A::f()
787
788 // CHECK-LABEL: VFTable for 'pr21031_1::B' in 'pr21031_1::C' (1 entry)
789 // CHECK-NEXT:   0 | void pr21031_1::B::g()
790
791 // MANGLING-DAG: @"??_7C@pr21031_1@@6BB@1@@" = {{.*}} constant { [1 x i8*] }
792 // MANGLING-DAG: @"??_7C@pr21031_1@@6B@" = {{.*}} constant { [1 x i8*] }
793 }
794
795 namespace pr21031_2 {
796 struct A { virtual void f(void); };
797 struct B : virtual A { virtual void g(void); };
798 struct C : B, virtual A { C(); };
799 C::C() {}
800
801 // CHECK-LABEL: VFTable for 'pr21031_2::B' in 'pr21031_2::C' (1 entry)
802 // CHECK-NEXT:   0 | void pr21031_2::B::g()
803
804 // CHECK-LABEL: VFTable for 'pr21031_2::A' in 'pr21031_2::B' in 'pr21031_2::C' (1 entry)
805 // CHECK-NEXT:   0 | void pr21031_2::A::f()
806
807 // MANGLING-DAG: @"??_7C@pr21031_2@@6BA@1@@" = {{.*}} constant { [1 x i8*] }
808 // MANGLING-DAG: @"??_7C@pr21031_2@@6BB@1@@" = {{.*}} constant { [1 x i8*] }
809 }
810
811 namespace pr21062_1 {
812 struct A { virtual void f(); };
813 struct B {};
814 struct C : virtual B {};
815 struct D : virtual C, virtual B, virtual A { D();};
816 D::D() {}
817
818 // CHECK-LABEL: VFTable for 'pr21062_1::A' in 'pr21062_1::D' (1 entry)
819 // CHECK-NEXT:   0 | void pr21062_1::A::f()
820
821 // MANGLING-DAG: @"??_7D@pr21062_1@@6B@" = {{.*}} constant { [1 x i8*] }
822 }
823
824 namespace pr21062_2 {
825 struct A { virtual void f(); };
826 struct B {};
827 struct C : virtual B {};
828 struct D : C, virtual B, virtual A { D(); };
829 D::D() {}
830
831 // CHECK-LABEL: VFTable for 'pr21062_2::A' in 'pr21062_2::D' (1 entry)
832 // CHECK-NEXT:   0 | void pr21062_2::A::f()
833
834 // MANGLING-DAG: @"??_7D@pr21062_2@@6B@" = {{.*}} constant { [1 x i8*] }
835 }
836
837 namespace pr21064 {
838 struct A {};
839 struct B { virtual void f(); };
840 struct C : virtual A, virtual B {};
841 struct D : virtual A, virtual C { D(); };
842 D::D() {}
843 // CHECK-LABEL: VFTable for 'pr21064::B' in 'pr21064::C' in 'pr21064::D' (1 entry)
844 // CHECK-NEXT:   0 | void pr21064::B::f()
845
846 // MANGLING-DAG: @"??_7D@pr21064@@6B@" = {{.*}} constant { [1 x i8*] }
847 }