1 // RUN: %clang_cc1 -std=c++2a -verify %s 2 3 namespace std { 4 class strong_ordering { 5 int n; strong_ordering(int n)6 constexpr strong_ordering(int n) : n(n) {} 7 public: 8 static const strong_ordering less, equal, greater; operator !=(int)9 bool operator!=(int) { return n != 0; } 10 }; 11 constexpr strong_ordering strong_ordering::less{-1}, 12 strong_ordering::equal{0}, strong_ordering::greater{1}; 13 14 class weak_ordering { 15 int n; weak_ordering(int n)16 constexpr weak_ordering(int n) : n(n) {} 17 public: 18 constexpr weak_ordering(strong_ordering o); 19 static const weak_ordering less, equivalent, greater; operator !=(int)20 bool operator!=(int) { return n != 0; } 21 }; 22 constexpr weak_ordering weak_ordering::less{-1}, 23 weak_ordering::equivalent{0}, weak_ordering::greater{1}; 24 25 class partial_ordering { 26 int n; partial_ordering(int n)27 constexpr partial_ordering(int n) : n(n) {} 28 public: 29 constexpr partial_ordering(strong_ordering o); 30 constexpr partial_ordering(weak_ordering o); 31 static const partial_ordering less, equivalent, greater, unordered; operator !=(int)32 bool operator!=(int) { return n != 0; } 33 }; 34 constexpr partial_ordering partial_ordering::less{-1}, 35 partial_ordering::equivalent{0}, partial_ordering::greater{1}, 36 partial_ordering::unordered{2}; 37 } 38 39 namespace DeducedNotCat { 40 struct A { 41 A operator<=>(const A&) const; // expected-note {{selected 'operator<=>' for member 'a' declared here}} 42 }; 43 struct B { 44 A a; // expected-note {{return type 'DeducedNotCat::A' of three-way comparison for member 'a' is not a standard comparison category type}} 45 auto operator<=>(const B&) const = default; // expected-warning {{implicitly deleted}} 46 }; 47 } 48 49 namespace DeducedVsSynthesized { 50 struct A { 51 bool operator==(const A&) const; 52 bool operator<(const A&) const; 53 }; 54 struct B { 55 A a; // expected-note {{no viable three-way comparison function for member 'a'}} 56 auto operator<=>(const B&) const = default; // expected-warning {{implicitly deleted}} 57 }; 58 } 59 60 namespace Deduction { 61 template<typename T> struct wrap { 62 T t; 63 friend auto operator<=>(const wrap&, const wrap&) = default; 64 }; 65 66 using strong = wrap<int>; 67 using strong2 = wrap<int*>; 68 struct weak { 69 friend std::weak_ordering operator<=>(weak, weak); 70 }; 71 using partial = wrap<float>; 72 73 template<typename ...T> struct A : T... { 74 friend auto operator<=>(const A&, const A&) = default; 75 }; 76 f()77 template<typename Expected, typename ...Ts> void f() { 78 using T = Expected; // expected-note {{previous}} 79 using T = decltype(A<Ts...>() <=> A<Ts...>()); // expected-error {{different type}} 80 void(A<Ts...>() <=> A<Ts...>()); // trigger synthesis of body 81 } 82 83 template void f<std::strong_ordering>(); 84 template void f<std::strong_ordering, strong>(); 85 template void f<std::strong_ordering, strong, strong2>(); 86 87 template void f<std::weak_ordering, weak>(); 88 template void f<std::weak_ordering, weak, strong>(); 89 template void f<std::weak_ordering, strong, weak>(); 90 91 template void f<std::partial_ordering, partial>(); 92 template void f<std::partial_ordering, weak, partial>(); 93 template void f<std::partial_ordering, strong, partial>(); 94 template void f<std::partial_ordering, partial, weak>(); 95 template void f<std::partial_ordering, partial, strong>(); 96 template void f<std::partial_ordering, weak, partial, strong>(); 97 98 // Check that the above mechanism works. 99 template void f<std::strong_ordering, weak>(); // expected-note {{instantiation of}} 100 101 std::strong_ordering x = A<strong>() <=> A<strong>(); 102 } 103 104 namespace PR44723 { 105 // Make sure we trigger return type deduction for a callee 'operator<=>' 106 // before inspecting its return type. 107 template<int> struct a { operator <=>(a const & lhs,a const & rhs)108 friend constexpr auto operator<=>(a const &lhs, a const &rhs) { 109 return std::strong_ordering::equal; 110 } 111 }; 112 struct b { 113 friend constexpr auto operator<=>(b const &, b const &) = default; 114 a<0> m_value; 115 }; 116 std::strong_ordering cmp_b = b() <=> b(); 117 118 struct c { 119 auto operator<=>(const c&) const&; // expected-note {{selected 'operator<=>' for base class 'c' declared here}} 120 }; 121 struct d : c { // expected-note {{base class 'c' declared here}} 122 friend auto operator<=>(const d&, const d&) = default; // #d 123 // expected-error@#d {{return type of defaulted 'operator<=>' cannot be deduced because three-way comparison for base class 'c' has a deduced return type and is not yet defined}} 124 // expected-warning@#d {{implicitly deleted}} 125 }; operator <=>(const c &) const126 auto c::operator<=>(const c&) const& { // #c 127 return std::strong_ordering::equal; 128 } 129 // expected-error@+1 {{overload resolution selected deleted operator '<=>'}} 130 std::strong_ordering cmp_d = d() <=> d(); 131 // expected-note@#c 2{{candidate}} 132 // expected-note@#d {{candidate function has been implicitly deleted}} 133 } 134 135 namespace BadDeducedType { 136 struct A { 137 // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'auto &'}} 138 friend auto &operator<=>(const A&, const A&) = default; 139 }; 140 141 struct B { 142 // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'const auto'}} 143 friend const auto operator<=>(const B&, const B&) = default; 144 }; 145 146 template<typename T> struct X {}; // expected-note {{here}} 147 struct C { 148 // expected-error@+1 {{deduction not allowed in function return type}} 149 friend X operator<=>(const C&, const C&) = default; 150 }; 151 152 template<typename T> concept CmpCat = true; 153 struct D { 154 // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'CmpCat auto'}} 155 friend CmpCat auto operator<=>(const D&, const D&) = default; 156 }; 157 } 158 159 namespace PR48856 { 160 struct A { 161 auto operator<=>(const A &) const = default; // expected-warning {{implicitly deleted}} 162 void (*x)(); // expected-note {{because there is no viable three-way comparison function for member 'x'}} 163 }; 164 165 struct B { 166 auto operator<=>(const B &) const = default; // expected-warning {{implicitly deleted}} 167 void (B::*x)(); // expected-note {{because there is no viable three-way comparison function for member 'x'}} 168 }; 169 170 struct C { 171 auto operator<=>(const C &) const = default; // expected-warning {{implicitly deleted}} 172 int C::*x; // expected-note {{because there is no viable three-way comparison function for member 'x'}} 173 }; 174 } 175 176 namespace PR50591 { 177 struct a1 { 178 operator int() const; 179 }; 180 struct b1 { 181 auto operator<=>(b1 const &) const = default; 182 a1 f; 183 }; 184 std::strong_ordering cmp_b1 = b1() <=> b1(); 185 186 struct a2 { 187 operator float() const; 188 }; 189 struct b2 { 190 auto operator<=>(b2 const &) const = default; 191 a2 f; 192 }; 193 std::partial_ordering cmp_b2 = b2() <=> b2(); 194 195 using fp = void (*)(); 196 197 struct a3 { 198 operator fp() const; 199 }; 200 struct b3 { 201 auto operator<=>(b3 const &) const = default; // expected-warning {{implicitly deleted}} 202 a3 f; // expected-note {{because there is no viable three-way comparison function}} 203 }; 204 205 struct a4 { // Test that function pointer conversion operator here is ignored for this overload resolution. 206 operator int() const; 207 operator fp() const; 208 }; 209 struct b4 { 210 auto operator<=>(b4 const &) const = default; 211 a4 f; 212 }; 213 std::strong_ordering cmp_b4 = b4() <=> b4(); 214 } 215