rucc_types/kind.rs
1//! What a C type is made of, before any of it has been interned.
2//!
3//! Design: `spec/07-types-and-semantics.md` section 7.1.
4//!
5//! Everything here is `Copy` and small, because [`TypeKind`] is the interning key and a key
6//! that owns a heap allocation cannot be hashed cheaply or compared cheaply. The two parts of
7//! a type that are genuinely variable length, a function's parameter list and a record's
8//! members, live in side tables and are referred to by index.
9
10use std::num::NonZeroU32;
11
12use rucc_base::Symbol;
13
14use crate::TypeId;
15
16/// The qualifiers a type can carry.
17///
18/// A bitmask in the interning key rather than a chain of wrapper nodes, so `const int` is one
19/// entry in the table beside `int` rather than a node pointing at it. That makes stripping
20/// qualifiers a field read instead of a walk, which matters because almost every semantic rule
21/// in C is stated on the unqualified type.
22///
23/// `_Atomic` is deliberately not here. C lets it be written in the same position as a
24/// qualifier, but `_Atomic(T)` is a different type from `T` with its own size and alignment,
25/// so it is a type constructor, [`TypeKind::Atomic`], and the parser is what maps the
26/// qualifier spelling onto it.
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash, PartialOrd, Ord)]
28pub struct Qualifiers(u8);
29
30impl Qualifiers {
31 /// No qualifiers.
32 pub const NONE: Qualifiers = Qualifiers(0);
33 /// `const`.
34 pub const CONST: Qualifiers = Qualifiers(1);
35 /// `volatile`.
36 pub const VOLATILE: Qualifiers = Qualifiers(2);
37 /// `restrict`.
38 pub const RESTRICT: Qualifiers = Qualifiers(4);
39
40 /// Whether every qualifier in `other` is present here.
41 #[inline]
42 #[must_use]
43 pub const fn has(self, other: Qualifiers) -> bool {
44 self.0 & other.0 == other.0
45 }
46
47 /// This set with `other` added.
48 #[inline]
49 #[must_use]
50 pub const fn with(self, other: Qualifiers) -> Qualifiers {
51 Qualifiers(self.0 | other.0)
52 }
53
54 /// This set with `other` removed.
55 #[inline]
56 #[must_use]
57 pub const fn without(self, other: Qualifiers) -> Qualifiers {
58 Qualifiers(self.0 & !other.0)
59 }
60
61 /// Whether there are no qualifiers at all.
62 #[inline]
63 #[must_use]
64 pub const fn is_none(self) -> bool {
65 self.0 == 0
66 }
67}
68
69/// The standard integer types, the character types kept apart from them, and `__int128`.
70///
71/// `Char` is its own kind rather than an alias for one of the other two. The standard makes
72/// plain `char` a third type distinct from both `signed char` and `unsigned char` even though
73/// it has the same range as one of them, and a compiler that folds it into whichever one the
74/// target picked gets `char *` and `signed char *` wrongly deemed compatible.
75///
76/// `__int128` is here rather than modelled as a `_BitInt(128)`, because the two are different
77/// types with different layouts: `__int128` is sixteen bytes aligned to sixteen on every
78/// target we have, and `_BitInt(128)` is aligned to its granule, which is eight on x86-64. It
79/// is available everywhere for us, since all three architectures are 64-bit, and GCC has it
80/// on every 64-bit target. It is deliberately not an extended integer type in the sense the
81/// standard means, which is what keeps `intmax_t` sixty four bits wide the way GCC has it.
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
83pub enum IntKind {
84 /// `char`, whose signedness is a target property.
85 Char,
86 /// `signed char`.
87 SChar,
88 /// `unsigned char`.
89 UChar,
90 /// `short`.
91 Short,
92 /// `unsigned short`.
93 UShort,
94 /// `int`.
95 Int,
96 /// `unsigned int`.
97 UInt,
98 /// `long`, the width that separates LP64 from Windows LLP64.
99 Long,
100 /// `unsigned long`.
101 ULong,
102 /// `long long`.
103 LongLong,
104 /// `unsigned long long`.
105 ULongLong,
106 /// `__int128`.
107 Int128,
108 /// `unsigned __int128`.
109 UInt128,
110}
111
112impl IntKind {
113 /// Every integer kind, in rank order, with `__int128` last.
114 ///
115 /// The order is what the internal index agrees with, and it is also the order the standard
116 /// walks when it picks the type of an integer constant, so a table walk over the candidate
117 /// list for a suffix is a walk over a slice of this. `__int128` is at the end because that
118 /// is where GCC reaches for it: after every standard type has been tried and none of them
119 /// was wide enough.
120 pub const ALL: [IntKind; 13] = [
121 IntKind::Char,
122 IntKind::SChar,
123 IntKind::UChar,
124 IntKind::Short,
125 IntKind::UShort,
126 IntKind::Int,
127 IntKind::UInt,
128 IntKind::Long,
129 IntKind::ULong,
130 IntKind::LongLong,
131 IntKind::ULongLong,
132 IntKind::Int128,
133 IntKind::UInt128,
134 ];
135
136 /// A dense index, so that one of these can select a slot in a fixed size array.
137 pub(crate) const fn index(self) -> usize {
138 match self {
139 IntKind::Char => 0,
140 IntKind::SChar => 1,
141 IntKind::UChar => 2,
142 IntKind::Short => 3,
143 IntKind::UShort => 4,
144 IntKind::Int => 5,
145 IntKind::UInt => 6,
146 IntKind::Long => 7,
147 IntKind::ULong => 8,
148 IntKind::LongLong => 9,
149 IntKind::ULongLong => 10,
150 IntKind::Int128 => 11,
151 IntKind::UInt128 => 12,
152 }
153 }
154
155 /// Whether this type is signed, given what the target says about plain `char`.
156 ///
157 /// The argument is there because `char` is the one integer type whose signedness is not
158 /// in the standard. It is signed on x86-64 and unsigned on AArch64 Linux, and a compiler
159 /// that assumes either one is the source of a whole genre of bug report.
160 #[must_use]
161 pub const fn is_signed(self, char_is_signed: bool) -> bool {
162 match self {
163 IntKind::Char => char_is_signed,
164 IntKind::SChar
165 | IntKind::Short
166 | IntKind::Int
167 | IntKind::Long
168 | IntKind::LongLong
169 | IntKind::Int128 => true,
170 IntKind::UChar
171 | IntKind::UShort
172 | IntKind::UInt
173 | IntKind::ULong
174 | IntKind::ULongLong
175 | IntKind::UInt128 => false,
176 }
177 }
178
179 /// The integer conversion rank, as an ordering rather than as a number from the standard.
180 ///
181 /// The standard gives no values, only a set of relations, and every one of them is a
182 /// comparison between two ranks. Signed and unsigned of the same width share a rank, which
183 /// is what makes the usual arithmetic conversions between them pick the unsigned type
184 /// rather than the wider one.
185 #[must_use]
186 pub const fn rank(self) -> u8 {
187 match self {
188 IntKind::Char | IntKind::SChar | IntKind::UChar => 1,
189 IntKind::Short | IntKind::UShort => 2,
190 IntKind::Int | IntKind::UInt => 3,
191 IntKind::Long | IntKind::ULong => 4,
192 IntKind::LongLong | IntKind::ULongLong => 5,
193 // Above `long long`, which is what makes `__int128 + unsigned long long` an
194 // `__int128` rather than an unsigned type. Both compilers agree.
195 IntKind::Int128 | IntKind::UInt128 => 6,
196 }
197 }
198
199 /// The same width with the other signedness.
200 ///
201 /// `char` maps to `unsigned char` and back to `signed char`, which is the mapping the
202 /// usual arithmetic conversions need and is not a round trip. That asymmetry is the type
203 /// system telling the truth: there is no way back to plain `char` from either of the
204 /// other two.
205 #[must_use]
206 pub const fn flip_sign(self) -> IntKind {
207 match self {
208 IntKind::Char | IntKind::SChar => IntKind::UChar,
209 IntKind::UChar => IntKind::SChar,
210 IntKind::Short => IntKind::UShort,
211 IntKind::UShort => IntKind::Short,
212 IntKind::Int => IntKind::UInt,
213 IntKind::UInt => IntKind::Int,
214 IntKind::Long => IntKind::ULong,
215 IntKind::ULong => IntKind::Long,
216 IntKind::LongLong => IntKind::ULongLong,
217 IntKind::ULongLong => IntKind::LongLong,
218 IntKind::Int128 => IntKind::UInt128,
219 IntKind::UInt128 => IntKind::Int128,
220 }
221 }
222
223 /// How the type is spelled in a diagnostic.
224 #[must_use]
225 pub const fn as_str(self) -> &'static str {
226 match self {
227 IntKind::Char => "char",
228 IntKind::SChar => "signed char",
229 IntKind::UChar => "unsigned char",
230 IntKind::Short => "short",
231 IntKind::UShort => "unsigned short",
232 IntKind::Int => "int",
233 IntKind::UInt => "unsigned int",
234 IntKind::Long => "long",
235 IntKind::ULong => "unsigned long",
236 IntKind::LongLong => "long long",
237 IntKind::ULongLong => "unsigned long long",
238 IntKind::Int128 => "__int128",
239 IntKind::UInt128 => "unsigned __int128",
240 }
241 }
242}
243
244/// The real floating types.
245///
246/// Nine of them, which is three standard ones and six from C23 Annex H. The interchange types
247/// `_Float16`, `_Float32`, `_Float64` and `_Float128` name an IEEE format outright, and the
248/// extended types `_Float32x` and `_Float64x` name whatever the target has that is wider than
249/// the interchange type they are named after, which makes `_Float64x` the x87 format on x86 and
250/// quad precision on AArch64. None of them is the standard type it shares a format with:
251/// `_Float64` and `double` are both binary64 and are two types, which `_Generic` can tell apart
252/// and which decides what `_Float64 + double` is.
253///
254/// `_Float128x` is a type no target gcc supports has, so it is not here. The decimal floating
255/// types from C23 are deferred past 1.0 by `spec/19-open-questions.md` and are deliberately
256/// absent rather than present and unimplemented.
257#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
258pub enum FloatKind {
259 /// `_Float16`, always the binary16 format.
260 Float16,
261 /// `float`, always the binary32 format.
262 Float,
263 /// `_Float32`, always the binary32 format, and not the same type as `float`.
264 Float32,
265 /// `double`, always the binary64 format.
266 Double,
267 /// `_Float32x`, the format the target has that is wider than `_Float32`, which is binary64
268 /// everywhere this compiles for.
269 Float32x,
270 /// `_Float64`, always the binary64 format, and not the same type as `double`.
271 Float64,
272 /// `long double`, whose format is a target property and is not always distinct from
273 /// `double`. It is 80 bits of x87 on SysV x86-64, quad precision on AArch64 Linux, and
274 /// the same as `double` on Apple and Windows.
275 LongDouble,
276 /// `_Float64x`, the format the target has that is wider than `_Float64`. That is the x87
277 /// eighty bit format on x86-64 and quad precision on AArch64 and RISC-V, and unlike
278 /// `long double` it does not become a `double` on Apple or on Windows.
279 Float64x,
280 /// `_Float128`, always the binary128 format.
281 Float128,
282}
283
284impl FloatKind {
285 /// Every real floating type, in the order they are written above.
286 ///
287 /// Not in rank order, because there is no such order to put them in: which of `long double`
288 /// and `_Float64x` is the wider one is a question about the target, and on Apple the answer
289 /// is the second.
290 pub const ALL: [FloatKind; 9] = [
291 FloatKind::Float16,
292 FloatKind::Float,
293 FloatKind::Float32,
294 FloatKind::Double,
295 FloatKind::Float32x,
296 FloatKind::Float64,
297 FloatKind::LongDouble,
298 FloatKind::Float64x,
299 FloatKind::Float128,
300 ];
301
302 /// A dense index, so that one of these can select a slot in a fixed size array.
303 pub(crate) const fn index(self) -> usize {
304 match self {
305 FloatKind::Float16 => 0,
306 FloatKind::Float => 1,
307 FloatKind::Float32 => 2,
308 FloatKind::Double => 3,
309 FloatKind::Float32x => 4,
310 FloatKind::Float64 => 5,
311 FloatKind::LongDouble => 6,
312 FloatKind::Float64x => 7,
313 FloatKind::Float128 => 8,
314 }
315 }
316
317 /// What decides between two of these when they have the same format.
318 ///
319 /// Two real floating types can be the same format and still be two types, and then the
320 /// format cannot say which of them an operation on both of them produces. C23 answers with
321 /// the family first: an interchange type wins over the standard type it shares a format
322 /// with, and the standard type wins over an extended one, so `double + _Float64` is a
323 /// `_Float64` and `double + _Float32x` is a `double`. Inside a family it is the usual order,
324 /// which only ever comes up between `double` and `long double` on the targets where the
325 /// second one is the first one.
326 ///
327 /// Higher wins. This is not an ordering on the types on its own, because it says nothing
328 /// about the formats: `_Float32` sits above `long double` here and loses to it everywhere it
329 /// meets it.
330 #[must_use]
331 pub const fn tie_break(self) -> u8 {
332 match self {
333 FloatKind::Float32x => 0,
334 FloatKind::Float64x => 1,
335 FloatKind::Float => 4,
336 FloatKind::Double => 5,
337 FloatKind::LongDouble => 6,
338 FloatKind::Float16 => 8,
339 FloatKind::Float32 => 9,
340 FloatKind::Float64 => 10,
341 FloatKind::Float128 => 11,
342 }
343 }
344
345 /// How the type is spelled in a diagnostic.
346 #[must_use]
347 pub const fn as_str(self) -> &'static str {
348 match self {
349 FloatKind::Float16 => "_Float16",
350 FloatKind::Float => "float",
351 FloatKind::Float32 => "_Float32",
352 FloatKind::Double => "double",
353 FloatKind::Float32x => "_Float32x",
354 FloatKind::Float64 => "_Float64",
355 FloatKind::LongDouble => "long double",
356 FloatKind::Float64x => "_Float64x",
357 FloatKind::Float128 => "_Float128",
358 }
359 }
360}
361
362/// How many elements an array has, which is four different answers in C.
363#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
364pub enum ArrayLen {
365 /// `int a[4]`. The count of elements, not the size in bytes.
366 Fixed(u64),
367 /// `int a[]`, an incomplete array type. It has an element type and no size, and it is
368 /// completed by an initializer or by a later declaration.
369 Unknown,
370 /// `int a[*]`, a variably modified type in a prototype, where the size exists but is not
371 /// available to the declaration that mentions it.
372 Star,
373 /// `int a[n]`, a variable length array. The size expression stays in the AST, and the
374 /// type carries only the identity of the one that made it, because two variable length
375 /// arrays written with the same element type are still distinct types.
376 Variable(VlaId),
377}
378
379/// The identity of one variable length array's size expression.
380///
381/// An opaque number handed out by whoever is building the type, which in practice is
382/// semantic analysis walking a declarator. This crate never looks inside it; it is here so
383/// that interning two variable length arrays does not accidentally make them the same type.
384#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
385pub struct VlaId(pub u32);
386
387/// Whether a record is a `struct` or a `union`.
388#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
389pub enum RecordKind {
390 /// `struct`, whose members are laid out one after another.
391 Struct,
392 /// `union`, whose members all start at offset zero.
393 Union,
394}
395
396impl RecordKind {
397 /// How the keyword is spelled in a diagnostic.
398 #[must_use]
399 pub const fn as_str(self) -> &'static str {
400 match self {
401 RecordKind::Struct => "struct",
402 RecordKind::Union => "union",
403 }
404 }
405}
406
407/// What a type is, with its qualifiers stripped off into [`Type::quals`].
408///
409/// This is `Copy` and sixteen bytes, which is what lets it be the interning key directly.
410/// Function types and record types are the two that carry a variable amount of information,
411/// and both of them are an index into a table this crate owns.
412#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
413pub enum TypeKind {
414 /// `void`.
415 Void,
416 /// `bool`, which C23 spells without an underscore and which is one byte with two values.
417 Bool,
418 /// One of the standard integer types.
419 Int(IntKind),
420 /// One of the real floating types.
421 Float(FloatKind),
422 /// `_Complex T` for a real floating `T`.
423 Complex(FloatKind),
424 /// `_BitInt(N)` and `unsigned _BitInt(N)`.
425 ///
426 /// A distinct kind rather than an integer type with a width, because these do not take
427 /// part in the integer promotions and folding them in with the standard types is how
428 /// that rule gets forgotten.
429 BitInt {
430 /// Whether the type is signed. A signed `_BitInt(1)` is legal and holds `0` and `-1`.
431 signed: bool,
432 /// The declared width in bits, which is what the standard calls `N`.
433 width: u32,
434 },
435 /// A pointer to the given type.
436 Pointer(TypeId),
437 /// `_Atomic(T)`, which is a type and not a qualifier. See [`Qualifiers`].
438 Atomic(TypeId),
439 /// An array of the given element type.
440 Array {
441 /// The element type.
442 elem: TypeId,
443 /// How many of them there are, which may be unknown.
444 len: ArrayLen,
445 },
446 /// A function type, whose parameter list is in this crate's side table.
447 Function(FunctionId),
448 /// A GNU vector type, `__attribute__((vector_size(n)))`.
449 Vector {
450 /// The element type, which must be a scalar.
451 elem: TypeId,
452 /// How many elements there are.
453 len: u32,
454 },
455 /// A `struct` or `union`, identified by its declaration rather than by its members.
456 Record(RecordId),
457 /// An `enum`, identified by its declaration.
458 Enum(EnumId),
459 /// A typedef name, which is sugar over whatever it was declared as.
460 ///
461 /// Every semantic decision reads [`Types::canonical`](crate::Types::canonical) and never
462 /// sees this; every diagnostic reads the type as written and sees nothing else, so the
463 /// error says `size_t` rather than `unsigned long`. Compilers that drop the sugar produce
464 /// messages nobody can act on, and compilers that decide on the sugar produce wrong
465 /// answers, and both are common.
466 Typedef {
467 /// The name, for printing.
468 name: Symbol,
469 /// What it was declared as.
470 underlying: TypeId,
471 /// What `__attribute__((aligned(n)))` on the typedef asked an object of it to be
472 /// aligned to, and [`None`] when it asked for nothing.
473 ///
474 /// The one thing a typedef changes about the type behind it, and the reason the
475 /// alignment is on this node rather than in a table beside it: two typedefs of one
476 /// underlying type that ask for different alignments are two types, so the alignment
477 /// has to be part of what the table interns them by.
478 ///
479 /// It is what the type is aligned to and not a floor on it. Written on a declaration
480 /// the attribute only ever raises, and written on a typedef GCC lets it lower as well,
481 /// so `typedef int L __attribute__((aligned(2)))` really is an `int` at a multiple of
482 /// two and `struct { char c; L x; }` really is six bytes.
483 align: Option<NonZeroU32>,
484 },
485}
486
487/// A type with its qualifiers, which together are one entry in the type table.
488#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
489pub struct Type {
490 /// What the type is.
491 pub kind: TypeKind,
492 /// What it is qualified with.
493 pub quals: Qualifiers,
494}
495
496impl Type {
497 /// An unqualified type of the given kind.
498 #[must_use]
499 pub const fn new(kind: TypeKind) -> Type {
500 Type { kind, quals: Qualifiers::NONE }
501 }
502}
503
504/// The identity of a function type in [`Types`](crate::Types).
505///
506/// Deduplicated by content, so two declarations written with the same return type, the same
507/// parameters and the same variadic flag share one of these and therefore one [`TypeId`].
508#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
509pub struct FunctionId(pub(crate) u32);
510
511/// The identity of a `struct` or `union` declaration in [`Types`](crate::Types).
512///
513/// Not deduplicated by content, because record types in C are nominal. Two `struct` types
514/// written with the same members in the same translation unit are different types, and the
515/// looser relation that does hold between them is compatibility rather than identity.
516#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
517pub struct RecordId(pub(crate) u32);
518
519/// The identity of an `enum` declaration in [`Types`](crate::Types).
520#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
521pub struct EnumId(pub(crate) u32);
522
523/// A function type.
524#[derive(Debug, Clone, PartialEq, Eq, Hash)]
525pub struct FunctionType {
526 /// What it returns.
527 pub ret: TypeId,
528 /// The parameter types, after the adjustments a parameter declaration gets: an array
529 /// parameter has already decayed to a pointer and a function parameter to a function
530 /// pointer, because those adjustments are part of forming the type and not part of
531 /// calling it.
532 pub params: Vec<TypeId>,
533 /// Whether the list ends in `...`.
534 pub variadic: bool,
535 /// Whether there was a prototype at all.
536 ///
537 /// `int f()` declares an unprototyped function before C23 and a function taking no
538 /// arguments from C23 onwards, and the difference is visible in what calls are checked
539 /// and in what the composite type of a redeclaration is. The dialect decides which
540 /// meaning `()` gets, and this records the decision rather than repeating it.
541 pub prototyped: bool,
542}