1*67e74705SXin Li // RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%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 namespace test1 {
6*67e74705SXin Li struct A {
7*67e74705SXin Li virtual void f();
8*67e74705SXin Li };
9*67e74705SXin Li
10*67e74705SXin Li struct B {
11*67e74705SXin Li virtual void g();
12*67e74705SXin Li // Add an extra virtual method so it's easier to check for the absence of thunks.
13*67e74705SXin Li virtual void h();
14*67e74705SXin Li };
15*67e74705SXin Li
16*67e74705SXin Li struct X : A, B {
17*67e74705SXin Li // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (1 entry)
18*67e74705SXin Li // CHECK-NEXT: 0 | void test1::X::f()
19*67e74705SXin Li
20*67e74705SXin Li // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (2 entries)
21*67e74705SXin Li // CHECK-NEXT: 0 | void test1::B::g()
22*67e74705SXin Li // CHECK-NEXT: 1 | void test1::B::h()
23*67e74705SXin Li
24*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry)
25*67e74705SXin Li // CHECK-NEXT: 0 | void test1::X::f()
26*67e74705SXin Li
27*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test1@@6BA@1@@"
28*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test1@@6BB@1@@"
29*67e74705SXin Li
30*67e74705SXin Li // Overrides only the left child's method (A::f), needs no thunks.
31*67e74705SXin Li virtual void f();
32*67e74705SXin Li } x;
33*67e74705SXin Li
build_vftable(X * obj)34*67e74705SXin Li void build_vftable(X *obj) { obj->f(); }
35*67e74705SXin Li }
36*67e74705SXin Li
37*67e74705SXin Li namespace test2 {
38*67e74705SXin Li struct A {
39*67e74705SXin Li virtual void f();
40*67e74705SXin Li };
41*67e74705SXin Li
42*67e74705SXin Li struct B {
43*67e74705SXin Li virtual void g();
44*67e74705SXin Li virtual void h();
45*67e74705SXin Li };
46*67e74705SXin Li
47*67e74705SXin Li struct X : A, B {
48*67e74705SXin Li // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry)
49*67e74705SXin Li // CHECK-NEXT: 0 | void test2::A::f()
50*67e74705SXin Li
51*67e74705SXin Li // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries)
52*67e74705SXin Li // CHECK-NEXT: 0 | void test2::X::g()
53*67e74705SXin Li // CHECK-NEXT: 1 | void test2::B::h()
54*67e74705SXin Li
55*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
56*67e74705SXin Li // CHECK-NEXT: via vfptr at offset 4
57*67e74705SXin Li // CHECK-NEXT: 0 | void test2::X::g()
58*67e74705SXin Li
59*67e74705SXin Li // Overrides only the right child's method (B::g), needs this adjustment but
60*67e74705SXin Li // not thunks.
61*67e74705SXin Li virtual void g();
62*67e74705SXin Li };
63*67e74705SXin Li
build_vftable(X * obj)64*67e74705SXin Li void build_vftable(X *obj) { obj->g(); }
65*67e74705SXin Li }
66*67e74705SXin Li
67*67e74705SXin Li namespace test3 {
68*67e74705SXin Li struct A {
69*67e74705SXin Li virtual void f();
70*67e74705SXin Li };
71*67e74705SXin Li
72*67e74705SXin Li struct B {
73*67e74705SXin Li virtual void g();
74*67e74705SXin Li virtual void h();
75*67e74705SXin Li };
76*67e74705SXin Li
77*67e74705SXin Li struct X : A, B {
78*67e74705SXin Li // CHECK-LABEL: VFTable for 'test3::A' in 'test3::X' (2 entries)
79*67e74705SXin Li // CHECK-NEXT: 0 | void test3::A::f()
80*67e74705SXin Li // CHECK-NEXT: 1 | void test3::X::i()
81*67e74705SXin Li
82*67e74705SXin Li // CHECK-LABEL: VFTable for 'test3::B' in 'test3::X' (2 entries)
83*67e74705SXin Li // CHECK-NEXT: 0 | void test3::B::g()
84*67e74705SXin Li // CHECK-NEXT: 1 | void test3::B::h()
85*67e74705SXin Li
86*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry).
87*67e74705SXin Li // CHECK-NEXT: 1 | void test3::X::i()
88*67e74705SXin Li
89*67e74705SXin Li // Only adds a new method.
90*67e74705SXin Li virtual void i();
91*67e74705SXin Li };
92*67e74705SXin Li
build_vftable(X * obj)93*67e74705SXin Li void build_vftable(X *obj) { obj->i(); }
94*67e74705SXin Li }
95*67e74705SXin Li
96*67e74705SXin Li namespace test4 {
97*67e74705SXin Li struct A {
98*67e74705SXin Li virtual void f();
99*67e74705SXin Li };
100*67e74705SXin Li
101*67e74705SXin Li struct Empty { }; // Doesn't have a vftable!
102*67e74705SXin Li
103*67e74705SXin Li // Only the right base has a vftable, so it's laid out before the left one!
104*67e74705SXin Li struct X : Empty, A {
105*67e74705SXin Li // CHECK-LABEL: VFTable for 'test4::A' in 'test4::X' (1 entry)
106*67e74705SXin Li // CHECK-NEXT: 0 | void test4::X::f()
107*67e74705SXin Li
108*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry).
109*67e74705SXin Li // CHECK-NEXT: 0 | void test4::X::f()
110*67e74705SXin Li
111*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test4@@6B@"
112*67e74705SXin Li
113*67e74705SXin Li virtual void f();
114*67e74705SXin Li } x;
115*67e74705SXin Li
build_vftable(X * obj)116*67e74705SXin Li void build_vftable(X *obj) { obj->f(); }
117*67e74705SXin Li }
118*67e74705SXin Li
119*67e74705SXin Li namespace test5 {
120*67e74705SXin Li struct A {
121*67e74705SXin Li virtual void f();
122*67e74705SXin Li };
123*67e74705SXin Li
124*67e74705SXin Li struct B {
125*67e74705SXin Li virtual void g();
126*67e74705SXin Li virtual void h();
127*67e74705SXin Li };
128*67e74705SXin Li
129*67e74705SXin Li struct C : A, B {
130*67e74705SXin Li virtual void f();
131*67e74705SXin Li };
132*67e74705SXin Li
133*67e74705SXin Li struct X : C {
134*67e74705SXin Li // CHECK-LABEL: VFTable for 'test5::A' in 'test5::C' in 'test5::X' (1 entry).
135*67e74705SXin Li // CHECK-NEXT: 0 | void test5::X::f()
136*67e74705SXin Li
137*67e74705SXin Li // CHECK-LABEL: VFTable for 'test5::B' in 'test5::C' in 'test5::X' (2 entries).
138*67e74705SXin Li // CHECK-NEXT: 0 | void test5::B::g()
139*67e74705SXin Li // CHECK-NEXT: 1 | void test5::B::h()
140*67e74705SXin Li
141*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry).
142*67e74705SXin Li // CHECK-NEXT: 0 | void test5::X::f()
143*67e74705SXin Li
144*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test5@@6BA@1@@"
145*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test5@@6BB@1@@"
146*67e74705SXin Li
147*67e74705SXin Li // Overrides both C::f and A::f.
148*67e74705SXin Li virtual void f();
149*67e74705SXin Li } x;
150*67e74705SXin Li
build_vftable(X * obj)151*67e74705SXin Li void build_vftable(X *obj) { obj->f(); }
152*67e74705SXin Li }
153*67e74705SXin Li
154*67e74705SXin Li namespace test6 {
155*67e74705SXin Li struct A {
156*67e74705SXin Li virtual void f();
157*67e74705SXin Li };
158*67e74705SXin Li
159*67e74705SXin Li struct B {
160*67e74705SXin Li virtual void g();
161*67e74705SXin Li virtual void h();
162*67e74705SXin Li };
163*67e74705SXin Li
164*67e74705SXin Li struct C : A, B {
165*67e74705SXin Li virtual void g();
166*67e74705SXin Li };
167*67e74705SXin Li
168*67e74705SXin Li struct X : C {
169*67e74705SXin Li // CHECK-LABEL: VFTable for 'test6::A' in 'test6::C' in 'test6::X' (1 entry).
170*67e74705SXin Li // CHECK-NEXT: 0 | void test6::A::f()
171*67e74705SXin Li
172*67e74705SXin Li // CHECK-LABEL: VFTable for 'test6::B' in 'test6::C' in 'test6::X' (2 entries).
173*67e74705SXin Li // CHECK-NEXT: 0 | void test6::X::g()
174*67e74705SXin Li // CHECK-NEXT: 1 | void test6::B::h()
175*67e74705SXin Li
176*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry).
177*67e74705SXin Li // CHECK-NEXT: via vfptr at offset 4
178*67e74705SXin Li // CHECK-NEXT: 0 | void test6::X::g()
179*67e74705SXin Li
180*67e74705SXin Li // Overrides both C::g and B::g.
181*67e74705SXin Li virtual void g();
182*67e74705SXin Li };
183*67e74705SXin Li
build_vftable(X * obj)184*67e74705SXin Li void build_vftable(X *obj) { obj->g(); }
185*67e74705SXin Li }
186*67e74705SXin Li
187*67e74705SXin Li namespace test7 {
188*67e74705SXin Li struct A {
189*67e74705SXin Li virtual void f();
190*67e74705SXin Li };
191*67e74705SXin Li
192*67e74705SXin Li struct B {
193*67e74705SXin Li virtual void g();
194*67e74705SXin Li virtual void h();
195*67e74705SXin Li };
196*67e74705SXin Li
197*67e74705SXin Li struct C : A, B {
198*67e74705SXin Li // Only adds a new method.
199*67e74705SXin Li virtual void i();
200*67e74705SXin Li };
201*67e74705SXin Li
202*67e74705SXin Li struct X : C {
203*67e74705SXin Li // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' in 'test7::X' (2 entries).
204*67e74705SXin Li // CHECK-NEXT: 0 | void test7::A::f()
205*67e74705SXin Li // CHECK-NEXT: 1 | void test7::C::i()
206*67e74705SXin Li
207*67e74705SXin Li // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' in 'test7::X' (2 entries).
208*67e74705SXin Li // CHECK-NEXT: 0 | void test7::X::g()
209*67e74705SXin Li // CHECK-NEXT: 1 | void test7::B::h()
210*67e74705SXin Li
211*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test7::X' (1 entry).
212*67e74705SXin Li // CHECK-NEXT: via vfptr at offset 4
213*67e74705SXin Li // CHECK-NEXT: 0 | void test7::X::g()
214*67e74705SXin Li
215*67e74705SXin Li // Overrides grandparent's B::g.
216*67e74705SXin Li virtual void g();
217*67e74705SXin Li };
218*67e74705SXin Li
build_vftable(X * obj)219*67e74705SXin Li void build_vftable(X *obj) { obj->g(); }
220*67e74705SXin Li }
221*67e74705SXin Li
222*67e74705SXin Li namespace test8 {
223*67e74705SXin Li struct A {
224*67e74705SXin Li virtual void f();
225*67e74705SXin Li };
226*67e74705SXin Li
227*67e74705SXin Li struct B : A {
228*67e74705SXin Li virtual void g();
229*67e74705SXin Li };
230*67e74705SXin Li
231*67e74705SXin Li // There are two 'A' subobjects in this class.
232*67e74705SXin Li struct X : A, B {
233*67e74705SXin Li // CHECK-LABEL: VFTable for 'test8::A' in 'test8::X' (2 entries).
234*67e74705SXin Li // CHECK-NEXT: 0 | void test8::A::f()
235*67e74705SXin Li // CHECK-NEXT: 1 | void test8::X::h()
236*67e74705SXin Li
237*67e74705SXin Li // CHECK-LABEL: VFTable for 'test8::A' in 'test8::B' in 'test8::X' (2 entries).
238*67e74705SXin Li // CHECK-NEXT: 0 | void test8::A::f()
239*67e74705SXin Li // CHECK-NEXT: 1 | void test8::B::g()
240*67e74705SXin Li
241*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test8::X' (1 entry).
242*67e74705SXin Li // CHECK-NEXT: 1 | void test8::X::h()
243*67e74705SXin Li
244*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test8@@6BA@1@@"
245*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test8@@6BB@1@@"
246*67e74705SXin Li
247*67e74705SXin Li virtual void h();
248*67e74705SXin Li } x;
249*67e74705SXin Li
build_vftable(X * obj)250*67e74705SXin Li void build_vftable(X *obj) { obj->h(); }
251*67e74705SXin Li }
252*67e74705SXin Li
253*67e74705SXin Li namespace test9 {
254*67e74705SXin Li struct A {
255*67e74705SXin Li virtual void f();
256*67e74705SXin Li };
257*67e74705SXin Li
258*67e74705SXin Li struct B {
259*67e74705SXin Li virtual void g();
260*67e74705SXin Li virtual void h();
261*67e74705SXin Li };
262*67e74705SXin Li
263*67e74705SXin Li struct C : A, B {
264*67e74705SXin Li // Overrides only the left child's method (A::f).
265*67e74705SXin Li virtual void f();
266*67e74705SXin Li };
267*67e74705SXin Li
268*67e74705SXin Li struct D : A, B {
269*67e74705SXin Li // Overrides only the right child's method (B::g).
270*67e74705SXin Li virtual void g();
271*67e74705SXin Li };
272*67e74705SXin Li
273*67e74705SXin Li // 2-level structure with repeating subobject types, but no thunks needed.
274*67e74705SXin Li struct X : C, D {
275*67e74705SXin Li // CHECK-LABEL: VFTable for 'test9::A' in 'test9::C' in 'test9::X' (2 entries)
276*67e74705SXin Li // CHECK-NEXT: 0 | void test9::C::f()
277*67e74705SXin Li // CHECK-NEXT: 1 | void test9::X::z()
278*67e74705SXin Li
279*67e74705SXin Li // CHECK-LABEL: VFTable for 'test9::B' in 'test9::C' in 'test9::X' (2 entries)
280*67e74705SXin Li // CHECK-NEXT: 0 | void test9::B::g()
281*67e74705SXin Li // CHECK-NEXT: 1 | void test9::B::h()
282*67e74705SXin Li
283*67e74705SXin Li // CHECK-LABEL: VFTable for 'test9::A' in 'test9::D' in 'test9::X' (1 entry)
284*67e74705SXin Li // CHECK-NEXT: 0 | void test9::A::f()
285*67e74705SXin Li
286*67e74705SXin Li // CHECK-LABEL: VFTable for 'test9::B' in 'test9::D' in 'test9::X' (2 entries)
287*67e74705SXin Li // CHECK-NEXT: 0 | void test9::D::g()
288*67e74705SXin Li // CHECK-NEXT: 1 | void test9::B::h()
289*67e74705SXin Li
290*67e74705SXin Li // CHECK-LABEL: VFTable indices for 'test9::X' (1 entry).
291*67e74705SXin Li // CHECK-NEXT: 1 | void test9::X::z()
292*67e74705SXin Li
293*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@C@1@@"
294*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@D@1@@"
295*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@C@1@@"
296*67e74705SXin Li // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@D@1@@"
297*67e74705SXin Li
298*67e74705SXin Li virtual void z();
299*67e74705SXin Li } x;
300*67e74705SXin Li
build_vftable(test9::X * obj)301*67e74705SXin Li void build_vftable(test9::X *obj) { obj->z(); }
302*67e74705SXin Li }
303