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