[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