Clang Project

clang_source_code/test/SemaCXX/warn-throw-out-noexcept-func.cpp
1// RUN: %clang_cc1 %s  -fdelayed-template-parsing -fcxx-exceptions -fsyntax-only -Wexceptions -verify -fdeclspec -std=c++17
2struct A_ShouldDiag {
3  ~A_ShouldDiag(); // implicitly noexcept(true)
4};
5A_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}
8struct B_ShouldDiag {
9  int i;
10  ~B_ShouldDiag() noexcept(true) {} //no disg, no throw stmt
11};
12struct 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
28struct M_ShouldNotDiag {
29  B_ShouldDiag b;
30  ~M_ShouldNotDiag() noexcept(false);
31};
32
33M_ShouldNotDiag::~M_ShouldNotDiag() noexcept(false) {
34  throw 1;
35}
36
37struct N_ShouldDiag {
38  B_ShouldDiag b;
39  ~N_ShouldDiag(); //implicitly noexcept(true)
40};
41
42N_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}
45struct 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};
51struct 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};
56struct C_ShouldNotDiag {
57  int i;
58  ~C_ShouldNotDiag() noexcept(false) {}
59};
60struct D_ShouldNotDiag {
61  C_ShouldNotDiag c;
62  ~D_ShouldNotDiag() { //implicitly noexcept(false)
63    throw 1;
64  }
65};
66struct E_ShouldNotDiag {
67  C_ShouldNotDiag c;
68  ~E_ShouldNotDiag(); //implicitly noexcept(false)
69};
70E_ShouldNotDiag::~E_ShouldNotDiag() //implicitly noexcept(false)
71{
72  throw 1;
73}
74
75template <typename T>
76class A1_ShouldDiag {
77  T b;
78
79public:
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};
84template <typename T>
85struct B1_ShouldDiag {
86  T i;
87  ~B1_ShouldDiag() noexcept(true) {}
88};
89template <typename T>
90struct 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};
97template <typename T>
98struct 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};
104void 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}
107struct except_fun {
108  static const bool i = false;
109};
110struct noexcept_fun {
111  static const bool i = true;
112};
113template <typename T>
114struct dependent_warn {
115  ~dependent_warn() noexcept(T::i) {
116    throw 1;
117  }
118};
119template <typename T>
120struct 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};
125template <typename T>
126struct 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};
131void foo() noexcept { //expected-note {{function declared non-throwing here}}
132  throw 1; // expected-warning {{has a non-throwing exception specification but}}
133}
134struct Throws {
135  ~Throws() noexcept(false);
136};
137
138struct 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};
144struct ShouldNotDiagnose {
145  Throws T;
146  ~ShouldNotDiagnose() {
147    throw;
148  }
149};
150
151void bar_ShouldNotDiag() noexcept {
152  try {
153    throw 1;
154  } catch (...) {
155  }
156}
157void f_ShouldNotDiag() noexcept {
158  try {
159    throw 12;
160  } catch (int) {
161  }
162}
163void g_ShouldNotDiag() noexcept {
164  try {
165    throw 12;
166  } catch (...) {
167  }
168}
169
170void 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
177void 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}
184void 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
192void 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
200void 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
210void loo1_ShouldNotDiag() noexcept {
211  if (0)
212    throw 12;
213}
214
215void 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}
219struct S {};
220
221void 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
228void m_ShouldNotDiag() noexcept {
229  try {
230    const S &s = S{};
231    throw s;
232  } catch (S s) {
233  }
234}
235void 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. 
244void o_ShouldNotDiag() noexcept {
245  try {
246    throw;
247  } catch (...) {
248  }
249}
250
251void 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
260void q_ShouldNotDiag() noexcept {
261  try {
262    throw;
263  } catch (int){
264  } catch (...){
265  }
266}
267
268#define NOEXCEPT noexcept
269void with_macro() NOEXCEPT { //expected-note {{function declared non-throwing here}}
270  throw 1; // expected-warning {{has a non-throwing exception specification but}}
271}
272
273void with_try_block() try {
274  throw 2;
275} catch (...) {
276}
277
278void 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
283namespace derived {
284struct B {};
285struct D: B {};
286void goodPlain() noexcept {
287  try {
288    throw D();
289  } catch (B) {}
290}
291void goodReference() noexcept {
292  try {
293    throw D();
294  } catch (B &) {}
295}
296void goodPointer() noexcept {
297  D d;
298  try {
299    throw &d;
300  } catch (B *) {}
301}
302void 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}
307void 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}
312void 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
320int 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
331namespace 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
343namespace 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
412namespace 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