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

            Bug ID: 124587
           Summary: unhelpful locations in warning (-Wnoexcept)
           Product: gcc
           Version: 14.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: diagnostics
          Assignee: dmalcolm at redhat dot com
          Reporter: [email protected]
  Target Milestone: ---

(Tested with g++ 14.2.0, but according to Godbolt, similar on trunk.)

% cat test.cpp
#include <vector>

struct T
{
  T () { }
};

struct S
{
  T a;
};

int main ()
{
  // S q;
  std::vector <S> v;
  v.emplace_back ();
}

% g++ -std=c++23 -Wnoexcept test.cpp
In file included from /usr/include/c++/14/bits/stl_iterator.h:78,
                 from /usr/include/c++/14/bits/stl_algobase.h:67,
                 from /usr/include/c++/14/vector:62,
                 from test.cpp:1:
/usr/include/c++/14/bits/stl_construct.h:95:14: warning: noexcept-expression
evaluates to 'false' because of a call to 'S::S()' [-Wnoexcept]
   95 |     noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:8:8: note: but 'S::S()' does not throw; perhaps it should be declared
'noexcept'
    8 | struct S
      |        ^

The warning refers to two locations which are not that helpful, the declaration
of S, and a library header, but it does not mention the two locations that are
of interest to the user (of course, as usual, in a small test program they're
easy to find, but in a bigger program, not so much):

1. The constructor T::T which actually should be declared 'noexcept'. -- S::S()
is defaulted; one could declare it manually with 'noexcept', but that would be
cumbersome and actually kind of wrong, basically claiming that S:S:() is
noexcept while the T::T() might not be (which could be defined in another TU,
written by another author etc.).

2. The emplace_back statement that actually cares for noexcept. -- I assume it
can choose a more efficient implementation based on it; at first I didn't even
think of it and wondered why 'noexcept' even played a role here, so I couldn't
even have searched for emplace_back.

To verify the last point, I added a simple declaration of an instance of S
(commented out above), just to see if this would trigger the warning too. As
expected, it didn't, but interestingly it improved the following warning which
now included 2. (though still not 1.):

In file included from /usr/include/c++/14/bits/stl_iterator.h:78,
                 from /usr/include/c++/14/bits/stl_algobase.h:67,
                 from /usr/include/c++/14/vector:62,
                 from test.cpp:1:
/usr/include/c++/14/bits/stl_construct.h: In instantiation of 'constexpr
decltype (::new(void*(0)) _Tp) std::construct_at(_Tp*, _Args&& ...) [with _Tp =
S; _Args = {}; decltype (::new(void*(0)) _Tp) = S*]':
/usr/include/c++/14/bits/alloc_traits.h:577:21:   required from 'static
constexpr void std::allocator_traits<std::allocator<_Up>
>::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = S; _Args = {}; _Tp
= S; allocator_type = std::allocator<S>]'
  577 |           std::construct_at(__p, std::forward<_Args>(__args)...);
      |           ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/vector.tcc:117:30:   required from 'constexpr
std::vector<_Tp, _Alloc>::reference std::vector<_Tp,
_Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = S; _Alloc =
std::allocator<S>; reference = S&]'
  117 |             _Alloc_traits::construct(this->_M_impl,
this->_M_impl._M_finish,
      |            
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  118 |                                      std::forward<_Args>(__args)...);
      |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:17:18:   required from here
   17 |   v.emplace_back ();
      |   ~~~~~~~~~~~~~~~^~
/usr/include/c++/14/bits/stl_construct.h:95:14: warning: noexcept-expression
evaluates to 'false' because of a call to 'S::S()' [-Wnoexcept]
   95 |     noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:8:8: note: but 'S::S()' does not throw; perhaps it should be declared
'noexcept'
    8 | struct S
      |        ^

It would be helpful if the warning always included these locations because they
would explain why 'noexcept' is relevant, and where to actually insert it.

Reply via email to