15253d913SRichard Smith // RUN: %clang_cc1 -std=c++2a -verify %s
25253d913SRichard Smith
35253d913SRichard Smith struct A {};
45253d913SRichard Smith struct B { bool operator==(B) const; };
55253d913SRichard Smith struct C { int operator==(C) const; };
65253d913SRichard Smith struct D {
75253d913SRichard Smith // expected-note@+2 {{candidate function not viable: 'this' argument has type 'const}}
85253d913SRichard Smith // expected-note@+1 {{candidate function (with reversed parameter order) not viable: 1st argument ('const}}
95253d913SRichard Smith bool operator==(D);
105253d913SRichard Smith };
11cafc7416SRichard Smith struct E {
12cafc7416SRichard Smith E(const E &) = delete; // expected-note {{deleted}}
13cafc7416SRichard Smith int operator==(E) const; // expected-note {{passing}}
14cafc7416SRichard Smith };
155253d913SRichard Smith struct F { void operator==(F) const; };
165253d913SRichard Smith struct G { bool operator==(G) const = delete; }; // expected-note {{deleted here}}
175253d913SRichard Smith
184a8530fcSMatheus Izvekov struct H1 {
194a8530fcSMatheus Izvekov bool operator==(const H1 &) const = default;
201376c739SNathan James bool operator<(const H1 &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}}
21c9fd92d5SMatheus Izvekov // expected-note@-1 {{because there is no viable three-way comparison function for 'H1'}}
224a8530fcSMatheus Izvekov void (*x)();
234a8530fcSMatheus Izvekov };
244a8530fcSMatheus Izvekov struct H2 {
254a8530fcSMatheus Izvekov bool operator==(const H2 &) const = default;
261376c739SNathan James bool operator<(const H2 &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}}
27c9fd92d5SMatheus Izvekov // expected-note@-1 {{because there is no viable three-way comparison function for 'H2'}}
284a8530fcSMatheus Izvekov void (H2::*x)();
294a8530fcSMatheus Izvekov };
304a8530fcSMatheus Izvekov struct H3 {
314a8530fcSMatheus Izvekov bool operator==(const H3 &) const = default;
321376c739SNathan James bool operator<(const H3 &) const = default; // expected-warning {{implicitly deleted}} expected-note{{replace 'default'}}
33c9fd92d5SMatheus Izvekov // expected-note@-1 {{because there is no viable three-way comparison function for 'H3'}}
344a8530fcSMatheus Izvekov int H3::*x;
354a8530fcSMatheus Izvekov };
364a8530fcSMatheus Izvekov
375253d913SRichard Smith template<typename T> struct X {
385253d913SRichard Smith X();
39e6e6e34bSRichard Smith bool operator==(const X&) const = default; // #x expected-note 4{{deleted here}}
40*02bb2beeSAmirreza Ashouri T t; // expected-note 3{{because there is no viable 'operator==' for member 't'}}
415253d913SRichard Smith // expected-note@-1 {{because it would invoke a deleted comparison function for member 't'}}
425253d913SRichard Smith };
435253d913SRichard Smith
445253d913SRichard Smith struct Mutable {
455253d913SRichard Smith bool operator==(const Mutable&) const = default;
465253d913SRichard Smith mutable D d;
475253d913SRichard Smith };
485253d913SRichard Smith
test()495253d913SRichard Smith void test() {
505253d913SRichard Smith void(X<A>() == X<A>()); // expected-error {{cannot be compared because its 'operator==' is implicitly deleted}}
515253d913SRichard Smith void(X<B>() == X<B>());
525253d913SRichard Smith void(X<C>() == X<C>());
535253d913SRichard Smith void(X<D>() == X<D>()); // expected-error {{cannot be compared because its 'operator==' is implicitly deleted}}
545253d913SRichard Smith void(Mutable() == Mutable());
555253d913SRichard Smith
56cafc7416SRichard Smith // FIXME: We would benefit from a note identifying the member of 'X' we were comparing here and below.
57cafc7416SRichard Smith // expected-error@#x {{call to deleted constructor of 'E'}}
58cafc7416SRichard Smith void(X<E>() == X<E>()); // expected-note {{in defaulted equality comparison operator for 'X<E>' first required here}}
59cafc7416SRichard Smith
60cafc7416SRichard Smith // FIXME: We would benefit from a note pointing at the selected 'operator==' here.
61cafc7416SRichard Smith // expected-error@#x {{value of type 'void' is not contextually convertible to 'bool'}}
62cafc7416SRichard Smith void(X<F>() == X<F>()); // expected-note {{in defaulted equality comparison operator for 'X<F>' first required here}}
635253d913SRichard Smith
645253d913SRichard Smith void(X<G>() == X<G>()); // expected-error {{cannot be compared because its 'operator==' is implicitly deleted}}
65e6e6e34bSRichard Smith
66e6e6e34bSRichard Smith void(X<A[3]>() == X<A[3]>()); // expected-error {{cannot be compared because its 'operator==' is implicitly deleted}}
67e6e6e34bSRichard Smith void(X<B[3]>() == X<B[3]>());
685253d913SRichard Smith }
698e0c9e21SRichard Smith
708e0c9e21SRichard Smith namespace Access {
718e0c9e21SRichard Smith class A {
728e0c9e21SRichard Smith bool operator==(const A &) const; // expected-note 2{{implicitly declared private here}}
738e0c9e21SRichard Smith };
748e0c9e21SRichard Smith struct B : A { // expected-note 2{{because it would invoke a private 'operator==' to compare base class 'A'}}
751376c739SNathan James bool operator==(const B &) const = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
761376c739SNathan James friend bool operator==(const B &, const B &) = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
778e0c9e21SRichard Smith };
788e0c9e21SRichard Smith
798e0c9e21SRichard Smith class C {
808e0c9e21SRichard Smith protected:
818e0c9e21SRichard Smith bool operator==(const C &) const; // expected-note 2{{declared protected here}}
828e0c9e21SRichard Smith };
838e0c9e21SRichard Smith struct D : C {
848e0c9e21SRichard Smith bool operator==(const D &) const = default;
858e0c9e21SRichard Smith friend bool operator==(const D &, const D&) = default;
868e0c9e21SRichard Smith };
878e0c9e21SRichard Smith struct E {
888e0c9e21SRichard Smith C c; // expected-note 2{{because it would invoke a protected 'operator==' member of 'Access::C' to compare member 'c'}}
891376c739SNathan James bool operator==(const E &) const = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
901376c739SNathan James friend bool operator==(const E &, const E &) = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
918e0c9e21SRichard Smith };
928e0c9e21SRichard Smith
938e0c9e21SRichard Smith struct F : C {
948e0c9e21SRichard Smith using C::operator==;
958e0c9e21SRichard Smith };
968e0c9e21SRichard Smith struct G : F {
978e0c9e21SRichard Smith bool operator==(const G&) const = default;
988e0c9e21SRichard Smith friend bool operator==(const G&, const G&) = default;
998e0c9e21SRichard Smith };
1008e0c9e21SRichard Smith
1018e0c9e21SRichard Smith struct H : C {
1028e0c9e21SRichard Smith private:
1038e0c9e21SRichard Smith using C::operator==; // expected-note 2{{declared private here}}
1048e0c9e21SRichard Smith };
1058e0c9e21SRichard Smith struct I : H { // expected-note 2{{private 'operator==' to compare base class 'H'}}
1061376c739SNathan James bool operator==(const I&) const = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
1071376c739SNathan James friend bool operator==(const I&, const I&) = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
1088e0c9e21SRichard Smith };
1098e0c9e21SRichard Smith
1108e0c9e21SRichard Smith class J {
1118e0c9e21SRichard Smith bool operator==(const J&) const;
1128e0c9e21SRichard Smith friend class K;
1138e0c9e21SRichard Smith };
1148e0c9e21SRichard Smith class K {
1158e0c9e21SRichard Smith J j;
1168e0c9e21SRichard Smith bool operator==(const K&) const = default;
1178e0c9e21SRichard Smith friend bool operator==(const K&, const K&) = default;
1188e0c9e21SRichard Smith };
1198e0c9e21SRichard Smith
1208e0c9e21SRichard Smith struct X {
1218e0c9e21SRichard Smith bool operator==(const X&) const; // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
1228e0c9e21SRichard Smith };
1238e0c9e21SRichard Smith struct Y : private X { // expected-note {{private}}
1248e0c9e21SRichard Smith using X::operator==;
1258e0c9e21SRichard Smith };
1268e0c9e21SRichard Smith struct Z : Y {
1278e0c9e21SRichard Smith // Note: this function is not deleted. The selected operator== is
1288e0c9e21SRichard Smith // accessible. But the derived-to-base conversion involves an inaccessible
1298e0c9e21SRichard Smith // base class, which we don't check for until we define the function.
13015f3cd6bSMatheus Izvekov bool operator==(const Z&) const = default; // expected-error {{cannot cast 'const Y' to its private base class 'const X'}} expected-warning {{ambiguous}}
1318e0c9e21SRichard Smith };
1328e0c9e21SRichard Smith bool z = Z() == Z(); // expected-note {{first required here}}
1338e0c9e21SRichard Smith }
134