1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 
11 // template<class T, class U, class Cat = partial_ordering>
12 // concept three_way_comparable_with = // see below
13 
14 #include <compare>
15 
16 #include "compare_types.h"
17 
18 template <class T, class U = T, typename Cat = std::partial_ordering>
check_three_way_comparable_with()19 constexpr bool check_three_way_comparable_with() {
20   constexpr bool result = std::three_way_comparable_with<T, U, Cat>;
21   static_assert(std::three_way_comparable_with<U, T, Cat> == result);
22   static_assert(std::three_way_comparable_with<T, U const, Cat> == result);
23   static_assert(std::three_way_comparable_with<T const, U const, Cat> == result);
24   static_assert(std::three_way_comparable_with<T, U const&, Cat> == result);
25   static_assert(std::three_way_comparable_with<T const, U const&, Cat> == result);
26   static_assert(std::three_way_comparable_with<T, U const&&, Cat> == result);
27   static_assert(std::three_way_comparable_with<T const, U const&&, Cat> == result);
28   if constexpr (!std::is_void_v<T>) {
29     static_assert(std::three_way_comparable_with<T&, U const, Cat> == result);
30     static_assert(std::three_way_comparable_with<T const&, U const, Cat> == result);
31     static_assert(std::three_way_comparable_with<T&, U const&, Cat> == result);
32     static_assert(std::three_way_comparable_with<T const&, U const&, Cat> == result);
33     static_assert(std::three_way_comparable_with<T&, U const&&, Cat> == result);
34     static_assert(std::three_way_comparable_with<T const&, U const&&, Cat> == result);
35     static_assert(std::three_way_comparable_with<T&&, U const, Cat> == result);
36     static_assert(std::three_way_comparable_with<T const&&, U const, Cat> == result);
37     static_assert(std::three_way_comparable_with<T&&, U const&, Cat> == result);
38     static_assert(std::three_way_comparable_with<T const&&, U const&, Cat> == result);
39     static_assert(std::three_way_comparable_with<T&&, U const&&, Cat> == result);
40     static_assert(std::three_way_comparable_with<T const&&, U const&&, Cat> == result);
41   }
42   return result;
43 }
44 
45 namespace fundamentals {
46 static_assert(check_three_way_comparable_with<int, int>());
47 static_assert(check_three_way_comparable_with<int, char>());
48 static_assert(!check_three_way_comparable_with<int, unsigned int>());
49 static_assert(check_three_way_comparable_with<int, double>());
50 static_assert(check_three_way_comparable_with<int*, int*>());
51 
52 static_assert(check_three_way_comparable_with<int, int, std::strong_ordering>());
53 static_assert(check_three_way_comparable_with<int, char, std::strong_ordering>());
54 static_assert(check_three_way_comparable_with<int, short, std::strong_ordering>());
55 
56 static_assert(check_three_way_comparable_with<int, int, std::weak_ordering>());
57 static_assert(check_three_way_comparable_with<int, char, std::weak_ordering>());
58 static_assert(!check_three_way_comparable_with<int, unsigned int, std::weak_ordering>());
59 
60 static_assert(!check_three_way_comparable_with<int, bool>());
61 static_assert(!check_three_way_comparable_with<int, int*>());
62 static_assert(!check_three_way_comparable_with<int, int[5]>());
63 static_assert(!check_three_way_comparable_with<int, int (*)()>());
64 static_assert(!check_three_way_comparable_with<int, int (&)()>());
65 struct S {};
66 static_assert(!check_three_way_comparable_with<int, int S::*>());
67 static_assert(!check_three_way_comparable_with<int, int (S::*)()>());
68 static_assert(!check_three_way_comparable_with<int, int (S::*)() noexcept>());
69 static_assert(!check_three_way_comparable_with<int, int (S::*)() const>());
70 static_assert(!check_three_way_comparable_with<int, int (S::*)() const noexcept>());
71 static_assert(!check_three_way_comparable_with<int, int (S::*)() volatile>());
72 static_assert(!check_three_way_comparable_with<int, int (S::*)() volatile noexcept>());
73 static_assert(!check_three_way_comparable_with<int, int (S::*)() const volatile>());
74 static_assert(!check_three_way_comparable_with<int, int (S::*)() const volatile noexcept>());
75 static_assert(!check_three_way_comparable_with<int, int (S::*)() &>());
76 static_assert(!check_three_way_comparable_with<int, int (S::*)() & noexcept>());
77 static_assert(!check_three_way_comparable_with<int, int (S::*)() const&>());
78 static_assert(!check_three_way_comparable_with<int, int (S::*)() const & noexcept>());
79 static_assert(!check_three_way_comparable_with<int, int (S::*)() volatile&>());
80 static_assert(!check_three_way_comparable_with<int, int (S::*)() volatile & noexcept>());
81 static_assert(!check_three_way_comparable_with<int, int (S::*)() const volatile&>());
82 static_assert(!check_three_way_comparable_with<int, int (S::*)() const volatile & noexcept>());
83 static_assert(!check_three_way_comparable_with<int, int (S::*)() &&>());
84 static_assert(!check_three_way_comparable_with<int, int (S::*)() && noexcept>());
85 static_assert(!check_three_way_comparable_with<int, int (S::*)() const&&>());
86 static_assert(!check_three_way_comparable_with<int, int (S::*)() const&& noexcept>());
87 static_assert(!check_three_way_comparable_with<int, int (S::*)() volatile&&>());
88 static_assert(!check_three_way_comparable_with<int, int (S::*)() volatile&& noexcept>());
89 static_assert(!check_three_way_comparable_with<int, int (S::*)() const volatile&&>());
90 static_assert(!check_three_way_comparable_with<int, int (S::*)() const volatile&& noexcept>());
91 static_assert(!check_three_way_comparable_with<int*, int[5]>());
92 static_assert(!check_three_way_comparable_with<int[5], int[5]>());
93 static_assert(!check_three_way_comparable_with<std::nullptr_t, int>());
94 static_assert(!check_three_way_comparable_with<std::nullptr_t, int*>());
95 static_assert(!check_three_way_comparable_with<std::nullptr_t, int[5]>());
96 static_assert(!check_three_way_comparable_with<std::nullptr_t, int (*)()>());
97 static_assert(!check_three_way_comparable_with<std::nullptr_t, int (&)()>());
98 static_assert(!check_three_way_comparable_with<std::nullptr_t, int (S::*)()>());
99 static_assert(!check_three_way_comparable_with<void, int>());
100 static_assert(!check_three_way_comparable_with<void, int*>());
101 static_assert(!check_three_way_comparable_with<void, std::nullptr_t>());
102 static_assert(!check_three_way_comparable_with<void, int[5]>());
103 static_assert(!check_three_way_comparable_with<void, int (*)()>());
104 static_assert(!check_three_way_comparable_with<void, int (&)()>());
105 static_assert(!check_three_way_comparable_with<void, int S::*>());
106 static_assert(!check_three_way_comparable_with<void, int (S::*)()>());
107 } // namespace fundamentals
108 
109 namespace user_defined {
110 struct S {
111     bool operator==(int) const;
112     std::strong_ordering operator<=>(int) const;
113     operator int() const;
114 
115     bool operator==(const S&) const = default;
116     auto operator<=>(const S&) const = default;
117 };
118 
119 static_assert(check_three_way_comparable_with<S, int>());
120 static_assert(check_three_way_comparable_with<S, int, std::strong_ordering>());
121 static_assert(check_three_way_comparable_with<S, int, std::weak_ordering>());
122 
123 struct SpaceshipNotDeclared {
124 };
125 
126 static_assert(!check_three_way_comparable_with<SpaceshipNotDeclared>());
127 
128 struct SpaceshipDeleted {
129     auto operator<=>(const SpaceshipDeleted&) const = delete;
130 };
131 
132 static_assert(!check_three_way_comparable_with<SpaceshipDeleted>());
133 
134 struct SpaceshipWithoutEqualityOperator {
135     auto operator<=>(const SpaceshipWithoutEqualityOperator&) const;
136 };
137 
138 static_assert(!check_three_way_comparable_with<SpaceshipWithoutEqualityOperator>());
139 
140 struct EqualityOperatorDeleted {
141     bool operator==(const EqualityOperatorDeleted&) const = delete;
142 };
143 
144 static_assert(!check_three_way_comparable_with<EqualityOperatorDeleted>());
145 
146 struct EqualityOperatorOnly {
147     bool operator==(const EqualityOperatorOnly&) const = default;
148 };
149 
150 static_assert(!check_three_way_comparable_with<EqualityOperatorOnly>());
151 
152 struct SpaceshipDeclaredEqualityOperatorDeleted {
153     bool operator==(const SpaceshipDeclaredEqualityOperatorDeleted&) const = delete;
154     auto operator<=>(const SpaceshipDeclaredEqualityOperatorDeleted&) const = default;
155 };
156 
157 static_assert(!check_three_way_comparable_with<SpaceshipDeclaredEqualityOperatorDeleted>());
158 
159 struct AllInequalityOperators {
160     bool operator<(const AllInequalityOperators&) const;
161     bool operator<=(const AllInequalityOperators&) const;
162     bool operator>(const AllInequalityOperators&) const;
163     bool operator>=(const AllInequalityOperators&) const;
164     bool operator!=(const AllInequalityOperators&) const;
165 };
166 
167 static_assert(!check_three_way_comparable_with<AllInequalityOperators>());
168 
169 struct AllComparisonOperators {
170     bool operator<(const AllComparisonOperators&) const;
171     bool operator<=(const AllComparisonOperators&) const;
172     bool operator>(const AllComparisonOperators&) const;
173     bool operator>=(const AllComparisonOperators&) const;
174     bool operator!=(const AllComparisonOperators&) const;
175     bool operator==(const AllComparisonOperators&) const;
176 };
177 
178 static_assert(!check_three_way_comparable_with<AllComparisonOperators>());
179 
180 struct AllButOneInequalityOperators {
181     bool operator<(const AllButOneInequalityOperators&) const;
182     bool operator<=(const AllButOneInequalityOperators&) const;
183     bool operator>(const AllButOneInequalityOperators&) const;
184     bool operator!=(const AllButOneInequalityOperators&) const;
185 };
186 
187 static_assert(!check_three_way_comparable_with<AllButOneInequalityOperators>());
188 
189 struct AllInequalityOperatorsOneDeleted {
190     bool operator<(const AllInequalityOperatorsOneDeleted&) const;
191     bool operator<=(const AllInequalityOperatorsOneDeleted&) const;
192     bool operator>(const AllInequalityOperatorsOneDeleted&) const;
193     bool operator>=(const AllInequalityOperatorsOneDeleted&) const = delete;
194     bool operator!=(const AllInequalityOperatorsOneDeleted&) const;
195 };
196 
197 static_assert(!check_three_way_comparable_with<AllInequalityOperatorsOneDeleted>());
198 
199 struct EqualityOperatorWrongReturnType {
200     int operator==(const EqualityOperatorWrongReturnType&);
201     auto operator<=>(const EqualityOperatorWrongReturnType&) const = default;
202 };
203 
204 static_assert(!check_three_way_comparable_with<EqualityOperatorWrongReturnType>());
205 
206 struct SpaceshipWrongReturnType {
207     bool operator==(const SpaceshipWrongReturnType&) const = default;
208     int operator<=>(const SpaceshipWrongReturnType&);
209 };
210 
211 static_assert(!check_three_way_comparable_with<SpaceshipWrongReturnType>());
212 
213 struct EqualityOperatorNonConstArgument {
214     bool operator==(EqualityOperatorNonConstArgument&);
215     auto operator<=>(const EqualityOperatorNonConstArgument&) const = default;
216 };
217 
218 static_assert(!check_three_way_comparable_with<EqualityOperatorNonConstArgument>());
219 
220 struct SpaceshipNonConstArgument {
221     bool operator==(const SpaceshipNonConstArgument&) const = default;
222     auto operator<=>(SpaceshipNonConstArgument&);
223 };
224 
225 static_assert(!check_three_way_comparable_with<SpaceshipNonConstArgument>());
226 } // namespace user_defined
227