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 134 135 136 137 138 139 140 141 142 143 144 145 146
|
// RUN: %clang_cc1 -std=c++2a -verify %s
// This test is for [class.compare.default]p3 as modified and renumbered to p4
// by P2002R0.
namespace std {
struct strong_ordering {
int n;
constexpr operator int() const { return n; }
static const strong_ordering less, equal, greater;
};
constexpr strong_ordering strong_ordering::less = {-1};
constexpr strong_ordering strong_ordering::equal = {0};
constexpr strong_ordering strong_ordering::greater = {1};
}
namespace N {
struct A {
friend constexpr std::strong_ordering operator<=>(const A&, const A&) = default;
};
constexpr bool (*test_a_not_found)(const A&, const A&) = &operator==; // expected-error {{undeclared}}
constexpr bool operator==(const A&, const A&) noexcept;
constexpr bool (*test_a)(const A&, const A&) noexcept = &operator==;
static_assert((*test_a)(A(), A()));
}
struct B1 {
virtual std::strong_ordering operator<=>(const B1&) const = default;
};
bool (B1::*test_b)(const B1&) const = &B1::operator==;
struct C1 : B1 {
// OK, B1::operator== is virtual.
bool operator==(const B1&) const override;
};
struct B2 {
std::strong_ordering operator<=>(const B2&) const = default;
};
struct C2 : B2 {
bool operator==(const B2&) const override; // expected-error {{only virtual member functions}}
};
struct D {
std::strong_ordering operator<=>(const D&) const;
virtual std::strong_ordering operator<=>(const struct E&) const = 0;
};
struct E : D {
// expected-error@+2 {{only virtual member functions}}
// expected-note@+1 {{while declaring the corresponding implicit 'operator==' for this defaulted 'operator<=>'}}
std::strong_ordering operator<=>(const E&) const override = default;
};
struct F {
[[deprecated("oh no")]] std::strong_ordering operator<=>(const F&) const = default; // expected-note 4{{deprecated}}
};
void use_f(F f) {
void(f <=> f); // expected-warning {{oh no}}
void(f < f); // expected-warning {{oh no}}
void(f == f); // expected-warning {{oh no}}
void(f != f); // expected-warning {{oh no}}
}
class G {
// expected-note@+2 {{implicitly declared private here}}
// expected-note-re@+1 {{{{^}}declared private here}}
std::strong_ordering operator<=>(const G&) const = default;
public:
};
void use_g(G g) {
void(g <=> g); // expected-error {{private}}
void(g == g); // expected-error {{private}}
}
struct H {
bool operator==(const H&) const; // expected-note {{here}}
constexpr std::strong_ordering operator<=>(const H&) const { return std::strong_ordering::equal; }
};
struct I {
H h; // expected-note {{used to compare}}
// expected-error@+1 {{defaulted definition of three-way comparison operator cannot be declared constexpr because the corresponding implicit 'operator==' invokes a non-constexpr comparison function}}
constexpr std::strong_ordering operator<=>(const I&) const = default;
};
struct J {
std::strong_ordering operator<=>(const J&) const & = default; // expected-note {{candidate function (the implicit 'operator==' for this 'operator<=>)'}}
friend std::strong_ordering operator<=>(const J&, const J&) = default; // expected-note {{candidate function (the implicit 'operator==' for this 'operator<=>)'}}
};
void use_j(J j) {
void(j == j); // expected-error {{ambiguous}}
}
namespace DeleteAfterFirstDecl {
bool operator==(const struct Q&, const struct Q&);
struct Q {
struct X {
friend std::strong_ordering operator<=>(const X&, const X&);
} x; // expected-note {{no viable comparison}}
// expected-error@+1 {{defaulting the corresponding implicit 'operator==' for this defaulted 'operator<=>' would delete it after its first declaration}}
friend std::strong_ordering operator<=>(const Q&, const Q&) = default;
};
}
// Note, substitution here results in the second parameter of 'operator=='
// referring to the first parameter of 'operator==', not to the first parameter
// of 'operator<=>'.
// FIXME: Find a case where this matters (attribute enable_if?).
struct K {
friend std::strong_ordering operator<=>(const K &k, decltype(k)) = default;
};
bool test_k = K() == K();
namespace NoInjectionIfOperatorEqualsDeclared {
struct A {
void operator==(int); // expected-note 2{{not viable}}
std::strong_ordering operator<=>(const A&) const = default;
};
bool test_a = A() == A(); // expected-error {{invalid operands}}
struct B {
friend void operator==(int, struct Q); // expected-note 2{{not viable}}
std::strong_ordering operator<=>(const B&) const = default;
};
bool test_b = B() == B(); // expected-error {{invalid operands}}
struct C {
void operator==(int); // expected-note 2{{not viable}}
friend std::strong_ordering operator<=>(const C&, const C&) = default;
};
bool test_c = C() == C(); // expected-error {{invalid operands}}
struct D {
void f() {
void operator==(const D&, int);
}
struct X {
friend void operator==(const D&, int);
};
friend std::strong_ordering operator<=>(const D&, const D&) = default;
};
bool test_d = D() == D();
}
|