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