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.