xref: /llvm-project/clang/test/AST/ByteCode/spaceship.cpp (revision a07aba5d44204a7ca0d891a3da05af9960081e4c)
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