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