[libcxx-commits] [libcxx] [libc++] P2944R3: Constrained comparisions - `optional` and `reference_wrapper` (PR #139368)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat May 10 07:04:30 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

<details>
<summary>Changes</summary>

Implements [P2944R3](https://wg21.link/P2944R3) partially, which adds constrained comparisons to `std::optional` and `std::reference_wrapper`.

- Moves the test helpers (concepts and types) for testing constrained comparisons to `test_comparisons.h`. 
- NFC to `std::expected` tests to use the new names of the tests helpers from `test_comparisions.h`. 
- Updates the `std::referencew_wrapper` implementation to use the concept `__core_convertible_to<bool>` as per comments in #<!-- -->135759.
- Implements constrained comparisons for `std::optional`.

Closes #<!-- -->136767
Closes #<!-- -->138233

Relates to: #<!-- -->135759

# References:
- [refwrap.comparisons](https://wg21.link/refwrap.comparisons)
- [optional.relops](https://wg21.link/optional.relops)
- [optional.comp.with.t](https://wg21.link/optional.comp.with.t)

---

Patch is 68.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139368.diff


41 Files Affected:

- (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1) 
- (modified) libcxx/include/__functional/reference_wrapper.h (+4-4) 
- (modified) libcxx/include/optional (+205-21) 
- (modified) libcxx/include/version (+3-3) 
- (modified) libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp (-1) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp (+33) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp (+2-2) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.compile.pass.cpp (+2-2) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp (+2-2) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.compile.pass.cpp (+2-2) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+2-2) 
- (modified) libcxx/test/std/utilities/expected/expected.expected/equality/equality.T2.pass.cpp (+4-4) 
- (modified) libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp (+11-11) 
- (modified) libcxx/test/std/utilities/expected/expected.expected/equality/equality.unexpected.pass.cpp (+4-4) 
- (modified) libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp (+11-11) 
- (modified) libcxx/test/std/utilities/expected/expected.void/equality/equality.unexpected.pass.cpp (+4-4) 
- (modified) libcxx/test/std/utilities/expected/types.h (-13) 
- (modified) libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp (+5-8) 
- (modified) libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp (+5-9) 
- (modified) libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp (+7-10) 
- (modified) libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp (+5-6) 
- (modified) libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp (+3-6) 
- (modified) libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp (+5-8) 
- (removed) libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h (-38) 
- (removed) libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h (-30) 
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/equal.pass.cpp (+21) 
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/greater.pass.cpp (+20) 
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/greater_equal.pass.cpp (+20) 
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/less_equal.pass.cpp (+20) 
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/less_than.pass.cpp (+20) 
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/not_equal.pass.cpp (+21) 
- (modified) libcxx/test/std/utilities/optional/optional.relops/equal.pass.cpp (+14) 
- (modified) libcxx/test/std/utilities/optional/optional.relops/greater_equal.pass.cpp (+13) 
- (modified) libcxx/test/std/utilities/optional/optional.relops/greater_than.pass.cpp (+13) 
- (modified) libcxx/test/std/utilities/optional/optional.relops/less_equal.pass.cpp (+13) 
- (modified) libcxx/test/std/utilities/optional/optional.relops/less_than.pass.cpp (+13) 
- (modified) libcxx/test/std/utilities/optional/optional.relops/not_equal.pass.cpp (+14) 
- (modified) libcxx/test/std/utilities/utility/pairs/pairs.spec/comparison.pass.cpp (+1-14) 
- (modified) libcxx/test/support/test_comparisons.h (+65-1) 
- (modified) libcxx/test/support/test_container_comparisons.h (-4) 
- (modified) libcxx/utils/generate_feature_test_macro_components.py (+5-2) 


``````````diff
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 3809446a57896..99fc0b38077ab 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -59,7 +59,7 @@
 "`P2248R8 <https://wg21.link/P2248R8>`__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","",""
 "`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","",""
 "`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","",""
-"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","Implemented changes to ``reference_wrapper`` and ``pair``"
+"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","Not implemented ``tuple`` and ``variant``"
 "`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","",""
 "`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19",""
 "","","","","",""
diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index b409ad7511f6c..c46203a4ca9a4 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -11,7 +11,6 @@
 #define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
 
 #include <__compare/synth_three_way.h>
-#include <__concepts/boolean_testable.h>
 #include <__config>
 #include <__functional/weak_result_type.h>
 #include <__memory/addressof.h>
@@ -19,6 +18,7 @@
 #include <__type_traits/enable_if.h>
 #include <__type_traits/invoke.h>
 #include <__type_traits/is_const.h>
+#include <__type_traits/is_core_convertible.h>
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/void_t.h>
 #include <__utility/declval.h>
@@ -75,7 +75,7 @@ class reference_wrapper : public __weak_result_type<_Tp> {
 
   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y)
     requires requires {
-      { __x.get() == __y.get() } -> __boolean_testable;
+      { __x.get() == __y.get() } -> __core_convertible_to<bool>;
     }
   {
     return __x.get() == __y.get();
@@ -83,7 +83,7 @@ class reference_wrapper : public __weak_result_type<_Tp> {
 
   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y)
     requires requires {
-      { __x.get() == __y } -> __boolean_testable;
+      { __x.get() == __y } -> __core_convertible_to<bool>;
     }
   {
     return __x.get() == __y;
@@ -91,7 +91,7 @@ class reference_wrapper : public __weak_result_type<_Tp> {
 
   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y)
     requires(!is_const_v<_Tp>) && requires {
-      { __x.get() == __y.get() } -> __boolean_testable;
+      { __x.get() == __y.get() } -> __core_convertible_to<bool>;
     }
   {
     return __x.get() == __y.get();
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 2153efb2ab899..059ca0156475b 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -205,6 +205,7 @@ namespace std {
 #  include <__type_traits/is_assignable.h>
 #  include <__type_traits/is_constructible.h>
 #  include <__type_traits/is_convertible.h>
+#  include <__type_traits/is_core_convertible.h>
 #  include <__type_traits/is_destructible.h>
 #  include <__type_traits/is_nothrow_assignable.h>
 #  include <__type_traits/is_nothrow_constructible.h>
@@ -983,12 +984,23 @@ public:
 template <class _Tp>
 optional(_Tp) -> optional<_Tp>;
 
-// Comparisons between optionals
+// [optional.relops] Relational operators
+
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y)
+#    if _LIBCPP_STD_VER >= 26
+  requires requires {
+    { *__x == *__y } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   if (static_cast<bool>(__x) != static_cast<bool>(__y))
     return false;
   if (!static_cast<bool>(__x))
@@ -996,11 +1008,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const
   return *__x == *__y;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y)
+#    if _LIBCPP_STD_VER >= 26
+  requires requires {
+    { *__x != *__y } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   if (static_cast<bool>(__x) != static_cast<bool>(__y))
     return true;
   if (!static_cast<bool>(__x))
@@ -1008,11 +1030,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const
   return *__x != *__y;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y)
+#    if _LIBCPP_STD_VER >= 26
+  requires requires {
+    { *__x < *__y } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   if (!static_cast<bool>(__y))
     return false;
   if (!static_cast<bool>(__x))
@@ -1020,11 +1052,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const o
   return *__x < *__y;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y)
+#    if _LIBCPP_STD_VER >= 26
+  requires requires {
+    { *__x > *__y } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   if (!static_cast<bool>(__x))
     return false;
   if (!static_cast<bool>(__y))
@@ -1032,11 +1074,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const o
   return *__x > *__y;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y)
+#    if _LIBCPP_STD_VER >= 26
+  requires requires {
+    { *__x <= *__y } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   if (!static_cast<bool>(__x))
     return true;
   if (!static_cast<bool>(__y))
@@ -1044,11 +1096,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const
   return *__x <= *__y;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y)
+#    if _LIBCPP_STD_VER >= 26
+  requires requires {
+    { *__x >= *__y } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   if (!static_cast<bool>(__y))
     return true;
   if (!static_cast<bool>(__x))
@@ -1068,7 +1130,8 @@ operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) {
 
 #    endif // _LIBCPP_STD_VER >= 20
 
-// Comparisons with nullopt
+// [optional.nullops] Comparison with nullopt
+
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, nullopt_t) noexcept {
   return !static_cast<bool>(__x);
@@ -1140,100 +1203,221 @@ _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>&
 
 #    endif // _LIBCPP_STD_VER <= 17
 
-// Comparisons with T
+// [optional.comp.with.t] Comparison with T
+
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Up>::value) && requires {
+    { *__x == __v } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? *__x == __v : false;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Tp>::value) && requires {
+    { __v == *__x } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? __v == *__x : false;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Up>::value) && requires {
+    { *__x != __v } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? *__x != __v : true;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Tp>::value) && requires {
+    { __v != *__x } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? __v != *__x : true;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Up>::value) && requires {
+    { *__x < __v } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? *__x < __v : true;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Tp>::value) && requires {
+    { __v < *__x } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? __v < *__x : false;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Up>::value) && requires {
+    { *__x <= __v } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? *__x <= __v : true;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Tp>::value) && requires {
+    { __v <= *__x } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? __v <= *__x : false;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Up>::value) && requires {
+    { *__x > __v } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? *__x > __v : false;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Tp>::value) && requires {
+    { __v > *__x } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? __v > *__x : true;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Up>::value) && requires {
+    { *__x >= __v } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? *__x >= __v : false;
 }
 
+#    if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+#    else
 template <
     class _Tp,
     class _Up,
     enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) {
+#    endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x)
+#    if _LIBCPP_STD_VER >= 26
+  requires(!__is_std_optional<_Tp>::value) && requires {
+    { __v >= *__x } -> __core_convertible_to<bool>;
+  }
+#    endif
+{
   return static_cast<bool>(__x) ? __v >= *__x : true;
 }
 
diff --git a/libcxx/include/version b/libcxx/include/version
index 77d97b93adc6c..3a173e30c47ae 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -80,8 +80,8 @@ __cpp_lib_constexpr_tuple                               201811L <tuple>
 __cpp_lib_constexpr_typeinfo                            202106L <typeinfo>
 __cpp_lib_constexpr_utility                             201811L <utility>
 __cpp_lib_constexpr_vector                              201907L <vector>
-__cpp_lib_constrained_equality                          202403L <optional> <tuple> <utility>
-                                                                <variant>
+__cpp_lib_constrained_equality                          202411L <expected> <optional> <tuple>
+                                                                <utility> <variant>
 __cpp_lib_containers_ranges                             202202L <deque> <forward_list> <list>
                                                                 <map> <queue> <set>
                                                                 <stack> <string> <unordered_map>
@@ -545,7 +545,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # if !defined(_LIBCPP_ABI_VCRUNTIME)
 #   define __cpp_lib_constexpr_new                      202406L
 # endif
-// # define __cpp_lib_constrained_equality                 202403L
+// # define __cpp_lib_constrained_equality                 202411L
 // # define __cpp_lib_copyable_function                    202306L
 // # define __cpp_lib_debugging                            202311L
 // # define __cpp_lib_default_template_type_for_algorithm_values 202403L
diff --git a/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp b/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp
index 01be1db73041b..671747f89a82e 100644
--- a/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp
@@ -26,7 +26,6 @@ constexpr std::size_t N{1};
 static_assert(std::three_way_comparable<std::array<int, N>>);
 
 // Thanks to SFINAE, the following is not a compiler error but returns `false`
-struct NonComparable {};
 static_assert(!std::three_way_comparable<std::array<NonComparable, N>>);
 
 // Implementation detail of `test_sequence_container_array_spaceship`
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp
index d58f726f66e2f..9c7a84f145dde 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp
@@ -20,6 +20,10 @@
 
 #if TEST_STD_VER < 14
 
+#  ifdef __cpp_lib_constrained_equality
+#    error "__cpp_lib_constrained_equality should not be defined before c++26"
+#  endif
+
 #  ifdef __cpp_lib_expected
 #    error "__cpp_lib_expected should not be defined before c++23"
 #  endif
@@ -30,6 +34,10 @@
 
 #elif TEST_STD_VER == 14
 
+#  ifdef __cpp_lib_constrained_equality
+#    error "__cpp_lib_constrained_equality should not be defined before c++26"
+#  endif
+
 #  ifdef __cpp_lib_expected
 #    error "__cpp_lib_expected should not be defined before c++23"
 #  endif
@@ -40,6 +48,10 @@
 
 #elif TEST_STD_VER == 17
 
+#  ifdef __cpp_lib_constrained_equality
+#    error "__cpp_lib_cons...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/139368


More information about the libcxx-commits mailing list