This implements the C++23 proposal P2404R3 "Move-only types for
equality_comparable_with, totally_ordered_with, and
three_way_comparable_with". As agreed with the maintainers of libc++ and
MSVC STL, we treat this as a DR for C++20. It allows reasonable code to
compile which wasn't originally allowed in C++20, and only affects some
obscure subsumption cases for valid C++20 code.

libstdc++-v3/ChangeLog:

        PR libstdc++/122946
        * include/bits/version.def (concepts): Set value to 202207.
        * include/bits/version.h: Regenerate.
        * include/std/concepts (__comparison_common_type_with_impl)
        (__comparison_common_type_with): New helper concepts.
        (equality_comparable_with): Use __comparison_common_type_with.
        * libsupc++/compare (three_way_comparable_with): Likewise.
        (__glibcxx_want_concepts): Define to get __cpp_lib_concepts
        here.
        * testsuite/std/concepts/concepts.compare/move_only.cc: New
        test.
---

Tested x86_64-linux.

If we're going to treat this as a DR for C++20 then we should ship it in
GCC 16 with the -std=gnu++20 default, so that we don't introduce a
change later which affects those obscure subsumption cases.

 libstdc++-v3/include/bits/version.def         |  6 +++-
 libstdc++-v3/include/bits/version.h           |  4 +--
 libstdc++-v3/include/std/concepts             | 23 ++++++++++++++-
 libstdc++-v3/libsupc++/compare                |  7 ++---
 .../concepts/concepts.compare/move_only.cc    | 28 +++++++++++++++++++
 5 files changed, 60 insertions(+), 8 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index d20e08519cac..071e78555e77 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -879,8 +879,12 @@ ftms = {
 
 ftms = {
   name = concepts;
+  // 201806 P0898R3 Standard Library Concepts
+  // 201907 P1754R1 Rename concepts to standard_case for C++20
+  // 202002 P1964R2 Wording for boolean-testable
+  // 202207 P2404R3 Move-only types for equality_comparable_with, etc.
   values = {
-    v = 202002;
+    v = 202207;
     cxxmin = 20;
     extra_cond = "__cpp_concepts >= 201907L";
   };
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index c75368d44c29..58633522d602 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -985,9 +985,9 @@
 
 #if !defined(__cpp_lib_concepts)
 # if (__cplusplus >= 202002L) && (__cpp_concepts >= 201907L)
-#  define __glibcxx_concepts 202002L
+#  define __glibcxx_concepts 202207L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_concepts)
-#   define __cpp_lib_concepts 202002L
+#   define __cpp_lib_concepts 202207L
 #  endif
 # endif
 #endif /* !defined(__cpp_lib_concepts) */
diff --git a/libstdc++-v3/include/std/concepts 
b/libstdc++-v3/include/std/concepts
index d9920a8f20a8..870b0a47eab1 100644
--- a/libstdc++-v3/include/std/concepts
+++ b/libstdc++-v3/include/std/concepts
@@ -296,6 +296,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          { { !static_cast<_Tp&&>(__t) } -> __boolean_testable_impl; };
   } // namespace __detail
 
+  // [concept.comparisoncommontype], helpers for comparison common types
+  namespace __detail
+  {
+    template<typename _Tp, typename _Up,
+            typename _Cref = 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 _Cref&>
+               || convertible_to<_Tp, const _Cref&>;
+             requires convertible_to<const _Up&, const _Cref&>
+               || convertible_to<_Up, const _Cref&>;
+           };
+
+    template<typename _Tp, typename _Up>
+      concept __comparison_common_type_with
+       = __comparison_common_type_with_impl<remove_cvref_t<_Tp>,
+                                            remove_cvref_t<_Up>>;
+  } // namespace __detail
+
   // [concept.equalitycomparable], concept equality_comparable
 
   namespace __detail
@@ -316,7 +337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Up>
     concept equality_comparable_with
       = equality_comparable<_Tp> && equality_comparable<_Up>
-      && common_reference_with<__detail::__cref<_Tp>, __detail::__cref<_Up>>
+      && __detail::__comparison_common_type_with<_Tp, _Up>
       && equality_comparable<common_reference_t<__detail::__cref<_Tp>,
                                                __detail::__cref<_Up>>>
       && __detail::__weakly_eq_cmp_with<_Tp, _Up>;
diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare
index 08f2b2ba47ed..5b4f47a94e3b 100644
--- a/libstdc++-v3/libsupc++/compare
+++ b/libstdc++-v3/libsupc++/compare
@@ -34,6 +34,7 @@
 #pragma GCC system_header
 #endif
 
+#define __glibcxx_want_concepts
 #define __glibcxx_want_three_way_comparison
 #define __glibcxx_want_type_order
 #include <bits/version.h>
@@ -499,10 +500,8 @@ namespace std _GLIBCXX_VISIBILITY(default)
 
   template<typename _Tp, typename _Up, typename _Cat = partial_ordering>
     concept three_way_comparable_with
-      = three_way_comparable<_Tp, _Cat>
-      && three_way_comparable<_Up, _Cat>
-      && common_reference_with<const remove_reference_t<_Tp>&,
-                              const remove_reference_t<_Up>&>
+      = three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat>
+      && __detail::__comparison_common_type_with<_Tp, _Up>
       && three_way_comparable<
          common_reference_t<const remove_reference_t<_Tp>&,
                             const remove_reference_t<_Up>&>, _Cat>
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc 
b/libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc
new file mode 100644
index 000000000000..01870d846267
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++20 } }
+
+#include <concepts>
+#include <compare>
+
+// P2404R3 Move-only types for equality_comparable_with,
+// totally_ordered_with, and three_way_comparable_with
+
+// This was approved for C++23 but we treat it as a DR for C++20.
+
+#ifndef __cpp_lib_concepts
+# error "Feature-test macro __cpp_lib_concepts is missing in <compare>"
+#elif __cpp_lib_concepts < 202207L
+# error "Feature-test macro __cpp_lib_concepts has wrong value in <compare>"
+#endif
+
+struct MoveOnly
+{
+  MoveOnly(int);
+  MoveOnly(MoveOnly&&) = default;
+  auto operator<=>(const MoveOnly&) const = default;
+  std::strong_ordering operator<=>(int) const;
+  bool operator==(const MoveOnly&) const;
+};
+
+static_assert(std::equality_comparable_with<MoveOnly, int>);
+static_assert(std::totally_ordered_with<MoveOnly, int>);
+static_assert(std::three_way_comparable_with<MoveOnly, int>);
-- 
2.52.0

Reply via email to