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

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 14 07:24:19 PST 2025


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

>From 2366f3cd4a0c4f20a925008bd27e020ebaa2b160 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/37] 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 ed828b6d723147..0e4d68ca56560a 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -240,7 +240,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 43f591ac02b01d..6e9fb3a7eca178 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -69,7 +69,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,
@@ -107,7 +107,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,
@@ -135,19 +135,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;
@@ -191,12 +193,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) {
@@ -236,7 +239,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;
@@ -255,13 +258,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 66adefb0f51fc7..db227a4ea1dc77 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 0ea964a2ef72971bac7dd9d657291249492fef93 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/37] 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 2a4251654665527353e32ee39981131147d6b28e 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/37] 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 14355d63f2901c..a093c6ad21b70a 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 7cf77e73c43675b39e403dd74bfbfb6c6020bfc4 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/37] 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 6659d815612d05..c64b32ee00ab56 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",""
 "`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",""

>From 05a13a74d94ae4a0cd64ce73efc6fb1f1d9c9ac8 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/37] 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 c64b32ee00ab56..0827aeb96a2c24 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",""
 "`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",""

>From e5b51d9cf58ff6fed8c573c25a2839f4436be536 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/37] 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 2ae4f9fd3528c151e74b5aff259c0199a5554367 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/37] 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 bf479373697179f48a80ac1c37fbc646c3748700 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/37] 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 5081abde98ea020984c90491f000f42b03d1e3ba 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/37] 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 6e9fb3a7eca178..6ed8ccc0607901 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -35,6 +35,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,
@@ -48,19 +60,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>();
       }
     }
@@ -84,22 +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>())
-        ::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;
     }
@@ -157,21 +169,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;
@@ -269,8 +281,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 9b139d384bfc478b16c201c311d80792bb1ecf78 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/37] 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 6ed8ccc0607901..dc418fd19ad6b1 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -35,15 +35,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
 
@@ -60,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((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>();
       }
     }
@@ -96,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((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;
     }
@@ -169,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((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;
@@ -282,6 +289,7 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
 }
 
 #undef __STABLE_SORT_NEW
+#undef __STABLE_SORT_NEW_IMPL
 _LIBCPP_END_NAMESPACE_STD
 _LIBCPP_POP_MACROS
 

>From 7dbd0043c33ec316ce1b12aaef33e6c96790809c 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/37] 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 dc418fd19ad6b1..e0ff647e08ef09 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -35,20 +35,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)
@@ -67,19 +68,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>();
       }
     }
@@ -103,22 +104,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;
     }
@@ -176,21 +177,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 363eb7c451b95271873b454f04aa3d3dadad9979 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/37] 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 e0ff647e08ef09..c56a1701d4c257 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -74,7 +74,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 11310980343b68471d279929bc59451e120d58a4 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/37] 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 c56a1701d4c257..d1f457ec47c672 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -122,7 +122,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 2aada1a62b38db06ed72f4e5d8ee5aee433bbf6e 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/37] 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 d1f457ec47c672..3c84c5b1dd7dc7 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -124,9 +124,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 8f16d4ff6fac76f2b437c4cf2dea417c27a96724 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/37] 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 3c84c5b1dd7dc7..640babe4c4466b 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -37,22 +37,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>
@@ -68,7 +58,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;
@@ -76,14 +66,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>();
       }
     }
@@ -107,27 +97,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;
     }
@@ -185,21 +170,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;
@@ -297,8 +282,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 2f90ac3f35926ce21902e7e445ef13e1e22e0539 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/37] 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 c91a11af11795131d2e560f04579aa269243c2dc 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/37] 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 47afcf17b679b0d8507fd02e92b928e82ebdd0cb 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/37] 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 61cc660f5a0f48de10cf3f767d3b8a99775bfec6 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/37] 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 648f1260d14b8a31a1e335db6f1e22330b6f0ccd 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/37] 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;
 }

>From d24a71411937fa43d9428d5b32138e54fd2ae213 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 9 Nov 2024 13:21:56 +0100
Subject: [PATCH 21/37] disable large test at compiletime

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp       | 2 +-
 1 file changed, 1 insertion(+), 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 bcc4505b4c0f3c..eb484bc9440f24 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
@@ -168,11 +168,11 @@ TEST_CONSTEXPR_CXX26 void test()
     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"
 #endif
     {
+        test_larger_sorts<997>();
         test_larger_sorts<1000>();
         test_larger_sorts<1009>();
     }

>From 61a5556fde397deec7e5ba250b85a0bd4624fcfc Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 9 Nov 2024 13:22:35 +0100
Subject: [PATCH 22/37] use construct_at for placement new gcc workaround

---
 libcxx/include/__algorithm/stable_sort.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 640babe4c4466b..7048ae2caf08b6 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -18,6 +18,7 @@
 #include <__cstddef/ptrdiff_t.h>
 #include <__debug_utils/strict_weak_ordering_check.h>
 #include <__iterator/iterator_traits.h>
+#include <__memory/construct_at.h>
 #include <__memory/destruct_n.h>
 #include <__memory/unique_ptr.h>
 #include <__memory/unique_temporary_buffer.h>
@@ -37,9 +38,9 @@ _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.
-#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
-#  define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter)                                             \
-    [__ptr, &__iter] { ::new ((void*)__ptr) __type(__move_func(__iter)); }()
+#if (_LIBCPP_STD_VER >= 20) ||                                                                                         \
+    (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100))
+#  define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) std::construct_at(__ptr, __move_func(__iter))
 #else
 #  define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter)                                             \
     ::new ((void*)__ptr) __type(__move_func(__iter))

>From 58ab844ee49afa95b04a02ac0ed54ca07b7092b8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 9 Nov 2024 17:20:53 +0100
Subject: [PATCH 23/37] tests: fix static asserts

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp     | 4 ++--
 1 file changed, 2 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 eb484bc9440f24..8548f1b01d77ac 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
@@ -84,8 +84,8 @@ TEST_CONSTEXPR_CXX26
 void
 test_larger_sorts()
 {
-    static_assert(N != 0);
-    static_assert(M != 0);
+    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();

>From e9ec61509d23c1b44b0f12d66472dcb6209b4235 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 10 Nov 2024 16:49:56 +0100
Subject: [PATCH 24/37] test: gcc hits constexpr operation limit

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp     | 4 ++--
 1 file changed, 2 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 8548f1b01d77ac..ea5f787390a8d8 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
@@ -166,12 +166,12 @@ TEST_CONSTEXPR_CXX26 void test()
   
     test_larger_sorts<256>();
     test_larger_sorts<257>();
-    test_larger_sorts<499>();
-    test_larger_sorts<500>();
 #if TEST_STD_VER >= 26
     if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
 #endif
     {
+        test_larger_sorts<499>();
+        test_larger_sorts<500>();
         test_larger_sorts<997>();
         test_larger_sorts<1000>();
         test_larger_sorts<1009>();

>From 87b56292497dafe0b0641710c1267a363575cd21 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 22 Nov 2024 22:11:52 +0100
Subject: [PATCH 25/37] add missing CONSTEXPR26 macros

---
 libcxx/include/__algorithm/inplace_merge.h | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index ad3fe6a7a505d9..eca848ebfedd11 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -47,17 +47,17 @@ class __invert // invert the sense of a comparison
   _Predicate __p_;
 
 public:
-  _LIBCPP_HIDE_FROM_ABI __invert() {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __invert() {}
 
-  _LIBCPP_HIDE_FROM_ABI explicit __invert(_Predicate __p) : __p_(__p) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit __invert(_Predicate __p) : __p_(__p) {}
 
   template <class _T1>
-  _LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool operator()(const _T1& __x) {
     return !__p_(__x);
   }
 
   template <class _T1, class _T2>
-  _LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x, const _T2& __y) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool operator()(const _T1& __x, const _T2& __y) {
     return __p_(__y, __x);
   }
 };
@@ -69,7 +69,7 @@ template <class _AlgPolicy,
           class _InputIterator2,
           class _Sent2,
           class _OutputIterator>
-_LIBCPP_HIDE_FROM_ABI void __half_inplace_merge(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __half_inplace_merge(
     _InputIterator1 __first1,
     _Sent1 __last1,
     _InputIterator2 __first2,
@@ -94,7 +94,7 @@ _LIBCPP_HIDE_FROM_ABI void __half_inplace_merge(
 }
 
 template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
-_LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __buffered_inplace_merge(
     _BidirectionalIterator __first,
     _BidirectionalIterator __middle,
     _BidirectionalIterator __last,
@@ -125,7 +125,7 @@ _LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge(
 }
 
 template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
-void __inplace_merge(
+_LIBCPP_CONSTEXPR_SINCE_CXX26 void __inplace_merge(
     _BidirectionalIterator __first,
     _BidirectionalIterator __middle,
     _BidirectionalIterator __last,

>From a7eb8c677e560452f35c278f3f4dfbd396e62a2f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 22 Nov 2024 22:12:29 +0100
Subject: [PATCH 26/37] simplify/fix placement new macro

---
 libcxx/include/__algorithm/stable_sort.h | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 7048ae2caf08b6..858d5c1e0f9dd0 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -36,10 +36,9 @@ _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.
-#if (_LIBCPP_STD_VER >= 20) ||                                                                                         \
-    (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100))
+// Making placement new available in constexpr contexts. This is necessary to work around a "constexpr placement new"
+// bug in gcc (fixed in 14.2). See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715.
+#if _LIBCPP_STD_VER >= 20
 #  define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) std::construct_at(__ptr, __move_func(__iter))
 #else
 #  define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter)                                             \

>From 50e50993aa64fdf8577987a90cc5d8a6e327b53e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 23 Nov 2024 20:03:51 +0100
Subject: [PATCH 27/37] formatting

---
 .../alg.sort/stable.sort/stable_sort.pass.cpp | 184 +++++++++---------
 1 file changed, 88 insertions(+), 96 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 ea5f787390a8d8..0c8919c337e346 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,119 +80,111 @@ 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* 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_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>();
 #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<499>();
-        test_larger_sorts<500>();
-        test_larger_sorts<997>();
-        test_larger_sorts<1000>();
-        test_larger_sorts<1009>();
-    }
+  {
+    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)
-#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;
 }

>From af7995700adb795ba924a44dc5138d25c7dd3a9c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 13 Dec 2024 22:04:08 +0100
Subject: [PATCH 28/37] make use of std::__construct_at

---
 libcxx/include/__algorithm/stable_sort.h | 34 +++++++++---------------
 1 file changed, 12 insertions(+), 22 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 858d5c1e0f9dd0..8f8226fdf85069 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -36,15 +36,6 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// Making placement new available in constexpr contexts. This is necessary to work around a "constexpr placement new"
-// bug in gcc (fixed in 14.2). See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715.
-#if _LIBCPP_STD_VER >= 20
-#  define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) std::construct_at(__ptr, __move_func(__iter))
-#else
-#  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>
 _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
     _BidirectionalIterator __first1,
@@ -58,7 +49,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;
-    _LIBCPP_MOVING_PLACEMENT_NEW(__last2, value_type, _Ops::__iter_move, __first1);
+    std::__construct_at(__last2, _Ops::__iter_move(__first1));
     __d.template __incr<value_type>();
     for (++__last2; ++__first1 != __last1; ++__last2) {
       value_type* __j2 = __last2;
@@ -66,14 +57,14 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
       if (__comp(*__first1, *--__i2)) {
         {
           value_type& __tmp = *__i2;
-          _LIBCPP_MOVING_PLACEMENT_NEW(__j2, value_type, std::move, __tmp);
+          std::__construct_at(__j2, 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 {
-        _LIBCPP_MOVING_PLACEMENT_NEW(__j2, value_type, _Ops::__iter_move, __first1);
+        std::__construct_at(__j2, _Ops::__iter_move(__first1));
         __d.template __incr<value_type>();
       }
     }
@@ -97,22 +88,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>())
-        _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first2);
+        std::__construct_at(__result, _Ops::__iter_move(__first2));
       __h.release();
       return;
     }
     if (__first2 == __last2) {
       for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr<value_type>())
-        _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first1);
+        std::__construct_at(__result, _Ops::__iter_move(__first1));
       __h.release();
       return;
     }
     if (__comp(*__first2, *__first1)) {
-      _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first2);
+      std::__construct_at(__result, _Ops::__iter_move(__first2));
       __d.template __incr<value_type>();
       ++__first2;
     } else {
-      _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first1);
+      std::__construct_at(__result, _Ops::__iter_move(__first1));
       __d.template __incr<value_type>();
       ++__first1;
     }
@@ -170,21 +161,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move(
   case 0:
     return;
   case 1:
-    _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
+    std::__construct_at(__first2, _Ops::__iter_move(__first1));
     return;
   case 2:
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
     if (__comp(*--__last1, *__first1)) {
-      _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
+      std::__construct_at(__first2, _Ops::__iter_move(__last1));
       __d.template __incr<value_type>();
       ++__first2;
-      _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
+      std::__construct_at(__first2, _Ops::__iter_move(__first1));
     } else {
-      _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
+      std::__construct_at(__first2, _Ops::__iter_move(__first1));
       __d.template __incr<value_type>();
       ++__first2;
-      _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
+      std::__construct_at(__first2, _Ops::__iter_move(__last1));
     }
     __h2.release();
     return;
@@ -282,7 +273,6 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
   std::stable_sort(__first, __last, __less<>());
 }
 
-#undef _LIBCPP_MOVING_PLACEMENT_NEW
 _LIBCPP_END_NAMESPACE_STD
 _LIBCPP_POP_MACROS
 

>From f26f23898649544232fd3894e67c328622dad1f9 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 13 Dec 2024 22:04:56 +0100
Subject: [PATCH 29/37] cleanup: undo unnecessary temp variable

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

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

>From 96c36b28a65f9e45268414606c874cb93beafc2b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 13 Dec 2024 22:14:08 +0100
Subject: [PATCH 30/37] test: use macro TEST_IS_CONSTANT_EVALUATED

---
 .../alg.sort/stable.sort/stable_sort.pass.cpp | 23 ++++++-------------
 1 file changed, 7 insertions(+), 16 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 0c8919c337e346..e8e84421f9b99b 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
@@ -96,9 +96,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   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
-#endif
+  if (!TEST_IS_CONSTANT_EVALUATED) // random-number generators not constexpr-friendly
   {
     static std::mt19937 randomness;
     std::shuffle(array, array + N, randomness);
@@ -142,10 +140,7 @@ TEST_CONSTEXPR_CXX26 void test() {
   std::stable_sort(&d, &d);
 
   // exhaustively test all possibilities up to length 8
-#if TEST_STD_VER >= 26
-  if !consteval
-#endif
-  {
+  if (!TEST_IS_CONSTANT_EVALUATED) {
     test_sort_<1>();
     test_sort_<2>();
     test_sort_<3>();
@@ -158,9 +153,7 @@ TEST_CONSTEXPR_CXX26 void test() {
 
   test_larger_sorts<256>();
   test_larger_sorts<257>();
-#if TEST_STD_VER >= 26
-  if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
-#endif
+  if (!TEST_IS_CONSTANT_EVALUATED) // only runtime tests bc. error: "constexpr evaluation hit maximum step limit"
   {
     test_larger_sorts<499>();
     test_larger_sorts<500>();
@@ -169,16 +162,14 @@ TEST_CONSTEXPR_CXX26 void test() {
     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
+  // check that the algorithm works without memory
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  if (!TEST_IS_CONSTANT_EVALUATED) {
     std::vector<int> vec(150, 3);
     getGlobalMemCounter()->throw_after = 0;
     std::stable_sort(vec.begin(), vec.end());
   }
-#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
+#endif
 }
 
 int main(int, char**) {

>From 032d66a14facd3e0b680abe6922fdcbbfc3687be Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 13 Dec 2024 22:15:46 +0100
Subject: [PATCH 31/37] test: return bool from test()

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp   | 6 ++++--
 1 file changed, 4 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 e8e84421f9b99b..07eb8be6faae1e 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
@@ -134,7 +134,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() {
   test_larger_sorts<N, N>();
 }
 
-TEST_CONSTEXPR_CXX26 void test() {
+TEST_CONSTEXPR_CXX26 bool test() {
   // test null range
   int d = 0;
   std::stable_sort(&d, &d);
@@ -170,12 +170,14 @@ TEST_CONSTEXPR_CXX26 void test() {
     std::stable_sort(vec.begin(), vec.end());
   }
 #endif
+
+  return true;
 }
 
 int main(int, char**) {
   test();
 #if TEST_STD_VER >= 26
-  static_assert((test(), true));
+  static_assert(test());
 #endif
   return 0;
 }

>From 18e8581deacd5c3b30aa1ab7ec8dc0b010ec0855 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 20 Dec 2024 21:01:34 +0100
Subject: [PATCH 32/37] increase constexpr-steps for gcc

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

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 07eb8be6faae1e..7f4114b32f9206 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
@@ -13,6 +13,7 @@
 //     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000
 
 #include <algorithm>
 #include <array>

>From 88dc8c88aa0ba2c3259fd5b044d7afe42fd77534 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 13 Jan 2025 11:09:46 -0500
Subject: [PATCH 33/37] Fix tests for stable_sort with predicate too

---
 libcxx/include/__algorithm/stable_sort.h      |   2 +-
 .../alg.sort/stable.sort/stable_sort.pass.cpp | 242 +++++++++---------
 .../stable.sort/stable_sort_comp.pass.cpp     |  90 ++++---
 3 files changed, 184 insertions(+), 150 deletions(-)

diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 4d546f366c45d7..3cfbcf08d2c5c4 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -42,7 +42,7 @@ _LIBCPP_PUSH_MACROS
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
-_LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __insertion_sort_move(
     _BidirectionalIterator __first1,
     _BidirectionalIterator __last1,
     typename iterator_traits<_BidirectionalIterator>::value_type* __first2,
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 14880ac686b328..5fb349b6701046 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
@@ -9,14 +9,13 @@
 // <algorithm>
 
 // template <class RandomAccessIterator>
-//     constexpr void               // constexpr in C++26
+//     constexpr void               // constexpr since C++26
 //     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000
 
 #include <algorithm>
-#include <array>
 #include <cassert>
 #include <iterator>
 #include <random>
@@ -25,154 +24,167 @@
 #include "count_new.h"
 #include "test_macros.h"
 
-template <class RI>
-void
-test_sort_helper(RI f, RI l)
-{
-    typedef typename std::iterator_traits<RI>::value_type value_type;
-    typedef typename std::iterator_traits<RI>::difference_type difference_type;
-
-    if (f != l)
-    {
-        difference_type len = l - f;
-        value_type* save(new value_type[len]);
-        do
-        {
-            std::copy(f, l, save);
-            std::stable_sort(save, save+len);
-            assert(std::is_sorted(save, save+len));
-        } while (std::next_permutation(f, l));
-        delete [] save;
-    }
+template <class Iterator>
+TEST_CONSTEXPR_CXX26 void test_all_permutations(Iterator first, Iterator last) {
+  using T = typename std::iterator_traits<Iterator>::value_type;
+
+  do {
+    std::vector<T> save(first, last);
+    std::stable_sort(save.begin(), save.end());
+    assert(std::is_sorted(save.begin(), save.end()));
+  } while (std::next_permutation(first, last));
 }
 
-template <class RI>
-void
-test_sort_driver_driver(RI f, RI l, int start, RI real_last)
-{
-  using value_type = typename std::iterator_traits<RI>::value_type;
+template <class Iterator>
+TEST_CONSTEXPR_CXX26 void test_sort_exhaustive_impl(Iterator first, Iterator last, int start, Iterator real_last) {
+  using T = typename std::iterator_traits<Iterator>::value_type;
 
-  for (RI i = l; i > f + start;) {
-    *--i = static_cast<value_type>(start);
-    if (f == i) {
-      test_sort_helper(f, real_last);
+  for (Iterator i = last; i > first + start;) {
+    *--i = static_cast<T>(start);
+    if (first == i) {
+      test_all_permutations(first, real_last);
     }
     if (start > 0)
-        test_sort_driver_driver(f, i, start-1, real_last);
+      test_sort_exhaustive_impl(first, i, start - 1, real_last);
   }
 }
 
-template <class RI>
-void
-test_sort_driver(RI f, RI l, int start)
-{
-    test_sort_driver_driver(f, l, start, l);
-}
-
-template <int sa, class V>
-void test_sort_() {
-  V ia[sa];
-  for (int i = 0; i < sa; ++i) {
-    test_sort_driver(ia, ia + sa, i);
+template <class T>
+TEST_CONSTEXPR_CXX26 void test_sort_exhaustive(int N) {
+  std::vector<T> vec;
+  vec.resize(N);
+  for (int i = 0; i < N; ++i) {
+    test_sort_exhaustive_impl(vec.begin(), vec.end(), i, vec.end());
   }
 }
 
-template <int sa>
-void test_sort_() {
-  test_sort_<sa, int>();
-  test_sort_<sa, float>();
-}
-
-template <class V>
-void test_larger_sorts(int N, int M) {
-  assert(N != 0);
-  assert(M != 0);
-  // create array length N filled with M different numbers
-  V* array = new V[N];
-  int x    = 0;
+template <class T>
+TEST_CONSTEXPR_CXX26 std::vector<T> generate_sawtooth(int N, int M) {
+  // Populate a sequence of length N with M different numbers
+  std::vector<T> v;
+  T x = 0;
   for (int i = 0; i < N; ++i) {
-    array[i] = static_cast<V>(x);
+    v.push_back(x);
     if (++x == M)
       x = 0;
   }
+  return v;
+}
+
+template <class T>
+TEST_CONSTEXPR_CXX26 void test_larger_sorts(int N, int M) {
+  assert(N != 0);
+  assert(M != 0);
+
   // test saw tooth pattern
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
+  {
+    auto v = generate_sawtooth<T>(N, M);
+    std::stable_sort(v.begin(), v.end());
+    assert(std::is_sorted(v.begin(), v.end()));
+  }
+
   // test random pattern
-  std::shuffle(array, array + N, randomness);
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
+  {
+    if (!TEST_IS_CONSTANT_EVALUATED) {
+      auto v = generate_sawtooth<T>(N, M);
+      std::mt19937 randomness;
+      std::shuffle(v.begin(), v.end(), randomness);
+      std::stable_sort(v.begin(), v.end());
+      assert(std::is_sorted(v.begin(), v.end()));
+    }
+  }
+
   // test sorted pattern
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
+  {
+    auto v = generate_sawtooth<T>(N, M);
+    std::sort(v.begin(), v.end());
+
+    std::stable_sort(v.begin(), v.end());
+    assert(std::is_sorted(v.begin(), v.end()));
+  }
+
   // test reverse sorted pattern
-  std::reverse(array, array + N);
-  std::stable_sort(array, array + N);
-  assert(std::is_sorted(array, array + N));
+  {
+    auto v = generate_sawtooth<T>(N, M);
+    std::sort(v.begin(), v.end());
+    std::reverse(v.begin(), v.end());
+
+    std::stable_sort(v.begin(), v.end());
+    assert(std::is_sorted(v.begin(), v.end()));
+  }
+
   // 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;
-}
+  {
+    auto v = generate_sawtooth<T>(N, M);
+    std::sort(v.begin(), v.end());
+    std::swap_ranges(v.begin(), v.begin() + (N / 2), v.begin() + (N / 2));
+
+    std::stable_sort(v.begin(), v.end());
+    assert(std::is_sorted(v.begin(), v.end()));
+  }
 
-void test_larger_sorts(int N, int M) {
-  test_larger_sorts<int>(N, M);
-  test_larger_sorts<float>(N, M);
+  // test reverse swap ranges 2 pattern
+  {
+    auto v = generate_sawtooth<T>(N, M);
+    std::sort(v.begin(), v.end());
+    std::reverse(v.begin(), v.end());
+    std::swap_ranges(v.begin(), v.begin() + (N / 2), v.begin() + (N / 2));
+
+    std::stable_sort(v.begin(), v.end());
+    assert(std::is_sorted(v.begin(), v.end()));
+  }
 }
 
-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>();
+template <class T>
+TEST_CONSTEXPR_CXX26 void test_larger_sorts(int N) {
+  test_larger_sorts<T>(N, 1);
+  test_larger_sorts<T>(N, 2);
+  test_larger_sorts<T>(N, 3);
+  test_larger_sorts<T>(N, N / 2 - 1);
+  test_larger_sorts<T>(N, N / 2);
+  test_larger_sorts<T>(N, N / 2 + 1);
+  test_larger_sorts<T>(N, N - 2);
+  test_larger_sorts<T>(N, N - 1);
+  test_larger_sorts<T>(N, N);
 }
 
+template <class T>
 TEST_CONSTEXPR_CXX26 bool test() {
   // test null range
-  int d = 0;
-  std::stable_sort(&d, &d);
+  {
+    T value = 0;
+    std::stable_sort(&value, &value);
+  }
 
   // exhaustively test all possibilities up to length 8
   if (!TEST_IS_CONSTANT_EVALUATED) {
-    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_sort_exhaustive<T>(1);
+    test_sort_exhaustive<T>(2);
+    test_sort_exhaustive<T>(3);
+    test_sort_exhaustive<T>(4);
+    test_sort_exhaustive<T>(5);
+    test_sort_exhaustive<T>(6);
+    test_sort_exhaustive<T>(7);
+    test_sort_exhaustive<T>(8);
   }
 
-  test_larger_sorts(256);
-  test_larger_sorts(257);
+  test_larger_sorts<T>(256);
+  test_larger_sorts<T>(257);
   if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constexpr evaluation limit
-    test_larger_sorts(499);
-    test_larger_sorts(500);
-    test_larger_sorts(997);
-    test_larger_sorts(1000);
-    test_larger_sorts(1009);
-    test_larger_sorts(1024);
-    test_larger_sorts(1031);
-    test_larger_sorts(2053);
+    test_larger_sorts<T>(499);
+    test_larger_sorts<T>(500);
+    test_larger_sorts<T>(997);
+    test_larger_sorts<T>(1000);
+    test_larger_sorts<T>(1009);
+    test_larger_sorts<T>(1024);
+    test_larger_sorts<T>(1031);
+    test_larger_sorts<T>(2053);
   }
 
   // check that the algorithm works without memory
 #ifndef TEST_HAS_NO_EXCEPTIONS
   if (!TEST_IS_CONSTANT_EVALUATED) {
-    std::vector<int> vec(150, 3);
+    std::vector<T> vec(150, T(3));
     getGlobalMemCounter()->throw_after = 0;
     std::stable_sort(vec.begin(), vec.end());
   }
@@ -182,9 +194,11 @@ TEST_CONSTEXPR_CXX26 bool test() {
 }
 
 int main(int, char**) {
-  test();
+  test<int>();
+  test<float>();
 #if TEST_STD_VER >= 26
-  static_assert(test());
+  static_assert(test<int>());
+  static_assert(test<float>());
 #endif
   return 0;
 }
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp
index 5ee6d89064941f..17b9c572a17297 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp
@@ -9,10 +9,8 @@
 // <algorithm>
 
 // template<RandomAccessIterator Iter, StrictWeakOrder<auto, Iter::value_type> Compare>
-//   requires ShuffleIterator<Iter>
-//         && CopyConstructible<Compare>
-//   void
-//   stable_sort(Iter first, Iter last, Compare comp);
+//   requires ShuffleIterator<Iter> && CopyConstructible<Compare>
+//   constexpr void stable_sort(Iter first, Iter last, Compare comp); // constexpr since C++26
 
 #include <algorithm>
 #include <functional>
@@ -27,57 +25,79 @@
 
 struct indirect_less {
   template <class P>
-  bool operator()(const P& x, const P& y) const {
+  TEST_CONSTEXPR_CXX26 bool operator()(const P& x, const P& y) const {
     return *x < *y;
   }
 };
 
-std::mt19937 randomness;
-
 struct first_only {
-  bool operator()(const std::pair<int, int>& x, const std::pair<int, int>& y) const { return x.first < y.first; }
+  TEST_CONSTEXPR_CXX26 bool operator()(const std::pair<int, int>& x, const std::pair<int, int>& y) const {
+    return x.first < y.first;
+  }
 };
 
-void test()
-{
-    typedef std::pair<int, int> P;
-    const int N = 1000;
-    const int M = 10;
-    std::vector<P> v(N);
-    int x = 0;
-    int ver = 0;
-    for (int i = 0; i < N; ++i)
-    {
-        v[i] = P(x, ver);
-        if (++x == M)
-        {
-            x = 0;
-            ++ver;
-        }
-    }
-    for (int i = 0; i < N - M; i += M)
-    {
-        std::shuffle(v.begin() + i, v.begin() + i + M, randomness);
+using Pair = std::pair<int, int>;
+
+TEST_CONSTEXPR_CXX26 std::vector<Pair> generate_sawtooth(int N, int M) {
+  std::vector<Pair> v(N);
+  int x   = 0;
+  int ver = 0;
+  for (int i = 0; i < N; ++i) {
+    v[i] = Pair(x, ver);
+    if (++x == M) {
+      x = 0;
+      ++ver;
     }
+  }
+  return v;
+}
+
+TEST_CONSTEXPR_CXX26 bool test() {
+  int const N = 1000;
+  int const M = 10;
+
+  // test sawtooth pattern
+  {
+    auto v = generate_sawtooth(N, M);
     std::stable_sort(v.begin(), v.end(), first_only());
     assert(std::is_sorted(v.begin(), v.end()));
-}
+  }
 
-int main(int, char**)
-{
-    test();
+  // Test sorting a sequence where subsequences of elements are not sorted with <,
+  // but everything is already sorted with respect to the first element. This ensures
+  // that we don't change the order of "equivalent" elements.
+  {
+    if (!TEST_IS_CONSTANT_EVALUATED) {
+      auto v = generate_sawtooth(N, M);
+      std::mt19937 randomness;
+      for (int i = 0; i < N - M; i += M) {
+        std::shuffle(v.begin() + i, v.begin() + i + M, randomness);
+      }
+      std::stable_sort(v.begin(), v.end(), first_only());
+      assert(std::is_sorted(v.begin(), v.end()));
+    }
+  }
 
 #if TEST_STD_VER >= 11
-    {
+  {
     std::vector<std::unique_ptr<int> > v(1000);
     for (int i = 0; static_cast<std::size_t>(i) < v.size(); ++i)
-        v[i].reset(new int(i));
+      v[i].reset(new int(i));
     std::stable_sort(v.begin(), v.end(), indirect_less());
     assert(std::is_sorted(v.begin(), v.end(), indirect_less()));
     assert(*v[0] == 0);
     assert(*v[1] == 1);
     assert(*v[2] == 2);
-    }
+  }
+#endif
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
 #endif
 
   return 0;

>From 6c108330cb520164b17d66b6c099ada67533b731 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 13 Jan 2025 14:46:04 -0500
Subject: [PATCH 34/37] Fix module issue

---
 libcxx/include/module.modulemap | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 69f1b7d094ada1..cdac9c883ecabf 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -819,7 +819,10 @@ module std [system] {
     module sort_heap                              { header "__algorithm/sort_heap.h" }
     module sort                                   { header "__algorithm/sort.h" }
     module stable_partition                       { header "__algorithm/stable_partition.h" }
-    module stable_sort                            { header "__algorithm/stable_sort.h" }
+    module stable_sort {
+      header "__algorithm/stable_sort.h"
+      export std.memory.unique_temporary_buffer // TODO: Workaround for https://github.com/llvm/llvm-project/issues/120108
+    }
     module swap_ranges                            { header "__algorithm/swap_ranges.h" }
     module three_way_comp_ref_type                { header "__algorithm/three_way_comp_ref_type.h" }
     module transform                              { header "__algorithm/transform.h" }

>From d5130b5c79781e01ae654f3a61fd3b5b2885b20c Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 13 Jan 2025 14:47:16 -0500
Subject: [PATCH 35/37] Try bumping constexpr ops limit on GCC

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp       | 2 +-
 1 file changed, 1 insertion(+), 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 5fb349b6701046..9baaf20dec58ed 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
@@ -13,7 +13,7 @@
 //     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
-// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=100000000
 
 #include <algorithm>
 #include <cassert>

>From d1d4653f066af0ebb8a244592c70ed96edee4d36 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 13 Jan 2025 15:21:26 -0500
Subject: [PATCH 36/37] Bump GCC constexpr limit

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp       | 2 +-
 1 file changed, 1 insertion(+), 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 9baaf20dec58ed..c3a95d3fd1ec7f 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
@@ -13,7 +13,7 @@
 //     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
-// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=100000000
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=200000000
 
 #include <algorithm>
 #include <cassert>

>From e2b160765cb46385290b6b818d15869498f6bf26 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 14 Jan 2025 10:23:44 -0500
Subject: [PATCH 37/37] Adjust constexpr steps

---
 .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp      | 2 +-
 .../alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp | 3 +++
 2 files changed, 4 insertions(+), 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 c3a95d3fd1ec7f..b3b458808c44ad 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 since C++26
 //     stable_sort(RandomAccessIterator first, RandomAccessIterator last);
 
-// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200000000
 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=200000000
 
 #include <algorithm>
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp
index 17b9c572a17297..a2c0ca747d0390 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp
@@ -11,6 +11,9 @@
 // template<RandomAccessIterator Iter, StrictWeakOrder<auto, Iter::value_type> Compare>
 //   requires ShuffleIterator<Iter> && CopyConstructible<Compare>
 //   constexpr void stable_sort(Iter first, Iter last, Compare comp); // constexpr since C++26
+//
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200000000
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=200000000
 
 #include <algorithm>
 #include <functional>



More information about the libcxx-commits mailing list