[InstCombine] Preserve NSW flags for `lshr (mul nuw X, C1), C2 -> mul nuw nsw X,...
[llvm-project.git] / clang / test / CodeGenCXX / microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp
blob954f39c068cc1ddceb843324aa30476f6770537f
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
5 namespace test1 {
6 struct A {
7 virtual void g();
8 // Add an extra virtual method so it's easier to check for the absence of thunks.
9 virtual void h();
12 struct B {
13 virtual void g();
16 // Overrides a method of two bases at the same time, thus needing thunks.
17 struct C : A, B {
18 virtual void g();
21 struct D {
22 virtual B* foo();
23 virtual void z();
26 struct X : D {
27 // CHECK-LABEL: VFTable for 'test1::D' in 'test1::X' (3 entries).
28 // CHECK-NEXT: 0 | C *test1::X::foo()
29 // CHECK-NEXT: [return adjustment (to type 'struct test1::B *'): 4 non-virtual]
30 // CHECK-NEXT: 1 | void test1::D::z()
31 // CHECK-NEXT: 2 | C *test1::X::foo()
33 // CHECK-LABEL: Thunks for 'C *test1::X::foo()' (1 entry).
34 // CHECK-NEXT: 0 | [return adjustment (to type 'struct test1::B *'): 4 non-virtual]
36 // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).
37 // CHECK-NEXT: 2 | C *test1::X::foo()
39 // MANGLING-DAG: @"??_7X@test1@@6B@"
41 virtual C* foo();
42 } x;
44 void build_vftable(X *obj) { obj->foo(); }
47 namespace test2 {
48 struct A {
49 virtual void g();
50 virtual void h();
53 struct B {
54 virtual void g();
57 struct C : A, B {
58 virtual void g();
61 struct D {
62 virtual B* foo();
63 virtual void z();
66 struct E : D {
67 virtual C* foo();
70 struct F : C { };
72 struct X : E {
73 virtual F* foo();
74 // CHECK-LABEL: VFTable for 'test2::D' in 'test2::E' in 'test2::X' (4 entries).
75 // CHECK-NEXT: 0 | F *test2::X::foo()
76 // CHECK-NEXT: [return adjustment (to type 'struct test2::B *'): 4 non-virtual]
77 // CHECK-NEXT: 1 | void test2::D::z()
78 // CHECK-NEXT: 2 | F *test2::X::foo()
79 // CHECK-NEXT: [return adjustment (to type 'struct test2::C *'): 0 non-virtual]
80 // CHECK-NEXT: 3 | F *test2::X::foo()
82 // CHECK-LABEL: Thunks for 'F *test2::X::foo()' (2 entries).
83 // CHECK-NEXT: 0 | [return adjustment (to type 'struct test2::C *'): 0 non-virtual]
84 // CHECK-NEXT: 1 | [return adjustment (to type 'struct test2::B *'): 4 non-virtual]
86 // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
87 // CHECK-NEXT: 3 | F *test2::X::foo()
90 void build_vftable(X *obj) { obj->foo(); }
93 namespace test3 {
94 struct A {
95 virtual void g();
96 virtual void h();
99 struct B {
100 virtual void g();
103 struct C : A, B {
104 virtual void g();
107 struct D {
108 virtual B* foo();
109 virtual void z();
112 struct E : D {
113 virtual C* foo();
116 struct F : A, C { };
118 struct X : E {
119 // CHECK-LABEL: VFTable for 'test3::D' in 'test3::E' in 'test3::X' (4 entries).
120 // CHECK-NEXT: 0 | F *test3::X::foo()
121 // CHECK-NEXT: [return adjustment (to type 'struct test3::B *'): 8 non-virtual]
122 // CHECK-NEXT: 1 | void test3::D::z()
123 // CHECK-NEXT: 2 | F *test3::X::foo()
124 // CHECK-NEXT: [return adjustment (to type 'struct test3::C *'): 4 non-virtual]
125 // CHECK-NEXT: 3 | F *test3::X::foo()
127 // CHECK-LABEL: Thunks for 'F *test3::X::foo()' (2 entries).
128 // CHECK-NEXT: 0 | [return adjustment (to type 'struct test3::C *'): 4 non-virtual]
129 // CHECK-NEXT: 1 | [return adjustment (to type 'struct test3::B *'): 8 non-virtual]
131 // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry).
132 // CHECK-NEXT: 3 | F *test3::X::foo()
134 virtual F* foo();
137 void build_vftable(X *obj) { obj->foo(); }
140 namespace test4 {
141 struct A {
142 virtual void g();
143 virtual void h();
146 struct B {
147 virtual void g();
150 struct C : A, B {
151 virtual void g();
154 struct D {
155 virtual B* foo();
156 virtual void z();
159 struct E : D {
160 virtual C* foo();
163 struct F : A, C { };
165 struct X : D, E {
166 // CHECK-LABEL: VFTable for 'test4::D' in 'test4::X' (3 entries).
167 // CHECK-NEXT: 0 | F *test4::X::foo()
168 // CHECK-NEXT: [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
169 // CHECK-NEXT: 1 | void test4::D::z()
170 // CHECK-NEXT: 2 | F *test4::X::foo()
172 // CHECK-LABEL: Thunks for 'F *test4::X::foo()' (1 entry).
173 // CHECK-NEXT: 0 | [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
175 // CHECK-LABEL: VFTable for 'test4::D' in 'test4::E' in 'test4::X' (4 entries).
176 // CHECK-NEXT: 0 | F *test4::X::foo()
177 // CHECK-NEXT: [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
178 // CHECK-NEXT: [this adjustment: -4 non-virtual]
179 // CHECK-NEXT: 1 | void test4::D::z()
180 // CHECK-NEXT: 2 | F *test4::X::foo()
181 // CHECK-NEXT: [return adjustment (to type 'struct test4::C *'): 4 non-virtual]
182 // CHECK-NEXT: [this adjustment: -4 non-virtual]
183 // CHECK-NEXT: 3 | F *test4::X::foo()
184 // CHECK-NEXT: [return adjustment (to type 'struct test4::F *'): 0 non-virtual]
185 // CHECK-NEXT: [this adjustment: -4 non-virtual]
187 // CHECK-LABEL: Thunks for 'F *test4::X::foo()' (3 entries).
188 // CHECK-NEXT: 0 | [return adjustment (to type 'struct test4::F *'): 0 non-virtual]
189 // CHECK-NEXT: [this adjustment: -4 non-virtual]
190 // CHECK-NEXT: 1 | [return adjustment (to type 'struct test4::C *'): 4 non-virtual]
191 // CHECK-NEXT: [this adjustment: -4 non-virtual]
192 // CHECK-NEXT: 2 | [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
193 // CHECK-NEXT: [this adjustment: -4 non-virtual]
195 // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry).
196 // CHECK-NEXT: 2 | F *test4::X::foo()
198 virtual F* foo();
201 void build_vftable(X *obj) { obj->foo(); }
204 namespace test5 {
205 struct A {
206 virtual void g();
207 virtual void h();
210 struct B {
211 virtual void g();
214 struct C : A, B {
215 virtual void g();
218 struct D {
219 virtual B* foo();
220 virtual void z();
223 struct X : A, D {
224 // CHECK-LABEL: VFTable for 'test5::A' in 'test5::X' (2 entries).
225 // CHECK-NEXT: 0 | void test5::A::g()
226 // CHECK-NEXT: 1 | void test5::A::h()
228 // CHECK-LABEL: VFTable for 'test5::D' in 'test5::X' (3 entries).
229 // CHECK-NEXT: 0 | C *test5::X::foo()
230 // CHECK-NEXT: [return adjustment (to type 'struct test5::B *'): 4 non-virtual]
231 // CHECK-NEXT: 1 | void test5::D::z()
232 // CHECK-NEXT: 2 | C *test5::X::foo()
234 // CHECK-LABEL: Thunks for 'C *test5::X::foo()' (1 entry).
235 // CHECK-NEXT: 0 | [return adjustment (to type 'struct test5::B *'): 4 non-virtual]
237 // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry).
238 // CHECK-NEXT: via vfptr at offset 4
239 // CHECK-NEXT: 2 | C *test5::X::foo()
241 virtual C* foo();
244 void build_vftable(X *obj) { obj->foo(); }
247 namespace test6 {
248 struct A {
249 virtual void g();
250 virtual void h();
253 struct B {
254 virtual void g();
257 struct C : A, B {
258 virtual void g();
261 struct D {
262 virtual B* foo();
263 virtual void z();
266 struct E : A, D {
267 virtual C* foo();
270 struct F : A, C { };
272 struct X : E {
273 // CHECK-LABEL: VFTable for 'test6::A' in 'test6::E' in 'test6::X' (2 entries).
274 // CHECK-NEXT: 0 | void test6::A::g()
275 // CHECK-NEXT: 1 | void test6::A::h()
277 // CHECK-LABEL: VFTable for 'test6::D' in 'test6::E' in 'test6::X' (4 entries).
278 // CHECK-NEXT: 0 | F *test6::X::foo()
279 // CHECK-NEXT: [return adjustment (to type 'struct test6::B *'): 8 non-virtual]
280 // CHECK-NEXT: 1 | void test6::D::z()
281 // CHECK-NEXT: 2 | F *test6::X::foo()
282 // CHECK-NEXT: [return adjustment (to type 'struct test6::C *'): 4 non-virtual]
283 // CHECK-NEXT: 3 | F *test6::X::foo()
285 // CHECK-LABEL: Thunks for 'F *test6::X::foo()' (2 entries).
286 // CHECK-NEXT: 0 | [return adjustment (to type 'struct test6::C *'): 4 non-virtual]
287 // CHECK-NEXT: 1 | [return adjustment (to type 'struct test6::B *'): 8 non-virtual]
289 // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry).
290 // CHECK-NEXT: -- accessible via vfptr at offset 4 --
291 // CHECK-NEXT: 3 | F *test6::X::foo()
293 virtual F* foo();
296 void build_vftable(X *obj) { obj->foo(); }
299 namespace test7 {
300 struct A {
301 virtual A *f() = 0;
303 struct B {
304 virtual void g();
306 struct C : B, A {
307 virtual void g();
308 virtual C *f() = 0;
309 // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' (1 entry).
310 // CHECK-NEXT: 0 | void test7::C::g()
312 // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' (2 entries).
313 // CHECK-NEXT: 0 | C *test7::C::f() [pure]
314 // CHECK-NEXT: 1 | C *test7::C::f() [pure]
316 // No return adjusting thunks needed for pure virtual methods.
317 // CHECK-NOT: Thunks for 'test7::C *test7::C::f()'
320 void build_vftable(C *obj) { obj->g(); }
323 namespace pr20444 {
324 struct A {
325 virtual A* f();
327 struct B {
328 virtual B* f();
330 struct C : A, B {
331 virtual C* f();
332 // CHECK-LABEL: VFTable for 'pr20444::A' in 'pr20444::C' (1 entry).
333 // CHECK-NEXT: 0 | C *pr20444::C::f()
335 // CHECK-LABEL: VFTable for 'pr20444::B' in 'pr20444::C' (2 entries).
336 // CHECK-NEXT: 0 | C *pr20444::C::f()
337 // CHECK-NEXT: [return adjustment (to type 'struct pr20444::B *'): 4 non-virtual]
338 // CHECK-NEXT: [this adjustment: -4 non-virtual]
339 // CHECK-NEXT: 1 | C *pr20444::C::f()
340 // CHECK-NEXT: [return adjustment (to type 'struct pr20444::C *'): 0 non-virtual]
341 // CHECK-NEXT: [this adjustment: -4 non-virtual]
344 void build_vftable(C *obj) { obj->f(); }
346 struct D : C {
347 virtual D* f();
348 // CHECK-LABEL: VFTable for 'pr20444::A' in 'pr20444::C' in 'pr20444::D' (1 entry).
349 // CHECK-NEXT: 0 | D *pr20444::D::f()
351 // CHECK-LABEL: VFTable for 'pr20444::B' in 'pr20444::C' in 'pr20444::D' (3 entries).
352 // CHECK-NEXT: 0 | D *pr20444::D::f()
353 // CHECK-NEXT: [return adjustment (to type 'struct pr20444::B *'): 4 non-virtual]
354 // CHECK-NEXT: [this adjustment: -4 non-virtual]
355 // CHECK-NEXT: 1 | D *pr20444::D::f()
356 // CHECK-NEXT: [return adjustment (to type 'struct pr20444::C *'): 0 non-virtual]
357 // CHECK-NEXT: [this adjustment: -4 non-virtual]
358 // CHECK-NEXT: 2 | D *pr20444::D::f()
359 // CHECK-NEXT: [return adjustment (to type 'struct pr20444::D *'): 0 non-virtual]
360 // CHECK-NEXT: [this adjustment: -4 non-virtual]
363 void build_vftable(D *obj) { obj->f(); }