Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 1 | // Force x86-64 because some of our heuristics are actually based |
| 2 | // on integer sizes. |
| 3 | |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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)); |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 10 | |
Richard Smith | 32f3973 | 2018-01-07 22:03:44 +0000 | [diff] [blame] | 11 | void self_compare() { |
| 12 | int a; |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 13 | int *b = nullptr; |
| 14 | |
Richard Smith | 32f3973 | 2018-01-07 22:03:44 +0000 | [diff] [blame] | 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'}} |
Richard Smith | 32f3973 | 2018-01-07 22:03:44 +0000 | [diff] [blame] | 17 | } |
| 18 | |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 19 | void test0(long a, unsigned long b) { |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 20 | enum EnumA : int {A}; |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 21 | enum EnumB {B}; |
| 22 | enum EnumC {C = 0x10000}; |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 23 | |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 28 | (void)(a <=> (unsigned int) b); |
| 29 | (void)(a <=> (unsigned short) b); |
| 30 | (void)(a <=> (unsigned char) b); |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 37 | (void)((short) a <=> (unsigned short) b); |
| 38 | (void)((signed char) a <=> (unsigned char) b); |
| 39 | |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 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) |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 55 | (void)(a <=> (unsigned long) B); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'long' to 'unsigned long'}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 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); |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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'}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 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) |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 83 | (void)(a <=> (unsigned long) C); // expected-error {{argument to 'operator<=>' cannot be narrowed from type 'long' to 'unsigned long'}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 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'}} |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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'}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 93 | (void)((short) a <=> (unsigned short) C); |
| 94 | (void)((signed char) a <=> (unsigned char) C); |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 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) |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 111 | (void)(a <=> (unsigned long)0x80000); // expected-error {{argument to 'operator<=>' cannot be narrowed}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 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'}} |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 121 | (void)((short) a <=> (unsigned short) 0x80000); |
| 122 | (void)((signed char) a <=> (unsigned char) 0x80000); |
| 123 | } |
| 124 | |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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')}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 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 |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 156 | |
| 157 | // Common unsigned, other unsigned, constant signed |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 158 | (void)((unsigned long)other <=> (int)(0xffff'ffff)); // expected-error {{argument to 'operator<=>' evaluates to -1, which cannot be narrowed to type 'unsigned long'}} |
Richard Smith | c70f1d6 | 2017-12-14 15:16:18 +0000 | [diff] [blame] | 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 | } |
Eric Fiselier | 0683c0e | 2018-05-07 21:07:10 +0000 | [diff] [blame] | 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 |