The following code fails for struct X on gcc 4.8.2 with: bla.cpp:15:3: error: function ‘X::X()’ defaulted on its first declaration with an exception-specification that differs from the implicit declaration ‘X::X()’ X() noexcept = default; bla.cpp:16:6: error: function ‘X& X::operator=(X&&)’ defaulted on its first declaration with an exception-specification that differs from the implicit declaration ‘X& X::operator=(X&&)’ X& operator=(X&&) noexcept = default; #include <type_traits> template<bool b> struct F { F() noexcept(b) {} F& operator=(F&&) noexcept(b) {return *this;} }; struct Simple { Simple() noexcept {} Simple& operator=(Simple&&) noexcept {return *this;} }; struct X { X() noexcept = default; X& operator=(X&&) noexcept = default; F<true> f; }; struct X2 { X2() /* noexcept */ = default; X2& operator=(X2&&) /* noexcept */ = default; F<true> f; }; struct X3 { X3() noexcept = default; X3& operator=(X3&&) noexcept = default; Simple f; }; static_assert(std::is_nothrow_constructible<X>::value, ""); static_assert(std::is_nothrow_move_assignable<X>::value, ""); static_assert(std::is_nothrow_constructible<X2>::value, ""); static_assert(std::is_nothrow_move_assignable<X2>::value, ""); static_assert(std::is_nothrow_constructible<X3>::value, ""); static_assert(std::is_nothrow_move_assignable<X3>::value, ""); X2 shows that a noexcept function is implicitly generated. X3 shows that it is necessary for the noexcept operator to depend on a template parameter to trigger this behavior.
Trunk doesn't give the same errors, but fails two of the assertions: n.cc:30:1: error: static assertion failed: static_assert(std::is_nothrow_constructible<X>::value, ""); ^ n.cc:31:1: error: static assertion failed: static_assert(std::is_nothrow_move_assignable<X>::value, ""); ^
(In reply to Jonathan Wakely from comment #1) > Trunk doesn't give the same errors, but fails two of the assertions: > > n.cc:30:1: error: static assertion failed: > static_assert(std::is_nothrow_constructible<X>::value, ""); The reason seems to be that the compiler makes this a deleted function, arguing "'X::X() noexcept' is implicitly deleted because its exception-specification does not match the implicit exception-specification 'noexcept (<uninstantiated>)' X() noexcept = default;" This looks incorrect to me.
This is fixed for 5.0.
The master branch has been updated by Francois Dumont <fdumont@gcc.gnu.org>: https://gcc.gnu.org/g:92456291849fe88303bbcab366f41dcd4a885ad5 commit r14-3926-g92456291849fe88303bbcab366f41dcd4a885ad5 Author: François Dumont <fdumont@gcc.gnu.org> Date: Wed Aug 23 19:15:43 2023 +0200 libstdc++: [_GLIBCXX_INLINE_VERSION] Fix <format> friend declaration GCC do not consider the inline namespace in friend function declarations. This is PR c++/59526, we need to explicit this namespace. libstdc++-v3/ChangeLog: * include/std/format (std::__format::_Arg_store): Explicit version namespace on make_format_args friend declaration.
The releases/gcc-13 branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:0547f663ee09aa5887dcd1bb0ea48eba24a30485 commit r13-7917-g0547f663ee09aa5887dcd1bb0ea48eba24a30485 Author: François Dumont <fdumont@gcc.gnu.org> Date: Wed Aug 23 19:15:43 2023 +0200 libstdc++: [_GLIBCXX_INLINE_VERSION] Fix <format> friend declaration GCC do not consider the inline namespace in friend function declarations. This is PR c++/59526, we need to explicit this namespace. libstdc++-v3/ChangeLog: * include/std/format (std::__format::_Arg_store): Explicit version namespace on make_format_args friend declaration. (cherry picked from commit 92456291849fe88303bbcab366f41dcd4a885ad5)