xref: /llvm-project/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp (revision c7df775440717ec5a3f47b6d485617d802cbd036)
1 // RUN: %clang_cc1 -std=c++2a -verify %s
2 
3 struct B {};
4 
5 template<typename T = void>
6   bool operator<(const B&, const B&) = default; // expected-error {{comparison operator template cannot be defaulted}}
7 
8 struct A {
9   friend bool operator==(const A&, const A&) = default;
10   friend bool operator!=(const A&, const B&) = default; // expected-error {{parameters for defaulted equality comparison operator must have the same type (found 'const A &' vs 'const B &')}}
11   friend bool operator!=(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison}}
12   friend bool operator<(const A&, const A&);
13   friend bool operator<(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted relational comparison}}
14   friend bool operator>(A, A) = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}}
15 
16   bool operator<(const A&) const;
17   bool operator<=(const A&) const = default;
18   bool operator==(const A&) const && = default; // expected-error {{ref-qualifier '&&' is not allowed on a defaulted comparison operator}}
19   bool operator<=(const A&&) const = default; // expected-error {{invalid parameter type for defaulted relational comparison operator; found 'const A &&', expected 'const A &'}}
20   bool operator<=(const int&) const = default; // expected-error {{invalid parameter type for defaulted relational comparison operator; found 'const int &', expected 'const A &'}}
21   bool operator>=(const A&) const volatile = default; // expected-error {{defaulted comparison function must not be volatile}}
22   bool operator<=>(const A&) = default; // expected-error {{defaulted member three-way comparison operator must be const-qualified}}
23   bool operator>=(const B&) const = default; // expected-error-re {{invalid parameter type for defaulted relational comparison operator; found 'const B &', expected 'const A &'{{$}}}}
24   static bool operator>(const B&) = default; // expected-error {{overloaded 'operator>' cannot be a static member function}}
25   friend bool operator>(A, const A&) = default; // expected-error {{must have the same type}} expected-note {{would be the best match}}
26 
27   template<typename T = void>
28     friend bool operator==(const A&, const A&) = default; // expected-error {{comparison operator template cannot be defaulted}}
29   template<typename T = void>
30     bool operator==(const A&) const = default; // expected-error {{comparison operator template cannot be defaulted}}
31 };
32 
33 template<class C> struct D {
34   C i;
35   friend bool operator==(const D&, D) = default; // expected-error {{must have the same type}}
36   friend bool operator>(D, const D&) = default; // expected-error {{must have the same type}}
37   friend bool operator<(const D&, const D&) = default;
38   friend bool operator<=(D, D) = default;
39 
40   bool operator!=(D) const = default; // expected-error {{invalid parameter type for defaulted equality comparison operator}}
41 };
42 
43 template<typename T> struct Dependent {
44   using U = typename T::type;
45   bool operator==(U) const = default; // expected-error {{found 'U'}}
46   friend bool operator==(U, U) = default; // expected-error {{found 'U'}}
47 };
48 
49 struct Good { using type = const Dependent<Good>&; };
50 template struct Dependent<Good>;
51 
52 struct Bad { using type = Dependent<Bad>&; };
53 template struct Dependent<Bad>; // expected-note {{in instantiation of}}
54 
55 
56 namespace std {
57   struct strong_ordering {
58     int n;
59     constexpr operator int() const { return n; }
60     static const strong_ordering equal, greater, less;
61   };
62   constexpr strong_ordering strong_ordering::equal = {0};
63   constexpr strong_ordering strong_ordering::greater = {1};
64   constexpr strong_ordering strong_ordering::less = {-1};
65 }
66 
67 namespace LookupContext {
68   struct A {};
69 
70   namespace N {
71     template <typename T> auto f() {
72       bool operator==(const T &, const T &);
73       bool operator<(const T &, const T &);
74       struct B {
75         T a;
76         std::strong_ordering operator<=>(const B &) const = default;
77       };
78       return B();
79     }
80 
81     auto g() {
82       struct Cmp { Cmp(std::strong_ordering); };
83       Cmp operator<=>(const A&, const A&);
84       bool operator!=(const Cmp&, int);
85       struct B {
86         A a;
87         Cmp operator<=>(const B &) const = default;
88       };
89       return B();
90     }
91 
92     auto h() {
93       struct B;
94       bool operator==(const B&, const B&);
95       bool operator!=(const B&, const B&); // expected-note 2{{best match}}
96       std::strong_ordering operator<=>(const B&, const B&);
97       bool operator<(const B&, const B&); // expected-note 2{{best match}}
98       bool operator<=(const B&, const B&); // expected-note 2{{best match}}
99       bool operator>(const B&, const B&); // expected-note 2{{best match}}
100       bool operator>=(const B&, const B&); // expected-note 2{{best match}}
101 
102       struct B {
103         bool operator!=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}} expected-note{{replace 'default'}}
104         bool operator<(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}} expected-note{{replace 'default'}}
105         bool operator<=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}} expected-note{{replace 'default'}}
106         bool operator>(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}} expected-note{{replace 'default'}}
107         bool operator>=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}} expected-note{{replace 'default'}}
108       };
109       return B();
110     }
111   }
112 
113   namespace M {
114     bool operator==(const A &, const A &) = delete;
115     bool operator<(const A &, const A &) = delete;
116     bool cmp = N::f<A>() < N::f<A>();
117 
118     void operator<=>(const A &, const A &) = delete;
119     auto cmp2 = N::g() <=> N::g();
120 
121     void use_h() {
122       N::h() != N::h(); // expected-error {{implicitly deleted}}
123       N::h() < N::h(); // expected-error {{implicitly deleted}}
124       N::h() <= N::h(); // expected-error {{implicitly deleted}}
125       N::h() > N::h(); // expected-error {{implicitly deleted}}
126       N::h() >= N::h(); // expected-error {{implicitly deleted}}
127     }
128   }
129 }
130 
131 namespace evil1 {
132 template <class T> struct Bad {
133   // expected-error@+1{{found 'const float &'}}
134   bool operator==(T const &) const = default;
135   Bad(int = 0);
136 };
137 
138 template <class T> struct Weird {
139   // expected-error@+1{{'float' cannot be used prior to '::'}}
140   bool operator==(typename T::Weird_ const &) const = default;
141   Weird(int = 0);
142 };
143 
144 struct evil {
145   using Weird_ = Weird<evil>;
146 };
147 template struct Bad<float>;   // expected-note{{evil1::Bad<float>' requested}}
148 template struct Weird<float>; // expected-note{{evil1::Weird<float>' requested}}
149 template struct Weird<evil>;
150 
151 } // namespace evil1
152 
153 namespace P1946 {
154   struct A {
155     friend bool operator==(A &, A &); // expected-note {{would lose const qualifier}}
156   };
157   struct B {
158     A a; // expected-note {{no viable 'operator=='}}
159     friend bool operator==(B, B) = default; // ok
160     friend bool operator==(const B&, const B&) = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
161   };
162 }
163 
164 namespace p2085 {
165 // out-of-class defaulting
166 
167 struct S1 {
168   bool operator==(S1 const &) const;
169 };
170 
171 bool S1::operator==(S1 const &) const = default;
172 
173 bool F1(S1 &s) {
174   return s != s;
175 }
176 
177 struct S2 {
178   friend bool operator==(S2 const &, S2 const &);
179 };
180 
181 bool operator==(S2 const &, S2 const &) = default;
182 bool F2(S2 &s) {
183   return s != s;
184 }
185 
186 struct S3 {};                                      // expected-note{{here}}
187 bool operator==(S3 const &, S3 const &) = default; // expected-error{{not a friend}}
188 
189 struct S4;                                         // expected-note{{forward declaration}}
190 bool operator==(S4 const &, S4 const &) = default; // expected-error{{not a friend}}
191 
192 struct S5;                         // expected-note 3{{forward declaration}}
193 bool operator==(S5, S5) = default; // expected-error{{not a friend}} expected-error 2{{has incomplete type}}
194 
195 struct S6;
196 bool operator==(const S6&, const S6&); // expected-note {{previous declaration}}
197 struct S6 {
198     friend bool operator==(const S6&, const S6&) = default; // expected-error {{because it was already declared outside}}
199 };
200 
201 struct S7 {
202   bool operator==(S7 const &) const &&;
203 };
204 bool S7::operator==(S7 const &) const && = default; // expected-error {{ref-qualifier '&&' is not allowed on a defaulted comparison operator}}
205 
206 enum e {};
207 bool operator==(e, int) = default; // expected-error{{expected class or reference to a constant class}}
208 
209 bool operator==(e *, int *) = default; // expected-error{{must have at least one}}
210 } // namespace p2085
211 
212 namespace p2085_2 {
213 template <class T> struct S6 {
214   bool operator==(T const &) const;
215 };
216 // expected-error@+2{{found 'const int &'}}
217 // expected-error@+1{{found 'const float &'}}
218 template <class T> bool S6<T>::operator==(T const &) const = default;
219 
220 template struct S6<int>; // expected-note{{S6<int>::operator==' requested}}
221 
222 void f1() {
223   S6<float> a;
224   (void)(a == 0); // expected-note{{S6<float>::operator==' requested}}
225 }
226 
227 template <class T> struct S7 {
228   // expected-error@+2{{'float' cannot be used}}
229   // expected-error@+1{{'int' cannot be used}}
230   bool operator==(typename T::S7_ const &) const;
231   S7(int = 0);
232 };
233 template <class T> bool S7<T>::operator==(typename T::S7_ const &) const = default;
234 
235 struct evil {
236   using S7_ = S7<evil>;
237 };
238 template struct S7<float>; // expected-note{{S7<float>' requested}}
239 
240 void f2() {
241   S7<int> a; // expected-note{{S7<int>' requested}}
242   S7<evil> b;
243   (void)(a == 0); // expected-error{{invalid operands}}
244   (void)(b == 0);
245 }
246 } // namespace p2085_2
247 
248 namespace GH61417 {
249 struct A {
250   unsigned x : 1;
251   unsigned   : 0;
252   unsigned y : 1;
253 
254   constexpr A() : x(0), y(0) {}
255   bool operator==(const A& rhs) const noexcept = default;
256 };
257 
258 void f1() {
259   constexpr A a, b;
260   constexpr bool c = (a == b); // no diagnostic, we should not be comparing the
261                                // unnamed bit-field which is indeterminate
262 }
263 
264 void f2() {
265     A a, b;
266     bool c = (a == b); // no diagnostic nor crash during codegen attempting to
267                        // access info for unnamed bit-field
268 }
269 }
270 
271 namespace GH96043 {
272 template <typename> class a {};
273 template <typename b> b c(a<b>);
274 template <typename d> class e {
275 public:
276   typedef a<d *> f;
277   f begin();
278 };
279 template <typename d, typename g> constexpr bool operator==(d h, g i) {
280   return *c(h.begin()) == *c(i.begin());
281 }
282 struct j {
283   e<j> bar;
284   bool operator==(const j &) const;
285 };
286 bool j::operator==(const j &) const = default;
287 }
288