1 // RUN: %clang_cc1 -std=c++2a -verify %s
2 
3 namespace Rel {
4   struct A {
5     int n;
operator <=>Rel::A6     constexpr int operator<=>(A a) const { return n - a.n; }
7     friend bool operator<(const A&, const A&) = default;
8     friend bool operator<=(const A&, const A&) = default;
9     friend bool operator>(const A&, const A&) = default;
10     friend bool operator>=(const A&, const A&) = default;
11   };
12   static_assert(A{0} < A{1});
13   static_assert(A{1} < A{1}); // expected-error {{failed}}
14   static_assert(A{0} <= A{1});
15   static_assert(A{1} <= A{1});
16   static_assert(A{2} <= A{1}); // expected-error {{failed}}
17   static_assert(A{1} > A{0});
18   static_assert(A{1} > A{1}); // expected-error {{failed}}
19   static_assert(A{1} >= A{0});
20   static_assert(A{1} >= A{1});
21   static_assert(A{1} >= A{2}); // expected-error {{failed}}
22 
23   struct B {
24     bool operator<=>(B) const = delete; // expected-note 4{{deleted here}} expected-note-re 8{{candidate {{.*}} deleted}}
25     friend bool operator<(const B&, const B&) = default; // expected-warning {{implicitly deleted}} expected-note {{because it would invoke a deleted comparison}} expected-note-re {{candidate {{.*}} deleted}}
26     friend bool operator<=(const B&, const B&) = default; // expected-warning {{implicitly deleted}} expected-note {{because it would invoke a deleted comparison}} expected-note-re {{candidate {{.*}} deleted}}
27     friend bool operator>(const B&, const B&) = default; // expected-warning {{implicitly deleted}} expected-note {{because it would invoke a deleted comparison}} expected-note-re {{candidate {{.*}} deleted}}
28     friend bool operator>=(const B&, const B&) = default; // expected-warning {{implicitly deleted}} expected-note {{because it would invoke a deleted comparison}} expected-note-re {{candidate {{.*}} deleted}}
29   };
30   bool b1 = B() < B(); // expected-error {{deleted}}
31   bool b2 = B() <= B(); // expected-error {{deleted}}
32   bool b3 = B() > B(); // expected-error {{deleted}}
33   bool b4 = B() >= B(); // expected-error {{deleted}}
34 
35   struct C {
36     friend bool operator<=>(const C&, const C&);
37     friend bool operator<(const C&, const C&); // expected-note {{because this non-rewritten comparison function would be the best match}}
38 
39     bool operator<(const C&) const = default; // expected-warning {{implicitly deleted}}
40     bool operator>(const C&) const = default; // OK
41   };
42 }
43 
44 // Under P2002R0, operator!= follows these rules too.
45 namespace NotEqual {
46   struct A {
47     int n;
operator ==NotEqual::A48     constexpr bool operator==(A a) const { return n == a.n; }
49     friend bool operator!=(const A&, const A&) = default;
50   };
51   static_assert(A{1} != A{2});
52   static_assert(A{1} != A{1}); // expected-error {{failed}}
53 
54   struct B {
55     bool operator==(B) const = delete; // expected-note {{deleted here}} expected-note-re 2{{candidate {{.*}} deleted}}
56     friend bool operator!=(const B&, const B&) = default; // expected-warning {{implicitly deleted}} expected-note {{because it would invoke a deleted comparison}} expected-note-re {{candidate {{.*}} deleted}}
57   };
58   bool b = B() != B(); // expected-error {{deleted}}
59 
60   struct C {
61     friend bool operator==(const C&, const C&);
62     friend bool operator!=(const C&, const C&); // expected-note {{because this non-rewritten comparison function would be the best match}}
63 
64     bool operator!=(const C&) const = default; // expected-warning {{implicitly deleted}}
65   };
66 
67   // Ensure we don't go into an infinite loop diagnosing this: the first function
68   // is deleted because it calls the second function, which is deleted because it
69   // calls the first.
70   struct Evil {
71     friend bool operator!=(const Evil&, const Evil&) = default; // expected-warning {{implicitly deleted}} expected-note {{would be the best match}}
72     bool operator!=(const Evil&) const = default; // expected-warning {{implicitly deleted}} expected-note {{would be the best match}}
73   };
74 }
75 
76 namespace Access {
77   class A {
78     int operator<=>(A) const; // expected-note {{private}}
79   };
80   struct B : A {
81     friend bool operator<(const B&, const B&) = default; // expected-warning {{implicitly deleted}}
82     // expected-note@-1 {{defaulted 'operator<' is implicitly deleted because it would invoke a private 'operator<=>' member of 'Access::A'}}
83   };
84 }
85