Skip to main content

cinrs_core/
codegen.rs

1//! Code generation: the typed [`ir`] becomes Rust tokens.
2//!
3//! Every token this module emits is stamped with the span of the C construct
4//! it came from, resolved through the [`SourceMap`]. That is what makes an
5//! error `rustc` raises about the *generated* code — a call with the wrong
6//! argument type, say — point at the C the user actually wrote.
7//!
8//! # Shape of the output
9//!
10//! One expansion produces, in this order: the alignment wrappers an
11//! over-aligned object needs, the `struct` and `union` items for every tag and
12//! the flexible-array companions that go with them, the `enum` aliases and
13//! their constants, the file-scope `typedef` aliases, an empty `extern` block
14//! per library the unit links, one `extern` block for everything the unit only
15//! declares, the `static mut` items, and finally the functions. A C function
16//! becomes
17//!
18//! ```text
19//! pub unsafe extern "C" fn name(mut p: ::core::ffi::c_int) -> ::core::ffi::c_int {
20//!     unsafe { … }
21//! }
22//! ```
23//!
24//! `pub` is dropped for a C `static` function, which is private to the module
25//! [`crate::expand`] wraps all of this in — that module is what makes C's
26//! internal linkage mean something, and what lets two `c99!` blocks in one
27//! Rust module both `#include` the same header. `#[inline]` is added for an
28//! `inline` function, and the body is wrapped in a single `unsafe` block
29//! because edition 2024 no longer treats the body of an `unsafe fn` as an
30//! unsafe block. Nothing here carries a lint exemption of its own: everything
31//! this module generates goes inside that one module, whose head carries a
32//! single `#![allow(…)]` — an inner attribute, so every item under it
33//! inherits it — for everything a naive translation provokes: unused
34//! bindings, redundant parentheses, non-Rust naming, code a human can see is
35//! unreachable, and so on. The list, and the reasons for each entry, are with
36//! the code in `lib.rs` that wraps a unit in its module.
37//!
38//! A function the unit marked [safe](crate::sema::check_safe) —
39//! `[[cinrs::safe]]`, `__attribute__((cinrs_safe))` or `#pragma cinrs safe` —
40//! is the one exception: it is generated as `pub extern "C" fn` and its body is
41//! *not* wrapped, so `rustc` checks every operation the translation of the C
42//! needs and refuses the ones that are unsafe, with the caret on the C.
43//!
44//! A unit that asked for `#pragma cinrs export` gives everything with external
45//! linkage `#[unsafe(no_mangle)]` on top of that, so that its functions and
46//! objects are real C symbols another unit can link against — with C's own
47//! risk of two definitions of one name, which only the linker will see.
48//!
49//! # Pointers, arrays and records
50//!
51//! Pointers are raw pointers — `T *` is `*mut T`, `const T *` is `*const T`,
52//! `void *` is `*mut c_void` — and pointer arithmetic is `offset`, so nothing
53//! in the output holds a reference and none of Rust's aliasing rules are
54//! involved. Arrays are `[T; N]` and decay to a pointer through
55//! `(&raw mut a).cast::<T>()`, which is a raw pointer from the start; a `&mut`
56//! would both change the meaning and trip `static_mut_refs` on a global. A
57//! function pointer is `Option<unsafe extern "C" fn(…) -> R>`, so that a null
58//! one is representable, and a call through it unwraps first.
59//!
60//! # Places
61//!
62//! Assignment, compound assignment, `++`/`--` and `&` all go through this
63//! module's `place` lowering, which turns an [`ir::Place`] into a *setup*
64//! (statements that must run first, where the pointer arithmetic lands) plus an
65//! *access* (a Rust place expression that may be evaluated more than once).
66//! `p[i()] += 1` therefore evaluates `i()` exactly once, and `s.f`, `p->f` and
67//! `a[i][j]` are all the same three lines of code.
68//!
69//! # Bit-fields
70//!
71//! A bit-field has no address, so it is not a field of the generated item: a
72//! run of them shares one `[u8; K]`, and sema has already worked out which
73//! bytes and bits each member owns (see [`crate::sema`]'s layout). This module
74//! turns that into a pair of inherent methods per named member — plain inline
75//! integer code, no helper type — and a place whose *access* is the record
76//! rather than the member, read with `.f()` and written with `.set_f(v)`. A
77//! constant initialiser is folded into the storage bytes here, which is what
78//! lets a `static` hold one; a non-constant one becomes a zeroed literal
79//! followed by setter calls. A place rooted in a `static mut` goes through
80//! `&raw mut` first, because the accessors borrow.
81//!
82//! # Loops
83//!
84//! Every loop gets a unique Rust label so that `break` and `continue` never
85//! depend on where they sit relative to a `switch`:
86//!
87//! ```text
88//! while (c) B      'lN: while c { B }                continue → continue 'lN
89//! do B while (c);  'lN: loop { 'lN_body: { B }       continue → break 'lN_body
90//!                             if !(c) { break 'lN } }
91//! for (i;c;s) B    { i; 'lN: loop { if !(c) { break 'lN }
92//!                                   'lN_body: { B } s; } }
93//! ```
94//!
95//! The body label exists exactly where `continue` has work to do afterwards —
96//! re-testing the condition of a `do`/`while`, or running the step of a `for`.
97//!
98//! # Switch
99//!
100//! Fallthrough is what makes `switch` interesting: control enters at one label
101//! and then runs *through* every group after it. Rust has no such construct,
102//! but labelled blocks compose into one. For groups `g0 … gN` the output is
103//!
104//! ```text
105//! 'swK: {
106//!     'swK_cN: { … 'swK_c1: { 'swK_c0: { match v { … } } g0 } g1 … }
107//!     gN
108//! }
109//! ```
110//!
111//! with the dispatch `match` innermost: `break 'swK_ci` lands immediately
112//! before group *i*, and control then falls out of each enclosing block in
113//! turn, running the groups after it in order. `break` inside the switch is
114//! `break 'swK`, and the `_` arm goes to the `default:` group, or out of the
115//! whole statement when there is none.
116//!
117//! # Functions that jump
118//!
119//! Most `goto`s stay here too. [`regions`](crate::regions) has wrapped the
120//! statements a label divides in an [`ir::Region`], which is one of
121//!
122//! ```text
123//! 'done: { … break 'done; … }      'retry: loop { … continue 'retry; … break 'retry; }
124//! ```
125//!
126//! named after the C label — with the number of the label appended when Rust
127//! cannot spell the name as a label (`loop:` is a keyword) or when this module
128//! already gives that name to a loop of its own. A [`Stmt::Goto`] left inside
129//! one is the `break` or the `continue`; which it is comes from the region it
130//! stands in.
131//!
132//! A body sema lowered into a [control-flow graph](crate::cfg) instead —
133//! because it holds a jump Rust cannot make at all — is emitted as a state
134//! machine over its blocks, with the function's locals defined once at the
135//! top. Everything below the statement level is shared: the expressions,
136//! places and conversions are generated by exactly the same code in both
137//! modes.
138//!
139//! # Calls without a prototype
140//!
141//! `int f();` says nothing about the parameters (C99 6.7.5.3p14), so the item
142//! generated for it is `unsafe extern "C" fn() -> R` — that is all the
143//! declaration said. What the *call* passes is decided at the call site
144//! (6.5.2.2p6): sema has already applied the default argument promotions to
145//! every argument, and this module transmutes the callee to the signature they
146//! make before calling it,
147//!
148//! ```text
149//! ::core::mem::transmute::<unsafe extern "C" fn() -> R,
150//!                          unsafe extern "C" fn(T1, …, Tn) -> R>(f)(a1, …, an)
151//! ```
152//!
153//! with the `Option` unwrapped first for a function pointer, and no cast at all
154//! when there are no arguments. Reinterpreting a function pointer like this is
155//! exactly the contract C's own ABI rests on: on every ABI this crate targets
156//! the address is the same one, and the call is defined precisely when the
157//! callee really was defined with parameters of those promoted types —
158//! undefined otherwise, which is the risk the program took by leaving the
159//! prototype out. The same route is taken whenever the argument count and the
160//! parameter count disagree at all, which keeps a call checked
161//! against an empty list from being emitted against a prototype a later
162//! declaration supplied.
163//!
164//! # Variadic definitions
165//!
166//! `R f(T a, ...)` becomes `unsafe extern "C" fn f(mut a: T, __cinrs_va: ...)`.
167//! The extra parameter is the argument list as the caller left it and is never
168//! advanced; `va_start` and every `va_list` local copy it, `va_arg` is
169//! `next_arg`, `va_copy` and passing a list on are `clone`, and `va_end` is
170//! nothing at all, because the list ends when its value is dropped. See
171//! [`crate::sema`]'s `va` module for the model.
172
173use std::cell::{Cell, RefCell};
174use std::collections::{BTreeSet, HashMap, HashSet};
175use std::str::FromStr;
176
177use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
178use quote::quote_spanned;
179
180use crate::Options;
181use crate::capture::{SourceMap, SourceRange};
182use crate::cfg::{BasicBlock, BlockId, Cfg, Terminator};
183use crate::ir::{
184    self, AtomicClass, BinOp, Body, BreakTarget, Callee, CmpOp, ConstValue, Expr, ExprKind,
185    Function, LogicalOp, LoopId, NEVER_RAW, Place, PlaceKind, Program, RecordKind, Stmt, Storage,
186    Switch, Ty,
187};
188use crate::reloop;
189
190/// Generates the Rust items for a fully checked program.
191pub fn generate(program: &Program, map: &SourceMap, options: &Options) -> TokenStream {
192    let mut cg = Codegen::new(program, map, options);
193    let mut out = cg.type_items();
194    out.extend(cg.extern_block());
195    for var in &program.statics {
196        out.extend(cg.static_item(var));
197    }
198    let mut initialisers = TokenStream::new();
199    for func in &program.functions {
200        if func.body.is_some() {
201            out.extend(cg.function_item(func));
202            if let Some(kind) = func.init_kind {
203                initialisers.extend(cg.init_array_item(func, kind));
204            }
205        }
206    }
207    if !initialisers.is_empty() {
208        out.extend(cg.init_array_guard());
209        out.extend(initialisers);
210    }
211    if out.is_empty() {
212        // A unit that declares nothing expands to nothing at all — not even a
213        // module — and there is no code for the data model to be wrong about.
214        return out;
215    }
216    let mut items = cg.data_model_check();
217    if cg.uses_cleanup.get() {
218        items.extend(cg.cleanup_guard_item(Span::call_site()));
219    }
220    if cg.uses_arena.get() {
221        let span = cg.arena_span.get().unwrap_or_else(Span::call_site);
222        items.extend(cg.arena_items(span));
223    }
224    // The shims the unit needs for the intrinsics whose address it took; see
225    // [`Codegen::address_taken`]. Collected while the bodies were generated,
226    // so this has to come after them.
227    items.extend(cg.intrinsic_shim_items());
228    items.extend(out);
229    items
230}
231
232/// Generates signature-only items for a program that did not type check.
233///
234/// The bodies are `::core::unreachable!()`: the expansion also carries
235/// `compile_error!`s, so nothing here can ever run. Their purpose is to keep a
236/// Rust call site that mentions one of these functions from producing a second,
237/// unrelated "cannot find function" error on top of the real one.
238pub fn generate_stubs(program: &Program, map: &SourceMap, options: &Options) -> TokenStream {
239    let mut cg = Codegen::new(program, map, options);
240    let mut out = cg.type_items();
241    out.extend(cg.extern_block());
242    for var in &program.statics {
243        out.extend(cg.static_item(var));
244    }
245    for func in &program.functions {
246        if !func.is_extern() {
247            out.extend(cg.stub_item(func));
248        }
249    }
250    out
251}
252
253// ---------------------------------------------------------------------------
254// precedence
255// ---------------------------------------------------------------------------
256
257/// Rust's expression precedence levels, tightest last.
258///
259/// Emitted expressions carry the level they parse at so that parentheses are
260/// added exactly where they are needed and nowhere else — the generated code is
261/// meant to be read.
262mod prec {
263    /// A block-like expression (`if`, `{ … }`): usable on its own, but needing
264    /// parentheses anywhere an operator or a statement boundary follows.
265    pub const BLOCK: u8 = 0;
266    /// The weakest level an operand can be handed to without parentheses.
267    pub const LOWEST: u8 = 0;
268    pub const OR: u8 = 2;
269    pub const AND: u8 = 3;
270    pub const CMP: u8 = 4;
271    pub const BIT_OR: u8 = 5;
272    pub const BIT_XOR: u8 = 6;
273    pub const BIT_AND: u8 = 7;
274    pub const SUM: u8 = 9;
275    pub const PRODUCT: u8 = 10;
276    pub const CAST: u8 = 11;
277    pub const UNARY: u8 = 12;
278    pub const CALL: u8 = 13;
279    pub const ATOM: u8 = 14;
280}
281
282/// An emitted expression together with the precedence it parses at.
283struct Value {
284    tokens: TokenStream,
285    prec: u8,
286    /// Set when the tokens are a bare non-negative integer literal, whose Rust
287    /// type is therefore still open to inference.
288    bare_integer: bool,
289    /// Set when the tokens end with the type of an `as`.
290    ///
291    /// `x as i32 < y` does not parse: Rust reads the `<` as the start of the
292    /// generic arguments of `i32`. (`>`, `<=`, `>=` and `==` are unambiguous
293    /// and need no help.)
294    ends_with_type: bool,
295}
296
297impl Value {
298    fn new(tokens: TokenStream, prec: u8) -> Self {
299        Self {
300            tokens,
301            prec,
302            bare_integer: false,
303            ends_with_type: false,
304        }
305    }
306
307    fn atom(tokens: TokenStream) -> Self {
308        Self::new(tokens, prec::ATOM)
309    }
310
311    /// Marks the tokens as ending with the type of an `as`.
312    fn type_end(mut self, flag: bool) -> Self {
313        self.ends_with_type = flag;
314        self
315    }
316
317    /// The tokens, parenthesised if they would not survive being used as an
318    /// operand at `min`.
319    fn at(self, min: u8, span: Span) -> TokenStream {
320        if self.prec >= min {
321            return self.tokens;
322        }
323        parenthesize(self.tokens, span)
324    }
325
326    /// The tokens, parenthesised only if they are block-like.
327    ///
328    /// Used where Rust starts parsing an expression that is followed by a block
329    /// — the condition of an `if` or a `while` — and would otherwise mistake
330    /// our expression's own braces for that block.
331    fn at_condition(self, span: Span) -> TokenStream {
332        if self.prec > prec::BLOCK {
333            return self.tokens;
334        }
335        parenthesize(self.tokens, span)
336    }
337}
338
339fn parenthesize(tokens: TokenStream, span: Span) -> TokenStream {
340    let mut group = Group::new(Delimiter::Parenthesis, tokens);
341    group.set_span(span);
342    TokenStream::from(TokenTree::Group(group))
343}
344
345/// Whether an emitted expression opens with a unary minus.
346///
347/// `as` is the one operator in front of which that matters: `rustc` reads
348/// `-1 as u32` as the negation of a `u32` rather than as a cast of `-1`, and
349/// refuses it with `E0600`.
350fn starts_with_minus(tokens: &TokenStream) -> bool {
351    matches!(
352        tokens.clone().into_iter().next(),
353        Some(TokenTree::Punct(punct)) if punct.as_char() == '-'
354    )
355}
356
357fn braced(tokens: TokenStream, span: Span) -> TokenStream {
358    let mut group = Group::new(Delimiter::Brace, tokens);
359    group.set_span(span);
360    TokenStream::from(TokenTree::Group(group))
361}
362
363fn bracketed(tokens: TokenStream, span: Span) -> TokenStream {
364    let mut group = Group::new(Delimiter::Bracket, tokens);
365    group.set_span(span);
366    TokenStream::from(TokenTree::Group(group))
367}
368
369// ---------------------------------------------------------------------------
370// the Microsoft library's inline printf family, and the names it exports under
371// a different spelling
372// ---------------------------------------------------------------------------
373
374/// The library that has out-of-line definitions of the `printf` and `scanf`
375/// families for the Microsoft C runtime.
376///
377/// It is part of the MSVC toolset —
378/// `VC/Tools/MSVC/<version>/lib/<arch>/legacy_stdio_definitions.lib`, one copy
379/// per architecture — so it is there on every `*-windows-msvc` target and on no
380/// other, which is why [`TargetModel::is_msvc`](crate::TargetModel::is_msvc) and
381/// not merely Windows is what asks for it.
382const LEGACY_STDIO_DEFINITIONS: &str = "legacy_stdio_definitions";
383
384/// The names that need [`LEGACY_STDIO_DEFINITIONS`] on an MSVC target, each with
385/// the library that defines it.
386///
387/// In the Universal CRT — the Microsoft C library from Visual Studio 2015 on —
388/// the `printf` and `scanf` families are **inline functions in `<stdio.h>` and
389/// `<wchar.h>`**, written over `__stdio_common_vfprintf` and its relatives, so
390/// the import library exports no `printf` at all: an `extern "C" { fn printf(…);
391/// }` is `LNK2019: unresolved external symbol printf` at link time. Microsoft
392/// ships `legacy_stdio_definitions.lib` with out-of-line definitions for exactly
393/// that case, and it is what Rust's own `libc` crate links for the same
394/// declarations (`#[cfg_attr(all(windows, target_env = "msvc"), link(name =
395/// "legacy_stdio_definitions"))]`). See "The printf and scanf family of
396/// functions are now defined inline" in Microsoft's change history:
397/// <https://learn.microsoft.com/en-us/cpp/porting/visual-cpp-change-history-2003-2015>
398///
399/// The rule this table serves is [`Codegen::legacy_stdio_libraries`], and it is
400/// keyed on the **symbol a generated declaration links by** rather than on a
401/// header: a unit may declare `int printf(const char *, ...);` itself, or reach
402/// the function through `__builtin_printf`, and never include `<stdio.h>` at
403/// all.
404///
405/// One row per name, so that a name can be given a different answer on its own
406/// should a toolchain ever disagree: a row may name a different library, or go,
407/// and nothing else changes. What it must never become is an alias to
408/// `_snprintf`, whose truncation semantics are not C's.
409///
410/// Every name here was read out of a real copy of the library —
411/// `dumpbin`/`nm` over `legacy_stdio_definitions.lib` from MSVC 14.44.35207,
412/// x64 and x86 both — so the list is the library's own contents and not a
413/// guess. `snprintf` and `vsnprintf` are in it, which is worth saying because
414/// they are C99 additions the Microsoft library had no out-of-line form of
415/// *before* the UCRT and so, unlike the rest, never "became" inline; `libc`
416/// declares `snprintf` in the very block it links this library for. The library
417/// also holds the `_l`, `_p`, `_s` and `_snprintf` variants, which are
418/// deliberately not here: they are Microsoft's functions rather than C's, and a
419/// unit that declares one has named the platform already and can say
420/// `#pragma cinrs link "legacy_stdio_definitions"` itself.
421const LEGACY_STDIO: &[(&str, &str)] = &[
422    ("printf", LEGACY_STDIO_DEFINITIONS),
423    ("fprintf", LEGACY_STDIO_DEFINITIONS),
424    ("sprintf", LEGACY_STDIO_DEFINITIONS),
425    ("snprintf", LEGACY_STDIO_DEFINITIONS),
426    ("vprintf", LEGACY_STDIO_DEFINITIONS),
427    ("vfprintf", LEGACY_STDIO_DEFINITIONS),
428    ("vsprintf", LEGACY_STDIO_DEFINITIONS),
429    ("vsnprintf", LEGACY_STDIO_DEFINITIONS),
430    ("scanf", LEGACY_STDIO_DEFINITIONS),
431    ("fscanf", LEGACY_STDIO_DEFINITIONS),
432    ("sscanf", LEGACY_STDIO_DEFINITIONS),
433    ("vscanf", LEGACY_STDIO_DEFINITIONS),
434    ("vfscanf", LEGACY_STDIO_DEFINITIONS),
435    ("vsscanf", LEGACY_STDIO_DEFINITIONS),
436    ("wprintf", LEGACY_STDIO_DEFINITIONS),
437    ("fwprintf", LEGACY_STDIO_DEFINITIONS),
438    ("swprintf", LEGACY_STDIO_DEFINITIONS),
439    ("vwprintf", LEGACY_STDIO_DEFINITIONS),
440    ("vfwprintf", LEGACY_STDIO_DEFINITIONS),
441    ("vswprintf", LEGACY_STDIO_DEFINITIONS),
442    ("wscanf", LEGACY_STDIO_DEFINITIONS),
443    ("fwscanf", LEGACY_STDIO_DEFINITIONS),
444    ("swscanf", LEGACY_STDIO_DEFINITIONS),
445    ("vwscanf", LEGACY_STDIO_DEFINITIONS),
446    ("vfwscanf", LEGACY_STDIO_DEFINITIONS),
447    ("vswscanf", LEGACY_STDIO_DEFINITIONS),
448];
449
450/// The C functions the Microsoft C runtime exports under **another name**, each
451/// with the symbol a declaration of it has to link by on an MSVC target.
452///
453/// `LEGACY_STDIO` above is about a family the UCRT defines inline and ships an
454/// out-of-line copy of in a library of its own. This is the other shape of the
455/// same problem: the function *is* in `ucrt.lib`, under a name that is not the
456/// one C gives it, and Microsoft's own headers paper over the difference with a
457/// macro (`#define time _time64`) that cinrs's bundled headers, which are the
458/// same on every platform, do not write.
459///
460/// Every row was read out of the real import libraries with `nm` — the Windows
461/// SDK's `ucrt.lib` and the MSVC toolset's `msvcrt.lib`, 10.0.26100.0 and
462/// 14.44.35207 — and not inferred. `ucrt.lib` exports each symbol on the right
463/// and none of the C names on the left.
464///
465/// The `<time.h>` rows are **not** merely a link error, which is what makes
466/// them worth a table rather than a paragraph in the documentation. The MSVC
467/// toolset's `msvcrt.lib` holds an "alias map" object per name that defines
468/// `time` as a *weak* external for `_time32`, and the rest likewise — so a
469/// declaration of `time` does link, silently, to the **32-bit** `time_t`
470/// function. cinrs's `<time.h>` makes `time_t` 64 bits on Windows, as the UCRT
471/// does, and the two disagree in ways a program sees: `_mktime32`'s `(time_t)-1`
472/// comes back as `0x0000_0000_FFFF_FFFF`, and `_gmtime32` answers `NULL` for
473/// every date after 2038 rather than a `struct tm`. Naming `_time64` and its
474/// siblings is therefore a correctness fix and not only a convenience.
475///
476/// `hypotf` is the one `<math.h>` name with an exported equivalent: `_hypotf`
477/// is a real export with C's signature (Microsoft's `<math.h>` makes `hypotf`
478/// inline over it). `fabsf`, `frexpf` and `ldexpf` have no symbol at all in any
479/// library on an MSVC link line — they are inline over the `double` forms — and
480/// so are not here; `doc/cross-compilation.md` records them, with the
481/// workaround. The same goes for `<wchar.h>`'s `wmemcpy`, `wmemmove`, `wmemset`,
482/// `wmemcmp`, `wmemchr`, `mbsinit` and `fwide`.
483///
484/// The rule this table serves is [`Codegen::msvc_symbol`], which applies to a
485/// **declaration** and after an `__asm__("…")` label: a program that has named
486/// the symbol it wants by hand has said the last word, which is also how a unit
487/// asks for `_time32` on purpose.
488const MSVC_RENAMED: &[(&str, &str)] = &[
489    ("time", "_time64"),
490    ("difftime", "_difftime64"),
491    ("mktime", "_mktime64"),
492    ("localtime", "_localtime64"),
493    ("gmtime", "_gmtime64"),
494    ("ctime", "_ctime64"),
495    ("timespec_get", "_timespec64_get"),
496    ("hypotf", "_hypotf"),
497];
498
499// ---------------------------------------------------------------------------
500// identifiers
501// ---------------------------------------------------------------------------
502
503/// Every Rust keyword, strict and reserved, in every edition up to 2024.
504const RUST_KEYWORDS: &[&str] = &[
505    "abstract", "as", "async", "await", "become", "box", "break", "const", "continue", "crate",
506    "do", "dyn", "else", "enum", "extern", "false", "final", "fn", "for", "gen", "if", "impl",
507    "in", "let", "loop", "macro", "match", "mod", "move", "mut", "override", "priv", "pub", "ref",
508    "return", "self", "static", "struct", "super", "trait", "true", "try", "type", "typeof",
509    "unsafe", "unsized", "use", "virtual", "where", "while", "yield", "Self",
510];
511
512/// Names that a `let` binding or a parameter must not carry, whatever the C
513/// program calls them.
514///
515/// Rust resolves a binding pattern against the value namespace first: a name
516/// that already means a unit variant there is a *pattern* that matches, not a
517/// new binding, and Rust refuses the ambiguity outright with `E0530`. The four
518/// below are in scope in every Rust file through the prelude; the rest of the
519/// set is computed per translation unit in [`Codegen::new`], because a C
520/// program may name a local exactly like one of its own globals or
521/// enumerators:
522///
523/// ```c
524/// int counter;
525/// int f(int counter) { return counter; }   /* two different objects */
526/// ```
527const PRELUDE_PATTERNS: &[&str] = &["Some", "None", "Ok", "Err"];
528
529/// Whether `segment` is an ordinary Rust identifier — one that can stand as a
530/// path segment spelled verbatim rather than as `r#…`.
531///
532/// Its one caller is [`is_crate_path`], whose value is pasted into the
533/// expansion as tokens; the three keywords a segment may nevertheless be are
534/// allowed there rather than here.
535fn is_path_segment(segment: &str) -> bool {
536    let mut chars = segment.chars();
537    chars
538        .next()
539        .is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
540        && chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
541        && !RUST_KEYWORDS.contains(&segment)
542        && !NEVER_RAW.contains(&segment)
543}
544
545/// Whether a string is usable as the Rust path of a crate:
546/// `#pragma cinrs crate "…"`.
547///
548/// A sequence of segments joined by `::`, optionally starting with one, where
549/// each segment is an identifier — with `crate`, `self` and `super` allowed as
550/// segments because a re-export is often reached through one. Deliberately
551/// strict: the value is pasted into the expansion as tokens, and anything else
552/// there would be a syntax error in generated code rather than a message about
553/// the pragma.
554pub fn is_crate_path(path: &str) -> bool {
555    /// The three keywords a path segment may be even though an ordinary
556    /// identifier may not.
557    const PATH_KEYWORDS: &[&str] = &["crate", "self", "super"];
558
559    let body = path.strip_prefix("::").unwrap_or(path);
560    if body.is_empty() {
561        return false;
562    }
563    body.split("::")
564        .all(|segment| PATH_KEYWORDS.contains(&segment) || is_path_segment(segment))
565}
566
567/// Turns a C identifier into the Rust identifier that stands for it, before
568/// the rest of the translation unit is taken into account.
569///
570/// C names are kept as they are, because that is what makes the expansion
571/// readable and what lets Rust call the functions by the names their author
572/// gave them. A name that collides with a Rust keyword becomes a raw
573/// identifier (`match` → `r#match`); the five names that cannot even be raw
574/// get an underscore appended instead. A `$` — which C takes as an identifier
575/// character and Rust has no spelling for — is written [`DOLLAR`].
576///
577/// The last two rules are the only ones that can hand two different C names
578/// the same Rust one, which is what [`Names`] exists to prevent: everything
579/// the generator emits goes through [`Names::ident`] rather than through this.
580fn c_ident(name: &str, span: Span) -> Ident {
581    let spelled = rust_spelling(name);
582    let name = spelled.as_ref();
583    if NEVER_RAW.contains(&name) {
584        return Ident::new(&format!("{name}_"), span);
585    }
586    if RUST_KEYWORDS.contains(&name) {
587        return Ident::new_raw(name, span);
588    }
589    Ident::new(name, span)
590}
591
592/// What a `$` in a C identifier is written as in the generated Rust.
593///
594/// `$` is an identifier character here — GCC takes it unconditionally and
595/// Clang by default, which is what WG14 DR027 allows and what
596/// [`crate::Options::dollar_in_identifiers`] switches on — and Rust has no
597/// spelling for it at all, not even a raw identifier. The C name is still what
598/// the symbol links by: an object or function that is not defined here carries
599/// it in `#[link_name]`, and one that is carries it in `#[unsafe(export_name)]`.
600pub const DOLLAR: &str = "_dollar_";
601
602/// A C identifier as Rust can spell it, which is the same string unless a `$`
603/// is in it.
604fn rust_spelling(name: &str) -> std::borrow::Cow<'_, str> {
605    if name.contains('$') {
606        std::borrow::Cow::Owned(name.replace('$', DOLLAR))
607    } else {
608        std::borrow::Cow::Borrowed(name)
609    }
610}
611
612/// Whether Rust spells `name` as something other than itself, so that another
613/// C name could be spelled the same way.
614///
615/// A keyword is not one of these: `r#match` is a token of its own and no name
616/// but `match` is written that way.
617fn respelled(name: &str) -> bool {
618    name.contains('$') || NEVER_RAW.contains(&name)
619}
620
621/// The text [`c_ident`] gives a name, without the `r#` a raw identifier is
622/// written with.
623fn plain_spelling(name: &str) -> String {
624    let spelled = rust_spelling(name);
625    if NEVER_RAW.contains(&spelled.as_ref()) {
626        return format!("{spelled}_");
627    }
628    spelled.into_owned()
629}
630
631/// The Rust spelling of every name the translation unit gives to something,
632/// made unique across the whole unit.
633///
634/// Two of the rules in [`c_ident`] change the spelling of a name, and a
635/// program is free to use the changed spelling itself:
636///
637/// ```c
638/// int f(void) { int self = 1; int self_ = 2; return self * 10 + self_; }
639/// ```
640///
641/// Both locals would be `self_`, the second binding would shadow the first,
642/// and `f` would quietly return 22 instead of 12. The same collision between
643/// two members is `E0124`, between two file-scope items `E0428`, and `a$b`
644/// next to `a_dollar_b` is the same story again.
645///
646/// So the spelling is settled once, here, for the unit as a whole. Every name
647/// the unit spells is collected — objects, functions and their parameters,
648/// tags, members, bit-field accessors, enumerators and `typedef` names, in
649/// every name space at once, because one C name must read as one Rust name
650/// wherever it appears. A name Rust spells as it is written keeps it; a name
651/// whose spelling changes takes the usual one and grows another `_` for as
652/// long as something else already has it. Nothing moves for a program that
653/// does not have the collision, which is very nearly every program.
654///
655/// Labels are left out: `'self_` is in a name space of its own, and
656/// [`Codegen::name_regions`] already keeps the labels of a function apart.
657struct Names {
658    /// The Rust spelling of each name whose spelling is not the name itself.
659    ///
660    /// Empty for a unit that writes no such name, which is the usual case.
661    renamed: HashMap<String, String>,
662}
663
664impl Names {
665    /// Works out the spellings of one translation unit.
666    fn new(program: &Program) -> Self {
667        let mut spelled: Vec<&str> = Vec::new();
668        for object in &program.objects {
669            spelled.push(&object.name);
670            match &object.storage {
671                Storage::Static { item_name, .. }
672                | Storage::ThreadLocal { item_name, .. }
673                | Storage::Extern { item_name } => spelled.push(item_name),
674                Storage::Automatic => {}
675            }
676        }
677        for func in &program.functions {
678            spelled.push(&func.name);
679            spelled.push(func.item_name());
680            spelled.extend(func.param_names.iter().flatten().map(String::as_str));
681            // The names the state-machine lowering hoists the locals under,
682            // which are what a CFG body's bindings are generated from.
683            if let Some(Body::Cfg(cfg)) = &func.body {
684                spelled.extend(cfg.locals.iter().map(|local| local.rust_name.as_str()));
685            }
686        }
687        for record in program.types.records() {
688            spelled.extend(record.tag.as_deref());
689            spelled.push(&record.rust_name);
690            for field in &record.fields {
691                spelled.push(&field.name);
692                if let Some(bits) = &field.bits {
693                    spelled.push(&bits.getter);
694                    spelled.push(&bits.setter);
695                }
696            }
697            for field in &record.rust_fields {
698                match field {
699                    ir::RustField::Bits { name, .. }
700                    | ir::RustField::Pad { name, .. }
701                    | ir::RustField::Align { name, .. } => spelled.push(name),
702                    ir::RustField::Member(_) => {}
703                }
704            }
705        }
706        for def in program.types.enums() {
707            spelled.extend(def.tag.as_deref());
708            spelled.push(&def.rust_name);
709        }
710        for constant in &program.enum_constants {
711            spelled.push(&constant.name);
712            spelled.push(&constant.rust_name);
713        }
714        for typedef in &program.typedefs {
715            spelled.push(&typedef.rust_name);
716        }
717
718        Self {
719            renamed: unique_spellings(spelled),
720        }
721    }
722
723    /// The Rust identifier a C name is generated as, everywhere it appears.
724    fn ident(&self, name: &str, span: Span) -> Ident {
725        match self.renamed.get(name) {
726            Some(unique) => Ident::new(unique, span),
727            None => c_ident(name, span),
728        }
729    }
730
731    /// The same as text, without the `r#` a raw identifier is written with.
732    fn spelling<'n>(&'n self, name: &'n str) -> std::borrow::Cow<'n, str> {
733        match self.renamed.get(name) {
734            Some(unique) => std::borrow::Cow::Borrowed(unique.as_str()),
735            None => std::borrow::Cow::Owned(plain_spelling(name)),
736        }
737    }
738}
739
740/// The rule [`Names`] is built on: what each name whose Rust spelling is not
741/// itself is spelled as, given everything the unit spells.
742///
743/// A name Rust writes as it stands claims that spelling first — two such
744/// names are distinct exactly when the C names are — and what is left grows
745/// another `_` for as long as something already has its spelling. The names
746/// that need one are settled in sorted order, so that the answer never
747/// depends on the order the arenas happen to be in.
748fn unique_spellings<'n>(spelled: impl IntoIterator<Item = &'n str>) -> HashMap<String, String> {
749    let mut taken: HashSet<&str> = HashSet::new();
750    let mut changing: BTreeSet<&str> = BTreeSet::new();
751    for name in spelled {
752        if respelled(name) {
753            changing.insert(name);
754        } else {
755            taken.insert(name);
756        }
757    }
758    let mut renamed: HashMap<String, String> = HashMap::new();
759    let mut assigned: HashSet<String> = HashSet::new();
760    for name in changing {
761        let mut candidate = plain_spelling(name);
762        while taken.contains(candidate.as_str()) || assigned.contains(&candidate) {
763            candidate.push('_');
764        }
765        assigned.insert(candidate.clone());
766        renamed.insert(name.to_owned(), candidate);
767    }
768    renamed
769}
770
771/// Whether `name` can stand as the label of a Rust block or loop.
772///
773/// A label is not a raw identifier, so a Rust keyword — `loop:` is a perfectly
774/// ordinary C label — cannot be one, nor can the five names that cannot even
775/// be raw. The labels this module builds itself are kept clear too, so that a
776/// `break` in a region never names a loop instead. A C label that is one of
777/// them keeps its own name with the label's number appended.
778fn is_label_name(name: &str) -> bool {
779    let mut chars = name.chars();
780    let starts = chars
781        .next()
782        .is_some_and(|c| c.is_ascii_alphabetic() || c == '_');
783    starts
784        && chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
785        && !RUST_KEYWORDS.contains(&name)
786        && !NEVER_RAW.contains(&name)
787        && !is_generated_label(name)
788}
789
790/// The labels this module gives its own loops, `switch`es, state machine and
791/// [recovered shapes](crate::reloop): `'cfg`, `'lN`, `'lN_body`, `'swN`,
792/// `'swN_cM`, `'bN` and `'rN`.
793fn is_generated_label(name: &str) -> bool {
794    fn digits(text: &str) -> bool {
795        !text.is_empty() && text.bytes().all(|b| b.is_ascii_digit())
796    }
797
798    if name == "cfg" {
799        return true;
800    }
801    if let Some(rest) = name.strip_prefix('l')
802        && digits(rest.strip_suffix("_body").unwrap_or(rest))
803    {
804        return true;
805    }
806    for prefix in ['b', 'r'] {
807        if let Some(rest) = name.strip_prefix(prefix)
808            && digits(rest)
809        {
810            return true;
811        }
812    }
813    if let Some(rest) = name.strip_prefix("sw") {
814        if digits(rest) {
815            return true;
816        }
817        if let Some((switch, case)) = rest.split_once("_c") {
818            return digits(switch) && digits(case);
819        }
820    }
821    false
822}
823
824/// Every [region](ir::Region) of a body, outermost first, with the C label it
825/// is named after.
826fn collect_regions(stmts: &[Stmt], out: &mut Vec<(ir::LabelId, String)>) {
827    for stmt in stmts {
828        match stmt {
829            Stmt::Region(region) => {
830                out.push((region.label, region.name.clone()));
831                collect_regions(&region.body, out);
832            }
833            Stmt::Block(items) => collect_regions(items, out),
834            Stmt::Label { body, .. } | Stmt::Case { body, .. } => {
835                collect_regions(std::slice::from_ref(body), out);
836            }
837            Stmt::If {
838                then_branch,
839                else_branch,
840                ..
841            } => {
842                collect_regions(std::slice::from_ref(then_branch), out);
843                if let Some(branch) = else_branch {
844                    collect_regions(std::slice::from_ref(branch), out);
845                }
846            }
847            Stmt::While { body, .. } | Stmt::DoWhile { body, .. } => {
848                collect_regions(std::slice::from_ref(body), out);
849            }
850            Stmt::For { init, body, .. } => {
851                collect_regions(init, out);
852                collect_regions(std::slice::from_ref(body), out);
853            }
854            Stmt::Switch(switch) => {
855                collect_regions(&switch.prelude, out);
856                for group in &switch.groups {
857                    collect_regions(&group.body, out);
858                }
859            }
860            Stmt::SwitchTree(switch) => collect_regions(std::slice::from_ref(&switch.body), out),
861            _ => {}
862        }
863    }
864}
865
866/// The lint exemptions every generated item carries.
867///
868/// A transliteration of C is unidiomatic Rust by construction: names are not
869/// snake case, locals are `mut` whether or not they are assigned again, a
870/// `switch` leaves labels that nothing jumps to, and a function that ends in an
871/// infinite loop leaves code behind that cannot run. `unknown_lints` comes
872/// first so that the list may name a lint an older compiler has never heard of.
873///
874/// Two of them are about the `extern` block. A C program declares the library
875/// its own way — `int strlen();` with no prototype is what a C89 program
876/// writes, and an implicit declaration is exactly that — so the declaration
877/// `cinrs` generates may disagree with the one Rust's own standard library
878/// uses for the same symbol (`clashing_extern_declarations`, and Rust 1.99's
879/// deny-by-default `invalid_runtime_symbol_definitions`). Nothing is
880/// *defined*: the symbol is the C library's either way, and a call through a
881/// type with no prototype is transmuted to the signature its arguments make
882/// before it is made, which is the contract C's own ABI runs on.
883///
884/// Two more are the deny-by-default `arithmetic_overflow` and
885/// `unconditional_panic`, which fire when `rustc` can see that an operation
886/// would trap: a division whose divisor it has const-propagated to zero, a
887/// shift past the width of the type, an overflowing constant. Each of those is
888/// *undefined behaviour* in C, so the C program is valid whatever it does and
889/// the operation is very often in a branch that cannot be taken —
890/// `execute/pr97888-1` is `if (h > -173) e = d / i;` with `i` a zero the
891/// program never reaches. Refusing to compile valid C is not an option;
892/// panicking at run time if it is ever reached is a perfectly good answer to
893/// undefined behaviour, and is what the same code already does when the
894/// divisor is only zero at run time.
895/// The label a [label address](ir::ExprKind::LabelAddr) names, through any
896/// conversions around it.
897fn label_state(expr: &Expr) -> Option<ir::LabelId> {
898    match &expr.kind {
899        ExprKind::LabelAddr(id) => Some(*id),
900        ExprKind::Cast(inner) => label_state(inner),
901        _ => None,
902    }
903}
904
905/// The name of the wrapper type an object aligned to `align` is generated
906/// inside; see [`Codegen::align_wrapper_items`].
907fn align_wrapper_ident(align: u64, span: Span) -> Ident {
908    Ident::new(&format!("__cinrs_align_{align}"), span)
909}
910
911/// The length of an array type, or `None` for anything else.
912fn array_len(types: &ir::Types, ty: Ty) -> Option<u64> {
913    match ty {
914        Ty::Array(id) => Some(types.array_type(id).len),
915        _ => None,
916    }
917}
918
919/// The name of a unit's `cleanup` drop guard type, in this crate's own
920/// hygiene: nothing a C program can write reaches it.
921fn cleanup_guard_ty() -> Ident {
922    Ident::new("__cinrs_cleanup", Span::mixed_site())
923}
924
925/// The name of a unit's bump arena type, in the same hygiene; see
926/// [`Codegen::arena_items`].
927fn arena_ty() -> Ident {
928    Ident::new("__cinrs_vla_arena", Span::mixed_site())
929}
930
931/// The name of a [CFG-mode](crate::cfg) function's array of arena marks, one
932/// slot per variable length array it declares; see [`Codegen::vla_def`].
933fn vla_marks_ident() -> Ident {
934    Ident::new("__cinrs_vla_marks", Span::mixed_site())
935}
936
937// ---------------------------------------------------------------------------
938// the generator
939// ---------------------------------------------------------------------------
940
941/// How `continue` leaves a particular loop.
942#[derive(Clone, Copy, PartialEq, Eq)]
943enum ContinueStyle {
944    /// The loop re-tests its condition on its own: `continue 'l`.
945    Head,
946    /// Work remains before the next iteration: `break 'l_body`.
947    BodyLabel,
948}
949
950/// A place, ready to be read from or written to.
951struct LoweredPlace {
952    /// Statements that must run before `access` is used.
953    setup: TokenStream,
954    /// A Rust place expression that may be evaluated more than once.
955    access: TokenStream,
956    /// Set when the place is a bit-field, in which case `access` is the record
957    /// holding it and the bits are reached through the generated accessors.
958    bits: Option<BitAccess>,
959    /// Set when the object may not be aligned the way its type asks.
960    ///
961    /// C reaches such an object through a packed member or a pointer cast, and
962    /// says nothing about the load; Rust makes `*p` on an underaligned `p`
963    /// undefined behaviour, which a debug build turns into an abort. Such a
964    /// place is read and written through `read_unaligned` and
965    /// `write_unaligned` instead. See [`Codegen::place_align`].
966    unaligned: bool,
967    /// Set when the object is `_Atomic`: reading it is a sequentially
968    /// consistent load and writing it a sequentially consistent store, both
969    /// through `AtomicX::from_ptr` over its address (C11 6.5.2.4, 6.5.16).
970    ///
971    /// The [class](AtomicClass) says which atomic, and the [`Ty`] is the
972    /// object's own type with the `_Atomic` taken off — what the value the
973    /// load produces is converted to.
974    atomic: Option<(AtomicClass, Ty)>,
975}
976
977impl LoweredPlace {
978    /// An ordinary place, whose access is the value.
979    fn plain(setup: TokenStream, access: TokenStream) -> Self {
980        Self {
981            setup,
982            access,
983            bits: None,
984            unaligned: false,
985            atomic: None,
986        }
987    }
988}
989
990/// What a read-modify-write of an `_Atomic` place does to it.
991enum PlaceRmw<'a> {
992    /// `place op= value`, in the type `compute`.
993    Compound {
994        /// The operator.
995        op: BinOp,
996        /// The right operand, already converted for `compute`.
997        value: &'a Expr,
998        /// The type the operation is carried out in.
999        compute: Ty,
1000    },
1001    /// `++place` or `--place`.
1002    Step {
1003        /// Whether this decrements.
1004        dec: bool,
1005    },
1006}
1007
1008/// Which value such a read-modify-write leaves behind.
1009#[derive(Clone, Copy, PartialEq, Eq)]
1010enum RmwValue {
1011    /// None: it was written as a statement.
1012    None,
1013    /// The value from before the update, which is what `x++` is.
1014    Old,
1015    /// The value after it, which is what `++x` and `x += v` are.
1016    New,
1017}
1018
1019/// The atomic operation a compound assignment operator performs, where there
1020/// is one.
1021fn rmw_of_binop(op: BinOp) -> Option<ir::AtomicRmw> {
1022    Some(match op {
1023        BinOp::Add => ir::AtomicRmw::Add,
1024        BinOp::Sub => ir::AtomicRmw::Sub,
1025        BinOp::BitAnd => ir::AtomicRmw::And,
1026        BinOp::BitOr => ir::AtomicRmw::Or,
1027        BinOp::BitXor => ir::AtomicRmw::Xor,
1028        _ => return None,
1029    })
1030}
1031
1032/// The accessors a bit-field place is read and written through.
1033struct BitAccess {
1034    getter: Ident,
1035    setter: Ident,
1036}
1037
1038/// The unsigned word a bit-field's bytes are gathered into, and what its
1039/// accessors need to know about it.
1040///
1041/// See [`Codegen::bit_field_window`]; the word is `u64` for every bit-field
1042/// standard C allows and `u128` for the wide ones GNU's `__int128` makes
1043/// possible.
1044struct BitWindow {
1045    /// The expression that reads the overlapping bytes into the word.
1046    read: TokenStream,
1047    /// The field's bit offset inside the word.
1048    shift: u32,
1049    /// The field's bits, in place, inside the word.
1050    mask: u128,
1051    /// The word's Rust type: `u64` or `::core::primitive::u128`.
1052    word: TokenStream,
1053    /// Its width in bits, which is what a mask and a sign extension are
1054    /// written against.
1055    word_bits: u32,
1056}
1057
1058/// Where the pristine argument list of the function being generated lives.
1059#[derive(Clone, Copy, PartialEq, Eq)]
1060enum VaSource {
1061    /// There is none: the function takes no variable arguments.
1062    None,
1063    /// The synthetic `...` parameter of a variadic definition.
1064    Ellipsis,
1065    /// The function's own `va_list` parameter.
1066    Param(ir::ObjectId),
1067    /// The function's own `va_list *` parameter, whose *pointee* is the list.
1068    PtrParam(ir::ObjectId),
1069}
1070
1071struct Codegen<'a> {
1072    program: &'a Program,
1073    map: &'a SourceMap,
1074    options: &'a Options,
1075    continue_styles: HashMap<LoopId, ContinueStyle>,
1076    /// The Rust names of the locals of the function being generated, wherever
1077    /// they differ from the C ones: in [CFG mode](crate::cfg), where every
1078    /// local of the function shares one scope, and for a local whose name
1079    /// would shadow a file-scope item (see [`PRELUDE_PATTERNS`]).
1080    local_names: HashMap<ir::ObjectId, String>,
1081    /// The hidden pointer the function being generated reaches each enclosing
1082    /// object through, when it is a [lifted nested function](ir::EnvParam).
1083    ///
1084    /// It is what a call from inside one passes on: an object this function
1085    /// does not own itself arrives as a pointer, and the callee wants the same
1086    /// pointer rather than the address of a local that is not there.
1087    env: HashMap<ir::ObjectId, ir::ObjectId>,
1088    /// The names a `let` binding or a parameter must not use.
1089    reserved: HashSet<String>,
1090    /// The Rust spelling of every C name the unit gives to something; see
1091    /// [`Names`].
1092    names: Names,
1093    va_source: VaSource,
1094    ret_ty: Ty,
1095    /// Whether the function being generated is a [state
1096    /// machine](crate::cfg), in which case every local is already bound at the
1097    /// top and a definition is an assignment.
1098    in_cfg: bool,
1099    /// Whether the function being generated is [safe](Function::is_safe), so
1100    /// that its body has no `unsafe` block around it.
1101    in_safe: bool,
1102    temporaries: u32,
1103    /// Set the first time a `__int128` reaches the output, which is what
1104    /// decides whether the [data-model check](Codegen::data_model_check) has
1105    /// anything to say about `i128`'s alignment.
1106    ///
1107    /// A [`Cell`] because [`Codegen::ty`] takes `&self`; the check is built
1108    /// after every item, so it sees the final answer.
1109    uses_int128: Cell<bool>,
1110    /// Set the first time a complex type reaches the output, for the same
1111    /// reason and by the same route as [`Codegen::uses_int128`]: only a unit
1112    /// that has one asserts the layout of `Complex<f32>` and `Complex<f64>`.
1113    uses_complex: Cell<bool>,
1114    /// Whether anything in the unit needs the `cleanup` drop guard item.
1115    uses_cleanup: Cell<bool>,
1116    /// Whether any function of the unit opens with the bump arena variable
1117    /// length arrays and `alloca` allocate from, so that the unit needs the
1118    /// arena's type; see [`Codegen::arena_items`].
1119    uses_arena: Cell<bool>,
1120    /// Where the unit's first variable length array or `alloca` was written,
1121    /// which is what the arena's items are spanned with: in a `#![no_std]`
1122    /// crate that did not say `#pragma cinrs no_std`, `rustc`'s "cannot find
1123    /// `std`" then points at the C that needed it.
1124    arena_span: Cell<Option<Span>>,
1125    /// In a [CFG-mode](crate::cfg) function, the slot of the function's array
1126    /// of arena marks each variable length array's hidden frame object is;
1127    /// see [`Codegen::vla_def`].
1128    vla_slots: HashMap<ir::ObjectId, usize>,
1129    /// Every [x86 intrinsic](crate::x86) whose *address* the unit took, in the
1130    /// order it first did.
1131    ///
1132    /// An intrinsic is not a symbol, and `core::arch`'s function has the Rust
1133    /// ABI, so its address is not an `unsafe extern "C" fn` pointer and cannot
1134    /// be made into one. What C asks for is a function of that signature that
1135    /// does what the intrinsic does, which is a shim — and GCC's own headers
1136    /// are exactly that, `__always_inline__` functions whose address is
1137    /// therefore takeable. One is generated per intrinsic, private to the
1138    /// unit's module, and the same `FuncId` used twice shares it.
1139    address_taken: RefCell<Vec<ir::FuncId>>,
1140    /// The number of every label a `&&label` took the address of — the value
1141    /// of its address — over the whole unit.
1142    ///
1143    /// A [`ir::LabelId`] is unique across the translation unit, which is what
1144    /// makes one map enough: a block-scope `static void *table[] = { &&a };`
1145    /// becomes an item at module level and is generated before any function
1146    /// body, so the number cannot be looked up in the function being emitted.
1147    /// See [`Cfg::labels`].
1148    label_states: HashMap<ir::LabelId, u32>,
1149    /// The Rust label each [region](ir::Region) of the function being
1150    /// generated carries: the C label's name, unless Rust cannot spell it as a
1151    /// label or this module already gives that name to a loop.
1152    region_names: HashMap<ir::LabelId, String>,
1153    /// The regions the statement being generated stands inside, which is what
1154    /// tells a `goto` whether it leaves one or restarts it.
1155    region_kinds: HashMap<ir::LabelId, ir::RegionKind>,
1156    /// The Rust label each loop [the relooper](crate::reloop) recovered
1157    /// carries: the C label its head stands at, or `'rN`.
1158    loop_names: HashMap<u32, String>,
1159    /// The labelled blocks and loops open around the shape being generated,
1160    /// outermost first.
1161    shape_scopes: Vec<ShapeScope>,
1162    /// Numbers the labelled blocks a sequence of shapes needs, so that each
1163    /// has a name of its own within the function.
1164    shape_labels: u32,
1165    /// The labels a jump really used: one nothing named is left out, braces
1166    /// and all.
1167    used_labels: HashSet<u32>,
1168}
1169
1170/// A labelled block or loop the shape being generated stands inside.
1171///
1172/// Together they are how a jump the graph still holds is emitted: the
1173/// innermost scope whose [exit](reloop::Exit) names the target block says
1174/// whether it is a `break` or a `continue`, and of what.
1175#[derive(Clone)]
1176struct ShapeScope {
1177    /// Identifies the label in [`Codegen::used_labels`]. A loop's is
1178    /// [`u32::MAX`], which is never looked up: a loop always carries its name.
1179    id: u32,
1180    /// The name, without the tick.
1181    name: String,
1182    /// Whether arriving at `exit` is `continue` rather than `break`.
1183    repeats: bool,
1184    /// Where the jump arrives.
1185    exit: reloop::Exit,
1186}
1187
1188impl<'a> Codegen<'a> {
1189    fn new(program: &'a Program, map: &'a SourceMap, options: &'a Options) -> Self {
1190        let mut reserved: HashSet<String> =
1191            PRELUDE_PATTERNS.iter().map(|s| (*s).to_owned()).collect();
1192        // A `static mut` and a `const` are both in the value namespace, so a
1193        // binding of the same name is `E0530` rather than a shadow.
1194        for var in &program.statics {
1195            if let Some(item_name) = program.object(var.object).storage.item_name() {
1196                reserved.insert(item_name.to_owned());
1197            }
1198        }
1199        for constant in &program.enum_constants {
1200            reserved.insert(constant.rust_name.clone());
1201        }
1202        let mut label_states = HashMap::new();
1203        for func in &program.functions {
1204            if let Some(ir::Body::Cfg(cfg)) = &func.body {
1205                label_states.extend(cfg.labels.iter().map(|(id, number)| (*id, *number)));
1206            }
1207        }
1208        Self {
1209            program,
1210            map,
1211            options,
1212            continue_styles: HashMap::new(),
1213            local_names: HashMap::new(),
1214            env: HashMap::new(),
1215            reserved,
1216            names: Names::new(program),
1217            va_source: VaSource::None,
1218            ret_ty: Ty::Void,
1219            in_cfg: false,
1220            in_safe: false,
1221            temporaries: 0,
1222            uses_int128: Cell::new(false),
1223            uses_complex: Cell::new(false),
1224            uses_cleanup: Cell::new(false),
1225            uses_arena: Cell::new(false),
1226            arena_span: Cell::new(None),
1227            vla_slots: HashMap::new(),
1228            address_taken: RefCell::new(Vec::new()),
1229            label_states,
1230            region_names: HashMap::new(),
1231            region_kinds: HashMap::new(),
1232            loop_names: HashMap::new(),
1233            shape_scopes: Vec::new(),
1234            shape_labels: 0,
1235            used_labels: HashSet::new(),
1236        }
1237    }
1238
1239    /// Whether `va_list` appears anywhere in a type.
1240    fn uses_va_list(&self, ty: Ty) -> bool {
1241        match ty {
1242            Ty::VaList => true,
1243            Ty::Pointer(id) => self.uses_va_list(self.program.types.pointer_type(id).pointee),
1244            Ty::Array(id) => self.uses_va_list(self.program.types.array_type(id).elem),
1245            Ty::Func(id) => {
1246                let func = self.program.types.func_type(id);
1247                self.uses_va_list(func.ret) || func.params.iter().any(|ty| self.uses_va_list(*ty))
1248            }
1249            _ => false,
1250        }
1251    }
1252
1253    fn sp(&self, range: SourceRange) -> Span {
1254        self.map.span(range)
1255    }
1256
1257    /// The Rust identifier a C name is generated as; see [`Names`].
1258    ///
1259    /// Every name the generator writes goes through here, so that one C name
1260    /// reads as one Rust name wherever it appears — as an item, as a member,
1261    /// as a designator, in `offsetof`, in a bit-field accessor.
1262    fn c_ident(&self, name: &str, span: Span) -> Ident {
1263        self.names.ident(name, span)
1264    }
1265
1266    /// The name of the companion type a record whose flexible array member
1267    /// holds `len` elements is generated under; see [`Codegen::flexible_items`].
1268    fn flexible_ident(&self, rust_name: &str, len: u64, span: Span) -> Ident {
1269        Ident::new(
1270            &format!("__cinrs_{}_{len}", self.names.spelling(rust_name)),
1271            span,
1272        )
1273    }
1274
1275    /// The name of the item an externally linked **object** is declared under;
1276    /// see [`Program::extern_object_name`] for why an object and not a
1277    /// function.
1278    ///
1279    /// The symbol itself is what `#[link_name]` says; this is only the Rust
1280    /// side of it, and it is built out of the spelling every other C name is
1281    /// given so that two symbols never end up under one item.
1282    fn extern_object_ident(&self, symbol: &str, span: Span) -> Ident {
1283        let spelling = self.names.spelling(symbol);
1284        Ident::new(&self.program.extern_object_name(&spelling), span)
1285    }
1286
1287    /// A name no C identifier can collide with.
1288    ///
1289    /// `Span::mixed_site()` gives the identifier this crate's own hygiene, so
1290    /// even a C variable spelled `__cinrs_tmp0` refers to something else.
1291    fn temporary(&mut self) -> Ident {
1292        let name = format!("__cinrs_tmp{}", self.temporaries);
1293        self.temporaries += 1;
1294        Ident::new(&name, Span::mixed_site())
1295    }
1296
1297    /// A temporary whose *position* is the C it came from, while it still
1298    /// resolves as though it had been written at the macro's definition site.
1299    ///
1300    /// `Span::mixed_site` carries both a hygiene context and a position, and
1301    /// the position it carries is the whole invocation. That is invisible until
1302    /// a diagnostic is about an expression built out of such a name — `p[i]`
1303    /// becomes a temporary holding `p.offset(i)` and the place
1304    /// `(*__cinrs_tmp0)`, whose span `rustc` widens to cover the name as well
1305    /// and therefore to the macro call as a whole. `resolved_at` keeps
1306    /// the hygiene and takes the position from the C instead, which is where
1307    /// the caret belongs: a dereference a *safe* function may not do is
1308    /// reported on the `p[i]` that asked for it.
1309    fn temporary_at(&mut self, span: Span) -> Ident {
1310        let name = format!("__cinrs_tmp{}", self.temporaries);
1311        self.temporaries += 1;
1312        Ident::new(&name, span.resolved_at(Span::mixed_site()))
1313    }
1314
1315    /// Builds a Rust label such as `'l0`.
1316    fn label(&self, name: &str, span: Span) -> TokenStream {
1317        let mut tick = Punct::new('\'', Spacing::Joint);
1318        tick.set_span(span);
1319        let mut out = TokenStream::new();
1320        out.extend([
1321            TokenTree::Punct(tick),
1322            TokenTree::Ident(Ident::new(name, span)),
1323        ]);
1324        out
1325    }
1326
1327    // -- types --------------------------------------------------------------
1328
1329    /// The Rust type a C type maps to, always fully qualified.
1330    fn ty(&self, ty: Ty, span: Span) -> TokenStream {
1331        let name = match ty {
1332            // Only reachable on the error path, where a `compile_error!` is
1333            // already going out; the unit type keeps the stub items parseable.
1334            Ty::Void | Ty::Error => return quote_spanned! {span=> () },
1335            // `typedef _Bool bool;` is what every C23 compatibility header
1336            // writes, so the name has to be the qualified one or the alias
1337            // this unit generates for it is `pub type bool = bool;`.
1338            Ty::Bool => return primitive_ty("bool", span),
1339            Ty::Char => "c_char",
1340            Ty::SChar => "c_schar",
1341            Ty::UChar => "c_uchar",
1342            Ty::Short => "c_short",
1343            Ty::UShort => "c_ushort",
1344            Ty::Int => "c_int",
1345            Ty::UInt => "c_uint",
1346            Ty::Long => "c_long",
1347            Ty::ULong => "c_ulong",
1348            Ty::LongLong => "c_longlong",
1349            Ty::ULongLong => "c_ulonglong",
1350            // `core::ffi` has no alias for these: `__int128` is not a C type
1351            // the standard knows, and Rust's own `i128` has had its ABI since
1352            // 1.77. The `core::primitive` path rather than the bare name,
1353            // because `typedef unsigned __int128 u128;` is how real C spells
1354            // it and `pub type u128 = u128;` is a cycle.
1355            Ty::Int128 => {
1356                self.uses_int128.set(true);
1357                return primitive_ty("i128", span);
1358            }
1359            Ty::UInt128 => {
1360                self.uses_int128.set(true);
1361                return primitive_ty("u128", span);
1362            }
1363            Ty::Float => "c_float",
1364            Ty::Double => "c_double",
1365            // `core::ffi` has nothing for these, and there is nothing it could
1366            // have: a complex value is a pair, and the pair the ecosystem
1367            // already agrees on is `num_complex::Complex`, which the runtime
1368            // re-exports. See [`Codegen::rt_path`].
1369            Ty::ComplexFloat | Ty::ComplexDouble => {
1370                self.uses_complex.set(true);
1371                let component =
1372                    primitive_ty(if ty == Ty::ComplexFloat { "f32" } else { "f64" }, span);
1373                let rt = self.rt_path(span);
1374                return quote_spanned! {span=> #rt::Complex<#component> };
1375            }
1376            // The lifetime is elided: `VaList` only ever appears as the type of
1377            // a parameter or of a local, where elision does the right thing.
1378            Ty::VaList => "VaList",
1379            // `core::arch`'s own `__m128i` and friends: the same name, the
1380            // same size, the same alignment and the same calling convention
1381            // as C's, which is what makes the intrinsics a name-level mapping
1382            // rather than a translation. The module is `x86_64` or `x86`
1383            // depending on the [target model](crate::target); a unit that
1384            // reaches one of these types on any other architecture never got
1385            // past the `#error` in the bundled header.
1386            Ty::Vector(vec) => {
1387                let module = self.arch_module(span);
1388                let name = Ident::new(vec.name(), span);
1389                return quote_spanned! {span=> ::core::arch::#module::#name };
1390            }
1391            Ty::Pointer(id) => {
1392                let pointer = self.program.types.pointer_type(id);
1393                if let Ty::Func(func) = pointer.pointee {
1394                    // C's function pointers can be null, and Rust's cannot;
1395                    // `Option` is how the two are reconciled, and it has the
1396                    // same representation.
1397                    let signature = self.fn_ty(func, span);
1398                    return quote_spanned! {span=> ::core::option::Option<#signature> };
1399                }
1400                let pointee = self.pointee_ty(pointer.pointee, span);
1401                return if pointer.konst {
1402                    quote_spanned! {span=> *const #pointee }
1403                } else {
1404                    quote_spanned! {span=> *mut #pointee }
1405                };
1406            }
1407            Ty::Array(id) => {
1408                // A variably modified array's object *is* a pointer to its
1409                // first element: the elements themselves are one bump off the
1410                // function's arena, however many dimensions there are, and nothing in the
1411                // generated code ever names the array as a value. See
1412                // [`ir::VlaDef`].
1413                if self.program.types.is_vm(ty) {
1414                    let step = self.ty(self.program.types.vm_step_ty(ty), span);
1415                    return quote_spanned! {span=> *mut #step };
1416                }
1417                let array = self.program.types.array_type(id);
1418                let elem = self.ty(array.elem, span);
1419                let len = usize_literal(array.len, span);
1420                let inner = quote_spanned! {span=> #elem ; #len };
1421                return bracketed(inner, span);
1422            }
1423            Ty::Func(id) => return self.fn_ty(id, span),
1424            Ty::Record(id) => {
1425                let name = self.c_ident(&self.program.types.record(id).rust_name, span);
1426                return quote_spanned! {span=> #name };
1427            }
1428            Ty::Enum(id) => {
1429                let name = self.c_ident(&self.program.types.enum_def(id).rust_name, span);
1430                return quote_spanned! {span=> #name };
1431            }
1432            // An `_Atomic T` object *is* a `T` in the generated Rust: the
1433            // atomicity is in how it is reached — `AtomicX::from_ptr` over its
1434            // address — and not in what it holds. Where the two differ is
1435            // alignment, which the layout code takes from the atomic type and
1436            // the generated item carries as `#[repr(C, align(N))]`.
1437            Ty::Atomic(id) => {
1438                let inner = self.program.types.atomic_inner(id);
1439                return self.ty(inner, span);
1440            }
1441        };
1442        let ident = Ident::new(name, span);
1443        quote_spanned! {span=> ::core::ffi::#ident }
1444    }
1445
1446    /// The `core::arch` submodule the x86 intrinsics and vector types live in:
1447    /// `x86_64` for a 64-bit target and `x86` for a 32-bit one.
1448    ///
1449    /// The two modules have the same names in them — `core::arch::x86` has
1450    /// `_mm_add_epi32` too — so only the path differs between the targets.
1451    /// Anything else is unreachable: the bundled `<immintrin.h>` is an
1452    /// `#error` on a target that is neither.
1453    fn arch_module(&self, span: Span) -> Ident {
1454        let name = if self.options.target.arch == crate::target::Arch::X86 {
1455            "x86"
1456        } else {
1457            "x86_64"
1458        };
1459        Ident::new(name, span)
1460    }
1461
1462    /// The path of the runtime module the generated code calls: `::cinrs::rt`,
1463    /// or whatever `#pragma cinrs crate` said instead of `::cinrs`.
1464    ///
1465    /// It is the one thing an expansion names outside `core` (and outside the
1466    /// `alloc`/`std` a variable length array needs), and it is named in full
1467    /// because the expansion lives in a module of its own where nothing is in
1468    /// scope. See [`ir::DEFAULT_CRATE_PATH`].
1469    fn rt_path(&self, span: Span) -> TokenStream {
1470        let path = TokenStream::from_str(&self.program.crate_path)
1471            .unwrap_or_else(|_| TokenStream::from_str(ir::DEFAULT_CRATE_PATH).expect("valid"));
1472        let path = respan(path, span);
1473        quote_spanned! {span=> #path::rt }
1474    }
1475
1476    /// A function of `cinrs_rt::complex`, by name.
1477    fn rt_complex(&self, name: &str, span: Span) -> TokenStream {
1478        let rt = self.rt_path(span);
1479        let ident = Ident::new(name, span);
1480        quote_spanned! {span=> #rt::complex::#ident }
1481    }
1482
1483    /// The suffix the runtime spells a complex type's component width with.
1484    fn complex_suffix(ty: Ty) -> &'static str {
1485        if ty.complex_component() == Ty::Float {
1486            "f32"
1487        } else {
1488            "f64"
1489        }
1490    }
1491
1492    /// `unsafe extern "C" fn(…) -> R`, the type a function pointer wraps.
1493    ///
1494    /// A function type with no prototype has no parameters to write, so it
1495    /// comes out as `unsafe extern "C" fn() -> R`; what a call through one
1496    /// really passes is written at the call site instead. See
1497    /// [`Codegen::call`].
1498    fn fn_ty(&self, id: ir::FuncTyId, span: Span) -> TokenStream {
1499        let func = self.program.types.func_type(id).clone();
1500        self.fn_ptr_ty(&func.params, func.variadic, func.ret, span)
1501    }
1502
1503    // -- the heap the emulated automatic storage comes from -------------------
1504
1505    /// The crate the `Vec`s behind the bump arena of variable length arrays
1506    /// and `alloca` come from.
1507    ///
1508    /// Everything else the expansion generates is `core`-only; the arena needs
1509    /// an allocator, which is `std` in an ordinary crate and `alloc` in one
1510    /// that said `#pragma cinrs no_std` (and therefore wrote
1511    /// `extern crate alloc;` itself, since a procedural macro cannot add one).
1512    fn alloc_crate(&self, span: Span) -> Ident {
1513        let name = if self.program.no_std { "alloc" } else { "std" };
1514        Ident::new(name, span)
1515    }
1516
1517    /// `::std::vec::Vec<T>`.
1518    fn vec_ty(&self, elem: TokenStream, span: Span) -> TokenStream {
1519        let krate = self.alloc_crate(span);
1520        quote_spanned! {span=> ::#krate::vec::Vec<#elem> }
1521    }
1522
1523    /// `::std::vec::Vec::new()`.
1524    fn vec_new(&self, span: Span) -> TokenStream {
1525        let krate = self.alloc_crate(span);
1526        quote_spanned! {span=> ::#krate::vec::Vec::new() }
1527    }
1528
1529    /// `::std::vec::from_elem(value, len)`, which is what `vec![value; len]`
1530    /// expands to; a procedural macro is better off naming the function.
1531    fn vec_of(&self, value: TokenStream, len: TokenStream, span: Span) -> TokenStream {
1532        let krate = self.alloc_crate(span);
1533        quote_spanned! {span=> ::#krate::vec::from_elem(#value, #len) }
1534    }
1535
1536    /// The Rust type a *pointee* maps to.
1537    ///
1538    /// `void *` is the one place where C's `void` is not Rust's `()`: it stands
1539    /// for "some object of unknown type", which is exactly what
1540    /// [`core::ffi::c_void`] is for. Its size is one byte, so the `void *`
1541    /// arithmetic GCC allows keeps working.
1542    fn pointee_ty(&self, ty: Ty, span: Span) -> TokenStream {
1543        if ty.is_void() {
1544            let ident = Ident::new("c_void", span);
1545            return quote_spanned! {span=> ::core::ffi::#ident };
1546        }
1547        // A pointer to a variably modified type points at what is left under
1548        // the variable dimensions — `double (*)[m]` is a `*mut c_double` —
1549        // and every offset through it is scaled by the bound at run time. See
1550        // [`Codegen::vm_scale`].
1551        if self.program.types.is_vm(ty) {
1552            return self.ty(self.program.types.vm_step_ty(ty), span);
1553        }
1554        self.ty(ty, span)
1555    }
1556
1557    // -- items --------------------------------------------------------------
1558
1559    /// The `struct`, `union`, `enum` and `typedef` items of the unit.
1560    fn type_items(&mut self) -> TokenStream {
1561        let mut out = self.align_wrapper_items();
1562        for record in self.program.types.records() {
1563            if !record.emit {
1564                continue;
1565            }
1566            out.extend(self.record_item(record));
1567        }
1568        out.extend(self.flexible_items());
1569        for def in self.program.types.enums() {
1570            if !def.emit {
1571                continue;
1572            }
1573            let span = self.sp(def.range);
1574            let name = self.c_ident(&def.rust_name, span);
1575            let int = self.ty(Ty::Int, span);
1576            // C says an enumerated type is compatible with an implementation
1577            // defined integer type; every ABI this targets picks `int`.
1578            out.extend(quote_spanned! {span=> pub type #name = #int; });
1579        }
1580        for constant in &self.program.enum_constants {
1581            let span = self.sp(constant.range);
1582            let name = self.c_ident(&constant.rust_name, span);
1583            let ty = self.ty(constant.ty, span);
1584            let value = bare_int_literal(constant.value, constant.ty, span);
1585            out.extend(quote_spanned! {span=> pub const #name: #ty = #value; });
1586        }
1587        for typedef in &self.program.typedefs {
1588            // No alias is generated for `va_list`, which is what the
1589            // `typedef` in <stdarg.h> writes. `core::ffi::VaList` carries the
1590            // lifetime of the frame it reads, so `pub type va_list = VaList;`
1591            // does not even parse — and nothing needs the alias, since every
1592            // generated signature names the type directly.
1593            if self.uses_va_list(typedef.ty) {
1594                continue;
1595            }
1596            let span = self.sp(typedef.range);
1597            let name = self.c_ident(&typedef.rust_name, span);
1598            let ty = self.ty(typedef.ty, span);
1599            out.extend(quote_spanned! {span=> pub type #name = #ty; });
1600        }
1601        out
1602    }
1603
1604    /// The `#[repr(C, align(N))]` wrappers the unit's over-aligned objects are
1605    /// generated inside, one per distinct alignment.
1606    ///
1607    /// Rust can over-align a *type* and nothing else, so an object an
1608    /// `_Alignas(64)` made stricter than its type becomes
1609    ///
1610    /// ```text
1611    /// #[repr(C, align(64))] #[derive(Copy, Clone)]
1612    /// pub struct __cinrs_align_64<T>(pub T);
1613    ///
1614    /// let mut buf: __cinrs_align_64<[c_char; 256]> = __cinrs_align_64(…);
1615    /// ```
1616    ///
1617    /// and every access to `buf` goes through `buf.0` — which is also how Rust
1618    /// code that reaches such an object reads it. The C type is unchanged:
1619    /// `sizeof buf` is the array's size, and only the binding knows about the
1620    /// wrapper. See [`ir::Object::align`].
1621    fn align_wrapper_items(&self) -> TokenStream {
1622        let mut wanted: Vec<(u64, SourceRange)> = self
1623            .program
1624            .objects
1625            .iter()
1626            .filter_map(|object| Some((object.align?, object.range)))
1627            .collect();
1628        wanted.sort_by_key(|(align, _)| *align);
1629        wanted.dedup_by_key(|(align, _)| *align);
1630        let mut out = TokenStream::new();
1631        for (align, range) in wanted {
1632            let span = self.sp(range);
1633            let name = align_wrapper_ident(align, span);
1634            let literal = Literal::u64_unsuffixed(align);
1635            out.extend(quote_spanned! {span=>
1636                #[repr(C, align(#literal))]
1637                #[derive(Copy, Clone)]
1638                pub struct #name<T>(pub T);
1639            });
1640        }
1641        out
1642    }
1643
1644    /// The companion types an object with a filled-in flexible array member
1645    /// needs, one per distinct (record, length).
1646    ///
1647    /// C99 forbids initialising such a member because the object would have to
1648    /// be larger than its type; GNU C allows it for an object with static
1649    /// storage duration, and this is where that extra room comes from:
1650    ///
1651    /// ```text
1652    /// #[repr(C)] pub struct __cinrs_W_3 { pub n: c_int, pub data: [c_int; 3] }
1653    /// pub static mut w: __cinrs_W_3 = __cinrs_W_3 { n: 3, data: [1, 2, 3] };
1654    /// ```
1655    ///
1656    /// The leading layout is the record's own — the same Rust fields, in the
1657    /// same order — so `(&raw mut w).cast::<W>()` is a pointer to a `W`, which
1658    /// is what every use of the object goes through. `sizeof w` is still
1659    /// `sizeof(struct W)`, as it is in GCC. See [`ir::Object::flexible_len`].
1660    fn flexible_items(&self) -> TokenStream {
1661        let mut wanted: Vec<(ir::RecordId, u64)> = self
1662            .program
1663            .objects
1664            .iter()
1665            .filter_map(|object| match (object.flexible_len, object.ty) {
1666                (Some(len), Ty::Record(record)) => Some((record, len)),
1667                _ => None,
1668            })
1669            .collect();
1670        wanted.sort_unstable_by_key(|(record, len)| (record.0, *len));
1671        wanted.dedup_by_key(|(record, len)| (record.0, *len));
1672        let mut out = TokenStream::new();
1673        for (record, len) in wanted {
1674            let def = self.program.types.record(record);
1675            let span = self.sp(def.range);
1676            let name = self.flexible_ident(&def.rust_name, len, span);
1677            out.extend(self.record_body(def, &name, Some(len)));
1678        }
1679        out
1680    }
1681
1682    fn record_item(&self, record: &ir::RecordDef) -> TokenStream {
1683        let span = self.sp(record.range);
1684        let name = self.c_ident(&record.rust_name, span);
1685        let item = self.record_body(record, &name, None);
1686        let accessors = self.bit_field_accessors(record, span);
1687        quote_spanned! {span=> #item #accessors }
1688    }
1689
1690    /// The `struct` (or `union`) item itself, under `name`.
1691    ///
1692    /// `tail` sizes the [flexible array member](ir::Field::flexible), which is
1693    /// what makes a [companion type](Codegen::flexible_items) differ from the
1694    /// record it stands for; `None` is the record as C declared it, whose
1695    /// member is the `[T; 0]` the type says it is.
1696    fn record_body(&self, record: &ir::RecordDef, name: &Ident, tail: Option<u64>) -> TokenStream {
1697        let span = self.sp(record.range);
1698        // `Copy` is what makes a C struct behave like one: assigning it,
1699        // passing it and returning it all copy the bytes.
1700        let derives = match (record.align, record.packed) {
1701            // `__attribute__((packed))` and `#pragma pack(N)` are exactly
1702            // Rust's own `packed(N)`: every field's alignment is capped at N,
1703            // and so is the record's.
1704            (_, Some(1)) => quote_spanned! {span=> #[repr(C, packed)] #[derive(Copy, Clone)] },
1705            (_, Some(pack)) => {
1706                let pack = usize_literal(pack, span);
1707                quote_spanned! {span=>
1708                    #[repr(C, packed(#pack))] #[derive(Copy, Clone)]
1709                }
1710            }
1711            // `_Alignas` or `aligned(N)` on a member, or a bit-field whose
1712            // type is stricter than any field the item really has, is honoured
1713            // by raising the *record's* alignment; sema has already placed the
1714            // members where that leaves them.
1715            (Some(align), None) => {
1716                let align = usize_literal(align, span);
1717                quote_spanned! {span=>
1718                    #[repr(C, align(#align))] #[derive(Copy, Clone)]
1719                }
1720            }
1721            (None, None) => quote_spanned! {span=> #[repr(C)] #[derive(Copy, Clone)] },
1722        };
1723        let byte = primitive_ty("u8", span);
1724        if !record.complete {
1725            // A tag that is never completed can still be pointed at. An empty
1726            // body is the closest Rust has to C's incomplete type.
1727            return quote_spanned! {span=>
1728                #derives pub struct #name { _incomplete: [#byte; 0] }
1729            };
1730        }
1731        let mut fields = TokenStream::new();
1732        for rust_field in &record.rust_fields {
1733            match rust_field {
1734                ir::RustField::Member(index) => {
1735                    let field = &record.fields[*index];
1736                    let fspan = self.sp(field.range);
1737                    let fname = self.c_ident(&field.name, fspan);
1738                    let fty = match (tail, field.flexible) {
1739                        (Some(len), true) => {
1740                            let elem = self
1741                                .program
1742                                .types
1743                                .elem(field.ty)
1744                                .expect("a flexible member is an array");
1745                            let elem = self.ty(elem, fspan);
1746                            let len = usize_literal(len, fspan);
1747                            bracketed(quote_spanned! {fspan=> #elem ; #len }, fspan)
1748                        }
1749                        _ => self.ty(field.ty, fspan),
1750                    };
1751                    // Members are `pub` so Rust code can build and read the
1752                    // value.
1753                    fields.extend(quote_spanned! {fspan=> pub #fname: #fty, });
1754                }
1755                ir::RustField::Bits { name, bytes, .. } | ir::RustField::Pad { name, bytes } => {
1756                    let fname = Ident::new(name, span);
1757                    let len = usize_literal(*bytes, span);
1758                    fields.extend(quote_spanned! {span=> pub #fname: [#byte; #len], });
1759                }
1760                ir::RustField::Align { name, align } => {
1761                    let fname = Ident::new(name, span);
1762                    let unit = unsigned_rust_ty((*align * 8) as u32, span);
1763                    fields.extend(quote_spanned! {span=> pub #fname: [#unit; 0], });
1764                }
1765            }
1766        }
1767        if record.rust_fields.is_empty() && record.kind == RecordKind::Union {
1768            // GCC gives an empty `union` a size of zero, and so does an empty
1769            // Rust `struct`; a Rust `union` has to have at least one field, so
1770            // this is the one place the two kinds are generated differently.
1771            fields.extend(quote_spanned! {span=> pub __cinrs_empty: [#byte; 0], });
1772        }
1773        let body = braced(fields, span);
1774        match record.kind {
1775            RecordKind::Struct => quote_spanned! {span=> #derives pub struct #name #body },
1776            RecordKind::Union => quote_spanned! {span=> #derives pub union #name #body },
1777        }
1778    }
1779
1780    /// The `impl` block holding one getter and one setter per named bit-field.
1781    ///
1782    /// The bits are not a field, so this is the only way to reach them — from
1783    /// the generated code and from Rust alike. Everything is written out
1784    /// inline: no helper type, no runtime, nothing to look up.
1785    fn bit_field_accessors(&self, record: &ir::RecordDef, span: Span) -> TokenStream {
1786        let mut methods = TokenStream::new();
1787        for field in &record.fields {
1788            let Some(bits) = &field.bits else {
1789                continue;
1790            };
1791            let fspan = self.sp(field.range);
1792            methods.extend(self.bit_field_getter(record, field, bits, fspan));
1793            methods.extend(self.bit_field_setter(record, field, bits, fspan));
1794        }
1795        if methods.is_empty() {
1796            return TokenStream::new();
1797        }
1798        let name = self.c_ident(&record.rust_name, span);
1799        quote_spanned! {span=> impl #name { #methods } }
1800    }
1801
1802    /// Reads the bytes a bit-field overlaps into one unsigned integer.
1803    ///
1804    /// The unit rule keeps a field inside one object of its own type, so eight
1805    /// bytes are enough for every type standard C allows a bit-field to have.
1806    /// GNU's `__int128` is the one that can ask for more — `unsigned __int128
1807    /// x : 70` overlaps nine or ten bytes — and the window widens to `u128`
1808    /// there. The word type and its width come back with the tokens, since the
1809    /// getter and the setter have to spell them too.
1810    fn bit_field_window(&self, bits: &ir::BitField, span: Span) -> BitWindow {
1811        let storage = Ident::new(&bits.storage, span);
1812        let start = bits.offset_in_storage();
1813        let first = start / 8;
1814        let shift = (start % 8) as u32;
1815        let count = (shift + bits.width).div_ceil(8);
1816        let word_bits: u32 = if shift + bits.width > 64 { 128 } else { 64 };
1817        let word = window_ty(word_bits, false, span);
1818        let mut read = TokenStream::new();
1819        for step in 0..count {
1820            let index = usize_literal(first + u64::from(step), span);
1821            let byte = if count == 1 {
1822                quote_spanned! {span=> self.#storage[#index] as #word }
1823            } else {
1824                quote_spanned! {span=> (self.#storage[#index] as #word) }
1825            };
1826            read.extend(if step == 0 {
1827                byte
1828            } else {
1829                let by = usize_literal(u64::from(step) * 8, span);
1830                quote_spanned! {span=> | (#byte << #by) }
1831            });
1832        }
1833        // The mask of the field's bits inside that window; the window was
1834        // chosen so that `shift + width` fits in it, which makes the shift fit
1835        // too.
1836        let mask = mask_of(shift + bits.width, word_bits) & !mask_of(shift, word_bits);
1837        BitWindow {
1838            read,
1839            shift,
1840            mask,
1841            word,
1842            word_bits,
1843        }
1844    }
1845
1846    fn bit_field_getter(
1847        &self,
1848        record: &ir::RecordDef,
1849        field: &ir::Field,
1850        bits: &ir::BitField,
1851        span: Span,
1852    ) -> TokenStream {
1853        let BitWindow {
1854            read,
1855            shift,
1856            word,
1857            word_bits,
1858            ..
1859        } = self.bit_field_window(bits, span);
1860        let ty = self.ty(field.ty, span);
1861        let name = self.c_ident(&bits.getter, span);
1862        let mask = word_literal(mask_of(bits.width, word_bits), word_bits, span);
1863        let shifted = if shift == 0 {
1864            quote_spanned! {span=> raw & #mask }
1865        } else {
1866            let by = usize_literal(u64::from(shift), span);
1867            quote_spanned! {span=> (raw >> #by) & #mask }
1868        };
1869        let value = if field.ty.is_bool() {
1870            quote_spanned! {span=> value != 0 }
1871        } else if !bits.signed || bits.width == word_bits {
1872            quote_spanned! {span=> value as #ty }
1873        } else {
1874            // Sign extension: shift the field's top bit up to the sign bit of
1875            // the window's signed counterpart and let the arithmetic shift
1876            // bring it back down.
1877            let signed = window_ty(word_bits, true, span);
1878            let by = usize_literal(u64::from(word_bits - bits.width), span);
1879            quote_spanned! {span=> (((value << #by) as #signed) >> #by) as #ty }
1880        };
1881        let body = self.accessor_body(
1882            record,
1883            quote_spanned! {span=>
1884                let raw: #word = #read;
1885                let value: #word = #shifted;
1886                #value
1887            },
1888            span,
1889        );
1890        quote_spanned! {span=>
1891            #[inline]
1892            pub fn #name(&self) -> #ty { #body }
1893        }
1894    }
1895
1896    fn bit_field_setter(
1897        &self,
1898        record: &ir::RecordDef,
1899        field: &ir::Field,
1900        bits: &ir::BitField,
1901        span: Span,
1902    ) -> TokenStream {
1903        let BitWindow {
1904            read,
1905            shift,
1906            mask,
1907            word,
1908            word_bits,
1909        } = self.bit_field_window(bits, span);
1910        let ty = self.ty(field.ty, span);
1911        let name = self.c_ident(&bits.setter, span);
1912        let storage = Ident::new(&bits.storage, span);
1913        let value = Ident::new("value", span);
1914        let field_mask = word_literal(mask, word_bits, span);
1915        let keep = word_literal(!mask & mask_of(word_bits, word_bits), word_bits, span);
1916        let shifted = if shift == 0 {
1917            quote_spanned! {span=> (#value as #word) & #field_mask }
1918        } else {
1919            let by = usize_literal(u64::from(shift), span);
1920            quote_spanned! {span=> ((#value as #word) << #by) & #field_mask }
1921        };
1922        let start = bits.offset_in_storage();
1923        let first = start / 8;
1924        let count = (shift + bits.width).div_ceil(8);
1925        let mut writes = TokenStream::new();
1926        let byte = primitive_ty("u8", span);
1927        for step in 0..count {
1928            let index = usize_literal(first + u64::from(step), span);
1929            if step == 0 {
1930                writes.extend(quote_spanned! {span=> self.#storage[#index] = raw as #byte; });
1931            } else {
1932                let by = usize_literal(u64::from(step) * 8, span);
1933                writes.extend(
1934                    quote_spanned! {span=> self.#storage[#index] = (raw >> #by) as #byte; },
1935                );
1936            }
1937        }
1938        let body = self.accessor_body(
1939            record,
1940            quote_spanned! {span=>
1941                let bits: #word = #shifted;
1942                let raw: #word = #read;
1943                let raw: #word = (raw & #keep) | bits;
1944                #writes
1945            },
1946            span,
1947        );
1948        quote_spanned! {span=>
1949            #[inline]
1950            pub fn #name(&mut self, #value: #ty) { #body }
1951        }
1952    }
1953
1954    /// Wraps an accessor body in `unsafe` where reading the storage needs it,
1955    /// which is exactly when the record is a `union`.
1956    fn accessor_body(&self, record: &ir::RecordDef, body: TokenStream, span: Span) -> TokenStream {
1957        if record.kind == RecordKind::Union {
1958            let block = braced(body, span);
1959            return quote_spanned! {span=> unsafe #block };
1960        }
1961        body
1962    }
1963
1964    /// `const _: () = { assert!(…); };` — the assumptions the data model made,
1965    /// checked against the target the expansion is really compiled for.
1966    ///
1967    /// Everything this crate computes at expansion time — `sizeof`, member
1968    /// offsets, bit-field storage, the type of an integer constant, the value
1969    /// of an `#if` — comes out of a [`TargetModel`](crate::TargetModel) that
1970    /// was chosen from `CINRS_TARGET`, from `#pragma cinrs target`, or (with
1971    /// neither) from the *host*. Any of the three may be the wrong one, and a
1972    /// wrong one would leave every one of those answers quietly wrong. So the
1973    /// expansion states them: `long` is this many bytes, a pointer is that
1974    /// many, plain `char` is signed, `double` is aligned so. The generated
1975    /// code uses the `core::ffi` aliases, which follow the *target*, so a
1976    /// mismatch is a failed assertion at the caret of the C rather than a
1977    /// program that computes the wrong thing — and the message names both the
1978    /// model that was used and the knob that chose it.
1979    ///
1980    /// `__int128`'s alignment is included only where the unit has one: it is
1981    /// the one scalar whose alignment is not fixed by its width, and a unit
1982    /// that never mentions it must not be refused over it.
1983    fn data_model_check(&self) -> TokenStream {
1984        let span = self.map.span(SourceRange::at(0));
1985        let target = &self.options.target;
1986        // Every message ends with this, so that a failure says what to change
1987        // rather than only what went wrong.
1988        let chosen = format!(
1989            "Translated for {}; set CINRS_TARGET from a build script \
1990             (cargo:rustc-env=CINRS_TARGET=$TARGET) or write #pragma cinrs target.",
1991            target.describe(&self.options.target_source)
1992        );
1993        let mut body = TokenStream::new();
1994        let mut width = |ty: TokenStream, bits: u32, what: &str| {
1995            let bytes = usize_literal(u64::from(bits).div_ceil(8), span);
1996            let message = message_literal(
1997                &format!(
1998                    "cinrs: {what} is {} bytes in the data model this unit was translated for, \
1999                     and is not on this target. {chosen}",
2000                    bits.div_ceil(8)
2001                ),
2002                span,
2003            );
2004            body.extend(quote_spanned! {span=>
2005                assert!(::core::mem::size_of::<#ty>() == #bytes, #message);
2006            });
2007        };
2008        width(
2009            quote_spanned! {span=> ::core::ffi::c_short },
2010            target.short_bits,
2011            "'short'",
2012        );
2013        width(
2014            quote_spanned! {span=> ::core::ffi::c_int },
2015            target.int_bits,
2016            "'int'",
2017        );
2018        width(
2019            quote_spanned! {span=> ::core::ffi::c_long },
2020            target.long_bits,
2021            "'long'",
2022        );
2023        width(
2024            quote_spanned! {span=> ::core::ffi::c_longlong },
2025            target.long_long_bits,
2026            "'long long'",
2027        );
2028        width(
2029            quote_spanned! {span=> *const ::core::ffi::c_void },
2030            target.ptr_bits,
2031            "a pointer",
2032        );
2033        // Plain `char`'s signedness decides what `'\xff'` is worth and how a
2034        // `char` widens, so it is an assumption like any other. `c_char` is an
2035        // alias for `i8` or `u8`, and only the unsigned one has a zero minimum.
2036        let (test, said) = if target.char_signed {
2037            (
2038                quote_spanned! {span=> ::core::ffi::c_char::MIN != 0 },
2039                "signed",
2040            )
2041        } else {
2042            (
2043                quote_spanned! {span=> ::core::ffi::c_char::MIN == 0 },
2044                "unsigned",
2045            )
2046        };
2047        let message = message_literal(
2048            &format!(
2049                "cinrs: plain 'char' is {said} in the data model this unit was translated \
2050                 for, and is not on this target. {chosen}"
2051            ),
2052            span,
2053        );
2054        body.extend(quote_spanned! {span=> assert!(#test, #message); });
2055        // The one property two targets of the same *data model* differ on: the
2056        // i386 System V ABI aligns `long long` and `double` to four bytes and
2057        // the Microsoft one to eight, and every member offset the front end
2058        // computed followed whichever this model says. `c_longlong` and
2059        // `c_double` are the aliases, so the assertion follows the target.
2060        let align = usize_literal(target.max_scalar_align.min(8), span);
2061        let message = message_literal(
2062            &format!(
2063                "cinrs: 'long long' and 'double' are {}-byte aligned in the data model this \
2064                 unit was translated for, and are not on this target — so every 'sizeof' and \
2065                 member offset in it would be wrong. {chosen}",
2066                target.max_scalar_align.min(8)
2067            ),
2068            span,
2069        );
2070        body.extend(quote_spanned! {span=>
2071            assert!(
2072                ::core::mem::align_of::<::core::ffi::c_longlong>() == #align
2073                    && ::core::mem::align_of::<::core::ffi::c_double>() == #align,
2074                #message
2075            );
2076        });
2077        if self.uses_int128.get() {
2078            let align = usize_literal(target.int128_align, span);
2079            let message = message_literal(
2080                &format!(
2081                    "cinrs: '__int128' is {}-byte aligned in the data model this unit was \
2082                     translated for, and is not on this target. {chosen}",
2083                    target.int128_align
2084                ),
2085                span,
2086            );
2087            let i128 = primitive_ty("i128", span);
2088            body.extend(quote_spanned! {span=>
2089                assert!(::core::mem::align_of::<#i128>() == #align, #message);
2090            });
2091        }
2092        if self.uses_complex.get() {
2093            // A complex type *is* two of its component type side by side —
2094            // that is the whole reason the runtime uses a `#[repr(C)]` pair —
2095            // and every `sizeof`, member offset and array stride in the unit
2096            // was computed from that. A `Complex<f64>` that is not sixteen
2097            // bytes would make all of them wrong, so the unit says so.
2098            for (ty, name) in [
2099                (Ty::ComplexFloat, "'float _Complex'"),
2100                (Ty::ComplexDouble, "'double _Complex'"),
2101            ] {
2102                let layout = self
2103                    .program
2104                    .types
2105                    .size_align(ty, target)
2106                    .expect("a complex type has a layout");
2107                let rust = self.ty(ty, span);
2108                let size = usize_literal(layout.size, span);
2109                let align = usize_literal(layout.align, span);
2110                let message = message_literal(
2111                    &format!(
2112                        "cinrs: {name} is {} bytes and {}-byte aligned in the data model this \
2113                         unit was translated for, and is not on this target. {chosen}",
2114                        layout.size, layout.align
2115                    ),
2116                    span,
2117                );
2118                body.extend(quote_spanned! {span=>
2119                    assert!(
2120                        ::core::mem::size_of::<#rust>() == #size
2121                            && ::core::mem::align_of::<#rust>() == #align,
2122                        #message
2123                    );
2124                });
2125            }
2126        }
2127        let block = braced(body, span);
2128        quote_spanned! {span=> const _: () = #block; }
2129    }
2130
2131    /// The `extern` block declaring everything the unit does not define, with
2132    /// the libraries the unit links beside it — one empty block each, never an
2133    /// attribute on this one; [`Codegen::link_blocks`] is why.
2134    ///
2135    /// A **function** is declared under its own C name — `pub fn crc32`, not a
2136    /// hidden one — so that the glob re-export carries it out of the unit's
2137    /// module and `#include <zlib.h>` is all Rust needs to call it. An
2138    /// **object** is not, because a glob-imported `static` changes what a `let`
2139    /// of the same name means; [`Program::extern_object_name`] is that rule and
2140    /// its reason.
2141    fn extern_block(&mut self) -> TokenStream {
2142        if !self.program.has_externs() {
2143            return TokenStream::new();
2144        }
2145        let span = self.map.span(SourceRange::at(0));
2146        let mut items = TokenStream::new();
2147        // The symbols this block links by, which is what decides whether it
2148        // needs a library of its own; see [`LEGACY_STDIO`]. Collected here
2149        // rather than asked of the program a second time, so that what the
2150        // attribute answers for and what the block declares cannot drift apart.
2151        let mut symbols: Vec<&str> = Vec::new();
2152        for id in &self.program.externs {
2153            let object = self.program.object(*id);
2154            let Storage::Extern { item_name } = &object.storage else {
2155                continue;
2156            };
2157            let ospan = self.sp(object.range);
2158            let rust_name = self.extern_object_ident(item_name, ospan);
2159            let ty = self.ty(object.ty, ospan);
2160            // An `__asm__("symbol")` label renames the declaration, which is
2161            // exactly what `#[link_name]` already says.
2162            let symbol = object.asm_label.as_deref().unwrap_or(item_name);
2163            symbols.push(symbol);
2164            let link = link_name(symbol, ospan);
2165            items.extend(quote_spanned! {ospan=> #link pub static mut #rust_name: #ty; });
2166        }
2167        for func in &self.program.functions {
2168            if !func.is_extern() {
2169                continue;
2170            }
2171            // An [x86 intrinsic](crate::x86) has no symbol: a call to it is
2172            // generated as `::core::arch::x86_64::<name>`, and declaring one
2173            // here would put a `pub fn _mm_add_ps` into the unit's module —
2174            // which the facade glob re-exports, so it would clash with a
2175            // `use core::arch::x86_64::*` in the user's own code and link
2176            // against nothing if it were ever called. The bundled
2177            // `<immintrin.h>` declares eight hundred of them; **none** of
2178            // them reaches the generated Rust.
2179            if func.intrinsic.is_some() {
2180                continue;
2181            }
2182            let fspan = self.sp(func.range);
2183            // The C name, through the same mapping every other name goes
2184            // through: a keyword becomes `r#yield`, `a$b` becomes
2185            // `a_dollar_b`, and [`Names`] has already made it unique within
2186            // the unit. It is what a call in this unit names too; see
2187            // [`Codegen::function_path`].
2188            let rust_name = self.c_ident(func.item_name(), fspan);
2189            let params = self.extern_params(func, fspan);
2190            let ret = if func.sig.ret.is_void() {
2191                TokenStream::new()
2192            } else {
2193                let ty = self.ty(func.sig.ret, fspan);
2194                quote_spanned! {fspan=> -> #ty }
2195            };
2196            // An `__asm__("symbol")` label is the program's own answer and wins;
2197            // failing that, a name the Microsoft library exports differently is
2198            // linked by the name it really has. See [`MSVC_RENAMED`].
2199            let symbol = match func.asm_label.as_deref() {
2200                Some(label) => label,
2201                None => self.msvc_symbol(&func.name),
2202            };
2203            symbols.push(symbol);
2204            let link = link_name(symbol, fspan);
2205            items.extend(quote_spanned! {fspan=> #link pub fn #rust_name(#params) #ret; });
2206        }
2207        let links = self.link_blocks(&symbols, span);
2208        quote_spanned! {span=> #links unsafe extern "C" { #items } }
2209    }
2210
2211    /// The libraries this unit links: one `#[link(name = "…")] unsafe extern "C"
2212    /// {}` — the ordinary Rust idiom for "also link this" — for every
2213    /// `#pragma cinrs link` the unit wrote, and for the library an MSVC target
2214    /// needs to resolve the `printf` family.
2215    ///
2216    /// Nothing here is needed for the C library itself, which the Rust runtime
2217    /// already links; the pragma is for the program that calls into something
2218    /// else, and [`LEGACY_STDIO`] is the one library cinrs asks for on its own
2219    /// initiative. `symbols` is what the declarations in the block next to these
2220    /// link by, which is what decides the second of those.
2221    ///
2222    /// A library named by both — `#pragma cinrs link "legacy_stdio_definitions"`
2223    /// written out by hand — is emitted once.
2224    ///
2225    /// # Why an empty block of its own, and not an attribute on the declarations
2226    ///
2227    /// Because `#[link(name = "…")]` says two things, and cinrs means only the
2228    /// first. It puts the library on the link line, and it also makes `rustc`
2229    /// reach every `static` declared *in that very block* through a `dllimport`
2230    /// on a Windows target — `native_library` is asked per foreign item, so a
2231    /// sibling block is untouched. A `dllimport` is right for an object that
2232    /// lives in another image and silently wrong for one that lives in this one:
2233    /// with the attribute on the declarations, a unit that declared
2234    /// `extern int counter;` while another exported unit of the same crate
2235    /// defined it read rubbish — 7887437 for 17, measured on Windows — and
2236    /// `lld-link` said `LNK4217: locally defined symbol imported`.
2237    ///
2238    /// For the `printf` rule that was cinrs's own doing: a unit that includes
2239    /// `<stdio.h>` never asked for a library. The pragma is the program's own
2240    /// statement, but it is no better placed to decide, because in C adding a
2241    /// `.lib` to a link line implies `__declspec(dllimport)` on nothing, and
2242    /// cinrs has no way to write that per declaration. So no generated
2243    /// declaration is a `dllimport`, which is C's own default, and a program that
2244    /// wants a DLL's *data* export — the one case the import library exposes as
2245    /// `__imp_name` alone — names that pointer itself:
2246    ///
2247    /// ```c
2248    /// #pragma cinrs link "gdi32"
2249    /// extern unsigned long *batch_limit __asm__("__imp_GdiBatchLimit");
2250    /// ```
2251    ///
2252    /// That reads the DLL's value; the same symbol declared as a plain object is
2253    /// `lld-link: error: undefined symbol: GdiBatchLimit` — loud, at link time,
2254    /// rather than a wrong value. With the attribute on the declarations even the
2255    /// pointer was out of reach: `rustc` asked for its `__imp_` in turn, and
2256    /// `lld-link` said `undefined symbol: __declspec(dllimport)
2257    /// __imp_GdiBatchLimit`. Every sentence here was measured on
2258    /// `x86_64-pc-windows-msvc`; `doc/cross-compilation.md` keeps the numbers and
2259    /// `tests/declared_names.rs` the cases.
2260    fn link_blocks(&self, symbols: &[&str], span: Span) -> TokenStream {
2261        let mut libraries: Vec<&str> = Vec::new();
2262        for name in &self.program.link_libraries {
2263            if !libraries.contains(&name.as_str()) {
2264                libraries.push(name);
2265            }
2266        }
2267        for library in self.legacy_stdio_libraries(symbols) {
2268            if !libraries.contains(&library) {
2269                libraries.push(library);
2270            }
2271        }
2272        let mut out = TokenStream::new();
2273        for name in libraries {
2274            let mut literal = Literal::string(name);
2275            literal.set_span(span);
2276            out.extend(quote_spanned! {span=> #[link(name = #literal)] unsafe extern "C" {} });
2277        }
2278        out
2279    }
2280
2281    /// The symbol a **declaration** of the C function `name` links by: the name
2282    /// itself, or, on an MSVC target, what the Microsoft C runtime exports it
2283    /// as. See [`MSVC_RENAMED`] for the table and for how each row was read out
2284    /// of a real import library.
2285    ///
2286    /// Only a declaration: a function this unit *defines* is its own symbol, and
2287    /// a C program that defines `time` has defined `time`.
2288    fn msvc_symbol<'name>(&self, name: &'name str) -> &'name str {
2289        if !self.options.target.is_msvc() {
2290            return name;
2291        }
2292        for (c_name, symbol) in MSVC_RENAMED {
2293            if *c_name == name {
2294                return symbol;
2295            }
2296        }
2297        name
2298    }
2299
2300    /// The libraries the `printf` and `scanf` declarations among `symbols` have
2301    /// to be linked against, in the order [`LEGACY_STDIO`] lists them.
2302    ///
2303    /// Empty on every target but an MSVC one: everywhere else the platform's
2304    /// library exports those functions as ordinary symbols and there is nothing
2305    /// to ask for. See [`LEGACY_STDIO`] for why the Microsoft library differs.
2306    fn legacy_stdio_libraries(&self, symbols: &[&str]) -> Vec<&'static str> {
2307        if !self.options.target.is_msvc() {
2308            return Vec::new();
2309        }
2310        let mut out: Vec<&'static str> = Vec::new();
2311        for (symbol, library) in LEGACY_STDIO {
2312            if symbols.contains(symbol) && !out.contains(library) {
2313                out.push(library);
2314            }
2315        }
2316        out
2317    }
2318
2319    fn extern_params(&self, func: &Function, span: Span) -> TokenStream {
2320        let mut params = TokenStream::new();
2321        for (index, ty) in func.sig.params.iter().enumerate() {
2322            if index > 0 {
2323                params.extend(quote_spanned! {span=> , });
2324            }
2325            let ty = self.ty(*ty, span);
2326            match func.param_names.get(index).and_then(|n| n.as_ref()) {
2327                Some(name) => {
2328                    let name = self.c_ident(name, span);
2329                    params.extend(quote_spanned! {span=> #name: #ty });
2330                }
2331                None => params.extend(quote_spanned! {span=> _: #ty }),
2332            }
2333        }
2334        if func.sig.variadic {
2335            if !func.sig.params.is_empty() {
2336                params.extend(quote_spanned! {span=> , });
2337            }
2338            params.extend(quote_spanned! {span=> ... });
2339        }
2340        params
2341    }
2342
2343    fn static_item(&mut self, var: &ir::StaticVar) -> TokenStream {
2344        let object = self.program.object(var.object);
2345        let span = self.sp(object.range);
2346        if object.storage.is_thread_local() {
2347            return self.thread_local_item(var);
2348        }
2349        let Storage::Static {
2350            item_name,
2351            exported,
2352        } = &object.storage
2353        else {
2354            return TokenStream::new();
2355        };
2356        let name = self.c_ident(item_name, span);
2357        let ty = self.binding_ty(var.object, self.storage_ty(var.object, span), span);
2358        let init = self.static_init(&var.init, object.ty, span);
2359        let init = self.binding_init(var.object, init, span);
2360        let (vis, export) = if *exported {
2361            let export = if self.program.export {
2362                let symbol = object.asm_label.as_deref().unwrap_or(&object.name);
2363                export_attr(symbol, &name, span)
2364            } else {
2365                TokenStream::new()
2366            };
2367            (quote_spanned! {span=> pub }, export)
2368        } else {
2369            (TokenStream::new(), TokenStream::new())
2370        };
2371        let section = match &object.section {
2372            Some(section) => {
2373                let mut literal = Literal::string(section);
2374                literal.set_span(span);
2375                quote_spanned! {span=> #[unsafe(link_section = #literal)] }
2376            }
2377            None => TokenStream::new(),
2378        };
2379        // `static mut` rather than a cell: C code assigns to globals from
2380        // anywhere, and reading or writing one directly (never taking a
2381        // reference) is what keeps edition 2024's `static_mut_refs` quiet.
2382        quote_spanned! {span=>
2383            #export
2384            #section
2385            #vis static mut #name: #ty = #init;
2386        }
2387    }
2388
2389    /// `std::thread_local! { static X: UnsafeCell<T> = const { … }; }` — the
2390    /// item a `_Thread_local` object becomes.
2391    ///
2392    /// C's thread-local object has static storage duration and one instance
2393    /// per thread, and `thread_local!` is exactly that. The cell is what makes
2394    /// the object *mutable*: `with` hands out a `&UnsafeCell<T>`, and the
2395    /// `*mut T` inside it is valid for as long as the thread's copy is, which
2396    /// is the lifetime C promises the address of such an object.
2397    ///
2398    /// The initialiser goes inside a `const` block wherever it can — that is
2399    /// the form with no lazy-initialisation flag and no destructor to register
2400    /// — and directly otherwise. Only one thing keeps it out: an initialiser
2401    /// that mentions the address of another item, which a `const` may not
2402    /// refer to (`E0013`).
2403    fn thread_local_item(&mut self, var: &ir::StaticVar) -> TokenStream {
2404        let object = self.program.object(var.object);
2405        let span = self.sp(object.range);
2406        let Storage::ThreadLocal {
2407            item_name,
2408            exported,
2409        } = &object.storage
2410        else {
2411            return TokenStream::new();
2412        };
2413        if self.program.no_std {
2414            // `sema::check_pragmas` has already said that a thread-local object
2415            // needs `std`; emitting `::std::thread_local!` anyway would add
2416            // `rustc`'s own "cannot find `std`" on top of it.
2417            return TokenStream::new();
2418        }
2419        let name = self.c_ident(item_name, span);
2420        let ty = self.binding_ty(var.object, self.storage_ty(var.object, span), span);
2421        let init = self.static_init(&var.init, object.ty, span);
2422        let init = self.binding_init(var.object, init, span);
2423        let vis = if *exported {
2424            quote_spanned! {span=> pub }
2425        } else {
2426            TokenStream::new()
2427        };
2428        let cell = quote_spanned! {span=> ::core::cell::UnsafeCell<#ty> };
2429        let value = quote_spanned! {span=> ::core::cell::UnsafeCell::new(#init) };
2430        let value = if self.const_initialisable(&var.init) {
2431            quote_spanned! {span=> const { #value } }
2432        } else {
2433            value
2434        };
2435        // The lint exemptions are the unit module's own (see
2436        // [`crate::in_module`]), and a `thread_local!` is expanded inside it
2437        // like anything else, so the `static` it generates inherits them.
2438        quote_spanned! {span=>
2439            ::std::thread_local! {
2440                #vis static #name: #cell = #value;
2441            }
2442        }
2443    }
2444
2445    /// Whether an initialiser may go inside a `const { … }` block.
2446    ///
2447    /// A Rust constant may not refer to a `static` (`E0013`), which rules out
2448    /// exactly the initialisers whose value is the address of another item: a
2449    /// pointer to a file-scope object, a function pointer, and the `static`
2450    /// that holds the characters of a wide string literal. A *narrow* literal
2451    /// is a byte string whose `as_ptr` is const, and every arithmetic constant
2452    /// is fine.
2453    ///
2454    /// This is what decides between `thread_local!`'s two forms; see
2455    /// [`Codegen::thread_local_item`].
2456    fn const_initialisable(&self, expr: &Expr) -> bool {
2457        match &expr.kind {
2458            ExprKind::FuncAddr(_) => false,
2459            ExprKind::AddrOf(place) | ExprKind::Load(place) => match &place.kind {
2460                PlaceKind::Str(id) => {
2461                    let elem = self.program.string(*id).elem;
2462                    elem.size_bytes(&self.options.target) == 1
2463                }
2464                _ => !rooted_in_static(place, self.program),
2465            },
2466            ExprKind::Cast(inner) => self.const_initialisable(inner),
2467            ExprKind::PtrOffset { ptr, .. } => self.const_initialisable(ptr),
2468            ExprKind::RecordLit { fields, .. } => {
2469                fields.iter().all(|f| self.const_initialisable(f))
2470            }
2471            ExprKind::UnionLit { value, .. } => self.const_initialisable(value),
2472            ExprKind::ArrayLit(items) => items.iter().all(|i| self.const_initialisable(i)),
2473            ExprKind::ArrayRepeat { value, .. } => self.const_initialisable(value),
2474            _ => true,
2475        }
2476    }
2477
2478    /// The initialiser of a `static mut`, wrapped in `unsafe` when it needs to
2479    /// be (`mem::zeroed`, or the address of another `static mut`).
2480    fn static_init(&mut self, expr: &Expr, ty: Ty, span: Span) -> TokenStream {
2481        let tokens = self.expr_at(expr, ty);
2482        if needs_unsafe(&self.program.types, expr) {
2483            let block = braced(tokens, span);
2484            return quote_spanned! {span=> unsafe #block };
2485        }
2486        tokens
2487    }
2488
2489    fn signature(&mut self, func: &Function) -> TokenStream {
2490        let span = self.sp(func.range);
2491        let name = self.c_ident(func.item_name(), span);
2492        let mut params = TokenStream::new();
2493        // A lifted nested function takes the objects it uses from the
2494        // enclosing frame as pointers, in front of everything the program
2495        // wrote; see [`ir::EnvParam`].
2496        for entry in &func.env {
2497            let object = self.program.object(entry.param);
2498            let pspan = self.sp(object.range);
2499            let pname = self.object_ident(entry.param, pspan);
2500            let pty = self.ty(object.ty, pspan);
2501            params.extend(quote_spanned! {pspan=> #pname: #pty , });
2502        }
2503        // A definition whose parameters did not check out may have fewer than
2504        // the signature says; either way the list still has to have the right
2505        // shape, so it falls back to names of our own.
2506        let named = func.params.len() == func.sig.params.len();
2507        for (index, ty) in func.sig.params.iter().enumerate() {
2508            if index > 0 {
2509                params.extend(quote_spanned! {span=> , });
2510            }
2511            if named {
2512                let id = func.params[index];
2513                let object = self.program.object(id);
2514                let pspan = self.sp(object.range);
2515                let pname = self.object_ident(id, pspan);
2516                let pty = self.ty(*ty, pspan);
2517                params.extend(quote_spanned! {pspan=> mut #pname: #pty });
2518            } else {
2519                let pname = Ident::new(&format!("__cinrs_arg{index}"), Span::mixed_site());
2520                let pty = self.ty(*ty, span);
2521                params.extend(quote_spanned! {span=> #pname: #pty });
2522            }
2523        }
2524        if func.sig.variadic {
2525            if !func.sig.params.is_empty() {
2526                params.extend(quote_spanned! {span=> , });
2527            }
2528            // The variable part of the argument list arrives as one more
2529            // parameter. It is never advanced: `va_start` and every `va_list`
2530            // local copy it, so it stays the list as the caller left it.
2531            let name = self.va_ident();
2532            params.extend(quote_spanned! {span=> #name: ... });
2533        }
2534        let ret = if func.sig.ret.is_void() {
2535            TokenStream::new()
2536        } else {
2537            let ty = self.ty(func.sig.ret, span);
2538            quote_spanned! {span=> -> #ty }
2539        };
2540        // A definition is a Rust item rather than a C symbol unless the unit
2541        // asked for real symbols, so an `__asm__("name")` label on one only
2542        // means something there — and there it names the symbol the item
2543        // takes, which is what `#[unsafe(export_name)]` says. On a *declaration*
2544        // the label is always honoured, through the `extern` block's
2545        // `#[link_name]`.
2546        let exported = !func.is_static && self.program.export;
2547        let vis = if func.is_static {
2548            TokenStream::new()
2549        } else {
2550            quote_spanned! {span=> pub }
2551        };
2552        let export = if exported {
2553            let symbol = func.asm_label.as_deref().unwrap_or(&func.name);
2554            export_attr(symbol, &name, span)
2555        } else {
2556            TokenStream::new()
2557        };
2558        // `#[inline]` is ignored on an exported function, and saying so is
2559        // `rustc`'s job rather than the user's to read: leave it out.
2560        //
2561        // `always_inline` on a function with a target feature — from
2562        // `__attribute__((target))` or `#pragma GCC target`, both of which
2563        // are in `target_features` — is `#[inline]`: rustc refuses
2564        // `#[inline(always)]` together with `#[target_feature]` ("cannot use
2565        // `#[inline(always)]` with `#[target_feature]`", rust-lang/rust#145574),
2566        // and BLAKE3's SIMD files are exactly that pairing, an `INLINE` macro
2567        // of `static inline __attribute__((always_inline))` under `#pragma GCC
2568        // target("sse4.1")`. The hint is then only a hint, and LLVM does not
2569        // always take it — so where it can, the helper drops the
2570        // `#[target_feature]` instead and keeps `#[inline(always)]`; see
2571        // [`Function::inline_helper`] for when, and why that is sound.
2572        let helper = func.inline_helper();
2573        let inline = match func.inline_hint {
2574            Some(_) if exported => TokenStream::new(),
2575            _ if helper => quote_spanned! {span=> #[inline(always)] },
2576            Some(ir::InlineHint::Always) if !func.target_features.is_empty() => {
2577                quote_spanned! {span=> #[inline] }
2578            }
2579            Some(ir::InlineHint::Always) => quote_spanned! {span=> #[inline(always)] },
2580            Some(ir::InlineHint::Never) => quote_spanned! {span=> #[inline(never)] },
2581            None if func.is_inline && !exported => quote_spanned! {span=> #[inline] },
2582            None => TokenStream::new(),
2583        };
2584        let cold = if func.cold {
2585            quote_spanned! {span=> #[cold] }
2586        } else {
2587            TokenStream::new()
2588        };
2589        let deprecated = match &func.deprecated {
2590            Some(Some(message)) => {
2591                let mut literal = Literal::string(message);
2592                literal.set_span(span);
2593                quote_spanned! {span=> #[deprecated(note = #literal)] }
2594            }
2595            Some(None) => quote_spanned! {span=> #[deprecated] },
2596            None => TokenStream::new(),
2597        };
2598        let section = match &func.section {
2599            Some(section) => {
2600                let mut literal = Literal::string(section);
2601                literal.set_span(span);
2602                quote_spanned! {span=> #[unsafe(link_section = #literal)] }
2603            }
2604            None => TokenStream::new(),
2605        };
2606        // `__attribute__((target("avx2")))`, which is the same promise
2607        // `#[target_feature(enable = "avx2")]` makes: the body may use that
2608        // instruction set, and a caller has to have checked that the
2609        // processor has it — with `__builtin_cpu_supports`, as in C.
2610        let target_feature = if helper {
2611            TokenStream::new()
2612        } else {
2613            self.target_feature_attrs(func, span)
2614        };
2615        // Everything is `extern "C"`, so that its address is a C function
2616        // pointer, except that helper, whose address nothing takes and which
2617        // could not pass a vector through the C ABI without the feature.
2618        let abi = if helper {
2619            TokenStream::new()
2620        } else {
2621            quote_spanned! {span=> extern "C" }
2622        };
2623        // A function the unit asked to be safe is generated without `unsafe`,
2624        // and its body without the `unsafe` block, so that `rustc` checks every
2625        // operation in it; see [`crate::sema::check_safe`] for what that
2626        // catches and what it refuses outright.
2627        let unsafety = if func.is_safe() {
2628            TokenStream::new()
2629        } else {
2630            quote_spanned! {span=> unsafe }
2631        };
2632        quote_spanned! {span=>
2633            #export
2634            #inline
2635            #cold
2636            #deprecated
2637            #section
2638            #target_feature
2639            #vis #unsafety #abi fn #name(#params) #ret
2640        }
2641    }
2642
2643    /// One `#[target_feature(enable = "…")]` per instruction set the function
2644    /// asked for.
2645    ///
2646    /// One attribute per name rather than one attribute with several `enable`s
2647    /// — both are legal, and this reads as the list of `-m` switches it came
2648    /// from.
2649    fn target_feature_attrs(&self, func: &Function, span: Span) -> TokenStream {
2650        let mut out = TokenStream::new();
2651        for feature in &func.target_features {
2652            let mut literal = Literal::string(feature);
2653            literal.set_span(span);
2654            out.extend(quote_spanned! {span=> #[target_feature(enable = #literal)] });
2655        }
2656        out
2657    }
2658
2659    /// The `static` that puts a `constructor` or `destructor` function into the
2660    /// table the runtime walks before `main` (or after it).
2661    ///
2662    /// ELF has `.init_array` and `.fini_array`, and Mach-O has
2663    /// `__DATA,__mod_init_func` and `__mod_term_func`; nothing else this crate
2664    /// can name has such a table, so a program that asks for one elsewhere is
2665    /// told so rather than quietly built without it.
2666    fn init_array_item(&mut self, func: &Function, kind: ir::InitKind) -> TokenStream {
2667        let span = self.sp(func.range);
2668        let name = self.c_ident(func.item_name(), span);
2669        let signature = self.function_pointer_ty(func, span);
2670        let item = Ident::new(
2671            &format!(
2672                "__CINRS_INIT_{:08x}_{}",
2673                self.program.unit_id as u32,
2674                func.item_name()
2675            ),
2676            span,
2677        );
2678        let elf = match kind {
2679            ir::InitKind::Constructor => ".init_array",
2680            ir::InitKind::Destructor => ".fini_array",
2681        };
2682        let apple = match kind {
2683            ir::InitKind::Constructor => "__DATA,__mod_init_func",
2684            ir::InitKind::Destructor => "__DATA,__mod_term_func",
2685        };
2686        let mut elf_literal = Literal::string(elf);
2687        elf_literal.set_span(span);
2688        let mut apple_literal = Literal::string(apple);
2689        apple_literal.set_span(span);
2690        // The section name is the one thing about this that is not portable,
2691        // so it is chosen at compile time rather than assumed.
2692        quote_spanned! {span=>
2693            #[used]
2694            #[cfg_attr(target_vendor = "apple", unsafe(link_section = #apple_literal))]
2695            #[cfg_attr(not(target_vendor = "apple"), unsafe(link_section = #elf_literal))]
2696            static #item: #signature = #name;
2697        }
2698    }
2699
2700    /// The one check a unit with a `constructor` or a `destructor` carries.
2701    ///
2702    /// A procedural macro is compiled for the *host*, so it cannot know which
2703    /// target the code it generates is for; the check therefore has to be part
2704    /// of the expansion. It is emitted once per unit rather than once per
2705    /// function, since it says the same thing either way.
2706    fn init_array_guard(&self) -> TokenStream {
2707        let span = self.map.span(SourceRange::at(0));
2708        quote_spanned! {span=>
2709            const _: () = {
2710                #[cfg(not(any(target_os = "linux", target_os = "android",
2711                              target_os = "freebsd", target_os = "netbsd",
2712                              target_os = "openbsd", target_os = "dragonfly",
2713                              target_vendor = "apple")))]
2714                ::core::compile_error!(
2715                    "'constructor' and 'destructor' need a target whose runtime walks an initialiser table (ELF or Mach-O)"
2716                );
2717            };
2718        }
2719    }
2720
2721    fn function_item(&mut self, func: &Function) -> TokenStream {
2722        let span = self.sp(func.range);
2723        let Some(body) = &func.body else {
2724            return TokenStream::new();
2725        };
2726        self.enter_function(func);
2727        let signature = self.signature(func);
2728        let body = match body {
2729            Body::Structured(stmts) => self.stmts(stmts),
2730            Body::Cfg(cfg) => self.cfg_body(cfg, span),
2731        };
2732        // `alloca`'s memory belongs to the function, not to the block the call
2733        // was written in, so the arena is opened here and dropped by whichever
2734        // `return` runs; a variable length array only borrows space from it
2735        // until its block ends.
2736        let arena = if func.uses_arena {
2737            self.uses_arena.set(true);
2738            let name = self.arena_ident(span);
2739            let ty = arena_ty();
2740            quote_spanned! {span=> let #name = #ty::new(); }
2741        } else {
2742            TokenStream::new()
2743        };
2744        // One `unsafe` block around the whole body: in edition 2024 the body of
2745        // an `unsafe fn` is not itself an unsafe block any more. A safe
2746        // function is exactly the one that does not get it — that block is what
2747        // would stop `rustc` checking the translation.
2748        if func.is_safe() {
2749            return quote_spanned! {span=>
2750                #signature { #arena #body }
2751            };
2752        }
2753        quote_spanned! {span=>
2754            #signature {
2755                unsafe { #arena #body }
2756            }
2757        }
2758    }
2759
2760    /// The name of the bump arena a function that declares a variable length
2761    /// array or calls `alloca` opens with, in this crate's own hygiene, for a
2762    /// use of it written at `span`.
2763    fn arena_ident(&self, span: Span) -> Ident {
2764        if self.arena_span.get().is_none() {
2765            self.arena_span.set(Some(span));
2766        }
2767        Ident::new("__cinrs_vla", Span::mixed_site())
2768    }
2769
2770    /// The bump arena's type and its frame guard: one pair of private items
2771    /// per unit that has a variable length array or an `alloca` anywhere.
2772    ///
2773    /// C gives both kinds of object automatic storage — a compiler bumps the
2774    /// stack pointer — and the emulation is the same idea on the heap, per
2775    /// function call:
2776    ///
2777    /// * the storage is a list of chunks that never move, each a `Vec<u128>`
2778    ///   so that its base is 16-byte aligned, and the position is a chunk
2779    ///   index and a byte offset in it. No chunk is allocated until the first
2780    ///   allocation, and the arena, dropped by the `return`, frees them all;
2781    /// * `alloc` pads the position up to the alignment — by address, so that
2782    ///   `aligned(64)` works in a 16-byte-aligned chunk — bumps it, and zeroes
2783    ///   what it hands out: C leaves the array indeterminate, but reading
2784    ///   uninitialised bytes through a raw pointer is undefined in Rust as
2785    ///   well, and zeroed memory is what the translation always gave. Only
2786    ///   when the current chunk is full does it go to the next one, reusing it
2787    ///   if it is big enough and otherwise dropping every chunk after the
2788    ///   current one — nothing above the position is live — for a new one of
2789    ///   at least twice the size;
2790    /// * a variable length array's lifetime is a frame: the position before it
2791    ///   was allocated, which the frame's `Drop` at the end of the block moves
2792    ///   the arena back down to. The position never goes below `floor`, which
2793    ///   `alloca` raises past each allocation it makes: its memory lives until
2794    ///   the function returns, even out of a block whose array is given back —
2795    ///   GCC's own rule;
2796    /// * a [CFG-mode](crate::cfg) function has no blocks to drop frames at, so
2797    ///   it keeps one mark per variable length array in an array, and
2798    ///   `redefine` moves the arena back down to a declaration's previous mark
2799    ///   when the declaration is reached again, forgetting every mark taken
2800    ///   after it: those arrays were declared later on the path that got here,
2801    ///   so jumping back over this declaration ended their lifetimes too.
2802    ///
2803    /// Everything is in [`Cell`]s so that any number of frames can hold a
2804    /// shared borrow of the arena at once. The methods are safe: the only
2805    /// memory they touch is the arena's own.
2806    fn arena_items(&self, span: Span) -> TokenStream {
2807        let arena = arena_ty();
2808        let frame = Ident::new("__cinrs_vla_frame", Span::mixed_site());
2809        let t = Ident::new("T", Span::mixed_site());
2810        let usize_ty = primitive_ty("usize", span);
2811        let u128_ty = primitive_ty("u128", span);
2812        let u8_ty = primitive_ty("u8", span);
2813        let chunk_ty = self.vec_ty(u128_ty.clone(), span);
2814        let chunks_ty = self.vec_ty(chunk_ty, span);
2815        let empty = self.vec_new(span);
2816        let new_chunk = self.vec_of(
2817            quote_spanned! {span=> 0 },
2818            quote_spanned! {span=> size.div_ceil(::core::mem::size_of::<#u128_ty>()) },
2819            span,
2820        );
2821        let void = self.pointee_ty(Ty::Void, span);
2822        quote_spanned! {span=>
2823            #[allow(
2824                unknown_lints,
2825                elided_lifetimes_in_paths,
2826                missing_debug_implementations,
2827                single_use_lifetimes,
2828                unused_qualifications,
2829                clippy::pedantic,
2830                clippy::nursery
2831            )]
2832            struct #arena {
2833                chunks: ::core::cell::UnsafeCell<#chunks_ty>,
2834                cur: ::core::cell::Cell<#usize_ty>,
2835                top: ::core::cell::Cell<#usize_ty>,
2836                floor: ::core::cell::Cell<(#usize_ty, #usize_ty)>,
2837            }
2838            #[allow(
2839                unknown_lints,
2840                elided_lifetimes_in_paths,
2841                single_use_lifetimes,
2842                unused_qualifications,
2843                clippy::pedantic,
2844                clippy::nursery
2845            )]
2846            impl #arena {
2847                #[inline(always)]
2848                fn new() -> Self {
2849                    Self {
2850                        chunks: ::core::cell::UnsafeCell::new(#empty),
2851                        cur: ::core::cell::Cell::new(0),
2852                        top: ::core::cell::Cell::new(0),
2853                        floor: ::core::cell::Cell::new((0, 0)),
2854                    }
2855                }
2856                #[inline(always)]
2857                fn mark(&self) -> (#usize_ty, #usize_ty) {
2858                    (self.cur.get(), self.top.get())
2859                }
2860                #[inline(always)]
2861                fn frame(&self) -> #frame<'_> {
2862                    #frame(self, self.mark())
2863                }
2864                /// Moves the position back down to `mark`, but never below
2865                /// `floor` and never up.
2866                #[inline(always)]
2867                fn release(&self, mark: (#usize_ty, #usize_ty)) {
2868                    let floor = self.floor.get();
2869                    let to = if mark > floor { mark } else { floor };
2870                    if to < self.mark() {
2871                        self.cur.set(to.0);
2872                        self.top.set(to.1);
2873                    }
2874                }
2875                #[inline(always)]
2876                fn bytes(&self, bytes: #usize_ty, align: #usize_ty) -> *mut #u8_ty {
2877                    // SAFETY: nothing else borrows the list of chunks while
2878                    // this runs, and the memory written is inside a chunk.
2879                    unsafe {
2880                        let chunks = &mut *self.chunks.get();
2881                        let top = self.top.get();
2882                        if let ::core::option::Option::Some(chunk) = chunks.get_mut(self.cur.get()) {
2883                            let base = chunk.as_mut_ptr().cast::<#u8_ty>();
2884                            let size = chunk.len() * ::core::mem::size_of::<#u128_ty>();
2885                            let start = top + (base.addr().wrapping_add(top).wrapping_neg() & (align - 1));
2886                            if start <= size && bytes <= size - start {
2887                                self.top.set(start + bytes);
2888                                let first = base.add(start);
2889                                ::core::ptr::write_bytes(first, 0, bytes);
2890                                return first;
2891                            }
2892                        }
2893                    }
2894                    self.grow(bytes, align)
2895                }
2896                #[cold]
2897                #[inline(never)]
2898                fn grow(&self, bytes: #usize_ty, align: #usize_ty) -> *mut #u8_ty {
2899                    let need = bytes
2900                        .checked_add(align)
2901                        .expect("a variable length array or alloca is larger than the address space");
2902                    {
2903                        // SAFETY: as in `bytes`; the chunks dropped are above
2904                        // the position, where nothing is live.
2905                        let chunks = unsafe { &mut *self.chunks.get() };
2906                        let next = if chunks.is_empty() { 0 } else { self.cur.get() + 1 };
2907                        let unit = ::core::mem::size_of::<#u128_ty>();
2908                        let fits = match chunks.get(next) {
2909                            ::core::option::Option::Some(chunk) => chunk.len() * unit >= need,
2910                            ::core::option::Option::None => false,
2911                        };
2912                        if !fits {
2913                            let last = match chunks.last() {
2914                                ::core::option::Option::Some(chunk) => chunk.len() * unit,
2915                                ::core::option::Option::None => 0,
2916                            };
2917                            chunks.truncate(next);
2918                            let size = need.max(last.saturating_mul(2)).max(4096);
2919                            chunks.push(#new_chunk);
2920                        }
2921                        self.cur.set(next);
2922                        self.top.set(0);
2923                    }
2924                    self.bytes(bytes, align)
2925                }
2926                /// `count` zeroed elements of `T`.
2927                #[inline(always)]
2928                fn alloc<#t>(&self, count: #usize_ty) -> *mut #t {
2929                    self.alloc_aligned::<#t>(count, 1)
2930                }
2931                /// `count` zeroed elements of `T`, the first at a multiple of
2932                /// `align` if that is stricter than `T`'s own alignment.
2933                #[inline(always)]
2934                fn alloc_aligned<#t>(&self, count: #usize_ty, align: #usize_ty) -> *mut #t {
2935                    let bytes = count
2936                        .checked_mul(::core::mem::size_of::<#t>())
2937                        .expect("a variable length array is larger than the address space");
2938                    let natural = ::core::mem::align_of::<#t>();
2939                    self.bytes(bytes, if align > natural { align } else { natural })
2940                        .cast::<#t>()
2941                }
2942                /// `size` zeroed bytes, 16-byte aligned, that no frame gives
2943                /// back: they live until the arena is dropped.
2944                #[inline(always)]
2945                fn alloca(&self, size: #usize_ty) -> *mut #void {
2946                    let first = self.bytes(size, 16);
2947                    self.floor.set(self.mark());
2948                    first.cast::<#void>()
2949                }
2950                /// A CFG-mode variable length array's declaration reached:
2951                /// gives back what its previous pass took, and everything
2952                /// allocated after that, and records where this one starts.
2953                #[inline]
2954                fn redefine(
2955                    &self,
2956                    marks: &mut [::core::option::Option<(#usize_ty, #usize_ty)>],
2957                    slot: #usize_ty,
2958                ) {
2959                    if let ::core::option::Option::Some(mine) = marks[slot] {
2960                        // No let chain: the user's crate may be on an
2961                        // edition before 2024.
2962                        for mark in marks.iter_mut() {
2963                            if let ::core::option::Option::Some(other) = *mark {
2964                                if other >= mine {
2965                                    *mark = ::core::option::Option::None;
2966                                }
2967                            }
2968                        }
2969                        self.release(mine);
2970                    }
2971                    marks[slot] = ::core::option::Option::Some(self.mark());
2972                }
2973            }
2974            #[allow(
2975                unknown_lints,
2976                elided_lifetimes_in_paths,
2977                missing_debug_implementations,
2978                single_use_lifetimes,
2979                clippy::pedantic,
2980                clippy::nursery
2981            )]
2982            struct #frame<'a>(&'a #arena, (#usize_ty, #usize_ty));
2983            #[allow(
2984                unknown_lints,
2985                elided_lifetimes_in_paths,
2986                single_use_lifetimes,
2987                clippy::pedantic,
2988                clippy::nursery
2989            )]
2990            impl ::core::ops::Drop for #frame<'_> {
2991                #[inline(always)]
2992                fn drop(&mut self) {
2993                    self.0.release(self.1);
2994                }
2995            }
2996        }
2997    }
2998
2999    fn stub_item(&mut self, func: &Function) -> TokenStream {
3000        let span = self.sp(func.range);
3001        self.enter_function(func);
3002        let signature = self.signature(func);
3003        if func.is_safe() {
3004            return quote_spanned! {span=>
3005                #signature { ::core::unreachable!() }
3006            };
3007        }
3008        quote_spanned! {span=>
3009            #signature {
3010                unsafe { ::core::unreachable!() }
3011            }
3012        }
3013    }
3014
3015    /// Resets the per-function state before a body is generated.
3016    fn enter_function(&mut self, func: &Function) {
3017        self.ret_ty = func.sig.ret;
3018        self.in_cfg = matches!(func.body, Some(Body::Cfg(_)));
3019        self.in_safe = func.is_safe();
3020        self.temporaries = 0;
3021        self.continue_styles.clear();
3022        self.local_names.clear();
3023        self.region_names.clear();
3024        self.region_kinds.clear();
3025        self.loop_names.clear();
3026        self.shape_scopes.clear();
3027        self.used_labels.clear();
3028        self.shape_labels = 0;
3029        self.vla_slots.clear();
3030        if let Some(Body::Structured(stmts)) = &func.body {
3031            self.name_regions(stmts);
3032        }
3033        if let Some(Body::Cfg(cfg)) = &func.body
3034            && let Some(plan) = &cfg.shape
3035        {
3036            let mut taken = HashSet::new();
3037            self.name_loops(&plan.body, &mut taken);
3038        }
3039        self.env = func
3040            .env
3041            .iter()
3042            .map(|entry| (entry.owner, entry.param))
3043            .collect();
3044
3045        // Every object this function binds with a `let` or a parameter, so
3046        // that one that would shadow a file-scope item can be renamed apart
3047        // and the rename can be checked against the others. Sema's list is
3048        // what makes a local declared inside a statement expression — which no
3049        // walk over the *statements* would reach — part of it.
3050        let mut bound: Vec<ir::ObjectId> = func.env.iter().map(|entry| entry.param).collect();
3051        bound.extend(func.params.iter().copied());
3052        if let Some(Body::Cfg(cfg)) = &func.body {
3053            for local in &cfg.locals {
3054                self.local_names
3055                    .insert(local.object, local.rust_name.clone());
3056            }
3057        }
3058        bound.extend(func.locals.iter().copied());
3059        self.rename_shadowing(&bound);
3060
3061        self.va_source = if func.sig.variadic {
3062            VaSource::Ellipsis
3063        } else {
3064            // A `va_list *` parameter points at the caller's list, which is
3065            // what a `va_list` local of this function starts out as — the same
3066            // thing a `va_list` parameter is, one indirection further out.
3067            func.params
3068                .iter()
3069                .find_map(|id| {
3070                    let ty = self.program.object(*id).ty;
3071                    if ty.is_va_list() {
3072                        return Some(VaSource::Param(*id));
3073                    }
3074                    let pointee = self.program.types.pointee(ty)?;
3075                    pointee.is_va_list().then_some(VaSource::PtrParam(*id))
3076                })
3077                .unwrap_or(VaSource::None)
3078        };
3079    }
3080
3081    /// The name a local or parameter would be generated under before the
3082    /// shadowing check.
3083    fn plain_local_name(&self, id: ir::ObjectId) -> String {
3084        match self.local_names.get(&id) {
3085            Some(name) => name.clone(),
3086            None => self.program.object(id).name.clone(),
3087        }
3088    }
3089
3090    /// Renames the bindings of the current function whose names would shadow a
3091    /// file-scope item.
3092    ///
3093    /// The new name is the C one with `_1`, `_2`, … appended, the same shape
3094    /// the [CFG lowering](crate::cfg) uses when it hoists two locals of the
3095    /// same name into one scope, and it is checked against the function's
3096    /// other bindings so that a rename never captures one of them. The check
3097    /// is against their Rust *spellings* (see [`Names`]), which is what two
3098    /// bindings collide in.
3099    fn rename_shadowing(&mut self, bound: &[ir::ObjectId]) {
3100        if self.reserved.is_empty() {
3101            return;
3102        }
3103        let mut used: HashSet<String> = bound
3104            .iter()
3105            .map(|id| {
3106                self.names
3107                    .spelling(&self.plain_local_name(*id))
3108                    .into_owned()
3109            })
3110            .collect();
3111        for id in bound {
3112            let base = self.plain_local_name(*id);
3113            if !self.reserved.contains(&base) {
3114                continue;
3115            }
3116            let name = (1u32..)
3117                .map(|n| format!("{base}_{n}"))
3118                .find(|c| {
3119                    !used.contains(self.names.spelling(c).as_ref()) && !self.reserved.contains(c)
3120                })
3121                .expect("the sequence of candidates is unbounded");
3122            used.insert(self.names.spelling(&name).into_owned());
3123            self.local_names.insert(*id, name);
3124        }
3125    }
3126
3127    /// The name of the synthetic `...` parameter.
3128    ///
3129    /// Mixed-site hygiene keeps it distinct from a C variable of the same
3130    /// name, however unlikely one is.
3131    fn va_ident(&self) -> Ident {
3132        Ident::new("__cinrs_va", Span::mixed_site())
3133    }
3134
3135    /// A fresh copy of the argument list the function was called with.
3136    fn va_pristine(&mut self, span: Span) -> TokenStream {
3137        match self.va_source {
3138            VaSource::Param(id) => {
3139                let name = self.object_ident(id, span);
3140                quote_spanned! {span=> #name.clone() }
3141            }
3142            VaSource::PtrParam(id) => {
3143                let name = self.object_ident(id, span);
3144                quote_spanned! {span=> (*#name).clone() }
3145            }
3146            // `VaSource::None` cannot reach codegen: sema refuses a `va_list`
3147            // that has nothing to copy.
3148            _ => {
3149                let name = self.va_ident();
3150                quote_spanned! {span=> #name.clone() }
3151            }
3152        }
3153    }
3154
3155    /// The alignment an object's binding has to be wrapped in, if any.
3156    ///
3157    /// Rust has no way to over-align a binding, so an object an `_Alignas` or
3158    /// an `aligned` made stricter than its type is generated inside a
3159    /// one-field wrapper that carries the alignment; see
3160    /// [`Codegen::align_wrapper_items`] and [`ir::Object::align`].
3161    fn object_align(&self, id: ir::ObjectId) -> Option<u64> {
3162        self.program.object(id).align
3163    }
3164
3165    /// The type an object's binding is declared with.
3166    fn binding_ty(&self, id: ir::ObjectId, ty: TokenStream, span: Span) -> TokenStream {
3167        match self.object_align(id) {
3168            Some(align) => {
3169                let wrapper = align_wrapper_ident(align, span);
3170                quote_spanned! {span=> #wrapper<#ty> }
3171            }
3172            None => ty,
3173        }
3174    }
3175
3176    /// The value an object's binding is initialised with.
3177    fn binding_init(&self, id: ir::ObjectId, init: TokenStream, span: Span) -> TokenStream {
3178        match self.object_align(id) {
3179            Some(align) => {
3180                let wrapper = align_wrapper_ident(align, span);
3181                quote_spanned! {span=> #wrapper(#init) }
3182            }
3183            None => init,
3184        }
3185    }
3186
3187    /// The type an object's *storage* has, which is its own except for the
3188    /// [companion](ir::Object::flexible_len) a filled-in flexible array member
3189    /// needs.
3190    fn storage_ty(&self, id: ir::ObjectId, span: Span) -> TokenStream {
3191        let object = self.program.object(id);
3192        match (object.flexible_len, object.ty) {
3193            (Some(len), Ty::Record(record)) => {
3194                let name =
3195                    self.flexible_ident(&self.program.types.record(record).rust_name, len, span);
3196                quote_spanned! {span=> #name }
3197            }
3198            _ => self.ty(object.ty, span),
3199        }
3200    }
3201
3202    /// The place expression naming an object, reaching through the alignment
3203    /// wrapper and the flexible-array companion when the binding has them.
3204    fn object_access(&self, id: ir::ObjectId, span: Span) -> TokenStream {
3205        let name = self.object_ident(id, span);
3206        self.through_storage(id, quote_spanned! {span=> #name }, span)
3207    }
3208
3209    /// Reaches the C object inside the storage its binding really has.
3210    ///
3211    /// Two wrappers can sit in between, and they compose: the
3212    /// [alignment](ir::Object::align) wrapper's one field, and the
3213    /// [flexible-array companion](ir::Object::flexible_len), whose leading
3214    /// layout is the record's and whose address is therefore a pointer to it.
3215    fn through_storage(&self, id: ir::ObjectId, base: TokenStream, span: Span) -> TokenStream {
3216        let object = self.program.object(id);
3217        let mut access = base;
3218        if object.align.is_some() {
3219            let field = Literal::usize_unsuffixed(0);
3220            access = quote_spanned! {span=> #access.#field };
3221        }
3222        if object.flexible_len.is_some() {
3223            let ty = self.ty(object.ty, span);
3224            access = parenthesize(
3225                quote_spanned! {span=> *(&raw mut #access).cast::<#ty>() },
3226                span,
3227            );
3228        }
3229        access
3230    }
3231
3232    /// Reading a `va_list` copies it: Rust's is not `Copy`, and C says a list
3233    /// passed on is indeterminate afterwards anyway.
3234    ///
3235    /// A `va_list` place is an object of its own or the `*p` of a `va_list *`
3236    /// — nothing may keep one as a member — so the only setup there can be is
3237    /// the temporary that pointer goes into. Out of line for the same reason
3238    /// [`Codegen::label_address`] is.
3239    #[inline(never)]
3240    fn va_list_load(&mut self, place: &Place, span: Span) -> Value {
3241        let lowered = self.place(place, false);
3242        let access = lowered.access;
3243        let value = Value::new(quote_spanned! {span=> #access.clone() }, prec::CALL);
3244        if lowered.setup.is_empty() {
3245            return value;
3246        }
3247        let setup = lowered.setup;
3248        let tokens = value.at(prec::LOWEST, span);
3249        Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
3250    }
3251
3252    /// GNU's `&&label`: the number the label was given among those of its
3253    /// function whose address is taken — from 1, so never a null pointer —
3254    /// cast to the pointer type the expression has. See [`crate::cfg`].
3255    ///
3256    /// Out of line — like [`Codegen::label_difference`] — because
3257    /// [`Codegen::expr_value`] recurses once per operator and every arm's
3258    /// locals are part of its frame; see
3259    /// `codegen_of_deeply_nested_input_fits_in_a_small_stack`.
3260    #[inline(never)]
3261    fn label_address(&self, id: ir::LabelId, ty: Ty, span: Span) -> Value {
3262        let state = self.label_states.get(&id).copied().unwrap_or(0);
3263        let mut literal = Literal::usize_suffixed(state as usize);
3264        literal.set_span(span);
3265        let target = self.ty(ty, span);
3266        Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
3267    }
3268
3269    /// GNU's `&&a - &&b`, folded on the two labels' numbers.
3270    #[inline(never)]
3271    fn label_difference(&self, lhs: &Expr, rhs: &Expr, ty: Ty, span: Span) -> Value {
3272        let left = self.label_state_literal(lhs, span);
3273        let right = self.label_state_literal(rhs, span);
3274        let target = self.ty(ty, span);
3275        Value::new(
3276            quote_spanned! {span=> (#left - #right) as #target },
3277            prec::CAST,
3278        )
3279        .type_end(true)
3280    }
3281
3282    /// The number a [label address](ir::ExprKind::LabelAddr) stands for, as an
3283    /// `isize` literal.
3284    fn label_state_literal(&self, expr: &Expr, span: Span) -> TokenStream {
3285        let id = label_state(expr).expect("a label address");
3286        let state = self.label_states.get(&id).copied().unwrap_or(0);
3287        let mut literal = Literal::isize_suffixed(state as isize);
3288        literal.set_span(span);
3289        quote_spanned! {span=> #literal }
3290    }
3291
3292    /// The Rust name an object is generated under.
3293    fn object_ident(&self, id: ir::ObjectId, span: Span) -> Ident {
3294        let object = self.program.object(id);
3295        match &object.storage {
3296            Storage::Automatic => match self.local_names.get(&id) {
3297                Some(name) => self.c_ident(name, span),
3298                None => self.c_ident(&object.name, span),
3299            },
3300            // A `static mut` is used as a place, never referenced, so
3301            // edition 2024's `static_mut_refs` lint has nothing to say.
3302            Storage::Static { item_name, .. } | Storage::ThreadLocal { item_name, .. } => {
3303                self.c_ident(item_name, span)
3304            }
3305            Storage::Extern { item_name } => self.extern_object_ident(item_name, span),
3306        }
3307    }
3308
3309    // -- the control-flow-graph form ----------------------------------------
3310
3311    /// Emits a [CFG](crate::cfg) body.
3312    ///
3313    /// Every local is bound at the top — Rust has no way to jump over a `let`
3314    /// — and then either the structured shapes [the relooper](crate::reloop)
3315    /// recovered, or, for a graph it gave up on, the state machine.
3316    fn cfg_body(&mut self, cfg: &Cfg, span: Span) -> TokenStream {
3317        let mut out = self.cfg_locals(cfg);
3318        match &cfg.shape {
3319            Some(plan) => {
3320                out.extend(self.shape_seq(cfg, &plan.body, &reloop::Exit::nowhere(), span))
3321            }
3322            None => out.extend(self.state_machine(cfg, span)),
3323        }
3324        out
3325    }
3326
3327    /// The `let` bindings every local of a graph-lowered function gets.
3328    fn cfg_locals(&mut self, cfg: &Cfg) -> TokenStream {
3329        let mut out = TokenStream::new();
3330        let mut slots = 0;
3331        let mut slots_span = None;
3332        for local in &cfg.locals {
3333            let object = self.program.object(local.object);
3334            let ospan = self.sp(object.range);
3335            // The hidden frame of a variable length array is a slot of one
3336            // array of arena marks, which starts out empty; the declaration
3337            // fills it where it was written, first giving back whatever a
3338            // previous pass over it took. See [`Codegen::arena_items`].
3339            if object.vla_storage {
3340                self.vla_slots.insert(local.object, slots);
3341                slots += 1;
3342                slots_span.get_or_insert(ospan);
3343                continue;
3344            }
3345            let name = self.object_ident(local.object, ospan);
3346            let (ty, init) = if object.ty.is_va_list() {
3347                // A `va_list` has no zero value; it starts out as a copy of
3348                // the list the function was called with, exactly as it does
3349                // when the declaration stays where it was written.
3350                (self.ty(object.ty, ospan), self.va_pristine(ospan))
3351            } else {
3352                (
3353                    self.ty(object.ty, ospan),
3354                    self.zero_tokens(object.ty, ospan),
3355                )
3356            };
3357            let ty = self.binding_ty(local.object, ty, ospan);
3358            let init = self.binding_init(local.object, init, ospan);
3359            out.extend(quote_spanned! {ospan=> let mut #name: #ty = #init; });
3360        }
3361        if let Some(span) = slots_span {
3362            let marks = vla_marks_ident();
3363            let usize_ty = primitive_ty("usize", span);
3364            let len = Literal::usize_unsuffixed(slots);
3365            out.extend(quote_spanned! {span=>
3366                let mut #marks: [::core::option::Option<(#usize_ty, #usize_ty)>; #len] =
3367                    [::core::option::Option::None; #len];
3368            });
3369        }
3370        out
3371    }
3372
3373    /// The graph as a state machine, for one [the relooper](crate::reloop) gave
3374    /// up on: shapes nested deeper than `rustc` parses.
3375    ///
3376    /// Every arm of the `match` ends in `continue 'cfg` or in a `return`, so
3377    /// the loop never finishes and the function needs no value after it.
3378    fn state_machine(&mut self, cfg: &Cfg, span: Span) -> TokenStream {
3379        let state = self.state_ident();
3380        let label = self.cfg_label();
3381        let mut arms = TokenStream::new();
3382        for (index, block) in cfg.blocks.iter().enumerate() {
3383            let bspan = self.block_span(block, span);
3384            let pattern = state_literal(index, bspan);
3385            let body = self.block_tokens(block, bspan);
3386            arms.extend(quote_spanned! {bspan=> #pattern => { #body } });
3387        }
3388        arms.extend(quote_spanned! {span=> _ => ::core::unreachable!(), });
3389        let u32_ty = primitive_ty("u32", span);
3390        quote_spanned! {span=>
3391            let mut #state: #u32_ty = 0;
3392            #label: loop {
3393                match #state { #arms }
3394            }
3395        }
3396    }
3397
3398    /// The state variable, in this crate's own hygiene.
3399    fn state_ident(&self) -> Ident {
3400        Ident::new("__cinrs_state", Span::mixed_site())
3401    }
3402
3403    fn cfg_label(&self) -> TokenStream {
3404        self.label("cfg", Span::mixed_site())
3405    }
3406
3407    /// Where a block's tokens are attributed to: the first thing in it that
3408    /// came from the C source.
3409    fn block_span(&self, block: &BasicBlock, fallback: Span) -> Span {
3410        if let Some(range) = block.stmts.iter().find_map(|s| self.stmt_range(s)) {
3411            return self.sp(range);
3412        }
3413        match &block.term {
3414            Terminator::Jump { range, .. }
3415            | Terminator::Switch { range, .. }
3416            | Terminator::Return { range, .. } => self.sp(*range),
3417            Terminator::Branch { cond, .. } => self.sp(cond.range),
3418            Terminator::Unreachable | Terminator::InvalidTarget => fallback,
3419        }
3420    }
3421
3422    fn block_tokens(&mut self, block: &BasicBlock, span: Span) -> TokenStream {
3423        let mut out = self.stmts(&block.stmts);
3424        let label = self.cfg_label();
3425        match &block.term {
3426            Terminator::Jump { target, range } => {
3427                let jump = self.enter_block(*target, self.sp(*range));
3428                out.extend(quote_spanned! {span=> #jump continue #label; });
3429            }
3430            Terminator::Branch {
3431                cond,
3432                then_blk,
3433                else_blk,
3434            } => {
3435                let cspan = self.sp(cond.range);
3436                let test = self.condition(cond).at_condition(cspan);
3437                let then_tokens = self.enter_block(*then_blk, cspan);
3438                let else_tokens = self.enter_block(*else_blk, cspan);
3439                out.extend(quote_spanned! {cspan=>
3440                    if #test { #then_tokens } else { #else_tokens }
3441                    continue #label;
3442                });
3443            }
3444            Terminator::Switch {
3445                value,
3446                cases,
3447                default,
3448                range,
3449            } => {
3450                let sspan = self.sp(*range);
3451                let scrutinee = self.expr(value).at(prec::UNARY, sspan);
3452                let mut arms = TokenStream::new();
3453                for (target, values) in group_cases(cases) {
3454                    let mut pattern = TokenStream::new();
3455                    for (index, case) in values.iter().enumerate() {
3456                        if index > 0 {
3457                            pattern.extend(quote_spanned! {sspan=> | });
3458                        }
3459                        pattern.extend(case_pattern(*case, value.ty, sspan));
3460                    }
3461                    let enter = self.enter_block(target, sspan);
3462                    arms.extend(quote_spanned! {sspan=> #pattern => { #enter } });
3463                }
3464                let enter = self.enter_block(*default, sspan);
3465                arms.extend(quote_spanned! {sspan=> _ => { #enter } });
3466                out.extend(quote_spanned! {sspan=>
3467                    match #scrutinee { #arms }
3468                    continue #label;
3469                });
3470            }
3471            Terminator::Return { value, range } => {
3472                let rspan = self.sp(*range);
3473                match value {
3474                    Some(value) => {
3475                        let ret = self.ret_ty;
3476                        let tokens = self.expr_at(value, ret);
3477                        out.extend(quote_spanned! {rspan=> return #tokens; });
3478                    }
3479                    None => out.extend(quote_spanned! {rspan=> return; }),
3480                }
3481            }
3482            Terminator::Unreachable => {
3483                out.extend(quote_spanned! {span=> ::core::unreachable!(); });
3484            }
3485            Terminator::InvalidTarget => out.extend(invalid_target(span)),
3486        }
3487        out
3488    }
3489
3490    /// The assignment that moves the state machine to `target`.
3491    fn enter_block(&self, target: BlockId, span: Span) -> TokenStream {
3492        let state = self.state_ident();
3493        let value = state_literal(target.0 as usize, span);
3494        quote_spanned! {span=> #state = #value; }
3495    }
3496
3497    // -- the structured form of the graph ------------------------------------
3498
3499    /// Names the loops [the relooper](crate::reloop) recovered, after the C
3500    /// labels their heads stand at.
3501    ///
3502    /// The same rules as [`Codegen::name_regions`]: a name Rust cannot spell
3503    /// as a label, or one this module gives its own loops and blocks, is
3504    /// replaced by `rN`, and a name two loops would share gets an underscore.
3505    fn name_loops(&mut self, seq: &reloop::Seq, taken: &mut HashSet<String>) {
3506        for shape in seq {
3507            match shape {
3508                reloop::Shape::Loop { id, name, body, .. } => {
3509                    let mut candidate = match name {
3510                        Some(name) => rust_spelling(name).into_owned(),
3511                        None => String::new(),
3512                    };
3513                    if !is_label_name(&candidate) {
3514                        candidate = format!("r{id}");
3515                    }
3516                    while taken.contains(&candidate) {
3517                        candidate.push('_');
3518                    }
3519                    taken.insert(candidate.clone());
3520                    self.loop_names.insert(*id, candidate);
3521                    self.name_loops(body, taken);
3522                }
3523                reloop::Shape::Simple { arms, .. } | reloop::Shape::Dispatch { arms, .. } => {
3524                    for arm in arms {
3525                        self.name_loops(&arm.body, taken);
3526                    }
3527                }
3528            }
3529        }
3530    }
3531
3532    /// A run of shapes, one after another.
3533    ///
3534    /// Everything before a shape stands inside a labelled block that ends
3535    /// where that shape begins, so that a jump forwards is `break` of it —
3536    /// the same shape [`regions`](crate::regions) gives an outward `goto`.
3537    /// The nesting runs the other way round from the order they are emitted
3538    /// in: the block for the *second* shape is the innermost one, so that
3539    /// breaking it lands on the second shape and breaking any of the others
3540    /// skips past what is in between.
3541    fn shape_seq(
3542        &mut self,
3543        cfg: &Cfg,
3544        seq: &reloop::Seq,
3545        fall: &reloop::Exit,
3546        span: Span,
3547    ) -> TokenStream {
3548        let Some(first) = seq.first() else {
3549            return TokenStream::new();
3550        };
3551        let exits: Vec<reloop::Exit> = seq.iter().map(reloop::Shape::exit).collect();
3552        // An irreducible region's state variable is bound before anything that
3553        // could jump into it, which is the head of the run it stands in.
3554        let mut out = TokenStream::new();
3555        for shape in seq {
3556            if let reloop::Shape::Loop {
3557                state: Some(state), ..
3558            } = shape
3559            {
3560                let name = entry_ident(*state);
3561                let u32_ty = primitive_ty("u32", span);
3562                out.extend(quote_spanned! {span=> let mut #name: #u32_ty = 0; });
3563            }
3564        }
3565        let ids: Vec<u32> = (1..seq.len())
3566            .map(|_| {
3567                let id = self.shape_labels;
3568                self.shape_labels += 1;
3569                id
3570            })
3571            .collect();
3572        for (index, id) in ids.iter().enumerate().rev() {
3573            self.shape_scopes.push(ShapeScope {
3574                id: *id,
3575                name: format!("b{id}"),
3576                repeats: false,
3577                exit: exits[index + 1].clone(),
3578            });
3579        }
3580        let mut code = self.shape(cfg, first, exits.get(1).unwrap_or(fall), span);
3581        for (index, shape) in seq.iter().enumerate().skip(1) {
3582            let scope = self.shape_scopes.pop().expect("one scope per shape");
3583            if self.used_labels.contains(&scope.id) {
3584                let label = self.label(&scope.name, span);
3585                code = quote_spanned! {span=> #label: { #code } };
3586            }
3587            code.extend(self.shape(cfg, shape, exits.get(index + 1).unwrap_or(fall), span));
3588        }
3589        out.extend(code);
3590        out
3591    }
3592
3593    /// One shape.
3594    fn shape(
3595        &mut self,
3596        cfg: &Cfg,
3597        shape: &reloop::Shape,
3598        fall: &reloop::Exit,
3599        span: Span,
3600    ) -> TokenStream {
3601        match shape {
3602            reloop::Shape::Simple { block, arms } => {
3603                self.shape_simple(cfg, *block, arms, fall, span)
3604            }
3605            reloop::Shape::Loop {
3606                id,
3607                entries,
3608                state,
3609                body,
3610                ..
3611            } => {
3612                let name = self
3613                    .loop_names
3614                    .get(id)
3615                    .cloned()
3616                    .unwrap_or_else(|| format!("r{id}"));
3617                let bspan = entries.first().map_or(span, |entry| {
3618                    self.block_span(&cfg.blocks[entry.index()], span)
3619                });
3620                let head = reloop::Exit {
3621                    targets: entries.clone(),
3622                    state: *state,
3623                };
3624                // Leaving the loop is `break`, going round again `continue`.
3625                self.shape_scopes.push(ShapeScope {
3626                    id: u32::MAX,
3627                    name: name.clone(),
3628                    repeats: false,
3629                    exit: fall.clone(),
3630                });
3631                self.shape_scopes.push(ShapeScope {
3632                    id: u32::MAX,
3633                    name: name.clone(),
3634                    repeats: true,
3635                    exit: head.clone(),
3636                });
3637                let body = self.shape_seq(cfg, body, &head, bspan);
3638                self.shape_scopes.pop();
3639                self.shape_scopes.pop();
3640                let label = self.label(&name, bspan);
3641                quote_spanned! {bspan=> #label: loop { #body } }
3642            }
3643            reloop::Shape::Dispatch { state, arms } => {
3644                self.shape_dispatch(cfg, *state, arms, fall, span)
3645            }
3646        }
3647    }
3648
3649    /// The head of an irreducible region: which entry this turn runs.
3650    fn shape_dispatch(
3651        &mut self,
3652        cfg: &Cfg,
3653        state: u32,
3654        arms: &[reloop::Arm],
3655        fall: &reloop::Exit,
3656        span: Span,
3657    ) -> TokenStream {
3658        let Some((last, rest)) = arms.split_last() else {
3659            return TokenStream::new();
3660        };
3661        if rest.is_empty() {
3662            return self.shape_seq(cfg, &last.body, fall, span);
3663        }
3664        let name = entry_ident(state);
3665        // Two heads is the common irreducible region, and two heads is an
3666        // `if`: a `match` of `0 =>` and `_ =>` says nothing more.
3667        if rest.len() == 1 {
3668            let first = self.shape_seq(cfg, &rest[0].body, fall, span);
3669            let second = self.shape_seq(cfg, &last.body, fall, span);
3670            let zero = state_literal(0, span);
3671            return quote_spanned! {span=>
3672                if #name == #zero { #first } else { #second }
3673            };
3674        }
3675        let mut cases = TokenStream::new();
3676        for (index, arm) in rest.iter().enumerate() {
3677            let body = self.shape_seq(cfg, &arm.body, fall, span);
3678            let pattern = state_literal(index, span);
3679            cases.extend(quote_spanned! {span=> #pattern => { #body } });
3680        }
3681        let body = self.shape_seq(cfg, &last.body, fall, span);
3682        cases.extend(quote_spanned! {span=> _ => { #body } });
3683        quote_spanned! {span=> match #name { #cases } }
3684    }
3685
3686    /// A block, and the branch its terminator becomes.
3687    fn shape_simple(
3688        &mut self,
3689        cfg: &Cfg,
3690        block: BlockId,
3691        arms: &[reloop::Arm],
3692        fall: &reloop::Exit,
3693        span: Span,
3694    ) -> TokenStream {
3695        let basic = &cfg.blocks[block.index()];
3696        let span = self.block_span(basic, span);
3697        let mut out = self.stmts(&basic.stmts);
3698        match &basic.term {
3699            Terminator::Jump { target, range } => {
3700                let jspan = self.sp(*range);
3701                out.extend(self.enter_shape(cfg, arms, *target, fall, jspan));
3702            }
3703            Terminator::Branch {
3704                cond,
3705                then_blk,
3706                else_blk,
3707            } => out.extend(self.shape_branch(cfg, arms, cond, *then_blk, *else_blk, fall)),
3708            Terminator::Switch {
3709                value,
3710                cases,
3711                default,
3712                range,
3713            } => {
3714                let sspan = self.sp(*range);
3715                out.extend(self.shape_switch(cfg, arms, value, cases, *default, fall, sspan));
3716            }
3717            Terminator::Return { value, range } => {
3718                let rspan = self.sp(*range);
3719                match value {
3720                    Some(value) => {
3721                        let ret = self.ret_ty;
3722                        let tokens = self.expr_at(value, ret);
3723                        out.extend(quote_spanned! {rspan=> return #tokens; });
3724                    }
3725                    None => out.extend(quote_spanned! {rspan=> return; }),
3726                }
3727            }
3728            Terminator::Unreachable => {
3729                out.extend(quote_spanned! {span=> ::core::unreachable!(); });
3730            }
3731            Terminator::InvalidTarget => out.extend(invalid_target(span)),
3732        }
3733        out
3734    }
3735
3736    /// A two-way branch: `if`, with the blocks only it reaches in its arms.
3737    fn shape_branch(
3738        &mut self,
3739        cfg: &Cfg,
3740        arms: &[reloop::Arm],
3741        cond: &Expr,
3742        then_blk: BlockId,
3743        else_blk: BlockId,
3744        fall: &reloop::Exit,
3745    ) -> TokenStream {
3746        let span = self.sp(cond.range);
3747        // Both edges lead to the same block: the condition is still evaluated,
3748        // for what it does rather than for what it says.
3749        if then_blk == else_blk {
3750            let effects = self.expr_stmt(cond);
3751            let jump = self.enter_shape(cfg, arms, then_blk, fall, span);
3752            return quote_spanned! {span=> #effects #jump };
3753        }
3754        let then_tokens = self.enter_shape(cfg, arms, then_blk, fall, span);
3755        let else_tokens = self.enter_shape(cfg, arms, else_blk, fall, span);
3756        if then_tokens.is_empty() && else_tokens.is_empty() {
3757            return self.expr_stmt(cond);
3758        }
3759        if else_tokens.is_empty() {
3760            let test = self.condition(cond).at_condition(span);
3761            return quote_spanned! {span=> if #test { #then_tokens } };
3762        }
3763        if then_tokens.is_empty() {
3764            // No empty arm: the test is inverted rather than left standing
3765            // with nothing in it.
3766            let test = self.condition(cond).at(prec::UNARY, span);
3767            return quote_spanned! {span=> if !#test { #else_tokens } };
3768        }
3769        let test = self.condition(cond).at_condition(span);
3770        quote_spanned! {span=> if #test { #then_tokens } else { #else_tokens } }
3771    }
3772
3773    /// A `switch`: one `match`, with the case bodies in its arms and
3774    /// fallthrough as the code that follows it.
3775    #[allow(clippy::too_many_arguments)]
3776    fn shape_switch(
3777        &mut self,
3778        cfg: &Cfg,
3779        arms: &[reloop::Arm],
3780        value: &Expr,
3781        cases: &[(ir::CaseRange, BlockId)],
3782        default: BlockId,
3783        fall: &reloop::Exit,
3784        span: Span,
3785    ) -> TokenStream {
3786        let groups = group_cases(cases);
3787        let mut lowered: Vec<(Vec<ir::CaseRange>, TokenStream)> = Vec::new();
3788        for (target, values) in groups {
3789            let tokens = self.enter_shape(cfg, arms, target, fall, span);
3790            lowered.push((values, tokens));
3791        }
3792        let fallback = self.enter_shape(cfg, arms, default, fall, span);
3793        // One arm is no dispatch at all: every value goes the same way, and
3794        // all the `match` would do is evaluate the controlling expression.
3795        if lowered.iter().all(|(_, tokens)| tokens.is_empty()) && fallback.is_empty() {
3796            return self.expr_stmt(value);
3797        }
3798        if lowered.is_empty() {
3799            let effects = self.expr_stmt(value);
3800            return quote_spanned! {span=> #effects #fallback };
3801        }
3802        let scrutinee = self.expr(value).at(prec::UNARY, span);
3803        let mut out = TokenStream::new();
3804        for (values, tokens) in lowered {
3805            let mut pattern = TokenStream::new();
3806            for (index, case) in values.iter().enumerate() {
3807                if index > 0 {
3808                    pattern.extend(quote_spanned! {span=> | });
3809                }
3810                pattern.extend(case_pattern(*case, value.ty, span));
3811            }
3812            out.extend(quote_spanned! {span=> #pattern => { #tokens } });
3813        }
3814        out.extend(quote_spanned! {span=> _ => { #fallback } });
3815        quote_spanned! {span=> match #scrutinee { #out } }
3816    }
3817
3818    /// What one edge of a terminator becomes: the shapes only it reaches,
3819    /// emitted here, or a jump to where they stand.
3820    fn enter_shape(
3821        &mut self,
3822        cfg: &Cfg,
3823        arms: &[reloop::Arm],
3824        target: BlockId,
3825        fall: &reloop::Exit,
3826        span: Span,
3827    ) -> TokenStream {
3828        match arms.iter().find(|arm| arm.entry == target) {
3829            Some(arm) => self.shape_seq(cfg, &arm.body, fall, span),
3830            None => self.goto_shape(target, fall, span),
3831        }
3832    }
3833
3834    /// The jump that reaches `target` from here.
3835    ///
3836    /// Falling out of the construct being generated is free; anything else is
3837    /// a `break` or a `continue` of the innermost labelled block or loop that
3838    /// arrives there. [`reloop::plan`] has checked that one of the two always
3839    /// applies.
3840    fn goto_shape(&mut self, target: BlockId, fall: &reloop::Exit, span: Span) -> TokenStream {
3841        if let Some(index) = fall.index_of(target) {
3842            return entry_assignment(fall, index, span);
3843        }
3844        for depth in (0..self.shape_scopes.len()).rev() {
3845            let Some(index) = self.shape_scopes[depth].exit.index_of(target) else {
3846                continue;
3847            };
3848            let scope = self.shape_scopes[depth].clone();
3849            self.used_labels.insert(scope.id);
3850            let label = self.label(&scope.name, span);
3851            let set = entry_assignment(&scope.exit, index, span);
3852            return if scope.repeats {
3853                quote_spanned! {span=> #set continue #label; }
3854            } else {
3855                quote_spanned! {span=> #set break #label; }
3856            };
3857        }
3858        unreachable!("the shapes were checked before they were generated")
3859    }
3860
3861    // -- statements ---------------------------------------------------------
3862
3863    fn stmts(&mut self, stmts: &[Stmt]) -> TokenStream {
3864        let mut out = TokenStream::new();
3865        for stmt in stmts {
3866            out.extend(self.stmt(stmt));
3867        }
3868        out
3869    }
3870
3871    /// Emits a statement as a braced block, reusing the braces C already wrote
3872    /// when it wrote a compound statement.
3873    fn block_of(&mut self, stmt: &Stmt, span: Span) -> TokenStream {
3874        match stmt {
3875            Stmt::Block(items) => {
3876                let items = self.stmts(items);
3877                braced(items, span)
3878            }
3879            other => {
3880                let tokens = self.stmt(other);
3881                braced(tokens, span)
3882            }
3883        }
3884    }
3885
3886    fn stmt(&mut self, stmt: &Stmt) -> TokenStream {
3887        match stmt {
3888            Stmt::Nop => TokenStream::new(),
3889            Stmt::Asm(asm) => self.asm_stmt(asm),
3890            Stmt::Expr(expr) => self.expr_stmt(expr),
3891            Stmt::Let { object, init, .. } => {
3892                let id = *object;
3893                let name = self.object_ident(id, self.sp(self.program.object(id).range));
3894                let object = self.program.object(id);
3895                let span = self.sp(object.range);
3896                let object_ty = object.ty;
3897                let ty = self.binding_ty(id, self.ty(object_ty, span), span);
3898                let init = self.expr_at(init, object_ty);
3899                let init = self.binding_init(id, init, span);
3900                quote_spanned! {span=> let mut #name: #ty = #init; }
3901            }
3902            Stmt::Vla(def) => self.vla_def(def),
3903            Stmt::Cleanup(def) => self.cleanup_def(def),
3904            Stmt::Block(items) => {
3905                let span = self.stmts_span(items);
3906                let items = self.stmts(items);
3907                braced(items, span)
3908            }
3909            Stmt::If {
3910                cond,
3911                then_branch,
3912                else_branch,
3913            } => {
3914                let span = self.sp(cond.range);
3915                let cond_tokens = self.condition(cond).at_condition(span);
3916                let then_tokens = self.block_of(then_branch, span);
3917                let else_tokens = match else_branch {
3918                    Some(branch) => {
3919                        let tokens = self.block_of(branch, span);
3920                        quote_spanned! {span=> else #tokens }
3921                    }
3922                    None => TokenStream::new(),
3923                };
3924                quote_spanned! {span=> if #cond_tokens #then_tokens #else_tokens }
3925            }
3926            Stmt::While {
3927                id,
3928                cond,
3929                body,
3930                range,
3931            } => {
3932                let span = self.sp(*range);
3933                self.continue_styles.insert(*id, ContinueStyle::Head);
3934                let label = self.loop_label(*id, span);
3935                let body_tokens = self.block_of(body, span);
3936                // `while (1)` becomes `loop`, not `while true`: only a `loop`
3937                // tells Rust the statement never finishes, which is what a
3938                // function ending in one relies on.
3939                if ir::is_always_true(cond) {
3940                    return quote_spanned! {span=> #label: loop #body_tokens };
3941                }
3942                let cond_tokens = self.condition(cond).at_condition(span);
3943                quote_spanned! {span=> #label: while #cond_tokens #body_tokens }
3944            }
3945            Stmt::DoWhile {
3946                id,
3947                body,
3948                cond,
3949                range,
3950            } => {
3951                let span = self.sp(*range);
3952                self.continue_styles.insert(*id, ContinueStyle::BodyLabel);
3953                let label = self.loop_label(*id, span);
3954                let body_label = self.loop_body_label(*id, span);
3955                let body_tokens = self.block_of(body, span);
3956                let test = if ir::is_always_true(cond) {
3957                    TokenStream::new()
3958                } else {
3959                    let cond_tokens = self.condition(cond).at(prec::LOWEST, span);
3960                    quote_spanned! {span=> if !(#cond_tokens) { break #label; } }
3961                };
3962                quote_spanned! {span=>
3963                    #label: loop {
3964                        #body_label: #body_tokens
3965                        #test
3966                    }
3967                }
3968            }
3969            Stmt::For {
3970                id,
3971                init,
3972                cond,
3973                step,
3974                body,
3975                range,
3976            } => {
3977                let span = self.sp(*range);
3978                self.continue_styles.insert(*id, ContinueStyle::BodyLabel);
3979                let label = self.loop_label(*id, span);
3980                let body_label = self.loop_body_label(*id, span);
3981                let init_tokens = self.stmts(init);
3982                let test = match cond {
3983                    Some(cond) if !ir::is_always_true(cond) => {
3984                        let tokens = self.condition(cond).at(prec::LOWEST, span);
3985                        quote_spanned! {span=> if !(#tokens) { break #label; } }
3986                    }
3987                    _ => TokenStream::new(),
3988                };
3989                let body_tokens = self.block_of(body, span);
3990                let step_tokens = match step {
3991                    Some(step) => self.expr_stmt(step),
3992                    None => TokenStream::new(),
3993                };
3994                // The whole loop is wrapped so that a C99 declaration in the
3995                // init clause stays scoped to the loop, as C says it is.
3996                quote_spanned! {span=>
3997                    {
3998                        #init_tokens
3999                        #label: loop {
4000                            #test
4001                            #body_label: #body_tokens
4002                            #step_tokens
4003                        }
4004                    }
4005                }
4006            }
4007            Stmt::Switch(switch) => self.switch(switch),
4008            Stmt::Region(region) => self.region(region),
4009            // The CFG lowering consumes these, and a label the structured mode
4010            // kept is where a region ends rather than anything of its own: only
4011            // the statement under it is left.
4012            Stmt::Label { body, .. } | Stmt::Case { body, .. } => self.stmt(body),
4013            // A `goto` left in a structured body leaves the region its label
4014            // stands for; see [`crate::regions`]. Anything else is consumed by
4015            // the CFG lowering, which is the only mode it is generated in.
4016            Stmt::Goto { id, range } => {
4017                let span = self.sp(*range);
4018                match self.region_kinds.get(id).copied() {
4019                    Some(kind) => {
4020                        let label = self.region_label(*id, span);
4021                        match kind {
4022                            ir::RegionKind::Block => quote_spanned! {span=> break #label; },
4023                            ir::RegionKind::Loop => quote_spanned! {span=> continue #label; },
4024                        }
4025                    }
4026                    None => TokenStream::new(),
4027                }
4028            }
4029            Stmt::GotoPtr { .. } => TokenStream::new(),
4030            Stmt::SwitchTree(switch) => self.stmt(&switch.body),
4031            Stmt::Break { target, range } => {
4032                let span = self.sp(*range);
4033                let label = match target {
4034                    BreakTarget::Loop(id) => self.loop_label(*id, span),
4035                    BreakTarget::Switch(id) => self.switch_label(*id, span),
4036                };
4037                quote_spanned! {span=> break #label; }
4038            }
4039            Stmt::Continue { id, range } => {
4040                let span = self.sp(*range);
4041                match self.continue_styles.get(id) {
4042                    Some(ContinueStyle::BodyLabel) => {
4043                        let label = self.loop_body_label(*id, span);
4044                        quote_spanned! {span=> break #label; }
4045                    }
4046                    _ => {
4047                        let label = self.loop_label(*id, span);
4048                        quote_spanned! {span=> continue #label; }
4049                    }
4050                }
4051            }
4052            Stmt::Return { value, range } => {
4053                let span = self.sp(*range);
4054                match value {
4055                    Some(value) => {
4056                        let ret = self.ret_ty;
4057                        let tokens = self.expr_at(value, ret);
4058                        quote_spanned! {span=> return #tokens; }
4059                    }
4060                    None => quote_spanned! {span=> return; },
4061                }
4062            }
4063        }
4064    }
4065
4066    /// A variable length array's definition, `T a[n];`.
4067    ///
4068    /// Two bindings after the bounds' own: the frame of the function's bump
4069    /// arena, whose `Drop` at the end of the block — on every way out of it —
4070    /// gives the space back and is the object's lifetime; and the object
4071    /// itself, a pointer to the first of the zeroed elements the arena bumps
4072    /// off. The frame stands first, so Rust drops it after anything declared
4073    /// with the array. See [`Codegen::arena_items`].
4074    ///
4075    /// In [CFG mode](crate::cfg) there are no blocks to drop a frame at, and
4076    /// the pointer is already bound at the top of the function — Rust has no
4077    /// way to jump over a `let` — so what is written here is the arena's
4078    /// `redefine` of this array's slot in the function's array of marks, which
4079    /// gives back a previous pass's space before taking the new mark, and an
4080    /// assignment.
4081    fn vla_def(&mut self, def: &ir::VlaDef) -> TokenStream {
4082        let span = self.sp(def.range);
4083        let object = self.program.object(def.object);
4084        // Whatever is left under the variable dimensions: one allocation
4085        // holds the whole object, however many of them there are.
4086        let elem = self.program.types.vm_step_ty(object.ty);
4087        let name = self.object_ident(def.object, span);
4088        let count = self.expr(&def.count).at(prec::CAST, span);
4089        let elem_ty = self.ty(elem, span);
4090        let usize_ty = primitive_ty("usize", span);
4091        let arena = self.arena_ident(span);
4092        // A requested alignment stricter than the element's pads the arena's
4093        // position up to a multiple of it before the array starts.
4094        let first = match def.align {
4095            Some(align) => {
4096                let align = Literal::usize_unsuffixed(align as usize);
4097                quote_spanned! {span=>
4098                    #arena.alloc_aligned::<#elem_ty>(#count as #usize_ty, #align)
4099                }
4100            }
4101            None => quote_spanned! {span=> #arena.alloc::<#elem_ty>(#count as #usize_ty) },
4102        };
4103        if self.in_cfg {
4104            let marks = vla_marks_ident();
4105            let slot = Literal::usize_unsuffixed(self.vla_slots[&def.storage]);
4106            return quote_spanned! {span=>
4107                #arena.redefine(&mut #marks, #slot);
4108                #name = #first;
4109            };
4110        }
4111        let frame = self.object_ident(def.storage, span);
4112        quote_spanned! {span=>
4113            let #frame = #arena.frame();
4114            let mut #name: *mut #elem_ty = #first;
4115        }
4116    }
4117
4118    /// A `cleanup` attribute's drop guard, in the structured lowering.
4119    ///
4120    /// The binding stands right after the object's own, so Rust drops it
4121    /// first — and drops it on every way out of the block, which is exactly
4122    /// what GCC promises. See [`ir::CleanupDef`].
4123    fn cleanup_def(&mut self, def: &ir::CleanupDef) -> TokenStream {
4124        let span = self.sp(def.range);
4125        let guard = cleanup_guard_ty();
4126        // One binding per object, in this crate's own hygiene: the C program
4127        // cannot name it, and two guards in one block cannot collide.
4128        let name = Ident::new(
4129            &format!("__cinrs_cleanup{}", def.object.0),
4130            Span::mixed_site(),
4131        );
4132        let object = self.program.object(def.object);
4133        let place = ir::Place {
4134            kind: PlaceKind::Object(def.object),
4135            ty: object.ty,
4136            is_const: object.is_const,
4137            range: def.range,
4138        };
4139        let address = self
4140            .address_of(&place, def.param, span)
4141            .at(prec::LOWEST, span);
4142        let function = self.func_pointer(def.func, span);
4143        self.uses_cleanup.set(true);
4144        quote_spanned! {span=>
4145            let #name = #guard(#address, #function);
4146        }
4147    }
4148
4149    /// `struct __cinrs_cleanup<P, R>(P, unsafe extern "C" fn(P) -> R);` and
4150    /// its `Drop`.
4151    ///
4152    /// One item per unit — each unit is a module of its own, so two of them in
4153    /// one Rust module do not collide — generated only when something asks for
4154    /// it. It is generic over the *pointer* the function takes rather than
4155    /// over the object's type, so that a `void *`-taking cleanup (the
4156    /// `_cleanup_free_` idiom) needs nothing special, and over the return
4157    /// type, which GCC ignores.
4158    fn cleanup_guard_item(&self, span: Span) -> TokenStream {
4159        let name = cleanup_guard_ty();
4160        let p = Ident::new("P", Span::mixed_site());
4161        let r = Ident::new("R", Span::mixed_site());
4162        quote_spanned! {span=>
4163            struct #name<#p: ::core::marker::Copy, #r>(#p, unsafe extern "C" fn(#p) -> #r);
4164            impl<#p: ::core::marker::Copy, #r> ::core::ops::Drop for #name<#p, #r> {
4165                fn drop(&mut self) {
4166                    unsafe {
4167                        (self.1)(self.0);
4168                    }
4169                }
4170            }
4171        }
4172    }
4173
4174    /// `Some(f as unsafe extern "C" fn(…) -> R)`: a function name used as a
4175    /// value.
4176    ///
4177    /// A method of its own rather than an arm of [`Codegen::expr`]'s match
4178    /// because that function is the recursion this module is bounded by, and in
4179    /// an unoptimised build every temporary of every arm has a stack slot of
4180    /// its own; see `expand.rs`'s `codegen_of_deeply_nested_input_fits_in_a_
4181    /// small_stack`.
4182    fn func_addr(&self, id: ir::FuncId, span: Span) -> Value {
4183        let function = self.program.function(id);
4184        let name = if function.intrinsic.is_some() {
4185            self.intrinsic_shim_name(id, span)
4186        } else {
4187            self.function_path(function, span)
4188        };
4189        let signature = self.function_pointer_ty(function, span);
4190        Value::new(
4191            quote_spanned! {span=> ::core::option::Option::Some(#name as #signature) },
4192            prec::CALL,
4193        )
4194    }
4195
4196    /// The name of the shim that stands for an x86 intrinsic whose address was
4197    /// taken, remembering that the unit needs it.
4198    ///
4199    /// `Span::mixed_site()` is the same hygiene the cleanup guard type uses: it
4200    /// puts the name out of reach of anything the C declares, so no
4201    /// `__cinrs_intrinsic_…` a program writes for itself can collide with it.
4202    fn intrinsic_shim_name(&self, id: ir::FuncId, span: Span) -> TokenStream {
4203        let function = self.program.function(id);
4204        {
4205            let mut wanted = self.address_taken.borrow_mut();
4206            if !wanted.contains(&id) {
4207                wanted.push(id);
4208            }
4209        }
4210        let name = Ident::new(
4211            &format!("__cinrs_intrinsic_{}", function.name),
4212            Span::mixed_site(),
4213        );
4214        quote_spanned! {span=> #name }
4215    }
4216
4217    /// One `unsafe extern "C" fn` per intrinsic whose address the unit took,
4218    /// forwarding to `core::arch`.
4219    ///
4220    /// The shim carries the intrinsic's own `#[target_feature]`, which is what
4221    /// GCC's `__always_inline__` header function carries too: without it a
4222    /// 256-bit vector could not be passed by value through the C ABI at all,
4223    /// and rustc refuses the definition. It is private to the unit's module —
4224    /// `pub` would put a name into the glob re-export that no C declared — and
4225    /// `#[inline]` so that the indirect call through it costs nothing when the
4226    /// optimiser can see the target. `#[inline(always)]` is deliberately *not*
4227    /// used: rustc refuses it together with `#[target_feature]`.
4228    fn intrinsic_shim_items(&self) -> TokenStream {
4229        let mut out = TokenStream::new();
4230        for id in self.address_taken.borrow().iter() {
4231            let function = self.program.function(*id);
4232            let Some(intr) = function.intrinsic else {
4233                continue;
4234            };
4235            let span = self.sp(function.range);
4236            let name = Ident::new(
4237                &format!("__cinrs_intrinsic_{}", function.name),
4238                Span::mixed_site(),
4239            );
4240            let mut params = TokenStream::new();
4241            let mut args = TokenStream::new();
4242            for (index, ty) in function.sig.params.iter().enumerate() {
4243                if index > 0 {
4244                    params.extend(quote_spanned! {span=> , });
4245                    args.extend(quote_spanned! {span=> , });
4246                }
4247                let pname = Ident::new(&format!("__cinrs_arg{index}"), Span::mixed_site());
4248                let pty = self.ty(*ty, span);
4249                params.extend(quote_spanned! {span=> #pname: #pty });
4250                // The same cast a direct call's pointer argument gets.
4251                let cast = self.intrinsic_pointer_arg(*ty, span).unwrap_or_default();
4252                args.extend(quote_spanned! {span=> #pname #cast });
4253            }
4254            let ret = if function.sig.ret.is_void() {
4255                TokenStream::new()
4256            } else {
4257                let ty = self.ty(function.sig.ret, span);
4258                quote_spanned! {span=> -> #ty }
4259            };
4260            let feature = if intr.feature.is_empty() {
4261                TokenStream::new()
4262            } else {
4263                let mut literal = Literal::string(intr.feature);
4264                literal.set_span(span);
4265                quote_spanned! {span=> #[target_feature(enable = #literal)] }
4266            };
4267            let module = self.arch_module(span);
4268            let call = Ident::new(intr.name, span);
4269            out.extend(quote_spanned! {span=>
4270                #[inline]
4271                #feature
4272                unsafe extern "C" fn #name(#params) #ret {
4273                    unsafe { ::core::arch::#module::#call(#args) }
4274                }
4275            });
4276        }
4277        out
4278    }
4279
4280    /// `f as unsafe extern "C" fn(…) -> R`, the function a drop guard holds.
4281    fn func_pointer(&self, id: ir::FuncId, span: Span) -> TokenStream {
4282        let function = self.program.function(id);
4283        let name = self.function_path(function, span);
4284        let signature = self.function_pointer_ty(function, span);
4285        quote_spanned! {span=> #name as #signature }
4286    }
4287
4288    /// A span standing for a run of statements.
4289    fn stmts_span(&self, stmts: &[Stmt]) -> Span {
4290        stmts
4291            .iter()
4292            .find_map(|s| self.stmt_range(s))
4293            .map_or_else(Span::call_site, |range| self.sp(range))
4294    }
4295
4296    /// An inline assembly statement: `::core::arch::asm!`, with the operands
4297    /// sema mapped (see `sema/asm.rs`).
4298    ///
4299    /// ```text
4300    /// {
4301    ///     let p = …;                          // each output place's setup, once
4302    ///     ::core::arch::asm!("addl {o1:e}, {o0:e}",
4303    ///         o0 = inout(reg) (*p).f,         // the place itself
4304    ///         o1 = in(reg) b,
4305    ///         out("rcx") _,
4306    ///         options(att_syntax));
4307    /// }
4308    /// ```
4309    ///
4310    /// An output is written straight into its place whenever that place is an
4311    /// ordinary Rust place expression: a [lowered place](LoweredPlace)'s
4312    /// access may be evaluated more than once and its setup — where the side
4313    /// effects of `a[i++]` or `f()->x` happen — runs exactly once, before the
4314    /// statement. Only a place that may be underaligned goes through a typed
4315    /// temporary, read with `read_unaligned` (for `+`) and stored back with
4316    /// `write_unaligned` after the statement: `asm!` would otherwise write it
4317    /// with an aligned store. Bit-fields and `_Atomic` objects never get here;
4318    /// sema refuses both.
4319    ///
4320    /// Inputs are emitted with [`Codegen::expr`], never bare: an `asm!`
4321    /// operand has no expected type, so an unsuffixed literal would be an
4322    /// `i32` whatever the C operand was, and the register would be read at the
4323    /// wrong width.
4324    fn asm_stmt(&mut self, asm: &ir::AsmStmt) -> TokenStream {
4325        let span = self.sp(asm.range);
4326        let mut setup = TokenStream::new();
4327        let mut store_back = TokenStream::new();
4328        let mut operands = TokenStream::new();
4329        for (index, operand) in asm.operands.iter().enumerate() {
4330            let op_span = self.sp(operand.range);
4331            let head = asm_operand_head(operand, op_span);
4332            let value = match &operand.kind {
4333                ir::AsmOperandKind::In(expr) => self.expr(expr).at(prec::LOWEST, op_span),
4334                ir::AsmOperandKind::Scratch(expr) => {
4335                    let value = self.expr(expr).at(prec::LOWEST, op_span);
4336                    quote_spanned! {op_span=> #value => _ }
4337                }
4338                ir::AsmOperandKind::Const(value) => asm_const_literal(*value, op_span),
4339                ir::AsmOperandKind::Out { place, .. } => {
4340                    self.asm_output(place, None, index, &mut setup, &mut store_back)
4341                }
4342                ir::AsmOperandKind::InOut { input, output } => {
4343                    let input = input
4344                        .as_ref()
4345                        .map(|expr| self.expr(expr).at(prec::LOWEST, op_span));
4346                    let read_place = input.is_none();
4347                    let target = self.asm_output(
4348                        output,
4349                        Some(read_place),
4350                        index,
4351                        &mut setup,
4352                        &mut store_back,
4353                    );
4354                    match input {
4355                        Some(input) => quote_spanned! {op_span=> #input => #target },
4356                        None => target,
4357                    }
4358                }
4359            };
4360            operands.extend(quote_spanned! {op_span=> #head #value, });
4361        }
4362        for clobber in &asm.clobbers {
4363            let name = Literal::string(clobber);
4364            operands.extend(quote_spanned! {span=> out(#name) _, });
4365        }
4366        let mut template = Literal::string(&asm.template);
4367        template.set_span(span);
4368        let call = quote_spanned! {span=>
4369            ::core::arch::asm!(#template, #operands options(att_syntax));
4370        };
4371        if setup.is_empty() && store_back.is_empty() {
4372            return call;
4373        }
4374        quote_spanned! {span=> { #setup #call #store_back } }
4375    }
4376
4377    /// Where an `asm` output goes: the place itself, or — for a place that
4378    /// may be underaligned — a temporary that is stored back afterwards.
4379    ///
4380    /// `read` is `None` for a pure output, and for an in/out operand says
4381    /// whether its input is the place's own value (GCC's `+`).
4382    fn asm_output(
4383        &mut self,
4384        place: &Place,
4385        read: Option<bool>,
4386        index: usize,
4387        setup: &mut TokenStream,
4388        store_back: &mut TokenStream,
4389    ) -> TokenStream {
4390        let span = self.sp(place.range);
4391        let lowered = self.place(place, true);
4392        setup.extend(lowered.setup.clone());
4393        if !lowered.unaligned {
4394            let access = &lowered.access;
4395            return quote_spanned! {span=> #access };
4396        }
4397        let temp = Ident::new(&format!("__cinrs_asm{index}"), span);
4398        let ty = self.ty(place.ty, span);
4399        let access = &lowered.access;
4400        // A pure output is initialised by the statement itself, exactly once.
4401        setup.extend(if read == Some(true) {
4402            quote_spanned! {span=> let mut #temp: #ty = (&raw const #access).read_unaligned(); }
4403        } else {
4404            quote_spanned! {span=> let #temp: #ty; }
4405        });
4406        store_back.extend(self.write(&lowered, quote_spanned! {span=> #temp }, span));
4407        quote_spanned! {span=> #temp }
4408    }
4409
4410    fn stmt_range(&self, stmt: &Stmt) -> Option<SourceRange> {
4411        Some(match stmt {
4412            Stmt::Expr(expr) => expr.range,
4413            Stmt::Let { object, .. } => self.program.object(*object).range,
4414            Stmt::Vla(def) => def.range,
4415            Stmt::Cleanup(def) => def.range,
4416            Stmt::If { cond, .. } => cond.range,
4417            Stmt::While { range, .. }
4418            | Stmt::DoWhile { range, .. }
4419            | Stmt::For { range, .. }
4420            | Stmt::Break { range, .. }
4421            | Stmt::Continue { range, .. }
4422            | Stmt::Return { range, .. }
4423            | Stmt::Label { range, .. }
4424            | Stmt::Case { range, .. }
4425            | Stmt::Goto { range, .. }
4426            | Stmt::GotoPtr { range, .. } => *range,
4427            Stmt::Switch(switch) => switch.range,
4428            Stmt::SwitchTree(switch) => switch.range,
4429            Stmt::Region(region) => region.range,
4430            Stmt::Asm(asm) => asm.range,
4431            Stmt::Block(items) => return items.iter().find_map(|s| self.stmt_range(s)),
4432            Stmt::Nop => return None,
4433        })
4434    }
4435
4436    fn loop_label(&self, id: LoopId, span: Span) -> TokenStream {
4437        self.label(&format!("l{}", id.0), span)
4438    }
4439
4440    fn loop_body_label(&self, id: LoopId, span: Span) -> TokenStream {
4441        self.label(&format!("l{}_body", id.0), span)
4442    }
4443
4444    fn switch_label(&self, id: ir::SwitchId, span: Span) -> TokenStream {
4445        self.label(&format!("sw{}", id.0), span)
4446    }
4447
4448    fn switch_case_label(&self, id: ir::SwitchId, index: usize, span: Span) -> TokenStream {
4449        self.label(&format!("sw{}_c{index}", id.0), span)
4450    }
4451
4452    /// The Rust label a [region](ir::Region) carries.
4453    fn region_label(&self, id: ir::LabelId, span: Span) -> TokenStream {
4454        match self.region_names.get(&id) {
4455            Some(name) => self.label(name, span),
4456            // Only a `goto` outside every region for its label, which
4457            // [`crate::regions`] does not leave behind.
4458            None => self.label(&format!("cinrs_label{}", id.0), span),
4459        }
4460    }
4461
4462    /// A labelled block or a labelled loop, and the statements inside it.
4463    ///
4464    /// The two shapes are what an outward `goto` becomes — see
4465    /// [`crate::regions`]. A loop ends with a `break` of its own so that
4466    /// falling off the end of the region leaves it; one whose body cannot
4467    /// reach its end has none, which is what lets a function ending in it need
4468    /// no `return`.
4469    fn region(&mut self, region: &ir::Region) -> TokenStream {
4470        let span = self.sp(region.range);
4471        let label = self.region_label(region.label, span);
4472        let previous = self.region_kinds.insert(region.label, region.kind);
4473        let body = self.stmts(&region.body);
4474        match previous {
4475            Some(kind) => self.region_kinds.insert(region.label, kind),
4476            None => self.region_kinds.remove(&region.label),
4477        };
4478        match region.kind {
4479            ir::RegionKind::Block => quote_spanned! {span=> #label: { #body } },
4480            ir::RegionKind::Loop if region.falls_out => quote_spanned! {span=>
4481                #label: loop { #body break #label; }
4482            },
4483            ir::RegionKind::Loop => quote_spanned! {span=> #label: loop { #body } },
4484        }
4485    }
4486
4487    /// Names the regions of a structured body, after the C labels they stand
4488    /// for.
4489    ///
4490    /// A name that Rust cannot spell as a label — a keyword, or one of the
4491    /// shapes this module gives a loop or a `switch` — gets the label's number
4492    /// appended, which no generated label can collide with; one it cannot
4493    /// spell at all, such as an extended identifier, gives up its own name.
4494    /// The block and the loop a label with jumps of both kinds gets are named
4495    /// once: they never overlap, and `break` and `continue` say which is meant.
4496    fn name_regions(&mut self, stmts: &[Stmt]) {
4497        let mut taken: HashSet<String> = HashSet::new();
4498        let mut found = Vec::new();
4499        collect_regions(stmts, &mut found);
4500        for (id, name) in found {
4501            if self.region_names.contains_key(&id) {
4502                continue;
4503            }
4504            let mut candidate = rust_spelling(&name).into_owned();
4505            if !is_label_name(&candidate) {
4506                candidate = format!("{candidate}_{}", id.0);
4507            }
4508            if !is_label_name(&candidate) {
4509                candidate = format!("cinrs_label{}", id.0);
4510            }
4511            while taken.contains(&candidate) {
4512                candidate.push('_');
4513            }
4514            taken.insert(candidate.clone());
4515            self.region_names.insert(id, candidate);
4516        }
4517    }
4518
4519    /// Builds the labelled-block chain described in the [module docs](self).
4520    fn switch(&mut self, switch: &Switch) -> TokenStream {
4521        let span = self.sp(switch.range);
4522        let scrutinee_ty = switch.scrutinee.ty;
4523        let scrutinee = self.expr(&switch.scrutinee).at(prec::UNARY, span);
4524
4525        let mut arms = TokenStream::new();
4526        for (index, group) in switch.groups.iter().enumerate() {
4527            if group.values.is_empty() {
4528                continue;
4529            }
4530            let label = self.switch_case_label(switch.id, index, span);
4531            let mut pattern = TokenStream::new();
4532            for (i, value) in group.values.iter().enumerate() {
4533                if i > 0 {
4534                    pattern.extend(quote_spanned! {span=> | });
4535                }
4536                // A pattern takes its type from the scrutinee, so the bare
4537                // literal is both correct and the most readable form.
4538                pattern.extend(case_pattern(*value, scrutinee_ty, span));
4539            }
4540            arms.extend(quote_spanned! {span=> #pattern => break #label, });
4541        }
4542        let fallback = match switch.default_group {
4543            Some(index) => self.switch_case_label(switch.id, index, span),
4544            None => self.switch_label(switch.id, span),
4545        };
4546        arms.extend(quote_spanned! {span=> _ => break #fallback, });
4547
4548        // Anything before the first label can never be reached, but it is still
4549        // part of the program and may declare things later groups use.
4550        let prelude = self.stmts(&switch.prelude);
4551        let mut inner = quote_spanned! {span=> match #scrutinee { #arms } #prelude };
4552        for (index, group) in switch.groups.iter().enumerate() {
4553            let label = self.switch_case_label(switch.id, index, span);
4554            let body = self.stmts(&group.body);
4555            inner = quote_spanned! {span=> #label: { #inner } #body };
4556        }
4557
4558        let mut hoisted = TokenStream::new();
4559        for id in &switch.hoisted {
4560            let object = self.program.object(*id);
4561            let ospan = self.sp(object.range);
4562            let name = self.object_ident(*id, ospan);
4563            let ty = self.binding_ty(*id, self.ty(object.ty, ospan), ospan);
4564            let zero = self.zero_tokens(object.ty, ospan);
4565            let zero = self.binding_init(*id, zero, ospan);
4566            hoisted.extend(quote_spanned! {ospan=> let mut #name: #ty = #zero; });
4567        }
4568
4569        let label = self.switch_label(switch.id, span);
4570        // The extra block keeps the hoisted declarations from shadowing
4571        // anything the enclosing block declared under the same name.
4572        quote_spanned! {span=>
4573            {
4574                #hoisted
4575                #label: { #inner }
4576            }
4577        }
4578    }
4579
4580    /// Emits an expression evaluated for its side effects.
4581    fn expr_stmt(&mut self, expr: &Expr) -> TokenStream {
4582        let span = self.sp(expr.range);
4583        match &expr.kind {
4584            ExprKind::Assign { place, value } => {
4585                let lowered = self.place(place, true);
4586                let value = self.expr_at(value, self.program.types.unatomic(place.ty));
4587                let store = self.write(&lowered, value, span);
4588                let setup = &lowered.setup;
4589                quote_spanned! {span=> #setup #store }
4590            }
4591            ExprKind::CompoundAssign {
4592                place,
4593                op,
4594                value,
4595                compute,
4596            } => {
4597                let lowered = self.place(place, true);
4598                if lowered.atomic.is_some() {
4599                    let kind = PlaceRmw::Compound {
4600                        op: *op,
4601                        value,
4602                        compute: *compute,
4603                    };
4604                    return self.atomic_place_rmw(&lowered, kind, RmwValue::None, span);
4605                }
4606                let (hoist, rhs) = self.compound_rhs(value);
4607                let current = self.read(&lowered, span);
4608                let updated = self.compound_value(current, place.ty, *op, value, rhs, *compute);
4609                let updated = updated.at(prec::LOWEST, span);
4610                let store = self.write(&lowered, updated, span);
4611                let setup = &lowered.setup;
4612                quote_spanned! {span=> #setup #hoist #store }
4613            }
4614            ExprKind::IncDec { place, dec, .. } => {
4615                let lowered = self.place(place, true);
4616                if lowered.atomic.is_some() {
4617                    let kind = PlaceRmw::Step { dec: *dec };
4618                    return self.atomic_place_rmw(&lowered, kind, RmwValue::None, span);
4619                }
4620                let current = self.read(&lowered, span);
4621                let next = self.step_value(current, place.ty, *dec, span);
4622                let store = self.write(&lowered, next, span);
4623                let setup = &lowered.setup;
4624                quote_spanned! {span=> #setup #store }
4625            }
4626            ExprKind::Call { .. } => {
4627                // A call to a `_Noreturn` function does not come back, and
4628                // Rust has to be told: the call's own type is whatever the
4629                // function was declared to return, so a function that ends in
4630                // `exit(1);` would otherwise be missing its value. The
4631                // `unreachable!()` is a panic rather than
4632                // `unreachable_unchecked`, because it is *this crate* putting
4633                // it there.
4634                let diverges = ir::expr_never_returns(expr, &self.program.functions);
4635                let tokens = self.expr(expr).at(prec::LOWEST, span);
4636                if diverges {
4637                    quote_spanned! {span=> #tokens; ::core::unreachable!(); }
4638                } else {
4639                    quote_spanned! {span=> #tokens; }
4640                }
4641            }
4642            ExprKind::Unreachable => {
4643                quote_spanned! {span=> ::core::hint::unreachable_unchecked(); }
4644            }
4645            // A store, a `clear` and a fence have no value at all, in C or in
4646            // the Rust they become; the `let _ =` the fallback below would
4647            // wrap them in says nothing.
4648            ExprKind::Atomic(_) if expr.ty.is_void() => {
4649                let tokens = self.expr(expr).at(prec::LOWEST, span);
4650                quote_spanned! {span=> #tokens; }
4651            }
4652            ExprKind::Comma { .. } => {
4653                // A chain of comma operators is a flat sequence of statements
4654                // — and one stack frame per operand if it is walked
4655                // recursively, which a four-thousand-character logical source
4656                // line cannot afford. See [`Codegen::binary_chain`].
4657                let mut out = TokenStream::new();
4658                for operand in comma_operands(expr) {
4659                    out.extend(self.expr_stmt(operand));
4660                }
4661                out
4662            }
4663            ExprKind::Cond { .. } => {
4664                // A chain of them is `if … else if … else …`, built without
4665                // recursing down the chain; see [`Codegen::cond_chain`].
4666                let mut spine = Vec::new();
4667                let mut node = expr;
4668                while let ExprKind::Cond {
4669                    cond,
4670                    then_expr,
4671                    else_expr,
4672                } = &node.kind
4673                {
4674                    let span = self.sp(node.range);
4675                    let cond_tokens = self.condition(cond).at_condition(span);
4676                    let then_tokens = self.expr_stmt(then_expr);
4677                    spine.push((cond_tokens, then_tokens, span));
4678                    node = else_expr;
4679                }
4680                let mut tokens = self.expr_stmt(node);
4681                while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
4682                    tokens = quote_spanned! {span=>
4683                        if #cond_tokens { #then_tokens } else { #tokens }
4684                    };
4685                }
4686                tokens
4687            }
4688            // `(void)x;` evaluates and discards, which is what the fall-through
4689            // below does anyway; unwrapping keeps the output tidy.
4690            ExprKind::Cast(inner) if expr.ty.is_void() => self.expr_stmt(inner),
4691            // `va_end(ap);` is a statement that does nothing at all.
4692            ExprKind::VaEnd => TokenStream::new(),
4693            _ => {
4694                let tokens = self.expr(expr).at(prec::LOWEST, span);
4695                quote_spanned! {span=> let _ = #tokens; }
4696            }
4697        }
4698    }
4699
4700    // -- expressions --------------------------------------------------------
4701
4702    /// Emits an expression whose type the surrounding context already fixes.
4703    ///
4704    /// A constant then needs no `as`, which is the difference between
4705    /// `let mut i: c_int = 0;` and `let mut i: c_int = 0 as c_int;`. It is the
4706    /// *only* place a bare literal is emitted from, and the reason it is safe
4707    /// is that every caller writes the tokens somewhere the type is already
4708    /// stated — the annotation of a `let`, a place being assigned to, a
4709    /// parameter, a field, the return type of the function.
4710    ///
4711    /// [`Codegen::expr`] has no such promise, so nothing it produces may
4712    /// depend on inference; that is what the conditional below is about.
4713    fn expr_at(&mut self, expr: &Expr, expected: Ty) -> TokenStream {
4714        let span = self.sp(expr.range);
4715        if expr.ty == expected {
4716            match &expr.kind {
4717                ExprKind::Int(value) => return bare_int_literal(*value, expected, span),
4718                ExprKind::Float(value) if value.is_finite() => {
4719                    return bare_float_literal(*value, span);
4720                }
4721                // The arms of a conditional may stay bare here, because
4722                // whatever fixes this expression's type fixes theirs — unless
4723                // the type is `void`, where the arms have no common type and
4724                // [`Codegen::expr`] emits each of them as a statement.
4725                ExprKind::Cond { .. } if !expected.is_void() => {
4726                    return self.cond_chain_at(expr, expected);
4727                }
4728                _ => {}
4729            }
4730        }
4731        self.expr(expr).at(prec::LOWEST, span)
4732    }
4733
4734    fn expr(&mut self, expr: &Expr) -> Value {
4735        let value = self.expr_value(expr);
4736        // A chain of binary operators reduces each of its own nodes; see
4737        // `Codegen::binary_chain`.
4738        if matches!(expr.kind, ExprKind::Binary { .. }) {
4739            return value;
4740        }
4741        self.reduce_bits(value, expr)
4742    }
4743
4744    /// Reduces a computed value to the precision the expression is evaluated
4745    /// in, which is narrower than its type only for a wide bit-field; see
4746    /// [`ir::Expr::bits`].
4747    ///
4748    /// Only an operator whose result can leave the field's range needs it: a
4749    /// bitwise `&`, `|` or `^` of two forty-bit values is a forty-bit value
4750    /// already, and so is a quotient, a remainder or a right shift.
4751    fn reduce_bits(&mut self, value: Value, expr: &Expr) -> Value {
4752        let Some(bits) = expr.bits else {
4753            return value;
4754        };
4755        let width = expr.ty.bits(&self.options.target);
4756        let overflows = match &expr.kind {
4757            ExprKind::Binary { op, .. } => {
4758                matches!(op, BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Shl)
4759            }
4760            ExprKind::Neg(_) | ExprKind::BitNot(_) => true,
4761            _ => false,
4762        };
4763        if !overflows || !expr.ty.is_integer() || bits == 0 || bits >= width {
4764            return value;
4765        }
4766        let span = self.sp(expr.range);
4767        if expr.ty.is_signed(&self.options.target) {
4768            // Sign extension: the two shifts are what a narrower signed type
4769            // does to a value that has just overflowed out of it.
4770            let shift = Literal::u32_unsuffixed(width - bits);
4771            let tokens = value.at(prec::CALL, span);
4772            return Value::new(
4773                quote_spanned! {span=> #tokens.wrapping_shl(#shift).wrapping_shr(#shift) },
4774                prec::CALL,
4775            );
4776        }
4777        let mask = bare_int_literal(((1u128 << bits) - 1) as i128, expr.ty, span);
4778        let tokens = value.at(prec::BIT_AND, span);
4779        Value::new(quote_spanned! {span=> #tokens & #mask }, prec::BIT_AND)
4780    }
4781
4782    fn expr_value(&mut self, expr: &Expr) -> Value {
4783        let span = self.sp(expr.range);
4784        match &expr.kind {
4785            ExprKind::Int(value) => self.int_literal(*value, expr.ty, span),
4786            ExprKind::Float(value) => self.float_literal(*value, expr.ty, span),
4787            ExprKind::Zeroed => Value::new(self.zero_tokens(expr.ty, span), zero_prec(expr.ty)),
4788            // Reading a `va_list` copies it: Rust's is not `Copy`, and C says
4789            // a list passed on is indeterminate afterwards anyway.
4790            ExprKind::Load(place) if place.ty.is_va_list() => self.va_list_load(place, span),
4791            ExprKind::Load(place) => {
4792                let lowered = self.place(place, false);
4793                let value = self.read(&lowered, span);
4794                if lowered.setup.is_empty() {
4795                    value
4796                } else {
4797                    let setup = &lowered.setup;
4798                    let tokens = value.at(prec::LOWEST, span);
4799                    Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
4800                }
4801            }
4802            ExprKind::AddrOf(place) => self.address_of(place, expr.ty, span),
4803            ExprKind::FuncAddr(id) => self.func_addr(*id, span),
4804            // GNU's `&&label`. The value is the label's number, cast to the
4805            // pointer type the expression has — which is what `goto *`'s
4806            // dispatch matches on, and what lets a dispatch table be an
4807            // ordinary array of `void *`.
4808            ExprKind::LabelAddr(id) => self.label_address(*id, expr.ty, span),
4809            ExprKind::Assign { .. } => self.assign_chain(expr),
4810            ExprKind::CompoundAssign {
4811                place,
4812                op,
4813                value,
4814                compute,
4815            } => {
4816                let lowered = self.place(place, true);
4817                if lowered.atomic.is_some() {
4818                    let kind = PlaceRmw::Compound {
4819                        op: *op,
4820                        value,
4821                        compute: *compute,
4822                    };
4823                    let tokens = self.atomic_place_rmw(&lowered, kind, RmwValue::New, span);
4824                    return Value::new(tokens, prec::BLOCK);
4825                }
4826                let (hoist, rhs) = self.compound_rhs(value);
4827                let current = self.read(&lowered, span);
4828                let updated = self.compound_value(current, place.ty, *op, value, rhs, *compute);
4829                let updated = updated.at(prec::LOWEST, span);
4830                let store = self.write(&lowered, updated, span);
4831                let read = self.read(&lowered, span).at(prec::LOWEST, span);
4832                let setup = &lowered.setup;
4833                Value::new(
4834                    quote_spanned! {span=> { #setup #hoist #store #read } },
4835                    prec::BLOCK,
4836                )
4837            }
4838            ExprKind::IncDec {
4839                place,
4840                dec,
4841                postfix,
4842            } => {
4843                let lowered = self.place(place, true);
4844                if lowered.atomic.is_some() {
4845                    let want = if *postfix {
4846                        RmwValue::Old
4847                    } else {
4848                        RmwValue::New
4849                    };
4850                    let tokens =
4851                        self.atomic_place_rmw(&lowered, PlaceRmw::Step { dec: *dec }, want, span);
4852                    return Value::new(tokens, prec::BLOCK);
4853                }
4854                let current = self.read(&lowered, span);
4855                let next = self.step_value(current, place.ty, *dec, span);
4856                let store = self.write(&lowered, next, span);
4857                let read = self.read(&lowered, span).at(prec::LOWEST, span);
4858                let setup = &lowered.setup;
4859                if *postfix {
4860                    let tmp = self.temporary();
4861                    Value::new(
4862                        quote_spanned! {span=>
4863                            { #setup let #tmp = #read; #store #tmp }
4864                        },
4865                        prec::BLOCK,
4866                    )
4867                } else {
4868                    Value::new(
4869                        quote_spanned! {span=> { #setup #store #read } },
4870                        prec::BLOCK,
4871                    )
4872                }
4873            }
4874            // The three complex shapes are one call apiece: this function is
4875            // the one code generation recurses through, and every local in it
4876            // costs a slice of the stack `rustc` gives macro expansion.
4877            ExprKind::ComplexOf { re, im } => self.complex_literal(expr.ty, re, im, span),
4878            ExprKind::Neg(operand) if expr.ty.is_complex() => self.complex_neg(operand, span),
4879            ExprKind::BitNot(operand) if expr.ty.is_complex() => {
4880                self.complex_conj(operand, expr.ty, span)
4881            }
4882            ExprKind::Neg(operand) => {
4883                let value = self.expr(operand);
4884                if expr.ty.is_floating() {
4885                    let ends_with_type = value.ends_with_type;
4886                    let tokens = value.at(prec::UNARY, span);
4887                    Value::new(quote_spanned! {span=> -#tokens }, prec::UNARY)
4888                        .type_end(ends_with_type)
4889                } else {
4890                    // Signed overflow is undefined in C and a panic in Rust;
4891                    // wrapping is the predictable choice, and it is what
4892                    // unsigned arithmetic requires anyway.
4893                    let tokens = value.at(prec::CALL, span);
4894                    Value::new(quote_spanned! {span=> #tokens.wrapping_neg() }, prec::CALL)
4895                }
4896            }
4897            ExprKind::BitNot(operand) => {
4898                let value = self.expr(operand);
4899                let ends_with_type = value.ends_with_type;
4900                let tokens = value.at(prec::UNARY, span);
4901                Value::new(quote_spanned! {span=> !#tokens }, prec::UNARY).type_end(ends_with_type)
4902            }
4903            ExprKind::Binary { .. } => self.binary_chain(expr),
4904            ExprKind::PtrOffset { ptr, index, sub } => {
4905                let pointee = self.program.types.pointee(ptr.ty).unwrap_or(Ty::Void);
4906                let base = self.expr(ptr).at(prec::CALL, span);
4907                let offset = self.scaled_offset(pointee, index, *sub, span);
4908                Value::new(quote_spanned! {span=> #base.offset(#offset) }, prec::CALL)
4909            }
4910            // GNU's label difference, `&&a - &&b`. Both operands are state
4911            // numbers rather than addresses, so the subtraction is done on the
4912            // numbers: `offset_from` would want two pointers into one object,
4913            // and a `static` table of such differences — which is the whole
4914            // idiom — needs an expression a `const` can fold.
4915            ExprKind::PtrDiff { lhs, rhs }
4916                if label_state(lhs).is_some() && label_state(rhs).is_some() =>
4917            {
4918                self.label_difference(lhs, rhs, expr.ty, span)
4919            }
4920            ExprKind::PtrDiff { lhs, rhs } => {
4921                let pointee = self.program.types.pointee(lhs.ty).unwrap_or(Ty::Void);
4922                let scale = self.vm_scale(pointee, span);
4923                let left = self.expr(lhs).at(prec::CALL, span);
4924                let right = self.expr(rhs).at(prec::LOWEST, span);
4925                let target = self.ty(expr.ty, span);
4926                // The difference the generated pointers give is in step-type
4927                // elements; C's is in whole ones.
4928                let difference = match scale {
4929                    None => quote_spanned! {span=> #left.offset_from(#right) },
4930                    Some(scale) => {
4931                        quote_spanned! {span=> (#left.offset_from(#right) / (#scale)) }
4932                    }
4933                };
4934                Value::new(quote_spanned! {span=> #difference as #target }, prec::CAST)
4935                    .type_end(true)
4936            }
4937            ExprKind::Compare { .. } | ExprKind::Logical { .. } => {
4938                // C's comparisons and logical operators produce an `int`.
4939                let condition = self.condition(expr).at(prec::LOWEST, span);
4940                let ty = self.ty(Ty::Int, span);
4941                let parens = parenthesize(condition, span);
4942                Value::new(quote_spanned! {span=> #parens as #ty }, prec::CAST).type_end(true)
4943            }
4944            // `(void)x` and a `void`-typed conditional have no value at all:
4945            // Rust's `()` is not something `as` produces, so each of them is
4946            // emitted as the statement it is, wrapped in a block whose own
4947            // value is `()`. A conditional gets here when it is written where
4948            // a value is expected — the left operand of a comma is a
4949            // statement, but the right one is not.
4950            ExprKind::Cast(inner) if expr.ty.is_void() => {
4951                let tokens = self.expr_stmt(inner);
4952                Value::new(quote_spanned! {span=> { #tokens } }, prec::BLOCK)
4953            }
4954            ExprKind::Cond { .. } if expr.ty.is_void() => {
4955                let tokens = self.expr_stmt(expr);
4956                Value::new(quote_spanned! {span=> { #tokens } }, prec::BLOCK)
4957            }
4958            ExprKind::Cast(inner) => {
4959                let from = inner.ty;
4960                let value = self.expr(inner);
4961                self.cast(value, from, expr.ty, span)
4962            }
4963            // Both arms are emitted as expressions of their own rather than at
4964            // the conditional's type: an `if` whose arms are two bare literals
4965            // is `{integer}`, which Rust either resolves to `i32` — wrong
4966            // wherever C said `long` — or refuses to resolve at all, as it
4967            // does for the receiver of `wrapping_mul` (`E0689`). The bare form
4968            // is still used from [`Codegen::expr_at`], where the context says
4969            // what the type is.
4970            ExprKind::Cond { .. } => self.cond_chain(expr),
4971            ExprKind::Comma { lhs, rhs } => {
4972                let lhs = self.expr_stmt(lhs);
4973                let rhs = self.expr(rhs).at(prec::LOWEST, span);
4974                Value::new(quote_spanned! {span=> { #lhs #rhs } }, prec::BLOCK)
4975            }
4976            ExprKind::Call { callee, args } => self.call(callee, args, span),
4977            ExprKind::RecordLit { record, fields } => self.record_literal(*record, fields, span),
4978            ExprKind::UnionLit {
4979                record,
4980                index,
4981                value,
4982            } => self.union_literal(*record, *index, value, span),
4983            ExprKind::ArrayLit(items) => {
4984                let elem = self.program.types.elem(expr.ty).unwrap_or(Ty::Int);
4985                let mut tokens = TokenStream::new();
4986                for (index, item) in items.iter().enumerate() {
4987                    if index > 0 {
4988                        tokens.extend(quote_spanned! {span=> , });
4989                    }
4990                    tokens.extend(self.expr_at(item, elem));
4991                }
4992                Value::atom(bracketed(tokens, span))
4993            }
4994            ExprKind::ArrayRepeat { value, len } => {
4995                let elem = self.program.types.elem(expr.ty).unwrap_or(value.ty);
4996                let tokens = self.expr_at(value, elem);
4997                let len = usize_literal(*len, span);
4998                Value::atom(bracketed(quote_spanned! {span=> #tokens ; #len }, span))
4999            }
5000            // GNU's `a ?: b`. The value is held in a temporary so that the
5001            // operand is evaluated exactly once, which is the whole point.
5002            ExprKind::CondDefault { value, else_expr } => {
5003                let ty = expr.ty;
5004                let first = self.expr_at(value, ty);
5005                let other = self.expr_at(else_expr, ty);
5006                let tmp = self.temporary();
5007                let target = self.ty(ty, span);
5008                let test = if ty.is_pointer() {
5009                    quote_spanned! {span=> !#tmp.is_null() }
5010                } else {
5011                    let zero = self.zero_tokens(ty, span);
5012                    quote_spanned! {span=> #tmp != #zero }
5013                };
5014                Value::new(
5015                    quote_spanned! {span=>
5016                        { let #tmp: #target = #first; if #test { #tmp } else { #other } }
5017                    },
5018                    prec::BLOCK,
5019                )
5020            }
5021            // GNU's statement expression, which is what a Rust block is.
5022            ExprKind::StmtExpr { stmts, value } => {
5023                let body = self.stmts(stmts);
5024                let tail = match value {
5025                    Some(value) => {
5026                        let ty = expr.ty;
5027                        self.expr_at(value, ty)
5028                    }
5029                    None => TokenStream::new(),
5030                };
5031                Value::new(quote_spanned! {span=> { #body #tail } }, prec::BLOCK)
5032            }
5033            ExprKind::Builtin { op, args } => self.builtin(*op, args, span),
5034            ExprKind::Atomic(atomic) => self.atomic(atomic, span),
5035            ExprKind::VaListPristine => Value::new(self.va_pristine(span), prec::CALL),
5036            ExprKind::VaArg { ap, record } => self.va_arg(ap, record.as_deref(), expr.ty, span),
5037            // `va_end` is nothing: the list ends when its value is dropped.
5038            ExprKind::VaEnd => Value::atom(quote_spanned! {span=> () }),
5039            // C23's `unreachable()`. C says reaching it is undefined, and
5040            // saying so to Rust is what lets the optimiser use the promise —
5041            // this is the one place the expansion trusts the C program with
5042            // undefined behaviour, because the program asked for it by name.
5043            ExprKind::Unreachable => Value::new(
5044                quote_spanned! {span=> ::core::hint::unreachable_unchecked() },
5045                prec::CALL,
5046            ),
5047        }
5048    }
5049
5050    // -- complex ------------------------------------------------------------
5051
5052    /// `::cinrs::rt::Complex::<f64>::new(re, im)`.
5053    ///
5054    /// A call rather than a struct literal, and with the component type spelled
5055    /// out: `Complex { … }` at the start of an `if` condition would be read as
5056    /// the condition's block, and a bare `0.0` part would infer `f64` where the
5057    /// type is `float _Complex`. `Complex::new` is a `const fn`, so this is
5058    /// also what a `static` initialiser holds.
5059    fn complex_new(&self, ty: Ty, re: TokenStream, im: TokenStream, span: Span) -> Value {
5060        self.uses_complex.set(true);
5061        let rt = self.rt_path(span);
5062        let component = primitive_ty(if ty == Ty::ComplexFloat { "f32" } else { "f64" }, span);
5063        Value::new(
5064            quote_spanned! {span=> #rt::Complex::<#component>::new(#re, #im) },
5065            prec::CALL,
5066        )
5067    }
5068
5069    /// `__builtin_complex(re, im)`, an imaginary constant, and a folded
5070    /// complex constant: the two parts, side by side.
5071    fn complex_literal(&mut self, ty: Ty, re: &Expr, im: &Expr, span: Span) -> Value {
5072        let re = self.expr(re).at(prec::LOWEST, span);
5073        let im = self.expr(im).at(prec::LOWEST, span);
5074        self.complex_new(ty, re, im, span)
5075    }
5076
5077    /// `-z`, which is `num_complex`'s own `Neg` — both parts negated exactly.
5078    fn complex_neg(&mut self, operand: &Expr, span: Span) -> Value {
5079        let tokens = self.expr(operand).at(prec::UNARY, span);
5080        Value::new(quote_spanned! {span=> -#tokens }, prec::UNARY)
5081    }
5082
5083    /// GNU's `~z` and `__builtin_conj(z)`: the conjugate.
5084    fn complex_conj(&mut self, operand: &Expr, ty: Ty, span: Span) -> Value {
5085        let tokens = self.expr(operand).at(prec::LOWEST, span);
5086        let conj = self.rt_complex(&format!("conj_{}", Self::complex_suffix(ty)), span);
5087        Value::new(quote_spanned! {span=> #conj(#tokens) }, prec::CALL)
5088    }
5089
5090    /// `+`, `-`, `*` or `/` with at least one complex operand.
5091    ///
5092    /// Each operand arrives with the C type its tokens have, because that is
5093    /// what decides which runtime function is called: C computes a *real*
5094    /// operand componentwise rather than widening it — see `cinrs_rt::complex`
5095    /// for what that changes and why. Two complex operands add and subtract
5096    /// through `num_complex`'s own operators, which are exactly componentwise,
5097    /// and multiply and divide through Annex G.
5098    fn complex_binary(
5099        &mut self,
5100        op: BinOp,
5101        (lhs, lhs_ty): (Value, Ty),
5102        (rhs, rhs_ty): (Value, Ty),
5103        ty: Ty,
5104        span: Span,
5105    ) -> Value {
5106        self.uses_complex.set(true);
5107        let suffix = Self::complex_suffix(ty);
5108        let both = lhs_ty.is_complex() && rhs_ty.is_complex();
5109        if both && matches!(op, BinOp::Add | BinOp::Sub) {
5110            let (level, tokens) = match op {
5111                BinOp::Add => (prec::SUM, quote_spanned! {span=> + }),
5112                _ => (prec::SUM, quote_spanned! {span=> - }),
5113            };
5114            let mut out = lhs.at(level, span);
5115            let rhs = rhs.at(level + 1, span);
5116            out.extend(quote_spanned! {span=> #tokens #rhs });
5117            return Value::new(out, level);
5118        }
5119        // `<what>_<suffix>`, with the name saying which operand is the real
5120        // one: `mul_real` is `z * x` and `real_mul` is `x * z`.
5121        let name = match (op, lhs_ty.is_complex(), rhs_ty.is_complex()) {
5122            (BinOp::Add, true, false) => "add_real",
5123            (BinOp::Add, false, true) => "real_add",
5124            (BinOp::Sub, true, false) => "sub_real",
5125            (BinOp::Sub, false, true) => "real_sub",
5126            (BinOp::Mul, true, true) => "mul",
5127            (BinOp::Mul, true, false) => "mul_real",
5128            (BinOp::Mul, false, true) => "real_mul",
5129            (BinOp::Div, true, true) => "div",
5130            (BinOp::Div, true, false) => "div_real",
5131            (BinOp::Div, false, true) => "real_div",
5132            // Sema refuses every other operator on a complex operand, and one
5133            // of the two always is complex.
5134            _ => unreachable!("'{}' does not reach complex code generation", op.as_str()),
5135        };
5136        let func = self.rt_complex(&format!("{name}_{suffix}"), span);
5137        let lhs = lhs.at(prec::LOWEST, span);
5138        let rhs = rhs.at(prec::LOWEST, span);
5139        Value::new(quote_spanned! {span=> #func(#lhs, #rhs) }, prec::CALL)
5140    }
5141
5142    /// A conversion with a complex type on one side or the other
5143    /// (C99 6.3.1.6, 6.3.1.7).
5144    fn complex_cast(&mut self, value: Value, from: Ty, to: Ty, span: Span) -> Value {
5145        self.uses_complex.set(true);
5146        if from.is_complex() && to.is_complex() {
5147            let name = if to == Ty::ComplexDouble {
5148                "widen_f32"
5149            } else {
5150                "narrow_f64"
5151            };
5152            let func = self.rt_complex(name, span);
5153            let tokens = value.at(prec::LOWEST, span);
5154            return Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL);
5155        }
5156        if to.is_complex() {
5157            // A real value becomes a complex one with a zero imaginary part.
5158            let component = to.complex_component();
5159            let re = self
5160                .cast(value, from, component, span)
5161                .at(prec::LOWEST, span);
5162            let zero = bare_float_literal(0.0, span);
5163            return self.complex_new(to, re, zero, span);
5164        }
5165        // Converting a complex value to a real type discards the imaginary
5166        // part — except for `_Bool`, which asks whether *either* part is
5167        // non-zero (C99 6.3.1.2).
5168        if to.is_bool() {
5169            let func = self.rt_complex(&format!("nonzero_{}", Self::complex_suffix(from)), span);
5170            let tokens = value.at(prec::LOWEST, span);
5171            return Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL);
5172        }
5173        let tokens = value.at(prec::CALL, span);
5174        let real = Value::new(quote_spanned! {span=> #tokens.re }, prec::CALL);
5175        self.cast(real, from.complex_component(), to, span)
5176    }
5177
5178    /// `z == w` and `z != w` (C99 6.5.9p3: equal exactly when both parts are).
5179    ///
5180    /// Rust's own `==` would give the same answer — the runtime's complex type
5181    /// derives `PartialEq` — and it is *not* used, because `PartialEq::eq`
5182    /// takes `&self`: a reference to a field of a `#[repr(packed)]` record is
5183    /// `E0793`, and a packed `__complex__ float` member compared against a
5184    /// constant is exactly `gcc.c-torture/execute/20020227-1`. The runtime's
5185    /// by-value equality asks for a *copy* of each operand, which a packed
5186    /// field will give.
5187    ///
5188    /// Sema converts both operands to one complex type before this, so a
5189    /// mixed real/complex comparison never arrives here.
5190    fn complex_equality(&mut self, op: CmpOp, lhs: &Expr, rhs: &Expr, span: Span) -> Value {
5191        self.uses_complex.set(true);
5192        let name = match op {
5193            CmpOp::Eq => "eq",
5194            CmpOp::Ne => "ne",
5195            // 6.5.8p2 gives the relational operators real operands only, and
5196            // sema has already said so.
5197            other => unreachable!("{other:?} does not reach a complex comparison"),
5198        };
5199        let func = self.rt_complex(&format!("{name}_{}", Self::complex_suffix(lhs.ty)), span);
5200        let (lhs, rhs) = self.operands(lhs, rhs, BinOp::BitOr);
5201        let lhs = lhs.at(prec::LOWEST, span);
5202        let rhs = rhs.at(prec::LOWEST, span);
5203        Value::new(quote_spanned! {span=> #func(#lhs, #rhs) }, prec::CALL)
5204    }
5205
5206    /// `z != 0` as Rust's `bool`: what an `if`, a `while` and `!z` ask of a
5207    /// complex value.
5208    fn complex_condition(&mut self, expr: &Expr, span: Span) -> Value {
5209        self.uses_complex.set(true);
5210        let func = self.rt_complex(&format!("nonzero_{}", Self::complex_suffix(expr.ty)), span);
5211        let tokens = self.expr(expr).at(prec::LOWEST, span);
5212        Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL)
5213    }
5214
5215    /// A `struct` value: one expression per member, in declaration order.
5216    ///
5217    /// Without bit-fields this is a plain Rust struct literal. With them the
5218    /// members that share a storage field have to be *packed* into it: every
5219    /// constant one is folded into the `[u8; K]` there and then, which is what
5220    /// lets a `static` — where nothing may run — hold a bit-field at all, and
5221    /// what makes the byte pattern visible in the expansion. A member whose
5222    /// value is not constant is stored afterwards through its setter, so the
5223    /// literal becomes a block.
5224    fn record_literal(&mut self, record: ir::RecordId, fields: &[Expr], span: Span) -> Value {
5225        let def = self.program.types.record(record).clone();
5226        // An initialised flexible array member makes the value the *companion*
5227        // type's rather than the record's: the tail is as long as the
5228        // initialiser, and the member's value carries that length.
5229        let tail = def
5230            .fields
5231            .iter()
5232            .position(|field| field.flexible)
5233            .and_then(|index| {
5234                Some((
5235                    index,
5236                    array_len(&self.program.types, fields.get(index)?.ty)?,
5237                ))
5238            })
5239            .filter(|(_, len)| *len > 0);
5240        let name = match tail {
5241            Some((_, len)) => self.flexible_ident(&def.rust_name, len, span),
5242            None => self.c_ident(&def.rust_name, span),
5243        };
5244        let mut packed: HashMap<String, Vec<u8>> = HashMap::new();
5245        let mut dynamic: Vec<usize> = Vec::new();
5246        for rust_field in &def.rust_fields {
5247            if let ir::RustField::Bits { name, bytes, .. } = rust_field {
5248                packed.insert(name.clone(), vec![0u8; *bytes as usize]);
5249            }
5250        }
5251        for (index, field) in def.fields.iter().enumerate() {
5252            let Some(bits) = &field.bits else { continue };
5253            match fields.get(index).and_then(constant_bits) {
5254                Some(value) => {
5255                    if let Some(storage) = packed.get_mut(&bits.storage) {
5256                        pack_bits(storage, bits, value);
5257                    }
5258                }
5259                None => dynamic.push(index),
5260            }
5261        }
5262
5263        let mut items = TokenStream::new();
5264        for rust_field in &def.rust_fields {
5265            match rust_field {
5266                ir::RustField::Member(index) => {
5267                    let field = &def.fields[*index];
5268                    let fname = self.c_ident(&field.name, span);
5269                    // The flexible member's value is longer than its own type,
5270                    // and the companion's field is what it fills.
5271                    let value = &fields[*index];
5272                    let want = match tail {
5273                        Some((flexible, _)) if flexible == *index => value.ty,
5274                        _ => field.ty,
5275                    };
5276                    let tokens = self.expr_at(value, want);
5277                    items.extend(quote_spanned! {span=> #fname: #tokens, });
5278                }
5279                ir::RustField::Bits { name, .. } => {
5280                    let fname = Ident::new(name, span);
5281                    let value = byte_array(&packed[name], span);
5282                    items.extend(quote_spanned! {span=> #fname: #value, });
5283                }
5284                ir::RustField::Pad { name, bytes } => {
5285                    let fname = Ident::new(name, span);
5286                    let len = usize_literal(*bytes, span);
5287                    items.extend(quote_spanned! {span=> #fname: [0; #len], });
5288                }
5289                ir::RustField::Align { name, .. } => {
5290                    let fname = Ident::new(name, span);
5291                    items.extend(quote_spanned! {span=> #fname: [], });
5292                }
5293            }
5294        }
5295        let body = braced(items, span);
5296        let literal = quote_spanned! {span=> #name #body };
5297        if dynamic.is_empty() {
5298            return Value::new(literal, prec::ATOM);
5299        }
5300        // The members that are not constants are stored through their setters,
5301        // in declaration order, which is one of the orders C allows.
5302        let tmp = self.temporary();
5303        let ty = self.ty(Ty::Record(record), span);
5304        let mut stores = TokenStream::new();
5305        for index in dynamic {
5306            let field = &def.fields[index];
5307            let bits = field.bits.as_ref().expect("only bit-fields are deferred");
5308            let setter = self.c_ident(&bits.setter, span);
5309            let value = self.expr_at(&fields[index], field.ty);
5310            stores.extend(quote_spanned! {span=> #tmp.#setter(#value); });
5311        }
5312        Value::new(
5313            quote_spanned! {span=>
5314                { let mut #tmp: #ty = #literal; #stores #tmp }
5315            },
5316            prec::BLOCK,
5317        )
5318    }
5319
5320    /// A `union` value, which initialises exactly one member.
5321    fn union_literal(
5322        &mut self,
5323        record: ir::RecordId,
5324        index: usize,
5325        value: &Expr,
5326        span: Span,
5327    ) -> Value {
5328        let def = self.program.types.record(record).clone();
5329        let name = self.c_ident(&def.rust_name, span);
5330        let field = &def.fields[index];
5331        let Some(bits) = &field.bits else {
5332            let fname = self.c_ident(&field.name, span);
5333            let tokens = self.expr_at(value, field.ty);
5334            let body = braced(quote_spanned! {span=> #fname: #tokens }, span);
5335            return Value::new(quote_spanned! {span=> #name #body }, prec::ATOM);
5336        };
5337        let bytes = def
5338            .rust_fields
5339            .iter()
5340            .find_map(|rust_field| match rust_field {
5341                ir::RustField::Bits { name, bytes, .. } if *name == bits.storage => Some(*bytes),
5342                _ => None,
5343            })
5344            .unwrap_or(0);
5345        let mut packed = vec![0u8; bytes as usize];
5346        let constant = constant_bits(value);
5347        if let Some(constant) = constant {
5348            pack_bits(&mut packed, bits, constant);
5349        }
5350        let storage = Ident::new(&bits.storage, span);
5351        let array = byte_array(&packed, span);
5352        let body = braced(quote_spanned! {span=> #storage: #array }, span);
5353        let literal = quote_spanned! {span=> #name #body };
5354        if constant.is_some() {
5355            return Value::new(literal, prec::ATOM);
5356        }
5357        let tmp = self.temporary();
5358        let ty = self.ty(Ty::Record(record), span);
5359        let setter = self.c_ident(&bits.setter, span);
5360        let value = self.expr_at(value, field.ty);
5361        Value::new(
5362            quote_spanned! {span=>
5363                { let mut #tmp: #ty = #literal; #tmp.#setter(#value); #tmp }
5364            },
5365            prec::BLOCK,
5366        )
5367    }
5368
5369    /// One of the builtins that becomes a fixed piece of Rust.
5370    ///
5371    /// The bit-manipulation ones are the integer methods of the same name, on
5372    /// the *unsigned* type of the operand's width — C's are defined on
5373    /// unsigned values and Rust's `leading_zeros` counts the same way. The
5374    /// overflow ones do the arithmetic in `i128` and ask whether the value
5375    /// survives the round trip through the type it is stored in, which is
5376    /// exactly "compute in infinite precision, then convert".
5377    fn builtin(&mut self, op: ir::BuiltinOp, args: &[Expr], span: Span) -> Value {
5378        use ir::BuiltinOp;
5379        let int = self.ty(Ty::Int, span);
5380        match op {
5381            BuiltinOp::ComplexProj => {
5382                let ty = args[0].ty;
5383                let func = self.rt_complex(&format!("proj_{}", Self::complex_suffix(ty)), span);
5384                let value = self.expr(&args[0]).at(prec::LOWEST, span);
5385                Value::new(quote_spanned! {span=> #func(#value) }, prec::CALL)
5386            }
5387            BuiltinOp::Discard => {
5388                let mut out = TokenStream::new();
5389                for arg in args {
5390                    out.extend(self.expr_stmt(arg));
5391                }
5392                Value::new(quote_spanned! {span=> { #out } }, prec::BLOCK)
5393            }
5394            // A hint, so dropping it is always correct, and it is dropped
5395            // where emitting it would change what compiles: a safe function
5396            // has no `unsafe` block for the call to sit in, and only x86 and
5397            // AArch64 have a stable way to say it.
5398            BuiltinOp::Prefetch(packed) => {
5399                let (write, locality) = ir::prefetch_hint(packed);
5400                let arch = self.options.target.arch;
5401                let pointer = self.expr(&args[0]).at(prec::LOWEST, span);
5402                let tmp = self.temporary();
5403                let prefetch = match arch {
5404                    _ if self.in_safe => TokenStream::new(),
5405                    // `_mm_prefetch` has no form for writing without
5406                    // `prefetchw`, which is a feature of its own, so `rw` is
5407                    // not passed on. The hints are GCC's: locality 3 is
5408                    // `prefetcht0`, 0 is `prefetchnta`. The `cfg` is for a
5409                    // 32-bit target without SSE (`i586`), where there is
5410                    // nothing to call; x86-64 always has SSE.
5411                    crate::target::Arch::X86 | crate::target::Arch::X86_64 => {
5412                        let module = self.arch_module(span);
5413                        let hint = Ident::new(
5414                            ["_MM_HINT_NTA", "_MM_HINT_T2", "_MM_HINT_T1", "_MM_HINT_T0"]
5415                                [usize::from(locality)],
5416                            span,
5417                        );
5418                        let sse = if arch == crate::target::Arch::X86 {
5419                            quote_spanned! {span=> #[cfg(target_feature = "sse")] }
5420                        } else {
5421                            TokenStream::new()
5422                        };
5423                        quote_spanned! {span=>
5424                            #sse
5425                            ::core::arch::#module::_mm_prefetch::<{ ::core::arch::#module::#hint }>(
5426                                #tmp.cast::<i8>()
5427                            );
5428                        }
5429                    }
5430                    // GCC's choice of `prfm` operation for each locality.
5431                    crate::target::Arch::Aarch64 => {
5432                        let kind = if write { "pst" } else { "pld" };
5433                        let level = ["l1strm", "l3keep", "l2keep", "l1keep"][usize::from(locality)];
5434                        let mut template = Literal::string(&format!("prfm {kind}{level}, [{{0}}]"));
5435                        template.set_span(span);
5436                        quote_spanned! {span=>
5437                            ::core::arch::asm!(
5438                                #template,
5439                                in(reg) #tmp,
5440                                options(nostack, preserves_flags, readonly)
5441                            );
5442                        }
5443                    }
5444                    _ => TokenStream::new(),
5445                };
5446                Value::new(
5447                    quote_spanned! {span=> { let #tmp = #pointer; #prefetch } },
5448                    prec::BLOCK,
5449                )
5450            }
5451            // `__builtin_cpu_supports("avx2")` asks the processor, exactly as
5452            // it does in C, and the answer is an `int` because that is what
5453            // GCC's builtin returns. Several features for one GCC name — `abm`
5454            // is LZCNT and POPCNT — are all of them or nothing.
5455            BuiltinOp::CpuSupports(row) => {
5456                let mut test = TokenStream::new();
5457                for (index, feature) in crate::x86::detect_features(row).iter().enumerate() {
5458                    if index > 0 {
5459                        test.extend(quote_spanned! {span=> && });
5460                    }
5461                    let mut literal = Literal::string(feature);
5462                    literal.set_span(span);
5463                    // The root path, not `std::arch`'s: `is_x86_feature_detected`
5464                    // has been a `std` root macro since 1.27, which is older
5465                    // than anything this crate supports.
5466                    test.extend(quote_spanned! {span=> ::std::is_x86_feature_detected!(#literal) });
5467                }
5468                Value::new(quote_spanned! {span=> ((#test) as #int) }, prec::LOWEST)
5469            }
5470            // Sixteen-byte aligned bytes off the function's arena, which no
5471            // variable length array's frame gives back: they live until the
5472            // function returns. See [`Codegen::arena_items`].
5473            BuiltinOp::Alloca => {
5474                let arena = self.arena_ident(span);
5475                let size = self.expr(&args[0]).at(prec::CAST, span);
5476                let usize_ty = primitive_ty("usize", span);
5477                Value::new(
5478                    quote_spanned! {span=> #arena.alloca(#size as #usize_ty) },
5479                    prec::CALL,
5480                )
5481            }
5482            BuiltinOp::Bswap => {
5483                let operand = args[0].ty;
5484                let value = self.unsigned_operand(&args[0], span);
5485                let target = self.ty(operand, span);
5486                Value::new(
5487                    quote_spanned! {span=> #value.swap_bytes() as #target },
5488                    prec::CAST,
5489                )
5490                .type_end(true)
5491            }
5492            BuiltinOp::Popcount => {
5493                let value = self.unsigned_operand(&args[0], span);
5494                Value::new(
5495                    quote_spanned! {span=> #value.count_ones() as #int },
5496                    prec::CAST,
5497                )
5498                .type_end(true)
5499            }
5500            BuiltinOp::Parity => {
5501                let value = self.unsigned_operand(&args[0], span);
5502                Value::new(
5503                    quote_spanned! {span=> (#value.count_ones() & 1) as #int },
5504                    prec::CAST,
5505                )
5506                .type_end(true)
5507            }
5508            BuiltinOp::Clz => {
5509                let value = self.unsigned_operand(&args[0], span);
5510                Value::new(
5511                    quote_spanned! {span=> #value.leading_zeros() as #int },
5512                    prec::CAST,
5513                )
5514                .type_end(true)
5515            }
5516            BuiltinOp::Ctz => {
5517                let value = self.unsigned_operand(&args[0], span);
5518                Value::new(
5519                    quote_spanned! {span=> #value.trailing_zeros() as #int },
5520                    prec::CAST,
5521                )
5522                .type_end(true)
5523            }
5524            BuiltinOp::Ffs => {
5525                let value = self.unsigned_operand(&args[0], span);
5526                let tmp = self.temporary();
5527                Value::new(
5528                    quote_spanned! {span=>
5529                        { let #tmp = #value;
5530                          if #tmp == 0 { 0 } else { #tmp.trailing_zeros() as #int + 1 } }
5531                    },
5532                    prec::BLOCK,
5533                )
5534            }
5535            // The number of leading bits that repeat the sign bit, not
5536            // counting the sign bit itself — which is what `leading_zeros` of
5537            // the value XORed with itself shifted left gives.
5538            BuiltinOp::Clrsb => {
5539                let width = args[0].ty.bits(&self.options.target);
5540                let signed = signed_rust_ty(width, span);
5541                let value = self.expr(&args[0]).at(prec::CAST, span);
5542                let tmp = self.temporary();
5543                let bits = usize_literal(u64::from(width), span);
5544                Value::new(
5545                    quote_spanned! {span=>
5546                        { let #tmp = #value as #signed;
5547                          ((#tmp ^ (#tmp << 1)).leading_zeros() as #int)
5548                              .min(#bits as #int - 1) }
5549                    },
5550                    prec::BLOCK,
5551                )
5552            }
5553            BuiltinOp::Overflow(bin) | BuiltinOp::OverflowP(bin) => {
5554                let store = matches!(op, BuiltinOp::Overflow(_));
5555                // The third operand carries the result type: the pointee of
5556                // the pointer the value is stored through, or the type of the
5557                // expression the `_p` forms only ask about.
5558                let result_ty = if store {
5559                    self.program.types.pointee(args[2].ty).unwrap_or(Ty::Int)
5560                } else {
5561                    args[2].ty
5562                };
5563                self.overflow_builtin(bin, args, store, result_ty, span)
5564            }
5565            BuiltinOp::Fabs => {
5566                let bits = self.float_bits_of(&args[0], span);
5567                let (float_ty, mask) = float_bit_ty(args[0].ty, span);
5568                Value::new(
5569                    quote_spanned! {span=> <#float_ty>::from_bits(#bits & #mask) },
5570                    prec::CALL,
5571                )
5572            }
5573            BuiltinOp::Copysign => {
5574                let magnitude = self.float_bits_of(&args[0], span);
5575                let sign = self.float_bits_of(&args[1], span);
5576                let (float_ty, mask) = float_bit_ty(args[0].ty, span);
5577                Value::new(
5578                    quote_spanned! {span=>
5579                        <#float_ty>::from_bits((#magnitude & #mask) | (#sign & !#mask))
5580                    },
5581                    prec::CALL,
5582                )
5583            }
5584            BuiltinOp::FloatOrder(order) => self.float_order(order, args, span),
5585            BuiltinOp::FloatClass(class) => self.float_class(class, &args[0], span),
5586            BuiltinOp::Fpclassify => {
5587                let value = self.expr(&args[5]).at(prec::CALL, span);
5588                let arms = ["Nan", "Infinite", "Normal", "Subnormal", "Zero"]
5589                    .iter()
5590                    .zip(args)
5591                    .map(|(name, answer)| {
5592                        let variant = Ident::new(name, span);
5593                        let answer = self.expr_at(answer, Ty::Int);
5594                        quote_spanned! {span=>
5595                            ::core::num::FpCategory::#variant => #answer,
5596                        }
5597                    })
5598                    .collect::<TokenStream>();
5599                Value::new(
5600                    quote_spanned! {span=> match #value.classify() { #arms } },
5601                    prec::BLOCK,
5602                )
5603            }
5604        }
5605    }
5606
5607    /// A floating operand as the unsigned integer of its own width.
5608    fn float_bits_of(&mut self, arg: &Expr, span: Span) -> TokenStream {
5609        let value = self.expr(arg).at(prec::CALL, span);
5610        parenthesize(quote_spanned! {span=> #value.to_bits() }, span)
5611    }
5612
5613    /// `__builtin_isgreater` and its relatives.
5614    ///
5615    /// Rust's floating comparisons are the quiet ones, which is exactly what
5616    /// C99 7.12.14 asks these for; the operands go into temporaries because
5617    /// two of the six mention each of them twice.
5618    fn float_order(&mut self, order: ir::FloatOrder, args: &[Expr], span: Span) -> Value {
5619        use ir::FloatOrder;
5620        let int = self.ty(Ty::Int, span);
5621        let lhs = self.expr(&args[0]).at(prec::LOWEST, span);
5622        let rhs = self.expr(&args[1]).at(prec::LOWEST, span);
5623        let (a, b) = (self.temporary(), self.temporary());
5624        let test = match order {
5625            FloatOrder::Greater => quote_spanned! {span=> #a > #b },
5626            FloatOrder::GreaterEqual => quote_spanned! {span=> #a >= #b },
5627            FloatOrder::Less => quote_spanned! {span=> #a < #b },
5628            FloatOrder::LessEqual => quote_spanned! {span=> #a <= #b },
5629            FloatOrder::LessGreater => quote_spanned! {span=> #a < #b || #a > #b },
5630            FloatOrder::Unordered => quote_spanned! {span=> #a.is_nan() || #b.is_nan() },
5631        };
5632        Value::new(
5633            quote_spanned! {span=>
5634                { let #a = #lhs; let #b = #rhs; (#test) as #int }
5635            },
5636            prec::BLOCK,
5637        )
5638    }
5639
5640    /// `__builtin_isnan` and its relatives.
5641    ///
5642    /// The predicates are `core`'s own, which are pure inspections of the bit
5643    /// pattern and so need nothing of the maths library; `issignaling` is the
5644    /// one that has no method, and is a NaN whose leading mantissa bit — the
5645    /// quiet bit — is clear.
5646    fn float_class(&mut self, class: ir::FloatClass, arg: &Expr, span: Span) -> Value {
5647        use ir::FloatClass;
5648        let int = self.ty(Ty::Int, span);
5649        let method = |name: &str| Ident::new(name, span);
5650        let test = match class {
5651            FloatClass::IsNan => Some(method("is_nan")),
5652            FloatClass::IsInf => Some(method("is_infinite")),
5653            FloatClass::IsFinite => Some(method("is_finite")),
5654            FloatClass::IsNormal => Some(method("is_normal")),
5655            FloatClass::SignBit => Some(method("is_sign_negative")),
5656            FloatClass::IsInfSign | FloatClass::IsSignaling => None,
5657        };
5658        if let Some(test) = test {
5659            let value = self.expr(arg).at(prec::CALL, span);
5660            return Value::new(quote_spanned! {span=> #value.#test() as #int }, prec::CAST)
5661                .type_end(true);
5662        }
5663        let tmp = self.temporary();
5664        let value = self.expr(arg).at(prec::LOWEST, span);
5665        if class == FloatClass::IsInfSign {
5666            return Value::new(
5667                quote_spanned! {span=>
5668                    { let #tmp = #value;
5669                      if #tmp.is_infinite() {
5670                          if #tmp.is_sign_negative() { -1 as #int } else { 1 as #int }
5671                      } else { 0 as #int } }
5672                },
5673                prec::BLOCK,
5674            );
5675        }
5676        // A signalling NaN is a NaN with the quiet bit clear: bit 51 of a
5677        // `double` and bit 22 of a `float`.
5678        let quiet = quiet_bit_literal(arg.ty, span);
5679        Value::new(
5680            quote_spanned! {span=>
5681                { let #tmp = #value;
5682                  (#tmp.is_nan() && (#tmp.to_bits() & #quiet) == 0) as #int }
5683            },
5684            prec::BLOCK,
5685        )
5686    }
5687
5688    // -- atomics ------------------------------------------------------------
5689
5690    /// `::core::sync::atomic::AtomicU32`, or `AtomicPtr<c_void>`.
5691    fn atomic_path(&self, class: AtomicClass, span: Span) -> TokenStream {
5692        if matches!(class, AtomicClass::Ptr | AtomicClass::FnPtr) {
5693            let void = self.pointee_ty(Ty::Void, span);
5694            return quote_spanned! {span=>
5695                ::core::sync::atomic::AtomicPtr::<#void>
5696            };
5697        }
5698        let name = Ident::new(class.rust_name(), span);
5699        quote_spanned! {span=> ::core::sync::atomic::#name }
5700    }
5701
5702    /// The Rust type the atomic holds, which is what its `from_ptr` points at.
5703    ///
5704    /// Every pointer goes through one `AtomicPtr<c_void>`: all object pointers
5705    /// have the same representation, and the value is cast back to the C type
5706    /// it came from as it comes out. A function pointer goes through the same
5707    /// one, transmuted rather than cast.
5708    fn atomic_repr_ty(&self, class: AtomicClass, span: Span) -> TokenStream {
5709        if matches!(class, AtomicClass::Ptr | AtomicClass::FnPtr) {
5710            let void = self.pointee_ty(Ty::Void, span);
5711            return quote_spanned! {span=> *mut #void };
5712        }
5713        primitive_ty(class.repr_name(), span)
5714    }
5715
5716    /// `AtomicU32::from_ptr(p as *mut u32)`, the `&AtomicU32` everything else
5717    /// is a method call on.
5718    ///
5719    /// `from_ptr` is safe to build here for the reason C gives: the object is
5720    /// properly aligned for its own type, and the atomic's alignment is that
5721    /// type's size, which is what [`ir::Types::size_align`] gives an
5722    /// `_Atomic` and what sema checks before it accepts a pointer to a plain
5723    /// one.
5724    fn atomic_ref(&self, class: AtomicClass, ptr: TokenStream, span: Span) -> TokenStream {
5725        let path = self.atomic_path(class, span);
5726        let repr = self.atomic_repr_ty(class, span);
5727        quote_spanned! {span=> #path::from_ptr(#ptr as *mut #repr) }
5728    }
5729
5730    /// `::core::sync::atomic::Ordering::SeqCst`.
5731    fn ordering(&self, order: ir::MemOrder, span: Span) -> TokenStream {
5732        let name = Ident::new(order.rust_name(), span);
5733        quote_spanned! {span=> ::core::sync::atomic::Ordering::#name }
5734    }
5735
5736    /// The value an atomic yields, as the C type the object has.
5737    fn repr_to_value(&self, class: AtomicClass, ty: Ty, value: TokenStream, span: Span) -> Value {
5738        match class {
5739            AtomicClass::Bool => Value::atom(value),
5740            AtomicClass::Float { bytes } => {
5741                let float = primitive_ty(if bytes == 4 { "f32" } else { "f64" }, span);
5742                Value::new(
5743                    quote_spanned! {span=> <#float>::from_bits(#value) },
5744                    prec::CALL,
5745                )
5746            }
5747            AtomicClass::Int { .. } | AtomicClass::Ptr => {
5748                let target = self.ty(ty, span);
5749                Value::new(quote_spanned! {span=> #value as #target }, prec::CAST).type_end(true)
5750            }
5751            // `*mut c_void` to `Option<unsafe extern "C" fn(…)>`: `as` does
5752            // not go that way, and the two have the same size and the same
5753            // null, so the conversion is one `transmute` with both types
5754            // written out — an inferred one here would be a bug waiting to
5755            // happen.
5756            AtomicClass::FnPtr => {
5757                let repr = self.atomic_repr_ty(class, span);
5758                let target = self.ty(ty, span);
5759                Value::new(
5760                    quote_spanned! {span=>
5761                        ::core::mem::transmute::<#repr, #target>(#value)
5762                    },
5763                    prec::CALL,
5764                )
5765            }
5766        }
5767    }
5768
5769    /// A C value, as the Rust primitive the atomic holds. `ty` is the C type
5770    /// the value has, which only the function-pointer class needs.
5771    fn value_to_repr(&self, class: AtomicClass, ty: Ty, value: Value, span: Span) -> TokenStream {
5772        match class {
5773            AtomicClass::Bool => value.at(prec::LOWEST, span),
5774            AtomicClass::Float { bytes } => {
5775                let float = primitive_ty(if bytes == 4 { "f32" } else { "f64" }, span);
5776                let value = value.at(prec::LOWEST, span);
5777                quote_spanned! {span=> <#float>::to_bits(#value) }
5778            }
5779            AtomicClass::Int { .. } | AtomicClass::Ptr => {
5780                let repr = self.atomic_repr_ty(class, span);
5781                let value = value.at(prec::CAST, span);
5782                quote_spanned! {span=> #value as #repr }
5783            }
5784            // The other half of [`Codegen::repr_to_value`]'s transmute.
5785            AtomicClass::FnPtr => {
5786                let repr = self.atomic_repr_ty(class, span);
5787                let source = self.ty(ty, span);
5788                let value = value.at(prec::LOWEST, span);
5789                quote_spanned! {span=>
5790                    ::core::mem::transmute::<#source, #repr>(#value)
5791                }
5792            }
5793        }
5794    }
5795
5796    /// `match … { Ok(v) | Err(v) => v }`, which is how the old value is taken
5797    /// out of a `fetch_update` that never says no.
5798    fn either_way(&mut self, result: TokenStream, span: Span) -> TokenStream {
5799        let value = self.temporary();
5800        quote_spanned! {span=>
5801            match #result {
5802                ::core::result::Result::Ok(#value) | ::core::result::Result::Err(#value) => #value,
5803            }
5804        }
5805    }
5806
5807    /// The compare-exchange loop an operation Rust has no method for becomes,
5808    /// whose value is the **old** one.
5809    ///
5810    /// `updated` is the new value written in terms of `current`, and is
5811    /// recomputed on every attempt, which is exactly what C's "read, modify,
5812    /// write, atomically" comes to when the processor has no single
5813    /// instruction for it — a `fetch_nand`, a `*=` on an atomic object, a
5814    /// pointer that moves by elements.
5815    ///
5816    /// Written out rather than left to `Atomic::fetch_update`: that method is
5817    /// being renamed to `try_update`, and the old name is deprecated on newer
5818    /// toolchains while the new one does not exist on the oldest this crate
5819    /// supports. The loop is what it does anyway.
5820    fn atomic_cas_loop(
5821        &mut self,
5822        object: &TokenStream,
5823        current: &Ident,
5824        updated: TokenStream,
5825        order: ir::MemOrder,
5826        span: Span,
5827    ) -> TokenStream {
5828        let success = self.ordering(order, span);
5829        let failure = self.ordering(order.failure_order(), span);
5830        let slot = self.temporary();
5831        let fresh = self.temporary();
5832        let seen = self.temporary();
5833        quote_spanned! {span=>
5834            {
5835                let #slot = #object;
5836                let mut #current = #slot.load(#failure);
5837                loop {
5838                    let #fresh = #updated;
5839                    match #slot.compare_exchange_weak(#current, #fresh, #success, #failure) {
5840                        ::core::result::Result::Ok(_) => break #current,
5841                        ::core::result::Result::Err(#seen) => #current = #seen,
5842                    }
5843                }
5844            }
5845        }
5846    }
5847
5848    /// One of the atomic builtins; see [`ir::AtomicExpr`].
5849    fn atomic(&mut self, atomic: &ir::AtomicExpr, span: Span) -> Value {
5850        let class = atomic.class;
5851        let success = self.ordering(atomic.success, span);
5852        if let ir::AtomicOp::Fence { signal } = atomic.op {
5853            // C11 7.17.4p2 makes a relaxed fence a no-op, and Rust's `fence`
5854            // panics on one rather than saying so.
5855            if atomic.success == ir::MemOrder::Relaxed {
5856                return Value::atom(quote_spanned! {span=> () });
5857            }
5858            let name = Ident::new(if signal { "compiler_fence" } else { "fence" }, span);
5859            return Value::new(
5860                quote_spanned! {span=> ::core::sync::atomic::#name(#success) },
5861                prec::CALL,
5862            );
5863        }
5864        let ptr = match &atomic.ptr {
5865            Some(ptr) => self.expr(ptr).at(prec::CAST, span),
5866            None => return Value::atom(quote_spanned! {span=> () }),
5867        };
5868        let object = self.atomic_ref(class, ptr, span);
5869        let ty = atomic.value_ty;
5870        match atomic.op {
5871            ir::AtomicOp::Fence { .. } => unreachable!("handled above"),
5872            ir::AtomicOp::Load => self.repr_to_value(
5873                class,
5874                ty,
5875                quote_spanned! {span=> #object.load(#success) },
5876                span,
5877            ),
5878            ir::AtomicOp::Store => {
5879                let value = self.atomic_operand(atomic, span);
5880                Value::new(
5881                    quote_spanned! {span=> #object.store(#value, #success) },
5882                    prec::CALL,
5883                )
5884            }
5885            ir::AtomicOp::Exchange => {
5886                let value = self.atomic_operand(atomic, span);
5887                self.repr_to_value(
5888                    class,
5889                    ty,
5890                    quote_spanned! {span=> #object.swap(#value, #success) },
5891                    span,
5892                )
5893            }
5894            ir::AtomicOp::Clear => Value::new(
5895                quote_spanned! {span=> #object.store(0, #success) },
5896                prec::CALL,
5897            ),
5898            // GCC sets the byte to `__GCC_ATOMIC_TEST_AND_SET_TRUEVAL`, which
5899            // is 1, and answers whether it was already set.
5900            ir::AtomicOp::TestAndSet => Value::new(
5901                quote_spanned! {span=> #object.swap(1, #success) != 0 },
5902                prec::CMP,
5903            ),
5904            ir::AtomicOp::CompareExchange { weak } => {
5905                self.compare_exchange(atomic, object, weak, span)
5906            }
5907            ir::AtomicOp::SyncCompareSwap { value_is_old } => {
5908                self.sync_compare_swap(atomic, object, value_is_old, span)
5909            }
5910            ir::AtomicOp::Rmw { op, returns_new } => {
5911                self.atomic_rmw(atomic, object, op, returns_new, span)
5912            }
5913        }
5914    }
5915
5916    /// The value operand of an atomic builtin, as the atomic's own type.
5917    fn atomic_operand(&mut self, atomic: &ir::AtomicExpr, span: Span) -> TokenStream {
5918        let Some(value) = &atomic.value else {
5919            return quote_spanned! {span=> () };
5920        };
5921        let value = self.expr(value);
5922        self.value_to_repr(atomic.class, atomic.value_ty, value, span)
5923    }
5924
5925    /// `__atomic_compare_exchange_n`, which writes the value it observed back
5926    /// through `expected` when it fails and answers whether it succeeded.
5927    fn compare_exchange(
5928        &mut self,
5929        atomic: &ir::AtomicExpr,
5930        object: TokenStream,
5931        weak: bool,
5932        span: Span,
5933    ) -> Value {
5934        let class = atomic.class;
5935        let ty = atomic.value_ty;
5936        let expected = match &atomic.expected {
5937            Some(expected) => self.expr(expected).at(prec::CALL, span),
5938            None => return Value::atom(quote_spanned! {span=> false }),
5939        };
5940        let desired = self.atomic_operand(atomic, span);
5941        let slot = self.temporary();
5942        let seen = self.temporary();
5943        let current = self.value_to_repr(
5944            class,
5945            ty,
5946            Value::atom(quote_spanned! {span=> *#slot }),
5947            span,
5948        );
5949        let method = Ident::new(
5950            if weak {
5951                "compare_exchange_weak"
5952            } else {
5953                "compare_exchange"
5954            },
5955            span,
5956        );
5957        let success = self.ordering(atomic.success, span);
5958        let failure = self.ordering(atomic.failure, span);
5959        let observed = self
5960            .repr_to_value(class, ty, quote_spanned! {span=> #seen }, span)
5961            .at(prec::LOWEST, span);
5962        Value::new(
5963            quote_spanned! {span=>
5964                {
5965                    let #slot = #expected;
5966                    match #object.#method(#current, #desired, #success, #failure) {
5967                        ::core::result::Result::Ok(_) => true,
5968                        ::core::result::Result::Err(#seen) => {
5969                            *#slot = #observed;
5970                            false
5971                        }
5972                    }
5973                }
5974            },
5975            prec::BLOCK,
5976        )
5977    }
5978
5979    /// `__sync_bool_compare_and_swap` and `__sync_val_compare_and_swap`, whose
5980    /// expected value is a value and which write nothing back.
5981    fn sync_compare_swap(
5982        &mut self,
5983        atomic: &ir::AtomicExpr,
5984        object: TokenStream,
5985        value_is_old: bool,
5986        span: Span,
5987    ) -> Value {
5988        let class = atomic.class;
5989        let ty = atomic.value_ty;
5990        let expected = match &atomic.expected {
5991            Some(expected) => {
5992                let value = self.expr(expected);
5993                self.value_to_repr(class, ty, value, span)
5994            }
5995            None => return Value::atom(quote_spanned! {span=> false }),
5996        };
5997        let desired = self.atomic_operand(atomic, span);
5998        let seq = self.ordering(ir::MemOrder::SeqCst, span);
5999        let call = quote_spanned! {span=>
6000            #object.compare_exchange(#expected, #desired, #seq, #seq)
6001        };
6002        if !value_is_old {
6003            return Value::new(quote_spanned! {span=> #call.is_ok() }, prec::CALL);
6004        }
6005        let old = self.either_way(call, span);
6006        self.repr_to_value(class, ty, parenthesize(old, span), span)
6007    }
6008
6009    /// The `fetch_add` family, and the compare-exchange loops the ones Rust
6010    /// has no method for turn into.
6011    fn atomic_rmw(
6012        &mut self,
6013        atomic: &ir::AtomicExpr,
6014        object: TokenStream,
6015        op: ir::AtomicRmw,
6016        returns_new: bool,
6017        span: Span,
6018    ) -> Value {
6019        let class = atomic.class;
6020        let ty = atomic.value_ty;
6021        let success = self.ordering(atomic.success, span);
6022        let operand = self.temporary();
6023        let old = self.temporary();
6024        // A pointer moves by *bytes*: the scaling C11 wants for
6025        // `atomic_fetch_add` is already in the operand, put there by sema.
6026        if class == AtomicClass::Ptr {
6027            let delta = match &atomic.value {
6028                Some(value) => self.expr(value).at(prec::CAST, span),
6029                None => quote_spanned! {span=> 0 },
6030            };
6031            let isize_ty = primitive_ty("isize", span);
6032            let signed = if op == ir::AtomicRmw::Sub {
6033                quote_spanned! {span=> -(#delta as #isize_ty) }
6034            } else {
6035                quote_spanned! {span=> #delta as #isize_ty }
6036            };
6037            let step = self.temporary();
6038            let updated = self.atomic_cas_loop(
6039                &object,
6040                &step,
6041                quote_spanned! {span=> #step.wrapping_byte_offset(#operand) },
6042                atomic.success,
6043                span,
6044            );
6045            let tail = if returns_new {
6046                quote_spanned! {span=> #old.wrapping_byte_offset(#operand) }
6047            } else {
6048                quote_spanned! {span=> #old }
6049            };
6050            let tail = self
6051                .repr_to_value(class, ty, tail, span)
6052                .at(prec::LOWEST, span);
6053            return Value::new(
6054                quote_spanned! {span=>
6055                    {
6056                        let #operand: #isize_ty = #signed;
6057                        let #old = #updated;
6058                        #tail
6059                    }
6060                },
6061                prec::BLOCK,
6062            );
6063        }
6064        let value = self.atomic_operand(atomic, span);
6065        let repr = self.atomic_repr_ty(class, span);
6066        // `fetch_nand` exists for `AtomicBool` and for nothing else, so an
6067        // integer nand is the compare-exchange loop Rust would have written.
6068        let update = match op.rust_method() {
6069            Some(method) if op != ir::AtomicRmw::Nand || class == AtomicClass::Bool => {
6070                let method = Ident::new(method, span);
6071                quote_spanned! {span=> #object.#method(#operand, #success) }
6072            }
6073            _ if class == AtomicClass::Bool => {
6074                let method = Ident::new("fetch_nand", span);
6075                quote_spanned! {span=> #object.#method(#operand, #success) }
6076            }
6077            _ => {
6078                let current = self.temporary();
6079                self.atomic_cas_loop(
6080                    &object,
6081                    &current,
6082                    quote_spanned! {span=> !(#current & #operand) },
6083                    atomic.success,
6084                    span,
6085                )
6086            }
6087        };
6088        let combined = self.atomic_combine(op, &old, &operand, span);
6089        let tail = if returns_new {
6090            combined
6091        } else {
6092            quote_spanned! {span=> #old }
6093        };
6094        let tail = self
6095            .repr_to_value(class, ty, tail, span)
6096            .at(prec::LOWEST, span);
6097        Value::new(
6098            quote_spanned! {span=>
6099                {
6100                    let #operand: #repr = #value;
6101                    let #old = #update;
6102                    #tail
6103                }
6104            },
6105            prec::BLOCK,
6106        )
6107    }
6108
6109    /// The read-modify-write an `x += v`, `x++` or `--x` on an `_Atomic`
6110    /// object performs.
6111    ///
6112    /// C11 6.5.16.2p3 and 6.5.2.4p2 make each of them *one* atomic
6113    /// read-modify-write, not a load and a store, so none of them may go
6114    /// through [`Codegen::read`] and [`Codegen::write`]. The five operators an
6115    /// atomic has a method for become that method; everything else — `*=`,
6116    /// `<<=`, a floating object, a pointer that moves by elements — becomes
6117    /// the `fetch_update` loop the method would have been.
6118    ///
6119    /// The right operand is always evaluated into a temporary first: the
6120    /// update is written twice when the value of the expression is the new
6121    /// one, and C evaluates it once.
6122    fn atomic_place_rmw(
6123        &mut self,
6124        lowered: &LoweredPlace,
6125        kind: PlaceRmw<'_>,
6126        want: RmwValue,
6127        span: Span,
6128    ) -> TokenStream {
6129        let (class, ty) = lowered.atomic.expect("an atomic place");
6130        let object = self.atomic_object_of(lowered, span);
6131        let setup = &lowered.setup;
6132        let operand = self.temporary();
6133        let old = self.temporary();
6134        let success = self.ordering(ir::MemOrder::SeqCst, span);
6135        // The one shape that is a plain `fetch_*`: an integer object whose
6136        // operator is one of the five, computed in the object's own type, so
6137        // that no widening happens between the read and the write.
6138        let method = match (class, &kind) {
6139            (
6140                AtomicClass::Int { .. },
6141                PlaceRmw::Compound {
6142                    op,
6143                    compute,
6144                    value: _,
6145                },
6146            ) if *compute == ty => rmw_of_binop(*op),
6147            (AtomicClass::Int { .. }, PlaceRmw::Step { dec }) => Some(if *dec {
6148                ir::AtomicRmw::Sub
6149            } else {
6150                ir::AtomicRmw::Add
6151            }),
6152            _ => None,
6153        };
6154        if let Some(op) = method.filter(|op| op.rust_method().is_some()) {
6155            let repr = self.atomic_repr_ty(class, span);
6156            let value = match &kind {
6157                PlaceRmw::Compound { value, compute, .. } => {
6158                    let tokens = self.expr_at(value, *compute);
6159                    self.value_to_repr(class, ty, Value::new(tokens, prec::LOWEST), span)
6160                }
6161                PlaceRmw::Step { .. } => quote_spanned! {span=> 1 },
6162            };
6163            let name = Ident::new(op.rust_method().expect("filtered"), span);
6164            let tail = self.atomic_rmw_tail((class, ty), op, &old, &operand, want, span);
6165            return quote_spanned! {span=>
6166                { #setup
6167                  let #operand: #repr = #value;
6168                  let #old = #object.#name(#operand, #success);
6169                  #tail }
6170            };
6171        }
6172        // The general form: a compare-exchange loop over the very expression
6173        // an ordinary compound assignment would have stored.
6174        let hoisted = match &kind {
6175            PlaceRmw::Compound { value, compute, .. } => {
6176                let tokens = self.expr_at(value, *compute);
6177                let rhs_ty = self.ty(*compute, span);
6178                Some(quote_spanned! {span=> let #operand: #rhs_ty = #tokens; })
6179            }
6180            PlaceRmw::Step { .. } => None,
6181        };
6182        let param = self.temporary();
6183        let current = self.repr_to_value(class, ty, quote_spanned! {span=> #param }, span);
6184        let updated = self.apply_place_rmw(&kind, current, ty, &operand, span);
6185        let updated = self.value_to_repr(class, ty, updated, span);
6186        let loop_result =
6187            self.atomic_cas_loop(&object, &param, updated, ir::MemOrder::SeqCst, span);
6188        let tail = match want {
6189            RmwValue::None => TokenStream::new(),
6190            RmwValue::Old => self
6191                .repr_to_value(class, ty, quote_spanned! {span=> #old }, span)
6192                .at(prec::LOWEST, span),
6193            RmwValue::New => {
6194                let previous = self.repr_to_value(class, ty, quote_spanned! {span=> #old }, span);
6195                let value = self.apply_place_rmw(&kind, previous, ty, &operand, span);
6196                value.at(prec::LOWEST, span)
6197            }
6198        };
6199        quote_spanned! {span=>
6200            { #setup #hoisted
6201              let #old = #loop_result;
6202              #tail }
6203        }
6204    }
6205
6206    /// The new value of an atomic place, from the old one.
6207    fn apply_place_rmw(
6208        &mut self,
6209        kind: &PlaceRmw<'_>,
6210        current: Value,
6211        ty: Ty,
6212        operand: &Ident,
6213        span: Span,
6214    ) -> Value {
6215        match kind {
6216            PlaceRmw::Compound { op, value, compute } => {
6217                let rhs = Value::atom(quote_spanned! {span=> #operand });
6218                self.compound_value(current, ty, *op, value, Some(rhs), *compute)
6219            }
6220            PlaceRmw::Step { dec } => {
6221                Value::new(self.step_value(current, ty, *dec, span), prec::LOWEST)
6222            }
6223        }
6224    }
6225
6226    /// The value a `fetch_*` on a place ends with: nothing, the old value or
6227    /// the new one.
6228    ///
6229    /// `atomic` is the place's [class](AtomicClass) and the C type behind it,
6230    /// which is what the value the atomic returned is converted back to.
6231    fn atomic_rmw_tail(
6232        &mut self,
6233        atomic: (AtomicClass, Ty),
6234        op: ir::AtomicRmw,
6235        old: &Ident,
6236        operand: &Ident,
6237        want: RmwValue,
6238        span: Span,
6239    ) -> TokenStream {
6240        let (class, ty) = atomic;
6241        let value = match want {
6242            RmwValue::None => return TokenStream::new(),
6243            RmwValue::Old => quote_spanned! {span=> #old },
6244            RmwValue::New => self.atomic_combine(op, old, operand, span),
6245        };
6246        self.repr_to_value(class, ty, value, span)
6247            .at(prec::LOWEST, span)
6248    }
6249
6250    /// The new value a `…_fetch` form answers with, computed from the old one
6251    /// the atomic returned and the operand.
6252    fn atomic_combine(
6253        &self,
6254        op: ir::AtomicRmw,
6255        old: &Ident,
6256        operand: &Ident,
6257        span: Span,
6258    ) -> TokenStream {
6259        match op {
6260            // Wrapping, because C's atomic arithmetic is modular even for the
6261            // signed types — the atomic instruction has no other behaviour.
6262            ir::AtomicRmw::Add => quote_spanned! {span=> #old.wrapping_add(#operand) },
6263            ir::AtomicRmw::Sub => quote_spanned! {span=> #old.wrapping_sub(#operand) },
6264            ir::AtomicRmw::And => quote_spanned! {span=> (#old & #operand) },
6265            ir::AtomicRmw::Or => quote_spanned! {span=> (#old | #operand) },
6266            ir::AtomicRmw::Xor => quote_spanned! {span=> (#old ^ #operand) },
6267            ir::AtomicRmw::Nand => quote_spanned! {span=> !(#old & #operand) },
6268        }
6269    }
6270
6271    /// The operand of a bit-manipulation builtin, as the unsigned integer of
6272    /// its own width.
6273    fn unsigned_operand(&mut self, arg: &Expr, span: Span) -> TokenStream {
6274        let width = arg.ty.bits(&self.options.target);
6275        let target = unsigned_rust_ty(width, span);
6276        let value = self.expr(arg).at(prec::CAST, span);
6277        parenthesize(quote_spanned! {span=> #value as #target }, span)
6278    }
6279
6280    /// `__builtin_add_overflow(a, b, &r)` and its relatives.
6281    ///
6282    /// The arithmetic happens in an `i128`, which is what "infinite precision"
6283    /// comes to while both operands are at most 64 bits wide — sema refuses a
6284    /// wider one. The *result* type may still be 128 bits, and that is the one
6285    /// thing that changes how the answer is checked: the general test asks
6286    /// whether the narrowed value converts back to what infinite precision
6287    /// gave, and a 128-bit conversion is a reinterpretation that always does.
6288    /// A signed 128-bit result therefore never overflows, and an unsigned one
6289    /// overflows exactly when the exact answer was negative.
6290    fn overflow_builtin(
6291        &mut self,
6292        op: BinOp,
6293        args: &[Expr],
6294        store: bool,
6295        result_ty: Ty,
6296        span: Span,
6297    ) -> Value {
6298        let method = match op {
6299            BinOp::Add => "wrapping_add",
6300            BinOp::Sub => "wrapping_sub",
6301            _ => "wrapping_mul",
6302        };
6303        let method = Ident::new(method, span);
6304        let checked = match op {
6305            BinOp::Add => "checked_add",
6306            BinOp::Sub => "checked_sub",
6307            _ => "checked_mul",
6308        };
6309        let checked = Ident::new(checked, span);
6310        let lhs = self.expr(&args[0]).at(prec::CAST, span);
6311        let rhs = self.expr(&args[1]).at(prec::CAST, span);
6312        let target = self.ty(result_ty, span);
6313        let a = self.temporary();
6314        let b = self.temporary();
6315        let wide = self.temporary();
6316        let narrow = self.temporary();
6317        // Pathed, because `typedef __int128 i128;` is a name a C unit may take.
6318        let i128 = primitive_ty("i128", span);
6319        let compute = quote_spanned! {span=>
6320            let #a: #i128 = #lhs as #i128;
6321            let #b: #i128 = #rhs as #i128;
6322            let #wide: #i128 = #a.#method(#b);
6323            let #narrow: #target = #wide as #target;
6324        };
6325        // The value overflows exactly when the wrapped result no longer equals
6326        // what infinite precision gave — and `i128` itself can only overflow
6327        // on a multiplication, where the answer is certainly out of range.
6328        let fits = match result_ty {
6329            // Both 128-bit conversions are reinterpretations, so the general
6330            // test below is vacuous there; what is left is the sign.
6331            Ty::Int128 => quote_spanned! {span=> false },
6332            Ty::UInt128 => quote_spanned! {span=> #wide < 0 },
6333            _ => quote_spanned! {span=> (#narrow as #i128) != #wide },
6334        };
6335        let flag = quote_spanned! {span=>
6336            #a.#checked(#b).is_none() || #fits
6337        };
6338        if !store {
6339            // The `_p` forms still evaluate their third operand.
6340            let third = self.expr_stmt(&args[2]);
6341            return Value::new(
6342                quote_spanned! {span=> { #third #compute #flag } },
6343                prec::BLOCK,
6344            );
6345        }
6346        let place = self.expr(&args[2]).at(prec::CALL, span);
6347        let out = self.temporary();
6348        Value::new(
6349            quote_spanned! {span=>
6350                { #compute let #out = #place; *#out = #narrow; #flag }
6351            },
6352            prec::BLOCK,
6353        )
6354    }
6355
6356    /// `va_arg(ap, T)`: reads the next argument and advances the list.
6357    ///
6358    /// `VaArgSafe` — the bound `next_arg` needs — is implemented for the
6359    /// primitives the `core::ffi` aliases stand for, so the C type can be
6360    /// asked for by name. A function pointer is the exception: `Option<fn>` is
6361    /// not one of them, so the argument is read as a `void *` and transmuted,
6362    /// which is what it is.
6363    ///
6364    /// A `struct` or a `union` is not a primitive at all, and is rebuilt from
6365    /// the registers the ABI passed it in — one `next_arg` per
6366    /// [eightbyte](ir::Eightbyte), which `sema` has already classified. The
6367    /// words are gathered into a `[u64; N]`, whose bytes are exactly the
6368    /// object's, and read back out of it: `read_unaligned` rather than a
6369    /// `transmute`, because the record may be *shorter* than the words that
6370    /// carried it — `struct { char x[13]; }` arrives in two of them — and
6371    /// because `[u64; N]` is eight-byte aligned while a record holding an
6372    /// `__int128` wants sixteen.
6373    fn va_arg(
6374        &mut self,
6375        ap: &Place,
6376        record: Option<&[ir::Eightbyte]>,
6377        ty: Ty,
6378        span: Span,
6379    ) -> Value {
6380        let access = self.place(ap, true).access;
6381        if let Some(classes) = record {
6382            let target = self.ty(ty, span);
6383            let u64_ty = primitive_ty("u64", span);
6384            let f64_ty = primitive_ty("f64", span);
6385            let words = classes.iter().map(|class| match class {
6386                ir::Eightbyte::Int => quote_spanned! {span=> #access.next_arg::<#u64_ty>() },
6387                ir::Eightbyte::Sse => {
6388                    quote_spanned! {span=> #access.next_arg::<#f64_ty>().to_bits() }
6389                }
6390                // The ABI passes an eightbyte nothing reaches in no register,
6391                // so there is nothing to read and nothing the record can see.
6392                ir::Eightbyte::None => quote_spanned! {span=> 0 },
6393            });
6394            let count = Literal::usize_unsuffixed(classes.len());
6395            let value = self.temporary();
6396            return Value::new(
6397                quote_spanned! {span=>
6398                    {
6399                        let #value: [#u64_ty; #count] = [#(#words),*];
6400                        ::core::ptr::read_unaligned(#value.as_ptr().cast::<#target>())
6401                    }
6402                },
6403                prec::BLOCK,
6404            );
6405        }
6406        if self.program.types.is_func_pointer(ty) {
6407            let target = self.ty(ty, span);
6408            let void = self.pointee_ty(Ty::Void, span);
6409            return Value::new(
6410                quote_spanned! {span=>
6411                    ::core::mem::transmute::<*mut #void, #target>(
6412                        #access.next_arg::<*mut #void>()
6413                    )
6414                },
6415                prec::CALL,
6416            );
6417        }
6418        let target = self.ty(ty, span);
6419        Value::new(
6420            quote_spanned! {span=> #access.next_arg::<#target>() },
6421            prec::CALL,
6422        )
6423    }
6424
6425    /// The argument of `offset`, which is always an `isize`.
6426    /// How far one element of a variably modified pointee is, in units of the
6427    /// [step type](ir::Types::vm_step_ty) the generated pointer points at.
6428    ///
6429    /// `double (*p)[m]` is a `*mut c_double` in the expansion, so `p + 1` has
6430    /// to move by `m` of them, and `double (*p)[n][3]` by `n` of the `[f64; 3]`
6431    /// it points at. Everything C says about such a pointer follows from
6432    /// scaling every offset by this product; `None` is the ordinary case,
6433    /// where Rust's own pointer arithmetic already has the right stride.
6434    fn vm_scale(&self, pointee: Ty, span: Span) -> Option<TokenStream> {
6435        if !self.program.types.is_vm(pointee) {
6436            return None;
6437        }
6438        let isize_ty = primitive_ty("isize", span);
6439        let mut product: Option<TokenStream> = None;
6440        for dim in self.program.types.vm_dims(pointee).iter().rev() {
6441            let factor = match dim {
6442                ir::VmDim::Fixed(len) => {
6443                    let literal = Literal::isize_unsuffixed(*len as isize);
6444                    quote_spanned! {span=> #literal }
6445                }
6446                ir::VmDim::Len(id) => {
6447                    let name = self.object_ident(*id, span);
6448                    quote_spanned! {span=> #name as #isize_ty }
6449                }
6450                // Sema refuses every expression that would need a bound it
6451                // never evaluated, so nothing reaches here.
6452                ir::VmDim::Unknown => quote_spanned! {span=> 1 },
6453            };
6454            product = Some(match product {
6455                None => factor,
6456                Some(left) => quote_spanned! {span=> (#left).wrapping_mul(#factor) },
6457            });
6458        }
6459        product
6460    }
6461
6462    /// An offset in elements, scaled for a [variably
6463    /// modified](Codegen::vm_scale) pointee.
6464    fn scaled_offset(&mut self, pointee: Ty, index: &Expr, sub: bool, span: Span) -> TokenStream {
6465        let Some(scale) = self.vm_scale(pointee, span) else {
6466            return self.offset_argument(index, sub, span);
6467        };
6468        let isize_ty = primitive_ty("isize", span);
6469        // A constant subscript comes out of `offset_argument` as a bare
6470        // literal, whose type `wrapping_mul` would have nothing to infer from.
6471        let offset = match &index.kind {
6472            ExprKind::Int(value) => {
6473                let value = if sub { -*value } else { *value };
6474                let literal = int_literal_token(value, span);
6475                quote_spanned! {span=> (#literal as #isize_ty) }
6476            }
6477            _ => {
6478                let inner = self.offset_argument(index, sub, span);
6479                quote_spanned! {span=> (#inner) }
6480            }
6481        };
6482        quote_spanned! {span=> #offset.wrapping_mul(#scale) }
6483    }
6484
6485    fn offset_argument(&mut self, index: &Expr, sub: bool, span: Span) -> TokenStream {
6486        if let ExprKind::Int(value) = &index.kind {
6487            let value = if sub { value.wrapping_neg() } else { *value };
6488            let literal = int_literal_token(value, span);
6489            // A small literal is left bare, and Rust infers the `isize`
6490            // `offset` wants. A larger one carries a suffix of its own —
6491            // `u64`, or `i128` — which is then the wrong type rather than an
6492            // open one, so it is converted. (`int a[2]; a[1L << 40]` is
6493            // undefined in C, and this is what `as` makes of it.)
6494            if value.unsigned_abs() > UNSUFFIXED_LIMIT as u128 {
6495                let isize_ty = primitive_ty("isize", span);
6496                return quote_spanned! {span=> (#literal as #isize_ty) };
6497            }
6498            return literal;
6499        }
6500        let tokens = self.expr(index).at(prec::CAST, span);
6501        let isize_ty = primitive_ty("isize", span);
6502        if sub {
6503            quote_spanned! {span=> -(#tokens as #isize_ty) }
6504        } else {
6505            quote_spanned! {span=> #tokens as #isize_ty }
6506        }
6507    }
6508
6509    fn call(&mut self, callee: &Callee, args: &[Expr], span: Span) -> Value {
6510        // An [x86 intrinsic](crate::x86) is not a symbol: the call is the
6511        // function of the same name in `core::arch`, with the immediate
6512        // operands moved into a turbofish.
6513        if let Callee::Direct(id) = callee
6514            && let Some(intr) = self.program.function(*id).intrinsic
6515        {
6516            return self.intrinsic_call(intr, *id, args, span);
6517        }
6518        let sig = self.callee_signature(callee);
6519        // A call through a function type with *no prototype* passes as many
6520        // arguments as it was given, each with the default argument promotions
6521        // applied, and the callee reads them as though the prototype had said
6522        // so (C99 6.5.2.2p6). Rust has no such call, so the reinterpretation is
6523        // written out: the callee is transmuted to the signature the promoted
6524        // arguments make, and that signature is called.
6525        //
6526        // It is the same contract C's own ABI relies on — the program is
6527        // defined only if the function really does take parameters of those
6528        // types, and undefined otherwise — and on every ABI this crate targets
6529        // a function pointer transmuted this way is the same address. Sema has
6530        // already applied the promotions, so `arg.ty` is the parameter type to
6531        // write.
6532        //
6533        // The argument *types* are compared as well as their number, because a
6534        // declaration with no prototype may be completed by a definition that
6535        // has one after the call was written: `int *h(); … h(j(), n); … int
6536        // *h(unsigned, int) { … }` — `execute/pr103209` — leaves the call
6537        // holding arguments the definition's parameters do not have. The call
6538        // was checked against the type in scope where it stands, which is the
6539        // one with no prototype, so the reinterpretation is what C says
6540        // happens there too. Where the prototype *was* in scope, sema has
6541        // already converted every argument to its parameter's type and the
6542        // comparison is an equality that holds.
6543        let reinterpreted = !sig.variadic
6544            && (args.len() != sig.params.len()
6545                || args.iter().zip(&sig.params).any(|(arg, param)| {
6546                    arg.ty != *param && !arg.ty.is_error() && !param.is_error()
6547                }));
6548        let promoted: Vec<Ty> = if reinterpreted {
6549            args.iter().map(|arg| arg.ty).collect()
6550        } else {
6551            Vec::new()
6552        };
6553        let params = if reinterpreted {
6554            &promoted
6555        } else {
6556            &sig.params
6557        };
6558
6559        let mut target = match callee {
6560            Callee::Direct(id) => {
6561                let function = self.program.function(*id);
6562                let path = self.function_path(function, span);
6563                if reinterpreted {
6564                    // A function *item* is not a function pointer, so the `as`
6565                    // coercion has to be written before it can be transmuted.
6566                    let source = self.function_pointer_ty(function, span);
6567                    parenthesize(quote_spanned! {span=> #path as #source }, span)
6568                } else {
6569                    path
6570                }
6571            }
6572            Callee::Indirect(expr) => {
6573                let value = self.expr(expr).at(prec::CALL, span);
6574                // C's function pointers may be null and Rust's may not, so the
6575                // `Option` has to come off before the call.
6576                parenthesize(
6577                    quote_spanned! {span=> #value.expect("null function pointer") },
6578                    span,
6579                )
6580            }
6581        };
6582        if reinterpreted {
6583            let source = self.fn_ptr_ty(&sig.params, sig.variadic, sig.ret, span);
6584            let wanted = self.fn_ptr_ty(params, false, sig.ret, span);
6585            target = parenthesize(
6586                quote_spanned! {span=>
6587                    ::core::mem::transmute::<#source, #wanted>(#target)
6588                },
6589                span,
6590            );
6591        }
6592
6593        // A lifted nested function's hidden arguments come first, and one
6594        // written argument after them needs the comma the loop would only put
6595        // between two of its own.
6596        let mut tokens = self.env_arguments(callee, span);
6597        let hidden = !tokens.is_empty();
6598        for (index, arg) in args.iter().enumerate() {
6599            if index > 0 || hidden {
6600                tokens.extend(quote_spanned! {span=> , });
6601            }
6602            match params.get(index) {
6603                // A parameter's type is what the argument is written at, so a
6604                // constant needs no `as`.
6605                Some(expected) => tokens.extend(self.expr_at(arg, *expected)),
6606                // An argument matched by `...` has no parameter to take its
6607                // type from, and Rust gives an unsuffixed literal in that
6608                // position `i32` (or `f64`), whatever C says it is: `%ld` with
6609                // a bare `-1` would read four bytes of an eight-byte
6610                // argument. The type has to be written out.
6611                None => {
6612                    let arg_span = self.sp(arg.range);
6613                    tokens.extend(self.expr(arg).at(prec::LOWEST, arg_span));
6614                }
6615            }
6616        }
6617        let call = parenthesize(tokens, span);
6618        Value::new(quote_spanned! {span=> #target #call }, prec::CALL)
6619    }
6620
6621    /// A call to an x86 intrinsic: `::core::arch::x86_64::_mm_slli_epi32::<{
6622    /// 3i32 }>(v)`.
6623    ///
6624    /// Everything about it lines up by construction — the bundled header's
6625    /// prototype was generated from the very signature `rustc` will check the
6626    /// call against — so there is none of the reinterpreting an ordinary call
6627    /// may need. Two things are not a plain transliteration:
6628    ///
6629    /// * the operands Intel requires to be integer constant expressions are
6630    ///   `const` generics in `core::arch`, so they move out of the argument
6631    ///   list into a turbofish. Sema has already folded each one to an
6632    ///   [`ExprKind::Int`] and reported the ones it could not (see
6633    ///   [`crate::x86::Intrinsic::imm`]);
6634    /// * the literal carries the `const` parameter's own type, and is wrapped
6635    ///   in a block, so that a negative value is still a const argument Rust
6636    ///   parses;
6637    /// * a pointer argument is cast with `as *const _` or `as *mut _` (see
6638    ///   [`Codegen::intrinsic_pointer_arg`]), because the header spells a
6639    ///   memory operand `void *` where GCC's does and `core::arch` types it.
6640    fn intrinsic_call(
6641        &mut self,
6642        intr: &'static crate::x86::Intrinsic,
6643        id: ir::FuncId,
6644        args: &[Expr],
6645        span: Span,
6646    ) -> Value {
6647        let module = self.arch_module(span);
6648        let name = Ident::new(intr.name, span);
6649        let mut generics = TokenStream::new();
6650        for (index, imm) in intr.imm.iter().enumerate() {
6651            if index > 0 {
6652                generics.extend(quote_spanned! {span=> , });
6653            }
6654            let value = match args.get(usize::from(imm.index)).map(|arg| &arg.kind) {
6655                Some(ExprKind::Int(value)) => *value,
6656                // Unreachable: sema folds every immediate and reports the ones
6657                // it cannot, and a unit with an error generates stubs rather
6658                // than this. A zero keeps the expansion parseable.
6659                _ => 0,
6660            };
6661            let literal = suffixed_int_literal(value, imm.rust_ty, span);
6662            generics.extend(quote_spanned! {span=> { #literal } });
6663        }
6664        let turbofish = if generics.is_empty() {
6665            TokenStream::new()
6666        } else {
6667            quote_spanned! {span=> ::<#generics> }
6668        };
6669
6670        let mut tokens = TokenStream::new();
6671        let mut written = 0usize;
6672        for (index, arg) in args.iter().enumerate() {
6673            if intr.immediate_at(index).is_some() {
6674                continue;
6675            }
6676            if written > 0 {
6677                tokens.extend(quote_spanned! {span=> , });
6678            }
6679            written += 1;
6680            let param = self.program.function(id).sig.params.get(index).copied();
6681            match param.and_then(|ty| self.intrinsic_pointer_arg(ty, span)) {
6682                Some(cast) => {
6683                    let value = self.expr(arg).at(prec::CAST, span);
6684                    tokens.extend(quote_spanned! {span=> #value #cast });
6685                }
6686                None => tokens.extend(self.expr_at(arg, arg.ty)),
6687            }
6688        }
6689        let call = parenthesize(tokens, span);
6690        Value::new(
6691            quote_spanned! {span=> ::core::arch::#module::#name #turbofish #call },
6692            prec::CALL,
6693        )
6694    }
6695
6696    /// The cast an intrinsic's pointer argument gets: `as *const _` when the
6697    /// C parameter points at `const`, `as *mut _` otherwise, and `None` for a
6698    /// parameter that is not a pointer.
6699    ///
6700    /// The header declares a memory operand `void *` wherever GCC's does, so
6701    /// that `_mm512_loadu_si512(p)` takes an `int *` as it does in GCC, while
6702    /// `core::arch` types it (`*const __m512i`); rustc infers the `_` from
6703    /// that. Every pointer parameter gets the cast, typed or not — for a
6704    /// typed one it is the identity, and one rule is simpler to state.
6705    fn intrinsic_pointer_arg(&self, param: Ty, span: Span) -> Option<TokenStream> {
6706        let Ty::Pointer(pointer) = param else {
6707            return None;
6708        };
6709        Some(if self.program.types.pointer_type(pointer).konst {
6710            quote_spanned! {span=> as *const _ }
6711        } else {
6712            quote_spanned! {span=> as *mut _ }
6713        })
6714    }
6715
6716    /// The hidden arguments a call to a lifted nested function opens with.
6717    ///
6718    /// Each one is the address of the object the callee wants: the enclosing
6719    /// function passes `&raw mut x` for a local of its own, and a function
6720    /// that was itself passed the pointer passes that on. Nothing else has a
6721    /// hidden argument, so this is empty for every ordinary call.
6722    fn env_arguments(&self, callee: &Callee, span: Span) -> TokenStream {
6723        let Callee::Direct(id) = callee else {
6724            return TokenStream::new();
6725        };
6726        let mut tokens = TokenStream::new();
6727        for (index, entry) in self.program.function(*id).env.iter().enumerate() {
6728            if index > 0 {
6729                tokens.extend(quote_spanned! {span=> , });
6730            }
6731            match self.env.get(&entry.owner) {
6732                // The caller was handed the pointer itself; it passes it on.
6733                Some(param) => {
6734                    let name = self.object_ident(*param, span);
6735                    tokens.extend(quote_spanned! {span=> #name });
6736                }
6737                // The object is the caller's own.
6738                None => {
6739                    let object = self.program.object(entry.owner);
6740                    let name = self.object_access(entry.owner, span);
6741                    tokens.extend(if object.is_const {
6742                        quote_spanned! {span=> &raw const #name }
6743                    } else {
6744                        quote_spanned! {span=> &raw mut #name }
6745                    });
6746                }
6747            }
6748        }
6749        tokens
6750    }
6751
6752    /// The signature a call goes through: the callee's own for a direct call,
6753    /// and the pointed-to function type for an indirect one.
6754    fn callee_signature(&self, callee: &Callee) -> ir::Signature {
6755        match callee {
6756            Callee::Direct(id) => self.program.function(*id).sig.clone(),
6757            Callee::Indirect(expr) => match self.program.types.pointee(expr.ty) {
6758                Some(Ty::Func(id)) => {
6759                    let func = self.program.types.func_type(id);
6760                    ir::Signature {
6761                        ret: func.ret,
6762                        params: func.params.clone(),
6763                        variadic: func.variadic,
6764                        prototyped: func.prototyped,
6765                    }
6766                }
6767                // Only reachable on the error path, where a `compile_error!` is
6768                // already going out.
6769                _ => ir::Signature {
6770                    ret: Ty::Void,
6771                    params: Vec::new(),
6772                    variadic: false,
6773                    prototyped: true,
6774                },
6775            },
6776        }
6777    }
6778
6779    /// `unsafe extern "C" fn(P…) -> R`, written out from its pieces.
6780    fn fn_ptr_ty(&self, params: &[Ty], variadic: bool, ret: Ty, span: Span) -> TokenStream {
6781        let mut list = TokenStream::new();
6782        for (index, param) in params.iter().enumerate() {
6783            if index > 0 {
6784                list.extend(quote_spanned! {span=> , });
6785            }
6786            list.extend(self.ty(*param, span));
6787        }
6788        if variadic {
6789            if !params.is_empty() {
6790                list.extend(quote_spanned! {span=> , });
6791            }
6792            list.extend(quote_spanned! {span=> ... });
6793        }
6794        let list = parenthesize(list, span);
6795        let ret = if ret.is_void() {
6796            TokenStream::new()
6797        } else {
6798            let ty = self.ty(ret, span);
6799            quote_spanned! {span=> -> #ty }
6800        };
6801        quote_spanned! {span=> unsafe extern "C" fn #list #ret }
6802    }
6803
6804    /// The path a call to `function` uses.
6805    ///
6806    /// One name whether the unit defines the function or only declares it: the
6807    /// item in the `extern` block carries the C name as well (see
6808    /// [`Codegen::extern_block`]), and a lifted nested function carries the name
6809    /// it was lifted under.
6810    fn function_path(&self, function: &Function, span: Span) -> TokenStream {
6811        let name = self.c_ident(function.item_name(), span);
6812        quote_spanned! {span=> #name }
6813    }
6814
6815    /// `unsafe extern "C" fn(…) -> R` for a named function, which is what its
6816    /// address has to be cast to.
6817    fn function_pointer_ty(&self, function: &Function, span: Span) -> TokenStream {
6818        let sig = &function.sig;
6819        self.fn_ptr_ty(&sig.params, sig.variadic, sig.ret, span)
6820    }
6821
6822    /// Emits an expression as a Rust `bool`, the way C tests a scalar against
6823    /// zero.
6824    fn condition(&mut self, expr: &Expr) -> Value {
6825        let span = self.sp(expr.range);
6826        match &expr.kind {
6827            ExprKind::Compare { op, lhs, rhs } => {
6828                if let Some(value) = self.null_test(*op, lhs, rhs, span) {
6829                    return value;
6830                }
6831                if lhs.ty.is_complex() && rhs.ty.is_complex() {
6832                    return self.complex_equality(*op, lhs, rhs, span);
6833                }
6834                let (lhs, rhs) = self.operands(lhs, rhs, BinOp::BitOr);
6835                let left_min = if *op == CmpOp::Lt && lhs.ends_with_type {
6836                    prec::CAST + 1
6837                } else {
6838                    prec::CMP + 1
6839                };
6840                let ends_with_type = rhs.ends_with_type;
6841                let lhs = lhs.at(left_min, span);
6842                let rhs = rhs.at(prec::CMP + 1, span);
6843                let op = cmp_tokens(*op, span);
6844                Value::new(quote_spanned! {span=> #lhs #op #rhs }, prec::CMP)
6845                    .type_end(ends_with_type)
6846            }
6847            ExprKind::Logical { .. } => self.logical_chain(expr),
6848            ExprKind::Int(value) => {
6849                let ident = Ident::new(if *value != 0 { "true" } else { "false" }, span);
6850                Value::atom(quote_spanned! {span=> #ident })
6851            }
6852            _ if expr.ty.is_bool() => self.expr(expr),
6853            _ if expr.ty.is_complex() => self.complex_condition(expr, span),
6854            _ if expr.ty.is_pointer() => self.not_null(expr, span),
6855            _ => {
6856                let ty = expr.ty;
6857                let value = self.expr(expr).at(prec::CMP + 1, span);
6858                let zero = self.zero_tokens(ty, span);
6859                Value::new(quote_spanned! {span=> #value != #zero }, prec::CMP)
6860            }
6861        }
6862    }
6863
6864    /// `p != NULL` reads better as `!p.is_null()`, and that is also the only
6865    /// form that works for a function pointer.
6866    fn null_test(&mut self, op: CmpOp, lhs: &Expr, rhs: &Expr, span: Span) -> Option<Value> {
6867        if !matches!(op, CmpOp::Eq | CmpOp::Ne) {
6868            return None;
6869        }
6870        let (pointer, _) = match (&lhs.kind, &rhs.kind) {
6871            (ExprKind::Zeroed, _) if rhs.ty.is_pointer() => (rhs, lhs),
6872            (_, ExprKind::Zeroed) if lhs.ty.is_pointer() => (lhs, rhs),
6873            _ => return None,
6874        };
6875        let test = self.is_null(pointer, span);
6876        if op == CmpOp::Eq {
6877            return Some(test);
6878        }
6879        let tokens = test.at(prec::UNARY, span);
6880        Some(Value::new(quote_spanned! {span=> !#tokens }, prec::UNARY))
6881    }
6882
6883    /// `p.is_null()`, or `{ p }.is_some()` for a function pointer.
6884    fn is_null(&mut self, expr: &Expr, span: Span) -> Value {
6885        if self.program.types.is_func_pointer(expr.ty) {
6886            let tokens = self.copied_receiver(expr, span);
6887            return Value::new(quote_spanned! {span=> #tokens.is_none() }, prec::CALL);
6888        }
6889        let tokens = self.expr(expr).at(prec::CALL, span);
6890        Value::new(quote_spanned! {span=> #tokens.is_null() }, prec::CALL)
6891    }
6892
6893    fn not_null(&mut self, expr: &Expr, span: Span) -> Value {
6894        if self.program.types.is_func_pointer(expr.ty) {
6895            let tokens = self.copied_receiver(expr, span);
6896            return Value::new(quote_spanned! {span=> #tokens.is_some() }, prec::CALL);
6897        }
6898        let tokens = self.expr(expr).at(prec::CALL, span);
6899        Value::new(quote_spanned! {span=> !#tokens.is_null() }, prec::UNARY)
6900    }
6901
6902    /// A receiver for a method that takes `&self`.
6903    ///
6904    /// `Option::is_some` borrows, and borrowing a `static mut` is an error in
6905    /// edition 2024; a block copies the value out first. Only a place that
6906    /// really is a `static mut` needs it, so an ordinary local keeps reading
6907    /// as one.
6908    fn copied_receiver(&mut self, expr: &Expr, span: Span) -> TokenStream {
6909        if self.reads_a_static(expr) {
6910            let tokens = self.expr(expr).at(prec::LOWEST, span);
6911            return braced(tokens, span);
6912        }
6913        self.expr(expr).at(prec::CALL, span)
6914    }
6915
6916    /// Whether an expression reads an object with static storage duration,
6917    /// which is what a shared reference may not be taken to.
6918    fn reads_a_static(&self, expr: &Expr) -> bool {
6919        let ExprKind::Load(place) = &expr.kind else {
6920            return false;
6921        };
6922        let mut place = place;
6923        loop {
6924            match &place.kind {
6925                PlaceKind::Object(id) => {
6926                    let storage = &self.program.object(*id).storage;
6927                    // A thread-local object is a `*mut T` out of its cell, so
6928                    // it is behind a raw pointer like anything else below.
6929                    return !matches!(storage, Storage::Automatic) && !storage.is_thread_local();
6930                }
6931                PlaceKind::Field { base, .. } => place = base,
6932                // Anything reached through a pointer is behind a raw pointer
6933                // already, so no reference to the static itself is created.
6934                _ => return false,
6935            }
6936        }
6937    }
6938
6939    /// Emits the operands of a binary operation.
6940    ///
6941    /// Both operands already have the result type, so a constant one can be
6942    /// left as a bare literal and take its Rust type from the other side —
6943    /// `n == 0` rather than `n == 0 as ::core::ffi::c_int`. That only works
6944    /// while the other side actually has a type to give, and never for the
6945    /// receiver of a method call, where a bare integer literal followed by a
6946    /// `.` would not survive being printed back out as text.
6947    fn operands(&mut self, lhs: &Expr, rhs: &Expr, op: BinOp) -> (Value, Value) {
6948        self.operands_with(None, lhs, rhs, op)
6949    }
6950
6951    /// [`Codegen::operands`] with the left operand possibly already emitted.
6952    ///
6953    /// `folded` is what [`Codegen::binary_chain`] has built so far. It is only
6954    /// ever a binary operation, and [`constant_of`] answers `None` for one, so
6955    /// the bare-literal reasoning below is unaffected by it.
6956    fn operands_with(
6957        &mut self,
6958        folded: Option<Value>,
6959        lhs: &Expr,
6960        rhs: &Expr,
6961        op: BinOp,
6962    ) -> (Value, Value) {
6963        let uses_method = matches!(
6964            op,
6965            BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Shl | BinOp::Shr
6966        );
6967        let lhs_constant = constant_of(lhs);
6968        let rhs_constant = constant_of(rhs);
6969
6970        // At most one side may be bare, and it is never the left one where a
6971        // method call follows.
6972        let lhs_bare = lhs_constant.is_some() && !uses_method && rhs_constant.is_none();
6973        let lhs_value = match (folded, lhs_constant) {
6974            (Some(value), _) => value,
6975            (None, Some(value)) if lhs_bare => self.bare_value(value, lhs.ty, self.sp(lhs.range)),
6976            (None, _) => self.expr(lhs),
6977        };
6978        let rhs_value = match rhs_constant {
6979            // The shift amount is converted to `u32` whatever its C type is,
6980            // so a constant there never needs the other operand's help — and
6981            // it is reduced to *that* `u32` here rather than left as the C
6982            // value. Every count a program may legitimately write is under
6983            // the width and so unchanged; the ones that are not are undefined
6984            // in C, and writing them out as they stand is what `rustc`
6985            // refuses. A negative one is `-64 as u32`, which it reads as the
6986            // negation of a `u32` (`E0600`, `execute/pr98681`) even
6987            // parenthesised, and one above `u32::MAX` is a literal out of
6988            // range. `wrapping_shl` masks the count by the width, exactly as
6989            // the hardware does.
6990            Some(ConstValue::Int(value)) if op.is_shift() => self.bare_value(
6991                ConstValue::Int(i128::from(value as u32)),
6992                Ty::UInt,
6993                self.sp(rhs.range),
6994            ),
6995            Some(value) if op.is_shift() => self.bare_value(value, rhs.ty, self.sp(rhs.range)),
6996            Some(value) if !lhs_bare => self.bare_value(value, rhs.ty, self.sp(rhs.range)),
6997            _ => self.expr(rhs),
6998        };
6999        (lhs_value, rhs_value)
7000    }
7001
7002    /// A constant emitted without its `as`, for a context that will supply the
7003    /// type.
7004    fn bare_value(&mut self, value: ConstValue, ty: Ty, span: Span) -> Value {
7005        match value {
7006            ConstValue::Int(v) => {
7007                let tokens = bare_int_literal(v, ty, span);
7008                let mut out = Value::new(tokens, if v < 0 { prec::UNARY } else { prec::ATOM });
7009                out.bare_integer = v >= 0 && !ty.is_bool();
7010                out
7011            }
7012            ConstValue::Float(v) => Value::new(
7013                bare_float_literal(v, span),
7014                if v.is_sign_negative() {
7015                    prec::UNARY
7016                } else {
7017                    prec::ATOM
7018                },
7019            ),
7020            // A complex constant is never *bare*: it has to name its own type,
7021            // and [`constant_of`] answers `None` for one so that nothing asks.
7022            ConstValue::Complex(re, im) => {
7023                let re = bare_float_literal(re, span);
7024                let im = bare_float_literal(im, span);
7025                self.complex_new(ty, re, im, span)
7026            }
7027        }
7028    }
7029
7030    /// A chain of conditional operators, folded without recursing down it.
7031    ///
7032    /// `a ? b : c ? d : e` is right-associative, so unlike the chains
7033    /// [`Codegen::binary_chain`] handles this one really is nesting: what
7034    /// comes out is `if … { … } else { if … }`, one level per operator, and
7035    /// that is as it should be. What must not be one level per operator is
7036    /// the *walk*, which runs on the eight mebibytes `rustc` gives macro
7037    /// expansion.
7038    ///
7039    /// The condition and the `then` arm of each level are emitted on the way
7040    /// down and the tree is built on the way back up, which is the order the
7041    /// recursive walk had — so the tokens, and the numbering of any
7042    /// temporaries in them, are exactly what it produced.
7043    fn cond_chain(&mut self, expr: &Expr) -> Value {
7044        let mut spine = Vec::new();
7045        let mut node = expr;
7046        while let ExprKind::Cond {
7047            cond,
7048            then_expr,
7049            else_expr,
7050        } = &node.kind
7051        {
7052            let span = self.sp(node.range);
7053            let cond_tokens = self.condition(cond).at_condition(span);
7054            let then_tokens = self.expr(then_expr).at(prec::LOWEST, span);
7055            spine.push((cond_tokens, then_tokens, span));
7056            node = else_expr;
7057        }
7058        // The innermost `else` is parenthesised against the span of the
7059        // conditional it belongs to, which is the innermost one on the spine.
7060        let inner = spine
7061            .last()
7062            .map_or_else(|| self.sp(expr.range), |(_, _, span)| *span);
7063        let mut tokens = self.expr(node).at(prec::LOWEST, inner);
7064        while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
7065            tokens = quote_spanned! {span=>
7066                if #cond_tokens { #then_tokens } else { #tokens }
7067            };
7068        }
7069        Value::new(tokens, prec::BLOCK)
7070    }
7071
7072    /// [`Codegen::cond_chain`] where the surrounding context fixes the type.
7073    ///
7074    /// The chain ends wherever a level's own type is no longer `expected`,
7075    /// which is where [`Codegen::expr_at`] would have stopped treating the
7076    /// arms as bare anyway.
7077    fn cond_chain_at(&mut self, expr: &Expr, expected: Ty) -> TokenStream {
7078        let mut spine = Vec::new();
7079        let mut node = expr;
7080        while let ExprKind::Cond {
7081            cond,
7082            then_expr,
7083            else_expr,
7084        } = &node.kind
7085        {
7086            if node.ty != expected {
7087                break;
7088            }
7089            let span = self.sp(node.range);
7090            let cond_tokens = self.condition(cond).at_condition(span);
7091            let then_tokens = self.expr_at(then_expr, expected);
7092            spine.push((cond_tokens, then_tokens, span));
7093            node = else_expr;
7094        }
7095        let mut tokens = self.expr_at(node, expected);
7096        while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
7097            tokens = quote_spanned! {span=>
7098                if #cond_tokens { #then_tokens } else { #tokens }
7099            };
7100        }
7101        tokens
7102    }
7103
7104    /// A chain of assignments, folded without recursing down it.
7105    ///
7106    /// `a = b = c` is right-associative, so this is nesting in the same way
7107    /// [`Codegen::cond_chain`] is, and the same bargain applies: the shape of
7108    /// the output is unchanged and only the walk is flattened. Each place is
7109    /// lowered on the way down — which is where the recursive walk lowered it,
7110    /// and therefore where it took any temporary it needed — and the blocks
7111    /// are built on the way back up, innermost first, exactly as the
7112    /// recursion unwound.
7113    fn assign_chain(&mut self, expr: &Expr) -> Value {
7114        let mut spine = Vec::new();
7115        let mut node = expr;
7116        while let ExprKind::Assign { place, value } = &node.kind {
7117            let span = self.sp(node.range);
7118            let lowered = self.place(place, true);
7119            spine.push((lowered, self.program.types.unatomic(place.ty), span));
7120            node = value;
7121        }
7122        let (_, innermost, _) = spine
7123            .last()
7124            .expect("assign_chain is only entered on an assignment");
7125        let mut tokens = self.expr_at(node, *innermost);
7126        while let Some((lowered, ty, span)) = spine.pop() {
7127            // The value of an assignment to an *atomic* object is the value
7128            // stored and not what the object holds afterwards: another thread
7129            // may have changed it already, and reading it back would be a
7130            // second atomic operation C never asked for.
7131            if lowered.atomic.is_some() {
7132                let tmp = self.temporary();
7133                let target = self.ty(ty, span);
7134                let store = self.write(&lowered, quote_spanned! {span=> #tmp }, span);
7135                let setup = &lowered.setup;
7136                tokens = quote_spanned! {span=>
7137                    { #setup let #tmp: #target = #tokens; #store #tmp }
7138                };
7139                continue;
7140            }
7141            let store = self.write(&lowered, tokens, span);
7142            // The value of an assignment is the value stored, which for a
7143            // place is exactly what reading it back gives — including for a
7144            // bit-field, where reading back is what truncates.
7145            let read = self.read(&lowered, span).at(prec::LOWEST, span);
7146            let setup = &lowered.setup;
7147            tokens = quote_spanned! {span=> { #setup #store #read } };
7148        }
7149        Value::new(tokens, prec::BLOCK)
7150    }
7151
7152    /// A chain of binary operators, folded without recursing down it.
7153    ///
7154    /// `a + b + c + …` is left-associative, so the tree it leaves behind is
7155    /// one node per operand with the whole of the rest hanging off its left.
7156    /// Walking that recursively is one stack frame per operand — and code
7157    /// generation runs on the caller's thread, which is the eight mebibytes
7158    /// `rustc` gives macro expansion, where a chain of about eight hundred is
7159    /// a "fatal runtime error: stack overflow" with no diagnostic at all.
7160    ///
7161    /// C23 5.2.5.2p1 asks every implementation to accept a logical source
7162    /// line of 4095 characters, which is well past that, so the spine is
7163    /// collected into a vector and folded back up in a loop: one frame,
7164    /// however long the chain. The tokens that come out are the same ones the
7165    /// recursive walk produced, and in the same order — `a.wrapping_add(b)
7166    /// .wrapping_add(c)` is a receiver chain, which is *flat*, so neither is
7167    /// the output deeply nested.
7168    ///
7169    /// Nesting — `a + (b + (c + …))`, which is one level of parentheses per
7170    /// operand — still costs a frame per level, and is what
7171    /// `parse::MAX_RECURSION_DEPTH` bounds.
7172    fn binary_chain(&mut self, expr: &Expr) -> Value {
7173        let mut spine = vec![expr];
7174        let mut node = expr;
7175        while let ExprKind::Binary { lhs, .. } = &node.kind {
7176            node = lhs;
7177            if matches!(node.kind, ExprKind::Binary { .. }) {
7178                spine.push(node);
7179            }
7180        }
7181        let mut folded = None;
7182        while let Some(node) = spine.pop() {
7183            let ExprKind::Binary { op, lhs, rhs } = &node.kind else {
7184                unreachable!("the spine holds binary operations only");
7185            };
7186            let span = self.sp(node.range);
7187            let (lhs_value, rhs_value) = self.operands_with(folded, lhs, rhs, *op);
7188            let value = if node.ty.is_complex() {
7189                self.complex_binary(*op, (lhs_value, lhs.ty), (rhs_value, rhs.ty), node.ty, span)
7190            } else {
7191                self.binary(*op, lhs_value, rhs_value, node.ty, span)
7192            };
7193            folded = Some(self.reduce_bits(value, node));
7194        }
7195        folded.expect("the chain has at least the node it started from")
7196    }
7197
7198    /// A chain of `&&` or `||`, folded without recursing down it.
7199    ///
7200    /// The same shape and the same reason as [`Codegen::binary_chain`]; these
7201    /// live on the `bool` side of code generation, so the fold is over
7202    /// [`Codegen::condition`] rather than over `expr`.
7203    fn logical_chain(&mut self, expr: &Expr) -> Value {
7204        let mut spine = vec![expr];
7205        let mut node = expr;
7206        while let ExprKind::Logical { lhs, .. } = &node.kind {
7207            node = lhs;
7208            if matches!(node.kind, ExprKind::Logical { .. }) {
7209                spine.push(node);
7210            }
7211        }
7212        // `node` is now the innermost left operand, which is not itself a
7213        // logical operator; emitting it first keeps the order the recursive
7214        // walk had, which is source order.
7215        let mut folded = self.condition(node);
7216        while let Some(node) = spine.pop() {
7217            let ExprKind::Logical { op, rhs, .. } = &node.kind else {
7218                unreachable!("the spine holds logical operations only");
7219            };
7220            let span = self.sp(node.range);
7221            let (level, tokens) = match op {
7222                LogicalOp::And => (prec::AND, quote_spanned! {span=> && }),
7223                LogicalOp::Or => (prec::OR, quote_spanned! {span=> || }),
7224            };
7225            let mut out = folded.at(level, span);
7226            let rhs = self.condition(rhs);
7227            let ends_with_type = rhs.ends_with_type;
7228            let rhs = rhs.at(level + 1, span);
7229            out.extend(quote_spanned! {span=> #tokens #rhs });
7230            folded = Value::new(out, level).type_end(ends_with_type);
7231        }
7232        folded
7233    }
7234
7235    fn binary(&mut self, op: BinOp, lhs: Value, rhs: Value, ty: Ty, span: Span) -> Value {
7236        if ty.is_floating() {
7237            let (level, tokens) = match op {
7238                BinOp::Add => (prec::SUM, quote_spanned! {span=> + }),
7239                BinOp::Sub => (prec::SUM, quote_spanned! {span=> - }),
7240                BinOp::Mul => (prec::PRODUCT, quote_spanned! {span=> * }),
7241                BinOp::Div => (prec::PRODUCT, quote_spanned! {span=> / }),
7242                // Sema rejects every other operator on floating operands.
7243                _ => (prec::PRODUCT, quote_spanned! {span=> % }),
7244            };
7245            let ends_with_type = rhs.ends_with_type;
7246            let mut out = lhs.at(level, span);
7247            let rhs = rhs.at(level + 1, span);
7248            // Appended in place rather than built into a fresh stream around
7249            // the left operand: a chain of a thousand would otherwise copy
7250            // the whole of it a thousand times over. See
7251            // [`Codegen::binary_chain`].
7252            out.extend(quote_spanned! {span=> #tokens #rhs });
7253            return Value::new(out, level).type_end(ends_with_type);
7254        }
7255
7256        // `+`, `-`, `*` and the shifts go through the wrapping methods:
7257        // unsigned wrap-around is defined in C, and while signed overflow is
7258        // undefined, wrapping is far more predictable than a panic in the
7259        // middle of translated code.
7260        let method = match op {
7261            BinOp::Add => Some("wrapping_add"),
7262            BinOp::Sub => Some("wrapping_sub"),
7263            BinOp::Mul => Some("wrapping_mul"),
7264            BinOp::Shl => Some("wrapping_shl"),
7265            BinOp::Shr => Some("wrapping_shr"),
7266            _ => None,
7267        };
7268        if let Some(method) = method {
7269            let mut receiver = lhs.at(prec::CALL, span);
7270            let method = Ident::new(method, span);
7271            let argument = if op.is_shift() && !rhs.bare_integer {
7272                // `wrapping_shl` takes the shift amount as a `u32` whatever the
7273                // shifted type is; a bare literal simply is one already.
7274                let amount = rhs.at(prec::CAST, span);
7275                // Belt and braces: nothing that reaches here opens with a
7276                // unary minus — a constant count was reduced to its `u32` in
7277                // [`Codegen::operands_with`] and `-x` is written
7278                // `x.wrapping_neg()` — and if one ever did, `rustc` would read
7279                // `-e as u32` as the negation of a `u32` and refuse it
7280                // (`E0600`) however it is bracketed by precedence.
7281                let amount = if starts_with_minus(&amount) {
7282                    parenthesize(amount, span)
7283                } else {
7284                    amount
7285                };
7286                let u32_ty = primitive_ty("u32", span);
7287                quote_spanned! {span=> #amount as #u32_ty }
7288            } else {
7289                rhs.at(prec::LOWEST, span)
7290            };
7291            let args = parenthesize(argument, span);
7292            receiver.extend(quote_spanned! {span=> .#method #args });
7293            return Value::new(receiver, prec::CALL);
7294        }
7295
7296        // `/` and `%` stay plain: Rust truncates towards zero and takes the
7297        // sign of the dividend, exactly as C99 does. Both panic where C is
7298        // undefined (division by zero, and `INT_MIN / -1`).
7299        let (level, tokens) = match op {
7300            BinOp::Div => (prec::PRODUCT, quote_spanned! {span=> / }),
7301            BinOp::Rem => (prec::PRODUCT, quote_spanned! {span=> % }),
7302            BinOp::BitAnd => (prec::BIT_AND, quote_spanned! {span=> & }),
7303            BinOp::BitXor => (prec::BIT_XOR, quote_spanned! {span=> ^ }),
7304            BinOp::BitOr => (prec::BIT_OR, quote_spanned! {span=> | }),
7305            _ => unreachable!("every other operator was handled above"),
7306        };
7307        let ends_with_type = rhs.ends_with_type;
7308        let mut out = lhs.at(level, span);
7309        let rhs = rhs.at(level + 1, span);
7310        out.extend(quote_spanned! {span=> #tokens #rhs });
7311        Value::new(out, level).type_end(ends_with_type)
7312    }
7313
7314    /// The value `place op= value` stores.
7315    ///
7316    /// `hoisted` is the right operand when it was evaluated ahead of the read;
7317    /// see [`Codegen::compound_rhs`].
7318    fn compound_value(
7319        &mut self,
7320        current: Value,
7321        place_ty: Ty,
7322        op: BinOp,
7323        value: &Expr,
7324        hoisted: Option<Value>,
7325        compute: Ty,
7326    ) -> Value {
7327        let span = self.sp(value.range);
7328        if place_ty.is_pointer() {
7329            // `p += n` moves by elements, not by bytes.
7330            let access = current.at(prec::CALL, span);
7331            let offset = match hoisted {
7332                Some(index) => self.offset_of_value(index, op == BinOp::Sub, span),
7333                None => self.offset_argument(value, op == BinOp::Sub, span),
7334            };
7335            let pointee = self.program.types.pointee(place_ty).unwrap_or(Ty::Void);
7336            let offset = match self.vm_scale(pointee, span) {
7337                None => offset,
7338                Some(scale) => quote_spanned! {span=> (#offset).wrapping_mul(#scale) },
7339            };
7340            return Value::new(quote_spanned! {span=> #access.offset(#offset) }, prec::CALL);
7341        }
7342        // A complex computation keeps a real operand real on *both* sides:
7343        // sema left the right one alone, and the left one — the place — is
7344        // widened only as far as the common real type when it is real too. See
7345        // [`Codegen::complex_binary`].
7346        if compute.is_complex() {
7347            let lhs_ty = if place_ty.is_complex() {
7348                compute
7349            } else {
7350                compute.complex_component()
7351            };
7352            let current = self.cast(current, place_ty, lhs_ty, span);
7353            let rhs = self.compound_operand(value, hoisted, span);
7354            let result = self.complex_binary(op, (current, lhs_ty), (rhs, value.ty), compute, span);
7355            return self.cast(result, compute, place_ty, span);
7356        }
7357        let current = self.cast(current, place_ty, compute, span);
7358        let rhs = self.compound_operand(value, hoisted, span);
7359        let result = self.binary(op, current, rhs, compute, span);
7360        self.cast(result, compute, place_ty, span)
7361    }
7362
7363    /// The right operand of a compound assignment, already hoisted or not.
7364    ///
7365    /// The left operand is a place and therefore always typed, so a constant
7366    /// right operand can stay a bare literal.
7367    fn compound_operand(&mut self, value: &Expr, hoisted: Option<Value>, span: Span) -> Value {
7368        match hoisted {
7369            Some(rhs) => rhs,
7370            None => match constant_of(value) {
7371                Some(constant) => self.bare_value(constant, value.ty, span),
7372                None => self.expr(value),
7373            },
7374        }
7375    }
7376
7377    /// Evaluates the right operand of a compound assignment ahead of the read,
7378    /// when C says it happens either wholly before it or wholly after it.
7379    ///
7380    /// `E1 op= E2` is a read, an operation and a write, and C11 6.5.16.2p3
7381    /// makes the three of them *one* evaluation with respect to an
7382    /// indeterminately sequenced function call. Writing them out as
7383    /// `E1 = E1 op E2` would read `E1`, call whatever `E2` calls, and only then
7384    /// store — which is the one order the standard rules out, and which GCC's
7385    /// `pr58943` is about. Binding `E2` to a temporary first restores it: the
7386    /// place is computed, then the call happens, then the read-modify-write.
7387    ///
7388    /// Only an operand that can call something needs it; everything else is
7389    /// left where it was written, because a temporary per `i += 1` would be
7390    /// noise.
7391    fn compound_rhs(&mut self, value: &Expr) -> (TokenStream, Option<Value>) {
7392        if !ir::calls_a_function(value) {
7393            return (TokenStream::new(), None);
7394        }
7395        let span = self.sp(value.range);
7396        let tokens = self.expr(value).at(prec::LOWEST, span);
7397        let tmp = self.temporary();
7398        (
7399            quote_spanned! {span=> let #tmp = #tokens; },
7400            Some(Value::atom(quote_spanned! {span=> #tmp })),
7401        )
7402    }
7403
7404    /// The `offset` argument for an index that has already been emitted.
7405    fn offset_of_value(&mut self, index: Value, sub: bool, span: Span) -> TokenStream {
7406        let tokens = index.at(prec::CAST, span);
7407        let isize_ty = primitive_ty("isize", span);
7408        if sub {
7409            quote_spanned! {span=> -(#tokens as #isize_ty) }
7410        } else {
7411            quote_spanned! {span=> #tokens as #isize_ty }
7412        }
7413    }
7414
7415    /// The value `++place` or `--place` stores.
7416    fn step_value(&mut self, current: Value, ty: Ty, dec: bool, span: Span) -> TokenStream {
7417        if ty.is_pointer() {
7418            let access = current.at(prec::CALL, span);
7419            let pointee = self.program.types.pointee(ty).unwrap_or(Ty::Void);
7420            let one = match (self.vm_scale(pointee, span), dec) {
7421                (None, true) => quote_spanned! {span=> -1 },
7422                (None, false) => quote_spanned! {span=> 1 },
7423                (Some(scale), true) => quote_spanned! {span=> -(#scale) },
7424                (Some(scale), false) => scale,
7425            };
7426            return quote_spanned! {span=> #access.offset(#one) };
7427        }
7428        if ty.is_floating() {
7429            let access = current.at(prec::SUM, span);
7430            let one = Literal::f64_unsuffixed(1.0);
7431            let op = if dec {
7432                quote_spanned! {span=> - }
7433            } else {
7434                quote_spanned! {span=> + }
7435            };
7436            return quote_spanned! {span=> #access #op #one };
7437        }
7438        if ty.is_complex() {
7439            // GCC's `z++` adds one to the *real* part and leaves the
7440            // imaginary one alone, which is the componentwise `z + 1`.
7441            let name = if dec { "sub_real" } else { "add_real" };
7442            let func = self.rt_complex(&format!("{name}_{}", Self::complex_suffix(ty)), span);
7443            let access = current.at(prec::LOWEST, span);
7444            let one = Literal::f64_unsuffixed(1.0);
7445            return quote_spanned! {span=> #func(#access, #one) };
7446        }
7447        if ty.is_bool() {
7448            // `b++` is `b = b + 1 != 0`, which is `true` for `++` and the
7449            // negation of `b` for `--`.
7450            let access = current.at(prec::CAST, span);
7451            let int = self.ty(Ty::Int, span);
7452            let method = Ident::new(if dec { "wrapping_sub" } else { "wrapping_add" }, span);
7453            return quote_spanned! {span=> (#access as #int).#method(1) != 0 };
7454        }
7455        let access = current.at(prec::CALL, span);
7456        let method = Ident::new(if dec { "wrapping_sub" } else { "wrapping_add" }, span);
7457        quote_spanned! {span=> #access.#method(1) }
7458    }
7459
7460    /// Emits a conversion between two scalar types.
7461    fn cast(&mut self, value: Value, from: Ty, to: Ty, span: Span) -> Value {
7462        if from == to {
7463            return value;
7464        }
7465        if from.is_complex() || to.is_complex() {
7466            return self.complex_cast(value, from, to, span);
7467        }
7468        let types = &self.program.types;
7469        let from_fn = types.is_func_pointer(from);
7470        let to_fn = types.is_func_pointer(to);
7471        if to.is_bool() {
7472            if from.is_pointer() {
7473                // Handled by the caller for the common shapes; this is the
7474                // explicit `(_Bool)p`.
7475                let tokens = value.at(prec::CALL, span);
7476                return if from_fn {
7477                    let braced = braced(tokens, span);
7478                    Value::new(quote_spanned! {span=> #braced.is_some() }, prec::CALL)
7479                } else {
7480                    Value::new(quote_spanned! {span=> !#tokens.is_null() }, prec::UNARY)
7481                };
7482            }
7483            // Converting to `_Bool` yields 0 or 1, which is what a comparison
7484            // against zero gives.
7485            let zero = self.zero_tokens(from, span);
7486            let tokens = value.at(prec::CMP + 1, span);
7487            return Value::new(quote_spanned! {span=> #tokens != #zero }, prec::CMP);
7488        }
7489        if from_fn || to_fn {
7490            // Rust has no `as` between an `Option<fn>` and anything else, so a
7491            // transmute is the honest translation of what C's cast does — but
7492            // only between two things of the same size. An integer of any
7493            // other width goes through `usize`, which is what C's own
7494            // implementation-defined conversion between a pointer and an
7495            // integer amounts to.
7496            let target = self.ty(to, span);
7497            let source = self.ty(from, span);
7498            // Two C function types the generated Rust cannot tell apart need
7499            // no transmute at all: `void (*)()` and `void (*)(void)` are
7500            // distinct types in C and one `Option<unsafe extern "C" fn()>`
7501            // here. Writing the transmute anyway would be a no-op that still
7502            // has to be inside an `unsafe` block, which a `static` initialiser
7503            // then has to grow.
7504            if from_fn && to_fn && source.to_string() == target.to_string() {
7505                return value;
7506            }
7507            let usize_ty = primitive_ty("usize", span);
7508            if to_fn && !from.is_pointer() {
7509                let tokens = value.at(prec::CAST, span);
7510                return Value::new(
7511                    quote_spanned! {span=>
7512                        ::core::mem::transmute::<#usize_ty, #target>(#tokens as #usize_ty)
7513                    },
7514                    prec::CALL,
7515                );
7516            }
7517            if from_fn && !to.is_pointer() {
7518                let tokens = value.at(prec::LOWEST, span);
7519                return Value::new(
7520                    quote_spanned! {span=>
7521                        ::core::mem::transmute::<#source, #usize_ty>(#tokens) as #target
7522                    },
7523                    prec::CAST,
7524                )
7525                .type_end(true);
7526            }
7527            let tokens = value.at(prec::LOWEST, span);
7528            return Value::new(
7529                quote_spanned! {span=>
7530                    ::core::mem::transmute::<#source, #target>(#tokens)
7531                },
7532                prec::CALL,
7533            );
7534        }
7535        let target = self.ty(to, span);
7536        if from.is_pointer() && to.is_integer() {
7537            // Rust only casts a pointer to `usize`; the rest is an ordinary
7538            // integer conversion.
7539            let tokens = value.at(prec::CAST, span);
7540            let usize_ty = primitive_ty("usize", span);
7541            return Value::new(
7542                quote_spanned! {span=> #tokens as #usize_ty as #target },
7543                prec::CAST,
7544            )
7545            .type_end(true);
7546        }
7547        if from.is_bool() && to.is_floating() {
7548            // Rust has no `bool as f64`; C's `_Bool` to floating conversion
7549            // goes through the integer value.
7550            let int = self.ty(Ty::Int, span);
7551            let tokens = value.at(prec::CAST, span);
7552            return Value::new(
7553                quote_spanned! {span=> #tokens as #int as #target },
7554                prec::CAST,
7555            )
7556            .type_end(true);
7557        }
7558        let tokens = value.at(prec::CAST, span);
7559        Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
7560    }
7561
7562    // -- places -------------------------------------------------------------
7563
7564    /// A place, ready to be read from or written to.
7565    ///
7566    /// `mutable` says whether the place is about to be assigned to or have its
7567    /// address taken, which is what decides whether a `const` pointer under it
7568    /// has to lose the qualifier: Rust refuses `&raw mut (*p).f` when `p` is a
7569    /// `*const T`, while reading through one is fine.
7570    fn place(&mut self, place: &Place, mutable: bool) -> LoweredPlace {
7571        // Even *reading* an atomic object needs a `*mut` to it:
7572        // `AtomicX::from_ptr` takes one, and a `const _Atomic int *` would
7573        // otherwise reach `&raw mut *p` through a `*const` pointer, which
7574        // Rust refuses. What C promises is enough for the cast — every object
7575        // this crate generates lives in writable storage.
7576        let atomic = matches!(place.ty, Ty::Atomic(_));
7577        let mut lowered = self.place_access(place, mutable || atomic);
7578        if lowered.bits.is_none() && self.place_underaligned(place) {
7579            lowered.unaligned = true;
7580        }
7581        if let Ty::Atomic(id) = place.ty {
7582            let inner = self.program.types.atomic_inner(id);
7583            lowered.atomic = ir::atomic_class(&self.program.types, inner, &self.options.target)
7584                .map(|c| (c, inner));
7585            // There is no unaligned atomic: the alignment of an `_Atomic` type
7586            // is its size, and sema refuses the declarations that could not
7587            // have it.
7588            if lowered.atomic.is_some() {
7589                lowered.unaligned = false;
7590            }
7591        }
7592        lowered
7593    }
7594
7595    /// Whether the place has to be reached through an unaligned load or store.
7596    ///
7597    /// Two shapes need one. A `*p` or a `p[i]` whose pointer this crate itself
7598    /// built out of a packed member is underaligned, and so is a member read
7599    /// through a pointer to a record that is: `(*(T *) &buf).f`, where `buf` is
7600    /// a `char` array, is a member access Rust would compile to an aligned load
7601    /// of a byte-aligned address. A member of a *packed* record whose own
7602    /// address is fine needs nothing — Rust knows the layout of the item it was
7603    /// given and reads such a member unaligned by itself.
7604    fn place_underaligned(&self, place: &Place) -> bool {
7605        match &place.kind {
7606            PlaceKind::Deref(_) | PlaceKind::Index { .. } => {
7607                self.place_align(place) < self.type_align(place.ty)
7608            }
7609            PlaceKind::Field { base, .. } => self.place_align(base) < self.type_align(base.ty),
7610            // A part of a complex object reached through a packed member is
7611            // no better aligned than the object is.
7612            PlaceKind::ComplexPart { .. } => self.place_align(place) < self.type_align(place.ty),
7613            _ => false,
7614        }
7615    }
7616
7617    /// The alignment code generation can count on for a place's address.
7618    ///
7619    /// Everything C promises about an object's alignment holds for a place that
7620    /// names one, so the interesting half is what this crate itself can see
7621    /// through: the address of a member sits at its offset from a base whose
7622    /// alignment is known, and a cast in between changes nothing. Anything else
7623    /// — a pointer out of a variable, a parameter, a call — is taken at C's
7624    /// word and assumed to point at something its type is aligned for.
7625    fn place_align(&self, place: &Place) -> u64 {
7626        match &place.kind {
7627            PlaceKind::Deref(ptr) => self.pointer_align(ptr),
7628            PlaceKind::Index { base, .. } => {
7629                // Every element of an array sits at a multiple of the element
7630                // size from the first, and a size is always a multiple of the
7631                // alignment, so the elements are no worse aligned than the
7632                // element type asks and no better than the array is.
7633                self.pointer_align(base).min(self.type_align(place.ty))
7634            }
7635            PlaceKind::Field {
7636                base,
7637                record,
7638                index,
7639            } => {
7640                let base_align = self.place_align(base);
7641                let offset = self.program.types.record(*record).fields[*index].offset;
7642                if offset == 0 {
7643                    base_align
7644                } else {
7645                    base_align.min(1 << offset.trailing_zeros())
7646                }
7647            }
7648            // The real part sits at the object's own address and the imaginary
7649            // one exactly one component later, which is a power of two.
7650            PlaceKind::ComplexPart { base, imag } => {
7651                let base_align = self.place_align(base);
7652                if *imag {
7653                    base_align.min(place.ty.size_bytes(&self.options.target).max(1))
7654                } else {
7655                    base_align
7656                }
7657            }
7658            // An `_Alignas` on the declaration is a promise about the object
7659            // that the wrapper really keeps.
7660            PlaceKind::Object(id) => self
7661                .object_align(*id)
7662                .unwrap_or(1)
7663                .max(self.type_align(place.ty)),
7664            _ => self.type_align(place.ty),
7665        }
7666    }
7667
7668    /// The alignment of what a pointer expression points at.
7669    fn pointer_align(&self, ptr: &Expr) -> u64 {
7670        match &ptr.kind {
7671            ExprKind::AddrOf(place) => self.place_align(place),
7672            // A pointer cast moves no bytes, and neither does the decay of an
7673            // array to its first element.
7674            ExprKind::Cast(inner) if inner.ty.is_pointer() || inner.ty.is_array() => {
7675                let from = self.pointer_align(inner);
7676                // ...but a cast *to* a pointer to an under-aligned `typedef`
7677                // takes back the promise: `*(const xxh_unalign64 *) p`.
7678                match &ptr.ty {
7679                    Ty::Pointer(id) => match self.program.types.pointer_type(*id).align {
7680                        Some(align) => from.min(align),
7681                        None => from,
7682                    },
7683                    _ => from,
7684                }
7685            }
7686            ExprKind::PtrOffset { ptr, .. } => self
7687                .pointer_align(ptr)
7688                .min(self.pointee_align(ptr.ty).unwrap_or(1)),
7689            _ => self.pointee_align(ptr.ty).unwrap_or(u64::MAX),
7690        }
7691    }
7692
7693    /// The alignment of the type a pointer or array type addresses.
7694    fn pointee_align(&self, ty: Ty) -> Option<u64> {
7695        // A pointer to an under-aligned `typedef` (`xxh_unalign64 *`) promises
7696        // only the `typedef`'s alignment; see `ir::PointerType::align`.
7697        if let Ty::Pointer(id) = ty
7698            && let Some(align) = self.program.types.pointer_type(id).align
7699        {
7700            return Some(align);
7701        }
7702        let pointee = self.program.types.pointee(ty)?;
7703        (!pointee.is_void() && !pointee.is_func()).then(|| self.type_align(pointee))
7704    }
7705
7706    /// The alignment the *generated Rust type* has, which is what a `*p` in the
7707    /// expansion is checked against.
7708    fn type_align(&self, ty: Ty) -> u64 {
7709        match ty {
7710            // A packed record's item is one byte aligned however strict C says
7711            // the record is; see `ir::RecordDef::rust_align`.
7712            Ty::Record(id) => self.program.types.record(id).rust_align,
7713            Ty::Array(id) => self.type_align(self.program.types.array_type(id).elem),
7714            _ => self
7715                .program
7716                .types
7717                .size_align(ty, &self.options.target)
7718                .map_or(1, |layout| layout.align),
7719        }
7720    }
7721
7722    fn place_access(&mut self, place: &Place, mutable: bool) -> LoweredPlace {
7723        let span = self.sp(place.range);
7724        match &place.kind {
7725            PlaceKind::Object(id) if self.program.object(*id).storage.is_thread_local() => {
7726                // A thread-local object is reached through the `*mut T` inside
7727                // its cell, which is valid for as long as this thread's copy
7728                // of the object is — exactly the lifetime C gives it. The
7729                // pointer is taken once and the place is a dereference of it,
7730                // so an expression that reads the object twice still calls
7731                // `with` once.
7732                let name = self.object_ident(*id, span);
7733                let tmp = self.temporary_at(span);
7734                let cell = Ident::new("__cinrs_cell", Span::mixed_site());
7735                // The cell holds whatever wrappers the storage carries, and
7736                // the object is reached through them exactly as it is for
7737                // every other storage class.
7738                let object = parenthesize(quote_spanned! {span=> *#tmp }, span);
7739                let object = self.through_storage(*id, object, span);
7740                LoweredPlace::plain(
7741                    quote_spanned! {span=>
7742                        let #tmp = #name.with(|#cell| ::core::cell::UnsafeCell::get(#cell));
7743                    },
7744                    object,
7745                )
7746            }
7747            PlaceKind::Object(id) => {
7748                let access = self.object_access(*id, span);
7749                LoweredPlace::plain(TokenStream::new(), access)
7750            }
7751            PlaceKind::Deref(ptr) => self.deref_place(ptr, place.ty, mutable, span),
7752            PlaceKind::Index { base, index } => {
7753                let pointer = self.pointer_operand(base, place.ty, mutable, span);
7754                let offset = self.scaled_offset(place.ty, index, false, span);
7755                let tmp = self.temporary_at(span);
7756                LoweredPlace::plain(
7757                    quote_spanned! {span=> let #tmp = #pointer.offset(#offset); },
7758                    parenthesize(quote_spanned! {span=> *#tmp }, span),
7759                )
7760            }
7761            PlaceKind::Field {
7762                base,
7763                record,
7764                index,
7765            } => {
7766                let field = self.program.types.record(*record).fields[*index].clone();
7767                let lowered = self.place(base, mutable);
7768                let access = lowered.access;
7769                let Some(bits) = &field.bits else {
7770                    let name = self.c_ident(&field.name, span);
7771                    return LoweredPlace::plain(
7772                        lowered.setup,
7773                        quote_spanned! {span=> #access.#name },
7774                    );
7775                };
7776                // The accessors take `&self` and `&mut self`, and a reference
7777                // to a `static mut` is exactly what edition 2024 refuses; the
7778                // raw pointer keeps the item out of the expression.
7779                let access = if rooted_in_static(base, self.program) {
7780                    parenthesize(quote_spanned! {span=> *(&raw mut #access) }, span)
7781                } else {
7782                    access
7783                };
7784                LoweredPlace {
7785                    setup: lowered.setup,
7786                    access,
7787                    bits: Some(BitAccess {
7788                        getter: self.c_ident(&bits.getter, span),
7789                        setter: self.c_ident(&bits.setter, span),
7790                    }),
7791                    unaligned: false,
7792                    atomic: None,
7793                }
7794            }
7795            // `__real__ z` and `__imag__ z` are the two fields of the runtime's
7796            // `Complex`, which is why they are assignable: the place is a Rust
7797            // place expression like any member access.
7798            PlaceKind::ComplexPart { base, imag } => {
7799                let lowered = self.place(base, mutable);
7800                let access = lowered.access;
7801                let field = Ident::new(if *imag { "im" } else { "re" }, span);
7802                LoweredPlace::plain(lowered.setup, quote_spanned! {span=> #access.#field })
7803            }
7804            PlaceKind::Str(id) => {
7805                let pointer = self.string_pointer(*id, !mutable, span);
7806                let tmp = self.temporary_at(span);
7807                LoweredPlace::plain(
7808                    quote_spanned! {span=> let #tmp = #pointer; },
7809                    parenthesize(quote_spanned! {span=> *#tmp }, span),
7810                )
7811            }
7812            PlaceKind::Temporary(expr) => {
7813                let ty = expr.ty;
7814                let value = self.expr_at(expr, ty);
7815                let tmp = self.temporary();
7816                LoweredPlace::plain(
7817                    quote_spanned! {span=> let mut #tmp = #value; },
7818                    quote_spanned! {span=> #tmp },
7819                )
7820            }
7821            // The binding itself was made at the top of the enclosing block —
7822            // C gives the object that lifetime, and it is what lets `&(T){…}`
7823            // outlive the expression. What happens *here* is the
7824            // initialisation, so that side effects in it happen where the
7825            // literal was written and a literal in a loop is rebuilt on every
7826            // iteration.
7827            PlaceKind::CompoundLiteral { object, init } => {
7828                let name = self.object_ident(*object, span);
7829                let value = self.expr_at(init, place.ty);
7830                LoweredPlace::plain(
7831                    quote_spanned! {span=> #name = #value; },
7832                    quote_spanned! {span=> #name },
7833                )
7834            }
7835        }
7836    }
7837
7838    /// Reads a lowered place.
7839    fn read(&self, place: &LoweredPlace, span: Span) -> Value {
7840        let access = &place.access;
7841        if let Some((class, ty)) = place.atomic {
7842            let object = self.atomic_object_of(place, span);
7843            let order = self.ordering(ir::MemOrder::SeqCst, span);
7844            return self.repr_to_value(
7845                class,
7846                ty,
7847                quote_spanned! {span=> #object.load(#order) },
7848                span,
7849            );
7850        }
7851        match &place.bits {
7852            Some(bits) => {
7853                let getter = &bits.getter;
7854                Value::new(quote_spanned! {span=> #access.#getter() }, prec::CALL)
7855            }
7856            None if place.unaligned => Value::new(
7857                quote_spanned! {span=> (&raw const #access).read_unaligned() },
7858                prec::CALL,
7859            ),
7860            None => Value::atom(access.clone()),
7861        }
7862    }
7863
7864    /// The statement that stores `value` into a lowered place.
7865    fn write(&self, place: &LoweredPlace, value: TokenStream, span: Span) -> TokenStream {
7866        let access = &place.access;
7867        if let Some((class, ty)) = place.atomic {
7868            let object = self.atomic_object_of(place, span);
7869            let order = self.ordering(ir::MemOrder::SeqCst, span);
7870            let value = self.value_to_repr(class, ty, Value::new(value, prec::LOWEST), span);
7871            return quote_spanned! {span=> #object.store(#value, #order); };
7872        }
7873        match &place.bits {
7874            Some(bits) => {
7875                let setter = &bits.setter;
7876                quote_spanned! {span=> #access.#setter(#value); }
7877            }
7878            None if place.unaligned => {
7879                quote_spanned! {span=> (&raw mut #access).write_unaligned(#value); }
7880            }
7881            None => quote_spanned! {span=> #access = #value; },
7882        }
7883    }
7884
7885    /// The `&AtomicX` an `_Atomic` place is reached through.
7886    ///
7887    /// A raw pointer to the object rather than a reference to it: the object
7888    /// is a plain `static mut` or `let mut` of the underlying type, and its
7889    /// address is what `from_ptr` wants.
7890    fn atomic_object_of(&self, place: &LoweredPlace, span: Span) -> TokenStream {
7891        let access = &place.access;
7892        let class = place.atomic.expect("an atomic place").0;
7893        self.atomic_ref(class, quote_spanned! {span=> (&raw mut #access) }, span)
7894    }
7895
7896    /// `*p` as a place.
7897    fn deref_place(&mut self, ptr: &Expr, pointee: Ty, mutable: bool, span: Span) -> LoweredPlace {
7898        let simple =
7899            matches!(&ptr.kind, ExprKind::Load(p) if matches!(p.kind, PlaceKind::Object(_)));
7900        if simple {
7901            // A variable holding the pointer can be dereferenced as often as
7902            // needed, so no temporary is called for.
7903            let tokens = self.pointer_operand(ptr, pointee, mutable, span);
7904            return LoweredPlace::plain(
7905                TokenStream::new(),
7906                parenthesize(quote_spanned! {span=> *#tokens }, span),
7907            );
7908        }
7909        let value = self.pointer_operand(ptr, pointee, mutable, span);
7910        let tmp = self.temporary_at(span);
7911        LoweredPlace::plain(
7912            quote_spanned! {span=> let #tmp = #value; },
7913            parenthesize(quote_spanned! {span=> *#tmp }, span),
7914        )
7915    }
7916
7917    /// The pointer a place is built on.
7918    ///
7919    /// Writing through a `*const T` is not allowed even in `unsafe` Rust, and
7920    /// C's own `const` checking has already happened in sema, so a place that
7921    /// is about to be written to (or have its address taken) drops the
7922    /// qualifier here rather than at every use.
7923    fn pointer_operand(
7924        &mut self,
7925        ptr: &Expr,
7926        pointee: Ty,
7927        mutable: bool,
7928        span: Span,
7929    ) -> TokenStream {
7930        if mutable && self.program.types.points_to_const(ptr.ty) {
7931            let target = self.pointee_ty(pointee, span);
7932            let tokens = self.expr(ptr).at(prec::CAST, span);
7933            return parenthesize(quote_spanned! {span=> #tokens as *mut #target }, span);
7934        }
7935        self.expr(ptr).at(prec::CALL, span)
7936    }
7937
7938    /// The address of a place, as a pointer of type `want`.
7939    fn address_of(&mut self, place: &Place, want: Ty, span: Span) -> Value {
7940        // A variably modified object's binding already *is* the address of its
7941        // first element, so both the decay `a` and the array pointer `&a` are
7942        // that binding — the second one only differs in its C type.
7943        if let PlaceKind::Object(id) = &place.kind
7944            && self.program.types.is_vm(place.ty)
7945        {
7946            let name = self.object_ident(*id, span);
7947            let value = Value::atom(quote_spanned! {span=> #name });
7948            let elem = self.program.types.elem(place.ty);
7949            let natural = self.program.types.pointee(want) == elem
7950                && !self.program.types.points_to_const(want);
7951            if natural {
7952                return value;
7953            }
7954            let target = self.ty(want, span);
7955            let tokens = value.at(prec::CAST, span);
7956            return Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST)
7957                .type_end(true);
7958        }
7959        // `&*p` is `p`, and `&a[i]` is `a + i`; saying so keeps the output
7960        // free of pointless round trips through a place.
7961        match &place.kind {
7962            PlaceKind::Deref(ptr) => {
7963                let from = ptr.ty;
7964                let value = self.expr(ptr);
7965                return self.pointer_cast(value, from, want, span);
7966            }
7967            PlaceKind::Index { base, index } => {
7968                let from = base.ty;
7969                let pointer = self.expr(base).at(prec::CALL, span);
7970                let offset = self.scaled_offset(place.ty, index, false, span);
7971                let value = Value::new(
7972                    quote_spanned! {span=> #pointer.offset(#offset) },
7973                    prec::CALL,
7974                );
7975                return self.pointer_cast(value, from, want, span);
7976            }
7977            PlaceKind::Str(id) => {
7978                let konst = self.program.types.points_to_const(want);
7979                let tokens = self.string_pointer(*id, konst, span);
7980                return Value::new(tokens, prec::CALL);
7981            }
7982            _ => {}
7983        }
7984        let lowered = self.place(place, true);
7985        let access = lowered.access;
7986        let address = quote_spanned! {span=> &raw mut #access };
7987        let natural = Value::new(parenthesize(address, span), prec::ATOM);
7988        let value = self.array_or_pointer_cast(natural, place.ty, want, span);
7989        if lowered.setup.is_empty() {
7990            return value;
7991        }
7992        let setup = lowered.setup;
7993        let tokens = value.at(prec::LOWEST, span);
7994        Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
7995    }
7996
7997    /// Adjusts `&raw mut place` to the pointer type the expression wants.
7998    fn array_or_pointer_cast(&mut self, value: Value, from: Ty, want: Ty, span: Span) -> Value {
7999        if let Ty::Array(id) = from {
8000            // The address of an array is a pointer to the array; decaying it
8001            // to a pointer to the first element is a `cast`, which — unlike
8002            // `as` — cannot silently change anything else.
8003            let array = self.program.types.array_type(id);
8004            let wanted_pointee = self.program.types.pointee(want);
8005            if wanted_pointee == Some(array.elem) {
8006                let elem = self.pointee_ty(array.elem, span);
8007                let tokens = value.at(prec::CALL, span);
8008                let cast = Value::new(quote_spanned! {span=> #tokens.cast::<#elem>() }, prec::CALL);
8009                return self.constify(cast, want, span);
8010            }
8011        }
8012        let natural_mut = matches!(self.program.types.pointee(want), Some(pointee) if pointee == from)
8013            && !self.program.types.points_to_const(want);
8014        if natural_mut {
8015            return value;
8016        }
8017        let target = self.ty(want, span);
8018        let tokens = value.at(prec::CAST, span);
8019        Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
8020    }
8021
8022    /// Adds the `as *const T` that a `*mut T` needs to become a `*const T`.
8023    fn constify(&mut self, value: Value, want: Ty, span: Span) -> Value {
8024        if !self.program.types.points_to_const(want) {
8025            return value;
8026        }
8027        let target = self.ty(want, span);
8028        let tokens = value.at(prec::CAST, span);
8029        Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
8030    }
8031
8032    /// Casts a pointer value to the pointer type wanted.
8033    fn pointer_cast(&mut self, value: Value, from: Ty, want: Ty, span: Span) -> Value {
8034        if from == want {
8035            return value;
8036        }
8037        let target = self.ty(want, span);
8038        let tokens = value.at(prec::CAST, span);
8039        Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
8040    }
8041
8042    /// The pointer a string literal decays to.
8043    fn string_pointer(&mut self, id: ir::StrId, konst: bool, span: Span) -> TokenStream {
8044        let data = self.program.string(id);
8045        let element = data.elem;
8046        if element.size_bytes(&self.options.target) > 1 {
8047            // A `wchar_t`, `char16_t` or `char32_t` literal needs real storage
8048            // of that type; a `static` in the enclosing block is the only
8049            // thing with a long enough lifetime.
8050            let elem = self.ty(element, span);
8051            let mut items = TokenStream::new();
8052            for value in data.values.iter().chain(std::iter::once(&0)) {
8053                let literal =
8054                    int_literal_token(element.wrap(i128::from(*value), &self.options.target), span);
8055                items.extend(quote_spanned! {span=> #literal, });
8056            }
8057            let len = usize_literal(data.len_with_nul(), span);
8058            let name = Ident::new("__CINRS_WIDE", Span::mixed_site());
8059            let array = bracketed(items, span);
8060            let ty = bracketed(quote_spanned! {span=> #elem ; #len }, span);
8061            let pointer = if konst {
8062                quote_spanned! {span=> (&raw const #name).cast::<#elem>() }
8063            } else {
8064                quote_spanned! {span=> (&raw const #name).cast::<#elem>().cast_mut() }
8065            };
8066            return quote_spanned! {span=>
8067                { static #name: #ty = #array; #pointer }
8068            };
8069        }
8070        // A narrow or `u8"…"` literal is a Rust byte string, whose elements
8071        // are the same bytes whether C calls them `char` or `char8_t`.
8072        let mut literal = Literal::byte_string(&nul_terminated(&data.values));
8073        literal.set_span(span);
8074        let elem = self.ty(element, span);
8075        if konst {
8076            quote_spanned! {span=> #literal.as_ptr().cast::<#elem>() }
8077        } else {
8078            quote_spanned! {span=> #literal.as_ptr().cast::<#elem>().cast_mut() }
8079        }
8080    }
8081
8082    // -- literals -----------------------------------------------------------
8083
8084    fn int_literal(&self, value: i128, ty: Ty, span: Span) -> Value {
8085        if ty.is_bool() {
8086            return Value::atom(bare_int_literal(value, ty, span));
8087        }
8088        if ty == Ty::UInt128 {
8089            // The constant is the bit pattern; the literal has to spell the
8090            // `u128` it stands for rather than the `i128` those bits read as.
8091            let literal = u128_literal_token(value as u128, span);
8092            let target = self.ty(ty, span);
8093            return Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST)
8094                .type_end(true);
8095        }
8096        let literal = int_literal_token(value, span);
8097        let target = self.ty(ty, span);
8098        Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
8099    }
8100
8101    fn float_literal(&self, value: f64, ty: Ty, span: Span) -> Value {
8102        if !value.is_finite() {
8103            return Value::new(self.non_finite_literal(value, ty, span), prec::CAST).type_end(true);
8104        }
8105        let literal = float_literal_token(value, span);
8106        let target = self.ty(ty, span);
8107        Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
8108    }
8109
8110    /// An infinity or a NaN, which no Rust literal can spell.
8111    ///
8112    /// A NaN that is not the default quiet one — `__builtin_nan("0x123")`, and
8113    /// the negative NaN `-__builtin_nan("")` is — is written out bit for bit.
8114    /// `f64::NAN` is *one* NaN, and a payload and a sign are part of the value
8115    /// a program asked for; `as` between the two widths is free to lose both.
8116    fn non_finite_literal(&self, value: f64, ty: Ty, span: Span) -> TokenStream {
8117        let target = self.ty(ty, span);
8118        let f64_ty = primitive_ty("f64", span);
8119        if value.is_nan() {
8120            let bits = value.to_bits();
8121            if bits == f64::NAN.to_bits() {
8122                return quote_spanned! {span=> <#f64_ty>::NAN as #target };
8123            }
8124            if ty == Ty::Float {
8125                let f32_ty = primitive_ty("f32", span);
8126                let literal =
8127                    unsigned_hex_literal(u64::from(ir::narrow_nan_bits(bits)), "u32", span);
8128                return quote_spanned! {span=> <#f32_ty>::from_bits(#literal) };
8129            }
8130            let literal = unsigned_hex_literal(bits, "u64", span);
8131            return quote_spanned! {span=> <#f64_ty>::from_bits(#literal) as #target };
8132        }
8133        if value.is_sign_negative() {
8134            quote_spanned! {span=> -<#f64_ty>::INFINITY as #target }
8135        } else {
8136            quote_spanned! {span=> <#f64_ty>::INFINITY as #target }
8137        }
8138    }
8139
8140    /// The all-bits-zero value of a type.
8141    fn zero_tokens(&self, ty: Ty, span: Span) -> TokenStream {
8142        match ty {
8143            // The zero of an `_Atomic T` is the zero of `T`: the object is
8144            // generated as a plain `T`, and initialising it is a plain write.
8145            Ty::Atomic(id) => self.zero_tokens(self.program.types.atomic_inner(id), span),
8146            _ if ty.is_complex() => {
8147                let zero = bare_float_literal(0.0, span);
8148                self.complex_new(ty, zero.clone(), zero, span)
8149                    .at(prec::LOWEST, span)
8150            }
8151            _ if ty.is_floating() => bare_float_literal(0.0, span),
8152            _ if ty.is_integer() => bare_int_literal(0, ty, span),
8153            // A variably modified array is generated as a pointer, and the
8154            // only thing that ever asks for its zero is the hoisting a [CFG
8155            // body](crate::cfg) does before the declaration is reached.
8156            Ty::Array(_) if self.program.types.is_vm(ty) => {
8157                let step = self.ty(self.program.types.vm_step_ty(ty), span);
8158                quote_spanned! {span=> ::core::ptr::null_mut::<#step>() }
8159            }
8160            Ty::Pointer(id) => {
8161                let pointer = self.program.types.pointer_type(id);
8162                if let Ty::Func(func) = pointer.pointee {
8163                    // The signature is written out rather than left to
8164                    // inference: a null function pointer is often the whole
8165                    // expression — `((void (*)(void))0)()` — and a bare
8166                    // `Option::None` there is `E0282`.
8167                    let signature = self.fn_ty(func, span);
8168                    return quote_spanned! {span=>
8169                        ::core::option::Option::<#signature>::None
8170                    };
8171                }
8172                let pointee = self.pointee_ty(pointer.pointee, span);
8173                if pointer.konst {
8174                    quote_spanned! {span=> ::core::ptr::null::<#pointee>() }
8175                } else {
8176                    quote_spanned! {span=> ::core::ptr::null_mut::<#pointee>() }
8177                }
8178            }
8179            other => {
8180                // A zeroed aggregate: `mem::zeroed` is a `const fn`, so this
8181                // works in a `static` initialiser as well as in a body.
8182                let target = self.ty(other, span);
8183                quote_spanned! {span=> ::core::mem::zeroed::<#target>() }
8184            }
8185        }
8186    }
8187}
8188
8189/// The value a bit-field's initialiser folds to, if it folds at all.
8190///
8191/// Sema has already reduced a constant to a bare `Int` node, and the implicit
8192/// zero every unmentioned member gets is either that or [`ExprKind::Zeroed`].
8193fn constant_bits(expr: &Expr) -> Option<i128> {
8194    match &expr.kind {
8195        ExprKind::Int(value) => Some(*value),
8196        ExprKind::Zeroed if expr.ty.is_integer() => Some(0),
8197        _ => None,
8198    }
8199}
8200
8201/// Writes the low `width` bits of `value` into a run's storage bytes.
8202fn pack_bits(storage: &mut [u8], bits: &ir::BitField, value: i128) {
8203    let start = bits.offset_in_storage();
8204    for bit in 0..u64::from(bits.width) {
8205        if (value as u128) >> bit & 1 == 0 {
8206            continue;
8207        }
8208        let at = start + bit;
8209        if let Some(byte) = storage.get_mut((at / 8) as usize) {
8210            *byte |= 1 << (at % 8);
8211        }
8212    }
8213}
8214
8215/// `[0x1f, 0x00, …]`, the initialiser of a storage field.
8216fn byte_array(bytes: &[u8], span: Span) -> TokenStream {
8217    if bytes.iter().all(|byte| *byte == 0) {
8218        let len = usize_literal(bytes.len() as u64, span);
8219        return bracketed(quote_spanned! {span=> 0; #len }, span);
8220    }
8221    let mut items = TokenStream::new();
8222    for byte in bytes {
8223        let value = hex_literal(u64::from(*byte), span);
8224        items.extend(quote_spanned! {span=> #value, });
8225    }
8226    bracketed(items, span)
8227}
8228
8229/// Whether a place ultimately names an object with static storage duration.
8230///
8231/// The bit-field accessors borrow, and edition 2024 refuses a reference to a
8232/// `static mut`; a place rooted in one is reached through `&raw mut` instead.
8233/// Anything behind a pointer is already a raw dereference, so it needs nothing
8234/// — a thread-local object included, since its place is the dereference of the
8235/// pointer out of its cell.
8236///
8237/// It is also what says whether an initialiser refers to an item, which a Rust
8238/// `const` may not; see [`Codegen::const_initialisable`].
8239fn rooted_in_static(place: &Place, program: &Program) -> bool {
8240    let mut place = place;
8241    loop {
8242        match &place.kind {
8243            PlaceKind::Object(id) => {
8244                let storage = &program.object(*id).storage;
8245                return !matches!(storage, Storage::Automatic) && !storage.is_thread_local();
8246            }
8247            PlaceKind::Field { base, .. } => place = base,
8248            _ => return false,
8249        }
8250    }
8251}
8252
8253/// The Rust unsigned integer of a given width, which is what the bit-counting
8254/// builtins are defined on.
8255fn unsigned_rust_ty(width: u32, span: Span) -> TokenStream {
8256    primitive_ty(
8257        match width {
8258            0..=8 => "u8",
8259            9..=16 => "u16",
8260            17..=32 => "u32",
8261            _ => "u64",
8262        },
8263        span,
8264    )
8265}
8266
8267/// The signed counterpart, for `__builtin_clrsb`.
8268fn signed_rust_ty(width: u32, span: Span) -> TokenStream {
8269    primitive_ty(
8270        match width {
8271            0..=8 => "i8",
8272            9..=16 => "i16",
8273            17..=32 => "i32",
8274            _ => "i64",
8275        },
8276        span,
8277    )
8278}
8279
8280/// A mask of `width` low bits, inside a word of `word_bits`.
8281fn mask_of(width: u32, word_bits: u32) -> u128 {
8282    let width = width.min(word_bits);
8283    if width >= 128 {
8284        u128::MAX
8285    } else {
8286        (1u128 << width) - 1
8287    }
8288}
8289
8290/// A mask literal, written in hexadecimal at the width of its word.
8291///
8292/// A `u128` mask carries its suffix: a bare hexadecimal literal above
8293/// `u64::MAX` would be out of range for whatever `u64` the surrounding
8294/// annotation asked for, and the annotation is what makes the narrow case
8295/// readable.
8296fn word_literal(value: u128, word_bits: u32, span: Span) -> TokenStream {
8297    if word_bits <= 64 {
8298        return hex_literal(value as u64, span);
8299    }
8300    let mut literal = Literal::from_str(&format!("0x{value:x}u128"))
8301        .unwrap_or_else(|_| Literal::u128_suffixed(value));
8302    literal.set_span(span);
8303    TokenStream::from(TokenTree::Literal(literal))
8304}
8305
8306/// A `u64` literal written in hexadecimal, which is how a mask reads.
8307fn hex_literal(value: u64, span: Span) -> TokenStream {
8308    let mut literal = Literal::from_str(&format!("0x{value:x}"))
8309        .unwrap_or_else(|_| Literal::u64_unsuffixed(value));
8310    literal.set_span(span);
8311    TokenStream::from(TokenTree::Literal(literal))
8312}
8313
8314/// The variable that says which entry of an irreducible region control is
8315/// going to, in this crate's own hygiene.
8316///
8317/// One per region rather than one per function; see [`crate::reloop`].
8318fn entry_ident(state: u32) -> Ident {
8319    Ident::new(&format!("__cinrs_entry{state}"), Span::mixed_site())
8320}
8321
8322/// The store that says which entry of a dispatch is meant, or nothing at all
8323/// when the jump has only one place to arrive.
8324fn entry_assignment(exit: &reloop::Exit, index: usize, span: Span) -> TokenStream {
8325    let Some(state) = exit.state else {
8326        return TokenStream::new();
8327    };
8328    let name = entry_ident(state);
8329    let value = state_literal(index, span);
8330    quote_spanned! {span=> #name = #value; }
8331}
8332
8333/// A state number, which is a `u32` because the state variable is.
8334/// The `default` of a computed `goto`'s dispatch: a value that is no label's
8335/// number, which is undefined behaviour in C.
8336///
8337/// A build with debug assertions — the user's, since `cfg!` is expanded in
8338/// their crate — panics, which catches the bug; any other build assumes it
8339/// away, as GCC does, which is what lets the `match` be a bare jump table.
8340fn invalid_target(span: Span) -> TokenStream {
8341    quote_spanned! {span=>
8342        if ::core::cfg!(debug_assertions) {
8343            ::core::unreachable!()
8344        } else {
8345            unsafe { ::core::hint::unreachable_unchecked() }
8346        }
8347    }
8348}
8349
8350fn state_literal(value: usize, span: Span) -> TokenStream {
8351    let mut literal = Literal::u32_unsuffixed(value as u32);
8352    literal.set_span(span);
8353    TokenStream::from(TokenTree::Literal(literal))
8354}
8355
8356/// Groups a switch's cases by the block they enter, keeping source order.
8357///
8358/// `case 0: case 1:` reaches the same block through two labels, and one arm
8359/// with an or-pattern is how that should read.
8360fn group_cases(cases: &[(ir::CaseRange, BlockId)]) -> Vec<(BlockId, Vec<ir::CaseRange>)> {
8361    let mut out: Vec<(BlockId, Vec<ir::CaseRange>)> = Vec::new();
8362    for (value, target) in cases {
8363        match out.iter_mut().find(|(block, _)| block == target) {
8364            Some((_, values)) => values.push(*value),
8365            None => out.push((*target, vec![*value])),
8366        }
8367    }
8368    out
8369}
8370
8371/// The Rust pattern one `case` label matches: a literal, or a range.
8372fn case_pattern(value: ir::CaseRange, ty: Ty, span: Span) -> TokenStream {
8373    let low = bare_int_literal(value.low, ty, span);
8374    if value.is_single() {
8375        return low;
8376    }
8377    let high = bare_int_literal(value.high, ty, span);
8378    quote_spanned! {span=> #low ..= #high }
8379}
8380
8381/// The precedence of the tokens [`Codegen::zero_tokens`] produces.
8382fn zero_prec(ty: Ty) -> u8 {
8383    if ty.is_arithmetic() {
8384        prec::ATOM
8385    } else {
8386        prec::CALL
8387    }
8388}
8389
8390/// `#[link_name = "…"]`, which points a renamed declaration back at its symbol.
8391fn link_name(symbol: &str, span: Span) -> TokenStream {
8392    let mut literal = Literal::string(symbol);
8393    literal.set_span(span);
8394    quote_spanned! {span=> #[link_name = #literal] }
8395}
8396
8397/// The attribute that gives a definition the C symbol `symbol`, for a unit
8398/// that asked for `#pragma cinrs export`.
8399///
8400/// `#[unsafe(no_mangle)]` is the edition-2024 spelling and is accepted in every
8401/// edition since 1.82, so one expansion works wherever it is written. It says
8402/// "the name of the item is the symbol", which is not quite always true here:
8403/// a C name that is a Rust keyword becomes `r#match`, and the five names that
8404/// cannot even be raw grow an underscore, so those go through `export_name`
8405/// instead and say the symbol outright.
8406fn export_attr(symbol: &str, item: &Ident, span: Span) -> TokenStream {
8407    if item.to_string().trim_start_matches("r#") == symbol {
8408        return quote_spanned! {span=> #[unsafe(no_mangle)] };
8409    }
8410    let mut literal = Literal::string(symbol);
8411    literal.set_span(span);
8412    quote_spanned! {span=> #[unsafe(export_name = #literal)] }
8413}
8414
8415/// Whether a static initialiser has to be wrapped in `unsafe`.
8416///
8417/// `types` is the arena, because one of the answers depends on it: a cast to
8418/// or from a function pointer is written out as a `transmute`, and that is an
8419/// unsafe call wherever it stands. `frob f[] = { abort };` with `typedef void
8420/// (*frob)();` is the shape — `execute/921110-1`.
8421fn needs_unsafe(types: &ir::Types, expr: &Expr) -> bool {
8422    let recurse = |inner| needs_unsafe(types, inner);
8423    match &expr.kind {
8424        // `mem::zeroed` is unsafe, and so is naming a `static mut`.
8425        ExprKind::Zeroed => !expr.ty.is_scalar(),
8426        // A string literal's address is safe to take; anything else with static
8427        // storage duration is a `static mut`.
8428        ExprKind::AddrOf(place) => !matches!(place.kind, PlaceKind::Str(_)),
8429        ExprKind::Cast(inner) => {
8430            let transmuted = types.is_func_pointer(expr.ty) || types.is_func_pointer(inner.ty);
8431            transmuted || recurse(inner)
8432        }
8433        // `<*mut T>::offset` is an unsafe call however safe its operand is:
8434        // `static const char *p = "foo" + 1;` — `execute/pr53084` — is the
8435        // address of a string literal, which is safe to take, plus one.
8436        ExprKind::PtrOffset { .. } => true,
8437        ExprKind::ComplexOf { re, im } => recurse(re) || recurse(im),
8438        ExprKind::RecordLit { fields, .. } => fields.iter().any(recurse),
8439        ExprKind::UnionLit { value, .. } => recurse(value),
8440        ExprKind::ArrayLit(items) => items.iter().any(recurse),
8441        ExprKind::ArrayRepeat { value, .. } => recurse(value),
8442        _ => false,
8443    }
8444}
8445
8446/// The bytes of a narrow string literal, with its terminating NUL.
8447fn nul_terminated(values: &[u32]) -> Vec<u8> {
8448    let mut bytes: Vec<u8> = values.iter().map(|v| *v as u8).collect();
8449    bytes.push(0);
8450    bytes
8451}
8452
8453// ---------------------------------------------------------------------------
8454// literal tokens
8455// ---------------------------------------------------------------------------
8456
8457/// The largest magnitude an unsuffixed literal is safe to have: Rust infers
8458/// `i32` for a literal with no other constraint.
8459const UNSUFFIXED_LIMIT: i128 = i32::MAX as i128;
8460
8461/// A `u128` literal, always suffixed: nothing else can spell a value above
8462/// `i128::MAX`.
8463fn u128_literal_token(value: u128, span: Span) -> TokenStream {
8464    let mut literal = Literal::u128_suffixed(value);
8465    literal.set_span(span);
8466    TokenStream::from(TokenTree::Literal(literal))
8467}
8468
8469/// A literal for `value`, with a Rust suffix only when inference needs one.
8470fn int_literal_token(value: i128, span: Span) -> TokenStream {
8471    if value == i128::MIN {
8472        // `-(2^127)` has no positive magnitude an `i128` can hold. Rust reads
8473        // the negation of the out-of-range literal as exactly this value,
8474        // which is how `i128::MIN` is written in Rust source too.
8475        let mut literal = Literal::from_str("170141183460469231731687303715884105728i128")
8476            .expect("a decimal literal followed by a suffix is a token");
8477        literal.set_span(span);
8478        return quote_spanned! {span=> -#literal };
8479    }
8480    let magnitude = value.unsigned_abs();
8481    let mut literal = if magnitude <= UNSUFFIXED_LIMIT as u128 {
8482        Literal::u128_unsuffixed(magnitude)
8483    } else if value >= 0 {
8484        if magnitude <= u32::MAX as u128 {
8485            Literal::u32_suffixed(magnitude as u32)
8486        } else if magnitude <= u64::MAX as u128 {
8487            Literal::u64_suffixed(magnitude as u64)
8488        } else {
8489            Literal::u128_suffixed(magnitude)
8490        }
8491    } else if magnitude <= i64::MAX as u128 {
8492        Literal::i64_suffixed(magnitude as i64)
8493    } else {
8494        Literal::i128_suffixed(magnitude as i128)
8495    };
8496    literal.set_span(span);
8497    if value < 0 {
8498        quote_spanned! {span=> -#literal }
8499    } else {
8500        TokenStream::from(TokenTree::Literal(literal))
8501    }
8502}
8503
8504/// A literal for `value` with no suffix at all, for a context that already
8505/// fixes its type.
8506fn bare_int_literal(value: i128, ty: Ty, span: Span) -> TokenStream {
8507    if ty.is_bool() {
8508        let ident = Ident::new(if value != 0 { "true" } else { "false" }, span);
8509        return quote_spanned! {span=> #ident };
8510    }
8511    if ty == Ty::UInt128 {
8512        // The value is carried as a bit pattern; `-1` in a `u128` context is
8513        // not what the constant means.
8514        let mut literal = Literal::u128_unsuffixed(value as u128);
8515        literal.set_span(span);
8516        return TokenStream::from(TokenTree::Literal(literal));
8517    }
8518    let mut literal = Literal::u128_unsuffixed(value.unsigned_abs());
8519    literal.set_span(span);
8520    if value < 0 {
8521        quote_spanned! {span=> -#literal }
8522    } else {
8523        TokenStream::from(TokenTree::Literal(literal))
8524    }
8525}
8526
8527/// The integer a bit-field's bytes are gathered into: `u64`/`i64` for a
8528/// window of 64 bits and the 128-bit primitives for a wider one.
8529///
8530/// All four take the [`core::primitive`] path, `typedef unsigned long long
8531/// u64;` being every bit as ordinary in C as `typedef unsigned __int128 u128;`.
8532fn window_ty(word_bits: u32, signed: bool, span: Span) -> TokenStream {
8533    match (word_bits, signed) {
8534        (128, false) => primitive_ty("u128", span),
8535        (128, true) => primitive_ty("i128", span),
8536        (_, false) => primitive_ty("u64", span),
8537        (_, true) => primitive_ty("i64", span),
8538    }
8539}
8540
8541/// `::core::primitive::u64` and every other primitive this code generator
8542/// writes.
8543///
8544/// **Every** bare primitive name goes through here, and none is ever written
8545/// as a bare identifier, because each of them is a name a C `typedef` can
8546/// take. `typedef _Bool bool;` is in the C23 compatibility header of half the
8547/// world's C — and in gcc.c-torture's `execute/20030714-1` — while `typedef
8548/// unsigned int u32;`, `typedef unsigned long usize;` and `typedef long long
8549/// i64;` are how a great deal of embedded C spells its types. The generated
8550/// item is then `pub type bool = bool;`, which is a cycle (`E0391`), and even
8551/// where it is not a cycle the alias shadows the primitive for the rest of the
8552/// module — so the padding of a `struct`, a bit-field accessor's window and a
8553/// pointer difference would all silently take the C type instead.
8554///
8555/// The [`core::primitive`] module exists for exactly this, and the leading
8556/// `::core` keeps it working in a crate that has renamed its own `core`.
8557fn primitive_ty(name: &str, span: Span) -> TokenStream {
8558    let ident = Ident::new(name, span);
8559    quote_spanned! {span=> ::core::primitive::#ident }
8560}
8561
8562/// Stamps every token of a stream with one span.
8563///
8564/// Only the crate path `#pragma cinrs crate` gives needs it: everything else
8565/// the generator emits is built token by token from a span it already has,
8566/// while that one is *parsed* out of a string and so arrives with call-site
8567/// spans that would send `rustc`'s complaint about a bad path to the wrong
8568/// place.
8569fn respan(tokens: TokenStream, span: Span) -> TokenStream {
8570    tokens
8571        .into_iter()
8572        .map(|tree| {
8573            let mut tree = match tree {
8574                TokenTree::Group(group) => {
8575                    TokenTree::Group(Group::new(group.delimiter(), respan(group.stream(), span)))
8576                }
8577                other => other,
8578            };
8579            tree.set_span(span);
8580            tree
8581        })
8582        .collect()
8583}
8584
8585/// A string literal for an `assert!` message, which a `const` context needs to
8586/// be a literal rather than anything formatted.
8587fn message_literal(text: &str, span: Span) -> TokenStream {
8588    let mut literal = Literal::string(text);
8589    literal.set_span(span);
8590    TokenStream::from(TokenTree::Literal(literal))
8591}
8592
8593/// An array length, which Rust counts in `usize`.
8594fn usize_literal(value: u64, span: Span) -> TokenStream {
8595    let mut literal = Literal::usize_unsuffixed(value as usize);
8596    literal.set_span(span);
8597    TokenStream::from(TokenTree::Literal(literal))
8598}
8599
8600/// An integer literal with the Rust suffix `ty` names: `3i32`, `7u32`.
8601///
8602/// It is what an x86 intrinsic's immediate operand becomes, where the type of
8603/// `core::arch`'s `const` parameter has to be written out because a const
8604/// argument is not inferred from the parameter.
8605/// The head of an `asm!` operand, up to its expression: `o0 = lateout(reg)`,
8606/// `inout("eax")`, `o2 = const`.
8607fn asm_operand_head(operand: &ir::AsmOperand, span: Span) -> TokenStream {
8608    let dir = match &operand.kind {
8609        ir::AsmOperandKind::In(_) => "in",
8610        ir::AsmOperandKind::Out { late: true, .. } => "lateout",
8611        ir::AsmOperandKind::Out { late: false, .. } => "out",
8612        ir::AsmOperandKind::InOut { .. } | ir::AsmOperandKind::Scratch(_) => "inout",
8613        ir::AsmOperandKind::Const(_) => "const",
8614    };
8615    let dir = Ident::new(dir, span);
8616    let reg = match (&operand.kind, operand.reg) {
8617        (ir::AsmOperandKind::Const(_), _) => TokenStream::new(),
8618        (_, ir::AsmReg::Class(class)) => {
8619            let class = Ident::new(class, span);
8620            quote_spanned! {span=> (#class) }
8621        }
8622        (_, ir::AsmReg::Explicit(name)) => {
8623            let mut name = Literal::string(name);
8624            name.set_span(span);
8625            quote_spanned! {span=> (#name) }
8626        }
8627    };
8628    match &operand.name {
8629        Some(name) => {
8630            let name = Ident::new(name, span);
8631            quote_spanned! {span=> #name = #dir #reg }
8632        }
8633        None => quote_spanned! {span=> #dir #reg },
8634    }
8635}
8636
8637/// The value of an `asm!` `const` operand: an `i64` literal, or a `u64` one
8638/// for a value only that holds, so that no inference default narrows it.
8639fn asm_const_literal(value: i128, span: Span) -> TokenStream {
8640    let mut literal = if i64::try_from(value).is_ok() {
8641        Literal::i64_suffixed(value as i64)
8642    } else {
8643        Literal::u64_suffixed(value as u64)
8644    };
8645    literal.set_span(span);
8646    TokenStream::from(TokenTree::Literal(literal))
8647}
8648
8649fn suffixed_int_literal(value: i128, ty: &str, span: Span) -> TokenStream {
8650    let mut literal = match ty {
8651        // An unsigned `const` parameter takes the bit pattern the C constant
8652        // was reduced to, which is what a mask written as `-1` means.
8653        "u32" => Literal::u32_suffixed(value as u32),
8654        "u64" => Literal::u64_suffixed(value as u64),
8655        "i64" => Literal::i64_suffixed(value as i64),
8656        // `i32` is what every immediate operand in `core::arch` is.
8657        _ => Literal::i32_suffixed(value as i32),
8658    };
8659    literal.set_span(span);
8660    TokenStream::from(TokenTree::Literal(literal))
8661}
8662
8663/// The Rust floating type of a C floating type, and the mask that clears the
8664/// sign bit of its bit pattern.
8665///
8666/// `long double` is `double` here, so only the two widths exist.
8667fn float_bit_ty(ty: Ty, span: Span) -> (TokenStream, TokenStream) {
8668    if ty == Ty::Float {
8669        return (
8670            primitive_ty("f32", span),
8671            unsigned_hex_literal(0x7fff_ffff, "u32", span),
8672        );
8673    }
8674    (
8675        primitive_ty("f64", span),
8676        unsigned_hex_literal(0x7fff_ffff_ffff_ffff, "u64", span),
8677    )
8678}
8679
8680/// The quiet bit of a floating type: the leading bit of the mantissa, which is
8681/// set in a quiet NaN and clear in a signalling one.
8682fn quiet_bit_literal(ty: Ty, span: Span) -> TokenStream {
8683    if ty == Ty::Float {
8684        return unsigned_hex_literal(1 << 22, "u32", span);
8685    }
8686    unsigned_hex_literal(1 << 51, "u64", span)
8687}
8688
8689/// A hexadecimal literal with an explicit unsigned suffix.
8690fn unsigned_hex_literal(value: u64, suffix: &str, span: Span) -> TokenStream {
8691    let mut literal = Literal::from_str(&format!("0x{value:x}{suffix}"))
8692        .expect("a hexadecimal literal followed by a suffix is a token");
8693    literal.set_span(span);
8694    TokenStream::from(TokenTree::Literal(literal))
8695}
8696
8697fn float_literal_token(value: f64, span: Span) -> TokenStream {
8698    let mut literal = Literal::f64_unsuffixed(value.abs());
8699    literal.set_span(span);
8700    if value.is_sign_negative() {
8701        quote_spanned! {span=> -#literal }
8702    } else {
8703        TokenStream::from(TokenTree::Literal(literal))
8704    }
8705}
8706
8707fn bare_float_literal(value: f64, span: Span) -> TokenStream {
8708    float_literal_token(value, span)
8709}
8710
8711/// The constant an expression is, if it is one.
8712///
8713/// Sema folds conversions of constants, so a constant is always a bare `Int`
8714/// or `Float` node rather than a cast wrapping one.
8715/// The operands of a chain of comma operators, in source order.
8716///
8717/// `a, b, c` is `Comma(Comma(a, b), c)`, so this walks down the left spine
8718/// into a vector and hands it back the right way round. Iterating rather than
8719/// recursing is what lets a logical source line hold the 4095 characters C23
8720/// 5.2.5.2p1 asks for; see [`Codegen::binary_chain`].
8721fn comma_operands(expr: &Expr) -> Vec<&Expr> {
8722    let mut out = Vec::new();
8723    let mut node = expr;
8724    while let ExprKind::Comma { lhs, rhs } = &node.kind {
8725        out.push(&**rhs);
8726        node = lhs;
8727    }
8728    out.push(node);
8729    out.reverse();
8730    out
8731}
8732
8733fn constant_of(expr: &Expr) -> Option<ConstValue> {
8734    match &expr.kind {
8735        ExprKind::Int(value) => Some(ConstValue::Int(*value)),
8736        ExprKind::Float(value) if value.is_finite() => Some(ConstValue::Float(*value)),
8737        _ => None,
8738    }
8739}
8740
8741fn cmp_tokens(op: CmpOp, span: Span) -> TokenStream {
8742    match op {
8743        CmpOp::Lt => quote_spanned! {span=> < },
8744        CmpOp::Gt => quote_spanned! {span=> > },
8745        CmpOp::Le => quote_spanned! {span=> <= },
8746        CmpOp::Ge => quote_spanned! {span=> >= },
8747        CmpOp::Eq => quote_spanned! {span=> == },
8748        CmpOp::Ne => quote_spanned! {span=> != },
8749    }
8750}
8751
8752#[cfg(test)]
8753mod tests {
8754    use super::*;
8755
8756    /// What a unit spelling `names` gives each of them, as `(C, Rust)` pairs
8757    /// of everything that does not keep its own name.
8758    fn spellings(names: &[&str]) -> Vec<(String, String)> {
8759        let mut pairs: Vec<(String, String)> = unique_spellings(names.iter().copied())
8760            .into_iter()
8761            .collect();
8762        pairs.sort();
8763        pairs
8764    }
8765
8766    /// Asserts that `names` are spelled as `expected` says, and that the unit
8767    /// has no two names with one spelling.
8768    fn assert_spellings(names: &[&str], expected: &[(&str, &str)]) {
8769        let renamed = unique_spellings(names.iter().copied());
8770        let want: Vec<(String, String)> = expected
8771            .iter()
8772            .map(|(c, rust)| ((*c).to_owned(), (*rust).to_owned()))
8773            .collect();
8774        assert_eq!(spellings(names), want);
8775        let mut seen: HashMap<String, &str> = HashMap::new();
8776        for name in names {
8777            let spelling = match renamed.get(*name) {
8778                Some(unique) => unique.clone(),
8779                None => plain_spelling(name),
8780            };
8781            if let Some(other) = seen.insert(spelling.clone(), name) {
8782                assert_eq!(
8783                    other, *name,
8784                    "{other} and {name} are both spelled {spelling}"
8785                );
8786            }
8787        }
8788    }
8789
8790    #[test]
8791    fn a_name_rust_can_spell_keeps_it() {
8792        // Nothing at all is renamed in the program that has no collision,
8793        // keywords included: `match` is `r#match`, which is a token of its
8794        // own.
8795        assert_spellings(&["counter", "match", "loop", "café"], &[]);
8796    }
8797
8798    #[test]
8799    fn the_five_names_that_cannot_be_raw_grow_an_underscore() {
8800        assert_spellings(
8801            &["self", "Self", "super", "crate", "_"],
8802            &[
8803                ("Self", "Self_"),
8804                ("_", "__"),
8805                ("crate", "crate_"),
8806                ("self", "self_"),
8807                ("super", "super_"),
8808            ],
8809        );
8810    }
8811
8812    #[test]
8813    fn a_dollar_is_spelled_out() {
8814        assert_spellings(
8815            &["a$b", "$", "x$"],
8816            &[
8817                ("$", "_dollar_"),
8818                ("a$b", "a_dollar_b"),
8819                ("x$", "x_dollar_"),
8820            ],
8821        );
8822    }
8823
8824    #[test]
8825    fn a_spelling_the_program_already_uses_grows_another_underscore() {
8826        // The collision the whole mechanism exists for: `self` cannot be
8827        // `self_`, because the program has a `self_` of its own.
8828        assert_spellings(&["self", "self_"], &[("self", "self__")]);
8829        assert_spellings(&["self", "self_", "self__"], &[("self", "self___")]);
8830        assert_spellings(&["a$b", "a_dollar_b"], &[("a$b", "a_dollar_b_")]);
8831    }
8832
8833    #[test]
8834    fn the_answer_does_not_depend_on_the_order_the_names_arrive_in() {
8835        let forwards = spellings(&["self", "self_", "crate", "crate_", "a$b", "a_dollar_b"]);
8836        let backwards = spellings(&["a_dollar_b", "a$b", "crate_", "crate", "self_", "self"]);
8837        assert_eq!(forwards, backwards);
8838    }
8839
8840    #[test]
8841    fn a_name_is_spelled_the_same_way_however_often_it_is_collected() {
8842        // Every name space is collected into one list, so a tag, a member and
8843        // a local all spelled `self` arrive several times over.
8844        assert_spellings(&["self", "self", "self_", "self"], &[("self", "self__")]);
8845    }
8846}