Message ID | 20240708194231.494096-1-jwakely@redhat.com |
---|---|
State | New |
Headers | show |
Series | libstdc++: ranges::find needs explicit conversion to size_t [PR115799] | expand |
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 >
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() &