https://gcc.gnu.org/g:ef11c1573d16db756c246ac029a99947bdc01aa3

commit r14-11539-gef11c1573d16db756c246ac029a99947bdc01aa3
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Wed Mar 26 11:47:05 2025 +0000

    libstdc++: Replace use of std::min in ranges::uninitialized_xxx algos 
[PR101587]
    
    Because ranges can have any signed integer-like type as difference_type,
    it's not valid to use std::min(diff1, diff2). Instead of calling
    std::min with an explicit template argument, this adds a new __mindist
    helper that determines the common type and uses that with std::min.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/101587
            * include/bits/ranges_uninitialized.h (__detail::__mindist):
            New function object.
            (ranges::uninitialized_copy, ranges::uninitialized_copy_n)
            (ranges::uninitialized_move, ranges::uninitialized_move_n): Use
            __mindist instead of std::min.
            * 
testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc:
            Check ranges with difference difference types.
            * 
testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc:
            Likewise.
    
    (cherry picked from commit f4b6acfc36fb1f72fdd5bf4da208515e6495a062)

Diff:
---
 libstdc++-v3/include/bits/ranges_uninitialized.h   | 32 ++++++++++++++++++----
 .../uninitialized_copy/constrained.cc              | 13 +++++++++
 .../uninitialized_move/constrained.cc              | 13 +++++++++
 3 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h 
b/libstdc++-v3/include/bits/ranges_uninitialized.h
index f16f2ef39f59..99a11f0fa7cc 100644
--- a/libstdc++-v3/include/bits/ranges_uninitialized.h
+++ b/libstdc++-v3/include/bits/ranges_uninitialized.h
@@ -252,6 +252,26 @@ namespace ranges
   inline constexpr __uninitialized_value_construct_n_fn
     uninitialized_value_construct_n;
 
+  namespace __detail
+  {
+    // This is only intended for finding smaller iterator differences below,
+    // not as a general purpose replacement for std::min.
+    struct __mindist_fn
+    {
+      template<typename _Dp1, typename _Dp2>
+       constexpr common_type_t<_Dp1, _Dp2>
+       operator()(_Dp1 __d1, _Dp2 __d2) const noexcept
+       {
+         // Every C++20 iterator I satisfies weakly_incrementable<I> which
+         // requires signed-integer-like<iter_difference_t<I>>.
+         static_assert(std::__detail::__is_signed_integer_like<_Dp1>);
+         static_assert(std::__detail::__is_signed_integer_like<_Dp2>);
+         return std::min<common_type_t<_Dp1, _Dp2>>(__d1, __d2);
+       }
+    };
+    inline constexpr __mindist_fn __mindist{};
+  }
+
   template<typename _Iter, typename _Out>
     using uninitialized_copy_result = in_out_result<_Iter, _Out>;
 
@@ -274,8 +294,8 @@ namespace ranges
          {
            auto __d1 = __ilast - __ifirst;
            auto __d2 = __olast - __ofirst;
-           return ranges::copy_n(std::move(__ifirst), std::min(__d1, __d2),
-                                 __ofirst);
+           return ranges::copy_n(std::move(__ifirst),
+                                 __detail::__mindist(__d1, __d2), __ofirst);
          }
        else
          {
@@ -321,8 +341,8 @@ namespace ranges
                                                 iter_reference_t<_Iter>>)
          {
            auto __d = __olast - __ofirst;
-           return ranges::copy_n(std::move(__ifirst), std::min(__n, __d),
-                                 __ofirst);
+           return ranges::copy_n(std::move(__ifirst),
+                                 __detail::__mindist(__n, __d), __ofirst);
          }
        else
          {
@@ -363,7 +383,7 @@ namespace ranges
            auto __d2 = __olast - __ofirst;
            auto [__in, __out]
              = ranges::copy_n(std::make_move_iterator(std::move(__ifirst)),
-                              std::min(__d1, __d2), __ofirst);
+                              __detail::__mindist(__d1, __d2), __ofirst);
            return {std::move(__in).base(), __out};
          }
        else
@@ -414,7 +434,7 @@ namespace ranges
            auto __d = __olast - __ofirst;
            auto [__in, __out]
              = ranges::copy_n(std::make_move_iterator(std::move(__ifirst)),
-                              std::min(__n, __d), __ofirst);
+                              __detail::__mindist(__n, __d), __ofirst);
            return {std::move(__in).base(), __out};
          }
        else
diff --git 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
index 79cf7afb29c9..a28b0607e925 100644
--- 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
@@ -175,6 +175,17 @@ test03()
     }
 }
 
+void
+test_pr101587()
+{
+  short in[1];
+  __gnu_test::test_contiguous_range r(in); // difference_type is integer-like
+  long out[1];
+  std::span<long> o(out); // difference_type is ptrdiff_t
+  ranges::uninitialized_copy(r, o);
+  ranges::uninitialized_copy_n(ranges::begin(r), 0, o.begin(), o.end());
+}
+
 int
 main()
 {
@@ -188,4 +199,6 @@ main()
 
   test02<false>();
   test02<true>();
+
+  test_pr101587();
 }
diff --git 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
index a9f7bbf0eb71..7d6e6b769577 100644
--- 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
@@ -185,6 +185,17 @@ test03()
     }
 }
 
+void
+test_pr101587()
+{
+  short in[1];
+  __gnu_test::test_contiguous_range r(in); // difference_type is integer-like
+  long out[1];
+  std::span<long> o(out); // difference_type is ptrdiff_t
+  ranges::uninitialized_move(r, o);
+  ranges::uninitialized_move_n(ranges::begin(r), 0, o.begin(), o.end());
+}
+
 int
 main()
 {
@@ -198,4 +209,6 @@ main()
 
   test02<false>();
   test02<true>();
+
+  test_pr101587();
 }

Reply via email to