https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93872
--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> --- It looks like those parameters have always been wrong (for more than a decade anyway). When we optimized them to a memmove for both copies and moves it didn't matter because memmove doesn't alter the source and so it can be const. For C++20 when std::is_constant_evaluated() is true, we do the actual assignments in a loop, and so the value category and cv-qualifiers need to be correct. I'm nervous about changing the parameter types in stage 4 because it affects all modes, not just C++20. I think the conservative fix for now is: --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -95,7 +95,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION for(; __num > 0; --__num) { if constexpr (_IsMove) - *__dst = std::move(*__src); + // This const_cast looks unsafe, but we only use this function + // for trivially-copyable types, which means this assignment + // is trivial and so doesn't alter the source anyway. + // See PR 93872 for why it's needed. + *__dst = std::move(*const_cast<_Tp*>(__src)); else *__dst = *__src; ++__src;