libstdc++: Implement P2404R3 relaxations to comparable_with concepts [PR122946]

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>
This commit is contained in:
Jonathan Wakely 2025-12-04 14:45:53 +00:00 committed by Jonathan Wakely
parent ea42e28cbc
commit 03562c1e02
No known key found for this signature in database
5 changed files with 60 additions and 8 deletions

View 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";
};

View File

@ -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) */

View 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>;

View 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>

View File

@ -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>);