• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // RUN: %clang_cc1 -std=c++2a -verify %s
2 // RUN: %clang_cc1 -std=c++2a -verify -Wall -DNO_ERRORS %s
3 
4 #ifndef NO_ERRORS
5 namespace bullet3 {
6   // the built-in candidates include all of the candidate operator fnuctions
7   // [...] that, compared to the given operator
8 
9   // - do not have the same parameter-type-list as any non-member candidate
10 
11   enum E { e };
12 
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')}}
16 
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.
23 }
24 
25 namespace bullet4 {
26   // The rewritten candidate set is determined as follows:
27 
28   template<int> struct X {};
29   X<1> x1;
30   X<2> x2;
31 
32   struct Y {
33     int operator<=>(X<2>) = delete; // #1member
34     bool operator==(X<2>) = delete; // #2member
35   };
36   Y y;
37 
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
41 
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 '<=>'}}
49 
50   // expected-note@#1member 5{{candidate function has been explicitly deleted}}
51   // expected-note@#1 5{{candidate function not viable: no known conversion from 'bullet4::Y' to 'X<1>' for 1st argument}}
52   // expected-note@#1 5{{candidate function (with reversed parameter order) not viable: no known conversion from 'bullet4::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 '<=>'}}
58 
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.
63 
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 '<=>'}}
71 
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 'bullet4::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 '<=>'}}
80 
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
84 
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 '=='}}
89 
90   // expected-note@#2member 2{{candidate function has been explicitly deleted}}
91   // expected-note@#2 2{{candidate function not viable: no known conversion from 'bullet4::Y' to 'X<1>' for 1st argument}}
92   // expected-note@#2 2{{candidate function (with reversed parameter order) not viable: no known conversion from 'bullet4::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 '=='}}
95 
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
99 
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 '=='}}
104 
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 'bullet4::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 '=='}}
110 
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}}
114 }
115 
116 namespace PR44627 {
117   namespace ADL {
118     struct type {};
operator ==(type lhs,int rhs)119     bool operator==(type lhs, int rhs) {
120       return true;
121     }
122   }
123 
124   bool b1 = ADL::type() == 0;
125   bool b2 = 0 == ADL::type();
126 }
127 
128 // Various C++17 cases that are known to be broken by the C++20 rules.
129 namespace problem_cases {
130   // We can have an ambiguity between an operator and its reversed form. This
131   // wasn't intended by the original "consistent comparison" proposal, and we
132   // allow it as extension, picking the non-reversed form.
133   struct A {
134     bool operator==(const A&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
135   };
136   bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}
137 
138   struct B {
139     virtual bool operator==(const B&) const;
140   };
141   struct D : B {
142     bool operator==(const B&) const override; // expected-note {{operator}}
143   };
144   bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
145 
146   template<typename T> struct CRTPBase {
147     bool operator==(const T&) const; // expected-note {{operator}} expected-note {{reversed}}
148     bool operator!=(const T&) const; // expected-note {{non-reversed}}
149   };
150   struct CRTP : CRTPBase<CRTP> {};
151   bool cmp_crtp = CRTP() == CRTP(); // expected-warning-re {{ambiguous despite there being a unique best viable function{{$}}}}}}
152   bool cmp_crtp2 = CRTP() != CRTP(); // expected-warning {{ambiguous despite there being a unique best viable function with non-reversed arguments}}
153 
154   // Given a choice between a rewritten and non-rewritten function with the
155   // same parameter types, where the rewritten function is reversed and each
156   // has a better conversion for one of the two arguments, prefer the
157   // non-rewritten one.
158   using UBool = signed char; // ICU uses this.
159   struct ICUBase {
160     virtual UBool operator==(const ICUBase&) const;
operator !=problem_cases::ICUBase161     UBool operator!=(const ICUBase &arg) const { return !operator==(arg); }
162   };
163   struct ICUDerived : ICUBase {
164     UBool operator==(const ICUBase&) const override; // expected-note {{declared here}} expected-note {{ambiguity is between}}
165   };
166   bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ambiguous}} expected-warning {{'bool', not 'problem_cases::UBool'}}
167 }
168 
169 #else // NO_ERRORS
170 
171 namespace problem_cases {
172   // We can select a reversed candidate where we used to select a non-reversed
173   // one, and in the worst case this can dramatically change the meaning of the
174   // program. Make sure we at least warn on the worst cases under -Wall.
175   struct iterator;
176   struct const_iterator {
177     const_iterator(iterator);
178     bool operator==(const const_iterator&) const;
179   };
180   struct iterator {
operator ==problem_cases::iterator181     bool operator==(const const_iterator &o) const { // expected-warning {{all paths through this function will call itself}}
182       return o == *this;
183     }
184   };
185 }
186 #endif // NO_ERRORS
187