https://gcc.gnu.org/g:03623fa91ff36ecb9faa3b55f7842a39b759594e

commit r15-4322-g03623fa91ff36ecb9faa3b55f7842a39b759594e
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Sun Oct 13 22:48:43 2024 +0100

    libstdc++: Use std::move for iterator in ranges::fill [PR117094]
    
    Input iterators aren't required to be copyable.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/117094
            * include/bits/ranges_algobase.h (__fill_fn): Use std::move for
            iterator that might not be copyable.
            * testsuite/25_algorithms/fill/constrained.cc: Check
            non-copyable iterator with sized sentinel.

Diff:
---
 libstdc++-v3/include/bits/ranges_algobase.h        |  2 +-
 .../testsuite/25_algorithms/fill/constrained.cc    | 34 ++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/ranges_algobase.h 
b/libstdc++-v3/include/bits/ranges_algobase.h
index 3c8d46198c5d..0345ea850a4e 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -592,7 +592,7 @@ namespace ranges
        if constexpr (sized_sentinel_for<_Sent, _Out>)
          {
            const auto __len = __last - __first;
-           return ranges::fill_n(__first, __len, __value);
+           return ranges::fill_n(std::move(__first), __len, __value);
          }
        else if constexpr (is_scalar_v<_Tp>)
          {
diff --git a/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc 
b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
index 126515eddcaa..7cae99f2d5ce 100644
--- a/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
@@ -83,9 +83,43 @@ test02()
   return ok;
 }
 
+void
+test03()
+{
+  // Bug libstdc++/117094 - ranges::fill misses std::move for output_iterator
+
+  // Move-only output iterator
+  struct Iterator
+  {
+    using difference_type = long;
+    Iterator(int* p) : p(p) { }
+    Iterator(Iterator&&) = default;
+    Iterator& operator=(Iterator&&) = default;
+    int& operator*() const { return *p; }
+    Iterator& operator++() { ++p; return *this; }
+    Iterator operator++(int) { return Iterator(p++ ); }
+    int* p;
+
+    struct Sentinel
+    {
+      const int* p;
+      bool operator==(const Iterator& i) const { return p == i.p; }
+      long operator-(const Iterator& i) const { return p - i.p; }
+    };
+
+    long operator-(Sentinel s) const { return p - s.p; }
+  };
+  static_assert(std::sized_sentinel_for<Iterator::Sentinel, Iterator>);
+  int a[2];
+  std::ranges::fill(Iterator(a), Iterator::Sentinel{a+2}, 999);
+  VERIFY( a[0] == 999 );
+  VERIFY( a[1] == 999 );
+}
+
 int
 main()
 {
   test01();
   static_assert(test02());
+  test03();
 }

Reply via email to