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 };
~A_ShouldDiag()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;
~B_ShouldDiagB_ShouldDiag10   ~B_ShouldDiag() noexcept(true) {} //no disg, no throw stmt
11 };
12 struct R_ShouldDiag : A_ShouldDiag {
13   B_ShouldDiag b;
~R_ShouldDiagR_ShouldDiag14   ~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   }
R_ShouldDiagR_ShouldDiag17   __attribute__((nothrow)) R_ShouldDiag() {// expected-note {{function declared non-throwing here}}
18     throw 1;// expected-warning {{has a non-throwing exception specification but}}
19   }
SomeThrowR_ShouldDiag20   void __attribute__((nothrow)) SomeThrow() {// expected-note {{function declared non-throwing here}}
21    throw 1; // expected-warning {{has a non-throwing exception specification but}}
22   }
SomeDeclspecThrowR_ShouldDiag23   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 
~M_ShouldNotDiag()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 
~N_ShouldDiag()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;
~X_ShouldDiagX_ShouldDiag47   ~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 {
~Y_ShouldDiagY_ShouldDiag52   ~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;
~C_ShouldNotDiagC_ShouldNotDiag58   ~C_ShouldNotDiag() noexcept(false) {}
59 };
60 struct D_ShouldNotDiag {
61   C_ShouldNotDiag c;
~D_ShouldNotDiagD_ShouldNotDiag62   ~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 };
~E_ShouldNotDiag()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:
~A1_ShouldDiag()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;
~B1_ShouldDiagB1_ShouldDiag87   ~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;
~R1_ShouldDiagR1_ShouldDiag93   ~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;
~S1_ShouldDiagS1_ShouldDiag100   ~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 };
operator delete(void * ptr)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 {
~dependent_warndependent_warn115   ~dependent_warn() noexcept(T::i) {
116     throw 1;
117   }
118 };
119 template <typename T>
120 struct dependent_warn_noexcept {
~dependent_warn_noexceptdependent_warn_noexcept121   ~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 {
~dependent_warn_bothdependent_warn_both127   ~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 };
foo()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;
~ShouldDiagnoseShouldDiagnose140   ~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;
~ShouldNotDiagnoseShouldNotDiagnose146   ~ShouldNotDiagnose() {
147     throw;
148   }
149 };
150 
bar_ShouldNotDiag()151 void bar_ShouldNotDiag() noexcept {
152   try {
153     throw 1;
154   } catch (...) {
155   }
156 }
f_ShouldNotDiag()157 void f_ShouldNotDiag() noexcept {
158   try {
159     throw 12;
160   } catch (int) {
161   }
162 }
g_ShouldNotDiag()163 void g_ShouldNotDiag() noexcept {
164   try {
165     throw 12;
166   } catch (...) {
167   }
168 }
169 
h_ShouldDiag()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 
i_ShouldDiag()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 }
j_ShouldDiag()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 
k_ShouldDiag()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 
loo_ShouldDiag(int i)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 
loo1_ShouldNotDiag()210 void loo1_ShouldNotDiag() noexcept {
211   if (0)
212     throw 12;
213 }
214 
loo2_ShouldDiag()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 
l_ShouldDiag()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 
m_ShouldNotDiag()228 void m_ShouldNotDiag() noexcept {
229   try {
230     const S &s = S{};
231     throw s;
232   } catch (S s) {
233   }
234 }
n_ShouldNotDiag()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.
o_ShouldNotDiag()244 void o_ShouldNotDiag() noexcept {
245   try {
246     throw;
247   } catch (...) {
248   }
249 }
250 
p_ShouldNotDiag()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 
q_ShouldNotDiag()260 void q_ShouldNotDiag() noexcept {
261   try {
262     throw;
263   } catch (int){
264   } catch (...){
265   }
266 }
267 
268 #define NOEXCEPT noexcept
with_macro()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 
with_try_block()273 void with_try_block() try {
274   throw 2;
275 } catch (...) {
276 }
277 
with_try_block1()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 {};
goodPlain()286 void goodPlain() noexcept {
287   try {
288     throw D();
289   } catch (B) {}
290 }
goodReference()291 void goodReference() noexcept {
292   try {
293     throw D();
294   } catch (B &) {}
295 }
goodPointer()296 void goodPointer() noexcept {
297   D d;
298   try {
299     throw &d;
300   } catch (B *) {}
301 }
badPlain()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 }
badReference()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 }
badPointer()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 
main()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   }
run()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 
good()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 
bad1()374   void bad1() throw() { // expected-note {{here}}
375     try { throw A(); } catch (const B&) {} // expected-warning {{still throw}}
376   }
bad2()377   void bad2() throw() { // expected-note {{here}}
378     try { throw AmbigDerived(); } catch (const AmbigBase&) {} // expected-warning {{still throw}}
379   }
bad3()380   void bad3() throw() { // expected-note {{here}}
381     try { throw PrivateDerived(); } catch (const PrivateBase&) {} // expected-warning {{still throw}}
382   }
bad4()383   void bad4() throw() { // expected-note {{here}}
384     try { throw (int*)0; } catch (void* &) {} // expected-warning {{still throw}}
385   }
bad5()386   void bad5() throw() { // expected-note {{here}}
387     try { throw (int*)0; } catch (void* const volatile &) {} // expected-warning {{still throw}}
388   }
bad6()389   void bad6() throw() { // expected-note {{here}}
390     try { throw (int* volatile)0; } catch (void* const volatile &) {} // expected-warning {{still throw}}
391   }
bad7()392   void bad7() throw() { // expected-note {{here}}
393     try { throw (AmbigDerived*)0; } catch (AmbigBase*) {} // expected-warning {{still throw}}
394   }
bad8()395   void bad8() throw() { // expected-note {{here}}
396     try { throw (PrivateDerived*)0; } catch (PrivateBase*) {} // expected-warning {{still throw}}
397   }
bad9()398   void bad9() throw() { // expected-note {{here}}
399     try { throw (B*)0; } catch (A* &) {} // expected-warning {{still throw}}
400   }
bad10()401   void bad10() throw() { // expected-note {{here}}
402     try { throw (void(*)())0; } catch (void (*)() noexcept) {} // expected-warning {{still throw}}
403   }
bad11()404   void bad11() throw() { // expected-note {{here}}
405     try { throw (int**)0; } catch (const int **) {} // expected-warning {{still throw}}
406   }
bad12()407   void bad12() throw() { // expected-note {{here}}
408     try { throw nullptr; } catch (int) {} // expected-warning {{still throw}}
409   }
410 }
411 
412 namespace NestedTry {
f()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 
g()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 
h()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.
i()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.
j()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