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=BITCODE %s < %t.ll |
4 | |
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(); |
10 | }; |
11 | |
12 | struct B { |
13 | virtual void g(); // Collides with A::g if both are bases of some class. |
14 | }; |
15 | |
16 | // Overrides methods of two bases at the same time, thus needing thunks. |
17 | struct X : A, B { |
18 | // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (2 entries). |
19 | // CHECK-NEXT: 0 | void test1::X::g() |
20 | // CHECK-NEXT: 1 | void test1::A::h() |
21 | |
22 | // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (1 entry). |
23 | // CHECK-NEXT: 0 | void test1::X::g() |
24 | // CHECK-NEXT: [this adjustment: -4 non-virtual] |
25 | |
26 | // CHECK-LABEL: Thunks for 'void test1::X::g()' (1 entry). |
27 | // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] |
28 | |
29 | // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry). |
30 | // CHECK-NEXT: 0 | void test1::X::g() |
31 | |
32 | // BITCODE-DAG: @"??_7X@test1@@6BA@1@@" |
33 | // BITCODE-DAG: @"??_7X@test1@@6BB@1@@" |
34 | |
35 | virtual void g(); |
36 | } x; |
37 | |
38 | void build_vftable(X *obj) { obj->g(); } |
39 | } |
40 | |
41 | namespace test2 { |
42 | struct A { |
43 | virtual void f(); |
44 | }; |
45 | |
46 | struct B { |
47 | virtual void g(); |
48 | virtual void h(); |
49 | }; |
50 | |
51 | struct C { |
52 | virtual void g(); |
53 | }; |
54 | |
55 | struct X : A, B, C { |
56 | // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry). |
57 | // CHECK-NEXT: 0 | void test2::A::f() |
58 | |
59 | // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries). |
60 | // CHECK-NEXT: 0 | void test2::X::g() |
61 | // CHECK-NEXT: 1 | void test2::B::h() |
62 | |
63 | // CHECK-LABEL: VFTable for 'test2::C' in 'test2::X' (1 entry). |
64 | // CHECK-NEXT: 0 | void test2::X::g() |
65 | // CHECK-NEXT: [this adjustment: -4 non-virtual] |
66 | |
67 | // CHECK-LABEL: Thunks for 'void test2::X::g()' (1 entry). |
68 | // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] |
69 | |
70 | // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry). |
71 | // CHECK-NEXT: via vfptr at offset 4 |
72 | // CHECK-NEXT: 0 | void test2::X::g() |
73 | |
74 | // BITCODE-DAG: @"??_7X@test2@@6BA@1@@" |
75 | // BITCODE-DAG: @"??_7X@test2@@6BB@1@@" |
76 | // BITCODE-DAG: @"??_7X@test2@@6BC@1@@" |
77 | |
78 | virtual void g(); |
79 | } x; |
80 | |
81 | void build_vftable(X *obj) { obj->g(); } |
82 | } |
83 | |
84 | namespace test3 { |
85 | struct A { |
86 | virtual void f(); |
87 | }; |
88 | |
89 | struct B { |
90 | virtual void g(); |
91 | virtual void h(); |
92 | }; |
93 | |
94 | struct C: A, B { |
95 | // Overrides only the left child's method (A::f), needs no thunks. |
96 | virtual void f(); |
97 | }; |
98 | |
99 | struct D: A, B { |
100 | // Overrides only the right child's method (B::g), |
101 | // needs this adjustment but not thunks. |
102 | virtual void g(); |
103 | }; |
104 | |
105 | // Overrides methods of two bases at the same time, thus needing thunks. |
106 | struct X: C, D { |
107 | // CHECK-LABEL: VFTable for 'test3::A' in 'test3::C' in 'test3::X' (1 entry). |
108 | // CHECK-NEXT: 0 | void test3::X::f() |
109 | |
110 | // CHECK-LABEL: VFTable for 'test3::B' in 'test3::C' in 'test3::X' (2 entries). |
111 | // CHECK-NEXT: 0 | void test3::X::g() |
112 | // CHECK-NEXT: 1 | void test3::B::h() |
113 | |
114 | // CHECK-LABEL: VFTable for 'test3::A' in 'test3::D' in 'test3::X' (1 entry). |
115 | // CHECK-NEXT: 0 | void test3::X::f() |
116 | // CHECK-NEXT: [this adjustment: -8 non-virtual] |
117 | |
118 | // CHECK-LABEL: Thunks for 'void test3::X::f()' (1 entry). |
119 | // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] |
120 | |
121 | // CHECK-LABEL: VFTable for 'test3::B' in 'test3::D' in 'test3::X' (2 entries). |
122 | // CHECK-NEXT: 0 | void test3::X::g() |
123 | // CHECK-NEXT: [this adjustment: -8 non-virtual] |
124 | // CHECK-NEXT: 1 | void test3::B::h() |
125 | |
126 | // CHECK-LABEL: Thunks for 'void test3::X::g()' (1 entry). |
127 | // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] |
128 | |
129 | // CHECK-LABEL: VFTable indices for 'test3::X' (2 entries). |
130 | // CHECK-NEXT: via vfptr at offset 0 |
131 | // CHECK-NEXT: 0 | void test3::X::f() |
132 | // CHECK-NEXT: via vfptr at offset 4 |
133 | // CHECK-NEXT: 0 | void test3::X::g() |
134 | |
135 | virtual void f(); |
136 | virtual void g(); |
137 | } x; |
138 | |
139 | void build_vftable(X *obj) { obj->g(); } |
140 | } |
141 | |
142 | namespace test4 { |
143 | struct A { |
144 | virtual void foo(); |
145 | }; |
146 | struct B { |
147 | virtual int filler(); |
148 | virtual int operator-(); |
149 | virtual int bar(); |
150 | }; |
151 | struct C : public A, public B { |
152 | virtual int filler(); |
153 | virtual int operator-(); |
154 | virtual int bar(); |
155 | }; |
156 | |
157 | // BITCODE-LABEL: define {{.*}}"?ffun@test4@@YAXAAUC@1@@Z |
158 | void ffun(C &c) { |
159 | // BITCODE: [[THIS1:%.+]] = bitcast %"struct.test4::C"* {{.*}} to i8* |
160 | // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, i8* [[THIS1]], i32 4 |
161 | // BITCODE: call x86_thiscallcc {{.*}}(i8* [[THIS2]]) |
162 | c.bar(); |
163 | } |
164 | |
165 | // BITCODE-LABEL: define {{.*}}"?fop@test4@@YAXAAUC@1@@Z |
166 | void fop(C &c) { |
167 | // BITCODE: [[THIS1:%.+]] = bitcast %"struct.test4::C"* {{.*}} to i8* |
168 | // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, i8* [[THIS1]], i32 4 |
169 | // BITCODE: call x86_thiscallcc {{.*}}(i8* [[THIS2]]) |
170 | -c; |
171 | } |
172 | |
173 | } |
174 | |
175 | namespace pr30293 { |
176 | struct NonTrivial { |
177 | ~NonTrivial(); |
178 | int x; |
179 | }; |
180 | struct A { virtual void f(); }; |
181 | struct B { virtual void __cdecl g(NonTrivial); }; |
182 | struct C final : A, B { |
183 | void f() override; |
184 | void __cdecl g(NonTrivial) override; |
185 | }; |
186 | C *whatsthis; |
187 | void C::f() { g(NonTrivial()); } |
188 | void C::g(NonTrivial o) { |
189 | whatsthis = this; |
190 | } |
191 | |
192 | // BITCODE-LABEL: define dso_local void @"?g@C@pr30293@@UAAXUNonTrivial@2@@Z"(<{ i8*, %"struct.pr30293::NonTrivial" }>* inalloca) |
193 | // BITCODE: %[[thisaddr:[^ ]*]] = getelementptr inbounds <{ i8*, %"struct.pr30293::NonTrivial" }>, <{ i8*, %"struct.pr30293::NonTrivial" }>* {{.*}}, i32 0, i32 0 |
194 | // BITCODE: %[[thisaddr1:[^ ]*]] = bitcast i8** %[[thisaddr]] to %"struct.pr30293::C"** |
195 | // BITCODE: %[[this1:[^ ]*]] = load %"struct.pr30293::C"*, %"struct.pr30293::C"** %[[thisaddr1]], align 4 |
196 | // BITCODE: %[[this2:[^ ]*]] = bitcast %"struct.pr30293::C"* %[[this1]] to i8* |
197 | // BITCODE: %[[this3:[^ ]*]] = getelementptr inbounds i8, i8* %[[this2]], i32 -4 |
198 | // BITCODE: %[[this4:[^ ]*]] = bitcast i8* %[[this3]] to %"struct.pr30293::C"* |
199 | // BITCODE: store %"struct.pr30293::C"* %[[this4]], %"struct.pr30293::C"** @"?whatsthis@pr30293@@3PAUC@1@A", align 4 |
200 | } |
201 | |