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()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 } 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()33M_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()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 } 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()70E_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)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 } 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()131void 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()151void bar_ShouldNotDiag() noexcept { 152 try { 153 throw 1; 154 } catch (...) { 155 } 156 } f_ShouldNotDiag()157void f_ShouldNotDiag() noexcept { 158 try { 159 throw 12; 160 } catch (int) { 161 } 162 } g_ShouldNotDiag()163void g_ShouldNotDiag() noexcept { 164 try { 165 throw 12; 166 } catch (...) { 167 } 168 } 169 h_ShouldDiag()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 i_ShouldDiag()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 } j_ShouldDiag()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 k_ShouldDiag()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 loo_ShouldDiag(int i)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 loo1_ShouldNotDiag()210void loo1_ShouldNotDiag() noexcept { 211 if (0) 212 throw 12; 213 } 214 loo2_ShouldDiag()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 } 219 struct S {}; 220 l_ShouldDiag()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 m_ShouldNotDiag()228void m_ShouldNotDiag() noexcept { 229 try { 230 const S &s = S{}; 231 throw s; 232 } catch (S s) { 233 } 234 } n_ShouldNotDiag()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. o_ShouldNotDiag()244void o_ShouldNotDiag() noexcept { 245 try { 246 throw; 247 } catch (...) { 248 } 249 } 250 p_ShouldNotDiag()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 q_ShouldNotDiag()260void q_ShouldNotDiag() noexcept { 261 try { 262 throw; 263 } catch (int){ 264 } catch (...){ 265 } 266 } 267 268 #define NOEXCEPT noexcept with_macro()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 with_try_block()273void with_try_block() try { 274 throw 2; 275 } catch (...) { 276 } 277 with_try_block1()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 283 namespace derived { 284 struct B {}; 285 struct D: B {}; goodPlain()286void goodPlain() noexcept { 287 try { 288 throw D(); 289 } catch (B) {} 290 } goodReference()291void goodReference() noexcept { 292 try { 293 throw D(); 294 } catch (B &) {} 295 } goodPointer()296void goodPointer() noexcept { 297 D d; 298 try { 299 throw &d; 300 } catch (B *) {} 301 } badPlain()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 } badReference()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 } badPointer()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 main()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 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