1 // RUN: %clang_cc1 -std=c++2a -verify %s
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
>;
9 constexpr Op
<A
, B
> operator<=>(A a
, B b
) { return {a
, "<=>", 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
}; }
12 template<typename T
, typename U
, typename V
> constexpr Op
<Op
<T
, U
>, V
> operator<= (Op
<T
, U
> a
, V b
) { return {a
, "<=", 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
}; }
14 template<typename T
, typename U
, typename V
> constexpr Op
<Op
<T
, U
>, V
> operator>= (Op
<T
, U
> a
, V b
) { return {a
, ">=", 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
}; }
17 template<typename T
, typename U
, typename V
> constexpr Op
<T
, Op
<U
, V
>> operator< (T a
, Op
<U
, V
> b
) { return {a
, "<", 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
}; }
19 template<typename T
, typename U
, typename V
> constexpr Op
<T
, Op
<U
, V
>> operator> (T a
, Op
<U
, V
> b
) { return {a
, ">", 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
}; }
21 template<typename T
, typename U
, typename V
> constexpr Op
<T
, Op
<U
, V
>> operator<=>(T a
, Op
<U
, V
> b
) { return {a
, "<=>", b
}; }
23 constexpr bool same(A
, A
) { return true; }
24 constexpr bool same(B
, B
) { return true; }
25 constexpr bool same(int a
, int b
) { return a
== b
; }
26 template<typename T
, typename U
>
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
);
31 // x @ y is interpreted as:
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)
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
)));
51 // We can rewrite into a call involving a builtin operator.
52 struct X
{ int result
; };
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}}