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