https://gcc.gnu.org/g:c29c3f713a9d166eb18c68645b9675d01421ccf6
commit r14-11625-gc29c3f713a9d166eb18c68645b9675d01421ccf6 Author: Jonathan Wakely <jwak...@redhat.com> Date: Thu Feb 27 13:27:17 2025 +0000 libstdc++: Fix ranges::move and ranges::move_backward to use iter_move [PR105609] The ranges::move and ranges::move_backward algorithms are supposed to use ranges::iter_move(iter) instead of std::move(*iter), which matters for an iterator type with an iter_move overload findable by ADL. Currently those algorithms use std::__assign_one which uses std::move, so define a new ranges::__detail::__assign_one helper function that uses ranges::iter_move. libstdc++-v3/ChangeLog: PR libstdc++/105609 * include/bits/ranges_algobase.h (__detail::__assign_one): New helper function. (__copy_or_move, __copy_or_move_backward): Use new function instead of std::__assign_one. * testsuite/25_algorithms/move/constrained.cc: Check that ADL iter_move is used in preference to std::move. * testsuite/25_algorithms/move_backward/constrained.cc: Likewise. (cherry picked from commit 3866ca796d5281d33f25b4165badacf8f198c6d1) Diff: --- libstdc++-v3/include/bits/ranges_algobase.h | 26 ++++++++++++++----- .../testsuite/25_algorithms/move/constrained.cc | 29 ++++++++++++++++++++++ .../25_algorithms/move_backward/constrained.cc | 29 ++++++++++++++++++++++ 3 files changed, 78 insertions(+), 6 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h index a578bdb6fc5f..a013de40318e 100644 --- a/libstdc++-v3/include/bits/ranges_algobase.h +++ b/libstdc++-v3/include/bits/ranges_algobase.h @@ -165,6 +165,20 @@ namespace ranges inline constexpr __equal_fn equal{}; +namespace __detail +{ + template<bool _IsMove, typename _OutIter, typename _InIter> + [[__gnu__::__always_inline__]] + constexpr void + __assign_one(_OutIter& __out, _InIter& __in) + { + if constexpr (_IsMove) + *__out = ranges::iter_move(__in); + else + *__out = *__in; + } +} // namespace __detail + template<typename _Iter, typename _Out> struct in_out_result { @@ -268,14 +282,14 @@ namespace ranges __builtin_memmove(__result, __first, sizeof(_ValueTypeI) * __num); else if (__num == 1) - std::__assign_one<_IsMove>(__result, __first); + __detail::__assign_one<_IsMove>(__result, __first); return {__first + __num, __result + __num}; } } for (auto __n = __last - __first; __n > 0; --__n) { - std::__assign_one<_IsMove>(__result, __first); + __detail::__assign_one<_IsMove>(__result, __first); ++__first; ++__result; } @@ -285,7 +299,7 @@ namespace ranges { while (__first != __last) { - std::__assign_one<_IsMove>(__result, __first); + __detail::__assign_one<_IsMove>(__result, __first); ++__first; ++__result; } @@ -397,7 +411,7 @@ namespace ranges __builtin_memmove(__result, __first, sizeof(_ValueTypeI) * __num); else if (__num == 1) - std::__assign_one<_IsMove>(__result, __first); + __detail::__assign_one<_IsMove>(__result, __first); return {__first + __num, __result}; } } @@ -409,7 +423,7 @@ namespace ranges { --__tail; --__result; - std::__assign_one<_IsMove>(__result, __tail); + __detail::__assign_one<_IsMove>(__result, __tail); } return {std::move(__lasti), std::move(__result)}; } @@ -422,7 +436,7 @@ namespace ranges { --__tail; --__result; - std::__assign_one<_IsMove>(__result, __tail); + __detail::__assign_one<_IsMove>(__result, __tail); } return {std::move(__lasti), std::move(__result)}; } diff --git a/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc index 096f3c6e594b..d8ed8857bb39 100644 --- a/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc @@ -204,6 +204,35 @@ test05() VERIFY( ranges::equal(v, (int[]){1,2,3,0}) ); } +namespace pr105609 +{ + struct I { + using value_type = int; + using difference_type = std::ptrdiff_t; + int operator*() const; + I& operator++(); + I operator++(int); + I& operator--(); + I operator--(int); + bool operator==(I) const; + friend int& iter_move(const I&); + }; +} + +void +test06(pr105609::I i) +{ + // PR libstdc++/105609 + // ranges::move should use ranges::iter_move instead of std::move + struct O { + O(int&) { } + O(int&&) = delete; + }; + + O* o = nullptr; + std::ranges::move(i, i, o); +} + int main() { diff --git a/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc index 3ad5d566ec9e..4cdac6a3a480 100644 --- a/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc @@ -160,6 +160,35 @@ test03() return ok; } +namespace pr105609 +{ + struct I { + using value_type = int; + using difference_type = std::ptrdiff_t; + int operator*() const; + I& operator++(); + I operator++(int); + I& operator--(); + I operator--(int); + bool operator==(I) const; + friend int& iter_move(const I&); + }; +} + +void +test04(pr105609::I i) +{ + // PR libstdc++/105609 + // ranges::move should use ranges::iter_move instead of std::move + struct O { + O(int&) { } + O(int&&) = delete; + }; + + O* o = nullptr; + std::ranges::move_backward(i, i, o); +} + int main() {