1 | // RUN: %clang_cc1 %s -fdelayed-template-parsing -fcxx-exceptions -fsyntax-only -Wexceptions -verify -fdeclspec -std=c++17 |
2 | struct A_ShouldDiag { |
3 | ~A_ShouldDiag(); // implicitly noexcept(true) |
4 | }; |
5 | A_ShouldDiag::~A_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} |
6 | throw 1; // expected-warning {{has a non-throwing exception specification but can still throw}} |
7 | } |
8 | struct B_ShouldDiag { |
9 | int i; |
10 | ~B_ShouldDiag() noexcept(true) {} //no disg, no throw stmt |
11 | }; |
12 | struct R_ShouldDiag : A_ShouldDiag { |
13 | B_ShouldDiag b; |
14 | ~R_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} |
15 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
16 | } |
17 | __attribute__((nothrow)) R_ShouldDiag() {// expected-note {{function declared non-throwing here}} |
18 | throw 1;// expected-warning {{has a non-throwing exception specification but}} |
19 | } |
20 | void __attribute__((nothrow)) SomeThrow() {// expected-note {{function declared non-throwing here}} |
21 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
22 | } |
23 | void __declspec(nothrow) SomeDeclspecThrow() {// expected-note {{function declared non-throwing here}} |
24 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
25 | } |
26 | }; |
27 | |
28 | struct M_ShouldNotDiag { |
29 | B_ShouldDiag b; |
30 | ~M_ShouldNotDiag() noexcept(false); |
31 | }; |
32 | |
33 | M_ShouldNotDiag::~M_ShouldNotDiag() noexcept(false) { |
34 | throw 1; |
35 | } |
36 | |
37 | struct N_ShouldDiag { |
38 | B_ShouldDiag b; |
39 | ~N_ShouldDiag(); //implicitly noexcept(true) |
40 | }; |
41 | |
42 | N_ShouldDiag::~N_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} |
43 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
44 | } |
45 | struct X_ShouldDiag { |
46 | B_ShouldDiag b; |
47 | ~X_ShouldDiag() noexcept { // expected-note {{destructor has a non-throwing exception}} |
48 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
49 | } |
50 | }; |
51 | struct Y_ShouldDiag : A_ShouldDiag { |
52 | ~Y_ShouldDiag() noexcept(true) { // expected-note {{destructor has a non-throwing exception specification}} |
53 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
54 | } |
55 | }; |
56 | struct C_ShouldNotDiag { |
57 | int i; |
58 | ~C_ShouldNotDiag() noexcept(false) {} |
59 | }; |
60 | struct D_ShouldNotDiag { |
61 | C_ShouldNotDiag c; |
62 | ~D_ShouldNotDiag() { //implicitly noexcept(false) |
63 | throw 1; |
64 | } |
65 | }; |
66 | struct E_ShouldNotDiag { |
67 | C_ShouldNotDiag c; |
68 | ~E_ShouldNotDiag(); //implicitly noexcept(false) |
69 | }; |
70 | E_ShouldNotDiag::~E_ShouldNotDiag() //implicitly noexcept(false) |
71 | { |
72 | throw 1; |
73 | } |
74 | |
75 | template <typename T> |
76 | class A1_ShouldDiag { |
77 | T b; |
78 | |
79 | public: |
80 | ~A1_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} |
81 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
82 | } |
83 | }; |
84 | template <typename T> |
85 | struct B1_ShouldDiag { |
86 | T i; |
87 | ~B1_ShouldDiag() noexcept(true) {} |
88 | }; |
89 | template <typename T> |
90 | struct R1_ShouldDiag : A1_ShouldDiag<T> //expected-note {{in instantiation of member function}} |
91 | { |
92 | B1_ShouldDiag<T> b; |
93 | ~R1_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} |
94 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
95 | } |
96 | }; |
97 | template <typename T> |
98 | struct S1_ShouldDiag : A1_ShouldDiag<T> { |
99 | B1_ShouldDiag<T> b; |
100 | ~S1_ShouldDiag() noexcept { // expected-note {{destructor has a non-throwing exception specification}} |
101 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
102 | } |
103 | }; |
104 | void operator delete(void *ptr) noexcept { // expected-note {{deallocator has a non-throwing exception specification}} |
105 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
106 | } |
107 | struct except_fun { |
108 | static const bool i = false; |
109 | }; |
110 | struct noexcept_fun { |
111 | static const bool i = true; |
112 | }; |
113 | template <typename T> |
114 | struct dependent_warn { |
115 | ~dependent_warn() noexcept(T::i) { |
116 | throw 1; |
117 | } |
118 | }; |
119 | template <typename T> |
120 | struct dependent_warn_noexcept { |
121 | ~dependent_warn_noexcept() noexcept(T::i) { // expected-note {{destructor has a non-throwing exception specification}} |
122 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
123 | } |
124 | }; |
125 | template <typename T> |
126 | struct dependent_warn_both { |
127 | ~dependent_warn_both() noexcept(T::i) { // expected-note {{destructor has a non-throwing exception specification}} |
128 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
129 | } |
130 | }; |
131 | void foo() noexcept { //expected-note {{function declared non-throwing here}} |
132 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
133 | } |
134 | struct Throws { |
135 | ~Throws() noexcept(false); |
136 | }; |
137 | |
138 | struct ShouldDiagnose { |
139 | Throws T; |
140 | ~ShouldDiagnose() noexcept { //expected-note {{destructor has a non-throwing exception specification}} |
141 | throw; // expected-warning {{has a non-throwing exception specification but}} |
142 | } |
143 | }; |
144 | struct ShouldNotDiagnose { |
145 | Throws T; |
146 | ~ShouldNotDiagnose() { |
147 | throw; |
148 | } |
149 | }; |
150 | |
151 | void bar_ShouldNotDiag() noexcept { |
152 | try { |
153 | throw 1; |
154 | } catch (...) { |
155 | } |
156 | } |
157 | void f_ShouldNotDiag() noexcept { |
158 | try { |
159 | throw 12; |
160 | } catch (int) { |
161 | } |
162 | } |
163 | void g_ShouldNotDiag() noexcept { |
164 | try { |
165 | throw 12; |
166 | } catch (...) { |
167 | } |
168 | } |
169 | |
170 | void h_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} |
171 | try { |
172 | throw 12; // expected-warning {{has a non-throwing exception specification but}} |
173 | } catch (const char *) { |
174 | } |
175 | } |
176 | |
177 | void i_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} |
178 | try { |
179 | throw 12; |
180 | } catch (int) { |
181 | throw; // expected-warning {{has a non-throwing exception specification but}} |
182 | } |
183 | } |
184 | void j_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} |
185 | try { |
186 | throw 12; |
187 | } catch (int) { |
188 | throw "haha"; // expected-warning {{has a non-throwing exception specification but}} |
189 | } |
190 | } |
191 | |
192 | void k_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} |
193 | try { |
194 | throw 12; |
195 | } catch (...) { |
196 | throw; // expected-warning {{has a non-throwing exception specification but}} |
197 | } |
198 | } |
199 | |
200 | void loo_ShouldDiag(int i) noexcept { //expected-note {{function declared non-throwing here}} |
201 | if (i) |
202 | try { |
203 | throw 12; |
204 | } catch (int) { |
205 | throw "haha"; //expected-warning {{has a non-throwing exception specification but}} |
206 | } |
207 | i = 10; |
208 | } |
209 | |
210 | void loo1_ShouldNotDiag() noexcept { |
211 | if (0) |
212 | throw 12; |
213 | } |
214 | |
215 | void loo2_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} |
216 | if (1) |
217 | throw 12; // expected-warning {{has a non-throwing exception specification but}} |
218 | } |
219 | struct S {}; |
220 | |
221 | void l_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} |
222 | try { |
223 | throw S{}; //expected-warning {{has a non-throwing exception specification but}} |
224 | } catch (S *s) { |
225 | } |
226 | } |
227 | |
228 | void m_ShouldNotDiag() noexcept { |
229 | try { |
230 | const S &s = S{}; |
231 | throw s; |
232 | } catch (S s) { |
233 | } |
234 | } |
235 | void n_ShouldNotDiag() noexcept { |
236 | try { |
237 | S s = S{}; |
238 | throw s; |
239 | } catch (const S &s) { |
240 | } |
241 | } |
242 | // As seen in p34973, this should not throw the warning. If there is an active |
243 | // exception, catch(...) catches everything. |
244 | void o_ShouldNotDiag() noexcept { |
245 | try { |
246 | throw; |
247 | } catch (...) { |
248 | } |
249 | } |
250 | |
251 | void p_ShouldNotDiag() noexcept { |
252 | // Don't warn here: it's possible that the user arranges to only call this |
253 | // when the active exception is of type 'int'. |
254 | try { |
255 | throw; |
256 | } catch (int){ |
257 | } |
258 | } |
259 | |
260 | void q_ShouldNotDiag() noexcept { |
261 | try { |
262 | throw; |
263 | } catch (int){ |
264 | } catch (...){ |
265 | } |
266 | } |
267 | |
268 | #define NOEXCEPT noexcept |
269 | void with_macro() NOEXCEPT { //expected-note {{function declared non-throwing here}} |
270 | throw 1; // expected-warning {{has a non-throwing exception specification but}} |
271 | } |
272 | |
273 | void with_try_block() try { |
274 | throw 2; |
275 | } catch (...) { |
276 | } |
277 | |
278 | void with_try_block1() noexcept try { //expected-note {{function declared non-throwing here}} |
279 | throw 2; // expected-warning {{has a non-throwing exception specification but}} |
280 | } catch (char *) { |
281 | } |
282 | |
283 | namespace derived { |
284 | struct B {}; |
285 | struct D: B {}; |
286 | void goodPlain() noexcept { |
287 | try { |
288 | throw D(); |
289 | } catch (B) {} |
290 | } |
291 | void goodReference() noexcept { |
292 | try { |
293 | throw D(); |
294 | } catch (B &) {} |
295 | } |
296 | void goodPointer() noexcept { |
297 | D d; |
298 | try { |
299 | throw &d; |
300 | } catch (B *) {} |
301 | } |
302 | void badPlain() noexcept { //expected-note {{function declared non-throwing here}} |
303 | try { |
304 | throw B(); // expected-warning {{'badPlain' has a non-throwing exception specification but can still throw}} |
305 | } catch (D) {} |
306 | } |
307 | void badReference() noexcept { //expected-note {{function declared non-throwing here}} |
308 | try { |
309 | throw B(); // expected-warning {{'badReference' has a non-throwing exception specification but can still throw}} |
310 | } catch (D &) {} |
311 | } |
312 | void badPointer() noexcept { //expected-note {{function declared non-throwing here}} |
313 | B b; |
314 | try { |
315 | throw &b; // expected-warning {{'badPointer' has a non-throwing exception specification but can still throw}} |
316 | } catch (D *) {} |
317 | } |
318 | } |
319 | |
320 | int main() { |
321 | R1_ShouldDiag<int> o; //expected-note {{in instantiation of member function}} |
322 | S1_ShouldDiag<int> b; //expected-note {{in instantiation of member function}} |
323 | dependent_warn<except_fun> f; |
324 | dependent_warn_noexcept<noexcept_fun> f1; //expected-note {{in instantiation of member function}} |
325 | dependent_warn_both<except_fun> f2; |
326 | dependent_warn_both<noexcept_fun> f3; //expected-note {{in instantiation of member function}} |
327 | ShouldDiagnose obj; |
328 | ShouldNotDiagnose obj1; |
329 | } |
330 | |
331 | namespace ExceptionInNamespace { |
332 | namespace N { |
333 | struct E {}; |
334 | } |
335 | void run() throw() { |
336 | try { |
337 | throw N::E(); |
338 | } catch (const N::E &e) { |
339 | } |
340 | } |
341 | } |
342 | |
343 | namespace HandlerSpecialCases { |
344 | struct A {}; |
345 | using CA = const A; |
346 | |
347 | struct B : A {}; |
348 | using CB = const B; |
349 | |
350 | struct AmbigBase {}; |
351 | struct AmbigMiddle : AmbigBase {}; |
352 | struct AmbigDerived : AmbigBase, AmbigMiddle {}; // expected-warning {{inaccessible}} |
353 | |
354 | struct PrivateBase {}; |
355 | struct PrivateDerived : private PrivateBase { friend void bad3() throw(); }; |
356 | |
357 | void good() throw() { |
358 | try { throw CA(); } catch (volatile A&) {} |
359 | try { throw B(); } catch (A&) {} |
360 | try { throw B(); } catch (const volatile A&) {} |
361 | try { throw CB(); } catch (A&) {} |
362 | try { throw (int*)0; } catch (void* const volatile) {} |
363 | try { throw (int*)0; } catch (void* const &) {} |
364 | try { throw (B*)0; } catch (A*) {} |
365 | try { throw (B*)0; } catch (A* const &) {} |
366 | try { throw (void(*)() noexcept)0; } catch (void (*)()) {} |
367 | try { throw (void(*)() noexcept)0; } catch (void (*const &)()) {} |
368 | try { throw (int**)0; } catch (const int * const*) {} |
369 | try { throw (int**)0; } catch (const int * const* const&) {} |
370 | try { throw nullptr; } catch (int*) {} |
371 | try { throw nullptr; } catch (int* const&) {} |
372 | } |
373 | |
374 | void bad1() throw() { // expected-note {{here}} |
375 | try { throw A(); } catch (const B&) {} // expected-warning {{still throw}} |
376 | } |
377 | void bad2() throw() { // expected-note {{here}} |
378 | try { throw AmbigDerived(); } catch (const AmbigBase&) {} // expected-warning {{still throw}} |
379 | } |
380 | void bad3() throw() { // expected-note {{here}} |
381 | try { throw PrivateDerived(); } catch (const PrivateBase&) {} // expected-warning {{still throw}} |
382 | } |
383 | void bad4() throw() { // expected-note {{here}} |
384 | try { throw (int*)0; } catch (void* &) {} // expected-warning {{still throw}} |
385 | } |
386 | void bad5() throw() { // expected-note {{here}} |
387 | try { throw (int*)0; } catch (void* const volatile &) {} // expected-warning {{still throw}} |
388 | } |
389 | void bad6() throw() { // expected-note {{here}} |
390 | try { throw (int* volatile)0; } catch (void* const volatile &) {} // expected-warning {{still throw}} |
391 | } |
392 | void bad7() throw() { // expected-note {{here}} |
393 | try { throw (AmbigDerived*)0; } catch (AmbigBase*) {} // expected-warning {{still throw}} |
394 | } |
395 | void bad8() throw() { // expected-note {{here}} |
396 | try { throw (PrivateDerived*)0; } catch (PrivateBase*) {} // expected-warning {{still throw}} |
397 | } |
398 | void bad9() throw() { // expected-note {{here}} |
399 | try { throw (B*)0; } catch (A* &) {} // expected-warning {{still throw}} |
400 | } |
401 | void bad10() throw() { // expected-note {{here}} |
402 | try { throw (void(*)())0; } catch (void (*)() noexcept) {} // expected-warning {{still throw}} |
403 | } |
404 | void bad11() throw() { // expected-note {{here}} |
405 | try { throw (int**)0; } catch (const int **) {} // expected-warning {{still throw}} |
406 | } |
407 | void bad12() throw() { // expected-note {{here}} |
408 | try { throw nullptr; } catch (int) {} // expected-warning {{still throw}} |
409 | } |
410 | } |
411 | |
412 | namespace NestedTry { |
413 | void f() noexcept { |
414 | try { |
415 | try { |
416 | throw 0; |
417 | } catch (float) {} |
418 | } catch (int) {} |
419 | } |
420 | |
421 | struct A { [[noreturn]] ~A(); }; |
422 | |
423 | void g() noexcept { // expected-note {{here}} |
424 | try { |
425 | try { |
426 | throw 0; // expected-warning {{still throw}} |
427 | } catch (float) {} |
428 | } catch (const char*) {} |
429 | } |
430 | |
431 | void h() noexcept { // expected-note {{here}} |
432 | try { |
433 | try { |
434 | throw 0; |
435 | } catch (float) {} |
436 | } catch (int) { |
437 | throw; // expected-warning {{still throw}} |
438 | } |
439 | } |
440 | |
441 | // FIXME: Ideally, this should still warn; we can track which types are |
442 | // potentially thrown by the rethrow. |
443 | void i() noexcept { |
444 | try { |
445 | try { |
446 | throw 0; |
447 | } catch (int) { |
448 | throw; |
449 | } |
450 | } catch (float) {} |
451 | } |
452 | |
453 | // FIXME: Ideally, this should not warn: the second catch block is |
454 | // unreachable. |
455 | void j() noexcept { // expected-note {{here}} |
456 | try { |
457 | try { |
458 | throw 0; |
459 | } catch (int) {} |
460 | } catch (float) { |
461 | throw; // expected-warning {{still throw}} |
462 | } |
463 | } |
464 | } |
465 | |