1 | // Force x86-64 because some of our heuristics are actually based |
2 | // on integer sizes. |
3 | |
4 | // RUN: %clang_cc1 -triple x86_64-apple-darwin -fcxx-exceptions -fsyntax-only -pedantic -verify -Wsign-compare -std=c++2a %s |
5 | |
6 | #include "Inputs/std-compare.h" |
7 | |
8 | #define ASSERT_TYPE(...) static_assert(__is_same(__VA_ARGS__)) |
9 | #define ASSERT_EXPR_TYPE(Expr, Expect) static_assert(__is_same(decltype(Expr), Expect)); |
10 | |
11 | void self_compare() { |
12 | int a; |
13 | int *b = nullptr; |
14 | |
15 | (void)(a <=> a); // expected-warning {{self-comparison always evaluates to 'std::strong_ordering::equal'}} |
16 | (void)(b <=> b); // expected-warning {{self-comparison always evaluates to 'std::strong_ordering::equal'}} |
17 | } |
18 | |
19 | void test0(long a, unsigned long b) { |
20 | enum EnumA : int {A}; |
21 | enum EnumB {B}; |
22 | enum EnumC {C = 0x10000}; |
23 | |
24 | (void)((short)a <=> (unsigned short)b); |
25 | |
26 | // (a,b) |
27 | (void)(a <=> (unsigned long)b); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
28 | (void)(a <=> (unsigned int) b); |
29 | (void)(a <=> (unsigned short) b); |
30 | (void)(a <=> (unsigned char) b); |
31 | (void)((long)a <=> b); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
32 | (void)((int)a <=> b); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
33 | (void)((short)a <=> b); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
34 | (void)((signed char)a <=> b); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
35 | (void)((long)a <=> (unsigned long)b); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
36 | (void)((int)a <=> (unsigned int)b); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
37 | (void)((short) a <=> (unsigned short) b); |
38 | (void)((signed char) a <=> (unsigned char) b); |
39 | |
40 | // (A,b) |
41 | (void)(A <=> (unsigned long) b); |
42 | (void)(A <=> (unsigned int) b); |
43 | (void)(A <=> (unsigned short) b); |
44 | (void)(A <=> (unsigned char) b); |
45 | (void)((long) A <=> b); |
46 | (void)((int) A <=> b); |
47 | (void)((short) A <=> b); |
48 | (void)((signed char) A <=> b); |
49 | (void)((long) A <=> (unsigned long) b); |
50 | (void)((int) A <=> (unsigned int) b); |
51 | (void)((short) A <=> (unsigned short) b); |
52 | (void)((signed char) A <=> (unsigned char) b); |
53 | |
54 | // (a,B) |
55 | (void)(a <=> (unsigned long) B); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'long' to 'unsigned long'}} |
56 | (void)(a <=> (unsigned int) B); |
57 | (void)(a <=> (unsigned short) B); |
58 | (void)(a <=> (unsigned char) B); |
59 | (void)((long) a <=> B); |
60 | (void)((int) a <=> B); |
61 | (void)((short) a <=> B); |
62 | (void)((signed char) a <=> B); |
63 | (void)((long) a <=> (unsigned long) B); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'long' to 'unsigned long'}} |
64 | (void)((int) a <=> (unsigned int) B); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'int' to 'unsigned int'}} |
65 | (void)((short) a <=> (unsigned short) B); |
66 | (void)((signed char) a <=> (unsigned char) B); |
67 | |
68 | // (C,b) |
69 | (void)(C <=> (unsigned long) b); |
70 | (void)(C <=> (unsigned int) b); |
71 | (void)(C <=> (unsigned short) b); // expected-warning {{comparison of constant 'C' (65536) with expression of type 'unsigned short' is always 'std::strong_ordering::greater'}} |
72 | (void)(C <=> (unsigned char) b); // expected-warning {{comparison of constant 'C' (65536) with expression of type 'unsigned char' is always 'std::strong_ordering::greater'}} |
73 | (void)((long) C <=> b); |
74 | (void)((int) C <=> b); |
75 | (void)((short) C <=> b); |
76 | (void)((signed char) C <=> b); |
77 | (void)((long) C <=> (unsigned long) b); |
78 | (void)((int) C <=> (unsigned int) b); |
79 | (void)((short) C <=> (unsigned short) b); |
80 | (void)((signed char) C <=> (unsigned char) b); |
81 | |
82 | // (a,C) |
83 | (void)(a <=> (unsigned long) C); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'long' to 'unsigned long'}} |
84 | (void)(a <=> (unsigned int) C); |
85 | (void)(a <=> (unsigned short) C); |
86 | (void)(a <=> (unsigned char) C); |
87 | (void)((long) a <=> C); |
88 | (void)((int) a <=> C); |
89 | (void)((short) a <=> C); // expected-warning {{comparison of constant 'C' (65536) with expression of type 'short' is always 'std::strong_ordering::less'}} |
90 | (void)((signed char) a <=> C); // expected-warning {{comparison of constant 'C' (65536) with expression of type 'signed char' is always 'std::strong_ordering::less'}} |
91 | (void)((long) a <=> (unsigned long) C); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'long' to 'unsigned long'}} |
92 | (void)((int) a <=> (unsigned int) C); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'int' to 'unsigned int'}} |
93 | (void)((short) a <=> (unsigned short) C); |
94 | (void)((signed char) a <=> (unsigned char) C); |
95 | |
96 | // (0x80000,b) |
97 | (void)(0x80000 <=> (unsigned long) b); |
98 | (void)(0x80000 <=> (unsigned int) b); |
99 | (void)(0x80000 <=> (unsigned short) b); // expected-warning {{result of comparison of constant 524288 with expression of type 'unsigned short' is always 'std::strong_ordering::greater'}} |
100 | (void)(0x80000 <=> (unsigned char) b); // expected-warning {{result of comparison of constant 524288 with expression of type 'unsigned char' is always 'std::strong_ordering::greater'}} |
101 | (void)((long) 0x80000 <=> b); |
102 | (void)((int) 0x80000 <=> b); |
103 | (void)((short) 0x80000 <=> b); |
104 | (void)((signed char) 0x80000 <=> b); |
105 | (void)((long) 0x80000 <=> (unsigned long) b); |
106 | (void)((int) 0x80000 <=> (unsigned int) b); |
107 | (void)((short) 0x80000 <=> (unsigned short) b); |
108 | (void)((signed char) 0x80000 <=> (unsigned char) b); |
109 | |
110 | // (a,0x80000) |
111 | (void)(a <=> (unsigned long)0x80000); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
112 | (void)(a <=> (unsigned int) 0x80000); |
113 | (void)(a <=> (unsigned short) 0x80000); |
114 | (void)(a <=> (unsigned char) 0x80000); |
115 | (void)((long) a <=> 0x80000); |
116 | (void)((int) a <=> 0x80000); |
117 | (void)((short) a <=> 0x80000); // expected-warning {{comparison of constant 524288 with expression of type 'short' is always 'std::strong_ordering::less'}} |
118 | (void)((signed char) a <=> 0x80000); // expected-warning {{comparison of constant 524288 with expression of type 'signed char' is always 'std::strong_ordering::less'}} |
119 | (void)((long)a <=> (unsigned long)0x80000); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
120 | (void)((int)a <=> (unsigned int)0x80000); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
121 | (void)((short) a <=> (unsigned short) 0x80000); |
122 | (void)((signed char) a <=> (unsigned char) 0x80000); |
123 | } |
124 | |
125 | void test5(bool b, bool b2) { |
126 | enum EnumA { A }; |
127 | (void)(b <=> b2); // OK |
128 | (void)(true <=> b); // OK |
129 | (void)(b <=> -10); // expected-error {{invalid operands to binary expression ('bool' and 'int')}} |
130 | (void)(b <=> char(1)); // expected-error {{invalid operands to binary expression ('bool' and 'char')}} |
131 | (void)(b <=> A); // expected-error {{invalid operands to binary expression ('bool' and 'EnumA')}} |
132 | |
133 | // FIXME: Should this be accepted when narrowing doesn't occur? |
134 | (void)(b <=> 0); // expected-error {{invalid operands to binary expression ('bool' and 'int')}} |
135 | (void)(b <=> 1); // expected-error {{invalid operands to binary expression ('bool' and 'int')}} |
136 | } |
137 | |
138 | void test6(signed char sc) { |
139 | (void)(sc <=> 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always 'std::strong_ordering::less'}} |
140 | (void)(200 <=> sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always 'std::strong_ordering::greater'}} |
141 | } |
142 | |
143 | // Test many signedness combinations. |
144 | void test7(unsigned long other) { |
145 | // Common unsigned, other unsigned, constant unsigned |
146 | (void)((unsigned)other <=> (unsigned long)(0x1'ffff'ffff)); // expected-warning{{less}} |
147 | (void)((unsigned)other <=> (unsigned long)(0xffff'ffff)); |
148 | (void)((unsigned long)other <=> (unsigned)(0x1'ffff'ffff)); |
149 | (void)((unsigned long)other <=> (unsigned)(0xffff'ffff)); |
150 | |
151 | // Common unsigned, other signed, constant unsigned |
152 | (void)((int)other <=> (unsigned long)(0xffff'ffff'ffff'ffff)); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
153 | (void)((int)other <=> (unsigned long)(0x0000'0000'ffff'ffff)); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
154 | (void)((int)other <=> (unsigned long)(0x0000'0000'0fff'ffff)); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
155 | (void)((int)other <=> (unsigned)(0x8000'0000)); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
156 | |
157 | // Common unsigned, other unsigned, constant signed |
158 | (void)((unsigned long)other <=> (int)(0xffff'ffff)); // expected-error {{argument to 'operator<=>' evaluates to -1, which cannot be narrowed to type 'unsigned long'}} |
159 | |
160 | // Common unsigned, other signed, constant signed |
161 | // Should not be possible as the common type should also be signed. |
162 | |
163 | // Common signed, other signed, constant signed |
164 | (void)((int)other <=> (long)(0xffff'ffff)); // expected-warning{{less}} |
165 | (void)((int)other <=> (long)(0xffff'ffff'0000'0000)); // expected-warning{{greater}} |
166 | (void)((int)other <=> (long)(0x0fff'ffff)); |
167 | (void)((int)other <=> (long)(0xffff'ffff'f000'0000)); |
168 | |
169 | // Common signed, other signed, constant unsigned |
170 | (void)((int)other <=> (unsigned char)(0xffff)); |
171 | (void)((int)other <=> (unsigned char)(0xff)); |
172 | |
173 | // Common signed, other unsigned, constant signed |
174 | (void)((unsigned char)other <=> (int)(0xff)); |
175 | (void)((unsigned char)other <=> (int)(0xffff)); // expected-warning{{less}} |
176 | |
177 | // Common signed, other unsigned, constant unsigned |
178 | (void)((unsigned char)other <=> (unsigned short)(0xff)); |
179 | (void)((unsigned char)other <=> (unsigned short)(0x100)); // expected-warning{{less}} |
180 | (void)((unsigned short)other <=> (unsigned char)(0xff)); |
181 | } |
182 | |
183 | void test8(void *vp, const void *cvp, int *ip) { |
184 | (void)(vp <=> cvp); // OK, void* comparisons are allowed. |
185 | (void)(vp <=> ip); |
186 | (void)(ip <=> cvp); |
187 | } |
188 | |
189 | void test9(long double ld, double d, float f, int i, long long ll) { |
190 | (void)(f <=> ll); // OK, floating-point to integer is OK |
191 | (void)(d <=> ld); |
192 | (void)(i <=> f); |
193 | } |
194 | |
195 | typedef int *INTPTR; |
196 | void test_typedef_bug(int *x, INTPTR y) { |
197 | (void)(x <=> y); |
198 | } |
199 | |
200 | using nullptr_t = decltype(nullptr); |
201 | |
202 | struct Class {}; |
203 | struct ClassB : Class {}; |
204 | struct Class2 {}; |
205 | using FnTy = void(int); |
206 | using FnTy2 = long(int); |
207 | using MemFnTy = void (Class::*)() const; |
208 | using MemFnTyB = void (ClassB::*)() const; |
209 | using MemFnTy2 = void (Class::*)(); |
210 | using MemFnTy3 = void (Class2::*)() const; |
211 | using MemDataTy = long(Class::*); |
212 | |
213 | void test_nullptr(int *x, FnTy *fp, MemFnTy memp, MemDataTy memdp) { |
214 | auto r1 = (nullptr <=> nullptr); |
215 | ASSERT_EXPR_TYPE(r1, std::strong_equality); |
216 | |
217 | auto r2 = (nullptr <=> x); |
218 | ASSERT_EXPR_TYPE(r2, std::strong_equality); |
219 | |
220 | auto r3 = (fp <=> nullptr); |
221 | ASSERT_EXPR_TYPE(r3, std::strong_equality); |
222 | |
223 | auto r4 = (0 <=> fp); |
224 | ASSERT_EXPR_TYPE(r4, std::strong_equality); |
225 | |
226 | auto r5 = (nullptr <=> memp); |
227 | ASSERT_EXPR_TYPE(r5, std::strong_equality); |
228 | |
229 | auto r6 = (0 <=> memdp); |
230 | ASSERT_EXPR_TYPE(r6, std::strong_equality); |
231 | |
232 | auto r7 = (0 <=> nullptr); |
233 | ASSERT_EXPR_TYPE(r7, std::strong_equality); |
234 | } |
235 | |
236 | void test_compatible_pointer(FnTy *f1, FnTy2 *f2, MemFnTy mf1, MemFnTyB mfb, |
237 | MemFnTy2 mf2, MemFnTy3 mf3) { |
238 | (void)(f1 <=> f2); // expected-error {{distinct pointer types}} |
239 | |
240 | auto r1 = (mf1 <=> mfb); // OK |
241 | ASSERT_EXPR_TYPE(r1, std::strong_equality); |
242 | ASSERT_EXPR_TYPE((mf1 <=> mfb), std::strong_equality); |
243 | |
244 | (void)(mf1 <=> mf2); // expected-error {{distinct pointer types}} |
245 | (void)(mf3 <=> mf1); // expected-error {{distinct pointer types}} |
246 | } |
247 | |
248 | // Test that variable narrowing is deferred for value dependent expressions |
249 | template <int Val> |
250 | auto test_template_overflow() { |
251 | // expected-error@+1 {{argument to 'operator<=>' evaluates to -1, which cannot be narrowed to type 'unsigned long'}} |
252 | return (Val <=> (unsigned long)0); |
253 | } |
254 | template auto test_template_overflow<0>(); |
255 | template auto test_template_overflow<-1>(); // expected-note {{requested here}} |
256 | |
257 | void test_enum_integral_compare() { |
258 | enum EnumA : int {A, ANeg = -1, AMax = __INT_MAX__}; |
259 | enum EnumB : unsigned {B, BMax = __UINT32_MAX__ }; |
260 | enum EnumC : int {C = -1, C0 = 0}; |
261 | |
262 | (void)(A <=> C); // expected-error {{invalid operands to binary expression ('EnumA' and 'EnumC')}} |
263 | |
264 | (void)(A <=> (unsigned)0); |
265 | (void)((unsigned)0 <=> A); |
266 | (void)(ANeg <=> (unsigned)0); // expected-error {{argument to 'operator<=>' evaluates to -1, which cannot be narrowed to type 'unsigned int'}} |
267 | (void)((unsigned)0 <=> ANeg); // expected-error {{cannot be narrowed}} |
268 | |
269 | (void)(B <=> 42); |
270 | (void)(42 <=> B); |
271 | (void)(B <=> (unsigned long long)42); |
272 | (void)(B <=> -1); // expected-error {{argument to 'operator<=>' evaluates to -1, which cannot be narrowed to type 'unsigned int'}} |
273 | (void)(BMax <=> (unsigned long)-1); |
274 | |
275 | (void)(C0 <=> (unsigned)42); |
276 | (void)(C <=> (unsigned)42); // expected-error {{argument to 'operator<=>' evaluates to -1, which cannot be narrowed to type 'unsigned int'}} |
277 | } |
278 | |
279 | namespace EnumCompareTests { |
280 | |
281 | enum class EnumA { A, A2 }; |
282 | enum class EnumB { B }; |
283 | enum class EnumC : unsigned { C }; |
284 | |
285 | void test_enum_enum_compare_no_builtin() { |
286 | auto r1 = (EnumA::A <=> EnumA::A2); // OK |
287 | ASSERT_EXPR_TYPE(r1, std::strong_ordering); |
288 | (void)(EnumA::A <=> EnumA::A); // expected-warning {{self-comparison always evaluates to 'std::strong_ordering::equal'}} |
289 | (void)(EnumA::A <=> EnumB::B); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumA' and 'EnumCompareTests::EnumB')}} |
290 | (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands}} |
291 | } |
292 | |
293 | template <int> |
294 | struct Tag {}; |
295 | // expected-note@+1 {{candidate}} |
296 | Tag<0> operator<=>(EnumA, EnumA) { |
297 | return {}; |
298 | } |
299 | Tag<1> operator<=>(EnumA, EnumB) { |
300 | return {}; |
301 | } |
302 | |
303 | void test_enum_ovl_provided() { |
304 | auto r1 = (EnumA::A <=> EnumA::A); |
305 | ASSERT_EXPR_TYPE(r1, Tag<0>); |
306 | auto r2 = (EnumA::A <=> EnumB::B); |
307 | ASSERT_EXPR_TYPE(r2, Tag<1>); |
308 | (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}} |
309 | } |
310 | |
311 | void enum_float_test() { |
312 | enum EnumA { A }; |
313 | (void)(A <=> (float)0); // expected-error {{invalid operands to binary expression ('EnumA' and 'float')}} |
314 | (void)((double)0 <=> A); // expected-error {{invalid operands to binary expression ('double' and 'EnumA')}} |
315 | (void)((long double)0 <=> A); // expected-error {{invalid operands to binary expression ('long double' and 'EnumA')}} |
316 | } |
317 | |
318 | enum class Bool1 : bool { Zero, |
319 | One }; |
320 | enum Bool2 : bool { B2_Zero, |
321 | B2_One }; |
322 | |
323 | void test_bool_enum(Bool1 A1, Bool1 A2, Bool2 B1, Bool2 B2) { |
324 | (void)(A1 <=> A2); |
325 | (void)(B1 <=> B2); |
326 | } |
327 | |
328 | } // namespace EnumCompareTests |
329 | |
330 | namespace TestUserDefinedConvSeq { |
331 | |
332 | template <class T, T Val> |
333 | struct Conv { |
334 | constexpr operator T() const { return Val; } |
335 | operator T() { return Val; } |
336 | }; |
337 | |
338 | void test_user_conv() { |
339 | { |
340 | using C = Conv<int, 0>; |
341 | C c; |
342 | const C cc; |
343 | (void)(0 <=> c); |
344 | (void)(c <=> -1); |
345 | (void)((unsigned)0 <=> cc); |
346 | (void)((unsigned)0 <=> c); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'int' to 'unsigned int'}} |
347 | } |
348 | { |
349 | using C = Conv<int, -1>; |
350 | C c; |
351 | const C cc; |
352 | (void)(c <=> 0); |
353 | (void)(cc <=> (unsigned)0); // expected-error {{argument to 'operator<=>' evaluates to -1, which cannot be narrowed to type 'unsigned int'}} |
354 | (void)(c <=> (unsigned)0); // expected-error {{cannot be narrowed from type 'int' to 'unsigned int'}} |
355 | } |
356 | } |
357 | |
358 | } // namespace TestUserDefinedConvSeq |
359 | |
360 | void test_array_conv() { |
361 | int arr[5]; |
362 | int *ap = arr + 2; |
363 | int arr2[3]; |
364 | (void)(arr <=> arr); // expected-error {{invalid operands to binary expression ('int [5]' and 'int [5]')}} |
365 | (void)(+arr <=> arr); |
366 | } |
367 | |
368 | void test_mixed_float_int(float f, double d, long double ld) { |
369 | extern int i; |
370 | extern unsigned u; |
371 | extern long l; |
372 | extern short s; |
373 | extern unsigned short us; |
374 | auto r1 = (f <=> i); |
375 | ASSERT_EXPR_TYPE(r1, std::partial_ordering); |
376 | |
377 | auto r2 = (us <=> ld); |
378 | ASSERT_EXPR_TYPE(r2, std::partial_ordering); |
379 | |
380 | auto r3 = (s <=> f); |
381 | ASSERT_EXPR_TYPE(r3, std::partial_ordering); |
382 | |
383 | auto r4 = (0.0 <=> i); |
384 | ASSERT_EXPR_TYPE(r4, std::partial_ordering); |
385 | } |
386 | |
387 | namespace NullptrTest { |
388 | using nullptr_t = decltype(nullptr); |
389 | void foo(nullptr_t x, nullptr_t y) { |
390 | auto r = x <=> y; |
391 | ASSERT_EXPR_TYPE(r, std::strong_equality); |
392 | } |
393 | } // namespace NullptrTest |
394 | |
395 | namespace ComplexTest { |
396 | |
397 | enum class StrongE {}; |
398 | enum WeakE { E_One, |
399 | E_Two }; |
400 | |
401 | void test_diag(_Complex int ci, _Complex float cf, _Complex double cd, int i, float f, StrongE E1, WeakE E2, int *p) { |
402 | (void)(ci <=> (_Complex int &)ci); |
403 | (void)(ci <=> cf); |
404 | (void)(ci <=> i); |
405 | (void)(ci <=> f); |
406 | (void)(cf <=> i); |
407 | (void)(cf <=> f); |
408 | (void)(ci <=> p); // expected-error {{invalid operands}} |
409 | (void)(ci <=> E1); // expected-error {{invalid operands}} |
410 | (void)(E2 <=> cf); // expected-error {{invalid operands}} |
411 | } |
412 | |
413 | void test_int(_Complex int x, _Complex int y) { |
414 | auto r = x <=> y; |
415 | ASSERT_EXPR_TYPE(r, std::strong_equality); |
416 | } |
417 | |
418 | void test_double(_Complex double x, _Complex double y) { |
419 | auto r = x <=> y; |
420 | ASSERT_EXPR_TYPE(r, std::weak_equality); |
421 | } |
422 | |
423 | } // namespace ComplexTest |
424 | |