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 } 233