1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This test case checks specifically the cases under bullet 3.1 & 3.2: |
10 | // |
11 | // C++ ABI 15.3: |
12 | // A handler is a match for an exception object of type E if |
13 | // * The handler is of type cv T or cv T& and E and T are the same type |
14 | // (ignoring the top-level cv-qualifiers), or |
15 | // * the handler is of type cv T or cv T& and T is an unambiguous base |
16 | // class of E, or |
17 | // > * the handler is of type cv1 T* cv2 and E is a pointer type that can < |
18 | // > be converted to the type of the handler by either or both of < |
19 | // > o a standard pointer conversion (4.10 [conv.ptr]) not involving < |
20 | // > conversions to private or protected or ambiguous classes < |
21 | // > o a qualification conversion < |
22 | // * the handler is a pointer or pointer to member type and E is |
23 | // std::nullptr_t |
24 | // |
25 | //===----------------------------------------------------------------------===// |
26 | |
27 | // UNSUPPORTED: no-exceptions |
28 | |
29 | #include <exception> |
30 | #include <stdlib.h> |
31 | #include <assert.h> |
32 | #include <stdio.h> |
33 | |
34 | struct Base {}; |
35 | struct Derived : Base {}; |
36 | struct Derived2 : Base {}; |
37 | struct Ambiguous : Derived, Derived2 {}; |
38 | struct Private : private Base {}; |
39 | struct Protected : protected Base {}; |
40 | |
41 | template <typename T // Handler type |
42 | ,typename E // Thrown exception type |
43 | ,typename O // Object type |
44 | > |
45 | void assert_catches() |
46 | { |
47 | try |
48 | { |
49 | O o; |
50 | throw static_cast<E>(&o); |
51 | printf("%s\n" , __PRETTY_FUNCTION__); |
52 | assert(false && "Statements after throw must be unreachable" ); |
53 | } |
54 | catch (T t) |
55 | { |
56 | assert(true); |
57 | return; |
58 | } |
59 | catch (...) |
60 | { |
61 | printf("%s\n" , __PRETTY_FUNCTION__); |
62 | assert(false && "Should not have entered catch-all" ); |
63 | } |
64 | |
65 | printf("%s\n" , __PRETTY_FUNCTION__); |
66 | assert(false && "The catch should have returned" ); |
67 | } |
68 | |
69 | template <typename T // Handler type |
70 | ,typename E // Thrown exception type |
71 | ,typename O // Object type |
72 | > |
73 | void assert_cannot_catch() |
74 | { |
75 | try |
76 | { |
77 | O o; |
78 | throw static_cast<E>(&o); |
79 | printf("%s\n" , __PRETTY_FUNCTION__); |
80 | assert(false && "Statements after throw must be unreachable" ); |
81 | } |
82 | catch (T t) |
83 | { |
84 | printf("%s\n" , __PRETTY_FUNCTION__); |
85 | assert(false && "Should not have entered the catch" ); |
86 | } |
87 | catch (...) |
88 | { |
89 | assert(true); |
90 | return; |
91 | } |
92 | |
93 | printf("%s\n" , __PRETTY_FUNCTION__); |
94 | assert(false && "The catch-all should have returned" ); |
95 | } |
96 | |
97 | void f1() |
98 | { |
99 | // Test that every combination of handler of type: |
100 | // cv1 Base * cv2 |
101 | // catches an exception of type: |
102 | // Derived * |
103 | assert_catches< Base * , Derived *, Derived>(); |
104 | assert_catches<const Base * , Derived *, Derived>(); |
105 | assert_catches< volatile Base * , Derived *, Derived>(); |
106 | assert_catches<const volatile Base * , Derived *, Derived>(); |
107 | assert_catches< Base * const , Derived *, Derived>(); |
108 | assert_catches<const Base * const , Derived *, Derived>(); |
109 | assert_catches< volatile Base * const , Derived *, Derived>(); |
110 | assert_catches<const volatile Base * const , Derived *, Derived>(); |
111 | assert_catches< Base * volatile, Derived *, Derived>(); |
112 | assert_catches<const Base * volatile, Derived *, Derived>(); |
113 | assert_catches< volatile Base * volatile, Derived *, Derived>(); |
114 | assert_catches<const volatile Base * volatile, Derived *, Derived>(); |
115 | assert_catches< Base * const volatile, Derived *, Derived>(); |
116 | assert_catches<const Base * const volatile, Derived *, Derived>(); |
117 | assert_catches< volatile Base * const volatile, Derived *, Derived>(); |
118 | assert_catches<const volatile Base * const volatile, Derived *, Derived>(); |
119 | } |
120 | |
121 | void f2() |
122 | { |
123 | // Test that every combination of handler of type: |
124 | // cv1 Base * cv2 |
125 | // catches an exception of type: |
126 | // Base * |
127 | assert_catches< Base * , Base *, Derived>(); |
128 | assert_catches<const Base * , Base *, Derived>(); |
129 | assert_catches< volatile Base * , Base *, Derived>(); |
130 | assert_catches<const volatile Base * , Base *, Derived>(); |
131 | assert_catches< Base * const , Base *, Derived>(); |
132 | assert_catches<const Base * const , Base *, Derived>(); |
133 | assert_catches< volatile Base * const , Base *, Derived>(); |
134 | assert_catches<const volatile Base * const , Base *, Derived>(); |
135 | assert_catches< Base * volatile, Base *, Derived>(); |
136 | assert_catches<const Base * volatile, Base *, Derived>(); |
137 | assert_catches< volatile Base * volatile, Base *, Derived>(); |
138 | assert_catches<const volatile Base * volatile, Base *, Derived>(); |
139 | assert_catches< Base * const volatile, Base *, Derived>(); |
140 | assert_catches<const Base * const volatile, Base *, Derived>(); |
141 | assert_catches< volatile Base * const volatile, Base *, Derived>(); |
142 | assert_catches<const volatile Base * const volatile, Base *, Derived>(); |
143 | } |
144 | |
145 | void f3() |
146 | { |
147 | // Test that every combination of handler of type: |
148 | // cv1 Derived * cv2 |
149 | // catches an exception of type: |
150 | // Derived * |
151 | assert_catches< Derived * , Derived *, Derived>(); |
152 | assert_catches<const Derived * , Derived *, Derived>(); |
153 | assert_catches< volatile Derived * , Derived *, Derived>(); |
154 | assert_catches<const volatile Derived * , Derived *, Derived>(); |
155 | assert_catches< Derived * const , Derived *, Derived>(); |
156 | assert_catches<const Derived * const , Derived *, Derived>(); |
157 | assert_catches< volatile Derived * const , Derived *, Derived>(); |
158 | assert_catches<const volatile Derived * const , Derived *, Derived>(); |
159 | assert_catches< Derived * volatile, Derived *, Derived>(); |
160 | assert_catches<const Derived * volatile, Derived *, Derived>(); |
161 | assert_catches< volatile Derived * volatile, Derived *, Derived>(); |
162 | assert_catches<const volatile Derived * volatile, Derived *, Derived>(); |
163 | assert_catches< Derived * const volatile, Derived *, Derived>(); |
164 | assert_catches<const Derived * const volatile, Derived *, Derived>(); |
165 | assert_catches< volatile Derived * const volatile, Derived *, Derived>(); |
166 | assert_catches<const volatile Derived * const volatile, Derived *, Derived>(); |
167 | } |
168 | |
169 | void f4() |
170 | { |
171 | // Test that every combination of handler of type: |
172 | // cv1 Derived * cv2 |
173 | // cannot catch an exception of type: |
174 | // Base * |
175 | assert_cannot_catch< Derived * , Base *, Derived>(); |
176 | assert_cannot_catch<const Derived * , Base *, Derived>(); |
177 | assert_cannot_catch< volatile Derived * , Base *, Derived>(); |
178 | assert_cannot_catch<const volatile Derived * , Base *, Derived>(); |
179 | assert_cannot_catch< Derived * const , Base *, Derived>(); |
180 | assert_cannot_catch<const Derived * const , Base *, Derived>(); |
181 | assert_cannot_catch< volatile Derived * const , Base *, Derived>(); |
182 | assert_cannot_catch<const volatile Derived * const , Base *, Derived>(); |
183 | assert_cannot_catch< Derived * volatile, Base *, Derived>(); |
184 | assert_cannot_catch<const Derived * volatile, Base *, Derived>(); |
185 | assert_cannot_catch< volatile Derived * volatile, Base *, Derived>(); |
186 | assert_cannot_catch<const volatile Derived * volatile, Base *, Derived>(); |
187 | assert_cannot_catch< Derived * const volatile, Base *, Derived>(); |
188 | assert_cannot_catch<const Derived * const volatile, Base *, Derived>(); |
189 | assert_cannot_catch< volatile Derived * const volatile, Base *, Derived>(); |
190 | assert_cannot_catch<const volatile Derived * const volatile, Base *, Derived>(); |
191 | } |
192 | |
193 | void f5() |
194 | { |
195 | // Test that every combination of handler of type: |
196 | // cv1 Derived * cv2 & |
197 | // catches an exception of type: |
198 | // Derived * |
199 | assert_catches< Derived * &, Derived *, Derived>(); |
200 | assert_catches<const Derived * &, Derived *, Derived>(); |
201 | assert_catches< volatile Derived * &, Derived *, Derived>(); |
202 | assert_catches<const volatile Derived * &, Derived *, Derived>(); |
203 | assert_catches< Derived * const &, Derived *, Derived>(); |
204 | assert_catches<const Derived * const &, Derived *, Derived>(); |
205 | assert_catches< volatile Derived * const &, Derived *, Derived>(); |
206 | assert_catches<const volatile Derived * const &, Derived *, Derived>(); |
207 | assert_catches< Derived * volatile &, Derived *, Derived>(); |
208 | assert_catches<const Derived * volatile &, Derived *, Derived>(); |
209 | assert_catches< volatile Derived * volatile &, Derived *, Derived>(); |
210 | assert_catches<const volatile Derived * volatile &, Derived *, Derived>(); |
211 | assert_catches< Derived * const volatile &, Derived *, Derived>(); |
212 | assert_catches<const Derived * const volatile &, Derived *, Derived>(); |
213 | assert_catches< volatile Derived * const volatile &, Derived *, Derived>(); |
214 | assert_catches<const volatile Derived * const volatile &, Derived *, Derived>(); |
215 | } |
216 | |
217 | void f6() |
218 | { |
219 | // Test that every combination of handler of type: |
220 | // cv1 Base * cv2 & |
221 | // catches an exception of type: |
222 | // Base * |
223 | assert_catches< Base * &, Base *, Derived>(); |
224 | assert_catches<const Base * &, Base *, Derived>(); |
225 | assert_catches< volatile Base * &, Base *, Derived>(); |
226 | assert_catches<const volatile Base * &, Base *, Derived>(); |
227 | assert_catches< Base * const &, Base *, Derived>(); |
228 | assert_catches<const Base * const &, Base *, Derived>(); |
229 | assert_catches< volatile Base * const &, Base *, Derived>(); |
230 | assert_catches<const volatile Base * const &, Base *, Derived>(); |
231 | assert_catches< Base * volatile &, Base *, Derived>(); |
232 | assert_catches<const Base * volatile &, Base *, Derived>(); |
233 | assert_catches< volatile Base * volatile &, Base *, Derived>(); |
234 | assert_catches<const volatile Base * volatile &, Base *, Derived>(); |
235 | assert_catches< Base * const volatile &, Base *, Derived>(); |
236 | assert_catches<const Base * const volatile &, Base *, Derived>(); |
237 | assert_catches< volatile Base * const volatile &, Base *, Derived>(); |
238 | assert_catches<const volatile Base * const volatile &, Base *, Derived>(); |
239 | |
240 | } |
241 | |
242 | void f7() |
243 | { |
244 | // Test that every combination of handler of type: |
245 | // cv1 Derived * cv2 & |
246 | // cannot catch an exception of type: |
247 | // Base * |
248 | assert_cannot_catch< Derived * &, Base *, Derived>(); |
249 | assert_cannot_catch<const Derived * &, Base *, Derived>(); |
250 | assert_cannot_catch< volatile Derived * &, Base *, Derived>(); |
251 | assert_cannot_catch<const volatile Derived * &, Base *, Derived>(); |
252 | assert_cannot_catch< Derived * const &, Base *, Derived>(); |
253 | assert_cannot_catch<const Derived * const &, Base *, Derived>(); |
254 | assert_cannot_catch< volatile Derived * const &, Base *, Derived>(); |
255 | assert_cannot_catch<const volatile Derived * const &, Base *, Derived>(); |
256 | assert_cannot_catch< Derived * volatile &, Base *, Derived>(); |
257 | assert_cannot_catch<const Derived * volatile &, Base *, Derived>(); |
258 | assert_cannot_catch< volatile Derived * volatile &, Base *, Derived>(); |
259 | assert_cannot_catch<const volatile Derived * volatile &, Base *, Derived>(); |
260 | assert_cannot_catch< Derived * const volatile &, Base *, Derived>(); |
261 | assert_cannot_catch<const Derived * const volatile &, Base *, Derived>(); |
262 | assert_cannot_catch< volatile Derived * const volatile &, Base *, Derived>(); |
263 | assert_cannot_catch<const volatile Derived * const volatile &, Base *, Derived>(); |
264 | } |
265 | |
266 | void f8() |
267 | { |
268 | // This test case has a caveat noted in the discussion here: |
269 | // https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html |
270 | // Specifically: |
271 | // This [test exposes a] corner case of the ARM C++ ABI. The generic C++ |
272 | // ABI also gets this wrong, because I failed to notice the subtlety here. |
273 | // The issue is that 15.3/3 3rd bullet says: |
274 | // The handler is of type cv1 T* cv2 and E is a pointer type that |
275 | // can be converted to the type of the handler by either or both of: |
276 | // * a standard pointer conversion (4.10) not involving conversions |
277 | // to pointers to private or protected or ambiguous classes |
278 | // Notice that the handlers of type "cv1 T*cv2&" are not allowed such |
279 | // freedom to find a base class. The ABI error is that we treat handlers |
280 | // of reference type exactly the same as the corresponding hander of |
281 | // non-reference type. Elsewhere in the exception handling this makes no |
282 | // difference (for instance bullet 1 explicitly says 'cv T or cv T&'). |
283 | // |
284 | // See also: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#388 |
285 | // |
286 | // TL;DR: it is an unresolved C++ ABI defect that these do catch |
287 | |
288 | // Test that every combination of handler of type: |
289 | // cv1 Base * cv2 & |
290 | // catches an exception of type: |
291 | // Derived * |
292 | assert_catches< Base * &, Derived *, Derived>(); |
293 | assert_catches<const Base * &, Derived *, Derived>(); |
294 | assert_catches< volatile Base * &, Derived *, Derived>(); |
295 | assert_catches<const volatile Base * &, Derived *, Derived>(); |
296 | assert_catches< Base * const &, Derived *, Derived>(); |
297 | assert_catches<const Base * const &, Derived *, Derived>(); |
298 | assert_catches< volatile Base * const &, Derived *, Derived>(); |
299 | assert_catches<const volatile Base * const &, Derived *, Derived>(); |
300 | assert_catches< Base * volatile &, Derived *, Derived>(); |
301 | assert_catches<const Base * volatile &, Derived *, Derived>(); |
302 | assert_catches< volatile Base * volatile &, Derived *, Derived>(); |
303 | assert_catches<const volatile Base * volatile &, Derived *, Derived>(); |
304 | assert_catches< Base * const volatile &, Derived *, Derived>(); |
305 | assert_catches<const Base * const volatile &, Derived *, Derived>(); |
306 | assert_catches< volatile Base * const volatile &, Derived *, Derived>(); |
307 | assert_catches<const volatile Base * const volatile &, Derived *, Derived>(); |
308 | } |
309 | |
310 | void f9() |
311 | { |
312 | // Test that every combination of handler of type: |
313 | // cv1 Base * cv2 |
314 | // cannot catch an exception of type: |
315 | // Ambiguous * |
316 | assert_cannot_catch< Base * , Ambiguous *, Ambiguous>(); |
317 | assert_cannot_catch<const Base * , Ambiguous *, Ambiguous>(); |
318 | assert_cannot_catch< volatile Base * , Ambiguous *, Ambiguous>(); |
319 | assert_cannot_catch<const volatile Base * , Ambiguous *, Ambiguous>(); |
320 | assert_cannot_catch< Base * const , Ambiguous *, Ambiguous>(); |
321 | assert_cannot_catch<const Base * const , Ambiguous *, Ambiguous>(); |
322 | assert_cannot_catch< volatile Base * const , Ambiguous *, Ambiguous>(); |
323 | assert_cannot_catch<const volatile Base * const , Ambiguous *, Ambiguous>(); |
324 | assert_cannot_catch< Base * volatile, Ambiguous *, Ambiguous>(); |
325 | assert_cannot_catch<const Base * volatile, Ambiguous *, Ambiguous>(); |
326 | assert_cannot_catch< volatile Base * volatile, Ambiguous *, Ambiguous>(); |
327 | assert_cannot_catch<const volatile Base * volatile, Ambiguous *, Ambiguous>(); |
328 | assert_cannot_catch< Base * const volatile, Ambiguous *, Ambiguous>(); |
329 | assert_cannot_catch<const Base * const volatile, Ambiguous *, Ambiguous>(); |
330 | assert_cannot_catch< volatile Base * const volatile, Ambiguous *, Ambiguous>(); |
331 | assert_cannot_catch<const volatile Base * const volatile, Ambiguous *, Ambiguous>(); |
332 | } |
333 | |
334 | void f10() |
335 | { |
336 | // Test that every combination of handler of type: |
337 | // cv1 Base * cv2 |
338 | // cannot catch an exception of type: |
339 | // Private * |
340 | assert_cannot_catch< Base * , Private *, Private>(); |
341 | assert_cannot_catch<const Base * , Private *, Private>(); |
342 | assert_cannot_catch< volatile Base * , Private *, Private>(); |
343 | assert_cannot_catch<const volatile Base * , Private *, Private>(); |
344 | assert_cannot_catch< Base * const , Private *, Private>(); |
345 | assert_cannot_catch<const Base * const , Private *, Private>(); |
346 | assert_cannot_catch< volatile Base * const , Private *, Private>(); |
347 | assert_cannot_catch<const volatile Base * const , Private *, Private>(); |
348 | assert_cannot_catch< Base * volatile, Private *, Private>(); |
349 | assert_cannot_catch<const Base * volatile, Private *, Private>(); |
350 | assert_cannot_catch< volatile Base * volatile, Private *, Private>(); |
351 | assert_cannot_catch<const volatile Base * volatile, Private *, Private>(); |
352 | assert_cannot_catch< Base * const volatile, Private *, Private>(); |
353 | assert_cannot_catch<const Base * const volatile, Private *, Private>(); |
354 | assert_cannot_catch< volatile Base * const volatile, Private *, Private>(); |
355 | assert_cannot_catch<const volatile Base * const volatile, Private *, Private>(); |
356 | } |
357 | |
358 | void f11() |
359 | { |
360 | // Test that every combination of handler of type: |
361 | // cv1 Base * cv2 |
362 | // cannot catch an exception of type: |
363 | // Protected * |
364 | assert_cannot_catch< Base * , Protected *, Protected>(); |
365 | assert_cannot_catch<const Base * , Protected *, Protected>(); |
366 | assert_cannot_catch< volatile Base * , Protected *, Protected>(); |
367 | assert_cannot_catch<const volatile Base * , Protected *, Protected>(); |
368 | assert_cannot_catch< Base * const , Protected *, Protected>(); |
369 | assert_cannot_catch<const Base * const , Protected *, Protected>(); |
370 | assert_cannot_catch< volatile Base * const , Protected *, Protected>(); |
371 | assert_cannot_catch<const volatile Base * const , Protected *, Protected>(); |
372 | assert_cannot_catch< Base * volatile, Protected *, Protected>(); |
373 | assert_cannot_catch<const Base * volatile, Protected *, Protected>(); |
374 | assert_cannot_catch< volatile Base * volatile, Protected *, Protected>(); |
375 | assert_cannot_catch<const volatile Base * volatile, Protected *, Protected>(); |
376 | assert_cannot_catch< Base * const volatile, Protected *, Protected>(); |
377 | assert_cannot_catch<const Base * const volatile, Protected *, Protected>(); |
378 | assert_cannot_catch< volatile Base * const volatile, Protected *, Protected>(); |
379 | assert_cannot_catch<const volatile Base * const volatile, Protected *, Protected>(); |
380 | } |
381 | |
382 | void f12() |
383 | { |
384 | // Test that every combination of handler of type: |
385 | // cv1 Base * cv2 & |
386 | // cannot catch an exception of type: |
387 | // Private * |
388 | assert_cannot_catch< Base * &, Private *, Private>(); |
389 | assert_cannot_catch<const Base * &, Private *, Private>(); |
390 | assert_cannot_catch< volatile Base * &, Private *, Private>(); |
391 | assert_cannot_catch<const volatile Base * &, Private *, Private>(); |
392 | assert_cannot_catch< Base * const &, Private *, Private>(); |
393 | assert_cannot_catch<const Base * const &, Private *, Private>(); |
394 | assert_cannot_catch< volatile Base * const &, Private *, Private>(); |
395 | assert_cannot_catch<const volatile Base * const &, Private *, Private>(); |
396 | assert_cannot_catch< Base * volatile &, Private *, Private>(); |
397 | assert_cannot_catch<const Base * volatile &, Private *, Private>(); |
398 | assert_cannot_catch< volatile Base * volatile &, Private *, Private>(); |
399 | assert_cannot_catch<const volatile Base * volatile &, Private *, Private>(); |
400 | assert_cannot_catch< Base * const volatile &, Private *, Private>(); |
401 | assert_cannot_catch<const Base * const volatile &, Private *, Private>(); |
402 | assert_cannot_catch< volatile Base * const volatile &, Private *, Private>(); |
403 | assert_cannot_catch<const volatile Base * const volatile &, Private *, Private>(); |
404 | } |
405 | |
406 | void f13() |
407 | { |
408 | // Test that every combination of handler of type: |
409 | // cv1 Base * cv2 & |
410 | // cannot catch an exception of type: |
411 | // Protected * |
412 | assert_cannot_catch< Base * &, Protected *, Protected>(); |
413 | assert_cannot_catch<const Base * &, Protected *, Protected>(); |
414 | assert_cannot_catch< volatile Base * &, Protected *, Protected>(); |
415 | assert_cannot_catch<const volatile Base * &, Protected *, Protected>(); |
416 | assert_cannot_catch< Base * const &, Protected *, Protected>(); |
417 | assert_cannot_catch<const Base * const &, Protected *, Protected>(); |
418 | assert_cannot_catch< volatile Base * const &, Protected *, Protected>(); |
419 | assert_cannot_catch<const volatile Base * const &, Protected *, Protected>(); |
420 | assert_cannot_catch< Base * volatile &, Protected *, Protected>(); |
421 | assert_cannot_catch<const Base * volatile &, Protected *, Protected>(); |
422 | assert_cannot_catch< volatile Base * volatile &, Protected *, Protected>(); |
423 | assert_cannot_catch<const volatile Base * volatile &, Protected *, Protected>(); |
424 | assert_cannot_catch< Base * const volatile &, Protected *, Protected>(); |
425 | assert_cannot_catch<const Base * const volatile &, Protected *, Protected>(); |
426 | assert_cannot_catch< volatile Base * const volatile &, Protected *, Protected>(); |
427 | assert_cannot_catch<const volatile Base * const volatile &, Protected *, Protected>(); |
428 | } |
429 | |
430 | int main(int, char**) |
431 | { |
432 | f1(); |
433 | f2(); |
434 | f3(); |
435 | f4(); |
436 | f5(); |
437 | f6(); |
438 | f7(); |
439 | f8(); |
440 | f9(); |
441 | f10(); |
442 | f11(); |
443 | f12(); |
444 | f13(); |
445 | |
446 | return 0; |
447 | } |
448 | |