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