xref: /llvm-project/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp (revision 1376c73927dcb899db5d46f7b970692e2e95f9ac)
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