Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6351,15 +6351,15 @@ "cannot use '%0' with exceptions disabled">; def err_objc_exceptions_disabled : Error< "cannot use '%0' with Objective-C exceptions disabled">; -def warn_throw_in_noexcept_func - : Warning<"%0 has a non-throwing exception specification but can still " - "throw, resulting in unexpected program termination">, - InGroup; -def note_throw_in_dtor - : Note<"destructor or deallocator has a (possibly implicit) non-throwing " - "excepton specification">; -def note_throw_in_function - : Note<"non-throwing function declare here">; +def warn_throw_in_noexcept_func + : Warning< + "%0 has a non-throwing exception specification but can " "still " + "throw">, + InGroup; +def note_throw_in_dtor : Note<"%select{destructor|deallocator}0 has a " + "%select{non-throwing|implicit " + "non-throwing}1 exception specification">; +def note_throw_in_function : Note<"function declared non-throwing here">; def err_seh_try_outside_functions : Error< "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; def err_mixing_cxx_try_seh_try : Error< Index: lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- lib/Sema/AnalysisBasedWarnings.cpp +++ lib/Sema/AnalysisBasedWarnings.cpp @@ -399,10 +399,19 @@ if (S.getLangOpts().CPlusPlus11 && (isa(FD) || FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || - FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) - S.Diag(FD->getLocation(), diag::note_throw_in_dtor); - else - S.Diag(FD->getLocation(), diag::note_throw_in_function); + FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) { + // No point to emit diagnoistic for no-user declared function. + if (FD->getTypeSourceInfo()) { + const auto *Ty = + FD->getTypeSourceInfo()->getType()->getAs(); + S.Diag(FD->getLocation(), diag::note_throw_in_dtor) + << !isa(FD) << !Ty->hasExceptionSpec() + << (Ty->hasExceptionSpec() ? FD->getExceptionSpecSourceRange() + : FD->getSourceRange()); + } + } else + S.Diag(FD->getLocation(), diag::note_throw_in_function) + << FD->getExceptionSpecSourceRange(); } } @@ -420,8 +429,7 @@ static bool isNoexcept(const FunctionDecl *FD) { const auto *FPT = FD->getType()->castAs(); - if (FPT->getExceptionSpecType() != EST_None && - FPT->isNothrow(FD->getASTContext())) + if (FPT->isNothrow(FD->getASTContext())) return true; return false; } Index: test/CXX/except/except.spec/p11.cpp =================================================================== --- test/CXX/except/except.spec/p11.cpp +++ test/CXX/except/except.spec/p11.cpp @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s // This is the "let the user shoot themselves in the foot" clause. -void f() noexcept { // expected-note {{non-throwing function declare here}} +void f() noexcept { // expected-note {{function declared non-throwing here}} throw 0; // expected-warning {{has a non-throwing exception specification but}} } -void g() throw() { // expected-note {{non-throwing function declare here}} +void g() throw() { // expected-note {{function declared non-throwing here}} throw 0; // expected-warning {{has a non-throwing exception specification but}} } void h() throw(int) { Index: test/SemaCXX/warn-throw-out-noexcept-func.cpp =================================================================== --- test/SemaCXX/warn-throw-out-noexcept-func.cpp +++ test/SemaCXX/warn-throw-out-noexcept-func.cpp @@ -2,8 +2,8 @@ struct A_ShouldDiag { ~A_ShouldDiag(); // implicitly noexcept(true) }; -A_ShouldDiag::~A_ShouldDiag() { // expected-note {{destructor or deallocator has a (possibly implicit) non-throwing excepton specification}} - throw 1; // expected-warning {{has a non-throwing exception specification but can still throw, resulting in unexpected program termination}} +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; @@ -11,7 +11,7 @@ }; struct R_ShouldDiag : A_ShouldDiag { B_ShouldDiag b; - ~R_ShouldDiag() { // expected-note {{destructor or deallocator has a}} + ~R_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; @@ -30,18 +30,18 @@ ~N_ShouldDiag(); //implicitly noexcept(true) }; -N_ShouldDiag::~N_ShouldDiag() { // expected-note {{destructor or deallocator has a}} +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 or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~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 or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~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 { @@ -54,7 +54,7 @@ throw 1; } }; -struct E_ShouldNotDiag { +struct E_ShouldNotDiag { C_ShouldNotDiag c; ~E_ShouldNotDiag(); //implicitly noexcept(false) }; @@ -68,7 +68,7 @@ T b; public: - ~A1_ShouldDiag() { // expected-note {{destructor or deallocator has a}} + ~A1_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; @@ -81,19 +81,19 @@ struct R1_ShouldDiag : A1_ShouldDiag //expected-note {{in instantiation of member function}} { B1_ShouldDiag b; - ~R1_ShouldDiag() { // expected-note {{destructor or deallocator has a}} + ~R1_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; template struct S1_ShouldDiag : A1_ShouldDiag { B1_ShouldDiag b; - ~S1_ShouldDiag() noexcept { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~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 {{destructor or deallocator has a}} - 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; @@ -109,18 +109,18 @@ }; template struct dependent_warn_noexcept { - ~dependent_warn_noexcept() noexcept(T::i) { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~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 struct dependent_warn_both { - ~dependent_warn_both() noexcept(T::i) { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~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 {{non-throwing function declare here}} - 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); @@ -128,14 +128,14 @@ struct ShouldDiagnose { Throws T; - ~ShouldDiagnose() noexcept { //expected-note {{destructor or deallocator has a}} + ~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; + ~ShouldNotDiagnose() { + throw; } }; @@ -158,21 +158,21 @@ } } -void h_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +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 {{non-throwing function declare here}} +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 {{non-throwing function declare here}} +void j_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw 12; } catch (int) { @@ -180,7 +180,7 @@ } } -void k_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void k_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw 12; } catch (...) { @@ -188,7 +188,7 @@ } } -void loo_ShouldDiag(int i) noexcept { //expected-note {{non-throwing function declare here}} +void loo_ShouldDiag(int i) noexcept { //expected-note {{function declared non-throwing here}} if (i) try { throw 12; @@ -203,13 +203,13 @@ throw 12; } -void loo2_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +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 {{non-throwing function declare here}} +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) { @@ -222,7 +222,6 @@ throw s; } catch (S s) { } - } void n_ShouldNotDiag() noexcept { try { @@ -231,7 +230,7 @@ } catch (const S &s) { } } -void o_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void o_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw; //expected-warning {{has a non-throwing exception specification but}} } catch (...) { @@ -239,7 +238,7 @@ } #define NOEXCEPT noexcept -void with_macro() NOEXCEPT { //expected-note {{non-throwing function declare here}} +void with_macro() NOEXCEPT { //expected-note {{function declared non-throwing here}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } @@ -248,8 +247,8 @@ } catch (...) { } -void with_try_block1() noexcept try { //expected-note {{non-throwing function declare here}} - throw 2; // expected-warning {{has a non-throwing exception specification but}} +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 *) { }