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}}
15 
16   bool operator<(const A&) const;
17   bool operator<=(const A&) const = default;
18   bool operator==(const A&) const volatile && = default; // surprisingly, OK
19   bool operator<=>(const A&) = default; // expected-error {{defaulted member three-way comparison operator must be const-qualified}}
20   bool operator>=(const B&) const = default; // expected-error-re {{invalid parameter type for defaulted relational comparison operator; found 'const B &', expected 'const A &'{{$}}}}
21   static bool operator>(const B&) = default; // expected-error {{overloaded 'operator>' cannot be a static member function}}
22   friend bool operator>(A, const A&) = default; // expected-error {{must have the same type}} expected-note {{would be the best match}}
23 
24   template<typename T = void>
25     friend bool operator==(const A&, const A&) = default; // expected-error {{comparison operator template cannot be defaulted}}
26   template<typename T = void>
27     bool operator==(const A&) const = default; // expected-error {{comparison operator template cannot be defaulted}}
28 };
29 
30 template<typename T> struct Dependent {
31   using U = typename T::type;
32   bool operator==(U) const = default; // expected-error {{found 'Dependent<Bad>::U'}}
33   friend bool operator==(U, U) = default; // expected-error {{found 'Dependent<Bad>::U'}}
34 };
35 
36 struct Good { using type = const Dependent<Good>&; };
37 template struct Dependent<Good>;
38 
39 struct Bad { using type = Dependent<Bad>&; };
40 template struct Dependent<Bad>; // expected-note {{in instantiation of}}
41 
42 
43 namespace std {
44   struct strong_ordering {
45     int n;
46     constexpr operator int() const { return n; }
47     static const strong_ordering equal, greater, less;
48   };
49   constexpr strong_ordering strong_ordering::equal = {0};
50   constexpr strong_ordering strong_ordering::greater = {1};
51   constexpr strong_ordering strong_ordering::less = {-1};
52 }
53 
54 namespace LookupContext {
55   struct A {};
56 
57   namespace N {
58     template <typename T> auto f() {
59       bool operator==(const T &, const T &);
60       bool operator<(const T &, const T &);
61       struct B {
62         T a;
63         std::strong_ordering operator<=>(const B &) const = default;
64       };
65       return B();
66     }
67 
68     auto g() {
69       struct Cmp { Cmp(std::strong_ordering); };
70       Cmp operator<=>(const A&, const A&);
71       bool operator!=(const Cmp&, int);
72       struct B {
73         A a;
74         Cmp operator<=>(const B &) const = default;
75       };
76       return B();
77     }
78 
79     auto h() {
80       struct B;
81       bool operator==(const B&, const B&);
82       bool operator!=(const B&, const B&); // expected-note 2{{best match}}
83       std::strong_ordering operator<=>(const B&, const B&);
84       bool operator<(const B&, const B&); // expected-note 2{{best match}}
85       bool operator<=(const B&, const B&); // expected-note 2{{best match}}
86       bool operator>(const B&, const B&); // expected-note 2{{best match}}
87       bool operator>=(const B&, const B&); // expected-note 2{{best match}}
88 
89       struct B {
90         bool operator!=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
91         bool operator<(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
92         bool operator<=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
93         bool operator>(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
94         bool operator>=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
95       };
96       return B();
97     }
98   }
99 
100   namespace M {
101     bool operator==(const A &, const A &) = delete;
102     bool operator<(const A &, const A &) = delete;
103     bool cmp = N::f<A>() < N::f<A>();
104 
105     void operator<=>(const A &, const A &) = delete;
106     auto cmp2 = N::g() <=> N::g();
107 
108     void use_h() {
109       N::h() != N::h(); // expected-error {{implicitly deleted}}
110       N::h() < N::h(); // expected-error {{implicitly deleted}}
111       N::h() <= N::h(); // expected-error {{implicitly deleted}}
112       N::h() > N::h(); // expected-error {{implicitly deleted}}
113       N::h() >= N::h(); // expected-error {{implicitly deleted}}
114     }
115   }
116 }
117 
118 namespace evil1 {
119 template <class T> struct Bad {
120   // expected-error@+1{{found 'const float &'}}
121   bool operator==(T const &) const = default;
122   Bad(int = 0);
123 };
124 
125 template <class T> struct Weird {
126   // expected-error@+1{{'float' cannot be used prior to '::'}}
127   bool operator==(typename T::Weird_ const &) const = default;
128   Weird(int = 0);
129 };
130 
131 struct evil {
132   using Weird_ = Weird<evil>;
133 };
134 template struct Bad<float>;   // expected-note{{evil1::Bad<float>' requested}}
135 template struct Weird<float>; // expected-note{{evil1::Weird<float>' requested}}
136 template struct Weird<evil>;
137 
138 } // namespace evil1
139 
140 namespace P1946 {
141   struct A {
142     friend bool operator==(A &, A &); // expected-note {{would lose const qualifier}}
143   };
144   struct B {
145     A a; // expected-note {{no viable three-way comparison}}
146     friend bool operator==(B, B) = default; // ok
147     friend bool operator==(const B&, const B&) = default; // expected-warning {{deleted}}
148   };
149 }
150 
151 namespace p2085 {
152 // out-of-class defaulting
153 
154 struct S1 {
155   bool operator==(S1 const &) const;
156 };
157 
158 bool S1::operator==(S1 const &) const = default;
159 
160 bool F1(S1 &s) {
161   return s != s;
162 }
163 
164 struct S2 {
165   friend bool operator==(S2 const &, S2 const &);
166 };
167 
168 bool operator==(S2 const &, S2 const &) = default;
169 bool F2(S2 &s) {
170   return s != s;
171 }
172 
173 struct S3 {};                                      // expected-note{{here}}
174 bool operator==(S3 const &, S3 const &) = default; // expected-error{{not a friend}}
175 
176 struct S4;                                         // expected-note{{forward declaration}}
177 bool operator==(S4 const &, S4 const &) = default; // expected-error{{not a friend}}
178 
179 struct S5;                         // expected-note 3{{forward declaration}}
180 bool operator==(S5, S5) = default; // expected-error{{not a friend}} expected-error 2{{has incomplete type}}
181 
182 enum e {};
183 bool operator==(e, int) = default; // expected-error{{expected class or reference to a constant class}}
184 
185 bool operator==(e *, int *) = default; // expected-error{{must have at least one}}
186 } // namespace p2085
187 
188 namespace p2085_2 {
189 template <class T> struct S6 {
190   // expected-error@+2{{found 'const int &'}}
191   // expected-error@+1{{found 'const float &'}}
192   bool operator==(T const &) const;
193 };
194 template <class T> bool S6<T>::operator==(T const &) const = default;
195 
196 template struct S6<int>; // expected-note{{S6<int>::operator==' requested}}
197 
198 void f1() {
199   S6<float> a;
200   (void)(a == 0); // expected-note{{S6<float>::operator==' requested}}
201 }
202 
203 template <class T> struct S7 {
204   // expected-error@+2{{'float' cannot be used}}
205   // expected-error@+1{{'int' cannot be used}}
206   bool operator==(typename T::S7_ const &) const;
207   S7(int = 0);
208 };
209 template <class T> bool S7<T>::operator==(typename T::S7_ const &) const = default;
210 
211 struct evil {
212   using S7_ = S7<evil>;
213 };
214 template struct S7<float>; // expected-note{{S7<float>' requested}}
215 
216 void f2() {
217   S7<int> a; // expected-note{{S7<int>' requested}}
218   S7<evil> b;
219   (void)(a == 0); // expected-error{{invalid operands}}
220   (void)(b == 0);
221 }
222 } // namespace p2085_2
223