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. --- Tested x86_64-linux. libstdc++-v3/include/bits/ranges_algobase.h | 26 +++++++++++++---- .../25_algorithms/move/constrained.cc | 29 +++++++++++++++++++ .../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 eceb859e88b..a08f659b3ae 100644 --- a/libstdc++-v3/include/bits/ranges_algobase.h +++ b/libstdc++-v3/include/bits/ranges_algobase.h @@ -188,6 +188,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 { @@ -291,14 +305,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; } @@ -308,7 +322,7 @@ namespace ranges { while (__first != __last) { - std::__assign_one<_IsMove>(__result, __first); + __detail::__assign_one<_IsMove>(__result, __first); ++__first; ++__result; } @@ -420,7 +434,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}; } } @@ -432,7 +446,7 @@ namespace ranges { --__tail; --__result; - std::__assign_one<_IsMove>(__result, __tail); + __detail::__assign_one<_IsMove>(__result, __tail); } return {std::move(__lasti), std::move(__result)}; } @@ -445,7 +459,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 587b2f3728b..e2b45b070ef 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 8f6fd455b4b..4d94d386dd0 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() { -- 2.48.1