1 // RUN: %clang_cc1 -std=c++2a -verify %s
2
3 template<typename L, typename R> struct Op { L l; const char *op; R r; };
4 // FIXME: Remove once we implement P1816R0.
5 template<typename L, typename R> Op(L, R) -> Op<L, R>;
6
7 struct A {};
8 struct B {};
operator <=>(A a,B b)9 constexpr Op<A, B> operator<=>(A a, B b) { return {a, "<=>", b}; }
10
operator <(Op<T,U> a,V b)11 template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator< (Op<T, U> a, V b) { return {a, "<", b}; }
operator <=(Op<T,U> a,V b)12 template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator<= (Op<T, U> a, V b) { return {a, "<=", b}; }
operator >(Op<T,U> a,V b)13 template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator> (Op<T, U> a, V b) { return {a, ">", b}; }
operator >=(Op<T,U> a,V b)14 template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator>= (Op<T, U> a, V b) { return {a, ">=", b}; }
operator <=>(Op<T,U> a,V b)15 template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator<=>(Op<T, U> a, V b) { return {a, "<=>", b}; }
16
operator <(T a,Op<U,V> b)17 template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator< (T a, Op<U, V> b) { return {a, "<", b}; }
operator <=(T a,Op<U,V> b)18 template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator<= (T a, Op<U, V> b) { return {a, "<=", b}; }
operator >(T a,Op<U,V> b)19 template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator> (T a, Op<U, V> b) { return {a, ">", b}; }
operator >=(T a,Op<U,V> b)20 template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator>= (T a, Op<U, V> b) { return {a, ">=", b}; }
operator <=>(T a,Op<U,V> b)21 template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator<=>(T a, Op<U, V> b) { return {a, "<=>", b}; }
22
same(A,A)23 constexpr bool same(A, A) { return true; }
same(B,B)24 constexpr bool same(B, B) { return true; }
same(int a,int b)25 constexpr bool same(int a, int b) { return a == b; }
26 template<typename T, typename U>
same(Op<T,U> x,Op<T,U> y)27 constexpr bool same(Op<T, U> x, Op<T, U> y) {
28 return same(x.l, y.l) && __builtin_strcmp(x.op, y.op) == 0 && same(x.r, y.r);
29 }
30
31 // x @ y is interpreted as:
f(A x,B y)32 void f(A x, B y) {
33 // -- (x <=> y) @ 0 if not reversed
34 static_assert(same(x < y, (x <=> y) < 0));
35 static_assert(same(x <= y, (x <=> y) <= 0));
36 static_assert(same(x > y, (x <=> y) > 0));
37 static_assert(same(x >= y, (x <=> y) >= 0));
38 static_assert(same(x <=> y, x <=> y)); // (not rewritten)
39 }
40
g(B x,A y)41 void g(B x, A y) {
42 // -- 0 @ (y <=> x) if reversed
43 static_assert(same(x < y, 0 < (y <=> x)));
44 static_assert(same(x <= y, 0 <= (y <=> x)));
45 static_assert(same(x > y, 0 > (y <=> x)));
46 static_assert(same(x >= y, 0 >= (y <=> x)));
47 static_assert(same(x <=> y, 0 <=> (y <=> x)));
48 }
49
50
51 // We can rewrite into a call involving a builtin operator.
52 struct X { int result; };
53 struct Y {};
operator <=>(X x,Y)54 constexpr int operator<=>(X x, Y) { return x.result; }
55 static_assert(X{-1} < Y{});
56 static_assert(X{0} < Y{}); // expected-error {{failed}}
57 static_assert(X{0} <= Y{});
58 static_assert(X{1} <= Y{}); // expected-error {{failed}}
59 static_assert(X{1} > Y{});
60 static_assert(X{0} > Y{}); // expected-error {{failed}}
61 static_assert(X{0} >= Y{});
62 static_assert(X{-1} >= Y{}); // expected-error {{failed}}
63 static_assert(Y{} < X{1});
64 static_assert(Y{} < X{0}); // expected-error {{failed}}
65 static_assert(Y{} <= X{0});
66 static_assert(Y{} <= X{-1}); // expected-error {{failed}}
67 static_assert(Y{} > X{-1});
68 static_assert(Y{} > X{0}); // expected-error {{failed}}
69 static_assert(Y{} >= X{0});
70 static_assert(Y{} >= X{1}); // expected-error {{failed}}
71