libstdc++: Fix algorithms to use iterators' difference_type for arithmetic [PR121890]

Message ID 20250911213937.1648612-1-jwakely@redhat.com
State New
Headers
Series libstdc++: Fix algorithms to use iterators' difference_type for arithmetic [PR121890] |

Commit Message

Jonathan Wakely Sept. 11, 2025, 9:37 p.m. UTC
  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. Use local variables in
	rotate to avoid duplicate expressions.
	(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.
	Use local variables in __rotate to avoid duplicate expressions.
	* 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.
---

v3: Change in boyer_moore_searcher suggested by Tomasz. Reverted
unnecessary ranges::next in ranges::rotate noticed by Patrick, and
changed it to use local variables as done for std::rotate in v2.

Tested powerpc64le-linux.

 libstdc++-v3/include/bits/ranges_algo.h       | 57 +++++++------
 libstdc++-v3/include/bits/ranges_base.h       |  4 +-
 libstdc++-v3/include/bits/stl_algo.h          | 81 +++++++++++++------
 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, 307 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
  

Comments

Jonathan Wakely Sept. 12, 2025, 11:05 a.m. UTC | #1
On Thu, 11 Sept 2025 at 22:41, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> 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. Use local variables in
>         rotate to avoid duplicate expressions.
>         (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.
>         Use local variables in __rotate to avoid duplicate expressions.
>         * 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.
> ---
>
> v3: Change in boyer_moore_searcher suggested by Tomasz. Reverted
> unnecessary ranges::next in ranges::rotate noticed by Patrick, and
> changed it to use local variables as done for std::rotate in v2.

I found one more change that's needed for debug mode:

--- a/libstdc++-v3/include/bits/stl_heap.h
+++ b/libstdc++-v3/include/bits/stl_heap.h
@@ -180,7 +180,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
      __glibcxx_requires_valid_range(__first, __last);
      __glibcxx_requires_irreflexive(__first, __last);
-      __glibcxx_requires_heap(__first, __last - 1);
+      __glibcxx_requires_heap(__first, __last - _DistanceType(1));

      __gnu_cxx::__ops::_Iter_less_val __comp;
      _ValueType __value = _GLIBCXX_MOVE(*(__last - _DistanceType(1)));


I'm also removing all but these two of the new tests:

       * testsuite/25_algorithms/fill_n/diff_type.cc: New test.
       * testsuite/25_algorithms/lexicographical_compare/diff_type.cc

That's because for the other algos the existing tests already use
__gnu_test::random_access_iterator_wrapper and so already fail with
the new deleted operators in that wrapper. So we don't need new tests
to check things that we're already checking.

For fill_n and lexicographical_compare, the existing tests didn't
trigger the deleted operators.
  
Patrick Palka Sept. 12, 2025, 5:16 p.m. UTC | #2
On Fri, 12 Sep 2025, Jonathan Wakely wrote:

> On Thu, 11 Sept 2025 at 22:41, Jonathan Wakely <jwakely@redhat.com> wrote:
> >
> > 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. Use local variables in
> >         rotate to avoid duplicate expressions.
> >         (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.
> >         Use local variables in __rotate to avoid duplicate expressions.
> >         * 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.
> > ---
> >
> > v3: Change in boyer_moore_searcher suggested by Tomasz. Reverted
> > unnecessary ranges::next in ranges::rotate noticed by Patrick, and
> > changed it to use local variables as done for std::rotate in v2.
> 
> I found one more change that's needed for debug mode:
> 
> --- a/libstdc++-v3/include/bits/stl_heap.h
> +++ b/libstdc++-v3/include/bits/stl_heap.h
> @@ -180,7 +180,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
>       __glibcxx_requires_valid_range(__first, __last);
>       __glibcxx_requires_irreflexive(__first, __last);
> -      __glibcxx_requires_heap(__first, __last - 1);
> +      __glibcxx_requires_heap(__first, __last - _DistanceType(1));
> 
>       __gnu_cxx::__ops::_Iter_less_val __comp;
>       _ValueType __value = _GLIBCXX_MOVE(*(__last - _DistanceType(1)));
> 
> 
> I'm also removing all but these two of the new tests:
> 
>        * testsuite/25_algorithms/fill_n/diff_type.cc: New test.
>        * testsuite/25_algorithms/lexicographical_compare/diff_type.cc
> 
> That's because for the other algos the existing tests already use
> __gnu_test::random_access_iterator_wrapper and so already fail with
> the new deleted operators in that wrapper. So we don't need new tests
> to check things that we're already checking.
> 
> For fill_n and lexicographical_compare, the existing tests didn't
> trigger the deleted operators.

LGTM
  

Patch

diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 6e1e06cb2d0f..609b82e26d8a 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1666,68 +1666,72 @@  namespace ranges
 	    auto __k = __middle - __first;
 
 	    if (__k == __n - __k)
 	      {
 		ranges::swap_ranges(__first, __middle, __middle, __middle + __k);
 		return {std::move(__middle), std::move(__lasti)};
 	      }
 
 	    auto __p = __first;
 	    auto __ret = __first + (__lasti - __middle);
 
 	    for (;;)
 	      {
 		if (__k < __n - __k)
 		  {
 		    // TODO: is_pod is deprecated, but this condition is
 		    // consistent with the STL implementation.
 		    if constexpr (__is_pod(iter_value_t<_Iter>))
 		      if (__k == 1)
 			{
+			  auto __mid = ranges::next(__p, __n - 1);
+			  auto __end = ranges::next(__mid);
 			  auto __t = std::move(*__p);
-			  ranges::move(__p + 1, __p + __n, __p);
-			  *(__p + __n - 1) = std::move(__t);
+			  ranges::move(ranges::next(__p), __end, __p);
+			  *__mid = std::move(__t);
 			  return {std::move(__ret), std::move(__lasti)};
 			}
 		    auto __q = __p + __k;
 		    for (decltype(__n) __i = 0; __i < __n - __k; ++ __i)
 		      {
 			ranges::iter_swap(__p, __q);
 			++__p;
 			++__q;
 		      }
 		    __n %= __k;
 		    if (__n == 0)
 		      return {std::move(__ret), std::move(__lasti)};
 		    ranges::swap(__n, __k);
 		    __k = __n - __k;
 		  }
 		else
 		  {
 		    __k = __n - __k;
 		    // TODO: is_pod is deprecated, but this condition is
 		    // consistent with the STL implementation.
 		    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 __mid = ranges::next(__p, __n - 1);
+			  auto __end = ranges::next(__mid);
+			  auto __t = std::move(*__mid);
+			  ranges::move_backward(__p, __mid, __end);
 			  *__p = std::move(__t);
 			  return {std::move(__ret), std::move(__lasti)};
 			}
 		    auto __q = __p + __n;
 		    __p = __q - __k;
 		    for (decltype(__n) __i = 0; __i < __n - __k; ++ __i)
 		      {
 			--__p;
 			--__q;
 			ranges::iter_swap(__p, __q);
 		      }
 		    __n %= __k;
 		    if (__n == 0)
 		      return {std::move(__ret), std::move(__lasti)};
 		    std::swap(__n, __k);
 		  }
 	      }
 	  }
 	else if constexpr (bidirectional_iterator<_Iter>)
 	  {
@@ -1953,75 +1957,77 @@  namespace ranges
       operator()(_Iter __first, _Sent __last, _Gen&& __g) const
       {
 	// FIXME: Correctly handle integer-class difference types.
 	if (__first == __last)
 	  return __first;
 
 	using _DistanceType = iter_difference_t<_Iter>;
 	using __ud_type = __detail::__make_unsigned_like_t<_DistanceType>;
 	using __distr_type = std::uniform_int_distribution<__ud_type>;
 	using __p_type = typename __distr_type::param_type;
 
 	using __uc_type
 	  = common_type_t<typename remove_reference_t<_Gen>::result_type, __ud_type>;
 
 	const __uc_type __urngrange = __g.max() - __g.min();
 	const __uc_type __urange = __uc_type(__last - __first);
 
 	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
 	    // do the first one up front:
 
 	    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,
 	    // using a single distribution invocation to produce swap positions
 	    // for two successive elements at a time:
 
 	    while (__i != __last)
 	      {
 		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;
 	  }
 
 	__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;
       }
 
     template<random_access_range _Range, typename _Gen>
       requires permutable<iterator_t<_Range>>
 	&& uniform_random_bit_generator<remove_reference_t<_Gen>>
       borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Gen&& __g) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
 		       std::forward<_Gen>(__g));
       }
   };
 
   inline constexpr __shuffle_fn shuffle{};
 
   namespace __detail
   {
     template<typename _Iter, typename _Comp>
@@ -2043,41 +2049,41 @@  namespace ranges
 	*(__first + __holeIndex) = std::move(__value);
       }
   } // namespace __detail
 
   struct __push_heap_fn
   {
     template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<_Iter, _Comp, _Proj>
       constexpr _Iter
       operator()(_Iter __first, _Sent __last,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
 	if constexpr (!same_as<_Iter, _Sent>)
 	  return (*this)(__first, ranges::next(__first, __last),
 			 std::move(__comp), std::move(__proj));
 	else
 	  {
 	    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;
 	  }
       }
 
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
       constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
 		       std::move(__comp), std::move(__proj));
       }
   };
 
   inline constexpr __push_heap_fn push_heap{};
 
   namespace __detail
   {
@@ -2120,42 +2126,43 @@  namespace ranges
 				std::move(__value), __comp);
       }
   } // namespace __detail
 
   struct __pop_heap_fn
   {
     template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<_Iter, _Comp, _Proj>
       constexpr _Iter
       operator()(_Iter __first, _Sent __last,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
 	if constexpr (!same_as<_Iter, _Sent>)
 	  return (*this)(__first, ranges::next(__first, __last),
 			 std::move(__comp), std::move(__proj));
 	else
 	  {
 	    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;
 	  }
       }
 
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
       constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
 		       std::move(__comp), std::move(__proj));
       }
   };
 
   inline constexpr __pop_heap_fn pop_heap{};
 
   struct __make_heap_fn
   {
@@ -2339,102 +2346,105 @@  namespace ranges
       {
 	iter_value_t<_Iter> __val = ranges::iter_move(__last);
 	_Iter __next = __last;
 	--__next;
 	while (__comp(__val, *__next))
 	  {
 	    *__last = ranges::iter_move(__next);
 	    __last = __next;
 	    --__next;
 	  }
 	*__last = std::move(__val);
       }
 
     template<typename _Iter, typename _Comp>
       constexpr void
       __insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
       {
 	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
 	      __detail::__unguarded_linear_insert(__i, __comp);
 	  }
       }
 
     template<typename _Iter, typename _Comp>
       constexpr void
       __unguarded_insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
       {
 	for (_Iter __i = __first; __i != __last; ++__i)
 	  __detail::__unguarded_linear_insert(__i, __comp);
       }
 
     inline constexpr int __sort_threshold = 16;
 
     template<typename _Iter, typename _Comp>
       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
 	  __detail::__insertion_sort(__first, __last, __comp);
       }
 
     template<typename _Iter, typename _Comp>
       constexpr _Iter
       __unguarded_partition(_Iter __first, _Iter __last, _Iter __pivot, _Comp __comp)
       {
 	while (true)
 	  {
 	    while (__comp(*__first, *__pivot))
 	      ++__first;
 	    --__last;
 	    while (__comp(*__pivot, *__last))
 	      --__last;
 	    if (!(__first < __last))
 	      return __first;
 	    ranges::iter_swap(__first, __last);
 	    ++__first;
 	  }
       }
 
     template<typename _Iter, typename _Comp>
       constexpr _Iter
       __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>
       constexpr void
       __heap_select(_Iter __first, _Iter __middle, _Iter __last, _Comp __comp)
       {
 	ranges::make_heap(__first, __middle, __comp);
 	for (_Iter __i = __middle; __i < __last; ++__i)
 	  if (__comp(*__i, *__first))
 	    __detail::__pop_heap(__first, __middle, __i, __comp);
       }
 
     template<typename _Iter, typename _Comp>
       constexpr void
       __partial_sort(_Iter __first, _Iter __middle, _Iter __last, _Comp __comp)
       {
 	__detail::__heap_select(__first, __middle, __last, __comp);
 	ranges::sort_heap(__first, __middle, __comp);
       }
 
@@ -2728,41 +2738,41 @@  namespace ranges
   struct __partial_sort_fn
   {
     template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<_Iter, _Comp, _Proj>
       constexpr _Iter
       operator()(_Iter __first, _Iter __middle, _Sent __last,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
 	if (__first == __middle)
 	  return ranges::next(__first, __last);
 
 	ranges::make_heap(__first, __middle, __comp, __proj);
 	auto __i = __middle;
 	for (; __i != __last; ++__i)
 	  if (std::__invoke(__comp,
 			    std::__invoke(__proj, *__i),
 			    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);
 
 	return __i;
       }
 
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
       constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, iterator_t<_Range> __middle,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), std::move(__middle),
 		       ranges::end(__r),
 		       std::move(__comp), std::move(__proj));
       }
   };
 
@@ -2795,41 +2805,41 @@  namespace ranges
 					std::move(__last));
 	    return {std::move(__lasti), std::move(__result_first)};
 	  }
 
 	auto __result_real_last = __result_first;
 	while (__first != __last && __result_real_last != __result_last)
 	  {
 	    *__result_real_last = *__first;
 	    ++__result_real_last;
 	    ++__first;
 	  }
 
 	ranges::make_heap(__result_first, __result_real_last, __comp, __proj2);
 	for (; __first != __last; ++__first)
 	  if (std::__invoke(__comp,
 			    std::__invoke(__proj1, *__first),
 			    std::__invoke(__proj2, *__result_first)))
 	    {
 	      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);
 	    }
 	ranges::sort_heap(__result_first, __result_real_last, __comp, __proj2);
 
 	return {std::move(__first), std::move(__result_real_last)};
       }
 
     template<input_range _Range1, random_access_range _Range2,
 	     typename _Comp = ranges::less,
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires indirectly_copyable<iterator_t<_Range1>, iterator_t<_Range2>>
 	&& sortable<iterator_t<_Range2>, _Comp, _Proj2>
 	&& indirect_strict_weak_order<_Comp,
 				      projected<iterator_t<_Range1>, _Proj1>,
 				      projected<iterator_t<_Range2>, _Proj2>>
       constexpr partial_sort_copy_result<borrowed_iterator_t<_Range1>,
 					 borrowed_iterator_t<_Range2>>
       operator()(_Range1&& __r, _Range2&& __out, _Comp __comp = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
@@ -2907,41 +2917,42 @@  namespace ranges
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
 		       std::move(__comp), std::move(__proj));
       }
   };
 
   inline constexpr __is_sorted_fn is_sorted{};
 
   namespace __detail
   {
     template<typename _Iter, typename _Comp>
       constexpr void
       __introselect(_Iter __first, _Iter __nth, _Iter __last,
 		    iter_difference_t<_Iter> __depth_limit, _Comp __comp)
       {
 	while (__last - __first > 3)
 	  {
 	    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;
 	      }
 	    --__depth_limit;
 	    _Iter __cut = __detail::__unguarded_partition_pivot(__first, __last, __comp);
 	    if (__cut <= __nth)
 	      __first = __cut;
 	    else
 	      __last = __cut;
 	  }
 	__detail::__insertion_sort(__first, __last, __comp);
       }
   } // namespace __detail
 
   struct __nth_element_fn
   {
     template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<_Iter, _Comp, _Proj>
diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
index 27829086a351..1c4bf432c8f4 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -883,61 +883,61 @@  namespace ranges
 	  {
 	    while (__it != __bound)
 	      ++__it;
 	  }
       }
 
     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
       constexpr iter_difference_t<_It>
       operator()(_It& __it, iter_difference_t<_It> __n, _Sent __bound) const
       {
 	if constexpr (sized_sentinel_for<_Sent, _It>)
 	  {
 	    const iter_difference_t<_It> __diff = __bound - __it;
 
 	    if (__diff == 0)
 	      {
 		// inline any possible side effects of advance(it, bound)
 		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)
 	      {
 		(*this)(__it, __bound);
 		return __n - __diff;
 	      }
 	    else if (__n != 0) [[likely]]
 	      {
 		// n and bound must not lead in opposite directions:
 		__glibcxx_assert((__n < 0) == (__diff < 0));
 
 		(*this)(__it, __n);
 		return 0;
 	      }
 	    else
 	      {
 		// 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;
 	      }
 	  }
 	else if (__n == 0 || __it == __bound)
 	  return __n;
 	else if (__n > 0)
 	  {
 	    iter_difference_t<_It> __m = 0;
 	    do
 	      {
 		++__it;
 		++__m;
 	      }
 	    while (__m != __n && __it != __bound);
 	    return __n - __m;
 	  }
 	else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>)
 	  {
 	    iter_difference_t<_It> __m = 0;
 	    do
diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h
index 81a2457ae6f2..78c63e79a279 100644
--- a/libstdc++-v3/include/bits/stl_algo.h
+++ b/libstdc++-v3/include/bits/stl_algo.h
@@ -187,41 +187,41 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __search_n_aux(_RandomAccessIter __first, _RandomAccessIter __last,
 		   _Integer __count, _UnaryPredicate __unary_pred,
 		   std::random_access_iterator_tag)
     {
       typedef typename std::iterator_traits<_RandomAccessIter>::difference_type
 	_DistanceType;
 
       _DistanceType __tailSize = __last - __first;
       _DistanceType __remainder = __count;
 
       while (__remainder <= __tailSize) // the main loop...
 	{
 	  __first += __remainder;
 	  __tailSize -= __remainder;
 	  // __first here is always pointing to one past the last element of
 	  // next possible match.
 	  _RandomAccessIter __backTrack = __first;
 	  while (__unary_pred(--__backTrack))
 	    {
 	      if (--__remainder == 0)
-		return (__first - __count); // Success
+		return __first - _DistanceType(__count); // Success
 	    }
 	  __remainder = __count + 1 - (__first - __backTrack);
 	}
       return __last; // Failure
     }
 
   template<typename _ForwardIterator, typename _Integer,
 	   typename _UnaryPredicate>
     _GLIBCXX20_CONSTEXPR
     _ForwardIterator
     __search_n(_ForwardIterator __first, _ForwardIterator __last,
 	       _Integer __count,
 	       _UnaryPredicate __unary_pred)
     {
       if (__count <= 0)
 	return __first;
 
       if (__count == 1)
 	return std::__find_if(__first, __last, __unary_pred);
 
@@ -1241,65 +1241,71 @@  _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
 #endif
 
       _Distance __n = __last   - __first;
       _Distance __k = __middle - __first;
 
       if (__k == __n - __k)
 	{
 	  std::swap_ranges(__first, __middle, __middle);
 	  return __middle;
 	}
 
       _RandomAccessIterator __p = __first;
       _RandomAccessIterator __ret = __first + (__last - __middle);
 
       for (;;)
 	{
 	  if (__k < __n - __k)
 	    {
 	      if (__is_pod(_ValueType) && __k == 1)
 		{
+		  _RandomAccessIterator __mid = __p + _Distance(__n - 1);
+		  _RandomAccessIterator __end = __mid;
+		  ++__end;
 		  _ValueType __t = _GLIBCXX_MOVE(*__p);
-		  _GLIBCXX_MOVE3(__p + 1, __p + __n, __p);
-		  *(__p + __n - 1) = _GLIBCXX_MOVE(__t);
+		  _GLIBCXX_MOVE3(__p + _Distance(1), __end, __p);
+		  *__mid = _GLIBCXX_MOVE(__t);
 		  return __ret;
 		}
 	      _RandomAccessIterator __q = __p + __k;
 	      for (_Distance __i = 0; __i < __n - __k; ++ __i)
 		{
 		  std::iter_swap(__p, __q);
 		  ++__p;
 		  ++__q;
 		}
 	      __n = static_cast<_UDistance>(__n) % static_cast<_UDistance>(__k);
 	      if (__n == 0)
 		return __ret;
 	      std::swap(__n, __k);
 	      __k = __n - __k;
 	    }
 	  else
 	    {
 	      __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);
+		  _RandomAccessIterator __mid = __p + _Distance(__n - 1);
+		  _RandomAccessIterator __end = __mid;
+		  ++__end;
+		  _ValueType __t = _GLIBCXX_MOVE(*__mid);
+		  _GLIBCXX_MOVE_BACKWARD3(__p, __mid, __end);
 		  *__p = _GLIBCXX_MOVE(__t);
 		  return __ret;
 		}
 	      _RandomAccessIterator __q = __p + __n;
 	      __p = __q - __k;
 	      for (_Distance __i = 0; __i < __n - __k; ++ __i)
 		{
 		  --__p;
 		  --__q;
 		  std::iter_swap(__p, __q);
 		}
 	      __n = static_cast<_UDistance>(__n) % static_cast<_UDistance>(__k);
 	      if (__n == 0)
 		return __ret;
 	      std::swap(__n, __k);
 	    }
 	}
     }
 
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1753,125 +1759,135 @@  _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
       typename iterator_traits<_RandomAccessIterator>::value_type
 	__val = _GLIBCXX_MOVE(*__last);
       _RandomAccessIterator __next = __last;
       --__next;
       while (__comp(__val, __next))
 	{
 	  *__last = _GLIBCXX_MOVE(*__next);
 	  __last = __next;
 	  --__next;
 	}
       *__last = _GLIBCXX_MOVE(__val);
     }
 
   /// This is a helper function for the sort routine.
   template<typename _RandomAccessIterator, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     void
     __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
 	    std::__unguarded_linear_insert(__i,
 				__gnu_cxx::__ops::__val_comp_iter(__comp));
 	}
     }
 
   /// This is a helper function for the sort routine.
   template<typename _RandomAccessIterator, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     inline void
     __unguarded_insertion_sort(_RandomAccessIterator __first,
 			       _RandomAccessIterator __last, _Compare __comp)
     {
       for (_RandomAccessIterator __i = __first; __i != __last; ++__i)
 	std::__unguarded_linear_insert(__i,
 				__gnu_cxx::__ops::__val_comp_iter(__comp));
     }
 
   /**
    *  @doctodo
    *  This controls some aspect of the sort routines.
   */
   enum { _S_threshold = 16 };
 
   /// This is a helper function for the sort routine.
   template<typename _RandomAccessIterator, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     void
     __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
 	std::__insertion_sort(__first, __last, __comp);
     }
 
   /// This is a helper function...
   template<typename _RandomAccessIterator, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     _RandomAccessIterator
     __unguarded_partition(_RandomAccessIterator __first,
 			  _RandomAccessIterator __last,
 			  _RandomAccessIterator __pivot, _Compare __comp)
     {
       while (true)
 	{
 	  while (__comp(__first, __pivot))
 	    ++__first;
 	  --__last;
 	  while (__comp(__pivot, __last))
 	    --__last;
 	  if (!(__first < __last))
 	    return __first;
 	  std::iter_swap(__first, __last);
 	  ++__first;
 	}
     }
 
   /// This is a helper function...
   template<typename _RandomAccessIterator, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     inline _RandomAccessIterator
     __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>
     _GLIBCXX20_CONSTEXPR
     inline void
     __partial_sort(_RandomAccessIterator __first,
 		   _RandomAccessIterator __middle,
 		   _RandomAccessIterator __last,
 		   _Compare __comp)
     {
       std::__heap_select(__first, __middle, __last, __comp);
       std::__sort_heap(__first, __middle, __comp);
     }
 
   /// This is a helper function for the sort routine.
   template<typename _RandomAccessIterator, typename _Size, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     void
     __introsort_loop(_RandomAccessIterator __first,
 		     _RandomAccessIterator __last,
@@ -1899,45 +1915,48 @@  _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
     inline void
     __sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
 	   _Compare __comp)
     {
       if (__first != __last)
 	{
 	  std::__introsort_loop(__first, __last,
 				std::__lg(__last - __first) * 2,
 				__comp);
 	  std::__final_insertion_sort(__first, __last, __comp);
 	}
     }
 
   template<typename _RandomAccessIterator, typename _Size, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     void
     __introselect(_RandomAccessIterator __first, _RandomAccessIterator __nth,
 		  _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;
 	    }
 	  --__depth_limit;
 	  _RandomAccessIterator __cut =
 	    std::__unguarded_partition_pivot(__first, __last, __comp);
 	  if (__cut <= __nth)
 	    __first = __cut;
 	  else
 	    __last = __cut;
 	}
       std::__insertion_sort(__first, __last, __comp);
     }
 
   /// @endcond
 
   // nth_element
 
   // lower_bound moved to stl_algobase.h
@@ -3805,41 +3824,42 @@  _GLIBCXX_BEGIN_NAMESPACE_ALGO
    *  @param  __first  An input iterator.
    *  @param  __n      A value convertible to an integer.
    *  @param  __f      A unary function object.
    *  @return   `__first+__n`
    *
    *  Applies the function object `__f` to each element in the range
    *  `[first, first+n)`.  `__f` must not modify the order of the sequence.
    *  If `__f` has a return value it is ignored.
   */
   template<typename _InputIterator, typename _Size, typename _Function>
     _GLIBCXX20_CONSTEXPR
     _InputIterator
     for_each_n(_InputIterator __first, _Size __n, _Function __f)
     {
       auto __n2 = std::__size_to_integer(__n);
       using _Cat = typename iterator_traits<_InputIterator>::iterator_category;
       if constexpr (is_base_of_v<random_access_iterator_tag, _Cat>)
 	{
 	  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;
 	}
       else
 	{
 	  while (__n2-->0)
 	    {
 	      __f(*__first);
 	      ++__first;
 	    }
 	  return __first;
 	}
     }
 #endif // C++17
 
   /**
    *  @brief Find the first occurrence of a value in a sequence.
    *  @ingroup non_mutating_algorithms
    *  @param  __first  An input iterator.
    *  @param  __last   An input iterator.
@@ -4527,110 +4547,119 @@  _GLIBCXX_BEGIN_NAMESPACE_ALGO
    *  distribution, so that every possible ordering of the sequence is
    *  equally likely.
    *
    *  @deprecated
    *  Since C++17, `std::random_shuffle` is not part of the C++ standard.
    *  Use `std::shuffle` instead, which was introduced in C++11.
   */
   template<typename _RandomAccessIterator>
     _GLIBCXX14_DEPRECATED_SUGGEST("std::shuffle")
     inline void
     random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last)
     {
       // concept requirements
       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
 	    _RandomAccessIterator>)
       __glibcxx_requires_valid_range(__first, __last);
 
       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))
 	{
 	  // Use a xorshift implementation seeded by two calls to rand()
 	  // 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);
 	    }
 	  return;
 	}
 #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);
 	}
     }
 
   /**
    *  @brief Shuffle the elements of a sequence using a random number
    *         generator.
    *  @ingroup mutating_algorithms
    *  @param  __first   A forward iterator.
    *  @param  __last    A forward iterator.
    *  @param  __rand    The RNG functor or function.
    *  @return  Nothing.
    *
    *  Reorders the elements in the range `[__first, __last)` using `__rand`
    *  to provide a random distribution. Calling `__rand(N)` for a positive
    *  integer `N` should return a randomly chosen integer from the
    *  range `[0, N)`.
    *
    *  @deprecated
    *  Since C++17, `std::random_shuffle` is not part of the C++ standard.
    *  Use `std::shuffle` instead, which was introduced in C++11.
   */
   template<typename _RandomAccessIterator, typename _RandomNumberGenerator>
     _GLIBCXX14_DEPRECATED_SUGGEST("std::shuffle")
     void
     random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
 #if __cplusplus >= 201103L
 		   _RandomNumberGenerator&& __rand)
 #else
 		   _RandomNumberGenerator& __rand)
 #endif
     {
       // concept requirements
       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
 	    _RandomAccessIterator>)
       __glibcxx_requires_valid_range(__first, __last);
 
       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);
 	}
     }
 #endif // HOSTED
 #endif // <= C++11 || USE_DEPRECATED
 
   /**
    *  @brief Move elements for which a predicate is true to the beginning
    *         of a sequence.
    *  @ingroup mutating_algorithms
    *  @param  __first   A forward iterator.
    *  @param  __last    A forward iterator.
    *  @param  __pred    A predicate functor.
    *  @return  An iterator `middle` such that `__pred(i)` is true for each
    *  iterator `i` in the range `[__first, middle)` and false for each `i`
    *  in the range `[middle, __last)`.
    *
    *  `__pred` must not modify its operand. `partition()` does not preserve
    *  the relative ordering of elements in each group, use
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
@@ -1133,44 +1133,46 @@  _GLIBCXX_END_NAMESPACE_CONTAINER
     {
 #if __cplusplus >= 201103L
       static_assert(is_integral<_Size>{}, "fill_n must pass integral size");
 #endif
       return __fill_n_a1(__first, __n, __value);
     }
 
   template<typename _OutputIterator, typename _Size, typename _Tp>
     __attribute__((__always_inline__))
     _GLIBCXX20_CONSTEXPR
     inline _OutputIterator
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value,
 	       std::random_access_iterator_tag)
     {
 #if __cplusplus >= 201103L
       static_assert(is_integral<_Size>{}, "fill_n must pass integral size");
 #endif
       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;
     }
 
   /**
    *  @brief Fills the range [first,first+n) with copies of value.
    *  @ingroup mutating_algorithms
    *  @param  __first  An output iterator.
    *  @param  __n      The count of copies to perform.
    *  @param  __value  A reference-to-const of arbitrary type.
    *  @return   The iterator at first+n.
    *
    *  This function fills a range with copies of the same value.  For char
    *  types filling contiguous areas of memory, this becomes an inline call
    *  to @c memset or @c wmemset.
    *
    *  If @p __n is negative, the function does nothing.
   */
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // DR 865. More algorithms that throw away information
   // DR 426. search_n(), fill_n(), and generate_n() with negative n
   template<typename _OI, typename _Size, typename _Tp>
@@ -1293,45 +1295,45 @@  _GLIBCXX_END_NAMESPACE_CONTAINER
 	static _II1
 	__newlast1(_II1, _II1 __last1, _II2, _II2)
 	{ return __last1; }
 
       template<typename _II>
 	_GLIBCXX20_CONSTEXPR
 	static bool
 	__cnd2(_II __first, _II __last)
 	{ return __first != __last; }
     };
 
   template<>
     struct __lc_rai<random_access_iterator_tag, random_access_iterator_tag>
     {
       template<typename _RAI1, typename _RAI2>
 	_GLIBCXX20_CONSTEXPR
 	static _RAI1
 	__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>
 	static _GLIBCXX20_CONSTEXPR bool
 	__cnd2(_RAI, _RAI)
 	{ return true; }
     };
 
   template<typename _II1, typename _II2, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     bool
     __lexicographical_compare_impl(_II1 __first1, _II1 __last1,
 				   _II2 __first2, _II2 __last2,
 				   _Compare __comp)
     {
       typedef typename iterator_traits<_II1>::iterator_category _Category1;
       typedef typename iterator_traits<_II2>::iterator_category _Category2;
       typedef std::__lc_rai<_Category1, _Category2> __rai_type;
 
       __last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2);
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
@@ -59,71 +59,79 @@ 
 #include <bits/move.h>
 #include <bits/predefined_ops.h>
 #include <bits/stl_iterator_base_funcs.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /**
    * @defgroup heap_algorithms Heap
    * @ingroup sorting_algorithms
    */
 
   template<typename _RandomAccessIterator, typename _Distance,
 	   typename _Compare>
     _GLIBCXX20_CONSTEXPR
     _Distance
     __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)
 	{
 	  if (__comp(__first + __parent, __first + __child))
 	    return __child;
 	  if ((__child & 1) == 0)
 	    ++__parent;
 	}
       return __n;
     }
 
   // __is_heap, a predicate testing whether or not a range is a heap.
   // This function is an extension, not part of the C++ standard.
   template<typename _RandomAccessIterator, typename _Distance>
     _GLIBCXX20_CONSTEXPR
     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,
 	   typename _Distance>
     _GLIBCXX20_CONSTEXPR
     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>
     _GLIBCXX20_CONSTEXPR
     inline bool
     __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
     { return std::__is_heap(__first, std::distance(__first, __last)); }
 
   template<typename _RandomAccessIterator, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     inline bool
     __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
 	      _Compare __comp)
     {
       return std::__is_heap(__first, _GLIBCXX_MOVE(__comp),
 			    std::distance(__first, __last));
     }
 
   // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap,
   // + is_heap and is_heap_until in C++0x.
@@ -158,78 +166,78 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   */
   template<typename _RandomAccessIterator>
     _GLIBCXX20_CONSTEXPR
     inline void
     push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
     {
       typedef typename iterator_traits<_RandomAccessIterator>::value_type
 	  _ValueType;
       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
 	  _DistanceType;
 
       // concept requirements
       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
 	    _RandomAccessIterator>)
       __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
       __glibcxx_requires_valid_range(__first, __last);
       __glibcxx_requires_irreflexive(__first, __last);
       __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);
     }
 
   /**
    *  @brief  Push an element onto a heap using comparison functor.
    *  @param  __first  Start of heap.
    *  @param  __last   End of heap + element.
    *  @param  __comp   Comparison functor.
    *  @ingroup heap_algorithms
    *
    *  This operation pushes the element at __last-1 onto the valid
    *  heap over the range [__first,__last-1).  After completion,
    *  [__first,__last) is a valid heap.  Compare operations are
    *  performed using comp.
   */
   template<typename _RandomAccessIterator, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     inline void
     push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
 	      _Compare __comp)
     {
       typedef typename iterator_traits<_RandomAccessIterator>::value_type
 	  _ValueType;
       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
 	  _DistanceType;
 
       // concept requirements
       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
 	    _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);
     }
 
   template<typename _RandomAccessIterator, typename _Distance,
 	   typename _Tp, typename _Compare>
     _GLIBCXX20_CONSTEXPR
     void
     __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
 		  _Distance __len, _Tp __value, _Compare __comp)
     {
       const _Distance __topIndex = __holeIndex;
       _Distance __secondChild = __holeIndex;
       while (__secondChild < (__len - 1) / 2)
 	{
 	  __secondChild = 2 * (__secondChild + 1);
 	  if (__comp(__first + __secondChild,
 		     __first + (__secondChild - 1)))
 	    __secondChild--;
 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index bf40995659d1..f86030d4ebf0 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -1328,38 +1328,38 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // to give consistent results for lookup in the map.
       static_assert(is_same_v<iter_value_t<_RAIter>,
 			      iter_value_t<_RandomAccessIterator2>>);
 #endif
       auto __patlen = _M_pat_end - _M_pat;
       if (__patlen == 0)
 	return std::make_pair(__first, __first);
       const auto& __pred = this->_M_pred();
       __diff_type __i = __patlen - 1;
       auto __stringlen = __last - __first;
       while (__i < __stringlen)
 	{
 	  __diff_type __j = __patlen - 1;
 	  while (__j >= 0 && __pred(__first[__i], _M_pat[__j]))
 	    {
 	      --__i;
 	      --__j;
 	    }
 	  if (__j < 0)
 	    {
-	      const auto __match = __first + __i + 1;
+	      const auto __match = __first + __diff_type(__i + 1);
 	      return std::make_pair(__match, __match + __patlen);
 	    }
 	  __i += std::max(_M_bad_char_shift(__first[__i]),
 			  _M_good_suffix[__j]);
 	}
       return std::make_pair(__last, __last);
     }
 #endif // __cpp_lib_boyer_moore_searcher
 
 #endif // C++17
 #endif // C++14
 #endif // C++11
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #endif // _GLIBCXX_FUNCTIONAL
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
@@ -25,41 +25,41 @@  using __gnu_test::test_range;
 using __gnu_test::random_access_iterator_wrapper;
 using __gnu_test::bidirectional_iterator_wrapper;
 using __gnu_test::forward_iterator_wrapper;
 using __gnu_test::input_iterator_wrapper;
 using __gnu_test::output_iterator_wrapper;
 
 void
 test01()
 {
   int a[2] = { };
   test_range<int, random_access_iterator_wrapper> r(a);
   auto iter = r.begin();
   std::ranges::advance(iter, 1);
   VERIFY( iter != r.begin() );
   VERIFY( iter != r.end() );
   std::ranges::advance(iter, 1);
   VERIFY( iter == r.end() );
   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());
   VERIFY( iter == r.begin() );
 
   auto diff = std::ranges::advance(iter, 99, r.end());
   VERIFY( iter == r.end() );
   VERIFY( diff == 97 );
   diff = std::ranges::advance(iter, -222, r.begin());
   VERIFY( iter == r.begin() );
   VERIFY( diff == -220 );
 }
 
 void
 test02()
 {
   int a[2] = { };
   test_range<int, bidirectional_iterator_wrapper> r(a);
   auto iter = r.begin();
   std::ranges::advance(iter, 1);
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
@@ -36,61 +36,61 @@  test01()
 {
   int x[50];
 
   auto pred = std::greater{};
   auto proj = [] (int a) { return -a; };
   for (int i = 0; i < 50; i++)
     {
       std::iota(x, x+50, 1);
       container<int, random_access_iterator_wrapper> rx(x);
 
       std::ranlux48_base g(i);
       ranges::shuffle(rx, g);
 
       auto iter = ranges::make_heap(rx, pred, proj);
       VERIFY( iter == rx.end() );
       VERIFY( ranges::is_heap(rx, pred, proj) );
       VERIFY( ranges::is_heap_until(rx, pred, proj) == rx.end() );
 
       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;
       iter = ranges::push_heap(rx.begin(), rx.end(), pred, proj);
       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);
       VERIFY( iter == rx.end() );
       VERIFY( ranges::is_sorted(rx, pred, proj) );
     }
 }
 
 constexpr bool
 test02()
 {
   bool ok = true;
   int x[] = {1,2,3,4,5};
   ranges::make_heap(x);
   ranges::pop_heap(x);
   x[4] = 7;
   ranges::push_heap(x);
   ok &= ranges::is_heap(x);
   ok &= ranges::is_heap_until(x) == x+5;
   ranges::sort_heap(x);
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
@@ -26,28 +26,28 @@ 
 
 using __gnu_test::test_container;
 using __gnu_test::random_access_iterator_wrapper;
 
 typedef test_container<int, random_access_iterator_wrapper> Container;
 
 void test01()
 {
   std::vector<int> v = {
     207089,
     202585,
     180067,
     157549,
     211592,
     216096,
     207089
   };
 
   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()
 {
   test01();
   return 0;
 }
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
@@ -21,41 +21,41 @@ 
 #include <algorithm>
 #include <random>
 #include <ranges>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
 using __gnu_test::test_container;
 using __gnu_test::test_range;
 using __gnu_test::random_access_iterator_wrapper;
 
 namespace ranges = std::ranges;
 
 void
 test01()
 {
   int x[50];
   std::iota(x, x+50, 0);
 
   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);
       ranges::shuffle(rx, g);
 
       auto result = ranges::nth_element(rx, rx.begin()+i, pred, proj);
       VERIFY( result == rx.end() );
       VERIFY( x[i] == i );
       for (int j = 0; j < i; j++)
 	for (int k = i; k < 50; k++)
 	  VERIFY( !pred(proj(x[k]), proj(x[j])) );
 
       result = ranges::nth_element(rx, rx.begin()+i, pred);
       VERIFY( result == rx.end() );
       VERIFY( x[i] == 49-i );
       for (int j = 0; j < i; j++)
 	for (int k = i; k < 50; k++)
 	  VERIFY( !pred(x[k], x[j]) );
     }
 }
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
@@ -20,42 +20,42 @@ 
 // { dg-require-cstdint "" }
 
 // 25.4.2 [lib.alg.nth.element]
 
 #include <algorithm>
 #include <random>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 #include <testsuite_containergen.h>
 
 using __gnu_test::test_container;
 using __gnu_test::random_access_iterator_wrapper;
 
 typedef test_container<int, random_access_iterator_wrapper> Container;
 
 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());
 
     if (element < size)
       {
         for (int i = 0; i < element; ++i)
 	  VERIFY( con.val(i) <= con.val(element) );
 
 	for (int i = element + 1; i < size; ++i)
 	  VERIFY( con.val(i) >= con.val(element) );
       }
   }
 };
 
 int 
 main()
 {
   __gnu_test::test_containers<Container>(testNthElement());
 }
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
@@ -26,57 +26,57 @@ 
 #undef _GLIBCXX_PARALLEL
 
 #include <algorithm>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 #include <testsuite_rvalref.h>
 
 using __gnu_test::test_container;
 using __gnu_test::random_access_iterator_wrapper;
 
 typedef __gnu_test::rvalstruct_compare_by_value V;
 typedef test_container<V, random_access_iterator_wrapper> Container;
 
 void
 test01()
 {
   V s1[] = { 10, 20, 1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7, 
 	     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 );
   for(int i = 10; i < N; ++i)
     VERIFY( s1[i].val > s1[9].val && s1[i].ok );
 
 }
 
 void
 test02()
 {
   V s1[] = { 10, 20, 1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7, 
 	     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)
     VERIFY( s1[i].val > s1[i - 1].val && s1[i].ok );
   for(int i = 10; i < N; ++i)
     VERIFY( s1[i].val > s1[9].val && s1[i].ok );
 }
 
 void
 test03()
 {
   V vvs[] = { 2, 0 };
   std::partial_sort(vvs, vvs + 2, vvs + 2);
   VERIFY( vvs[0].ok && vvs[0].val == 0 );
   VERIFY( vvs[1].ok && vvs[1].val == 2 );
 }
 
 int
 main()
 {
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
@@ -30,41 +30,42 @@  using __gnu_test::random_access_iterator_wrapper;
 
 namespace ranges = std::ranges;
 
 void
 test01()
 {
   for (unsigned size = 0; size < 50; ++size)
     {
       std::vector<int> vref(size);
       std::iota(vref.begin(), vref.end(), 0);
       std::vector<int> v1(vref), v2(vref);
       test_container<int, random_access_iterator_wrapper> c
 	= {v1.data(), v1.data() + size};
       test_range<int, random_access_iterator_wrapper> r
 	= {v2.data(), v2.data() + size};
 
       std::ranlux48_base g1(size), g2(size + 1);
       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<>{});
 	  VERIFY( res1 == c.end() );
 
 	  auto res2 = ranges::partial_sort(r,
 					   ranges::begin(r)+middle,
 					   ranges::greater{});
 	  VERIFY( res2 == ranges::end(r) );
 
 	  VERIFY( ranges::equal(c.begin(), c.begin()+middle,
 				r.begin(), r.begin()+middle) );
 	  VERIFY( ranges::equal(c.begin(), c.begin()+middle,
 				vref.rbegin(), vref.rbegin()+middle) );
 	}
     }
 }
 
 constexpr bool
 test02()
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
@@ -20,41 +20,41 @@ 
 // { dg-require-cstdint "" }
 
 // 25.4.1.3 [lib.alg.partial.sort]
 
 #include <algorithm>
 #include <random>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 #include <testsuite_containergen.h>
 
 using __gnu_test::test_container;
 using __gnu_test::random_access_iterator_wrapper;
 
 typedef test_container<int, random_access_iterator_wrapper> Container;
 
 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());
 
     VERIFY( std::is_sorted(con.begin(), con.begin() + element) );
 
     if (element > 0)
       {
         for (int i = element; i < size; ++i)
 	  VERIFY( con.val(element - 1) <= con.val(i) );
       }
   }
 };
 
 int 
 main()
 {
   __gnu_test::test_containers<Container>(testPartialSort());
 }
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
@@ -18,51 +18,51 @@ 
 // { dg-do run { target c++20 } }
 // { dg-require-cstdint "" }
 
 #include <algorithm>
 #include <random>
 #include <vector>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
 using __gnu_test::test_container;
 using __gnu_test::test_range;
 using __gnu_test::input_iterator_wrapper;
 using __gnu_test::forward_iterator_wrapper;
 using __gnu_test::random_access_iterator_wrapper;
 
 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);
       std::vector<int> v1(vref), v2(vref);
 
       std::ranlux48_base g1(size), g2(size + 1);
       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};
 	  test_range<int, input_iterator_wrapper> r
 	    = {v2.data(), v2.data() + size};
 
 	  std::vector<int> o1(middle), o2(middle);
 	  test_range<int, random_access_iterator_wrapper> w1
 	    = {o1.data(), o1.data()+middle};
 	  test_range<int, random_access_iterator_wrapper> w2
 	    = {o2.data(), o2.data()+middle};
 
 	  auto [in1, out1] = ranges::partial_sort_copy(c.begin(), c.end(),
 						       w1.begin(), w1.end(),
 						       {},
 						       std::negate<>{},
 						       std::negate<>{});
 	  VERIFY( in1 == c.end() );
 	  VERIFY( out1 == w1.begin() + std::min(size, middle) );
 
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
@@ -21,43 +21,43 @@ 
 
 // 25.4.1.4 [lib.alg.partial.sort.copy]
 
 #include <algorithm>
 #include <random>
 #include <vector>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 #include <testsuite_containergen.h>
 
 using __gnu_test::test_container;
 using __gnu_test::random_access_iterator_wrapper;
 
 typedef test_container<int, random_access_iterator_wrapper> Container;
 
 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
 
     Container out(outvec.data(), outvec.data() + element);
 
     std::partial_sort_copy(con.begin(), con.end(),
 			   out.begin(), out.begin() + element);
 
     VERIFY( std::is_sorted(out.begin(), out.begin() + element) );
 
     std::sort(con.begin(), con.end());
 
     for (int i = 0; i < element; ++i)
       VERIFY( con.val(i) == out.val(i) );
   }
 };
 
 int 
 main()
 {
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
@@ -226,41 +226,41 @@  test08()
 
   short a[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
   test_range<short, ra_test_wrapper> ra(a);
   static_assert( ranges::random_access_range<decltype(ra)> );
   ranges::subrange nonsized = {ra.begin(), std::unreachable_sentinel};
   using Nonsized = decltype(nonsized);
   static_assert( ranges::random_access_range<Nonsized> );
   static_assert( ! ranges::sized_range<Nonsized> );
   auto v1 = nonsized | views::drop(5);
   VERIFY( ra_test_wrapper<short>::increment_count == 0 );
   auto b1 = v1.begin();
   VERIFY( ra_test_wrapper<short>::increment_count == 5 );
   VERIFY( v1.begin() == b1 );
   VERIFY( ra_test_wrapper<short>::increment_count == 5 );
   VERIFY( *b1 == 5 );
   VERIFY( *v1.begin() == 5 );
   VERIFY( ra_test_wrapper<short>::increment_count == 5 );
 
   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> );
   auto v2 = sized | views::drop(6);
   auto b2 = v2.begin();
   VERIFY( ra_test_wrapper<long>::increment_count == 0 );
   VERIFY( v2.begin() == b2 );
   VERIFY( ra_test_wrapper<long>::increment_count == 0 );
   VERIFY( *b2 == 6 );
   VERIFY( *v2.begin() == 6 );
   VERIFY( ra_test_wrapper<long>::increment_count == 0 );
 }
 
 template<auto drop = views::drop>
 void
 test09()
 {
   // Verify SFINAE behavior.
   extern int x[5];
   int* n = 0;
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
@@ -590,78 +590,96 @@  namespace __gnu_test
     _GLIBCXX14_CONSTEXPR
     random_access_iterator_wrapper
     operator-(std::ptrdiff_t n) const
     {
       random_access_iterator_wrapper<T> tmp = *this;
       return tmp -= n;
     }
 
     _GLIBCXX14_CONSTEXPR
     std::ptrdiff_t
     operator-(const random_access_iterator_wrapper<T>& in) const
     {
       ITERATOR_VERIFY(this->SharedInfo == in.SharedInfo);
       return this->ptr - in.ptr;
     }
 
     _GLIBCXX14_CONSTEXPR
     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
     {
       ITERATOR_VERIFY(this->SharedInfo == in.SharedInfo);
       return this->ptr < in.ptr;
     }
 
     _GLIBCXX14_CONSTEXPR
     bool operator>(const random_access_iterator_wrapper<T>& in) const
     {
       return in < *this;
     }
 
     _GLIBCXX14_CONSTEXPR
     bool operator>=(const random_access_iterator_wrapper<T>& in) const
     {
       return !(*this < in);
     }
 
     _GLIBCXX14_CONSTEXPR
     bool operator<=(const random_access_iterator_wrapper<T>& in) const
     {
       return !(*this > in);
     }
   };
 
   template<typename T>
     _GLIBCXX14_CONSTEXPR
     random_access_iterator_wrapper<T>
     operator+(random_access_iterator_wrapper<T> it, std::ptrdiff_t n)
     { return it += n; }
 
   template<typename T>
     _GLIBCXX14_CONSTEXPR
     random_access_iterator_wrapper<T>
     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
    * test_container takes two parameters, a class T and an iterator
    * wrapper templated by T (for example forward_iterator_wrapper<T>.
    * It takes two pointers representing a range and presents them as
    * a container of iterators.
    */
   template <class T, template<class TT> class ItType>
   struct test_container
   {
     typename ItType<T>::ContainerType bounds;
 
     _GLIBCXX_CONSTEXPR
     test_container(T* _first, T* _last) : bounds(_first, _last)
     { }
 
     template<std::size_t N>
       explicit
       _GLIBCXX_CONSTEXPR