Whenever we use operator+ or similar operators on random access iterators we need to be careful to use the iterator's difference_type rather than some other integer type. It's not guaranteed that an expression with an arbitrary integer type, such as `it + 1u`, has the same effects as `it + iter_difference_t<It>(1)`.
Some of our algorithms need changes to cast values to the correct type, or to use std::next or ranges::next instead of `it + n`. Several tests also need fixes where the arithmetic occurs directly in the test. The __gnu_test::random_access_iterator_wrapper class template is adjusted to have deleted operators that make programs ill-formed if the argument to relevant operators is not the difference_type. This will make it easier to avoid regressing in future. libstdc++-v3/ChangeLog: PR libstdc++/121890 * include/bits/ranges_algo.h (ranges::rotate, ranges::shuffle) (__insertion_sort, __unguarded_partition_pivot, __introselect): Use ranges::next to advance iterators. (ranges::push_heap, ranges::pop_heap, ranges::partial_sort) (ranges::partial_sort_copy): Use ranges::prev. (__final_insertion_sort): Use iter_difference_t<Iter> for operand of operator+ on iterator. * include/bits/ranges_base.h (ranges::advance): Use iterator's difference_type for all iterator arithmetic. * include/bits/stl_algo.h (__search_n_aux, __rotate) (__insertion_sort, __unguarded_partition_pivot, __introselect) (__final_insertion_sort, for_each_n, random_shuffle): Likewise. * include/bits/stl_algobase.h (__fill_n_a, __lc_rai::__newlast1): Likewise. * include/bits/stl_heap.h (push_heap): Likewise. (__is_heap_until): Add static_assert. (__is_heap): Convert distance to difference_type. * include/std/functional (boyer_moore_searcher::operator()): Use iterator's difference_type for iterator arithmetic. * testsuite/util/testsuite_iterators.h (random_access_iterator_wrapper): Add deleted overloads of operators that should be called with difference_type. * testsuite/24_iterators/range_operations/advance.cc: Use ranges::next. * testsuite/25_algorithms/heap/constrained.cc: Use ranges::next and ranges::prev. * testsuite/25_algorithms/nth_element/58800.cc: Use std::next. * testsuite/25_algorithms/nth_element/constrained.cc: Use ptrdiff_t for loop variable. * testsuite/25_algorithms/nth_element/random_test.cc: Use iterator's difference_type instead of int. * testsuite/25_algorithms/partial_sort/check_compare_by_value.cc: Use std::next. * testsuite/25_algorithms/partial_sort/constrained.cc: Use ptrdiff_t for loop variable. * testsuite/25_algorithms/partial_sort/random_test.cc: Use iterator's difference_type instead of int. * testsuite/25_algorithms/partial_sort_copy/constrained.cc: Use ptrdiff_t for loop variable. * testsuite/25_algorithms/partial_sort_copy/random_test.cc: Use iterator's difference_type instead of int. * testsuite/std/ranges/adaptors/drop.cc: Use ranges::next. * testsuite/25_algorithms/fill_n/diff_type.cc: New test. * testsuite/25_algorithms/for_each/diff_type.cc: New test. * testsuite/25_algorithms/lexicographical_compare/diff_type.cc: New test. * testsuite/25_algorithms/push_heap/diff_type.cc: New test. * testsuite/25_algorithms/nth_element/diff_type.cc: New test. * testsuite/25_algorithms/rotate/diff_type.cc: New test. * testsuite/25_algorithms/search_n/diff_type.cc: New test. * testsuite/25_algorithms/sort/diff_type.cc: New test. --- Tested powerpc64le-linux. libstdc++-v3/include/bits/ranges_algo.h | 56 ++++++++------ libstdc++-v3/include/bits/ranges_base.h | 4 +- libstdc++-v3/include/bits/stl_algo.h | 76 ++++++++++++------- libstdc++-v3/include/bits/stl_algobase.h | 18 +++-- libstdc++-v3/include/bits/stl_heap.h | 18 +++-- libstdc++-v3/include/std/functional | 2 +- .../24_iterators/range_operations/advance.cc | 2 +- .../25_algorithms/fill_n/diff_type.cc | 13 ++++ .../25_algorithms/for_each/diff_type.cc | 13 ++++ .../25_algorithms/heap/constrained.cc | 20 ++--- .../lexicographical_compare/diff_type.cc | 57 ++++++++++++++ .../25_algorithms/nth_element/58800.cc | 2 +- .../25_algorithms/nth_element/constrained.cc | 2 +- .../25_algorithms/nth_element/diff_type.cc | 13 ++++ .../25_algorithms/nth_element/random_test.cc | 4 +- .../partial_sort/check_compare_by_value.cc | 4 +- .../25_algorithms/partial_sort/constrained.cc | 3 +- .../25_algorithms/partial_sort/random_test.cc | 4 +- .../partial_sort_copy/constrained.cc | 4 +- .../partial_sort_copy/random_test.cc | 4 +- .../25_algorithms/push_heap/diff_type.cc | 13 ++++ .../25_algorithms/rotate/diff_type.cc | 13 ++++ .../25_algorithms/search_n/diff_type.cc | 13 ++++ .../testsuite/25_algorithms/sort/diff_type.cc | 13 ++++ .../testsuite/std/ranges/adaptors/drop.cc | 2 +- .../testsuite/util/testsuite_iterators.h | 18 +++++ 26 files changed, 301 insertions(+), 90 deletions(-) create mode 100644 libstdc++-v3/testsuite/25_algorithms/fill_n/diff_type.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/for_each/diff_type.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/diff_type.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/nth_element/diff_type.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/push_heap/diff_type.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/rotate/diff_type.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/search_n/diff_type.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/sort/diff_type.cc diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index 6e1e06cb2d0f..65356fd2dfd0 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -1684,8 +1684,9 @@ namespace ranges if (__k == 1) { auto __t = std::move(*__p); - ranges::move(__p + 1, __p + __n, __p); - *(__p + __n - 1) = std::move(__t); + ranges::move(ranges::next(__p), + ranges::next(__p, __n), __p); + *ranges::next(__p, __n - 1) = std::move(__t); return {std::move(__ret), std::move(__lasti)}; } auto __q = __p + __k; @@ -1709,8 +1710,10 @@ namespace ranges if constexpr (__is_pod(iter_value_t<_Iter>)) if (__k == 1) { - auto __t = std::move(*(__p + __n - 1)); - ranges::move_backward(__p, __p + __n - 1, __p + __n); + auto __t = std::move(*ranges::next(__p, __n - 1)); + ranges::move_backward(__p, + ranges::next(__p, __n - 1), + ranges::next(__p, __n)); *__p = std::move(__t); return {std::move(__ret), std::move(__lasti)}; } @@ -1970,7 +1973,7 @@ namespace ranges if (__urngrange / __urange >= __urange) // I.e. (__urngrange >= __urange * __urange) but without wrap issues. { - _Iter __i = __first + 1; + _Iter __i = ranges::next(__first); // Since we know the range isn't empty, an even number of elements // means an uneven number of elements /to swap/, in which case we @@ -1979,7 +1982,7 @@ namespace ranges if ((__urange % 2) == 0) { __distr_type __d{0, 1}; - ranges::iter_swap(__i++, __first + __d(__g)); + ranges::iter_swap(__i++, ranges::next(__first, __d(__g))); } // Now we know that __last - __i is even, so we do the rest in pairs, @@ -1990,11 +1993,11 @@ namespace ranges { const __uc_type __swap_range = __uc_type(__i - __first) + 1; - const pair<__uc_type, __uc_type> __pospos = + const pair<_DistanceType, _DistanceType> __pospos = __gen_two_uniform_ints(__swap_range, __swap_range + 1, __g); - ranges::iter_swap(__i++, __first + __pospos.first); - ranges::iter_swap(__i++, __first + __pospos.second); + ranges::iter_swap(__i++, ranges::next(__first, __pospos.first)); + ranges::iter_swap(__i++, ranges::next(__first, __pospos.second)); } return __i; @@ -2002,9 +2005,11 @@ namespace ranges __distr_type __d; - _Iter __i = __first + 1; + _Iter __i = ranges::next(__first); for (; __i != __last; ++__i) - ranges::iter_swap(__i, __first + __d(__g, __p_type(0, __i - __first))); + ranges::iter_swap(__i, + ranges::next(__first, + __d(__g, __p_type(0, __i - __first)))); return __i; } @@ -2060,7 +2065,7 @@ namespace ranges { auto __comp_proj = __detail::__make_comp_proj(__comp, __proj); __detail::__push_heap(__first, (__last - __first) - 1, - 0, ranges::iter_move(__last - 1), + 0, ranges::iter_move(ranges::prev(__last)), __comp_proj); return __last; } @@ -2137,8 +2142,9 @@ namespace ranges { if (__last - __first > 1) { + auto __back = ranges::prev(__last); auto __comp_proj = __detail::__make_comp_proj(__comp, __proj); - __detail::__pop_heap(__first, __last - 1, __last - 1, __comp_proj); + __detail::__pop_heap(__first, __back, __back, __comp_proj); } return __last; } @@ -2356,12 +2362,12 @@ namespace ranges if (__first == __last) return; - for (_Iter __i = __first + 1; __i != __last; ++__i) + for (_Iter __i = ranges::next(__first); __i != __last; ++__i) { if (__comp(*__i, *__first)) { iter_value_t<_Iter> __val = ranges::iter_move(__i); - ranges::move_backward(__first, __i, __i + 1); + ranges::move_backward(__first, __i, ranges::next(__i)); *__first = std::move(__val); } else @@ -2383,10 +2389,11 @@ namespace ranges constexpr void __final_insertion_sort(_Iter __first, _Iter __last, _Comp __comp) { - if (__last - __first > __sort_threshold) + constexpr iter_difference_t<_Iter> __threshold = __sort_threshold; + if (__last - __first > __threshold) { - __detail::__insertion_sort(__first, __first + __sort_threshold, __comp); - __detail::__unguarded_insertion_sort(__first + __sort_threshold, __last, + __detail::__insertion_sort(__first, __first + __threshold, __comp); + __detail::__unguarded_insertion_sort(__first + __threshold, __last, __comp); } else @@ -2416,8 +2423,10 @@ namespace ranges __unguarded_partition_pivot(_Iter __first, _Iter __last, _Comp __comp) { _Iter __mid = __first + (__last - __first) / 2; - __detail::__move_median_to_first(__first, __first + 1, __mid, __last - 1, __comp); - return __detail::__unguarded_partition(__first + 1, __last, __first, __comp); + __detail::__move_median_to_first(__first, ranges::next(__first), __mid, + ranges::prev(__last), __comp); + return __detail::__unguarded_partition(ranges::next(__first), __last, + __first, __comp); } template<typename _Iter, typename _Comp> @@ -2745,7 +2754,7 @@ namespace ranges std::__invoke(__proj, *__first))) { ranges::pop_heap(__first, __middle, __comp, __proj); - ranges::iter_swap(__middle-1, __i); + ranges::iter_swap(std::prev(__middle), __i); ranges::push_heap(__first, __middle, __comp, __proj); } ranges::sort_heap(__first, __middle, __comp, __proj); @@ -2812,7 +2821,7 @@ namespace ranges { ranges::pop_heap(__result_first, __result_real_last, __comp, __proj2); - *(__result_real_last-1) = *__first; + *ranges::prev(__result_real_last) = *__first; ranges::push_heap(__result_first, __result_real_last, __comp, __proj2); } @@ -2924,7 +2933,8 @@ namespace ranges { if (__depth_limit == 0) { - __detail::__heap_select(__first, __nth + 1, __last, __comp); + __detail::__heap_select(__first, ranges::next(__nth), __last, + __comp); // Place the nth largest element in its final position. ranges::iter_swap(__first, __nth); return; diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 7df638db2d6f..02e13a2027d1 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -887,7 +887,7 @@ namespace ranges if constexpr (assignable_from<_It&, _Sent>) __it = std::move(__bound); else if constexpr (random_access_iterator<_It>) - __it += 0; + __it += iter_difference_t<_It>(0); return __n; } else if (__diff > 0 ? __n >= __diff : __n <= __diff) @@ -907,7 +907,7 @@ namespace ranges { // inline any possible side effects of advance(it, n) if constexpr (random_access_iterator<_It>) - __it += 0; + __it += iter_difference_t<_It>(0); return 0; } } diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index 81a2457ae6f2..e8a92e869619 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -204,7 +204,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION while (__unary_pred(--__backTrack)) { if (--__remainder == 0) - return (__first - __count); // Success + return __first - _DistanceType(__count); // Success } __remainder = __count + 1 - (__first - __backTrack); } @@ -1259,8 +1259,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2) if (__is_pod(_ValueType) && __k == 1) { _ValueType __t = _GLIBCXX_MOVE(*__p); - _GLIBCXX_MOVE3(__p + 1, __p + __n, __p); - *(__p + __n - 1) = _GLIBCXX_MOVE(__t); + _GLIBCXX_MOVE3(__p + _Distance(1), __p + __n, __p); + *(__p + __n - _Distance(1)) = _GLIBCXX_MOVE(__t); return __ret; } _RandomAccessIterator __q = __p + __k; @@ -1281,8 +1281,9 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2) __k = __n - __k; if (__is_pod(_ValueType) && __k == 1) { - _ValueType __t = _GLIBCXX_MOVE(*(__p + __n - 1)); - _GLIBCXX_MOVE_BACKWARD3(__p, __p + __n - 1, __p + __n); + _ValueType __t = _GLIBCXX_MOVE(*(__p + __n - _Distance(1))); + _GLIBCXX_MOVE_BACKWARD3(__p, __p + __n - _Distance(1), + __p + __n); *__p = _GLIBCXX_MOVE(__t); return __ret; } @@ -1770,15 +1771,18 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) __insertion_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { - if (__first == __last) return; + if (__first == __last) + return; - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + typedef iterator_traits<_RandomAccessIterator> _IterTraits; + typedef typename _IterTraits::difference_type _Dist; + + for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i) { if (__comp(__i, __first)) { - typename iterator_traits<_RandomAccessIterator>::value_type - __val = _GLIBCXX_MOVE(*__i); - _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1); + typename _IterTraits::value_type __val = _GLIBCXX_MOVE(*__i); + _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + _Dist(1)); *__first = _GLIBCXX_MOVE(__val); } else @@ -1812,10 +1816,13 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) __final_insertion_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { - if (__last - __first > int(_S_threshold)) + typename iterator_traits<_RandomAccessIterator>::difference_type + __threshold = _S_threshold; + + if (__last - __first > __threshold) { - std::__insertion_sort(__first, __first + int(_S_threshold), __comp); - std::__unguarded_insertion_sort(__first + int(_S_threshold), __last, + std::__insertion_sort(__first, __first + __threshold, __comp); + std::__unguarded_insertion_sort(__first + __threshold, __last, __comp); } else @@ -1851,10 +1858,14 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) __unguarded_partition_pivot(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { - _RandomAccessIterator __mid = __first + (__last - __first) / 2; - std::__move_median_to_first(__first, __first + 1, __mid, __last - 1, + typedef iterator_traits<_RandomAccessIterator> _IterTraits; + typedef typename _IterTraits::difference_type _Dist; + + _RandomAccessIterator __mid = __first + _Dist((__last - __first) / 2); + _RandomAccessIterator __second = __first + _Dist(1); + std::__move_median_to_first(__first, __second, __mid, __last - _Dist(1), __comp); - return std::__unguarded_partition(__first + 1, __last, __first, __comp); + return std::__unguarded_partition(__second, __last, __first, __comp); } template<typename _RandomAccessIterator, typename _Compare> @@ -1916,11 +1927,14 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) _RandomAccessIterator __last, _Size __depth_limit, _Compare __comp) { + _RandomAccessIterator __after_nth = __nth; + ++__after_nth; + while (__last - __first > 3) { if (__depth_limit == 0) { - std::__heap_select(__first, __nth + 1, __last, __comp); + std::__heap_select(__first, __after_nth, __last, __comp); // Place the nth largest element in its final position. std::iter_swap(__first, __nth); return; @@ -3822,7 +3836,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO { if (__n2 <= 0) return __first; - auto __last = __first + __n2; + typename iterator_traits<_InputIterator>::difference_type __d = __n2; + auto __last = __first + __d; std::for_each(__first, __last, std::move(__f)); return __last; } @@ -4544,6 +4559,9 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO if (__first == __last) return; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _Dist; + #if RAND_MAX < __INT_MAX__ if (__builtin_expect((__last - __first) >= RAND_MAX / 4, 0)) { @@ -4551,14 +4569,15 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO // instead of using rand() for all the random numbers needed. unsigned __xss = (unsigned)std::rand() ^ ((unsigned)std::rand() << 15); - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; + ++__i) { __xss += !__xss; __xss ^= __xss << 13; __xss ^= __xss >> 17; __xss ^= __xss << 5; - _RandomAccessIterator __j = __first - + (__xss % ((__i - __first) + 1)); + _RandomAccessIterator __j + = __first + _Dist(__xss % ((__i - __first) + 1)); if (__i != __j) std::iter_swap(__i, __j); } @@ -4566,11 +4585,11 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } #endif - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i) { // XXX rand() % N is not uniformly distributed - _RandomAccessIterator __j = __first - + (std::rand() % ((__i - __first) + 1)); + _RandomAccessIterator __j + = __first + _Dist(std::rand() % ((__i - __first) + 1)); if (__i != __j) std::iter_swap(__i, __j); } @@ -4611,9 +4630,14 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO if (__first == __last) return; - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _Dist; + + for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i) { - _RandomAccessIterator __j = __first + __rand((__i - __first) + 1); + _RandomAccessIterator __j + = __first + _Dist(__rand((__i - __first) + 1)); if (__i != __j) std::iter_swap(__i, __j); } diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index b104ec2536a0..820091aee2dc 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -1150,10 +1150,12 @@ _GLIBCXX_END_NAMESPACE_CONTAINER if (__n <= 0) return __first; - __glibcxx_requires_can_increment(__first, __n); + typename iterator_traits<_OutputIterator>::difference_type __d = __n; + __glibcxx_requires_can_increment(__first, __d); - std::__fill_a(__first, __first + __n, __value); - return __first + __n; + _OutputIterator __last = __first + __d; + std::__fill_a(__first, __last, __value); + return __last; } /** @@ -1310,11 +1312,11 @@ _GLIBCXX_END_NAMESPACE_CONTAINER __newlast1(_RAI1 __first1, _RAI1 __last1, _RAI2 __first2, _RAI2 __last2) { - const typename iterator_traits<_RAI1>::difference_type - __diff1 = __last1 - __first1; - const typename iterator_traits<_RAI2>::difference_type - __diff2 = __last2 - __first2; - return __diff2 < __diff1 ? __first1 + __diff2 : __last1; + typedef typename iterator_traits<_RAI1>::difference_type _Diff1; + typedef typename iterator_traits<_RAI2>::difference_type _Diff2; + const _Diff1 __diff1 = __last1 - __first1; + const _Diff2 __diff2 = __last2 - __first2; + return __diff2 < __diff1 ? __first1 + _Diff1(__diff2) : __last1; } template<typename _RAI> diff --git a/libstdc++-v3/include/bits/stl_heap.h b/libstdc++-v3/include/bits/stl_heap.h index 028ac83eeb70..0e9c94c6865b 100644 --- a/libstdc++-v3/include/bits/stl_heap.h +++ b/libstdc++-v3/include/bits/stl_heap.h @@ -76,6 +76,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __is_heap_until(_RandomAccessIterator __first, _Distance __n, _Compare& __comp) { +#if __cplusplus >= 201103L + using _IterTraits = iterator_traits<_RandomAccessIterator>; + static_assert(is_same<typename _IterTraits::difference_type, + _Distance>::value, + "Argument 'n' must be the iterator's difference type"); +#endif _Distance __parent = 0; for (_Distance __child = 1; __child < __n; ++__child) { @@ -94,8 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline bool __is_heap(_RandomAccessIterator __first, _Distance __n) { + typename iterator_traits<_RandomAccessIterator>::difference_type __d(__n); __gnu_cxx::__ops::_Iter_less_iter __comp; - return std::__is_heap_until(__first, __n, __comp) == __n; + return std::__is_heap_until(__first, __d, __comp) == __n; } template<typename _RandomAccessIterator, typename _Compare, @@ -104,9 +111,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline bool __is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n) { + typename iterator_traits<_RandomAccessIterator>::difference_type __d(__n); typedef __decltype(__comp) _Cmp; __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp)); - return std::__is_heap_until(__first, __n, __cmp) == __n; + return std::__is_heap_until(__first, __d, __cmp) == __n; } template<typename _RandomAccessIterator> @@ -175,7 +183,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_requires_heap(__first, __last - 1); __gnu_cxx::__ops::_Iter_less_val __comp; - _ValueType __value = _GLIBCXX_MOVE(*(__last - 1)); + _ValueType __value = _GLIBCXX_MOVE(*(__last - _DistanceType(1))); std::__push_heap(__first, _DistanceType((__last - __first) - 1), _DistanceType(0), _GLIBCXX_MOVE(__value), __comp); } @@ -208,11 +216,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _RandomAccessIterator>) __glibcxx_requires_valid_range(__first, __last); __glibcxx_requires_irreflexive_pred(__first, __last, __comp); - __glibcxx_requires_heap_pred(__first, __last - 1, __comp); + __glibcxx_requires_heap_pred(__first, __last - _DistanceType(1), __comp); __decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp))) __cmp(_GLIBCXX_MOVE(__comp)); - _ValueType __value = _GLIBCXX_MOVE(*(__last - 1)); + _ValueType __value = _GLIBCXX_MOVE(*(__last - _DistanceType(1))); std::__push_heap(__first, _DistanceType((__last - __first) - 1), _DistanceType(0), _GLIBCXX_MOVE(__value), __cmp); } diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index bf40995659d1..9d3410f3a2cd 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -1345,7 +1345,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } if (__j < 0) { - const auto __match = __first + __i + 1; + const auto __match = __first + __i + __diff_type(1); return std::make_pair(__match, __match + __patlen); } __i += std::max(_M_bad_char_shift(__first[__i]), diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc index 2f48181fb675..8229b1ee6c16 100644 --- a/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc +++ b/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc @@ -42,7 +42,7 @@ test01() std::ranges::advance(iter, -2); VERIFY( iter == r.begin() ); - std::ranges::advance(iter, r.begin() + 1); + std::ranges::advance(iter, std::ranges::next(r.begin())); VERIFY( iter != r.begin() ); VERIFY( iter != r.end() ); std::ranges::advance(iter, r.begin()); diff --git a/libstdc++-v3/testsuite/25_algorithms/fill_n/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/fill_n/diff_type.cc new file mode 100644 index 000000000000..7265d396217d --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/fill_n/diff_type.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } + +#include <algorithm> +#include <testsuite_iterators.h> + +void +test_pr121890() +{ + // algorithms do not use iterator's difference_type for arithmetic + int a[1]; + __gnu_test::random_access_container<int> c(a); + std::fill_n(c.begin(), 1U, 0); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/for_each/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/for_each/diff_type.cc new file mode 100644 index 000000000000..d78ba192fa8f --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/for_each/diff_type.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++17 } } + +#include <algorithm> +#include <testsuite_iterators.h> + +void +test_pr121890() +{ + // algorithms do not use iterator's difference_type for arithmetic + int a[1]; + __gnu_test::random_access_container<int> c(a); + std::for_each_n(c.begin(), 1U, [](int){}); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc index 5486c8552d03..2f818e2b2870 100644 --- a/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc @@ -53,17 +53,17 @@ test01() iter = ranges::pop_heap(rx, pred, proj); VERIFY( iter == rx.end() ); - VERIFY( *(iter-1) == 50 ); - VERIFY( ranges::is_heap_until(rx, pred, proj) == iter-1 ); + VERIFY( *ranges::prev(iter) == 50 ); + VERIFY( ranges::is_heap_until(rx, pred, proj) == ranges::prev(iter) ); - iter = ranges::pop_heap(rx.begin(), iter-1, pred, proj); - VERIFY( iter+1 == rx.end() ); - VERIFY( *(iter-1) == 49 ); - VERIFY( ranges::is_heap_until(rx, pred, proj) == iter-1 ); + iter = ranges::pop_heap(rx.begin(), ranges::prev(iter), pred, proj); + VERIFY( ranges::next(iter) == rx.end() ); + VERIFY( *ranges::prev(iter) == 49 ); + VERIFY( ranges::is_heap_until(rx, pred, proj) == ranges::prev(iter) ); - *(iter-1) = i; + *ranges::prev(iter) = i; iter = ranges::push_heap(rx.begin(), iter, pred, proj); - VERIFY( iter+1 == rx.end() ); + VERIFY( ranges::next(iter) == rx.end() ); VERIFY( ranges::is_heap_until(rx, pred, proj) == iter ); *iter = 2*i; @@ -71,9 +71,9 @@ test01() VERIFY( iter == rx.end() ); VERIFY( ranges::is_heap_until(rx, pred, proj) == iter ); - *(rx.begin()+1) *= -1; + *ranges::next(rx.begin()) *= -1; VERIFY( !ranges::is_heap(rx, pred, proj) ); - *(rx.begin()+1) *= -1; + *ranges::next(rx.begin()) *= -1; VERIFY( ranges::is_heap(rx, pred, proj) ); iter = ranges::sort_heap(rx, pred, proj); diff --git a/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/diff_type.cc new file mode 100644 index 000000000000..b790197715b6 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/diff_type.cc @@ -0,0 +1,57 @@ +// { dg-do compile { target c++11 } } + +#include <algorithm> +#include <testsuite_iterators.h> + +struct Iter +{ + using value_type = int; + using difference_type = short; + using iterator_category = std::random_access_iterator_tag; + using pointer = const value_type*; + using reference = const value_type&; + + Iter() : p(nullptr) { } + explicit Iter(pointer p) : p(p) { } + reference operator*() const { return *p; } + pointer operator->() const { return p; } + reference operator[](difference_type n) const { return p[n]; } + Iter& operator++() { ++p; return *this; } + Iter& operator--() { --p; return *this; } + Iter operator++(int) { return Iter(p++); } + Iter operator--(int) { return Iter(p--); } + Iter& operator+=(difference_type n) { p += n; return *this; } + Iter& operator-=(difference_type n) { p -= n; return *this; } + + friend Iter operator+(Iter i, difference_type n) { return i += n; } + friend Iter operator+(difference_type n, Iter i) { return i += n; } + friend Iter operator-(Iter i, difference_type n) { return i -= n; } + friend difference_type operator-(Iter i, Iter j) { return i.p - j.p; } + + template<typename D> void operator[](D) const = delete; + template<typename D> void operator+=(D) = delete; + template<typename D> void operator-=(D) = delete; + template<typename D> friend void operator+(Iter, difference_type) = delete; + template<typename D> friend void operator+(difference_type, Iter) = delete; + template<typename D> friend void operator-(Iter, difference_type) = delete; + + friend bool operator==(Iter i, Iter j) { return i.p == j.p; } + friend bool operator!=(Iter i, Iter j) { return i.p != j.p; } + friend bool operator<(Iter i, Iter j) { return i.p < j.p; } + friend bool operator<=(Iter i, Iter j) { return i.p <= j.p; } + friend bool operator>(Iter i, Iter j) { return i.p > j.p; } + friend bool operator>=(Iter i, Iter j) { return i.p >= j.p; } + +private: + pointer p; +}; + +void +test_pr121890() +{ + // algorithms do not use iterator's difference_type for arithmetic + int a[1] = { }; + __gnu_test::random_access_container<int> c(a); + (void) std::lexicographical_compare(c.begin(), c.end(), Iter(a), Iter(a+1)); + (void) std::lexicographical_compare(Iter(a), Iter(a+1), c.begin(), c.end()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc index 3989ee0bbb50..ff86c63614f5 100644 --- a/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc +++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc @@ -43,7 +43,7 @@ void test01() Container con(v.data(), v.data() + 7); - std::nth_element(con.begin(), con.begin() + 3, con.end()); + std::nth_element(con.begin(), std::next(con.begin(), 3), con.end()); } int main() diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc index 8cb1625dd4d5..8d3a057e93dc 100644 --- a/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc @@ -38,7 +38,7 @@ test01() auto pred = std::greater{}; auto proj = [] (int a) { return -a; }; - for (int i = 0; i < 50; i++) + for (std::ptrdiff_t i = 0; i < 50; i++) { test_range<int, random_access_iterator_wrapper> rx(x); std::ranlux48_base g(i); diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/diff_type.cc new file mode 100644 index 000000000000..4cc9ca92698a --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/diff_type.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } + +#include <algorithm> +#include <testsuite_iterators.h> + +void +test_pr121890() +{ + // algorithms do not use iterator's difference_type for arithmetic + int a[1] = { }; + __gnu_test::random_access_container<int> c(a); + std::nth_element(c.begin(), c.begin(), c.end()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/random_test.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/random_test.cc index 2e9d4b3b6e1e..9eaef61c1690 100644 --- a/libstdc++-v3/testsuite/25_algorithms/nth_element/random_test.cc +++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/random_test.cc @@ -37,9 +37,9 @@ struct testNthElement template<typename Container, typename RandomGen> void operator()(Container con, RandomGen& rg) { - const int size = con.end() - con.begin(); + const auto size = con.end() - con.begin(); auto dist = std::uniform_int_distribution<>(0, size); - const int element = dist(rg); + const decltype(size) element = dist(rg); std::nth_element(con.begin(), con.begin() + element, con.end()); diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc index 05f4f1cbdb55..e1ba840a5a3c 100644 --- a/libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc +++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc @@ -43,7 +43,7 @@ test01() 17, 8, 18, 9, 19 }; const int N = sizeof(s1) / sizeof(V); Container con(s1, s1 + N); - std::partial_sort(con.begin(), con.begin() + 10, con.end()); + std::partial_sort(con.begin(), std::next(con.begin(), 10), con.end()); VERIFY( s1[0].ok ); for(int i = 1; i < 10; ++i) VERIFY( s1[i].val > s1[i - 1].val && s1[i].ok ); @@ -59,7 +59,7 @@ test02() 17, 8, 18, 9, 19 }; const int N = sizeof(s1) / sizeof(V); Container con(s1, s1 + N); - std::partial_sort(con.begin(), con.begin() + 10, con.end(), + std::partial_sort(con.begin(), std::next(con.begin(), 10), con.end(), __gnu_test::order); VERIFY( s1[0].ok ); for(int i = 1; i < 10; ++i) diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc index 032ffe75d890..554a8d76a4b8 100644 --- a/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc @@ -47,7 +47,8 @@ test01() ranges::shuffle(c, g1); ranges::shuffle(ranges::begin(r), ranges::end(r), g2); - for (unsigned middle = 0; middle < std::min(size, 10U); ++middle) + for (std::ptrdiff_t middle = 0, end = std::min(size, 10U); + middle < end; ++middle) { auto res1 = ranges::partial_sort(c.begin(), c.begin()+middle, c.end(), {}, std::negate<>{}); diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc index 89eb99266608..4e690008e74a 100644 --- a/libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc +++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc @@ -37,9 +37,9 @@ struct testPartialSort template<typename Container, typename RandomGen> void operator()(Container con, RandomGen& rg) { - const int size = con.end() - con.begin(); + const auto size = con.end() - con.begin(); auto dist = std::uniform_int_distribution<>(0, size); - const int element = dist(rg); + const decltype(size) element = dist(rg); std::partial_sort(con.begin(), con.begin() + element, con.end()); diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc index a0bd48be638b..38b2dda45199 100644 --- a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc @@ -35,7 +35,7 @@ namespace ranges = std::ranges; void test01() { - for (unsigned size = 0; size < 50; ++size) + for (std::ptrdiff_t size = 0; size < 50; ++size) { std::vector<int> vref(size); std::iota(vref.begin(), vref.end(), 0); @@ -45,7 +45,7 @@ test01() ranges::shuffle(v1, g1); ranges::shuffle(v2, g2); - for (unsigned middle = 0; middle < 10; ++middle) + for (std::ptrdiff_t middle = 0; middle < 10; ++middle) { test_container<int, forward_iterator_wrapper> c = {v1.data(), v1.data() + size}; diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc index 2c0b8bca2bef..be033a240140 100644 --- a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc +++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc @@ -38,9 +38,9 @@ struct testPartialSortCopy template<typename Container, typename RandomGen> void operator()(Container con, RandomGen& rg) { - const int size = con.end() - con.begin(); + const auto size = con.end() - con.begin(); auto dist = std::uniform_int_distribution<>(0, size); - const int element = dist(rg); + const decltype(size) element = dist(rg); std::vector<int> outvec(element + 1); // add +1 to avoid empty issues diff --git a/libstdc++-v3/testsuite/25_algorithms/push_heap/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/push_heap/diff_type.cc new file mode 100644 index 000000000000..ab4587e946d0 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/push_heap/diff_type.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } + +#include <algorithm> +#include <testsuite_iterators.h> + +void +test_pr121890() +{ + // algorithms do not use iterator's difference_type for arithmetic + int a[1] = { }; + __gnu_test::random_access_container<int> c(a); + std::push_heap(c.begin(), c.end()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/rotate/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/rotate/diff_type.cc new file mode 100644 index 000000000000..cbf2958df0fb --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/rotate/diff_type.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } + +#include <algorithm> +#include <testsuite_iterators.h> + +void +test_pr121890() +{ + // algorithms do not use iterator's difference_type for arithmetic + int a[1] = { }; + __gnu_test::random_access_container<int> c(a); + std::rotate(c.begin(), c.begin(), c.end()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/search_n/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/search_n/diff_type.cc new file mode 100644 index 000000000000..20253e9ca2a6 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/search_n/diff_type.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } + +#include <algorithm> +#include <testsuite_iterators.h> + +void +test_pr121890() +{ + // algorithms do not use iterator's difference_type for arithmetic + int a[1] = { }; + __gnu_test::random_access_container<int> c(a); + (void) std::search_n(c.begin(), c.begin(), 1U, 0); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/sort/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/sort/diff_type.cc new file mode 100644 index 000000000000..52a83e88ff81 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/sort/diff_type.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } + +#include <algorithm> +#include <testsuite_iterators.h> + +void +test_pr121890() +{ + // algorithms do not use iterator's difference_type for arithmetic + int a[1] = { }; + __gnu_test::random_access_container<int> c(a); + std::sort(c.begin(), c.begin()); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc index 4583fb0e7130..57db806069ed 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc @@ -243,7 +243,7 @@ test08() long b[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; test_range<long, ra_test_wrapper> rb(b); - ranges::subrange sized = {rb.begin(), rb.begin()+6}; + ranges::subrange sized = {rb.begin(), ranges::next(rb.begin(), 6)}; using Sized = decltype(sized); static_assert( ranges::random_access_range<Sized> ); static_assert( ranges::sized_range<Sized> ); diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h index acd412af0f22..5bf2e704e843 100644 --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h @@ -607,6 +607,16 @@ namespace __gnu_test T& operator[](std::ptrdiff_t n) const { return *(*this + n); } +#if __cplusplus >= 201103L + // Ensure that the iterator's difference_type is always used. + template<typename D> void operator+=(D) = delete; + template<typename D> void operator-=(D) = delete; + template<typename D> void operator[](D) const = delete; + template<typename D> + typename std::enable_if<std::is_integral<D>::value>::type + operator-(D) const = delete; +#endif + _GLIBCXX14_CONSTEXPR bool operator<(const random_access_iterator_wrapper<T>& in) const { @@ -645,6 +655,14 @@ namespace __gnu_test operator+(std::ptrdiff_t n, random_access_iterator_wrapper<T> it) { return it += n; } +#if __cplusplus >= 201103L + // Ensure that the iterator's difference_type is always used. + template<typename T, typename D> + void operator+(random_access_iterator_wrapper<T>, D) = delete; + template<typename T, typename D> + void operator+(D, random_access_iterator_wrapper<T>) = delete; +#endif + /** * @brief A container-type class for holding iterator wrappers -- 2.51.0