xref: /llvm-project/clang/test/CXX/class/class.compare/class.spaceship/p1.cpp (revision 02bb2beeef3d93360694de29573430f584caafe9)
1cafc7416SRichard Smith // RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions
25253d913SRichard Smith 
35253d913SRichard Smith namespace std {
4e6e6e34bSRichard Smith   struct strong_ordering { // expected-note 6{{candidate}}
55253d913SRichard Smith     int n;
operator intstd::strong_ordering65253d913SRichard Smith     constexpr operator int() const { return n; }
75253d913SRichard Smith     static const strong_ordering less, equal, greater;
85253d913SRichard Smith   };
95253d913SRichard Smith   constexpr strong_ordering strong_ordering::less{-1},
105253d913SRichard Smith       strong_ordering::equal{0}, strong_ordering::greater{1};
11cafc7416SRichard Smith 
12cafc7416SRichard Smith   struct weak_ordering {
13cafc7416SRichard Smith     int n;
weak_orderingstd::weak_ordering14cafc7416SRichard Smith     constexpr weak_ordering(int n) : n(n) {}
weak_orderingstd::weak_ordering15cafc7416SRichard Smith     constexpr weak_ordering(strong_ordering o) : n(o.n) {}
operator intstd::weak_ordering16cafc7416SRichard Smith     constexpr operator int() const { return n; }
17cafc7416SRichard Smith     static const weak_ordering less, equivalent, greater;
18cafc7416SRichard Smith   };
19cafc7416SRichard Smith   constexpr weak_ordering weak_ordering::less{-1},
20cafc7416SRichard Smith       weak_ordering::equivalent{0}, weak_ordering::greater{1};
21cafc7416SRichard Smith 
22cafc7416SRichard Smith   struct partial_ordering {
23cafc7416SRichard Smith     double d;
partial_orderingstd::partial_ordering24cafc7416SRichard Smith     constexpr partial_ordering(double d) : d(d) {}
partial_orderingstd::partial_ordering25cafc7416SRichard Smith     constexpr partial_ordering(strong_ordering o) : d(o.n) {}
partial_orderingstd::partial_ordering26cafc7416SRichard Smith     constexpr partial_ordering(weak_ordering o) : d(o.n) {}
operator doublestd::partial_ordering27cafc7416SRichard Smith     constexpr operator double() const { return d; }
28cafc7416SRichard Smith     static const partial_ordering less, equivalent, greater, unordered;
29cafc7416SRichard Smith   };
30cafc7416SRichard Smith   constexpr partial_ordering partial_ordering::less{-1},
31cafc7416SRichard Smith       partial_ordering::equivalent{0}, partial_ordering::greater{1},
32cafc7416SRichard Smith       partial_ordering::unordered{__builtin_nan("")};
33cafc7416SRichard Smith 
34cafc7416SRichard Smith   static_assert(!(partial_ordering::unordered < 0));
35cafc7416SRichard Smith   static_assert(!(partial_ordering::unordered == 0));
36cafc7416SRichard Smith   static_assert(!(partial_ordering::unordered > 0));
375253d913SRichard Smith }
385253d913SRichard Smith 
395253d913SRichard Smith namespace Deletedness {
405253d913SRichard Smith   struct A {
415253d913SRichard Smith     std::strong_ordering operator<=>(const A&) const;
425253d913SRichard Smith   };
435253d913SRichard Smith   struct B {
445253d913SRichard Smith     bool operator==(const B&) const;
455253d913SRichard Smith     bool operator<(const B&) const;
465253d913SRichard Smith   };
475253d913SRichard Smith   struct C {
48e6e6e34bSRichard Smith     std::strong_ordering operator<=>(const C&) const = delete; // expected-note 2{{deleted}}
495253d913SRichard Smith   };
505253d913SRichard Smith   struct D1 {
515253d913SRichard Smith     bool operator==(const D1&) const;
52e6e6e34bSRichard Smith     std::strong_ordering operator<=>(int) const; // expected-note 2{{function not viable}} expected-note 2{{function (with reversed parameter order) not viable}}
53e6e6e34bSRichard Smith     bool operator<(int) const; // expected-note 2{{function not viable}}
545253d913SRichard Smith   };
555253d913SRichard Smith   struct D2 {
565253d913SRichard Smith     bool operator<(const D2&) const;
57e6e6e34bSRichard Smith     std::strong_ordering operator<=>(int) const; // expected-note 2{{function not viable}} expected-note 2{{function (with reversed parameter order) not viable}}
58e6e6e34bSRichard Smith     bool operator==(int) const; // expected-note 2{{function not viable}}
595253d913SRichard Smith   };
605253d913SRichard Smith   struct E {
615253d913SRichard Smith     bool operator==(const E&) const;
62e6e6e34bSRichard Smith     bool operator<(const E&) const = delete; // expected-note 2{{deleted}}
635253d913SRichard Smith   };
645253d913SRichard Smith   struct F {
65e6e6e34bSRichard Smith     std::strong_ordering operator<=>(const F&) const; // expected-note 2{{candidate}}
66e6e6e34bSRichard Smith     std::strong_ordering operator<=>(F) const; // expected-note 2{{candidate}}
675253d913SRichard Smith   };
685253d913SRichard Smith   struct G1 {
695253d913SRichard Smith     bool operator==(const G1&) const;
705253d913SRichard Smith     void operator<(const G1&) const;
715253d913SRichard Smith   };
725253d913SRichard Smith   struct G2 {
735253d913SRichard Smith     void operator==(const G2&) const;
745253d913SRichard Smith     bool operator<(const G2&) const;
755253d913SRichard Smith   };
765253d913SRichard Smith   struct H {
775253d913SRichard Smith     void operator<=>(const H&) const;
785253d913SRichard Smith   };
795253d913SRichard Smith 
805253d913SRichard Smith   // expected-note@#base {{deleted comparison function for base class 'C'}}
81c9fd92d5SMatheus Izvekov   // expected-note@#base {{no viable three-way comparison function for base class 'D1'}}
825253d913SRichard Smith   // expected-note@#base {{three-way comparison cannot be synthesized because there is no viable function for '<' comparison}}
83*02bb2beeSAmirreza Ashouri   // expected-note@#base {{no viable 'operator==' for base class 'D2'}}
845253d913SRichard Smith   // expected-note@#base {{three-way comparison cannot be synthesized because there is no viable function for '==' comparison}}
855253d913SRichard Smith   // expected-note@#base {{deleted comparison function for base class 'E'}}
865253d913SRichard Smith   // expected-note@#base {{implied comparison for base class 'F' is ambiguous}}
875253d913SRichard Smith   template<typename T> struct Cmp : T { // #base
88cafc7416SRichard Smith     std::strong_ordering operator<=>(const Cmp&) const = default; // #cmp expected-note 5{{here}}
895253d913SRichard Smith   };
905253d913SRichard Smith 
915253d913SRichard Smith   void use(...);
f()925253d913SRichard Smith   void f() {
935253d913SRichard Smith     use(
945253d913SRichard Smith       Cmp<A>() <=> Cmp<A>(),
955253d913SRichard Smith       Cmp<B>() <=> Cmp<B>(),
965253d913SRichard Smith       Cmp<C>() <=> Cmp<C>(), // expected-error {{deleted}}
975253d913SRichard Smith       Cmp<D1>() <=> Cmp<D1>(), // expected-error {{deleted}}
985253d913SRichard Smith       Cmp<D2>() <=> Cmp<D2>(), // expected-error {{deleted}}
995253d913SRichard Smith       Cmp<E>() <=> Cmp<E>(), // expected-error {{deleted}}
1005253d913SRichard Smith       Cmp<F>() <=> Cmp<F>(), // expected-error {{deleted}}
101cafc7416SRichard Smith       // FIXME: The following three errors are not very good.
102cafc7416SRichard Smith       // expected-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}}
103cafc7416SRichard Smith       Cmp<G1>() <=> Cmp<G1>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G1>' first required here}}j
104cafc7416SRichard Smith       // expected-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}}
105cafc7416SRichard Smith       Cmp<G2>() <=> Cmp<G2>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G2>' first required here}}j
106cafc7416SRichard Smith       // expected-error@#cmp {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}}
107cafc7416SRichard Smith       Cmp<H>() <=> Cmp<H>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}H>' first required here}}j
1085253d913SRichard Smith       0
1095253d913SRichard Smith     );
1105253d913SRichard Smith   }
111e6e6e34bSRichard Smith 
112e6e6e34bSRichard Smith   // expected-note@#arr {{deleted comparison function for member 'arr'}}
113c9fd92d5SMatheus Izvekov   // expected-note@#arr {{no viable three-way comparison function for member 'arr'}}
114e6e6e34bSRichard Smith   // expected-note@#arr {{three-way comparison cannot be synthesized because there is no viable function for '<' comparison}}
115*02bb2beeSAmirreza Ashouri   // expected-note@#arr {{no viable 'operator==' for member 'arr'}}
116e6e6e34bSRichard Smith   // expected-note@#arr {{three-way comparison cannot be synthesized because there is no viable function for '==' comparison}}
117e6e6e34bSRichard Smith   // expected-note@#arr {{deleted comparison function for member 'arr'}}
118e6e6e34bSRichard Smith   // expected-note@#arr {{implied comparison for member 'arr' is ambiguous}}
119e6e6e34bSRichard Smith   template<typename T> struct CmpArray {
120e6e6e34bSRichard Smith     T arr[3]; // #arr
121e6e6e34bSRichard Smith     std::strong_ordering operator<=>(const CmpArray&) const = default; // #cmparray expected-note 5{{here}}
122e6e6e34bSRichard Smith   };
g()123e6e6e34bSRichard Smith   void g() {
124e6e6e34bSRichard Smith     use(
125e6e6e34bSRichard Smith       CmpArray<A>() <=> CmpArray<A>(),
126e6e6e34bSRichard Smith       CmpArray<B>() <=> CmpArray<B>(),
127e6e6e34bSRichard Smith       CmpArray<C>() <=> CmpArray<C>(), // expected-error {{deleted}}
128e6e6e34bSRichard Smith       CmpArray<D1>() <=> CmpArray<D1>(), // expected-error {{deleted}}
129e6e6e34bSRichard Smith       CmpArray<D2>() <=> CmpArray<D2>(), // expected-error {{deleted}}
130e6e6e34bSRichard Smith       CmpArray<E>() <=> CmpArray<E>(), // expected-error {{deleted}}
131e6e6e34bSRichard Smith       CmpArray<F>() <=> CmpArray<F>(), // expected-error {{deleted}}
132e6e6e34bSRichard Smith       // FIXME: The following three errors are not very good.
133e6e6e34bSRichard Smith       // expected-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}}
134e6e6e34bSRichard Smith       CmpArray<G1>() <=> CmpArray<G1>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G1>' first required here}}j
135e6e6e34bSRichard Smith       // expected-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}}
136e6e6e34bSRichard Smith       CmpArray<G2>() <=> CmpArray<G2>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G2>' first required here}}j
137e6e6e34bSRichard Smith       // expected-error@#cmparray {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}}
138e6e6e34bSRichard Smith       CmpArray<H>() <=> CmpArray<H>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}H>' first required here}}j
139e6e6e34bSRichard Smith       0
140e6e6e34bSRichard Smith     );
141e6e6e34bSRichard Smith   }
1425253d913SRichard Smith }
143cafc7416SRichard Smith 
1448e0c9e21SRichard Smith namespace Access {
1458e0c9e21SRichard Smith   class A {
1468e0c9e21SRichard Smith     std::strong_ordering operator<=>(const A &) const; // expected-note {{here}}
1478e0c9e21SRichard Smith   public:
1488e0c9e21SRichard Smith     bool operator==(const A &) const;
1498e0c9e21SRichard Smith     bool operator<(const A &) const;
1508e0c9e21SRichard Smith   };
1518e0c9e21SRichard Smith   struct B {
1528e0c9e21SRichard Smith     A a; // expected-note {{would invoke a private 'operator<=>'}}
1531376c739SNathan James     friend std::strong_ordering operator<=>(const B &, const B &) = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
1548e0c9e21SRichard Smith   };
1558e0c9e21SRichard Smith 
1568e0c9e21SRichard Smith   class C {
1578e0c9e21SRichard Smith     std::strong_ordering operator<=>(const C &); // not viable (not const)
1588e0c9e21SRichard Smith     bool operator==(const C &) const; // expected-note {{here}}
1598e0c9e21SRichard Smith     bool operator<(const C &) const;
1608e0c9e21SRichard Smith   };
1618e0c9e21SRichard Smith   struct D {
1628e0c9e21SRichard Smith     C c; // expected-note {{would invoke a private 'operator=='}}
1631376c739SNathan James     friend std::strong_ordering operator<=>(const D &, const D &) = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}
1648e0c9e21SRichard Smith   };
1658e0c9e21SRichard Smith }
1668e0c9e21SRichard Smith 
167cafc7416SRichard Smith namespace Synthesis {
168cafc7416SRichard Smith   enum Result { False, True, Mu };
169cafc7416SRichard Smith 
toBool(Result R)170cafc7416SRichard Smith   constexpr bool toBool(Result R) {
171cafc7416SRichard Smith     if (R == Mu) throw "should not ask this question";
172cafc7416SRichard Smith     return R == True;
173cafc7416SRichard Smith   }
174cafc7416SRichard Smith 
175cafc7416SRichard Smith   struct Val {
176cafc7416SRichard Smith     Result equal, less;
operator ==Synthesis::Val177cafc7416SRichard Smith     constexpr bool operator==(const Val&) const { return toBool(equal); }
operator <Synthesis::Val178cafc7416SRichard Smith     constexpr bool operator<(const Val&) const { return toBool(less); }
179cafc7416SRichard Smith   };
180cafc7416SRichard Smith 
181cafc7416SRichard Smith   template<typename T> struct Cmp {
182cafc7416SRichard Smith     Val val;
183cafc7416SRichard Smith     friend T operator<=>(const Cmp&, const Cmp&) = default; // expected-note {{deleted}}
184cafc7416SRichard Smith   };
185cafc7416SRichard Smith 
cmp(Result equal,Result less=Mu,Result reverse_less=Mu)186cafc7416SRichard Smith   template<typename T> constexpr auto cmp(Result equal, Result less = Mu, Result reverse_less = Mu) {
187cafc7416SRichard Smith     return Cmp<T>{equal, less} <=> Cmp<T>{Mu, reverse_less};
188cafc7416SRichard Smith   }
189cafc7416SRichard Smith 
190cafc7416SRichard Smith   static_assert(cmp<std::strong_ordering>(True) == 0);
191cafc7416SRichard Smith   static_assert(cmp<std::strong_ordering>(False, True) < 0);
192cafc7416SRichard Smith   static_assert(cmp<std::strong_ordering>(False, False) > 0);
193cafc7416SRichard Smith 
194cafc7416SRichard Smith   static_assert(cmp<std::weak_ordering>(True) == 0);
195cafc7416SRichard Smith   static_assert(cmp<std::weak_ordering>(False, True) < 0);
196cafc7416SRichard Smith   static_assert(cmp<std::weak_ordering>(False, False) > 0);
197cafc7416SRichard Smith 
198cafc7416SRichard Smith   static_assert(cmp<std::partial_ordering>(True) == 0);
199cafc7416SRichard Smith   static_assert(cmp<std::partial_ordering>(False, True) < 0);
200cafc7416SRichard Smith   static_assert(cmp<std::partial_ordering>(False, False, True) > 0);
201cafc7416SRichard Smith   static_assert(!(cmp<std::partial_ordering>(False, False, False) > 0));
202cafc7416SRichard Smith   static_assert(!(cmp<std::partial_ordering>(False, False, False) == 0));
203cafc7416SRichard Smith   static_assert(!(cmp<std::partial_ordering>(False, False, False) < 0));
204cafc7416SRichard Smith 
205cafc7416SRichard Smith   // No synthesis is performed for a custom return type, even if it can be
206cafc7416SRichard Smith   // converted from a standard ordering.
207cafc7416SRichard Smith   struct custom_ordering {
208cafc7416SRichard Smith     custom_ordering(std::strong_ordering o);
209cafc7416SRichard Smith   };
f(Cmp<custom_ordering> c)210cafc7416SRichard Smith   void f(Cmp<custom_ordering> c) {
211cafc7416SRichard Smith     c <=> c; // expected-error {{deleted}}
212cafc7416SRichard Smith   }
213cafc7416SRichard Smith }
214cafc7416SRichard Smith 
215cafc7416SRichard Smith namespace Preference {
216cafc7416SRichard Smith   struct A {
217cafc7416SRichard Smith     A(const A&) = delete; // expected-note {{deleted}}
218cafc7416SRichard Smith     // "usable" candidate that can't actually be called
219cafc7416SRichard Smith     friend void operator<=>(A, A); // expected-note {{passing}}
220cafc7416SRichard Smith     // Callable candidates for synthesis not considered.
221cafc7416SRichard Smith     friend bool operator==(A, A);
222cafc7416SRichard Smith     friend bool operator<(A, A);
223cafc7416SRichard Smith   };
224cafc7416SRichard Smith 
225cafc7416SRichard Smith   struct B {
226cafc7416SRichard Smith     B();
227cafc7416SRichard Smith     A a;
22815f3cd6bSMatheus Izvekov     std::strong_ordering operator<=>(const B&) const = default; // expected-error {{call to deleted constructor of 'A'}}
229cafc7416SRichard Smith   };
2305df593a3SCongcong Cai   bool x = B() < B(); // expected-note {{in defaulted three-way comparison operator for 'B' first required here}}
231cafc7416SRichard Smith }
232