cinrs_core/ir.rs
1//! The typed intermediate representation.
2//!
3//! [`sema`](crate::sema) turns the untyped [`ast`](crate::ast) into this tree
4//! and [`codegen`](crate::codegen) turns this tree into Rust tokens. The two
5//! halves are deliberately separated by a data structure rather than by a
6//! traversal, for three reasons:
7//!
8//! * **Types never leak into the AST.** The AST records what the user wrote;
9//! the IR records what it *means*. Every implicit conversion C performs —
10//! integer promotions, the usual arithmetic conversions, array-to-pointer
11//! decay, the conversion on assignment, initialisation, argument passing and
12//! `return` — is an explicit node here, so codegen never has to re-derive a
13//! type or guess where an `as` belongs.
14//!
15//! * **Sema is pure.** Nothing in this module refers to `proc_macro2`; every
16//! node carries a [`SourceRange`] into the captured C text, which codegen
17//! resolves to a span. That is what lets sema run on a thread with a large
18//! stack while codegen — which needs the (non-`Send`) source map — runs on
19//! the caller's.
20//!
21//! * **Control flow is already resolved.** `break` and `continue` name the
22//! loop or switch they leave ([`BreakTarget`], [`LoopId`]), a `goto` names
23//! the label it jumps to ([`LabelId`]), and a `switch` arrives as an ordered
24//! list of groups rather than as a statement tree with labels buried in it.
25//! Codegen can therefore be a straight transliteration.
26//!
27//! A function that jumps is the exception: `goto`, and a `case` label the
28//! groups cannot express, send the whole body through [`crate::cfg`] instead,
29//! and its [`Body`] is a graph of basic blocks rather than a statement list.
30//!
31//! # Interned types
32//!
33//! [`Ty`] stays a small `Copy` value even though C's types are trees: the
34//! scalar types are variants of their own, and every derived type (pointer,
35//! array, function) is an index into the [`Types`] arena that hash-conses them.
36//! Two `int *` written in different places therefore compare equal with a
37//! single integer comparison, which is what the assignment rules and the switch
38//! over "what kind of thing is this" in codegen are written against.
39//!
40//! `struct`, `union` and `enum` are *nominal*, exactly as C says: each tag
41//! definition allocates a [`RecordId`] or [`EnumId`] of its own, and two
42//! structurally identical tags are different types. The tables also hold the
43//! computed [`Layout`], so `sizeof` folds to a constant everywhere.
44//!
45//! # Places
46//!
47//! Anything assignable is a [`Place`]: a named object, `*p`, `a[i]`, `s.f`, a
48//! string literal, or the temporary that holds a `struct` returned by value.
49//! The abstraction is what compound assignment and `++`/`--` are written
50//! against, so the "evaluate the operand exactly once" rule is expressed
51//! structurally: `p[i()] += 1` is one [`ExprKind::CompoundAssign`] holding one
52//! place, not a re-evaluated expression. Codegen lowers a place into a *setup*
53//! (statements that must run first, where the pointer arithmetic lands) plus an
54//! *access* that can be evaluated as often as needed.
55
56use std::collections::HashMap;
57
58use crate::capture::SourceRange;
59use crate::target::TargetModel;
60
61// ---------------------------------------------------------------------------
62// types
63// ---------------------------------------------------------------------------
64
65/// The spelling of the `va_list` type the compiler owns, which means
66/// [`Ty::VaList`].
67///
68/// It is the only one: the bundled `<stdarg.h>` writes
69/// `typedef __builtin_va_list va_list;`, the way GCC's own header does, so a
70/// translation unit that does not include it may use `va_list`, `va_end` and
71/// the rest as ordinary identifiers of its own. The name is seeded into the
72/// parser's and sema's outermost scopes, where a program may repeat the
73/// `typedef` but not give the name a different meaning.
74pub const VA_LIST_NAMES: &[&str] = &["__builtin_va_list"];
75
76/// The `typedef` names the compiler owns for the two 128-bit integer types,
77/// with the [`Ty`] each one means.
78///
79/// GCC predefines `__int128_t` and `__uint128_t` in every mode alongside the
80/// `__int128` keyword, and a great deal of code spells them that way. Like
81/// [`VA_LIST_NAMES`] they are seeded into the parser's and sema's outermost
82/// scopes, so `__int128_t *p;` is a declaration rather than a multiplication.
83pub const INT128_TYPEDEF_NAMES: &[(&str, Ty)] =
84 &[("__int128_t", Ty::Int128), ("__uint128_t", Ty::UInt128)];
85
86/// The `typedef` names the compiler owns for the x86 vector types, with the
87/// [`Ty`] each one means.
88///
89/// `__m128` and its five relatives are the compiler's types, not the library's:
90/// GCC writes them in `<xmmintrin.h>` as `__attribute__((vector_size(16)))`,
91/// which cinrs has no equivalent of, so the bundled header writes
92/// `typedef __cinrs_m128 __m128;` over a name seeded into the parser's and
93/// sema's outermost scopes — exactly the arrangement [`VA_LIST_NAMES`] uses
94/// for `va_list`. A translation unit that does not include the header may
95/// therefore still use `__m128` as an identifier of its own.
96pub const X86_VECTOR_TYPEDEF_NAMES: &[(&str, Ty)] = &[
97 ("__cinrs_m128", Ty::Vector(VecTy::M128)),
98 ("__cinrs_m128d", Ty::Vector(VecTy::M128d)),
99 ("__cinrs_m128i", Ty::Vector(VecTy::M128i)),
100 ("__cinrs_m256", Ty::Vector(VecTy::M256)),
101 ("__cinrs_m256d", Ty::Vector(VecTy::M256d)),
102 ("__cinrs_m256i", Ty::Vector(VecTy::M256i)),
103 ("__cinrs_m512", Ty::Vector(VecTy::M512)),
104 ("__cinrs_m512d", Ty::Vector(VecTy::M512d)),
105 ("__cinrs_m512i", Ty::Vector(VecTy::M512i)),
106 ("__cinrs_m128bh", Ty::Vector(VecTy::M128bh)),
107 ("__cinrs_m256bh", Ty::Vector(VecTy::M256bh)),
108 ("__cinrs_m512bh", Ty::Vector(VecTy::M512bh)),
109 ("__cinrs_m128h", Ty::Vector(VecTy::M128h)),
110 ("__cinrs_m256h", Ty::Vector(VecTy::M256h)),
111 ("__cinrs_m512h", Ty::Vector(VecTy::M512h)),
112];
113
114/// The builtin C23's `unreachable()` stands for.
115///
116/// The bundled `<stddef.h>` writes `#define unreachable() __builtin_unreachable()`,
117/// the way GCC's does, so a unit that does not include it may use the name
118/// `unreachable` for whatever it likes.
119pub const UNREACHABLE_BUILTIN: &str = "__builtin_unreachable";
120
121/// The names Rust cannot spell even as raw identifiers.
122///
123/// A C identifier that is one of them is generated with an underscore
124/// appended, which both code generation and the naming of the bit-field
125/// accessors have to agree on.
126pub const NEVER_RAW: &[&str] = &["self", "Self", "super", "crate", "_"];
127
128/// The Rust identifier a C name is generated as, spelled out.
129///
130/// Only the names [`NEVER_RAW`] lists change; a name that collides with an
131/// ordinary keyword becomes a raw identifier, which is the same identifier.
132///
133/// This is the rule as it stands before the translation unit is taken into
134/// account — enough to tell two accessor names of one record apart, which is
135/// all [`crate::sema`] needs it for. The spelling the generated code actually
136/// carries is [`crate::codegen`]'s, which also keeps a changed spelling clear
137/// of every other name the unit uses.
138pub fn rust_name_of(name: &str) -> String {
139 if NEVER_RAW.contains(&name) {
140 return format!("{name}_");
141 }
142 name.to_owned()
143}
144
145/// A pointer type in the [`Types`] arena.
146#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
147pub struct PointerId(pub u32);
148
149/// An array type in the [`Types`] arena.
150#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
151pub struct ArrayId(pub u32);
152
153/// A function type in the [`Types`] arena.
154#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
155pub struct FuncTyId(pub u32);
156
157/// A `struct` or `union` definition in the [`Types`] arena.
158#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
159pub struct RecordId(pub u32);
160
161/// An `enum` definition in the [`Types`] arena.
162#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
163pub struct EnumId(pub u32);
164
165/// An `_Atomic` type in the [`Types`] arena.
166#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
167pub struct AtomicId(pub u32);
168
169/// A resolved C type.
170///
171/// `long double` is mapped onto [`Ty::Double`] when the type is resolved,
172/// because there is no portable Rust type with the layout of an x87 extended
173/// double; the mapping is documented rather than diagnosed, since a procedural
174/// macro has no stable way to raise a warning.
175#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
176pub enum Ty {
177 /// `void`
178 Void,
179 /// `_Bool`
180 Bool,
181 /// Plain `char`, whose signedness is the target's business and which is a
182 /// distinct type from both `signed char` and `unsigned char`.
183 Char,
184 /// `signed char`
185 SChar,
186 /// `unsigned char`
187 UChar,
188 /// `short`
189 Short,
190 /// `unsigned short`
191 UShort,
192 /// `int`
193 Int,
194 /// `unsigned int`
195 UInt,
196 /// `long`
197 Long,
198 /// `unsigned long`
199 ULong,
200 /// `long long`
201 LongLong,
202 /// `unsigned long long`
203 ULongLong,
204 /// GNU's `__int128` (also spelled `__int128_t`), which ranks above
205 /// `long long` and is generated as Rust's `i128`.
206 Int128,
207 /// `unsigned __int128` (also spelled `__uint128_t`), generated as `u128`.
208 UInt128,
209 /// `float`
210 Float,
211 /// `double` (and `long double`)
212 Double,
213 /// `float _Complex`, generated as `cinrs_rt::Complex<f32>`.
214 ///
215 /// C calls the complex types *floating* types and therefore arithmetic
216 /// ones, but almost nothing in this crate wants them where a `float` or a
217 /// `double` goes: [`Ty::is_floating`] is deliberately the *real* floating
218 /// types only, and [`Ty::is_complex`] is the question to ask about these.
219 ComplexFloat,
220 /// `double _Complex` (and `long double _Complex`), generated as
221 /// `cinrs_rt::Complex<f64>`.
222 ComplexDouble,
223 /// A pointer, including a pointer to a function.
224 Pointer(PointerId),
225 /// An array of a known length.
226 Array(ArrayId),
227 /// A function type. Only ever reached through a pointer or as the type of
228 /// a function designator.
229 Func(FuncTyId),
230 /// A `struct` or `union`, complete or not.
231 Record(RecordId),
232 /// A file-scope `enum` with a tag, which becomes a named `c_int` alias.
233 /// Every other `enum` is simply [`Ty::Int`].
234 Enum(EnumId),
235 /// `va_list` (and its `__builtin_va_list` / `__gnuc_va_list` spellings),
236 /// which becomes [`core::ffi::VaList`].
237 ///
238 /// The type is opaque: it has no size, nothing may point at it, and it may
239 /// only be a local variable or a parameter — see [`crate::sema`] for why.
240 VaList,
241 /// One of x86's vector types: `__m128`, `__m128i`, `__m128d`, `__m256`,
242 /// `__m256i` or `__m256d`.
243 ///
244 /// Opaque, exactly as C sees it: there is no arithmetic on one, no
245 /// conversion to or from one, and no way to reach a lane except through an
246 /// intrinsic or through a union. What it *is* is an object of a known size
247 /// and alignment — sixteen or thirty-two bytes, aligned to itself — which
248 /// is what makes it a member, an element, a parameter, a return value and
249 /// the thing a `union { __m128i v; int i[4]; }` punnes. Code generation
250 /// writes `::core::arch::x86_64::__m128i`, whose layout is the same.
251 Vector(VecTy),
252 /// `_Atomic T`, for a scalar `T` (C11 6.7.2.4).
253 ///
254 /// It is the type of an *object*, never of a value: reading an atomic
255 /// lvalue is an atomic load whose result has the underlying type, so
256 /// [`ExprKind::Load`] of an atomic place is typed [`Types::unatomic`] of
257 /// it and nothing downstream of the load ever meets this variant. Where it
258 /// does appear is a declared object, a member, a pointee and `sizeof` —
259 /// which is why it is a type rather than a flag on the declaration:
260 /// `_Atomic int *` and `int *` are different types, and a store through
261 /// the first one is atomic.
262 ///
263 /// The alignment is the size (see [`Types::size_align`]), which is what
264 /// makes `_Atomic long long` eight-byte aligned on a target whose plain
265 /// `long long` is not.
266 Atomic(AtomicId),
267 /// The type of something whose declaration was already reported as wrong.
268 ///
269 /// It exists so that one bad declaration produces one diagnostic: an object
270 /// declared `int a[n]` still enters the symbol table, and every later use of
271 /// it is checked against a type that silences further complaints instead of
272 /// "use of undeclared identifier".
273 Error,
274}
275
276/// Which x86 vector type a [`Ty::Vector`] is.
277///
278/// The name is the same in C and in `core::arch`, which is the whole point:
279/// the generated Rust says `::core::arch::x86_64::__m128i` and Rust's type has
280/// the size, the alignment and the calling convention C's has.
281#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
282pub enum VecTy {
283 /// `__m128`: four `float` lanes.
284 M128,
285 /// `__m128i`: sixteen bytes of integer lanes, whatever width.
286 M128i,
287 /// `__m128d`: two `double` lanes.
288 M128d,
289 /// `__m256`: eight `float` lanes.
290 M256,
291 /// `__m256i`: thirty-two bytes of integer lanes.
292 M256i,
293 /// `__m256d`: four `double` lanes.
294 M256d,
295 /// `__m512`: sixteen `float` lanes (AVX-512).
296 M512,
297 /// `__m512i`: sixty-four bytes of integer lanes.
298 M512i,
299 /// `__m512d`: eight `double` lanes.
300 M512d,
301 /// `__m128bh`, `__m256bh`, `__m512bh`: bfloat16 lanes (AVX512-BF16). C
302 /// only moves them between intrinsics; no scalar `__bf16` is needed.
303 M128bh,
304 /// See [`VecTy::M128bh`].
305 M256bh,
306 /// See [`VecTy::M128bh`].
307 M512bh,
308 /// `__m128h`, `__m256h`, `__m512h`: half-precision lanes (AVX512-FP16),
309 /// opaque in the same way: no `_Float16` scalar is needed.
310 M128h,
311 /// See [`VecTy::M128h`].
312 M256h,
313 /// See [`VecTy::M128h`].
314 M512h,
315}
316
317impl VecTy {
318 /// The name, which C and `core::arch` spell the same way.
319 pub fn name(self) -> &'static str {
320 match self {
321 VecTy::M128 => "__m128",
322 VecTy::M128i => "__m128i",
323 VecTy::M128d => "__m128d",
324 VecTy::M256 => "__m256",
325 VecTy::M256i => "__m256i",
326 VecTy::M256d => "__m256d",
327 VecTy::M512 => "__m512",
328 VecTy::M512i => "__m512i",
329 VecTy::M512d => "__m512d",
330 VecTy::M128bh => "__m128bh",
331 VecTy::M256bh => "__m256bh",
332 VecTy::M512bh => "__m512bh",
333 VecTy::M128h => "__m128h",
334 VecTy::M256h => "__m256h",
335 VecTy::M512h => "__m512h",
336 }
337 }
338
339 /// `sizeof`, which is also `_Alignof`: a vector type is aligned to its own
340 /// width on every x86 ABI, and so is Rust's.
341 pub fn bytes(self) -> u64 {
342 match self {
343 VecTy::M128 | VecTy::M128i | VecTy::M128d | VecTy::M128bh | VecTy::M128h => 16,
344 VecTy::M256 | VecTy::M256i | VecTy::M256d | VecTy::M256bh | VecTy::M256h => 32,
345 VecTy::M512 | VecTy::M512i | VecTy::M512d | VecTy::M512bh | VecTy::M512h => 64,
346 }
347 }
348}
349
350/// A pointer type: what it points at, and whether that is `const`.
351#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
352pub struct PointerType {
353 /// The pointee type.
354 pub pointee: Ty,
355 /// Whether the pointee is `const`-qualified, which decides between
356 /// `*const T` and `*mut T`.
357 pub konst: bool,
358 /// The alignment the pointee has *in C*, when a `typedef` gave it one
359 /// that is not its type's own: `typedef uint64_t
360 /// __attribute__((aligned(1))) u64_unaligned;` makes `u64_unaligned *` a
361 /// pointer to a `u64` that may sit at any address. The Rust type is the
362 /// same `*const u64`; what changes is that every access through it is a
363 /// `read_unaligned`/`write_unaligned` (see `Codegen::place_underaligned`).
364 /// `None` is the pointee type's own alignment, which is almost always.
365 /// Two pointer types differing only here are compatible (GCC treats the
366 /// `typedef` as a variant of the same type).
367 pub align: Option<u64>,
368}
369
370/// One dimension of a [variably modified](Types::is_vm) array type.
371#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
372pub enum VmDim {
373 /// A constant bound, outside a variable one: the `3` of `int a[3][n]`.
374 Fixed(u64),
375 /// A run-time bound, held by a hidden `size_t` object.
376 Len(ObjectId),
377 /// A run-time bound the type does not carry — `int a[*]`, or a
378 /// prototype's, which is never evaluated (C99 6.7.5.3p7).
379 Unknown,
380}
381
382/// An array type.
383#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
384pub struct ArrayType {
385 /// The element type.
386 pub elem: Ty,
387 /// The number of elements, zero for a [variable length
388 /// array](ArrayType::vla), whose length is only known at run time.
389 pub len: u64,
390 /// Whether the element type is `const`-qualified, which is what decides
391 /// the constness of the pointer the array decays to.
392 pub elem_const: bool,
393 /// Whether this is a variable length array (C99 6.7.5.2), whose bound was
394 /// not an integer constant expression.
395 ///
396 /// The bound itself is not a number here but a *run-time object*, named by
397 /// [`ArrayType::vla_len`], which is why `sizeof` of one is an expression
398 /// rather than a constant. See [`Stmt::Vla`].
399 pub vla: bool,
400 /// The hidden `size_t` object holding this dimension's length, for a
401 /// [variable length array](ArrayType::vla) whose declaration evaluated its
402 /// bound.
403 ///
404 /// `None` says the length is not available: `int a[*]`, and the parameter
405 /// types of a prototype, whose bounds are never evaluated because C99
406 /// 6.7.5.3p7 leaves them out of the type. Two variably modified types are
407 /// compatible whatever their bounds (6.7.5.2p6), so this is deliberately
408 /// *not* part of what [`crate::sema`] compares — only of what the
409 /// generated code computes with.
410 pub vla_len: Option<ObjectId>,
411 /// Whether the bound was left out — `int j[]`, C99 6.2.5p22's *incomplete*
412 /// array type.
413 ///
414 /// It is what `extern int j[];` declares, and what a file-scope `int j[];`
415 /// with no initialiser is until the end of the translation unit completes
416 /// it to one element (6.9.2p5). `sizeof` of one is an error, but it may be
417 /// pointed at, subscripted and decayed like any other array, and it is
418 /// *compatible* with every completed array of the same element type
419 /// (6.2.7p1), which is what lets `extern int j[]; int j[3];` declare one
420 /// object.
421 pub incomplete: bool,
422}
423
424/// A function type.
425#[derive(Clone, PartialEq, Eq, Hash, Debug)]
426pub struct FuncType {
427 /// The return type.
428 pub ret: Ty,
429 /// The parameter types, after the adjustments C applies to them.
430 pub params: Vec<Ty>,
431 /// Whether the prototype ended with `, ...`.
432 pub variadic: bool,
433 /// Whether a parameter type list was given at all.
434 ///
435 /// `int f(void)` and `int f(int)` have a prototype; `int f()` — before C23,
436 /// which removed the form — does not, and says nothing about the number or
437 /// the types of the parameters. An unprototyped type has no parameters and
438 /// is never variadic, so `ret` is all that distinguishes two of them; the
439 /// difference from `int (void)` is what a call site has to know, since an
440 /// argument passed to one gets the default argument promotions and is then
441 /// passed as if the prototype had been written that way (C99 6.5.2.2p6).
442 pub prototyped: bool,
443}
444
445/// `struct` or `union`.
446#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
447pub enum RecordKind {
448 /// `struct`
449 Struct,
450 /// `union`
451 Union,
452}
453
454impl RecordKind {
455 /// The keyword that introduces this kind of record.
456 pub fn as_str(self) -> &'static str {
457 match self {
458 RecordKind::Struct => "struct",
459 RecordKind::Union => "union",
460 }
461 }
462}
463
464/// The size and alignment of a complete type, in bytes.
465#[derive(Clone, Copy, PartialEq, Eq, Debug)]
466pub struct Layout {
467 /// `sizeof` the type.
468 pub size: u64,
469 /// `_Alignof` the type.
470 pub align: u64,
471}
472
473/// What makes a member a bit-field (C99 6.7.2.1).
474///
475/// A bit-field has no address of its own, so it is not a Rust field: a maximal
476/// run of them shares one `[u8; K]` storage field, and reading or writing one
477/// goes through a pair of generated accessors. Everything code generation needs
478/// to emit those — where the bits are and how wide they are — lives here.
479#[derive(Clone, Debug)]
480pub struct BitField {
481 /// The declared width, in bits.
482 pub width: u32,
483 /// The bit offset from the start of the record, counting from the least
484 /// significant bit of byte 0 (the little-endian bit order every ABI this
485 /// crate targets uses).
486 pub bit_offset: u64,
487 /// Whether reading the field sign-extends.
488 ///
489 /// Usually the signedness of the declared type; an `enum` bit-field follows
490 /// the enumeration's underlying type instead, which GCC and Clang make
491 /// unsigned when no enumerator is negative.
492 pub signed: bool,
493 /// The name of the `[u8; K]` field the bits live in.
494 pub storage: String,
495 /// The byte offset of that field within the record.
496 pub storage_offset: u64,
497 /// The name of the generated getter.
498 pub getter: String,
499 /// The name of the generated setter.
500 pub setter: String,
501}
502
503impl BitField {
504 /// The bit offset of the field within its storage array.
505 pub fn offset_in_storage(&self) -> u64 {
506 self.bit_offset - self.storage_offset * 8
507 }
508}
509
510/// One member of a `struct` or `union`.
511#[derive(Clone, Debug)]
512pub struct Field {
513 /// The member name as written in C, or the synthetic `__cinrs_anonN` an
514 /// anonymous member is generated under.
515 pub name: String,
516 /// Whether this is an anonymous `struct`/`union` member (C11 6.7.2.1p13),
517 /// whose own members are reached through it as if they were the enclosing
518 /// record's.
519 pub anonymous: bool,
520 /// The member type.
521 pub ty: Ty,
522 /// Whether the member's type is `const`-qualified.
523 pub is_const: bool,
524 /// The byte offset from the start of the record (always 0 in a union).
525 ///
526 /// For a bit-field this is the byte the field's first bit falls in; the
527 /// exact position is in [`Field::bits`].
528 pub offset: u64,
529 /// Set when the member was declared with a width.
530 pub bits: Option<BitField>,
531 /// Whether this is the flexible array member `int data[];` — an array of
532 /// no elements that the object is expected to be over-allocated for.
533 pub flexible: bool,
534 /// Where the member was declared.
535 pub range: SourceRange,
536}
537
538/// One field of the generated Rust item.
539///
540/// A record without bit-fields maps one C member onto one Rust field, and this
541/// is simply its member list. Bit-fields break that correspondence: they share
542/// storage, they may be unnamed, and the bytes they occupy do not always start
543/// where `#[repr(C)]` would put the next field on its own.
544#[derive(Clone, Debug)]
545pub enum RustField {
546 /// A C member, by its index in [`RecordDef::fields`].
547 Member(usize),
548 /// The bytes one maximal run of bit-fields lives in.
549 Bits {
550 /// The field name, `__cinrs_bitsN`.
551 name: String,
552 /// The byte offset of the run within the record.
553 offset: u64,
554 /// How many bytes it covers.
555 bytes: u64,
556 },
557 /// Filler that puts the field after it where C puts it.
558 Pad {
559 /// The field name, `__cinrs_padN`.
560 name: String,
561 /// How many bytes it covers.
562 bytes: u64,
563 },
564 /// A zero-sized field whose only job is to raise the item's alignment.
565 ///
566 /// `#[repr(C, align(N))]` says the same thing and reads better, so it is
567 /// what a record normally carries. A record that is a member of a *packed*
568 /// one cannot use it: Rust refuses a packed type that transitively holds a
569 /// `#[repr(align)]` one (`E0588`), while C is perfectly happy to pack such
570 /// a member. A `[uN; 0]` field costs no bytes, raises the alignment the
571 /// same way, and is not a `repr(align)` type.
572 Align {
573 /// The field name, `__cinrs_alignN`.
574 name: String,
575 /// The alignment it carries, in bytes.
576 align: u64,
577 },
578}
579
580/// A `struct` or `union` tag.
581#[derive(Clone, Debug)]
582pub struct RecordDef {
583 /// Whether this is a `struct` or a `union`.
584 pub kind: RecordKind,
585 /// The C tag, absent for an anonymous `struct { … }`.
586 pub tag: Option<String>,
587 /// The name of the generated Rust item, already made unique.
588 pub rust_name: String,
589 /// Whether `rust_name` is still the synthetic name given to an anonymous
590 /// tag, and may therefore be replaced by the name of a `typedef` of it.
591 pub anonymous: bool,
592 /// The members, in declaration order. Empty while the tag is incomplete.
593 ///
594 /// An unnamed bit-field is *not* here: it declares no member, so nothing
595 /// can name it and no initialiser reaches it. It still occupies bits, and
596 /// [`RecordDef::rust_fields`] accounts for them.
597 pub fields: Vec<Field>,
598 /// The fields of the generated Rust item, in order.
599 pub rust_fields: Vec<RustField>,
600 /// Whether a member list has been seen.
601 pub complete: bool,
602 /// The layout, computed once the tag is complete.
603 pub layout: Option<Layout>,
604 /// The alignment `_Alignas` on a member raised the record to, which
605 /// becomes `#[repr(C, align(N))]` on the generated item.
606 pub align: Option<u64>,
607 /// The maximum member alignment `__attribute__((packed))` or
608 /// `#pragma pack(N)` asked for, which becomes `#[repr(C, packed(N))]`.
609 pub packed: Option<u64>,
610 /// The alignment the *generated Rust item* has, which is [`Layout::align`]
611 /// except for a packed record — Rust refuses `packed` and `align(N)`
612 /// together, so such an item is one byte aligned however strict C says the
613 /// record is. Laying out a record that has one as a member reads this
614 /// rather than the C alignment, so that the padding it inserts puts the
615 /// member where both sides agree it goes.
616 pub rust_align: u64,
617 /// Whether the record ends in a flexible array member.
618 pub flexible: bool,
619 /// Whether an item should be generated for this tag.
620 pub emit: bool,
621 /// The C type this record stands in for, when it is not a record in C at
622 /// all: `_Float128`, which may be named but never computed with, is a
623 /// struct of sixteen bytes here. Diagnostics name the C type.
624 pub stands_for: Option<&'static str>,
625 /// Where the tag was defined (or first mentioned).
626 pub range: SourceRange,
627}
628
629/// One `enum` constant.
630#[derive(Clone, Debug)]
631pub struct Enumerator {
632 /// The name as written in C.
633 pub name: String,
634 /// The name of the generated Rust `const`, already made unique.
635 pub rust_name: String,
636 /// The constant's type: `int`, or the fixed underlying type a C23 `enum`
637 /// was given.
638 pub ty: Ty,
639 /// The value.
640 pub value: i128,
641 /// Where it was written.
642 pub range: SourceRange,
643}
644
645/// A file-scope `enum` tag, which becomes a named `c_int` alias.
646#[derive(Clone, Debug)]
647pub struct EnumDef {
648 /// Whether the enumeration's underlying type is unsigned, which is what GCC
649 /// and Clang pick when no enumerator is negative.
650 ///
651 /// The choice is implementation defined and only observable through a
652 /// bit-field of the type, which is where this is used; everywhere else an
653 /// enumeration is `int`, as [`Ty::Enum`] says.
654 pub unsigned: bool,
655 /// The C tag, if one was written.
656 pub tag: Option<String>,
657 /// The name of the generated Rust type alias.
658 pub rust_name: String,
659 /// Whether `rust_name` is still synthetic and may be replaced by a
660 /// `typedef` name.
661 pub anonymous: bool,
662 /// Whether an alias item should be generated.
663 pub emit: bool,
664 /// Where the tag was defined.
665 pub range: SourceRange,
666}
667
668/// The arena of derived and tagged types.
669///
670/// Pointers, arrays and function types are hash-consed, so [`Ty`] equality is
671/// C's type compatibility for them; `struct`, `union` and `enum` are nominal
672/// and are simply appended.
673#[derive(Clone, Debug, Default)]
674pub struct Types {
675 pointers: Vec<PointerType>,
676 arrays: Vec<ArrayType>,
677 funcs: Vec<FuncType>,
678 records: Vec<RecordDef>,
679 enums: Vec<EnumDef>,
680 atomics: Vec<Ty>,
681 pointer_index: HashMap<PointerType, PointerId>,
682 array_index: HashMap<ArrayType, ArrayId>,
683 func_index: HashMap<FuncType, FuncTyId>,
684 atomic_index: HashMap<Ty, AtomicId>,
685}
686
687impl Types {
688 /// An empty arena.
689 pub fn new() -> Self {
690 Self::default()
691 }
692
693 /// The type `pointee *`, with `konst` set when the pointee is `const`.
694 pub fn pointer(&mut self, pointee: Ty, konst: bool) -> Ty {
695 self.pointer_aligned(pointee, konst, None)
696 }
697
698 /// The type `pointee *` where the pointee's C alignment is `align` rather
699 /// than its type's own; see [`PointerType::align`].
700 pub fn pointer_aligned(&mut self, pointee: Ty, konst: bool, align: Option<u64>) -> Ty {
701 let key = PointerType {
702 pointee,
703 konst,
704 align,
705 };
706 if let Some(id) = self.pointer_index.get(&key) {
707 return Ty::Pointer(*id);
708 }
709 let id = PointerId(self.pointers.len() as u32);
710 self.pointers.push(key);
711 self.pointer_index.insert(key, id);
712 Ty::Pointer(id)
713 }
714
715 /// The type `_Atomic inner`, for a scalar `inner`.
716 ///
717 /// Wrapping an atomic type again gives the same type back: C11 6.7.3p5
718 /// makes `_Atomic _Atomic int` the same as `_Atomic int`, exactly as a
719 /// repeated `const` is.
720 pub fn atomic(&mut self, inner: Ty) -> Ty {
721 if matches!(inner, Ty::Atomic(_)) {
722 return inner;
723 }
724 if let Some(id) = self.atomic_index.get(&inner) {
725 return Ty::Atomic(*id);
726 }
727 let id = AtomicId(self.atomics.len() as u32);
728 self.atomics.push(inner);
729 self.atomic_index.insert(inner, id);
730 Ty::Atomic(id)
731 }
732
733 /// The type inside a [`Ty::Atomic`].
734 ///
735 /// # Panics
736 ///
737 /// Panics if `id` did not come from this arena.
738 pub fn atomic_inner(&self, id: AtomicId) -> Ty {
739 self.atomics[id.0 as usize]
740 }
741
742 /// `ty` with an `_Atomic` taken off it, which is what reading an atomic
743 /// lvalue produces (C11 6.3.2.1p2: lvalue conversion drops the
744 /// qualifiers).
745 pub fn unatomic(&self, ty: Ty) -> Ty {
746 match ty {
747 Ty::Atomic(id) => self.atomic_inner(id),
748 other => other,
749 }
750 }
751
752 /// Whether `ty` is an `_Atomic` type.
753 pub fn is_atomic(&self, ty: Ty) -> bool {
754 matches!(ty, Ty::Atomic(_))
755 }
756
757 /// The type `elem[len]`.
758 pub fn array(&mut self, elem: Ty, len: u64, elem_const: bool) -> Ty {
759 self.array_type_of(ArrayType {
760 elem,
761 len,
762 elem_const,
763 vla: false,
764 vla_len: None,
765 incomplete: false,
766 })
767 }
768
769 /// The type `elem[n]` for a bound that is not a constant: a variable
770 /// length array, whose length lives in the object `vla_len` names.
771 pub fn vla_array(&mut self, elem: Ty, elem_const: bool, vla_len: Option<ObjectId>) -> Ty {
772 self.array_type_of(ArrayType {
773 elem,
774 len: 0,
775 elem_const,
776 vla: true,
777 vla_len,
778 incomplete: false,
779 })
780 }
781
782 /// The type `elem[]` — an array whose bound was left out (6.2.5p22).
783 pub fn incomplete_array(&mut self, elem: Ty, elem_const: bool) -> Ty {
784 self.array_type_of(ArrayType {
785 elem,
786 len: 0,
787 elem_const,
788 vla: false,
789 vla_len: None,
790 incomplete: true,
791 })
792 }
793
794 /// The same type with the elements of every array in it `const`.
795 ///
796 /// C99 6.7.3p9: "If the specification of an array type includes any type
797 /// qualifiers, the element type is so-qualified, not the array type."
798 /// Writing the declarator says so by itself — the qualifier in
799 /// `const int a[1]` is on `int` — but the `typedef` spelling does not:
800 ///
801 /// ```c
802 /// typedef int A[1];
803 /// const A a; /* `const int[1]`, so `&a` is `const int (*)[1]` */
804 /// ```
805 ///
806 /// and neither does `typeof`. Anything that is not an array is returned
807 /// as it stands, because every other type carries `const` on the object
808 /// rather than in [`Ty`].
809 ///
810 /// A multidimensional array is an array *of arrays*, and the element type
811 /// the qualifier lands on is the one that is not an array — exactly where
812 /// the declarator spelling puts it, so that `const int a[2][3]` and
813 /// `typedef int A[2][3]; const A a;` are one type.
814 pub fn const_elements(&mut self, ty: Ty) -> Ty {
815 let Ty::Array(id) = ty else {
816 return ty;
817 };
818 let array = self.array_type(id);
819 if array.elem.is_array() {
820 let elem = self.const_elements(array.elem);
821 if elem == array.elem {
822 return ty;
823 }
824 return self.array_type_of(ArrayType { elem, ..array });
825 }
826 if array.elem_const {
827 return ty;
828 }
829 self.array_type_of(ArrayType {
830 elem_const: true,
831 ..array
832 })
833 }
834
835 fn array_type_of(&mut self, key: ArrayType) -> Ty {
836 if let Some(id) = self.array_index.get(&key) {
837 return Ty::Array(*id);
838 }
839 let id = ArrayId(self.arrays.len() as u32);
840 self.arrays.push(key);
841 self.array_index.insert(key, id);
842 Ty::Array(id)
843 }
844
845 /// The type of a function with a prototype.
846 pub fn func(&mut self, ret: Ty, params: Vec<Ty>, variadic: bool) -> Ty {
847 self.func_type_of(FuncType {
848 ret,
849 params,
850 variadic,
851 prototyped: true,
852 })
853 }
854
855 /// The type `ret ()`: a function whose parameters are unspecified.
856 ///
857 /// See [`FuncType::prototyped`]. Only the return type varies, so this needs
858 /// nothing else.
859 pub fn unprototyped_func(&mut self, ret: Ty) -> Ty {
860 self.func_type_of(FuncType {
861 ret,
862 params: Vec::new(),
863 variadic: false,
864 prototyped: false,
865 })
866 }
867
868 /// The interned type for a function type description.
869 pub fn func_type_of(&mut self, key: FuncType) -> Ty {
870 if let Some(id) = self.func_index.get(&key) {
871 return Ty::Func(*id);
872 }
873 let id = FuncTyId(self.funcs.len() as u32);
874 self.funcs.push(key.clone());
875 self.func_index.insert(key, id);
876 Ty::Func(id)
877 }
878
879 /// Adds a `struct` or `union` tag.
880 pub fn add_record(&mut self, def: RecordDef) -> RecordId {
881 let id = RecordId(self.records.len() as u32);
882 self.records.push(def);
883 id
884 }
885
886 /// Adds an `enum` tag.
887 pub fn add_enum(&mut self, def: EnumDef) -> EnumId {
888 let id = EnumId(self.enums.len() as u32);
889 self.enums.push(def);
890 id
891 }
892
893 /// The pointer type behind a [`Ty::Pointer`].
894 ///
895 /// # Panics
896 ///
897 /// Panics if `id` did not come from this arena.
898 pub fn pointer_type(&self, id: PointerId) -> PointerType {
899 self.pointers[id.0 as usize]
900 }
901
902 /// The array type behind a [`Ty::Array`].
903 ///
904 /// # Panics
905 ///
906 /// Panics if `id` did not come from this arena.
907 pub fn array_type(&self, id: ArrayId) -> ArrayType {
908 self.arrays[id.0 as usize]
909 }
910
911 /// The function type behind a [`Ty::Func`].
912 ///
913 /// # Panics
914 ///
915 /// Panics if `id` did not come from this arena.
916 pub fn func_type(&self, id: FuncTyId) -> &FuncType {
917 &self.funcs[id.0 as usize]
918 }
919
920 /// A tag definition.
921 ///
922 /// # Panics
923 ///
924 /// Panics if `id` did not come from this arena.
925 pub fn record(&self, id: RecordId) -> &RecordDef {
926 &self.records[id.0 as usize]
927 }
928
929 /// A tag definition, mutably.
930 ///
931 /// # Panics
932 ///
933 /// Panics if `id` did not come from this arena.
934 pub fn record_mut(&mut self, id: RecordId) -> &mut RecordDef {
935 &mut self.records[id.0 as usize]
936 }
937
938 /// Every tag, in definition order.
939 pub fn records(&self) -> &[RecordDef] {
940 &self.records
941 }
942
943 /// Generates no item for any tag added since there were `mark` of them.
944 ///
945 /// What this is for is C23's repeated definition of one tag (N3037): the
946 /// second member list has to be *resolved* to be compared with the first,
947 /// and everything that resolving it created — the tag itself, and any
948 /// anonymous member of it — is then a duplicate of something the first
949 /// definition already generated. The type the program sees is the first
950 /// one; these are left in the arena, unreferenced and unemitted, because
951 /// removing them would move every [`RecordId`] after them.
952 pub fn suppress_records_from(&mut self, mark: usize) {
953 for def in &mut self.records[mark..] {
954 def.emit = false;
955 }
956 }
957
958 /// An `enum` definition.
959 ///
960 /// # Panics
961 ///
962 /// Panics if `id` did not come from this arena.
963 pub fn enum_def(&self, id: EnumId) -> &EnumDef {
964 &self.enums[id.0 as usize]
965 }
966
967 /// An `enum` definition, mutably.
968 ///
969 /// # Panics
970 ///
971 /// Panics if `id` did not come from this arena.
972 pub fn enum_mut(&mut self, id: EnumId) -> &mut EnumDef {
973 &mut self.enums[id.0 as usize]
974 }
975
976 /// Every `enum` definition, in definition order.
977 pub fn enums(&self) -> &[EnumDef] {
978 &self.enums
979 }
980
981 /// What a pointer points at, if `ty` is a pointer.
982 pub fn pointee(&self, ty: Ty) -> Option<Ty> {
983 match ty {
984 Ty::Pointer(id) => Some(self.pointer_type(id).pointee),
985 _ => None,
986 }
987 }
988
989 /// Whether `ty` is a pointer whose pointee is `const`.
990 pub fn points_to_const(&self, ty: Ty) -> bool {
991 match ty {
992 Ty::Pointer(id) => self.pointer_type(id).konst,
993 _ => false,
994 }
995 }
996
997 /// The element type of an array.
998 pub fn elem(&self, ty: Ty) -> Option<Ty> {
999 match ty {
1000 Ty::Array(id) => Some(self.array_type(id).elem),
1001 _ => None,
1002 }
1003 }
1004
1005 /// Whether `ty` is an array whose own bound is a run-time value.
1006 ///
1007 /// `int a[n]` is one and `int a[3][n]` is not — that one is an array *of*
1008 /// variable length arrays, which C calls variably modified all the same.
1009 /// [`Types::is_vm`] is the question to ask about the type as a whole.
1010 pub fn is_vla(&self, ty: Ty) -> bool {
1011 matches!(ty, Ty::Array(id) if self.array_type(id).vla)
1012 }
1013
1014 /// Whether `ty` is *variably modified* (C99 6.7.5.2p4): an array with a
1015 /// run-time bound anywhere in it.
1016 ///
1017 /// A pointer to one is variably modified too by C's definition, but what
1018 /// the question is asked for here is "does this type have a size only the
1019 /// running program knows", and a pointer's size is a constant.
1020 pub fn is_vm(&self, ty: Ty) -> bool {
1021 match ty {
1022 Ty::Array(id) => {
1023 let array = self.array_type(id);
1024 array.vla || self.is_vm(array.elem)
1025 }
1026 _ => false,
1027 }
1028 }
1029
1030 /// The type a pointer into a [variably modified](Types::is_vm) array
1031 /// addresses: what is left after every dimension with a run-time size is
1032 /// taken off.
1033 ///
1034 /// It is the element type a [`Stmt::Vla`] allocates off the function's
1035 /// arena and the pointee of the generated Rust pointer — `double a[n][m]` is a
1036 /// `*mut c_double` over `n * m` of them, and `double a[n][3]` a
1037 /// `*mut [c_double; 3]` over `n`. Everything else about a variably
1038 /// modified type is arithmetic on top of that: see [`Types::vm_dims`].
1039 pub fn vm_step_ty(&self, ty: Ty) -> Ty {
1040 match ty {
1041 Ty::Array(id) if self.is_vm(ty) => self.vm_step_ty(self.array_type(id).elem),
1042 other => other,
1043 }
1044 }
1045
1046 /// The dimensions between `ty` and its [step type](Types::vm_step_ty),
1047 /// outermost first.
1048 ///
1049 /// Their product is how many step-type elements the type holds, which is
1050 /// what `sizeof` multiplies by the element size and what pointer
1051 /// arithmetic on a pointer to `ty` scales by.
1052 pub fn vm_dims(&self, ty: Ty) -> Vec<VmDim> {
1053 let mut out = Vec::new();
1054 let mut ty = ty;
1055 while self.is_vm(ty) {
1056 let Ty::Array(id) = ty else { break };
1057 let array = self.array_type(id);
1058 out.push(match (array.vla, array.vla_len) {
1059 (true, Some(len)) => VmDim::Len(len),
1060 (true, None) => VmDim::Unknown,
1061 // A fixed dimension outside a variable one counts too: the
1062 // rows of `int a[3][n]` are `n` ints apart, and there are
1063 // three of them.
1064 (false, _) => VmDim::Fixed(array.len),
1065 });
1066 ty = array.elem;
1067 }
1068 out
1069 }
1070
1071 /// Whether `ty` is an array whose bound was left out — `int j[]`.
1072 pub fn is_incomplete_array(&self, ty: Ty) -> bool {
1073 matches!(ty, Ty::Array(id) if self.array_type(id).incomplete)
1074 }
1075
1076 /// `elem[1]`, for an incomplete array type: what C99 6.9.2p5 completes a
1077 /// tentative definition with one to at the end of the translation unit.
1078 pub fn complete_tentative_array(&mut self, ty: Ty) -> Option<Ty> {
1079 let Ty::Array(id) = ty else { return None };
1080 let array = self.array_type(id);
1081 if !array.incomplete {
1082 return None;
1083 }
1084 Some(self.array(array.elem, 1, array.elem_const))
1085 }
1086
1087 /// Whether `ty` is a pointer to a function.
1088 pub fn is_func_pointer(&self, ty: Ty) -> bool {
1089 matches!(self.pointee(ty), Some(Ty::Func(_)))
1090 }
1091
1092 /// Whether `ty` is `void *` (however qualified).
1093 pub fn is_void_pointer(&self, ty: Ty) -> bool {
1094 self.pointee(ty) == Some(Ty::Void)
1095 }
1096
1097 /// Whether the two pointer types point at the same thing, ignoring `const`.
1098 pub fn same_pointee(&self, a: Ty, b: Ty) -> bool {
1099 match (a, b) {
1100 (Ty::Pointer(a), Ty::Pointer(b)) => {
1101 self.pointer_type(a).pointee == self.pointer_type(b).pointee
1102 }
1103 _ => false,
1104 }
1105 }
1106
1107 /// The type an array or function decays to in a value context.
1108 pub fn decayed(&mut self, ty: Ty, konst: bool) -> Ty {
1109 match ty {
1110 Ty::Array(id) => {
1111 let array = self.array_type(id);
1112 self.pointer(array.elem, array.elem_const || konst)
1113 }
1114 Ty::Func(_) => self.pointer(ty, false),
1115 other => other,
1116 }
1117 }
1118
1119 /// Whether the type is complete, i.e. whether `sizeof` applies to it.
1120 pub fn is_complete(&self, ty: Ty) -> bool {
1121 match ty {
1122 Ty::Void | Ty::Func(_) | Ty::Error => false,
1123 Ty::Record(id) => self.record(id).complete,
1124 Ty::Array(id) => {
1125 let array = self.array_type(id);
1126 !array.incomplete && self.is_complete(array.elem)
1127 }
1128 _ => true,
1129 }
1130 }
1131
1132 /// The name of a `const`-qualified member of `ty`, if it has one.
1133 ///
1134 /// C11 6.3.2.1p1 makes a structure or union with such a member — "any
1135 /// member (including, recursively, any member or element of all contained
1136 /// aggregates or unions)" — something other than a modifiable lvalue, so
1137 /// the whole object cannot be assigned to even though nothing about the
1138 /// object itself was declared `const`. WG14 DR131 is that rule, and
1139 /// `drs/dr1xx.c` is where it is checked.
1140 ///
1141 /// The walk terminates: a record cannot contain itself by value.
1142 pub fn const_member(&self, ty: Ty) -> Option<&str> {
1143 match ty {
1144 Ty::Record(id) => self.record(id).fields.iter().find_map(|field| {
1145 if field.is_const || self.has_const_elements(field.ty) {
1146 Some(field.name.as_str())
1147 } else {
1148 self.const_member(field.ty)
1149 }
1150 }),
1151 Ty::Array(id) => self.const_member(self.array_type(id).elem),
1152 _ => None,
1153 }
1154 }
1155
1156 /// Whether `ty` is an array whose elements are `const`-qualified.
1157 ///
1158 /// An array type is never itself qualified — 6.7.3p9 puts the qualifiers
1159 /// on the elements — so `const int a[3];` as a member is a `const` member
1160 /// with `is_const` clear.
1161 fn has_const_elements(&self, ty: Ty) -> bool {
1162 match ty {
1163 Ty::Array(id) => {
1164 let array = self.array_type(id);
1165 array.elem_const || self.has_const_elements(array.elem)
1166 }
1167 _ => false,
1168 }
1169 }
1170
1171 /// The size and alignment of `ty`, or `None` when it is incomplete.
1172 pub fn size_align(&self, ty: Ty, target: &TargetModel) -> Option<Layout> {
1173 Some(match ty {
1174 // `va_list` has a layout, but not one this crate can know: it is
1175 // whatever the target's ABI made of it.
1176 Ty::Void | Ty::Func(_) | Ty::Error | Ty::VaList => return None,
1177 Ty::Pointer(_) => {
1178 let size = u64::from(target.ptr_bits).div_ceil(8);
1179 Layout { size, align: size }
1180 }
1181 Ty::Array(id) => {
1182 let array = self.array_type(id);
1183 let elem = self.size_align(array.elem, target)?;
1184 // A variable length array has no size the front end can know:
1185 // `sizeof` of one is a run-time value, computed from the
1186 // object's own hidden length. Answering `None` here is what
1187 // keeps a path that forgot about that loud rather than silently
1188 // wrong.
1189 // An incomplete array has no size either, and `sizeof` of one
1190 // is a constraint violation until a later declaration in the
1191 // same unit completes it.
1192 if array.vla || array.incomplete {
1193 return None;
1194 }
1195 Layout {
1196 size: elem.size.saturating_mul(array.len),
1197 align: elem.align,
1198 }
1199 }
1200 Ty::Record(id) => self.record(id).layout?,
1201 // C11 6.2.5p27 lets an atomic type have a different size and
1202 // alignment from its underlying one, and every implementation
1203 // makes the alignment at least the size: `_Atomic long long` is
1204 // eight-byte aligned on i386, where a plain `long long` is
1205 // four-byte aligned, because that is what a lock-free 64-bit
1206 // instruction needs. Rust's `AtomicU64` says the same thing.
1207 Ty::Atomic(id) => {
1208 let inner = self.size_align(self.atomic_inner(id), target)?;
1209 Layout {
1210 size: inner.size,
1211 align: inner.size.max(inner.align).max(1),
1212 }
1213 }
1214 Ty::Enum(_) => {
1215 let size = u64::from(target.int_bits).div_ceil(8);
1216 Layout { size, align: size }
1217 }
1218 // A complex type is two of its component type laid out side by
1219 // side (C99 6.2.5p13), so it is twice as big and no more strictly
1220 // aligned — which is what `#[repr(C)] struct Complex<T>` gives
1221 // and what every ABI this crate targets says.
1222 Ty::ComplexFloat | Ty::ComplexDouble => {
1223 let component = ty.complex_component().size_bytes(target);
1224 Layout {
1225 size: component * 2,
1226 align: component.min(target.max_scalar_align).max(1),
1227 }
1228 }
1229 // The one scalar whose alignment is not its size on every target;
1230 // see [`TargetModel::int128_align`].
1231 Ty::Int128 | Ty::UInt128 => Layout {
1232 size: 16,
1233 align: target.int128_align,
1234 },
1235 // A vector type is aligned to its own width — sixteen bytes for a
1236 // `__m128i`, thirty-two for a `__m256i` — which is both what the
1237 // x86 ABIs say and what `core::arch`'s types have. The scalar rule
1238 // below would clamp it to [`TargetModel::max_scalar_align`], which
1239 // is eight, and a `_mm_load_si128` from an object aligned to eight
1240 // faults.
1241 Ty::Vector(vec) => Layout {
1242 size: vec.bytes(),
1243 align: vec.bytes(),
1244 },
1245 scalar => {
1246 let size = scalar.size_bytes(target);
1247 // A scalar is aligned to its own width, up to whatever the ABI
1248 // stops at: the i386 System V ABI aligns `long long` and
1249 // `double` to four bytes rather than eight, and `rustc` gives
1250 // `u64` and `f64` the same alignment there. See
1251 // [`TargetModel::max_scalar_align`].
1252 Layout {
1253 size,
1254 align: size.min(target.max_scalar_align).max(1),
1255 }
1256 }
1257 })
1258 }
1259
1260 /// `sizeof ty`, or `None` when it is incomplete.
1261 pub fn size_of(&self, ty: Ty, target: &TargetModel) -> Option<u64> {
1262 self.size_align(ty, target).map(|l| l.size)
1263 }
1264
1265 /// The C spelling of a type, as it should appear in a diagnostic.
1266 pub fn name(&self, ty: Ty) -> String {
1267 match ty {
1268 Ty::Pointer(id) => {
1269 let p = self.pointer_type(id);
1270 if let Ty::Func(f) = p.pointee {
1271 return self.func_name(f, "(*)");
1272 }
1273 let prefix = if p.konst { "const " } else { "" };
1274 format!("{prefix}{} *", self.name(p.pointee))
1275 }
1276 Ty::Array(id) => {
1277 let a = self.array_type(id);
1278 let prefix = if a.elem_const { "const " } else { "" };
1279 if a.vla {
1280 // C's own spelling for an array whose bound is not a
1281 // constant expression; the bound belongs to the object, so
1282 // there is nothing else honest to print.
1283 return format!("{prefix}{}[*]", self.name(a.elem));
1284 }
1285 if a.incomplete {
1286 return format!("{prefix}{}[]", self.name(a.elem));
1287 }
1288 format!("{prefix}{}[{}]", self.name(a.elem), a.len)
1289 }
1290 Ty::Func(id) => self.func_name(id, ""),
1291 Ty::Record(id) => {
1292 let record = self.record(id);
1293 if let Some(c_type) = record.stands_for {
1294 return c_type.to_owned();
1295 }
1296 match &record.tag {
1297 Some(tag) => format!("{} {tag}", record.kind.as_str()),
1298 None => format!("{} {}", record.kind.as_str(), record.rust_name),
1299 }
1300 }
1301 Ty::Enum(id) => {
1302 let def = self.enum_def(id);
1303 match &def.tag {
1304 Some(tag) => format!("enum {tag}"),
1305 None => format!("enum {}", def.rust_name),
1306 }
1307 }
1308 Ty::Atomic(id) => format!("_Atomic({})", self.name(self.atomic_inner(id))),
1309 Ty::Error => "<error>".to_owned(),
1310 scalar => scalar.scalar_name().to_owned(),
1311 }
1312 }
1313
1314 fn func_name(&self, id: FuncTyId, middle: &str) -> String {
1315 let f = self.func_type(id);
1316 let mut params: Vec<String> = f.params.iter().map(|p| self.name(*p)).collect();
1317 if f.variadic {
1318 params.push("...".to_owned());
1319 }
1320 // `int ()` and `int (void)` are two types, and a diagnostic that says
1321 // which one it means is the whole point of the distinction.
1322 if params.is_empty() && f.prototyped {
1323 params.push("void".to_owned());
1324 }
1325 format!("{} {middle}({})", self.name(f.ret), params.join(", "))
1326 }
1327}
1328
1329impl Ty {
1330 /// The C spelling of a scalar type.
1331 ///
1332 /// Derived and tagged types need the arena; use [`Types::name`] for a type
1333 /// that may be one of those.
1334 pub fn scalar_name(self) -> &'static str {
1335 match self {
1336 Ty::Void => "void",
1337 Ty::Bool => "_Bool",
1338 Ty::Char => "char",
1339 Ty::SChar => "signed char",
1340 Ty::UChar => "unsigned char",
1341 Ty::Short => "short",
1342 Ty::UShort => "unsigned short",
1343 Ty::Int => "int",
1344 Ty::UInt => "unsigned int",
1345 Ty::Long => "long",
1346 Ty::ULong => "unsigned long",
1347 Ty::LongLong => "long long",
1348 Ty::ULongLong => "unsigned long long",
1349 Ty::Int128 => "__int128",
1350 Ty::UInt128 => "unsigned __int128",
1351 Ty::Float => "float",
1352 Ty::Double => "double",
1353 Ty::ComplexFloat => "float _Complex",
1354 Ty::ComplexDouble => "double _Complex",
1355 Ty::Pointer(_) => "pointer",
1356 Ty::Array(_) => "array",
1357 Ty::Func(_) => "function",
1358 Ty::Record(_) => "struct",
1359 Ty::Enum(_) => "enum",
1360 Ty::VaList => "va_list",
1361 Ty::Vector(vec) => vec.name(),
1362 Ty::Atomic(_) => "_Atomic",
1363 Ty::Error => "<error>",
1364 }
1365 }
1366
1367 /// Whether this is `void`.
1368 pub fn is_void(self) -> bool {
1369 self == Ty::Void
1370 }
1371
1372 /// Whether this is `_Bool`.
1373 pub fn is_bool(self) -> bool {
1374 self == Ty::Bool
1375 }
1376
1377 /// Whether this is a pointer.
1378 pub fn is_pointer(self) -> bool {
1379 matches!(self, Ty::Pointer(_))
1380 }
1381
1382 /// Whether this is an array.
1383 pub fn is_array(self) -> bool {
1384 matches!(self, Ty::Array(_))
1385 }
1386
1387 /// Whether this is a `struct` or `union`.
1388 pub fn is_record(self) -> bool {
1389 matches!(self, Ty::Record(_))
1390 }
1391
1392 /// Whether this is a function type.
1393 pub fn is_func(self) -> bool {
1394 matches!(self, Ty::Func(_))
1395 }
1396
1397 /// Whether this is a named `enum` type.
1398 pub fn is_enum(self) -> bool {
1399 matches!(self, Ty::Enum(_))
1400 }
1401
1402 /// Whether this is `va_list`.
1403 pub fn is_va_list(self) -> bool {
1404 self == Ty::VaList
1405 }
1406
1407 /// Whether this is one of x86's vector types.
1408 ///
1409 /// They are neither arithmetic nor scalar — nothing C does to a number can
1410 /// be done to one — so every operator asks this before complaining, and
1411 /// says "use an intrinsic" rather than the generic "invalid operands".
1412 pub fn is_vector(self) -> bool {
1413 matches!(self, Ty::Vector(_))
1414 }
1415
1416 /// Whether this stands for something already reported as ill formed.
1417 pub fn is_error(self) -> bool {
1418 self == Ty::Error
1419 }
1420
1421 /// Whether this is an integer type (`_Bool` and `enum` included, as C
1422 /// requires).
1423 pub fn is_integer(self) -> bool {
1424 matches!(
1425 self,
1426 Ty::Bool
1427 | Ty::Char
1428 | Ty::SChar
1429 | Ty::UChar
1430 | Ty::Short
1431 | Ty::UShort
1432 | Ty::Int
1433 | Ty::UInt
1434 | Ty::Long
1435 | Ty::ULong
1436 | Ty::LongLong
1437 | Ty::ULongLong
1438 | Ty::Int128
1439 | Ty::UInt128
1440 | Ty::Enum(_)
1441 )
1442 }
1443
1444 /// Whether this is one of the two 128-bit integer types.
1445 ///
1446 /// They are the only integers whose values do not all fit in the `i128` a
1447 /// constant is carried in, so the places that fold, print or emit one have
1448 /// to know; see [`Ty::wrap`].
1449 pub fn is_int128(self) -> bool {
1450 matches!(self, Ty::Int128 | Ty::UInt128)
1451 }
1452
1453 /// Whether this is `float` or `double` — one of C's *real* floating types.
1454 ///
1455 /// The complex types are floating types too as far as the standard's
1456 /// wording goes; [`Ty::is_complex`] is the question about those, and
1457 /// keeping them out of this one is what stops every existing floating-point
1458 /// path from silently treating a `Complex<f64>` as an `f64`.
1459 pub fn is_floating(self) -> bool {
1460 matches!(self, Ty::Float | Ty::Double)
1461 }
1462
1463 /// Whether this is one of the complex types.
1464 pub fn is_complex(self) -> bool {
1465 matches!(self, Ty::ComplexFloat | Ty::ComplexDouble)
1466 }
1467
1468 /// The *corresponding real type* (C99 6.2.5p14) — the type of each part of
1469 /// a complex value, and the type itself for everything else.
1470 pub fn complex_component(self) -> Ty {
1471 match self {
1472 Ty::ComplexFloat => Ty::Float,
1473 Ty::ComplexDouble => Ty::Double,
1474 other => other,
1475 }
1476 }
1477
1478 /// The complex type whose parts have this real type (C99 6.2.5p13).
1479 ///
1480 /// Anything that is not a real floating type gets `double _Complex`, which
1481 /// is what the usual arithmetic conversions give an integer operand.
1482 pub fn complex_of(self) -> Ty {
1483 match self {
1484 Ty::Float => Ty::ComplexFloat,
1485 Ty::ComplexFloat => Ty::ComplexFloat,
1486 _ => Ty::ComplexDouble,
1487 }
1488 }
1489
1490 /// Whether this is an arithmetic type: an integer, a real floating type, or
1491 /// a complex one (C99 6.2.5p18).
1492 pub fn is_arithmetic(self) -> bool {
1493 self.is_integer() || self.is_floating() || self.is_complex()
1494 }
1495
1496 /// Whether this is a scalar, i.e. something C can compare against zero.
1497 ///
1498 /// An [`Ty::Atomic`] is *not* one: it is the type of an object, and a
1499 /// value read out of one has the underlying type. Everything that asks
1500 /// this question about a declared type therefore has to take the
1501 /// `_Atomic` off first, with [`Types::unatomic`].
1502 pub fn is_scalar(self) -> bool {
1503 self.is_arithmetic() || self.is_pointer()
1504 }
1505
1506 /// Whether this is `_Atomic T`.
1507 pub fn is_atomic(self) -> bool {
1508 matches!(self, Ty::Atomic(_))
1509 }
1510
1511 /// Whether values of this type are signed.
1512 pub fn is_signed(self, target: &TargetModel) -> bool {
1513 match self {
1514 Ty::Char => target.char_signed,
1515 Ty::SChar | Ty::Short | Ty::Int | Ty::Long | Ty::LongLong | Ty::Enum(_) => true,
1516 Ty::Int128 => true,
1517 Ty::Float | Ty::Double | Ty::ComplexFloat | Ty::ComplexDouble => true,
1518 _ => false,
1519 }
1520 }
1521
1522 /// The width of this type in bits.
1523 pub fn bits(self, target: &TargetModel) -> u32 {
1524 match self {
1525 Ty::Void => 0,
1526 Ty::Bool => 1,
1527 Ty::Char | Ty::SChar | Ty::UChar => 8,
1528 Ty::Short | Ty::UShort => target.short_bits,
1529 Ty::Int | Ty::UInt | Ty::Enum(_) => target.int_bits,
1530 Ty::Long | Ty::ULong => target.long_bits,
1531 Ty::LongLong | Ty::ULongLong => target.long_long_bits,
1532 // Not a knob: GCC's `__int128` is 128 bits wherever it exists.
1533 Ty::Int128 | Ty::UInt128 => 128,
1534 Ty::Float => 32,
1535 Ty::Double => 64,
1536 Ty::ComplexFloat => 64,
1537 Ty::ComplexDouble => 128,
1538 Ty::Pointer(_) => target.ptr_bits,
1539 // Not a number of *value* bits — a vector type has no value this
1540 // crate reasons about — but the width the object occupies, which
1541 // is what `sizeof` asks for through [`Ty::size_bytes`].
1542 Ty::Vector(vec) => (vec.bytes() * 8) as u32,
1543 // An atomic type's width is its underlying one's, which needs the
1544 // arena; nothing asks this about one, because every value has
1545 // already had the `_Atomic` taken off it.
1546 Ty::Array(_) | Ty::Func(_) | Ty::Record(_) | Ty::VaList | Ty::Atomic(_) | Ty::Error => {
1547 0
1548 }
1549 }
1550 }
1551
1552 /// `sizeof` this scalar type, in bytes.
1553 ///
1554 /// Aggregates need the arena; use [`Types::size_of`] for a type that may be
1555 /// one.
1556 pub fn size_bytes(self, target: &TargetModel) -> u64 {
1557 match self {
1558 Ty::Void => 1, // GCC's extension; C says this is an error.
1559 Ty::Bool => 1,
1560 _ => u64::from(self.bits(target)).div_ceil(8),
1561 }
1562 }
1563
1564 /// The conversion rank of an integer type (C99 6.3.1.1).
1565 ///
1566 /// Only the ordering matters; the absolute values are arbitrary.
1567 pub fn rank(self) -> u32 {
1568 match self {
1569 Ty::Bool => 1,
1570 Ty::Char | Ty::SChar | Ty::UChar => 2,
1571 Ty::Short | Ty::UShort => 3,
1572 Ty::Int | Ty::UInt | Ty::Enum(_) => 4,
1573 Ty::Long | Ty::ULong => 5,
1574 Ty::LongLong | Ty::ULongLong => 6,
1575 // GCC ranks `__int128` above every standard integer type, which is
1576 // what makes `(__int128)x * y` compute in 128 bits.
1577 Ty::Int128 | Ty::UInt128 => 7,
1578 Ty::Float => 8,
1579 Ty::Double => 9,
1580 // The complex types have no *conversion* rank of their own: C
1581 // ranks their corresponding real types and makes the result
1582 // complex, which is what `usual_arithmetic` does before this is
1583 // ever consulted.
1584 _ => 0,
1585 }
1586 }
1587
1588 /// The unsigned type of the same rank.
1589 pub fn to_unsigned(self) -> Ty {
1590 match self {
1591 Ty::Char | Ty::SChar => Ty::UChar,
1592 Ty::Short => Ty::UShort,
1593 Ty::Int | Ty::Enum(_) => Ty::UInt,
1594 Ty::Long => Ty::ULong,
1595 Ty::LongLong => Ty::ULongLong,
1596 Ty::Int128 => Ty::UInt128,
1597 other => other,
1598 }
1599 }
1600
1601 /// The smallest value this integer type can hold.
1602 pub fn min_value(self, target: &TargetModel) -> i128 {
1603 if !self.is_signed(target) {
1604 return 0;
1605 }
1606 let bits = self.bits(target);
1607 if bits >= 128 {
1608 return i128::MIN;
1609 }
1610 -(1i128 << (bits - 1))
1611 }
1612
1613 /// The largest value this integer type can hold.
1614 ///
1615 /// `unsigned __int128` is the one type whose largest value does not fit in
1616 /// the `i128` this returns, and it is clamped to [`i128::MAX`]. Nothing
1617 /// reads it: the only comparison of two maxima is the last step of the
1618 /// [usual arithmetic conversions](Ty::usual_arithmetic), which is reached
1619 /// only when the *unsigned* operand has the lower rank — and no integer
1620 /// type ranks above `unsigned __int128`.
1621 pub fn max_value(self, target: &TargetModel) -> i128 {
1622 if self == Ty::Bool {
1623 return 1;
1624 }
1625 let bits = self.bits(target);
1626 if bits >= 128 {
1627 return i128::MAX;
1628 }
1629 if self.is_signed(target) {
1630 (1i128 << (bits - 1)) - 1
1631 } else {
1632 (1i128 << bits) - 1
1633 }
1634 }
1635
1636 /// Whether `value` fits in this integer type without conversion.
1637 pub fn can_represent(self, value: i128, target: &TargetModel) -> bool {
1638 value >= self.min_value(target) && value <= self.max_value(target)
1639 }
1640
1641 /// Converts an integer value to this type the way C's conversions do:
1642 /// modulo 2^N for unsigned types, and the same (implementation-defined)
1643 /// wrap-around for signed ones.
1644 ///
1645 /// # How a 128-bit constant is carried
1646 ///
1647 /// A folded constant is an `i128`, which holds every value of every type
1648 /// this models except those of `unsigned __int128` above `i128::MAX`. Such
1649 /// a value is carried as its **two's-complement bit pattern**, which is
1650 /// what this returns unchanged for a 128-bit type: for every narrower type
1651 /// the bit pattern and the mathematical value coincide, so the invariant is
1652 /// "the value, except that an `unsigned __int128` is reinterpreted". The
1653 /// places where the difference shows — division, remainder, a right shift,
1654 /// a comparison and the literal that is finally emitted — dispatch on
1655 /// [`Ty::is_signed`] instead of on the sign of the `i128`.
1656 pub fn wrap(self, value: i128, target: &TargetModel) -> i128 {
1657 if self == Ty::Bool {
1658 return i128::from(value != 0);
1659 }
1660 let bits = self.bits(target);
1661 if bits == 0 || bits >= 128 {
1662 return value;
1663 }
1664 let masked = (value as u128) & (u128::MAX >> (128 - bits));
1665 if self.is_signed(target) && masked >> (bits - 1) != 0 {
1666 (masked | (u128::MAX << bits)) as i128
1667 } else {
1668 masked as i128
1669 }
1670 }
1671
1672 /// The integer promotions (C99 6.3.1.1p2).
1673 ///
1674 /// Anything of lower rank than `int` becomes `int` when `int` can hold
1675 /// every one of its values and `unsigned int` otherwise; an `enum` becomes
1676 /// `int`; everything else is unchanged.
1677 pub fn promote(self, target: &TargetModel) -> Ty {
1678 if self.is_enum() {
1679 return Ty::Int;
1680 }
1681 if !self.is_integer() || self.rank() >= Ty::Int.rank() {
1682 return self;
1683 }
1684 if Ty::Int.can_represent(self.min_value(target), target)
1685 && Ty::Int.can_represent(self.max_value(target), target)
1686 {
1687 Ty::Int
1688 } else {
1689 Ty::UInt
1690 }
1691 }
1692
1693 /// The integer promotions applied to a bit-field (C99 6.3.1.1p2, "as
1694 /// restricted by the width").
1695 ///
1696 /// The value of a bit-field of width `width` ranges over `width` bits
1697 /// rather than over the whole declared type, so `unsigned x : 31` promotes
1698 /// to `int` — every value fits — while `unsigned x : 32` promotes to
1699 /// `unsigned int`. The standard only defines the promotions for a type
1700 /// whose rank is at most `int`'s, which is the only case standard C allows
1701 /// a bit-field to have; GCC and Clang apply the same width-restricted rule
1702 /// to the wider types they accept as an extension, so `unsigned long x : 31`
1703 /// is an `int` too and `unsigned long x : 33` keeps its declared type. This
1704 /// follows them.
1705 ///
1706 /// `signed` is the signedness of the *field*, which is the declared type's
1707 /// except for an `enum` whose underlying type the implementation made
1708 /// unsigned.
1709 pub fn promote_bit_field(self, width: u32, signed: bool, target: &TargetModel) -> Ty {
1710 if !self.is_integer() || width == 0 || width > 127 {
1711 return self.promote(target);
1712 }
1713 let (min, max) = if signed {
1714 (-(1i128 << (width - 1)), (1i128 << (width - 1)) - 1)
1715 } else {
1716 (0, (1i128 << width) - 1)
1717 };
1718 for candidate in [Ty::Int, Ty::UInt] {
1719 if candidate.can_represent(min, target) && candidate.can_represent(max, target) {
1720 return candidate;
1721 }
1722 }
1723 self
1724 }
1725
1726 /// The default argument promotions, applied to the variable part of a
1727 /// variadic call: `float` becomes `double`, and the integer promotions do
1728 /// the rest.
1729 pub fn promote_argument(self, target: &TargetModel) -> Ty {
1730 if self == Ty::Float {
1731 return Ty::Double;
1732 }
1733 self.promote(target)
1734 }
1735
1736 /// The usual arithmetic conversions (C99 6.3.1.8): the common type two
1737 /// arithmetic operands are converted to.
1738 ///
1739 /// With a complex operand the standard's rule is in two steps: the *common
1740 /// real type* is worked out from the two operands' corresponding real
1741 /// types, and the result is the complex type belonging to it if either
1742 /// operand was complex. `float _Complex + long` is therefore
1743 /// `float _Complex`, not `double _Complex`.
1744 pub fn usual_arithmetic(lhs: Ty, rhs: Ty, target: &TargetModel) -> Ty {
1745 if lhs.is_complex() || rhs.is_complex() {
1746 let real =
1747 Ty::usual_arithmetic(lhs.complex_component(), rhs.complex_component(), target);
1748 return real.complex_of();
1749 }
1750 if lhs == Ty::Double || rhs == Ty::Double {
1751 return Ty::Double;
1752 }
1753 if lhs == Ty::Float || rhs == Ty::Float {
1754 return Ty::Float;
1755 }
1756 let lhs = lhs.promote(target);
1757 let rhs = rhs.promote(target);
1758 if lhs == rhs {
1759 return lhs;
1760 }
1761 let lhs_signed = lhs.is_signed(target);
1762 if lhs_signed == rhs.is_signed(target) {
1763 return if lhs.rank() >= rhs.rank() { lhs } else { rhs };
1764 }
1765 let (unsigned, signed) = if lhs_signed { (rhs, lhs) } else { (lhs, rhs) };
1766 if unsigned.rank() >= signed.rank() {
1767 unsigned
1768 } else if signed.max_value(target) >= unsigned.max_value(target) {
1769 signed
1770 } else {
1771 signed.to_unsigned()
1772 }
1773 }
1774
1775 /// `size_t` for `target`.
1776 ///
1777 /// The *narrowest* unsigned type as wide as a pointer, which is how GCC
1778 /// picks it and therefore what `__SIZE_TYPE__` says: `unsigned int` on
1779 /// i686, `unsigned long` on LP64, `unsigned long long` on 64-bit Windows,
1780 /// where `long` is only 32 bits.
1781 pub fn size_ty(target: &TargetModel) -> Ty {
1782 if target.int_bits >= target.ptr_bits {
1783 Ty::UInt
1784 } else if target.long_bits >= target.ptr_bits {
1785 Ty::ULong
1786 } else {
1787 Ty::ULongLong
1788 }
1789 }
1790
1791 /// `ptrdiff_t` for `target`, chosen the same way as [`Ty::size_ty`].
1792 pub fn ptrdiff_ty(target: &TargetModel) -> Ty {
1793 if target.int_bits >= target.ptr_bits {
1794 Ty::Int
1795 } else if target.long_bits >= target.ptr_bits {
1796 Ty::Long
1797 } else {
1798 Ty::LongLong
1799 }
1800 }
1801
1802 /// `wchar_t` for `target`: `unsigned short` on Windows, `unsigned int` on
1803 /// Arm outside Apple's platforms, and `int` everywhere else.
1804 ///
1805 /// This is the type `L'x'` and `L"…"` get, and what the bundled
1806 /// `<stddef.h>` typedefs from `__WCHAR_TYPE__`; the two have to agree, or
1807 /// a call passing `L"…"` to a `const wchar_t *` would be a type error.
1808 pub fn wchar_ty(target: &TargetModel) -> Ty {
1809 match (target.wchar_bits, target.wchar_signed) {
1810 (16, true) => Ty::Short,
1811 (16, false) => Ty::UShort,
1812 (_, true) => Ty::Int,
1813 (_, false) => Ty::UInt,
1814 }
1815 }
1816
1817 /// `char16_t` (C11 7.28), which is `uint_least16_t` — `unsigned short` on
1818 /// every target this models, and what the bundled `<uchar.h>` typedefs it
1819 /// to.
1820 pub fn char16_ty() -> Ty {
1821 Ty::UShort
1822 }
1823
1824 /// `char32_t` (C11 7.28), which is `uint_least32_t` — `unsigned int`.
1825 pub fn char32_ty() -> Ty {
1826 Ty::UInt
1827 }
1828}
1829
1830// ---------------------------------------------------------------------------
1831// identifiers
1832// ---------------------------------------------------------------------------
1833
1834/// Identifies a named object (a local, a parameter, a `static` local or a
1835/// file-scope variable) inside a [`Program`].
1836#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1837pub struct ObjectId(pub u32);
1838
1839/// Identifies a function inside a [`Program`].
1840#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1841pub struct FuncId(pub u32);
1842
1843/// Identifies one loop inside a function; used to build its Rust label.
1844#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1845pub struct LoopId(pub u32);
1846
1847/// Identifies one `switch` inside a function; used to build its Rust label.
1848#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1849pub struct SwitchId(pub u32);
1850
1851/// Identifies one `goto` label inside a function.
1852///
1853/// C gives labels function scope and their own namespace, so every label of a
1854/// function is collected before its body is checked — that is what lets a
1855/// `goto` jump forwards.
1856#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
1857pub struct LabelId(pub u32);
1858
1859/// Identifies a string literal inside a [`Program`].
1860#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1861pub struct StrId(pub u32);
1862
1863// ---------------------------------------------------------------------------
1864// objects and functions
1865// ---------------------------------------------------------------------------
1866
1867/// Where an object lives, and how it is generated.
1868#[derive(Clone, Debug, PartialEq, Eq)]
1869pub enum Storage {
1870 /// A `let` binding: a local variable or a parameter.
1871 Automatic,
1872 /// A `static mut` item: a file-scope variable or a function-local `static`.
1873 Static {
1874 /// The name of the generated Rust item, already made unique.
1875 item_name: String,
1876 /// Whether the item is `pub` — true for a file-scope object without
1877 /// `static`, which C gives external linkage and which Rust code should
1878 /// therefore be able to reach.
1879 exported: bool,
1880 },
1881 /// A `thread_local!` item: an object declared `_Thread_local`,
1882 /// `thread_local` or `__thread`.
1883 ///
1884 /// C gives it static storage duration and one instance per thread, which
1885 /// is exactly what `std::thread_local!` provides. The item holds an
1886 /// `UnsafeCell<T>`, and every access goes through the `*mut T` its `with`
1887 /// hands out — valid for as long as the current thread's copy is, which is
1888 /// the lifetime C promises. It is the third construct whose expansion
1889 /// needs more than `core`, after variable length arrays and `alloca`.
1890 ThreadLocal {
1891 /// The name of the generated Rust item, already made unique.
1892 item_name: String,
1893 /// Whether the item is `pub`; see [`Storage::Static`].
1894 exported: bool,
1895 },
1896 /// An object defined outside the translation unit, declared in the
1897 /// expansion's `extern` block.
1898 Extern {
1899 /// The name the symbol has.
1900 item_name: String,
1901 },
1902}
1903
1904impl Storage {
1905 /// The name of the generated item, for the two storage classes that have
1906 /// one of their own.
1907 pub fn item_name(&self) -> Option<&str> {
1908 match self {
1909 Storage::Static { item_name, .. } | Storage::ThreadLocal { item_name, .. } => {
1910 Some(item_name)
1911 }
1912 Storage::Automatic | Storage::Extern { .. } => None,
1913 }
1914 }
1915
1916 /// Whether this is a thread-local object.
1917 pub fn is_thread_local(&self) -> bool {
1918 matches!(self, Storage::ThreadLocal { .. })
1919 }
1920}
1921
1922/// A named object.
1923#[derive(Clone, Debug)]
1924pub struct Object {
1925 /// The name as written in C.
1926 pub name: String,
1927 /// The object's type.
1928 pub ty: Ty,
1929 /// How the object is stored.
1930 pub storage: Storage,
1931 /// Whether the object's type is `const`-qualified.
1932 pub is_const: bool,
1933 /// Whether the declaration said `register`.
1934 ///
1935 /// The specifier is a hint about speed that this crate has nothing to do
1936 /// with — Rust decides where a local lives — but it has one rule with
1937 /// teeth: C11 6.7.1p6 says the address of such an object "cannot be
1938 /// computed, either explicitly (by use of the unary `&` operator as
1939 /// discussed in 6.5.3.2) or implicitly (by converting an array name to a
1940 /// pointer as discussed in 6.3.2.1)", so `sizeof` is the only operator an
1941 /// array declared `register` can be the operand of. WG14 DR116 is that
1942 /// rule; `drs/dr1xx.c` is where it is checked.
1943 pub is_register: bool,
1944 /// Set when this is the hidden frame of a
1945 /// [variable length array](Stmt::Vla): the mark of the function's bump
1946 /// arena taken just before the elements were allocated, in which case
1947 /// [`Object::ty`] is the *element* type and the generated binding is the
1948 /// arena's frame guard (a slot of the function's array of marks in
1949 /// [CFG mode](crate::cfg)).
1950 ///
1951 /// It is not an object of the C program at all; it exists so that the
1952 /// arena moves back down to the mark when the block ends, which is the
1953 /// lifetime C gives the array.
1954 pub vla_storage: bool,
1955 /// The alignment `_Alignas(N)` or `__attribute__((aligned(N)))` asked for,
1956 /// when it is stricter than the one the type already has.
1957 ///
1958 /// Rust has no way to over-align a binding, so the object is generated
1959 /// inside a one-field wrapper that carries the alignment —
1960 /// `#[repr(C, align(N))] struct __cinrs_align_N<T>(pub T);` — and every
1961 /// access to it goes through the field. The C object's *type* is unchanged:
1962 /// `sizeof` is the type's size and the wrapper is invisible to everything
1963 /// but the generated binding. See [`codegen`](crate::codegen).
1964 ///
1965 /// `None` is the ordinary case, and also what a request no stricter than
1966 /// the natural alignment leaves behind — there is nothing for a wrapper to
1967 /// say.
1968 pub align: Option<u64>,
1969 /// How many elements the object's storage gives the record's [flexible
1970 /// array member](Field::flexible), when an initialiser filled it in.
1971 ///
1972 /// GNU C lets an object with *static* storage duration initialise the
1973 /// member (`static struct W w = { 3, { 1, 2, 3 } };`), which makes the
1974 /// object larger than its own type — something Rust has no way to say
1975 /// about a value of type `W`. The item is therefore given a *companion*
1976 /// type with the same leading layout and a tail of this length,
1977 /// `__cinrs_W_3`, and every use of the object is a place reached through
1978 /// `(*(&raw mut w).cast::<W>())`. `sizeof w` is still `sizeof(struct W)`,
1979 /// which is what GCC says too. See [`codegen`](crate::codegen).
1980 pub flexible_len: Option<u64>,
1981 /// The symbol `__asm__("name")` renamed the object to.
1982 pub asm_label: Option<String>,
1983 /// The section `__attribute__((section("…")))` asked for.
1984 pub section: Option<String>,
1985 /// Where the declarator was written.
1986 pub range: SourceRange,
1987}
1988
1989/// A `static mut` item and its constant initialiser.
1990#[derive(Clone, Debug)]
1991pub struct StaticVar {
1992 /// The object the item defines.
1993 pub object: ObjectId,
1994 /// The initial value; C zero-initialises objects with static storage
1995 /// duration, so this is present even when the source wrote no initialiser.
1996 pub init: Expr,
1997}
1998
1999/// A function's signature.
2000#[derive(Clone, Debug, PartialEq, Eq)]
2001pub struct Signature {
2002 /// The return type.
2003 pub ret: Ty,
2004 /// The parameter types.
2005 pub params: Vec<Ty>,
2006 /// Whether the prototype ended with `, ...`.
2007 pub variadic: bool,
2008 /// Whether a parameter type list was given at all; see
2009 /// [`FuncType::prototyped`].
2010 ///
2011 /// `int f();` before C23 declares a function whose parameters are
2012 /// unspecified: `params` is empty because nothing was said, not because
2013 /// there are none. A *definition* written that way does take no parameters
2014 /// — that is what the generated item has — but its type still has no
2015 /// prototype, so a call with arguments is legal C and reaches the callee
2016 /// with the default argument promotions applied.
2017 pub prototyped: bool,
2018}
2019
2020/// How a function's body is lowered.
2021///
2022/// Nearly every C function maps onto Rust's own control flow, which is what
2023/// makes the expansion readable. A function that jumps around — a `goto`, or a
2024/// `case` label the enclosing `switch` cannot reach without one — cannot, and
2025/// is lowered into a [control-flow graph](crate::cfg) instead.
2026#[derive(Clone, Debug)]
2027pub enum Body {
2028 /// Rust control flow mirrors C's.
2029 Structured(Vec<Stmt>),
2030 /// A graph of basic blocks; see [`crate::cfg`].
2031 Cfg(crate::cfg::Cfg),
2032}
2033
2034/// A function declared or defined in the translation unit.
2035#[derive(Clone, Debug)]
2036pub struct Function {
2037 /// The name as written in C.
2038 pub name: String,
2039 /// The signature every declaration of it must agree on.
2040 pub sig: Signature,
2041 /// The parameter objects. Empty until the definition is seen.
2042 pub params: Vec<ObjectId>,
2043 /// The parameter names as first declared, for the generated `extern` block.
2044 pub param_names: Vec<Option<String>>,
2045 /// Whether the function was declared `static`, i.e. is private to the unit.
2046 pub is_static: bool,
2047 /// Whether the function was declared `inline`.
2048 pub is_inline: bool,
2049 /// Whether the function was declared `_Noreturn` (or `[[noreturn]]`), so
2050 /// that a call to it ends the statement it is in.
2051 pub noreturn: bool,
2052 /// What `always_inline` / `noinline` asked for.
2053 pub inline_hint: Option<InlineHint>,
2054 /// Whether `__attribute__((cold))` marked it unlikely.
2055 pub cold: bool,
2056 /// The message `__attribute__((deprecated))` gave, if it was there at all.
2057 pub deprecated: Option<Option<String>>,
2058 /// The section `__attribute__((section("…")))` asked for.
2059 pub section: Option<String>,
2060 /// The symbol `__asm__("name")` renamed the function to.
2061 pub asm_label: Option<String>,
2062 /// Whether `__attribute__((constructor))` asked for it to run before
2063 /// `main`, or `destructor` for after it.
2064 pub init_kind: Option<InitKind>,
2065 /// The instruction sets `__attribute__((target("…")))` or
2066 /// `#pragma GCC target("…")` asked for, in Rust's spelling, which the
2067 /// generated item carries as `#[target_feature(enable = "…")]`.
2068 ///
2069 /// Only a *definition* can carry them: an `extern` declaration has no item
2070 /// for the attribute to go on, and the function it names was compiled
2071 /// somewhere else.
2072 pub target_features: Vec<String>,
2073 /// Whether anything in the unit uses the function other than by calling
2074 /// it by name: its address taken as a value (`&f`, or `f` where a pointer
2075 /// is wanted), or it named by `__attribute__((cleanup))`, whose guard
2076 /// holds a pointer to it. Such a function has to be an `extern "C" fn`,
2077 /// since that is what a C function pointer is; one that is only ever called
2078 /// can be a Rust function, which is what an
2079 /// [always-inline helper with target features](Function::inline_helper)
2080 /// needs.
2081 pub address_taken: bool,
2082 /// Set when this name is an [x86 intrinsic](crate::x86) rather than a
2083 /// symbol: a call to it is generated as `::core::arch::x86_64::<name>`,
2084 /// and it is left out of the unit's `extern` block because there is
2085 /// nothing to link.
2086 pub intrinsic: Option<&'static crate::x86::Intrinsic>,
2087 /// Where the function was asked to be [safe](crate::sema::check_safe), if
2088 /// it was: `[[cinrs::safe]]`, `__attribute__((cinrs_safe))` or
2089 /// `#pragma cinrs safe`.
2090 ///
2091 /// A safe function is generated as `extern "C" fn` rather than
2092 /// `unsafe extern "C" fn`, and its body is *not* wrapped in an `unsafe`
2093 /// block, so `rustc` checks it. The range is where the request was
2094 /// written, which is what the diagnostics about it point at.
2095 pub safe: Option<SourceRange>,
2096 /// Whether the body declares a variable length array or calls `alloca`,
2097 /// in which case the generated item opens with the bump arena both
2098 /// emulations allocate out of.
2099 ///
2100 /// The arena is per function and is dropped by the `return`, which frees
2101 /// everything in it: that is `alloca`'s lifetime, and a variable length
2102 /// array gives its space back earlier, at the end of its block, by moving
2103 /// the arena's position back down. See [`codegen`](crate::codegen).
2104 pub uses_arena: bool,
2105 /// Every automatic object the body declared, in declaration order.
2106 ///
2107 /// Code generation needs the whole list — not only the ones a `let`
2108 /// statement is visible for — because a local declared inside a statement
2109 /// expression is a binding too and may need renaming apart.
2110 pub locals: Vec<ObjectId>,
2111 /// The body, present once a definition has been type checked.
2112 pub body: Option<Body>,
2113 /// The Rust item name, when it is not the C name.
2114 ///
2115 /// Only a lifted [GNU nested function](EnvParam) has one: it becomes a
2116 /// file-scope item, so it needs a name that cannot collide with the C
2117 /// function of the same name at file scope, while [`Function::name`] stays
2118 /// what the program called it — which is what diagnostics and `__func__`
2119 /// say.
2120 pub item_name: Option<String>,
2121 /// The hidden environment parameters a lifted GNU nested function takes in
2122 /// front of its declared ones, in the order they are passed.
2123 ///
2124 /// Empty for every ordinary function, and for a nested one that captures
2125 /// nothing — which is why such a nested function's address may still be
2126 /// taken: the generated item has exactly the signature C gave it.
2127 pub env: Vec<EnvParam>,
2128 /// Where the function's name was written, at its definition if there is one
2129 /// and at its first declaration otherwise.
2130 pub range: SourceRange,
2131}
2132
2133/// One hidden parameter of a lifted [GNU nested
2134/// function](crate::sema#nested-functions).
2135///
2136/// GCC gives a nested function a *static chain* — a pointer to the enclosing
2137/// frame — and writes a trampoline when its address is taken. This crate
2138/// lambda-lifts instead: each enclosing object the body uses becomes a
2139/// pointer parameter of its own, the body reads and writes it through that
2140/// pointer, and every call site passes the address of the object it has. The
2141/// sharing C promises is therefore kept — a store in the nested function is
2142/// visible in the enclosing one — without a trampoline, at the price of not
2143/// being able to hand the function's address out.
2144#[derive(Clone, Copy, Debug)]
2145pub struct EnvParam {
2146 /// The enclosing function's object the pointer carries.
2147 pub owner: ObjectId,
2148 /// The `*mut T` (or `*const T`) parameter of *this* function that holds
2149 /// its address.
2150 pub param: ObjectId,
2151}
2152
2153/// What `always_inline` and `noinline` ask for.
2154#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2155pub enum InlineHint {
2156 /// `#[inline(always)]`
2157 Always,
2158 /// `#[inline(never)]`
2159 Never,
2160}
2161
2162/// Whether a function runs before `main` or after it.
2163#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2164pub enum InitKind {
2165 /// `__attribute__((constructor))`
2166 Constructor,
2167 /// `__attribute__((destructor))`
2168 Destructor,
2169}
2170
2171impl Function {
2172 /// Whether this function is only declared here and linked from elsewhere.
2173 pub fn is_extern(&self) -> bool {
2174 self.body.is_none()
2175 }
2176
2177 /// The name the generated Rust item has.
2178 pub fn item_name(&self) -> &str {
2179 self.item_name.as_deref().unwrap_or(&self.name)
2180 }
2181
2182 /// Whether this is a lifted GNU nested function.
2183 pub fn is_nested(&self) -> bool {
2184 self.item_name.is_some()
2185 }
2186
2187 /// Whether the function is generated without `unsafe`; see
2188 /// [`Function::safe`].
2189 pub fn is_safe(&self) -> bool {
2190 self.safe.is_some()
2191 }
2192
2193 /// Whether the function is an `always_inline` helper under a target
2194 /// feature that is generated as a Rust `#[inline(always)] unsafe fn`
2195 /// *without* `#[target_feature]`.
2196 ///
2197 /// rustc refuses `#[inline(always)]` together with `#[target_feature]`
2198 /// (rust-lang/rust#145574), and `#[inline]` alone is a hint LLVM may
2199 /// decline: BLAKE3's `round_fn16`, called seven times from one kernel, was
2200 /// left out of line, its state spilled to the stack around every call.
2201 /// GCC's contract makes the attribute unnecessary: it refuses to inline an
2202 /// `always_inline` function into a caller without its target options, so
2203 /// every caller of one that compiles has the features, and once the helper
2204 /// is inlined into such a caller the intrinsics in its body are inlined
2205 /// there too. Without the attribute the helper must not be a C-ABI
2206 /// function — the C ABI passes a 256- or 512-bit vector in registers the
2207 /// feature provides — so it is a Rust function, and that is only possible
2208 /// when nothing needs it as a C function pointer: it is `static`, never
2209 /// has its address taken, is not variadic, nested, safe (whose body would
2210 /// then call intrinsics without `unsafe`), a constructor or an intrinsic.
2211 pub fn inline_helper(&self) -> bool {
2212 self.inline_hint == Some(InlineHint::Always)
2213 && !self.target_features.is_empty()
2214 && self.is_static
2215 && !self.address_taken
2216 && !self.sig.variadic
2217 && !self.is_nested()
2218 && !self.is_safe()
2219 && self.init_kind.is_none()
2220 && self.intrinsic.is_none()
2221 }
2222}
2223
2224/// One direct call, from the function whose body holds it to the function it
2225/// names.
2226///
2227/// Sema records these as it checks the calls, and
2228/// [`check_safe`](crate::sema::check_safe) is the one thing that reads them: a
2229/// [safe](Function::safe) function calling one that is not gets a diagnostic
2230/// worded in C rather than `rustc`'s "call to unsafe function". A call through
2231/// a *pointer* has no edge — there is no callee to name — and is left to
2232/// `rustc`, which refuses it in a safe function like any other unsafe
2233/// operation.
2234#[derive(Clone, Copy, Debug)]
2235pub struct CallEdge {
2236 /// The function the call was written in.
2237 pub caller: FuncId,
2238 /// The function it calls.
2239 pub callee: FuncId,
2240 /// Where the callee was named, which is where a diagnostic points.
2241 pub range: SourceRange,
2242}
2243
2244/// A file-scope `typedef`, which becomes a Rust type alias.
2245#[derive(Clone, Debug)]
2246pub struct TypedefItem {
2247 /// The name of the generated alias.
2248 pub rust_name: String,
2249 /// What it stands for.
2250 pub ty: Ty,
2251 /// Where it was written.
2252 pub range: SourceRange,
2253}
2254
2255/// A string literal's decoded contents.
2256#[derive(Clone, Debug)]
2257pub struct StrData {
2258 /// The elements, without the terminating NUL: bytes for a narrow or
2259 /// `u8"…"` literal, UTF-16 code units for `u"…"`, and character values for
2260 /// `U"…"` and `L"…"`.
2261 pub values: Vec<u32>,
2262 /// The type of one element: `char`, `char8_t`, `char16_t`, `char32_t` or
2263 /// `wchar_t`, whichever prefix the literal was written with.
2264 pub elem: Ty,
2265}
2266
2267impl StrData {
2268 /// The number of elements including the terminating NUL.
2269 pub fn len_with_nul(&self) -> u64 {
2270 self.values.len() as u64 + 1
2271 }
2272}
2273
2274/// Everything one translation unit generates.
2275#[derive(Clone, Debug, Default)]
2276pub struct Program {
2277 /// A hash of the invocation site, used to build the synthetic item names
2278 /// that must not collide between two `c99!` blocks in one module.
2279 pub unit_id: u64,
2280 /// Every derived and tagged type.
2281 pub types: Types,
2282 /// Every named object, indexed by [`ObjectId`].
2283 pub objects: Vec<Object>,
2284 /// The objects that become `static mut` items, in declaration order.
2285 pub statics: Vec<StaticVar>,
2286 /// The objects declared `extern`, in declaration order.
2287 pub externs: Vec<ObjectId>,
2288 /// Every function, indexed by [`FuncId`], in declaration order.
2289 pub functions: Vec<Function>,
2290 /// Every direct call the unit's bodies make; see [`CallEdge`].
2291 pub calls: Vec<CallEdge>,
2292 /// The file-scope `typedef`s, in declaration order.
2293 pub typedefs: Vec<TypedefItem>,
2294 /// The `enum` constants that become Rust `const` items, in order.
2295 pub enum_constants: Vec<Enumerator>,
2296 /// Every string literal, indexed by [`StrId`].
2297 pub strings: Vec<StrData>,
2298 /// The libraries the unit must be linked against, named by
2299 /// `#pragma cinrs link "…"`.
2300 ///
2301 /// Filled in after semantic analysis: it is the preprocessor that reads
2302 /// the pragma, and nothing about the program itself depends on it.
2303 pub link_libraries: Vec<String>,
2304 /// Whether `#pragma cinrs export` asked for every function and object with
2305 /// external linkage to become a real C symbol.
2306 ///
2307 /// Filled in after semantic analysis, for the same reason as
2308 /// [`Program::link_libraries`].
2309 pub export: bool,
2310 /// Every `__builtin_cpu_supports` the unit wrote, by where it was written.
2311 ///
2312 /// It becomes `::std::is_x86_feature_detected!`, and `core` has no CPU
2313 /// detection at all — so a unit that said `#pragma cinrs no_std` cannot
2314 /// have one. The pragma is only known after semantic analysis, which is
2315 /// why the sites are collected rather than checked where they are met; see
2316 /// [`crate::sema::check_pragmas`].
2317 pub cpu_supports: Vec<SourceRange>,
2318 /// Whether `#pragma cinrs no_std` said the expansion goes into a
2319 /// `#![no_std]` crate.
2320 ///
2321 /// Everything generated is `core`-only except the storage a [variable
2322 /// length array](Stmt::Vla) and `alloca` need, which is a bump arena made
2323 /// of `Vec`s; this decides whether they are spelled `::std::vec::Vec` or
2324 /// `::alloc::vec::Vec`. Filled in after semantic analysis, for the same
2325 /// reason as [`Program::link_libraries`].
2326 pub no_std: bool,
2327 /// The Rust path of the `cinrs` facade crate, which the generated code
2328 /// names when it needs the runtime: `::cinrs` unless
2329 /// `#pragma cinrs crate "…"` said otherwise.
2330 ///
2331 /// Only a unit that uses a complex type spells it at all. Filled in after
2332 /// semantic analysis, for the same reason as [`Program::link_libraries`].
2333 pub crate_path: String,
2334}
2335
2336/// The Rust path of the facade crate the generated code names, when the unit
2337/// does not say.
2338///
2339/// A crate renamed in `Cargo.toml` — `cinrs = { package = "cinrs", … }` under
2340/// another name — is reached with `#pragma cinrs crate "<path>"` instead.
2341pub const DEFAULT_CRATE_PATH: &str = "::cinrs";
2342
2343impl Program {
2344 /// Looks an object up.
2345 ///
2346 /// # Panics
2347 ///
2348 /// Panics if `id` did not come from this program.
2349 pub fn object(&self, id: ObjectId) -> &Object {
2350 &self.objects[id.0 as usize]
2351 }
2352
2353 /// Looks a function up.
2354 ///
2355 /// # Panics
2356 ///
2357 /// Panics if `id` did not come from this program.
2358 pub fn function(&self, id: FuncId) -> &Function {
2359 &self.functions[id.0 as usize]
2360 }
2361
2362 /// Looks a string literal up.
2363 ///
2364 /// # Panics
2365 ///
2366 /// Panics if `id` did not come from this program.
2367 pub fn string(&self, id: StrId) -> &StrData {
2368 &self.strings[id.0 as usize]
2369 }
2370
2371 /// The hidden Rust name an externally linked **object** is declared under.
2372 ///
2373 /// Only an object. A function the unit merely declares is generated under
2374 /// its own C name, like everything else the unit spells, so that
2375 /// `#include <zlib.h>` is enough for Rust to call `crc32`; an object is
2376 /// not, and the difference is Rust's rule for patterns rather than a
2377 /// matter of taste.
2378 ///
2379 /// A glob-imported **function** cannot change the meaning of Rust code
2380 /// that does not mention it: a function is not a pattern, so `let read =
2381 /// 1;` beside a unit that declares `read` is still a new binding. A glob
2382 /// imported **static** can. Rust resolves a binding pattern against the
2383 /// value namespace first, and a `static` there is not a name a `let` may
2384 /// shadow:
2385 ///
2386 /// ```text
2387 /// error[E0530]: let bindings cannot shadow statics
2388 /// ```
2389 ///
2390 /// — which is what `let stdout = std::io::stdout();` would become next to a
2391 /// block that includes `<stdio.h>`, and `let timezone = …` next to one that
2392 /// includes glibc's `<time.h>`. `optarg`, `optind` and `environ` are the
2393 /// same story. So a declared-only object keeps a name of its own,
2394 /// `__cinrs_<unit>_<symbol>`, and Rust reaches it the way C code does in
2395 /// the same situation: through an accessor written in the block,
2396 /// `FILE *get_stdout(void) { return stdout; }`.
2397 ///
2398 /// The C code in the unit is unaffected either way — it refers to the
2399 /// object by its C name, and this is only the Rust side of that.
2400 ///
2401 /// A module of its own for the `extern` block would have avoided the
2402 /// question altogether, but a module cannot see the `struct` items of the
2403 /// block it is written in, which an `extern` declaration taking a `struct`
2404 /// needs.
2405 ///
2406 /// A `$` in the C name — an identifier character here, and one Rust has no
2407 /// spelling for — is written [`crate::codegen::DOLLAR`]; the symbol the
2408 /// declaration links by is a `#[link_name]` string and keeps the `$`.
2409 pub fn extern_object_name(&self, symbol: &str) -> String {
2410 format!(
2411 "__cinrs_{:08x}_{}",
2412 self.unit_id as u32,
2413 symbol.replace('$', crate::codegen::DOLLAR)
2414 )
2415 }
2416
2417 /// Whether anything at all has to go into the `extern` block.
2418 ///
2419 /// An [x86 intrinsic](crate::x86) does not count: it is declared like any
2420 /// other function and generated as a call to `core::arch`, so a unit whose
2421 /// only declarations came from `<immintrin.h>` needs no block at all.
2422 pub fn has_externs(&self) -> bool {
2423 !self.externs.is_empty()
2424 || self
2425 .functions
2426 .iter()
2427 .any(|func| func.is_extern() && func.intrinsic.is_none())
2428 }
2429}
2430
2431// ---------------------------------------------------------------------------
2432// constants
2433// ---------------------------------------------------------------------------
2434
2435/// The value of an arithmetic constant expression.
2436#[derive(Clone, Copy, PartialEq, Debug)]
2437pub enum ConstValue {
2438 /// An integer value, already reduced to the range of its type.
2439 Int(i128),
2440 /// A floating value.
2441 Float(f64),
2442 /// A complex value: the real part and the imaginary one, each already
2443 /// rounded to the component type.
2444 ///
2445 /// Both parts are carried as `f64` whatever the type is, exactly as a
2446 /// `float` constant is; the rounding to `f32` happens where the value is
2447 /// stored, so that `(float _Complex) 0.1` is the same number here and in
2448 /// the generated code.
2449 Complex(f64, f64),
2450}
2451
2452// ---------------------------------------------------------------------------
2453// expressions
2454// ---------------------------------------------------------------------------
2455
2456/// A binary arithmetic, bitwise or shift operator.
2457#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2458#[allow(missing_docs)]
2459pub enum BinOp {
2460 Add,
2461 Sub,
2462 Mul,
2463 Div,
2464 Rem,
2465 BitAnd,
2466 BitXor,
2467 BitOr,
2468 Shl,
2469 Shr,
2470}
2471
2472impl BinOp {
2473 /// The C spelling.
2474 pub fn as_str(self) -> &'static str {
2475 match self {
2476 BinOp::Add => "+",
2477 BinOp::Sub => "-",
2478 BinOp::Mul => "*",
2479 BinOp::Div => "/",
2480 BinOp::Rem => "%",
2481 BinOp::BitAnd => "&",
2482 BinOp::BitXor => "^",
2483 BinOp::BitOr => "|",
2484 BinOp::Shl => "<<",
2485 BinOp::Shr => ">>",
2486 }
2487 }
2488
2489 /// Whether this operator shifts, in which case its operands are promoted
2490 /// separately rather than converted to a common type.
2491 pub fn is_shift(self) -> bool {
2492 matches!(self, BinOp::Shl | BinOp::Shr)
2493 }
2494}
2495
2496/// A relational or equality operator.
2497#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2498#[allow(missing_docs)]
2499pub enum CmpOp {
2500 Lt,
2501 Gt,
2502 Le,
2503 Ge,
2504 Eq,
2505 Ne,
2506}
2507
2508/// `&&` or `||`.
2509#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2510pub enum LogicalOp {
2511 /// `&&`
2512 And,
2513 /// `||`
2514 Or,
2515}
2516
2517/// The `(rw, locality)` of a [`BuiltinOp::Prefetch`]: whether it is a
2518/// prefetch for writing, and how long the line should stay, 0 to 3.
2519pub fn prefetch_hint(packed: u8) -> (bool, u8) {
2520 (packed & 4 != 0, packed & 3)
2521}
2522
2523/// A GNU builtin that becomes a fixed piece of Rust rather than a call.
2524///
2525/// The bit-manipulation ones map onto the integer methods of the same name;
2526/// the overflow ones do the arithmetic in `i128` and check the result against
2527/// the range of the type it is stored in, which is exactly the "compute in
2528/// infinite precision, then convert" the builtins are defined by.
2529#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2530pub enum BuiltinOp {
2531 /// `__builtin_popcount…`
2532 Popcount,
2533 /// `__builtin_clz…`; undefined for zero in C, and this follows Rust.
2534 Clz,
2535 /// `__builtin_ctz…`
2536 Ctz,
2537 /// `__builtin_ffs…`: one more than the index of the lowest set bit, or 0.
2538 Ffs,
2539 /// `__builtin_parity…`
2540 Parity,
2541 /// `__builtin_clrsb…`: leading redundant sign bits.
2542 Clrsb,
2543 /// `__builtin_bswap16/32/64`
2544 Bswap,
2545 /// `__builtin_{add,sub,mul}_overflow(a, b, &r)`, whose value is the flag.
2546 Overflow(BinOp),
2547 /// The `_p` forms, which only ask whether it *would* overflow.
2548 OverflowP(BinOp),
2549 /// Evaluate the operands and produce nothing: `__builtin_assume` and
2550 /// `__builtin_speculation_safe_value`, which promise something the
2551 /// generated code cannot pass on.
2552 Discard,
2553 /// `__builtin_prefetch(p, rw, locality)`, whose one operand is `p`
2554 /// converted to `const void *`. The payload is the two constants packed
2555 /// into one byte, `locality | rw << 2`, so that [`BuiltinOp`] stays two
2556 /// bytes wide (see [`BuiltinOp::CpuSupports`]); [`prefetch_hint`] takes
2557 /// it apart.
2558 ///
2559 /// On x86 it is `_mm_prefetch` with the locality's hint, on AArch64 a
2560 /// `prfm`, and anywhere else — or in a [safe](Function::is_safe) function,
2561 /// where the call would need `unsafe` — the operand is evaluated and the
2562 /// hint dropped, which is always a correct translation of a hint.
2563 Prefetch(u8),
2564 /// `__builtin_alloca(size)`, whose one operand is the size in bytes,
2565 /// converted to `size_t`.
2566 ///
2567 /// The memory comes out of the arena [`Function::uses_arena`] puts at the
2568 /// top of the function, and no variable length array's end of scope gives
2569 /// it back, so it is freed by the `return` — which is `alloca`'s own
2570 /// lifetime.
2571 Alloca,
2572 /// `__builtin_fabs…`: the sign bit cleared, which is what C's `fabs` is
2573 /// defined as and what makes it exact for a NaN and for a zero.
2574 Fabs,
2575 /// `__builtin_copysign…`: the first operand's magnitude with the second
2576 /// operand's sign bit.
2577 Copysign,
2578 /// One of the quiet comparison macros' builtins, whose value is an `int`.
2579 FloatOrder(FloatOrder),
2580 /// One of the classification builtins, whose value is an `int`.
2581 FloatClass(FloatClass),
2582 /// `__builtin_fpclassify(nan, inf, normal, subnormal, zero, x)`: the one
2583 /// of the first five operands the sixth one's class selects.
2584 Fpclassify,
2585 /// `__builtin_cpu_supports("avx2")`: whether the processor running the
2586 /// program has that instruction set, as an `int`.
2587 ///
2588 /// It becomes `::std::is_x86_feature_detected!("avx2")`, which is the same
2589 /// question asked of the same `cpuid` leaves. The payload is the row of
2590 /// [`crate::x86::TARGET_FEATURES`] the instruction set is in, so that
2591 /// [`BuiltinOp`] stays two bytes wide — it is a field of [`ExprKind`], and
2592 /// every expression in the program pays for whatever the largest variant
2593 /// is. Several Rust features for one GCC name (`abm` is LZCNT and POPCNT)
2594 /// are `&&`ed together; [`crate::x86::detect_features`] is the lookup.
2595 CpuSupports(u8),
2596 /// `__builtin_cproj(z)`: C99 7.3.9.5's projection onto the Riemann sphere.
2597 ///
2598 /// Everything is itself except a value with an infinite part, which becomes
2599 /// `+∞` with the imaginary part's sign kept on a zero — so every infinity
2600 /// is the *one* point at infinity.
2601 ComplexProj,
2602}
2603
2604/// The `float` bit pattern of a NaN that travels through the IR as a `double`.
2605///
2606/// A NaN's payload and its sign are part of its value — `__builtin_nanf
2607/// ("0x123")` asks for one in particular — and [`ExprKind::Float`] carries
2608/// every floating constant as an `f64`, so a `float` NaN is carried as the
2609/// `double` whose sign, quiet bit and payload are the same. Widening with `as`
2610/// would not do: it may quiet a signalling NaN and is free to choose the
2611/// payload. This and [`widen_nan_bits`] are exact inverses.
2612pub fn narrow_nan_bits(bits: u64) -> u32 {
2613 let sign = ((bits >> 63) as u32) << 31;
2614 let payload = ((bits >> 29) & 0x7f_ffff) as u32;
2615 sign | 0x7f80_0000 | payload
2616}
2617
2618/// The `double` bit pattern a `float` NaN is carried as; see
2619/// [`narrow_nan_bits`].
2620pub fn widen_nan_bits(bits: u32) -> u64 {
2621 let sign = u64::from(bits >> 31) << 63;
2622 let payload = u64::from(bits & 0x7f_ffff) << 29;
2623 sign | 0x7ff0_0000_0000_0000 | payload
2624}
2625
2626/// A quiet floating-point comparison: `__builtin_isgreater` and its relatives.
2627///
2628/// "Quiet" is the whole point of them — C99 7.12.14 defines each as the
2629/// comparison it names *without* raising the invalid exception on a NaN, which
2630/// `<` and friends would. Rust's floating comparison operators are the quiet
2631/// ones, so each is written out as the operator it stands for.
2632#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2633pub enum FloatOrder {
2634 /// `__builtin_isgreater`
2635 Greater,
2636 /// `__builtin_isgreaterequal`
2637 GreaterEqual,
2638 /// `__builtin_isless`
2639 Less,
2640 /// `__builtin_islessequal`
2641 LessEqual,
2642 /// `__builtin_islessgreater`: `x < y || x > y`, which is `x != y` without
2643 /// the NaN case.
2644 LessGreater,
2645 /// `__builtin_isunordered`: either operand is a NaN.
2646 Unordered,
2647}
2648
2649/// A floating-point classification: `__builtin_isnan` and its relatives.
2650#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2651pub enum FloatClass {
2652 /// `__builtin_isnan…`
2653 IsNan,
2654 /// `__builtin_isinf…`
2655 IsInf,
2656 /// `__builtin_isinf_sign`, whose value is -1, 0 or 1.
2657 IsInfSign,
2658 /// `__builtin_isfinite`
2659 IsFinite,
2660 /// `__builtin_isnormal`
2661 IsNormal,
2662 /// `__builtin_issignaling`: a NaN whose quiet bit is clear.
2663 IsSignaling,
2664 /// `__builtin_signbit…`, which is 1 for a negative zero too.
2665 SignBit,
2666}
2667
2668// ---------------------------------------------------------------------------
2669// atomics
2670// ---------------------------------------------------------------------------
2671
2672/// A memory order, C11 7.17.3's `memory_order` and Rust's `Ordering`.
2673///
2674/// `memory_order_consume` is not here: no compiler implements dependency
2675/// ordering and Rust has no `Consume`, so it arrives as [`MemOrder::Acquire`]
2676/// — which is what GCC and Clang also emit for it, and what C11 7.17.3p1
2677/// allows an implementation to do.
2678#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2679pub enum MemOrder {
2680 /// `memory_order_relaxed`
2681 Relaxed,
2682 /// `memory_order_acquire` (and `memory_order_consume`).
2683 Acquire,
2684 /// `memory_order_release`
2685 Release,
2686 /// `memory_order_acq_rel`
2687 AcqRel,
2688 /// `memory_order_seq_cst`
2689 SeqCst,
2690}
2691
2692impl MemOrder {
2693 /// The name of the `core::sync::atomic::Ordering` variant.
2694 pub fn rust_name(self) -> &'static str {
2695 match self {
2696 MemOrder::Relaxed => "Relaxed",
2697 MemOrder::Acquire => "Acquire",
2698 MemOrder::Release => "Release",
2699 MemOrder::AcqRel => "AcqRel",
2700 MemOrder::SeqCst => "SeqCst",
2701 }
2702 }
2703
2704 /// The C spelling, for a diagnostic.
2705 pub fn c_name(self) -> &'static str {
2706 match self {
2707 MemOrder::Relaxed => "memory_order_relaxed",
2708 MemOrder::Acquire => "memory_order_acquire",
2709 MemOrder::Release => "memory_order_release",
2710 MemOrder::AcqRel => "memory_order_acq_rel",
2711 MemOrder::SeqCst => "memory_order_seq_cst",
2712 }
2713 }
2714
2715 /// Whether a load may be performed with this order (C11 7.17.7.2p3).
2716 pub fn valid_for_load(self) -> bool {
2717 !matches!(self, MemOrder::Release | MemOrder::AcqRel)
2718 }
2719
2720 /// Whether a store may be performed with this order (C11 7.17.7.1p2).
2721 pub fn valid_for_store(self) -> bool {
2722 !matches!(self, MemOrder::Acquire | MemOrder::AcqRel)
2723 }
2724
2725 /// How strong the order is, for the rule that a compare-exchange's failure
2726 /// order may not be stronger than its success order.
2727 pub fn strength(self) -> u8 {
2728 match self {
2729 MemOrder::Relaxed => 0,
2730 MemOrder::Acquire | MemOrder::Release => 1,
2731 MemOrder::AcqRel => 2,
2732 MemOrder::SeqCst => 3,
2733 }
2734 }
2735
2736 /// The strongest order a failed compare-exchange may use beside this one,
2737 /// which is what `fetch_update` and a nand loop are given.
2738 pub fn failure_order(self) -> MemOrder {
2739 match self {
2740 MemOrder::Release => MemOrder::Relaxed,
2741 MemOrder::AcqRel => MemOrder::Acquire,
2742 other => other,
2743 }
2744 }
2745}
2746
2747/// What kind of Rust atomic an object is reached through.
2748///
2749/// The width comes from the C type's size, so `long` is an `AtomicI64` on an
2750/// LP64 target and an `AtomicI32` on an ILP32 one; the
2751/// [data-model check](crate::codegen) is what makes that assumption safe.
2752#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2753pub enum AtomicClass {
2754 /// `_Bool`, which is `AtomicBool` — a Rust `bool` may only ever hold 0 or
2755 /// 1, so it may not be reached through an integer atomic.
2756 Bool,
2757 /// An integer (or `enum`) of `bytes` bytes: `AtomicI8` … `AtomicU64`.
2758 Int {
2759 /// The width in bytes: 1, 2, 4 or 8.
2760 bytes: u64,
2761 /// Whether the C type is signed.
2762 signed: bool,
2763 },
2764 /// `float` or `double`, reached through the integer atomic of the same
2765 /// width and `to_bits`/`from_bits`.
2766 Float {
2767 /// The width in bytes: 4 or 8.
2768 bytes: u64,
2769 },
2770 /// An object pointer, which is `AtomicPtr`.
2771 Ptr,
2772 /// A *function* pointer, which is also an `AtomicPtr` — but whose C value
2773 /// is an `Option<unsafe extern "C" fn(…)>` in Rust rather than a raw
2774 /// pointer, so the two ends of every operation are a `transmute` instead
2775 /// of a cast.
2776 ///
2777 /// That transmute is sound because an `Option<fn>` is pointer-sized with
2778 /// the null pointer as its `None` niche, which is exactly the
2779 /// representation C gives a function pointer that may be null. Arithmetic
2780 /// is not: C has none on a function pointer, and neither has this.
2781 FnPtr,
2782}
2783
2784impl AtomicClass {
2785 /// The name of the `core::sync::atomic` type.
2786 pub fn rust_name(self) -> &'static str {
2787 match self {
2788 AtomicClass::Bool => "AtomicBool",
2789 AtomicClass::Ptr | AtomicClass::FnPtr => "AtomicPtr",
2790 AtomicClass::Float { bytes } => match bytes {
2791 4 => "AtomicU32",
2792 _ => "AtomicU64",
2793 },
2794 AtomicClass::Int { bytes, signed } => match (bytes, signed) {
2795 (1, true) => "AtomicI8",
2796 (1, false) => "AtomicU8",
2797 (2, true) => "AtomicI16",
2798 (2, false) => "AtomicU16",
2799 (4, true) => "AtomicI32",
2800 (4, false) => "AtomicU32",
2801 (_, true) => "AtomicI64",
2802 (_, false) => "AtomicU64",
2803 },
2804 }
2805 }
2806
2807 /// The Rust primitive the atomic holds, which is what the pointer handed
2808 /// to `from_ptr` points at.
2809 pub fn repr_name(self) -> &'static str {
2810 match self {
2811 AtomicClass::Bool => "bool",
2812 AtomicClass::Ptr | AtomicClass::FnPtr => "",
2813 AtomicClass::Float { bytes } => match bytes {
2814 4 => "u32",
2815 _ => "u64",
2816 },
2817 AtomicClass::Int { bytes, signed } => match (bytes, signed) {
2818 (1, true) => "i8",
2819 (1, false) => "u8",
2820 (2, true) => "i16",
2821 (2, false) => "u16",
2822 (4, true) => "i32",
2823 (4, false) => "u32",
2824 (_, true) => "i64",
2825 (_, false) => "u64",
2826 },
2827 }
2828 }
2829}
2830
2831/// The operation an [`ExprKind::Atomic`] performs.
2832#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2833pub enum AtomicOp {
2834 /// An atomic load, whose value has the object's type.
2835 Load,
2836 /// An atomic store, whose value is `void`.
2837 Store,
2838 /// An atomic exchange, whose value is the old one.
2839 Exchange,
2840 /// A compare-and-exchange whose value is `_Bool`, writing the value it
2841 /// observed back through the `expected` pointer when it fails — C11's
2842 /// `atomic_compare_exchange_strong` and GCC's
2843 /// `__atomic_compare_exchange_n`.
2844 CompareExchange {
2845 /// Whether a spurious failure is allowed (`compare_exchange_weak`).
2846 weak: bool,
2847 },
2848 /// The older `__sync_bool_compare_and_swap` and
2849 /// `__sync_val_compare_and_swap`, whose expected value is a *value* rather
2850 /// than a pointer and which write nothing back.
2851 SyncCompareSwap {
2852 /// Whether the value of the expression is the old one rather than
2853 /// whether the swap happened.
2854 value_is_old: bool,
2855 },
2856 /// A read-modify-write, whose value is the old one for `fetch_op` and the
2857 /// new one for `op_fetch`.
2858 Rmw {
2859 /// The operation.
2860 op: AtomicRmw,
2861 /// Whether the value of the expression is the *new* one.
2862 returns_new: bool,
2863 },
2864 /// `__atomic_test_and_set`: an atomic exchange of "set" into a byte, whose
2865 /// value is what was there before, as a `_Bool`.
2866 TestAndSet,
2867 /// `__atomic_clear`: an atomic store of zero into a byte.
2868 Clear,
2869 /// A fence, which has no operand at all.
2870 Fence {
2871 /// Whether this is a `signal_fence`, which is a compiler fence only.
2872 signal: bool,
2873 },
2874}
2875
2876/// The arithmetic a [`AtomicOp::Rmw`] performs.
2877#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2878pub enum AtomicRmw {
2879 /// `+`
2880 Add,
2881 /// `-`
2882 Sub,
2883 /// `&`
2884 And,
2885 /// `|`
2886 Or,
2887 /// `^`
2888 Xor,
2889 /// `~(a & b)`, which Rust has no `fetch_nand` for on the integers and
2890 /// which is therefore a `fetch_update`.
2891 Nand,
2892}
2893
2894impl AtomicRmw {
2895 /// The `core::sync::atomic` method that performs it, where there is one.
2896 pub fn rust_method(self) -> Option<&'static str> {
2897 Some(match self {
2898 AtomicRmw::Add => "fetch_add",
2899 AtomicRmw::Sub => "fetch_sub",
2900 AtomicRmw::And => "fetch_and",
2901 AtomicRmw::Or => "fetch_or",
2902 AtomicRmw::Xor => "fetch_xor",
2903 AtomicRmw::Nand => return None,
2904 })
2905 }
2906
2907 /// The C operator, for a diagnostic.
2908 pub fn c_op(self) -> &'static str {
2909 match self {
2910 AtomicRmw::Add => "+",
2911 AtomicRmw::Sub => "-",
2912 AtomicRmw::And => "&",
2913 AtomicRmw::Or => "|",
2914 AtomicRmw::Xor => "^",
2915 AtomicRmw::Nand => "~&",
2916 }
2917 }
2918}
2919
2920/// One of the `__atomic_*`, `__sync_*` or `__c11_atomic_*` builtins, resolved.
2921///
2922/// The pointer is the object the operation is performed on; sema has already
2923/// checked that what it points at is one of the types
2924/// [`AtomicClass`] covers, and has resolved the memory orders — which C
2925/// requires to be integer constant expressions here, exactly as `<stdatomic.h>`
2926/// writes them.
2927#[derive(Clone, Debug)]
2928pub struct AtomicExpr {
2929 /// What to do.
2930 pub op: AtomicOp,
2931 /// What kind of atomic to do it through.
2932 pub class: AtomicClass,
2933 /// The C type of the object, with any `_Atomic` already taken off: the
2934 /// type of the value the operation produces or stores.
2935 pub value_ty: Ty,
2936 /// The object's address, absent only for a fence.
2937 pub ptr: Option<Expr>,
2938 /// The value operand — what is stored, exchanged or added.
2939 pub value: Option<Expr>,
2940 /// The expected value of a compare-and-exchange: a *pointer* to it for
2941 /// [`AtomicOp::CompareExchange`], which writes the observed value back
2942 /// through it, and the value itself for [`AtomicOp::SyncCompareSwap`].
2943 pub expected: Option<Expr>,
2944 /// The order of the operation, and of a successful compare-and-exchange.
2945 pub success: MemOrder,
2946 /// The order of a *failed* compare-and-exchange.
2947 pub failure: MemOrder,
2948}
2949
2950impl AtomicExpr {
2951 /// Every expression the node holds, in evaluation order.
2952 pub fn operands(&self) -> impl Iterator<Item = &Expr> {
2953 self.ptr
2954 .iter()
2955 .chain(self.expected.iter())
2956 .chain(self.value.iter())
2957 }
2958}
2959
2960/// Which Rust atomic a C object type is reached through, if any is.
2961///
2962/// The width comes from the target model, which the [data-model
2963/// check](crate::codegen) makes safe to rely on. `None` means there is no
2964/// atomic of that width or shape: a 128-bit integer, an aggregate.
2965pub fn atomic_class(types: &Types, ty: Ty, target: &TargetModel) -> Option<AtomicClass> {
2966 let ty = types.unatomic(ty);
2967 if ty == Ty::Bool {
2968 return Some(AtomicClass::Bool);
2969 }
2970 if ty.is_integer() {
2971 let bytes = ty.size_bytes(target);
2972 return matches!(bytes, 1 | 2 | 4 | 8).then_some(AtomicClass::Int {
2973 bytes,
2974 signed: ty.is_signed(target),
2975 });
2976 }
2977 if ty.is_floating() {
2978 let bytes = ty.size_bytes(target);
2979 return matches!(bytes, 4 | 8).then_some(AtomicClass::Float { bytes });
2980 }
2981 if ty.is_pointer() {
2982 return Some(if types.is_func_pointer(ty) {
2983 AtomicClass::FnPtr
2984 } else {
2985 AtomicClass::Ptr
2986 });
2987 }
2988 None
2989}
2990
2991/// An assignable location.
2992#[derive(Clone, Debug)]
2993pub struct Place {
2994 /// What is being addressed.
2995 pub kind: PlaceKind,
2996 /// The type of the object addressed.
2997 pub ty: Ty,
2998 /// Whether the object is `const`-qualified, and therefore not assignable.
2999 pub is_const: bool,
3000 /// Where it was written.
3001 pub range: SourceRange,
3002}
3003
3004/// The shape of a [`Place`].
3005#[derive(Clone, Debug)]
3006pub enum PlaceKind {
3007 /// A named object.
3008 Object(ObjectId),
3009 /// `*ptr`, where `ptr` has pointer type.
3010 Deref(Box<Expr>),
3011 /// `base[index]`, where `base` has pointer type: the same thing as
3012 /// `*(base + index)`, which is what C says it is.
3013 Index {
3014 /// The pointer the subscript is relative to.
3015 base: Box<Expr>,
3016 /// The subscript, of integer type.
3017 index: Box<Expr>,
3018 },
3019 /// `base.field`, where `field` indexes the record's member list. `p->f`
3020 /// arrives as a `Field` over a `Deref`.
3021 Field {
3022 /// The record the member belongs to.
3023 base: Box<Place>,
3024 /// The record's identity.
3025 record: RecordId,
3026 /// The index of the member in the record's field list.
3027 index: usize,
3028 },
3029 /// `__real__ z` or `__imag__ z`: one part of a complex object, which GNU C
3030 /// makes an lvalue whenever `z` is one, so `__imag__ z = 1.0;` assigns.
3031 ///
3032 /// The type of the place is the [corresponding real
3033 /// type](Ty::complex_component); `base` is the complex object, which may be
3034 /// a [`PlaceKind::Temporary`] when the operand was an rvalue.
3035 ComplexPart {
3036 /// The complex object the part belongs to.
3037 base: Box<Place>,
3038 /// Whether this is `__imag__` rather than `__real__`.
3039 imag: bool,
3040 },
3041 /// A string literal, whose type is an array of `char` (or of `wchar_t`).
3042 Str(StrId),
3043 /// A temporary holding the value of an expression, which is what makes
3044 /// `f().field` work for a `struct` returned by value.
3045 Temporary(Box<Expr>),
3046 /// The object a block-scope compound literal (`(T){ … }`, C99 6.5.2.5)
3047 /// denotes.
3048 ///
3049 /// Unlike a [`PlaceKind::Temporary`] it is a real object with automatic
3050 /// storage duration and the lifetime of the *enclosing block*, so its
3051 /// address may be taken and used for the rest of that block. `object` is a
3052 /// hidden local sema declares at the top of that block, zero-initialised;
3053 /// `init` is the value the literal was written with, and is evaluated
3054 /// *here* — where the literal stands — so that C's evaluation order
3055 /// survives and a literal inside a loop is built afresh on every
3056 /// iteration. A compound literal at *file* scope is an ordinary
3057 /// [`Storage::Static`] object instead and arrives as a
3058 /// [`PlaceKind::Object`].
3059 CompoundLiteral {
3060 /// The hidden local the object lives in.
3061 object: ObjectId,
3062 /// The value stored into it where the literal was written.
3063 init: Box<Expr>,
3064 },
3065}
3066
3067/// A typed expression.
3068#[derive(Clone, Debug)]
3069pub struct Expr {
3070 /// What the expression computes.
3071 pub kind: ExprKind,
3072 /// The type of its value.
3073 pub ty: Ty,
3074 /// The number of bits the value is reduced to, when that is narrower than
3075 /// [`Expr::ty`].
3076 ///
3077 /// A bit-field wider than `int` keeps its declared type through the
3078 /// integer promotions (6.3.1.1p2 has nothing to say about it), but its
3079 /// *value* still ranges over the declared width only, and C99 6.7.2.1p10
3080 /// makes that width the type the arithmetic happens in: `unsigned long
3081 /// long b : 40` multiplies, adds and shifts in forty bits, exactly as an
3082 /// `unsigned int` does in thirty-two. Nothing else in the type model can
3083 /// say that, so the width rides along on the expression and code
3084 /// generation reduces the result to it.
3085 pub bits: Option<u32>,
3086 /// Where it was written.
3087 pub range: SourceRange,
3088}
3089
3090impl Expr {
3091 /// Builds an expression.
3092 pub fn new(kind: ExprKind, ty: Ty, range: SourceRange) -> Self {
3093 Self {
3094 kind,
3095 ty,
3096 bits: None,
3097 range,
3098 }
3099 }
3100
3101 /// The same expression, computed in `bits` bits; see [`Expr::bits`].
3102 pub fn narrowed(mut self, bits: Option<u32>) -> Self {
3103 self.bits = bits;
3104 self
3105 }
3106
3107 /// An integer constant of type `ty`.
3108 pub fn int(value: i128, ty: Ty, range: SourceRange) -> Self {
3109 Self::new(ExprKind::Int(value), ty, range)
3110 }
3111}
3112
3113/// The class of one *eightbyte* of a `struct` or `union` read out of an
3114/// argument list, under the x86-64 System V classification (AMD64 psABI
3115/// 3.2.3).
3116///
3117/// [`crate::sema`] computes it and code generation turns each entry into one
3118/// `next_arg` call. There is deliberately no `SseUp`: the reference
3119/// implementation this mirrors — `rustc_target`'s
3120/// `compiler/rustc_target/src/callconv/x86_64.rs` — needs that class for SIMD
3121/// vectors and for the floating types wider than eight bytes, and a C program
3122/// this crate translates has neither, `long double` being mapped to `double`.
3123#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3124pub enum Eightbyte {
3125 /// An integer register: read as a `u64`.
3126 Int,
3127 /// An SSE register: read as an `f64`, whose bits are the eightbyte.
3128 Sse,
3129 /// Nothing of the object reaches this eightbyte — it is padding, which the
3130 /// ABI passes in no register at all, so nothing is read for it.
3131 None,
3132}
3133
3134/// Who is being called.
3135#[derive(Clone, Debug)]
3136pub enum Callee {
3137 /// A named function.
3138 Direct(FuncId),
3139 /// An expression of function-pointer type.
3140 Indirect(Box<Expr>),
3141}
3142
3143/// The shape of an [`Expr`].
3144#[derive(Clone, Debug)]
3145pub enum ExprKind {
3146 /// An integer constant, already reduced to the range of its type.
3147 Int(i128),
3148 /// A floating constant.
3149 Float(f64),
3150 /// A complex value built from its two parts, which have the
3151 /// [corresponding real type](Ty::complex_component).
3152 ///
3153 /// It is what `__builtin_complex(x, y)` — and therefore `CMPLX` — makes,
3154 /// what an imaginary constant such as `2.0i` is, and what a folded complex
3155 /// constant comes back as.
3156 ComplexOf {
3157 /// The real part.
3158 re: Box<Expr>,
3159 /// The imaginary part.
3160 im: Box<Expr>,
3161 },
3162 /// The all-bits-zero value of the expression's type: `0`, `0.0`, `false`,
3163 /// a null pointer, or a zeroed aggregate.
3164 Zeroed,
3165 /// Reading a place.
3166 Load(Place),
3167 /// The address of a place. The expression's type says what pointer type is
3168 /// wanted, which is what turns an array place into a pointer to its first
3169 /// element.
3170 AddrOf(Place),
3171 /// The address of a function, whose type is a pointer to it.
3172 FuncAddr(FuncId),
3173 /// GNU's `&&label`: the address of a label of the enclosing function, of
3174 /// type `void *`.
3175 ///
3176 /// A function that takes one is lowered through a [control-flow
3177 /// graph](crate::cfg), and the value is the label's *number* among the
3178 /// function's labels whose address is taken, from 1, cast to a pointer —
3179 /// which is what `goto *e`'s `switch` matches on. It is an *address constant*,
3180 /// so a `static void *table[] = { &&a, &&b };` holds a table of them.
3181 LabelAddr(LabelId),
3182 /// `place = value`, whose value is the value stored.
3183 Assign {
3184 /// The assigned-to location.
3185 place: Place,
3186 /// The value, already converted to the place's type.
3187 value: Box<Expr>,
3188 },
3189 /// `place op= value`, whose value is the value stored.
3190 ///
3191 /// For a pointer place `compute` is the pointer type and `value` keeps its
3192 /// integer type: `p += n` is pointer arithmetic, not an addition.
3193 CompoundAssign {
3194 /// The assigned-to location, evaluated exactly once.
3195 place: Place,
3196 /// The operator.
3197 op: BinOp,
3198 /// The right operand, already converted for `compute`.
3199 value: Box<Expr>,
3200 /// The type the operation is carried out in, before the result is
3201 /// converted back to the place's type.
3202 compute: Ty,
3203 },
3204 /// `++place`, `place++`, `--place` or `place--`.
3205 IncDec {
3206 /// The affected location.
3207 place: Place,
3208 /// Whether this decrements.
3209 dec: bool,
3210 /// Whether the value is the one from before the update.
3211 postfix: bool,
3212 },
3213 /// Arithmetic negation, on an already promoted operand.
3214 Neg(Box<Expr>),
3215 /// `~x`, on an already promoted operand.
3216 BitNot(Box<Expr>),
3217 /// A binary operation. Both operands already have the result type, except
3218 /// for shifts, whose operands are promoted separately.
3219 Binary {
3220 /// The operator.
3221 op: BinOp,
3222 /// Left operand.
3223 lhs: Box<Expr>,
3224 /// Right operand.
3225 rhs: Box<Expr>,
3226 },
3227 /// `ptr + index` or `ptr - index`: pointer arithmetic in units of the
3228 /// pointee, which is what `<*mut T>::offset` does.
3229 PtrOffset {
3230 /// The pointer, which is also the type of the result.
3231 ptr: Box<Expr>,
3232 /// The offset, of integer type.
3233 index: Box<Expr>,
3234 /// Whether the offset is subtracted.
3235 sub: bool,
3236 },
3237 /// `lhs - rhs` between two pointers, whose value has type `ptrdiff_t`.
3238 PtrDiff {
3239 /// Left operand.
3240 lhs: Box<Expr>,
3241 /// Right operand.
3242 rhs: Box<Expr>,
3243 },
3244 /// A comparison. Both operands already have a common type; the result has
3245 /// type `int` and is 0 or 1.
3246 Compare {
3247 /// The operator.
3248 op: CmpOp,
3249 /// Left operand.
3250 lhs: Box<Expr>,
3251 /// Right operand.
3252 rhs: Box<Expr>,
3253 },
3254 /// `&&` or `||`: each operand is tested against zero, the right one only if
3255 /// the left does not already decide the result. The result has type `int`
3256 /// and is 0 or 1.
3257 Logical {
3258 /// The operator.
3259 op: LogicalOp,
3260 /// Left operand.
3261 lhs: Box<Expr>,
3262 /// Right operand.
3263 rhs: Box<Expr>,
3264 },
3265 /// A conversion to the expression's own type.
3266 Cast(Box<Expr>),
3267 /// `cond ? then_expr : else_expr`, with both arms already converted to the
3268 /// expression's type.
3269 Cond {
3270 /// The controlling expression.
3271 cond: Box<Expr>,
3272 /// The value when the condition is true.
3273 then_expr: Box<Expr>,
3274 /// The value otherwise.
3275 else_expr: Box<Expr>,
3276 },
3277 /// GNU's `a ?: b`: `a` if it is non-zero and `b` otherwise, with `a`
3278 /// evaluated exactly once. Both operands already have the result type.
3279 CondDefault {
3280 /// The value that is both the condition and the first result.
3281 value: Box<Expr>,
3282 /// The value when it is zero.
3283 else_expr: Box<Expr>,
3284 },
3285 /// GNU's statement expression, `({ …; e; })`.
3286 StmtExpr {
3287 /// The statements, in order.
3288 stmts: Vec<Stmt>,
3289 /// The value of the last expression statement, if there was one.
3290 value: Option<Box<Expr>>,
3291 },
3292 /// A builtin lowered to a fixed piece of Rust; see [`BuiltinOp`].
3293 Builtin {
3294 /// Which builtin.
3295 op: BuiltinOp,
3296 /// Its operands, already converted.
3297 args: Vec<Expr>,
3298 },
3299 /// One of the atomic builtins; see [`AtomicExpr`].
3300 ///
3301 /// Boxed because it is much the largest thing an expression can hold and
3302 /// every other node would grow to its size.
3303 Atomic(Box<AtomicExpr>),
3304 /// `lhs, rhs`: `lhs` is evaluated for its side effects only.
3305 Comma {
3306 /// Evaluated and discarded.
3307 lhs: Box<Expr>,
3308 /// The result.
3309 rhs: Box<Expr>,
3310 },
3311 /// A call, with every argument already converted to its parameter's type
3312 /// (or promoted, for the variable part of a variadic call).
3313 Call {
3314 /// What is called.
3315 callee: Callee,
3316 /// The arguments.
3317 args: Vec<Expr>,
3318 },
3319 /// A `struct` value: one expression per member, in declaration order.
3320 RecordLit {
3321 /// The record's identity.
3322 record: RecordId,
3323 /// The member values.
3324 fields: Vec<Expr>,
3325 },
3326 /// A `union` value, which initialises exactly one member.
3327 UnionLit {
3328 /// The record's identity.
3329 record: RecordId,
3330 /// The index of the initialised member.
3331 index: usize,
3332 /// Its value.
3333 value: Box<Expr>,
3334 },
3335 /// An array value: one expression per element.
3336 ArrayLit(Vec<Expr>),
3337 /// An array value whose elements are all the same: `[value; len]`.
3338 ArrayRepeat {
3339 /// The repeated element.
3340 value: Box<Expr>,
3341 /// How many times it is repeated.
3342 len: u64,
3343 },
3344 /// A fresh copy of the argument list the function was called with.
3345 ///
3346 /// It is what `va_start` stores and what a `va_list` local starts out as;
3347 /// the list it copies is the `...` parameter of a variadic definition, or
3348 /// the function's own `va_list` parameter. Its type is [`Ty::VaList`].
3349 VaListPristine,
3350 /// `va_arg(ap, T)`: reads the next argument and advances `ap`. The
3351 /// expression's own type is `T`.
3352 VaArg {
3353 /// The list to read from and advance.
3354 ap: Place,
3355 /// How a `struct` or `union` is taken apart to be read: one entry per
3356 /// [eightbyte](Eightbyte) of it, in order. `None` for every other
3357 /// type, which is read in one `next_arg` at the type itself.
3358 record: Option<Vec<Eightbyte>>,
3359 },
3360 /// C23's `unreachable()`, which promises control never gets here.
3361 Unreachable,
3362 /// `va_end(ap)`, whose type is `void`.
3363 ///
3364 /// Rust ends a list when it goes out of scope, so this does nothing; it is
3365 /// a node of its own so that the expansion does not have to pretend the
3366 /// call happened.
3367 VaEnd,
3368}
3369
3370// ---------------------------------------------------------------------------
3371// statements
3372// ---------------------------------------------------------------------------
3373
3374/// What a `break` leaves.
3375#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3376pub enum BreakTarget {
3377 /// The innermost enclosing loop.
3378 Loop(LoopId),
3379 /// The innermost enclosing `switch`.
3380 Switch(SwitchId),
3381}
3382
3383/// A typed statement.
3384#[derive(Clone, Debug)]
3385pub enum Stmt {
3386 /// The null statement.
3387 Nop,
3388 /// An expression evaluated for its side effects.
3389 Expr(Expr),
3390 /// A local variable definition. C leaves an uninitialised local
3391 /// indeterminate; the initialiser here is a zero of the right type in that
3392 /// case, so that the generated Rust never reads uninitialised memory.
3393 Let {
3394 /// The object being defined.
3395 object: ObjectId,
3396 /// Its initial value, already converted to the object's type.
3397 init: Expr,
3398 /// Whether the source wrote an initialiser at all.
3399 ///
3400 /// It decides what happens when the definition has to be hoisted out
3401 /// of the block it was written in — out of a `switch` body, or to the
3402 /// top of a function lowered into a [control-flow graph](crate::cfg).
3403 /// The hoisted definition zero-initialises; only an initialiser the
3404 /// program actually wrote has to run again where it was written.
3405 explicit: bool,
3406 },
3407 /// The definition of a variable length array (C99 6.7.5.2).
3408 ///
3409 /// It is a [`Stmt::Let`] with two bindings instead of one, because the
3410 /// object needs storage whose size is only known here; see [`VlaDef`].
3411 Vla(Box<VlaDef>),
3412 /// `T x __attribute__((cleanup(f)));` — the registration of the call that
3413 /// runs when `x` goes out of scope. See [`CleanupDef`].
3414 Cleanup(Box<CleanupDef>),
3415 /// A compound statement.
3416 Block(Vec<Stmt>),
3417 /// `if (cond) then_branch else else_branch`
3418 If {
3419 /// The controlling expression.
3420 cond: Expr,
3421 /// Taken when `cond` is non-zero.
3422 then_branch: Box<Stmt>,
3423 /// Taken otherwise.
3424 else_branch: Option<Box<Stmt>>,
3425 },
3426 /// `while (cond) body`
3427 While {
3428 /// This loop's identity.
3429 id: LoopId,
3430 /// The controlling expression.
3431 cond: Expr,
3432 /// The loop body.
3433 body: Box<Stmt>,
3434 /// Where the statement was written.
3435 range: SourceRange,
3436 },
3437 /// `do body while (cond);`
3438 DoWhile {
3439 /// This loop's identity.
3440 id: LoopId,
3441 /// The loop body.
3442 body: Box<Stmt>,
3443 /// The controlling expression.
3444 cond: Expr,
3445 /// Where the statement was written.
3446 range: SourceRange,
3447 },
3448 /// `for (init; cond; step) body`
3449 For {
3450 /// This loop's identity.
3451 id: LoopId,
3452 /// The init clause, which may declare variables scoped to the loop.
3453 init: Vec<Stmt>,
3454 /// The controlling expression; absent means "always true".
3455 cond: Option<Expr>,
3456 /// The iteration expression.
3457 step: Option<Expr>,
3458 /// The loop body.
3459 body: Box<Stmt>,
3460 /// Where the statement was written.
3461 range: SourceRange,
3462 },
3463 /// `switch (scrutinee) { … }`
3464 Switch(Box<Switch>),
3465 /// `switch (scrutinee) body`, with the body left as a statement tree.
3466 ///
3467 /// Only produced in [CFG mode](crate::cfg), where the labels stay where
3468 /// they were written — a `case` inside a nested statement (Duff's device)
3469 /// is simply another edge into the loop the CFG builds.
3470 SwitchTree(Box<SwitchTree>),
3471 /// `case value:` or `default:` inside a [`Stmt::SwitchTree`].
3472 Case {
3473 /// The `switch` the label belongs to.
3474 switch: SwitchId,
3475 /// The values that enter here, or `None` for `default:`.
3476 value: Option<CaseRange>,
3477 /// The labelled statement.
3478 body: Box<Stmt>,
3479 /// Where the label was written.
3480 range: SourceRange,
3481 },
3482 /// `label: body` — a `goto` target.
3483 Label {
3484 /// The label's identity.
3485 id: LabelId,
3486 /// The labelled statement.
3487 body: Box<Stmt>,
3488 /// Where the label was written.
3489 range: SourceRange,
3490 },
3491 /// A labelled region a `goto` leaves, in the structured lowering.
3492 ///
3493 /// Only produced by [`regions`](crate::regions), which is where the shape
3494 /// and the two kinds are described. A [`Stmt::Goto`] inside one names its
3495 /// label and becomes `break` or `continue` accordingly.
3496 Region(Box<Region>),
3497 /// `goto label;`
3498 Goto {
3499 /// The label jumped to.
3500 id: LabelId,
3501 /// Where the statement was written.
3502 range: SourceRange,
3503 },
3504 /// GNU's computed `goto *e;`, whose operand is a [label
3505 /// address](ExprKind::LabelAddr).
3506 ///
3507 /// Only produced in [CFG mode](crate::cfg), which is the only mode a
3508 /// function containing one is lowered in.
3509 GotoPtr {
3510 /// The pointer jumped through.
3511 target: Expr,
3512 /// Where the statement was written.
3513 range: SourceRange,
3514 },
3515 /// `break;`
3516 Break {
3517 /// What the `break` leaves.
3518 target: BreakTarget,
3519 /// Where the statement was written.
3520 range: SourceRange,
3521 },
3522 /// `continue;`
3523 Continue {
3524 /// The loop the `continue` restarts.
3525 id: LoopId,
3526 /// Where the statement was written.
3527 range: SourceRange,
3528 },
3529 /// `return;` or `return expr;`
3530 Return {
3531 /// The returned value.
3532 value: Option<Expr>,
3533 /// Where the statement was written.
3534 range: SourceRange,
3535 },
3536 /// GNU inline assembly, mapped onto `core::arch::asm!`; see [`AsmStmt`].
3537 ///
3538 /// It has no control flow of its own (`asm goto` is refused), so the
3539 /// [control-flow graph](crate::cfg) carries it as a simple statement.
3540 Asm(Box<AsmStmt>),
3541}
3542
3543/// An inline assembly statement, already in `asm!`'s terms.
3544///
3545/// Sema has done all the mapping (see `sema/asm.rs`): the template is Rust's
3546/// — `%0` is `{o0}`, `%%` is `%`, braces are doubled — and each operand says
3547/// which register and which direction. What is left for code generation is
3548/// evaluating the operands and storing the outputs back.
3549#[derive(Clone, Debug)]
3550pub struct AsmStmt {
3551 /// The template in `asm!`'s syntax, still AT&T assembly: code generation
3552 /// always adds `options(att_syntax)`.
3553 pub template: String,
3554 /// The operands, in GCC's order (outputs, then inputs), with each tied
3555 /// input folded into the output it is tied to.
3556 pub operands: Vec<AsmOperand>,
3557 /// The registers the statement clobbers, in `asm!`'s spelling (`rax`,
3558 /// `xmm0`), each of which becomes `out("rax") _`. `"memory"` and `"cc"`
3559 /// are not here: they are what `asm!` assumes without being told.
3560 pub clobbers: Vec<&'static str>,
3561 /// Where the statement was written.
3562 pub range: SourceRange,
3563}
3564
3565/// One operand of an [`AsmStmt`].
3566#[derive(Clone, Debug)]
3567pub struct AsmOperand {
3568 /// The `asm!` name the template refers to it by — `o` and the GCC
3569 /// operand number — or `None` for an explicit register, which `asm!`
3570 /// does not let a template name (sema writes the register itself).
3571 pub name: Option<String>,
3572 /// Where the value lives.
3573 pub reg: AsmReg,
3574 /// The direction, and the C side of it.
3575 pub kind: AsmOperandKind,
3576 /// The C type of the value, which is what the `asm!` operand has.
3577 pub ty: Ty,
3578 /// Where the operand was written.
3579 pub range: SourceRange,
3580}
3581
3582impl AsmOperand {
3583 /// The head of the `asm!` operand, up to the expression: `o0 =
3584 /// lateout(reg)`, `inout("eax")`, `o2 = const`.
3585 pub fn head(&self) -> String {
3586 let dir = match &self.kind {
3587 AsmOperandKind::In(_) => "in",
3588 AsmOperandKind::Out { late: true, .. } => "lateout",
3589 AsmOperandKind::Out { late: false, .. } => "out",
3590 AsmOperandKind::InOut { .. } | AsmOperandKind::Scratch(_) => "inout",
3591 AsmOperandKind::Const(_) => "const",
3592 };
3593 let reg = match (&self.kind, self.reg) {
3594 (AsmOperandKind::Const(_), _) => String::new(),
3595 (_, AsmReg::Class(class)) => format!("({class})"),
3596 (_, AsmReg::Explicit(name)) => format!("(\"{name}\")"),
3597 };
3598 match &self.name {
3599 Some(name) => format!("{name} = {dir}{reg}"),
3600 None => format!("{dir}{reg}"),
3601 }
3602 }
3603}
3604
3605/// Where an [`AsmOperand`] lives.
3606#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3607pub enum AsmReg {
3608 /// A register `asm!` allocates from a class: `reg`, `reg_byte`,
3609 /// `reg_abcd`, `xmm_reg`, `ymm_reg`, `zmm_reg`.
3610 Class(&'static str),
3611 /// One register, spelled at the operand's width: `al`, `ecx`, `rdx`.
3612 Explicit(&'static str),
3613}
3614
3615/// The direction of an [`AsmOperand`].
3616#[derive(Clone, Debug)]
3617pub enum AsmOperandKind {
3618 /// An input: the value is computed before the statement.
3619 In(Expr),
3620 /// An output, stored into `place` afterwards. `late` is `lateout` — GCC's
3621 /// plain `=`, written only after every input has been read — and its
3622 /// absence is `out`, GCC's early clobber `=&`.
3623 Out {
3624 /// Where the value goes.
3625 place: Place,
3626 /// Whether the register may share one with an input.
3627 late: bool,
3628 },
3629 /// An operand that is read and written: GCC's `+`, or an output with an
3630 /// input tied to it by a digit constraint (`"=r"(x) : "0"(y)`).
3631 InOut {
3632 /// The tied input's value, already converted to the output's type;
3633 /// `None` for `+`, where the input is whatever `output` holds.
3634 input: Option<Expr>,
3635 /// Where the value goes.
3636 output: Place,
3637 },
3638 /// An input whose register the statement overwrites, so the value it
3639 /// leaves there is thrown away: `inout(reg) value => _`. This is an
3640 /// input with the constraint `"b"`, carried through a scratch register
3641 /// that the `xchg` around the template swaps with rbx (see `sema/asm.rs`).
3642 Scratch(Expr),
3643 /// An immediate, folded: `"i"(3)` is `const 3`.
3644 Const(i128),
3645}
3646
3647impl Stmt {
3648 /// Whether this is a [`cleanup`](CleanupDef) registration.
3649 pub fn is_cleanup(&self) -> bool {
3650 matches!(self, Stmt::Cleanup(_))
3651 }
3652}
3653
3654/// A variably modified object's definition: `T a[n];`, `T a[n][m];`.
3655///
3656/// C99 6.7.5.2 gives the object automatic storage duration, a size fixed when
3657/// the declaration is reached, and the lifetime of the block it is written in;
3658/// each bound is evaluated exactly once, where the declaration stands, and
3659/// lives in a hidden `size_t` object the [type](ArrayType::vla_len) points at.
3660/// This crate emulates the storage with a per-function bump arena on the heap
3661/// — the elements are bumped off it, and a hidden frame guard whose `Drop`
3662/// moves the arena back down is that lifetime — so the one definition becomes
3663/// a [`Stmt::Let`] per bound followed by two more bindings:
3664///
3665/// ```text
3666/// let __cinrs_vla_len_a: size_t = <n>; // one per bound
3667/// let __cinrs_vla_frame_a = __cinrs_vla.frame(); // frame
3668/// let mut a: *mut T = __cinrs_vla.alloc::<T>(count); // object
3669/// ```
3670///
3671/// From there the object *is* a pointer to the first element: decay is the
3672/// identity, `a[i]` is pointer indexing scaled by the run-time size of a row,
3673/// and `sizeof a` is the product of the bounds times the element size — see
3674/// [`Types::vm_step_ty`] for what "element" means once more than one dimension
3675/// is variable.
3676#[derive(Clone, Debug)]
3677pub struct VlaDef {
3678 /// The object the C program declared, whose type is the array type and
3679 /// whose generated binding is a pointer to the first element.
3680 pub object: ObjectId,
3681 /// The hidden frame that gives the elements back; see
3682 /// [`Object::vla_storage`].
3683 pub storage: ObjectId,
3684 /// The number of elements to allocate: the product of every dimension,
3685 /// read out of the hidden bound objects, in units of the storage's
3686 /// element type.
3687 pub count: Expr,
3688 /// The alignment `_Alignas(N)` or `__attribute__((aligned(N)))` asked
3689 /// for, when it is stricter than the element type's: the arena then pads
3690 /// its position to the first address that is a multiple of it.
3691 pub align: Option<u64>,
3692 /// Where the declarator was written.
3693 pub range: SourceRange,
3694}
3695
3696/// A `cleanup` attribute's registration: `T x __attribute__((cleanup(f)));`.
3697///
3698/// GCC calls `f(&x)` on *every* exit from the scope `x` was declared in, in
3699/// reverse declaration order. The two lowerings say that in different ways:
3700///
3701/// * the structured one binds a drop guard right after the object, so that
3702/// Rust's own drop order — reverse declaration order, on every path out of
3703/// the block, `return` from inside a statement expression included — is C's;
3704/// * the [CFG](crate::cfg) one has no scopes left to drop in, so it emits
3705/// [`CleanupDef::call`] on each edge that leaves the scope.
3706#[derive(Clone, Debug)]
3707pub struct CleanupDef {
3708 /// The variable whose address the function is given.
3709 pub object: ObjectId,
3710 /// The function called with it.
3711 pub func: FuncId,
3712 /// The type of that function's one parameter, which is the pointer type
3713 /// the address is converted to.
3714 pub param: Ty,
3715 /// `f(&x)`, ready to be emitted where a scope is left.
3716 pub call: Expr,
3717 /// Where the declarator was written.
3718 pub range: SourceRange,
3719}
3720
3721/// A `switch` statement, flattened into the groups its labels delimit.
3722///
3723/// The body of a `switch` is a single statement that execution *jumps into*,
3724/// which is why it cannot be a tree here: the labels split it into a sequence
3725/// of groups that fall through into one another. See [`codegen`](crate::codegen)
3726/// for how the sequence becomes Rust.
3727#[derive(Clone, Debug)]
3728pub struct Switch {
3729 /// This switch's identity.
3730 pub id: SwitchId,
3731 /// The controlling expression, after the integer promotions.
3732 pub scrutinee: Expr,
3733 /// Objects declared directly in the switch body.
3734 ///
3735 /// C keeps them alive for the whole body even though execution may jump
3736 /// past their declaration, so they are defined ahead of the dispatch and
3737 /// zero-initialised; whatever initialiser the source wrote stays where it
3738 /// was written, as an assignment.
3739 pub hoisted: Vec<ObjectId>,
3740 /// Statements between the `{` and the first label. C can never reach them.
3741 pub prelude: Vec<Stmt>,
3742 /// The groups, in source order.
3743 pub groups: Vec<SwitchGroup>,
3744 /// The index in `groups` that `default:` labels, if any.
3745 pub default_group: Option<usize>,
3746 /// Where the statement was written.
3747 pub range: SourceRange,
3748}
3749
3750/// A labelled region a `goto` leaves or restarts.
3751///
3752/// The statements a C label divides are wrapped in one of these when every
3753/// `goto` to that label is a jump Rust can make on its own; see
3754/// [`regions`](crate::regions) for which jumps those are and how the
3755/// boundaries are chosen. Code generation emits a labelled block or a labelled
3756/// loop, named after the C label:
3757///
3758/// ```text
3759/// 'done: { … break 'done; … } 'retry: loop { … continue 'retry; … break 'retry; }
3760/// ```
3761#[derive(Clone, Debug)]
3762pub struct Region {
3763 /// The label the region belongs to, which the `goto`s inside it name.
3764 pub label: LabelId,
3765 /// The label's name in C, which the generated Rust label is built from.
3766 pub name: String,
3767 /// Whether a `goto` to it leaves the region or restarts it.
3768 pub kind: RegionKind,
3769 /// The statements inside.
3770 pub body: Vec<Stmt>,
3771 /// Whether control can reach the end of `body`, so that a
3772 /// [loop](RegionKind::Loop) needs a `break` there to leave it. A loop
3773 /// without one is a Rust `loop` that never finishes, which is what makes a
3774 /// function ending in it need no `return`.
3775 pub falls_out: bool,
3776 /// Where the label was written.
3777 pub range: SourceRange,
3778}
3779
3780/// Which way a [`Region`]'s label is entered.
3781#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3782pub enum RegionKind {
3783 /// The label stands *after* the region: a `goto` to it is `break 'l`, and
3784 /// the statements the label introduces follow the block.
3785 Block,
3786 /// The label stands at the *start* of the region: a `goto` to it is
3787 /// `continue 'l`, and control leaves by falling off the end.
3788 Loop,
3789}
3790
3791/// A `switch` whose body has been left as a statement tree.
3792///
3793/// The [CFG lowering](crate::cfg) walks the tree and turns every [`Stmt::Case`]
3794/// it finds into an edge from this statement's dispatch, wherever in the tree
3795/// it sits. That is what makes Duff's device work, and it is why sema does not
3796/// need to flatten the body into groups in that mode.
3797#[derive(Clone, Debug)]
3798pub struct SwitchTree {
3799 /// This switch's identity, which `break` and the labels refer to.
3800 pub id: SwitchId,
3801 /// The controlling expression, after the integer promotions.
3802 pub scrutinee: Expr,
3803 /// The body, with its labels still in place.
3804 pub body: Box<Stmt>,
3805 /// Where the statement was written.
3806 pub range: SourceRange,
3807}
3808
3809/// The values one `case` label matches.
3810///
3811/// A plain `case k:` is the range `k..=k`; GNU's `case low ... high:` is the
3812/// whole interval, which code generation emits as one Rust range pattern
3813/// rather than as one arm per value — `case 0 ... 1000000:` is a perfectly
3814/// ordinary thing to write.
3815#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3816pub struct CaseRange {
3817 /// The lowest value, already converted to the controlling type.
3818 pub low: i128,
3819 /// The highest, which equals `low` for a plain label.
3820 pub high: i128,
3821}
3822
3823impl CaseRange {
3824 /// The range one value makes.
3825 pub fn single(value: i128) -> Self {
3826 Self {
3827 low: value,
3828 high: value,
3829 }
3830 }
3831
3832 /// Whether this is a plain `case k:`.
3833 pub fn is_single(self) -> bool {
3834 self.low == self.high
3835 }
3836
3837 /// Whether two labels would both match some value.
3838 pub fn overlaps(self, other: CaseRange) -> bool {
3839 self.low <= other.high && other.low <= self.high
3840 }
3841}
3842
3843/// One run of statements in a `switch`, together with the values that enter it.
3844#[derive(Clone, Debug)]
3845pub struct SwitchGroup {
3846 /// The `case` values that jump here, already converted to the type of the
3847 /// controlling expression.
3848 pub values: Vec<CaseRange>,
3849 /// The statements, which fall through into the next group.
3850 pub body: Vec<Stmt>,
3851}
3852
3853// ---------------------------------------------------------------------------
3854// reachability
3855// ---------------------------------------------------------------------------
3856
3857/// Whether control can never fall off the end of `stmts`.
3858///
3859/// Used to decide whether a non-`void` function needs a synthesised
3860/// `return`. Deliberately conservative: saying "no" only ever costs a
3861/// `return` statement the program does not reach, while saying "yes" wrongly
3862/// would produce Rust that does not compile.
3863///
3864/// `functions` is the program's function table, which is what a call to a
3865/// `_Noreturn` function is recognised through; code generation makes that
3866/// divergence visible to Rust by following such a call with
3867/// `::core::unreachable!()`.
3868pub fn always_terminates(stmts: &[Stmt], functions: &[Function]) -> bool {
3869 stmts
3870 .last()
3871 .is_some_and(|stmt| stmt_always_terminates(stmt, functions))
3872}
3873
3874/// Whether evaluating `expr` never returns.
3875///
3876/// Only a direct call to a `_Noreturn` function counts: a call through a
3877/// pointer has no declaration to read the specifier from.
3878pub fn expr_never_returns(expr: &Expr, functions: &[Function]) -> bool {
3879 match &expr.kind {
3880 ExprKind::Call {
3881 callee: Callee::Direct(id),
3882 ..
3883 } => functions
3884 .get(id.0 as usize)
3885 .is_some_and(|func| func.noreturn),
3886 ExprKind::Unreachable => true,
3887 // `(void)abort();` and `f(), abort();` end just as surely.
3888 ExprKind::Cast(inner) => expr_never_returns(inner, functions),
3889 ExprKind::Comma { rhs, .. } => expr_never_returns(rhs, functions),
3890 _ => false,
3891 }
3892}
3893
3894/// Whether evaluating `expr` can call a function.
3895///
3896/// C11 6.5.16.2p3 is why this is worth asking: a compound assignment is, "with
3897/// respect to an indeterminately-sequenced function call, a single evaluation",
3898/// so the read-modify-write of `x |= f()` may not be split around the call to
3899/// `f` the way `x = x | f()` would be. Code generation evaluates such a right
3900/// operand into a temporary first, and asks this to know when it has to.
3901pub fn calls_a_function(expr: &Expr) -> bool {
3902 let any = |list: &[Expr]| list.iter().any(calls_a_function);
3903 match &expr.kind {
3904 // A statement expression is a block, which can hold anything.
3905 ExprKind::Call { .. } | ExprKind::StmtExpr { .. } => true,
3906 ExprKind::Int(_)
3907 | ExprKind::Float(_)
3908 | ExprKind::Zeroed
3909 | ExprKind::FuncAddr(_)
3910 | ExprKind::LabelAddr(_)
3911 | ExprKind::VaListPristine
3912 | ExprKind::Unreachable
3913 | ExprKind::VaEnd => false,
3914 ExprKind::Load(place) | ExprKind::AddrOf(place) => place_calls_a_function(place),
3915 ExprKind::VaArg { ap, .. } => place_calls_a_function(ap),
3916 ExprKind::Assign { place, value } | ExprKind::CompoundAssign { place, value, .. } => {
3917 place_calls_a_function(place) || calls_a_function(value)
3918 }
3919 ExprKind::IncDec { place, .. } => place_calls_a_function(place),
3920 ExprKind::Neg(inner) | ExprKind::BitNot(inner) | ExprKind::Cast(inner) => {
3921 calls_a_function(inner)
3922 }
3923 ExprKind::Binary { lhs, rhs, .. }
3924 | ExprKind::Compare { lhs, rhs, .. }
3925 | ExprKind::Logical { lhs, rhs, .. }
3926 | ExprKind::PtrDiff { lhs, rhs }
3927 | ExprKind::Comma { lhs, rhs } => calls_a_function(lhs) || calls_a_function(rhs),
3928 ExprKind::ComplexOf { re, im } => calls_a_function(re) || calls_a_function(im),
3929 ExprKind::PtrOffset { ptr, index, .. } => calls_a_function(ptr) || calls_a_function(index),
3930 ExprKind::Cond {
3931 cond,
3932 then_expr,
3933 else_expr,
3934 } => calls_a_function(cond) || calls_a_function(then_expr) || calls_a_function(else_expr),
3935 ExprKind::CondDefault { value, else_expr } => {
3936 calls_a_function(value) || calls_a_function(else_expr)
3937 }
3938 ExprKind::Builtin { args, .. } => any(args),
3939 ExprKind::Atomic(atomic) => atomic.operands().any(calls_a_function),
3940 ExprKind::RecordLit { fields, .. } => any(fields),
3941 ExprKind::UnionLit { value, .. } => calls_a_function(value),
3942 ExprKind::ArrayLit(items) => any(items),
3943 ExprKind::ArrayRepeat { value, .. } => calls_a_function(value),
3944 }
3945}
3946
3947/// [`calls_a_function`], for the expressions inside a place.
3948fn place_calls_a_function(place: &Place) -> bool {
3949 match &place.kind {
3950 PlaceKind::Object(_) | PlaceKind::Str(_) => false,
3951 PlaceKind::Deref(ptr) => calls_a_function(ptr),
3952 PlaceKind::Index { base, index } => calls_a_function(base) || calls_a_function(index),
3953 PlaceKind::Field { base, .. } | PlaceKind::ComplexPart { base, .. } => {
3954 place_calls_a_function(base)
3955 }
3956 PlaceKind::Temporary(expr) => calls_a_function(expr),
3957 PlaceKind::CompoundLiteral { init, .. } => calls_a_function(init),
3958 }
3959}
3960
3961/// Whether `expr` reads or takes the address of `object`.
3962///
3963/// C99 6.2.1p7 puts an identifier in scope from the end of its declarator, so
3964/// an initialiser may name the object it initialises: `struct list head = {
3965/// &head, &head }` is the idiom, and `T *p = malloc(sizeof *p)` is the one
3966/// everybody writes. A Rust binding cannot be named in its own initialiser, so
3967/// an *automatic* object whose initialiser does this is defined with a zero
3968/// and assigned afterwards; this is what tells the two apart. An object with
3969/// static storage duration needs nothing: the generated item takes its own
3970/// address with `&raw mut`, which reads nothing and is a constant.
3971pub fn mentions_object(expr: &Expr, object: ObjectId) -> bool {
3972 mentions_object_in(expr, object, false)
3973}
3974
3975/// The index of `table[index]` read as a value — the whole of `expr` being
3976/// that read, the array decayed to a pointer to its first element and only
3977/// conversions around the decay.
3978///
3979/// This is the one use of a dispatch table of label addresses that leaves the
3980/// table's contents known; see [`crate::cfg`]'s table fold.
3981pub fn table_read(expr: &Expr, table: ObjectId) -> Option<&Expr> {
3982 let ExprKind::Load(place) = &expr.kind else {
3983 return None;
3984 };
3985 let PlaceKind::Index { base, index } = &place.kind else {
3986 return None;
3987 };
3988 let mut base: &Expr = base;
3989 while let ExprKind::Cast(inner) = &base.kind {
3990 base = inner;
3991 }
3992 match &base.kind {
3993 ExprKind::AddrOf(Place {
3994 kind: PlaceKind::Object(id),
3995 ..
3996 }) if *id == table => Some(index),
3997 _ => None,
3998 }
3999}
4000
4001/// Whether any of `stmts` names `object` other than in a [`table_read`] of
4002/// it — which is what says a table is never written, never has its address
4003/// taken and never goes anywhere, so its contents are its initialiser's.
4004///
4005/// Conservative: a statement expression, a variable length array's size and
4006/// an inline assembly statement all count as naming it.
4007pub fn stmts_use_object_beyond_reads(stmts: &[Stmt], object: ObjectId) -> bool {
4008 stmts.iter().any(|stmt| stmt_uses_object(stmt, object))
4009}
4010
4011/// The initialisers of every [`Stmt::Let`] that defines `object` in `stmts`,
4012/// however deeply nested.
4013pub fn lets_of(stmts: &[Stmt], object: ObjectId) -> Vec<&Expr> {
4014 fn walk<'a>(stmt: &'a Stmt, object: ObjectId, out: &mut Vec<&'a Expr>) {
4015 match stmt {
4016 Stmt::Let {
4017 object: id, init, ..
4018 } if *id == object => out.push(init),
4019 Stmt::Block(items) => items.iter().for_each(|s| walk(s, object, out)),
4020 Stmt::If {
4021 then_branch,
4022 else_branch,
4023 ..
4024 } => {
4025 walk(then_branch, object, out);
4026 if let Some(branch) = else_branch {
4027 walk(branch, object, out);
4028 }
4029 }
4030 Stmt::For { init, body, .. } => {
4031 init.iter().for_each(|s| walk(s, object, out));
4032 walk(body, object, out);
4033 }
4034 Stmt::While { body, .. }
4035 | Stmt::DoWhile { body, .. }
4036 | Stmt::Case { body, .. }
4037 | Stmt::Label { body, .. } => walk(body, object, out),
4038 Stmt::SwitchTree(switch) => walk(&switch.body, object, out),
4039 _ => {}
4040 }
4041 }
4042 let mut out = Vec::new();
4043 stmts.iter().for_each(|s| walk(s, object, &mut out));
4044 out
4045}
4046
4047fn stmt_uses_object(stmt: &Stmt, object: ObjectId) -> bool {
4048 let expr = |e: &Expr| mentions_object_in(e, object, true);
4049 let sub = |s: &Stmt| stmt_uses_object(s, object);
4050 match stmt {
4051 Stmt::Nop
4052 | Stmt::Goto { .. }
4053 | Stmt::Break { .. }
4054 | Stmt::Continue { .. }
4055 | Stmt::Return { value: None, .. } => false,
4056 Stmt::Expr(e) | Stmt::GotoPtr { target: e, .. } => expr(e),
4057 Stmt::Return { value: Some(e), .. } => expr(e),
4058 Stmt::Let { init, .. } => expr(init),
4059 Stmt::Cleanup(def) => expr(&def.call),
4060 Stmt::Block(items) => items.iter().any(sub),
4061 Stmt::If {
4062 cond,
4063 then_branch,
4064 else_branch,
4065 } => expr(cond) || sub(then_branch) || else_branch.as_deref().is_some_and(sub),
4066 Stmt::While { cond, body, .. } | Stmt::DoWhile { cond, body, .. } => {
4067 expr(cond) || sub(body)
4068 }
4069 Stmt::For {
4070 init,
4071 cond,
4072 step,
4073 body,
4074 ..
4075 } => {
4076 init.iter().any(sub)
4077 || cond.as_ref().is_some_and(expr)
4078 || step.as_ref().is_some_and(expr)
4079 || sub(body)
4080 }
4081 Stmt::SwitchTree(switch) => expr(&switch.scrutinee) || sub(&switch.body),
4082 Stmt::Case { body, .. } | Stmt::Label { body, .. } => sub(body),
4083 Stmt::Vla(_) | Stmt::Asm(_) | Stmt::Switch(_) | Stmt::Region(_) => true,
4084 }
4085}
4086
4087/// [`mentions_object`], or — with `reads_ok` — the same with every
4088/// [`table_read`] of the object counted as not naming it.
4089fn mentions_object_in(expr: &Expr, object: ObjectId, reads_ok: bool) -> bool {
4090 if reads_ok && let Some(index) = table_read(expr, object) {
4091 return mentions_object_in(index, object, reads_ok);
4092 }
4093 let mentions_object = |e: &Expr, object: ObjectId| mentions_object_in(e, object, reads_ok);
4094 let place_mentions_object =
4095 |p: &Place, object: ObjectId| place_mentions_in(p, object, reads_ok);
4096 let any = |list: &[Expr]| list.iter().any(|e| mentions_object(e, object));
4097 match &expr.kind {
4098 ExprKind::Int(_)
4099 | ExprKind::Float(_)
4100 | ExprKind::Zeroed
4101 | ExprKind::FuncAddr(_)
4102 | ExprKind::LabelAddr(_)
4103 | ExprKind::VaListPristine
4104 | ExprKind::Unreachable
4105 | ExprKind::VaEnd => false,
4106 ExprKind::Load(place) | ExprKind::AddrOf(place) => place_mentions_object(place, object),
4107 ExprKind::VaArg { ap, .. } => place_mentions_object(ap, object),
4108 ExprKind::Assign { place, value } | ExprKind::CompoundAssign { place, value, .. } => {
4109 place_mentions_object(place, object) || mentions_object(value, object)
4110 }
4111 ExprKind::IncDec { place, .. } => place_mentions_object(place, object),
4112 ExprKind::Neg(inner) | ExprKind::BitNot(inner) | ExprKind::Cast(inner) => {
4113 mentions_object(inner, object)
4114 }
4115 ExprKind::Binary { lhs, rhs, .. }
4116 | ExprKind::Compare { lhs, rhs, .. }
4117 | ExprKind::Logical { lhs, rhs, .. }
4118 | ExprKind::PtrDiff { lhs, rhs }
4119 | ExprKind::Comma { lhs, rhs } => {
4120 mentions_object(lhs, object) || mentions_object(rhs, object)
4121 }
4122 ExprKind::ComplexOf { re, im } => {
4123 mentions_object(re, object) || mentions_object(im, object)
4124 }
4125 ExprKind::PtrOffset { ptr, index, .. } => {
4126 mentions_object(ptr, object) || mentions_object(index, object)
4127 }
4128 ExprKind::Cond {
4129 cond,
4130 then_expr,
4131 else_expr,
4132 } => {
4133 mentions_object(cond, object)
4134 || mentions_object(then_expr, object)
4135 || mentions_object(else_expr, object)
4136 }
4137 ExprKind::CondDefault { value, else_expr } => {
4138 mentions_object(value, object) || mentions_object(else_expr, object)
4139 }
4140 ExprKind::Call { callee, args } => {
4141 let callee = match callee {
4142 Callee::Direct(_) => false,
4143 Callee::Indirect(target) => mentions_object(target, object),
4144 };
4145 callee || any(args)
4146 }
4147 ExprKind::Builtin { args, .. } => any(args),
4148 ExprKind::Atomic(atomic) => atomic.operands().any(|e| mentions_object(e, object)),
4149 ExprKind::RecordLit { fields, .. } => any(fields),
4150 ExprKind::UnionLit { value, .. } => mentions_object(value, object),
4151 ExprKind::ArrayLit(items) => any(items),
4152 ExprKind::ArrayRepeat { value, .. } => mentions_object(value, object),
4153 // A statement expression is a block of its own; whatever it names, it
4154 // names through a scope this cannot walk, so it is taken to reach the
4155 // object rather than risk a binding read before it exists.
4156 ExprKind::StmtExpr { .. } => true,
4157 }
4158}
4159
4160/// [`mentions_object_in`], for the expressions inside a place.
4161fn place_mentions_in(place: &Place, object: ObjectId, reads_ok: bool) -> bool {
4162 let mentions_object = |e: &Expr, object: ObjectId| mentions_object_in(e, object, reads_ok);
4163 let place_mentions_object =
4164 |p: &Place, object: ObjectId| place_mentions_in(p, object, reads_ok);
4165 match &place.kind {
4166 PlaceKind::Object(id) => *id == object,
4167 PlaceKind::Str(_) => false,
4168 PlaceKind::Deref(ptr) => mentions_object(ptr, object),
4169 PlaceKind::Index { base, index } => {
4170 mentions_object(base, object) || mentions_object(index, object)
4171 }
4172 PlaceKind::Field { base, .. } | PlaceKind::ComplexPart { base, .. } => {
4173 place_mentions_object(base, object)
4174 }
4175 PlaceKind::Temporary(expr) => mentions_object(expr, object),
4176 PlaceKind::CompoundLiteral { init, .. } => mentions_object(init, object),
4177 }
4178}
4179
4180fn stmt_always_terminates(stmt: &Stmt, functions: &[Function]) -> bool {
4181 let terminates = |stmt: &Stmt| stmt_always_terminates(stmt, functions);
4182 match stmt {
4183 Stmt::Return { .. } => true,
4184 Stmt::Expr(expr) => expr_never_returns(expr, functions),
4185 Stmt::Block(items) => always_terminates(items, functions),
4186 Stmt::Label { body, .. } => terminates(body),
4187 // Control does not continue into the next statement: the jump is a
4188 // `break` or a `continue` of a region that encloses it.
4189 Stmt::Goto { .. } => true,
4190 // A block is left by falling off its end or by a `break` to its label,
4191 // and both continue at the label the region ends before; a loop is
4192 // left only by the `break` that stands at the end of its body, so one
4193 // that needs none never finishes.
4194 Stmt::Region(region) => match region.kind {
4195 RegionKind::Block => {
4196 always_terminates(®ion.body, functions) && !jumps_to(®ion.body, region.label)
4197 }
4198 RegionKind::Loop => !region.falls_out,
4199 },
4200 Stmt::If {
4201 then_branch,
4202 else_branch: Some(else_branch),
4203 ..
4204 } => terminates(then_branch) && terminates(else_branch),
4205 Stmt::While { id, cond, body, .. } => {
4206 is_always_true(cond) && !breaks_to(body, BreakTarget::Loop(*id))
4207 }
4208 Stmt::DoWhile { id, body, cond, .. } => {
4209 is_always_true(cond) && !breaks_to(body, BreakTarget::Loop(*id))
4210 }
4211 Stmt::For { id, cond, body, .. } => {
4212 cond.as_ref().is_none_or(is_always_true) && !breaks_to(body, BreakTarget::Loop(*id))
4213 }
4214 // Control enters a `switch` at one label and then runs through every
4215 // group after it, so the statement terminates exactly when it can
4216 // neither be skipped (there is a `default:`) nor left early (nothing
4217 // `break`s out of it) and the last group terminates.
4218 Stmt::Switch(switch) => {
4219 switch.default_group.is_some()
4220 && switch
4221 .groups
4222 .last()
4223 .is_some_and(|group| always_terminates(&group.body, functions))
4224 && !switch
4225 .groups
4226 .iter()
4227 .flat_map(|group| group.body.iter())
4228 .chain(switch.prelude.iter())
4229 .any(|s| breaks_to(s, BreakTarget::Switch(switch.id)))
4230 }
4231 _ => false,
4232 }
4233}
4234
4235/// Whether `expr` is a constant that C treats as true.
4236///
4237/// Code generation asks the same question, so that a loop it turns into a Rust
4238/// `loop` — which has no exit for the type checker to see — is exactly the loop
4239/// [`always_terminates`] promised would not fall through.
4240pub fn is_always_true(expr: &Expr) -> bool {
4241 match &expr.kind {
4242 ExprKind::Int(v) => *v != 0,
4243 ExprKind::Float(v) => *v != 0.0,
4244 ExprKind::Cast(inner) => is_always_true(inner),
4245 _ => false,
4246 }
4247}
4248
4249/// Whether any `goto` inside `stmts` names `label`.
4250///
4251/// Every `goto` left in a structured body is a jump to a [`Region`] enclosing
4252/// it, so this is what says whether control can leave a [block](
4253/// RegionKind::Block) other than by falling off its end.
4254fn jumps_to(stmts: &[Stmt], label: LabelId) -> bool {
4255 stmts.iter().any(|stmt| stmt_jumps_to(stmt, label))
4256}
4257
4258fn stmt_jumps_to(stmt: &Stmt, label: LabelId) -> bool {
4259 let jumps = |stmt: &Stmt| stmt_jumps_to(stmt, label);
4260 match stmt {
4261 Stmt::Goto { id, .. } => *id == label,
4262 Stmt::Block(items) => items.iter().any(jumps),
4263 Stmt::Region(region) => region.body.iter().any(jumps),
4264 Stmt::If {
4265 then_branch,
4266 else_branch,
4267 ..
4268 } => jumps(then_branch) || else_branch.as_ref().is_some_and(|s| jumps(s)),
4269 Stmt::While { body, .. }
4270 | Stmt::DoWhile { body, .. }
4271 | Stmt::For { body, .. }
4272 | Stmt::Label { body, .. }
4273 | Stmt::Case { body, .. } => jumps(body),
4274 Stmt::Switch(switch) => {
4275 switch.prelude.iter().any(jumps)
4276 || switch
4277 .groups
4278 .iter()
4279 .any(|group| group.body.iter().any(jumps))
4280 }
4281 Stmt::SwitchTree(switch) => jumps(&switch.body),
4282 _ => false,
4283 }
4284}
4285
4286/// Whether any `break` inside `stmt` leaves `target`.
4287///
4288/// Every `break` names what it leaves, so this never has to reason about
4289/// nesting: a `break` belonging to an inner loop simply names that loop.
4290fn breaks_to(stmt: &Stmt, target: BreakTarget) -> bool {
4291 let breaks = |stmt: &Stmt| breaks_to(stmt, target);
4292 match stmt {
4293 Stmt::Break { target: found, .. } => *found == target,
4294 Stmt::Block(items) => items.iter().any(breaks),
4295 Stmt::Region(region) => region.body.iter().any(breaks),
4296 Stmt::If {
4297 then_branch,
4298 else_branch,
4299 ..
4300 } => breaks(then_branch) || else_branch.as_ref().is_some_and(|s| breaks(s)),
4301 Stmt::While { body, .. }
4302 | Stmt::DoWhile { body, .. }
4303 | Stmt::For { body, .. }
4304 | Stmt::Label { body, .. }
4305 | Stmt::Case { body, .. } => breaks(body),
4306 Stmt::Switch(switch) => {
4307 switch.prelude.iter().any(breaks)
4308 || switch
4309 .groups
4310 .iter()
4311 .any(|g| g.body.iter().any(|s| breaks_to(s, target)))
4312 }
4313 Stmt::SwitchTree(switch) => breaks(&switch.body),
4314 _ => false,
4315 }
4316}
4317
4318#[cfg(test)]
4319mod tests {
4320 use super::*;
4321
4322 const T: TargetModel = TargetModel::LP64;
4323
4324 #[test]
4325 fn small_types_promote_to_int() {
4326 for ty in [
4327 Ty::Bool,
4328 Ty::Char,
4329 Ty::SChar,
4330 Ty::UChar,
4331 Ty::Short,
4332 Ty::UShort,
4333 ] {
4334 assert_eq!(ty.promote(&T), Ty::Int, "{}", ty.scalar_name());
4335 }
4336 assert_eq!(Ty::Int.promote(&T), Ty::Int);
4337 assert_eq!(Ty::UInt.promote(&T), Ty::UInt);
4338 assert_eq!(Ty::Double.promote(&T), Ty::Double);
4339 }
4340
4341 #[test]
4342 fn bit_fields_promote_by_their_width() {
4343 // 6.3.1.1p2's "as restricted by the width": `int` first, then
4344 // `unsigned int`, and only then the declared type. The expectations
4345 // were read off gcc 15 and clang 21 on x86-64.
4346 let p = |ty: Ty, width: u32| ty.promote_bit_field(width, ty.is_signed(&T), &T);
4347 assert_eq!(p(Ty::UInt, 31), Ty::Int);
4348 assert_eq!(p(Ty::UInt, 32), Ty::UInt);
4349 assert_eq!(p(Ty::Int, 32), Ty::Int);
4350 assert_eq!(p(Ty::Int, 3), Ty::Int);
4351 assert_eq!(p(Ty::Bool, 1), Ty::Int);
4352 assert_eq!(p(Ty::Char, 8), Ty::Int);
4353 assert_eq!(p(Ty::UChar, 8), Ty::Int);
4354 assert_eq!(p(Ty::UShort, 16), Ty::Int);
4355 // The types GCC accepts as an extension follow the same rule, so a
4356 // narrow field of a wide type is still an `int`.
4357 assert_eq!(p(Ty::ULong, 31), Ty::Int);
4358 assert_eq!(p(Ty::ULong, 32), Ty::UInt);
4359 assert_eq!(p(Ty::ULong, 33), Ty::ULong);
4360 assert_eq!(p(Ty::Long, 33), Ty::Long);
4361 assert_eq!(p(Ty::LongLong, 32), Ty::Int);
4362 assert_eq!(p(Ty::ULongLong, 40), Ty::ULongLong);
4363 assert_eq!(p(Ty::ULongLong, 64), Ty::ULongLong);
4364 // An `enum` whose underlying type the implementation made unsigned.
4365 assert_eq!(Ty::Int.promote_bit_field(8, false, &T), Ty::Int);
4366 assert_eq!(Ty::Int.promote_bit_field(32, false, &T), Ty::UInt);
4367 }
4368
4369 #[test]
4370 fn unsigned_short_promotes_to_unsigned_int_on_a_16_bit_target() {
4371 let t = TargetModel {
4372 int_bits: 16,
4373 ..TargetModel::ILP32
4374 };
4375 assert_eq!(Ty::UShort.promote(&t), Ty::UInt);
4376 assert_eq!(Ty::Short.promote(&t), Ty::Int);
4377 }
4378
4379 #[test]
4380 fn the_usual_arithmetic_conversions_follow_6_3_1_8() {
4381 let u = |a, b| Ty::usual_arithmetic(a, b, &T);
4382 assert_eq!(u(Ty::Int, Ty::UInt), Ty::UInt);
4383 assert_eq!(u(Ty::Char, Ty::Char), Ty::Int);
4384 assert_eq!(u(Ty::Int, Ty::Long), Ty::Long);
4385 // `long` is wider than `unsigned int` on LP64, so it wins.
4386 assert_eq!(u(Ty::UInt, Ty::Long), Ty::Long);
4387 // ... but not on ILP32, where the result is `unsigned long`.
4388 assert_eq!(
4389 Ty::usual_arithmetic(Ty::UInt, Ty::Long, &TargetModel::ILP32),
4390 Ty::ULong
4391 );
4392 // `long long` cannot hold every `unsigned long`, so both become
4393 // `unsigned long long` — the last clause of 6.3.1.8.
4394 assert_eq!(u(Ty::ULong, Ty::LongLong), Ty::ULongLong);
4395 assert_eq!(u(Ty::UChar, Ty::Long), Ty::Long);
4396 assert_eq!(u(Ty::Float, Ty::LongLong), Ty::Float);
4397 assert_eq!(u(Ty::Double, Ty::Float), Ty::Double);
4398 }
4399
4400 /// GNU's `__int128` ranks above every standard integer type, which is what
4401 /// makes `(__int128) a * b` a 128-bit multiplication.
4402 #[test]
4403 fn int128_outranks_every_standard_integer_type() {
4404 let u = |a, b| Ty::usual_arithmetic(a, b, &T);
4405 assert_eq!(u(Ty::Int128, Ty::LongLong), Ty::Int128);
4406 assert_eq!(u(Ty::Int128, Ty::ULongLong), Ty::Int128);
4407 assert_eq!(u(Ty::UInt128, Ty::LongLong), Ty::UInt128);
4408 assert_eq!(u(Ty::UInt128, Ty::Int128), Ty::UInt128);
4409 assert_eq!(u(Ty::Int128, Ty::Int), Ty::Int128);
4410 // …and a floating type still outranks it.
4411 assert_eq!(u(Ty::Float, Ty::UInt128), Ty::Float);
4412 assert_eq!(u(Ty::Double, Ty::Int128), Ty::Double);
4413 // The promotions leave it alone, as they do every type of `int`'s rank
4414 // or above.
4415 assert_eq!(Ty::Int128.promote(&T), Ty::Int128);
4416 assert_eq!(Ty::UInt128.promote(&T), Ty::UInt128);
4417 assert_eq!(Ty::Int128.promote_argument(&T), Ty::Int128);
4418 assert_eq!(Ty::Int128.to_unsigned(), Ty::UInt128);
4419 assert!(Ty::Int128.is_signed(&T));
4420 assert!(!Ty::UInt128.is_signed(&T));
4421 assert_eq!(Ty::Int128.size_bytes(&T), 16);
4422 assert_eq!(Ty::UInt128.bits(&T), 128);
4423 }
4424
4425 /// A 128-bit constant is carried as its two's-complement bit pattern, so
4426 /// `wrap` leaves it alone and the ends of the range come out exactly.
4427 #[test]
4428 fn int128_constants_are_carried_as_bit_patterns() {
4429 assert_eq!(Ty::UInt128.wrap(-1, &T), -1);
4430 assert_eq!(Ty::Int128.wrap(-1, &T), -1);
4431 assert_eq!(Ty::Int128.wrap(i128::MIN, &T), i128::MIN);
4432 assert_eq!(Ty::Int128.min_value(&T), i128::MIN);
4433 assert_eq!(Ty::Int128.max_value(&T), i128::MAX);
4434 assert_eq!(Ty::UInt128.min_value(&T), 0);
4435 // Clamped, and documented as such: the real maximum is 2^128 - 1.
4436 assert_eq!(Ty::UInt128.max_value(&T), i128::MAX);
4437 // Converting a 128-bit pattern down to a narrower type is the ordinary
4438 // truncation.
4439 assert_eq!(Ty::UInt.wrap(-1, &T), 4_294_967_295);
4440 }
4441
4442 /// `__int128` is sixteen bytes; its *alignment* is the one thing the model
4443 /// decides, because it is the one scalar whose alignment is not its size
4444 /// on every target.
4445 #[test]
4446 fn int128_takes_its_alignment_from_the_model() {
4447 let types = Types::new();
4448 let layout = types
4449 .size_align(Ty::UInt128, &T)
4450 .expect("a scalar has a layout");
4451 assert_eq!(layout.size, 16);
4452 assert_eq!(layout.align, 16);
4453 let eight = TargetModel {
4454 int128_align: 8,
4455 ..TargetModel::LP64
4456 };
4457 let layout = types
4458 .size_align(Ty::Int128, &eight)
4459 .expect("a scalar has a layout");
4460 assert_eq!(layout.size, 16);
4461 assert_eq!(layout.align, 8);
4462 }
4463
4464 #[test]
4465 fn conversions_wrap() {
4466 assert_eq!(Ty::UChar.wrap(300, &T), 44);
4467 assert_eq!(Ty::SChar.wrap(200, &T), -56);
4468 assert_eq!(Ty::UInt.wrap(-1, &T), 4_294_967_295);
4469 assert_eq!(Ty::Int.wrap(4_294_967_295, &T), -1);
4470 assert_eq!(Ty::Bool.wrap(5, &T), 1);
4471 assert_eq!(Ty::Bool.wrap(0, &T), 0);
4472 assert_eq!(Ty::ULongLong.wrap(-1, &T), u64::MAX as i128);
4473 }
4474
4475 #[test]
4476 fn derived_types_are_interned() {
4477 let mut types = Types::new();
4478 let a = types.pointer(Ty::Int, false);
4479 let b = types.pointer(Ty::Int, false);
4480 let c = types.pointer(Ty::Int, true);
4481 assert_eq!(a, b);
4482 assert_ne!(a, c);
4483 assert!(types.same_pointee(a, c));
4484 assert_eq!(types.pointee(a), Some(Ty::Int));
4485 let arr = types.array(Ty::Char, 4, false);
4486 assert_eq!(arr, types.array(Ty::Char, 4, false));
4487 assert_ne!(arr, types.array(Ty::Char, 5, false));
4488 let f = types.func(Ty::Int, vec![a], false);
4489 assert_eq!(f, types.func(Ty::Int, vec![b], false));
4490 assert_ne!(f, types.func(Ty::Int, vec![a], true));
4491 }
4492
4493 #[test]
4494 fn layouts_follow_natural_alignment() {
4495 let mut types = Types::new();
4496 let arr = types.array(Ty::Char, 5, false);
4497 assert_eq!(
4498 types.size_align(arr, &T),
4499 Some(Layout { size: 5, align: 1 })
4500 );
4501 let ptr = types.pointer(Ty::Void, false);
4502 assert_eq!(
4503 types.size_align(ptr, &T),
4504 Some(Layout { size: 8, align: 8 })
4505 );
4506 // A function type has no size at all.
4507 let f = types.func(Ty::Void, Vec::new(), false);
4508 assert_eq!(types.size_align(f, &T), None);
4509 }
4510
4511 #[test]
4512 fn names_read_like_c() {
4513 let mut types = Types::new();
4514 let cchar = types.pointer(Ty::Char, true);
4515 assert_eq!(types.name(cchar), "const char *");
4516 let arr = types.array(Ty::Int, 3, false);
4517 assert_eq!(types.name(arr), "int[3]");
4518 let f = types.func(Ty::Int, vec![cchar], true);
4519 let fp = types.pointer(f, false);
4520 assert_eq!(types.name(fp), "int (*)(const char *, ...)");
4521 }
4522}