1*67e74705SXin Li // RUN: %clang_cc1 -fno-rtti -emit-llvm -fdump-vtable-layouts %s -o %t.ll -triple=i386-pc-win32 > %t
2*67e74705SXin Li // RUN: FileCheck %s < %t
3*67e74705SXin Li // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
4*67e74705SXin Li
5*67e74705SXin Li // For now, just make sure x86_64 doesn't crash.
6*67e74705SXin Li // RUN: %clang_cc1 -fno-rtti -emit-llvm-only -fdump-vtable-layouts %s -triple=x86_64-pc-win32 > /dev/null
7*67e74705SXin Li
8*67e74705SXin Li struct V1 {
9*67e74705SXin Li virtual void f();
10*67e74705SXin Li virtual ~V1();
11*67e74705SXin Li };
12*67e74705SXin Li
13*67e74705SXin Li struct V2 {
14*67e74705SXin Li virtual void f();
15*67e74705SXin Li virtual ~V2();
16*67e74705SXin Li int v;
17*67e74705SXin Li };
18*67e74705SXin Li
19*67e74705SXin Li struct Z {
20*67e74705SXin Li virtual void g();
21*67e74705SXin Li virtual ~Z();
22*67e74705SXin Li int x;
23*67e74705SXin Li };
24*67e74705SXin Li
25*67e74705SXin Li struct V3 : Z, V2 {
26*67e74705SXin Li };
27*67e74705SXin Li
28*67e74705SXin Li struct V4 : Z, V1, V2 {
29*67e74705SXin Li int y;
30*67e74705SXin Li };
31*67e74705SXin Li
32*67e74705SXin Li void use_somewhere_else(void*);
33*67e74705SXin Li
34*67e74705SXin Li namespace simple {
35*67e74705SXin Li // In case of a single-layer virtual inheritance, the "this" adjustment for a
36*67e74705SXin Li // virtual method is done statically:
37*67e74705SXin Li // struct A {
38*67e74705SXin Li // virtual void f(); // Expects "(A*)this" in ECX
39*67e74705SXin Li // };
40*67e74705SXin Li // struct B : virtual A {
41*67e74705SXin Li // virtual void f(); // Expects "(char*)(B*)this + 12" in ECX
42*67e74705SXin Li // virtual ~B(); // Might call f()
43*67e74705SXin Li // };
44*67e74705SXin Li //
45*67e74705SXin Li // If a class overrides a virtual function of its base and has a non-trivial
46*67e74705SXin Li // ctor/dtor that call(s) the virtual function (or may escape "this" to some
47*67e74705SXin Li // code that might call it), a virtual adjustment might be needed in case the
48*67e74705SXin Li // current class layout and the most derived class layout are different.
49*67e74705SXin Li // This is done using vtordisp thunks.
50*67e74705SXin Li //
51*67e74705SXin Li // A simple vtordisp{x,y} thunk for Method@Class is something like:
52*67e74705SXin Li // sub ecx, [ecx+x] // apply the vtordisp adjustment
53*67e74705SXin Li // sub ecx, y // apply the subobject adjustment, if needed.
54*67e74705SXin Li // jmp Method@Class
55*67e74705SXin Li
56*67e74705SXin Li struct A : virtual V1 {
57*67e74705SXin Li // CHECK-LABEL: VFTable for 'V1' in 'simple::A' (2 entries).
58*67e74705SXin Li // CHECK-NEXT: 0 | void simple::A::f()
59*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
60*67e74705SXin Li // CHECK-NEXT: 1 | simple::A::~A() [scalar deleting]
61*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
62*67e74705SXin Li
63*67e74705SXin Li // CHECK-LABEL: Thunks for 'simple::A::~A()' (1 entry).
64*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, 0 non-virtual]
65*67e74705SXin Li
66*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::A::f()' (1 entry).
67*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, 0 non-virtual]
68*67e74705SXin Li
69*67e74705SXin Li virtual void f();
70*67e74705SXin Li // MANGLING-DAG: @"\01?f@A@simple@@$4PPPPPPPM@A@AEXXZ"
71*67e74705SXin Li
72*67e74705SXin Li virtual ~A();
73*67e74705SXin Li // MANGLING-DAG: @"\01??_EA@simple@@$4PPPPPPPM@A@AEPAXI@Z"
74*67e74705SXin Li };
75*67e74705SXin Li
76*67e74705SXin Li A a;
use(A * obj)77*67e74705SXin Li void use(A *obj) { obj->f(); }
78*67e74705SXin Li
79*67e74705SXin Li struct B : virtual V3 {
80*67e74705SXin Li // CHECK-LABEL: VFTable for 'Z' in 'V3' in 'simple::B' (2 entries).
81*67e74705SXin Li // CHECK-NEXT: 0 | void Z::g()
82*67e74705SXin Li // CHECK-NEXT: 1 | simple::B::~B() [scalar deleting]
83*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
84*67e74705SXin Li
85*67e74705SXin Li // CHECK-LABEL: Thunks for 'simple::B::~B()' (1 entry).
86*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, 0 non-virtual]
87*67e74705SXin Li
88*67e74705SXin Li // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::B' (2 entries).
89*67e74705SXin Li // CHECK-NEXT: 0 | void simple::B::f()
90*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, 0 non-virtual]
91*67e74705SXin Li // CHECK-NEXT: 1 | simple::B::~B() [scalar deleting]
92*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
93*67e74705SXin Li
94*67e74705SXin Li // CHECK-LABEL: Thunks for 'simple::B::~B()' (1 entry).
95*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -12, -8 non-virtual]
96*67e74705SXin Li
97*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::B::f()' (1 entry).
98*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -12, 0 non-virtual]
99*67e74705SXin Li
100*67e74705SXin Li // FIXME: The vtordisp thunk should only get emitted for a constructor
101*67e74705SXin Li // if "this" leaves scope.
Bsimple::B102*67e74705SXin Li B() { use_somewhere_else(this); }
103*67e74705SXin Li
104*67e74705SXin Li virtual void f();
105*67e74705SXin Li // MANGLING-DAG: @"\01?f@B@simple@@$4PPPPPPPE@A@AEXXZ"
106*67e74705SXin Li
107*67e74705SXin Li // Has an implicit destructor.
108*67e74705SXin Li // MANGLING-DAG: @"\01??_EB@simple@@$4PPPPPPPE@7AEPAXI@Z"
109*67e74705SXin Li // MANGLING-DAG: @"\01??_EB@simple@@$4PPPPPPPM@A@AEPAXI@Z"
110*67e74705SXin Li };
111*67e74705SXin Li
112*67e74705SXin Li B b;
use(B * obj)113*67e74705SXin Li void use(B *obj) { obj->f(); }
114*67e74705SXin Li
115*67e74705SXin Li struct C : virtual V4 {
116*67e74705SXin Li // CHECK-LABEL: VFTable for 'Z' in 'V4' in 'simple::C' (2 entries).
117*67e74705SXin Li // CHECK-NEXT: 0 | void Z::g()
118*67e74705SXin Li // CHECK-NEXT: 1 | simple::C::~C() [scalar deleting]
119*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
120*67e74705SXin Li
121*67e74705SXin Li // CHECK-LABEL: Thunks for 'simple::C::~C()' (1 entry).
122*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, 0 non-virtual]
123*67e74705SXin Li
124*67e74705SXin Li // CHECK-LABEL: VFTable for 'V1' in 'V4' in 'simple::C' (2 entries).
125*67e74705SXin Li // CHECK-NEXT: 0 | void simple::C::f()
126*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, 0 non-virtual]
127*67e74705SXin Li // CHECK-NEXT: 1 | simple::C::~C() [scalar deleting]
128*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
129*67e74705SXin Li
130*67e74705SXin Li // CHECK-LABEL: Thunks for 'simple::C::~C()' (1 entry).
131*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -12, -8 non-virtual]
132*67e74705SXin Li
133*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::C::f()' (1 entry).
134*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -12, 0 non-virtual]
135*67e74705SXin Li
136*67e74705SXin Li // CHECK-LABEL: VFTable for 'V2' in 'V4' in 'simple::C' (2 entries).
137*67e74705SXin Li // CHECK-NEXT: 0 | void simple::C::f()
138*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -16, -4 non-virtual]
139*67e74705SXin Li // CHECK-NEXT: 1 | simple::C::~C() [scalar deleting]
140*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -16, -12 non-virtual]
141*67e74705SXin Li
142*67e74705SXin Li // CHECK-LABEL: Thunks for 'simple::C::~C()' (1 entry).
143*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -16, -12 non-virtual]
144*67e74705SXin Li
145*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::C::f()' (1 entry).
146*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -16, -4 non-virtual]
147*67e74705SXin Li
148*67e74705SXin Li int x;
149*67e74705SXin Li virtual void f();
150*67e74705SXin Li // MANGLING-DAG: @"\01?f@C@simple@@$4PPPPPPPA@3AEXXZ"
151*67e74705SXin Li // MANGLING-DAG: @"\01?f@C@simple@@$4PPPPPPPE@A@AEXXZ"
152*67e74705SXin Li virtual ~C();
153*67e74705SXin Li // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPA@M@AEPAXI@Z"
154*67e74705SXin Li // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPE@7AEPAXI@Z"
155*67e74705SXin Li // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPM@A@AEPAXI@Z"
156*67e74705SXin Li };
157*67e74705SXin Li
158*67e74705SXin Li C c;
use(C * obj)159*67e74705SXin Li void use(C *obj) { obj->f(); }
160*67e74705SXin Li
161*67e74705SXin Li class D : B {
162*67e74705SXin Li // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::B' in 'simple::D' (2 entries).
163*67e74705SXin Li // CHECK-NEXT: 0 | void simple::B::f()
164*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, -4 non-virtual]
165*67e74705SXin Li // CHECK-NEXT: 1 | simple::D::~D() [scalar deleting]
166*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
167*67e74705SXin Li D();
168*67e74705SXin Li int z;
169*67e74705SXin Li
170*67e74705SXin Li // MANGLING-DAG: @"\01?f@B@simple@@$4PPPPPPPE@3AEXXZ"
171*67e74705SXin Li };
172*67e74705SXin Li
D()173*67e74705SXin Li D::D() {}
174*67e74705SXin Li
175*67e74705SXin Li struct E : V3 {
176*67e74705SXin Li virtual void f();
177*67e74705SXin Li };
178*67e74705SXin Li
179*67e74705SXin Li struct F : virtual E {
180*67e74705SXin Li // CHECK-LABEL: VFTable for 'Z' in 'V3' in 'simple::E' in 'simple::F' (2 entries).
181*67e74705SXin Li // CHECK-NEXT: 0 | void simple::F::g()
182*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
183*67e74705SXin Li // CHECK-NEXT: 1 | simple::F::~F() [scalar deleting]
184*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
185*67e74705SXin Li
186*67e74705SXin Li // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::E' in 'simple::F' (2 entries).
187*67e74705SXin Li // CHECK-NEXT: 0 | void simple::E::f()
188*67e74705SXin Li // CHECK-NEXT: 1 | simple::F::~F() [scalar deleting]
189*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
190*67e74705SXin Li
191*67e74705SXin Li F();
192*67e74705SXin Li virtual void g(); // Force a vtordisp.
193*67e74705SXin Li int f;
194*67e74705SXin Li
195*67e74705SXin Li // MANGLING-DAG: @"\01?g@F@simple@@$4PPPPPPPM@A@AEXXZ"{{.*}}??_EF@simple@@$4PPPPPPPM@A@AEPAXI@Z
196*67e74705SXin Li // MANGLING-DAG: ?f@E@simple@@UAEXXZ{{.*}}??_EF@simple@@$4PPPPPPPE@7AEPAXI@Z
197*67e74705SXin Li };
198*67e74705SXin Li
F()199*67e74705SXin Li F::F() {}
200*67e74705SXin Li
201*67e74705SXin Li struct G : F {
202*67e74705SXin Li // CHECK-LABEL: VFTable for 'Z' in 'V3' in 'simple::E' in 'simple::F' in 'simple::G' (2 entries).
203*67e74705SXin Li // CHECK-NEXT: 0 | void simple::F::g()
204*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual]
205*67e74705SXin Li // CHECK-NEXT: 1 | simple::G::~G() [scalar deleting]
206*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
207*67e74705SXin Li
208*67e74705SXin Li // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::E' in 'simple::F' in 'simple::G' (2 entries).
209*67e74705SXin Li // CHECK-NEXT: 0 | void simple::E::f()
210*67e74705SXin Li // CHECK-NEXT: 1 | simple::G::~G() [scalar deleting]
211*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
212*67e74705SXin Li
213*67e74705SXin Li G();
214*67e74705SXin Li int g;
215*67e74705SXin Li
216*67e74705SXin Li // MANGLING-DAG: @"\01?g@F@simple@@$4PPPPPPPM@3AEXXZ"{{.*}}@"\01??_EG@simple@@$4PPPPPPPM@A@AEPAXI@Z"
217*67e74705SXin Li // MANGLING-DAG: @"\01?f@E@simple@@UAEXXZ"{{.*}}@"\01??_EG@simple@@$4PPPPPPPE@7AEPAXI@Z"
218*67e74705SXin Li };
219*67e74705SXin Li
G()220*67e74705SXin Li G::G() {}
221*67e74705SXin Li }
222*67e74705SXin Li
223*67e74705SXin Li namespace extended {
224*67e74705SXin Li // If a virtual function requires vtordisp adjustment and the final overrider
225*67e74705SXin Li // is defined in another virtual base of the most derived class,
226*67e74705SXin Li // we need to know two vbase offsets.
227*67e74705SXin Li // In this case, we should use the extended form of vtordisp thunks, called
228*67e74705SXin Li // vtordispex thunks.
229*67e74705SXin Li //
230*67e74705SXin Li // vtordispex{x,y,z,w} thunk for Method@Class is something like:
231*67e74705SXin Li // sub ecx, [ecx+z] // apply the vtordisp adjustment
232*67e74705SXin Li // sub ecx, x // jump to the vbptr of the most derived class
233*67e74705SXin Li // mov eax, [ecx] // load the vbtable address
234*67e74705SXin Li // add ecx, [eax+y] // lookup the final overrider's vbase offset
235*67e74705SXin Li // add ecx, w // apphy the subobject offset if needed
236*67e74705SXin Li // jmp Method@Class
237*67e74705SXin Li
238*67e74705SXin Li struct A : virtual simple::A {
239*67e74705SXin Li // CHECK-LABEL: VFTable for 'V1' in 'simple::A' in 'extended::A' (2 entries).
240*67e74705SXin Li // CHECK-NEXT: 0 | void simple::A::f()
241*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left,
242*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
243*67e74705SXin Li // CHECK-NEXT: 1 | extended::A::~A() [scalar deleting]
244*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
245*67e74705SXin Li
246*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::A::f()' (1 entry).
247*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, vbptr at 8 to the left,
248*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
249*67e74705SXin Li
250*67e74705SXin Li // `vtordispex{8,8,4294967292,8}'
251*67e74705SXin Li // MANGLING-DAG: @"\01?f@A@simple@@$R477PPPPPPPM@7AEXXZ"
252*67e74705SXin Li
253*67e74705SXin Li virtual ~A();
254*67e74705SXin Li // vtordisp{4294967292,0}
255*67e74705SXin Li // MANGLING-DAG: @"\01??_EA@extended@@$4PPPPPPPM@A@AEPAXI@Z"
256*67e74705SXin Li };
257*67e74705SXin Li
258*67e74705SXin Li A a;
use(A * obj)259*67e74705SXin Li void use(A *obj) { delete obj; }
260*67e74705SXin Li
261*67e74705SXin Li struct B : virtual simple::A {
262*67e74705SXin Li // This class has an implicit dtor. Vdtors don't require vtordispex thunks
263*67e74705SXin Li // as the most derived class always has an implicit dtor,
264*67e74705SXin Li // which is a final overrider.
265*67e74705SXin Li
266*67e74705SXin Li // CHECK-LABEL: VFTable for 'V1' in 'simple::A' in 'extended::B' (2 entries).
267*67e74705SXin Li // ...
268*67e74705SXin Li // CHECK: 1 | extended::B::~B() [scalar deleting]
269*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
270*67e74705SXin Li
271*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::A::f()' (1 entry).
272*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, vbptr at 8 to the left,
273*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
274*67e74705SXin Li
275*67e74705SXin Li // vtordisp{4294967292,0}
276*67e74705SXin Li // MANGLING-DAG: @"\01??_EB@extended@@$4PPPPPPPM@A@AEPAXI@Z"
277*67e74705SXin Li };
278*67e74705SXin Li
279*67e74705SXin Li B b;
use(B * obj)280*67e74705SXin Li void use(B *obj) { delete obj; }
281*67e74705SXin Li
282*67e74705SXin Li struct C : virtual simple::A {
283*67e74705SXin Li // CHECK-LABEL: VFTable for 'V1' in 'simple::A' in 'extended::C' (2 entries).
284*67e74705SXin Li // CHECK-NEXT: 0 | void simple::A::f()
285*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, vbptr at 12 to the left,
286*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
287*67e74705SXin Li
288*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::A::f()' (1 entry).
289*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, vbptr at 12 to the left,
290*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
291*67e74705SXin Li
292*67e74705SXin Li // `vtordispex{12,8,4294967292,8}'
293*67e74705SXin Li // MANGLING-DAG: @"\01?f@A@simple@@$R4M@7PPPPPPPM@7AEXXZ"
294*67e74705SXin Li int x;
295*67e74705SXin Li virtual ~C();
296*67e74705SXin Li // MANGLING-DAG: @"\01??_EC@extended@@$4PPPPPPPM@A@AEPAXI@Z"
297*67e74705SXin Li };
298*67e74705SXin Li
299*67e74705SXin Li C c;
use(C * obj)300*67e74705SXin Li void use(C *obj) { delete obj; }
301*67e74705SXin Li
302*67e74705SXin Li struct D : virtual V2 {
303*67e74705SXin Li virtual void f();
304*67e74705SXin Li virtual ~D();
305*67e74705SXin Li int x;
306*67e74705SXin Li };
307*67e74705SXin Li
308*67e74705SXin Li struct E : virtual D {
309*67e74705SXin Li // CHECK-LABEL: VFTable for 'V2' in 'extended::D' in 'extended::E' (2 entries).
310*67e74705SXin Li // CHECK-NEXT: 0 | void extended::D::f()
311*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left,
312*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 12 non-virtual]
313*67e74705SXin Li
314*67e74705SXin Li // CHECK-LABEL: Thunks for 'void extended::D::f()' (1 entry).
315*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, vbptr at 8 to the left,
316*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 12 non-virtual]
317*67e74705SXin Li
318*67e74705SXin Li // `vtordispex{8,8,4294967292,12}'
319*67e74705SXin Li // MANGLING-DAG: @"\01?f@D@extended@@$R477PPPPPPPM@M@AEXXZ"
320*67e74705SXin Li
321*67e74705SXin Li virtual ~E();
322*67e74705SXin Li // MANGLING-DAG: @"\01??_EE@extended@@$4PPPPPPPM@A@AEPAXI@Z"
323*67e74705SXin Li };
324*67e74705SXin Li
325*67e74705SXin Li E e;
use(E * obj)326*67e74705SXin Li void use(E *obj) { delete obj; }
327*67e74705SXin Li
328*67e74705SXin Li struct F : virtual Z, virtual D {
329*67e74705SXin Li // CHECK-LABEL: VFTable for 'V2' in 'extended::D' in 'extended::F' (2 entries).
330*67e74705SXin Li // CHECK-NEXT: 0 | void extended::D::f()
331*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, vbptr at 20 to the left,
332*67e74705SXin Li // CHECK-NEXT: vboffset at 12 in the vbtable, 12 non-virtual]
333*67e74705SXin Li
334*67e74705SXin Li // CHECK-LABEL: Thunks for 'void extended::D::f()' (1 entry).
335*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, vbptr at 20 to the left,
336*67e74705SXin Li // CHECK-NEXT: vboffset at 12 in the vbtable, 12 non-virtual]
337*67e74705SXin Li
338*67e74705SXin Li // `vtordispex{20,12,4294967292,12}'
339*67e74705SXin Li // MANGLING-DAG: @"\01?f@D@extended@@$R4BE@M@PPPPPPPM@M@AEXXZ"
340*67e74705SXin Li int x;
341*67e74705SXin Li virtual ~F();
342*67e74705SXin Li // MANGLING-DAG: @"\01??_EF@extended@@$4PPPPPPPM@M@AEPAXI@Z"
343*67e74705SXin Li };
344*67e74705SXin Li
345*67e74705SXin Li F f;
use(F * obj)346*67e74705SXin Li void use(F *obj) { delete obj; }
347*67e74705SXin Li
348*67e74705SXin Li struct G : virtual simple::A {
349*67e74705SXin Li // CHECK-LABEL: VFTable for 'extended::G' (1 entry).
350*67e74705SXin Li // CHECK-NEXT: 0 | void extended::G::g()
351*67e74705SXin Li
352*67e74705SXin Li // CHECK-LABEL: VFTable for 'V1' in 'simple::A' in 'extended::G' (2 entries).
353*67e74705SXin Li // CHECK-NEXT: 0 | void simple::A::f()
354*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left,
355*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
356*67e74705SXin Li // CHECK-NEXT: 1 | extended::G::~G() [scalar deleting]
357*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
358*67e74705SXin Li
359*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::A::f()' (1 entry).
360*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, vbptr at 8 to the left,
361*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
362*67e74705SXin Li
363*67e74705SXin Li // Emits a G's own vfptr, thus moving the vbptr in the layout.
364*67e74705SXin Li virtual void g();
365*67e74705SXin Li
366*67e74705SXin Li virtual ~G();
367*67e74705SXin Li // vtordisp{4294967292,0}
368*67e74705SXin Li // MANGLING-DAG: @"\01??_EG@extended@@$4PPPPPPPM@A@AEPAXI@Z"
369*67e74705SXin Li };
370*67e74705SXin Li
371*67e74705SXin Li G g;
use(G * obj)372*67e74705SXin Li void use(G *obj) { obj->g(); }
373*67e74705SXin Li
374*67e74705SXin Li struct H : Z, A {
375*67e74705SXin Li // CHECK-LABEL: VFTable for 'Z' in 'extended::H' (2 entries).
376*67e74705SXin Li // CHECK-NEXT: 0 | void Z::g()
377*67e74705SXin Li // CHECK-NEXT: 1 | extended::H::~H() [scalar deleting]
378*67e74705SXin Li
379*67e74705SXin Li // CHECK-LABEL: VFTable for 'V1' in 'simple::A' in 'extended::A' in 'extended::H' (2 entries).
380*67e74705SXin Li // CHECK-NEXT: 0 | void simple::A::f()
381*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left,
382*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
383*67e74705SXin Li
384*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::A::f()' (1 entry).
385*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -4, vbptr at 8 to the left,
386*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
387*67e74705SXin Li
388*67e74705SXin Li // MANGLING-DAG: @"\01?f@A@simple@@$R477PPPPPPPM@7AEXXZ"
389*67e74705SXin Li // MANGLING-DAG: @"\01??_EH@extended@@$4PPPPPPPM@BA@AEPAXI@Z"
390*67e74705SXin Li };
391*67e74705SXin Li
392*67e74705SXin Li H h;
use(H * obj)393*67e74705SXin Li void use(H *obj) { delete obj; }
394*67e74705SXin Li }
395*67e74705SXin Li
396*67e74705SXin Li namespace pr17738 {
397*67e74705SXin Li // These classes should have vtordispex thunks but MSVS CL miscompiles them.
398*67e74705SXin Li // Just do the right thing.
399*67e74705SXin Li
400*67e74705SXin Li struct A : virtual simple::B {
401*67e74705SXin Li // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::B' in 'pr17738::A' (2 entries).
402*67e74705SXin Li // CHECK-NEXT: 0 | void simple::B::f()
403*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -12, vbptr at 20 to the left,
404*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 16 non-virtual]
405*67e74705SXin Li
406*67e74705SXin Li // CHECK-LABEL: Thunks for 'void simple::B::f()' (1 entry).
407*67e74705SXin Li // CHECK-NEXT: 0 | [this adjustment: vtordisp at -12, vbptr at 20 to the left,
408*67e74705SXin Li // CHECK-NEXT: vboffset at 8 in the vbtable, 16 non-virtual]
409*67e74705SXin Li
410*67e74705SXin Li // MANGLING-DAG: @"\01?f@B@simple@@$R4BE@7PPPPPPPE@BA@AEXXZ"
411*67e74705SXin Li int a;
412*67e74705SXin Li virtual ~A();
413*67e74705SXin Li };
414*67e74705SXin Li
415*67e74705SXin Li A a;
use(A * obj)416*67e74705SXin Li void use(A *obj) { delete obj; }
417*67e74705SXin Li }
418*67e74705SXin Li
419*67e74705SXin Li namespace pr19408 {
420*67e74705SXin Li // In this test, the vptr used to vcall D::f() is located in the A vbase.
421*67e74705SXin Li // The offset of A in different in C and D, so the D vtordisp thunk should
422*67e74705SXin Li // adjust "this" so C::f gets the right value.
423*67e74705SXin Li struct A {
424*67e74705SXin Li A();
425*67e74705SXin Li virtual void f();
426*67e74705SXin Li int a;
427*67e74705SXin Li };
428*67e74705SXin Li
429*67e74705SXin Li struct B : virtual A {
430*67e74705SXin Li B();
431*67e74705SXin Li int b;
432*67e74705SXin Li };
433*67e74705SXin Li
434*67e74705SXin Li struct C : B {
435*67e74705SXin Li C();
436*67e74705SXin Li virtual void f();
437*67e74705SXin Li int c;
438*67e74705SXin Li };
439*67e74705SXin Li
440*67e74705SXin Li struct D : C {
441*67e74705SXin Li // CHECK-LABEL: VFTable for 'pr19408::A' in 'pr19408::B' in 'pr19408::C' in 'pr19408::D' (1 entry).
442*67e74705SXin Li // CHECK-NEXT: 0 | void pr19408::C::f()
443*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual]
444*67e74705SXin Li
445*67e74705SXin Li // MANGLING-DAG: @"\01?f@C@pr19408@@$4PPPPPPPM@3AEXXZ"
446*67e74705SXin Li D();
447*67e74705SXin Li int d;
448*67e74705SXin Li };
449*67e74705SXin Li
D()450*67e74705SXin Li D::D() {}
451*67e74705SXin Li }
452*67e74705SXin Li
453*67e74705SXin Li namespace access {
454*67e74705SXin Li struct A {
455*67e74705SXin Li virtual ~A();
456*67e74705SXin Li protected:
457*67e74705SXin Li virtual void prot();
458*67e74705SXin Li private:
459*67e74705SXin Li virtual void priv();
460*67e74705SXin Li };
461*67e74705SXin Li
462*67e74705SXin Li struct B : virtual A {
463*67e74705SXin Li virtual ~B();
464*67e74705SXin Li protected:
465*67e74705SXin Li virtual void prot();
466*67e74705SXin Li // MANGLING-DAG: @"\01?prot@B@access@@$2PPPPPPPM@A@AEXXZ"
467*67e74705SXin Li private:
468*67e74705SXin Li virtual void priv();
469*67e74705SXin Li // MANGLING-DAG: @"\01?priv@B@access@@$0PPPPPPPM@A@AEXXZ"
470*67e74705SXin Li };
471*67e74705SXin Li
472*67e74705SXin Li B b;
473*67e74705SXin Li
474*67e74705SXin Li struct C : virtual B {
475*67e74705SXin Li virtual ~C();
476*67e74705SXin Li
477*67e74705SXin Li // MANGLING-DAG: @"\01?prot@B@access@@$R277PPPPPPPM@7AEXXZ"
478*67e74705SXin Li // MANGLING-DAG: @"\01?priv@B@access@@$R077PPPPPPPM@7AEXXZ"
479*67e74705SXin Li };
480*67e74705SXin Li
481*67e74705SXin Li C c;
482*67e74705SXin Li }
483*67e74705SXin Li
484*67e74705SXin Li namespace pr19505 {
485*67e74705SXin Li struct A {
486*67e74705SXin Li virtual void f();
487*67e74705SXin Li virtual void z();
488*67e74705SXin Li };
489*67e74705SXin Li
490*67e74705SXin Li struct B : A {
491*67e74705SXin Li virtual void f();
492*67e74705SXin Li };
493*67e74705SXin Li
494*67e74705SXin Li struct C : A, B {
495*67e74705SXin Li virtual void g();
496*67e74705SXin Li };
497*67e74705SXin Li
498*67e74705SXin Li struct X : B, virtual C {
Xpr19505::X499*67e74705SXin Li X() {}
500*67e74705SXin Li virtual void g();
501*67e74705SXin Li
502*67e74705SXin Li // CHECK-LABEL: VFTable for 'pr19505::A' in 'pr19505::B' in 'pr19505::C' in 'pr19505::X' (2 entries).
503*67e74705SXin Li // CHECK-NEXT: 0 | void pr19505::B::f()
504*67e74705SXin Li // CHECK-NEXT: 1 | void pr19505::A::z()
505*67e74705SXin Li
506*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@pr19505@@6BB@1@@" = {{.*}}@"\01?f@B@pr19505@@UAEXXZ"
507*67e74705SXin Li } x;
508*67e74705SXin Li
build_vftable(X * obj)509*67e74705SXin Li void build_vftable(X *obj) { obj->g(); }
510*67e74705SXin Li }
511*67e74705SXin Li
512*67e74705SXin Li namespace pr19506 {
513*67e74705SXin Li struct A {
514*67e74705SXin Li virtual void f();
515*67e74705SXin Li virtual void g();
516*67e74705SXin Li };
517*67e74705SXin Li
518*67e74705SXin Li struct B : A {
519*67e74705SXin Li virtual void f();
520*67e74705SXin Li };
521*67e74705SXin Li
522*67e74705SXin Li struct C : B {};
523*67e74705SXin Li
524*67e74705SXin Li struct X : C, virtual B {
525*67e74705SXin Li virtual void g();
Xpr19506::X526*67e74705SXin Li X() {}
527*67e74705SXin Li
528*67e74705SXin Li // CHECK-LABEL: VFTable for 'pr19506::A' in 'pr19506::B' in 'pr19506::X' (2 entries).
529*67e74705SXin Li // CHECK-NEXT: 0 | void pr19506::B::f()
530*67e74705SXin Li // CHECK-NEXT: 1 | void pr19506::X::g()
531*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, -12 non-virtual]
532*67e74705SXin Li
533*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@pr19506@@6BB@1@@" = {{.*}}@"\01?f@B@pr19506@@UAEXXZ"
534*67e74705SXin Li } x;
535*67e74705SXin Li
build_vftable(X * obj)536*67e74705SXin Li void build_vftable(X *obj) { obj->g(); }
537*67e74705SXin Li }
538*67e74705SXin Li
539*67e74705SXin Li namespace pr19519 {
540*67e74705SXin Li // VS2013 CL miscompiles this, just make sure we don't regress.
541*67e74705SXin Li
542*67e74705SXin Li struct A {
543*67e74705SXin Li virtual void f();
544*67e74705SXin Li virtual void g();
545*67e74705SXin Li };
546*67e74705SXin Li
547*67e74705SXin Li struct B : virtual A {
548*67e74705SXin Li virtual void f();
549*67e74705SXin Li B();
550*67e74705SXin Li };
551*67e74705SXin Li
552*67e74705SXin Li struct C : virtual A {
553*67e74705SXin Li virtual void g();
554*67e74705SXin Li };
555*67e74705SXin Li
556*67e74705SXin Li struct X : B, C {
557*67e74705SXin Li X();
558*67e74705SXin Li
559*67e74705SXin Li // CHECK-LABEL: VFTable for 'pr19519::A' in 'pr19519::B' in 'pr19519::X' (2 entries).
560*67e74705SXin Li // CHECK-NEXT: 0 | void pr19519::B::f()
561*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual]
562*67e74705SXin Li // CHECK-NEXT: 1 | void pr19519::C::g()
563*67e74705SXin Li // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual]
564*67e74705SXin Li
565*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@pr19519@@6B@" = {{.*}}@"\01?g@C@pr19519@@$4PPPPPPPM@3AEXXZ"
566*67e74705SXin Li };
567*67e74705SXin Li
X()568*67e74705SXin Li X::X() {}
569*67e74705SXin Li }
570