Skip to content

[libc++][concepts] P2404R3: Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with #99420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_char8_t`` ``201907L``
---------------------------------------------------------- -----------------
``__cpp_lib_concepts`` ``202002L``
``__cpp_lib_concepts`` ``202207L``
---------------------------------------------------------- -----------------
``__cpp_lib_constexpr_algorithms`` ``201806L``
---------------------------------------------------------- -----------------
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/21.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Implemented Papers
- P1222R4: A Standard ``flat_set`` (`Github <https://github.com/llvm/llvm-project/issues/105193>`__)
- P2897R7: ``aligned_accessor``: An mdspan accessor expressing pointer over-alignment (`Github <https://github.com/llvm/llvm-project/issues/118372>`__)
- P3247R2: Deprecate the notion of trivial types (`Github <https://github.com/llvm/llvm-project/issues/118387>`__)
- P2404R3 - Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with`` (`Github <https://github.com/llvm/llvm-project/pull/99420>`__)

Improvements and New Features
-----------------------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx23Papers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"`P2302R4 <https://wg21.link/P2302R4>`__","``std::ranges::contains``","2022-07 (Virtual)","|Complete|","19",""
"`P2322R6 <https://wg21.link/P2322R6>`__","``ranges::fold``","2022-07 (Virtual)","","",""
"`P2374R4 <https://wg21.link/P2374R4>`__","``views::cartesian_product``","2022-07 (Virtual)","","",""
"`P2404R3 <https://wg21.link/P2404R3>`__","Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with``","2022-07 (Virtual)","","",""
"`P2404R3 <https://wg21.link/P2404R3>`__","Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with``","2022-07 (Virtual)","|Complete|","21",""
"`P2408R5 <https://wg21.link/P2408R5>`__","Ranges iterators as inputs to non-Ranges algorithms","2022-07 (Virtual)","","",""
"`P2417R2 <https://wg21.link/P2417R2>`__","A more ``constexpr`` ``bitset``","2022-07 (Virtual)","|Complete|","16",""
"`P2419R2 <https://wg21.link/P2419R2>`__","Clarify handling of encodings in localized formatting of chrono types","2022-07 (Virtual)","","",""
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ set(files
__concepts/class_or_enum.h
__concepts/common_reference_with.h
__concepts/common_with.h
__concepts/comparison_common_type.h
__concepts/constructible.h
__concepts/convertible_to.h
__concepts/copyable.h
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__compare/three_way_comparable.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <__compare/common_comparison_category.h>
#include <__compare/ordering.h>
#include <__concepts/common_reference_with.h>
#include <__concepts/comparison_common_type.h>
#include <__concepts/equality_comparable.h>
#include <__concepts/same_as.h>
#include <__concepts/totally_ordered.h>
Expand Down Expand Up @@ -39,8 +40,7 @@ concept three_way_comparable =

template <class _Tp, class _Up, class _Cat = partial_ordering>
concept three_way_comparable_with =
three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> &&
common_reference_with<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>> &&
three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> && __comparison_common_type_with<_Tp, _Up> &&
three_way_comparable<common_reference_t<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>>, _Cat> &&
__weakly_equality_comparable_with<_Tp, _Up> && __partially_ordered_with<_Tp, _Up> &&
requires(__make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) {
Expand Down
40 changes: 40 additions & 0 deletions libcxx/include/__concepts/comparison_common_type.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H
#define _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H

#include <__concepts/convertible_to.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__type_traits/common_reference.h>
#include <__type_traits/remove_cvref.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

#if _LIBCPP_STD_VER >= 20

template <class _Tp, class _Up, class _CommonRef = 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 _CommonRef&> || convertible_to<_Tp, const _CommonRef&>;
requires convertible_to<const _Up&, const _CommonRef&> || convertible_to<_Up, const _CommonRef&>;
};

template <class _Tp, class _Up>
concept __comparison_common_type_with = __comparison_common_type_with_impl<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>;

#endif // _LIBCPP_STD_VER >= 20

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H
3 changes: 2 additions & 1 deletion libcxx/include/__concepts/equality_comparable.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <__concepts/boolean_testable.h>
#include <__concepts/common_reference_with.h>
#include <__concepts/comparison_common_type.h>
#include <__config>
#include <__type_traits/common_reference.h>
#include <__type_traits/make_const_lvalue_ref.h>
Expand Down Expand Up @@ -41,7 +42,7 @@ concept equality_comparable = __weakly_equality_comparable_with<_Tp, _Tp>;
template <class _Tp, class _Up>
concept equality_comparable_with =
equality_comparable<_Tp> && equality_comparable<_Up> &&
common_reference_with<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>> &&
__comparison_common_type_with<_Tp, _Up> &&
equality_comparable<
common_reference_t<
__make_const_lvalue_ref<_Tp>,
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@ module std [system] {
module class_or_enum { header "__concepts/class_or_enum.h" }
module common_reference_with { header "__concepts/common_reference_with.h" }
module common_with { header "__concepts/common_with.h" }
module comparison_common_type { header "__concepts/comparison_common_type.h" }
module constructible { header "__concepts/constructible.h" }
module convertible_to { header "__concepts/convertible_to.h" }
module copyable { header "__concepts/copyable.h" }
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ __cpp_lib_chrono 201611L <chrono>
__cpp_lib_chrono_udls 201304L <chrono>
__cpp_lib_clamp 201603L <algorithm>
__cpp_lib_complex_udls 201309L <complex>
__cpp_lib_concepts 202002L <concepts>
__cpp_lib_concepts 202207L <concepts>
__cpp_lib_constexpr_algorithms 202306L <algorithm> <utility>
201806L // C++20
__cpp_lib_constexpr_bitset 202207L <bitset>
Expand Down Expand Up @@ -400,7 +400,7 @@ __cpp_lib_void_t 201411L <type_traits>
# if _LIBCPP_HAS_CHAR8_T
# define __cpp_lib_char8_t 201907L
# endif
# define __cpp_lib_concepts 202002L
# define __cpp_lib_concepts 202207L
# define __cpp_lib_constexpr_algorithms 201806L
# define __cpp_lib_constexpr_complex 201711L
# define __cpp_lib_constexpr_dynamic_alloc 201907L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ static_assert(!HasPartialSortCopyIter<int*, int*, int*, int*, IndirectUnaryPredi
static_assert(!HasPartialSortCopyIter<int*, int*, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);

// !indirectly_copyable<I1, I2>
static_assert(!HasPartialSortCopyIter<int*, int*, MoveOnly*>);
struct OrderedConvertibleToInt {
friend auto operator<=>(OrderedConvertibleToInt const&, OrderedConvertibleToInt const&) = default;
operator int() const;
};

static_assert(!HasPartialSortCopyIter<int*, int*, OrderedConvertibleToInt*, OrderedConvertibleToInt*>);

// !sortable<I2, Comp, Proj2>
static_assert(!HasPartialSortCopyIter<int*, int*, const int*, const int*>);
Expand All @@ -84,6 +89,9 @@ struct NoComparator {};
// !indirect_strict_weak_order<Comp, projected<I1, Proj1>, projected<I2, Proj2>>
static_assert(!HasPartialSortCopyIter<NoComparator*, NoComparator*, NoComparator*, NoComparator*>);

// P2404
static_assert(HasPartialSortCopyIter<int*, int*, MoveOnly*, MoveOnly*>);

// Test constraints of the (range) overload.
// ======================================================

Expand All @@ -109,14 +117,17 @@ static_assert(!HasPartialSortCopyRange<R<int*>, RandomAccessRangeNotDerivedFrom>
static_assert(!HasPartialSortCopyRange<R<int*>, RandomAccessRangeBadIndex>);

// !indirectly_copyable<iterator_t<R1>, iterator_t<R2>>
static_assert(!HasPartialSortCopyRange<R<int*>, R<MoveOnly*>>);
static_assert(!HasPartialSortCopyRange<R<int*>, R<OrderedConvertibleToInt*>>);

// !sortable<iterator_t<R2>, Comp, Proj2>
static_assert(!HasPartialSortCopyRange<R<int*>, R<const int*>>);

// !indirect_strict_weak_order<Comp, projected<iterator_t<R1>, Proj1>, projected<iterator_t<R2>, Proj2>>
static_assert(!HasPartialSortCopyRange<R<NoComparator*>, R<NoComparator*>>);

// P2404
static_assert(HasPartialSortCopyRange<R<int*>, R<MoveOnly*>>);

static_assert(std::is_same_v<std::ranges::partial_sort_copy_result<int, int>, std::ranges::in_out_result<int, int>>);

template <class Iter, class Sent, class OutIter, class OutSent, std::size_t N>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1116,4 +1116,12 @@ static_assert(
std::common_reference_with<one_way_ne const&, explicit_operators const&>);
static_assert(
!check_equality_comparable_with<one_way_ne, explicit_operators>());

// P2404
static_assert(check_equality_comparable_with<move_only_equality_with_int, int>());
static_assert(check_equality_comparable_with<std::unique_ptr<int>, std::nullptr_t>());
static_assert(!check_equality_comparable_with<nonmovable_equality_with_int, int>());

// For testing
static_assert(!std::equality_comparable_with<nonmovable_equality_with_int, int>);
} // namespace types_fit_for_purpose
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <cstddef>

#include "compare_types.h"
#include "test_macros.h"

template <class T, class U = T, typename Cat = std::partial_ordering>
constexpr bool check_three_way_comparable_with() {
Expand Down Expand Up @@ -224,4 +225,31 @@ struct SpaceshipNonConstArgument {
};

static_assert(!check_three_way_comparable_with<SpaceshipNonConstArgument>());

struct MoveOnlyIntComparable {
MoveOnlyIntComparable(int) {}

MoveOnlyIntComparable(MoveOnlyIntComparable&&) = default;
MoveOnlyIntComparable& operator=(MoveOnlyIntComparable&&) = default;

friend auto operator<=>(MoveOnlyIntComparable const&, MoveOnlyIntComparable const&) = default;
};

// P2404
static_assert(check_three_way_comparable_with<MoveOnlyIntComparable, int>());

struct NonMovableIntComparable {
NonMovableIntComparable(int) {}

NonMovableIntComparable(NonMovableIntComparable&&) = delete;
NonMovableIntComparable& operator=(NonMovableIntComparable&&) = delete;

friend auto operator<=>(NonMovableIntComparable const&, NonMovableIntComparable const&) = default;
};

static_assert(!check_three_way_comparable_with<NonMovableIntComparable, int>());

// For testing
static_assert(!std::three_way_comparable_with<NonMovableIntComparable, int>);

} // namespace user_defined
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,26 @@
# ifndef __cpp_lib_concepts
# error "__cpp_lib_concepts should be defined in c++20"
# endif
# if __cpp_lib_concepts != 202002L
# error "__cpp_lib_concepts should have the value 202002L in c++20"
# if __cpp_lib_concepts != 202207L
# error "__cpp_lib_concepts should have the value 202207L in c++20"
# endif

#elif TEST_STD_VER == 23

# ifndef __cpp_lib_concepts
# error "__cpp_lib_concepts should be defined in c++23"
# endif
# if __cpp_lib_concepts != 202002L
# error "__cpp_lib_concepts should have the value 202002L in c++23"
# if __cpp_lib_concepts != 202207L
# error "__cpp_lib_concepts should have the value 202207L in c++23"
# endif

#elif TEST_STD_VER > 23

# ifndef __cpp_lib_concepts
# error "__cpp_lib_concepts should be defined in c++26"
# endif
# if __cpp_lib_concepts != 202002L
# error "__cpp_lib_concepts should have the value 202002L in c++26"
# if __cpp_lib_concepts != 202207L
# error "__cpp_lib_concepts should have the value 202207L in c++26"
# endif

#endif // TEST_STD_VER > 23
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3267,8 +3267,8 @@
# ifndef __cpp_lib_concepts
# error "__cpp_lib_concepts should be defined in c++20"
# endif
# if __cpp_lib_concepts != 202002L
# error "__cpp_lib_concepts should have the value 202002L in c++20"
# if __cpp_lib_concepts != 202207L
# error "__cpp_lib_concepts should have the value 202207L in c++20"
# endif

# ifndef __cpp_lib_constexpr_algorithms
Expand Down Expand Up @@ -4704,8 +4704,8 @@
# ifndef __cpp_lib_concepts
# error "__cpp_lib_concepts should be defined in c++23"
# endif
# if __cpp_lib_concepts != 202002L
# error "__cpp_lib_concepts should have the value 202002L in c++23"
# if __cpp_lib_concepts != 202207L
# error "__cpp_lib_concepts should have the value 202207L in c++23"
# endif

# ifndef __cpp_lib_constexpr_algorithms
Expand Down Expand Up @@ -6375,8 +6375,8 @@
# ifndef __cpp_lib_concepts
# error "__cpp_lib_concepts should be defined in c++26"
# endif
# if __cpp_lib_concepts != 202002L
# error "__cpp_lib_concepts should have the value 202002L in c++26"
# if __cpp_lib_concepts != 202207L
# error "__cpp_lib_concepts should have the value 202207L in c++26"
# endif

# ifndef __cpp_lib_constexpr_algorithms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ struct NotEqualityComparable {
};

static_assert(!std::is_invocable_v<std::ranges::equal_to, NotEqualityComparable, NotEqualityComparable>);
static_assert(!std::is_invocable_v<std::ranges::equal_to, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::equal_to, explicit_operators, explicit_operators>);

// P2404
static_assert(std::is_invocable_v<std::ranges::equal_to, int, MoveOnly>);

static_assert(requires { typename std::ranges::equal_to::is_transparent; });

constexpr bool test() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ struct NotTotallyOrdered {
};

static_assert(!std::is_invocable_v<std::ranges::greater, NotTotallyOrdered, NotTotallyOrdered>);
static_assert(!std::is_invocable_v<std::ranges::greater, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::greater, explicit_operators, explicit_operators>);

// P2404
static_assert(std::is_invocable_v<std::ranges::greater, int, MoveOnly>);

static_assert(requires { typename std::ranges::greater::is_transparent; });

constexpr bool test() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ struct NotTotallyOrdered {
};

static_assert(!std::is_invocable_v<std::ranges::greater_equal, NotTotallyOrdered, NotTotallyOrdered>);
static_assert(!std::is_invocable_v<std::ranges::greater_equal, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::greater_equal, explicit_operators, explicit_operators>);

// P2404
static_assert(std::is_invocable_v<std::ranges::greater_equal, int, MoveOnly>);

static_assert(requires { typename std::ranges::greater_equal::is_transparent; });

constexpr bool test() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ struct NotTotallyOrdered {
};

static_assert(!std::is_invocable_v<std::ranges::less, NotTotallyOrdered, NotTotallyOrdered>);
static_assert(!std::is_invocable_v<std::ranges::less, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::less, explicit_operators, explicit_operators>);

// P2404
static_assert(std::is_invocable_v<std::ranges::less, int, MoveOnly>);

static_assert(requires { typename std::ranges::less::is_transparent; });

constexpr bool test() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ struct NotTotallyOrdered {
};

static_assert(!std::is_invocable_v<std::ranges::less_equal, NotTotallyOrdered, NotTotallyOrdered>);
static_assert(!std::is_invocable_v<std::ranges::less_equal, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::less_equal, explicit_operators, explicit_operators>);

// P2404
static_assert(std::is_invocable_v<std::ranges::less_equal, int, MoveOnly>);

static_assert(requires { typename std::ranges::less_equal::is_transparent; });

constexpr bool test() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ struct NotEqualityComparable {
};

static_assert(!std::is_invocable_v<std::ranges::equal_to, NotEqualityComparable, NotEqualityComparable>);
static_assert(!std::is_invocable_v<std::ranges::equal_to, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::equal_to, explicit_operators, explicit_operators>);

// P2404
static_assert(std::is_invocable_v<std::ranges::not_equal_to, int, MoveOnly>);

static_assert(requires { typename std::ranges::not_equal_to::is_transparent; });

struct PtrAndNotEqOperator {
Expand Down
Loading
Loading