1// RUN: %clang_cc1 -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
5struct Empty { };
6
7struct A {
8  virtual void f();
9  virtual void z();  // Useful to check there are no thunks for f() when appropriate.
10};
11
12struct B {
13  virtual void g();
14};
15
16struct 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: @"\01??_7C@@6B@"
26
27  virtual void f() {}
28};
29
30C c;
31void use(C *obj) { obj->f(); }
32
33struct 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: @"\01??_7D@@6B0@@"
48  // MANGLING-DAG: @"\01??_7D@@6BA@@@"
49
50  virtual void f();
51  virtual void h();
52};
53
54D d;
55void use(D *obj) { obj->h(); }
56
57namespace Test1 {
58
59struct X { int x; };
60
61// X and A get reordered in the layout since X doesn't have a vfptr while A has.
62struct Y : X, A { };
63// MANGLING-DAG: @"\01??_7Y@Test1@@6B@"
64
65struct 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: @"\01??_7Z@Test1@@6B@"
74};
75
76Z::Z() {}
77}
78
79namespace Test2 {
80
81struct 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: @"\01??_7X@Test2@@6B01@@"
96  // MANGLING-DAG: @"\01??_7X@Test2@@6BA@@@"
97  // MANGLING-DAG: @"\01??_7X@Test2@@6BB@@@"
98
99  virtual void h();
100};
101
102X x;
103void use(X *obj) { obj->h(); }
104}
105
106namespace Test3 {
107
108struct X : virtual A {
109  // MANGLING-DAG: @"\01??_7X@Test3@@6B@"
110};
111
112struct 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: @"\01??_7Y@Test3@@6B@"
121};
122
123Y::Y() {}
124}
125
126namespace Test4 {
127
128struct 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: @"\01??_7X@Test4@@6B@"
146
147  // Also check the mangling of the thunk.
148  // MANGLING-DAG: define linkonce_odr x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ"
149};
150
151X::X() {}
152}
153
154namespace Test5 {
155
156// New methods are added to the base's vftable.
157struct X : A {
158  // MANGLING-DAG: @"\01??_7X@Test5@@6B@"
159  virtual void g();
160};
161
162struct 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: @"\01??_7Y@Test5@@6B01@@"
175  // MANGLING-DAG: @"\01??_7Y@Test5@@6BX@1@@"
176
177  virtual void h();
178};
179
180Y y;
181void use(Y *obj) { obj->h(); }
182}
183
184namespace Test6 {
185
186struct 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: @"\01??_7X@Test6@@6B@"
195};
196
197X::X() {}
198}
199
200namespace Test7 {
201
202struct X : C {
203  // MANGLING-DAG: @"\01??_7X@Test7@@6B@"
204};
205
206struct 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: @"\01??_7Y@Test7@@6B@"
219};
220
221Y::Y() {}
222}
223
224namespace Test8 {
225
226// This is a typical diamond inheritance with a shared 'A' vbase.
227struct 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: @"\01??_7X@Test8@@6BA@@@"
240  // MANGLING-DAG: @"\01??_7X@Test8@@6BD@@@"
241
242  virtual void f();
243};
244
245X x;
246void use(X *obj) { obj->f(); }
247
248// Another diamond inheritance which led to AST crashes.
249struct Y : virtual A {};
250
251struct 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};
261Z z;
262void use(Z *obj) { obj->f(); }
263
264// Another diamond inheritance which we miscompiled (PR18967).
265struct W : virtual A {
266  virtual void bar();
267};
268
269struct 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};
283T t;
284void use(T *obj) { obj->bar(); }
285}
286
287namespace Test9 {
288
289struct X : A { };
290
291struct 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: @"\01??_7Y@Test9@@6B01@@"
303  // MANGLING-DAG: @"\01??_7Y@Test9@@6BX@1@@"
304
305  virtual void h();
306};
307
308Y y;
309void use(Y *obj) { obj->h(); }
310
311struct 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: @"\01??_7Z@Test9@@6BX@1@@"
326  // MANGLING-DAG: @"\01??_7Z@Test9@@6BY@1@@"
327
328  // MANGLING-DAG: @"\01??_7Z@Test9@@6B@"
329};
330
331Z::Z() {}
332
333struct 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: @"\01??_7W@Test9@@6BA@@@"
359  // MANGLING-DAG: @"\01??_7W@Test9@@6BD@@@"
360  // MANGLING-DAG: @"\01??_7W@Test9@@6BX@1@@"
361
362  // MANGLING-DAG: @"\01??_7W@Test9@@6B@"
363  // MANGLING-DAG: @"\01??_7W@Test9@@6BY@1@@"
364};
365
366W::W() {}
367
368struct 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: @"\01??_7T@Test9@@6BA@@@"
408  // MANGLING-DAG: @"\01??_7T@Test9@@6BD@@@"
409  // MANGLING-DAG: @"\01??_7T@Test9@@6BX@1@@"
410
411  // MANGLING-DAG: @"\01??_7T@Test9@@6B@"
412  // MANGLING-DAG: @"\01??_7T@Test9@@6BY@1@@"
413
414  virtual void f();
415  virtual void g();
416  virtual void h();
417  virtual void z();
418};
419
420T t;
421void use(T *obj) { obj->f(); }
422}
423
424namespace Test10 {
425struct 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
436void X::f() {}
437X x;
438void use(X *obj) { obj->f(); }
439}
440
441namespace Test11 {
442struct X : virtual A {};
443struct Y { virtual void g(); };
444
445struct Z : virtual X, Y {
446  // MANGLING-DAG: @"\01??_7Z@Test11@@6BY@1@@"
447  // MANGLING-DAG: @"\01??_7Z@Test11@@6BX@1@@"
448};
449
450Z z;
451
452struct W : virtual X, A {};
453
454// Used to crash, PR17748.
455W w;
456}
457
458namespace Test12 {
459struct X : B, A { };
460
461struct Y : X {
462  virtual void f();  // Overrides A::f.
463};
464
465struct 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: @"\01??_7Z@Test12@@6BA@@@" = {{.*}}@"\01?f@Y@Test12@@UAEXXZ"
472};
473
474struct 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: @"\01??_7W@Test12@@6BA@@@" = {{.*}}@"\01?f@Y@Test12@@UAEXXZ"
482};
483
484W::W() {}
485}
486
487namespace vdtors {
488struct X {
489  virtual ~X();
490  virtual void zzz();
491};
492
493struct 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
502Y y;
503void use(Y *obj) { delete obj; }
504
505struct Z {
506  virtual void z();
507};
508
509struct W : Z, X {
510  // Implicit virtual dtor.
511};
512
513struct 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
531U u;
532void use(U *obj) { delete obj; }
533
534struct 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
551V v;
552void use(V *obj) { delete obj; }
553
554struct T : virtual X {
555  virtual ~T();
556};
557
558struct 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
567P p;
568void use(P *obj) { delete obj; }
569
570struct Q {
571  virtual ~Q();
572};
573
574// PR19172: Yet another diamond we miscompiled.
575struct 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
592R r;
593void use(R *obj) { delete obj; }
594}
595
596namespace return_adjustment {
597
598struct X : virtual A {
599  virtual void f();
600};
601
602struct Y : virtual A, virtual X {
603  virtual void f();
604};
605
606struct Z {
607  virtual A* foo();
608};
609
610struct 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
625W w;
626void use(W *obj) { obj->foo(); }
627
628struct 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
646T t;
647void use(T *obj) { obj->foo(); }
648
649struct U : virtual A {
650  virtual void g();  // adds a vfptr
651};
652
653struct 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
668V v;
669void use(V *obj) { obj->foo(); }
670}
671
672namespace pr17748 {
673struct A {
674  virtual void f() {}
675};
676
677struct B : virtual A {
678  B() {}
679};
680
681struct C : virtual B, A {
682  C() {}
683};
684C c;
685
686// MANGLING-DAG: @"\01??_7A@pr17748@@6B@"
687// MANGLING-DAG: @"\01??_7B@pr17748@@6B@"
688// MANGLING-DAG: @"\01??_7C@pr17748@@6BA@1@@"
689// MANGLING-DAG: @"\01??_7C@pr17748@@6BB@1@@"
690}
691
692namespace pr19066 {
693struct X : virtual B {};
694
695struct 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
704Y::Y() {}
705}
706
707namespace pr19240 {
708struct A {
709  virtual void c();
710};
711
712struct B : virtual A {
713  virtual void c();
714};
715
716struct C { };
717
718struct D : virtual A, virtual C, B {};
719
720D obj;
721
722// Each MDC only has one vftable.
723
724// MANGLING-DAG: @"\01??_7D@pr19240@@6B@"
725// MANGLING-DAG: @"\01??_7A@pr19240@@6B@"
726// MANGLING-DAG: @"\01??_7B@pr19240@@6B@"
727
728}
729
730namespace pr19408 {
731// This test is a non-vtordisp version of the reproducer for PR19408.
732struct X : virtual A {
733  int x;
734};
735
736struct Y : X {
737  virtual void f();
738  int y;
739};
740
741struct 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: @"\01??_7Z@pr19408@@6B@" = {{.*}}@"\01?f@Y@pr19408@@W3AEXXZ"
750};
751
752Z::Z() {}
753
754struct 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: @"\01??_7W@pr19408@@6BY@1@@" = {{.*}}@"\01?f@Y@pr19408@@W3AEXXZ"
763};
764
765W::W() {}
766}
767