From 5035cd662459b09605370f2ba41b2238119c69b1 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 26 Jan 2020 00:37:24 -0500 Subject: [PATCH] c++: Fix -Wnoexcept handling of system headers (PR90992). The immediate issue here was that the second warning didn't depend on the first one, so if the first location was in a system header, we'd mysteriously give the second by itself. It's also the case that the thing we care about being in a system header is the function that we want to suggest adding 'noexcept' to, not the noexcept-expression; it's useful to suggest adding noexcept to a user function to satisfy a noexcept-expression in a system header. PR c++/90992 * except.c (maybe_noexcept_warning): Check DECL_IN_SYSTEM_HEADER and temporarily enable -Wsystem-headers. Change second warning to conditional inform. --- gcc/cp/ChangeLog | 5 ++++ gcc/cp/except.c | 16 ++++++----- gcc/testsuite/g++.dg/warn/Wnoexcept1.C | 34 +++++++++++++++++++++++ gcc/testsuite/g++.dg/warn/Wnoexcept1.h | 37 ++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wnoexcept1.C create mode 100644 gcc/testsuite/g++.dg/warn/Wnoexcept1.h diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0b17abae3a3..b51d67fad2e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,10 @@ 2020-01-26 Jason Merrill + PR c++/90992 + * except.c (maybe_noexcept_warning): Check DECL_IN_SYSTEM_HEADER and + temporarily enable -Wsystem-headers. Change second warning to + conditional inform. + PR c++/90997 * semantics.c (finish_call_expr): Don't call instantiate_non_dependent_expr before warn_for_memset. diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 0b40234e228..788b96de243 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1165,13 +1165,17 @@ static GTY(()) vec *pending_noexcept_checks; static void maybe_noexcept_warning (tree fn) { - if (TREE_NOTHROW (fn)) + if (TREE_NOTHROW (fn) + && (!DECL_IN_SYSTEM_HEADER (fn) + || global_dc->dc_warn_system_headers)) { - warning (OPT_Wnoexcept, "noexcept-expression evaluates to % " - "because of a call to %qD", fn); - warning_at (DECL_SOURCE_LOCATION (fn), OPT_Wnoexcept, - "but %qD does not throw; perhaps " - "it should be declared %", fn); + temp_override s (global_dc->dc_warn_system_headers, true); + auto_diagnostic_group d; + if (warning (OPT_Wnoexcept, "noexcept-expression evaluates to % " + "because of a call to %qD", fn)) + inform (DECL_SOURCE_LOCATION (fn), + "but %qD does not throw; perhaps " + "it should be declared %", fn); } } diff --git a/gcc/testsuite/g++.dg/warn/Wnoexcept1.C b/gcc/testsuite/g++.dg/warn/Wnoexcept1.C new file mode 100644 index 00000000000..e3a5df64459 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wnoexcept1.C @@ -0,0 +1,34 @@ +// PR c++/90992 +// { dg-do compile { target c++11 } } +// { dg-additional-options -Wnoexcept } + +#include "Wnoexcept1.h" + +// We expect a warning at the declaration of construct2, since Automatic2 is +// defined below; we don't expect one for construct1, because Automatic1 is +// defined in the fake system header. +// { dg-warning "noexcept-expression" "" { target *-*-* } 26 } + +class Automatic2 { +public: + Automatic2(size_t bla) : Bla(bla) {}; // { dg-message "noexcept" } + +private: + size_t Bla; + NotNoexcept Dummy; +}; + +union U +{ + unsigned char buf[sizeof(Automatic1)]; + Automatic1 a1; + Automatic2 a2; + U(): buf{} {} + ~U() {} +}; + +int main() { + U u; + construct1(&u.a1, 42); + construct2(&u.a2, 42); +} diff --git a/gcc/testsuite/g++.dg/warn/Wnoexcept1.h b/gcc/testsuite/g++.dg/warn/Wnoexcept1.h new file mode 100644 index 00000000000..f59733e705f --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wnoexcept1.h @@ -0,0 +1,37 @@ +// -*- C++ -*- +#pragma GCC system_header + +using size_t = decltype(sizeof(42)); +inline void * operator new (size_t, void *p) noexcept { return p; } + +class NotNoexcept { +public: + NotNoexcept() noexcept(false) {} + NotNoexcept(const NotNoexcept&) noexcept(false) {} + NotNoexcept(NotNoexcept &&) noexcept(false) {} + ~NotNoexcept() noexcept(false) {} + + NotNoexcept&operator=(const NotNoexcept&) noexcept(false) { return *this;} + NotNoexcept&operator=(NotNoexcept &&) noexcept(false) {return *this;} +}; + +template +void +construct1(_Up* __p, _Args... __args) + noexcept(noexcept(::new((void *)__p) _Up(__args...))) +{ ::new((void *)__p) _Up(__args...); } + +template +void +construct2(_Up* __p, _Args... __args) + noexcept(noexcept(::new((void *)__p) _Up(__args...))) +{ ::new((void *)__p) _Up(__args...); } + +class Automatic1 { +public: + Automatic1(size_t bla) : Bla(bla) {}; + +private: + size_t Bla; + NotNoexcept Dummy; +}; -- 2.30.2