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 '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}} expected-note{{replace 'default'}} 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}} expected-note{{replace 'default'}} 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 // expected-note@#d {{replace 'default'}} 126 }; operator <=>(const c &) const127 auto c::operator<=>(const c&) const& { // #c 128 return std::strong_ordering::equal; 129 } 130 // expected-error@+1 {{overload resolution selected deleted operator '<=>'}} 131 std::strong_ordering cmp_d = d() <=> d(); 132 // expected-note@#c 2{{candidate}} 133 // expected-note@#d {{candidate function has been implicitly deleted}} 134 } 135 136 namespace BadDeducedType { 137 struct A { 138 // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'auto &'}} 139 friend auto &operator<=>(const A&, const A&) = default; 140 }; 141 142 struct B { 143 // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'const auto'}} 144 friend const auto operator<=>(const B&, const B&) = default; 145 }; 146 147 template<typename T> struct X {}; // expected-note {{here}} 148 struct C { 149 // expected-error@+1 {{deduction not allowed in function return type}} 150 friend X operator<=>(const C&, const C&) = default; 151 }; 152 153 template<typename T> concept CmpCat = true; 154 struct D { 155 // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'CmpCat auto'}} 156 friend CmpCat auto operator<=>(const D&, const D&) = default; 157 }; 158 } 159 160 namespace PR48856 { 161 struct A { 162 auto operator<=>(const A &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 163 void (*x)(); // expected-note {{because there is no viable three-way comparison function for member 'x'}} 164 }; 165 166 struct B { 167 auto operator<=>(const B &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 168 void (B::*x)(); // expected-note {{because there is no viable three-way comparison function for member 'x'}} 169 }; 170 171 struct C { 172 auto operator<=>(const C &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 173 int C::*x; // expected-note {{because there is no viable three-way comparison function for member 'x'}} 174 }; 175 } 176 177 namespace PR50591 { 178 struct a1 { 179 operator int() const; 180 }; 181 struct b1 { 182 auto operator<=>(b1 const &) const = default; 183 a1 f; 184 }; 185 std::strong_ordering cmp_b1 = b1() <=> b1(); 186 187 struct a2 { 188 operator float() const; 189 }; 190 struct b2 { 191 auto operator<=>(b2 const &) const = default; 192 a2 f; 193 }; 194 std::partial_ordering cmp_b2 = b2() <=> b2(); 195 196 using fp = void (*)(); 197 198 struct a3 { 199 operator fp() const; 200 }; 201 struct b3 { 202 auto operator<=>(b3 const &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 203 a3 f; // expected-note {{because there is no viable three-way comparison function}} 204 }; 205 206 struct a4 { // Test that function pointer conversion operator here is ignored for this overload resolution. 207 operator int() const; 208 operator fp() const; 209 }; 210 struct b4 { 211 auto operator<=>(b4 const &) const = default; 212 a4 f; 213 }; 214 std::strong_ordering cmp_b4 = b4() <=> b4(); 215 } 216