1 // RUN: %clang_cc1 -std=c++2a -verify %s
2 
3 struct B {};
4 bool operator==(const B&, const B&) = default; // expected-error {{equality comparison operator can only be defaulted in a class definition}} expected-note {{candidate}}
5 bool operator<=>(const B&, const B&) = default; // expected-error {{three-way comparison operator can only be defaulted in a class definition}}
6 
7 template<typename T = void>
8   bool operator<(const B&, const B&) = default; // expected-error {{comparison operator template cannot be defaulted}}
9 
10 struct A {
11   friend bool operator==(const A&, const A&) = default;
12   friend bool operator!=(const A&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison operator; found 'const B &', expected 'A' or 'const A &'}}
13   friend bool operator!=(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison}}
14   friend bool operator<(const A&, const A&);
15   friend bool operator<(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted relational comparison}}
16   friend bool operator>(A, A) = default; // expected-warning {{implicitly deleted}}
17 
18   bool operator<(const A&) const;
19   bool operator<=(const A&) const = default;
20   bool operator==(const A&) const volatile && = default; // surprisingly, OK
21   bool operator<=>(const A&) = default; // expected-error {{defaulted member three-way comparison operator must be const-qualified}}
22   bool operator>=(const B&) const = default; // expected-error-re {{invalid parameter type for defaulted relational comparison operator; found 'const B &', expected 'const A &'{{$}}}}
23   static bool operator>(const B&) = default; // expected-error {{overloaded 'operator>' cannot be a static member function}}
24   friend bool operator>(A, const A&) = default; // expected-error {{must have the same type}} expected-note {{would be the best match}}
25 
26   template<typename T = void>
27     friend bool operator==(const A&, const A&) = default; // expected-error {{comparison operator template cannot be defaulted}}
28   template<typename T = void>
29     bool operator==(const A&) const = default; // expected-error {{comparison operator template cannot be defaulted}}
30 };
31 
32 // FIXME: The wording is not clear as to whether these are valid, but the
33 // intention is that they are not.
34 bool operator<(const A&, const A&) = default; // expected-error {{relational comparison operator can only be defaulted in a class definition}}
35 bool A::operator<(const A&) const = default; // expected-error {{can only be defaulted in a class definition}}
36 
37 template<typename T> struct Dependent {
38   using U = typename T::type;
39   bool operator==(U) const = default; // expected-error {{found 'Dependent<Bad>::U'}}
40   friend bool operator==(U, U) = default; // expected-error {{found 'Dependent<Bad>::U'}}
41 };
42 
43 struct Good { using type = const Dependent<Good>&; };
44 template struct Dependent<Good>;
45 
46 struct Bad { using type = Dependent<Bad>&; };
47 template struct Dependent<Bad>; // expected-note {{in instantiation of}}
48 
49 
50 namespace std {
51   struct strong_ordering {
52     int n;
operator intstd::strong_ordering53     constexpr operator int() const { return n; }
54     static const strong_ordering equal, greater, less;
55   };
56   constexpr strong_ordering strong_ordering::equal = {0};
57   constexpr strong_ordering strong_ordering::greater = {1};
58   constexpr strong_ordering strong_ordering::less = {-1};
59 }
60 
61 namespace LookupContext {
62   struct A {};
63 
64   namespace N {
f()65     template <typename T> auto f() {
66       bool operator==(const T &, const T &);
67       bool operator<(const T &, const T &);
68       struct B {
69         T a;
70         std::strong_ordering operator<=>(const B &) const = default;
71       };
72       return B();
73     }
74 
g()75     auto g() {
76       struct Cmp { Cmp(std::strong_ordering); };
77       Cmp operator<=>(const A&, const A&);
78       bool operator!=(const Cmp&, int);
79       struct B {
80         A a;
81         Cmp operator<=>(const B &) const = default;
82       };
83       return B();
84     }
85 
h()86     auto h() {
87       struct B;
88       bool operator==(const B&, const B&);
89       bool operator!=(const B&, const B&); // expected-note 2{{best match}}
90       std::strong_ordering operator<=>(const B&, const B&);
91       bool operator<(const B&, const B&); // expected-note 2{{best match}}
92       bool operator<=(const B&, const B&); // expected-note 2{{best match}}
93       bool operator>(const B&, const B&); // expected-note 2{{best match}}
94       bool operator>=(const B&, const B&); // expected-note 2{{best match}}
95 
96       struct B {
97         bool operator!=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
98         bool operator<(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
99         bool operator<=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
100         bool operator>(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
101         bool operator>=(const B&) const = default; // expected-warning {{implicitly deleted}} expected-note {{deleted here}}
102       };
103       return B();
104     }
105   }
106 
107   namespace M {
108     bool operator==(const A &, const A &) = delete;
109     bool operator<(const A &, const A &) = delete;
110     bool cmp = N::f<A>() < N::f<A>();
111 
112     void operator<=>(const A &, const A &) = delete;
113     auto cmp2 = N::g() <=> N::g();
114 
use_h()115     void use_h() {
116       N::h() != N::h(); // expected-error {{implicitly deleted}}
117       N::h() < N::h(); // expected-error {{implicitly deleted}}
118       N::h() <= N::h(); // expected-error {{implicitly deleted}}
119       N::h() > N::h(); // expected-error {{implicitly deleted}}
120       N::h() >= N::h(); // expected-error {{implicitly deleted}}
121     }
122   }
123 }
124 
125 namespace P1946 {
126   struct A {
127     friend bool operator==(A &, A &); // expected-note {{would lose const qualifier}}
128   };
129   struct B {
130     A a; // expected-note {{no viable comparison}}
131     friend bool operator==(B, B) = default; // ok
132     friend bool operator==(const B&, const B&) = default; // expected-warning {{deleted}}
133   };
134 }
135