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