On Fri, Dec 5, 2025 at 4:38 PM Jonathan Wakely <[email protected]> wrote:

> 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.
>
I needed to remind myself what the changes were from the paper. One
of these small change, big impact cases.

LGTM.


> 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