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