465 lines · cpp
1// RUN: %clang_cc1 %s -fdelayed-template-parsing -fcxx-exceptions -fsyntax-only -Wexceptions -verify -fdeclspec -std=c++172struct 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 stmt11};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 active243// 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 this253 // 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 noexcept269void 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 are442 // 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 is454 // 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