15253d913SRichard Smith // RUN: %clang_cc1 -std=c++2a -verify %s 25253d913SRichard Smith 35253d913SRichard Smith namespace Rel { 45253d913SRichard Smith struct A { 5cafc7416SRichard Smith int n; operator <=>Rel::A6cafc7416SRichard Smith constexpr int operator<=>(A a) const { return n - a.n; } 75253d913SRichard Smith friend bool operator<(const A&, const A&) = default; 85253d913SRichard Smith friend bool operator<=(const A&, const A&) = default; 95253d913SRichard Smith friend bool operator>(const A&, const A&) = default; 105253d913SRichard Smith friend bool operator>=(const A&, const A&) = default; 115253d913SRichard Smith }; 12cafc7416SRichard Smith static_assert(A{0} < A{1}); 13cafc7416SRichard Smith static_assert(A{1} < A{1}); // expected-error {{failed}} 14cafc7416SRichard Smith static_assert(A{0} <= A{1}); 15cafc7416SRichard Smith static_assert(A{1} <= A{1}); 16cafc7416SRichard Smith static_assert(A{2} <= A{1}); // expected-error {{failed}} 17cafc7416SRichard Smith static_assert(A{1} > A{0}); 18cafc7416SRichard Smith static_assert(A{1} > A{1}); // expected-error {{failed}} 19cafc7416SRichard Smith static_assert(A{1} >= A{0}); 20cafc7416SRichard Smith static_assert(A{1} >= A{1}); 21cafc7416SRichard Smith static_assert(A{1} >= A{2}); // expected-error {{failed}} 225253d913SRichard Smith 235253d913SRichard Smith struct B { 245253d913SRichard Smith bool operator<=>(B) const = delete; // expected-note 4{{deleted here}} expected-note-re 8{{candidate {{.*}} deleted}} 25*1376c739SNathan James 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}} expected-note{{replace 'default'}} 26*1376c739SNathan James 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}} expected-note{{replace 'default'}} 27*1376c739SNathan James 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}} expected-note{{replace 'default'}} 28*1376c739SNathan James 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}} expected-note{{replace 'default'}} 295253d913SRichard Smith }; 305253d913SRichard Smith bool b1 = B() < B(); // expected-error {{deleted}} 315253d913SRichard Smith bool b2 = B() <= B(); // expected-error {{deleted}} 325253d913SRichard Smith bool b3 = B() > B(); // expected-error {{deleted}} 335253d913SRichard Smith bool b4 = B() >= B(); // expected-error {{deleted}} 345253d913SRichard Smith 355253d913SRichard Smith struct C { 365253d913SRichard Smith friend bool operator<=>(const C&, const C&); 375253d913SRichard Smith friend bool operator<(const C&, const C&); // expected-note {{because this non-rewritten comparison function would be the best match}} 385253d913SRichard Smith 39*1376c739SNathan James bool operator<(const C&) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 405253d913SRichard Smith bool operator>(const C&) const = default; // OK 415253d913SRichard Smith }; 425253d913SRichard Smith } 435253d913SRichard Smith 445253d913SRichard Smith // Under P2002R0, operator!= follows these rules too. 455253d913SRichard Smith namespace NotEqual { 465253d913SRichard Smith struct A { 47cafc7416SRichard Smith int n; operator ==NotEqual::A48cafc7416SRichard Smith constexpr bool operator==(A a) const { return n == a.n; } 495253d913SRichard Smith friend bool operator!=(const A&, const A&) = default; 505253d913SRichard Smith }; 51cafc7416SRichard Smith static_assert(A{1} != A{2}); 52cafc7416SRichard Smith static_assert(A{1} != A{1}); // expected-error {{failed}} 535253d913SRichard Smith 545253d913SRichard Smith struct B { 555253d913SRichard Smith bool operator==(B) const = delete; // expected-note {{deleted here}} expected-note-re 2{{candidate {{.*}} deleted}} 56*1376c739SNathan James 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}} expected-note{{replace 'default'}} 575253d913SRichard Smith }; 585253d913SRichard Smith bool b = B() != B(); // expected-error {{deleted}} 595253d913SRichard Smith 605253d913SRichard Smith struct C { 615253d913SRichard Smith friend bool operator==(const C&, const C&); 625253d913SRichard Smith friend bool operator!=(const C&, const C&); // expected-note {{because this non-rewritten comparison function would be the best match}} 635253d913SRichard Smith 64*1376c739SNathan James bool operator!=(const C&) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 655253d913SRichard Smith }; 665253d913SRichard Smith 675253d913SRichard Smith // Ensure we don't go into an infinite loop diagnosing this: the first function 685253d913SRichard Smith // is deleted because it calls the second function, which is deleted because it 695253d913SRichard Smith // calls the first. 705253d913SRichard Smith struct Evil { 71*1376c739SNathan James friend bool operator!=(const Evil&, const Evil&) = default; // expected-warning {{implicitly deleted}} expected-note {{would be the best match}} expected-note{{replace 'default'}} 72*1376c739SNathan James bool operator!=(const Evil&) const = default; // expected-warning {{implicitly deleted}} expected-note {{would be the best match}} expected-note{{replace 'default'}} 735253d913SRichard Smith }; 745253d913SRichard Smith } 758e0c9e21SRichard Smith 768e0c9e21SRichard Smith namespace Access { 778e0c9e21SRichard Smith class A { 788e0c9e21SRichard Smith int operator<=>(A) const; // expected-note {{private}} 798e0c9e21SRichard Smith }; 808e0c9e21SRichard Smith struct B : A { 81*1376c739SNathan James friend bool operator<(const B&, const B&) = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}} 828e0c9e21SRichard Smith // expected-note@-1 {{defaulted 'operator<' is implicitly deleted because it would invoke a private 'operator<=>' member of 'Access::A'}} 838e0c9e21SRichard Smith }; 848e0c9e21SRichard Smith } 85