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