|
| 1 | +// RUN: %clang_cc1 -std=c++2a -verify=both,ref %s -fcxx-exceptions |
| 2 | +// RUN: %clang_cc1 -std=c++2a -verify=both,expected %s -fcxx-exceptions -fexperimental-new-constant-interpreter |
| 3 | + |
| 4 | +namespace std { |
| 5 | + struct strong_ordering { // both-note 6{{candidate}} |
| 6 | + int n; |
| 7 | + constexpr operator int() const { return n; } |
| 8 | + static const strong_ordering less, equal, greater; |
| 9 | + }; |
| 10 | + constexpr strong_ordering strong_ordering::less{-1}, |
| 11 | + strong_ordering::equal{0}, strong_ordering::greater{1}; |
| 12 | + |
| 13 | + struct weak_ordering { |
| 14 | + int n; |
| 15 | + constexpr weak_ordering(int n) : n(n) {} |
| 16 | + constexpr weak_ordering(strong_ordering o) : n(o.n) {} |
| 17 | + constexpr operator int() const { return n; } |
| 18 | + static const weak_ordering less, equivalent, greater; |
| 19 | + }; |
| 20 | + constexpr weak_ordering weak_ordering::less{-1}, |
| 21 | + weak_ordering::equivalent{0}, weak_ordering::greater{1}; |
| 22 | + |
| 23 | + struct partial_ordering { |
| 24 | + double d; |
| 25 | + constexpr partial_ordering(double d) : d(d) {} |
| 26 | + constexpr partial_ordering(strong_ordering o) : d(o.n) {} |
| 27 | + constexpr partial_ordering(weak_ordering o) : d(o.n) {} |
| 28 | + constexpr operator double() const { return d; } |
| 29 | + static const partial_ordering less, equivalent, greater, unordered; |
| 30 | + }; |
| 31 | + constexpr partial_ordering partial_ordering::less{-1}, |
| 32 | + partial_ordering::equivalent{0}, partial_ordering::greater{1}, |
| 33 | + partial_ordering::unordered{__builtin_nan("")}; |
| 34 | + |
| 35 | + static_assert(!(partial_ordering::unordered < 0)); |
| 36 | + static_assert(!(partial_ordering::unordered == 0)); |
| 37 | + static_assert(!(partial_ordering::unordered > 0)); |
| 38 | +} |
| 39 | + |
| 40 | +namespace Deletedness { |
| 41 | + struct A { |
| 42 | + std::strong_ordering operator<=>(const A&) const; |
| 43 | + }; |
| 44 | + struct B { |
| 45 | + bool operator==(const B&) const; |
| 46 | + bool operator<(const B&) const; |
| 47 | + }; |
| 48 | + struct C { |
| 49 | + std::strong_ordering operator<=>(const C&) const = delete; // both-note 2{{deleted}} |
| 50 | + }; |
| 51 | + struct D1 { |
| 52 | + bool operator==(const D1&) const; |
| 53 | + std::strong_ordering operator<=>(int) const; // both-note 2{{function not viable}} both-note 2{{function (with reversed parameter order) not viable}} |
| 54 | + bool operator<(int) const; // both-note 2{{function not viable}} |
| 55 | + }; |
| 56 | + struct D2 { |
| 57 | + bool operator<(const D2&) const; |
| 58 | + std::strong_ordering operator<=>(int) const; // both-note 2{{function not viable}} both-note 2{{function (with reversed parameter order) not viable}} |
| 59 | + bool operator==(int) const; // both-note 2{{function not viable}} |
| 60 | + }; |
| 61 | + struct E { |
| 62 | + bool operator==(const E&) const; |
| 63 | + bool operator<(const E&) const = delete; // both-note 2{{deleted}} |
| 64 | + }; |
| 65 | + struct F { |
| 66 | + std::strong_ordering operator<=>(const F&) const; // both-note 2{{candidate}} |
| 67 | + std::strong_ordering operator<=>(F) const; // both-note 2{{candidate}} |
| 68 | + }; |
| 69 | + struct G1 { |
| 70 | + bool operator==(const G1&) const; |
| 71 | + void operator<(const G1&) const; |
| 72 | + }; |
| 73 | + struct G2 { |
| 74 | + void operator==(const G2&) const; |
| 75 | + bool operator<(const G2&) const; |
| 76 | + }; |
| 77 | + struct H { |
| 78 | + void operator<=>(const H&) const; |
| 79 | + }; |
| 80 | + |
| 81 | + // both-note@#base {{deleted comparison function for base class 'C'}} |
| 82 | + // both-note@#base {{no viable three-way comparison function for base class 'D1'}} |
| 83 | + // both-note@#base {{three-way comparison cannot be synthesized because there is no viable function for '<' comparison}} |
| 84 | + // both-note@#base {{no viable 'operator==' for base class 'D2'}} |
| 85 | + // both-note@#base {{three-way comparison cannot be synthesized because there is no viable function for '==' comparison}} |
| 86 | + // both-note@#base {{deleted comparison function for base class 'E'}} |
| 87 | + // both-note@#base {{implied comparison for base class 'F' is ambiguous}} |
| 88 | + template<typename T> struct Cmp : T { // #base |
| 89 | + std::strong_ordering operator<=>(const Cmp&) const = default; // #cmp both-note 5{{here}} |
| 90 | + }; |
| 91 | + |
| 92 | + void use(...); |
| 93 | + void f() { |
| 94 | + use( |
| 95 | + Cmp<A>() <=> Cmp<A>(), |
| 96 | + Cmp<B>() <=> Cmp<B>(), |
| 97 | + Cmp<C>() <=> Cmp<C>(), // both-error {{deleted}} |
| 98 | + Cmp<D1>() <=> Cmp<D1>(), // both-error {{deleted}} |
| 99 | + Cmp<D2>() <=> Cmp<D2>(), // both-error {{deleted}} |
| 100 | + Cmp<E>() <=> Cmp<E>(), // both-error {{deleted}} |
| 101 | + Cmp<F>() <=> Cmp<F>(), // both-error {{deleted}} |
| 102 | + // FIXME: The following three errors are not very good. |
| 103 | + // both-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}} |
| 104 | + Cmp<G1>() <=> Cmp<G1>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G1>' first required here}}j |
| 105 | + // both-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}} |
| 106 | + Cmp<G2>() <=> Cmp<G2>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G2>' first required here}}j |
| 107 | + // both-error@#cmp {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}} |
| 108 | + Cmp<H>() <=> Cmp<H>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}H>' first required here}}j |
| 109 | + 0 |
| 110 | + ); |
| 111 | + } |
| 112 | + |
| 113 | + // both-note@#arr {{deleted comparison function for member 'arr'}} |
| 114 | + // both-note@#arr {{no viable three-way comparison function for member 'arr'}} |
| 115 | + // both-note@#arr {{three-way comparison cannot be synthesized because there is no viable function for '<' comparison}} |
| 116 | + // both-note@#arr {{no viable 'operator==' for member 'arr'}} |
| 117 | + // both-note@#arr {{three-way comparison cannot be synthesized because there is no viable function for '==' comparison}} |
| 118 | + // both-note@#arr {{deleted comparison function for member 'arr'}} |
| 119 | + // both-note@#arr {{implied comparison for member 'arr' is ambiguous}} |
| 120 | + template<typename T> struct CmpArray { |
| 121 | + T arr[3]; // #arr |
| 122 | + std::strong_ordering operator<=>(const CmpArray&) const = default; // #cmparray both-note 5{{here}} |
| 123 | + }; |
| 124 | + void g() { |
| 125 | + use( |
| 126 | + CmpArray<A>() <=> CmpArray<A>(), |
| 127 | + CmpArray<B>() <=> CmpArray<B>(), |
| 128 | + CmpArray<C>() <=> CmpArray<C>(), // both-error {{deleted}} |
| 129 | + CmpArray<D1>() <=> CmpArray<D1>(), // both-error {{deleted}} |
| 130 | + CmpArray<D2>() <=> CmpArray<D2>(), // both-error {{deleted}} |
| 131 | + CmpArray<E>() <=> CmpArray<E>(), // both-error {{deleted}} |
| 132 | + CmpArray<F>() <=> CmpArray<F>(), // both-error {{deleted}} |
| 133 | + // FIXME: The following three errors are not very good. |
| 134 | + // both-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}} |
| 135 | + CmpArray<G1>() <=> CmpArray<G1>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G1>' first required here}}j |
| 136 | + // both-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}} |
| 137 | + CmpArray<G2>() <=> CmpArray<G2>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G2>' first required here}}j |
| 138 | + // both-error@#cmparray {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}} |
| 139 | + CmpArray<H>() <=> CmpArray<H>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}H>' first required here}}j |
| 140 | + 0 |
| 141 | + ); |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +namespace Access { |
| 146 | + class A { |
| 147 | + std::strong_ordering operator<=>(const A &) const; // both-note {{here}} |
| 148 | + public: |
| 149 | + bool operator==(const A &) const; |
| 150 | + bool operator<(const A &) const; |
| 151 | + }; |
| 152 | + struct B { |
| 153 | + A a; // both-note {{would invoke a private 'operator<=>'}} |
| 154 | + friend std::strong_ordering operator<=>(const B &, const B &) = default; // both-warning {{deleted}} both-note{{replace 'default'}} |
| 155 | + }; |
| 156 | + |
| 157 | + class C { |
| 158 | + std::strong_ordering operator<=>(const C &); // not viable (not const) |
| 159 | + bool operator==(const C &) const; // both-note {{here}} |
| 160 | + bool operator<(const C &) const; |
| 161 | + }; |
| 162 | + struct D { |
| 163 | + C c; // both-note {{would invoke a private 'operator=='}} |
| 164 | + friend std::strong_ordering operator<=>(const D &, const D &) = default; // both-warning {{deleted}} both-note{{replace 'default'}} |
| 165 | + }; |
| 166 | +} |
| 167 | + |
| 168 | +namespace Synthesis { |
| 169 | + enum Result { False, True, Mu }; |
| 170 | + |
| 171 | + constexpr bool toBool(Result R) { |
| 172 | + if (R == Mu) throw "should not ask this question"; |
| 173 | + return R == True; |
| 174 | + } |
| 175 | + |
| 176 | + struct Val { |
| 177 | + Result equal, less; |
| 178 | + constexpr bool operator==(const Val&) const { return toBool(equal); } |
| 179 | + constexpr bool operator<(const Val&) const { return toBool(less); } |
| 180 | + }; |
| 181 | + |
| 182 | + template<typename T> struct Cmp { |
| 183 | + Val val; |
| 184 | + friend T operator<=>(const Cmp&, const Cmp&) = default; // both-note {{deleted}} |
| 185 | + }; |
| 186 | + |
| 187 | + template<typename T> constexpr auto cmp(Result equal, Result less = Mu, Result reverse_less = Mu) { |
| 188 | + return Cmp<T>{equal, less} <=> Cmp<T>{Mu, reverse_less}; |
| 189 | + } |
| 190 | + |
| 191 | + static_assert(cmp<std::strong_ordering>(True) == 0); |
| 192 | + static_assert(cmp<std::strong_ordering>(False, True) < 0); |
| 193 | + static_assert(cmp<std::strong_ordering>(False, False) > 0); |
| 194 | + |
| 195 | + static_assert(cmp<std::weak_ordering>(True) == 0); |
| 196 | + static_assert(cmp<std::weak_ordering>(False, True) < 0); |
| 197 | + static_assert(cmp<std::weak_ordering>(False, False) > 0); |
| 198 | + |
| 199 | + static_assert(cmp<std::partial_ordering>(True) == 0); |
| 200 | + static_assert(cmp<std::partial_ordering>(False, True) < 0); |
| 201 | + static_assert(cmp<std::partial_ordering>(False, False, True) > 0); |
| 202 | + static_assert(!(cmp<std::partial_ordering>(False, False, False) > 0)); |
| 203 | + static_assert(!(cmp<std::partial_ordering>(False, False, False) == 0)); |
| 204 | + static_assert(!(cmp<std::partial_ordering>(False, False, False) < 0)); |
| 205 | + |
| 206 | + // No synthesis is performed for a custom return type, even if it can be |
| 207 | + // converted from a standard ordering. |
| 208 | + struct custom_ordering { |
| 209 | + custom_ordering(std::strong_ordering o); |
| 210 | + }; |
| 211 | + void f(Cmp<custom_ordering> c) { |
| 212 | + c <=> c; // both-error {{deleted}} |
| 213 | + } |
| 214 | +} |
| 215 | + |
| 216 | +namespace Preference { |
| 217 | + struct A { |
| 218 | + A(const A&) = delete; // both-note {{deleted}} |
| 219 | + // "usable" candidate that can't actually be called |
| 220 | + friend void operator<=>(A, A); // both-note {{passing}} |
| 221 | + // Callable candidates for synthesis not considered. |
| 222 | + friend bool operator==(A, A); |
| 223 | + friend bool operator<(A, A); |
| 224 | + }; |
| 225 | + |
| 226 | + struct B { |
| 227 | + B(); |
| 228 | + A a; |
| 229 | + std::strong_ordering operator<=>(const B&) const = default; // both-error {{call to deleted constructor of 'A'}} |
| 230 | + }; |
| 231 | + bool x = B() < B(); // both-note {{in defaulted three-way comparison operator for 'B' first required here}} |
| 232 | +} |
0 commit comments