[gcc r13-9543] libstdc++: Fix ranges::move and ranges::move_backward to use iter_move [PR105609]

Jonathan Wakely redi@gcc.gnu.org
Wed Apr 16 19:20:08 GMT 2025


https://gcc.gnu.org/g:285f01004e902ece64714cb4fb1d527b25437f2e

commit r13-9543-g285f01004e902ece64714cb4fb1d527b25437f2e
Author: Jonathan Wakely <jwakely@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 001f72edb789..c9bfdaa1d5f5 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -158,6 +158,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
     {
@@ -261,14 +275,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;
 	    }
@@ -278,7 +292,7 @@ namespace ranges
 	{
 	  while (__first != __last)
 	    {
-	      std::__assign_one<_IsMove>(__result, __first);
+	      __detail::__assign_one<_IsMove>(__result, __first);
 	      ++__first;
 	      ++__result;
 	    }
@@ -390,7 +404,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};
 		}
 	    }
@@ -402,7 +416,7 @@ namespace ranges
 	    {
 	      --__tail;
 	      --__result;
-	      std::__assign_one<_IsMove>(__result, __tail);
+	      __detail::__assign_one<_IsMove>(__result, __tail);
 	    }
 	  return {std::move(__lasti), std::move(__result)};
 	}
@@ -415,7 +429,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 29a1abaaa021..6436c837abbb 100644
--- a/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc
@@ -205,6 +205,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 bf9be9c730da..908aa4190016 100644
--- a/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc
@@ -161,6 +161,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()
 {


More information about the Libstdc++-cvs mailing list