https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116471
Bug ID: 116471 Summary: Strange/bogus static_assert in ranges::copy / move algorithms Product: gcc Version: 14.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: dangelog at gmail dot com Target Milestone: --- Hi, This code fails to build on GCC 14 (CE link: https://gcc.godbolt.org/z/qnYGd48Ko ) #include <algorithm> struct X { X& operator=(X&) = default; // non-const }; int main() { extern X *b, *e, *out; std::ranges::copy(b, e, out); } /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/ranges_algobase.h:259:23: error: static assertion failed 258 | static_assert(_IsMove | ~~~~~~~ 259 | ? is_move_assignable_v<_ValueTypeI> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 260 | : is_copy_assignable_v<_ValueTypeI>); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/ranges_algobase.h:259:23: note: '(false ? std::is_move_assignable_v<X> : std::is_copy_assignable_v<X>)' evaluates to false Indeed X fails is_copy_assignable because its copy assignment operator takes by non-const reference. It's not entirely clear why that static_assert is there, given that ranges::copy/move algorithms are already constrained on concepts (like indirectly_copyable). It's also worth noting that the static_assert is into a if constexpr( __memcpyable<_Iter, _Out>::__value) branch. memcpyable basically means trivially copyable (except for pointers to volatile), however trivially copyable does NOT imply is_copy_assignable (because it just checks that eligible copy assignments are trivial, not that they work from a `const T`). I can send a patch, but I'm not sure in which direction this should go. I stumbled upon this while extending the fix PR108846 to range algorithms.