libstdc++: ranges::find needs explicit conversion to size_t [PR115799]

Message ID 20240708194231.494096-1-jwakely@redhat.com
State New
Headers
Series libstdc++: ranges::find needs explicit conversion to size_t [PR115799] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed

Commit Message

Jonathan Wakely July 8, 2024, 7:42 p.m. UTC
  This fixes another problem with my recent changes to use memchr in
std::find.

Tested x86_64-linux.

-- >8 --

For an integer-class type we need to use an explicit conversion to size_t.

libstdc++-v3/ChangeLog:

	PR libstdc++/115799
	* include/bits/ranges_util.h (__find_fn): Make conversion
	from difference type ti size_t explicit.
	* testsuite/25_algorithms/find/bytes.cc: Check ranges::find with
	__gnu_test::test_contiguous_range.
	* testsuite/std/ranges/range.cc: Adjust expected difference_type
	for __gnu_test::test_contiguous_range.
	* testsuite/util/testsuite_iterators.h (contiguous_iterator_wrapper):
	Use __max_diff_type as difference type.
	(test_range::sentinel, test_sized_range_sized_sent::sentinel):
	Ensure that operator- returns difference_type.
---
 libstdc++-v3/include/bits/ranges_util.h       |  3 +-
 .../testsuite/25_algorithms/find/bytes.cc     | 10 +++++
 libstdc++-v3/testsuite/std/ranges/range.cc    |  5 ++-
 .../testsuite/util/testsuite_iterators.h      | 42 ++++++++++++++-----
 4 files changed, 48 insertions(+), 12 deletions(-)
  

Comments

Jonathan Wakely July 10, 2024, 9:06 p.m. UTC | #1
Pushed to trunk.

On Mon, 8 Jul 2024 at 20:44, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> This fixes another problem with my recent changes to use memchr in
> std::find.
>
> Tested x86_64-linux.
>
> -- >8 --
>
> For an integer-class type we need to use an explicit conversion to size_t.
>
> libstdc++-v3/ChangeLog:
>
>         PR libstdc++/115799
>         * include/bits/ranges_util.h (__find_fn): Make conversion
>         from difference type ti size_t explicit.
>         * testsuite/25_algorithms/find/bytes.cc: Check ranges::find with
>         __gnu_test::test_contiguous_range.
>         * testsuite/std/ranges/range.cc: Adjust expected difference_type
>         for __gnu_test::test_contiguous_range.
>         * testsuite/util/testsuite_iterators.h (contiguous_iterator_wrapper):
>         Use __max_diff_type as difference type.
>         (test_range::sentinel, test_sized_range_sized_sent::sentinel):
>         Ensure that operator- returns difference_type.
> ---
>  libstdc++-v3/include/bits/ranges_util.h       |  3 +-
>  .../testsuite/25_algorithms/find/bytes.cc     | 10 +++++
>  libstdc++-v3/testsuite/std/ranges/range.cc    |  5 ++-
>  .../testsuite/util/testsuite_iterators.h      | 42 ++++++++++++++-----
>  4 files changed, 48 insertions(+), 12 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h
> index a1f42875b11..e6d96073e87 100644
> --- a/libstdc++-v3/include/bits/ranges_util.h
> +++ b/libstdc++-v3/include/bits/ranges_util.h
> @@ -506,9 +506,10 @@ namespace ranges
>                     if (static_cast<_Vt>(__value) == __value) [[likely]]
>                       if (__n > 0)
>                         {
> +                         const size_t __nu = static_cast<size_t>(__n);
>                           const int __ival = static_cast<int>(__value);
>                           const void* __p0 = std::to_address(__first);
> -                         if (auto __p1 = __builtin_memchr(__p0, __ival, __n))
> +                         if (auto __p1 = __builtin_memchr(__p0, __ival, __nu))
>                             __n = (const char*)__p1 - (const char*)__p0;
>                         }
>                     return __first + __n;
> diff --git a/libstdc++-v3/testsuite/25_algorithms/find/bytes.cc b/libstdc++-v3/testsuite/25_algorithms/find/bytes.cc
> index e1d6c01ab21..03dada0fec7 100644
> --- a/libstdc++-v3/testsuite/25_algorithms/find/bytes.cc
> +++ b/libstdc++-v3/testsuite/25_algorithms/find/bytes.cc
> @@ -114,9 +114,19 @@ test_non_characters()
>  #endif
>  }
>
> +#if __cpp_lib_ranges
> +void
> +test_pr115799c0(__gnu_test::test_contiguous_range<char> r)
> +{
> +  // Non-common range with integer-class type as difference_type.
> +  (void) std::ranges::find(r, 'a');
> +}
> +#endif
> +
>  void
>  test_pr115799c2(__gnu_test::input_iterator_wrapper<char> i)
>  {
> +  // Non-contiguous range of character type.
>    (void) std::find(i, i, 'a');
>  }
>
> diff --git a/libstdc++-v3/testsuite/std/ranges/range.cc b/libstdc++-v3/testsuite/std/ranges/range.cc
> index 760f6ffacfd..5464a9bf66b 100644
> --- a/libstdc++-v3/testsuite/std/ranges/range.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/range.cc
> @@ -56,6 +56,7 @@ static_assert( std::ranges::range<test_output_sized_range<int>&> );
>  using std::same_as;
>
>  using C = test_contiguous_range<char>;
> +using R = test_random_access_range<char>;
>  using I = test_input_range<char>;
>  using O = test_output_range<char>;
>
> @@ -69,7 +70,9 @@ static_assert( same_as<std::ranges::sentinel_t<C>,
>  static_assert( same_as<std::ranges::sentinel_t<O>,
>                        decltype(std::declval<O&>().end())> );
>
> -static_assert( same_as<std::ranges::range_difference_t<C>,
> +static_assert( ! same_as<std::ranges::range_difference_t<C>,
> +                        std::ptrdiff_t> ); // __detail::__max_diff_type
> +static_assert( same_as<std::ranges::range_difference_t<R>,
>                        std::ptrdiff_t> );
>  static_assert( same_as<std::ranges::range_difference_t<O>,
>                        std::ptrdiff_t> );
> diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
> index ec2971284b4..e7f7abe222d 100644
> --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
> +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
> @@ -34,6 +34,10 @@
>  #include <bits/move.h>
>  #endif
>
> +#if __cplusplus > 201703L
> +#include <bits/max_size_type.h>
> +#endif
> +
>  #ifndef _TESTSUITE_ITERATORS
>  #define _TESTSUITE_ITERATORS
>
> @@ -675,6 +679,9 @@ namespace __gnu_test
>
>        using iterator_concept = std::contiguous_iterator_tag;
>
> +      // Use an integer-class type to try and break the library code.
> +      using difference_type = std::ranges::__detail::__max_diff_type;
> +
>        contiguous_iterator_wrapper&
>        operator++()
>        {
> @@ -706,27 +713,42 @@ namespace __gnu_test
>        }
>
>        contiguous_iterator_wrapper&
> -      operator+=(std::ptrdiff_t n)
> +      operator+=(difference_type n)
>        {
> -       random_access_iterator_wrapper<T>::operator+=(n);
> +       auto d = static_cast<std::ptrdiff_t>(n);
> +       random_access_iterator_wrapper<T>::operator+=(d);
>         return *this;
>        }
>
>        friend contiguous_iterator_wrapper
> -      operator+(contiguous_iterator_wrapper iter, std::ptrdiff_t n)
> +      operator+(contiguous_iterator_wrapper iter, difference_type n)
>        { return iter += n; }
>
>        friend contiguous_iterator_wrapper
> -      operator+(std::ptrdiff_t n, contiguous_iterator_wrapper iter)
> +      operator+(difference_type n, contiguous_iterator_wrapper iter)
>        { return iter += n; }
>
>        contiguous_iterator_wrapper&
> -      operator-=(std::ptrdiff_t n)
> +      operator-=(difference_type n)
>        { return *this += -n; }
>
>        friend contiguous_iterator_wrapper
> -      operator-(contiguous_iterator_wrapper iter, std::ptrdiff_t n)
> +      operator-(contiguous_iterator_wrapper iter, difference_type n)
>        { return iter -= n; }
> +
> +      friend difference_type
> +      operator-(contiguous_iterator_wrapper l, contiguous_iterator_wrapper r)
> +      {
> +       const random_access_iterator_wrapper<T>& lbase = l;
> +       const random_access_iterator_wrapper<T>& rbase = r;
> +       return static_cast<difference_type>(lbase - rbase);
> +      }
> +
> +      decltype(auto) operator[](difference_type n) const
> +      {
> +       auto d = static_cast<std::ptrdiff_t>(n);
> +       return random_access_iterator_wrapper<T>::operator[](d);
> +      }
>      };
>
>    template<typename T>
> @@ -788,11 +810,11 @@ namespace __gnu_test
>
>           friend auto operator-(const sentinel& s, const I& i) noexcept
>             requires std::random_access_iterator<I>
> -         { return s.end - i.ptr; }
> +         { return std::iter_difference_t<I>(s.end - i.ptr); }
>
>           friend auto operator-(const I& i, const sentinel& s) noexcept
>             requires std::random_access_iterator<I>
> -         { return i.ptr - s.end; }
> +         { return std::iter_difference_t<I>(i.ptr - s.end); }
>         };
>
>      protected:
> @@ -890,11 +912,11 @@ namespace __gnu_test
>
>           friend std::iter_difference_t<I>
>           operator-(const sentinel& s, const I& i) noexcept
> -         { return s.end - i.ptr; }
> +         { return std::iter_difference_t<I>(s.end - i.ptr); }
>
>           friend std::iter_difference_t<I>
>           operator-(const I& i, const sentinel& s) noexcept
> -         { return i.ptr - s.end; }
> +         { return std::iter_difference_t<I>(i.ptr - s.end); }
>         };
>
>        auto end() &
> --
> 2.45.2
>
  

Patch

diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h
index a1f42875b11..e6d96073e87 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -506,9 +506,10 @@  namespace ranges
 		    if (static_cast<_Vt>(__value) == __value) [[likely]]
 		      if (__n > 0)
 			{
+			  const size_t __nu = static_cast<size_t>(__n);
 			  const int __ival = static_cast<int>(__value);
 			  const void* __p0 = std::to_address(__first);
-			  if (auto __p1 = __builtin_memchr(__p0, __ival, __n))
+			  if (auto __p1 = __builtin_memchr(__p0, __ival, __nu))
 			    __n = (const char*)__p1 - (const char*)__p0;
 			}
 		    return __first + __n;
diff --git a/libstdc++-v3/testsuite/25_algorithms/find/bytes.cc b/libstdc++-v3/testsuite/25_algorithms/find/bytes.cc
index e1d6c01ab21..03dada0fec7 100644
--- a/libstdc++-v3/testsuite/25_algorithms/find/bytes.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/find/bytes.cc
@@ -114,9 +114,19 @@  test_non_characters()
 #endif
 }
 
+#if __cpp_lib_ranges
+void
+test_pr115799c0(__gnu_test::test_contiguous_range<char> r)
+{
+  // Non-common range with integer-class type as difference_type.
+  (void) std::ranges::find(r, 'a');
+}
+#endif
+
 void
 test_pr115799c2(__gnu_test::input_iterator_wrapper<char> i)
 {
+  // Non-contiguous range of character type.
   (void) std::find(i, i, 'a');
 }
 
diff --git a/libstdc++-v3/testsuite/std/ranges/range.cc b/libstdc++-v3/testsuite/std/ranges/range.cc
index 760f6ffacfd..5464a9bf66b 100644
--- a/libstdc++-v3/testsuite/std/ranges/range.cc
+++ b/libstdc++-v3/testsuite/std/ranges/range.cc
@@ -56,6 +56,7 @@  static_assert( std::ranges::range<test_output_sized_range<int>&> );
 using std::same_as;
 
 using C = test_contiguous_range<char>;
+using R = test_random_access_range<char>;
 using I = test_input_range<char>;
 using O = test_output_range<char>;
 
@@ -69,7 +70,9 @@  static_assert( same_as<std::ranges::sentinel_t<C>,
 static_assert( same_as<std::ranges::sentinel_t<O>,
 		       decltype(std::declval<O&>().end())> );
 
-static_assert( same_as<std::ranges::range_difference_t<C>,
+static_assert( ! same_as<std::ranges::range_difference_t<C>,
+			 std::ptrdiff_t> ); // __detail::__max_diff_type
+static_assert( same_as<std::ranges::range_difference_t<R>,
 		       std::ptrdiff_t> );
 static_assert( same_as<std::ranges::range_difference_t<O>,
 		       std::ptrdiff_t> );
diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index ec2971284b4..e7f7abe222d 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -34,6 +34,10 @@ 
 #include <bits/move.h>
 #endif
 
+#if __cplusplus > 201703L
+#include <bits/max_size_type.h>
+#endif
+
 #ifndef _TESTSUITE_ITERATORS
 #define _TESTSUITE_ITERATORS
 
@@ -675,6 +679,9 @@  namespace __gnu_test
 
       using iterator_concept = std::contiguous_iterator_tag;
 
+      // Use an integer-class type to try and break the library code.
+      using difference_type = std::ranges::__detail::__max_diff_type;
+
       contiguous_iterator_wrapper&
       operator++()
       {
@@ -706,27 +713,42 @@  namespace __gnu_test
       }
 
       contiguous_iterator_wrapper&
-      operator+=(std::ptrdiff_t n)
+      operator+=(difference_type n)
       {
-	random_access_iterator_wrapper<T>::operator+=(n);
+	auto d = static_cast<std::ptrdiff_t>(n);
+	random_access_iterator_wrapper<T>::operator+=(d);
 	return *this;
       }
 
       friend contiguous_iterator_wrapper
-      operator+(contiguous_iterator_wrapper iter, std::ptrdiff_t n)
+      operator+(contiguous_iterator_wrapper iter, difference_type n)
       { return iter += n; }
 
       friend contiguous_iterator_wrapper
-      operator+(std::ptrdiff_t n, contiguous_iterator_wrapper iter)
+      operator+(difference_type n, contiguous_iterator_wrapper iter)
       { return iter += n; }
 
       contiguous_iterator_wrapper&
-      operator-=(std::ptrdiff_t n)
+      operator-=(difference_type n)
       { return *this += -n; }
 
       friend contiguous_iterator_wrapper
-      operator-(contiguous_iterator_wrapper iter, std::ptrdiff_t n)
+      operator-(contiguous_iterator_wrapper iter, difference_type n)
       { return iter -= n; }
+
+      friend difference_type
+      operator-(contiguous_iterator_wrapper l, contiguous_iterator_wrapper r)
+      {
+	const random_access_iterator_wrapper<T>& lbase = l;
+	const random_access_iterator_wrapper<T>& rbase = r;
+	return static_cast<difference_type>(lbase - rbase);
+      }
+
+      decltype(auto) operator[](difference_type n) const
+      {
+	auto d = static_cast<std::ptrdiff_t>(n);
+	return random_access_iterator_wrapper<T>::operator[](d);
+      }
     };
 
   template<typename T>
@@ -788,11 +810,11 @@  namespace __gnu_test
 
 	  friend auto operator-(const sentinel& s, const I& i) noexcept
 	    requires std::random_access_iterator<I>
-	  { return s.end - i.ptr; }
+	  { return std::iter_difference_t<I>(s.end - i.ptr); }
 
 	  friend auto operator-(const I& i, const sentinel& s) noexcept
 	    requires std::random_access_iterator<I>
-	  { return i.ptr - s.end; }
+	  { return std::iter_difference_t<I>(i.ptr - s.end); }
 	};
 
     protected:
@@ -890,11 +912,11 @@  namespace __gnu_test
 
 	  friend std::iter_difference_t<I>
 	  operator-(const sentinel& s, const I& i) noexcept
-	  { return s.end - i.ptr; }
+	  { return std::iter_difference_t<I>(s.end - i.ptr); }
 
 	  friend std::iter_difference_t<I>
 	  operator-(const I& i, const sentinel& s) noexcept
-	  { return i.ptr - s.end; }
+	  { return std::iter_difference_t<I>(i.ptr - s.end); }
 	};
 
       auto end() &