1 // RUN: %clang_cc1 -std=c++2a -verify %s 2 3 struct A {}; 4 struct B { bool operator==(B) const; }; 5 struct C { int operator==(C) const; }; 6 struct D { 7 // expected-note@+2 {{candidate function not viable: 'this' argument has type 'const}} 8 // expected-note@+1 {{candidate function (with reversed parameter order) not viable: 1st argument ('const}} 9 bool operator==(D); 10 }; 11 struct E { 12 E(const E &) = delete; // expected-note {{deleted}} 13 int operator==(E) const; // expected-note {{passing}} 14 }; 15 struct F { void operator==(F) const; }; 16 struct G { bool operator==(G) const = delete; }; // expected-note {{deleted here}} 17 18 struct H1 { 19 bool operator==(const H1 &) const = default; 20 bool operator<(const H1 &) const = default; // expected-warning {{implicitly deleted}} 21 // expected-note@-1 {{because there is no viable three-way comparison function for 'H1'}} 22 void (*x)(); 23 }; 24 struct H2 { 25 bool operator==(const H2 &) const = default; 26 bool operator<(const H2 &) const = default; // expected-warning {{implicitly deleted}} 27 // expected-note@-1 {{because there is no viable three-way comparison function for 'H2'}} 28 void (H2::*x)(); 29 }; 30 struct H3 { 31 bool operator==(const H3 &) const = default; 32 bool operator<(const H3 &) const = default; // expected-warning {{implicitly deleted}} 33 // expected-note@-1 {{because there is no viable three-way comparison function for 'H3'}} 34 int H3::*x; 35 }; 36 37 template<typename T> struct X { 38 X(); 39 bool operator==(const X&) const = default; // #x expected-note 4{{deleted here}} 40 T t; // expected-note 3{{because there is no viable three-way comparison function for member 't'}} 41 // expected-note@-1 {{because it would invoke a deleted comparison function for member 't'}} 42 }; 43 44 struct Mutable { 45 bool operator==(const Mutable&) const = default; 46 mutable D d; 47 }; 48 49 void test() { 50 void(X<A>() == X<A>()); // expected-error {{cannot be compared because its 'operator==' is implicitly deleted}} 51 void(X<B>() == X<B>()); 52 void(X<C>() == X<C>()); 53 void(X<D>() == X<D>()); // expected-error {{cannot be compared because its 'operator==' is implicitly deleted}} 54 void(Mutable() == Mutable()); 55 56 // FIXME: We would benefit from a note identifying the member of 'X' we were comparing here and below. 57 // expected-error@#x {{call to deleted constructor of 'E'}} 58 void(X<E>() == X<E>()); // expected-note {{in defaulted equality comparison operator for 'X<E>' first required here}} 59 60 // FIXME: We would benefit from a note pointing at the selected 'operator==' here. 61 // expected-error@#x {{value of type 'void' is not contextually convertible to 'bool'}} 62 void(X<F>() == X<F>()); // expected-note {{in defaulted equality comparison operator for 'X<F>' first required here}} 63 64 void(X<G>() == X<G>()); // expected-error {{cannot be compared because its 'operator==' is implicitly deleted}} 65 66 void(X<A[3]>() == X<A[3]>()); // expected-error {{cannot be compared because its 'operator==' is implicitly deleted}} 67 void(X<B[3]>() == X<B[3]>()); 68 } 69 70 namespace Access { 71 class A { 72 bool operator==(const A &) const; // expected-note 2{{implicitly declared private here}} 73 }; 74 struct B : A { // expected-note 2{{because it would invoke a private 'operator==' to compare base class 'A'}} 75 bool operator==(const B &) const = default; // expected-warning {{deleted}} 76 friend bool operator==(const B &, const B &) = default; // expected-warning {{deleted}} 77 }; 78 79 class C { 80 protected: 81 bool operator==(const C &) const; // expected-note 2{{declared protected here}} 82 }; 83 struct D : C { 84 bool operator==(const D &) const = default; 85 friend bool operator==(const D &, const D&) = default; 86 }; 87 struct E { 88 C c; // expected-note 2{{because it would invoke a protected 'operator==' member of 'Access::C' to compare member 'c'}} 89 bool operator==(const E &) const = default; // expected-warning {{deleted}} 90 friend bool operator==(const E &, const E &) = default; // expected-warning {{deleted}} 91 }; 92 93 struct F : C { 94 using C::operator==; 95 }; 96 struct G : F { 97 bool operator==(const G&) const = default; 98 friend bool operator==(const G&, const G&) = default; 99 }; 100 101 struct H : C { 102 private: 103 using C::operator==; // expected-note 2{{declared private here}} 104 }; 105 struct I : H { // expected-note 2{{private 'operator==' to compare base class 'H'}} 106 bool operator==(const I&) const = default; // expected-warning {{deleted}} 107 friend bool operator==(const I&, const I&) = default; // expected-warning {{deleted}} 108 }; 109 110 class J { 111 bool operator==(const J&) const; 112 friend class K; 113 }; 114 class K { 115 J j; 116 bool operator==(const K&) const = default; 117 friend bool operator==(const K&, const K&) = default; 118 }; 119 120 struct X { 121 bool operator==(const X&) const; // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}} 122 }; 123 struct Y : private X { // expected-note {{private}} 124 using X::operator==; 125 }; 126 struct Z : Y { 127 // Note: this function is not deleted. The selected operator== is 128 // accessible. But the derived-to-base conversion involves an inaccessible 129 // base class, which we don't check for until we define the function. 130 bool operator==(const Z&) const = default; // expected-error {{cannot cast 'const Access::Y' to its private base class 'const Access::X'}} expected-warning {{ambiguous}} 131 }; 132 bool z = Z() == Z(); // expected-note {{first required here}} 133 } 134