1 // RUN: %clang_cc1 -std=c++2a -verify %s
2 // RUN: %clang_cc1 -std=c++2a -verify %s -DDEFINE_FIRST
4 // As modified by P2002R0:
5 // The exception specification for a comparison operator function (12.6.2)
6 // without a noexcept-specifier that is defaulted on its first declaration is
7 // potentially-throwing if and only if any expression in the implicit
8 // definition is potentially-throwing.
10 #define CAT2(a, b) a ## b
11 #define CAT(a, b) CAT2(a, b)
14 #define DEF(x) auto CAT(a, __LINE__) = x
20 struct strong_ordering
{
22 static const strong_ordering equal
, less
, greater
;
24 constexpr strong_ordering
strong_ordering::equal
{0},
25 strong_ordering::less
{-1}, strong_ordering::greater
{1};
26 bool operator!=(std::strong_ordering o
, int n
) noexcept
;
31 bool operator==(const A
&) const = default;
34 static_assert(noexcept(A() == A()));
37 bool operator==(const B
&) const;
41 bool operator==(const C
&) const = default;
44 static_assert(!noexcept(C() == C()));
46 // Ensure we do not trigger odr-use from exception specification computation.
47 template<typename T
> struct D
{
48 bool operator==(const D
&) const {
49 typename
T::error error
; // expected-error {{no type}}
54 bool operator==(const E
&) const = default;
56 static_assert(!noexcept(E() == E()));
58 // (but we do when defining the function).
61 bool operator==(const F
&) const = default; // expected-note {{in instantiation}}
63 bool equal
= F() == F();
64 static_assert(!noexcept(F() == F()));
69 friend std::strong_ordering
operator<=>(X
, X
);
72 friend std::strong_ordering
operator<=>(Y
, Y
) = default;
75 static_assert(!noexcept(Y() <=> Y()));
77 struct ThrowingCmpCat
{
78 ThrowingCmpCat(std::strong_ordering
);
79 operator std::strong_ordering();
81 bool operator!=(ThrowingCmpCat o
, int n
) noexcept
;
84 friend ThrowingCmpCat
operator<=>(A
, A
) noexcept
;
89 std::strong_ordering
operator<=>(const B
&) const = default;
92 static_assert(!noexcept(B() <=> B()));
96 ThrowingCmpCat
operator<=>(const C
&) const = default;
99 static_assert(!noexcept(C() <=> C()));
103 std::strong_ordering
operator<=>(const D
&) const = default;
106 static_assert(noexcept(D() <=> D()));
109 struct ThrowingCmpCat2
{
110 ThrowingCmpCat2(std::strong_ordering
) noexcept
;
111 operator std::strong_ordering() noexcept
;
113 bool operator!=(ThrowingCmpCat2 o
, int n
);
116 friend ThrowingCmpCat2
operator<=>(E
, E
) noexcept
;
121 std::strong_ordering
operator<=>(const F
&) const = default;
124 static_assert(noexcept(F() <=> F()));
128 ThrowingCmpCat2
operator<=>(const G
&) const = default;
131 static_assert(!noexcept(G() <=> G()));
136 friend bool operator==(A
, A
) noexcept
;
137 friend bool operator<(A
, A
) noexcept
;
141 friend std::strong_ordering
operator<=>(B
, B
) = default;
143 std::strong_ordering
operator<=>(B
, B
) noexcept
;
146 friend bool operator==(C
, C
);
147 friend bool operator<(C
, C
) noexcept
;
151 friend std::strong_ordering
operator<=>(D
, D
) = default; // expected-note {{previous}}
153 std::strong_ordering
operator<=>(D
, D
) noexcept
; // expected-error {{does not match}}
156 friend bool operator==(E
, E
) noexcept
;
157 friend bool operator<(E
, E
);
161 friend std::strong_ordering
operator<=>(F
, F
) = default; // expected-note {{previous}}
163 std::strong_ordering
operator<=>(F
, F
) noexcept
; // expected-error {{does not match}}
166 namespace Secondary
{
168 friend bool operator==(A
, A
);
169 friend bool operator!=(A
, A
) = default; // expected-note {{previous}}
171 friend int operator<=>(A
, A
);
172 friend bool operator<(A
, A
) = default; // expected-note {{previous}}
173 friend bool operator<=(A
, A
) = default; // expected-note {{previous}}
174 friend bool operator>(A
, A
) = default; // expected-note {{previous}}
175 friend bool operator>=(A
, A
) = default; // expected-note {{previous}}
177 bool operator!=(A
, A
) noexcept
; // expected-error {{does not match}}
178 bool operator<(A
, A
) noexcept
; // expected-error {{does not match}}
179 bool operator<=(A
, A
) noexcept
; // expected-error {{does not match}}
180 bool operator>(A
, A
) noexcept
; // expected-error {{does not match}}
181 bool operator>=(A
, A
) noexcept
; // expected-error {{does not match}}
184 friend bool operator==(B
, B
) noexcept
;
185 friend bool operator!=(B
, B
) = default;
187 friend int operator<=>(B
, B
) noexcept
;
188 friend bool operator<(B
, B
) = default;
189 friend bool operator<=(B
, B
) = default;
190 friend bool operator>(B
, B
) = default;
191 friend bool operator>=(B
, B
) = default;
193 bool operator!=(B
, B
) noexcept
;
194 bool operator<(B
, B
) noexcept
;
195 bool operator<=(B
, B
) noexcept
;
196 bool operator>(B
, B
) noexcept
;
197 bool operator>=(B
, B
) noexcept
;
200 // Check that we attempt to define a defaulted comparison before trying to
201 // compute its exception specification.
202 namespace DefineBeforeComputingExceptionSpec
{
203 template<int> struct A
{
205 A(const A
&) = delete; // expected-note 3{{here}}
206 friend bool operator==(A
, A
); // expected-note 3{{passing}}
207 friend bool operator!=(const A
&, const A
&) = default; // expected-error 3{{call to deleted constructor}}
210 bool a0
= A
<0>() != A
<0>(); // expected-note {{in defaulted equality comparison operator}}
211 bool a1
= operator!=(A
<1>(), A
<1>()); // expected-note {{in defaulted equality comparison operator}}
213 template struct A
<2>;
214 bool operator!=(const A
<2>&, const A
<2>&) noexcept
; // expected-note {{in evaluation of exception specification}}
216 template<int> struct B
{
218 B(const B
&) = delete; // expected-note 3{{here}}
219 friend bool operator==(B
, B
); // expected-note 3{{passing}}
220 bool operator!=(const B
&) const = default; // expected-error 3{{call to deleted constructor}}
223 bool b0
= B
<0>() != B
<0>(); // expected-note {{in defaulted equality comparison operator}}
224 bool b1
= B
<1>().operator!=(B
<1>()); // expected-note {{in defaulted equality comparison operator}}
225 int b2
= sizeof(&B
<2>::operator!=); // expected-note {{in evaluation of exception specification}}