p4.cpp
4.94 KB
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();
}