[libcxx-commits] [libcxx] ef19006 - [libc++][concepts] P2404R3: Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with (#99420)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Dec 19 01:56:38 PST 2025


Author: Janet Cobb
Date: 2025-12-19T17:56:32+08:00
New Revision: ef190061d342865dd9289ddc59fff4b0ab3428d1

URL: https://github.com/llvm/llvm-project/commit/ef190061d342865dd9289ddc59fff4b0ab3428d1
DIFF: https://github.com/llvm/llvm-project/commit/ef190061d342865dd9289ddc59fff4b0ab3428d1.diff

LOG: [libc++][concepts] P2404R3: Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with (#99420)

This implements all of [P2404R3](https://wg21.link/p2404r3)'s concept
changes.

---------

Co-authored-by: A. Jiang <de34 at live.cn>
Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>

Added: 
    libcxx/include/__concepts/comparison_common_type.h

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes/22.rst
    libcxx/docs/Status/Cxx23Papers.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/__compare/three_way_comparable.h
    libcxx/include/__concepts/equality_comparable.h
    libcxx/include/module.modulemap.in
    libcxx/include/version
    libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort.copy/ranges_partial_sort_copy.pass.cpp
    libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp
    libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/concepts.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp
    libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp
    libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp
    libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp
    libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp
    libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp
    libcxx/test/support/compare_types.h
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 756bdf71f8b22..5f1e521bd79c2 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -202,7 +202,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_common_reference_wrapper``                     ``202302L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_concepts``                                     ``202002L``
+    ``__cpp_lib_concepts``                                     ``202207L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_constexpr_algorithms``                         ``201806L``
     ---------------------------------------------------------- -----------------

diff  --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 603551cb0f603..76d3bb263290f 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -44,6 +44,8 @@ Implemented Papers
 - P3044R2: sub-``string_view`` from ``string`` (`Github <https://llvm.org/PR148140>`__)
 - P3223R2: Making ``std::istream::ignore`` less surprising (`Github <https://llvm.org/PR148178>`__)
 - P3060R3: Add ``std::views::indices(n)`` (`Github <https://llvm.org/PR148175>`__)
+- P2404R3: Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with``
+  (`Github <https://llvm.org/PR105210>`__)
 - P2641R4: Checking if a ``union`` alternative is active (``std::is_within_lifetime``)
   (`Github <https://llvm.org/PR105381>`__)
 - P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)

diff  --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index b655384bad7f2..e4c6cb0f51065 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -67,7 +67,7 @@
 "`P2302R4 <https://wg21.link/P2302R4>`__","``std::ranges::contains``","2022-07 (Virtual)","|Complete|","19","`#105206 <https://github.com/llvm/llvm-project/issues/105206>`__",""
 "`P2322R6 <https://wg21.link/P2322R6>`__","``ranges::fold``","2022-07 (Virtual)","","","`#105208 <https://github.com/llvm/llvm-project/issues/105208>`__",""
 "`P2374R4 <https://wg21.link/P2374R4>`__","``views::cartesian_product``","2022-07 (Virtual)","","","`#105209 <https://github.com/llvm/llvm-project/issues/105209>`__",""
-"`P2404R3 <https://wg21.link/P2404R3>`__","Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with``","2022-07 (Virtual)","","","`#105210 <https://github.com/llvm/llvm-project/issues/105210>`__",""
+"`P2404R3 <https://wg21.link/P2404R3>`__","Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with``","2022-07 (Virtual)","|Complete|","22","`#105210 <https://github.com/llvm/llvm-project/issues/105210>`__","Implemented as a DR in C++20."
 "`P2408R5 <https://wg21.link/P2408R5>`__","Ranges iterators as inputs to non-Ranges algorithms","2022-07 (Virtual)","","","`#105211 <https://github.com/llvm/llvm-project/issues/105211>`__",""
 "`P2417R2 <https://wg21.link/P2417R2>`__","A more ``constexpr`` ``bitset``","2022-07 (Virtual)","|Complete|","16","`#105212 <https://github.com/llvm/llvm-project/issues/105212>`__",""
 "`P2419R2 <https://wg21.link/P2419R2>`__","Clarify handling of encodings in localized formatting of chrono types","2022-07 (Virtual)","","","`#105213 <https://github.com/llvm/llvm-project/issues/105213>`__",""

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index e6d5d444cc1c2..9df40eab678a2 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -308,6 +308,7 @@ set(files
   __concepts/class_or_enum.h
   __concepts/common_reference_with.h
   __concepts/common_with.h
+  __concepts/comparison_common_type.h
   __concepts/constructible.h
   __concepts/convertible_to.h
   __concepts/copyable.h

diff  --git a/libcxx/include/__compare/three_way_comparable.h b/libcxx/include/__compare/three_way_comparable.h
index 7a44ea9158a6f..ad6d05a681145 100644
--- a/libcxx/include/__compare/three_way_comparable.h
+++ b/libcxx/include/__compare/three_way_comparable.h
@@ -12,6 +12,7 @@
 #include <__compare/common_comparison_category.h>
 #include <__compare/ordering.h>
 #include <__concepts/common_reference_with.h>
+#include <__concepts/comparison_common_type.h>
 #include <__concepts/equality_comparable.h>
 #include <__concepts/same_as.h>
 #include <__concepts/totally_ordered.h>
@@ -39,8 +40,7 @@ concept three_way_comparable =
 
 template <class _Tp, class _Up, class _Cat = partial_ordering>
 concept three_way_comparable_with =
-    three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> &&
-    common_reference_with<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>> &&
+    three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> && __comparison_common_type_with<_Tp, _Up> &&
     three_way_comparable<common_reference_t<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>>, _Cat> &&
     __weakly_equality_comparable_with<_Tp, _Up> && __partially_ordered_with<_Tp, _Up> &&
     requires(__make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) {

diff  --git a/libcxx/include/__concepts/comparison_common_type.h b/libcxx/include/__concepts/comparison_common_type.h
new file mode 100644
index 0000000000000..3f0d770511f47
--- /dev/null
+++ b/libcxx/include/__concepts/comparison_common_type.h
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H
+#define _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H
+
+#include <__concepts/convertible_to.h>
+#include <__concepts/same_as.h>
+#include <__config>
+#include <__type_traits/common_reference.h>
+#include <__type_traits/remove_cvref.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Tp, class _Up, class _CommonRef = common_reference_t<const _Tp&, const _Up&>>
+concept __comparison_common_type_with_impl =
+    same_as<common_reference_t<const _Tp&, const _Up&>, common_reference_t<const _Up&, const _Tp&>> && requires {
+      requires convertible_to<const _Tp&, const _CommonRef&> || convertible_to<_Tp, const _CommonRef&>;
+      requires convertible_to<const _Up&, const _CommonRef&> || convertible_to<_Up, const _CommonRef&>;
+    };
+
+template <class _Tp, class _Up>
+concept __comparison_common_type_with = __comparison_common_type_with_impl<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>;
+
+#endif // _LIBCPP_STD_VER >= 20
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H

diff  --git a/libcxx/include/__concepts/equality_comparable.h b/libcxx/include/__concepts/equality_comparable.h
index 278fc76409289..56fc6f8b685c0 100644
--- a/libcxx/include/__concepts/equality_comparable.h
+++ b/libcxx/include/__concepts/equality_comparable.h
@@ -11,6 +11,7 @@
 
 #include <__concepts/boolean_testable.h>
 #include <__concepts/common_reference_with.h>
+#include <__concepts/comparison_common_type.h>
 #include <__config>
 #include <__type_traits/common_reference.h>
 #include <__type_traits/make_const_lvalue_ref.h>
@@ -41,7 +42,7 @@ concept equality_comparable = __weakly_equality_comparable_with<_Tp, _Tp>;
 template <class _Tp, class _Up>
 concept equality_comparable_with =
     equality_comparable<_Tp> && equality_comparable<_Up> &&
-    common_reference_with<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>> &&
+    __comparison_common_type_with<_Tp, _Up> &&
     equality_comparable<
         common_reference_t<
             __make_const_lvalue_ref<_Tp>,

diff  --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index feb6249e1e6db..ce168f77dfea4 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1065,6 +1065,7 @@ module std [system] {
     module class_or_enum            { header "__concepts/class_or_enum.h" }
     module common_reference_with    { header "__concepts/common_reference_with.h" }
     module common_with              { header "__concepts/common_with.h" }
+    module comparison_common_type   { header "__concepts/comparison_common_type.h" }
     module constructible            { header "__concepts/constructible.h" }
     module convertible_to           { header "__concepts/convertible_to.h" }
     module copyable                 { header "__concepts/copyable.h" }

diff  --git a/libcxx/include/version b/libcxx/include/version
index 05532ea731ff3..c4daaffd89acf 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -63,7 +63,7 @@ __cpp_lib_clamp                                         201603L <algorithm>
 __cpp_lib_common_reference                              202302L <type_traits>
 __cpp_lib_common_reference_wrapper                      202302L <functional>
 __cpp_lib_complex_udls                                  201309L <complex>
-__cpp_lib_concepts                                      202002L <concepts>
+__cpp_lib_concepts                                      202207L <concepts>
 __cpp_lib_constexpr_algorithms                          202306L <algorithm> <utility>
                                                         201806L // C++20
 __cpp_lib_constexpr_bitset                              202207L <bitset>
@@ -410,7 +410,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # endif
 # define __cpp_lib_common_reference                     202302L
 # define __cpp_lib_common_reference_wrapper             202302L
-# define __cpp_lib_concepts                             202002L
+# define __cpp_lib_concepts                             202207L
 # define __cpp_lib_constexpr_algorithms                 201806L
 # define __cpp_lib_constexpr_complex                    201711L
 # define __cpp_lib_constexpr_dynamic_alloc              201907L

diff  --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort.copy/ranges_partial_sort_copy.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort.copy/ranges_partial_sort_copy.pass.cpp
index 532ee9b03efc0..36ec7892faa22 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort.copy/ranges_partial_sort_copy.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort.copy/ranges_partial_sort_copy.pass.cpp
@@ -75,7 +75,12 @@ static_assert(!HasPartialSortCopyIter<int*, int*, int*, int*, IndirectUnaryPredi
 static_assert(!HasPartialSortCopyIter<int*, int*, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
 
 // !indirectly_copyable<I1, I2>
-static_assert(!HasPartialSortCopyIter<int*, int*, MoveOnly*>);
+struct OrderedConvertibleToInt {
+  friend auto operator<=>(OrderedConvertibleToInt const&, OrderedConvertibleToInt const&) = default;
+  operator int() const;
+};
+
+static_assert(!HasPartialSortCopyIter<int*, int*, OrderedConvertibleToInt*, OrderedConvertibleToInt*>);
 
 // !sortable<I2, Comp, Proj2>
 static_assert(!HasPartialSortCopyIter<int*, int*, const int*, const int*>);
@@ -84,6 +89,9 @@ struct NoComparator {};
 // !indirect_strict_weak_order<Comp, projected<I1, Proj1>, projected<I2, Proj2>>
 static_assert(!HasPartialSortCopyIter<NoComparator*, NoComparator*, NoComparator*, NoComparator*>);
 
+// P2404
+static_assert(HasPartialSortCopyIter<int*, int*, MoveOnly*, MoveOnly*>);
+
 // Test constraints of the (range) overload.
 // ======================================================
 
@@ -109,7 +117,7 @@ static_assert(!HasPartialSortCopyRange<R<int*>, RandomAccessRangeNotDerivedFrom>
 static_assert(!HasPartialSortCopyRange<R<int*>, RandomAccessRangeBadIndex>);
 
 // !indirectly_copyable<iterator_t<R1>, iterator_t<R2>>
-static_assert(!HasPartialSortCopyRange<R<int*>, R<MoveOnly*>>);
+static_assert(!HasPartialSortCopyRange<R<int*>, R<OrderedConvertibleToInt*>>);
 
 // !sortable<iterator_t<R2>, Comp, Proj2>
 static_assert(!HasPartialSortCopyRange<R<int*>, R<const int*>>);
@@ -117,6 +125,9 @@ static_assert(!HasPartialSortCopyRange<R<int*>, R<const int*>>);
 // !indirect_strict_weak_order<Comp, projected<iterator_t<R1>, Proj1>, projected<iterator_t<R2>, Proj2>>
 static_assert(!HasPartialSortCopyRange<R<NoComparator*>, R<NoComparator*>>);
 
+// P2404
+static_assert(HasPartialSortCopyRange<R<int*>, R<MoveOnly*>>);
+
 static_assert(std::is_same_v<std::ranges::partial_sort_copy_result<int, int>, std::ranges::in_out_result<int, int>>);
 
 template <class Iter, class Sent, class OutIter, class OutSent, std::size_t N>

diff  --git a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp
index 2f8d7862c0f4d..5ac48ccf9ad0f 100644
--- a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp
+++ b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp
@@ -1131,4 +1131,14 @@ static_assert(
     std::common_reference_with<one_way_ne const&, explicit_operators const&>);
 static_assert(
     !check_equality_comparable_with<one_way_ne, explicit_operators>());
+
+// P2404
+static_assert(check_equality_comparable_with<move_only_equality_with_int, int>());
+static_assert(check_equality_comparable_with<std::unique_ptr<int>, std::nullptr_t>());
+// TODO: Clang is broken, see https://llvm.org/PR171438
+#if defined(TEST_COMPILER_CLANG) && !defined(TEST_COMPILER_APPLE_CLANG)
+static_assert(check_equality_comparable_with<nonmovable_equality_with_int, int>());
+#else
+static_assert(!check_equality_comparable_with<nonmovable_equality_with_int, int>());
+#endif
 } // namespace types_fit_for_purpose

diff  --git a/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp
index aa2ab1c0e9ef1..7cd3ad1bbe316 100644
--- a/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp
+++ b/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp
@@ -15,6 +15,7 @@
 #include <cstddef>
 
 #include "compare_types.h"
+#include "test_macros.h"
 
 template <class T, class U = T, typename Cat = std::partial_ordering>
 constexpr bool check_three_way_comparable_with() {
@@ -224,4 +225,33 @@ struct SpaceshipNonConstArgument {
 };
 
 static_assert(!check_three_way_comparable_with<SpaceshipNonConstArgument>());
+
+struct MoveOnlyIntComparable {
+  MoveOnlyIntComparable(int) {}
+
+  MoveOnlyIntComparable(MoveOnlyIntComparable&&)            = default;
+  MoveOnlyIntComparable& operator=(MoveOnlyIntComparable&&) = default;
+
+  friend auto operator<=>(MoveOnlyIntComparable const&, MoveOnlyIntComparable const&) = default;
+};
+
+// P2404
+static_assert(check_three_way_comparable_with<MoveOnlyIntComparable, int>());
+
+struct NonMovableIntComparable {
+  NonMovableIntComparable(int) {}
+
+  NonMovableIntComparable(NonMovableIntComparable&&)            = delete;
+  NonMovableIntComparable& operator=(NonMovableIntComparable&&) = delete;
+
+  friend auto operator<=>(NonMovableIntComparable const&, NonMovableIntComparable const&) = default;
+};
+
+// TODO: Clang is broken, see https://llvm.org/PR171438
+#if defined(TEST_COMPILER_CLANG) && !defined(TEST_COMPILER_APPLE_CLANG)
+static_assert(check_three_way_comparable_with<NonMovableIntComparable, int>());
+#else
+static_assert(!check_three_way_comparable_with<NonMovableIntComparable, int>());
+#endif
+
 } // namespace user_defined

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/concepts.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/concepts.version.compile.pass.cpp
index e4058c2348f9b..15f1d30060ef1 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/concepts.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/concepts.version.compile.pass.cpp
@@ -41,8 +41,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++20"
 #  endif
-#  if __cpp_lib_concepts != 202002L
-#    error "__cpp_lib_concepts should have the value 202002L in c++20"
+#  if __cpp_lib_concepts != 202207L
+#    error "__cpp_lib_concepts should have the value 202207L in c++20"
 #  endif
 
 #elif TEST_STD_VER == 23
@@ -50,8 +50,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++23"
 #  endif
-#  if __cpp_lib_concepts != 202002L
-#    error "__cpp_lib_concepts should have the value 202002L in c++23"
+#  if __cpp_lib_concepts != 202207L
+#    error "__cpp_lib_concepts should have the value 202207L in c++23"
 #  endif
 
 #elif TEST_STD_VER > 23
@@ -59,8 +59,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++26"
 #  endif
-#  if __cpp_lib_concepts != 202002L
-#    error "__cpp_lib_concepts should have the value 202002L in c++26"
+#  if __cpp_lib_concepts != 202207L
+#    error "__cpp_lib_concepts should have the value 202207L in c++26"
 #  endif
 
 #endif // TEST_STD_VER > 23

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 996ec29dce697..65cdf2ded816d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -3371,8 +3371,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++20"
 #  endif
-#  if __cpp_lib_concepts != 202002L
-#    error "__cpp_lib_concepts should have the value 202002L in c++20"
+#  if __cpp_lib_concepts != 202207L
+#    error "__cpp_lib_concepts should have the value 202207L in c++20"
 #  endif
 
 #  ifndef __cpp_lib_constexpr_algorithms
@@ -4840,8 +4840,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++23"
 #  endif
-#  if __cpp_lib_concepts != 202002L
-#    error "__cpp_lib_concepts should have the value 202002L in c++23"
+#  if __cpp_lib_concepts != 202207L
+#    error "__cpp_lib_concepts should have the value 202207L in c++23"
 #  endif
 
 #  ifndef __cpp_lib_constexpr_algorithms
@@ -6537,8 +6537,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++26"
 #  endif
-#  if __cpp_lib_concepts != 202002L
-#    error "__cpp_lib_concepts should have the value 202002L in c++26"
+#  if __cpp_lib_concepts != 202207L
+#    error "__cpp_lib_concepts should have the value 202207L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_constexpr_algorithms

diff  --git a/libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp
index 6d207548b2175..8b2b877092c69 100644
--- a/libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp
@@ -28,9 +28,11 @@ struct NotEqualityComparable {
 };
 
 static_assert(!std::is_invocable_v<std::ranges::equal_to, NotEqualityComparable, NotEqualityComparable>);
-static_assert(!std::is_invocable_v<std::ranges::equal_to, int, MoveOnly>);
 static_assert(std::is_invocable_v<std::ranges::equal_to, explicit_operators, explicit_operators>);
 
+// P2404
+static_assert(std::is_invocable_v<std::ranges::equal_to, int, MoveOnly>);
+
 static_assert(requires { typename std::ranges::equal_to::is_transparent; });
 
 constexpr bool test() {

diff  --git a/libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp
index 002ec10e07aff..0a3a1f07841b3 100644
--- a/libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp
@@ -27,9 +27,11 @@ struct NotTotallyOrdered {
 };
 
 static_assert(!std::is_invocable_v<std::ranges::greater, NotTotallyOrdered, NotTotallyOrdered>);
-static_assert(!std::is_invocable_v<std::ranges::greater, int, MoveOnly>);
 static_assert(std::is_invocable_v<std::ranges::greater, explicit_operators, explicit_operators>);
 
+// P2404
+static_assert(std::is_invocable_v<std::ranges::greater, int, MoveOnly>);
+
 static_assert(requires { typename std::ranges::greater::is_transparent; });
 
 constexpr bool test() {

diff  --git a/libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp
index ad24a98a168cf..2074599966b70 100644
--- a/libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp
@@ -27,9 +27,11 @@ struct NotTotallyOrdered {
 };
 
 static_assert(!std::is_invocable_v<std::ranges::greater_equal, NotTotallyOrdered, NotTotallyOrdered>);
-static_assert(!std::is_invocable_v<std::ranges::greater_equal, int, MoveOnly>);
 static_assert(std::is_invocable_v<std::ranges::greater_equal, explicit_operators, explicit_operators>);
 
+// P2404
+static_assert(std::is_invocable_v<std::ranges::greater_equal, int, MoveOnly>);
+
 static_assert(requires { typename std::ranges::greater_equal::is_transparent; });
 
 constexpr bool test() {

diff  --git a/libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp
index 5afb7e0ebdef4..b1a3cb8e86897 100644
--- a/libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp
@@ -27,9 +27,11 @@ struct NotTotallyOrdered {
 };
 
 static_assert(!std::is_invocable_v<std::ranges::less, NotTotallyOrdered, NotTotallyOrdered>);
-static_assert(!std::is_invocable_v<std::ranges::less, int, MoveOnly>);
 static_assert(std::is_invocable_v<std::ranges::less, explicit_operators, explicit_operators>);
 
+// P2404
+static_assert(std::is_invocable_v<std::ranges::less, int, MoveOnly>);
+
 static_assert(requires { typename std::ranges::less::is_transparent; });
 
 constexpr bool test() {

diff  --git a/libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp
index 3aa903fa6321a..739cc3b2a912e 100644
--- a/libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp
@@ -27,9 +27,11 @@ struct NotTotallyOrdered {
 };
 
 static_assert(!std::is_invocable_v<std::ranges::less_equal, NotTotallyOrdered, NotTotallyOrdered>);
-static_assert(!std::is_invocable_v<std::ranges::less_equal, int, MoveOnly>);
 static_assert(std::is_invocable_v<std::ranges::less_equal, explicit_operators, explicit_operators>);
 
+// P2404
+static_assert(std::is_invocable_v<std::ranges::less_equal, int, MoveOnly>);
+
 static_assert(requires { typename std::ranges::less_equal::is_transparent; });
 
 constexpr bool test() {

diff  --git a/libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp
index 4b46bae76ce48..5cff83143e463 100644
--- a/libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp
@@ -28,9 +28,11 @@ struct NotEqualityComparable {
 };
 
 static_assert(!std::is_invocable_v<std::ranges::equal_to, NotEqualityComparable, NotEqualityComparable>);
-static_assert(!std::is_invocable_v<std::ranges::equal_to, int, MoveOnly>);
 static_assert(std::is_invocable_v<std::ranges::equal_to, explicit_operators, explicit_operators>);
 
+// P2404
+static_assert(std::is_invocable_v<std::ranges::not_equal_to, int, MoveOnly>);
+
 static_assert(requires { typename std::ranges::not_equal_to::is_transparent; });
 
 struct PtrAndNotEqOperator {

diff  --git a/libcxx/test/support/compare_types.h b/libcxx/test/support/compare_types.h
index 8155f6221540c..b52e201f240ac 100644
--- a/libcxx/test/support/compare_types.h
+++ b/libcxx/test/support/compare_types.h
@@ -529,4 +529,30 @@ struct ForwardingTestObject {
   constexpr bool operator>=(const ForwardingTestObject&) const& { return false; }
 };
 
+struct move_only_equality_with_int {
+  move_only_equality_with_int(int);
+
+  move_only_equality_with_int(move_only_equality_with_int&&)            = default;
+  move_only_equality_with_int& operator=(move_only_equality_with_int&&) = default;
+
+  move_only_equality_with_int(move_only_equality_with_int const&)            = delete;
+  move_only_equality_with_int& operator=(move_only_equality_with_int const&) = delete;
+
+  friend bool operator==(move_only_equality_with_int const&, move_only_equality_with_int const&) = default;
+  friend bool operator==(move_only_equality_with_int const&, int);
+};
+
+struct nonmovable_equality_with_int {
+  nonmovable_equality_with_int(int);
+
+  nonmovable_equality_with_int(nonmovable_equality_with_int&&)            = delete;
+  nonmovable_equality_with_int& operator=(nonmovable_equality_with_int&&) = delete;
+
+  nonmovable_equality_with_int(nonmovable_equality_with_int const&)            = delete;
+  nonmovable_equality_with_int& operator=(nonmovable_equality_with_int const&) = delete;
+
+  friend bool operator==(nonmovable_equality_with_int const&, nonmovable_equality_with_int const&) = default;
+  friend bool operator==(nonmovable_equality_with_int const&, int);
+};
+
 #endif // TEST_SUPPORT_COMPARE_TYPES_H

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 0802f865f9406..c91bdf4ed99ec 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -331,7 +331,7 @@ def add_version_header(tc):
         },
         {
             "name": "__cpp_lib_concepts",
-            "values": {"c++20": 202002},
+            "values": {"c++20": 202207},
             "headers": ["concepts"],
         },
         {


        


More information about the libcxx-commits mailing list