168009c24SRichard Smith // RUN: %clang_cc1 -std=c++2a -verify %s 268009c24SRichard Smith 368009c24SRichard Smith namespace std { 468009c24SRichard Smith class strong_ordering { 568009c24SRichard Smith int n; strong_ordering(int n)668009c24SRichard Smith constexpr strong_ordering(int n) : n(n) {} 768009c24SRichard Smith public: 868009c24SRichard Smith static const strong_ordering less, equal, greater; operator !=(int)968009c24SRichard Smith bool operator!=(int) { return n != 0; } 1068009c24SRichard Smith }; 1168009c24SRichard Smith constexpr strong_ordering strong_ordering::less{-1}, 1268009c24SRichard Smith strong_ordering::equal{0}, strong_ordering::greater{1}; 1368009c24SRichard Smith 1468009c24SRichard Smith class weak_ordering { 1568009c24SRichard Smith int n; weak_ordering(int n)1668009c24SRichard Smith constexpr weak_ordering(int n) : n(n) {} 1768009c24SRichard Smith public: 1868009c24SRichard Smith constexpr weak_ordering(strong_ordering o); 1968009c24SRichard Smith static const weak_ordering less, equivalent, greater; operator !=(int)2068009c24SRichard Smith bool operator!=(int) { return n != 0; } 2168009c24SRichard Smith }; 2268009c24SRichard Smith constexpr weak_ordering weak_ordering::less{-1}, 2368009c24SRichard Smith weak_ordering::equivalent{0}, weak_ordering::greater{1}; 2468009c24SRichard Smith 2568009c24SRichard Smith class partial_ordering { 2668009c24SRichard Smith int n; partial_ordering(int n)2768009c24SRichard Smith constexpr partial_ordering(int n) : n(n) {} 2868009c24SRichard Smith public: 2968009c24SRichard Smith constexpr partial_ordering(strong_ordering o); 3068009c24SRichard Smith constexpr partial_ordering(weak_ordering o); 3168009c24SRichard Smith static const partial_ordering less, equivalent, greater, unordered; operator !=(int)3268009c24SRichard Smith bool operator!=(int) { return n != 0; } 3368009c24SRichard Smith }; 3468009c24SRichard Smith constexpr partial_ordering partial_ordering::less{-1}, 3568009c24SRichard Smith partial_ordering::equivalent{0}, partial_ordering::greater{1}, 3668009c24SRichard Smith partial_ordering::unordered{2}; 3768009c24SRichard Smith } 3868009c24SRichard Smith 3968009c24SRichard Smith namespace DeducedNotCat { 4068009c24SRichard Smith struct A { 4168009c24SRichard Smith A operator<=>(const A&) const; // expected-note {{selected 'operator<=>' for member 'a' declared here}} 4268009c24SRichard Smith }; 4368009c24SRichard Smith struct B { 4415f3cd6bSMatheus Izvekov A a; // expected-note {{return type 'A' of three-way comparison for member 'a' is not a standard comparison category type}} 45*1376c739SNathan James auto operator<=>(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 4668009c24SRichard Smith }; 4768009c24SRichard Smith } 4868009c24SRichard Smith 4968009c24SRichard Smith namespace DeducedVsSynthesized { 5068009c24SRichard Smith struct A { 5168009c24SRichard Smith bool operator==(const A&) const; 5268009c24SRichard Smith bool operator<(const A&) const; 5368009c24SRichard Smith }; 5468009c24SRichard Smith struct B { 55c9fd92d5SMatheus Izvekov A a; // expected-note {{no viable three-way comparison function for member 'a'}} 56*1376c739SNathan James auto operator<=>(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 5768009c24SRichard Smith }; 5868009c24SRichard Smith } 5968009c24SRichard Smith 6068009c24SRichard Smith namespace Deduction { 6168009c24SRichard Smith template<typename T> struct wrap { 6268009c24SRichard Smith T t; 6368009c24SRichard Smith friend auto operator<=>(const wrap&, const wrap&) = default; 6468009c24SRichard Smith }; 6568009c24SRichard Smith 6668009c24SRichard Smith using strong = wrap<int>; 6768009c24SRichard Smith using strong2 = wrap<int*>; 6868009c24SRichard Smith struct weak { 6968009c24SRichard Smith friend std::weak_ordering operator<=>(weak, weak); 7068009c24SRichard Smith }; 7168009c24SRichard Smith using partial = wrap<float>; 7268009c24SRichard Smith 7368009c24SRichard Smith template<typename ...T> struct A : T... { 7468009c24SRichard Smith friend auto operator<=>(const A&, const A&) = default; 7568009c24SRichard Smith }; 7668009c24SRichard Smith f()7768009c24SRichard Smith template<typename Expected, typename ...Ts> void f() { 7868009c24SRichard Smith using T = Expected; // expected-note {{previous}} 7968009c24SRichard Smith using T = decltype(A<Ts...>() <=> A<Ts...>()); // expected-error {{different type}} 8068009c24SRichard Smith void(A<Ts...>() <=> A<Ts...>()); // trigger synthesis of body 8168009c24SRichard Smith } 8268009c24SRichard Smith 8368009c24SRichard Smith template void f<std::strong_ordering>(); 8468009c24SRichard Smith template void f<std::strong_ordering, strong>(); 8568009c24SRichard Smith template void f<std::strong_ordering, strong, strong2>(); 8668009c24SRichard Smith 8768009c24SRichard Smith template void f<std::weak_ordering, weak>(); 8868009c24SRichard Smith template void f<std::weak_ordering, weak, strong>(); 8968009c24SRichard Smith template void f<std::weak_ordering, strong, weak>(); 9068009c24SRichard Smith 9168009c24SRichard Smith template void f<std::partial_ordering, partial>(); 9268009c24SRichard Smith template void f<std::partial_ordering, weak, partial>(); 9368009c24SRichard Smith template void f<std::partial_ordering, strong, partial>(); 9468009c24SRichard Smith template void f<std::partial_ordering, partial, weak>(); 9568009c24SRichard Smith template void f<std::partial_ordering, partial, strong>(); 9668009c24SRichard Smith template void f<std::partial_ordering, weak, partial, strong>(); 9768009c24SRichard Smith 9868009c24SRichard Smith // Check that the above mechanism works. 9968009c24SRichard Smith template void f<std::strong_ordering, weak>(); // expected-note {{instantiation of}} 10042d4a55fSRichard Smith 10142d4a55fSRichard Smith std::strong_ordering x = A<strong>() <=> A<strong>(); 10242d4a55fSRichard Smith } 10342d4a55fSRichard Smith 10442d4a55fSRichard Smith namespace PR44723 { 10542d4a55fSRichard Smith // Make sure we trigger return type deduction for a callee 'operator<=>' 10642d4a55fSRichard Smith // before inspecting its return type. 10742d4a55fSRichard Smith template<int> struct a { operator <=>(a const & lhs,a const & rhs)10842d4a55fSRichard Smith friend constexpr auto operator<=>(a const &lhs, a const &rhs) { 10942d4a55fSRichard Smith return std::strong_ordering::equal; 11042d4a55fSRichard Smith } 11142d4a55fSRichard Smith }; 11242d4a55fSRichard Smith struct b { 11342d4a55fSRichard Smith friend constexpr auto operator<=>(b const &, b const &) = default; 11442d4a55fSRichard Smith a<0> m_value; 11542d4a55fSRichard Smith }; 11642d4a55fSRichard Smith std::strong_ordering cmp_b = b() <=> b(); 11742d4a55fSRichard Smith 11842d4a55fSRichard Smith struct c { 11942d4a55fSRichard Smith auto operator<=>(const c&) const&; // expected-note {{selected 'operator<=>' for base class 'c' declared here}} 12042d4a55fSRichard Smith }; 12142d4a55fSRichard Smith struct d : c { // expected-note {{base class 'c' declared here}} 12242d4a55fSRichard Smith friend auto operator<=>(const d&, const d&) = default; // #d 12342d4a55fSRichard Smith // 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}} 12442d4a55fSRichard Smith // expected-warning@#d {{implicitly deleted}} 125*1376c739SNathan James // expected-note@#d {{replace 'default'}} 12642d4a55fSRichard Smith }; operator <=>(const c &) const12742d4a55fSRichard Smith auto c::operator<=>(const c&) const& { // #c 12842d4a55fSRichard Smith return std::strong_ordering::equal; 12942d4a55fSRichard Smith } 13042d4a55fSRichard Smith // expected-error@+1 {{overload resolution selected deleted operator '<=>'}} 13142d4a55fSRichard Smith std::strong_ordering cmp_d = d() <=> d(); 13242d4a55fSRichard Smith // expected-note@#c 2{{candidate}} 13342d4a55fSRichard Smith // expected-note@#d {{candidate function has been implicitly deleted}} 13468009c24SRichard Smith } 13568009c24SRichard Smith 13668009c24SRichard Smith namespace BadDeducedType { 13768009c24SRichard Smith struct A { 13868009c24SRichard Smith // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'auto &'}} 13968009c24SRichard Smith friend auto &operator<=>(const A&, const A&) = default; 14068009c24SRichard Smith }; 14168009c24SRichard Smith 14268009c24SRichard Smith struct B { 14368009c24SRichard Smith // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'const auto'}} 14468009c24SRichard Smith friend const auto operator<=>(const B&, const B&) = default; 14568009c24SRichard Smith }; 14668009c24SRichard Smith 14768009c24SRichard Smith template<typename T> struct X {}; // expected-note {{here}} 14868009c24SRichard Smith struct C { 14968009c24SRichard Smith // expected-error@+1 {{deduction not allowed in function return type}} 15068009c24SRichard Smith friend X operator<=>(const C&, const C&) = default; 15168009c24SRichard Smith }; 15268009c24SRichard Smith 15368009c24SRichard Smith template<typename T> concept CmpCat = true; 15468009c24SRichard Smith struct D { 15567c608a9SSaar Raz // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'CmpCat auto'}} 15667c608a9SSaar Raz friend CmpCat auto operator<=>(const D&, const D&) = default; 15768009c24SRichard Smith }; 15868009c24SRichard Smith } 1594a8530fcSMatheus Izvekov 1604a8530fcSMatheus Izvekov namespace PR48856 { 1614a8530fcSMatheus Izvekov struct A { 162*1376c739SNathan James auto operator<=>(const A &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 163ad14b5b0SMatheus Izvekov void (*x)(); // expected-note {{because there is no viable three-way comparison function for member 'x'}} 1644a8530fcSMatheus Izvekov }; 1654a8530fcSMatheus Izvekov 1664a8530fcSMatheus Izvekov struct B { 167*1376c739SNathan James auto operator<=>(const B &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 168c9fd92d5SMatheus Izvekov void (B::*x)(); // expected-note {{because there is no viable three-way comparison function for member 'x'}} 1694a8530fcSMatheus Izvekov }; 1704a8530fcSMatheus Izvekov 1714a8530fcSMatheus Izvekov struct C { 172*1376c739SNathan James auto operator<=>(const C &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 173c9fd92d5SMatheus Izvekov int C::*x; // expected-note {{because there is no viable three-way comparison function for member 'x'}} 1744a8530fcSMatheus Izvekov }; 1754a8530fcSMatheus Izvekov } 176b88eb855SMatheus Izvekov 177b88eb855SMatheus Izvekov namespace PR50591 { 178b88eb855SMatheus Izvekov struct a1 { 179b88eb855SMatheus Izvekov operator int() const; 180b88eb855SMatheus Izvekov }; 181b88eb855SMatheus Izvekov struct b1 { 182b88eb855SMatheus Izvekov auto operator<=>(b1 const &) const = default; 183b88eb855SMatheus Izvekov a1 f; 184b88eb855SMatheus Izvekov }; 185b88eb855SMatheus Izvekov std::strong_ordering cmp_b1 = b1() <=> b1(); 186b88eb855SMatheus Izvekov 187b88eb855SMatheus Izvekov struct a2 { 188b88eb855SMatheus Izvekov operator float() const; 189b88eb855SMatheus Izvekov }; 190b88eb855SMatheus Izvekov struct b2 { 191b88eb855SMatheus Izvekov auto operator<=>(b2 const &) const = default; 192b88eb855SMatheus Izvekov a2 f; 193b88eb855SMatheus Izvekov }; 194b88eb855SMatheus Izvekov std::partial_ordering cmp_b2 = b2() <=> b2(); 1957ddd15cdSMatheus Izvekov 1967ddd15cdSMatheus Izvekov using fp = void (*)(); 197ad14b5b0SMatheus Izvekov 198ad14b5b0SMatheus Izvekov struct a3 { 1997ddd15cdSMatheus Izvekov operator fp() const; 2007ddd15cdSMatheus Izvekov }; 2017ddd15cdSMatheus Izvekov struct b3 { 202*1376c739SNathan James auto operator<=>(b3 const &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 203ad14b5b0SMatheus Izvekov a3 f; // expected-note {{because there is no viable three-way comparison function}} 2047ddd15cdSMatheus Izvekov }; 205ad14b5b0SMatheus Izvekov 206ad14b5b0SMatheus Izvekov struct a4 { // Test that function pointer conversion operator here is ignored for this overload resolution. 207ad14b5b0SMatheus Izvekov operator int() const; 208ad14b5b0SMatheus Izvekov operator fp() const; 209ad14b5b0SMatheus Izvekov }; 210ad14b5b0SMatheus Izvekov struct b4 { 211ad14b5b0SMatheus Izvekov auto operator<=>(b4 const &) const = default; 212ad14b5b0SMatheus Izvekov a4 f; 213ad14b5b0SMatheus Izvekov }; 214ad14b5b0SMatheus Izvekov std::strong_ordering cmp_b4 = b4() <=> b4(); 215b88eb855SMatheus Izvekov } 216