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 |
5 | |
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() |
15 | |
16 | virtual void f(); |
17 | virtual void g(); |
18 | virtual void h(); |
19 | int ia; |
20 | }; |
21 | A a; |
22 | // EMITS-VFTABLE-DAG: @"??_7A@@6B@" = linkonce_odr unnamed_addr constant { [3 x i8*] } |
23 | void use(A *obj) { obj->f(); } |
24 | |
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() |
36 | |
37 | virtual void f(); // overrides A::f() |
38 | virtual void i(); |
39 | virtual void j(); |
40 | }; |
41 | B b; |
42 | // EMITS-VFTABLE-DAG: @"??_7B@@6B@" = linkonce_odr unnamed_addr constant { [5 x i8*] } |
43 | void use(B *obj) { obj->f(); } |
44 | |
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() |
52 | |
53 | virtual ~C(); |
54 | virtual void f(); |
55 | }; |
56 | void C::f() {} |
57 | // NO-VFTABLE-NOT: @"??_7C@@6B@" |
58 | void use(C *obj) { obj->f(); } |
59 | |
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] |
67 | |
68 | virtual void f(); |
69 | virtual ~D(); |
70 | }; |
71 | D d; |
72 | // EMITS-VFTABLE-DAG: @"??_7D@@6B@" = linkonce_odr unnamed_addr constant { [2 x i8*] } |
73 | void use(D *obj) { obj->f(); } |
74 | |
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() |
85 | |
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(); |
90 | }; |
91 | void E::i() {} |
92 | // NO-VFTABLE-NOT: @"??_7E@@6B@" |
93 | void use(E *obj) { obj->i(); } |
94 | |
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] |
105 | |
106 | virtual void i(); |
107 | virtual ~F(); |
108 | }; |
109 | F f; |
110 | // EMITS-VFTABLE-DAG: @"??_7F@@6B@" = linkonce_odr unnamed_addr constant { [5 x i8*] } |
111 | void use(F *obj) { obj->i(); } |
112 | |
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() |
125 | |
126 | virtual void f(); // overrides A::f() |
127 | virtual ~G(); |
128 | virtual void j(); |
129 | }; |
130 | void G::j() {} |
131 | // NO-VFTABLE-NOT: @"??_7G@@6B@" |
132 | void use(G *obj) { obj->j(); } |
133 | |
134 | // Test that the usual Itanium-style key method does not emit a vtable. |
135 | struct H { |
136 | virtual void f(); |
137 | }; |
138 | void H::f() {} |
139 | // NO-VFTABLE-NOT: @"??_7H@@6B@" |
140 | |
141 | struct Empty { }; |
142 | |
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(); |
149 | }; |
150 | |
151 | I i; |
152 | void use(I *obj) { obj->f(); } |
153 | |
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); |
168 | }; |
169 | |
170 | J j; |
171 | void use(J *obj) { obj->foo(42); } |
172 | |
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); |
187 | }; |
188 | |
189 | K k; |
190 | void use(K *obj) { obj->foo(42.0f); } |
191 | |
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) |
203 | |
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); |
210 | }; |
211 | |
212 | L l; |
213 | void use(L *obj) { obj->foo(42.0f); } |
214 | |
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) |
228 | |
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); |
235 | }; |
236 | |
237 | M m; |
238 | void use(M *obj) { obj->foo(42.0f); } |
239 | |
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); |
250 | }; |
251 | |
252 | N n; |
253 | void use(N *obj) { obj->operator+(42); } |
254 | |
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() |
262 | |
263 | // CHECK-LABEL: VFTable for 'O' in 'P' (1 entry) |
264 | // CHECK-NEXT: 0 | B *P::f() |
265 | |
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); |
274 | }; |
275 | |
276 | Q q; |
277 | void use(Q *obj) { obj->foo(42); } |
278 | |
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); |
288 | }; |
289 | |
290 | R r; |
291 | void use(R *obj) { obj->foo(42l); } |
292 | |
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 i8*] } { [1 x i8*] [i8* bitcast (void ()* @_purecall to i8*)] } |
299 | }; |
300 | |
301 | S::S() {} |
302 | |
303 | struct T { |
304 | struct U {}; |
305 | }; |
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(); |
314 | }; |
315 | |
316 | V::V() {} |
317 | |