]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Implement P2404R3 relaxations to comparable_with concepts [PR122946]
authorJonathan Wakely <jwakely@redhat.com>
Thu, 4 Dec 2025 14:45:53 +0000 (14:45 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 8 Dec 2025 18:55:02 +0000 (18:55 +0000)
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.

Reviewed-by: Tomasz KamiƄski <tkaminsk@redhat.com>
libstdc++-v3/include/bits/version.def
libstdc++-v3/include/bits/version.h
libstdc++-v3/include/std/concepts
libstdc++-v3/libsupc++/compare
libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc [new file with mode: 0644]

index 412b9ce96f8af020e77ec9824c4198f1be3dc8c5..bbc8d383938fa6a560351e6715ee1f946c48855d 100644 (file)
@@ -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";
   };
index 2b96934ca099f05ded5c3ef083ec1444251c72f8..7ee9ae84215e6e51d84339dc43858f4a0b8fd191 100644 (file)
 
 #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) */
index d9920a8f20a855a325009571e08842c6a5e35475..870b0a47eab164dc76e6cb27403b05d07776aa62 100644 (file)
@@ -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>;
index 08f2b2ba47ed2a7a45d4b91202ca6350b01bc696..5b4f47a94e3b084cf266dca12a2818ff2236e7b8 100644 (file)
@@ -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 (file)
index 0000000..01870d8
--- /dev/null
@@ -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>);