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