1 | // RUN: %clang_cc1 %s -triple=x86_64-pc-windows-msvc -debug-info-kind=limited -S -emit-llvm -o - | FileCheck %s |
2 | // RUN: %clang_cc1 %s -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - | FileCheck %s -check-prefix=ITANIUM |
3 | // |
4 | // Validate we emit a "DIFlagThunk" flag on DISubprogram entries for thunks. |
5 | // This flag is used for emitting S_THUNK32 symbols for CodeView debugging. |
6 | // |
7 | // NOTE: |
8 | // Because thunks are compiler generated and don't exist in the source, this |
9 | // test is dependent upon the linkage name to identify the thunk. Any changes |
10 | // in the name mangling may require this test to be updated. |
11 | // |
12 | // NOTE: |
13 | // The FileCheck directives below use CHECK-DAG because the thunks may not be |
14 | // emitted in source order. |
15 | // |
16 | |
17 | namespace Test1 { |
18 | struct A { |
19 | virtual void f(); |
20 | }; |
21 | |
22 | struct B { |
23 | virtual void f(); |
24 | }; |
25 | |
26 | struct C : A, B { |
27 | virtual void c(); |
28 | |
29 | virtual void f(); |
30 | }; |
31 | |
32 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@Test1@@W7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk |
33 | void C::f() { } |
34 | } |
35 | |
36 | namespace Test2 { |
37 | struct V1 { }; |
38 | struct V2 : virtual V1 { }; |
39 | |
40 | struct A { |
41 | virtual V1 *f(); |
42 | }; |
43 | |
44 | struct B : A { |
45 | virtual void b(); |
46 | |
47 | virtual V2 *f(); |
48 | }; |
49 | |
50 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@B@Test2@@QEAAPEAUV1@2@XZ"{{.*}} flags: {{.*}}DIFlagThunk |
51 | V2 *B::f() { return 0; } |
52 | } |
53 | |
54 | namespace Test3 { |
55 | struct A { |
56 | virtual void f(); |
57 | }; |
58 | |
59 | struct B { |
60 | virtual void f(); |
61 | }; |
62 | |
63 | struct __attribute__((visibility("protected"))) C : A, B { |
64 | virtual void c(); |
65 | |
66 | virtual void f(); |
67 | }; |
68 | |
69 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@Test3@@W7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk |
70 | void C::f() { } |
71 | } |
72 | |
73 | namespace Test4 { |
74 | struct A { |
75 | virtual void f(); |
76 | }; |
77 | |
78 | struct B { |
79 | virtual void f(); |
80 | }; |
81 | |
82 | namespace { |
83 | struct C : A, B { |
84 | virtual void c(); |
85 | virtual void f(); |
86 | }; |
87 | } |
88 | void C::c() {} |
89 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@?A0x{{[^@]*}}@Test4@@W7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk |
90 | void C::f() {} |
91 | |
92 | // Force C::f to be used. |
93 | void f() { |
94 | C c; |
95 | c.f(); |
96 | } |
97 | } |
98 | |
99 | namespace Test5 { |
100 | struct X { |
101 | X(); |
102 | X(const X&); |
103 | X &operator=(const X&); |
104 | ~X(); |
105 | }; |
106 | |
107 | struct P { |
108 | P(); |
109 | P(const P&); |
110 | ~P(); |
111 | X first; |
112 | X second; |
113 | }; |
114 | |
115 | P getP(); |
116 | |
117 | struct Base1 { |
118 | int i; |
119 | |
120 | virtual X f() { return X(); } |
121 | }; |
122 | |
123 | struct Base2 { |
124 | float real; |
125 | |
126 | virtual X f() { return X(); } |
127 | }; |
128 | |
129 | struct Thunks : Base1, Base2 { |
130 | long l; |
131 | |
132 | virtual X f(); |
133 | }; |
134 | |
135 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@Thunks@Test5@@WBA@EAA?AUX@2@XZ"{{.*}} flags: {{.*}}DIFlagThunk |
136 | X Thunks::f() { return X(); } |
137 | } |
138 | |
139 | namespace Test6 { |
140 | struct X { |
141 | X(); |
142 | X(const X&); |
143 | X &operator=(const X&); |
144 | ~X(); |
145 | }; |
146 | |
147 | struct Small { short s; }; |
148 | struct Large { |
149 | char array[1024]; |
150 | }; |
151 | |
152 | class A { |
153 | protected: |
154 | virtual void foo() = 0; |
155 | }; |
156 | |
157 | class B : public A { |
158 | protected: |
159 | virtual void bar() = 0; |
160 | }; |
161 | |
162 | class C : public A { |
163 | protected: |
164 | virtual void baz(X, X&, _Complex float, Small, Small&, Large) = 0; |
165 | }; |
166 | |
167 | class D : public B, |
168 | public C { |
169 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?foo@D@Test6@@G7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk |
170 | void foo() {} |
171 | void bar() {} |
172 | void baz(X, X&, _Complex float, Small, Small&, Large); |
173 | }; |
174 | |
175 | void D::baz(X, X&, _Complex float, Small, Small&, Large) { } |
176 | |
177 | void testD() { D d; } |
178 | } |
179 | |
180 | namespace Test7 { |
181 | struct A { virtual void foo(); }; |
182 | struct B { virtual void foo(); }; |
183 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?foo@C@Test7@@W7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk |
184 | struct C : A, B { void foo() {} }; |
185 | |
186 | // Test later. |
187 | void test() { |
188 | C c; |
189 | } |
190 | } |
191 | |
192 | namespace Test8 { |
193 | struct A { virtual A* f(); }; |
194 | struct B : virtual A { virtual A* f(); }; |
195 | struct C : B { virtual C* f(); }; |
196 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@Test8@@QEAAPEAUA@2@XZ"{{.*}} flags: {{.*}}DIFlagThunk |
197 | C* C::f() { return 0; } |
198 | } |
199 | |
200 | namespace Test9 { |
201 | struct B1 { |
202 | virtual B1 &foo1(); |
203 | }; |
204 | struct Pad1 { |
205 | virtual ~Pad1(); |
206 | }; |
207 | struct Proxy1 : Pad1, B1 { |
208 | virtual ~Proxy1(); |
209 | }; |
210 | struct D : virtual Proxy1 { |
211 | virtual ~D(); |
212 | virtual D &foo1(); |
213 | }; |
214 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?foo1@D@Test9@@$4PPPPPPPE@A@EAAAEAUB1@2@XZ"{{.*}} flags: {{.*}}DIFlagThunk |
215 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?foo1@D@Test9@@$4PPPPPPPE@A@EAAAEAU12@XZ"{{.*}} flags: {{.*}}DIFlagThunk |
216 | D& D::foo1() { |
217 | return *this; |
218 | } |
219 | } |
220 | |
221 | namespace Test10 { |
222 | class A { |
223 | virtual void f(); |
224 | }; |
225 | class B { |
226 | virtual void f(); |
227 | }; |
228 | class C : public A, public B { |
229 | virtual void f(); |
230 | }; |
231 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@Test10@@G7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk |
232 | void C::f() { |
233 | } |
234 | } |
235 | |
236 | namespace Test11 { |
237 | class A { |
238 | public: |
239 | virtual void f(); |
240 | }; |
241 | |
242 | void test() { |
243 | // CHECK-DAG: DISubprogram{{.*}}linkageName: "??_9A@Test11@@$BA@AA"{{.*}} flags: {{.*}}DIFlagThunk |
244 | void (A::*p)() = &A::f; |
245 | } |
246 | } |
247 | |
248 | namespace Test12 { |
249 | struct A { |
250 | virtual void f(); |
251 | }; |
252 | |
253 | struct B { |
254 | virtual void f(); |
255 | }; |
256 | |
257 | struct C : A, B { |
258 | virtual void f(); |
259 | }; |
260 | |
261 | void C::f() { } |
262 | // ITANIUM: define {{.*}}void @_ZThn{{[48]}}_N6Test121C1fEv |
263 | // ITANIUM-SAME: !dbg ![[SP:[0-9]+]] |
264 | // ITANIUM-NOT: {{ret }} |
265 | // ITANIUM: = load{{.*}} !dbg ![[DBG:[0-9]+]] |
266 | // ITANIUM-NOT: {{ret }} |
267 | // ITANIUM: ret void, !dbg ![[DBG]] |
268 | // |
269 | // ITANIUM: ![[SP]] = distinct !DISubprogram(linkageName: "_ZThn{{[48]}}_N6Test121C1fEv" |
270 | // ITANIUM-SAME: line: 261 |
271 | // ITANIUM-SAME: DIFlagArtificial |
272 | // ITANIUM-SAME: DIFlagThunk |
273 | // ITANIUM-SAME: DISPFlagDefinition |
274 | // ITANIUM-SAME: ){{$}} |
275 | // |
276 | // ITANIUM: ![[DBG]] = !DILocation(line: 0 |
277 | } |
278 | |