[libcxx-commits] [libcxx] [libc++] Implement `ranges::shift_right` (PR #177847)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Feb 7 11:33:55 PST 2026
https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/177847
>From 295afa2234d4448b792d31cda25b628fe4e158d3 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 25 Jan 2026 10:29:27 +0000
Subject: [PATCH 1/6] [libc++] Implement
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +
libcxx/docs/ReleaseNotes/23.rst | 2 +-
libcxx/docs/Status/Cxx23Papers.csv | 2 +-
libcxx/include/CMakeLists.txt | 1 +
.../include/__algorithm/ranges_shift_right.h | 77 +++++
libcxx/include/__algorithm/shift_right.h | 79 +++--
libcxx/include/algorithm | 8 +
libcxx/include/module.modulemap.in | 3 +
libcxx/include/version | 5 +-
libcxx/modules/std/algorithm.inc | 4 +-
.../alg.shift/assert.shift_right.pass.cpp | 28 ++
.../alg.shift/ranges_shift_right.pass.cpp | 307 ++++++++++++++++++
.../ranges_robust_against_dangling.pass.cpp | 1 +
...es_robust_against_proxy_iterators.pass.cpp | 2 +
.../algorithm.version.compile.pass.cpp | 8 +-
.../version.version.compile.pass.cpp | 8 +-
.../niebloid.compile.pass.cpp | 1 +
.../generate_feature_test_macro_components.py | 2 +-
18 files changed, 497 insertions(+), 43 deletions(-)
create mode 100644 libcxx/include/__algorithm/ranges_shift_right.h
create mode 100644 libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp
create mode 100644 libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges_shift_right.pass.cpp
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index d2b76cb96e866..0f65770a4fa14 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -394,6 +394,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_reference_from_temporary`` *unimplemented*
---------------------------------------------------------- -----------------
+ ``__cpp_lib_shift`` ``202202L``
+ ---------------------------------------------------------- -----------------
``__cpp_lib_spanstream`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_stacktrace`` *unimplemented*
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index bec665c167ce3..ffc586d9630a3 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -38,7 +38,7 @@ What's New in Libc++ 23.0.0?
Implemented Papers
------------------
-- P2440R1 (partial): ``ranges::iota`` and ``ranges::shift_left`` are supported (`Github <https://llvm.org/PR105184>`__)
+- P2440R1: ``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right`` (`Github <https://llvm.org/PR105184>`__)
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index a787a4a6215ec..fd99ff635aa00 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -46,7 +46,7 @@
"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","`#105180 <https://github.com/llvm/llvm-project/issues/105180>`__","Implemented the type traits only."
"`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","`#105182 <https://github.com/llvm/llvm-project/issues/105182>`__",""
"`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","`#105183 <https://github.com/llvm/llvm-project/issues/105183>`__",""
-"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial|","","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__","``ranges::iota`` and ``ranges::shift_left`` are implemented."
+"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Complete|","23","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__",""
"`P2441R2 <https://wg21.link/P2441R2>`__","``views::join_with``","2022-02 (Virtual)","|Complete|","21","`#105185 <https://github.com/llvm/llvm-project/issues/105185>`__",""
"`P2442R1 <https://wg21.link/P2442R1>`__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","`#105187 <https://github.com/llvm/llvm-project/issues/105187>`__",""
"`P2443R1 <https://wg21.link/P2443R1>`__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","`#105188 <https://github.com/llvm/llvm-project/issues/105188>`__",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1ceba14329cb2..b0b1487eedddb 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -158,6 +158,7 @@ set(files
__algorithm/ranges_set_symmetric_difference.h
__algorithm/ranges_set_union.h
__algorithm/ranges_shift_left.h
+ __algorithm/ranges_shift_right.h
__algorithm/ranges_shuffle.h
__algorithm/ranges_sort.h
__algorithm/ranges_sort_heap.h
diff --git a/libcxx/include/__algorithm/ranges_shift_right.h b/libcxx/include/__algorithm/ranges_shift_right.h
new file mode 100644
index 0000000000000..9b3f27ea2bb0a
--- /dev/null
+++ b/libcxx/include/__algorithm/ranges_shift_right.h
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_RANGES_SHIFT_RIGHT_H
+#define _LIBCPP___ALGORITHM_RANGES_SHIFT_RIGHT_H
+
+#include <__algorithm/iterator_operations.h>
+#include <__algorithm/shift_right.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/distance.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/permutable.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/subrange.h>
+#include <__utility/move.h>
+#include <iterator>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+namespace __shift_right {
+
+struct __fn {
+ template <permutable _Iter, sentinel_for<_Iter> _Sent>
+ _LIBCPP_HIDE_FROM_ABI static constexpr subrange<_Iter>
+ operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __n) {
+ auto __ret = std::__shift_right<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__n));
+ return {std::move(__ret.first), std::move(__ret.second)};
+ }
+
+ template <forward_range _Range>
+ requires permutable<iterator_t<_Range>>
+ _LIBCPP_HIDE_FROM_ABI static constexpr borrowed_subrange_t<_Range>
+ operator()(_Range&& __range, range_difference_t<_Range> __n) {
+ if constexpr (sized_range<_Range>) {
+ if (__n >= ranges::distance(__range)) {
+ auto __iter = ranges::begin(__range);
+ auto __end = ranges::end(__range);
+ ranges::advance(__iter, __end);
+ return {__iter, std::move(__iter)};
+ }
+ }
+
+ auto __ret = std::__shift_right<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), std::move(__n));
+ return {std::move(__ret.first), std::move(__ret.second)};
+ }
+};
+} // namespace __shift_right
+
+inline namespace __cpo {
+inline constexpr auto shift_right = __shift_right::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ALGORITHM_RANGES_SHIFT_RIGHT_H
diff --git a/libcxx/include/__algorithm/shift_right.h b/libcxx/include/__algorithm/shift_right.h
index 01853057fc478..338a1401dad72 100644
--- a/libcxx/include/__algorithm/shift_right.h
+++ b/libcxx/include/__algorithm/shift_right.h
@@ -9,12 +9,18 @@
#ifndef _LIBCPP___ALGORITHM_SHIFT_RIGHT_H
#define _LIBCPP___ALGORITHM_SHIFT_RIGHT_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/move.h>
#include <__algorithm/move_backward.h>
#include <__algorithm/swap_ranges.h>
+#include <__assert>
#include <__config>
+#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
#include <__utility/swap.h>
+#include <concepts>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -27,36 +33,41 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
-template <class _ForwardIterator>
-inline _LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator
-shift_right(_ForwardIterator __first,
- _ForwardIterator __last,
- typename iterator_traits<_ForwardIterator>::difference_type __n) {
+template <class _AlgPolicy, class _Iter, class _Sent>
+_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter>
+__shift_right(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n >= 0, "n must be greater than or equal to 0");
+ _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
if (__n == 0) {
- return __first;
+ return pair<_Iter, _Iter>(std::move(__first), std::move(__end));
}
- if constexpr (__has_random_access_iterator_category<_ForwardIterator>::value) {
- decltype(__n) __d = __last - __first;
- if (__n >= __d) {
- return __last;
+ using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iter>;
+
+ if constexpr (derived_from<_IterCategory, random_access_iterator_tag>) {
+ auto __size = __end - __first;
+ if (__n >= __size) {
+ return pair<_Iter, _Iter>(__end, std::move(__end));
}
- _ForwardIterator __m = __first + (__d - __n);
- return std::move_backward(__first, __m, __last);
- } else if constexpr (__has_bidirectional_iterator_category<_ForwardIterator>::value) {
- _ForwardIterator __m = __last;
+ _Iter __m = __first;
+ _IterOps<_AlgPolicy>::advance(__m, (__size - __n));
+ auto __ret = std::__move_backward<_AlgPolicy>(std::move(__first), std::move(__m), __end);
+ return pair<_Iter, _Iter>(std::move(__ret.second), std::move(__end));
+ } else if constexpr (derived_from<_IterCategory, bidirectional_iterator_tag>) {
+ _Iter __m = __end;
for (; __n > 0; --__n) {
if (__m == __first) {
- return __last;
+ return pair<_Iter, _Iter>(__end, std::move(__end));
}
--__m;
}
- return std::move_backward(__first, __m, __last);
+ auto __ret = std::__move_backward<_AlgPolicy>(std::move(__first), std::move(__m), __end);
+ return pair<_Iter, _Iter>(std::move(__ret.second), std::move(__end));
} else {
- _ForwardIterator __ret = __first;
+ _Iter __ret = __first;
for (; __n > 0; --__n) {
- if (__ret == __last) {
- return __last;
+ if (__ret == __end) {
+ return pair<_Iter, _Iter>(__end, std::move(__end));
}
++__ret;
}
@@ -64,28 +75,28 @@ shift_right(_ForwardIterator __first,
// We have an __n-element scratch space from __first to __ret.
// Slide an __n-element window [__trail, __lead) from left to right.
// We're essentially doing swap_ranges(__first, __ret, __trail, __lead)
- // over and over; but once __lead reaches __last we needn't bother
- // to save the values of elements [__trail, __last).
+ // over and over; but once __lead reaches __end we needn't bother
+ // to save the values of elements [__trail, __end).
auto __trail = __first;
auto __lead = __ret;
while (__trail != __ret) {
- if (__lead == __last) {
- std::move(__first, __trail, __ret);
- return __ret;
+ if (__lead == __end) {
+ std::__move<_AlgPolicy>(std::move(__first), std::move(__trail), __ret);
+ return pair<_Iter, _Iter>(__ret, std::move(__end));
}
++__trail;
++__lead;
}
- _ForwardIterator __mid = __first;
+ _Iter __mid = __first;
while (true) {
- if (__lead == __last) {
- __trail = std::move(__mid, __ret, __trail);
- std::move(__first, __mid, __trail);
- return __ret;
+ if (__lead == __end) {
+ __trail = std::__move<_AlgPolicy>(__mid, __ret, __trail).second;
+ std::__move<_AlgPolicy>(std::move(__first), std::move(__mid), std::move(__trail));
+ return pair<_Iter, _Iter>(__ret, std::move(__end));
}
- swap(*__mid, *__trail);
+ _IterOps<_AlgPolicy>::iter_swap(__mid, __trail);
++__mid;
++__trail;
++__lead;
@@ -96,6 +107,14 @@ shift_right(_ForwardIterator __first,
}
}
+template <class _ForwardIterator>
+_LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator
+shift_right(_ForwardIterator __first,
+ _ForwardIterator __last,
+ typename iterator_traits<_ForwardIterator>::difference_type __n) {
+ return std::__shift_right<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __n).first;
+}
+
#endif // _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 5dd7b9dc990e1..2200ce6219eb4 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -1496,6 +1496,13 @@ template<class ForwardIterator>
shift_right(ForwardIterator first, ForwardIterator last,
typename iterator_traits<ForwardIterator>::difference_type n); // C++20
+ template<permutable I, sentinel_for<I> S>
+ constexpr subrange<I> ranges::shift_right(I first, S last, iter_difference_t<I> n); // since C++23
+
+ template<forward_range R>
+ requires permutable<iterator_t<R>>
+ constexpr borrowed_subrange_t<R> ranges::shift_right(R&& r, range_difference_t<R> n) // since C++23
+
template <class InputIterator, class Predicate>
constexpr bool // constexpr since C++20
is_partitioned(InputIterator first, InputIterator last, Predicate pred);
@@ -2043,6 +2050,7 @@ template <class BidirectionalIterator, class Compare>
# include <__algorithm/ranges_find_last.h>
# include <__algorithm/ranges_fold.h>
# include <__algorithm/ranges_shift_left.h>
+# include <__algorithm/ranges_shift_right.h>
# include <__algorithm/ranges_starts_with.h>
# endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 83b0259cac9e4..a1dbf4bad3559 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -763,6 +763,9 @@ module std [system] {
module ranges_shift_left {
header "__algorithm/ranges_shift_left.h"
}
+ module ranges_shift_right {
+ header "__algorithm/ranges_shift_right.h"
+ }
module ranges_shuffle {
header "__algorithm/ranges_shuffle.h"
}
diff --git a/libcxx/include/version b/libcxx/include/version
index 7d77677a012ce..562538c5393cc 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -236,7 +236,8 @@ __cpp_lib_shared_ptr_arrays 201707L <memory>
201611L // C++17
__cpp_lib_shared_ptr_weak_type 201606L <memory>
__cpp_lib_shared_timed_mutex 201402L <shared_mutex>
-__cpp_lib_shift 201806L <algorithm>
+__cpp_lib_shift 202202L <algorithm>
+ 201806L // C++20
__cpp_lib_smart_ptr_for_overwrite 202002L <memory>
__cpp_lib_smart_ptr_owner_equality 202306L <memory>
__cpp_lib_source_location 201907L <source_location>
@@ -533,6 +534,8 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_ranges_to_container 202202L
# define __cpp_lib_ranges_zip 202110L
// # define __cpp_lib_reference_from_temporary 202202L
+# undef __cpp_lib_shift
+# define __cpp_lib_shift 202202L
// # define __cpp_lib_spanstream 202106L
// # define __cpp_lib_stacktrace 202011L
# define __cpp_lib_stdatomic_h 202011L
diff --git a/libcxx/modules/std/algorithm.inc b/libcxx/modules/std/algorithm.inc
index 540bcc3879678..bb582b6a7d84e 100644
--- a/libcxx/modules/std/algorithm.inc
+++ b/libcxx/modules/std/algorithm.inc
@@ -364,9 +364,11 @@ export namespace std {
using std::shift_right;
+ #if _LIBCPP_STD_VER >= 23
namespace ranges {
- // using std::ranges::shift_right;
+ using std::ranges::shift_right;
}
+ #endif // _LIBCPP_STD_VER >= 23
// [alg.sorting], sorting and related operations
// [alg.sort], sorting
diff --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp
new file mode 100644
index 0000000000000..0a49a82276c48
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: libcpp-hardening-mode=none
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+#include <algorithm>
+#include <array>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ std::array<int, 5> arr = {1, 2, 3, 4, 5};
+ TEST_LIBCPP_ASSERT_FAILURE(std::ranges::shift_right(arr, -2), "n must be greater than or equal to 0");
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::ranges::shift_right(arr.begin(), arr.end(), -2), "n must be greater than or equal to 0");
+
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges_shift_right.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges_shift_right.pass.cpp
new file mode 100644
index 0000000000000..48bb35f4b4589
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges_shift_right.pass.cpp
@@ -0,0 +1,307 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=9000000
+
+// <algorithm>
+
+// template<permutable I, sentinel_for<I> S>
+// constexpr subrange<I> ranges::shift_right(I first, S last, iter_difference_t<I> n);
+
+// template<forward_range R>
+// requires permutable<iterator_t<R>>
+// constexpr borrowed_subrange_t<R> ranges::shift_right(R&& r, range_difference_t<R> n)
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <ranges>
+#include <vector>
+
+#include "almost_satisfies_types.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "MoveOnly.h"
+
+struct InvalidDifferenceT {};
+
+template <class Iter, class Sent = Iter, class N = std::iter_difference_t<Iter>>
+concept HasShiftRightIt = requires(Iter iter, Sent sent, N n) { std::ranges::shift_right(iter, sent, n); };
+
+static_assert(HasShiftRightIt<int*>);
+static_assert(HasShiftRightIt<int*, sentinel_wrapper<int*>>);
+static_assert(HasShiftRightIt<int*, sized_sentinel<int*>>);
+static_assert(!HasShiftRightIt<int*, int*, InvalidDifferenceT>);
+static_assert(!HasShiftRightIt<int*, int, int>);
+
+static_assert(!HasShiftRightIt<ForwardIteratorNotDerivedFrom>);
+static_assert(!HasShiftRightIt<PermutableNotForwardIterator>);
+static_assert(!HasShiftRightIt<PermutableNotSwappable>);
+
+template <class Range, class N = std::ranges::range_difference_t<Range>>
+concept HasShiftRightR = requires(Range range, N n) { std::ranges::shift_right(range, n); };
+
+static_assert(HasShiftRightR<UncheckedRange<int*>>);
+static_assert(!HasShiftRightR<UncheckedRange<int*>, InvalidDifferenceT>);
+
+static_assert(!HasShiftRightR<ForwardRangeNotDerivedFrom>);
+static_assert(!HasShiftRightR<PermutableRangeNotForwardIterator>);
+static_assert(!HasShiftRightR<PermutableRangeNotSwappable>);
+
+struct TrackCopyMove {
+ mutable int copy_count = 0;
+ int move_count = 0;
+
+ constexpr TrackCopyMove() = default;
+ constexpr TrackCopyMove(const TrackCopyMove& other) : copy_count(other.copy_count), move_count(other.move_count) {
+ ++copy_count;
+ ++other.copy_count;
+ }
+
+ constexpr TrackCopyMove(TrackCopyMove&& other) noexcept : copy_count(other.copy_count), move_count(other.move_count) {
+ ++move_count;
+ ++other.move_count;
+ }
+ constexpr TrackCopyMove& operator=(const TrackCopyMove& other) {
+ ++copy_count;
+ ++other.copy_count;
+ return *this;
+ }
+ constexpr TrackCopyMove& operator=(TrackCopyMove&& other) noexcept {
+ ++move_count;
+ ++other.move_count;
+ return *this;
+ }
+};
+
+template <class Iter, class Sent>
+constexpr void test_iter_sent() {
+ {
+ const std::array<int, 8> original = {3, 1, 4, 1, 5, 9, 2, 6};
+
+ // (iterator, sentinel) overload
+ for (size_t n = 0; n <= original.size(); ++n) {
+ for (size_t k = 0; k <= n + 2; ++k) {
+ std::vector<int> scratch(n);
+ auto begin = Iter(scratch.data());
+ auto end = Sent(Iter(scratch.data() + n));
+ std::ranges::copy(original.begin(), original.begin() + n, begin);
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::shift_right(begin, end, k);
+
+ assert(result.end() == end);
+ if (k < n) {
+ assert(result.begin() == Iter(scratch.data() + k));
+ assert(std::ranges::equal(original.begin(), original.begin() + n - k, result.begin(), result.end()));
+ } else {
+ assert(result.begin() == end);
+ assert(std::ranges::equal(original.begin(), original.begin() + n, begin, end));
+ }
+ }
+ }
+
+ // (range) overload
+ for (size_t n = 0; n <= original.size(); ++n) {
+ for (size_t k = 0; k <= n + 2; ++k) {
+ std::vector<int> scratch(n);
+ auto begin = Iter(scratch.data());
+ auto end = Sent(Iter(scratch.data() + n));
+ std::ranges::copy(original.begin(), original.begin() + n, begin);
+ auto range = std::ranges::subrange(begin, end);
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::shift_right(range, k);
+
+ assert(result.end() == end);
+ if (k < n) {
+ assert(result.begin() == Iter(scratch.data() + k));
+ assert(std::ranges::equal(original.begin(), original.begin() + n - k, result.begin(), result.end()));
+ } else {
+ assert(result.begin() == end);
+ assert(std::ranges::equal(original.begin(), original.begin() + n, begin, end));
+ }
+ }
+ }
+ }
+ // n == 0
+ {
+ std::array<int, 3> input = {0, 1, 2};
+ const std::array<int, 3> expected = {0, 1, 2};
+
+ { // (iterator, sentinel) overload
+ auto in = input;
+ auto begin = Iter(in.data());
+ auto end = Sent(Iter(in.data() + in.size()));
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::shift_right(begin, end, 0);
+ assert(std::ranges::equal(expected, result));
+ assert(result.begin() == begin);
+ assert(result.end() == end);
+ }
+
+ { // (range) overload
+ auto in = input;
+ auto begin = Iter(in.data());
+ auto end = Sent(Iter(in.data() + in.size()));
+ auto range = std::ranges::subrange(begin, end);
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::shift_right(range, 0);
+ assert(std::ranges::equal(expected, result));
+ assert(result.begin() == begin);
+ assert(result.end() == end);
+ }
+ }
+
+ // n == len
+ {
+ std::array<int, 3> input = {0, 1, 2};
+ const std::array<int, 3> expected = {0, 1, 2};
+
+ { // (iterator, sentinel) overload
+ auto in = input;
+ auto begin = Iter(in.data());
+ auto end = Sent(Iter(in.data() + in.size()));
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result =
+ std::ranges::shift_right(begin, end, input.size());
+ assert(std::ranges::equal(expected, input));
+ assert(result.begin() == end);
+ assert(result.end() == end);
+ }
+
+ { // (range) overload
+ auto in = input;
+ auto begin = Iter(in.data());
+ auto end = Sent(Iter(in.data() + in.size()));
+ auto range = std::ranges::subrange(begin, end);
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::shift_right(range, input.size());
+ assert(std::ranges::equal(expected, input));
+ assert(result.begin() == end);
+ assert(result.end() == end);
+ }
+ }
+
+ // n > len
+ {
+ std::array<int, 3> input = {0, 1, 2};
+ const std::array<int, 3> expected = {0, 1, 2};
+
+ { // (iterator, sentinel) overload
+ auto in = input;
+ auto begin = Iter(in.data());
+ auto end = Sent(Iter(in.data() + in.size()));
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result =
+ std::ranges::shift_right(begin, end, input.size() + 1);
+ assert(std::ranges::equal(expected, input));
+ assert(result.begin() == end);
+ assert(result.end() == end);
+ }
+
+ { // (range) overload
+ auto in = input;
+ auto begin = Iter(in.data());
+ auto end = Sent(Iter(in.data() + in.size()));
+ auto range = std::ranges::subrange(begin, end);
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result =
+ std::ranges::shift_right(range, input.size() + 1);
+ assert(std::ranges::equal(expected, input));
+ assert(result.begin() == end);
+ assert(result.end() == end);
+ }
+ }
+
+ // empty range
+ {
+ std::vector<int> input = {};
+ const std::vector<int> expected = {};
+ { // (iterator, sentinel) overload
+ auto in = input;
+ auto begin = Iter(in.data());
+ auto end = Sent(Iter(in.data() + in.size()));
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result =
+ std::ranges::shift_right(begin, end, input.size() + 1);
+ assert(std::ranges::equal(expected, input));
+ assert(result.begin() == begin);
+ assert(result.end() == begin);
+ }
+
+ { // (range) overload
+ auto in = input;
+ auto begin = Iter(in.data());
+ auto end = Sent(Iter(in.data() + in.size()));
+ auto range = std::ranges::subrange(begin, end);
+ std::same_as<std::ranges::subrange<Iter>> decltype(auto) result =
+ std::ranges::shift_right(range, input.size() + 1);
+ assert(std::ranges::equal(expected, input));
+ assert(result.begin() == begin);
+ assert(result.end() == begin);
+ }
+ }
+}
+
+constexpr bool test() {
+ types::for_each(types::forward_iterator_list<int*>{}, []<class Iter> {
+ test_iter_sent<Iter, Iter>();
+ test_iter_sent<Iter, sentinel_wrapper<Iter>>();
+ test_iter_sent<Iter, sized_sentinel<Iter>>();
+ });
+
+ // Complexity: At most (last - first) - n assignments or swaps.
+ {
+ constexpr int length = 100;
+ constexpr int n = length / 2;
+ auto make_vec = []() {
+ std::vector<TrackCopyMove> vec;
+ vec.reserve(length);
+ for (int i = 0; i < length; ++i) {
+ vec.emplace_back();
+ }
+ return vec;
+ };
+
+ { // (iterator, sentinel) overload
+ auto input = make_vec();
+ auto result = std::ranges::shift_right(input.begin(), input.end(), n);
+ assert(result.begin() == input.begin() + length - n);
+ assert(result.end() == input.end());
+
+ auto total_copies = 0;
+ auto total_moves = 0;
+ for (auto it = result.begin(); it != result.end(); ++it) {
+ const auto& item = *it;
+ total_copies += item.copy_count;
+ total_moves += item.move_count;
+ }
+
+ assert(total_copies == 0);
+ assert(total_moves <= length - n);
+ }
+
+ { // (range) overload
+ auto input = make_vec();
+ auto result = std::ranges::shift_right(input, n);
+ assert(result.begin() == input.begin() + length - n);
+ assert(result.end() == input.end());
+
+ auto total_copies = 0;
+ auto total_moves = 0;
+ for (auto it = result.begin(); it != result.end(); ++it) {
+ const auto& item = *it;
+ total_copies += item.copy_count;
+ total_moves += item.move_count;
+ }
+
+ assert(total_copies == 0);
+ assert(total_moves <= length - n);
+ }
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
index 17037acfe7184..a4536b7455c46 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
@@ -225,6 +225,7 @@ constexpr bool test_all() {
#if TEST_STD_VER >= 23
dangling_1st<out_value_result<dangling, decltype(x)>>(std::ranges::iota, in, x);
dangling_1st(std::ranges::shift_left, in, x);
+ dangling_1st(std::ranges::shift_right, in, x);
#endif
return true;
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
index a442743333ea8..c77d4cd9f420a 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
@@ -193,7 +193,9 @@ constexpr void run_tests() {
test(std::ranges::next_permutation, in);
#if TEST_STD_VER >= 23
test(std::ranges::shift_left, in, count);
+ test(std::ranges::shift_right, in, count);
#endif
+
// The algorithms that work on uninitialized memory have constraints that prevent proxy iterators from being used with
// them.
}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp
index bc479f1bcb1e0..beecf87cd4aa7 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp
@@ -348,8 +348,8 @@
# ifndef __cpp_lib_shift
# error "__cpp_lib_shift should be defined in c++23"
# endif
-# if __cpp_lib_shift != 201806L
-# error "__cpp_lib_shift should have the value 201806L in c++23"
+# if __cpp_lib_shift != 202202L
+# error "__cpp_lib_shift should have the value 202202L in c++23"
# endif
#elif TEST_STD_VER > 23
@@ -452,8 +452,8 @@
# ifndef __cpp_lib_shift
# error "__cpp_lib_shift should be defined in c++26"
# endif
-# if __cpp_lib_shift != 201806L
-# error "__cpp_lib_shift should have the value 201806L in c++26"
+# if __cpp_lib_shift != 202202L
+# error "__cpp_lib_shift should have the value 202202L in c++26"
# endif
#endif // TEST_STD_VER > 23
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index f442b22c6d752..e74c2b58717a9 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -5916,8 +5916,8 @@
# ifndef __cpp_lib_shift
# error "__cpp_lib_shift should be defined in c++23"
# endif
-# if __cpp_lib_shift != 201806L
-# error "__cpp_lib_shift should have the value 201806L in c++23"
+# if __cpp_lib_shift != 202202L
+# error "__cpp_lib_shift should have the value 202202L in c++23"
# endif
# ifndef __cpp_lib_smart_ptr_for_overwrite
@@ -7868,8 +7868,8 @@
# ifndef __cpp_lib_shift
# error "__cpp_lib_shift should be defined in c++26"
# endif
-# if __cpp_lib_shift != 201806L
-# error "__cpp_lib_shift should have the value 201806L in c++26"
+# if __cpp_lib_shift != 202202L
+# error "__cpp_lib_shift should have the value 202202L in c++26"
# endif
# ifndef __cpp_lib_smart_ptr_for_overwrite
diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
index c799af04fc688..d78d513e92d3f 100644
--- a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
+++ b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
@@ -157,6 +157,7 @@ static_assert(test(std::ranges::set_symmetric_difference, a, a, a));
static_assert(test(std::ranges::set_union, a, a, a));
#if TEST_STD_VER >= 23
static_assert(test(std::ranges::shift_left, a, 42));
+static_assert(test(std::ranges::shift_right, a, 42));
#endif
static_assert(test(std::ranges::shuffle, a, g));
static_assert(test(std::ranges::sort, a));
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 88431c76a00f5..9d2e095ab9ff7 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1270,7 +1270,7 @@ def add_version_header(tc):
},
{
"name": "__cpp_lib_shift",
- "values": {"c++20": 201806},
+ "values": {"c++20": 201806, "c++23": 202202},
"headers": ["algorithm"],
},
{
>From eb6ff0746d3892135eaed0e28d0cb7ad8e76fb86 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 25 Jan 2026 10:33:19 +0000
Subject: [PATCH 2/6] ci
---
libcxx/modules/std/algorithm.inc | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/modules/std/algorithm.inc b/libcxx/modules/std/algorithm.inc
index bb582b6a7d84e..5cca7636da1df 100644
--- a/libcxx/modules/std/algorithm.inc
+++ b/libcxx/modules/std/algorithm.inc
@@ -364,11 +364,11 @@ export namespace std {
using std::shift_right;
- #if _LIBCPP_STD_VER >= 23
+#if _LIBCPP_STD_VER >= 23
namespace ranges {
using std::ranges::shift_right;
}
- #endif // _LIBCPP_STD_VER >= 23
+#endif // _LIBCPP_STD_VER >= 23
// [alg.sorting], sorting and related operations
// [alg.sort], sorting
>From 3aba0a86c338126fb1de0f820f05017d57bd7bd9 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 25 Jan 2026 10:40:44 +0000
Subject: [PATCH 3/6] ci
---
libcxx/include/__algorithm/shift_right.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__algorithm/shift_right.h b/libcxx/include/__algorithm/shift_right.h
index 338a1401dad72..9cc6cfb851e40 100644
--- a/libcxx/include/__algorithm/shift_right.h
+++ b/libcxx/include/__algorithm/shift_right.h
@@ -14,13 +14,13 @@
#include <__algorithm/move_backward.h>
#include <__algorithm/swap_ranges.h>
#include <__assert>
+#include <__concepts/derived_from.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
#include <__utility/pair.h>
#include <__utility/swap.h>
-#include <concepts>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
>From 7f3cf052f5d84898c72b61e605f5ff6131b75d1b Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 25 Jan 2026 11:26:39 +0000
Subject: [PATCH 4/6] ci
---
libcxx/include/__algorithm/ranges_shift_right.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/include/__algorithm/ranges_shift_right.h b/libcxx/include/__algorithm/ranges_shift_right.h
index 9b3f27ea2bb0a..d3521b958271d 100644
--- a/libcxx/include/__algorithm/ranges_shift_right.h
+++ b/libcxx/include/__algorithm/ranges_shift_right.h
@@ -20,7 +20,6 @@
#include <__ranges/concepts.h>
#include <__ranges/subrange.h>
#include <__utility/move.h>
-#include <iterator>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
>From 9fb4ea4d15a71efbb9132b5ea8af729371a702f7 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sat, 31 Jan 2026 14:14:21 +0000
Subject: [PATCH 5/6] review
---
libcxx/include/__algorithm/shift_right.h | 8 +++++++-
.../alg.shift/assert.shift_right.pass.cpp | 5 +++--
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__algorithm/shift_right.h b/libcxx/include/__algorithm/shift_right.h
index 9cc6cfb851e40..db0b947d8321f 100644
--- a/libcxx/include/__algorithm/shift_right.h
+++ b/libcxx/include/__algorithm/shift_right.h
@@ -36,12 +36,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _AlgPolicy, class _Iter, class _Sent>
_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter>
__shift_right(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n >= 0, "n must be greater than or equal to 0");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n >= 0, "Providing a negative shift amount to shift_right is UB");
_Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
if (__n == 0) {
return pair<_Iter, _Iter>(std::move(__first), std::move(__end));
}
+ if constexpr (sized_sentinel_for<_Sent, _Iter>) {
+ if (__n >= ranges::distance(__first, __last)) {
+ return pair<_Iter, _Iter>(__end, std::move(__end));
+ }
+ }
+
using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iter>;
if constexpr (derived_from<_IterCategory, random_access_iterator_tag>) {
diff --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp
index 0a49a82276c48..2c6f54304eacf 100644
--- a/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp
@@ -20,9 +20,10 @@
int main(int, char**) {
std::array<int, 5> arr = {1, 2, 3, 4, 5};
- TEST_LIBCPP_ASSERT_FAILURE(std::ranges::shift_right(arr, -2), "n must be greater than or equal to 0");
TEST_LIBCPP_ASSERT_FAILURE(
- std::ranges::shift_right(arr.begin(), arr.end(), -2), "n must be greater than or equal to 0");
+ std::ranges::shift_right(arr, -2), "Providing a negative shift amount to shift_right is UB");
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::ranges::shift_right(arr.begin(), arr.end(), -2), "Providing a negative shift amount to shift_right is UB");
return 0;
}
>From ebb0054587aaff47a568dbc5a6db0757848cd056 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sat, 7 Feb 2026 19:33:40 +0000
Subject: [PATCH 6/6] review
---
libcxx/include/__algorithm/shift_right.h | 27 ++++++++++++------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/__algorithm/shift_right.h b/libcxx/include/__algorithm/shift_right.h
index db0b947d8321f..917e255965cfe 100644
--- a/libcxx/include/__algorithm/shift_right.h
+++ b/libcxx/include/__algorithm/shift_right.h
@@ -37,20 +37,15 @@ template <class _AlgPolicy, class _Iter, class _Sent>
_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter>
__shift_right(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n >= 0, "Providing a negative shift amount to shift_right is UB");
- _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
if (__n == 0) {
+ _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
return pair<_Iter, _Iter>(std::move(__first), std::move(__end));
}
- if constexpr (sized_sentinel_for<_Sent, _Iter>) {
- if (__n >= ranges::distance(__first, __last)) {
- return pair<_Iter, _Iter>(__end, std::move(__end));
- }
- }
-
using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iter>;
if constexpr (derived_from<_IterCategory, random_access_iterator_tag>) {
+ _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
auto __size = __end - __first;
if (__n >= __size) {
return pair<_Iter, _Iter>(__end, std::move(__end));
@@ -60,6 +55,12 @@ __shift_right(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::templa
auto __ret = std::__move_backward<_AlgPolicy>(std::move(__first), std::move(__m), __end);
return pair<_Iter, _Iter>(std::move(__ret.second), std::move(__end));
} else if constexpr (derived_from<_IterCategory, bidirectional_iterator_tag>) {
+ _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
+ if constexpr (sized_sentinel_for<_Sent, _Iter>) {
+ if (__n >= ranges::distance(__first, __last)) {
+ return pair<_Iter, _Iter>(__end, std::move(__end));
+ }
+ }
_Iter __m = __end;
for (; __n > 0; --__n) {
if (__m == __first) {
@@ -72,8 +73,8 @@ __shift_right(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::templa
} else {
_Iter __ret = __first;
for (; __n > 0; --__n) {
- if (__ret == __end) {
- return pair<_Iter, _Iter>(__end, std::move(__end));
+ if (__ret == __last) {
+ return pair<_Iter, _Iter>(__ret, std::move(__ret));
}
++__ret;
}
@@ -87,9 +88,9 @@ __shift_right(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::templa
auto __trail = __first;
auto __lead = __ret;
while (__trail != __ret) {
- if (__lead == __end) {
+ if (__lead == __last) {
std::__move<_AlgPolicy>(std::move(__first), std::move(__trail), __ret);
- return pair<_Iter, _Iter>(__ret, std::move(__end));
+ return pair<_Iter, _Iter>(__ret, std::move(__lead));
}
++__trail;
++__lead;
@@ -97,10 +98,10 @@ __shift_right(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::templa
_Iter __mid = __first;
while (true) {
- if (__lead == __end) {
+ if (__lead == __last) {
__trail = std::__move<_AlgPolicy>(__mid, __ret, __trail).second;
std::__move<_AlgPolicy>(std::move(__first), std::move(__mid), std::move(__trail));
- return pair<_Iter, _Iter>(__ret, std::move(__end));
+ return pair<_Iter, _Iter>(__ret, std::move(__lead));
}
_IterOps<_AlgPolicy>::iter_swap(__mid, __trail);
++__mid;
More information about the libcxx-commits
mailing list