1 | // RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu |
2 | |
3 | #include "Inputs/std-compare.h" |
4 | |
5 | namespace ThreeWayComparison { |
6 | struct A { |
7 | int n; |
8 | constexpr friend int operator<=>(const A &a, const A &b) { |
9 | return a.n < b.n ? -1 : a.n > b.n ? 1 : 0; |
10 | } |
11 | }; |
12 | static_assert(A{1} <=> A{2} < 0); |
13 | static_assert(A{2} <=> A{1} > 0); |
14 | static_assert(A{2} <=> A{2} == 0); |
15 | |
16 | static_assert(1 <=> 2 < 0); |
17 | static_assert(2 <=> 1 > 0); |
18 | static_assert(1 <=> 1 == 0); |
19 | constexpr int k = (1 <=> 1, 0); |
20 | // expected-warning@-1 {{three-way comparison result unused}} |
21 | |
22 | static_assert(std::strong_ordering::equal == 0); |
23 | |
24 | constexpr void f() { |
25 | void(1 <=> 1); |
26 | } |
27 | |
28 | struct MemPtr { |
29 | void foo() {} |
30 | void bar() {} |
31 | int data; |
32 | int data2; |
33 | long data3; |
34 | }; |
35 | |
36 | struct MemPtr2 { |
37 | void foo() {} |
38 | void bar() {} |
39 | int data; |
40 | int data2; |
41 | long data3; |
42 | }; |
43 | using MemPtrT = void (MemPtr::*)(); |
44 | |
45 | using FnPtrT = void (*)(); |
46 | |
47 | void FnPtr1() {} |
48 | void FnPtr2() {} |
49 | |
50 | #define CHECK(...) ((__VA_ARGS__) ? void() : throw "error") |
51 | #define CHECK_TYPE(...) static_assert(__is_same(__VA_ARGS__)); |
52 | |
53 | constexpr bool test_constexpr_success = [] { |
54 | { |
55 | auto &EQ = std::strong_ordering::equal; |
56 | auto &LESS = std::strong_ordering::less; |
57 | auto &GREATER = std::strong_ordering::greater; |
58 | using SO = std::strong_ordering; |
59 | auto eq = (42 <=> 42); |
60 | CHECK_TYPE(decltype(eq), SO); |
61 | CHECK(eq.test_eq(EQ)); |
62 | |
63 | auto less = (-1 <=> 0); |
64 | CHECK_TYPE(decltype(less), SO); |
65 | CHECK(less.test_eq(LESS)); |
66 | |
67 | auto greater = (42l <=> 1u); |
68 | CHECK_TYPE(decltype(greater), SO); |
69 | CHECK(greater.test_eq(GREATER)); |
70 | } |
71 | { |
72 | using PO = std::partial_ordering; |
73 | auto EQUIV = PO::equivalent; |
74 | auto LESS = PO::less; |
75 | auto GREATER = PO::greater; |
76 | |
77 | auto eq = (42.0 <=> 42.0); |
78 | CHECK_TYPE(decltype(eq), PO); |
79 | CHECK(eq.test_eq(EQUIV)); |
80 | |
81 | auto less = (39.0 <=> 42.0); |
82 | CHECK_TYPE(decltype(less), PO); |
83 | CHECK(less.test_eq(LESS)); |
84 | |
85 | auto greater = (-10.123 <=> -101.1); |
86 | CHECK_TYPE(decltype(greater), PO); |
87 | CHECK(greater.test_eq(GREATER)); |
88 | } |
89 | { |
90 | using SE = std::strong_equality; |
91 | auto EQ = SE::equal; |
92 | auto NEQ = SE::nonequal; |
93 | |
94 | MemPtrT P1 = &MemPtr::foo; |
95 | MemPtrT P12 = &MemPtr::foo; |
96 | MemPtrT P2 = &MemPtr::bar; |
97 | MemPtrT P3 = nullptr; |
98 | |
99 | auto eq = (P1 <=> P12); |
100 | CHECK_TYPE(decltype(eq), SE); |
101 | CHECK(eq.test_eq(EQ)); |
102 | |
103 | auto neq = (P1 <=> P2); |
104 | CHECK_TYPE(decltype(eq), SE); |
105 | CHECK(neq.test_eq(NEQ)); |
106 | |
107 | auto eq2 = (P3 <=> nullptr); |
108 | CHECK_TYPE(decltype(eq2), SE); |
109 | CHECK(eq2.test_eq(EQ)); |
110 | } |
111 | { |
112 | using SE = std::strong_equality; |
113 | auto EQ = SE::equal; |
114 | auto NEQ = SE::nonequal; |
115 | |
116 | FnPtrT F1 = &FnPtr1; |
117 | FnPtrT F12 = &FnPtr1; |
118 | FnPtrT F2 = &FnPtr2; |
119 | FnPtrT F3 = nullptr; |
120 | |
121 | auto eq = (F1 <=> F12); |
122 | CHECK_TYPE(decltype(eq), SE); |
123 | CHECK(eq.test_eq(EQ)); |
124 | |
125 | auto neq = (F1 <=> F2); |
126 | CHECK_TYPE(decltype(neq), SE); |
127 | CHECK(neq.test_eq(NEQ)); |
128 | } |
129 | { // mixed nullptr tests |
130 | using SO = std::strong_ordering; |
131 | using SE = std::strong_equality; |
132 | |
133 | int x = 42; |
134 | int *xp = &x; |
135 | |
136 | MemPtrT mf = nullptr; |
137 | MemPtrT mf2 = &MemPtr::foo; |
138 | auto r3 = (mf <=> nullptr); |
139 | CHECK_TYPE(decltype(r3), std::strong_equality); |
140 | CHECK(r3.test_eq(SE::equal)); |
141 | } |
142 | |
143 | return true; |
144 | }(); |
145 | |
146 | template <auto LHS, auto RHS, bool ExpectTrue = false> |
147 | constexpr bool test_constexpr() { |
148 | using nullptr_t = decltype(nullptr); |
149 | using LHSTy = decltype(LHS); |
150 | using RHSTy = decltype(RHS); |
151 | // expected-note@+1 {{subexpression not valid in a constant expression}} |
152 | auto Res = (LHS <=> RHS); |
153 | if constexpr (__is_same(LHSTy, nullptr_t) || __is_same(RHSTy, nullptr_t)) { |
154 | CHECK_TYPE(decltype(Res), std::strong_equality); |
155 | } |
156 | if (ExpectTrue) |
157 | return Res == 0; |
158 | return Res != 0; |
159 | } |
160 | int dummy = 42; |
161 | int dummy2 = 101; |
162 | |
163 | constexpr bool tc1 = test_constexpr<nullptr, &dummy>(); |
164 | constexpr bool tc2 = test_constexpr<&dummy, nullptr>(); |
165 | |
166 | // OK, equality comparison only |
167 | constexpr bool tc3 = test_constexpr<&MemPtr::foo, nullptr>(); |
168 | constexpr bool tc4 = test_constexpr<nullptr, &MemPtr::foo>(); |
169 | constexpr bool tc5 = test_constexpr<&MemPtr::foo, &MemPtr::bar>(); |
170 | |
171 | constexpr bool tc6 = test_constexpr<&MemPtr::data, nullptr>(); |
172 | constexpr bool tc7 = test_constexpr<nullptr, &MemPtr::data>(); |
173 | constexpr bool tc8 = test_constexpr<&MemPtr::data, &MemPtr::data2>(); |
174 | |
175 | // expected-error@+1 {{must be initialized by a constant expression}} |
176 | constexpr bool tc9 = test_constexpr<&dummy, &dummy2>(); // expected-note {{in call}} |
177 | |
178 | template <class T, class R, class I> |
179 | constexpr T makeComplex(R r, I i) { |
180 | T res{r, i}; |
181 | return res; |
182 | }; |
183 | |
184 | template <class T, class ResultT> |
185 | constexpr bool complex_test(T x, T y, ResultT Expect) { |
186 | auto res = x <=> y; |
187 | CHECK_TYPE(decltype(res), ResultT); |
188 | return res.test_eq(Expect); |
189 | } |
190 | static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0), |
191 | makeComplex<_Complex double>(0.0, 0.0), |
192 | std::weak_equality::equivalent)); |
193 | static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0), |
194 | makeComplex<_Complex double>(1.0, 0.0), |
195 | std::weak_equality::nonequivalent)); |
196 | static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0), |
197 | makeComplex<_Complex double>(0.0, 1.0), |
198 | std::weak_equality::nonequivalent)); |
199 | static_assert(complex_test(makeComplex<_Complex int>(0, 0), |
200 | makeComplex<_Complex int>(0, 0), |
201 | std::strong_equality::equal)); |
202 | static_assert(complex_test(makeComplex<_Complex int>(0, 0), |
203 | makeComplex<_Complex int>(1, 0), |
204 | std::strong_equality::nonequal)); |
205 | // TODO: defaulted operator <=> |
206 | } // namespace ThreeWayComparison |
207 | |
208 | constexpr bool for_range_init() { |
209 | int k = 0; |
210 | for (int arr[3] = {1, 2, 3}; int n : arr) k += n; |
211 | return k == 6; |
212 | } |
213 | static_assert(for_range_init()); |
214 | |