]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix ranges::move and ranges::move_backward to use iter_move [PR105609]
authorJonathan Wakely <jwakely@redhat.com>
Thu, 27 Feb 2025 13:27:17 +0000 (13:27 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 28 Feb 2025 21:35:27 +0000 (21:35 +0000)
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.

libstdc++-v3/include/bits/ranges_algobase.h
libstdc++-v3/testsuite/25_algorithms/move/constrained.cc
libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc

index eceb859e88bafafcfbb8745b35cb8624c7a92c58..a08f659b3aeface7214904928bb530259c317d9a 100644 (file)
@@ -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)};
        }
index 587b2f3728b1c2821a722e85bc31ad0da6e6d869..e2b45b070ef2a2fbe0d0371c92db5560656ab755 100644 (file)
@@ -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()
 {
index 8f6fd455b4b6763b085e7f8fa5f324e2cb3ff20e..4d94d386dd0bd036966b16755ba095aeb91dab65 100644 (file)
@@ -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()
 {