xref: /aosp_15_r20/external/clang/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li // RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o %t.ll > %t
2*67e74705SXin Li // RUN: FileCheck --check-prefix=EMITS-VFTABLE %s < %t.ll
3*67e74705SXin Li // RUN: FileCheck --check-prefix=NO-VFTABLE %s < %t.ll
4*67e74705SXin Li // RUN: FileCheck %s < %t
5*67e74705SXin Li 
6*67e74705SXin Li struct A {
7*67e74705SXin Li   // CHECK-LABEL: VFTable for 'A' (3 entries)
8*67e74705SXin Li   // CHECK-NEXT: 0 | void A::f()
9*67e74705SXin Li   // CHECK-NEXT: 1 | void A::g()
10*67e74705SXin Li   // CHECK-NEXT: 2 | void A::h()
11*67e74705SXin Li   // CHECK-LABEL: VFTable indices for 'A' (3 entries)
12*67e74705SXin Li   // CHECK-NEXT: 0 | void A::f()
13*67e74705SXin Li   // CHECK-NEXT: 1 | void A::g()
14*67e74705SXin Li   // CHECK-NEXT: 2 | void A::h()
15*67e74705SXin Li 
16*67e74705SXin Li   virtual void f();
17*67e74705SXin Li   virtual void g();
18*67e74705SXin Li   virtual void h();
19*67e74705SXin Li   int ia;
20*67e74705SXin Li };
21*67e74705SXin Li A a;
22*67e74705SXin Li // EMITS-VFTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*]
use(A * obj)23*67e74705SXin Li void use(A *obj) { obj->f(); }
24*67e74705SXin Li 
25*67e74705SXin Li struct B : A {
26*67e74705SXin Li   // CHECK-LABEL: VFTable for 'A' in 'B' (5 entries)
27*67e74705SXin Li   // CHECK-NEXT: 0 | void B::f()
28*67e74705SXin Li   // CHECK-NEXT: 1 | void A::g()
29*67e74705SXin Li   // CHECK-NEXT: 2 | void A::h()
30*67e74705SXin Li   // CHECK-NEXT: 3 | void B::i()
31*67e74705SXin Li   // CHECK-NEXT: 4 | void B::j()
32*67e74705SXin Li   // CHECK-LABEL: VFTable indices for 'B' (3 entries)
33*67e74705SXin Li   // CHECK-NEXT: 0 | void B::f()
34*67e74705SXin Li   // CHECK-NEXT: 3 | void B::i()
35*67e74705SXin Li   // CHECK-NEXT: 4 | void B::j()
36*67e74705SXin Li 
37*67e74705SXin Li   virtual void f();  // overrides A::f()
38*67e74705SXin Li   virtual void i();
39*67e74705SXin Li   virtual void j();
40*67e74705SXin Li };
41*67e74705SXin Li B b;
42*67e74705SXin Li // EMITS-VFTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*]
use(B * obj)43*67e74705SXin Li void use(B *obj) { obj->f(); }
44*67e74705SXin Li 
45*67e74705SXin Li struct C {
46*67e74705SXin Li   // CHECK-LABEL: VFTable for 'C' (2 entries)
47*67e74705SXin Li   // CHECK-NEXT: 0 | C::~C() [scalar deleting]
48*67e74705SXin Li   // CHECK-NEXT: 1 | void C::f()
49*67e74705SXin Li   // CHECK-LABEL: VFTable indices for 'C' (2 entries).
50*67e74705SXin Li   // CHECK-NEXT: 0 | C::~C() [scalar deleting]
51*67e74705SXin Li   // CHECK-NEXT: 1 | void C::f()
52*67e74705SXin Li 
53*67e74705SXin Li   virtual ~C();
54*67e74705SXin Li   virtual void f();
55*67e74705SXin Li };
f()56*67e74705SXin Li void C::f() {}
57*67e74705SXin Li // NO-VFTABLE-NOT: @"\01??_7C@@6B@"
use(C * obj)58*67e74705SXin Li void use(C *obj) { obj->f(); }
59*67e74705SXin Li 
60*67e74705SXin Li struct D {
61*67e74705SXin Li   // CHECK-LABEL: VFTable for 'D' (2 entries)
62*67e74705SXin Li   // CHECK-NEXT: 0 | void D::f()
63*67e74705SXin Li   // CHECK-NEXT: 1 | D::~D() [scalar deleting]
64*67e74705SXin Li   // CHECK-LABEL: VFTable indices for 'D' (2 entries)
65*67e74705SXin Li   // CHECK-NEXT: 0 | void D::f()
66*67e74705SXin Li   // CHECK-NEXT: 1 | D::~D() [scalar deleting]
67*67e74705SXin Li 
68*67e74705SXin Li   virtual void f();
69*67e74705SXin Li   virtual ~D();
70*67e74705SXin Li };
71*67e74705SXin Li D d;
72*67e74705SXin Li // EMITS-VFTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*]
use(D * obj)73*67e74705SXin Li void use(D *obj) { obj->f(); }
74*67e74705SXin Li 
75*67e74705SXin Li struct E : A {
76*67e74705SXin Li   // CHECK-LABEL: VFTable for 'A' in 'E' (5 entries)
77*67e74705SXin Li   // CHECK-NEXT: 0 | void A::f()
78*67e74705SXin Li   // CHECK-NEXT: 1 | void A::g()
79*67e74705SXin Li   // CHECK-NEXT: 2 | void A::h()
80*67e74705SXin Li   // CHECK-NEXT: 3 | E::~E() [scalar deleting]
81*67e74705SXin Li   // CHECK-NEXT: 4 | void E::i()
82*67e74705SXin Li   // CHECK-LABEL: VFTable indices for 'E' (2 entries).
83*67e74705SXin Li   // CHECK-NEXT: 3 | E::~E() [scalar deleting]
84*67e74705SXin Li   // CHECK-NEXT: 4 | void E::i()
85*67e74705SXin Li 
86*67e74705SXin Li   // ~E would be the key method, but it isn't used, and MS ABI has no key
87*67e74705SXin Li   // methods.
88*67e74705SXin Li   virtual ~E();
89*67e74705SXin Li   virtual void i();
90*67e74705SXin Li };
i()91*67e74705SXin Li void E::i() {}
92*67e74705SXin Li // NO-VFTABLE-NOT: @"\01??_7E@@6B@"
use(E * obj)93*67e74705SXin Li void use(E *obj) { obj->i(); }
94*67e74705SXin Li 
95*67e74705SXin Li struct F : A {
96*67e74705SXin Li   // CHECK-LABEL: VFTable for 'A' in 'F' (5 entries)
97*67e74705SXin Li   // CHECK-NEXT: 0 | void A::f()
98*67e74705SXin Li   // CHECK-NEXT: 1 | void A::g()
99*67e74705SXin Li   // CHECK-NEXT: 2 | void A::h()
100*67e74705SXin Li   // CHECK-NEXT: 3 | void F::i()
101*67e74705SXin Li   // CHECK-NEXT: 4 | F::~F() [scalar deleting]
102*67e74705SXin Li   // CHECK-LABEL: VFTable indices for 'F' (2 entries).
103*67e74705SXin Li   // CHECK-NEXT: 3 | void F::i()
104*67e74705SXin Li   // CHECK-NEXT: 4 | F::~F() [scalar deleting]
105*67e74705SXin Li 
106*67e74705SXin Li   virtual void i();
107*67e74705SXin Li   virtual ~F();
108*67e74705SXin Li };
109*67e74705SXin Li F f;
110*67e74705SXin Li // EMITS-VFTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*]
use(F * obj)111*67e74705SXin Li void use(F *obj) { obj->i(); }
112*67e74705SXin Li 
113*67e74705SXin Li struct G : E {
114*67e74705SXin Li   // CHECK-LABEL: VFTable for 'A' in 'E' in 'G' (6 entries)
115*67e74705SXin Li   // CHECK-NEXT: 0 | void G::f()
116*67e74705SXin Li   // CHECK-NEXT: 1 | void A::g()
117*67e74705SXin Li   // CHECK-NEXT: 2 | void A::h()
118*67e74705SXin Li   // CHECK-NEXT: 3 | G::~G() [scalar deleting]
119*67e74705SXin Li   // CHECK-NEXT: 4 | void E::i()
120*67e74705SXin Li   // CHECK-NEXT: 5 | void G::j()
121*67e74705SXin Li   // CHECK-LABEL: VFTable indices for 'G' (3 entries).
122*67e74705SXin Li   // CHECK-NEXT: 0 | void G::f()
123*67e74705SXin Li   // CHECK-NEXT: 3 | G::~G() [scalar deleting]
124*67e74705SXin Li   // CHECK-NEXT: 5 | void G::j()
125*67e74705SXin Li 
126*67e74705SXin Li   virtual void f();  // overrides A::f()
127*67e74705SXin Li   virtual ~G();
128*67e74705SXin Li   virtual void j();
129*67e74705SXin Li };
j()130*67e74705SXin Li void G::j() {}
131*67e74705SXin Li // NO-VFTABLE-NOT: @"\01??_7G@@6B@"
use(G * obj)132*67e74705SXin Li void use(G *obj) { obj->j(); }
133*67e74705SXin Li 
134*67e74705SXin Li // Test that the usual Itanium-style key method does not emit a vtable.
135*67e74705SXin Li struct H {
136*67e74705SXin Li   virtual void f();
137*67e74705SXin Li };
f()138*67e74705SXin Li void H::f() {}
139*67e74705SXin Li // NO-VFTABLE-NOT: @"\01??_7H@@6B@"
140*67e74705SXin Li 
141*67e74705SXin Li struct Empty { };
142*67e74705SXin Li 
143*67e74705SXin Li struct I : Empty {
144*67e74705SXin Li   // CHECK-LABEL: VFTable for 'I' (2 entries)
145*67e74705SXin Li   // CHECK-NEXT: 0 | void I::f()
146*67e74705SXin Li   // CHECK-NEXT: 1 | void I::g()
147*67e74705SXin Li   virtual void f();
148*67e74705SXin Li   virtual void g();
149*67e74705SXin Li };
150*67e74705SXin Li 
151*67e74705SXin Li I i;
use(I * obj)152*67e74705SXin Li void use(I *obj) { obj->f(); }
153*67e74705SXin Li 
154*67e74705SXin Li struct J {
155*67e74705SXin Li   // CHECK-LABEL: VFTable for 'J' (6 entries)
156*67e74705SXin Li   // CHECK-NEXT: 0 | void J::foo(long)
157*67e74705SXin Li   // CHECK-NEXT: 1 | void J::foo(int)
158*67e74705SXin Li   // CHECK-NEXT: 2 | void J::foo(short)
159*67e74705SXin Li   // CHECK-NEXT: 3 | void J::bar(long)
160*67e74705SXin Li   // CHECK-NEXT: 4 | void J::bar(int)
161*67e74705SXin Li   // CHECK-NEXT: 5 | void J::bar(short)
162*67e74705SXin Li   virtual void foo(short);
163*67e74705SXin Li   virtual void bar(short);
164*67e74705SXin Li   virtual void foo(int);
165*67e74705SXin Li   virtual void bar(int);
166*67e74705SXin Li   virtual void foo(long);
167*67e74705SXin Li   virtual void bar(long);
168*67e74705SXin Li };
169*67e74705SXin Li 
170*67e74705SXin Li J j;
use(J * obj)171*67e74705SXin Li void use(J *obj) { obj->foo(42); }
172*67e74705SXin Li 
173*67e74705SXin Li struct K : J {
174*67e74705SXin Li   // CHECK-LABEL: VFTable for 'J' in 'K' (9 entries)
175*67e74705SXin Li   // CHECK-NEXT: 0 | void J::foo(long)
176*67e74705SXin Li   // CHECK-NEXT: 1 | void J::foo(int)
177*67e74705SXin Li   // CHECK-NEXT: 2 | void J::foo(short)
178*67e74705SXin Li   // CHECK-NEXT: 3 | void J::bar(long)
179*67e74705SXin Li   // CHECK-NEXT: 4 | void J::bar(int)
180*67e74705SXin Li   // CHECK-NEXT: 5 | void J::bar(short)
181*67e74705SXin Li   // CHECK-NEXT: 6 | void K::bar(double)
182*67e74705SXin Li   // CHECK-NEXT: 7 | void K::bar(float)
183*67e74705SXin Li   // CHECK-NEXT: 8 | void K::foo(float)
184*67e74705SXin Li   virtual void bar(float);
185*67e74705SXin Li   virtual void foo(float);
186*67e74705SXin Li   virtual void bar(double);
187*67e74705SXin Li };
188*67e74705SXin Li 
189*67e74705SXin Li K k;
use(K * obj)190*67e74705SXin Li void use(K *obj) { obj->foo(42.0f); }
191*67e74705SXin Li 
192*67e74705SXin Li struct L : J {
193*67e74705SXin Li   // CHECK-LABEL: VFTable for 'J' in 'L' (9 entries)
194*67e74705SXin Li   // CHECK-NEXT: 0 | void J::foo(long)
195*67e74705SXin Li   // CHECK-NEXT: 1 | void L::foo(int)
196*67e74705SXin Li   // CHECK-NEXT: 2 | void J::foo(short)
197*67e74705SXin Li   // CHECK-NEXT: 3 | void J::bar(long)
198*67e74705SXin Li   // CHECK-NEXT: 4 | void J::bar(int)
199*67e74705SXin Li   // CHECK-NEXT: 5 | void J::bar(short)
200*67e74705SXin Li   // CHECK-NEXT: 6 | void L::foo(float)
201*67e74705SXin Li   // CHECK-NEXT: 7 | void L::bar(double)
202*67e74705SXin Li   // CHECK-NEXT: 8 | void L::bar(float)
203*67e74705SXin Li 
204*67e74705SXin Li   // This case is interesting. Since the J::foo(int) override is the first method in
205*67e74705SXin Li   // the class, foo(float) precedes the bar(double) and bar(float) in the vftable.
206*67e74705SXin Li   virtual void foo(int);
207*67e74705SXin Li   virtual void bar(float);
208*67e74705SXin Li   virtual void foo(float);
209*67e74705SXin Li   virtual void bar(double);
210*67e74705SXin Li };
211*67e74705SXin Li 
212*67e74705SXin Li L l;
use(L * obj)213*67e74705SXin Li void use(L *obj) { obj->foo(42.0f); }
214*67e74705SXin Li 
215*67e74705SXin Li struct M : J {
216*67e74705SXin Li   // CHECK-LABEL: VFTable for 'J' in 'M' (11 entries)
217*67e74705SXin Li   // CHECK-NEXT:  0 | void J::foo(long)
218*67e74705SXin Li   // CHECK-NEXT:  1 | void M::foo(int)
219*67e74705SXin Li   // CHECK-NEXT:  2 | void J::foo(short)
220*67e74705SXin Li   // CHECK-NEXT:  3 | void J::bar(long)
221*67e74705SXin Li   // CHECK-NEXT:  4 | void J::bar(int)
222*67e74705SXin Li   // CHECK-NEXT:  5 | void J::bar(short)
223*67e74705SXin Li   // CHECK-NEXT:  6 | void M::foo(float)
224*67e74705SXin Li   // CHECK-NEXT:  7 | void M::spam(long)
225*67e74705SXin Li   // CHECK-NEXT:  8 | void M::spam(int)
226*67e74705SXin Li   // CHECK-NEXT:  9 | void M::bar(double)
227*67e74705SXin Li   // CHECK-NEXT: 10 | void M::bar(float)
228*67e74705SXin Li 
229*67e74705SXin Li   virtual void foo(int);
230*67e74705SXin Li   virtual void spam(int);
231*67e74705SXin Li   virtual void bar(float);
232*67e74705SXin Li   virtual void bar(double);
233*67e74705SXin Li   virtual void foo(float);
234*67e74705SXin Li   virtual void spam(long);
235*67e74705SXin Li };
236*67e74705SXin Li 
237*67e74705SXin Li M m;
use(M * obj)238*67e74705SXin Li void use(M *obj) { obj->foo(42.0f); }
239*67e74705SXin Li 
240*67e74705SXin Li struct N {
241*67e74705SXin Li   // CHECK-LABEL: VFTable for 'N' (4 entries)
242*67e74705SXin Li   // CHECK-NEXT: 0 | void N::operator+(int)
243*67e74705SXin Li   // CHECK-NEXT: 1 | void N::operator+(short)
244*67e74705SXin Li   // CHECK-NEXT: 2 | void N::operator*(int)
245*67e74705SXin Li   // CHECK-NEXT: 3 | void N::operator*(short)
246*67e74705SXin Li   virtual void operator+(short);
247*67e74705SXin Li   virtual void operator*(short);
248*67e74705SXin Li   virtual void operator+(int);
249*67e74705SXin Li   virtual void operator*(int);
250*67e74705SXin Li };
251*67e74705SXin Li 
252*67e74705SXin Li N n;
use(N * obj)253*67e74705SXin Li void use(N *obj) { obj->operator+(42); }
254*67e74705SXin Li 
255*67e74705SXin Li struct O { virtual A *f(); };
256*67e74705SXin Li struct P : O { virtual B *f(); };
257*67e74705SXin Li P p;
use(O * obj)258*67e74705SXin Li void use(O *obj) { obj->f(); }
use(P * obj)259*67e74705SXin Li void use(P *obj) { obj->f(); }
260*67e74705SXin Li // CHECK-LABEL: VFTable for 'O' (1 entry)
261*67e74705SXin Li // CHECK-NEXT: 0 | A *O::f()
262*67e74705SXin Li 
263*67e74705SXin Li // CHECK-LABEL: VFTable for 'O' in 'P' (1 entry)
264*67e74705SXin Li // CHECK-NEXT: 0 | B *P::f()
265*67e74705SXin Li 
266*67e74705SXin Li struct Q {
267*67e74705SXin Li   // CHECK-LABEL: VFTable for 'Q' (2 entries)
268*67e74705SXin Li   // CHECK-NEXT: 0 | void Q::foo(int)
269*67e74705SXin Li   // CHECK-NEXT: 1 | void Q::bar(int)
270*67e74705SXin Li   void foo(short);
271*67e74705SXin Li   void bar(short);
272*67e74705SXin Li   virtual void bar(int);
273*67e74705SXin Li   virtual void foo(int);
274*67e74705SXin Li };
275*67e74705SXin Li 
276*67e74705SXin Li Q q;
use(Q * obj)277*67e74705SXin Li void use(Q *obj) { obj->foo(42); }
278*67e74705SXin Li 
279*67e74705SXin Li // Inherited non-virtual overloads don't participate in the ordering.
280*67e74705SXin Li struct R : Q {
281*67e74705SXin Li   // CHECK-LABEL: VFTable for 'Q' in 'R' (4 entries)
282*67e74705SXin Li   // CHECK-NEXT: 0 | void Q::foo(int)
283*67e74705SXin Li   // CHECK-NEXT: 1 | void Q::bar(int)
284*67e74705SXin Li   // CHECK-NEXT: 2 | void R::bar(long)
285*67e74705SXin Li   // CHECK-NEXT: 3 | void R::foo(long)
286*67e74705SXin Li   virtual void bar(long);
287*67e74705SXin Li   virtual void foo(long);
288*67e74705SXin Li };
289*67e74705SXin Li 
290*67e74705SXin Li R r;
use(R * obj)291*67e74705SXin Li void use(R *obj) { obj->foo(42l); }
292*67e74705SXin Li 
293*67e74705SXin Li struct S {
294*67e74705SXin Li   // CHECK-LABEL: VFTable for 'S' (1 entry).
295*67e74705SXin Li   // CHECK-NEXT:   0 | void S::f() [deleted]
296*67e74705SXin Li   virtual void f() = delete;
297*67e74705SXin Li   S();
298*67e74705SXin Li   // EMITS-VFTABLE-DAG: @"\01??_7S@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (void ()* @_purecall to i8*)]
299*67e74705SXin Li };
300*67e74705SXin Li 
S()301*67e74705SXin Li S::S() {}
302*67e74705SXin Li 
303*67e74705SXin Li struct T {
304*67e74705SXin Li   struct U {};
305*67e74705SXin Li };
306*67e74705SXin Li struct V : T {
307*67e74705SXin Li   // CHECK-LABEL: VFTable for 'V' (2 entries).
308*67e74705SXin Li   // CHECK-NEXT:   0 | void V::U()
309*67e74705SXin Li   // CHECK-NEXT:   1 | void V::f()
310*67e74705SXin Li   using T::U;
311*67e74705SXin Li   virtual void f();
312*67e74705SXin Li   virtual void U();
313*67e74705SXin Li   V();
314*67e74705SXin Li };
315*67e74705SXin Li 
V()316*67e74705SXin Li V::V() {}
317