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