|  | // RUN: %clang_cc1 %s  -fdelayed-template-parsing -fcxx-exceptions -fsyntax-only -Wexceptions -verify -fdeclspec -std=c++17 | 
|  | struct A_ShouldDiag { | 
|  | ~A_ShouldDiag(); // implicitly noexcept(true) | 
|  | }; | 
|  | A_ShouldDiag::~A_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but can still throw}} | 
|  | } | 
|  | struct B_ShouldDiag { | 
|  | int i; | 
|  | ~B_ShouldDiag() noexcept(true) {} //no disg, no throw stmt | 
|  | }; | 
|  | struct R_ShouldDiag : A_ShouldDiag { | 
|  | B_ShouldDiag b; | 
|  | ~R_ShouldDiag() { // expected-note  {{destructor has a implicit non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | __attribute__((nothrow)) R_ShouldDiag() {// expected-note {{function declared non-throwing here}} | 
|  | throw 1;// expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | void __attribute__((nothrow)) SomeThrow() {// expected-note {{function declared non-throwing here}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | void __declspec(nothrow) SomeDeclspecThrow() {// expected-note {{function declared non-throwing here}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct M_ShouldNotDiag { | 
|  | B_ShouldDiag b; | 
|  | ~M_ShouldNotDiag() noexcept(false); | 
|  | }; | 
|  |  | 
|  | M_ShouldNotDiag::~M_ShouldNotDiag() noexcept(false) { | 
|  | throw 1; | 
|  | } | 
|  |  | 
|  | struct N_ShouldDiag { | 
|  | B_ShouldDiag b; | 
|  | ~N_ShouldDiag(); //implicitly noexcept(true) | 
|  | }; | 
|  |  | 
|  | N_ShouldDiag::~N_ShouldDiag() { // expected-note  {{destructor has a implicit non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | struct X_ShouldDiag { | 
|  | B_ShouldDiag b; | 
|  | ~X_ShouldDiag() noexcept { // expected-note  {{destructor has a non-throwing exception}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  | struct Y_ShouldDiag : A_ShouldDiag { | 
|  | ~Y_ShouldDiag() noexcept(true) { // expected-note  {{destructor has a non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  | struct C_ShouldNotDiag { | 
|  | int i; | 
|  | ~C_ShouldNotDiag() noexcept(false) {} | 
|  | }; | 
|  | struct D_ShouldNotDiag { | 
|  | C_ShouldNotDiag c; | 
|  | ~D_ShouldNotDiag() { //implicitly noexcept(false) | 
|  | throw 1; | 
|  | } | 
|  | }; | 
|  | struct E_ShouldNotDiag { | 
|  | C_ShouldNotDiag c; | 
|  | ~E_ShouldNotDiag(); //implicitly noexcept(false) | 
|  | }; | 
|  | E_ShouldNotDiag::~E_ShouldNotDiag() //implicitly noexcept(false) | 
|  | { | 
|  | throw 1; | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | class A1_ShouldDiag { | 
|  | T b; | 
|  |  | 
|  | public: | 
|  | ~A1_ShouldDiag() { // expected-note  {{destructor has a implicit non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  | template <typename T> | 
|  | struct B1_ShouldDiag { | 
|  | T i; | 
|  | ~B1_ShouldDiag() noexcept(true) {} | 
|  | }; | 
|  | template <typename T> | 
|  | struct R1_ShouldDiag : A1_ShouldDiag<T> //expected-note {{in instantiation of member function}} | 
|  | { | 
|  | B1_ShouldDiag<T> b; | 
|  | ~R1_ShouldDiag() { // expected-note  {{destructor has a implicit non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  | template <typename T> | 
|  | struct S1_ShouldDiag : A1_ShouldDiag<T> { | 
|  | B1_ShouldDiag<T> b; | 
|  | ~S1_ShouldDiag() noexcept { // expected-note  {{destructor has a non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  | void operator delete(void *ptr) noexcept { // expected-note  {{deallocator has a non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | struct except_fun { | 
|  | static const bool i = false; | 
|  | }; | 
|  | struct noexcept_fun { | 
|  | static const bool i = true; | 
|  | }; | 
|  | template <typename T> | 
|  | struct dependent_warn { | 
|  | ~dependent_warn() noexcept(T::i) { | 
|  | throw 1; | 
|  | } | 
|  | }; | 
|  | template <typename T> | 
|  | struct dependent_warn_noexcept { | 
|  | ~dependent_warn_noexcept() noexcept(T::i) { // expected-note  {{destructor has a non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  | template <typename T> | 
|  | struct dependent_warn_both { | 
|  | ~dependent_warn_both() noexcept(T::i) { // expected-note  {{destructor has a non-throwing exception specification}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  | void foo() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | struct Throws { | 
|  | ~Throws() noexcept(false); | 
|  | }; | 
|  |  | 
|  | struct ShouldDiagnose { | 
|  | Throws T; | 
|  | ~ShouldDiagnose() noexcept { //expected-note {{destructor has a non-throwing exception specification}} | 
|  | throw; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | }; | 
|  | struct ShouldNotDiagnose { | 
|  | Throws T; | 
|  | ~ShouldNotDiagnose() { | 
|  | throw; | 
|  | } | 
|  | }; | 
|  |  | 
|  | void bar_ShouldNotDiag() noexcept { | 
|  | try { | 
|  | throw 1; | 
|  | } catch (...) { | 
|  | } | 
|  | } | 
|  | void f_ShouldNotDiag() noexcept { | 
|  | try { | 
|  | throw 12; | 
|  | } catch (int) { | 
|  | } | 
|  | } | 
|  | void g_ShouldNotDiag() noexcept { | 
|  | try { | 
|  | throw 12; | 
|  | } catch (...) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void h_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | try { | 
|  | throw 12; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } catch (const char *) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void i_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | try { | 
|  | throw 12; | 
|  | } catch (int) { | 
|  | throw; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | } | 
|  | void j_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | try { | 
|  | throw 12; | 
|  | } catch (int) { | 
|  | throw "haha"; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | } | 
|  |  | 
|  | void k_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | try { | 
|  | throw 12; | 
|  | } catch (...) { | 
|  | throw; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | } | 
|  |  | 
|  | void loo_ShouldDiag(int i) noexcept { //expected-note {{function declared non-throwing here}} | 
|  | if (i) | 
|  | try { | 
|  | throw 12; | 
|  | } catch (int) { | 
|  | throw "haha"; //expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | i = 10; | 
|  | } | 
|  |  | 
|  | void loo1_ShouldNotDiag() noexcept { | 
|  | if (0) | 
|  | throw 12; | 
|  | } | 
|  |  | 
|  | void loo2_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | if (1) | 
|  | throw 12; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  | struct S {}; | 
|  |  | 
|  | void l_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | try { | 
|  | throw S{}; //expected-warning {{has a non-throwing exception specification but}} | 
|  | } catch (S *s) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void m_ShouldNotDiag() noexcept { | 
|  | try { | 
|  | const S &s = S{}; | 
|  | throw s; | 
|  | } catch (S s) { | 
|  | } | 
|  | } | 
|  | void n_ShouldNotDiag() noexcept { | 
|  | try { | 
|  | S s = S{}; | 
|  | throw s; | 
|  | } catch (const S &s) { | 
|  | } | 
|  | } | 
|  | // As seen in p34973, this should not throw the warning.  If there is an active | 
|  | // exception, catch(...) catches everything. | 
|  | void o_ShouldNotDiag() noexcept { | 
|  | try { | 
|  | throw; | 
|  | } catch (...) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void p_ShouldNotDiag() noexcept { | 
|  | // Don't warn here: it's possible that the user arranges to only call this | 
|  | // when the active exception is of type 'int'. | 
|  | try { | 
|  | throw; | 
|  | } catch (int){ | 
|  | } | 
|  | } | 
|  |  | 
|  | void q_ShouldNotDiag() noexcept { | 
|  | try { | 
|  | throw; | 
|  | } catch (int){ | 
|  | } catch (...){ | 
|  | } | 
|  | } | 
|  |  | 
|  | #define NOEXCEPT noexcept | 
|  | void with_macro() NOEXCEPT { //expected-note {{function declared non-throwing here}} | 
|  | throw 1; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } | 
|  |  | 
|  | void with_try_block() try { | 
|  | throw 2; | 
|  | } catch (...) { | 
|  | } | 
|  |  | 
|  | void with_try_block1() noexcept try { //expected-note {{function declared non-throwing here}} | 
|  | throw 2; // expected-warning {{has a non-throwing exception specification but}} | 
|  | } catch (char *) { | 
|  | } | 
|  |  | 
|  | namespace derived { | 
|  | struct B {}; | 
|  | struct D: B {}; | 
|  | void goodPlain() noexcept { | 
|  | try { | 
|  | throw D(); | 
|  | } catch (B) {} | 
|  | } | 
|  | void goodReference() noexcept { | 
|  | try { | 
|  | throw D(); | 
|  | } catch (B &) {} | 
|  | } | 
|  | void goodPointer() noexcept { | 
|  | D d; | 
|  | try { | 
|  | throw &d; | 
|  | } catch (B *) {} | 
|  | } | 
|  | void badPlain() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | try { | 
|  | throw B(); // expected-warning {{'badPlain' has a non-throwing exception specification but can still throw}} | 
|  | } catch (D) {} | 
|  | } | 
|  | void badReference() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | try { | 
|  | throw B(); // expected-warning {{'badReference' has a non-throwing exception specification but can still throw}} | 
|  | } catch (D &) {} | 
|  | } | 
|  | void badPointer() noexcept { //expected-note {{function declared non-throwing here}} | 
|  | B b; | 
|  | try { | 
|  | throw &b; // expected-warning {{'badPointer' has a non-throwing exception specification but can still throw}} | 
|  | } catch (D *) {} | 
|  | } | 
|  | } | 
|  |  | 
|  | int main() { | 
|  | R1_ShouldDiag<int> o; //expected-note {{in instantiation of member function}} | 
|  | S1_ShouldDiag<int> b; //expected-note {{in instantiation of member function}} | 
|  | dependent_warn<except_fun> f; | 
|  | dependent_warn_noexcept<noexcept_fun> f1; //expected-note {{in instantiation of member function}} | 
|  | dependent_warn_both<except_fun> f2; | 
|  | dependent_warn_both<noexcept_fun> f3; //expected-note {{in instantiation of member function}} | 
|  | ShouldDiagnose obj; | 
|  | ShouldNotDiagnose obj1; | 
|  | } | 
|  |  | 
|  | namespace ExceptionInNamespace { | 
|  | namespace N { | 
|  | struct E {}; | 
|  | } | 
|  | void run() throw() { | 
|  | try { | 
|  | throw N::E(); | 
|  | } catch (const N::E &e) { | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace HandlerSpecialCases { | 
|  | struct A {}; | 
|  | using CA = const A; | 
|  |  | 
|  | struct B : A {}; | 
|  | using CB = const B; | 
|  |  | 
|  | struct AmbigBase {}; | 
|  | struct AmbigMiddle : AmbigBase {}; | 
|  | struct AmbigDerived : AmbigBase, AmbigMiddle {}; // expected-warning {{inaccessible}} | 
|  |  | 
|  | struct PrivateBase {}; | 
|  | struct PrivateDerived : private PrivateBase { friend void bad3() throw(); }; | 
|  |  | 
|  | void good() throw() { | 
|  | try { throw CA(); } catch (volatile A&) {} | 
|  | try { throw B(); } catch (A&) {} | 
|  | try { throw B(); } catch (const volatile A&) {} | 
|  | try { throw CB(); } catch (A&) {} | 
|  | try { throw (int*)0; } catch (void* const volatile) {} | 
|  | try { throw (int*)0; } catch (void* const &) {} | 
|  | try { throw (B*)0; } catch (A*) {} | 
|  | try { throw (B*)0; } catch (A* const &) {} | 
|  | try { throw (void(*)() noexcept)0; } catch (void (*)()) {} | 
|  | try { throw (void(*)() noexcept)0; } catch (void (*const &)()) {} | 
|  | try { throw (int**)0; } catch (const int * const*) {} | 
|  | try { throw (int**)0; } catch (const int * const* const&) {} | 
|  | try { throw nullptr; } catch (int*) {} | 
|  | try { throw nullptr; } catch (int* const&) {} | 
|  | } | 
|  |  | 
|  | void bad1() throw() { // expected-note {{here}} | 
|  | try { throw A(); } catch (const B&) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad2() throw() { // expected-note {{here}} | 
|  | try { throw AmbigDerived(); } catch (const AmbigBase&) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad3() throw() { // expected-note {{here}} | 
|  | try { throw PrivateDerived(); } catch (const PrivateBase&) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad4() throw() { // expected-note {{here}} | 
|  | try { throw (int*)0; } catch (void* &) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad5() throw() { // expected-note {{here}} | 
|  | try { throw (int*)0; } catch (void* const volatile &) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad6() throw() { // expected-note {{here}} | 
|  | try { throw (int* volatile)0; } catch (void* const volatile &) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad7() throw() { // expected-note {{here}} | 
|  | try { throw (AmbigDerived*)0; } catch (AmbigBase*) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad8() throw() { // expected-note {{here}} | 
|  | try { throw (PrivateDerived*)0; } catch (PrivateBase*) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad9() throw() { // expected-note {{here}} | 
|  | try { throw (B*)0; } catch (A* &) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad10() throw() { // expected-note {{here}} | 
|  | try { throw (void(*)())0; } catch (void (*)() noexcept) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad11() throw() { // expected-note {{here}} | 
|  | try { throw (int**)0; } catch (const int **) {} // expected-warning {{still throw}} | 
|  | } | 
|  | void bad12() throw() { // expected-note {{here}} | 
|  | try { throw nullptr; } catch (int) {} // expected-warning {{still throw}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace NestedTry { | 
|  | void f() noexcept { | 
|  | try { | 
|  | try { | 
|  | throw 0; | 
|  | } catch (float) {} | 
|  | } catch (int) {} | 
|  | } | 
|  |  | 
|  | struct A { [[noreturn]] ~A(); }; | 
|  |  | 
|  | void g() noexcept { // expected-note {{here}} | 
|  | try { | 
|  | try { | 
|  | throw 0; // expected-warning {{still throw}} | 
|  | } catch (float) {} | 
|  | } catch (const char*) {} | 
|  | } | 
|  |  | 
|  | void h() noexcept { // expected-note {{here}} | 
|  | try { | 
|  | try { | 
|  | throw 0; | 
|  | } catch (float) {} | 
|  | } catch (int) { | 
|  | throw; // expected-warning {{still throw}} | 
|  | } | 
|  | } | 
|  |  | 
|  | // FIXME: Ideally, this should still warn; we can track which types are | 
|  | // potentially thrown by the rethrow. | 
|  | void i() noexcept { | 
|  | try { | 
|  | try { | 
|  | throw 0; | 
|  | } catch (int) { | 
|  | throw; | 
|  | } | 
|  | } catch (float) {} | 
|  | } | 
|  |  | 
|  | // FIXME: Ideally, this should not warn: the second catch block is | 
|  | // unreachable. | 
|  | void j() noexcept { // expected-note {{here}} | 
|  | try { | 
|  | try { | 
|  | throw 0; | 
|  | } catch (int) {} | 
|  | } catch (float) { | 
|  | throw; // expected-warning {{still throw}} | 
|  | } | 
|  | } | 
|  | } |