1 // RUN: %clang_cc1 -std=c++2a -verify %s
2 // RUN: %clang_cc1 -std=c++2a -verify -Wall -DNO_ERRORS %s
6 // the built-in candidates include all of the candidate operator fnuctions
7 // [...] that, compared to the given operator
9 // - do not have the same parameter-type-list as any non-member candidate
13 // Suppress both builtin operator<=>(E, E) and operator<(E, E).
14 void operator<=>(E
, E
); // expected-note {{while rewriting}}
15 bool cmp
= e
< e
; // expected-error {{invalid operands to binary expression ('void' and 'int')}}
17 // None of the other bullets have anything to test here. In principle we
18 // need to suppress both builtin operator@(A, B) and operator@(B, A) when we
19 // see a user-declared reversible operator@(A, B), and we do, but that's
20 // untestable because the only built-in reversible candidates are
21 // operator<=>(E, E) and operator==(E, E) for E an enumeration type, and
22 // those are both symmetric anyway.
26 // The rewritten candidate set is determined as follows:
28 template<int> struct X
{};
33 int operator<=>(X
<2>) = delete; // #1member
34 bool operator==(X
<2>) = delete; // #2member
38 // - For the relational operators, the rewritten candidates include all
39 // non-rewritten candidates for the expression x <=> y.
40 int operator<=>(X
<1>, X
<2>) = delete; // #1
42 // expected-note@#1 5{{candidate function has been explicitly deleted}}
43 // expected-note@#1 5{{candidate function (with reversed parameter order) not viable: no known conversion from 'X<1>' to 'X<2>' for 1st argument}}
44 bool lt
= x1
< x2
; // expected-error {{selected deleted operator '<=>'}}
45 bool le
= x1
<= x2
; // expected-error {{selected deleted operator '<=>'}}
46 bool gt
= x1
> x2
; // expected-error {{selected deleted operator '<=>'}}
47 bool ge
= x1
>= x2
; // expected-error {{selected deleted operator '<=>'}}
48 bool cmp
= x1
<=> x2
; // expected-error {{selected deleted operator '<=>'}}
50 // expected-note@#1member 5{{candidate function has been explicitly deleted}}
51 // expected-note@#1 5{{candidate function not viable: no known conversion from 'Y' to 'X<1>' for 1st argument}}
52 // expected-note@#1 5{{candidate function (with reversed parameter order) not viable: no known conversion from 'Y' to 'X<2>' for 1st argument}}
53 bool mem_lt
= y
< x2
; // expected-error {{selected deleted operator '<=>'}}
54 bool mem_le
= y
<= x2
; // expected-error {{selected deleted operator '<=>'}}
55 bool mem_gt
= y
> x2
; // expected-error {{selected deleted operator '<=>'}}
56 bool mem_ge
= y
>= x2
; // expected-error {{selected deleted operator '<=>'}}
57 bool mem_cmp
= y
<=> x2
; // expected-error {{selected deleted operator '<=>'}}
59 // - For the relational and three-way comparison operators, the rewritten
60 // candidates also include a synthesized candidate, with the order of the
61 // two parameters reversed, for each non-rewritten candidate for the
62 // expression y <=> x.
64 // expected-note@#1 5{{candidate function (with reversed parameter order) has been explicitly deleted}}
65 // expected-note@#1 5{{candidate function not viable: no known conversion from 'X<2>' to 'X<1>' for 1st argument}}
66 bool rlt
= x2
< x1
; // expected-error {{selected deleted operator '<=>'}}
67 bool rle
= x2
<= x1
; // expected-error {{selected deleted operator '<=>'}}
68 bool rgt
= x2
> x1
; // expected-error {{selected deleted operator '<=>'}}
69 bool rge
= x2
>= x1
; // expected-error {{selected deleted operator '<=>'}}
70 bool rcmp
= x2
<=> x1
; // expected-error {{selected deleted operator '<=>'}}
72 // expected-note@#1member 5{{candidate function (with reversed parameter order) has been explicitly deleted}}
73 // expected-note@#1 5{{candidate function not viable: no known conversion from 'X<2>' to 'X<1>' for 1st argument}}
74 // expected-note@#1 5{{candidate function (with reversed parameter order) not viable: no known conversion from 'Y' to 'X<1>' for 2nd argument}}
75 bool mem_rlt
= x2
< y
; // expected-error {{selected deleted operator '<=>'}}
76 bool mem_rle
= x2
<= y
; // expected-error {{selected deleted operator '<=>'}}
77 bool mem_rgt
= x2
> y
; // expected-error {{selected deleted operator '<=>'}}
78 bool mem_rge
= x2
>= y
; // expected-error {{selected deleted operator '<=>'}}
79 bool mem_rcmp
= x2
<=> y
; // expected-error {{selected deleted operator '<=>'}}
81 // For the != operator, the rewritten candidates include all non-rewritten
82 // candidates for the expression x == y
83 int operator==(X
<1>, X
<2>) = delete; // #2
85 // expected-note@#2 2{{candidate function has been explicitly deleted}}
86 // expected-note@#2 2{{candidate function (with reversed parameter order) not viable: no known conversion from 'X<1>' to 'X<2>' for 1st argument}}
87 bool eq
= x1
== x2
; // expected-error {{selected deleted operator '=='}}
88 bool ne
= x1
!= x2
; // expected-error {{selected deleted operator '=='}}
90 // expected-note@#2member 2{{candidate function has been explicitly deleted}}
91 // expected-note@#2 2{{candidate function not viable: no known conversion from 'Y' to 'X<1>' for 1st argument}}
92 // expected-note@#2 2{{candidate function (with reversed parameter order) not viable: no known conversion from 'Y' to 'X<2>' for 1st argument}}
93 bool mem_eq
= y
== x2
; // expected-error {{selected deleted operator '=='}}
94 bool mem_ne
= y
!= x2
; // expected-error {{selected deleted operator '=='}}
96 // For the equality operators, the rewritten candidates also include a
97 // synthesized candidate, with the order of the two parameters reversed, for
98 // each non-rewritten candidate for the expression y == x
100 // expected-note@#2 2{{candidate function (with reversed parameter order) has been explicitly deleted}}
101 // expected-note@#2 2{{candidate function not viable: no known conversion from 'X<2>' to 'X<1>' for 1st argument}}
102 bool req
= x2
== x1
; // expected-error {{selected deleted operator '=='}}
103 bool rne
= x2
!= x1
; // expected-error {{selected deleted operator '=='}}
105 // expected-note@#2member 2{{candidate function (with reversed parameter order) has been explicitly deleted}}
106 // expected-note@#2 2{{candidate function not viable: no known conversion from 'X<2>' to 'X<1>' for 1st argument}}
107 // expected-note@#2 2{{candidate function (with reversed parameter order) not viable: no known conversion from 'Y' to 'X<1>' for 2nd argument}}
108 bool mem_req
= x2
== y
; // expected-error {{selected deleted operator '=='}}
109 bool mem_rne
= x2
!= y
; // expected-error {{selected deleted operator '=='}}
111 // For all other operators, the rewritten candidate set is empty.
112 X
<3> operator+(X
<1>, X
<2>) = delete; // expected-note {{no known conversion from 'X<2>' to 'X<1>'}}
113 X
<3> reversed_add
= x2
+ x1
; // expected-error {{invalid operands}}
119 bool operator==(type lhs
, int rhs
) {
124 bool b1
= ADL::type() == 0;
125 bool b2
= 0 == ADL::type();
129 // Problem cases prior to P2468R2 but now intentionally rejected.
130 struct SymmetricNonConst
{
131 bool operator==(const SymmetricNonConst
&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
132 // expected-note@-1 {{mark 'operator==' as const or add a matching 'operator!=' to resolve the ambiguity}}
134 bool cmp_non_const
= SymmetricNonConst() == SymmetricNonConst(); // expected-warning {{ambiguous}}
136 struct SymmetricConst
{
137 bool operator==(const SymmetricConst
&) const;
139 bool cmp_const
= SymmetricConst() == SymmetricConst();
141 struct SymmetricNonConstWithoutConstRef
{
142 bool operator==(SymmetricNonConstWithoutConstRef
);
144 bool cmp_non_const_wo_ref
= SymmetricNonConstWithoutConstRef() == SymmetricNonConstWithoutConstRef();
147 virtual bool operator==(const B
&) const;
150 bool operator==(const B
&) const override
; // expected-note {{operator}}
152 bool cmp_base_derived
= D() == D(); // expected-warning {{ambiguous}}
154 // Reversed "3" not used because we find "2".
155 // Rewrite != from "3" but warn that "chosen rewritten candidate must return cv-bool".
156 using UBool
= signed char;
158 virtual UBool
operator==(const ICUBase
&) const; // 1.
159 UBool
operator!=(const ICUBase
&arg
) const { return !operator==(arg
); } // 2.
161 struct ICUDerived
: ICUBase
{
163 UBool
operator==(const ICUBase
&) const override
; // expected-note {{declared here}}
165 bool cmp_icu
= ICUDerived() != ICUDerived(); // expected-warning {{ISO C++20 requires return type of selected 'operator==' function for rewritten '!=' comparison to be 'bool', not 'UBool' (aka 'signed char')}}
166 // Accepted by P2468R2.
169 bool operator==(const S
&) { return true; }
170 bool operator!=(const S
&) { return false; }
172 bool ts
= S
{} != S
{};
174 template<typename T
> struct CRTPBase
{
175 bool operator==(const T
&) const;
176 bool operator!=(const T
&) const;
178 struct CRTP
: CRTPBase
<CRTP
> {};
179 bool cmp_crtp
= CRTP() == CRTP();
180 bool cmp_crtp2
= CRTP() != CRTP();
181 // https://github.com/llvm/llvm-project/issues/57711
182 namespace issue_57711
{
184 bool compare(T l
, T r
)
185 requires requires
{ l
== r
; } {
190 compare(CRTP(), CRTP()); // previously this was a hard error (due to SFINAE failure).
195 struct GenericIterator
{
196 using ConstIterator
= GenericIterator
<true>;
197 using NonConstIterator
= GenericIterator
<false>;
198 GenericIterator() = default;
199 GenericIterator(const NonConstIterator
&);
201 bool operator==(ConstIterator
) const;
202 bool operator!=(ConstIterator
) const;
204 using Iterator
= GenericIterator
<false>;
206 bool biter
= Iterator
{} == Iterator
{};
208 // Intentionally rejected by P2468R2
212 bool operator==(const ImplicitInt
&) const; // expected-note {{candidate function (with reversed parameter order)}}
213 operator int*() const;
215 bool implicit_int
= nullptr != ImplicitInt
{}; // expected-error {{use of overloaded operator '!=' is ambiguous (with operand types 'std::nullptr_t' and 'ImplicitInt')}}
216 // expected-note@-1 4 {{built-in candidate operator!=}}
218 // https://eel.is/c++draft/over.match.oper#example-2
221 template<typename T
> bool operator==(A
, T
); // 1. expected-note {{candidate function template not viable: no known conversion from 'int' to 'A' for 1st argument}}
222 bool a1
= 0 == A(); // OK, calls reversed 1
223 template<typename T
> bool operator!=(A
, T
);
224 bool a2
= 0 == A(); // expected-error {{invalid operands to binary expression ('int' and 'A')}}
227 bool operator==(const B
&); // 2
228 // expected-note@-1 {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
233 bool operator!=(const B
&); // 3
235 bool c1
= B() == C(); // OK, calls 2; reversed 2 is not a candidate because search for operator!= in C finds 3
236 bool c2
= C() == B(); // Search for operator!= inside B never finds 3. expected-warning {{ISO C++20 considers use of overloaded operator '==' (with operand types 'C' and 'B') to be ambiguous despite there being a unique best viable function}}
239 template<typename T
> bool operator==(D
, T
); // 4
241 template<typename T
> bool operator!=(D
, T
); // 5
243 bool d1
= 0 == D(); // OK, calls reversed 4; 5 does not forbid 4 as a rewrite target as "search" does not look inside inline namespaces.
244 } // namespace example
246 namespace template_tests
{
247 namespace template_head_does_not_match
{
249 template<typename T
, class U
= int> bool operator==(A
, T
);
250 template <class T
> bool operator!=(A
, T
);
251 bool x
= 0 == A(); // Ok. Use rewritten candidate.
254 namespace template_with_different_param_name_are_equivalent
{
256 template<typename T
> bool operator==(A
, T
); // expected-note {{candidate function template not viable: no known conversion from 'int' to 'A' for 1st argument}}
257 template <typename U
> bool operator!=(A
, U
);
258 bool x
= 0 == A(); // expected-error {{invalid operands to binary expression ('int' and 'A')}}
261 namespace template_and_non_template
{
263 template<typename T
> bool operator==(const T
&);
264 // expected-note@-1{{mark 'operator==' as const or add a matching 'operator!=' to resolve the ambiguity}}
265 // expected-note@-2{{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
267 bool a
= A() == A(); // expected-warning {{ambiguous despite there being a unique best viable function}}
270 template<typename T
> bool operator==(const T
&) const;
271 bool operator!=(const B
&);
273 bool b
= B() == B(); // ok. No rewrite due to const.
276 template <class T
=int>
277 bool operator==(C
, int);
278 bool operator!=(C
, int);
279 bool c
= 0 == C(); // Ok. Use rewritten candidate as the non-template 'operator!=' does not correspond to template 'operator=='
283 namespace using_decls
{
286 bool operator==(C
, int); // expected-note {{candidate function not viable: no known conversion from 'int' to 'C' for 1st argument}}
287 bool a
= 0 == C(); // Ok. Use rewritten candidate.
288 namespace other_ns
{ bool operator!=(C
, int); }
289 bool b
= 0 == C(); // Ok. Use rewritten candidate.
290 using other_ns::operator!=;
291 bool c
= 0 == C(); // Rewrite not possible. expected-error {{invalid operands to binary expression ('int' and 'C')}}
293 namespace templated
{
296 bool operator==(C
, T
); // expected-note {{candidate function template not viable: no known conversion from 'int' to 'C' for 1st argument}}
297 bool a
= 0 == C(); // Ok. Use rewritten candidate.
298 namespace other_ns
{ template<typename T
> bool operator!=(C
, T
); }
299 bool b
= 0 == C(); // Ok. Use rewritten candidate.
300 using other_ns::operator!=;
301 bool c
= 0 == C(); // Rewrite not possible. expected-error {{invalid operands to binary expression ('int' and 'C')}}
305 // FIXME(GH58185): Match requires clause.
306 namespace match_requires_clause
{
309 bool operator==(int) requires (x
==1); // 1.
310 bool operator!=(int) requires (x
==2); // 2.
312 int a1
= 0 == A
<1>(); // Should not find 2 as the requires clause does not match. \
313 // expected-error {{invalid operands to binary expression ('int' and 'A<1>')}}
316 namespace static_operators
{
319 bool operator ==(X
const&); // expected-note {{ambiguity is between a regular call}}
320 // expected-note@-1 {{mark 'operator==' as const or add a matching 'operator!=' to resolve the ambiguity}}
321 static bool operator !=(X
const&, X
const&); // expected-error {{overloaded 'operator!=' cannot be a static member function}}
323 bool x
= X() == X(); // expected-warning {{ambiguous}}
325 } // namespace P2468R2
328 namespace friend_template_1
{
331 friend bool operator==(const P
&, const T
&) { return true; } // expected-note {{candidate}} \
332 // expected-note {{ambiguous candidate function with reversed arguments}}
334 struct A
: public P
{};
335 struct B
: public P
{};
336 bool check(A a
, B b
) { return a
== b
; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
339 namespace friend_template_2
{
342 friend bool operator==(const T
&, const P
&) { return true; } // expected-note {{candidate}} \
343 // expected-note {{ambiguous candidate function with reversed arguments}}
345 struct A
: public P
{};
346 struct B
: public P
{};
347 bool check(A a
, B b
) { return a
== b
; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
350 namespace friend_template_class_template
{
354 friend bool operator==(const T
&, const P
&) { // expected-note 2 {{candidate}}
358 struct A
: public P
<int> {};
359 struct B
: public P
<bool> {};
360 bool check(A a
, B b
) { return a
== b
; } // expected-warning {{ambiguous}}
363 namespace friend_template_fixme
{
364 // FIXME(GH70210): This should not rewrite operator== and definitely not a hard error.
367 friend bool operator==(const T
&, const P
&) { return true; } // expected-note 2 {{candidate}}
369 friend bool operator!=(const T
&, const P
&) { return true; } // expected-note {{candidate}}
371 struct A
: public P
{};
372 struct B
: public P
{};
373 bool check(A a
, B b
) { return a
!= b
; } // expected-error{{ambiguous}}
376 namespace member_template_1
{
379 bool operator==(const S
&) const; // expected-note {{candidate}} \
380 // expected-note {{ambiguous candidate function with reversed arguments}}
382 struct A
: public P
{};
383 struct B
: public P
{};
384 bool check(A a
, B b
) { return a
== b
; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
385 } // namespace member_template
387 namespace member_template_2
{
388 template <typename T
>
391 template <typename U
= T
>
392 bool operator==(const Foo
& other
) const;
394 bool x
= Foo
<int>{} == Foo
<int>{};
395 } // namespace template_member_opeqeq
397 namespace non_member_template_1
{
400 bool operator==(const P
&, const S
&); // expected-note {{candidate}} \
401 // expected-note {{ambiguous candidate function with reversed arguments}}
403 struct A
: public P
{};
404 struct B
: public P
{};
405 bool check(A a
, B b
) { return a
== b
; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
407 template<class S
> bool operator!=(const P
&, const S
&);
408 bool fine(A a
, B b
) { return a
== b
; } // Ok. Found a matching operator!=.
409 } // namespace non_member_template_1
411 namespace non_member_template_2
{
414 bool operator==(const S
&, const P
&); // expected-note {{candidate}} \
415 // expected-note {{ambiguous candidate function with reversed arguments}}
417 struct A
: public P
{};
418 struct B
: public P
{};
419 bool check(A a
, B b
) { return a
== b
; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
420 } // namespace non_member_template_2
422 namespace class_and_member_template
{
425 template <typename OtherT
>
426 bool operator==(const OtherT
&rhs
); // expected-note {{candidate}} \
427 // expected-note {{reversed arguments}}
429 struct A
: S
<int> {};
430 struct B
: S
<bool> {};
431 bool x
= A
{} == B
{}; // expected-warning {{ambiguous}}
432 } // namespace class_and_member_template
434 namespace ambiguous_case
{
437 template <class T
, class U
> bool operator==(Foo
<U
>, Foo
<T
*>); // expected-note{{candidate}}
438 template <class T
, class U
> bool operator==(Foo
<T
*>, Foo
<U
>); // expected-note{{candidate}}
441 Foo
<int*>() == Foo
<int*>(); // expected-error{{ambiguous}}
443 } // namespace ambiguous_case
445 namespace ADL_GH68901
{
449 bool operator==(S
, int); // expected-note {{no known conversion from 'int' to 'S' for 1st argument}}
450 bool a
= 0 == A::S(); // Ok. Operator!= not visible.
451 bool operator!=(S
, int);
453 bool a
= 0 == A::S(); // expected-error {{invalid operands to binary expression ('int' and 'A::S')}}
459 struct Base
: Derived
{};
461 bool operator==(Derived
& a
, Base
& b
);
462 bool operator!=(Derived
& a
, Base
& b
);
472 namespace template_
{
474 template <class T
> struct A
{};
475 template <class T
> struct B
: A
<T
> {};
477 template <class T
> bool operator==(B
<T
>, A
<T
>); // expected-note {{candidate template ignored: could not match 'B' against 'ns::A'}}
478 template <class T
> bool operator!=(B
<T
>, A
<T
>);
484 a
== b
; // expected-error {{invalid operands to binary expression}}
488 namespace using_not_eq
{
492 bool operator!=(S
, int);
494 bool operator==(S
, int); // expected-note {{candidate}}
497 bool a
= 0 == A::S(); // expected-error {{invalid operands to binary expression}}
498 } // namespace reversed_lookup_not_like_ADL
500 namespace using_eqeq
{
504 bool operator==(S
, int); // expected-note {{candidate}}
505 bool operator!=(S
, int);
509 bool a
= 0 == A::S(); // expected-error {{invalid operands to binary expression}}
512 } // namespace ADL_GH68901
514 namespace function_scope_operator_eqeq
{
515 // For non-members, we always lookup for matching operator!= in the namespace scope of
516 // operator== (and not in the scope of operator==).
517 struct X
{ operator int(); };
520 bool operator==(X
, int); // expected-note {{reversed}}
521 return x
== x
; // expected-warning {{ambiguous}}
525 bool operator==(X
, int); // expected-note {{reversed}}
526 bool operator!=(X
, int);
527 return x
== x
; // expected-warning {{ambiguous}}
532 bool operator!=(X
, int);
535 bool operator==(X
, int);
540 bool operator==(X
, int);
541 bool operator!=(X
, int);
545 } // namespace function_scope_operator_eqeq
549 namespace problem_cases
{
550 // We can select a reversed candidate where we used to select a non-reversed
551 // one, and in the worst case this can dramatically change the meaning of the
552 // program. Make sure we at least warn on the worst cases under -Wall.
554 struct const_iterator
{
555 const_iterator(iterator
);
556 bool operator==(const const_iterator
&) const;
559 bool operator==(const const_iterator
&o
) const { // expected-warning {{all paths through this function will call itself}}