Skip to content

Commit c9fd3da

Browse files
committed
[Clang] Introduce __builtin_meow_synthesises_from_spaceship
1 parent 430c037 commit c9fd3da

File tree

5 files changed

+282
-21
lines changed

5 files changed

+282
-21
lines changed

clang/include/clang/Basic/TokenKinds.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,10 @@ TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX)
552552
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
553553
TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX)
554554
TYPE_TRAIT_2(__reference_converts_from_temporary, ReferenceConvertsFromTemporary, KEYCXX)
555+
TYPE_TRAIT_2(__builtin_lt_synthesises_from_spaceship, LtSynthesisesFromSpaceship, KEYCXX)
556+
TYPE_TRAIT_2(__builtin_le_synthesises_from_spaceship, LeSynthesisesFromSpaceship, KEYCXX)
557+
TYPE_TRAIT_2(__builtin_gt_synthesises_from_spaceship, GtSynthesisesFromSpaceship, KEYCXX)
558+
TYPE_TRAIT_2(__builtin_ge_synthesises_from_spaceship, GeSynthesisesFromSpaceship, KEYCXX)
555559
// IsDeducible is only used internally by clang for CTAD implementation and
556560
// is not exposed to users.
557561
TYPE_TRAIT_2(/*EmptySpellingName*/, IsDeducible, KEYCXX)

clang/lib/Sema/SemaTypeTraits.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,51 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
18241824

18251825
return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
18261826
}
1827+
case BTT_LtSynthesisesFromSpaceship:
1828+
case BTT_LeSynthesisesFromSpaceship:
1829+
case BTT_GtSynthesisesFromSpaceship:
1830+
case BTT_GeSynthesisesFromSpaceship: {
1831+
EnterExpressionEvaluationContext UnevaluatedContext(
1832+
Self, Sema::ExpressionEvaluationContext::Unevaluated);
1833+
Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
1834+
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
1835+
1836+
OpaqueValueExpr LHS(KeyLoc, LhsT.getNonReferenceType(),
1837+
LhsT->isLValueReferenceType() ? ExprValueKind::VK_LValue
1838+
: LhsT->isRValueReferenceType()
1839+
? ExprValueKind::VK_XValue
1840+
: ExprValueKind::VK_PRValue);
1841+
OpaqueValueExpr RHS(KeyLoc, RhsT.getNonReferenceType(),
1842+
RhsT->isLValueReferenceType() ? ExprValueKind::VK_LValue
1843+
: RhsT->isRValueReferenceType()
1844+
? ExprValueKind::VK_XValue
1845+
: ExprValueKind::VK_PRValue);
1846+
1847+
auto OpKind = [&] {
1848+
switch (BTT) {
1849+
case BTT_LtSynthesisesFromSpaceship:
1850+
return BinaryOperatorKind::BO_LT;
1851+
case BTT_LeSynthesisesFromSpaceship:
1852+
return BinaryOperatorKind::BO_LE;
1853+
case BTT_GtSynthesisesFromSpaceship:
1854+
return BinaryOperatorKind::BO_GT;
1855+
case BTT_GeSynthesisesFromSpaceship:
1856+
return BinaryOperatorKind::BO_GE;
1857+
default:
1858+
llvm_unreachable("Trying to Synthesize non-comparison operator?");
1859+
}
1860+
}();
1861+
1862+
UnresolvedSet<16> Functions;
1863+
Self.LookupBinOp(Self.TUScope, KeyLoc, OpKind, Functions);
1864+
1865+
auto Result =
1866+
Self.CreateOverloadedBinOp(KeyLoc, OpKind, Functions, &LHS, &RHS);
1867+
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
1868+
return false;
1869+
1870+
return isa<CXXRewrittenBinaryOperator>(Result.get());
1871+
}
18271872
default:
18281873
llvm_unreachable("not a BTT");
18291874
}

clang/test/SemaCXX/type-trait-common-type.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,16 @@ static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], int [
7979
static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], long [[clang::address_space(1)]]>, type_identity<long [[clang::address_space(1)]]>));
8080
static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], long [[clang::address_space(2)]]>, type_identity<long>));
8181

82-
struct S {};
83-
struct T : S {};
82+
struct DefaultSpaceship {};
83+
struct T : DefaultSpaceship {};
8484

85-
static_assert(__is_same(common_type_base<int S::*, int S::*>, type_identity<int S::*>));
86-
static_assert(__is_same(common_type_base<int S::*, int T::*>, type_identity<int T::*>));
87-
static_assert(__is_same(common_type_base<int S::*, long S::*>, empty_type));
85+
static_assert(__is_same(common_type_base<int DefaultSpaceship::*, int DefaultSpaceship::*>, type_identity<int DefaultSpaceship::*>));
86+
static_assert(__is_same(common_type_base<int DefaultSpaceship::*, int T::*>, type_identity<int T::*>));
87+
static_assert(__is_same(common_type_base<int DefaultSpaceship::*, long DefaultSpaceship::*>, empty_type));
8888

89-
static_assert(__is_same(common_type_base<int (S::*)(), int (S::*)()>, type_identity<int (S::*)()>));
90-
static_assert(__is_same(common_type_base<int (S::*)(), int (T::*)()>, type_identity<int (T::*)()>));
91-
static_assert(__is_same(common_type_base<int (S::*)(), long (S::*)()>, empty_type));
89+
static_assert(__is_same(common_type_base<int (DefaultSpaceship::*)(), int (DefaultSpaceship::*)()>, type_identity<int (DefaultSpaceship::*)()>));
90+
static_assert(__is_same(common_type_base<int (DefaultSpaceship::*)(), int (T::*)()>, type_identity<int (T::*)()>));
91+
static_assert(__is_same(common_type_base<int (DefaultSpaceship::*)(), long (DefaultSpaceship::*)()>, empty_type));
9292

9393
struct NoCommonType {};
9494

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
2+
3+
static_assert(!__builtin_lt_synthesises_from_spaceship()); // expected-error {{expected a type}}
4+
static_assert(!__builtin_lt_synthesises_from_spaceship(int)); // expected-error {{type trait requires 2 arguments; have 1 argument}}
5+
static_assert(!__builtin_lt_synthesises_from_spaceship(int, int, int)); // expected-error {{type trait requires 2 arguments; have 3 argument}}
6+
static_assert(!__builtin_lt_synthesises_from_spaceship(int, 0)); // expected-error {{expected a type}}
7+
8+
static_assert(!__builtin_le_synthesises_from_spaceship()); // expected-error {{expected a type}}
9+
static_assert(!__builtin_le_synthesises_from_spaceship(int)); // expected-error {{type trait requires 2 arguments; have 1 argument}}
10+
static_assert(!__builtin_le_synthesises_from_spaceship(int, int, int)); // expected-error {{type trait requires 2 arguments; have 3 argument}}
11+
static_assert(!__builtin_le_synthesises_from_spaceship(int, 0)); // expected-error {{expected a type}}
12+
13+
static_assert(!__builtin_gt_synthesises_from_spaceship()); // expected-error {{expected a type}}
14+
static_assert(!__builtin_gt_synthesises_from_spaceship(int)); // expected-error {{type trait requires 2 arguments; have 1 argument}}
15+
static_assert(!__builtin_gt_synthesises_from_spaceship(int, int, int)); // expected-error {{type trait requires 2 arguments; have 3 argument}}
16+
static_assert(!__builtin_gt_synthesises_from_spaceship(int, 0)); // expected-error {{expected a type}}
17+
18+
static_assert(!__builtin_ge_synthesises_from_spaceship()); // expected-error {{expected a type}}
19+
static_assert(!__builtin_ge_synthesises_from_spaceship(int)); // expected-error {{type trait requires 2 arguments; have 1 argument}}
20+
static_assert(!__builtin_ge_synthesises_from_spaceship(int, int, int)); // expected-error {{type trait requires 2 arguments; have 3 argument}}
21+
static_assert(!__builtin_ge_synthesises_from_spaceship(int, 0)); // expected-error {{expected a type}}
22+
23+
namespace std {
24+
struct strong_ordering {
25+
int n;
26+
constexpr operator int() const { return n; }
27+
static const strong_ordering less, equal, greater;
28+
};
29+
constexpr strong_ordering strong_ordering::less = {-1};
30+
constexpr strong_ordering strong_ordering::equal = {0};
31+
constexpr strong_ordering strong_ordering::greater = {1};
32+
}
33+
34+
struct DefaultSpaceship {
35+
friend auto operator<=>(DefaultSpaceship, DefaultSpaceship) = default;
36+
};
37+
38+
static_assert(__builtin_lt_synthesises_from_spaceship(const DefaultSpaceship&, const DefaultSpaceship&));
39+
static_assert(__builtin_le_synthesises_from_spaceship(const DefaultSpaceship&, const DefaultSpaceship&));
40+
static_assert(__builtin_gt_synthesises_from_spaceship(const DefaultSpaceship&, const DefaultSpaceship&));
41+
static_assert(__builtin_ge_synthesises_from_spaceship(const DefaultSpaceship&, const DefaultSpaceship&));
42+
43+
struct CustomSpaceship {
44+
int i;
45+
46+
friend auto operator<=>(CustomSpaceship lhs, CustomSpaceship rhs) {
47+
return rhs.i <=> lhs.i;
48+
}
49+
};
50+
51+
static_assert(__builtin_lt_synthesises_from_spaceship(const CustomSpaceship&, const CustomSpaceship&));
52+
static_assert(__builtin_le_synthesises_from_spaceship(const CustomSpaceship&, const CustomSpaceship&));
53+
static_assert(__builtin_gt_synthesises_from_spaceship(const CustomSpaceship&, const CustomSpaceship&));
54+
static_assert(__builtin_ge_synthesises_from_spaceship(const CustomSpaceship&, const CustomSpaceship&));
55+
56+
struct CustomLT {
57+
int i;
58+
59+
friend auto operator<(CustomLT lhs, CustomLT rhs) {
60+
return rhs.i < lhs.i;
61+
}
62+
};
63+
64+
static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomLT&, const CustomLT&));
65+
static_assert(!__builtin_le_synthesises_from_spaceship(const CustomLT&, const CustomLT&));
66+
static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomLT&, const CustomLT&));
67+
static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomLT&, const CustomLT&));
68+
69+
struct CustomLE {
70+
int i;
71+
72+
friend auto operator<=(CustomLE lhs, CustomLE rhs) {
73+
return rhs.i < lhs.i;
74+
}
75+
};
76+
77+
static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomLE&, const CustomLE&));
78+
static_assert(!__builtin_le_synthesises_from_spaceship(const CustomLE&, const CustomLE&));
79+
static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomLE&, const CustomLE&));
80+
static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomLE&, const CustomLE&));
81+
82+
struct CustomGT {
83+
int i;
84+
85+
friend auto operator>(CustomGT lhs, CustomGT rhs) {
86+
return rhs.i < lhs.i;
87+
}
88+
};
89+
90+
static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomGT&, const CustomGT&));
91+
static_assert(!__builtin_le_synthesises_from_spaceship(const CustomGT&, const CustomGT&));
92+
static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomGT&, const CustomGT&));
93+
static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomGT&, const CustomGT&));
94+
95+
struct CustomGE {
96+
int i;
97+
98+
friend auto operator>=(CustomGE lhs, CustomGE rhs) {
99+
return rhs.i < lhs.i;
100+
}
101+
};
102+
103+
static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomGE&, const CustomGE&));
104+
static_assert(!__builtin_le_synthesises_from_spaceship(const CustomGE&, const CustomGE&));
105+
static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomGE&, const CustomGE&));
106+
static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomGE&, const CustomGE&));
107+
108+
struct CustomLTAndSpaceship {
109+
int i;
110+
111+
friend auto operator<=>(CustomLTAndSpaceship lhs, CustomLTAndSpaceship rhs) {
112+
return rhs.i <=> lhs.i;
113+
}
114+
115+
friend auto operator<(CustomLTAndSpaceship lhs, CustomLTAndSpaceship rhs) {
116+
return rhs.i < lhs.i;
117+
}
118+
};
119+
120+
static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomLTAndSpaceship&, const CustomLTAndSpaceship&));
121+
static_assert(__builtin_le_synthesises_from_spaceship(const CustomLTAndSpaceship&, const CustomLTAndSpaceship&));
122+
static_assert(__builtin_gt_synthesises_from_spaceship(const CustomLTAndSpaceship&, const CustomLTAndSpaceship&));
123+
static_assert(__builtin_ge_synthesises_from_spaceship(const CustomLTAndSpaceship&, const CustomLTAndSpaceship&));
124+
125+
struct CustomLEAndSpaceship {
126+
int i;
127+
128+
friend auto operator<=>(CustomLEAndSpaceship lhs, CustomLEAndSpaceship rhs) {
129+
return rhs.i <=> lhs.i;
130+
}
131+
132+
friend auto operator<=(CustomLEAndSpaceship lhs, CustomLEAndSpaceship rhs) {
133+
return rhs.i < lhs.i;
134+
}
135+
};
136+
137+
static_assert(__builtin_lt_synthesises_from_spaceship(const CustomLEAndSpaceship&, const CustomLEAndSpaceship&));
138+
static_assert(!__builtin_le_synthesises_from_spaceship(const CustomLEAndSpaceship&, const CustomLEAndSpaceship&));
139+
static_assert(__builtin_gt_synthesises_from_spaceship(const CustomLEAndSpaceship&, const CustomLEAndSpaceship&));
140+
static_assert(__builtin_ge_synthesises_from_spaceship(const CustomLEAndSpaceship&, const CustomLEAndSpaceship&));
141+
142+
struct CustomGTAndSpaceship {
143+
int i;
144+
145+
friend auto operator<=>(CustomGTAndSpaceship lhs, CustomGTAndSpaceship rhs) {
146+
return rhs.i <=> lhs.i;
147+
}
148+
149+
friend auto operator>(CustomGTAndSpaceship lhs, CustomGTAndSpaceship rhs) {
150+
return rhs.i < lhs.i;
151+
}
152+
};
153+
154+
static_assert(__builtin_lt_synthesises_from_spaceship(const CustomGTAndSpaceship&, const CustomGTAndSpaceship&));
155+
static_assert(__builtin_le_synthesises_from_spaceship(const CustomGTAndSpaceship&, const CustomGTAndSpaceship&));
156+
static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomGTAndSpaceship&, const CustomGTAndSpaceship&));
157+
static_assert(__builtin_ge_synthesises_from_spaceship(const CustomGTAndSpaceship&, const CustomGTAndSpaceship&));
158+
159+
struct CustomGEAndSpaceship {
160+
int i;
161+
162+
friend auto operator<=>(CustomGEAndSpaceship lhs, CustomGEAndSpaceship rhs) {
163+
return rhs.i <=> lhs.i;
164+
}
165+
166+
friend auto operator>=(CustomGEAndSpaceship lhs, CustomGEAndSpaceship rhs) {
167+
return rhs.i < lhs.i;
168+
}
169+
};
170+
171+
static_assert(__builtin_lt_synthesises_from_spaceship(const CustomGEAndSpaceship&, const CustomGEAndSpaceship&));
172+
static_assert(__builtin_le_synthesises_from_spaceship(const CustomGEAndSpaceship&, const CustomGEAndSpaceship&));
173+
static_assert(__builtin_gt_synthesises_from_spaceship(const CustomGEAndSpaceship&, const CustomGEAndSpaceship&));
174+
static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomGEAndSpaceship&, const CustomGEAndSpaceship&));
175+
176+
struct DefaultedCmpAndSpaceship {
177+
int i;
178+
179+
friend auto operator<=>(DefaultedCmpAndSpaceship lhs, DefaultedCmpAndSpaceship rhs) {
180+
return rhs.i <=> lhs.i;
181+
}
182+
183+
friend bool operator<(DefaultedCmpAndSpaceship lhs, DefaultedCmpAndSpaceship rhs) = default;
184+
friend bool operator<=(DefaultedCmpAndSpaceship lhs, DefaultedCmpAndSpaceship rhs) = default;
185+
friend bool operator>(DefaultedCmpAndSpaceship lhs, DefaultedCmpAndSpaceship rhs) = default;
186+
friend bool operator>=(DefaultedCmpAndSpaceship lhs, DefaultedCmpAndSpaceship rhs) = default;
187+
};
188+
189+
// TODO: This should probably return true
190+
static_assert(!__builtin_lt_synthesises_from_spaceship(const DefaultedCmpAndSpaceship&, const DefaultedCmpAndSpaceship&));
191+
static_assert(!__builtin_le_synthesises_from_spaceship(const DefaultedCmpAndSpaceship&, const DefaultedCmpAndSpaceship&));
192+
static_assert(!__builtin_gt_synthesises_from_spaceship(const DefaultedCmpAndSpaceship&, const DefaultedCmpAndSpaceship&));
193+
static_assert(!__builtin_ge_synthesises_from_spaceship(const DefaultedCmpAndSpaceship&, const DefaultedCmpAndSpaceship&));
194+
195+
struct DifferentTypes {
196+
int i;
197+
198+
friend auto operator<=>(DifferentTypes lhs, int rhs) {
199+
return rhs <=> lhs.i;
200+
}
201+
};
202+
203+
static_assert(__builtin_lt_synthesises_from_spaceship(const DifferentTypes&, const int&));
204+
static_assert(__builtin_le_synthesises_from_spaceship(const DifferentTypes&, const int&));
205+
static_assert(__builtin_gt_synthesises_from_spaceship(const DifferentTypes&, const int&));
206+
static_assert(__builtin_ge_synthesises_from_spaceship(const DifferentTypes&, const int&));
207+
208+
// TODO: Should this return true? It's technically not synthesized from spaceship, but it behaves exactly as-if it was
209+
static_assert(!__builtin_lt_synthesises_from_spaceship(int, int));
210+
static_assert(!__builtin_le_synthesises_from_spaceship(int, int));
211+
static_assert(!__builtin_gt_synthesises_from_spaceship(int, int));
212+
static_assert(!__builtin_ge_synthesises_from_spaceship(int, int));

clang/test/SemaCXX/type-traits.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4199,7 +4199,7 @@ class Template {};
41994199
static_assert(!__is_trivially_equality_comparable(Template<Template<int>>));
42004200

42014201

4202-
struct S operator==(S, S);
4202+
struct DefaultSpaceship operator==(S, S);
42034203

42044204
template <class> struct basic_string_view {};
42054205

@@ -4778,7 +4778,7 @@ void check_decay() {
47784778

47794779
template <class T> struct CheckAbominableFunction {};
47804780
template <class M>
4781-
struct CheckAbominableFunction<M S::*> {
4781+
struct CheckAbominableFunction<M DefaultSpaceship::*> {
47824782
static void checks() {
47834783
static_assert(__is_same(add_lvalue_reference_t<M>, M));
47844784
static_assert(__is_same(add_pointer_t<M>, M));
@@ -4794,17 +4794,17 @@ struct CheckAbominableFunction<M S::*> {
47944794
};
47954795

47964796
void check_abominable_function() {
4797-
{ CheckAbominableFunction<int (S::*)() &> x; }
4798-
{ CheckAbominableFunction<int (S::*)() &&> x; }
4799-
{ CheckAbominableFunction<int (S::*)() const> x; }
4800-
{ CheckAbominableFunction<int (S::*)() const &> x; }
4801-
{ CheckAbominableFunction<int (S::*)() const &&> x; }
4802-
{ CheckAbominableFunction<int (S::*)() volatile> x; }
4803-
{ CheckAbominableFunction<int (S::*)() volatile &> x; }
4804-
{ CheckAbominableFunction<int (S::*)() volatile &&> x; }
4805-
{ CheckAbominableFunction<int (S::*)() const volatile> x; }
4806-
{ CheckAbominableFunction<int (S::*)() const volatile &> x; }
4807-
{ CheckAbominableFunction<int (S::*)() const volatile &&> x; }
4797+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() &> x; }
4798+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() &&> x; }
4799+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() const> x; }
4800+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() const &> x; }
4801+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() const &&> x; }
4802+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() volatile> x; }
4803+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() volatile &> x; }
4804+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() volatile &&> x; }
4805+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() const volatile> x; }
4806+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() const volatile &> x; }
4807+
{ CheckAbominableFunction<int (DefaultSpaceship::*)() const volatile &&> x; }
48084808
}
48094809

48104810
template <class T> using make_signed_t = __make_signed(T);

0 commit comments

Comments
 (0)