https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87805

            Bug ID: 87805
           Summary: Incomplete diagnostic for -Wnoexcept
           Product: gcc
           Version: 8.2.0
            Status: UNCONFIRMED
          Keywords: diagnostic
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: reichelt at gcc dot gnu.org
  Target Milestone: ---

The warning option "-Wnoexcept" produces incomplete diagnostics
for the following testcase:

==================================================
#include <unordered_set>

struct Hash
{
  char operator()(char) const { return 0; }
};

std::unordered_set<char, Hash> x;
==================================================

==================================================
/gcc-8.2.0/include/c++/8.2.0/type_traits: In instantiation of 'constexpr bool
std::__call_is_nt(std::__invoke_other) [with _Fn = const Hash&; _Args = {const
char&}]':
/gcc-8.2.0/include/c++/8.2.0/type_traits:2658:34:   required by substitution of
'template<bool __v> using __bool_constant = std::integral_constant<bool, __v>
[with bool __v = std::__call_is_nt<const Hash&, const
char&>((std::__result_of_success<char, std::__invoke_other>::__invoke_type{},
std::__result_of_success<char, std::__invoke_other>::__invoke_type()))]'
/gcc-8.2.0/include/c++/8.2.0/type_traits:2656:12:   required from 'struct
std::__call_is_nothrow<std::__invoke_result<const Hash&, const char&>, const
Hash&, const char&>'
/gcc-8.2.0/include/c++/8.2.0/type_traits:131:12:   required from 'struct
std::__and_<std::__is_invocable<const Hash&, const char&>,
std::__call_is_nothrow<std::__invoke_result<const Hash&, const char&>, const
Hash&, const char&> >'
/gcc-8.2.0/include/c++/8.2.0/type_traits:2668:12:   required from 'struct
std::__is_nothrow_invocable<const Hash&, const char&>'
/gcc-8.2.0/include/c++/8.2.0/type_traits:131:12:   required from 'struct
std::__and_<std::__is_fast_hash<Hash>, std::__is_nothrow_invocable<const Hash&,
const char&> >'
/gcc-8.2.0/include/c++/8.2.0/type_traits:142:31:   required from 'struct
std::__not_<std::__and_<std::__is_fast_hash<Hash>,
std::__is_nothrow_invocable<const Hash&, const char&> > >'
/gcc-8.2.0/include/c++/8.2.0/bits/unordered_set.h:99:63:   required from 'class
std::unordered_set<char, Hash>'
bug.cc:8:32:   required from here
bug.cc:5:8: warning: but 'char Hash::operator()(char) const' does not throw;
perhaps it should be declared 'noexcept' [-Wnoexcept]
   char operator()(char) const { return 0; }
        ^~~~~~~~
==================================================

Only with the additional option "-Wsystem-headers" you get the complete
diagnostics:

==================================================
In file included from /gcc-8.2.0/include/c++/8.2.0/unordered_set:38,
                 from bug.cc:1:
/gcc-8.2.0/include/c++/8.2.0/type_traits: In instantiation of 'constexpr bool
std::__call_is_nt(std::__invoke_other) [with _Fn = const Hash&; _Args = {const
char&}]':
/gcc-8.2.0/include/c++/8.2.0/type_traits:2658:34:   required by substitution of
'template<bool __v> using __bool_constant = std::integral_constant<bool, __v>
[with bool __v = std::__call_is_nt<const Hash&, const
char&>((std::__result_of_success<char, std::__invoke_other>::__invoke_type{},
std::__result_of_success<char, std::__invoke_other>::__invoke_type()))]'
/gcc-8.2.0/include/c++/8.2.0/type_traits:2656:12:   required from 'struct
std::__call_is_nothrow<std::__invoke_result<const Hash&, const char&>, const
Hash&, const char&>'
/gcc-8.2.0/include/c++/8.2.0/type_traits:131:12:   required from 'struct
std::__and_<std::__is_invocable<const Hash&, const char&>,
std::__call_is_nothrow<std::__invoke_result<const Hash&, const char&>, const
Hash&, const char&> >'
/gcc-8.2.0/include/c++/8.2.0/type_traits:2668:12:   required from 'struct
std::__is_nothrow_invocable<const Hash&, const char&>'
/gcc-8.2.0/include/c++/8.2.0/type_traits:131:12:   required from 'struct
std::__and_<std::__is_fast_hash<Hash>, std::__is_nothrow_invocable<const Hash&,
const char&> >'
/gcc-8.2.0/include/c++/8.2.0/type_traits:142:31:   required from 'struct
std::__not_<std::__and_<std::__is_fast_hash<Hash>,
std::__is_nothrow_invocable<const Hash&, const char&> > >'
/gcc-8.2.0/include/c++/8.2.0/bits/unordered_set.h:99:63:   required from 'class
std::unordered_set<char, Hash>'
bug.cc:8:32:   required from here
/gcc-8.2.0/include/c++/8.2.0/type_traits:2652:68: warning: noexcept-expression
evaluates to 'false' because of a call to 'char Hash::operator()(char) const'
[-Wnoexcept]
       return noexcept(std::declval<_Fn>()(std::declval<_Args>()...));
                                                                    ^
bug.cc:5:8: warning: but 'char Hash::operator()(char) const' does not throw;
perhaps it should be declared 'noexcept' [-Wnoexcept]
   char operator()(char) const { return 0; }
        ^~~~~~~~
==================================================

The culprit seems to be the function maybe_noexcept_warning from cp/except.c
where both parts of the warning are emitted as separate warnings.
The first part is (wrongly) suppressed when it is located in a system header:

static void
maybe_noexcept_warning (tree fn)
{
  if (TREE_NOTHROW (fn))
    {
      warning (OPT_Wnoexcept, "noexcept-expression evaluates to %<false%> "
               "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 %<noexcept%>", fn);
    }
}

Reply via email to