[libcxx-commits] [libcxx] [libc++] Support sorting consteval-only ranges (PR #134623)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Tue Apr 15 16:44:35 PDT 2025


https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/134623

>From d4f2563db2f4a82e0d36a133b172bcf09c2f672a Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 8 Apr 2025 05:59:20 +0800
Subject: [PATCH 1/3] [libc++] Support sorting consteval-only ranges

In [P2996R11](https://isocpp.org/files/papers/P2996R11.html), it is
reported that libc++'s `sort` mechanisms eventually instantiate some
non-`constexpr` function templates, which will be ill-fomred for
`consteval`-only `std::meta::info`. Unfortunately, such ill-formedness
can be reproduced in C++20 with DRs, e.g., by an iterator type which
only supports `consteval` operations.

This patch fixes that issue by making non-`constexpr` branches (since
C++20) only contain externally instiantiated `__sort` specializations.
This also makes `sort` perform the same operations at compile time and
run time.

Drive-by: Enables test cases for `ranges::sort` with proxy iterators.
---
 libcxx/include/__algorithm/sort.h             | 134 ++++++-----
 libcxx/include/__bit/bit_log2.h               |   6 +-
 .../alg.sort/sort/ranges.sort.pass.cpp        |   7 +-
 .../alg.sort/sort/sort_constexpr.pass.cpp     |  33 +++
 .../sort/sort_constexpr_comp.pass.cpp         |  33 +++
 libcxx/test/support/test_iterators.h          | 211 ++++++++++++++++++
 6 files changed, 357 insertions(+), 67 deletions(-)

diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 4332b62544b40..54e3c8d5efcf8 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -17,10 +17,13 @@
 #include <__algorithm/partial_sort.h>
 #include <__algorithm/unwrap_iter.h>
 #include <__assert>
+#include <__bit/bit_log2.h>
 #include <__bit/blsr.h>
 #include <__bit/countl.h>
 #include <__bit/countr.h>
 #include <__config>
+#include <__cstddef/ptrdiff_t.h>
+#include <__cstddef/size_t.h>
 #include <__debug_utils/randomize_range.h>
 #include <__debug_utils/strict_weak_ordering_check.h>
 #include <__functional/operations.h>
@@ -34,6 +37,7 @@
 #include <__type_traits/is_constant_evaluated.h>
 #include <__type_traits/is_same.h>
 #include <__type_traits/is_trivially_copyable.h>
+#include <__type_traits/make_unsigned.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
 #include <climits>
@@ -138,7 +142,7 @@ template <class,
           class _Compare,
           class _RandomAccessIterator,
           __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __sort4(_RandomAccessIterator __x1,
         _RandomAccessIterator __x2,
         _RandomAccessIterator __x3,
@@ -155,7 +159,7 @@ template <class _AlgPolicy,
           class _Compare,
           class _RandomAccessIterator,
           __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __sort4(_RandomAccessIterator __x1,
         _RandomAccessIterator __x2,
         _RandomAccessIterator __x3,
@@ -180,7 +184,7 @@ template <class _AlgPolicy,
           class _Compare,
           class _RandomAccessIterator,
           __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __sort5(_RandomAccessIterator __x1,
         _RandomAccessIterator __x2,
         _RandomAccessIterator __x3,
@@ -199,7 +203,7 @@ template <class _AlgPolicy,
           class _Compare,
           class _RandomAccessIterator,
           __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __sort5(_RandomAccessIterator __x1,
         _RandomAccessIterator __x2,
         _RandomAccessIterator __x3,
@@ -238,7 +242,7 @@ __selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last,
 // Sort the iterator range [__first, __last) using the comparator __comp using
 // the insertion sort algorithm.
 template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
 
@@ -268,7 +272,7 @@ __insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last,
 // Assumes that there is an element in the position (__first - 1) and that each
 // element in the input range is greater or equal to the element at __first - 1.
 template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
-_LIBCPP_HIDE_FROM_ABI void
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __insertion_sort_unguarded(_RandomAccessIterator const __first, _RandomAccessIterator __last, _Compare __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
   typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
@@ -296,7 +300,7 @@ __insertion_sort_unguarded(_RandomAccessIterator const __first, _RandomAccessIte
 }
 
 template <class _AlgPolicy, class _Comp, class _RandomAccessIterator>
-_LIBCPP_HIDE_FROM_ABI bool
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
 __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
 
@@ -350,7 +354,7 @@ __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIterator
 }
 
 template <class _AlgPolicy, class _RandomAccessIterator>
-inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos(
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap_bitmap_pos(
     _RandomAccessIterator __first, _RandomAccessIterator __last, uint64_t& __left_bitset, uint64_t& __right_bitset) {
   using _Ops = _IterOps<_AlgPolicy>;
   typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type;
@@ -368,7 +372,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos(
 template <class _Compare,
           class _RandomAccessIterator,
           class _ValueType = typename iterator_traits<_RandomAccessIterator>::value_type>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __populate_left_bitset(_RandomAccessIterator __first, _Compare __comp, _ValueType& __pivot, uint64_t& __left_bitset) {
   // Possible vectorization. With a proper "-march" flag, the following loop
   // will be compiled into a set of SIMD instructions.
@@ -384,7 +388,7 @@ __populate_left_bitset(_RandomAccessIterator __first, _Compare __comp, _ValueTyp
 template <class _Compare,
           class _RandomAccessIterator,
           class _ValueType = typename iterator_traits<_RandomAccessIterator>::value_type>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __populate_right_bitset(_RandomAccessIterator __lm1, _Compare __comp, _ValueType& __pivot, uint64_t& __right_bitset) {
   // Possible vectorization. With a proper "-march" flag, the following loop
   // will be compiled into a set of SIMD instructions.
@@ -401,7 +405,7 @@ template <class _AlgPolicy,
           class _Compare,
           class _RandomAccessIterator,
           class _ValueType = typename iterator_traits<_RandomAccessIterator>::value_type>
-inline _LIBCPP_HIDE_FROM_ABI void __bitset_partition_partial_blocks(
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __bitset_partition_partial_blocks(
     _RandomAccessIterator& __first,
     _RandomAccessIterator& __lm1,
     _Compare __comp,
@@ -448,7 +452,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __bitset_partition_partial_blocks(
 }
 
 template <class _AlgPolicy, class _RandomAccessIterator>
-inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within(
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap_bitmap_pos_within(
     _RandomAccessIterator& __first, _RandomAccessIterator& __lm1, uint64_t& __left_bitset, uint64_t& __right_bitset) {
   using _Ops = _IterOps<_AlgPolicy>;
   typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type;
@@ -489,7 +493,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within(
 // __bitset_partition uses bitsets for storing outcomes of the comparisons
 // between the pivot and other elements.
 template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
-_LIBCPP_HIDE_FROM_ABI std::pair<_RandomAccessIterator, bool>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 std::pair<_RandomAccessIterator, bool>
 __bitset_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
   typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type;
@@ -581,7 +585,7 @@ __bitset_partition(_RandomAccessIterator __first, _RandomAccessIterator __last,
 // the provided range is already sorted, false otherwise.  We assume that the
 // length of the range is at least three elements.
 template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
-_LIBCPP_HIDE_FROM_ABI std::pair<_RandomAccessIterator, bool>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 std::pair<_RandomAccessIterator, bool>
 __partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
   typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
@@ -649,7 +653,7 @@ __partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIte
 // Similar to the above function.  Elements equivalent to the pivot are put to
 // the left of the pivot.  Returns the iterator to the pivot element.
 template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
-_LIBCPP_HIDE_FROM_ABI _RandomAccessIterator
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator
 __partition_with_equals_on_left(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
   typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
@@ -712,11 +716,12 @@ __partition_with_equals_on_left(_RandomAccessIterator __first, _RandomAccessIter
 // The implementation is partly based on Orson Peters' pattern-defeating
 // quicksort, published at: <https://github.com/orlp/pdqsort>.
 template <class _AlgPolicy, class _Compare, class _RandomAccessIterator, bool _UseBitSetPartition>
-void __introsort(_RandomAccessIterator __first,
-                 _RandomAccessIterator __last,
-                 _Compare __comp,
-                 typename iterator_traits<_RandomAccessIterator>::difference_type __depth,
-                 bool __leftmost = true) {
+_LIBCPP_CONSTEXPR_SINCE_CXX20 void
+__introsort(_RandomAccessIterator __first,
+            _RandomAccessIterator __last,
+            _Compare __comp,
+            typename iterator_traits<_RandomAccessIterator>::difference_type __depth,
+            bool __leftmost = true) {
   using _Ops = _IterOps<_AlgPolicy>;
   typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
   using _Comp_ref = __comp_ref_type<_Compare>;
@@ -826,25 +831,6 @@ void __introsort(_RandomAccessIterator __first,
   }
 }
 
-template <typename _Number>
-inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) {
-  if (__n == 0)
-    return 0;
-  if (sizeof(__n) <= sizeof(unsigned))
-    return sizeof(unsigned) * CHAR_BIT - 1 - __libcpp_clz(static_cast<unsigned>(__n));
-  if (sizeof(__n) <= sizeof(unsigned long))
-    return sizeof(unsigned long) * CHAR_BIT - 1 - __libcpp_clz(static_cast<unsigned long>(__n));
-  if (sizeof(__n) <= sizeof(unsigned long long))
-    return sizeof(unsigned long long) * CHAR_BIT - 1 - __libcpp_clz(static_cast<unsigned long long>(__n));
-
-  _Number __log2 = 0;
-  while (__n > 1) {
-    __log2++;
-    __n >>= 1;
-  }
-  return __log2;
-}
-
 template <class _Comp, class _RandomAccessIterator>
 void __sort(_RandomAccessIterator, _RandomAccessIterator, _Comp);
 
@@ -877,8 +863,10 @@ __sort<__less<long double>&, long double*>(long double*, long double*, __less<lo
 template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __sort_dispatch(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
-  typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
-  difference_type __depth_limit = 2 * std::__log2i(__last - __first);
+  using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
+  using __size_type     = __make_unsigned_t<difference_type>;
+  difference_type __depth_limit =
+      static_cast<difference_type>(2 * std::__bit_log2(static_cast<__size_type>(__last - __first)));
 
   // Only use bitset partitioning for arithmetic types.  We should also check
   // that the default comparator is in use so that we are sure that there are no
@@ -912,30 +900,63 @@ using __sort_is_specialized_in_library _LIBCPP_NODEBUG = __is_any_of<
     long double>;
 
 template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, __less<>&) {
-  __less<_Type> __comp;
-  std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __sort_dispatch(_Type* __first, _Type* __last, __less<>&) {
+#if _LIBCPP_STD_VER >= 20
+  if (std::is_constant_evaluated()) {
+    auto __depth_limit = static_cast<ptrdiff_t>(2 * std::__bit_log2(static_cast<size_t>(__last - __first)));
+    std::__introsort<_ClassicAlgPolicy, ranges::less, _Type*, __use_branchless_sort<ranges::less, _Type*>>(
+        __first, __last, ranges::less{}, __depth_limit);
+  } else
+#endif
+  {
+    __less<_Type> __comp;
+    std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+  }
 }
 
 template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, less<_Type>&) {
-  __less<_Type> __comp;
-  std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __sort_dispatch(_Type* __first, _Type* __last, less<_Type>&) {
+#if _LIBCPP_STD_VER >= 20
+  if (std::is_constant_evaluated()) {
+    auto __depth_limit = static_cast<ptrdiff_t>(2 * std::__bit_log2(static_cast<size_t>(__last - __first)));
+    std::__introsort<_ClassicAlgPolicy, ranges::less, _Type*, __use_branchless_sort<ranges::less, _Type*>>(
+        __first, __last, ranges::less{}, __depth_limit);
+  } else
+#endif
+  {
+    __less<_Type> __comp;
+    std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+  }
 }
 
 #if _LIBCPP_STD_VER >= 14
 template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, less<>&) {
-  __less<_Type> __comp;
-  std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __sort_dispatch(_Type* __first, _Type* __last, less<>&) {
+#  if _LIBCPP_STD_VER >= 20
+  if (std::is_constant_evaluated()) {
+    auto __depth_limit = static_cast<ptrdiff_t>(2 * std::__bit_log2(static_cast<size_t>(__last - __first)));
+    std::__introsort<_ClassicAlgPolicy, ranges::less, _Type*, __use_branchless_sort<ranges::less, _Type*>>(
+        __first, __last, ranges::less{}, __depth_limit);
+  } else
+#  endif
+  {
+    __less<_Type> __comp;
+    std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+  }
 }
 #endif
 
 #if _LIBCPP_STD_VER >= 20
 template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, ranges::less&) {
-  __less<_Type> __comp;
-  std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+_LIBCPP_HIDE_FROM_ABI constexpr void __sort_dispatch(_Type* __first, _Type* __last, ranges::less&) {
+  if (std::is_constant_evaluated()) {
+    auto __depth_limit = static_cast<ptrdiff_t>(2 * std::__bit_log2(static_cast<size_t>(__last - __first)));
+    std::__introsort<_ClassicAlgPolicy, ranges::less, _Type*, __use_branchless_sort<ranges::less, _Type*>>(
+        __first, __last, ranges::less{}, __depth_limit);
+  } else {
+    __less<_Type> __comp;
+    std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+  }
 }
 #endif
 
@@ -944,12 +965,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
   std::__debug_randomize_range<_AlgPolicy>(__first, __last);
 
-  if (__libcpp_is_constant_evaluated()) {
-    std::__partial_sort<_AlgPolicy>(
-        std::__unwrap_iter(__first), std::__unwrap_iter(__last), std::__unwrap_iter(__last), __comp);
-  } else {
-    std::__sort_dispatch<_AlgPolicy>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __comp);
-  }
+  std::__sort_dispatch<_AlgPolicy>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __comp);
   std::__check_strict_weak_ordering_sorted(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __comp);
 }
 
diff --git a/libcxx/include/__bit/bit_log2.h b/libcxx/include/__bit/bit_log2.h
index 94ee6c3b2bb1d..b22e1ce1f84e6 100644
--- a/libcxx/include/__bit/bit_log2.h
+++ b/libcxx/include/__bit/bit_log2.h
@@ -20,16 +20,12 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if _LIBCPP_STD_VER >= 14
-
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI constexpr _Tp __bit_log2(_Tp __t) noexcept {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __bit_log2(_Tp __t) _NOEXCEPT {
   static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__bit_log2 requires an unsigned integer type");
   return numeric_limits<_Tp>::digits - 1 - std::__countl_zero(__t);
 }
 
-#endif // _LIBCPP_STD_VER >= 14
-
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___BIT_BIT_LOG2_H
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
index d7bf6dd75f90f..271254406dd94 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
@@ -115,6 +115,10 @@ constexpr void test_iterators() {
   test_iterators_1<random_access_iterator<int*>>();
   test_iterators_1<contiguous_iterator<int*>>();
   test_iterators_1<int*>();
+#if __cpp_consteval >= 202211L // TODO: Remove this guard when MSVC implements P2564R3.
+  test_iterators_1<consteval_random_access_iterator<int*>>();
+  test_iterators_1<consteval_contiguous_iterator<int*>>();
+#endif
 }
 
 constexpr bool test() {
@@ -187,8 +191,6 @@ constexpr bool test() {
     [[maybe_unused]] std::same_as<std::ranges::dangling> decltype(auto) result = std::ranges::sort(std::array{1, 2, 3});
   }
 
-  // TODO: Enable the tests once the implementation switched to use iter_move/iter_swap
-  /*
   { // ProxyIterator
     {
       std::array in = {2, 1, 3};
@@ -205,7 +207,6 @@ constexpr bool test() {
       assert((in == std::array{1, 2, 3}));
     }
   }
-  */
 
   return true;
 }
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
index afe199da1c1af..c864c2c687218 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
@@ -112,6 +112,39 @@ int main(int, char**)
     static_assert(test_pointers<17, int, int**>());
     static_assert(test_pointers<17, int, random_access_iterator<int**>>());
     static_assert(test_pointers<17, int, contiguous_iterator<int**>>());
+
+    // Test consteval-only operations
+#  if __cpp_consteval >= 202211L // TODO: Remove this guard when MSVC implements P2564R3.
+    (void)test<7, int, consteval_random_access_iterator<int*>>();
+    (void)test<7, int, consteval_contiguous_iterator<int*>>();
+    (void)test<LargeN, int, consteval_random_access_iterator<int*>>();
+    (void)test<LargeN, int, consteval_contiguous_iterator<int*>>();
+    (void)test<7, MoveOnly, consteval_random_access_iterator<MoveOnly*>>();
+    (void)test<7, MoveOnly, consteval_contiguous_iterator<MoveOnly*>>();
+    (void)test<LargeN, MoveOnly, consteval_random_access_iterator<MoveOnly*>>();
+    (void)test<LargeN, MoveOnly, consteval_contiguous_iterator<MoveOnly*>>();
+    (void)test_pointers<17, char, consteval_random_access_iterator<char**>>();
+    (void)test_pointers<17, char, consteval_contiguous_iterator<char**>>();
+    (void)test_pointers<17, const char, consteval_random_access_iterator<const char**>>();
+    (void)test_pointers<17, const char, consteval_contiguous_iterator<const char**>>();
+    (void)test_pointers<17, int, consteval_random_access_iterator<int**>>();
+    (void)test_pointers<17, int, consteval_contiguous_iterator<int**>>();
+
+    static_assert(test<7, int, consteval_random_access_iterator<int*>>());
+    static_assert(test<7, int, consteval_contiguous_iterator<int*>>());
+    static_assert(test<LargeN, int, consteval_random_access_iterator<int*>>());
+    static_assert(test<LargeN, int, consteval_contiguous_iterator<int*>>());
+    static_assert(test<7, MoveOnly, consteval_random_access_iterator<MoveOnly*>>());
+    static_assert(test<7, MoveOnly, consteval_contiguous_iterator<MoveOnly*>>());
+    static_assert(test<LargeN, MoveOnly, consteval_random_access_iterator<MoveOnly*>>());
+    static_assert(test<LargeN, MoveOnly, consteval_contiguous_iterator<MoveOnly*>>());
+    static_assert(test_pointers<17, char, consteval_random_access_iterator<char**>>());
+    static_assert(test_pointers<17, char, consteval_contiguous_iterator<char**>>());
+    static_assert(test_pointers<17, const char, consteval_random_access_iterator<const char**>>());
+    static_assert(test_pointers<17, const char, consteval_contiguous_iterator<const char**>>());
+    static_assert(test_pointers<17, int, consteval_random_access_iterator<int**>>());
+    static_assert(test_pointers<17, int, consteval_contiguous_iterator<int**>>());
+#  endif
 #endif
 
     return 0;
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
index 134830fe54110..865bb1eef0146 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
@@ -113,6 +113,39 @@ int main(int, char**)
     static_assert(test_pointers<17, int, int**>());
     static_assert(test_pointers<17, int, random_access_iterator<int**>>());
     static_assert(test_pointers<17, int, contiguous_iterator<int**>>());
+
+    // Test consteval-only operations
+#  if __cpp_consteval >= 202211L // TODO: Remove this guard when MSVC implements P2564R3.
+    (void)test<7, int, consteval_random_access_iterator<int*>>();
+    (void)test<7, int, consteval_contiguous_iterator<int*>>();
+    (void)test<LargeN, int, consteval_random_access_iterator<int*>>();
+    (void)test<LargeN, int, consteval_contiguous_iterator<int*>>();
+    (void)test<7, MoveOnly, consteval_random_access_iterator<MoveOnly*>>();
+    (void)test<7, MoveOnly, consteval_contiguous_iterator<MoveOnly*>>();
+    (void)test<LargeN, MoveOnly, consteval_random_access_iterator<MoveOnly*>>();
+    (void)test<LargeN, MoveOnly, consteval_contiguous_iterator<MoveOnly*>>();
+    (void)test_pointers<17, char, consteval_random_access_iterator<char**>>();
+    (void)test_pointers<17, char, consteval_contiguous_iterator<char**>>();
+    (void)test_pointers<17, const char, consteval_random_access_iterator<const char**>>();
+    (void)test_pointers<17, const char, consteval_contiguous_iterator<const char**>>();
+    (void)test_pointers<17, int, consteval_random_access_iterator<int**>>();
+    (void)test_pointers<17, int, consteval_contiguous_iterator<int**>>();
+
+    static_assert(test<7, int, consteval_random_access_iterator<int*>>());
+    static_assert(test<7, int, consteval_contiguous_iterator<int*>>());
+    static_assert(test<LargeN, int, consteval_random_access_iterator<int*>>());
+    static_assert(test<LargeN, int, consteval_contiguous_iterator<int*>>());
+    static_assert(test<7, MoveOnly, consteval_random_access_iterator<MoveOnly*>>());
+    static_assert(test<7, MoveOnly, consteval_contiguous_iterator<MoveOnly*>>());
+    static_assert(test<LargeN, MoveOnly, consteval_random_access_iterator<MoveOnly*>>());
+    static_assert(test<LargeN, MoveOnly, consteval_contiguous_iterator<MoveOnly*>>());
+    static_assert(test_pointers<17, char, consteval_random_access_iterator<char**>>());
+    static_assert(test_pointers<17, char, consteval_contiguous_iterator<char**>>());
+    static_assert(test_pointers<17, const char, consteval_random_access_iterator<const char**>>());
+    static_assert(test_pointers<17, const char, consteval_contiguous_iterator<const char**>>());
+    static_assert(test_pointers<17, int, consteval_random_access_iterator<int**>>());
+    static_assert(test_pointers<17, int, consteval_contiguous_iterator<int**>>());
+#  endif
 #endif
 
     return 0;
diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index 702b82b9e15a7..5ac6fa3c97055 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -362,6 +362,111 @@ cpp20_random_access_iterator(It) -> cpp20_random_access_iterator<It>;
 
 static_assert(std::random_access_iterator<cpp20_random_access_iterator<int*>>);
 
+template <std::random_access_iterator It>
+class consteval_random_access_iterator {
+  It it_;
+  support::double_move_tracker tracker_;
+
+  template <std::random_access_iterator>
+  friend class consteval_random_access_iterator;
+
+public:
+  using iterator_category = std::input_iterator_tag;
+  using iterator_concept  = std::random_access_iterator_tag;
+  using value_type        = typename std::iterator_traits<It>::value_type;
+  using difference_type   = typename std::iterator_traits<It>::difference_type;
+
+  consteval consteval_random_access_iterator() : it_() {}
+  consteval explicit consteval_random_access_iterator(It it) : it_(it) {}
+  consteval consteval_random_access_iterator(const consteval_random_access_iterator&) = default;
+  consteval consteval_random_access_iterator(consteval_random_access_iterator&&)      = default;
+
+  consteval consteval_random_access_iterator& operator=(const consteval_random_access_iterator&) = default;
+  consteval consteval_random_access_iterator& operator=(consteval_random_access_iterator&&)      = default;
+
+  template <class U>
+  consteval consteval_random_access_iterator(const consteval_random_access_iterator<U>& u)
+      : it_(u.it_), tracker_(u.tracker_) {}
+
+  template <class U>
+  consteval consteval_random_access_iterator(consteval_random_access_iterator<U>&& u)
+      : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+    u.it_ = U();
+  }
+
+  consteval decltype(auto) operator*() const { return *it_; }
+  consteval decltype(auto) operator[](difference_type n) const { return it_[n]; }
+
+  consteval consteval_random_access_iterator& operator++() {
+    ++it_;
+    return *this;
+  }
+  consteval consteval_random_access_iterator& operator--() {
+    --it_;
+    return *this;
+  }
+  consteval consteval_random_access_iterator operator++(int) { return consteval_random_access_iterator(it_++); }
+  consteval consteval_random_access_iterator operator--(int) { return consteval_random_access_iterator(it_--); }
+
+  consteval consteval_random_access_iterator& operator+=(difference_type n) {
+    it_ += n;
+    return *this;
+  }
+  consteval consteval_random_access_iterator& operator-=(difference_type n) {
+    it_ -= n;
+    return *this;
+  }
+  friend consteval consteval_random_access_iterator operator+(consteval_random_access_iterator x, difference_type n) {
+    x += n;
+    return x;
+  }
+  friend consteval consteval_random_access_iterator operator+(difference_type n, consteval_random_access_iterator x) {
+    x += n;
+    return x;
+  }
+  friend consteval consteval_random_access_iterator operator-(consteval_random_access_iterator x, difference_type n) {
+    x -= n;
+    return x;
+  }
+  friend consteval difference_type operator-(consteval_random_access_iterator x, consteval_random_access_iterator y) {
+    return x.it_ - y.it_;
+  }
+
+  friend consteval bool
+  operator==(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend consteval bool
+  operator!=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ != y.it_;
+  }
+  friend consteval bool
+  operator<(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend consteval bool
+  operator<=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend consteval bool
+  operator>(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend consteval bool
+  operator>=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ >= y.it_;
+  }
+
+  friend consteval It base(const consteval_random_access_iterator& i) { return i.it_; }
+
+  template <class T>
+  void operator,(T const&) = delete;
+};
+template <class It>
+consteval_random_access_iterator(It) -> consteval_random_access_iterator<It>;
+
+static_assert(std::random_access_iterator<consteval_random_access_iterator<int*>>);
+
 template <std::contiguous_iterator It>
 class contiguous_iterator {
   It it_;
@@ -453,6 +558,112 @@ class contiguous_iterator {
 template <class It>
 contiguous_iterator(It) -> contiguous_iterator<It>;
 
+template <std::contiguous_iterator It>
+class consteval_contiguous_iterator {
+  It it_;
+  support::double_move_tracker tracker_;
+
+  template <std::contiguous_iterator U>
+  friend class consteval_contiguous_iterator;
+
+public:
+  using iterator_category = std::contiguous_iterator_tag;
+  using value_type        = typename std::iterator_traits<It>::value_type;
+  using difference_type   = typename std::iterator_traits<It>::difference_type;
+  using pointer           = typename std::iterator_traits<It>::pointer;
+  using reference         = typename std::iterator_traits<It>::reference;
+  using element_type      = value_type;
+
+  consteval It base() const { return it_; }
+
+  consteval consteval_contiguous_iterator() : it_() {}
+  consteval explicit consteval_contiguous_iterator(It it) : it_(it) {}
+  consteval consteval_contiguous_iterator(const consteval_contiguous_iterator&) = default;
+  consteval consteval_contiguous_iterator(consteval_contiguous_iterator&&)      = default;
+
+  consteval consteval_contiguous_iterator& operator=(const consteval_contiguous_iterator&) = default;
+  consteval consteval_contiguous_iterator& operator=(consteval_contiguous_iterator&&)      = default;
+
+  template <class U>
+  consteval consteval_contiguous_iterator(const consteval_contiguous_iterator<U>& u)
+      : it_(u.it_), tracker_(u.tracker_) {}
+
+  template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
+  consteval consteval_contiguous_iterator(consteval_contiguous_iterator<U>&& u)
+      : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+    u.it_ = U();
+  }
+
+  consteval reference operator*() const { return *it_; }
+  consteval pointer operator->() const { return it_; }
+  consteval reference operator[](difference_type n) const { return it_[n]; }
+
+  consteval consteval_contiguous_iterator& operator++() {
+    ++it_;
+    return *this;
+  }
+  consteval consteval_contiguous_iterator& operator--() {
+    --it_;
+    return *this;
+  }
+  consteval consteval_contiguous_iterator operator++(int) { return consteval_contiguous_iterator(it_++); }
+  consteval consteval_contiguous_iterator operator--(int) { return consteval_contiguous_iterator(it_--); }
+
+  consteval consteval_contiguous_iterator& operator+=(difference_type n) {
+    it_ += n;
+    return *this;
+  }
+  consteval consteval_contiguous_iterator& operator-=(difference_type n) {
+    it_ -= n;
+    return *this;
+  }
+  friend consteval consteval_contiguous_iterator operator+(consteval_contiguous_iterator x, difference_type n) {
+    x += n;
+    return x;
+  }
+  friend consteval consteval_contiguous_iterator operator+(difference_type n, consteval_contiguous_iterator x) {
+    x += n;
+    return x;
+  }
+  friend consteval consteval_contiguous_iterator operator-(consteval_contiguous_iterator x, difference_type n) {
+    x -= n;
+    return x;
+  }
+  friend consteval difference_type operator-(consteval_contiguous_iterator x, consteval_contiguous_iterator y) {
+    return x.it_ - y.it_;
+  }
+
+  friend consteval bool operator==(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend consteval bool operator!=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ != y.it_;
+  }
+  friend consteval bool operator<(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend consteval bool operator<=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend consteval bool operator>(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend consteval bool operator>=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ >= y.it_;
+  }
+
+  // Note no operator<=>, use three_way_contiguous_iterator for testing operator<=>
+
+  friend consteval It base(const consteval_contiguous_iterator& i) { return i.it_; }
+
+  template <class T>
+  void operator,(T const&) = delete;
+};
+template <class It>
+consteval_contiguous_iterator(It) -> consteval_contiguous_iterator<It>;
+
+static_assert(std::contiguous_iterator<consteval_contiguous_iterator<int*>>);
+
 template <class It>
 class three_way_contiguous_iterator
 {

>From 9625fe98bb6ce91dfbe91a6e7c5619fac0173089 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Fri, 11 Apr 2025 10:40:34 +0800
Subject: [PATCH 2/3] Create `test_consteval_iterators.h` and include it

---
 .../alg.sort/sort/ranges.sort.pass.cpp        |   1 +
 .../alg.sort/sort/sort_constexpr.pass.cpp     |   1 +
 .../sort/sort_constexpr_comp.pass.cpp         |   1 +
 .../test/support/test_consteval_iterators.h   | 234 ++++++++++++++++++
 libcxx/test/support/test_iterators.h          | 211 ----------------
 5 files changed, 237 insertions(+), 211 deletions(-)
 create mode 100644 libcxx/test/support/test_consteval_iterators.h

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
index 271254406dd94..97e759f2b6df4 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
@@ -29,6 +29,7 @@
 
 #include "almost_satisfies_types.h"
 #include "test_iterators.h"
+#include "test_consteval_iterators.h"
 
 // SFINAE tests.
 
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
index c864c2c687218..a3ca2ac4bedcc 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
@@ -19,6 +19,7 @@
 
 #include "test_macros.h"
 #include "test_iterators.h"
+#include "test_consteval_iterators.h"
 #include "MoveOnly.h"
 
 const int LargeN = 128;
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
index 865bb1eef0146..925fd74ac99e0 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
@@ -20,6 +20,7 @@
 
 #include "test_macros.h"
 #include "test_iterators.h"
+#include "test_consteval_iterators.h"
 #include "MoveOnly.h"
 
 const int LargeN = 128;
diff --git a/libcxx/test/support/test_consteval_iterators.h b/libcxx/test/support/test_consteval_iterators.h
new file mode 100644
index 0000000000000..f69ba2540cc95
--- /dev/null
+++ b/libcxx/test/support/test_consteval_iterators.h
@@ -0,0 +1,234 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 SUPPORT_TEST_CONSTEVAL_ITERATORS_H
+#define SUPPORT_TEST_CONSTEVAL_ITERATORS_H
+
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+#include "double_move_tracker.h"
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 20
+
+template <std::random_access_iterator It>
+class consteval_random_access_iterator {
+  It it_;
+  support::double_move_tracker tracker_;
+
+  template <std::random_access_iterator>
+  friend class consteval_random_access_iterator;
+
+public:
+  using iterator_category = std::input_iterator_tag;
+  using iterator_concept  = std::random_access_iterator_tag;
+  using value_type        = std::iterator_traits<It>::value_type;
+  using difference_type   = std::iterator_traits<It>::difference_type;
+
+  consteval consteval_random_access_iterator() : it_() {}
+  consteval explicit consteval_random_access_iterator(It it) : it_(it) {}
+  consteval consteval_random_access_iterator(const consteval_random_access_iterator&) = default;
+  consteval consteval_random_access_iterator(consteval_random_access_iterator&&)      = default;
+
+  consteval consteval_random_access_iterator& operator=(const consteval_random_access_iterator&) = default;
+  consteval consteval_random_access_iterator& operator=(consteval_random_access_iterator&&)      = default;
+
+  template <class U>
+  consteval consteval_random_access_iterator(const consteval_random_access_iterator<U>& u)
+      : it_(u.it_), tracker_(u.tracker_) {}
+
+  template <class U>
+  consteval consteval_random_access_iterator(consteval_random_access_iterator<U>&& u)
+      : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+    u.it_ = U();
+  }
+
+  consteval decltype(auto) operator*() const { return *it_; }
+  consteval decltype(auto) operator[](difference_type n) const { return it_[n]; }
+
+  consteval consteval_random_access_iterator& operator++() {
+    ++it_;
+    return *this;
+  }
+  consteval consteval_random_access_iterator& operator--() {
+    --it_;
+    return *this;
+  }
+  consteval consteval_random_access_iterator operator++(int) { return consteval_random_access_iterator(it_++); }
+  consteval consteval_random_access_iterator operator--(int) { return consteval_random_access_iterator(it_--); }
+
+  consteval consteval_random_access_iterator& operator+=(difference_type n) {
+    it_ += n;
+    return *this;
+  }
+  consteval consteval_random_access_iterator& operator-=(difference_type n) {
+    it_ -= n;
+    return *this;
+  }
+  friend consteval consteval_random_access_iterator operator+(consteval_random_access_iterator x, difference_type n) {
+    x += n;
+    return x;
+  }
+  friend consteval consteval_random_access_iterator operator+(difference_type n, consteval_random_access_iterator x) {
+    x += n;
+    return x;
+  }
+  friend consteval consteval_random_access_iterator operator-(consteval_random_access_iterator x, difference_type n) {
+    x -= n;
+    return x;
+  }
+  friend consteval difference_type operator-(consteval_random_access_iterator x, consteval_random_access_iterator y) {
+    return x.it_ - y.it_;
+  }
+
+  friend consteval bool
+  operator==(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend consteval bool
+  operator!=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ != y.it_;
+  }
+  friend consteval bool
+  operator<(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend consteval bool
+  operator<=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend consteval bool
+  operator>(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend consteval bool
+  operator>=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
+    return x.it_ >= y.it_;
+  }
+
+  friend consteval It base(const consteval_random_access_iterator& i) { return i.it_; }
+
+  template <class T>
+  void operator,(T const&) = delete;
+};
+template <class It>
+consteval_random_access_iterator(It) -> consteval_random_access_iterator<It>;
+
+static_assert(std::random_access_iterator<consteval_random_access_iterator<int*>>);
+
+template <std::contiguous_iterator It>
+class consteval_contiguous_iterator {
+  It it_;
+  support::double_move_tracker tracker_;
+
+  template <std::contiguous_iterator U>
+  friend class consteval_contiguous_iterator;
+
+public:
+  using iterator_category = std::contiguous_iterator_tag;
+  using value_type        = std::iterator_traits<It>::value_type;
+  using difference_type   = std::iterator_traits<It>::difference_type;
+  using pointer           = std::iterator_traits<It>::pointer;
+  using reference         = std::iterator_traits<It>::reference;
+  using element_type      = value_type;
+
+  consteval It base() const { return it_; }
+
+  consteval consteval_contiguous_iterator() : it_() {}
+  consteval explicit consteval_contiguous_iterator(It it) : it_(it) {}
+  consteval consteval_contiguous_iterator(const consteval_contiguous_iterator&) = default;
+  consteval consteval_contiguous_iterator(consteval_contiguous_iterator&&)      = default;
+
+  consteval consteval_contiguous_iterator& operator=(const consteval_contiguous_iterator&) = default;
+  consteval consteval_contiguous_iterator& operator=(consteval_contiguous_iterator&&)      = default;
+
+  template <class U>
+  consteval consteval_contiguous_iterator(const consteval_contiguous_iterator<U>& u)
+      : it_(u.it_), tracker_(u.tracker_) {}
+
+  template <class U, std::enable_if_t<std::is_default_constructible_v<U>, int> = 0>
+  consteval consteval_contiguous_iterator(consteval_contiguous_iterator<U>&& u)
+      : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+    u.it_ = U();
+  }
+
+  consteval reference operator*() const { return *it_; }
+  consteval pointer operator->() const { return it_; }
+  consteval reference operator[](difference_type n) const { return it_[n]; }
+
+  consteval consteval_contiguous_iterator& operator++() {
+    ++it_;
+    return *this;
+  }
+  consteval consteval_contiguous_iterator& operator--() {
+    --it_;
+    return *this;
+  }
+  consteval consteval_contiguous_iterator operator++(int) { return consteval_contiguous_iterator(it_++); }
+  consteval consteval_contiguous_iterator operator--(int) { return consteval_contiguous_iterator(it_--); }
+
+  consteval consteval_contiguous_iterator& operator+=(difference_type n) {
+    it_ += n;
+    return *this;
+  }
+  consteval consteval_contiguous_iterator& operator-=(difference_type n) {
+    it_ -= n;
+    return *this;
+  }
+  friend consteval consteval_contiguous_iterator operator+(consteval_contiguous_iterator x, difference_type n) {
+    x += n;
+    return x;
+  }
+  friend consteval consteval_contiguous_iterator operator+(difference_type n, consteval_contiguous_iterator x) {
+    x += n;
+    return x;
+  }
+  friend consteval consteval_contiguous_iterator operator-(consteval_contiguous_iterator x, difference_type n) {
+    x -= n;
+    return x;
+  }
+  friend consteval difference_type operator-(consteval_contiguous_iterator x, consteval_contiguous_iterator y) {
+    return x.it_ - y.it_;
+  }
+
+  friend consteval bool operator==(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend consteval bool operator!=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ != y.it_;
+  }
+  friend consteval bool operator<(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend consteval bool operator<=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend consteval bool operator>(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend consteval bool operator>=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
+    return x.it_ >= y.it_;
+  }
+
+  // Note no operator<=>, use three_way_contiguous_iterator for testing operator<=>
+
+  friend consteval It base(const consteval_contiguous_iterator& i) { return i.it_; }
+
+  template <class T>
+  void operator,(T const&) = delete;
+};
+template <class It>
+consteval_contiguous_iterator(It) -> consteval_contiguous_iterator<It>;
+
+static_assert(std::contiguous_iterator<consteval_contiguous_iterator<int*>>);
+
+#endif // TEST_STD_VER >= 20
+
+#endif // SUPPORT_TEST_CONSTEVAL_ITERATORS_H
diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index 5ac6fa3c97055..702b82b9e15a7 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -362,111 +362,6 @@ cpp20_random_access_iterator(It) -> cpp20_random_access_iterator<It>;
 
 static_assert(std::random_access_iterator<cpp20_random_access_iterator<int*>>);
 
-template <std::random_access_iterator It>
-class consteval_random_access_iterator {
-  It it_;
-  support::double_move_tracker tracker_;
-
-  template <std::random_access_iterator>
-  friend class consteval_random_access_iterator;
-
-public:
-  using iterator_category = std::input_iterator_tag;
-  using iterator_concept  = std::random_access_iterator_tag;
-  using value_type        = typename std::iterator_traits<It>::value_type;
-  using difference_type   = typename std::iterator_traits<It>::difference_type;
-
-  consteval consteval_random_access_iterator() : it_() {}
-  consteval explicit consteval_random_access_iterator(It it) : it_(it) {}
-  consteval consteval_random_access_iterator(const consteval_random_access_iterator&) = default;
-  consteval consteval_random_access_iterator(consteval_random_access_iterator&&)      = default;
-
-  consteval consteval_random_access_iterator& operator=(const consteval_random_access_iterator&) = default;
-  consteval consteval_random_access_iterator& operator=(consteval_random_access_iterator&&)      = default;
-
-  template <class U>
-  consteval consteval_random_access_iterator(const consteval_random_access_iterator<U>& u)
-      : it_(u.it_), tracker_(u.tracker_) {}
-
-  template <class U>
-  consteval consteval_random_access_iterator(consteval_random_access_iterator<U>&& u)
-      : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
-    u.it_ = U();
-  }
-
-  consteval decltype(auto) operator*() const { return *it_; }
-  consteval decltype(auto) operator[](difference_type n) const { return it_[n]; }
-
-  consteval consteval_random_access_iterator& operator++() {
-    ++it_;
-    return *this;
-  }
-  consteval consteval_random_access_iterator& operator--() {
-    --it_;
-    return *this;
-  }
-  consteval consteval_random_access_iterator operator++(int) { return consteval_random_access_iterator(it_++); }
-  consteval consteval_random_access_iterator operator--(int) { return consteval_random_access_iterator(it_--); }
-
-  consteval consteval_random_access_iterator& operator+=(difference_type n) {
-    it_ += n;
-    return *this;
-  }
-  consteval consteval_random_access_iterator& operator-=(difference_type n) {
-    it_ -= n;
-    return *this;
-  }
-  friend consteval consteval_random_access_iterator operator+(consteval_random_access_iterator x, difference_type n) {
-    x += n;
-    return x;
-  }
-  friend consteval consteval_random_access_iterator operator+(difference_type n, consteval_random_access_iterator x) {
-    x += n;
-    return x;
-  }
-  friend consteval consteval_random_access_iterator operator-(consteval_random_access_iterator x, difference_type n) {
-    x -= n;
-    return x;
-  }
-  friend consteval difference_type operator-(consteval_random_access_iterator x, consteval_random_access_iterator y) {
-    return x.it_ - y.it_;
-  }
-
-  friend consteval bool
-  operator==(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
-    return x.it_ == y.it_;
-  }
-  friend consteval bool
-  operator!=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
-    return x.it_ != y.it_;
-  }
-  friend consteval bool
-  operator<(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
-    return x.it_ < y.it_;
-  }
-  friend consteval bool
-  operator<=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
-    return x.it_ <= y.it_;
-  }
-  friend consteval bool
-  operator>(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
-    return x.it_ > y.it_;
-  }
-  friend consteval bool
-  operator>=(const consteval_random_access_iterator& x, const consteval_random_access_iterator& y) {
-    return x.it_ >= y.it_;
-  }
-
-  friend consteval It base(const consteval_random_access_iterator& i) { return i.it_; }
-
-  template <class T>
-  void operator,(T const&) = delete;
-};
-template <class It>
-consteval_random_access_iterator(It) -> consteval_random_access_iterator<It>;
-
-static_assert(std::random_access_iterator<consteval_random_access_iterator<int*>>);
-
 template <std::contiguous_iterator It>
 class contiguous_iterator {
   It it_;
@@ -558,112 +453,6 @@ class contiguous_iterator {
 template <class It>
 contiguous_iterator(It) -> contiguous_iterator<It>;
 
-template <std::contiguous_iterator It>
-class consteval_contiguous_iterator {
-  It it_;
-  support::double_move_tracker tracker_;
-
-  template <std::contiguous_iterator U>
-  friend class consteval_contiguous_iterator;
-
-public:
-  using iterator_category = std::contiguous_iterator_tag;
-  using value_type        = typename std::iterator_traits<It>::value_type;
-  using difference_type   = typename std::iterator_traits<It>::difference_type;
-  using pointer           = typename std::iterator_traits<It>::pointer;
-  using reference         = typename std::iterator_traits<It>::reference;
-  using element_type      = value_type;
-
-  consteval It base() const { return it_; }
-
-  consteval consteval_contiguous_iterator() : it_() {}
-  consteval explicit consteval_contiguous_iterator(It it) : it_(it) {}
-  consteval consteval_contiguous_iterator(const consteval_contiguous_iterator&) = default;
-  consteval consteval_contiguous_iterator(consteval_contiguous_iterator&&)      = default;
-
-  consteval consteval_contiguous_iterator& operator=(const consteval_contiguous_iterator&) = default;
-  consteval consteval_contiguous_iterator& operator=(consteval_contiguous_iterator&&)      = default;
-
-  template <class U>
-  consteval consteval_contiguous_iterator(const consteval_contiguous_iterator<U>& u)
-      : it_(u.it_), tracker_(u.tracker_) {}
-
-  template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-  consteval consteval_contiguous_iterator(consteval_contiguous_iterator<U>&& u)
-      : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
-    u.it_ = U();
-  }
-
-  consteval reference operator*() const { return *it_; }
-  consteval pointer operator->() const { return it_; }
-  consteval reference operator[](difference_type n) const { return it_[n]; }
-
-  consteval consteval_contiguous_iterator& operator++() {
-    ++it_;
-    return *this;
-  }
-  consteval consteval_contiguous_iterator& operator--() {
-    --it_;
-    return *this;
-  }
-  consteval consteval_contiguous_iterator operator++(int) { return consteval_contiguous_iterator(it_++); }
-  consteval consteval_contiguous_iterator operator--(int) { return consteval_contiguous_iterator(it_--); }
-
-  consteval consteval_contiguous_iterator& operator+=(difference_type n) {
-    it_ += n;
-    return *this;
-  }
-  consteval consteval_contiguous_iterator& operator-=(difference_type n) {
-    it_ -= n;
-    return *this;
-  }
-  friend consteval consteval_contiguous_iterator operator+(consteval_contiguous_iterator x, difference_type n) {
-    x += n;
-    return x;
-  }
-  friend consteval consteval_contiguous_iterator operator+(difference_type n, consteval_contiguous_iterator x) {
-    x += n;
-    return x;
-  }
-  friend consteval consteval_contiguous_iterator operator-(consteval_contiguous_iterator x, difference_type n) {
-    x -= n;
-    return x;
-  }
-  friend consteval difference_type operator-(consteval_contiguous_iterator x, consteval_contiguous_iterator y) {
-    return x.it_ - y.it_;
-  }
-
-  friend consteval bool operator==(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
-    return x.it_ == y.it_;
-  }
-  friend consteval bool operator!=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
-    return x.it_ != y.it_;
-  }
-  friend consteval bool operator<(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
-    return x.it_ < y.it_;
-  }
-  friend consteval bool operator<=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
-    return x.it_ <= y.it_;
-  }
-  friend consteval bool operator>(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
-    return x.it_ > y.it_;
-  }
-  friend consteval bool operator>=(const consteval_contiguous_iterator& x, const consteval_contiguous_iterator& y) {
-    return x.it_ >= y.it_;
-  }
-
-  // Note no operator<=>, use three_way_contiguous_iterator for testing operator<=>
-
-  friend consteval It base(const consteval_contiguous_iterator& i) { return i.it_; }
-
-  template <class T>
-  void operator,(T const&) = delete;
-};
-template <class It>
-consteval_contiguous_iterator(It) -> consteval_contiguous_iterator<It>;
-
-static_assert(std::contiguous_iterator<consteval_contiguous_iterator<int*>>);
-
 template <class It>
 class three_way_contiguous_iterator
 {

>From 421e46e00978ce79db60f707a1c9d0321655a6e2 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Fri, 11 Apr 2025 10:41:23 +0800
Subject: [PATCH 3/3] Remove workaround for other standard libraries

---
 .../algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp   | 2 --
 .../alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp           | 2 --
 .../alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp      | 2 --
 3 files changed, 6 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
index 97e759f2b6df4..2764d956e5f00 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp
@@ -116,10 +116,8 @@ constexpr void test_iterators() {
   test_iterators_1<random_access_iterator<int*>>();
   test_iterators_1<contiguous_iterator<int*>>();
   test_iterators_1<int*>();
-#if __cpp_consteval >= 202211L // TODO: Remove this guard when MSVC implements P2564R3.
   test_iterators_1<consteval_random_access_iterator<int*>>();
   test_iterators_1<consteval_contiguous_iterator<int*>>();
-#endif
 }
 
 constexpr bool test() {
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
index a3ca2ac4bedcc..ac12f9b5a096d 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
@@ -115,7 +115,6 @@ int main(int, char**)
     static_assert(test_pointers<17, int, contiguous_iterator<int**>>());
 
     // Test consteval-only operations
-#  if __cpp_consteval >= 202211L // TODO: Remove this guard when MSVC implements P2564R3.
     (void)test<7, int, consteval_random_access_iterator<int*>>();
     (void)test<7, int, consteval_contiguous_iterator<int*>>();
     (void)test<LargeN, int, consteval_random_access_iterator<int*>>();
@@ -145,7 +144,6 @@ int main(int, char**)
     static_assert(test_pointers<17, const char, consteval_contiguous_iterator<const char**>>());
     static_assert(test_pointers<17, int, consteval_random_access_iterator<int**>>());
     static_assert(test_pointers<17, int, consteval_contiguous_iterator<int**>>());
-#  endif
 #endif
 
     return 0;
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
index 925fd74ac99e0..b732157b1b08e 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
@@ -116,7 +116,6 @@ int main(int, char**)
     static_assert(test_pointers<17, int, contiguous_iterator<int**>>());
 
     // Test consteval-only operations
-#  if __cpp_consteval >= 202211L // TODO: Remove this guard when MSVC implements P2564R3.
     (void)test<7, int, consteval_random_access_iterator<int*>>();
     (void)test<7, int, consteval_contiguous_iterator<int*>>();
     (void)test<LargeN, int, consteval_random_access_iterator<int*>>();
@@ -146,7 +145,6 @@ int main(int, char**)
     static_assert(test_pointers<17, const char, consteval_contiguous_iterator<const char**>>());
     static_assert(test_pointers<17, int, consteval_random_access_iterator<int**>>());
     static_assert(test_pointers<17, int, consteval_contiguous_iterator<int**>>());
-#  endif
 #endif
 
     return 0;



More information about the libcxx-commits mailing list