[libcxx-commits] [libcxx] [libc++][C++26] P2562R1: `constexpr` Stable Sorting (PR #110320)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Nov 9 04:05:29 PST 2024


https://github.com/PaulXiCao updated https://github.com/llvm/llvm-project/pull/110320

>From 477f2f38a97cd0075869857b7ef956bf04c059bf Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 27 Sep 2024 21:36:37 +0200
Subject: [PATCH 01/20] constexpr stable_sort

---
 libcxx/include/__algorithm/sort.h        |  2 +-
 libcxx/include/__algorithm/stable_sort.h | 48 +++++++++++++-----------
 libcxx/include/__memory/destruct_n.h     | 20 +++++-----
 3 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 0b2137dee2f77e..2e858fd15022d8 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -283,7 +283,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 void
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
 __insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
 
diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index ec556aad82e8d8..4f7f8b7615781c 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -68,7 +68,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
 }
 
 template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2>
-_LIBCPP_HIDE_FROM_ABI void __merge_move_construct(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
     _InputIterator1 __first1,
     _InputIterator1 __last1,
     _InputIterator2 __first2,
@@ -106,7 +106,7 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_construct(
 }
 
 template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
-_LIBCPP_HIDE_FROM_ABI void __merge_move_assign(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_assign(
     _InputIterator1 __first1,
     _InputIterator1 __last1,
     _InputIterator2 __first2,
@@ -134,19 +134,21 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_assign(
 }
 
 template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
-void __stable_sort(_RandomAccessIterator __first,
-                   _RandomAccessIterator __last,
-                   _Compare __comp,
-                   typename iterator_traits<_RandomAccessIterator>::difference_type __len,
-                   typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
-                   ptrdiff_t __buff_size);
+_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort(
+    _RandomAccessIterator __first,
+    _RandomAccessIterator __last,
+    _Compare __comp,
+    typename iterator_traits<_RandomAccessIterator>::difference_type __len,
+    typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
+    ptrdiff_t __buff_size);
 
 template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
-void __stable_sort_move(_RandomAccessIterator __first1,
-                        _RandomAccessIterator __last1,
-                        _Compare __comp,
-                        typename iterator_traits<_RandomAccessIterator>::difference_type __len,
-                        typename iterator_traits<_RandomAccessIterator>::value_type* __first2) {
+_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move(
+    _RandomAccessIterator __first1,
+    _RandomAccessIterator __last1,
+    _Compare __comp,
+    typename iterator_traits<_RandomAccessIterator>::difference_type __len,
+    typename iterator_traits<_RandomAccessIterator>::value_type* __first2) {
   using _Ops = _IterOps<_AlgPolicy>;
 
   typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
@@ -190,12 +192,13 @@ struct __stable_sort_switch {
 };
 
 template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
-void __stable_sort(_RandomAccessIterator __first,
-                   _RandomAccessIterator __last,
-                   _Compare __comp,
-                   typename iterator_traits<_RandomAccessIterator>::difference_type __len,
-                   typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
-                   ptrdiff_t __buff_size) {
+_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort(
+    _RandomAccessIterator __first,
+    _RandomAccessIterator __last,
+    _Compare __comp,
+    typename iterator_traits<_RandomAccessIterator>::difference_type __len,
+    typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
+    ptrdiff_t __buff_size) {
   typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
   typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
   switch (__len) {
@@ -235,7 +238,7 @@ void __stable_sort(_RandomAccessIterator __first,
 }
 
 template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
-inline _LIBCPP_HIDE_FROM_ABI void
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
 __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
   using value_type      = typename iterator_traits<_RandomAccessIterator>::value_type;
   using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
@@ -254,13 +257,14 @@ __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last,
 }
 
 template <class _RandomAccessIterator, class _Compare>
-inline _LIBCPP_HIDE_FROM_ABI void
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
 stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
   std::__stable_sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
 }
 
 template <class _RandomAccessIterator>
-inline _LIBCPP_HIDE_FROM_ABI void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
   std::stable_sort(__first, __last, __less<>());
 }
 
diff --git a/libcxx/include/__memory/destruct_n.h b/libcxx/include/__memory/destruct_n.h
index 78635ad0af04bd..1445a909162d32 100644
--- a/libcxx/include/__memory/destruct_n.h
+++ b/libcxx/include/__memory/destruct_n.h
@@ -25,35 +25,35 @@ struct __destruct_n {
   size_t __size_;
 
   template <class _Tp>
-  _LIBCPP_HIDE_FROM_ABI void __process(_Tp* __p, false_type) _NOEXCEPT {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __process(_Tp* __p, false_type) _NOEXCEPT {
     for (size_t __i = 0; __i < __size_; ++__i, ++__p)
       __p->~_Tp();
   }
 
   template <class _Tp>
-  _LIBCPP_HIDE_FROM_ABI void __process(_Tp*, true_type) _NOEXCEPT {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __process(_Tp*, true_type) _NOEXCEPT {}
 
-  _LIBCPP_HIDE_FROM_ABI void __incr(false_type) _NOEXCEPT { ++__size_; }
-  _LIBCPP_HIDE_FROM_ABI void __incr(true_type) _NOEXCEPT {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr(false_type) _NOEXCEPT { ++__size_; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr(true_type) _NOEXCEPT {}
 
-  _LIBCPP_HIDE_FROM_ABI void __set(size_t __s, false_type) _NOEXCEPT { __size_ = __s; }
-  _LIBCPP_HIDE_FROM_ABI void __set(size_t, true_type) _NOEXCEPT {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t __s, false_type) _NOEXCEPT { __size_ = __s; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t, true_type) _NOEXCEPT {}
 
 public:
-  _LIBCPP_HIDE_FROM_ABI explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {}
 
   template <class _Tp>
-  _LIBCPP_HIDE_FROM_ABI void __incr() _NOEXCEPT {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr() _NOEXCEPT {
     __incr(integral_constant<bool, is_trivially_destructible<_Tp>::value>());
   }
 
   template <class _Tp>
-  _LIBCPP_HIDE_FROM_ABI void __set(size_t __s, _Tp*) _NOEXCEPT {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t __s, _Tp*) _NOEXCEPT {
     __set(__s, integral_constant<bool, is_trivially_destructible<_Tp>::value>());
   }
 
   template <class _Tp>
-  _LIBCPP_HIDE_FROM_ABI void operator()(_Tp* __p) _NOEXCEPT {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void operator()(_Tp* __p) _NOEXCEPT {
     __process(__p, integral_constant<bool, is_trivially_destructible<_Tp>::value>());
   }
 };

>From 5dbcf56fa84f73fcab779edd480d7d7de5b4acee Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 27 Sep 2024 21:36:54 +0200
Subject: [PATCH 02/20] tests

---
 .../alg.sort/stable.sort/stable_sort.pass.cpp | 233 ++++++++++++------
 1 file changed, 163 insertions(+), 70 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index 4301d22027de85..92803c89dbcb7c 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -14,7 +14,9 @@
 //   void
 //   stable_sort(Iter first, Iter last);
 
+#include <__config>
 #include <algorithm>
+#include <array>
 #include <cassert>
 #include <iterator>
 #include <random>
@@ -23,8 +25,6 @@
 #include "count_new.h"
 #include "test_macros.h"
 
-std::mt19937 randomness;
-
 template <class RI>
 void
 test_sort_helper(RI f, RI l)
@@ -80,66 +80,149 @@ test_sort_()
     }
 }
 
-void
-test_larger_sorts(int N, int M)
-{
-    assert(N != 0);
-    assert(M != 0);
-    // create array length N filled with M different numbers
-    int* array = new int[N];
-    int x = 0;
-    for (int i = 0; i < N; ++i)
-    {
-        array[i] = x;
-        if (++x == M)
-            x = 0;
+template <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> init_saw_tooth_pattern() {
+  std::array<int, N> array;
+  for (int i = 0, x = 0; i < N; ++i) {
+    array[i] = x;
+    if (++x == M)
+      x = 0;
+  }
+  return array;
+}
+
+template <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_saw_tooth_pattern() {
+  std::array<int, N> array = init_saw_tooth_pattern<N, M>();
+  std::stable_sort(array.begin(), array.end());
+  return array;
+}
+
+template <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_already_sorted() {
+  std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+  std::stable_sort(array.begin(), array.end());
+  return array;
+}
+
+template <int N, int M>
+std::array<int, N> sort_reversely_sorted() {
+  std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+  std::reverse(array.begin(), array.end());
+  std::stable_sort(array.begin(), array.end());
+  return array;
+}
+
+template <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_swapped_sorted_ranges() {
+  std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+  std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2);
+  std::stable_sort(array.begin(), array.end());
+  return array;
+}
+
+template <int N, int M>
+std::array<int, N> sort_reversely_swapped_sorted_ranges() {
+  std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+  std::reverse(array.begin(), array.end());
+  std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2);
+  std::stable_sort(array.begin(), array.end());
+  return array;
+}
+
+#if _LIBCPP_STD_VER >= 26
+#  define COMPILE_OR_RUNTIME_ASSERT(func)                                                                              \
+    if consteval {                                                                                                     \
+      static_assert(func);                                                                                             \
+    } else {                                                                                                           \
+      assert(func);                                                                                                    \
     }
-    // test saw tooth pattern
-    std::stable_sort(array, array+N);
-    assert(std::is_sorted(array, array+N));
-    // test random pattern
-    std::shuffle(array, array+N, randomness);
-    std::stable_sort(array, array+N);
-    assert(std::is_sorted(array, array+N));
-    // test sorted pattern
-    std::stable_sort(array, array+N);
-    assert(std::is_sorted(array, array+N));
-    // test reverse sorted pattern
-    std::reverse(array, array+N);
-    std::stable_sort(array, array+N);
-    assert(std::is_sorted(array, array+N));
-    // test swap ranges 2 pattern
-    std::swap_ranges(array, array+N/2, array+N/2);
-    std::stable_sort(array, array+N);
-    assert(std::is_sorted(array, array+N));
-    // test reverse swap ranges 2 pattern
-    std::reverse(array, array+N);
-    std::swap_ranges(array, array+N/2, array+N/2);
-    std::stable_sort(array, array+N);
-    assert(std::is_sorted(array, array+N));
-    delete [] array;
+#else
+#  define COMPILE_OR_RUNTIME_ASSERT(func) assert(func);
+#endif
+
+template <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() {
+  static_assert(N > 0, "");
+  static_assert(M > 0, "");
+
+  { // test saw tooth pattern
+    _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+    COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
+  }
+
+#if _LIBCPP_STD_VER >= 26
+  if !consteval
+#endif
+  { // test random pattern
+    // random-number generators not constexpr-friendly
+    static std::mt19937 randomness;
+    std::array<int, N> array = init_saw_tooth_pattern<N, M>();
+    std::shuffle(array.begin(), array.end(), randomness);
+    std::stable_sort(array.begin(), array.end());
+    assert(std::is_sorted(array.begin(), array.end()));
+  }
+
+  { // test sorted pattern
+    _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> array = sort_already_sorted<N, M>();
+    COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
+  }
+
+#if _LIBCPP_STD_VER >= 26
+  if !consteval
+#endif
+  { // test reverse sorted pattern
+    // consteval error: "constexpr evaluation hit maximum step limit"
+    std::array<int, N> array = sort_reversely_sorted<N, M>();
+    assert(std::is_sorted(array.begin(), array.end()));
+  }
+
+  { // test swap ranges 2 pattern
+    _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> array = sort_swapped_sorted_ranges<N, M>();
+    COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
+  }
+
+#if _LIBCPP_STD_VER >= 26
+  if !consteval
+#endif
+  { // test reverse swap ranges 2 pattern
+    // consteval error: "constexpr evaluation hit maximum step limit"
+    std::array<int, N> array = sort_reversely_swapped_sorted_ranges<N, M>();
+    assert(std::is_sorted(array.begin(), array.end()));
+  }
 }
 
-void
-test_larger_sorts(int N)
-{
-    test_larger_sorts(N, 1);
-    test_larger_sorts(N, 2);
-    test_larger_sorts(N, 3);
-    test_larger_sorts(N, N/2-1);
-    test_larger_sorts(N, N/2);
-    test_larger_sorts(N, N/2+1);
-    test_larger_sorts(N, N-2);
-    test_larger_sorts(N, N-1);
-    test_larger_sorts(N, N);
+template <int N>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() {
+  test_larger_sorts<N, 1>();
+  test_larger_sorts<N, 2>();
+  test_larger_sorts<N, 3>();
+  test_larger_sorts<N, N / 2 - 1>();
+  test_larger_sorts<N, N / 2>();
+  test_larger_sorts<N, N / 2 + 1>();
+  test_larger_sorts<N, N - 2>();
+  test_larger_sorts<N, N - 1>();
+  test_larger_sorts<N, N>();
 }
 
-int main(int, char**)
-{
-    // test null range
+#if _LIBCPP_STD_VER >= 26
+#  define COMPILE_AND_RUNTIME_CALL(func)                                                                               \
+    func;                                                                                                              \
+    static_assert((func, true));
+#else
+#  define COMPILE_AND_RUNTIME_CALL(func) func;
+#endif
+
+int main(int, char**) {
+  { // test null range
     int d = 0;
     std::stable_sort(&d, &d);
-    // exhaustively test all possibilities up to length 8
+#if _LIBCPP_STD_VER >= 26
+    static_assert((std::stable_sort(&d, &d), true));
+#endif
+  }
+
+  { // exhaustively test all possibilities up to length 8
     test_sort_<1>();
     test_sort_<2>();
     test_sort_<3>();
@@ -148,22 +231,32 @@ int main(int, char**)
     test_sort_<6>();
     test_sort_<7>();
     test_sort_<8>();
+  }
 
-    test_larger_sorts(256);
-    test_larger_sorts(257);
-    test_larger_sorts(499);
-    test_larger_sorts(500);
-    test_larger_sorts(997);
-    test_larger_sorts(1000);
-    test_larger_sorts(1009);
-
-#if !defined(TEST_HAS_NO_EXCEPTIONS)
-    { // check that the algorithm works without memory
-        std::vector<int> vec(150, 3);
-        getGlobalMemCounter()->throw_after = 0;
-        std::stable_sort(vec.begin(), vec.end());
-    }
-#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
+  { // larger sorts
+    // run- and conditionally compile-time tests
+    test_larger_sorts<256>();
+    test_larger_sorts<257>();
+#if _LIBCPP_STD_VER >= 26
+    static_assert((test_larger_sorts<256>(), true));
+    static_assert((test_larger_sorts<257>(), true));
+#endif
+
+    // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
+    test_larger_sorts<499>();
+    test_larger_sorts<500>();
+    test_larger_sorts<997>();
+    test_larger_sorts<1000>();
+    test_larger_sorts<1009>();
+  }
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  { // check that the algorithm works without memory
+    std::vector<int> vec(150, 3);
+    getGlobalMemCounter()->throw_after = 0;
+    std::stable_sort(vec.begin(), vec.end());
+  }
+#endif
 
   return 0;
 }

>From 0733a85daccad052dac87920045b3ad2459fa60b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 27 Sep 2024 21:48:37 +0200
Subject: [PATCH 03/20] update algorithm synopsis

---
 libcxx/include/algorithm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 17d63ce0cf1c0f..fd80bd7150829d 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -1530,11 +1530,11 @@ template <class RandomAccessIterator, class Compare>
     sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
 
 template <class RandomAccessIterator>
-    void
+    constexpr void               // constexpr in C++26
     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
 template <class RandomAccessIterator, class Compare>
-    void
+    constexpr void               // constexpr in C++26
     stable_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
 
 template <class RandomAccessIterator>

>From db314e2b7ce99b93ce4a19c75e022d8c5f91ecab Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 27 Sep 2024 21:50:51 +0200
Subject: [PATCH 04/20] update docs

---
 libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 8864b1ebe28891..a780c721f63d96 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -2,7 +2,7 @@
 "`P2497R0 <https://wg21.link/P2497R0>`__","Testing for success or failure of ``<charconv>`` functions","2023-06 (Varna)","|Complete|","18.0",""
 "`P2592R3 <https://wg21.link/P2592R3>`__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","",""
 "`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","","",""
-"`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","","",""
+"`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Complete|","20.0",""
 "`P2545R4 <https://wg21.link/P2545R4>`__","Read-Copy Update (RCU)","2023-06 (Varna)","","",""
 "`P2530R3 <https://wg21.link/P2530R3>`__","Hazard Pointers for C++26","2023-06 (Varna)","","",""
 "`P2538R1 <https://wg21.link/P2538R1>`__","ADL-proof ``std::projected``","2023-06 (Varna)","|Complete|","18.0",""

>From 8221f443f8a5eedbbadfcf55502db4aae1af4942 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Wed, 2 Oct 2024 22:39:53 +0200
Subject: [PATCH 05/20] paper status: partial

---
 libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index a780c721f63d96..8bdf7464e22e40 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -2,7 +2,7 @@
 "`P2497R0 <https://wg21.link/P2497R0>`__","Testing for success or failure of ``<charconv>`` functions","2023-06 (Varna)","|Complete|","18.0",""
 "`P2592R3 <https://wg21.link/P2592R3>`__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","",""
 "`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","","",""
-"`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Complete|","20.0",""
+"`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Partial|","20.0",""
 "`P2545R4 <https://wg21.link/P2545R4>`__","Read-Copy Update (RCU)","2023-06 (Varna)","","",""
 "`P2530R3 <https://wg21.link/P2530R3>`__","Hazard Pointers for C++26","2023-06 (Varna)","","",""
 "`P2538R1 <https://wg21.link/P2538R1>`__","ADL-proof ``std::projected``","2023-06 (Varna)","|Complete|","18.0",""

>From 7abb0b8a40979bf24b1ef0e3eb30561d7f0ddaa8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 19:13:04 +0200
Subject: [PATCH 06/20] remove include of internal header

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp        | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index 92803c89dbcb7c..14560a98fff727 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -14,7 +14,6 @@
 //   void
 //   stable_sort(Iter first, Iter last);
 
-#include <__config>
 #include <algorithm>
 #include <array>
 #include <cassert>

>From da3173c7f23fce94b0e17873c3a8f397b340c378 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 19:15:42 +0200
Subject: [PATCH 07/20] replace _LIBCPP_CONSTEXPR_SINCE_CXX26 by
 TEST_CONSTEXPR_CXX26

---
 .../alg.sort/stable.sort/stable_sort.pass.cpp  | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index 14560a98fff727..89cf06bad3046a 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -80,7 +80,7 @@ test_sort_()
 }
 
 template <int N, int M>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> init_saw_tooth_pattern() {
+TEST_CONSTEXPR_CXX26 std::array<int, N> init_saw_tooth_pattern() {
   std::array<int, N> array;
   for (int i = 0, x = 0; i < N; ++i) {
     array[i] = x;
@@ -91,14 +91,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> init_saw_tooth_pattern() {
 }
 
 template <int N, int M>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_saw_tooth_pattern() {
+TEST_CONSTEXPR_CXX26 std::array<int, N> sort_saw_tooth_pattern() {
   std::array<int, N> array = init_saw_tooth_pattern<N, M>();
   std::stable_sort(array.begin(), array.end());
   return array;
 }
 
 template <int N, int M>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_already_sorted() {
+TEST_CONSTEXPR_CXX26 std::array<int, N> sort_already_sorted() {
   std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
   std::stable_sort(array.begin(), array.end());
   return array;
@@ -113,7 +113,7 @@ std::array<int, N> sort_reversely_sorted() {
 }
 
 template <int N, int M>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_swapped_sorted_ranges() {
+TEST_CONSTEXPR_CXX26 std::array<int, N> sort_swapped_sorted_ranges() {
   std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
   std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2);
   std::stable_sort(array.begin(), array.end());
@@ -141,12 +141,12 @@ std::array<int, N> sort_reversely_swapped_sorted_ranges() {
 #endif
 
 template <int N, int M>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() {
+TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   static_assert(N > 0, "");
   static_assert(M > 0, "");
 
   { // test saw tooth pattern
-    _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+    TEST_CONSTEXPR_CXX26 std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
     COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
   }
 
@@ -163,7 +163,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() {
   }
 
   { // test sorted pattern
-    _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> array = sort_already_sorted<N, M>();
+    TEST_CONSTEXPR_CXX26 std::array<int, N> array = sort_already_sorted<N, M>();
     COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
   }
 
@@ -177,7 +177,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() {
   }
 
   { // test swap ranges 2 pattern
-    _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> array = sort_swapped_sorted_ranges<N, M>();
+    TEST_CONSTEXPR_CXX26 std::array<int, N> array = sort_swapped_sorted_ranges<N, M>();
     COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
   }
 
@@ -192,7 +192,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() {
 }
 
 template <int N>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() {
+TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   test_larger_sorts<N, 1>();
   test_larger_sorts<N, 2>();
   test_larger_sorts<N, 3>();

>From 5f518d27f7a363b6ca468669899eae26174cfa83 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 4 Oct 2024 19:14:05 +0200
Subject: [PATCH 08/20] documentation: use proper function declaration

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index 89cf06bad3046a..cb32174a2ca0c5 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -8,11 +8,9 @@
 
 // <algorithm>
 
-// template<RandomAccessIterator Iter>
-//   requires ShuffleIterator<Iter>
-//         && LessThanComparable<Iter::value_type>
-//   void
-//   stable_sort(Iter first, Iter last);
+// template <class RandomAccessIterator>
+//     constexpr void               // constexpr in C++26
+//     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
 #include <algorithm>
 #include <array>

>From 693c338552ca78a69163b8428230fe6305d1b13f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 5 Oct 2024 22:13:23 +0200
Subject: [PATCH 09/20] workaround for gcc bug with placement new

---
 libcxx/include/__algorithm/stable_sort.h | 38 ++++++++++++++++--------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 4f7f8b7615781c..feb28c69a8175b 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -34,6 +34,18 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
+#  define __STABLE_SORT_NEW(__placement_args, __type, __new_initializer)                                               \
+    do {                                                                                                               \
+      [__placement_args] { ::new (__placement_args) __type(__new_initializer); }();                                    \
+    } while (0)
+#else
+#  define __STABLE_SORT_NEW(__placement_args, __type, __new_initializer)                                               \
+    do {                                                                                                               \
+      ::new (__placement_args) __type(__new_initializer);                                                              \
+    } while (0)
+#endif
+
 template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
 _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
     _BidirectionalIterator __first1,
@@ -47,19 +59,19 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
     value_type* __last2 = __first2;
-    ::new ((void*)__last2) value_type(_Ops::__iter_move(__first1));
+    __STABLE_SORT_NEW((void*)__last2, value_type, _Ops::__iter_move(__first1));
     __d.template __incr<value_type>();
     for (++__last2; ++__first1 != __last1; ++__last2) {
       value_type* __j2 = __last2;
       value_type* __i2 = __j2;
       if (__comp(*__first1, *--__i2)) {
-        ::new ((void*)__j2) value_type(std::move(*__i2));
+        __STABLE_SORT_NEW((void*)__j2, value_type, std::move(*__i2));
         __d.template __incr<value_type>();
         for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
           *__j2 = std::move(*__i2);
         *__j2 = _Ops::__iter_move(__first1);
       } else {
-        ::new ((void*)__j2) value_type(_Ops::__iter_move(__first1));
+        __STABLE_SORT_NEW((void*)__j2, value_type, _Ops::__iter_move(__first1));
         __d.template __incr<value_type>();
       }
     }
@@ -83,22 +95,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
   for (; true; ++__result) {
     if (__first1 == __last1) {
       for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr<value_type>())
-        ::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
+        __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first2));
       __h.release();
       return;
     }
     if (__first2 == __last2) {
       for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr<value_type>())
-        ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
+        __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first1));
       __h.release();
       return;
     }
     if (__comp(*__first2, *__first1)) {
-      ::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
+      __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first2));
       __d.template __incr<value_type>();
       ++__first2;
     } else {
-      ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
+      __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first1));
       __d.template __incr<value_type>();
       ++__first1;
     }
@@ -156,21 +168,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move(
   case 0:
     return;
   case 1:
-    ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
+    __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1));
     return;
   case 2:
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
     if (__comp(*--__last1, *__first1)) {
-      ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
+      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__last1));
       __d.template __incr<value_type>();
       ++__first2;
-      ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
+      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1));
     } else {
-      ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
+      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1));
       __d.template __incr<value_type>();
       ++__first2;
-      ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
+      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__last1));
     }
     __h2.release();
     return;
@@ -268,8 +280,8 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
   std::stable_sort(__first, __last, __less<>());
 }
 
+#undef __STABLE_SORT_NEW
 _LIBCPP_END_NAMESPACE_STD
-
 _LIBCPP_POP_MACROS
 
 #endif // _LIBCPP___ALGORITHM_STABLE_SORT_H

>From e401b3c438cdec9f5ff99f9a7986ac9f9bd9c0bb Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 6 Oct 2024 15:00:48 +0200
Subject: [PATCH 10/20] workaround for gcc bug with placement new: fix lambda
 capturing

---
 libcxx/include/__algorithm/stable_sort.h | 40 ++++++++++++++----------
 1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index feb28c69a8175b..7ad8c36b19e077 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -34,15 +34,22 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#define __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                 \
+  do {                                                                                                                 \
+    ::new (__placement_arg) __type(__new_initializer_func(__new_initializer_arg));                                     \
+  } while (0)
+
 #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
-#  define __STABLE_SORT_NEW(__placement_args, __type, __new_initializer)                                               \
+#  define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                    \
     do {                                                                                                               \
-      [__placement_args] { ::new (__placement_args) __type(__new_initializer); }();                                    \
+      [__placement_arg, &__new_initializer_arg] {                                                                       \
+        __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg);                \
+      }();                                                                                                             \
     } while (0)
 #else
-#  define __STABLE_SORT_NEW(__placement_args, __type, __new_initializer)                                               \
+#  define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                                                \
     do {                                                                                                               \
-      ::new (__placement_args) __type(__new_initializer);                                                              \
+      __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg);                  \
     } while (0)
 #endif
 
@@ -59,19 +66,19 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
     value_type* __last2 = __first2;
-    __STABLE_SORT_NEW((void*)__last2, value_type, _Ops::__iter_move(__first1));
+    __STABLE_SORT_NEW((void*)__last2, value_type, _Ops::__iter_move, __first1);
     __d.template __incr<value_type>();
     for (++__last2; ++__first1 != __last1; ++__last2) {
       value_type* __j2 = __last2;
       value_type* __i2 = __j2;
       if (__comp(*__first1, *--__i2)) {
-        __STABLE_SORT_NEW((void*)__j2, value_type, std::move(*__i2));
+        __STABLE_SORT_NEW((void*)__j2, value_type, std::move, *__i2);
         __d.template __incr<value_type>();
         for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
           *__j2 = std::move(*__i2);
         *__j2 = _Ops::__iter_move(__first1);
       } else {
-        __STABLE_SORT_NEW((void*)__j2, value_type, _Ops::__iter_move(__first1));
+        __STABLE_SORT_NEW((void*)__j2, value_type, _Ops::__iter_move, __first1);
         __d.template __incr<value_type>();
       }
     }
@@ -95,22 +102,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
   for (; true; ++__result) {
     if (__first1 == __last1) {
       for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr<value_type>())
-        __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first2));
+        __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first2);
       __h.release();
       return;
     }
     if (__first2 == __last2) {
       for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr<value_type>())
-        __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first1));
+        __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first1);
       __h.release();
       return;
     }
     if (__comp(*__first2, *__first1)) {
-      __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first2));
+      __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first2);
       __d.template __incr<value_type>();
       ++__first2;
     } else {
-      __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first1));
+      __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first1);
       __d.template __incr<value_type>();
       ++__first1;
     }
@@ -168,21 +175,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move(
   case 0:
     return;
   case 1:
-    __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1));
+    __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1);
     return;
   case 2:
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
     if (__comp(*--__last1, *__first1)) {
-      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__last1));
+      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __last1);
       __d.template __incr<value_type>();
       ++__first2;
-      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1));
+      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1);
     } else {
-      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1));
+      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1);
       __d.template __incr<value_type>();
       ++__first2;
-      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__last1));
+      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __last1);
     }
     __h2.release();
     return;
@@ -281,6 +288,7 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
 }
 
 #undef __STABLE_SORT_NEW
+#undef __STABLE_SORT_NEW_IMPL
 _LIBCPP_END_NAMESPACE_STD
 _LIBCPP_POP_MACROS
 

>From 514ecdb5b65a564085f6addb7901ce8b26ca0fe2 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 6 Oct 2024 21:16:33 +0200
Subject: [PATCH 11/20] workaround for gcc bug with placement new: v3

---
 libcxx/include/__algorithm/stable_sort.h | 33 ++++++++++++------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 7ad8c36b19e077..2fe78c0346a9c7 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -34,20 +34,21 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+// Workaround for "constexpr placement new" bug in gcc (fixed in 14.2).
+// See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715.
 #define __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                 \
   do {                                                                                                                 \
-    ::new (__placement_arg) __type(__new_initializer_func(__new_initializer_arg));                                     \
+    ::new ((void*)__placement_arg) __type(__new_initializer_func(__new_initializer_arg));                              \
   } while (0)
-
 #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
 #  define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                    \
     do {                                                                                                               \
-      [__placement_arg, &__new_initializer_arg] {                                                                       \
+      [__placement_arg, &__new_initializer_arg] {                                                                      \
         __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg);                \
       }();                                                                                                             \
     } while (0)
 #else
-#  define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                                                \
+#  define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                    \
     do {                                                                                                               \
       __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg);                  \
     } while (0)
@@ -66,19 +67,19 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
     value_type* __last2 = __first2;
-    __STABLE_SORT_NEW((void*)__last2, value_type, _Ops::__iter_move, __first1);
+    __STABLE_SORT_NEW(__last2, value_type, _Ops::__iter_move, __first1);
     __d.template __incr<value_type>();
     for (++__last2; ++__first1 != __last1; ++__last2) {
       value_type* __j2 = __last2;
       value_type* __i2 = __j2;
       if (__comp(*__first1, *--__i2)) {
-        __STABLE_SORT_NEW((void*)__j2, value_type, std::move, *__i2);
+        __STABLE_SORT_NEW(__j2, value_type, std::move, *__i2);
         __d.template __incr<value_type>();
         for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
           *__j2 = std::move(*__i2);
         *__j2 = _Ops::__iter_move(__first1);
       } else {
-        __STABLE_SORT_NEW((void*)__j2, value_type, _Ops::__iter_move, __first1);
+        __STABLE_SORT_NEW(__j2, value_type, _Ops::__iter_move, __first1);
         __d.template __incr<value_type>();
       }
     }
@@ -102,22 +103,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
   for (; true; ++__result) {
     if (__first1 == __last1) {
       for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr<value_type>())
-        __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first2);
+        __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2);
       __h.release();
       return;
     }
     if (__first2 == __last2) {
       for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr<value_type>())
-        __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first1);
+        __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
       __h.release();
       return;
     }
     if (__comp(*__first2, *__first1)) {
-      __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first2);
+      __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2);
       __d.template __incr<value_type>();
       ++__first2;
     } else {
-      __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first1);
+      __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
       __d.template __incr<value_type>();
       ++__first1;
     }
@@ -175,21 +176,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move(
   case 0:
     return;
   case 1:
-    __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1);
+    __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
     return;
   case 2:
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
     if (__comp(*--__last1, *__first1)) {
-      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __last1);
+      __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
       __d.template __incr<value_type>();
       ++__first2;
-      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1);
+      __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
     } else {
-      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1);
+      __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
       __d.template __incr<value_type>();
       ++__first2;
-      __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __last1);
+      __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
     }
     __h2.release();
     return;

>From 39f2aff5d884d1a7c935a36cf5b893d56305229c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 6 Oct 2024 21:26:55 +0200
Subject: [PATCH 12/20] workaround for gcc bug with placement new: v4

---
 libcxx/include/__algorithm/stable_sort.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 2fe78c0346a9c7..66378042acda72 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -73,7 +73,10 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
       value_type* __j2 = __last2;
       value_type* __i2 = __j2;
       if (__comp(*__first1, *--__i2)) {
-        __STABLE_SORT_NEW(__j2, value_type, std::move, *__i2);
+        {
+          value_type& __tmp = *__i2;
+          __STABLE_SORT_NEW(__j2, value_type, std::move, __tmp);
+        }
         __d.template __incr<value_type>();
         for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
           *__j2 = std::move(*__i2);

>From 1fe36c2ccc2de90485a950337903b9e20a025faf Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 11 Oct 2024 21:53:13 +0200
Subject: [PATCH 13/20] workaround for gcc bug with placement new: v5 (test)

---
 libcxx/include/__algorithm/stable_sort.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 66378042acda72..73b9da9cfd8a32 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -121,7 +121,12 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
       __d.template __incr<value_type>();
       ++__first2;
     } else {
-      __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
+// __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
+#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
+      [__result, &__first1] { ::new (__result) value_type(_Ops::__iter_move(__first1)); }();
+#else
+      ::new (__result) value_type(_Ops::__iter_move(__first1));
+#endif
       __d.template __incr<value_type>();
       ++__first1;
     }

>From f6cc51bfdb663ef5e1704d8bf3fd11846ba3a944 Mon Sep 17 00:00:00 2001
From: PaulXiCao <paul.luckner at rwth-aachen.de>
Date: Sat, 12 Oct 2024 09:14:30 +0000
Subject: [PATCH 14/20] workaround for gcc bug with placement new: v6

Co-authored-by: A. Jiang <de34 at live.cn>
---
 libcxx/include/__algorithm/stable_sort.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 73b9da9cfd8a32..fb95fcc9ea6fbd 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -123,9 +123,9 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
     } else {
 // __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
 #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
-      [__result, &__first1] { ::new (__result) value_type(_Ops::__iter_move(__first1)); }();
+      [__result, &__first1] { ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); }();
 #else
-      ::new (__result) value_type(_Ops::__iter_move(__first1));
+      ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
 #endif
       __d.template __incr<value_type>();
       ++__first1;

>From d7c4fa921a8319a42087bf0abd902ddeb20b3997 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 13 Oct 2024 18:57:43 +0200
Subject: [PATCH 15/20] workaround for gcc bug with placement new: v7

---
 libcxx/include/__algorithm/stable_sort.h | 50 ++++++++----------------
 1 file changed, 17 insertions(+), 33 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index fb95fcc9ea6fbd..d9428d6672b086 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -36,22 +36,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // Workaround for "constexpr placement new" bug in gcc (fixed in 14.2).
 // See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715.
-#define __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                 \
-  do {                                                                                                                 \
-    ::new ((void*)__placement_arg) __type(__new_initializer_func(__new_initializer_arg));                              \
-  } while (0)
 #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
-#  define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                    \
-    do {                                                                                                               \
-      [__placement_arg, &__new_initializer_arg] {                                                                      \
-        __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg);                \
-      }();                                                                                                             \
-    } while (0)
+#  define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter)                                             \
+    [__ptr, &__iter] { ::new ((void*)__ptr) __type(__move_func(__iter)); }()
 #else
-#  define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg)                    \
-    do {                                                                                                               \
-      __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg);                  \
-    } while (0)
+#  define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter)                                             \
+    ::new ((void*)__ptr) __type(__move_func(__iter))
 #endif
 
 template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
@@ -67,7 +57,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
     value_type* __last2 = __first2;
-    __STABLE_SORT_NEW(__last2, value_type, _Ops::__iter_move, __first1);
+    _LIBCPP_MOVING_PLACEMENT_NEW(__last2, value_type, _Ops::__iter_move, __first1);
     __d.template __incr<value_type>();
     for (++__last2; ++__first1 != __last1; ++__last2) {
       value_type* __j2 = __last2;
@@ -75,14 +65,14 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
       if (__comp(*__first1, *--__i2)) {
         {
           value_type& __tmp = *__i2;
-          __STABLE_SORT_NEW(__j2, value_type, std::move, __tmp);
+          _LIBCPP_MOVING_PLACEMENT_NEW(__j2, value_type, std::move, __tmp);
         }
         __d.template __incr<value_type>();
         for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
           *__j2 = std::move(*__i2);
         *__j2 = _Ops::__iter_move(__first1);
       } else {
-        __STABLE_SORT_NEW(__j2, value_type, _Ops::__iter_move, __first1);
+        _LIBCPP_MOVING_PLACEMENT_NEW(__j2, value_type, _Ops::__iter_move, __first1);
         __d.template __incr<value_type>();
       }
     }
@@ -106,27 +96,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
   for (; true; ++__result) {
     if (__first1 == __last1) {
       for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr<value_type>())
-        __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2);
+        _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first2);
       __h.release();
       return;
     }
     if (__first2 == __last2) {
       for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr<value_type>())
-        __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
+        _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first1);
       __h.release();
       return;
     }
     if (__comp(*__first2, *__first1)) {
-      __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2);
+      _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first2);
       __d.template __incr<value_type>();
       ++__first2;
     } else {
-// __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
-#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
-      [__result, &__first1] { ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); }();
-#else
-      ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
-#endif
+      _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first1);
       __d.template __incr<value_type>();
       ++__first1;
     }
@@ -184,21 +169,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move(
   case 0:
     return;
   case 1:
-    __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
+    _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
     return;
   case 2:
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
     if (__comp(*--__last1, *__first1)) {
-      __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
+      _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
       __d.template __incr<value_type>();
       ++__first2;
-      __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
+      _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
     } else {
-      __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
+      _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
       __d.template __incr<value_type>();
       ++__first2;
-      __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
+      _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
     }
     __h2.release();
     return;
@@ -296,8 +281,7 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
   std::stable_sort(__first, __last, __less<>());
 }
 
-#undef __STABLE_SORT_NEW
-#undef __STABLE_SORT_NEW_IMPL
+#undef _LIBCPP_MOVING_PLACEMENT_NEW
 _LIBCPP_END_NAMESPACE_STD
 _LIBCPP_POP_MACROS
 

>From c3470a27beb71efc855ed8bdc9fe343ce0918ef4 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 13 Oct 2024 19:00:27 +0200
Subject: [PATCH 16/20] test: use TEST_STD_VER

---
 .../alg.sort/stable.sort/stable_sort.pass.cpp      | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index cb32174a2ca0c5..720b93e5d1779c 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -127,7 +127,7 @@ std::array<int, N> sort_reversely_swapped_sorted_ranges() {
   return array;
 }
 
-#if _LIBCPP_STD_VER >= 26
+#if TEST_STD_VER >= 26
 #  define COMPILE_OR_RUNTIME_ASSERT(func)                                                                              \
     if consteval {                                                                                                     \
       static_assert(func);                                                                                             \
@@ -148,7 +148,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
     COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
   }
 
-#if _LIBCPP_STD_VER >= 26
+#if TEST_STD_VER >= 26
   if !consteval
 #endif
   { // test random pattern
@@ -165,7 +165,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
     COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
   }
 
-#if _LIBCPP_STD_VER >= 26
+#if TEST_STD_VER >= 26
   if !consteval
 #endif
   { // test reverse sorted pattern
@@ -179,7 +179,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
     COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
   }
 
-#if _LIBCPP_STD_VER >= 26
+#if TEST_STD_VER >= 26
   if !consteval
 #endif
   { // test reverse swap ranges 2 pattern
@@ -202,7 +202,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   test_larger_sorts<N, N>();
 }
 
-#if _LIBCPP_STD_VER >= 26
+#if TEST_STD_VER >= 26
 #  define COMPILE_AND_RUNTIME_CALL(func)                                                                               \
     func;                                                                                                              \
     static_assert((func, true));
@@ -214,7 +214,7 @@ int main(int, char**) {
   { // test null range
     int d = 0;
     std::stable_sort(&d, &d);
-#if _LIBCPP_STD_VER >= 26
+#if TEST_STD_VER >= 26
     static_assert((std::stable_sort(&d, &d), true));
 #endif
   }
@@ -234,7 +234,7 @@ int main(int, char**) {
     // run- and conditionally compile-time tests
     test_larger_sorts<256>();
     test_larger_sorts<257>();
-#if _LIBCPP_STD_VER >= 26
+#if TEST_STD_VER >= 26
     static_assert((test_larger_sorts<256>(), true));
     static_assert((test_larger_sorts<257>(), true));
 #endif

>From 6bd6297886133ccf22ff68ea927ec87fe3994a63 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 18 Oct 2024 21:19:47 +0200
Subject: [PATCH 17/20] increase constexpr-steps as unstable abi tests cause
 more evaluation steps

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index 720b93e5d1779c..bcd5155138a169 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -12,6 +12,8 @@
 //     constexpr void               // constexpr in C++26
 //     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000
+
 #include <algorithm>
 #include <array>
 #include <cassert>
@@ -234,14 +236,16 @@ int main(int, char**) {
     // run- and conditionally compile-time tests
     test_larger_sorts<256>();
     test_larger_sorts<257>();
+    test_larger_sorts<499>();
+    test_larger_sorts<500>();
 #if TEST_STD_VER >= 26
     static_assert((test_larger_sorts<256>(), true));
     static_assert((test_larger_sorts<257>(), true));
+    static_assert((test_larger_sorts<499>(), true));
+    static_assert((test_larger_sorts<500>(), true));
 #endif
 
     // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
-    test_larger_sorts<499>();
-    test_larger_sorts<500>();
     test_larger_sorts<997>();
     test_larger_sorts<1000>();
     test_larger_sorts<1009>();

>From e93a63069067e3779d44f5a2c11d74b16eaac6a3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 18 Oct 2024 22:06:51 +0200
Subject: [PATCH 18/20] simplify testing (possible b.c. increase of
 constexpr-steps)

---
 .../alg.sort/stable.sort/stable_sort.pass.cpp | 53 +++++--------------
 1 file changed, 12 insertions(+), 41 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index bcd5155138a169..8302c59ef0ef54 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -12,7 +12,7 @@
 //     constexpr void               // constexpr in C++26
 //     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
-// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
 
 #include <algorithm>
 #include <array>
@@ -105,7 +105,7 @@ TEST_CONSTEXPR_CXX26 std::array<int, N> sort_already_sorted() {
 }
 
 template <int N, int M>
-std::array<int, N> sort_reversely_sorted() {
+TEST_CONSTEXPR_CXX26 std::array<int, N> sort_reversely_sorted() {
   std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
   std::reverse(array.begin(), array.end());
   std::stable_sort(array.begin(), array.end());
@@ -121,7 +121,7 @@ TEST_CONSTEXPR_CXX26 std::array<int, N> sort_swapped_sorted_ranges() {
 }
 
 template <int N, int M>
-std::array<int, N> sort_reversely_swapped_sorted_ranges() {
+TEST_CONSTEXPR_CXX26 std::array<int, N> sort_reversely_swapped_sorted_ranges() {
   std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
   std::reverse(array.begin(), array.end());
   std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2);
@@ -129,25 +129,14 @@ std::array<int, N> sort_reversely_swapped_sorted_ranges() {
   return array;
 }
 
-#if TEST_STD_VER >= 26
-#  define COMPILE_OR_RUNTIME_ASSERT(func)                                                                              \
-    if consteval {                                                                                                     \
-      static_assert(func);                                                                                             \
-    } else {                                                                                                           \
-      assert(func);                                                                                                    \
-    }
-#else
-#  define COMPILE_OR_RUNTIME_ASSERT(func) assert(func);
-#endif
-
 template <int N, int M>
 TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   static_assert(N > 0, "");
   static_assert(M > 0, "");
 
   { // test saw tooth pattern
-    TEST_CONSTEXPR_CXX26 std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
-    COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
+    std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+    assert(std::is_sorted(array.begin(), array.end()));
   }
 
 #if TEST_STD_VER >= 26
@@ -163,29 +152,21 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   }
 
   { // test sorted pattern
-    TEST_CONSTEXPR_CXX26 std::array<int, N> array = sort_already_sorted<N, M>();
-    COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
+    std::array<int, N> array = sort_already_sorted<N, M>();
+    assert(std::is_sorted(array.begin(), array.end()));
   }
 
-#if TEST_STD_VER >= 26
-  if !consteval
-#endif
   { // test reverse sorted pattern
-    // consteval error: "constexpr evaluation hit maximum step limit"
     std::array<int, N> array = sort_reversely_sorted<N, M>();
     assert(std::is_sorted(array.begin(), array.end()));
   }
 
   { // test swap ranges 2 pattern
-    TEST_CONSTEXPR_CXX26 std::array<int, N> array = sort_swapped_sorted_ranges<N, M>();
-    COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end()))
+    std::array<int, N> array = sort_swapped_sorted_ranges<N, M>();
+    assert(std::is_sorted(array.begin(), array.end()));
   }
 
-#if TEST_STD_VER >= 26
-  if !consteval
-#endif
   { // test reverse swap ranges 2 pattern
-    // consteval error: "constexpr evaluation hit maximum step limit"
     std::array<int, N> array = sort_reversely_swapped_sorted_ranges<N, M>();
     assert(std::is_sorted(array.begin(), array.end()));
   }
@@ -204,14 +185,6 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   test_larger_sorts<N, N>();
 }
 
-#if TEST_STD_VER >= 26
-#  define COMPILE_AND_RUNTIME_CALL(func)                                                                               \
-    func;                                                                                                              \
-    static_assert((func, true));
-#else
-#  define COMPILE_AND_RUNTIME_CALL(func) func;
-#endif
-
 int main(int, char**) {
   { // test null range
     int d = 0;
@@ -233,19 +206,17 @@ int main(int, char**) {
   }
 
   { // larger sorts
-    // run- and conditionally compile-time tests
+    // run- and compile-time tests
     test_larger_sorts<256>();
     test_larger_sorts<257>();
-    test_larger_sorts<499>();
-    test_larger_sorts<500>();
 #if TEST_STD_VER >= 26
     static_assert((test_larger_sorts<256>(), true));
     static_assert((test_larger_sorts<257>(), true));
-    static_assert((test_larger_sorts<499>(), true));
-    static_assert((test_larger_sorts<500>(), true));
 #endif
 
     // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
+    test_larger_sorts<499>();
+    test_larger_sorts<500>();
     test_larger_sorts<997>();
     test_larger_sorts<1000>();
     test_larger_sorts<1009>();

>From 0e4559e6ec101356213063fe6cc8b9aa8c740def Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 9 Nov 2024 12:56:13 +0100
Subject: [PATCH 19/20] refactor tests: do not extract tests into separate
 functions

---
 .../alg.sort/stable.sort/stable_sort.pass.cpp | 163 +++++++-----------
 1 file changed, 60 insertions(+), 103 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index 8302c59ef0ef54..e924d3562c9246 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -80,96 +80,48 @@ test_sort_()
 }
 
 template <int N, int M>
-TEST_CONSTEXPR_CXX26 std::array<int, N> init_saw_tooth_pattern() {
-  std::array<int, N> array;
-  for (int i = 0, x = 0; i < N; ++i) {
+TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
+  static_assert(N != 0);
+  static_assert(M != 0);
+
+  // create array length N filled with M different numbers
+  std::array<int, N> array_;
+  int* const array = array_.data();
+  int x            = 0;
+  for (int i = 0; i < N; ++i) {
     array[i] = x;
     if (++x == M)
       x = 0;
   }
-  return array;
-}
-
-template <int N, int M>
-TEST_CONSTEXPR_CXX26 std::array<int, N> sort_saw_tooth_pattern() {
-  std::array<int, N> array = init_saw_tooth_pattern<N, M>();
-  std::stable_sort(array.begin(), array.end());
-  return array;
-}
-
-template <int N, int M>
-TEST_CONSTEXPR_CXX26 std::array<int, N> sort_already_sorted() {
-  std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
-  std::stable_sort(array.begin(), array.end());
-  return array;
-}
-
-template <int N, int M>
-TEST_CONSTEXPR_CXX26 std::array<int, N> sort_reversely_sorted() {
-  std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
-  std::reverse(array.begin(), array.end());
-  std::stable_sort(array.begin(), array.end());
-  return array;
-}
-
-template <int N, int M>
-TEST_CONSTEXPR_CXX26 std::array<int, N> sort_swapped_sorted_ranges() {
-  std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
-  std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2);
-  std::stable_sort(array.begin(), array.end());
-  return array;
-}
-
-template <int N, int M>
-TEST_CONSTEXPR_CXX26 std::array<int, N> sort_reversely_swapped_sorted_ranges() {
-  std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
-  std::reverse(array.begin(), array.end());
-  std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2);
-  std::stable_sort(array.begin(), array.end());
-  return array;
-}
-
-template <int N, int M>
-TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
-  static_assert(N > 0, "");
-  static_assert(M > 0, "");
-
-  { // test saw tooth pattern
-    std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
-    assert(std::is_sorted(array.begin(), array.end()));
-  }
-
+  // test saw tooth pattern
+  std::stable_sort(array, array + N);
+  assert(std::is_sorted(array, array + N));
+  // test random pattern
 #if TEST_STD_VER >= 26
-  if !consteval
+  if !consteval // random-number generators not constexpr-friendly
 #endif
-  { // test random pattern
-    // random-number generators not constexpr-friendly
+  {
     static std::mt19937 randomness;
-    std::array<int, N> array = init_saw_tooth_pattern<N, M>();
-    std::shuffle(array.begin(), array.end(), randomness);
-    std::stable_sort(array.begin(), array.end());
-    assert(std::is_sorted(array.begin(), array.end()));
-  }
-
-  { // test sorted pattern
-    std::array<int, N> array = sort_already_sorted<N, M>();
-    assert(std::is_sorted(array.begin(), array.end()));
-  }
-
-  { // test reverse sorted pattern
-    std::array<int, N> array = sort_reversely_sorted<N, M>();
-    assert(std::is_sorted(array.begin(), array.end()));
-  }
-
-  { // test swap ranges 2 pattern
-    std::array<int, N> array = sort_swapped_sorted_ranges<N, M>();
-    assert(std::is_sorted(array.begin(), array.end()));
-  }
-
-  { // test reverse swap ranges 2 pattern
-    std::array<int, N> array = sort_reversely_swapped_sorted_ranges<N, M>();
-    assert(std::is_sorted(array.begin(), array.end()));
+    std::shuffle(array, array + N, randomness);
+    std::stable_sort(array, array + N);
+    assert(std::is_sorted(array, array + N));
   }
+  // test sorted pattern
+  std::stable_sort(array, array + N);
+  assert(std::is_sorted(array, array + N));
+  // test reverse sorted pattern
+  std::reverse(array, array + N);
+  std::stable_sort(array, array + N);
+  assert(std::is_sorted(array, array + N));
+  // test swap ranges 2 pattern
+  std::swap_ranges(array, array + N / 2, array + N / 2);
+  std::stable_sort(array, array + N);
+  assert(std::is_sorted(array, array + N));
+  // test reverse swap ranges 2 pattern
+  std::reverse(array, array + N);
+  std::swap_ranges(array, array + N / 2, array + N / 2);
+  std::stable_sort(array, array + N);
+  assert(std::is_sorted(array, array + N));
 }
 
 template <int N>
@@ -185,16 +137,16 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   test_larger_sorts<N, N>();
 }
 
-int main(int, char**) {
-  { // test null range
-    int d = 0;
-    std::stable_sort(&d, &d);
+TEST_CONSTEXPR_CXX26 void test() {
+  // test null range
+  int d = 0;
+  std::stable_sort(&d, &d);
+
+  // exhaustively test all possibilities up to length 8
 #if TEST_STD_VER >= 26
-    static_assert((std::stable_sort(&d, &d), true));
+  if !consteval
 #endif
-  }
-
-  { // exhaustively test all possibilities up to length 8
+  {
     test_sort_<1>();
     test_sort_<2>();
     test_sort_<3>();
@@ -205,30 +157,35 @@ int main(int, char**) {
     test_sort_<8>();
   }
 
-  { // larger sorts
-    // run- and compile-time tests
-    test_larger_sorts<256>();
-    test_larger_sorts<257>();
+  test_larger_sorts<256>();
+  test_larger_sorts<257>();
+  test_larger_sorts<499>();
+  test_larger_sorts<500>();
+  test_larger_sorts<997>();
 #if TEST_STD_VER >= 26
-    static_assert((test_larger_sorts<256>(), true));
-    static_assert((test_larger_sorts<257>(), true));
+  if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
 #endif
-
-    // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
-    test_larger_sorts<499>();
-    test_larger_sorts<500>();
-    test_larger_sorts<997>();
+  {
     test_larger_sorts<1000>();
     test_larger_sorts<1009>();
   }
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
+#if !defined(TEST_HAS_NO_EXCEPTIONS)
+#  if TEST_STD_VER >= 26
+  if !consteval
+#  endif
   { // check that the algorithm works without memory
     std::vector<int> vec(150, 3);
     getGlobalMemCounter()->throw_after = 0;
     std::stable_sort(vec.begin(), vec.end());
   }
-#endif
+#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
+}
 
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert((test(), true));
+#endif
   return 0;
 }

>From 6709efc01a033b4b7b3c4ffba3312b911ae0724f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 9 Nov 2024 13:04:48 +0100
Subject: [PATCH 20/20] tests: match previous formatting

---
 .../alg.sort/stable.sort/stable_sort.pass.cpp | 185 +++++++++---------
 1 file changed, 96 insertions(+), 89 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
index e924d3562c9246..bcc4505b4c0f3c 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp
@@ -80,112 +80,119 @@ test_sort_()
 }
 
 template <int N, int M>
-TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
-  static_assert(N != 0);
-  static_assert(M != 0);
-
-  // create array length N filled with M different numbers
-  std::array<int, N> array_;
-  int* const array = array_.data();
-  int x            = 0;
-  for (int i = 0; i < N; ++i) {
-    array[i] = x;
-    if (++x == M)
-      x = 0;
-  }
-  // test saw tooth pattern
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
-  // test random pattern
+TEST_CONSTEXPR_CXX26
+void
+test_larger_sorts()
+{
+    static_assert(N != 0);
+    static_assert(M != 0);
+    // create array length N filled with M different numbers
+    std::array<int, N> array_;
+    int* array = array_.data();
+    int x = 0;
+    for (int i = 0; i < N; ++i)
+    {
+        array[i] = x;
+        if (++x == M)
+            x = 0;
+    }
+    // test saw tooth pattern
+    std::stable_sort(array, array+N);
+    assert(std::is_sorted(array, array+N));
+    // test random pattern
 #if TEST_STD_VER >= 26
-  if !consteval // random-number generators not constexpr-friendly
+    if !consteval // random-number generators not constexpr-friendly
 #endif
-  {
-    static std::mt19937 randomness;
-    std::shuffle(array, array + N, randomness);
-    std::stable_sort(array, array + N);
-    assert(std::is_sorted(array, array + N));
-  }
-  // test sorted pattern
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
-  // test reverse sorted pattern
-  std::reverse(array, array + N);
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
-  // test swap ranges 2 pattern
-  std::swap_ranges(array, array + N / 2, array + N / 2);
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
-  // test reverse swap ranges 2 pattern
-  std::reverse(array, array + N);
-  std::swap_ranges(array, array + N / 2, array + N / 2);
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
+    {
+        static std::mt19937 randomness;
+        std::shuffle(array, array+N, randomness);
+        std::stable_sort(array, array+N);
+        assert(std::is_sorted(array, array+N));
+    }
+    // test sorted pattern
+    std::stable_sort(array, array+N);
+    assert(std::is_sorted(array, array+N));
+    // test reverse sorted pattern
+    std::reverse(array, array+N);
+    std::stable_sort(array, array+N);
+    assert(std::is_sorted(array, array+N));
+    // test swap ranges 2 pattern
+    std::swap_ranges(array, array+N/2, array+N/2);
+    std::stable_sort(array, array+N);
+    assert(std::is_sorted(array, array+N));
+    // test reverse swap ranges 2 pattern
+    std::reverse(array, array+N);
+    std::swap_ranges(array, array+N/2, array+N/2);
+    std::stable_sort(array, array+N);
+    assert(std::is_sorted(array, array+N));
 }
 
 template <int N>
-TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
-  test_larger_sorts<N, 1>();
-  test_larger_sorts<N, 2>();
-  test_larger_sorts<N, 3>();
-  test_larger_sorts<N, N / 2 - 1>();
-  test_larger_sorts<N, N / 2>();
-  test_larger_sorts<N, N / 2 + 1>();
-  test_larger_sorts<N, N - 2>();
-  test_larger_sorts<N, N - 1>();
-  test_larger_sorts<N, N>();
+TEST_CONSTEXPR_CXX26
+void
+test_larger_sorts()
+{
+    test_larger_sorts<N, 1>();
+    test_larger_sorts<N, 2>();
+    test_larger_sorts<N, 3>();
+    test_larger_sorts<N, N/2-1>();
+    test_larger_sorts<N, N/2>();
+    test_larger_sorts<N, N/2+1>();
+    test_larger_sorts<N, N-2>();
+    test_larger_sorts<N, N-1>();
+    test_larger_sorts<N, N>();
 }
 
-TEST_CONSTEXPR_CXX26 void test() {
-  // test null range
-  int d = 0;
-  std::stable_sort(&d, &d);
-
-  // exhaustively test all possibilities up to length 8
+TEST_CONSTEXPR_CXX26 void test()
+{
+    // test null range
+    int d = 0;
+    std::stable_sort(&d, &d);
+  
+    // exhaustively test all possibilities up to length 8
 #if TEST_STD_VER >= 26
-  if !consteval
+    if !consteval
 #endif
-  {
-    test_sort_<1>();
-    test_sort_<2>();
-    test_sort_<3>();
-    test_sort_<4>();
-    test_sort_<5>();
-    test_sort_<6>();
-    test_sort_<7>();
-    test_sort_<8>();
-  }
-
-  test_larger_sorts<256>();
-  test_larger_sorts<257>();
-  test_larger_sorts<499>();
-  test_larger_sorts<500>();
-  test_larger_sorts<997>();
+    {
+        test_sort_<1>();
+        test_sort_<2>();
+        test_sort_<3>();
+        test_sort_<4>();
+        test_sort_<5>();
+        test_sort_<6>();
+        test_sort_<7>();
+        test_sort_<8>();
+    }
+  
+    test_larger_sorts<256>();
+    test_larger_sorts<257>();
+    test_larger_sorts<499>();
+    test_larger_sorts<500>();
+    test_larger_sorts<997>();
 #if TEST_STD_VER >= 26
-  if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
+    if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
 #endif
-  {
-    test_larger_sorts<1000>();
-    test_larger_sorts<1009>();
-  }
+    {
+        test_larger_sorts<1000>();
+        test_larger_sorts<1009>();
+    }
 
 #if !defined(TEST_HAS_NO_EXCEPTIONS)
-#  if TEST_STD_VER >= 26
-  if !consteval
-#  endif
-  { // check that the algorithm works without memory
-    std::vector<int> vec(150, 3);
-    getGlobalMemCounter()->throw_after = 0;
-    std::stable_sort(vec.begin(), vec.end());
-  }
+#if TEST_STD_VER >= 26
+    if !consteval
+#endif
+    { // check that the algorithm works without memory
+        std::vector<int> vec(150, 3);
+        getGlobalMemCounter()->throw_after = 0;
+        std::stable_sort(vec.begin(), vec.end());
+    }
 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
 }
 
 int main(int, char**) {
-  test();
+    test();
 #if TEST_STD_VER >= 26
-  static_assert((test(), true));
+    static_assert((test(), true));
 #endif
-  return 0;
+    return 0;
 }



More information about the libcxx-commits mailing list