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;
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};
188
189/// Generates the Rust items for a fully checked program.
190pub fn generate(program: &Program, map: &SourceMap, options: &Options) -> TokenStream {
191    let mut cg = Codegen::new(program, map, options);
192    let mut out = cg.type_items();
193    out.extend(cg.extern_block());
194    for var in &program.statics {
195        out.extend(cg.static_item(var));
196    }
197    let mut initialisers = TokenStream::new();
198    for func in &program.functions {
199        if func.body.is_some() && !cg.beyond_toolchain(func) {
200            out.extend(cg.function_item(func));
201            if let Some(kind) = func.init_kind {
202                initialisers.extend(cg.init_array_item(func, kind));
203            }
204        }
205    }
206    if !initialisers.is_empty() {
207        out.extend(cg.init_array_guard());
208        out.extend(initialisers);
209    }
210    if out.is_empty() {
211        // A unit that declares nothing expands to nothing at all — not even a
212        // module — and there is no code for the data model to be wrong about.
213        return out;
214    }
215    let mut items = cg.data_model_check();
216    if cg.uses_cleanup.get() {
217        items.extend(cg.cleanup_guard_item(Span::call_site()));
218    }
219    items.extend(out);
220    items
221}
222
223/// Generates signature-only items for a program that did not type check.
224///
225/// The bodies are `::core::unreachable!()`: the expansion also carries
226/// `compile_error!`s, so nothing here can ever run. Their purpose is to keep a
227/// Rust call site that mentions one of these functions from producing a second,
228/// unrelated "cannot find function" error on top of the real one.
229pub fn generate_stubs(program: &Program, map: &SourceMap, options: &Options) -> TokenStream {
230    let mut cg = Codegen::new(program, map, options);
231    let mut out = cg.type_items();
232    out.extend(cg.extern_block());
233    for var in &program.statics {
234        out.extend(cg.static_item(var));
235    }
236    for func in &program.functions {
237        if !func.is_extern() && !cg.beyond_toolchain(func) {
238            out.extend(cg.stub_item(func));
239        }
240    }
241    out
242}
243
244// ---------------------------------------------------------------------------
245// precedence
246// ---------------------------------------------------------------------------
247
248/// Rust's expression precedence levels, tightest last.
249///
250/// Emitted expressions carry the level they parse at so that parentheses are
251/// added exactly where they are needed and nowhere else — the generated code is
252/// meant to be read.
253mod prec {
254    /// A block-like expression (`if`, `{ … }`): usable on its own, but needing
255    /// parentheses anywhere an operator or a statement boundary follows.
256    pub const BLOCK: u8 = 0;
257    /// The weakest level an operand can be handed to without parentheses.
258    pub const LOWEST: u8 = 0;
259    pub const OR: u8 = 2;
260    pub const AND: u8 = 3;
261    pub const CMP: u8 = 4;
262    pub const BIT_OR: u8 = 5;
263    pub const BIT_XOR: u8 = 6;
264    pub const BIT_AND: u8 = 7;
265    pub const SUM: u8 = 9;
266    pub const PRODUCT: u8 = 10;
267    pub const CAST: u8 = 11;
268    pub const UNARY: u8 = 12;
269    pub const CALL: u8 = 13;
270    pub const ATOM: u8 = 14;
271}
272
273/// An emitted expression together with the precedence it parses at.
274struct Value {
275    tokens: TokenStream,
276    prec: u8,
277    /// Set when the tokens are a bare non-negative integer literal, whose Rust
278    /// type is therefore still open to inference.
279    bare_integer: bool,
280    /// Set when the tokens end with the type of an `as`.
281    ///
282    /// `x as i32 < y` does not parse: Rust reads the `<` as the start of the
283    /// generic arguments of `i32`. (`>`, `<=`, `>=` and `==` are unambiguous
284    /// and need no help.)
285    ends_with_type: bool,
286}
287
288impl Value {
289    fn new(tokens: TokenStream, prec: u8) -> Self {
290        Self {
291            tokens,
292            prec,
293            bare_integer: false,
294            ends_with_type: false,
295        }
296    }
297
298    fn atom(tokens: TokenStream) -> Self {
299        Self::new(tokens, prec::ATOM)
300    }
301
302    /// Marks the tokens as ending with the type of an `as`.
303    fn type_end(mut self, flag: bool) -> Self {
304        self.ends_with_type = flag;
305        self
306    }
307
308    /// The tokens, parenthesised if they would not survive being used as an
309    /// operand at `min`.
310    fn at(self, min: u8, span: Span) -> TokenStream {
311        if self.prec >= min {
312            return self.tokens;
313        }
314        parenthesize(self.tokens, span)
315    }
316
317    /// The tokens, parenthesised only if they are block-like.
318    ///
319    /// Used where Rust starts parsing an expression that is followed by a block
320    /// — the condition of an `if` or a `while` — and would otherwise mistake
321    /// our expression's own braces for that block.
322    fn at_condition(self, span: Span) -> TokenStream {
323        if self.prec > prec::BLOCK {
324            return self.tokens;
325        }
326        parenthesize(self.tokens, span)
327    }
328}
329
330fn parenthesize(tokens: TokenStream, span: Span) -> TokenStream {
331    let mut group = Group::new(Delimiter::Parenthesis, tokens);
332    group.set_span(span);
333    TokenStream::from(TokenTree::Group(group))
334}
335
336/// Whether an emitted expression opens with a unary minus.
337///
338/// `as` is the one operator in front of which that matters: `rustc` reads
339/// `-1 as u32` as the negation of a `u32` rather than as a cast of `-1`, and
340/// refuses it with `E0600`.
341fn starts_with_minus(tokens: &TokenStream) -> bool {
342    matches!(
343        tokens.clone().into_iter().next(),
344        Some(TokenTree::Punct(punct)) if punct.as_char() == '-'
345    )
346}
347
348fn braced(tokens: TokenStream, span: Span) -> TokenStream {
349    let mut group = Group::new(Delimiter::Brace, tokens);
350    group.set_span(span);
351    TokenStream::from(TokenTree::Group(group))
352}
353
354fn bracketed(tokens: TokenStream, span: Span) -> TokenStream {
355    let mut group = Group::new(Delimiter::Bracket, tokens);
356    group.set_span(span);
357    TokenStream::from(TokenTree::Group(group))
358}
359
360// ---------------------------------------------------------------------------
361// the Microsoft library's inline printf family, and the names it exports under
362// a different spelling
363// ---------------------------------------------------------------------------
364
365/// The library that has out-of-line definitions of the `printf` and `scanf`
366/// families for the Microsoft C runtime.
367///
368/// It is part of the MSVC toolset —
369/// `VC/Tools/MSVC/<version>/lib/<arch>/legacy_stdio_definitions.lib`, one copy
370/// per architecture — so it is there on every `*-windows-msvc` target and on no
371/// other, which is why [`TargetModel::is_msvc`](crate::TargetModel::is_msvc) and
372/// not merely Windows is what asks for it.
373const LEGACY_STDIO_DEFINITIONS: &str = "legacy_stdio_definitions";
374
375/// The names that need [`LEGACY_STDIO_DEFINITIONS`] on an MSVC target, each with
376/// the library that defines it.
377///
378/// In the Universal CRT — the Microsoft C library from Visual Studio 2015 on —
379/// the `printf` and `scanf` families are **inline functions in `<stdio.h>` and
380/// `<wchar.h>`**, written over `__stdio_common_vfprintf` and its relatives, so
381/// the import library exports no `printf` at all: an `extern "C" { fn printf(…);
382/// }` is `LNK2019: unresolved external symbol printf` at link time. Microsoft
383/// ships `legacy_stdio_definitions.lib` with out-of-line definitions for exactly
384/// that case, and it is what Rust's own `libc` crate links for the same
385/// declarations (`#[cfg_attr(all(windows, target_env = "msvc"), link(name =
386/// "legacy_stdio_definitions"))]`). See "The printf and scanf family of
387/// functions are now defined inline" in Microsoft's change history:
388/// <https://learn.microsoft.com/en-us/cpp/porting/visual-cpp-change-history-2003-2015>
389///
390/// The rule this table serves is [`Codegen::legacy_stdio_libraries`], and it is
391/// keyed on the **symbol a generated declaration links by** rather than on a
392/// header: a unit may declare `int printf(const char *, ...);` itself, or reach
393/// the function through `__builtin_printf`, and never include `<stdio.h>` at
394/// all.
395///
396/// One row per name, so that a name can be given a different answer on its own
397/// should a toolchain ever disagree: a row may name a different library, or go,
398/// and nothing else changes. What it must never become is an alias to
399/// `_snprintf`, whose truncation semantics are not C's.
400///
401/// Every name here was read out of a real copy of the library —
402/// `dumpbin`/`nm` over `legacy_stdio_definitions.lib` from MSVC 14.44.35207,
403/// x64 and x86 both — so the list is the library's own contents and not a
404/// guess. `snprintf` and `vsnprintf` are in it, which is worth saying because
405/// they are C99 additions the Microsoft library had no out-of-line form of
406/// *before* the UCRT and so, unlike the rest, never "became" inline; `libc`
407/// declares `snprintf` in the very block it links this library for. The library
408/// also holds the `_l`, `_p`, `_s` and `_snprintf` variants, which are
409/// deliberately not here: they are Microsoft's functions rather than C's, and a
410/// unit that declares one has named the platform already and can say
411/// `#pragma cinrs link "legacy_stdio_definitions"` itself.
412const LEGACY_STDIO: &[(&str, &str)] = &[
413    ("printf", LEGACY_STDIO_DEFINITIONS),
414    ("fprintf", LEGACY_STDIO_DEFINITIONS),
415    ("sprintf", LEGACY_STDIO_DEFINITIONS),
416    ("snprintf", LEGACY_STDIO_DEFINITIONS),
417    ("vprintf", LEGACY_STDIO_DEFINITIONS),
418    ("vfprintf", LEGACY_STDIO_DEFINITIONS),
419    ("vsprintf", LEGACY_STDIO_DEFINITIONS),
420    ("vsnprintf", LEGACY_STDIO_DEFINITIONS),
421    ("scanf", LEGACY_STDIO_DEFINITIONS),
422    ("fscanf", LEGACY_STDIO_DEFINITIONS),
423    ("sscanf", LEGACY_STDIO_DEFINITIONS),
424    ("vscanf", LEGACY_STDIO_DEFINITIONS),
425    ("vfscanf", LEGACY_STDIO_DEFINITIONS),
426    ("vsscanf", LEGACY_STDIO_DEFINITIONS),
427    ("wprintf", LEGACY_STDIO_DEFINITIONS),
428    ("fwprintf", LEGACY_STDIO_DEFINITIONS),
429    ("swprintf", LEGACY_STDIO_DEFINITIONS),
430    ("vwprintf", LEGACY_STDIO_DEFINITIONS),
431    ("vfwprintf", LEGACY_STDIO_DEFINITIONS),
432    ("vswprintf", LEGACY_STDIO_DEFINITIONS),
433    ("wscanf", LEGACY_STDIO_DEFINITIONS),
434    ("fwscanf", LEGACY_STDIO_DEFINITIONS),
435    ("swscanf", LEGACY_STDIO_DEFINITIONS),
436    ("vwscanf", LEGACY_STDIO_DEFINITIONS),
437    ("vfwscanf", LEGACY_STDIO_DEFINITIONS),
438    ("vswscanf", LEGACY_STDIO_DEFINITIONS),
439];
440
441/// The C functions the Microsoft C runtime exports under **another name**, each
442/// with the symbol a declaration of it has to link by on an MSVC target.
443///
444/// `LEGACY_STDIO` above is about a family the UCRT defines inline and ships an
445/// out-of-line copy of in a library of its own. This is the other shape of the
446/// same problem: the function *is* in `ucrt.lib`, under a name that is not the
447/// one C gives it, and Microsoft's own headers paper over the difference with a
448/// macro (`#define time _time64`) that cinrs's bundled headers, which are the
449/// same on every platform, do not write.
450///
451/// Every row was read out of the real import libraries with `nm` — the Windows
452/// SDK's `ucrt.lib` and the MSVC toolset's `msvcrt.lib`, 10.0.26100.0 and
453/// 14.44.35207 — and not inferred. `ucrt.lib` exports each symbol on the right
454/// and none of the C names on the left.
455///
456/// The `<time.h>` rows are **not** merely a link error, which is what makes
457/// them worth a table rather than a paragraph in the documentation. The MSVC
458/// toolset's `msvcrt.lib` holds an "alias map" object per name that defines
459/// `time` as a *weak* external for `_time32`, and the rest likewise — so a
460/// declaration of `time` does link, silently, to the **32-bit** `time_t`
461/// function. cinrs's `<time.h>` makes `time_t` 64 bits on Windows, as the UCRT
462/// does, and the two disagree in ways a program sees: `_mktime32`'s `(time_t)-1`
463/// comes back as `0x0000_0000_FFFF_FFFF`, and `_gmtime32` answers `NULL` for
464/// every date after 2038 rather than a `struct tm`. Naming `_time64` and its
465/// siblings is therefore a correctness fix and not only a convenience.
466///
467/// `hypotf` is the one `<math.h>` name with an exported equivalent: `_hypotf`
468/// is a real export with C's signature (Microsoft's `<math.h>` makes `hypotf`
469/// inline over it). `fabsf`, `frexpf` and `ldexpf` have no symbol at all in any
470/// library on an MSVC link line — they are inline over the `double` forms — and
471/// so are not here; `doc/cross-compilation.md` records them, with the
472/// workaround. The same goes for `<wchar.h>`'s `wmemcpy`, `wmemmove`, `wmemset`,
473/// `wmemcmp`, `wmemchr`, `mbsinit` and `fwide`.
474///
475/// The rule this table serves is [`Codegen::msvc_symbol`], which applies to a
476/// **declaration** and after an `__asm__("…")` label: a program that has named
477/// the symbol it wants by hand has said the last word, which is also how a unit
478/// asks for `_time32` on purpose.
479const MSVC_RENAMED: &[(&str, &str)] = &[
480    ("time", "_time64"),
481    ("difftime", "_difftime64"),
482    ("mktime", "_mktime64"),
483    ("localtime", "_localtime64"),
484    ("gmtime", "_gmtime64"),
485    ("ctime", "_ctime64"),
486    ("timespec_get", "_timespec64_get"),
487    ("hypotf", "_hypotf"),
488];
489
490// ---------------------------------------------------------------------------
491// identifiers
492// ---------------------------------------------------------------------------
493
494/// Every Rust keyword, strict and reserved, in every edition up to 2024.
495const RUST_KEYWORDS: &[&str] = &[
496    "abstract", "as", "async", "await", "become", "box", "break", "const", "continue", "crate",
497    "do", "dyn", "else", "enum", "extern", "false", "final", "fn", "for", "gen", "if", "impl",
498    "in", "let", "loop", "macro", "match", "mod", "move", "mut", "override", "priv", "pub", "ref",
499    "return", "self", "static", "struct", "super", "trait", "true", "try", "type", "typeof",
500    "unsafe", "unsized", "use", "virtual", "where", "while", "yield", "Self",
501];
502
503/// Names that a `let` binding or a parameter must not carry, whatever the C
504/// program calls them.
505///
506/// Rust resolves a binding pattern against the value namespace first: a name
507/// that already means a unit variant there is a *pattern* that matches, not a
508/// new binding, and Rust refuses the ambiguity outright with `E0530`. The four
509/// below are in scope in every Rust file through the prelude; the rest of the
510/// set is computed per translation unit in [`Codegen::new`], because a C
511/// program may name a local exactly like one of its own globals or
512/// enumerators:
513///
514/// ```c
515/// int counter;
516/// int f(int counter) { return counter; }   /* two different objects */
517/// ```
518const PRELUDE_PATTERNS: &[&str] = &["Some", "None", "Ok", "Err"];
519
520/// Whether `segment` is an ordinary Rust identifier — one that can stand as a
521/// path segment spelled verbatim rather than as `r#…`.
522///
523/// Its one caller is [`is_crate_path`], whose value is pasted into the
524/// expansion as tokens; the three keywords a segment may nevertheless be are
525/// allowed there rather than here.
526fn is_path_segment(segment: &str) -> bool {
527    let mut chars = segment.chars();
528    chars
529        .next()
530        .is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
531        && chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
532        && !RUST_KEYWORDS.contains(&segment)
533        && !NEVER_RAW.contains(&segment)
534}
535
536/// Whether a string is usable as the Rust path of a crate:
537/// `#pragma cinrs crate "…"`.
538///
539/// A sequence of segments joined by `::`, optionally starting with one, where
540/// each segment is an identifier — with `crate`, `self` and `super` allowed as
541/// segments because a re-export is often reached through one. Deliberately
542/// strict: the value is pasted into the expansion as tokens, and anything else
543/// there would be a syntax error in generated code rather than a message about
544/// the pragma.
545pub fn is_crate_path(path: &str) -> bool {
546    /// The three keywords a path segment may be even though an ordinary
547    /// identifier may not.
548    const PATH_KEYWORDS: &[&str] = &["crate", "self", "super"];
549
550    let body = path.strip_prefix("::").unwrap_or(path);
551    if body.is_empty() {
552        return false;
553    }
554    body.split("::")
555        .all(|segment| PATH_KEYWORDS.contains(&segment) || is_path_segment(segment))
556}
557
558/// Turns a C identifier into the Rust identifier that stands for it, before
559/// the rest of the translation unit is taken into account.
560///
561/// C names are kept as they are, because that is what makes the expansion
562/// readable and what lets Rust call the functions by the names their author
563/// gave them. A name that collides with a Rust keyword becomes a raw
564/// identifier (`match` → `r#match`); the five names that cannot even be raw
565/// get an underscore appended instead. A `$` — which C takes as an identifier
566/// character and Rust has no spelling for — is written [`DOLLAR`].
567///
568/// The last two rules are the only ones that can hand two different C names
569/// the same Rust one, which is what [`Names`] exists to prevent: everything
570/// the generator emits goes through [`Names::ident`] rather than through this.
571fn c_ident(name: &str, span: Span) -> Ident {
572    let spelled = rust_spelling(name);
573    let name = spelled.as_ref();
574    if NEVER_RAW.contains(&name) {
575        return Ident::new(&format!("{name}_"), span);
576    }
577    if RUST_KEYWORDS.contains(&name) {
578        return Ident::new_raw(name, span);
579    }
580    Ident::new(name, span)
581}
582
583/// What a `$` in a C identifier is written as in the generated Rust.
584///
585/// `$` is an identifier character here — GCC takes it unconditionally and
586/// Clang by default, which is what WG14 DR027 allows and what
587/// [`crate::Options::dollar_in_identifiers`] switches on — and Rust has no
588/// spelling for it at all, not even a raw identifier. The C name is still what
589/// the symbol links by: an object or function that is not defined here carries
590/// it in `#[link_name]`, and one that is carries it in `#[unsafe(export_name)]`.
591pub const DOLLAR: &str = "_dollar_";
592
593/// A C identifier as Rust can spell it, which is the same string unless a `$`
594/// is in it.
595fn rust_spelling(name: &str) -> std::borrow::Cow<'_, str> {
596    if name.contains('$') {
597        std::borrow::Cow::Owned(name.replace('$', DOLLAR))
598    } else {
599        std::borrow::Cow::Borrowed(name)
600    }
601}
602
603/// Whether Rust spells `name` as something other than itself, so that another
604/// C name could be spelled the same way.
605///
606/// A keyword is not one of these: `r#match` is a token of its own and no name
607/// but `match` is written that way.
608fn respelled(name: &str) -> bool {
609    name.contains('$') || NEVER_RAW.contains(&name)
610}
611
612/// The text [`c_ident`] gives a name, without the `r#` a raw identifier is
613/// written with.
614fn plain_spelling(name: &str) -> String {
615    let spelled = rust_spelling(name);
616    if NEVER_RAW.contains(&spelled.as_ref()) {
617        return format!("{spelled}_");
618    }
619    spelled.into_owned()
620}
621
622/// The Rust spelling of every name the translation unit gives to something,
623/// made unique across the whole unit.
624///
625/// Two of the rules in [`c_ident`] change the spelling of a name, and a
626/// program is free to use the changed spelling itself:
627///
628/// ```c
629/// int f(void) { int self = 1; int self_ = 2; return self * 10 + self_; }
630/// ```
631///
632/// Both locals would be `self_`, the second binding would shadow the first,
633/// and `f` would quietly return 22 instead of 12. The same collision between
634/// two members is `E0124`, between two file-scope items `E0428`, and `a$b`
635/// next to `a_dollar_b` is the same story again.
636///
637/// So the spelling is settled once, here, for the unit as a whole. Every name
638/// the unit spells is collected — objects, functions and their parameters,
639/// tags, members, bit-field accessors, enumerators and `typedef` names, in
640/// every name space at once, because one C name must read as one Rust name
641/// wherever it appears. A name Rust spells as it is written keeps it; a name
642/// whose spelling changes takes the usual one and grows another `_` for as
643/// long as something else already has it. Nothing moves for a program that
644/// does not have the collision, which is very nearly every program.
645///
646/// Labels are left out: `'self_` is in a name space of its own, and
647/// [`Codegen::name_regions`] already keeps the labels of a function apart.
648struct Names {
649    /// The Rust spelling of each name whose spelling is not the name itself.
650    ///
651    /// Empty for a unit that writes no such name, which is the usual case.
652    renamed: HashMap<String, String>,
653}
654
655impl Names {
656    /// Works out the spellings of one translation unit.
657    fn new(program: &Program) -> Self {
658        let mut spelled: Vec<&str> = Vec::new();
659        for object in &program.objects {
660            spelled.push(&object.name);
661            match &object.storage {
662                Storage::Static { item_name, .. }
663                | Storage::ThreadLocal { item_name, .. }
664                | Storage::Extern { item_name } => spelled.push(item_name),
665                Storage::Automatic => {}
666            }
667        }
668        for func in &program.functions {
669            spelled.push(&func.name);
670            spelled.push(func.item_name());
671            spelled.extend(func.param_names.iter().flatten().map(String::as_str));
672            // The names the state-machine lowering hoists the locals under,
673            // which are what a CFG body's bindings are generated from.
674            if let Some(Body::Cfg(cfg)) = &func.body {
675                spelled.extend(cfg.locals.iter().map(|local| local.rust_name.as_str()));
676            }
677        }
678        for record in program.types.records() {
679            spelled.extend(record.tag.as_deref());
680            spelled.push(&record.rust_name);
681            for field in &record.fields {
682                spelled.push(&field.name);
683                if let Some(bits) = &field.bits {
684                    spelled.push(&bits.getter);
685                    spelled.push(&bits.setter);
686                }
687            }
688            for field in &record.rust_fields {
689                match field {
690                    ir::RustField::Bits { name, .. }
691                    | ir::RustField::Pad { name, .. }
692                    | ir::RustField::Align { name, .. } => spelled.push(name),
693                    ir::RustField::Member(_) => {}
694                }
695            }
696        }
697        for def in program.types.enums() {
698            spelled.extend(def.tag.as_deref());
699            spelled.push(&def.rust_name);
700        }
701        for constant in &program.enum_constants {
702            spelled.push(&constant.name);
703            spelled.push(&constant.rust_name);
704        }
705        for typedef in &program.typedefs {
706            spelled.push(&typedef.rust_name);
707        }
708
709        Self {
710            renamed: unique_spellings(spelled),
711        }
712    }
713
714    /// The Rust identifier a C name is generated as, everywhere it appears.
715    fn ident(&self, name: &str, span: Span) -> Ident {
716        match self.renamed.get(name) {
717            Some(unique) => Ident::new(unique, span),
718            None => c_ident(name, span),
719        }
720    }
721
722    /// The same as text, without the `r#` a raw identifier is written with.
723    fn spelling<'n>(&'n self, name: &'n str) -> std::borrow::Cow<'n, str> {
724        match self.renamed.get(name) {
725            Some(unique) => std::borrow::Cow::Borrowed(unique.as_str()),
726            None => std::borrow::Cow::Owned(plain_spelling(name)),
727        }
728    }
729}
730
731/// The rule [`Names`] is built on: what each name whose Rust spelling is not
732/// itself is spelled as, given everything the unit spells.
733///
734/// A name Rust writes as it stands claims that spelling first — two such
735/// names are distinct exactly when the C names are — and what is left grows
736/// another `_` for as long as something already has its spelling. The names
737/// that need one are settled in sorted order, so that the answer never
738/// depends on the order the arenas happen to be in.
739fn unique_spellings<'n>(spelled: impl IntoIterator<Item = &'n str>) -> HashMap<String, String> {
740    let mut taken: HashSet<&str> = HashSet::new();
741    let mut changing: BTreeSet<&str> = BTreeSet::new();
742    for name in spelled {
743        if respelled(name) {
744            changing.insert(name);
745        } else {
746            taken.insert(name);
747        }
748    }
749    let mut renamed: HashMap<String, String> = HashMap::new();
750    let mut assigned: HashSet<String> = HashSet::new();
751    for name in changing {
752        let mut candidate = plain_spelling(name);
753        while taken.contains(candidate.as_str()) || assigned.contains(&candidate) {
754            candidate.push('_');
755        }
756        assigned.insert(candidate.clone());
757        renamed.insert(name.to_owned(), candidate);
758    }
759    renamed
760}
761
762/// Whether `name` can stand as the label of a Rust block or loop.
763///
764/// A label is not a raw identifier, so a Rust keyword — `loop:` is a perfectly
765/// ordinary C label — cannot be one, nor can the five names that cannot even
766/// be raw. The labels this module builds itself are kept clear too, so that a
767/// `break` in a region never names a loop instead. A C label that is one of
768/// them keeps its own name with the label's number appended.
769fn is_label_name(name: &str) -> bool {
770    let mut chars = name.chars();
771    let starts = chars
772        .next()
773        .is_some_and(|c| c.is_ascii_alphabetic() || c == '_');
774    starts
775        && chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
776        && !RUST_KEYWORDS.contains(&name)
777        && !NEVER_RAW.contains(&name)
778        && !is_generated_label(name)
779}
780
781/// The labels this module gives its own loops, `switch`es and state machine:
782/// `'cfg`, `'lN`, `'lN_body`, `'swN` and `'swN_cM`.
783fn is_generated_label(name: &str) -> bool {
784    fn digits(text: &str) -> bool {
785        !text.is_empty() && text.bytes().all(|b| b.is_ascii_digit())
786    }
787
788    if name == "cfg" {
789        return true;
790    }
791    if let Some(rest) = name.strip_prefix('l')
792        && digits(rest.strip_suffix("_body").unwrap_or(rest))
793    {
794        return true;
795    }
796    if let Some(rest) = name.strip_prefix("sw") {
797        if digits(rest) {
798            return true;
799        }
800        if let Some((switch, case)) = rest.split_once("_c") {
801            return digits(switch) && digits(case);
802        }
803    }
804    false
805}
806
807/// Every [region](ir::Region) of a body, outermost first, with the C label it
808/// is named after.
809fn collect_regions(stmts: &[Stmt], out: &mut Vec<(ir::LabelId, String)>) {
810    for stmt in stmts {
811        match stmt {
812            Stmt::Region(region) => {
813                out.push((region.label, region.name.clone()));
814                collect_regions(&region.body, out);
815            }
816            Stmt::Block(items) => collect_regions(items, out),
817            Stmt::Label { body, .. } | Stmt::Case { body, .. } => {
818                collect_regions(std::slice::from_ref(body), out);
819            }
820            Stmt::If {
821                then_branch,
822                else_branch,
823                ..
824            } => {
825                collect_regions(std::slice::from_ref(then_branch), out);
826                if let Some(branch) = else_branch {
827                    collect_regions(std::slice::from_ref(branch), out);
828                }
829            }
830            Stmt::While { body, .. } | Stmt::DoWhile { body, .. } => {
831                collect_regions(std::slice::from_ref(body), out);
832            }
833            Stmt::For { init, body, .. } => {
834                collect_regions(init, out);
835                collect_regions(std::slice::from_ref(body), out);
836            }
837            Stmt::Switch(switch) => {
838                collect_regions(&switch.prelude, out);
839                for group in &switch.groups {
840                    collect_regions(&group.body, out);
841                }
842            }
843            Stmt::SwitchTree(switch) => collect_regions(std::slice::from_ref(&switch.body), out),
844            _ => {}
845        }
846    }
847}
848
849/// The lint exemptions every generated item carries.
850///
851/// A transliteration of C is unidiomatic Rust by construction: names are not
852/// snake case, locals are `mut` whether or not they are assigned again, a
853/// `switch` leaves labels that nothing jumps to, and a function that ends in an
854/// infinite loop leaves code behind that cannot run. `unknown_lints` comes
855/// first so that the list may name a lint an older compiler has never heard of.
856///
857/// Two of them are about the `extern` block. A C program declares the library
858/// its own way — `int strlen();` with no prototype is what a C89 program
859/// writes, and an implicit declaration is exactly that — so the declaration
860/// `cinrs` generates may disagree with the one Rust's own standard library
861/// uses for the same symbol (`clashing_extern_declarations`, and Rust 1.99's
862/// deny-by-default `invalid_runtime_symbol_definitions`). Nothing is
863/// *defined*: the symbol is the C library's either way, and a call through a
864/// type with no prototype is transmuted to the signature its arguments make
865/// before it is made, which is the contract C's own ABI runs on.
866///
867/// Two more are the deny-by-default `arithmetic_overflow` and
868/// `unconditional_panic`, which fire when `rustc` can see that an operation
869/// would trap: a division whose divisor it has const-propagated to zero, a
870/// shift past the width of the type, an overflowing constant. Each of those is
871/// *undefined behaviour* in C, so the C program is valid whatever it does and
872/// the operation is very often in a branch that cannot be taken —
873/// `execute/pr97888-1` is `if (h > -173) e = d / i;` with `i` a zero the
874/// program never reaches. Refusing to compile valid C is not an option;
875/// panicking at run time if it is ever reached is a perfectly good answer to
876/// undefined behaviour, and is what the same code already does when the
877/// divisor is only zero at run time.
878/// The label a [label address](ir::ExprKind::LabelAddr) names, through any
879/// conversions around it.
880fn label_state(expr: &Expr) -> Option<ir::LabelId> {
881    match &expr.kind {
882        ExprKind::LabelAddr(id) => Some(*id),
883        ExprKind::Cast(inner) => label_state(inner),
884        _ => None,
885    }
886}
887
888/// The name of the wrapper type an object aligned to `align` is generated
889/// inside; see [`Codegen::align_wrapper_items`].
890fn align_wrapper_ident(align: u64, span: Span) -> Ident {
891    Ident::new(&format!("__cinrs_align_{align}"), span)
892}
893
894/// The length of an array type, or `None` for anything else.
895fn array_len(types: &ir::Types, ty: Ty) -> Option<u64> {
896    match ty {
897        Ty::Array(id) => Some(types.array_type(id).len),
898        _ => None,
899    }
900}
901
902/// The name of a unit's `cleanup` drop guard type, in this crate's own
903/// hygiene: nothing a C program can write reaches it.
904fn cleanup_guard_ty() -> Ident {
905    Ident::new("__cinrs_cleanup", Span::mixed_site())
906}
907
908// ---------------------------------------------------------------------------
909// the generator
910// ---------------------------------------------------------------------------
911
912/// How `continue` leaves a particular loop.
913#[derive(Clone, Copy, PartialEq, Eq)]
914enum ContinueStyle {
915    /// The loop re-tests its condition on its own: `continue 'l`.
916    Head,
917    /// Work remains before the next iteration: `break 'l_body`.
918    BodyLabel,
919}
920
921/// A place, ready to be read from or written to.
922struct LoweredPlace {
923    /// Statements that must run before `access` is used.
924    setup: TokenStream,
925    /// A Rust place expression that may be evaluated more than once.
926    access: TokenStream,
927    /// Set when the place is a bit-field, in which case `access` is the record
928    /// holding it and the bits are reached through the generated accessors.
929    bits: Option<BitAccess>,
930    /// Set when the object may not be aligned the way its type asks.
931    ///
932    /// C reaches such an object through a packed member or a pointer cast, and
933    /// says nothing about the load; Rust makes `*p` on an underaligned `p`
934    /// undefined behaviour, which a debug build turns into an abort. Such a
935    /// place is read and written through `read_unaligned` and
936    /// `write_unaligned` instead. See [`Codegen::place_align`].
937    unaligned: bool,
938    /// Set when the object is `_Atomic`: reading it is a sequentially
939    /// consistent load and writing it a sequentially consistent store, both
940    /// through `AtomicX::from_ptr` over its address (C11 6.5.2.4, 6.5.16).
941    ///
942    /// The [class](AtomicClass) says which atomic, and the [`Ty`] is the
943    /// object's own type with the `_Atomic` taken off — what the value the
944    /// load produces is converted to.
945    atomic: Option<(AtomicClass, Ty)>,
946}
947
948impl LoweredPlace {
949    /// An ordinary place, whose access is the value.
950    fn plain(setup: TokenStream, access: TokenStream) -> Self {
951        Self {
952            setup,
953            access,
954            bits: None,
955            unaligned: false,
956            atomic: None,
957        }
958    }
959}
960
961/// What a read-modify-write of an `_Atomic` place does to it.
962enum PlaceRmw<'a> {
963    /// `place op= value`, in the type `compute`.
964    Compound {
965        /// The operator.
966        op: BinOp,
967        /// The right operand, already converted for `compute`.
968        value: &'a Expr,
969        /// The type the operation is carried out in.
970        compute: Ty,
971    },
972    /// `++place` or `--place`.
973    Step {
974        /// Whether this decrements.
975        dec: bool,
976    },
977}
978
979/// Which value such a read-modify-write leaves behind.
980#[derive(Clone, Copy, PartialEq, Eq)]
981enum RmwValue {
982    /// None: it was written as a statement.
983    None,
984    /// The value from before the update, which is what `x++` is.
985    Old,
986    /// The value after it, which is what `++x` and `x += v` are.
987    New,
988}
989
990/// The atomic operation a compound assignment operator performs, where there
991/// is one.
992fn rmw_of_binop(op: BinOp) -> Option<ir::AtomicRmw> {
993    Some(match op {
994        BinOp::Add => ir::AtomicRmw::Add,
995        BinOp::Sub => ir::AtomicRmw::Sub,
996        BinOp::BitAnd => ir::AtomicRmw::And,
997        BinOp::BitOr => ir::AtomicRmw::Or,
998        BinOp::BitXor => ir::AtomicRmw::Xor,
999        _ => return None,
1000    })
1001}
1002
1003/// The accessors a bit-field place is read and written through.
1004struct BitAccess {
1005    getter: Ident,
1006    setter: Ident,
1007}
1008
1009/// The unsigned word a bit-field's bytes are gathered into, and what its
1010/// accessors need to know about it.
1011///
1012/// See [`Codegen::bit_field_window`]; the word is `u64` for every bit-field
1013/// standard C allows and `u128` for the wide ones GNU's `__int128` makes
1014/// possible.
1015struct BitWindow {
1016    /// The expression that reads the overlapping bytes into the word.
1017    read: TokenStream,
1018    /// The field's bit offset inside the word.
1019    shift: u32,
1020    /// The field's bits, in place, inside the word.
1021    mask: u128,
1022    /// The word's Rust type: `u64` or `::core::primitive::u128`.
1023    word: TokenStream,
1024    /// Its width in bits, which is what a mask and a sign extension are
1025    /// written against.
1026    word_bits: u32,
1027}
1028
1029/// Where the pristine argument list of the function being generated lives.
1030#[derive(Clone, Copy, PartialEq, Eq)]
1031enum VaSource {
1032    /// There is none: the function takes no variable arguments.
1033    None,
1034    /// The synthetic `...` parameter of a variadic definition.
1035    Ellipsis,
1036    /// The function's own `va_list` parameter.
1037    Param(ir::ObjectId),
1038    /// The function's own `va_list *` parameter, whose *pointee* is the list.
1039    PtrParam(ir::ObjectId),
1040}
1041
1042struct Codegen<'a> {
1043    program: &'a Program,
1044    map: &'a SourceMap,
1045    options: &'a Options,
1046    continue_styles: HashMap<LoopId, ContinueStyle>,
1047    /// The Rust names of the locals of the function being generated, wherever
1048    /// they differ from the C ones: in [CFG mode](crate::cfg), where every
1049    /// local of the function shares one scope, and for a local whose name
1050    /// would shadow a file-scope item (see [`PRELUDE_PATTERNS`]).
1051    local_names: HashMap<ir::ObjectId, String>,
1052    /// The hidden pointer the function being generated reaches each enclosing
1053    /// object through, when it is a [lifted nested function](ir::EnvParam).
1054    ///
1055    /// It is what a call from inside one passes on: an object this function
1056    /// does not own itself arrives as a pointer, and the callee wants the same
1057    /// pointer rather than the address of a local that is not there.
1058    env: HashMap<ir::ObjectId, ir::ObjectId>,
1059    /// The names a `let` binding or a parameter must not use.
1060    reserved: HashSet<String>,
1061    /// The Rust spelling of every C name the unit gives to something; see
1062    /// [`Names`].
1063    names: Names,
1064    va_source: VaSource,
1065    ret_ty: Ty,
1066    /// Whether the function being generated is a [state
1067    /// machine](crate::cfg), in which case every local is already bound at the
1068    /// top and a definition is an assignment.
1069    in_cfg: bool,
1070    temporaries: u32,
1071    /// Set the first time a `__int128` reaches the output, which is what
1072    /// decides whether the [data-model check](Codegen::data_model_check) has
1073    /// anything to say about `i128`'s alignment.
1074    ///
1075    /// A [`Cell`] because [`Codegen::ty`] takes `&self`; the check is built
1076    /// after every item, so it sees the final answer.
1077    uses_int128: Cell<bool>,
1078    /// Set the first time a complex type reaches the output, for the same
1079    /// reason and by the same route as [`Codegen::uses_int128`]: only a unit
1080    /// that has one asserts the layout of `Complex<f32>` and `Complex<f64>`.
1081    uses_complex: Cell<bool>,
1082    /// Whether anything in the unit needs the `cleanup` drop guard item.
1083    uses_cleanup: Cell<bool>,
1084    /// The state number of every label a `&&label` took the address of, over
1085    /// the whole unit.
1086    ///
1087    /// A [`ir::LabelId`] is unique across the translation unit, which is what
1088    /// makes one map enough: a block-scope `static void *table[] = { &&a };`
1089    /// becomes an item at module level and is generated before any function
1090    /// body, so the number cannot be looked up in the function being emitted.
1091    /// See [`Cfg::labels`].
1092    label_states: HashMap<ir::LabelId, u32>,
1093    /// The Rust label each [region](ir::Region) of the function being
1094    /// generated carries: the C label's name, unless Rust cannot spell it as a
1095    /// label or this module already gives that name to a loop.
1096    region_names: HashMap<ir::LabelId, String>,
1097    /// The regions the statement being generated stands inside, which is what
1098    /// tells a `goto` whether it leaves one or restarts it.
1099    region_kinds: HashMap<ir::LabelId, ir::RegionKind>,
1100}
1101
1102impl<'a> Codegen<'a> {
1103    fn new(program: &'a Program, map: &'a SourceMap, options: &'a Options) -> Self {
1104        let mut reserved: HashSet<String> =
1105            PRELUDE_PATTERNS.iter().map(|s| (*s).to_owned()).collect();
1106        // A `static mut` and a `const` are both in the value namespace, so a
1107        // binding of the same name is `E0530` rather than a shadow.
1108        for var in &program.statics {
1109            if let Some(item_name) = program.object(var.object).storage.item_name() {
1110                reserved.insert(item_name.to_owned());
1111            }
1112        }
1113        for constant in &program.enum_constants {
1114            reserved.insert(constant.rust_name.clone());
1115        }
1116        let mut label_states = HashMap::new();
1117        for func in &program.functions {
1118            if let Some(ir::Body::Cfg(cfg)) = &func.body {
1119                for (id, block) in &cfg.labels {
1120                    label_states.insert(*id, block.0);
1121                }
1122            }
1123        }
1124        Self {
1125            program,
1126            map,
1127            options,
1128            continue_styles: HashMap::new(),
1129            local_names: HashMap::new(),
1130            env: HashMap::new(),
1131            reserved,
1132            names: Names::new(program),
1133            va_source: VaSource::None,
1134            ret_ty: Ty::Void,
1135            in_cfg: false,
1136            temporaries: 0,
1137            uses_int128: Cell::new(false),
1138            uses_complex: Cell::new(false),
1139            uses_cleanup: Cell::new(false),
1140            label_states,
1141            region_names: HashMap::new(),
1142            region_kinds: HashMap::new(),
1143        }
1144    }
1145
1146    /// Whether a function's signature needs more than the compiling toolchain
1147    /// can do, in which case no item is generated for it at all.
1148    ///
1149    /// Sema has already reported it — see [`crate::C_VARIADIC_SUPPORTED`] — and
1150    /// emitting the item anyway would add `rustc`'s own `E0658` on top of a
1151    /// diagnostic that already says what to do.
1152    fn beyond_toolchain(&self, func: &Function) -> bool {
1153        if self.options.c_variadic {
1154            return false;
1155        }
1156        (func.sig.variadic && !func.is_extern())
1157            || self.uses_va_list(func.sig.ret)
1158            || func.sig.params.iter().any(|ty| self.uses_va_list(*ty))
1159    }
1160
1161    /// Whether `va_list` appears anywhere in a type.
1162    fn uses_va_list(&self, ty: Ty) -> bool {
1163        match ty {
1164            Ty::VaList => true,
1165            Ty::Pointer(id) => self.uses_va_list(self.program.types.pointer_type(id).pointee),
1166            Ty::Array(id) => self.uses_va_list(self.program.types.array_type(id).elem),
1167            Ty::Func(id) => {
1168                let func = self.program.types.func_type(id);
1169                self.uses_va_list(func.ret) || func.params.iter().any(|ty| self.uses_va_list(*ty))
1170            }
1171            _ => false,
1172        }
1173    }
1174
1175    fn sp(&self, range: SourceRange) -> Span {
1176        self.map.span(range)
1177    }
1178
1179    /// The Rust identifier a C name is generated as; see [`Names`].
1180    ///
1181    /// Every name the generator writes goes through here, so that one C name
1182    /// reads as one Rust name wherever it appears — as an item, as a member,
1183    /// as a designator, in `offsetof`, in a bit-field accessor.
1184    fn c_ident(&self, name: &str, span: Span) -> Ident {
1185        self.names.ident(name, span)
1186    }
1187
1188    /// The name of the companion type a record whose flexible array member
1189    /// holds `len` elements is generated under; see [`Codegen::flexible_items`].
1190    fn flexible_ident(&self, rust_name: &str, len: u64, span: Span) -> Ident {
1191        Ident::new(
1192            &format!("__cinrs_{}_{len}", self.names.spelling(rust_name)),
1193            span,
1194        )
1195    }
1196
1197    /// The name of the item an externally linked **object** is declared under;
1198    /// see [`Program::extern_object_name`] for why an object and not a
1199    /// function.
1200    ///
1201    /// The symbol itself is what `#[link_name]` says; this is only the Rust
1202    /// side of it, and it is built out of the spelling every other C name is
1203    /// given so that two symbols never end up under one item.
1204    fn extern_object_ident(&self, symbol: &str, span: Span) -> Ident {
1205        let spelling = self.names.spelling(symbol);
1206        Ident::new(&self.program.extern_object_name(&spelling), span)
1207    }
1208
1209    /// A name no C identifier can collide with.
1210    ///
1211    /// `Span::mixed_site()` gives the identifier this crate's own hygiene, so
1212    /// even a C variable spelled `__cinrs_tmp0` refers to something else.
1213    fn temporary(&mut self) -> Ident {
1214        let name = format!("__cinrs_tmp{}", self.temporaries);
1215        self.temporaries += 1;
1216        Ident::new(&name, Span::mixed_site())
1217    }
1218
1219    /// A temporary whose *position* is the C it came from, while it still
1220    /// resolves as though it had been written at the macro's definition site.
1221    ///
1222    /// `Span::mixed_site` carries both a hygiene context and a position, and
1223    /// the position it carries is the whole invocation. That is invisible until
1224    /// a diagnostic is about an expression built out of such a name — `p[i]`
1225    /// becomes a temporary holding `p.offset(i)` and the place
1226    /// `(*__cinrs_tmp0)`, whose span `rustc` widens to cover the name as well
1227    /// and therefore to the macro call as a whole. `resolved_at` keeps
1228    /// the hygiene and takes the position from the C instead, which is where
1229    /// the caret belongs: a dereference a *safe* function may not do is
1230    /// reported on the `p[i]` that asked for it.
1231    fn temporary_at(&mut self, span: Span) -> Ident {
1232        let name = format!("__cinrs_tmp{}", self.temporaries);
1233        self.temporaries += 1;
1234        Ident::new(&name, span.resolved_at(Span::mixed_site()))
1235    }
1236
1237    /// Builds a Rust label such as `'l0`.
1238    fn label(&self, name: &str, span: Span) -> TokenStream {
1239        let mut tick = Punct::new('\'', Spacing::Joint);
1240        tick.set_span(span);
1241        let mut out = TokenStream::new();
1242        out.extend([
1243            TokenTree::Punct(tick),
1244            TokenTree::Ident(Ident::new(name, span)),
1245        ]);
1246        out
1247    }
1248
1249    // -- types --------------------------------------------------------------
1250
1251    /// The Rust type a C type maps to, always fully qualified.
1252    fn ty(&self, ty: Ty, span: Span) -> TokenStream {
1253        let name = match ty {
1254            // Only reachable on the error path, where a `compile_error!` is
1255            // already going out; the unit type keeps the stub items parseable.
1256            Ty::Void | Ty::Error => return quote_spanned! {span=> () },
1257            // `typedef _Bool bool;` is what every C23 compatibility header
1258            // writes, so the name has to be the qualified one or the alias
1259            // this unit generates for it is `pub type bool = bool;`.
1260            Ty::Bool => return primitive_ty("bool", span),
1261            Ty::Char => "c_char",
1262            Ty::SChar => "c_schar",
1263            Ty::UChar => "c_uchar",
1264            Ty::Short => "c_short",
1265            Ty::UShort => "c_ushort",
1266            Ty::Int => "c_int",
1267            Ty::UInt => "c_uint",
1268            Ty::Long => "c_long",
1269            Ty::ULong => "c_ulong",
1270            Ty::LongLong => "c_longlong",
1271            Ty::ULongLong => "c_ulonglong",
1272            // `core::ffi` has no alias for these: `__int128` is not a C type
1273            // the standard knows, and Rust's own `i128` has had its ABI since
1274            // 1.77. The `core::primitive` path rather than the bare name,
1275            // because `typedef unsigned __int128 u128;` is how real C spells
1276            // it and `pub type u128 = u128;` is a cycle.
1277            Ty::Int128 => {
1278                self.uses_int128.set(true);
1279                return primitive_ty("i128", span);
1280            }
1281            Ty::UInt128 => {
1282                self.uses_int128.set(true);
1283                return primitive_ty("u128", span);
1284            }
1285            Ty::Float => "c_float",
1286            Ty::Double => "c_double",
1287            // `core::ffi` has nothing for these, and there is nothing it could
1288            // have: a complex value is a pair, and the pair the ecosystem
1289            // already agrees on is `num_complex::Complex`, which the runtime
1290            // re-exports. See [`Codegen::rt_path`].
1291            Ty::ComplexFloat | Ty::ComplexDouble => {
1292                self.uses_complex.set(true);
1293                let component =
1294                    primitive_ty(if ty == Ty::ComplexFloat { "f32" } else { "f64" }, span);
1295                let rt = self.rt_path(span);
1296                return quote_spanned! {span=> #rt::Complex<#component> };
1297            }
1298            // The lifetime is elided: `VaList` only ever appears as the type of
1299            // a parameter or of a local, where elision does the right thing.
1300            Ty::VaList => "VaList",
1301            Ty::Pointer(id) => {
1302                let pointer = self.program.types.pointer_type(id);
1303                if let Ty::Func(func) = pointer.pointee {
1304                    // C's function pointers can be null, and Rust's cannot;
1305                    // `Option` is how the two are reconciled, and it has the
1306                    // same representation.
1307                    let signature = self.fn_ty(func, span);
1308                    return quote_spanned! {span=> ::core::option::Option<#signature> };
1309                }
1310                let pointee = self.pointee_ty(pointer.pointee, span);
1311                return if pointer.konst {
1312                    quote_spanned! {span=> *const #pointee }
1313                } else {
1314                    quote_spanned! {span=> *mut #pointee }
1315                };
1316            }
1317            Ty::Array(id) => {
1318                // A variably modified array's object *is* a pointer to its
1319                // first element: the elements themselves live in one hidden
1320                // `Vec`, however many dimensions there are, and nothing in the
1321                // generated code ever names the array as a value. See
1322                // [`ir::VlaDef`].
1323                if self.program.types.is_vm(ty) {
1324                    let step = self.ty(self.program.types.vm_step_ty(ty), span);
1325                    return quote_spanned! {span=> *mut #step };
1326                }
1327                let array = self.program.types.array_type(id);
1328                let elem = self.ty(array.elem, span);
1329                let len = usize_literal(array.len, span);
1330                let inner = quote_spanned! {span=> #elem ; #len };
1331                return bracketed(inner, span);
1332            }
1333            Ty::Func(id) => return self.fn_ty(id, span),
1334            Ty::Record(id) => {
1335                let name = self.c_ident(&self.program.types.record(id).rust_name, span);
1336                return quote_spanned! {span=> #name };
1337            }
1338            Ty::Enum(id) => {
1339                let name = self.c_ident(&self.program.types.enum_def(id).rust_name, span);
1340                return quote_spanned! {span=> #name };
1341            }
1342            // An `_Atomic T` object *is* a `T` in the generated Rust: the
1343            // atomicity is in how it is reached — `AtomicX::from_ptr` over its
1344            // address — and not in what it holds. Where the two differ is
1345            // alignment, which the layout code takes from the atomic type and
1346            // the generated item carries as `#[repr(C, align(N))]`.
1347            Ty::Atomic(id) => {
1348                let inner = self.program.types.atomic_inner(id);
1349                return self.ty(inner, span);
1350            }
1351        };
1352        let ident = Ident::new(name, span);
1353        quote_spanned! {span=> ::core::ffi::#ident }
1354    }
1355
1356    /// The path of the runtime module the generated code calls: `::cinrs::rt`,
1357    /// or whatever `#pragma cinrs crate` said instead of `::cinrs`.
1358    ///
1359    /// It is the one thing an expansion names outside `core` (and outside the
1360    /// `alloc`/`std` a variable length array needs), and it is named in full
1361    /// because the expansion lives in a module of its own where nothing is in
1362    /// scope. See [`ir::DEFAULT_CRATE_PATH`].
1363    fn rt_path(&self, span: Span) -> TokenStream {
1364        let path = TokenStream::from_str(&self.program.crate_path)
1365            .unwrap_or_else(|_| TokenStream::from_str(ir::DEFAULT_CRATE_PATH).expect("valid"));
1366        let path = respan(path, span);
1367        quote_spanned! {span=> #path::rt }
1368    }
1369
1370    /// A function of `cinrs_rt::complex`, by name.
1371    fn rt_complex(&self, name: &str, span: Span) -> TokenStream {
1372        let rt = self.rt_path(span);
1373        let ident = Ident::new(name, span);
1374        quote_spanned! {span=> #rt::complex::#ident }
1375    }
1376
1377    /// The suffix the runtime spells a complex type's component width with.
1378    fn complex_suffix(ty: Ty) -> &'static str {
1379        if ty.complex_component() == Ty::Float {
1380            "f32"
1381        } else {
1382            "f64"
1383        }
1384    }
1385
1386    /// `unsafe extern "C" fn(…) -> R`, the type a function pointer wraps.
1387    ///
1388    /// A function type with no prototype has no parameters to write, so it
1389    /// comes out as `unsafe extern "C" fn() -> R`; what a call through one
1390    /// really passes is written at the call site instead. See
1391    /// [`Codegen::call`].
1392    fn fn_ty(&self, id: ir::FuncTyId, span: Span) -> TokenStream {
1393        let func = self.program.types.func_type(id).clone();
1394        self.fn_ptr_ty(&func.params, func.variadic, func.ret, span)
1395    }
1396
1397    // -- the heap the emulated automatic storage comes from -------------------
1398
1399    /// The crate the `Vec` behind a variable length array and `alloca` comes
1400    /// from.
1401    ///
1402    /// Everything else the expansion generates is `core`-only; these two need
1403    /// an allocator, which is `std` in an ordinary crate and `alloc` in one
1404    /// that said `#pragma cinrs no_std` (and therefore wrote
1405    /// `extern crate alloc;` itself, since a procedural macro cannot add one).
1406    fn alloc_crate(&self, span: Span) -> Ident {
1407        let name = if self.program.no_std { "alloc" } else { "std" };
1408        Ident::new(name, span)
1409    }
1410
1411    /// `::std::vec::Vec<T>`.
1412    fn vec_ty(&self, elem: TokenStream, span: Span) -> TokenStream {
1413        let krate = self.alloc_crate(span);
1414        quote_spanned! {span=> ::#krate::vec::Vec<#elem> }
1415    }
1416
1417    /// `::std::vec::Vec::new()`.
1418    fn vec_new(&self, span: Span) -> TokenStream {
1419        let krate = self.alloc_crate(span);
1420        quote_spanned! {span=> ::#krate::vec::Vec::new() }
1421    }
1422
1423    /// `::std::vec::from_elem(value, len)`, which is what `vec![value; len]`
1424    /// expands to; a procedural macro is better off naming the function.
1425    fn vec_of(&self, value: TokenStream, len: TokenStream, span: Span) -> TokenStream {
1426        let krate = self.alloc_crate(span);
1427        quote_spanned! {span=> ::#krate::vec::from_elem(#value, #len) }
1428    }
1429
1430    /// The Rust type a *pointee* maps to.
1431    ///
1432    /// `void *` is the one place where C's `void` is not Rust's `()`: it stands
1433    /// for "some object of unknown type", which is exactly what
1434    /// [`core::ffi::c_void`] is for. Its size is one byte, so the `void *`
1435    /// arithmetic GCC allows keeps working.
1436    fn pointee_ty(&self, ty: Ty, span: Span) -> TokenStream {
1437        if ty.is_void() {
1438            let ident = Ident::new("c_void", span);
1439            return quote_spanned! {span=> ::core::ffi::#ident };
1440        }
1441        // A pointer to a variably modified type points at what is left under
1442        // the variable dimensions — `double (*)[m]` is a `*mut c_double` —
1443        // and every offset through it is scaled by the bound at run time. See
1444        // [`Codegen::vm_scale`].
1445        if self.program.types.is_vm(ty) {
1446            return self.ty(self.program.types.vm_step_ty(ty), span);
1447        }
1448        self.ty(ty, span)
1449    }
1450
1451    // -- items --------------------------------------------------------------
1452
1453    /// The `struct`, `union`, `enum` and `typedef` items of the unit.
1454    fn type_items(&mut self) -> TokenStream {
1455        let mut out = self.align_wrapper_items();
1456        for record in self.program.types.records() {
1457            if !record.emit {
1458                continue;
1459            }
1460            out.extend(self.record_item(record));
1461        }
1462        out.extend(self.flexible_items());
1463        for def in self.program.types.enums() {
1464            if !def.emit {
1465                continue;
1466            }
1467            let span = self.sp(def.range);
1468            let name = self.c_ident(&def.rust_name, span);
1469            let int = self.ty(Ty::Int, span);
1470            // C says an enumerated type is compatible with an implementation
1471            // defined integer type; every ABI this targets picks `int`.
1472            out.extend(quote_spanned! {span=> pub type #name = #int; });
1473        }
1474        for constant in &self.program.enum_constants {
1475            let span = self.sp(constant.range);
1476            let name = self.c_ident(&constant.rust_name, span);
1477            let ty = self.ty(constant.ty, span);
1478            let value = bare_int_literal(constant.value, constant.ty, span);
1479            out.extend(quote_spanned! {span=> pub const #name: #ty = #value; });
1480        }
1481        for typedef in &self.program.typedefs {
1482            // No alias is generated for `va_list`, which is what the
1483            // `typedef` in <stdarg.h> writes. `core::ffi::VaList` carries the
1484            // lifetime of the frame it reads, so `pub type va_list = VaList;`
1485            // does not even parse — and nothing needs the alias, since every
1486            // generated signature names the type directly.
1487            if self.uses_va_list(typedef.ty) {
1488                continue;
1489            }
1490            let span = self.sp(typedef.range);
1491            let name = self.c_ident(&typedef.rust_name, span);
1492            let ty = self.ty(typedef.ty, span);
1493            out.extend(quote_spanned! {span=> pub type #name = #ty; });
1494        }
1495        out
1496    }
1497
1498    /// The `#[repr(C, align(N))]` wrappers the unit's over-aligned objects are
1499    /// generated inside, one per distinct alignment.
1500    ///
1501    /// Rust can over-align a *type* and nothing else, so an object an
1502    /// `_Alignas(64)` made stricter than its type becomes
1503    ///
1504    /// ```text
1505    /// #[repr(C, align(64))] #[derive(Copy, Clone)]
1506    /// pub struct __cinrs_align_64<T>(pub T);
1507    ///
1508    /// let mut buf: __cinrs_align_64<[c_char; 256]> = __cinrs_align_64(…);
1509    /// ```
1510    ///
1511    /// and every access to `buf` goes through `buf.0` — which is also how Rust
1512    /// code that reaches such an object reads it. The C type is unchanged:
1513    /// `sizeof buf` is the array's size, and only the binding knows about the
1514    /// wrapper. See [`ir::Object::align`].
1515    fn align_wrapper_items(&self) -> TokenStream {
1516        let mut wanted: Vec<(u64, SourceRange)> = self
1517            .program
1518            .objects
1519            .iter()
1520            .filter_map(|object| Some((object.align?, object.range)))
1521            .collect();
1522        wanted.sort_by_key(|(align, _)| *align);
1523        wanted.dedup_by_key(|(align, _)| *align);
1524        let mut out = TokenStream::new();
1525        for (align, range) in wanted {
1526            let span = self.sp(range);
1527            let name = align_wrapper_ident(align, span);
1528            let literal = Literal::u64_unsuffixed(align);
1529            out.extend(quote_spanned! {span=>
1530                #[repr(C, align(#literal))]
1531                #[derive(Copy, Clone)]
1532                pub struct #name<T>(pub T);
1533            });
1534        }
1535        out
1536    }
1537
1538    /// The companion types an object with a filled-in flexible array member
1539    /// needs, one per distinct (record, length).
1540    ///
1541    /// C99 forbids initialising such a member because the object would have to
1542    /// be larger than its type; GNU C allows it for an object with static
1543    /// storage duration, and this is where that extra room comes from:
1544    ///
1545    /// ```text
1546    /// #[repr(C)] pub struct __cinrs_W_3 { pub n: c_int, pub data: [c_int; 3] }
1547    /// pub static mut w: __cinrs_W_3 = __cinrs_W_3 { n: 3, data: [1, 2, 3] };
1548    /// ```
1549    ///
1550    /// The leading layout is the record's own — the same Rust fields, in the
1551    /// same order — so `(&raw mut w).cast::<W>()` is a pointer to a `W`, which
1552    /// is what every use of the object goes through. `sizeof w` is still
1553    /// `sizeof(struct W)`, as it is in GCC. See [`ir::Object::flexible_len`].
1554    fn flexible_items(&self) -> TokenStream {
1555        let mut wanted: Vec<(ir::RecordId, u64)> = self
1556            .program
1557            .objects
1558            .iter()
1559            .filter_map(|object| match (object.flexible_len, object.ty) {
1560                (Some(len), Ty::Record(record)) => Some((record, len)),
1561                _ => None,
1562            })
1563            .collect();
1564        wanted.sort_unstable_by_key(|(record, len)| (record.0, *len));
1565        wanted.dedup_by_key(|(record, len)| (record.0, *len));
1566        let mut out = TokenStream::new();
1567        for (record, len) in wanted {
1568            let def = self.program.types.record(record);
1569            let span = self.sp(def.range);
1570            let name = self.flexible_ident(&def.rust_name, len, span);
1571            out.extend(self.record_body(def, &name, Some(len)));
1572        }
1573        out
1574    }
1575
1576    fn record_item(&self, record: &ir::RecordDef) -> TokenStream {
1577        let span = self.sp(record.range);
1578        let name = self.c_ident(&record.rust_name, span);
1579        let item = self.record_body(record, &name, None);
1580        let accessors = self.bit_field_accessors(record, span);
1581        quote_spanned! {span=> #item #accessors }
1582    }
1583
1584    /// The `struct` (or `union`) item itself, under `name`.
1585    ///
1586    /// `tail` sizes the [flexible array member](ir::Field::flexible), which is
1587    /// what makes a [companion type](Codegen::flexible_items) differ from the
1588    /// record it stands for; `None` is the record as C declared it, whose
1589    /// member is the `[T; 0]` the type says it is.
1590    fn record_body(&self, record: &ir::RecordDef, name: &Ident, tail: Option<u64>) -> TokenStream {
1591        let span = self.sp(record.range);
1592        // `Copy` is what makes a C struct behave like one: assigning it,
1593        // passing it and returning it all copy the bytes.
1594        let derives = match (record.align, record.packed) {
1595            // `__attribute__((packed))` and `#pragma pack(N)` are exactly
1596            // Rust's own `packed(N)`: every field's alignment is capped at N,
1597            // and so is the record's.
1598            (_, Some(1)) => quote_spanned! {span=> #[repr(C, packed)] #[derive(Copy, Clone)] },
1599            (_, Some(pack)) => {
1600                let pack = usize_literal(pack, span);
1601                quote_spanned! {span=>
1602                    #[repr(C, packed(#pack))] #[derive(Copy, Clone)]
1603                }
1604            }
1605            // `_Alignas` or `aligned(N)` on a member, or a bit-field whose
1606            // type is stricter than any field the item really has, is honoured
1607            // by raising the *record's* alignment; sema has already placed the
1608            // members where that leaves them.
1609            (Some(align), None) => {
1610                let align = usize_literal(align, span);
1611                quote_spanned! {span=>
1612                    #[repr(C, align(#align))] #[derive(Copy, Clone)]
1613                }
1614            }
1615            (None, None) => quote_spanned! {span=> #[repr(C)] #[derive(Copy, Clone)] },
1616        };
1617        let byte = primitive_ty("u8", span);
1618        if !record.complete {
1619            // A tag that is never completed can still be pointed at. An empty
1620            // body is the closest Rust has to C's incomplete type.
1621            return quote_spanned! {span=>
1622                #derives pub struct #name { _incomplete: [#byte; 0] }
1623            };
1624        }
1625        let mut fields = TokenStream::new();
1626        for rust_field in &record.rust_fields {
1627            match rust_field {
1628                ir::RustField::Member(index) => {
1629                    let field = &record.fields[*index];
1630                    let fspan = self.sp(field.range);
1631                    let fname = self.c_ident(&field.name, fspan);
1632                    let fty = match (tail, field.flexible) {
1633                        (Some(len), true) => {
1634                            let elem = self
1635                                .program
1636                                .types
1637                                .elem(field.ty)
1638                                .expect("a flexible member is an array");
1639                            let elem = self.ty(elem, fspan);
1640                            let len = usize_literal(len, fspan);
1641                            bracketed(quote_spanned! {fspan=> #elem ; #len }, fspan)
1642                        }
1643                        _ => self.ty(field.ty, fspan),
1644                    };
1645                    // Members are `pub` so Rust code can build and read the
1646                    // value.
1647                    fields.extend(quote_spanned! {fspan=> pub #fname: #fty, });
1648                }
1649                ir::RustField::Bits { name, bytes, .. } | ir::RustField::Pad { name, bytes } => {
1650                    let fname = Ident::new(name, span);
1651                    let len = usize_literal(*bytes, span);
1652                    fields.extend(quote_spanned! {span=> pub #fname: [#byte; #len], });
1653                }
1654                ir::RustField::Align { name, align } => {
1655                    let fname = Ident::new(name, span);
1656                    let unit = unsigned_rust_ty((*align * 8) as u32, span);
1657                    fields.extend(quote_spanned! {span=> pub #fname: [#unit; 0], });
1658                }
1659            }
1660        }
1661        if record.rust_fields.is_empty() && record.kind == RecordKind::Union {
1662            // GCC gives an empty `union` a size of zero, and so does an empty
1663            // Rust `struct`; a Rust `union` has to have at least one field, so
1664            // this is the one place the two kinds are generated differently.
1665            fields.extend(quote_spanned! {span=> pub __cinrs_empty: [#byte; 0], });
1666        }
1667        let body = braced(fields, span);
1668        match record.kind {
1669            RecordKind::Struct => quote_spanned! {span=> #derives pub struct #name #body },
1670            RecordKind::Union => quote_spanned! {span=> #derives pub union #name #body },
1671        }
1672    }
1673
1674    /// The `impl` block holding one getter and one setter per named bit-field.
1675    ///
1676    /// The bits are not a field, so this is the only way to reach them — from
1677    /// the generated code and from Rust alike. Everything is written out
1678    /// inline: no helper type, no runtime, nothing to look up.
1679    fn bit_field_accessors(&self, record: &ir::RecordDef, span: Span) -> TokenStream {
1680        let mut methods = TokenStream::new();
1681        for field in &record.fields {
1682            let Some(bits) = &field.bits else {
1683                continue;
1684            };
1685            let fspan = self.sp(field.range);
1686            methods.extend(self.bit_field_getter(record, field, bits, fspan));
1687            methods.extend(self.bit_field_setter(record, field, bits, fspan));
1688        }
1689        if methods.is_empty() {
1690            return TokenStream::new();
1691        }
1692        let name = self.c_ident(&record.rust_name, span);
1693        quote_spanned! {span=> impl #name { #methods } }
1694    }
1695
1696    /// Reads the bytes a bit-field overlaps into one unsigned integer.
1697    ///
1698    /// The unit rule keeps a field inside one object of its own type, so eight
1699    /// bytes are enough for every type standard C allows a bit-field to have.
1700    /// GNU's `__int128` is the one that can ask for more — `unsigned __int128
1701    /// x : 70` overlaps nine or ten bytes — and the window widens to `u128`
1702    /// there. The word type and its width come back with the tokens, since the
1703    /// getter and the setter have to spell them too.
1704    fn bit_field_window(&self, bits: &ir::BitField, span: Span) -> BitWindow {
1705        let storage = Ident::new(&bits.storage, span);
1706        let start = bits.offset_in_storage();
1707        let first = start / 8;
1708        let shift = (start % 8) as u32;
1709        let count = (shift + bits.width).div_ceil(8);
1710        let word_bits: u32 = if shift + bits.width > 64 { 128 } else { 64 };
1711        let word = window_ty(word_bits, false, span);
1712        let mut read = TokenStream::new();
1713        for step in 0..count {
1714            let index = usize_literal(first + u64::from(step), span);
1715            let byte = if count == 1 {
1716                quote_spanned! {span=> self.#storage[#index] as #word }
1717            } else {
1718                quote_spanned! {span=> (self.#storage[#index] as #word) }
1719            };
1720            read.extend(if step == 0 {
1721                byte
1722            } else {
1723                let by = usize_literal(u64::from(step) * 8, span);
1724                quote_spanned! {span=> | (#byte << #by) }
1725            });
1726        }
1727        // The mask of the field's bits inside that window; the window was
1728        // chosen so that `shift + width` fits in it, which makes the shift fit
1729        // too.
1730        let mask = mask_of(shift + bits.width, word_bits) & !mask_of(shift, word_bits);
1731        BitWindow {
1732            read,
1733            shift,
1734            mask,
1735            word,
1736            word_bits,
1737        }
1738    }
1739
1740    fn bit_field_getter(
1741        &self,
1742        record: &ir::RecordDef,
1743        field: &ir::Field,
1744        bits: &ir::BitField,
1745        span: Span,
1746    ) -> TokenStream {
1747        let BitWindow {
1748            read,
1749            shift,
1750            word,
1751            word_bits,
1752            ..
1753        } = self.bit_field_window(bits, span);
1754        let ty = self.ty(field.ty, span);
1755        let name = self.c_ident(&bits.getter, span);
1756        let mask = word_literal(mask_of(bits.width, word_bits), word_bits, span);
1757        let shifted = if shift == 0 {
1758            quote_spanned! {span=> raw & #mask }
1759        } else {
1760            let by = usize_literal(u64::from(shift), span);
1761            quote_spanned! {span=> (raw >> #by) & #mask }
1762        };
1763        let value = if field.ty.is_bool() {
1764            quote_spanned! {span=> value != 0 }
1765        } else if !bits.signed || bits.width == word_bits {
1766            quote_spanned! {span=> value as #ty }
1767        } else {
1768            // Sign extension: shift the field's top bit up to the sign bit of
1769            // the window's signed counterpart and let the arithmetic shift
1770            // bring it back down.
1771            let signed = window_ty(word_bits, true, span);
1772            let by = usize_literal(u64::from(word_bits - bits.width), span);
1773            quote_spanned! {span=> (((value << #by) as #signed) >> #by) as #ty }
1774        };
1775        let body = self.accessor_body(
1776            record,
1777            quote_spanned! {span=>
1778                let raw: #word = #read;
1779                let value: #word = #shifted;
1780                #value
1781            },
1782            span,
1783        );
1784        quote_spanned! {span=>
1785            #[inline]
1786            pub fn #name(&self) -> #ty { #body }
1787        }
1788    }
1789
1790    fn bit_field_setter(
1791        &self,
1792        record: &ir::RecordDef,
1793        field: &ir::Field,
1794        bits: &ir::BitField,
1795        span: Span,
1796    ) -> TokenStream {
1797        let BitWindow {
1798            read,
1799            shift,
1800            mask,
1801            word,
1802            word_bits,
1803        } = self.bit_field_window(bits, span);
1804        let ty = self.ty(field.ty, span);
1805        let name = self.c_ident(&bits.setter, span);
1806        let storage = Ident::new(&bits.storage, span);
1807        let value = Ident::new("value", span);
1808        let field_mask = word_literal(mask, word_bits, span);
1809        let keep = word_literal(!mask & mask_of(word_bits, word_bits), word_bits, span);
1810        let shifted = if shift == 0 {
1811            quote_spanned! {span=> (#value as #word) & #field_mask }
1812        } else {
1813            let by = usize_literal(u64::from(shift), span);
1814            quote_spanned! {span=> ((#value as #word) << #by) & #field_mask }
1815        };
1816        let start = bits.offset_in_storage();
1817        let first = start / 8;
1818        let count = (shift + bits.width).div_ceil(8);
1819        let mut writes = TokenStream::new();
1820        let byte = primitive_ty("u8", span);
1821        for step in 0..count {
1822            let index = usize_literal(first + u64::from(step), span);
1823            if step == 0 {
1824                writes.extend(quote_spanned! {span=> self.#storage[#index] = raw as #byte; });
1825            } else {
1826                let by = usize_literal(u64::from(step) * 8, span);
1827                writes.extend(
1828                    quote_spanned! {span=> self.#storage[#index] = (raw >> #by) as #byte; },
1829                );
1830            }
1831        }
1832        let body = self.accessor_body(
1833            record,
1834            quote_spanned! {span=>
1835                let bits: #word = #shifted;
1836                let raw: #word = #read;
1837                let raw: #word = (raw & #keep) | bits;
1838                #writes
1839            },
1840            span,
1841        );
1842        quote_spanned! {span=>
1843            #[inline]
1844            pub fn #name(&mut self, #value: #ty) { #body }
1845        }
1846    }
1847
1848    /// Wraps an accessor body in `unsafe` where reading the storage needs it,
1849    /// which is exactly when the record is a `union`.
1850    fn accessor_body(&self, record: &ir::RecordDef, body: TokenStream, span: Span) -> TokenStream {
1851        if record.kind == RecordKind::Union {
1852            let block = braced(body, span);
1853            return quote_spanned! {span=> unsafe #block };
1854        }
1855        body
1856    }
1857
1858    /// `const _: () = { assert!(…); };` — the assumptions the data model made,
1859    /// checked against the target the expansion is really compiled for.
1860    ///
1861    /// Everything this crate computes at expansion time — `sizeof`, member
1862    /// offsets, bit-field storage, the type of an integer constant, the value
1863    /// of an `#if` — comes out of a [`TargetModel`](crate::TargetModel) that
1864    /// was chosen from `CINRS_TARGET`, from `#pragma cinrs target`, or (with
1865    /// neither) from the *host*. Any of the three may be the wrong one, and a
1866    /// wrong one would leave every one of those answers quietly wrong. So the
1867    /// expansion states them: `long` is this many bytes, a pointer is that
1868    /// many, plain `char` is signed, `double` is aligned so. The generated
1869    /// code uses the `core::ffi` aliases, which follow the *target*, so a
1870    /// mismatch is a failed assertion at the caret of the C rather than a
1871    /// program that computes the wrong thing — and the message names both the
1872    /// model that was used and the knob that chose it.
1873    ///
1874    /// `__int128`'s alignment is included only where the unit has one: it is
1875    /// the one scalar whose alignment is not fixed by its width, and a unit
1876    /// that never mentions it must not be refused over it.
1877    fn data_model_check(&self) -> TokenStream {
1878        let span = self.map.span(SourceRange::at(0));
1879        let target = &self.options.target;
1880        // Every message ends with this, so that a failure says what to change
1881        // rather than only what went wrong.
1882        let chosen = format!(
1883            "Translated for {}; set CINRS_TARGET from a build script \
1884             (cargo:rustc-env=CINRS_TARGET=$TARGET) or write #pragma cinrs target.",
1885            target.describe(&self.options.target_source)
1886        );
1887        let mut body = TokenStream::new();
1888        let mut width = |ty: TokenStream, bits: u32, what: &str| {
1889            let bytes = usize_literal(u64::from(bits).div_ceil(8), span);
1890            let message = message_literal(
1891                &format!(
1892                    "cinrs: {what} is {} bytes in the data model this unit was translated for, \
1893                     and is not on this target. {chosen}",
1894                    bits.div_ceil(8)
1895                ),
1896                span,
1897            );
1898            body.extend(quote_spanned! {span=>
1899                assert!(::core::mem::size_of::<#ty>() == #bytes, #message);
1900            });
1901        };
1902        width(
1903            quote_spanned! {span=> ::core::ffi::c_short },
1904            target.short_bits,
1905            "'short'",
1906        );
1907        width(
1908            quote_spanned! {span=> ::core::ffi::c_int },
1909            target.int_bits,
1910            "'int'",
1911        );
1912        width(
1913            quote_spanned! {span=> ::core::ffi::c_long },
1914            target.long_bits,
1915            "'long'",
1916        );
1917        width(
1918            quote_spanned! {span=> ::core::ffi::c_longlong },
1919            target.long_long_bits,
1920            "'long long'",
1921        );
1922        width(
1923            quote_spanned! {span=> *const ::core::ffi::c_void },
1924            target.ptr_bits,
1925            "a pointer",
1926        );
1927        // Plain `char`'s signedness decides what `'\xff'` is worth and how a
1928        // `char` widens, so it is an assumption like any other. `c_char` is an
1929        // alias for `i8` or `u8`, and only the unsigned one has a zero minimum.
1930        let (test, said) = if target.char_signed {
1931            (
1932                quote_spanned! {span=> ::core::ffi::c_char::MIN != 0 },
1933                "signed",
1934            )
1935        } else {
1936            (
1937                quote_spanned! {span=> ::core::ffi::c_char::MIN == 0 },
1938                "unsigned",
1939            )
1940        };
1941        let message = message_literal(
1942            &format!(
1943                "cinrs: plain 'char' is {said} in the data model this unit was translated \
1944                 for, and is not on this target. {chosen}"
1945            ),
1946            span,
1947        );
1948        body.extend(quote_spanned! {span=> assert!(#test, #message); });
1949        // The one property two targets of the same *data model* differ on: the
1950        // i386 System V ABI aligns `long long` and `double` to four bytes and
1951        // the Microsoft one to eight, and every member offset the front end
1952        // computed followed whichever this model says. `c_longlong` and
1953        // `c_double` are the aliases, so the assertion follows the target.
1954        let align = usize_literal(target.max_scalar_align.min(8), span);
1955        let message = message_literal(
1956            &format!(
1957                "cinrs: 'long long' and 'double' are {}-byte aligned in the data model this \
1958                 unit was translated for, and are not on this target — so every 'sizeof' and \
1959                 member offset in it would be wrong. {chosen}",
1960                target.max_scalar_align.min(8)
1961            ),
1962            span,
1963        );
1964        body.extend(quote_spanned! {span=>
1965            assert!(
1966                ::core::mem::align_of::<::core::ffi::c_longlong>() == #align
1967                    && ::core::mem::align_of::<::core::ffi::c_double>() == #align,
1968                #message
1969            );
1970        });
1971        if self.uses_int128.get() {
1972            let align = usize_literal(target.int128_align, span);
1973            let message = message_literal(
1974                &format!(
1975                    "cinrs: '__int128' is {}-byte aligned in the data model this unit was \
1976                     translated for, and is not on this target. {chosen}",
1977                    target.int128_align
1978                ),
1979                span,
1980            );
1981            let i128 = primitive_ty("i128", span);
1982            body.extend(quote_spanned! {span=>
1983                assert!(::core::mem::align_of::<#i128>() == #align, #message);
1984            });
1985        }
1986        if self.uses_complex.get() {
1987            // A complex type *is* two of its component type side by side —
1988            // that is the whole reason the runtime uses a `#[repr(C)]` pair —
1989            // and every `sizeof`, member offset and array stride in the unit
1990            // was computed from that. A `Complex<f64>` that is not sixteen
1991            // bytes would make all of them wrong, so the unit says so.
1992            for (ty, name) in [
1993                (Ty::ComplexFloat, "'float _Complex'"),
1994                (Ty::ComplexDouble, "'double _Complex'"),
1995            ] {
1996                let layout = self
1997                    .program
1998                    .types
1999                    .size_align(ty, target)
2000                    .expect("a complex type has a layout");
2001                let rust = self.ty(ty, span);
2002                let size = usize_literal(layout.size, span);
2003                let align = usize_literal(layout.align, span);
2004                let message = message_literal(
2005                    &format!(
2006                        "cinrs: {name} is {} bytes and {}-byte aligned in the data model this \
2007                         unit was translated for, and is not on this target. {chosen}",
2008                        layout.size, layout.align
2009                    ),
2010                    span,
2011                );
2012                body.extend(quote_spanned! {span=>
2013                    assert!(
2014                        ::core::mem::size_of::<#rust>() == #size
2015                            && ::core::mem::align_of::<#rust>() == #align,
2016                        #message
2017                    );
2018                });
2019            }
2020        }
2021        let block = braced(body, span);
2022        quote_spanned! {span=> const _: () = #block; }
2023    }
2024
2025    /// The `extern` block declaring everything the unit does not define, with
2026    /// the libraries the unit links beside it — one empty block each, never an
2027    /// attribute on this one; [`Codegen::link_blocks`] is why.
2028    ///
2029    /// A **function** is declared under its own C name — `pub fn crc32`, not a
2030    /// hidden one — so that the glob re-export carries it out of the unit's
2031    /// module and `#include <zlib.h>` is all Rust needs to call it. An
2032    /// **object** is not, because a glob-imported `static` changes what a `let`
2033    /// of the same name means; [`Program::extern_object_name`] is that rule and
2034    /// its reason.
2035    fn extern_block(&mut self) -> TokenStream {
2036        if !self.program.has_externs() {
2037            return TokenStream::new();
2038        }
2039        let span = self.map.span(SourceRange::at(0));
2040        let mut items = TokenStream::new();
2041        // The symbols this block links by, which is what decides whether it
2042        // needs a library of its own; see [`LEGACY_STDIO`]. Collected here
2043        // rather than asked of the program a second time, so that what the
2044        // attribute answers for and what the block declares cannot drift apart.
2045        let mut symbols: Vec<&str> = Vec::new();
2046        for id in &self.program.externs {
2047            let object = self.program.object(*id);
2048            let Storage::Extern { item_name } = &object.storage else {
2049                continue;
2050            };
2051            let ospan = self.sp(object.range);
2052            let rust_name = self.extern_object_ident(item_name, ospan);
2053            let ty = self.ty(object.ty, ospan);
2054            // An `__asm__("symbol")` label renames the declaration, which is
2055            // exactly what `#[link_name]` already says.
2056            let symbol = object.asm_label.as_deref().unwrap_or(item_name);
2057            symbols.push(symbol);
2058            let link = link_name(symbol, ospan);
2059            items.extend(quote_spanned! {ospan=> #link pub static mut #rust_name: #ty; });
2060        }
2061        for func in &self.program.functions {
2062            if !func.is_extern() || self.beyond_toolchain(func) {
2063                continue;
2064            }
2065            let fspan = self.sp(func.range);
2066            // The C name, through the same mapping every other name goes
2067            // through: a keyword becomes `r#yield`, `a$b` becomes
2068            // `a_dollar_b`, and [`Names`] has already made it unique within
2069            // the unit. It is what a call in this unit names too; see
2070            // [`Codegen::function_path`].
2071            let rust_name = self.c_ident(func.item_name(), fspan);
2072            let params = self.extern_params(func, fspan);
2073            let ret = if func.sig.ret.is_void() {
2074                TokenStream::new()
2075            } else {
2076                let ty = self.ty(func.sig.ret, fspan);
2077                quote_spanned! {fspan=> -> #ty }
2078            };
2079            // An `__asm__("symbol")` label is the program's own answer and wins;
2080            // failing that, a name the Microsoft library exports differently is
2081            // linked by the name it really has. See [`MSVC_RENAMED`].
2082            let symbol = match func.asm_label.as_deref() {
2083                Some(label) => label,
2084                None => self.msvc_symbol(&func.name),
2085            };
2086            symbols.push(symbol);
2087            let link = link_name(symbol, fspan);
2088            items.extend(quote_spanned! {fspan=> #link pub fn #rust_name(#params) #ret; });
2089        }
2090        let links = self.link_blocks(&symbols, span);
2091        quote_spanned! {span=> #links unsafe extern "C" { #items } }
2092    }
2093
2094    /// The libraries this unit links: one `#[link(name = "…")] unsafe extern "C"
2095    /// {}` — the ordinary Rust idiom for "also link this" — for every
2096    /// `#pragma cinrs link` the unit wrote, and for the library an MSVC target
2097    /// needs to resolve the `printf` family.
2098    ///
2099    /// Nothing here is needed for the C library itself, which the Rust runtime
2100    /// already links; the pragma is for the program that calls into something
2101    /// else, and [`LEGACY_STDIO`] is the one library cinrs asks for on its own
2102    /// initiative. `symbols` is what the declarations in the block next to these
2103    /// link by, which is what decides the second of those.
2104    ///
2105    /// A library named by both — `#pragma cinrs link "legacy_stdio_definitions"`
2106    /// written out by hand — is emitted once.
2107    ///
2108    /// # Why an empty block of its own, and not an attribute on the declarations
2109    ///
2110    /// Because `#[link(name = "…")]` says two things, and cinrs means only the
2111    /// first. It puts the library on the link line, and it also makes `rustc`
2112    /// reach every `static` declared *in that very block* through a `dllimport`
2113    /// on a Windows target — `native_library` is asked per foreign item, so a
2114    /// sibling block is untouched. A `dllimport` is right for an object that
2115    /// lives in another image and silently wrong for one that lives in this one:
2116    /// with the attribute on the declarations, a unit that declared
2117    /// `extern int counter;` while another exported unit of the same crate
2118    /// defined it read rubbish — 7887437 for 17, measured on Windows — and
2119    /// `lld-link` said `LNK4217: locally defined symbol imported`.
2120    ///
2121    /// For the `printf` rule that was cinrs's own doing: a unit that includes
2122    /// `<stdio.h>` never asked for a library. The pragma is the program's own
2123    /// statement, but it is no better placed to decide, because in C adding a
2124    /// `.lib` to a link line implies `__declspec(dllimport)` on nothing, and
2125    /// cinrs has no way to write that per declaration. So no generated
2126    /// declaration is a `dllimport`, which is C's own default, and a program that
2127    /// wants a DLL's *data* export — the one case the import library exposes as
2128    /// `__imp_name` alone — names that pointer itself:
2129    ///
2130    /// ```c
2131    /// #pragma cinrs link "gdi32"
2132    /// extern unsigned long *batch_limit __asm__("__imp_GdiBatchLimit");
2133    /// ```
2134    ///
2135    /// That reads the DLL's value; the same symbol declared as a plain object is
2136    /// `lld-link: error: undefined symbol: GdiBatchLimit` — loud, at link time,
2137    /// rather than a wrong value. With the attribute on the declarations even the
2138    /// pointer was out of reach: `rustc` asked for its `__imp_` in turn, and
2139    /// `lld-link` said `undefined symbol: __declspec(dllimport)
2140    /// __imp_GdiBatchLimit`. Every sentence here was measured on
2141    /// `x86_64-pc-windows-msvc`; `doc/cross-compilation.md` keeps the numbers and
2142    /// `tests/declared_names.rs` the cases.
2143    fn link_blocks(&self, symbols: &[&str], span: Span) -> TokenStream {
2144        let mut libraries: Vec<&str> = Vec::new();
2145        for name in &self.program.link_libraries {
2146            if !libraries.contains(&name.as_str()) {
2147                libraries.push(name);
2148            }
2149        }
2150        for library in self.legacy_stdio_libraries(symbols) {
2151            if !libraries.contains(&library) {
2152                libraries.push(library);
2153            }
2154        }
2155        let mut out = TokenStream::new();
2156        for name in libraries {
2157            let mut literal = Literal::string(name);
2158            literal.set_span(span);
2159            out.extend(quote_spanned! {span=> #[link(name = #literal)] unsafe extern "C" {} });
2160        }
2161        out
2162    }
2163
2164    /// The symbol a **declaration** of the C function `name` links by: the name
2165    /// itself, or, on an MSVC target, what the Microsoft C runtime exports it
2166    /// as. See [`MSVC_RENAMED`] for the table and for how each row was read out
2167    /// of a real import library.
2168    ///
2169    /// Only a declaration: a function this unit *defines* is its own symbol, and
2170    /// a C program that defines `time` has defined `time`.
2171    fn msvc_symbol<'name>(&self, name: &'name str) -> &'name str {
2172        if !self.options.target.is_msvc() {
2173            return name;
2174        }
2175        for (c_name, symbol) in MSVC_RENAMED {
2176            if *c_name == name {
2177                return symbol;
2178            }
2179        }
2180        name
2181    }
2182
2183    /// The libraries the `printf` and `scanf` declarations among `symbols` have
2184    /// to be linked against, in the order [`LEGACY_STDIO`] lists them.
2185    ///
2186    /// Empty on every target but an MSVC one: everywhere else the platform's
2187    /// library exports those functions as ordinary symbols and there is nothing
2188    /// to ask for. See [`LEGACY_STDIO`] for why the Microsoft library differs.
2189    fn legacy_stdio_libraries(&self, symbols: &[&str]) -> Vec<&'static str> {
2190        if !self.options.target.is_msvc() {
2191            return Vec::new();
2192        }
2193        let mut out: Vec<&'static str> = Vec::new();
2194        for (symbol, library) in LEGACY_STDIO {
2195            if symbols.contains(symbol) && !out.contains(library) {
2196                out.push(library);
2197            }
2198        }
2199        out
2200    }
2201
2202    fn extern_params(&self, func: &Function, span: Span) -> TokenStream {
2203        let mut params = TokenStream::new();
2204        for (index, ty) in func.sig.params.iter().enumerate() {
2205            if index > 0 {
2206                params.extend(quote_spanned! {span=> , });
2207            }
2208            let ty = self.ty(*ty, span);
2209            match func.param_names.get(index).and_then(|n| n.as_ref()) {
2210                Some(name) => {
2211                    let name = self.c_ident(name, span);
2212                    params.extend(quote_spanned! {span=> #name: #ty });
2213                }
2214                None => params.extend(quote_spanned! {span=> _: #ty }),
2215            }
2216        }
2217        if func.sig.variadic {
2218            if !func.sig.params.is_empty() {
2219                params.extend(quote_spanned! {span=> , });
2220            }
2221            params.extend(quote_spanned! {span=> ... });
2222        }
2223        params
2224    }
2225
2226    fn static_item(&mut self, var: &ir::StaticVar) -> TokenStream {
2227        let object = self.program.object(var.object);
2228        let span = self.sp(object.range);
2229        if object.storage.is_thread_local() {
2230            return self.thread_local_item(var);
2231        }
2232        let Storage::Static {
2233            item_name,
2234            exported,
2235        } = &object.storage
2236        else {
2237            return TokenStream::new();
2238        };
2239        let name = self.c_ident(item_name, span);
2240        let ty = self.binding_ty(var.object, self.storage_ty(var.object, span), span);
2241        let init = self.static_init(&var.init, object.ty, span);
2242        let init = self.binding_init(var.object, init, span);
2243        let (vis, export) = if *exported {
2244            let export = if self.program.export {
2245                let symbol = object.asm_label.as_deref().unwrap_or(&object.name);
2246                export_attr(symbol, &name, span)
2247            } else {
2248                TokenStream::new()
2249            };
2250            (quote_spanned! {span=> pub }, export)
2251        } else {
2252            (TokenStream::new(), TokenStream::new())
2253        };
2254        let section = match &object.section {
2255            Some(section) => {
2256                let mut literal = Literal::string(section);
2257                literal.set_span(span);
2258                quote_spanned! {span=> #[unsafe(link_section = #literal)] }
2259            }
2260            None => TokenStream::new(),
2261        };
2262        // `static mut` rather than a cell: C code assigns to globals from
2263        // anywhere, and reading or writing one directly (never taking a
2264        // reference) is what keeps edition 2024's `static_mut_refs` quiet.
2265        quote_spanned! {span=>
2266            #export
2267            #section
2268            #vis static mut #name: #ty = #init;
2269        }
2270    }
2271
2272    /// `std::thread_local! { static X: UnsafeCell<T> = const { … }; }` — the
2273    /// item a `_Thread_local` object becomes.
2274    ///
2275    /// C's thread-local object has static storage duration and one instance
2276    /// per thread, and `thread_local!` is exactly that. The cell is what makes
2277    /// the object *mutable*: `with` hands out a `&UnsafeCell<T>`, and the
2278    /// `*mut T` inside it is valid for as long as the thread's copy is, which
2279    /// is the lifetime C promises the address of such an object.
2280    ///
2281    /// The initialiser goes inside a `const` block wherever it can — that is
2282    /// the form with no lazy-initialisation flag and no destructor to register
2283    /// — and directly otherwise. Only one thing keeps it out: an initialiser
2284    /// that mentions the address of another item, which a `const` may not
2285    /// refer to (`E0013`).
2286    fn thread_local_item(&mut self, var: &ir::StaticVar) -> TokenStream {
2287        let object = self.program.object(var.object);
2288        let span = self.sp(object.range);
2289        let Storage::ThreadLocal {
2290            item_name,
2291            exported,
2292        } = &object.storage
2293        else {
2294            return TokenStream::new();
2295        };
2296        if self.program.no_std {
2297            // `sema::check_pragmas` has already said that a thread-local object
2298            // needs `std`; emitting `::std::thread_local!` anyway would add
2299            // `rustc`'s own "cannot find `std`" on top of it.
2300            return TokenStream::new();
2301        }
2302        let name = self.c_ident(item_name, span);
2303        let ty = self.binding_ty(var.object, self.storage_ty(var.object, span), span);
2304        let init = self.static_init(&var.init, object.ty, span);
2305        let init = self.binding_init(var.object, init, span);
2306        let vis = if *exported {
2307            quote_spanned! {span=> pub }
2308        } else {
2309            TokenStream::new()
2310        };
2311        let cell = quote_spanned! {span=> ::core::cell::UnsafeCell<#ty> };
2312        let value = quote_spanned! {span=> ::core::cell::UnsafeCell::new(#init) };
2313        let value = if self.const_initialisable(&var.init) {
2314            quote_spanned! {span=> const { #value } }
2315        } else {
2316            value
2317        };
2318        // The lint exemptions are the unit module's own (see
2319        // [`crate::in_module`]), and a `thread_local!` is expanded inside it
2320        // like anything else, so the `static` it generates inherits them.
2321        quote_spanned! {span=>
2322            ::std::thread_local! {
2323                #vis static #name: #cell = #value;
2324            }
2325        }
2326    }
2327
2328    /// Whether an initialiser may go inside a `const { … }` block.
2329    ///
2330    /// A Rust constant may not refer to a `static` (`E0013`), which rules out
2331    /// exactly the initialisers whose value is the address of another item: a
2332    /// pointer to a file-scope object, a function pointer, and the `static`
2333    /// that holds the characters of a wide string literal. A *narrow* literal
2334    /// is a byte string whose `as_ptr` is const, and every arithmetic constant
2335    /// is fine.
2336    ///
2337    /// This is what decides between `thread_local!`'s two forms; see
2338    /// [`Codegen::thread_local_item`].
2339    fn const_initialisable(&self, expr: &Expr) -> bool {
2340        match &expr.kind {
2341            ExprKind::FuncAddr(_) => false,
2342            ExprKind::AddrOf(place) | ExprKind::Load(place) => match &place.kind {
2343                PlaceKind::Str(id) => {
2344                    let elem = self.program.string(*id).elem;
2345                    elem.size_bytes(&self.options.target) == 1
2346                }
2347                _ => !rooted_in_static(place, self.program),
2348            },
2349            ExprKind::Cast(inner) => self.const_initialisable(inner),
2350            ExprKind::PtrOffset { ptr, .. } => self.const_initialisable(ptr),
2351            ExprKind::RecordLit { fields, .. } => {
2352                fields.iter().all(|f| self.const_initialisable(f))
2353            }
2354            ExprKind::UnionLit { value, .. } => self.const_initialisable(value),
2355            ExprKind::ArrayLit(items) => items.iter().all(|i| self.const_initialisable(i)),
2356            ExprKind::ArrayRepeat { value, .. } => self.const_initialisable(value),
2357            _ => true,
2358        }
2359    }
2360
2361    /// The initialiser of a `static mut`, wrapped in `unsafe` when it needs to
2362    /// be (`mem::zeroed`, or the address of another `static mut`).
2363    fn static_init(&mut self, expr: &Expr, ty: Ty, span: Span) -> TokenStream {
2364        let tokens = self.expr_at(expr, ty);
2365        if needs_unsafe(&self.program.types, expr) {
2366            let block = braced(tokens, span);
2367            return quote_spanned! {span=> unsafe #block };
2368        }
2369        tokens
2370    }
2371
2372    fn signature(&mut self, func: &Function) -> TokenStream {
2373        let span = self.sp(func.range);
2374        let name = self.c_ident(func.item_name(), span);
2375        let mut params = TokenStream::new();
2376        // A lifted nested function takes the objects it uses from the
2377        // enclosing frame as pointers, in front of everything the program
2378        // wrote; see [`ir::EnvParam`].
2379        for entry in &func.env {
2380            let object = self.program.object(entry.param);
2381            let pspan = self.sp(object.range);
2382            let pname = self.object_ident(entry.param, pspan);
2383            let pty = self.ty(object.ty, pspan);
2384            params.extend(quote_spanned! {pspan=> #pname: #pty , });
2385        }
2386        // A definition whose parameters did not check out may have fewer than
2387        // the signature says; either way the list still has to have the right
2388        // shape, so it falls back to names of our own.
2389        let named = func.params.len() == func.sig.params.len();
2390        for (index, ty) in func.sig.params.iter().enumerate() {
2391            if index > 0 {
2392                params.extend(quote_spanned! {span=> , });
2393            }
2394            if named {
2395                let id = func.params[index];
2396                let object = self.program.object(id);
2397                let pspan = self.sp(object.range);
2398                let pname = self.object_ident(id, pspan);
2399                let pty = self.ty(*ty, pspan);
2400                params.extend(quote_spanned! {pspan=> mut #pname: #pty });
2401            } else {
2402                let pname = Ident::new(&format!("__cinrs_arg{index}"), Span::mixed_site());
2403                let pty = self.ty(*ty, span);
2404                params.extend(quote_spanned! {span=> #pname: #pty });
2405            }
2406        }
2407        if func.sig.variadic {
2408            if !func.sig.params.is_empty() {
2409                params.extend(quote_spanned! {span=> , });
2410            }
2411            // The variable part of the argument list arrives as one more
2412            // parameter. It is never advanced: `va_start` and every `va_list`
2413            // local copy it, so it stays the list as the caller left it.
2414            let name = self.va_ident();
2415            params.extend(quote_spanned! {span=> #name: ... });
2416        }
2417        let ret = if func.sig.ret.is_void() {
2418            TokenStream::new()
2419        } else {
2420            let ty = self.ty(func.sig.ret, span);
2421            quote_spanned! {span=> -> #ty }
2422        };
2423        // A definition is a Rust item rather than a C symbol unless the unit
2424        // asked for real symbols, so an `__asm__("name")` label on one only
2425        // means something there — and there it names the symbol the item
2426        // takes, which is what `#[unsafe(export_name)]` says. On a *declaration*
2427        // the label is always honoured, through the `extern` block's
2428        // `#[link_name]`.
2429        let exported = !func.is_static && self.program.export;
2430        let vis = if func.is_static {
2431            TokenStream::new()
2432        } else {
2433            quote_spanned! {span=> pub }
2434        };
2435        let export = if exported {
2436            let symbol = func.asm_label.as_deref().unwrap_or(&func.name);
2437            export_attr(symbol, &name, span)
2438        } else {
2439            TokenStream::new()
2440        };
2441        // `#[inline]` is ignored on an exported function, and saying so is
2442        // `rustc`'s job rather than the user's to read: leave it out.
2443        let inline = match func.inline_hint {
2444            Some(_) if exported => TokenStream::new(),
2445            Some(ir::InlineHint::Always) => quote_spanned! {span=> #[inline(always)] },
2446            Some(ir::InlineHint::Never) => quote_spanned! {span=> #[inline(never)] },
2447            None if func.is_inline && !exported => quote_spanned! {span=> #[inline] },
2448            None => TokenStream::new(),
2449        };
2450        let cold = if func.cold {
2451            quote_spanned! {span=> #[cold] }
2452        } else {
2453            TokenStream::new()
2454        };
2455        let deprecated = match &func.deprecated {
2456            Some(Some(message)) => {
2457                let mut literal = Literal::string(message);
2458                literal.set_span(span);
2459                quote_spanned! {span=> #[deprecated(note = #literal)] }
2460            }
2461            Some(None) => quote_spanned! {span=> #[deprecated] },
2462            None => TokenStream::new(),
2463        };
2464        let section = match &func.section {
2465            Some(section) => {
2466                let mut literal = Literal::string(section);
2467                literal.set_span(span);
2468                quote_spanned! {span=> #[unsafe(link_section = #literal)] }
2469            }
2470            None => TokenStream::new(),
2471        };
2472        // A function the unit asked to be safe is generated without `unsafe`,
2473        // and its body without the `unsafe` block, so that `rustc` checks every
2474        // operation in it; see [`crate::sema::check_safe`] for what that
2475        // catches and what it refuses outright.
2476        let unsafety = if func.is_safe() {
2477            TokenStream::new()
2478        } else {
2479            quote_spanned! {span=> unsafe }
2480        };
2481        quote_spanned! {span=>
2482            #export
2483            #inline
2484            #cold
2485            #deprecated
2486            #section
2487            #vis #unsafety extern "C" fn #name(#params) #ret
2488        }
2489    }
2490
2491    /// The `static` that puts a `constructor` or `destructor` function into the
2492    /// table the runtime walks before `main` (or after it).
2493    ///
2494    /// ELF has `.init_array` and `.fini_array`, and Mach-O has
2495    /// `__DATA,__mod_init_func` and `__mod_term_func`; nothing else this crate
2496    /// can name has such a table, so a program that asks for one elsewhere is
2497    /// told so rather than quietly built without it.
2498    fn init_array_item(&mut self, func: &Function, kind: ir::InitKind) -> TokenStream {
2499        let span = self.sp(func.range);
2500        let name = self.c_ident(func.item_name(), span);
2501        let signature = self.function_pointer_ty(func, span);
2502        let item = Ident::new(
2503            &format!(
2504                "__CINRS_INIT_{:08x}_{}",
2505                self.program.unit_id as u32,
2506                func.item_name()
2507            ),
2508            span,
2509        );
2510        let elf = match kind {
2511            ir::InitKind::Constructor => ".init_array",
2512            ir::InitKind::Destructor => ".fini_array",
2513        };
2514        let apple = match kind {
2515            ir::InitKind::Constructor => "__DATA,__mod_init_func",
2516            ir::InitKind::Destructor => "__DATA,__mod_term_func",
2517        };
2518        let mut elf_literal = Literal::string(elf);
2519        elf_literal.set_span(span);
2520        let mut apple_literal = Literal::string(apple);
2521        apple_literal.set_span(span);
2522        // The section name is the one thing about this that is not portable,
2523        // so it is chosen at compile time rather than assumed.
2524        quote_spanned! {span=>
2525            #[used]
2526            #[cfg_attr(target_vendor = "apple", unsafe(link_section = #apple_literal))]
2527            #[cfg_attr(not(target_vendor = "apple"), unsafe(link_section = #elf_literal))]
2528            static #item: #signature = #name;
2529        }
2530    }
2531
2532    /// The one check a unit with a `constructor` or a `destructor` carries.
2533    ///
2534    /// A procedural macro is compiled for the *host*, so it cannot know which
2535    /// target the code it generates is for; the check therefore has to be part
2536    /// of the expansion. It is emitted once per unit rather than once per
2537    /// function, since it says the same thing either way.
2538    fn init_array_guard(&self) -> TokenStream {
2539        let span = self.map.span(SourceRange::at(0));
2540        quote_spanned! {span=>
2541            const _: () = {
2542                #[cfg(not(any(target_os = "linux", target_os = "android",
2543                              target_os = "freebsd", target_os = "netbsd",
2544                              target_os = "openbsd", target_os = "dragonfly",
2545                              target_vendor = "apple")))]
2546                ::core::compile_error!(
2547                    "'constructor' and 'destructor' need a target whose runtime walks an initialiser table (ELF or Mach-O)"
2548                );
2549            };
2550        }
2551    }
2552
2553    fn function_item(&mut self, func: &Function) -> TokenStream {
2554        let span = self.sp(func.range);
2555        let Some(body) = &func.body else {
2556            return TokenStream::new();
2557        };
2558        self.enter_function(func);
2559        let signature = self.signature(func);
2560        let body = match body {
2561            Body::Structured(stmts) => self.stmts(stmts),
2562            Body::Cfg(cfg) => self.cfg_body(cfg, span),
2563        };
2564        // `alloca`'s memory belongs to the function, not to the block the call
2565        // was written in, so the arena is opened here and dropped by whichever
2566        // `return` runs.
2567        let arena = if func.uses_alloca {
2568            self.alloca_arena(span)
2569        } else {
2570            TokenStream::new()
2571        };
2572        // One `unsafe` block around the whole body: in edition 2024 the body of
2573        // an `unsafe fn` is not itself an unsafe block any more. A safe
2574        // function is exactly the one that does not get it — that block is what
2575        // would stop `rustc` checking the translation.
2576        if func.is_safe() {
2577            return quote_spanned! {span=>
2578                #signature { #arena #body }
2579            };
2580        }
2581        quote_spanned! {span=>
2582            #signature {
2583                unsafe { #arena #body }
2584            }
2585        }
2586    }
2587
2588    /// The arena `alloca` allocates out of, at the top of a function that
2589    /// calls it.
2590    ///
2591    /// One `Vec` per call, of `u128` so that every block is 16-byte aligned —
2592    /// the alignment a real `alloca` gives — and all of them freed together
2593    /// when the arena is dropped, which is when the function returns.
2594    fn alloca_arena(&self, span: Span) -> TokenStream {
2595        let name = self.alloca_ident();
2596        let block = self.vec_ty(primitive_ty("u128", span), span);
2597        let arena = self.vec_ty(block, span);
2598        let empty = self.vec_new(span);
2599        quote_spanned! {span=> let mut #name: #arena = #empty; }
2600    }
2601
2602    /// The name of that arena, in this crate's own hygiene.
2603    fn alloca_ident(&self) -> Ident {
2604        Ident::new("__cinrs_alloca", Span::mixed_site())
2605    }
2606
2607    fn stub_item(&mut self, func: &Function) -> TokenStream {
2608        let span = self.sp(func.range);
2609        self.enter_function(func);
2610        let signature = self.signature(func);
2611        if func.is_safe() {
2612            return quote_spanned! {span=>
2613                #signature { ::core::unreachable!() }
2614            };
2615        }
2616        quote_spanned! {span=>
2617            #signature {
2618                unsafe { ::core::unreachable!() }
2619            }
2620        }
2621    }
2622
2623    /// Resets the per-function state before a body is generated.
2624    fn enter_function(&mut self, func: &Function) {
2625        self.ret_ty = func.sig.ret;
2626        self.in_cfg = matches!(func.body, Some(Body::Cfg(_)));
2627        self.temporaries = 0;
2628        self.continue_styles.clear();
2629        self.local_names.clear();
2630        self.region_names.clear();
2631        self.region_kinds.clear();
2632        if let Some(Body::Structured(stmts)) = &func.body {
2633            self.name_regions(stmts);
2634        }
2635        self.env = func
2636            .env
2637            .iter()
2638            .map(|entry| (entry.owner, entry.param))
2639            .collect();
2640
2641        // Every object this function binds with a `let` or a parameter, so
2642        // that one that would shadow a file-scope item can be renamed apart
2643        // and the rename can be checked against the others. Sema's list is
2644        // what makes a local declared inside a statement expression — which no
2645        // walk over the *statements* would reach — part of it.
2646        let mut bound: Vec<ir::ObjectId> = func.env.iter().map(|entry| entry.param).collect();
2647        bound.extend(func.params.iter().copied());
2648        if let Some(Body::Cfg(cfg)) = &func.body {
2649            for local in &cfg.locals {
2650                self.local_names
2651                    .insert(local.object, local.rust_name.clone());
2652            }
2653        }
2654        bound.extend(func.locals.iter().copied());
2655        self.rename_shadowing(&bound);
2656
2657        self.va_source = if func.sig.variadic {
2658            VaSource::Ellipsis
2659        } else {
2660            // A `va_list *` parameter points at the caller's list, which is
2661            // what a `va_list` local of this function starts out as — the same
2662            // thing a `va_list` parameter is, one indirection further out.
2663            func.params
2664                .iter()
2665                .find_map(|id| {
2666                    let ty = self.program.object(*id).ty;
2667                    if ty.is_va_list() {
2668                        return Some(VaSource::Param(*id));
2669                    }
2670                    let pointee = self.program.types.pointee(ty)?;
2671                    pointee.is_va_list().then_some(VaSource::PtrParam(*id))
2672                })
2673                .unwrap_or(VaSource::None)
2674        };
2675    }
2676
2677    /// The name a local or parameter would be generated under before the
2678    /// shadowing check.
2679    fn plain_local_name(&self, id: ir::ObjectId) -> String {
2680        match self.local_names.get(&id) {
2681            Some(name) => name.clone(),
2682            None => self.program.object(id).name.clone(),
2683        }
2684    }
2685
2686    /// Renames the bindings of the current function whose names would shadow a
2687    /// file-scope item.
2688    ///
2689    /// The new name is the C one with `_1`, `_2`, … appended, the same shape
2690    /// the [CFG lowering](crate::cfg) uses when it hoists two locals of the
2691    /// same name into one scope, and it is checked against the function's
2692    /// other bindings so that a rename never captures one of them. The check
2693    /// is against their Rust *spellings* (see [`Names`]), which is what two
2694    /// bindings collide in.
2695    fn rename_shadowing(&mut self, bound: &[ir::ObjectId]) {
2696        if self.reserved.is_empty() {
2697            return;
2698        }
2699        let mut used: HashSet<String> = bound
2700            .iter()
2701            .map(|id| {
2702                self.names
2703                    .spelling(&self.plain_local_name(*id))
2704                    .into_owned()
2705            })
2706            .collect();
2707        for id in bound {
2708            let base = self.plain_local_name(*id);
2709            if !self.reserved.contains(&base) {
2710                continue;
2711            }
2712            let name = (1u32..)
2713                .map(|n| format!("{base}_{n}"))
2714                .find(|c| {
2715                    !used.contains(self.names.spelling(c).as_ref()) && !self.reserved.contains(c)
2716                })
2717                .expect("the sequence of candidates is unbounded");
2718            used.insert(self.names.spelling(&name).into_owned());
2719            self.local_names.insert(*id, name);
2720        }
2721    }
2722
2723    /// The name of the synthetic `...` parameter.
2724    ///
2725    /// Mixed-site hygiene keeps it distinct from a C variable of the same
2726    /// name, however unlikely one is.
2727    fn va_ident(&self) -> Ident {
2728        Ident::new("__cinrs_va", Span::mixed_site())
2729    }
2730
2731    /// A fresh copy of the argument list the function was called with.
2732    fn va_pristine(&mut self, span: Span) -> TokenStream {
2733        match self.va_source {
2734            VaSource::Param(id) => {
2735                let name = self.object_ident(id, span);
2736                quote_spanned! {span=> #name.clone() }
2737            }
2738            VaSource::PtrParam(id) => {
2739                let name = self.object_ident(id, span);
2740                quote_spanned! {span=> (*#name).clone() }
2741            }
2742            // `VaSource::None` cannot reach codegen: sema refuses a `va_list`
2743            // that has nothing to copy.
2744            _ => {
2745                let name = self.va_ident();
2746                quote_spanned! {span=> #name.clone() }
2747            }
2748        }
2749    }
2750
2751    /// The alignment an object's binding has to be wrapped in, if any.
2752    ///
2753    /// Rust has no way to over-align a binding, so an object an `_Alignas` or
2754    /// an `aligned` made stricter than its type is generated inside a
2755    /// one-field wrapper that carries the alignment; see
2756    /// [`Codegen::align_wrapper_items`] and [`ir::Object::align`].
2757    fn object_align(&self, id: ir::ObjectId) -> Option<u64> {
2758        self.program.object(id).align
2759    }
2760
2761    /// The type an object's binding is declared with.
2762    fn binding_ty(&self, id: ir::ObjectId, ty: TokenStream, span: Span) -> TokenStream {
2763        match self.object_align(id) {
2764            Some(align) => {
2765                let wrapper = align_wrapper_ident(align, span);
2766                quote_spanned! {span=> #wrapper<#ty> }
2767            }
2768            None => ty,
2769        }
2770    }
2771
2772    /// The value an object's binding is initialised with.
2773    fn binding_init(&self, id: ir::ObjectId, init: TokenStream, span: Span) -> TokenStream {
2774        match self.object_align(id) {
2775            Some(align) => {
2776                let wrapper = align_wrapper_ident(align, span);
2777                quote_spanned! {span=> #wrapper(#init) }
2778            }
2779            None => init,
2780        }
2781    }
2782
2783    /// The type an object's *storage* has, which is its own except for the
2784    /// [companion](ir::Object::flexible_len) a filled-in flexible array member
2785    /// needs.
2786    fn storage_ty(&self, id: ir::ObjectId, span: Span) -> TokenStream {
2787        let object = self.program.object(id);
2788        match (object.flexible_len, object.ty) {
2789            (Some(len), Ty::Record(record)) => {
2790                let name =
2791                    self.flexible_ident(&self.program.types.record(record).rust_name, len, span);
2792                quote_spanned! {span=> #name }
2793            }
2794            _ => self.ty(object.ty, span),
2795        }
2796    }
2797
2798    /// The place expression naming an object, reaching through the alignment
2799    /// wrapper and the flexible-array companion when the binding has them.
2800    fn object_access(&self, id: ir::ObjectId, span: Span) -> TokenStream {
2801        let name = self.object_ident(id, span);
2802        self.through_storage(id, quote_spanned! {span=> #name }, span)
2803    }
2804
2805    /// Reaches the C object inside the storage its binding really has.
2806    ///
2807    /// Two wrappers can sit in between, and they compose: the
2808    /// [alignment](ir::Object::align) wrapper's one field, and the
2809    /// [flexible-array companion](ir::Object::flexible_len), whose leading
2810    /// layout is the record's and whose address is therefore a pointer to it.
2811    fn through_storage(&self, id: ir::ObjectId, base: TokenStream, span: Span) -> TokenStream {
2812        let object = self.program.object(id);
2813        let mut access = base;
2814        if object.align.is_some() {
2815            let field = Literal::usize_unsuffixed(0);
2816            access = quote_spanned! {span=> #access.#field };
2817        }
2818        if object.flexible_len.is_some() {
2819            let ty = self.ty(object.ty, span);
2820            access = parenthesize(
2821                quote_spanned! {span=> *(&raw mut #access).cast::<#ty>() },
2822                span,
2823            );
2824        }
2825        access
2826    }
2827
2828    /// Reading a `va_list` copies it: Rust's is not `Copy`, and C says a list
2829    /// passed on is indeterminate afterwards anyway.
2830    ///
2831    /// A `va_list` place is an object of its own or the `*p` of a `va_list *`
2832    /// — nothing may keep one as a member — so the only setup there can be is
2833    /// the temporary that pointer goes into. Out of line for the same reason
2834    /// [`Codegen::label_address`] is.
2835    #[inline(never)]
2836    fn va_list_load(&mut self, place: &Place, span: Span) -> Value {
2837        let lowered = self.place(place, false);
2838        let access = lowered.access;
2839        let value = Value::new(quote_spanned! {span=> #access.clone() }, prec::CALL);
2840        if lowered.setup.is_empty() {
2841            return value;
2842        }
2843        let setup = lowered.setup;
2844        let tokens = value.at(prec::LOWEST, span);
2845        Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
2846    }
2847
2848    /// GNU's `&&label`: the state number the label's block was given, cast to
2849    /// the pointer type the expression has.
2850    ///
2851    /// Out of line — like [`Codegen::label_difference`] — because
2852    /// [`Codegen::expr_value`] recurses once per operator and every arm's
2853    /// locals are part of its frame; see
2854    /// `codegen_of_deeply_nested_input_fits_in_a_small_stack`.
2855    #[inline(never)]
2856    fn label_address(&self, id: ir::LabelId, ty: Ty, span: Span) -> Value {
2857        let state = self.label_states.get(&id).copied().unwrap_or(0);
2858        let mut literal = Literal::usize_suffixed(state as usize);
2859        literal.set_span(span);
2860        let target = self.ty(ty, span);
2861        Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
2862    }
2863
2864    /// GNU's `&&a - &&b`, folded on the two state numbers.
2865    #[inline(never)]
2866    fn label_difference(&self, lhs: &Expr, rhs: &Expr, ty: Ty, span: Span) -> Value {
2867        let left = self.label_state_literal(lhs, span);
2868        let right = self.label_state_literal(rhs, span);
2869        let target = self.ty(ty, span);
2870        Value::new(
2871            quote_spanned! {span=> (#left - #right) as #target },
2872            prec::CAST,
2873        )
2874        .type_end(true)
2875    }
2876
2877    /// The state number a [label address](ir::ExprKind::LabelAddr) stands for,
2878    /// as an `isize` literal.
2879    fn label_state_literal(&self, expr: &Expr, span: Span) -> TokenStream {
2880        let id = label_state(expr).expect("a label address");
2881        let state = self.label_states.get(&id).copied().unwrap_or(0);
2882        let mut literal = Literal::isize_suffixed(state as isize);
2883        literal.set_span(span);
2884        quote_spanned! {span=> #literal }
2885    }
2886
2887    /// The Rust name an object is generated under.
2888    fn object_ident(&self, id: ir::ObjectId, span: Span) -> Ident {
2889        let object = self.program.object(id);
2890        match &object.storage {
2891            Storage::Automatic => match self.local_names.get(&id) {
2892                Some(name) => self.c_ident(name, span),
2893                None => self.c_ident(&object.name, span),
2894            },
2895            // A `static mut` is used as a place, never referenced, so
2896            // edition 2024's `static_mut_refs` lint has nothing to say.
2897            Storage::Static { item_name, .. } | Storage::ThreadLocal { item_name, .. } => {
2898                self.c_ident(item_name, span)
2899            }
2900            Storage::Extern { item_name } => self.extern_object_ident(item_name, span),
2901        }
2902    }
2903
2904    // -- the control-flow-graph form ----------------------------------------
2905
2906    /// Emits a [CFG](crate::cfg) body as a state machine.
2907    ///
2908    /// Every arm of the `match` ends in `continue 'cfg` or in a `return`, so
2909    /// the loop never finishes and the function needs no value after it.
2910    fn cfg_body(&mut self, cfg: &Cfg, span: Span) -> TokenStream {
2911        let mut out = TokenStream::new();
2912        for local in &cfg.locals {
2913            let object = self.program.object(local.object);
2914            let ospan = self.sp(object.range);
2915            let name = self.object_ident(local.object, ospan);
2916            // The hidden `Vec` of a variable length array starts out empty and
2917            // is replaced where the declaration was written, which is also
2918            // what frees the storage of a previous pass over it.
2919            let (ty, init) = if object.vla_storage {
2920                let elem = self.ty(object.ty, ospan);
2921                (self.vec_ty(elem, ospan), self.vec_new(ospan))
2922            } else if object.ty.is_va_list() {
2923                // A `va_list` has no zero value; it starts out as a copy of
2924                // the list the function was called with, exactly as it does
2925                // when the declaration stays where it was written.
2926                (self.ty(object.ty, ospan), self.va_pristine(ospan))
2927            } else {
2928                (
2929                    self.ty(object.ty, ospan),
2930                    self.zero_tokens(object.ty, ospan),
2931                )
2932            };
2933            let ty = self.binding_ty(local.object, ty, ospan);
2934            let init = self.binding_init(local.object, init, ospan);
2935            out.extend(quote_spanned! {ospan=> let mut #name: #ty = #init; });
2936        }
2937        let state = self.state_ident();
2938        let label = self.cfg_label();
2939        let mut arms = TokenStream::new();
2940        for (index, block) in cfg.blocks.iter().enumerate() {
2941            let bspan = self.block_span(block, span);
2942            let pattern = state_literal(index, bspan);
2943            let body = self.block_tokens(block, bspan);
2944            arms.extend(quote_spanned! {bspan=> #pattern => { #body } });
2945        }
2946        arms.extend(quote_spanned! {span=> _ => ::core::unreachable!(), });
2947        let u32_ty = primitive_ty("u32", span);
2948        quote_spanned! {span=>
2949            #out
2950            let mut #state: #u32_ty = 0;
2951            #label: loop {
2952                match #state { #arms }
2953            }
2954        }
2955    }
2956
2957    /// The state variable, in this crate's own hygiene.
2958    fn state_ident(&self) -> Ident {
2959        Ident::new("__cinrs_state", Span::mixed_site())
2960    }
2961
2962    fn cfg_label(&self) -> TokenStream {
2963        self.label("cfg", Span::mixed_site())
2964    }
2965
2966    /// Where a block's tokens are attributed to: the first thing in it that
2967    /// came from the C source.
2968    fn block_span(&self, block: &BasicBlock, fallback: Span) -> Span {
2969        if let Some(range) = block.stmts.iter().find_map(|s| self.stmt_range(s)) {
2970            return self.sp(range);
2971        }
2972        match &block.term {
2973            Terminator::Jump { range, .. }
2974            | Terminator::Switch { range, .. }
2975            | Terminator::IndirectJump { range, .. }
2976            | Terminator::Return { range, .. } => self.sp(*range),
2977            Terminator::Branch { cond, .. } => self.sp(cond.range),
2978            Terminator::Unreachable => fallback,
2979        }
2980    }
2981
2982    fn block_tokens(&mut self, block: &BasicBlock, span: Span) -> TokenStream {
2983        let mut out = self.stmts(&block.stmts);
2984        let label = self.cfg_label();
2985        match &block.term {
2986            Terminator::Jump { target, range } => {
2987                let jump = self.enter_block(*target, self.sp(*range));
2988                out.extend(quote_spanned! {span=> #jump continue #label; });
2989            }
2990            // GNU's computed `goto *e`: the pointer *is* the state number the
2991            // label's block was given, so the jump is a store and another turn
2992            // round the dispatch. A value that names no block lands on the
2993            // `unreachable!()` arm, which is the undefined behaviour C had.
2994            Terminator::IndirectJump { target, range, .. } => {
2995                let gspan = self.sp(*range);
2996                let state = self.state_ident();
2997                let pointer = self.expr(target).at(prec::CAST, gspan);
2998                let usize_ty = primitive_ty("usize", gspan);
2999                let u32_ty = primitive_ty("u32", gspan);
3000                out.extend(quote_spanned! {gspan=>
3001                    #state = #pointer as #usize_ty as #u32_ty;
3002                    continue #label;
3003                });
3004            }
3005            Terminator::Branch {
3006                cond,
3007                then_blk,
3008                else_blk,
3009            } => {
3010                let cspan = self.sp(cond.range);
3011                let test = self.condition(cond).at_condition(cspan);
3012                let then_tokens = self.enter_block(*then_blk, cspan);
3013                let else_tokens = self.enter_block(*else_blk, cspan);
3014                out.extend(quote_spanned! {cspan=>
3015                    if #test { #then_tokens } else { #else_tokens }
3016                    continue #label;
3017                });
3018            }
3019            Terminator::Switch {
3020                value,
3021                cases,
3022                default,
3023                range,
3024            } => {
3025                let sspan = self.sp(*range);
3026                let scrutinee = self.expr(value).at(prec::UNARY, sspan);
3027                let mut arms = TokenStream::new();
3028                for (target, values) in group_cases(cases) {
3029                    let mut pattern = TokenStream::new();
3030                    for (index, case) in values.iter().enumerate() {
3031                        if index > 0 {
3032                            pattern.extend(quote_spanned! {sspan=> | });
3033                        }
3034                        pattern.extend(case_pattern(*case, value.ty, sspan));
3035                    }
3036                    let enter = self.enter_block(target, sspan);
3037                    arms.extend(quote_spanned! {sspan=> #pattern => { #enter } });
3038                }
3039                let enter = self.enter_block(*default, sspan);
3040                arms.extend(quote_spanned! {sspan=> _ => { #enter } });
3041                out.extend(quote_spanned! {sspan=>
3042                    match #scrutinee { #arms }
3043                    continue #label;
3044                });
3045            }
3046            Terminator::Return { value, range } => {
3047                let rspan = self.sp(*range);
3048                match value {
3049                    Some(value) => {
3050                        let ret = self.ret_ty;
3051                        let tokens = self.expr_at(value, ret);
3052                        out.extend(quote_spanned! {rspan=> return #tokens; });
3053                    }
3054                    None => out.extend(quote_spanned! {rspan=> return; }),
3055                }
3056            }
3057            Terminator::Unreachable => {
3058                out.extend(quote_spanned! {span=> ::core::unreachable!(); });
3059            }
3060        }
3061        out
3062    }
3063
3064    /// The assignment that moves the state machine to `target`.
3065    fn enter_block(&self, target: BlockId, span: Span) -> TokenStream {
3066        let state = self.state_ident();
3067        let value = state_literal(target.0 as usize, span);
3068        quote_spanned! {span=> #state = #value; }
3069    }
3070
3071    // -- statements ---------------------------------------------------------
3072
3073    fn stmts(&mut self, stmts: &[Stmt]) -> TokenStream {
3074        let mut out = TokenStream::new();
3075        for stmt in stmts {
3076            out.extend(self.stmt(stmt));
3077        }
3078        out
3079    }
3080
3081    /// Emits a statement as a braced block, reusing the braces C already wrote
3082    /// when it wrote a compound statement.
3083    fn block_of(&mut self, stmt: &Stmt, span: Span) -> TokenStream {
3084        match stmt {
3085            Stmt::Block(items) => {
3086                let items = self.stmts(items);
3087                braced(items, span)
3088            }
3089            other => {
3090                let tokens = self.stmt(other);
3091                braced(tokens, span)
3092            }
3093        }
3094    }
3095
3096    fn stmt(&mut self, stmt: &Stmt) -> TokenStream {
3097        match stmt {
3098            Stmt::Nop => TokenStream::new(),
3099            Stmt::Expr(expr) => self.expr_stmt(expr),
3100            Stmt::Let { object, init, .. } => {
3101                let id = *object;
3102                let name = self.object_ident(id, self.sp(self.program.object(id).range));
3103                let object = self.program.object(id);
3104                let span = self.sp(object.range);
3105                let object_ty = object.ty;
3106                let ty = self.binding_ty(id, self.ty(object_ty, span), span);
3107                let init = self.expr_at(init, object_ty);
3108                let init = self.binding_init(id, init, span);
3109                quote_spanned! {span=> let mut #name: #ty = #init; }
3110            }
3111            Stmt::Vla(def) => self.vla_def(def),
3112            Stmt::Cleanup(def) => self.cleanup_def(def),
3113            Stmt::Block(items) => {
3114                let span = self.stmts_span(items);
3115                let items = self.stmts(items);
3116                braced(items, span)
3117            }
3118            Stmt::If {
3119                cond,
3120                then_branch,
3121                else_branch,
3122            } => {
3123                let span = self.sp(cond.range);
3124                let cond_tokens = self.condition(cond).at_condition(span);
3125                let then_tokens = self.block_of(then_branch, span);
3126                let else_tokens = match else_branch {
3127                    Some(branch) => {
3128                        let tokens = self.block_of(branch, span);
3129                        quote_spanned! {span=> else #tokens }
3130                    }
3131                    None => TokenStream::new(),
3132                };
3133                quote_spanned! {span=> if #cond_tokens #then_tokens #else_tokens }
3134            }
3135            Stmt::While {
3136                id,
3137                cond,
3138                body,
3139                range,
3140            } => {
3141                let span = self.sp(*range);
3142                self.continue_styles.insert(*id, ContinueStyle::Head);
3143                let label = self.loop_label(*id, span);
3144                let body_tokens = self.block_of(body, span);
3145                // `while (1)` becomes `loop`, not `while true`: only a `loop`
3146                // tells Rust the statement never finishes, which is what a
3147                // function ending in one relies on.
3148                if ir::is_always_true(cond) {
3149                    return quote_spanned! {span=> #label: loop #body_tokens };
3150                }
3151                let cond_tokens = self.condition(cond).at_condition(span);
3152                quote_spanned! {span=> #label: while #cond_tokens #body_tokens }
3153            }
3154            Stmt::DoWhile {
3155                id,
3156                body,
3157                cond,
3158                range,
3159            } => {
3160                let span = self.sp(*range);
3161                self.continue_styles.insert(*id, ContinueStyle::BodyLabel);
3162                let label = self.loop_label(*id, span);
3163                let body_label = self.loop_body_label(*id, span);
3164                let body_tokens = self.block_of(body, span);
3165                let test = if ir::is_always_true(cond) {
3166                    TokenStream::new()
3167                } else {
3168                    let cond_tokens = self.condition(cond).at(prec::LOWEST, span);
3169                    quote_spanned! {span=> if !(#cond_tokens) { break #label; } }
3170                };
3171                quote_spanned! {span=>
3172                    #label: loop {
3173                        #body_label: #body_tokens
3174                        #test
3175                    }
3176                }
3177            }
3178            Stmt::For {
3179                id,
3180                init,
3181                cond,
3182                step,
3183                body,
3184                range,
3185            } => {
3186                let span = self.sp(*range);
3187                self.continue_styles.insert(*id, ContinueStyle::BodyLabel);
3188                let label = self.loop_label(*id, span);
3189                let body_label = self.loop_body_label(*id, span);
3190                let init_tokens = self.stmts(init);
3191                let test = match cond {
3192                    Some(cond) if !ir::is_always_true(cond) => {
3193                        let tokens = self.condition(cond).at(prec::LOWEST, span);
3194                        quote_spanned! {span=> if !(#tokens) { break #label; } }
3195                    }
3196                    _ => TokenStream::new(),
3197                };
3198                let body_tokens = self.block_of(body, span);
3199                let step_tokens = match step {
3200                    Some(step) => self.expr_stmt(step),
3201                    None => TokenStream::new(),
3202                };
3203                // The whole loop is wrapped so that a C99 declaration in the
3204                // init clause stays scoped to the loop, as C says it is.
3205                quote_spanned! {span=>
3206                    {
3207                        #init_tokens
3208                        #label: loop {
3209                            #test
3210                            #body_label: #body_tokens
3211                            #step_tokens
3212                        }
3213                    }
3214                }
3215            }
3216            Stmt::Switch(switch) => self.switch(switch),
3217            Stmt::Region(region) => self.region(region),
3218            // The CFG lowering consumes these, and a label the structured mode
3219            // kept is where a region ends rather than anything of its own: only
3220            // the statement under it is left.
3221            Stmt::Label { body, .. } | Stmt::Case { body, .. } => self.stmt(body),
3222            // A `goto` left in a structured body leaves the region its label
3223            // stands for; see [`crate::regions`]. Anything else is consumed by
3224            // the CFG lowering, which is the only mode it is generated in.
3225            Stmt::Goto { id, range } => {
3226                let span = self.sp(*range);
3227                match self.region_kinds.get(id).copied() {
3228                    Some(kind) => {
3229                        let label = self.region_label(*id, span);
3230                        match kind {
3231                            ir::RegionKind::Block => quote_spanned! {span=> break #label; },
3232                            ir::RegionKind::Loop => quote_spanned! {span=> continue #label; },
3233                        }
3234                    }
3235                    None => TokenStream::new(),
3236                }
3237            }
3238            Stmt::GotoPtr { .. } => TokenStream::new(),
3239            Stmt::SwitchTree(switch) => self.stmt(&switch.body),
3240            Stmt::Break { target, range } => {
3241                let span = self.sp(*range);
3242                let label = match target {
3243                    BreakTarget::Loop(id) => self.loop_label(*id, span),
3244                    BreakTarget::Switch(id) => self.switch_label(*id, span),
3245                };
3246                quote_spanned! {span=> break #label; }
3247            }
3248            Stmt::Continue { id, range } => {
3249                let span = self.sp(*range);
3250                match self.continue_styles.get(id) {
3251                    Some(ContinueStyle::BodyLabel) => {
3252                        let label = self.loop_body_label(*id, span);
3253                        quote_spanned! {span=> break #label; }
3254                    }
3255                    _ => {
3256                        let label = self.loop_label(*id, span);
3257                        quote_spanned! {span=> continue #label; }
3258                    }
3259                }
3260            }
3261            Stmt::Return { value, range } => {
3262                let span = self.sp(*range);
3263                match value {
3264                    Some(value) => {
3265                        let ret = self.ret_ty;
3266                        let tokens = self.expr_at(value, ret);
3267                        quote_spanned! {span=> return #tokens; }
3268                    }
3269                    None => quote_spanned! {span=> return; },
3270                }
3271            }
3272        }
3273    }
3274
3275    /// A variable length array's definition, `T a[n];`.
3276    ///
3277    /// Three bindings: the number of elements, evaluated exactly once here; the
3278    /// `Vec` that holds them, whose `Drop` at the end of the block is the
3279    /// object's lifetime; and the object itself, which is a pointer to the
3280    /// first element. In [CFG mode](crate::cfg) the three are already bound at
3281    /// the top of the function — Rust has no way to jump over a `let` — so what
3282    /// is written here is the three assignments instead.
3283    fn vla_def(&mut self, def: &ir::VlaDef) -> TokenStream {
3284        let span = self.sp(def.range);
3285        let object = self.program.object(def.object);
3286        // Whatever is left under the variable dimensions: one `Vec` holds the
3287        // whole object, however many of them there are.
3288        let elem = self.program.types.vm_step_ty(object.ty);
3289        let store = self.object_ident(def.storage, span);
3290        let name = self.object_ident(def.object, span);
3291        let count = self.expr(&def.count).at(prec::CAST, span);
3292        let zero = self.zero_tokens(elem, span);
3293        let elem_ty = self.ty(elem, span);
3294        let usize_ty = primitive_ty("usize", span);
3295        let elements = self.vec_of(zero, quote_spanned! {span=> #count as #usize_ty }, span);
3296        if self.in_cfg {
3297            return quote_spanned! {span=>
3298                #store = #elements;
3299                #name = #store.as_mut_ptr();
3300            };
3301        }
3302        let vec_ty = self.vec_ty(elem_ty.clone(), span);
3303        quote_spanned! {span=>
3304            let mut #store: #vec_ty = #elements;
3305            let mut #name: *mut #elem_ty = #store.as_mut_ptr();
3306        }
3307    }
3308
3309    /// A `cleanup` attribute's drop guard, in the structured lowering.
3310    ///
3311    /// The binding stands right after the object's own, so Rust drops it
3312    /// first — and drops it on every way out of the block, which is exactly
3313    /// what GCC promises. See [`ir::CleanupDef`].
3314    fn cleanup_def(&mut self, def: &ir::CleanupDef) -> TokenStream {
3315        let span = self.sp(def.range);
3316        let guard = cleanup_guard_ty();
3317        // One binding per object, in this crate's own hygiene: the C program
3318        // cannot name it, and two guards in one block cannot collide.
3319        let name = Ident::new(
3320            &format!("__cinrs_cleanup{}", def.object.0),
3321            Span::mixed_site(),
3322        );
3323        let object = self.program.object(def.object);
3324        let place = ir::Place {
3325            kind: PlaceKind::Object(def.object),
3326            ty: object.ty,
3327            is_const: object.is_const,
3328            range: def.range,
3329        };
3330        let address = self
3331            .address_of(&place, def.param, span)
3332            .at(prec::LOWEST, span);
3333        let function = self.func_pointer(def.func, span);
3334        self.uses_cleanup.set(true);
3335        quote_spanned! {span=>
3336            let #name = #guard(#address, #function);
3337        }
3338    }
3339
3340    /// `struct __cinrs_cleanup<P, R>(P, unsafe extern "C" fn(P) -> R);` and
3341    /// its `Drop`.
3342    ///
3343    /// One item per unit — each unit is a module of its own, so two of them in
3344    /// one Rust module do not collide — generated only when something asks for
3345    /// it. It is generic over the *pointer* the function takes rather than
3346    /// over the object's type, so that a `void *`-taking cleanup (the
3347    /// `_cleanup_free_` idiom) needs nothing special, and over the return
3348    /// type, which GCC ignores.
3349    fn cleanup_guard_item(&self, span: Span) -> TokenStream {
3350        let name = cleanup_guard_ty();
3351        let p = Ident::new("P", Span::mixed_site());
3352        let r = Ident::new("R", Span::mixed_site());
3353        quote_spanned! {span=>
3354            struct #name<#p: ::core::marker::Copy, #r>(#p, unsafe extern "C" fn(#p) -> #r);
3355            impl<#p: ::core::marker::Copy, #r> ::core::ops::Drop for #name<#p, #r> {
3356                fn drop(&mut self) {
3357                    unsafe {
3358                        (self.1)(self.0);
3359                    }
3360                }
3361            }
3362        }
3363    }
3364
3365    /// `f as unsafe extern "C" fn(…) -> R`, the function a drop guard holds.
3366    fn func_pointer(&self, id: ir::FuncId, span: Span) -> TokenStream {
3367        let function = self.program.function(id);
3368        let name = self.function_path(function, span);
3369        let signature = self.function_pointer_ty(function, span);
3370        quote_spanned! {span=> #name as #signature }
3371    }
3372
3373    /// A span standing for a run of statements.
3374    fn stmts_span(&self, stmts: &[Stmt]) -> Span {
3375        stmts
3376            .iter()
3377            .find_map(|s| self.stmt_range(s))
3378            .map_or_else(Span::call_site, |range| self.sp(range))
3379    }
3380
3381    fn stmt_range(&self, stmt: &Stmt) -> Option<SourceRange> {
3382        Some(match stmt {
3383            Stmt::Expr(expr) => expr.range,
3384            Stmt::Let { object, .. } => self.program.object(*object).range,
3385            Stmt::Vla(def) => def.range,
3386            Stmt::Cleanup(def) => def.range,
3387            Stmt::If { cond, .. } => cond.range,
3388            Stmt::While { range, .. }
3389            | Stmt::DoWhile { range, .. }
3390            | Stmt::For { range, .. }
3391            | Stmt::Break { range, .. }
3392            | Stmt::Continue { range, .. }
3393            | Stmt::Return { range, .. }
3394            | Stmt::Label { range, .. }
3395            | Stmt::Case { range, .. }
3396            | Stmt::Goto { range, .. }
3397            | Stmt::GotoPtr { range, .. } => *range,
3398            Stmt::Switch(switch) => switch.range,
3399            Stmt::SwitchTree(switch) => switch.range,
3400            Stmt::Region(region) => region.range,
3401            Stmt::Block(items) => return items.iter().find_map(|s| self.stmt_range(s)),
3402            Stmt::Nop => return None,
3403        })
3404    }
3405
3406    fn loop_label(&self, id: LoopId, span: Span) -> TokenStream {
3407        self.label(&format!("l{}", id.0), span)
3408    }
3409
3410    fn loop_body_label(&self, id: LoopId, span: Span) -> TokenStream {
3411        self.label(&format!("l{}_body", id.0), span)
3412    }
3413
3414    fn switch_label(&self, id: ir::SwitchId, span: Span) -> TokenStream {
3415        self.label(&format!("sw{}", id.0), span)
3416    }
3417
3418    fn switch_case_label(&self, id: ir::SwitchId, index: usize, span: Span) -> TokenStream {
3419        self.label(&format!("sw{}_c{index}", id.0), span)
3420    }
3421
3422    /// The Rust label a [region](ir::Region) carries.
3423    fn region_label(&self, id: ir::LabelId, span: Span) -> TokenStream {
3424        match self.region_names.get(&id) {
3425            Some(name) => self.label(name, span),
3426            // Only a `goto` outside every region for its label, which
3427            // [`crate::regions`] does not leave behind.
3428            None => self.label(&format!("cinrs_label{}", id.0), span),
3429        }
3430    }
3431
3432    /// A labelled block or a labelled loop, and the statements inside it.
3433    ///
3434    /// The two shapes are what an outward `goto` becomes — see
3435    /// [`crate::regions`]. A loop ends with a `break` of its own so that
3436    /// falling off the end of the region leaves it; one whose body cannot
3437    /// reach its end has none, which is what lets a function ending in it need
3438    /// no `return`.
3439    fn region(&mut self, region: &ir::Region) -> TokenStream {
3440        let span = self.sp(region.range);
3441        let label = self.region_label(region.label, span);
3442        let previous = self.region_kinds.insert(region.label, region.kind);
3443        let body = self.stmts(&region.body);
3444        match previous {
3445            Some(kind) => self.region_kinds.insert(region.label, kind),
3446            None => self.region_kinds.remove(&region.label),
3447        };
3448        match region.kind {
3449            ir::RegionKind::Block => quote_spanned! {span=> #label: { #body } },
3450            ir::RegionKind::Loop if region.falls_out => quote_spanned! {span=>
3451                #label: loop { #body break #label; }
3452            },
3453            ir::RegionKind::Loop => quote_spanned! {span=> #label: loop { #body } },
3454        }
3455    }
3456
3457    /// Names the regions of a structured body, after the C labels they stand
3458    /// for.
3459    ///
3460    /// A name that Rust cannot spell as a label — a keyword, or one of the
3461    /// shapes this module gives a loop or a `switch` — gets the label's number
3462    /// appended, which no generated label can collide with; one it cannot
3463    /// spell at all, such as an extended identifier, gives up its own name.
3464    /// The block and the loop a label with jumps of both kinds gets are named
3465    /// once: they never overlap, and `break` and `continue` say which is meant.
3466    fn name_regions(&mut self, stmts: &[Stmt]) {
3467        let mut taken: HashSet<String> = HashSet::new();
3468        let mut found = Vec::new();
3469        collect_regions(stmts, &mut found);
3470        for (id, name) in found {
3471            if self.region_names.contains_key(&id) {
3472                continue;
3473            }
3474            let mut candidate = rust_spelling(&name).into_owned();
3475            if !is_label_name(&candidate) {
3476                candidate = format!("{candidate}_{}", id.0);
3477            }
3478            if !is_label_name(&candidate) {
3479                candidate = format!("cinrs_label{}", id.0);
3480            }
3481            while taken.contains(&candidate) {
3482                candidate.push('_');
3483            }
3484            taken.insert(candidate.clone());
3485            self.region_names.insert(id, candidate);
3486        }
3487    }
3488
3489    /// Builds the labelled-block chain described in the [module docs](self).
3490    fn switch(&mut self, switch: &Switch) -> TokenStream {
3491        let span = self.sp(switch.range);
3492        let scrutinee_ty = switch.scrutinee.ty;
3493        let scrutinee = self.expr(&switch.scrutinee).at(prec::UNARY, span);
3494
3495        let mut arms = TokenStream::new();
3496        for (index, group) in switch.groups.iter().enumerate() {
3497            if group.values.is_empty() {
3498                continue;
3499            }
3500            let label = self.switch_case_label(switch.id, index, span);
3501            let mut pattern = TokenStream::new();
3502            for (i, value) in group.values.iter().enumerate() {
3503                if i > 0 {
3504                    pattern.extend(quote_spanned! {span=> | });
3505                }
3506                // A pattern takes its type from the scrutinee, so the bare
3507                // literal is both correct and the most readable form.
3508                pattern.extend(case_pattern(*value, scrutinee_ty, span));
3509            }
3510            arms.extend(quote_spanned! {span=> #pattern => break #label, });
3511        }
3512        let fallback = match switch.default_group {
3513            Some(index) => self.switch_case_label(switch.id, index, span),
3514            None => self.switch_label(switch.id, span),
3515        };
3516        arms.extend(quote_spanned! {span=> _ => break #fallback, });
3517
3518        // Anything before the first label can never be reached, but it is still
3519        // part of the program and may declare things later groups use.
3520        let prelude = self.stmts(&switch.prelude);
3521        let mut inner = quote_spanned! {span=> match #scrutinee { #arms } #prelude };
3522        for (index, group) in switch.groups.iter().enumerate() {
3523            let label = self.switch_case_label(switch.id, index, span);
3524            let body = self.stmts(&group.body);
3525            inner = quote_spanned! {span=> #label: { #inner } #body };
3526        }
3527
3528        let mut hoisted = TokenStream::new();
3529        for id in &switch.hoisted {
3530            let object = self.program.object(*id);
3531            let ospan = self.sp(object.range);
3532            let name = self.object_ident(*id, ospan);
3533            let ty = self.binding_ty(*id, self.ty(object.ty, ospan), ospan);
3534            let zero = self.zero_tokens(object.ty, ospan);
3535            let zero = self.binding_init(*id, zero, ospan);
3536            hoisted.extend(quote_spanned! {ospan=> let mut #name: #ty = #zero; });
3537        }
3538
3539        let label = self.switch_label(switch.id, span);
3540        // The extra block keeps the hoisted declarations from shadowing
3541        // anything the enclosing block declared under the same name.
3542        quote_spanned! {span=>
3543            {
3544                #hoisted
3545                #label: { #inner }
3546            }
3547        }
3548    }
3549
3550    /// Emits an expression evaluated for its side effects.
3551    fn expr_stmt(&mut self, expr: &Expr) -> TokenStream {
3552        let span = self.sp(expr.range);
3553        match &expr.kind {
3554            ExprKind::Assign { place, value } => {
3555                let lowered = self.place(place, true);
3556                let value = self.expr_at(value, self.program.types.unatomic(place.ty));
3557                let store = self.write(&lowered, value, span);
3558                let setup = &lowered.setup;
3559                quote_spanned! {span=> #setup #store }
3560            }
3561            ExprKind::CompoundAssign {
3562                place,
3563                op,
3564                value,
3565                compute,
3566            } => {
3567                let lowered = self.place(place, true);
3568                if lowered.atomic.is_some() {
3569                    let kind = PlaceRmw::Compound {
3570                        op: *op,
3571                        value,
3572                        compute: *compute,
3573                    };
3574                    return self.atomic_place_rmw(&lowered, kind, RmwValue::None, span);
3575                }
3576                let (hoist, rhs) = self.compound_rhs(value);
3577                let current = self.read(&lowered, span);
3578                let updated = self.compound_value(current, place.ty, *op, value, rhs, *compute);
3579                let updated = updated.at(prec::LOWEST, span);
3580                let store = self.write(&lowered, updated, span);
3581                let setup = &lowered.setup;
3582                quote_spanned! {span=> #setup #hoist #store }
3583            }
3584            ExprKind::IncDec { place, dec, .. } => {
3585                let lowered = self.place(place, true);
3586                if lowered.atomic.is_some() {
3587                    let kind = PlaceRmw::Step { dec: *dec };
3588                    return self.atomic_place_rmw(&lowered, kind, RmwValue::None, span);
3589                }
3590                let current = self.read(&lowered, span);
3591                let next = self.step_value(current, place.ty, *dec, span);
3592                let store = self.write(&lowered, next, span);
3593                let setup = &lowered.setup;
3594                quote_spanned! {span=> #setup #store }
3595            }
3596            ExprKind::Call { .. } => {
3597                // A call to a `_Noreturn` function does not come back, and
3598                // Rust has to be told: the call's own type is whatever the
3599                // function was declared to return, so a function that ends in
3600                // `exit(1);` would otherwise be missing its value. The
3601                // `unreachable!()` is a panic rather than
3602                // `unreachable_unchecked`, because it is *this crate* putting
3603                // it there.
3604                let diverges = ir::expr_never_returns(expr, &self.program.functions);
3605                let tokens = self.expr(expr).at(prec::LOWEST, span);
3606                if diverges {
3607                    quote_spanned! {span=> #tokens; ::core::unreachable!(); }
3608                } else {
3609                    quote_spanned! {span=> #tokens; }
3610                }
3611            }
3612            ExprKind::Unreachable => {
3613                quote_spanned! {span=> ::core::hint::unreachable_unchecked(); }
3614            }
3615            // A store, a `clear` and a fence have no value at all, in C or in
3616            // the Rust they become; the `let _ =` the fallback below would
3617            // wrap them in says nothing.
3618            ExprKind::Atomic(_) if expr.ty.is_void() => {
3619                let tokens = self.expr(expr).at(prec::LOWEST, span);
3620                quote_spanned! {span=> #tokens; }
3621            }
3622            ExprKind::Comma { .. } => {
3623                // A chain of comma operators is a flat sequence of statements
3624                // — and one stack frame per operand if it is walked
3625                // recursively, which a four-thousand-character logical source
3626                // line cannot afford. See [`Codegen::binary_chain`].
3627                let mut out = TokenStream::new();
3628                for operand in comma_operands(expr) {
3629                    out.extend(self.expr_stmt(operand));
3630                }
3631                out
3632            }
3633            ExprKind::Cond { .. } => {
3634                // A chain of them is `if … else if … else …`, built without
3635                // recursing down the chain; see [`Codegen::cond_chain`].
3636                let mut spine = Vec::new();
3637                let mut node = expr;
3638                while let ExprKind::Cond {
3639                    cond,
3640                    then_expr,
3641                    else_expr,
3642                } = &node.kind
3643                {
3644                    let span = self.sp(node.range);
3645                    let cond_tokens = self.condition(cond).at_condition(span);
3646                    let then_tokens = self.expr_stmt(then_expr);
3647                    spine.push((cond_tokens, then_tokens, span));
3648                    node = else_expr;
3649                }
3650                let mut tokens = self.expr_stmt(node);
3651                while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
3652                    tokens = quote_spanned! {span=>
3653                        if #cond_tokens { #then_tokens } else { #tokens }
3654                    };
3655                }
3656                tokens
3657            }
3658            // `(void)x;` evaluates and discards, which is what the fall-through
3659            // below does anyway; unwrapping keeps the output tidy.
3660            ExprKind::Cast(inner) if expr.ty.is_void() => self.expr_stmt(inner),
3661            // `va_end(ap);` is a statement that does nothing at all.
3662            ExprKind::VaEnd => TokenStream::new(),
3663            _ => {
3664                let tokens = self.expr(expr).at(prec::LOWEST, span);
3665                quote_spanned! {span=> let _ = #tokens; }
3666            }
3667        }
3668    }
3669
3670    // -- expressions --------------------------------------------------------
3671
3672    /// Emits an expression whose type the surrounding context already fixes.
3673    ///
3674    /// A constant then needs no `as`, which is the difference between
3675    /// `let mut i: c_int = 0;` and `let mut i: c_int = 0 as c_int;`. It is the
3676    /// *only* place a bare literal is emitted from, and the reason it is safe
3677    /// is that every caller writes the tokens somewhere the type is already
3678    /// stated — the annotation of a `let`, a place being assigned to, a
3679    /// parameter, a field, the return type of the function.
3680    ///
3681    /// [`Codegen::expr`] has no such promise, so nothing it produces may
3682    /// depend on inference; that is what the conditional below is about.
3683    fn expr_at(&mut self, expr: &Expr, expected: Ty) -> TokenStream {
3684        let span = self.sp(expr.range);
3685        if expr.ty == expected {
3686            match &expr.kind {
3687                ExprKind::Int(value) => return bare_int_literal(*value, expected, span),
3688                ExprKind::Float(value) if value.is_finite() => {
3689                    return bare_float_literal(*value, span);
3690                }
3691                // The arms of a conditional may stay bare here, because
3692                // whatever fixes this expression's type fixes theirs — unless
3693                // the type is `void`, where the arms have no common type and
3694                // [`Codegen::expr`] emits each of them as a statement.
3695                ExprKind::Cond { .. } if !expected.is_void() => {
3696                    return self.cond_chain_at(expr, expected);
3697                }
3698                _ => {}
3699            }
3700        }
3701        self.expr(expr).at(prec::LOWEST, span)
3702    }
3703
3704    fn expr(&mut self, expr: &Expr) -> Value {
3705        let value = self.expr_value(expr);
3706        // A chain of binary operators reduces each of its own nodes; see
3707        // `Codegen::binary_chain`.
3708        if matches!(expr.kind, ExprKind::Binary { .. }) {
3709            return value;
3710        }
3711        self.reduce_bits(value, expr)
3712    }
3713
3714    /// Reduces a computed value to the precision the expression is evaluated
3715    /// in, which is narrower than its type only for a wide bit-field; see
3716    /// [`ir::Expr::bits`].
3717    ///
3718    /// Only an operator whose result can leave the field's range needs it: a
3719    /// bitwise `&`, `|` or `^` of two forty-bit values is a forty-bit value
3720    /// already, and so is a quotient, a remainder or a right shift.
3721    fn reduce_bits(&mut self, value: Value, expr: &Expr) -> Value {
3722        let Some(bits) = expr.bits else {
3723            return value;
3724        };
3725        let width = expr.ty.bits(&self.options.target);
3726        let overflows = match &expr.kind {
3727            ExprKind::Binary { op, .. } => {
3728                matches!(op, BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Shl)
3729            }
3730            ExprKind::Neg(_) | ExprKind::BitNot(_) => true,
3731            _ => false,
3732        };
3733        if !overflows || !expr.ty.is_integer() || bits == 0 || bits >= width {
3734            return value;
3735        }
3736        let span = self.sp(expr.range);
3737        if expr.ty.is_signed(&self.options.target) {
3738            // Sign extension: the two shifts are what a narrower signed type
3739            // does to a value that has just overflowed out of it.
3740            let shift = Literal::u32_unsuffixed(width - bits);
3741            let tokens = value.at(prec::CALL, span);
3742            return Value::new(
3743                quote_spanned! {span=> #tokens.wrapping_shl(#shift).wrapping_shr(#shift) },
3744                prec::CALL,
3745            );
3746        }
3747        let mask = bare_int_literal(((1u128 << bits) - 1) as i128, expr.ty, span);
3748        let tokens = value.at(prec::BIT_AND, span);
3749        Value::new(quote_spanned! {span=> #tokens & #mask }, prec::BIT_AND)
3750    }
3751
3752    fn expr_value(&mut self, expr: &Expr) -> Value {
3753        let span = self.sp(expr.range);
3754        match &expr.kind {
3755            ExprKind::Int(value) => self.int_literal(*value, expr.ty, span),
3756            ExprKind::Float(value) => self.float_literal(*value, expr.ty, span),
3757            ExprKind::Zeroed => Value::new(self.zero_tokens(expr.ty, span), zero_prec(expr.ty)),
3758            // Reading a `va_list` copies it: Rust's is not `Copy`, and C says
3759            // a list passed on is indeterminate afterwards anyway.
3760            ExprKind::Load(place) if place.ty.is_va_list() => self.va_list_load(place, span),
3761            ExprKind::Load(place) => {
3762                let lowered = self.place(place, false);
3763                let value = self.read(&lowered, span);
3764                if lowered.setup.is_empty() {
3765                    value
3766                } else {
3767                    let setup = &lowered.setup;
3768                    let tokens = value.at(prec::LOWEST, span);
3769                    Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
3770                }
3771            }
3772            ExprKind::AddrOf(place) => self.address_of(place, expr.ty, span),
3773            ExprKind::FuncAddr(id) => {
3774                let function = self.program.function(*id);
3775                let name = self.function_path(function, span);
3776                let signature = self.function_pointer_ty(function, span);
3777                Value::new(
3778                    quote_spanned! {span=> ::core::option::Option::Some(#name as #signature) },
3779                    prec::CALL,
3780                )
3781            }
3782            // GNU's `&&label`. The value is the state number the label's block
3783            // was given, cast to the pointer type the expression has — which
3784            // is what makes `goto *` a store to the state variable, and what
3785            // lets a dispatch table be an ordinary array of `void *`.
3786            ExprKind::LabelAddr(id) => self.label_address(*id, expr.ty, span),
3787            ExprKind::Assign { .. } => self.assign_chain(expr),
3788            ExprKind::CompoundAssign {
3789                place,
3790                op,
3791                value,
3792                compute,
3793            } => {
3794                let lowered = self.place(place, true);
3795                if lowered.atomic.is_some() {
3796                    let kind = PlaceRmw::Compound {
3797                        op: *op,
3798                        value,
3799                        compute: *compute,
3800                    };
3801                    let tokens = self.atomic_place_rmw(&lowered, kind, RmwValue::New, span);
3802                    return Value::new(tokens, prec::BLOCK);
3803                }
3804                let (hoist, rhs) = self.compound_rhs(value);
3805                let current = self.read(&lowered, span);
3806                let updated = self.compound_value(current, place.ty, *op, value, rhs, *compute);
3807                let updated = updated.at(prec::LOWEST, span);
3808                let store = self.write(&lowered, updated, span);
3809                let read = self.read(&lowered, span).at(prec::LOWEST, span);
3810                let setup = &lowered.setup;
3811                Value::new(
3812                    quote_spanned! {span=> { #setup #hoist #store #read } },
3813                    prec::BLOCK,
3814                )
3815            }
3816            ExprKind::IncDec {
3817                place,
3818                dec,
3819                postfix,
3820            } => {
3821                let lowered = self.place(place, true);
3822                if lowered.atomic.is_some() {
3823                    let want = if *postfix {
3824                        RmwValue::Old
3825                    } else {
3826                        RmwValue::New
3827                    };
3828                    let tokens =
3829                        self.atomic_place_rmw(&lowered, PlaceRmw::Step { dec: *dec }, want, span);
3830                    return Value::new(tokens, prec::BLOCK);
3831                }
3832                let current = self.read(&lowered, span);
3833                let next = self.step_value(current, place.ty, *dec, span);
3834                let store = self.write(&lowered, next, span);
3835                let read = self.read(&lowered, span).at(prec::LOWEST, span);
3836                let setup = &lowered.setup;
3837                if *postfix {
3838                    let tmp = self.temporary();
3839                    Value::new(
3840                        quote_spanned! {span=>
3841                            { #setup let #tmp = #read; #store #tmp }
3842                        },
3843                        prec::BLOCK,
3844                    )
3845                } else {
3846                    Value::new(
3847                        quote_spanned! {span=> { #setup #store #read } },
3848                        prec::BLOCK,
3849                    )
3850                }
3851            }
3852            // The three complex shapes are one call apiece: this function is
3853            // the one code generation recurses through, and every local in it
3854            // costs a slice of the stack `rustc` gives macro expansion.
3855            ExprKind::ComplexOf { re, im } => self.complex_literal(expr.ty, re, im, span),
3856            ExprKind::Neg(operand) if expr.ty.is_complex() => self.complex_neg(operand, span),
3857            ExprKind::BitNot(operand) if expr.ty.is_complex() => {
3858                self.complex_conj(operand, expr.ty, span)
3859            }
3860            ExprKind::Neg(operand) => {
3861                let value = self.expr(operand);
3862                if expr.ty.is_floating() {
3863                    let ends_with_type = value.ends_with_type;
3864                    let tokens = value.at(prec::UNARY, span);
3865                    Value::new(quote_spanned! {span=> -#tokens }, prec::UNARY)
3866                        .type_end(ends_with_type)
3867                } else {
3868                    // Signed overflow is undefined in C and a panic in Rust;
3869                    // wrapping is the predictable choice, and it is what
3870                    // unsigned arithmetic requires anyway.
3871                    let tokens = value.at(prec::CALL, span);
3872                    Value::new(quote_spanned! {span=> #tokens.wrapping_neg() }, prec::CALL)
3873                }
3874            }
3875            ExprKind::BitNot(operand) => {
3876                let value = self.expr(operand);
3877                let ends_with_type = value.ends_with_type;
3878                let tokens = value.at(prec::UNARY, span);
3879                Value::new(quote_spanned! {span=> !#tokens }, prec::UNARY).type_end(ends_with_type)
3880            }
3881            ExprKind::Binary { .. } => self.binary_chain(expr),
3882            ExprKind::PtrOffset { ptr, index, sub } => {
3883                let pointee = self.program.types.pointee(ptr.ty).unwrap_or(Ty::Void);
3884                let base = self.expr(ptr).at(prec::CALL, span);
3885                let offset = self.scaled_offset(pointee, index, *sub, span);
3886                Value::new(quote_spanned! {span=> #base.offset(#offset) }, prec::CALL)
3887            }
3888            // GNU's label difference, `&&a - &&b`. Both operands are state
3889            // numbers rather than addresses, so the subtraction is done on the
3890            // numbers: `offset_from` would want two pointers into one object,
3891            // and a `static` table of such differences — which is the whole
3892            // idiom — needs an expression a `const` can fold.
3893            ExprKind::PtrDiff { lhs, rhs }
3894                if label_state(lhs).is_some() && label_state(rhs).is_some() =>
3895            {
3896                self.label_difference(lhs, rhs, expr.ty, span)
3897            }
3898            ExprKind::PtrDiff { lhs, rhs } => {
3899                let pointee = self.program.types.pointee(lhs.ty).unwrap_or(Ty::Void);
3900                let scale = self.vm_scale(pointee, span);
3901                let left = self.expr(lhs).at(prec::CALL, span);
3902                let right = self.expr(rhs).at(prec::LOWEST, span);
3903                let target = self.ty(expr.ty, span);
3904                // The difference the generated pointers give is in step-type
3905                // elements; C's is in whole ones.
3906                let difference = match scale {
3907                    None => quote_spanned! {span=> #left.offset_from(#right) },
3908                    Some(scale) => {
3909                        quote_spanned! {span=> (#left.offset_from(#right) / (#scale)) }
3910                    }
3911                };
3912                Value::new(quote_spanned! {span=> #difference as #target }, prec::CAST)
3913                    .type_end(true)
3914            }
3915            ExprKind::Compare { .. } | ExprKind::Logical { .. } => {
3916                // C's comparisons and logical operators produce an `int`.
3917                let condition = self.condition(expr).at(prec::LOWEST, span);
3918                let ty = self.ty(Ty::Int, span);
3919                let parens = parenthesize(condition, span);
3920                Value::new(quote_spanned! {span=> #parens as #ty }, prec::CAST).type_end(true)
3921            }
3922            // `(void)x` and a `void`-typed conditional have no value at all:
3923            // Rust's `()` is not something `as` produces, so each of them is
3924            // emitted as the statement it is, wrapped in a block whose own
3925            // value is `()`. A conditional gets here when it is written where
3926            // a value is expected — the left operand of a comma is a
3927            // statement, but the right one is not.
3928            ExprKind::Cast(inner) if expr.ty.is_void() => {
3929                let tokens = self.expr_stmt(inner);
3930                Value::new(quote_spanned! {span=> { #tokens } }, prec::BLOCK)
3931            }
3932            ExprKind::Cond { .. } if expr.ty.is_void() => {
3933                let tokens = self.expr_stmt(expr);
3934                Value::new(quote_spanned! {span=> { #tokens } }, prec::BLOCK)
3935            }
3936            ExprKind::Cast(inner) => {
3937                let from = inner.ty;
3938                let value = self.expr(inner);
3939                self.cast(value, from, expr.ty, span)
3940            }
3941            // Both arms are emitted as expressions of their own rather than at
3942            // the conditional's type: an `if` whose arms are two bare literals
3943            // is `{integer}`, which Rust either resolves to `i32` — wrong
3944            // wherever C said `long` — or refuses to resolve at all, as it
3945            // does for the receiver of `wrapping_mul` (`E0689`). The bare form
3946            // is still used from [`Codegen::expr_at`], where the context says
3947            // what the type is.
3948            ExprKind::Cond { .. } => self.cond_chain(expr),
3949            ExprKind::Comma { lhs, rhs } => {
3950                let lhs = self.expr_stmt(lhs);
3951                let rhs = self.expr(rhs).at(prec::LOWEST, span);
3952                Value::new(quote_spanned! {span=> { #lhs #rhs } }, prec::BLOCK)
3953            }
3954            ExprKind::Call { callee, args } => self.call(callee, args, span),
3955            ExprKind::RecordLit { record, fields } => self.record_literal(*record, fields, span),
3956            ExprKind::UnionLit {
3957                record,
3958                index,
3959                value,
3960            } => self.union_literal(*record, *index, value, span),
3961            ExprKind::ArrayLit(items) => {
3962                let elem = self.program.types.elem(expr.ty).unwrap_or(Ty::Int);
3963                let mut tokens = TokenStream::new();
3964                for (index, item) in items.iter().enumerate() {
3965                    if index > 0 {
3966                        tokens.extend(quote_spanned! {span=> , });
3967                    }
3968                    tokens.extend(self.expr_at(item, elem));
3969                }
3970                Value::atom(bracketed(tokens, span))
3971            }
3972            ExprKind::ArrayRepeat { value, len } => {
3973                let elem = self.program.types.elem(expr.ty).unwrap_or(value.ty);
3974                let tokens = self.expr_at(value, elem);
3975                let len = usize_literal(*len, span);
3976                Value::atom(bracketed(quote_spanned! {span=> #tokens ; #len }, span))
3977            }
3978            // GNU's `a ?: b`. The value is held in a temporary so that the
3979            // operand is evaluated exactly once, which is the whole point.
3980            ExprKind::CondDefault { value, else_expr } => {
3981                let ty = expr.ty;
3982                let first = self.expr_at(value, ty);
3983                let other = self.expr_at(else_expr, ty);
3984                let tmp = self.temporary();
3985                let target = self.ty(ty, span);
3986                let test = if ty.is_pointer() {
3987                    quote_spanned! {span=> !#tmp.is_null() }
3988                } else {
3989                    let zero = self.zero_tokens(ty, span);
3990                    quote_spanned! {span=> #tmp != #zero }
3991                };
3992                Value::new(
3993                    quote_spanned! {span=>
3994                        { let #tmp: #target = #first; if #test { #tmp } else { #other } }
3995                    },
3996                    prec::BLOCK,
3997                )
3998            }
3999            // GNU's statement expression, which is what a Rust block is.
4000            ExprKind::StmtExpr { stmts, value } => {
4001                let body = self.stmts(stmts);
4002                let tail = match value {
4003                    Some(value) => {
4004                        let ty = expr.ty;
4005                        self.expr_at(value, ty)
4006                    }
4007                    None => TokenStream::new(),
4008                };
4009                Value::new(quote_spanned! {span=> { #body #tail } }, prec::BLOCK)
4010            }
4011            ExprKind::Builtin { op, args } => self.builtin(*op, args, span),
4012            ExprKind::Atomic(atomic) => self.atomic(atomic, span),
4013            ExprKind::VaListPristine => Value::new(self.va_pristine(span), prec::CALL),
4014            ExprKind::VaArg { ap, record } => self.va_arg(ap, record.as_deref(), expr.ty, span),
4015            // `va_end` is nothing: the list ends when its value is dropped.
4016            ExprKind::VaEnd => Value::atom(quote_spanned! {span=> () }),
4017            // C23's `unreachable()`. C says reaching it is undefined, and
4018            // saying so to Rust is what lets the optimiser use the promise —
4019            // this is the one place the expansion trusts the C program with
4020            // undefined behaviour, because the program asked for it by name.
4021            ExprKind::Unreachable => Value::new(
4022                quote_spanned! {span=> ::core::hint::unreachable_unchecked() },
4023                prec::CALL,
4024            ),
4025        }
4026    }
4027
4028    // -- complex ------------------------------------------------------------
4029
4030    /// `::cinrs::rt::Complex::<f64>::new(re, im)`.
4031    ///
4032    /// A call rather than a struct literal, and with the component type spelled
4033    /// out: `Complex { … }` at the start of an `if` condition would be read as
4034    /// the condition's block, and a bare `0.0` part would infer `f64` where the
4035    /// type is `float _Complex`. `Complex::new` is a `const fn`, so this is
4036    /// also what a `static` initialiser holds.
4037    fn complex_new(&self, ty: Ty, re: TokenStream, im: TokenStream, span: Span) -> Value {
4038        self.uses_complex.set(true);
4039        let rt = self.rt_path(span);
4040        let component = primitive_ty(if ty == Ty::ComplexFloat { "f32" } else { "f64" }, span);
4041        Value::new(
4042            quote_spanned! {span=> #rt::Complex::<#component>::new(#re, #im) },
4043            prec::CALL,
4044        )
4045    }
4046
4047    /// `__builtin_complex(re, im)`, an imaginary constant, and a folded
4048    /// complex constant: the two parts, side by side.
4049    fn complex_literal(&mut self, ty: Ty, re: &Expr, im: &Expr, span: Span) -> Value {
4050        let re = self.expr(re).at(prec::LOWEST, span);
4051        let im = self.expr(im).at(prec::LOWEST, span);
4052        self.complex_new(ty, re, im, span)
4053    }
4054
4055    /// `-z`, which is `num_complex`'s own `Neg` — both parts negated exactly.
4056    fn complex_neg(&mut self, operand: &Expr, span: Span) -> Value {
4057        let tokens = self.expr(operand).at(prec::UNARY, span);
4058        Value::new(quote_spanned! {span=> -#tokens }, prec::UNARY)
4059    }
4060
4061    /// GNU's `~z` and `__builtin_conj(z)`: the conjugate.
4062    fn complex_conj(&mut self, operand: &Expr, ty: Ty, span: Span) -> Value {
4063        let tokens = self.expr(operand).at(prec::LOWEST, span);
4064        let conj = self.rt_complex(&format!("conj_{}", Self::complex_suffix(ty)), span);
4065        Value::new(quote_spanned! {span=> #conj(#tokens) }, prec::CALL)
4066    }
4067
4068    /// `+`, `-`, `*` or `/` with at least one complex operand.
4069    ///
4070    /// Each operand arrives with the C type its tokens have, because that is
4071    /// what decides which runtime function is called: C computes a *real*
4072    /// operand componentwise rather than widening it — see `cinrs_rt::complex`
4073    /// for what that changes and why. Two complex operands add and subtract
4074    /// through `num_complex`'s own operators, which are exactly componentwise,
4075    /// and multiply and divide through Annex G.
4076    fn complex_binary(
4077        &mut self,
4078        op: BinOp,
4079        (lhs, lhs_ty): (Value, Ty),
4080        (rhs, rhs_ty): (Value, Ty),
4081        ty: Ty,
4082        span: Span,
4083    ) -> Value {
4084        self.uses_complex.set(true);
4085        let suffix = Self::complex_suffix(ty);
4086        let both = lhs_ty.is_complex() && rhs_ty.is_complex();
4087        if both && matches!(op, BinOp::Add | BinOp::Sub) {
4088            let (level, tokens) = match op {
4089                BinOp::Add => (prec::SUM, quote_spanned! {span=> + }),
4090                _ => (prec::SUM, quote_spanned! {span=> - }),
4091            };
4092            let mut out = lhs.at(level, span);
4093            let rhs = rhs.at(level + 1, span);
4094            out.extend(quote_spanned! {span=> #tokens #rhs });
4095            return Value::new(out, level);
4096        }
4097        // `<what>_<suffix>`, with the name saying which operand is the real
4098        // one: `mul_real` is `z * x` and `real_mul` is `x * z`.
4099        let name = match (op, lhs_ty.is_complex(), rhs_ty.is_complex()) {
4100            (BinOp::Add, true, false) => "add_real",
4101            (BinOp::Add, false, true) => "real_add",
4102            (BinOp::Sub, true, false) => "sub_real",
4103            (BinOp::Sub, false, true) => "real_sub",
4104            (BinOp::Mul, true, true) => "mul",
4105            (BinOp::Mul, true, false) => "mul_real",
4106            (BinOp::Mul, false, true) => "real_mul",
4107            (BinOp::Div, true, true) => "div",
4108            (BinOp::Div, true, false) => "div_real",
4109            (BinOp::Div, false, true) => "real_div",
4110            // Sema refuses every other operator on a complex operand, and one
4111            // of the two always is complex.
4112            _ => unreachable!("'{}' does not reach complex code generation", op.as_str()),
4113        };
4114        let func = self.rt_complex(&format!("{name}_{suffix}"), span);
4115        let lhs = lhs.at(prec::LOWEST, span);
4116        let rhs = rhs.at(prec::LOWEST, span);
4117        Value::new(quote_spanned! {span=> #func(#lhs, #rhs) }, prec::CALL)
4118    }
4119
4120    /// A conversion with a complex type on one side or the other
4121    /// (C99 6.3.1.6, 6.3.1.7).
4122    fn complex_cast(&mut self, value: Value, from: Ty, to: Ty, span: Span) -> Value {
4123        self.uses_complex.set(true);
4124        if from.is_complex() && to.is_complex() {
4125            let name = if to == Ty::ComplexDouble {
4126                "widen_f32"
4127            } else {
4128                "narrow_f64"
4129            };
4130            let func = self.rt_complex(name, span);
4131            let tokens = value.at(prec::LOWEST, span);
4132            return Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL);
4133        }
4134        if to.is_complex() {
4135            // A real value becomes a complex one with a zero imaginary part.
4136            let component = to.complex_component();
4137            let re = self
4138                .cast(value, from, component, span)
4139                .at(prec::LOWEST, span);
4140            let zero = bare_float_literal(0.0, span);
4141            return self.complex_new(to, re, zero, span);
4142        }
4143        // Converting a complex value to a real type discards the imaginary
4144        // part — except for `_Bool`, which asks whether *either* part is
4145        // non-zero (C99 6.3.1.2).
4146        if to.is_bool() {
4147            let func = self.rt_complex(&format!("nonzero_{}", Self::complex_suffix(from)), span);
4148            let tokens = value.at(prec::LOWEST, span);
4149            return Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL);
4150        }
4151        let tokens = value.at(prec::CALL, span);
4152        let real = Value::new(quote_spanned! {span=> #tokens.re }, prec::CALL);
4153        self.cast(real, from.complex_component(), to, span)
4154    }
4155
4156    /// `z == w` and `z != w` (C99 6.5.9p3: equal exactly when both parts are).
4157    ///
4158    /// Rust's own `==` would give the same answer — the runtime's complex type
4159    /// derives `PartialEq` — and it is *not* used, because `PartialEq::eq`
4160    /// takes `&self`: a reference to a field of a `#[repr(packed)]` record is
4161    /// `E0793`, and a packed `__complex__ float` member compared against a
4162    /// constant is exactly `gcc.c-torture/execute/20020227-1`. The runtime's
4163    /// by-value equality asks for a *copy* of each operand, which a packed
4164    /// field will give.
4165    ///
4166    /// Sema converts both operands to one complex type before this, so a
4167    /// mixed real/complex comparison never arrives here.
4168    fn complex_equality(&mut self, op: CmpOp, lhs: &Expr, rhs: &Expr, span: Span) -> Value {
4169        self.uses_complex.set(true);
4170        let name = match op {
4171            CmpOp::Eq => "eq",
4172            CmpOp::Ne => "ne",
4173            // 6.5.8p2 gives the relational operators real operands only, and
4174            // sema has already said so.
4175            other => unreachable!("{other:?} does not reach a complex comparison"),
4176        };
4177        let func = self.rt_complex(&format!("{name}_{}", Self::complex_suffix(lhs.ty)), span);
4178        let (lhs, rhs) = self.operands(lhs, rhs, BinOp::BitOr);
4179        let lhs = lhs.at(prec::LOWEST, span);
4180        let rhs = rhs.at(prec::LOWEST, span);
4181        Value::new(quote_spanned! {span=> #func(#lhs, #rhs) }, prec::CALL)
4182    }
4183
4184    /// `z != 0` as Rust's `bool`: what an `if`, a `while` and `!z` ask of a
4185    /// complex value.
4186    fn complex_condition(&mut self, expr: &Expr, span: Span) -> Value {
4187        self.uses_complex.set(true);
4188        let func = self.rt_complex(&format!("nonzero_{}", Self::complex_suffix(expr.ty)), span);
4189        let tokens = self.expr(expr).at(prec::LOWEST, span);
4190        Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL)
4191    }
4192
4193    /// A `struct` value: one expression per member, in declaration order.
4194    ///
4195    /// Without bit-fields this is a plain Rust struct literal. With them the
4196    /// members that share a storage field have to be *packed* into it: every
4197    /// constant one is folded into the `[u8; K]` there and then, which is what
4198    /// lets a `static` — where nothing may run — hold a bit-field at all, and
4199    /// what makes the byte pattern visible in the expansion. A member whose
4200    /// value is not constant is stored afterwards through its setter, so the
4201    /// literal becomes a block.
4202    fn record_literal(&mut self, record: ir::RecordId, fields: &[Expr], span: Span) -> Value {
4203        let def = self.program.types.record(record).clone();
4204        // An initialised flexible array member makes the value the *companion*
4205        // type's rather than the record's: the tail is as long as the
4206        // initialiser, and the member's value carries that length.
4207        let tail = def
4208            .fields
4209            .iter()
4210            .position(|field| field.flexible)
4211            .and_then(|index| {
4212                Some((
4213                    index,
4214                    array_len(&self.program.types, fields.get(index)?.ty)?,
4215                ))
4216            })
4217            .filter(|(_, len)| *len > 0);
4218        let name = match tail {
4219            Some((_, len)) => self.flexible_ident(&def.rust_name, len, span),
4220            None => self.c_ident(&def.rust_name, span),
4221        };
4222        let mut packed: HashMap<String, Vec<u8>> = HashMap::new();
4223        let mut dynamic: Vec<usize> = Vec::new();
4224        for rust_field in &def.rust_fields {
4225            if let ir::RustField::Bits { name, bytes, .. } = rust_field {
4226                packed.insert(name.clone(), vec![0u8; *bytes as usize]);
4227            }
4228        }
4229        for (index, field) in def.fields.iter().enumerate() {
4230            let Some(bits) = &field.bits else { continue };
4231            match fields.get(index).and_then(constant_bits) {
4232                Some(value) => {
4233                    if let Some(storage) = packed.get_mut(&bits.storage) {
4234                        pack_bits(storage, bits, value);
4235                    }
4236                }
4237                None => dynamic.push(index),
4238            }
4239        }
4240
4241        let mut items = TokenStream::new();
4242        for rust_field in &def.rust_fields {
4243            match rust_field {
4244                ir::RustField::Member(index) => {
4245                    let field = &def.fields[*index];
4246                    let fname = self.c_ident(&field.name, span);
4247                    // The flexible member's value is longer than its own type,
4248                    // and the companion's field is what it fills.
4249                    let value = &fields[*index];
4250                    let want = match tail {
4251                        Some((flexible, _)) if flexible == *index => value.ty,
4252                        _ => field.ty,
4253                    };
4254                    let tokens = self.expr_at(value, want);
4255                    items.extend(quote_spanned! {span=> #fname: #tokens, });
4256                }
4257                ir::RustField::Bits { name, .. } => {
4258                    let fname = Ident::new(name, span);
4259                    let value = byte_array(&packed[name], span);
4260                    items.extend(quote_spanned! {span=> #fname: #value, });
4261                }
4262                ir::RustField::Pad { name, bytes } => {
4263                    let fname = Ident::new(name, span);
4264                    let len = usize_literal(*bytes, span);
4265                    items.extend(quote_spanned! {span=> #fname: [0; #len], });
4266                }
4267                ir::RustField::Align { name, .. } => {
4268                    let fname = Ident::new(name, span);
4269                    items.extend(quote_spanned! {span=> #fname: [], });
4270                }
4271            }
4272        }
4273        let body = braced(items, span);
4274        let literal = quote_spanned! {span=> #name #body };
4275        if dynamic.is_empty() {
4276            return Value::new(literal, prec::ATOM);
4277        }
4278        // The members that are not constants are stored through their setters,
4279        // in declaration order, which is one of the orders C allows.
4280        let tmp = self.temporary();
4281        let ty = self.ty(Ty::Record(record), span);
4282        let mut stores = TokenStream::new();
4283        for index in dynamic {
4284            let field = &def.fields[index];
4285            let bits = field.bits.as_ref().expect("only bit-fields are deferred");
4286            let setter = self.c_ident(&bits.setter, span);
4287            let value = self.expr_at(&fields[index], field.ty);
4288            stores.extend(quote_spanned! {span=> #tmp.#setter(#value); });
4289        }
4290        Value::new(
4291            quote_spanned! {span=>
4292                { let mut #tmp: #ty = #literal; #stores #tmp }
4293            },
4294            prec::BLOCK,
4295        )
4296    }
4297
4298    /// A `union` value, which initialises exactly one member.
4299    fn union_literal(
4300        &mut self,
4301        record: ir::RecordId,
4302        index: usize,
4303        value: &Expr,
4304        span: Span,
4305    ) -> Value {
4306        let def = self.program.types.record(record).clone();
4307        let name = self.c_ident(&def.rust_name, span);
4308        let field = &def.fields[index];
4309        let Some(bits) = &field.bits else {
4310            let fname = self.c_ident(&field.name, span);
4311            let tokens = self.expr_at(value, field.ty);
4312            let body = braced(quote_spanned! {span=> #fname: #tokens }, span);
4313            return Value::new(quote_spanned! {span=> #name #body }, prec::ATOM);
4314        };
4315        let bytes = def
4316            .rust_fields
4317            .iter()
4318            .find_map(|rust_field| match rust_field {
4319                ir::RustField::Bits { name, bytes, .. } if *name == bits.storage => Some(*bytes),
4320                _ => None,
4321            })
4322            .unwrap_or(0);
4323        let mut packed = vec![0u8; bytes as usize];
4324        let constant = constant_bits(value);
4325        if let Some(constant) = constant {
4326            pack_bits(&mut packed, bits, constant);
4327        }
4328        let storage = Ident::new(&bits.storage, span);
4329        let array = byte_array(&packed, span);
4330        let body = braced(quote_spanned! {span=> #storage: #array }, span);
4331        let literal = quote_spanned! {span=> #name #body };
4332        if constant.is_some() {
4333            return Value::new(literal, prec::ATOM);
4334        }
4335        let tmp = self.temporary();
4336        let ty = self.ty(Ty::Record(record), span);
4337        let setter = self.c_ident(&bits.setter, span);
4338        let value = self.expr_at(value, field.ty);
4339        Value::new(
4340            quote_spanned! {span=>
4341                { let mut #tmp: #ty = #literal; #tmp.#setter(#value); #tmp }
4342            },
4343            prec::BLOCK,
4344        )
4345    }
4346
4347    /// One of the builtins that becomes a fixed piece of Rust.
4348    ///
4349    /// The bit-manipulation ones are the integer methods of the same name, on
4350    /// the *unsigned* type of the operand's width — C's are defined on
4351    /// unsigned values and Rust's `leading_zeros` counts the same way. The
4352    /// overflow ones do the arithmetic in `i128` and ask whether the value
4353    /// survives the round trip through the type it is stored in, which is
4354    /// exactly "compute in infinite precision, then convert".
4355    fn builtin(&mut self, op: ir::BuiltinOp, args: &[Expr], span: Span) -> Value {
4356        use ir::BuiltinOp;
4357        let int = self.ty(Ty::Int, span);
4358        match op {
4359            BuiltinOp::ComplexProj => {
4360                let ty = args[0].ty;
4361                let func = self.rt_complex(&format!("proj_{}", Self::complex_suffix(ty)), span);
4362                let value = self.expr(&args[0]).at(prec::LOWEST, span);
4363                Value::new(quote_spanned! {span=> #func(#value) }, prec::CALL)
4364            }
4365            BuiltinOp::Discard => {
4366                let mut out = TokenStream::new();
4367                for arg in args {
4368                    out.extend(self.expr_stmt(arg));
4369                }
4370                Value::new(quote_spanned! {span=> { #out } }, prec::BLOCK)
4371            }
4372            // One block of the function's arena per call, rounded up to a
4373            // whole number of `u128`s so that the pointer is 16-byte aligned.
4374            // The pointer is taken before the block is put away, since moving
4375            // a `Vec` does not move the memory it owns.
4376            BuiltinOp::Alloca => {
4377                let arena = self.alloca_ident();
4378                let size = self.expr(&args[0]).at(prec::CAST, span);
4379                let block = self.temporary();
4380                let pointer = self.temporary();
4381                let void = self.pointee_ty(Ty::Void, span);
4382                let usize_ty = primitive_ty("usize", span);
4383                let elements = self.vec_of(
4384                    quote_spanned! {span=> 0u128 },
4385                    quote_spanned! {span=> (#size as #usize_ty).div_ceil(16) },
4386                    span,
4387                );
4388                Value::new(
4389                    quote_spanned! {span=>
4390                        {
4391                            let mut #block = #elements;
4392                            let #pointer = #block.as_mut_ptr().cast::<#void>();
4393                            #arena.push(#block);
4394                            #pointer
4395                        }
4396                    },
4397                    prec::BLOCK,
4398                )
4399            }
4400            BuiltinOp::Bswap => {
4401                let operand = args[0].ty;
4402                let value = self.unsigned_operand(&args[0], span);
4403                let target = self.ty(operand, span);
4404                Value::new(
4405                    quote_spanned! {span=> #value.swap_bytes() as #target },
4406                    prec::CAST,
4407                )
4408                .type_end(true)
4409            }
4410            BuiltinOp::Popcount => {
4411                let value = self.unsigned_operand(&args[0], span);
4412                Value::new(
4413                    quote_spanned! {span=> #value.count_ones() as #int },
4414                    prec::CAST,
4415                )
4416                .type_end(true)
4417            }
4418            BuiltinOp::Parity => {
4419                let value = self.unsigned_operand(&args[0], span);
4420                Value::new(
4421                    quote_spanned! {span=> (#value.count_ones() & 1) as #int },
4422                    prec::CAST,
4423                )
4424                .type_end(true)
4425            }
4426            BuiltinOp::Clz => {
4427                let value = self.unsigned_operand(&args[0], span);
4428                Value::new(
4429                    quote_spanned! {span=> #value.leading_zeros() as #int },
4430                    prec::CAST,
4431                )
4432                .type_end(true)
4433            }
4434            BuiltinOp::Ctz => {
4435                let value = self.unsigned_operand(&args[0], span);
4436                Value::new(
4437                    quote_spanned! {span=> #value.trailing_zeros() as #int },
4438                    prec::CAST,
4439                )
4440                .type_end(true)
4441            }
4442            BuiltinOp::Ffs => {
4443                let value = self.unsigned_operand(&args[0], span);
4444                let tmp = self.temporary();
4445                Value::new(
4446                    quote_spanned! {span=>
4447                        { let #tmp = #value;
4448                          if #tmp == 0 { 0 } else { #tmp.trailing_zeros() as #int + 1 } }
4449                    },
4450                    prec::BLOCK,
4451                )
4452            }
4453            // The number of leading bits that repeat the sign bit, not
4454            // counting the sign bit itself — which is what `leading_zeros` of
4455            // the value XORed with itself shifted left gives.
4456            BuiltinOp::Clrsb => {
4457                let width = args[0].ty.bits(&self.options.target);
4458                let signed = signed_rust_ty(width, span);
4459                let value = self.expr(&args[0]).at(prec::CAST, span);
4460                let tmp = self.temporary();
4461                let bits = usize_literal(u64::from(width), span);
4462                Value::new(
4463                    quote_spanned! {span=>
4464                        { let #tmp = #value as #signed;
4465                          ((#tmp ^ (#tmp << 1)).leading_zeros() as #int)
4466                              .min(#bits as #int - 1) }
4467                    },
4468                    prec::BLOCK,
4469                )
4470            }
4471            BuiltinOp::Overflow(bin) | BuiltinOp::OverflowP(bin) => {
4472                let store = matches!(op, BuiltinOp::Overflow(_));
4473                // The third operand carries the result type: the pointee of
4474                // the pointer the value is stored through, or the type of the
4475                // expression the `_p` forms only ask about.
4476                let result_ty = if store {
4477                    self.program.types.pointee(args[2].ty).unwrap_or(Ty::Int)
4478                } else {
4479                    args[2].ty
4480                };
4481                self.overflow_builtin(bin, args, store, result_ty, span)
4482            }
4483            BuiltinOp::Fabs => {
4484                let bits = self.float_bits_of(&args[0], span);
4485                let (float_ty, mask) = float_bit_ty(args[0].ty, span);
4486                Value::new(
4487                    quote_spanned! {span=> <#float_ty>::from_bits(#bits & #mask) },
4488                    prec::CALL,
4489                )
4490            }
4491            BuiltinOp::Copysign => {
4492                let magnitude = self.float_bits_of(&args[0], span);
4493                let sign = self.float_bits_of(&args[1], span);
4494                let (float_ty, mask) = float_bit_ty(args[0].ty, span);
4495                Value::new(
4496                    quote_spanned! {span=>
4497                        <#float_ty>::from_bits((#magnitude & #mask) | (#sign & !#mask))
4498                    },
4499                    prec::CALL,
4500                )
4501            }
4502            BuiltinOp::FloatOrder(order) => self.float_order(order, args, span),
4503            BuiltinOp::FloatClass(class) => self.float_class(class, &args[0], span),
4504            BuiltinOp::Fpclassify => {
4505                let value = self.expr(&args[5]).at(prec::CALL, span);
4506                let arms = ["Nan", "Infinite", "Normal", "Subnormal", "Zero"]
4507                    .iter()
4508                    .zip(args)
4509                    .map(|(name, answer)| {
4510                        let variant = Ident::new(name, span);
4511                        let answer = self.expr_at(answer, Ty::Int);
4512                        quote_spanned! {span=>
4513                            ::core::num::FpCategory::#variant => #answer,
4514                        }
4515                    })
4516                    .collect::<TokenStream>();
4517                Value::new(
4518                    quote_spanned! {span=> match #value.classify() { #arms } },
4519                    prec::BLOCK,
4520                )
4521            }
4522        }
4523    }
4524
4525    /// A floating operand as the unsigned integer of its own width.
4526    fn float_bits_of(&mut self, arg: &Expr, span: Span) -> TokenStream {
4527        let value = self.expr(arg).at(prec::CALL, span);
4528        parenthesize(quote_spanned! {span=> #value.to_bits() }, span)
4529    }
4530
4531    /// `__builtin_isgreater` and its relatives.
4532    ///
4533    /// Rust's floating comparisons are the quiet ones, which is exactly what
4534    /// C99 7.12.14 asks these for; the operands go into temporaries because
4535    /// two of the six mention each of them twice.
4536    fn float_order(&mut self, order: ir::FloatOrder, args: &[Expr], span: Span) -> Value {
4537        use ir::FloatOrder;
4538        let int = self.ty(Ty::Int, span);
4539        let lhs = self.expr(&args[0]).at(prec::LOWEST, span);
4540        let rhs = self.expr(&args[1]).at(prec::LOWEST, span);
4541        let (a, b) = (self.temporary(), self.temporary());
4542        let test = match order {
4543            FloatOrder::Greater => quote_spanned! {span=> #a > #b },
4544            FloatOrder::GreaterEqual => quote_spanned! {span=> #a >= #b },
4545            FloatOrder::Less => quote_spanned! {span=> #a < #b },
4546            FloatOrder::LessEqual => quote_spanned! {span=> #a <= #b },
4547            FloatOrder::LessGreater => quote_spanned! {span=> #a < #b || #a > #b },
4548            FloatOrder::Unordered => quote_spanned! {span=> #a.is_nan() || #b.is_nan() },
4549        };
4550        Value::new(
4551            quote_spanned! {span=>
4552                { let #a = #lhs; let #b = #rhs; (#test) as #int }
4553            },
4554            prec::BLOCK,
4555        )
4556    }
4557
4558    /// `__builtin_isnan` and its relatives.
4559    ///
4560    /// The predicates are `core`'s own, which are pure inspections of the bit
4561    /// pattern and so need nothing of the maths library; `issignaling` is the
4562    /// one that has no method, and is a NaN whose leading mantissa bit — the
4563    /// quiet bit — is clear.
4564    fn float_class(&mut self, class: ir::FloatClass, arg: &Expr, span: Span) -> Value {
4565        use ir::FloatClass;
4566        let int = self.ty(Ty::Int, span);
4567        let method = |name: &str| Ident::new(name, span);
4568        let test = match class {
4569            FloatClass::IsNan => Some(method("is_nan")),
4570            FloatClass::IsInf => Some(method("is_infinite")),
4571            FloatClass::IsFinite => Some(method("is_finite")),
4572            FloatClass::IsNormal => Some(method("is_normal")),
4573            FloatClass::SignBit => Some(method("is_sign_negative")),
4574            FloatClass::IsInfSign | FloatClass::IsSignaling => None,
4575        };
4576        if let Some(test) = test {
4577            let value = self.expr(arg).at(prec::CALL, span);
4578            return Value::new(quote_spanned! {span=> #value.#test() as #int }, prec::CAST)
4579                .type_end(true);
4580        }
4581        let tmp = self.temporary();
4582        let value = self.expr(arg).at(prec::LOWEST, span);
4583        if class == FloatClass::IsInfSign {
4584            return Value::new(
4585                quote_spanned! {span=>
4586                    { let #tmp = #value;
4587                      if #tmp.is_infinite() {
4588                          if #tmp.is_sign_negative() { -1 as #int } else { 1 as #int }
4589                      } else { 0 as #int } }
4590                },
4591                prec::BLOCK,
4592            );
4593        }
4594        // A signalling NaN is a NaN with the quiet bit clear: bit 51 of a
4595        // `double` and bit 22 of a `float`.
4596        let quiet = quiet_bit_literal(arg.ty, span);
4597        Value::new(
4598            quote_spanned! {span=>
4599                { let #tmp = #value;
4600                  (#tmp.is_nan() && (#tmp.to_bits() & #quiet) == 0) as #int }
4601            },
4602            prec::BLOCK,
4603        )
4604    }
4605
4606    // -- atomics ------------------------------------------------------------
4607
4608    /// `::core::sync::atomic::AtomicU32`, or `AtomicPtr<c_void>`.
4609    fn atomic_path(&self, class: AtomicClass, span: Span) -> TokenStream {
4610        if class == AtomicClass::Ptr {
4611            let void = self.pointee_ty(Ty::Void, span);
4612            return quote_spanned! {span=>
4613                ::core::sync::atomic::AtomicPtr::<#void>
4614            };
4615        }
4616        let name = Ident::new(class.rust_name(), span);
4617        quote_spanned! {span=> ::core::sync::atomic::#name }
4618    }
4619
4620    /// The Rust type the atomic holds, which is what its `from_ptr` points at.
4621    ///
4622    /// Every pointer goes through one `AtomicPtr<c_void>`: all object pointers
4623    /// have the same representation, and the value is cast back to the C type
4624    /// it came from as it comes out.
4625    fn atomic_repr_ty(&self, class: AtomicClass, span: Span) -> TokenStream {
4626        if class == AtomicClass::Ptr {
4627            let void = self.pointee_ty(Ty::Void, span);
4628            return quote_spanned! {span=> *mut #void };
4629        }
4630        primitive_ty(class.repr_name(), span)
4631    }
4632
4633    /// `AtomicU32::from_ptr(p as *mut u32)`, the `&AtomicU32` everything else
4634    /// is a method call on.
4635    ///
4636    /// `from_ptr` is safe to build here for the reason C gives: the object is
4637    /// properly aligned for its own type, and the atomic's alignment is that
4638    /// type's size, which is what [`ir::Types::size_align`] gives an
4639    /// `_Atomic` and what sema checks before it accepts a pointer to a plain
4640    /// one.
4641    fn atomic_ref(&self, class: AtomicClass, ptr: TokenStream, span: Span) -> TokenStream {
4642        let path = self.atomic_path(class, span);
4643        let repr = self.atomic_repr_ty(class, span);
4644        quote_spanned! {span=> #path::from_ptr(#ptr as *mut #repr) }
4645    }
4646
4647    /// `::core::sync::atomic::Ordering::SeqCst`.
4648    fn ordering(&self, order: ir::MemOrder, span: Span) -> TokenStream {
4649        let name = Ident::new(order.rust_name(), span);
4650        quote_spanned! {span=> ::core::sync::atomic::Ordering::#name }
4651    }
4652
4653    /// The value an atomic yields, as the C type the object has.
4654    fn repr_to_value(&self, class: AtomicClass, ty: Ty, value: TokenStream, span: Span) -> Value {
4655        match class {
4656            AtomicClass::Bool => Value::atom(value),
4657            AtomicClass::Float { bytes } => {
4658                let float = primitive_ty(if bytes == 4 { "f32" } else { "f64" }, span);
4659                Value::new(
4660                    quote_spanned! {span=> <#float>::from_bits(#value) },
4661                    prec::CALL,
4662                )
4663            }
4664            AtomicClass::Int { .. } | AtomicClass::Ptr => {
4665                let target = self.ty(ty, span);
4666                Value::new(quote_spanned! {span=> #value as #target }, prec::CAST).type_end(true)
4667            }
4668        }
4669    }
4670
4671    /// A C value, as the Rust primitive the atomic holds.
4672    fn value_to_repr(&self, class: AtomicClass, value: Value, span: Span) -> TokenStream {
4673        match class {
4674            AtomicClass::Bool => value.at(prec::LOWEST, span),
4675            AtomicClass::Float { bytes } => {
4676                let float = primitive_ty(if bytes == 4 { "f32" } else { "f64" }, span);
4677                let value = value.at(prec::LOWEST, span);
4678                quote_spanned! {span=> <#float>::to_bits(#value) }
4679            }
4680            AtomicClass::Int { .. } | AtomicClass::Ptr => {
4681                let repr = self.atomic_repr_ty(class, span);
4682                let value = value.at(prec::CAST, span);
4683                quote_spanned! {span=> #value as #repr }
4684            }
4685        }
4686    }
4687
4688    /// `match … { Ok(v) | Err(v) => v }`, which is how the old value is taken
4689    /// out of a `fetch_update` that never says no.
4690    fn either_way(&mut self, result: TokenStream, span: Span) -> TokenStream {
4691        let value = self.temporary();
4692        quote_spanned! {span=>
4693            match #result {
4694                ::core::result::Result::Ok(#value) | ::core::result::Result::Err(#value) => #value,
4695            }
4696        }
4697    }
4698
4699    /// The compare-exchange loop an operation Rust has no method for becomes,
4700    /// whose value is the **old** one.
4701    ///
4702    /// `updated` is the new value written in terms of `current`, and is
4703    /// recomputed on every attempt, which is exactly what C's "read, modify,
4704    /// write, atomically" comes to when the processor has no single
4705    /// instruction for it — a `fetch_nand`, a `*=` on an atomic object, a
4706    /// pointer that moves by elements.
4707    ///
4708    /// Written out rather than left to `Atomic::fetch_update`: that method is
4709    /// being renamed to `try_update`, and the old name is deprecated on newer
4710    /// toolchains while the new one does not exist on the oldest this crate
4711    /// supports. The loop is what it does anyway.
4712    fn atomic_cas_loop(
4713        &mut self,
4714        object: &TokenStream,
4715        current: &Ident,
4716        updated: TokenStream,
4717        order: ir::MemOrder,
4718        span: Span,
4719    ) -> TokenStream {
4720        let success = self.ordering(order, span);
4721        let failure = self.ordering(order.failure_order(), span);
4722        let slot = self.temporary();
4723        let fresh = self.temporary();
4724        let seen = self.temporary();
4725        quote_spanned! {span=>
4726            {
4727                let #slot = #object;
4728                let mut #current = #slot.load(#failure);
4729                loop {
4730                    let #fresh = #updated;
4731                    match #slot.compare_exchange_weak(#current, #fresh, #success, #failure) {
4732                        ::core::result::Result::Ok(_) => break #current,
4733                        ::core::result::Result::Err(#seen) => #current = #seen,
4734                    }
4735                }
4736            }
4737        }
4738    }
4739
4740    /// One of the atomic builtins; see [`ir::AtomicExpr`].
4741    fn atomic(&mut self, atomic: &ir::AtomicExpr, span: Span) -> Value {
4742        let class = atomic.class;
4743        let success = self.ordering(atomic.success, span);
4744        if let ir::AtomicOp::Fence { signal } = atomic.op {
4745            // C11 7.17.4p2 makes a relaxed fence a no-op, and Rust's `fence`
4746            // panics on one rather than saying so.
4747            if atomic.success == ir::MemOrder::Relaxed {
4748                return Value::atom(quote_spanned! {span=> () });
4749            }
4750            let name = Ident::new(if signal { "compiler_fence" } else { "fence" }, span);
4751            return Value::new(
4752                quote_spanned! {span=> ::core::sync::atomic::#name(#success) },
4753                prec::CALL,
4754            );
4755        }
4756        let ptr = match &atomic.ptr {
4757            Some(ptr) => self.expr(ptr).at(prec::CAST, span),
4758            None => return Value::atom(quote_spanned! {span=> () }),
4759        };
4760        let object = self.atomic_ref(class, ptr, span);
4761        let ty = atomic.value_ty;
4762        match atomic.op {
4763            ir::AtomicOp::Fence { .. } => unreachable!("handled above"),
4764            ir::AtomicOp::Load => self.repr_to_value(
4765                class,
4766                ty,
4767                quote_spanned! {span=> #object.load(#success) },
4768                span,
4769            ),
4770            ir::AtomicOp::Store => {
4771                let value = self.atomic_operand(atomic, span);
4772                Value::new(
4773                    quote_spanned! {span=> #object.store(#value, #success) },
4774                    prec::CALL,
4775                )
4776            }
4777            ir::AtomicOp::Exchange => {
4778                let value = self.atomic_operand(atomic, span);
4779                self.repr_to_value(
4780                    class,
4781                    ty,
4782                    quote_spanned! {span=> #object.swap(#value, #success) },
4783                    span,
4784                )
4785            }
4786            ir::AtomicOp::Clear => Value::new(
4787                quote_spanned! {span=> #object.store(0, #success) },
4788                prec::CALL,
4789            ),
4790            // GCC sets the byte to `__GCC_ATOMIC_TEST_AND_SET_TRUEVAL`, which
4791            // is 1, and answers whether it was already set.
4792            ir::AtomicOp::TestAndSet => Value::new(
4793                quote_spanned! {span=> #object.swap(1, #success) != 0 },
4794                prec::CMP,
4795            ),
4796            ir::AtomicOp::CompareExchange { weak } => {
4797                self.compare_exchange(atomic, object, weak, span)
4798            }
4799            ir::AtomicOp::SyncCompareSwap { value_is_old } => {
4800                self.sync_compare_swap(atomic, object, value_is_old, span)
4801            }
4802            ir::AtomicOp::Rmw { op, returns_new } => {
4803                self.atomic_rmw(atomic, object, op, returns_new, span)
4804            }
4805        }
4806    }
4807
4808    /// The value operand of an atomic builtin, as the atomic's own type.
4809    fn atomic_operand(&mut self, atomic: &ir::AtomicExpr, span: Span) -> TokenStream {
4810        let Some(value) = &atomic.value else {
4811            return quote_spanned! {span=> () };
4812        };
4813        let value = self.expr(value);
4814        self.value_to_repr(atomic.class, value, span)
4815    }
4816
4817    /// `__atomic_compare_exchange_n`, which writes the value it observed back
4818    /// through `expected` when it fails and answers whether it succeeded.
4819    fn compare_exchange(
4820        &mut self,
4821        atomic: &ir::AtomicExpr,
4822        object: TokenStream,
4823        weak: bool,
4824        span: Span,
4825    ) -> Value {
4826        let class = atomic.class;
4827        let ty = atomic.value_ty;
4828        let expected = match &atomic.expected {
4829            Some(expected) => self.expr(expected).at(prec::CALL, span),
4830            None => return Value::atom(quote_spanned! {span=> false }),
4831        };
4832        let desired = self.atomic_operand(atomic, span);
4833        let slot = self.temporary();
4834        let seen = self.temporary();
4835        let current = self.value_to_repr(class, Value::atom(quote_spanned! {span=> *#slot }), span);
4836        let method = Ident::new(
4837            if weak {
4838                "compare_exchange_weak"
4839            } else {
4840                "compare_exchange"
4841            },
4842            span,
4843        );
4844        let success = self.ordering(atomic.success, span);
4845        let failure = self.ordering(atomic.failure, span);
4846        let observed = self
4847            .repr_to_value(class, ty, quote_spanned! {span=> #seen }, span)
4848            .at(prec::LOWEST, span);
4849        Value::new(
4850            quote_spanned! {span=>
4851                {
4852                    let #slot = #expected;
4853                    match #object.#method(#current, #desired, #success, #failure) {
4854                        ::core::result::Result::Ok(_) => true,
4855                        ::core::result::Result::Err(#seen) => {
4856                            *#slot = #observed;
4857                            false
4858                        }
4859                    }
4860                }
4861            },
4862            prec::BLOCK,
4863        )
4864    }
4865
4866    /// `__sync_bool_compare_and_swap` and `__sync_val_compare_and_swap`, whose
4867    /// expected value is a value and which write nothing back.
4868    fn sync_compare_swap(
4869        &mut self,
4870        atomic: &ir::AtomicExpr,
4871        object: TokenStream,
4872        value_is_old: bool,
4873        span: Span,
4874    ) -> Value {
4875        let class = atomic.class;
4876        let ty = atomic.value_ty;
4877        let expected = match &atomic.expected {
4878            Some(expected) => {
4879                let value = self.expr(expected);
4880                self.value_to_repr(class, value, span)
4881            }
4882            None => return Value::atom(quote_spanned! {span=> false }),
4883        };
4884        let desired = self.atomic_operand(atomic, span);
4885        let seq = self.ordering(ir::MemOrder::SeqCst, span);
4886        let call = quote_spanned! {span=>
4887            #object.compare_exchange(#expected, #desired, #seq, #seq)
4888        };
4889        if !value_is_old {
4890            return Value::new(quote_spanned! {span=> #call.is_ok() }, prec::CALL);
4891        }
4892        let old = self.either_way(call, span);
4893        self.repr_to_value(class, ty, parenthesize(old, span), span)
4894    }
4895
4896    /// The `fetch_add` family, and the compare-exchange loops the ones Rust
4897    /// has no method for turn into.
4898    fn atomic_rmw(
4899        &mut self,
4900        atomic: &ir::AtomicExpr,
4901        object: TokenStream,
4902        op: ir::AtomicRmw,
4903        returns_new: bool,
4904        span: Span,
4905    ) -> Value {
4906        let class = atomic.class;
4907        let ty = atomic.value_ty;
4908        let success = self.ordering(atomic.success, span);
4909        let operand = self.temporary();
4910        let old = self.temporary();
4911        // A pointer moves by *bytes*: the scaling C11 wants for
4912        // `atomic_fetch_add` is already in the operand, put there by sema.
4913        if class == AtomicClass::Ptr {
4914            let delta = match &atomic.value {
4915                Some(value) => self.expr(value).at(prec::CAST, span),
4916                None => quote_spanned! {span=> 0 },
4917            };
4918            let isize_ty = primitive_ty("isize", span);
4919            let signed = if op == ir::AtomicRmw::Sub {
4920                quote_spanned! {span=> -(#delta as #isize_ty) }
4921            } else {
4922                quote_spanned! {span=> #delta as #isize_ty }
4923            };
4924            let step = self.temporary();
4925            let updated = self.atomic_cas_loop(
4926                &object,
4927                &step,
4928                quote_spanned! {span=> #step.wrapping_byte_offset(#operand) },
4929                atomic.success,
4930                span,
4931            );
4932            let tail = if returns_new {
4933                quote_spanned! {span=> #old.wrapping_byte_offset(#operand) }
4934            } else {
4935                quote_spanned! {span=> #old }
4936            };
4937            let tail = self
4938                .repr_to_value(class, ty, tail, span)
4939                .at(prec::LOWEST, span);
4940            return Value::new(
4941                quote_spanned! {span=>
4942                    {
4943                        let #operand: #isize_ty = #signed;
4944                        let #old = #updated;
4945                        #tail
4946                    }
4947                },
4948                prec::BLOCK,
4949            );
4950        }
4951        let value = self.atomic_operand(atomic, span);
4952        let repr = self.atomic_repr_ty(class, span);
4953        // `fetch_nand` exists for `AtomicBool` and for nothing else, so an
4954        // integer nand is the compare-exchange loop Rust would have written.
4955        let update = match op.rust_method() {
4956            Some(method) if op != ir::AtomicRmw::Nand || class == AtomicClass::Bool => {
4957                let method = Ident::new(method, span);
4958                quote_spanned! {span=> #object.#method(#operand, #success) }
4959            }
4960            _ if class == AtomicClass::Bool => {
4961                let method = Ident::new("fetch_nand", span);
4962                quote_spanned! {span=> #object.#method(#operand, #success) }
4963            }
4964            _ => {
4965                let current = self.temporary();
4966                self.atomic_cas_loop(
4967                    &object,
4968                    &current,
4969                    quote_spanned! {span=> !(#current & #operand) },
4970                    atomic.success,
4971                    span,
4972                )
4973            }
4974        };
4975        let combined = self.atomic_combine(op, &old, &operand, span);
4976        let tail = if returns_new {
4977            combined
4978        } else {
4979            quote_spanned! {span=> #old }
4980        };
4981        let tail = self
4982            .repr_to_value(class, ty, tail, span)
4983            .at(prec::LOWEST, span);
4984        Value::new(
4985            quote_spanned! {span=>
4986                {
4987                    let #operand: #repr = #value;
4988                    let #old = #update;
4989                    #tail
4990                }
4991            },
4992            prec::BLOCK,
4993        )
4994    }
4995
4996    /// The read-modify-write an `x += v`, `x++` or `--x` on an `_Atomic`
4997    /// object performs.
4998    ///
4999    /// C11 6.5.16.2p3 and 6.5.2.4p2 make each of them *one* atomic
5000    /// read-modify-write, not a load and a store, so none of them may go
5001    /// through [`Codegen::read`] and [`Codegen::write`]. The five operators an
5002    /// atomic has a method for become that method; everything else — `*=`,
5003    /// `<<=`, a floating object, a pointer that moves by elements — becomes
5004    /// the `fetch_update` loop the method would have been.
5005    ///
5006    /// The right operand is always evaluated into a temporary first: the
5007    /// update is written twice when the value of the expression is the new
5008    /// one, and C evaluates it once.
5009    fn atomic_place_rmw(
5010        &mut self,
5011        lowered: &LoweredPlace,
5012        kind: PlaceRmw<'_>,
5013        want: RmwValue,
5014        span: Span,
5015    ) -> TokenStream {
5016        let (class, ty) = lowered.atomic.expect("an atomic place");
5017        let object = self.atomic_object_of(lowered, span);
5018        let setup = &lowered.setup;
5019        let operand = self.temporary();
5020        let old = self.temporary();
5021        let success = self.ordering(ir::MemOrder::SeqCst, span);
5022        // The one shape that is a plain `fetch_*`: an integer object whose
5023        // operator is one of the five, computed in the object's own type, so
5024        // that no widening happens between the read and the write.
5025        let method = match (class, &kind) {
5026            (
5027                AtomicClass::Int { .. },
5028                PlaceRmw::Compound {
5029                    op,
5030                    compute,
5031                    value: _,
5032                },
5033            ) if *compute == ty => rmw_of_binop(*op),
5034            (AtomicClass::Int { .. }, PlaceRmw::Step { dec }) => Some(if *dec {
5035                ir::AtomicRmw::Sub
5036            } else {
5037                ir::AtomicRmw::Add
5038            }),
5039            _ => None,
5040        };
5041        if let Some(op) = method.filter(|op| op.rust_method().is_some()) {
5042            let repr = self.atomic_repr_ty(class, span);
5043            let value = match &kind {
5044                PlaceRmw::Compound { value, compute, .. } => {
5045                    let tokens = self.expr_at(value, *compute);
5046                    self.value_to_repr(class, Value::new(tokens, prec::LOWEST), span)
5047                }
5048                PlaceRmw::Step { .. } => quote_spanned! {span=> 1 },
5049            };
5050            let name = Ident::new(op.rust_method().expect("filtered"), span);
5051            let tail = self.atomic_rmw_tail((class, ty), op, &old, &operand, want, span);
5052            return quote_spanned! {span=>
5053                { #setup
5054                  let #operand: #repr = #value;
5055                  let #old = #object.#name(#operand, #success);
5056                  #tail }
5057            };
5058        }
5059        // The general form: a compare-exchange loop over the very expression
5060        // an ordinary compound assignment would have stored.
5061        let hoisted = match &kind {
5062            PlaceRmw::Compound { value, compute, .. } => {
5063                let tokens = self.expr_at(value, *compute);
5064                let rhs_ty = self.ty(*compute, span);
5065                Some(quote_spanned! {span=> let #operand: #rhs_ty = #tokens; })
5066            }
5067            PlaceRmw::Step { .. } => None,
5068        };
5069        let param = self.temporary();
5070        let current = self.repr_to_value(class, ty, quote_spanned! {span=> #param }, span);
5071        let updated = self.apply_place_rmw(&kind, current, ty, &operand, span);
5072        let updated = self.value_to_repr(class, updated, span);
5073        let loop_result =
5074            self.atomic_cas_loop(&object, &param, updated, ir::MemOrder::SeqCst, span);
5075        let tail = match want {
5076            RmwValue::None => TokenStream::new(),
5077            RmwValue::Old => self
5078                .repr_to_value(class, ty, quote_spanned! {span=> #old }, span)
5079                .at(prec::LOWEST, span),
5080            RmwValue::New => {
5081                let previous = self.repr_to_value(class, ty, quote_spanned! {span=> #old }, span);
5082                let value = self.apply_place_rmw(&kind, previous, ty, &operand, span);
5083                value.at(prec::LOWEST, span)
5084            }
5085        };
5086        quote_spanned! {span=>
5087            { #setup #hoisted
5088              let #old = #loop_result;
5089              #tail }
5090        }
5091    }
5092
5093    /// The new value of an atomic place, from the old one.
5094    fn apply_place_rmw(
5095        &mut self,
5096        kind: &PlaceRmw<'_>,
5097        current: Value,
5098        ty: Ty,
5099        operand: &Ident,
5100        span: Span,
5101    ) -> Value {
5102        match kind {
5103            PlaceRmw::Compound { op, value, compute } => {
5104                let rhs = Value::atom(quote_spanned! {span=> #operand });
5105                self.compound_value(current, ty, *op, value, Some(rhs), *compute)
5106            }
5107            PlaceRmw::Step { dec } => {
5108                Value::new(self.step_value(current, ty, *dec, span), prec::LOWEST)
5109            }
5110        }
5111    }
5112
5113    /// The value a `fetch_*` on a place ends with: nothing, the old value or
5114    /// the new one.
5115    ///
5116    /// `atomic` is the place's [class](AtomicClass) and the C type behind it,
5117    /// which is what the value the atomic returned is converted back to.
5118    fn atomic_rmw_tail(
5119        &mut self,
5120        atomic: (AtomicClass, Ty),
5121        op: ir::AtomicRmw,
5122        old: &Ident,
5123        operand: &Ident,
5124        want: RmwValue,
5125        span: Span,
5126    ) -> TokenStream {
5127        let (class, ty) = atomic;
5128        let value = match want {
5129            RmwValue::None => return TokenStream::new(),
5130            RmwValue::Old => quote_spanned! {span=> #old },
5131            RmwValue::New => self.atomic_combine(op, old, operand, span),
5132        };
5133        self.repr_to_value(class, ty, value, span)
5134            .at(prec::LOWEST, span)
5135    }
5136
5137    /// The new value a `…_fetch` form answers with, computed from the old one
5138    /// the atomic returned and the operand.
5139    fn atomic_combine(
5140        &self,
5141        op: ir::AtomicRmw,
5142        old: &Ident,
5143        operand: &Ident,
5144        span: Span,
5145    ) -> TokenStream {
5146        match op {
5147            // Wrapping, because C's atomic arithmetic is modular even for the
5148            // signed types — the atomic instruction has no other behaviour.
5149            ir::AtomicRmw::Add => quote_spanned! {span=> #old.wrapping_add(#operand) },
5150            ir::AtomicRmw::Sub => quote_spanned! {span=> #old.wrapping_sub(#operand) },
5151            ir::AtomicRmw::And => quote_spanned! {span=> (#old & #operand) },
5152            ir::AtomicRmw::Or => quote_spanned! {span=> (#old | #operand) },
5153            ir::AtomicRmw::Xor => quote_spanned! {span=> (#old ^ #operand) },
5154            ir::AtomicRmw::Nand => quote_spanned! {span=> !(#old & #operand) },
5155        }
5156    }
5157
5158    /// The operand of a bit-manipulation builtin, as the unsigned integer of
5159    /// its own width.
5160    fn unsigned_operand(&mut self, arg: &Expr, span: Span) -> TokenStream {
5161        let width = arg.ty.bits(&self.options.target);
5162        let target = unsigned_rust_ty(width, span);
5163        let value = self.expr(arg).at(prec::CAST, span);
5164        parenthesize(quote_spanned! {span=> #value as #target }, span)
5165    }
5166
5167    /// `__builtin_add_overflow(a, b, &r)` and its relatives.
5168    ///
5169    /// The arithmetic happens in an `i128`, which is what "infinite precision"
5170    /// comes to while both operands are at most 64 bits wide — sema refuses a
5171    /// wider one. The *result* type may still be 128 bits, and that is the one
5172    /// thing that changes how the answer is checked: the general test asks
5173    /// whether the narrowed value converts back to what infinite precision
5174    /// gave, and a 128-bit conversion is a reinterpretation that always does.
5175    /// A signed 128-bit result therefore never overflows, and an unsigned one
5176    /// overflows exactly when the exact answer was negative.
5177    fn overflow_builtin(
5178        &mut self,
5179        op: BinOp,
5180        args: &[Expr],
5181        store: bool,
5182        result_ty: Ty,
5183        span: Span,
5184    ) -> Value {
5185        let method = match op {
5186            BinOp::Add => "wrapping_add",
5187            BinOp::Sub => "wrapping_sub",
5188            _ => "wrapping_mul",
5189        };
5190        let method = Ident::new(method, span);
5191        let checked = match op {
5192            BinOp::Add => "checked_add",
5193            BinOp::Sub => "checked_sub",
5194            _ => "checked_mul",
5195        };
5196        let checked = Ident::new(checked, span);
5197        let lhs = self.expr(&args[0]).at(prec::CAST, span);
5198        let rhs = self.expr(&args[1]).at(prec::CAST, span);
5199        let target = self.ty(result_ty, span);
5200        let a = self.temporary();
5201        let b = self.temporary();
5202        let wide = self.temporary();
5203        let narrow = self.temporary();
5204        // Pathed, because `typedef __int128 i128;` is a name a C unit may take.
5205        let i128 = primitive_ty("i128", span);
5206        let compute = quote_spanned! {span=>
5207            let #a: #i128 = #lhs as #i128;
5208            let #b: #i128 = #rhs as #i128;
5209            let #wide: #i128 = #a.#method(#b);
5210            let #narrow: #target = #wide as #target;
5211        };
5212        // The value overflows exactly when the wrapped result no longer equals
5213        // what infinite precision gave — and `i128` itself can only overflow
5214        // on a multiplication, where the answer is certainly out of range.
5215        let fits = match result_ty {
5216            // Both 128-bit conversions are reinterpretations, so the general
5217            // test below is vacuous there; what is left is the sign.
5218            Ty::Int128 => quote_spanned! {span=> false },
5219            Ty::UInt128 => quote_spanned! {span=> #wide < 0 },
5220            _ => quote_spanned! {span=> (#narrow as #i128) != #wide },
5221        };
5222        let flag = quote_spanned! {span=>
5223            #a.#checked(#b).is_none() || #fits
5224        };
5225        if !store {
5226            // The `_p` forms still evaluate their third operand.
5227            let third = self.expr_stmt(&args[2]);
5228            return Value::new(
5229                quote_spanned! {span=> { #third #compute #flag } },
5230                prec::BLOCK,
5231            );
5232        }
5233        let place = self.expr(&args[2]).at(prec::CALL, span);
5234        let out = self.temporary();
5235        Value::new(
5236            quote_spanned! {span=>
5237                { #compute let #out = #place; *#out = #narrow; #flag }
5238            },
5239            prec::BLOCK,
5240        )
5241    }
5242
5243    /// `va_arg(ap, T)`: reads the next argument and advances the list.
5244    ///
5245    /// `VaArgSafe` — the bound `next_arg` needs — is implemented for the
5246    /// primitives the `core::ffi` aliases stand for, so the C type can be
5247    /// asked for by name. A function pointer is the exception: `Option<fn>` is
5248    /// not one of them, so the argument is read as a `void *` and transmuted,
5249    /// which is what it is.
5250    ///
5251    /// A `struct` or a `union` is not a primitive at all, and is rebuilt from
5252    /// the registers the ABI passed it in — one `next_arg` per
5253    /// [eightbyte](ir::Eightbyte), which `sema` has already classified. The
5254    /// words are gathered into a `[u64; N]`, whose bytes are exactly the
5255    /// object's, and read back out of it: `read_unaligned` rather than a
5256    /// `transmute`, because the record may be *shorter* than the words that
5257    /// carried it — `struct { char x[13]; }` arrives in two of them — and
5258    /// because `[u64; N]` is eight-byte aligned while a record holding an
5259    /// `__int128` wants sixteen.
5260    fn va_arg(
5261        &mut self,
5262        ap: &Place,
5263        record: Option<&[ir::Eightbyte]>,
5264        ty: Ty,
5265        span: Span,
5266    ) -> Value {
5267        let access = self.place(ap, true).access;
5268        if let Some(classes) = record {
5269            let target = self.ty(ty, span);
5270            let u64_ty = primitive_ty("u64", span);
5271            let f64_ty = primitive_ty("f64", span);
5272            let words = classes.iter().map(|class| match class {
5273                ir::Eightbyte::Int => quote_spanned! {span=> #access.next_arg::<#u64_ty>() },
5274                ir::Eightbyte::Sse => {
5275                    quote_spanned! {span=> #access.next_arg::<#f64_ty>().to_bits() }
5276                }
5277                // The ABI passes an eightbyte nothing reaches in no register,
5278                // so there is nothing to read and nothing the record can see.
5279                ir::Eightbyte::None => quote_spanned! {span=> 0 },
5280            });
5281            let count = Literal::usize_unsuffixed(classes.len());
5282            let value = self.temporary();
5283            return Value::new(
5284                quote_spanned! {span=>
5285                    {
5286                        let #value: [#u64_ty; #count] = [#(#words),*];
5287                        ::core::ptr::read_unaligned(#value.as_ptr().cast::<#target>())
5288                    }
5289                },
5290                prec::BLOCK,
5291            );
5292        }
5293        if self.program.types.is_func_pointer(ty) {
5294            let target = self.ty(ty, span);
5295            let void = self.pointee_ty(Ty::Void, span);
5296            return Value::new(
5297                quote_spanned! {span=>
5298                    ::core::mem::transmute::<*mut #void, #target>(
5299                        #access.next_arg::<*mut #void>()
5300                    )
5301                },
5302                prec::CALL,
5303            );
5304        }
5305        let target = self.ty(ty, span);
5306        Value::new(
5307            quote_spanned! {span=> #access.next_arg::<#target>() },
5308            prec::CALL,
5309        )
5310    }
5311
5312    /// The argument of `offset`, which is always an `isize`.
5313    /// How far one element of a variably modified pointee is, in units of the
5314    /// [step type](ir::Types::vm_step_ty) the generated pointer points at.
5315    ///
5316    /// `double (*p)[m]` is a `*mut c_double` in the expansion, so `p + 1` has
5317    /// to move by `m` of them, and `double (*p)[n][3]` by `n` of the `[f64; 3]`
5318    /// it points at. Everything C says about such a pointer follows from
5319    /// scaling every offset by this product; `None` is the ordinary case,
5320    /// where Rust's own pointer arithmetic already has the right stride.
5321    fn vm_scale(&self, pointee: Ty, span: Span) -> Option<TokenStream> {
5322        if !self.program.types.is_vm(pointee) {
5323            return None;
5324        }
5325        let isize_ty = primitive_ty("isize", span);
5326        let mut product: Option<TokenStream> = None;
5327        for dim in self.program.types.vm_dims(pointee).iter().rev() {
5328            let factor = match dim {
5329                ir::VmDim::Fixed(len) => {
5330                    let literal = Literal::isize_unsuffixed(*len as isize);
5331                    quote_spanned! {span=> #literal }
5332                }
5333                ir::VmDim::Len(id) => {
5334                    let name = self.object_ident(*id, span);
5335                    quote_spanned! {span=> #name as #isize_ty }
5336                }
5337                // Sema refuses every expression that would need a bound it
5338                // never evaluated, so nothing reaches here.
5339                ir::VmDim::Unknown => quote_spanned! {span=> 1 },
5340            };
5341            product = Some(match product {
5342                None => factor,
5343                Some(left) => quote_spanned! {span=> (#left).wrapping_mul(#factor) },
5344            });
5345        }
5346        product
5347    }
5348
5349    /// An offset in elements, scaled for a [variably
5350    /// modified](Codegen::vm_scale) pointee.
5351    fn scaled_offset(&mut self, pointee: Ty, index: &Expr, sub: bool, span: Span) -> TokenStream {
5352        let Some(scale) = self.vm_scale(pointee, span) else {
5353            return self.offset_argument(index, sub, span);
5354        };
5355        let isize_ty = primitive_ty("isize", span);
5356        // A constant subscript comes out of `offset_argument` as a bare
5357        // literal, whose type `wrapping_mul` would have nothing to infer from.
5358        let offset = match &index.kind {
5359            ExprKind::Int(value) => {
5360                let value = if sub { -*value } else { *value };
5361                let literal = int_literal_token(value, span);
5362                quote_spanned! {span=> (#literal as #isize_ty) }
5363            }
5364            _ => {
5365                let inner = self.offset_argument(index, sub, span);
5366                quote_spanned! {span=> (#inner) }
5367            }
5368        };
5369        quote_spanned! {span=> #offset.wrapping_mul(#scale) }
5370    }
5371
5372    fn offset_argument(&mut self, index: &Expr, sub: bool, span: Span) -> TokenStream {
5373        if let ExprKind::Int(value) = &index.kind {
5374            let value = if sub { value.wrapping_neg() } else { *value };
5375            let literal = int_literal_token(value, span);
5376            // A small literal is left bare, and Rust infers the `isize`
5377            // `offset` wants. A larger one carries a suffix of its own —
5378            // `u64`, or `i128` — which is then the wrong type rather than an
5379            // open one, so it is converted. (`int a[2]; a[1L << 40]` is
5380            // undefined in C, and this is what `as` makes of it.)
5381            if value.unsigned_abs() > UNSUFFIXED_LIMIT as u128 {
5382                let isize_ty = primitive_ty("isize", span);
5383                return quote_spanned! {span=> (#literal as #isize_ty) };
5384            }
5385            return literal;
5386        }
5387        let tokens = self.expr(index).at(prec::CAST, span);
5388        let isize_ty = primitive_ty("isize", span);
5389        if sub {
5390            quote_spanned! {span=> -(#tokens as #isize_ty) }
5391        } else {
5392            quote_spanned! {span=> #tokens as #isize_ty }
5393        }
5394    }
5395
5396    fn call(&mut self, callee: &Callee, args: &[Expr], span: Span) -> Value {
5397        let sig = self.callee_signature(callee);
5398        // A call through a function type with *no prototype* passes as many
5399        // arguments as it was given, each with the default argument promotions
5400        // applied, and the callee reads them as though the prototype had said
5401        // so (C99 6.5.2.2p6). Rust has no such call, so the reinterpretation is
5402        // written out: the callee is transmuted to the signature the promoted
5403        // arguments make, and that signature is called.
5404        //
5405        // It is the same contract C's own ABI relies on — the program is
5406        // defined only if the function really does take parameters of those
5407        // types, and undefined otherwise — and on every ABI this crate targets
5408        // a function pointer transmuted this way is the same address. Sema has
5409        // already applied the promotions, so `arg.ty` is the parameter type to
5410        // write.
5411        //
5412        // The argument *types* are compared as well as their number, because a
5413        // declaration with no prototype may be completed by a definition that
5414        // has one after the call was written: `int *h(); … h(j(), n); … int
5415        // *h(unsigned, int) { … }` — `execute/pr103209` — leaves the call
5416        // holding arguments the definition's parameters do not have. The call
5417        // was checked against the type in scope where it stands, which is the
5418        // one with no prototype, so the reinterpretation is what C says
5419        // happens there too. Where the prototype *was* in scope, sema has
5420        // already converted every argument to its parameter's type and the
5421        // comparison is an equality that holds.
5422        let reinterpreted = !sig.variadic
5423            && (args.len() != sig.params.len()
5424                || args.iter().zip(&sig.params).any(|(arg, param)| {
5425                    arg.ty != *param && !arg.ty.is_error() && !param.is_error()
5426                }));
5427        let promoted: Vec<Ty> = if reinterpreted {
5428            args.iter().map(|arg| arg.ty).collect()
5429        } else {
5430            Vec::new()
5431        };
5432        let params = if reinterpreted {
5433            &promoted
5434        } else {
5435            &sig.params
5436        };
5437
5438        let mut target = match callee {
5439            Callee::Direct(id) => {
5440                let function = self.program.function(*id);
5441                let path = self.function_path(function, span);
5442                if reinterpreted {
5443                    // A function *item* is not a function pointer, so the `as`
5444                    // coercion has to be written before it can be transmuted.
5445                    let source = self.function_pointer_ty(function, span);
5446                    parenthesize(quote_spanned! {span=> #path as #source }, span)
5447                } else {
5448                    path
5449                }
5450            }
5451            Callee::Indirect(expr) => {
5452                let value = self.expr(expr).at(prec::CALL, span);
5453                // C's function pointers may be null and Rust's may not, so the
5454                // `Option` has to come off before the call.
5455                parenthesize(
5456                    quote_spanned! {span=> #value.expect("null function pointer") },
5457                    span,
5458                )
5459            }
5460        };
5461        if reinterpreted {
5462            let source = self.fn_ptr_ty(&sig.params, sig.variadic, sig.ret, span);
5463            let wanted = self.fn_ptr_ty(params, false, sig.ret, span);
5464            target = parenthesize(
5465                quote_spanned! {span=>
5466                    ::core::mem::transmute::<#source, #wanted>(#target)
5467                },
5468                span,
5469            );
5470        }
5471
5472        // A lifted nested function's hidden arguments come first, and one
5473        // written argument after them needs the comma the loop would only put
5474        // between two of its own.
5475        let mut tokens = self.env_arguments(callee, span);
5476        let hidden = !tokens.is_empty();
5477        for (index, arg) in args.iter().enumerate() {
5478            if index > 0 || hidden {
5479                tokens.extend(quote_spanned! {span=> , });
5480            }
5481            match params.get(index) {
5482                // A parameter's type is what the argument is written at, so a
5483                // constant needs no `as`.
5484                Some(expected) => tokens.extend(self.expr_at(arg, *expected)),
5485                // An argument matched by `...` has no parameter to take its
5486                // type from, and Rust gives an unsuffixed literal in that
5487                // position `i32` (or `f64`), whatever C says it is: `%ld` with
5488                // a bare `-1` would read four bytes of an eight-byte
5489                // argument. The type has to be written out.
5490                None => {
5491                    let arg_span = self.sp(arg.range);
5492                    tokens.extend(self.expr(arg).at(prec::LOWEST, arg_span));
5493                }
5494            }
5495        }
5496        let call = parenthesize(tokens, span);
5497        Value::new(quote_spanned! {span=> #target #call }, prec::CALL)
5498    }
5499
5500    /// The hidden arguments a call to a lifted nested function opens with.
5501    ///
5502    /// Each one is the address of the object the callee wants: the enclosing
5503    /// function passes `&raw mut x` for a local of its own, and a function
5504    /// that was itself passed the pointer passes that on. Nothing else has a
5505    /// hidden argument, so this is empty for every ordinary call.
5506    fn env_arguments(&self, callee: &Callee, span: Span) -> TokenStream {
5507        let Callee::Direct(id) = callee else {
5508            return TokenStream::new();
5509        };
5510        let mut tokens = TokenStream::new();
5511        for (index, entry) in self.program.function(*id).env.iter().enumerate() {
5512            if index > 0 {
5513                tokens.extend(quote_spanned! {span=> , });
5514            }
5515            match self.env.get(&entry.owner) {
5516                // The caller was handed the pointer itself; it passes it on.
5517                Some(param) => {
5518                    let name = self.object_ident(*param, span);
5519                    tokens.extend(quote_spanned! {span=> #name });
5520                }
5521                // The object is the caller's own.
5522                None => {
5523                    let object = self.program.object(entry.owner);
5524                    let name = self.object_access(entry.owner, span);
5525                    tokens.extend(if object.is_const {
5526                        quote_spanned! {span=> &raw const #name }
5527                    } else {
5528                        quote_spanned! {span=> &raw mut #name }
5529                    });
5530                }
5531            }
5532        }
5533        tokens
5534    }
5535
5536    /// The signature a call goes through: the callee's own for a direct call,
5537    /// and the pointed-to function type for an indirect one.
5538    fn callee_signature(&self, callee: &Callee) -> ir::Signature {
5539        match callee {
5540            Callee::Direct(id) => self.program.function(*id).sig.clone(),
5541            Callee::Indirect(expr) => match self.program.types.pointee(expr.ty) {
5542                Some(Ty::Func(id)) => {
5543                    let func = self.program.types.func_type(id);
5544                    ir::Signature {
5545                        ret: func.ret,
5546                        params: func.params.clone(),
5547                        variadic: func.variadic,
5548                        prototyped: func.prototyped,
5549                    }
5550                }
5551                // Only reachable on the error path, where a `compile_error!` is
5552                // already going out.
5553                _ => ir::Signature {
5554                    ret: Ty::Void,
5555                    params: Vec::new(),
5556                    variadic: false,
5557                    prototyped: true,
5558                },
5559            },
5560        }
5561    }
5562
5563    /// `unsafe extern "C" fn(P…) -> R`, written out from its pieces.
5564    fn fn_ptr_ty(&self, params: &[Ty], variadic: bool, ret: Ty, span: Span) -> TokenStream {
5565        let mut list = TokenStream::new();
5566        for (index, param) in params.iter().enumerate() {
5567            if index > 0 {
5568                list.extend(quote_spanned! {span=> , });
5569            }
5570            list.extend(self.ty(*param, span));
5571        }
5572        if variadic {
5573            if !params.is_empty() {
5574                list.extend(quote_spanned! {span=> , });
5575            }
5576            list.extend(quote_spanned! {span=> ... });
5577        }
5578        let list = parenthesize(list, span);
5579        let ret = if ret.is_void() {
5580            TokenStream::new()
5581        } else {
5582            let ty = self.ty(ret, span);
5583            quote_spanned! {span=> -> #ty }
5584        };
5585        quote_spanned! {span=> unsafe extern "C" fn #list #ret }
5586    }
5587
5588    /// The path a call to `function` uses.
5589    ///
5590    /// One name whether the unit defines the function or only declares it: the
5591    /// item in the `extern` block carries the C name as well (see
5592    /// [`Codegen::extern_block`]), and a lifted nested function carries the name
5593    /// it was lifted under.
5594    fn function_path(&self, function: &Function, span: Span) -> TokenStream {
5595        let name = self.c_ident(function.item_name(), span);
5596        quote_spanned! {span=> #name }
5597    }
5598
5599    /// `unsafe extern "C" fn(…) -> R` for a named function, which is what its
5600    /// address has to be cast to.
5601    fn function_pointer_ty(&self, function: &Function, span: Span) -> TokenStream {
5602        let sig = &function.sig;
5603        self.fn_ptr_ty(&sig.params, sig.variadic, sig.ret, span)
5604    }
5605
5606    /// Emits an expression as a Rust `bool`, the way C tests a scalar against
5607    /// zero.
5608    fn condition(&mut self, expr: &Expr) -> Value {
5609        let span = self.sp(expr.range);
5610        match &expr.kind {
5611            ExprKind::Compare { op, lhs, rhs } => {
5612                if let Some(value) = self.null_test(*op, lhs, rhs, span) {
5613                    return value;
5614                }
5615                if lhs.ty.is_complex() && rhs.ty.is_complex() {
5616                    return self.complex_equality(*op, lhs, rhs, span);
5617                }
5618                let (lhs, rhs) = self.operands(lhs, rhs, BinOp::BitOr);
5619                let left_min = if *op == CmpOp::Lt && lhs.ends_with_type {
5620                    prec::CAST + 1
5621                } else {
5622                    prec::CMP + 1
5623                };
5624                let ends_with_type = rhs.ends_with_type;
5625                let lhs = lhs.at(left_min, span);
5626                let rhs = rhs.at(prec::CMP + 1, span);
5627                let op = cmp_tokens(*op, span);
5628                Value::new(quote_spanned! {span=> #lhs #op #rhs }, prec::CMP)
5629                    .type_end(ends_with_type)
5630            }
5631            ExprKind::Logical { .. } => self.logical_chain(expr),
5632            ExprKind::Int(value) => {
5633                let ident = Ident::new(if *value != 0 { "true" } else { "false" }, span);
5634                Value::atom(quote_spanned! {span=> #ident })
5635            }
5636            _ if expr.ty.is_bool() => self.expr(expr),
5637            _ if expr.ty.is_complex() => self.complex_condition(expr, span),
5638            _ if expr.ty.is_pointer() => self.not_null(expr, span),
5639            _ => {
5640                let ty = expr.ty;
5641                let value = self.expr(expr).at(prec::CMP + 1, span);
5642                let zero = self.zero_tokens(ty, span);
5643                Value::new(quote_spanned! {span=> #value != #zero }, prec::CMP)
5644            }
5645        }
5646    }
5647
5648    /// `p != NULL` reads better as `!p.is_null()`, and that is also the only
5649    /// form that works for a function pointer.
5650    fn null_test(&mut self, op: CmpOp, lhs: &Expr, rhs: &Expr, span: Span) -> Option<Value> {
5651        if !matches!(op, CmpOp::Eq | CmpOp::Ne) {
5652            return None;
5653        }
5654        let (pointer, _) = match (&lhs.kind, &rhs.kind) {
5655            (ExprKind::Zeroed, _) if rhs.ty.is_pointer() => (rhs, lhs),
5656            (_, ExprKind::Zeroed) if lhs.ty.is_pointer() => (lhs, rhs),
5657            _ => return None,
5658        };
5659        let test = self.is_null(pointer, span);
5660        if op == CmpOp::Eq {
5661            return Some(test);
5662        }
5663        let tokens = test.at(prec::UNARY, span);
5664        Some(Value::new(quote_spanned! {span=> !#tokens }, prec::UNARY))
5665    }
5666
5667    /// `p.is_null()`, or `{ p }.is_some()` for a function pointer.
5668    fn is_null(&mut self, expr: &Expr, span: Span) -> Value {
5669        if self.program.types.is_func_pointer(expr.ty) {
5670            let tokens = self.copied_receiver(expr, span);
5671            return Value::new(quote_spanned! {span=> #tokens.is_none() }, prec::CALL);
5672        }
5673        let tokens = self.expr(expr).at(prec::CALL, span);
5674        Value::new(quote_spanned! {span=> #tokens.is_null() }, prec::CALL)
5675    }
5676
5677    fn not_null(&mut self, expr: &Expr, span: Span) -> Value {
5678        if self.program.types.is_func_pointer(expr.ty) {
5679            let tokens = self.copied_receiver(expr, span);
5680            return Value::new(quote_spanned! {span=> #tokens.is_some() }, prec::CALL);
5681        }
5682        let tokens = self.expr(expr).at(prec::CALL, span);
5683        Value::new(quote_spanned! {span=> !#tokens.is_null() }, prec::UNARY)
5684    }
5685
5686    /// A receiver for a method that takes `&self`.
5687    ///
5688    /// `Option::is_some` borrows, and borrowing a `static mut` is an error in
5689    /// edition 2024; a block copies the value out first. Only a place that
5690    /// really is a `static mut` needs it, so an ordinary local keeps reading
5691    /// as one.
5692    fn copied_receiver(&mut self, expr: &Expr, span: Span) -> TokenStream {
5693        if self.reads_a_static(expr) {
5694            let tokens = self.expr(expr).at(prec::LOWEST, span);
5695            return braced(tokens, span);
5696        }
5697        self.expr(expr).at(prec::CALL, span)
5698    }
5699
5700    /// Whether an expression reads an object with static storage duration,
5701    /// which is what a shared reference may not be taken to.
5702    fn reads_a_static(&self, expr: &Expr) -> bool {
5703        let ExprKind::Load(place) = &expr.kind else {
5704            return false;
5705        };
5706        let mut place = place;
5707        loop {
5708            match &place.kind {
5709                PlaceKind::Object(id) => {
5710                    let storage = &self.program.object(*id).storage;
5711                    // A thread-local object is a `*mut T` out of its cell, so
5712                    // it is behind a raw pointer like anything else below.
5713                    return !matches!(storage, Storage::Automatic) && !storage.is_thread_local();
5714                }
5715                PlaceKind::Field { base, .. } => place = base,
5716                // Anything reached through a pointer is behind a raw pointer
5717                // already, so no reference to the static itself is created.
5718                _ => return false,
5719            }
5720        }
5721    }
5722
5723    /// Emits the operands of a binary operation.
5724    ///
5725    /// Both operands already have the result type, so a constant one can be
5726    /// left as a bare literal and take its Rust type from the other side —
5727    /// `n == 0` rather than `n == 0 as ::core::ffi::c_int`. That only works
5728    /// while the other side actually has a type to give, and never for the
5729    /// receiver of a method call, where a bare integer literal followed by a
5730    /// `.` would not survive being printed back out as text.
5731    fn operands(&mut self, lhs: &Expr, rhs: &Expr, op: BinOp) -> (Value, Value) {
5732        self.operands_with(None, lhs, rhs, op)
5733    }
5734
5735    /// [`Codegen::operands`] with the left operand possibly already emitted.
5736    ///
5737    /// `folded` is what [`Codegen::binary_chain`] has built so far. It is only
5738    /// ever a binary operation, and [`constant_of`] answers `None` for one, so
5739    /// the bare-literal reasoning below is unaffected by it.
5740    fn operands_with(
5741        &mut self,
5742        folded: Option<Value>,
5743        lhs: &Expr,
5744        rhs: &Expr,
5745        op: BinOp,
5746    ) -> (Value, Value) {
5747        let uses_method = matches!(
5748            op,
5749            BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Shl | BinOp::Shr
5750        );
5751        let lhs_constant = constant_of(lhs);
5752        let rhs_constant = constant_of(rhs);
5753
5754        // At most one side may be bare, and it is never the left one where a
5755        // method call follows.
5756        let lhs_bare = lhs_constant.is_some() && !uses_method && rhs_constant.is_none();
5757        let lhs_value = match (folded, lhs_constant) {
5758            (Some(value), _) => value,
5759            (None, Some(value)) if lhs_bare => self.bare_value(value, lhs.ty, self.sp(lhs.range)),
5760            (None, _) => self.expr(lhs),
5761        };
5762        let rhs_value = match rhs_constant {
5763            // The shift amount is converted to `u32` whatever its C type is,
5764            // so a constant there never needs the other operand's help — and
5765            // it is reduced to *that* `u32` here rather than left as the C
5766            // value. Every count a program may legitimately write is under
5767            // the width and so unchanged; the ones that are not are undefined
5768            // in C, and writing them out as they stand is what `rustc`
5769            // refuses. A negative one is `-64 as u32`, which it reads as the
5770            // negation of a `u32` (`E0600`, `execute/pr98681`) even
5771            // parenthesised, and one above `u32::MAX` is a literal out of
5772            // range. `wrapping_shl` masks the count by the width, exactly as
5773            // the hardware does.
5774            Some(ConstValue::Int(value)) if op.is_shift() => self.bare_value(
5775                ConstValue::Int(i128::from(value as u32)),
5776                Ty::UInt,
5777                self.sp(rhs.range),
5778            ),
5779            Some(value) if op.is_shift() => self.bare_value(value, rhs.ty, self.sp(rhs.range)),
5780            Some(value) if !lhs_bare => self.bare_value(value, rhs.ty, self.sp(rhs.range)),
5781            _ => self.expr(rhs),
5782        };
5783        (lhs_value, rhs_value)
5784    }
5785
5786    /// A constant emitted without its `as`, for a context that will supply the
5787    /// type.
5788    fn bare_value(&mut self, value: ConstValue, ty: Ty, span: Span) -> Value {
5789        match value {
5790            ConstValue::Int(v) => {
5791                let tokens = bare_int_literal(v, ty, span);
5792                let mut out = Value::new(tokens, if v < 0 { prec::UNARY } else { prec::ATOM });
5793                out.bare_integer = v >= 0 && !ty.is_bool();
5794                out
5795            }
5796            ConstValue::Float(v) => Value::new(
5797                bare_float_literal(v, span),
5798                if v.is_sign_negative() {
5799                    prec::UNARY
5800                } else {
5801                    prec::ATOM
5802                },
5803            ),
5804            // A complex constant is never *bare*: it has to name its own type,
5805            // and [`constant_of`] answers `None` for one so that nothing asks.
5806            ConstValue::Complex(re, im) => {
5807                let re = bare_float_literal(re, span);
5808                let im = bare_float_literal(im, span);
5809                self.complex_new(ty, re, im, span)
5810            }
5811        }
5812    }
5813
5814    /// A chain of conditional operators, folded without recursing down it.
5815    ///
5816    /// `a ? b : c ? d : e` is right-associative, so unlike the chains
5817    /// [`Codegen::binary_chain`] handles this one really is nesting: what
5818    /// comes out is `if … { … } else { if … }`, one level per operator, and
5819    /// that is as it should be. What must not be one level per operator is
5820    /// the *walk*, which runs on the eight mebibytes `rustc` gives macro
5821    /// expansion.
5822    ///
5823    /// The condition and the `then` arm of each level are emitted on the way
5824    /// down and the tree is built on the way back up, which is the order the
5825    /// recursive walk had — so the tokens, and the numbering of any
5826    /// temporaries in them, are exactly what it produced.
5827    fn cond_chain(&mut self, expr: &Expr) -> Value {
5828        let mut spine = Vec::new();
5829        let mut node = expr;
5830        while let ExprKind::Cond {
5831            cond,
5832            then_expr,
5833            else_expr,
5834        } = &node.kind
5835        {
5836            let span = self.sp(node.range);
5837            let cond_tokens = self.condition(cond).at_condition(span);
5838            let then_tokens = self.expr(then_expr).at(prec::LOWEST, span);
5839            spine.push((cond_tokens, then_tokens, span));
5840            node = else_expr;
5841        }
5842        // The innermost `else` is parenthesised against the span of the
5843        // conditional it belongs to, which is the innermost one on the spine.
5844        let inner = spine
5845            .last()
5846            .map_or_else(|| self.sp(expr.range), |(_, _, span)| *span);
5847        let mut tokens = self.expr(node).at(prec::LOWEST, inner);
5848        while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
5849            tokens = quote_spanned! {span=>
5850                if #cond_tokens { #then_tokens } else { #tokens }
5851            };
5852        }
5853        Value::new(tokens, prec::BLOCK)
5854    }
5855
5856    /// [`Codegen::cond_chain`] where the surrounding context fixes the type.
5857    ///
5858    /// The chain ends wherever a level's own type is no longer `expected`,
5859    /// which is where [`Codegen::expr_at`] would have stopped treating the
5860    /// arms as bare anyway.
5861    fn cond_chain_at(&mut self, expr: &Expr, expected: Ty) -> TokenStream {
5862        let mut spine = Vec::new();
5863        let mut node = expr;
5864        while let ExprKind::Cond {
5865            cond,
5866            then_expr,
5867            else_expr,
5868        } = &node.kind
5869        {
5870            if node.ty != expected {
5871                break;
5872            }
5873            let span = self.sp(node.range);
5874            let cond_tokens = self.condition(cond).at_condition(span);
5875            let then_tokens = self.expr_at(then_expr, expected);
5876            spine.push((cond_tokens, then_tokens, span));
5877            node = else_expr;
5878        }
5879        let mut tokens = self.expr_at(node, expected);
5880        while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
5881            tokens = quote_spanned! {span=>
5882                if #cond_tokens { #then_tokens } else { #tokens }
5883            };
5884        }
5885        tokens
5886    }
5887
5888    /// A chain of assignments, folded without recursing down it.
5889    ///
5890    /// `a = b = c` is right-associative, so this is nesting in the same way
5891    /// [`Codegen::cond_chain`] is, and the same bargain applies: the shape of
5892    /// the output is unchanged and only the walk is flattened. Each place is
5893    /// lowered on the way down — which is where the recursive walk lowered it,
5894    /// and therefore where it took any temporary it needed — and the blocks
5895    /// are built on the way back up, innermost first, exactly as the
5896    /// recursion unwound.
5897    fn assign_chain(&mut self, expr: &Expr) -> Value {
5898        let mut spine = Vec::new();
5899        let mut node = expr;
5900        while let ExprKind::Assign { place, value } = &node.kind {
5901            let span = self.sp(node.range);
5902            let lowered = self.place(place, true);
5903            spine.push((lowered, self.program.types.unatomic(place.ty), span));
5904            node = value;
5905        }
5906        let (_, innermost, _) = spine
5907            .last()
5908            .expect("assign_chain is only entered on an assignment");
5909        let mut tokens = self.expr_at(node, *innermost);
5910        while let Some((lowered, ty, span)) = spine.pop() {
5911            // The value of an assignment to an *atomic* object is the value
5912            // stored and not what the object holds afterwards: another thread
5913            // may have changed it already, and reading it back would be a
5914            // second atomic operation C never asked for.
5915            if lowered.atomic.is_some() {
5916                let tmp = self.temporary();
5917                let target = self.ty(ty, span);
5918                let store = self.write(&lowered, quote_spanned! {span=> #tmp }, span);
5919                let setup = &lowered.setup;
5920                tokens = quote_spanned! {span=>
5921                    { #setup let #tmp: #target = #tokens; #store #tmp }
5922                };
5923                continue;
5924            }
5925            let store = self.write(&lowered, tokens, span);
5926            // The value of an assignment is the value stored, which for a
5927            // place is exactly what reading it back gives — including for a
5928            // bit-field, where reading back is what truncates.
5929            let read = self.read(&lowered, span).at(prec::LOWEST, span);
5930            let setup = &lowered.setup;
5931            tokens = quote_spanned! {span=> { #setup #store #read } };
5932        }
5933        Value::new(tokens, prec::BLOCK)
5934    }
5935
5936    /// A chain of binary operators, folded without recursing down it.
5937    ///
5938    /// `a + b + c + …` is left-associative, so the tree it leaves behind is
5939    /// one node per operand with the whole of the rest hanging off its left.
5940    /// Walking that recursively is one stack frame per operand — and code
5941    /// generation runs on the caller's thread, which is the eight mebibytes
5942    /// `rustc` gives macro expansion, where a chain of about eight hundred is
5943    /// a "fatal runtime error: stack overflow" with no diagnostic at all.
5944    ///
5945    /// C23 5.2.5.2p1 asks every implementation to accept a logical source
5946    /// line of 4095 characters, which is well past that, so the spine is
5947    /// collected into a vector and folded back up in a loop: one frame,
5948    /// however long the chain. The tokens that come out are the same ones the
5949    /// recursive walk produced, and in the same order — `a.wrapping_add(b)
5950    /// .wrapping_add(c)` is a receiver chain, which is *flat*, so neither is
5951    /// the output deeply nested.
5952    ///
5953    /// Nesting — `a + (b + (c + …))`, which is one level of parentheses per
5954    /// operand — still costs a frame per level, and is what
5955    /// `parse::MAX_RECURSION_DEPTH` bounds.
5956    fn binary_chain(&mut self, expr: &Expr) -> Value {
5957        let mut spine = vec![expr];
5958        let mut node = expr;
5959        while let ExprKind::Binary { lhs, .. } = &node.kind {
5960            node = lhs;
5961            if matches!(node.kind, ExprKind::Binary { .. }) {
5962                spine.push(node);
5963            }
5964        }
5965        let mut folded = None;
5966        while let Some(node) = spine.pop() {
5967            let ExprKind::Binary { op, lhs, rhs } = &node.kind else {
5968                unreachable!("the spine holds binary operations only");
5969            };
5970            let span = self.sp(node.range);
5971            let (lhs_value, rhs_value) = self.operands_with(folded, lhs, rhs, *op);
5972            let value = if node.ty.is_complex() {
5973                self.complex_binary(*op, (lhs_value, lhs.ty), (rhs_value, rhs.ty), node.ty, span)
5974            } else {
5975                self.binary(*op, lhs_value, rhs_value, node.ty, span)
5976            };
5977            folded = Some(self.reduce_bits(value, node));
5978        }
5979        folded.expect("the chain has at least the node it started from")
5980    }
5981
5982    /// A chain of `&&` or `||`, folded without recursing down it.
5983    ///
5984    /// The same shape and the same reason as [`Codegen::binary_chain`]; these
5985    /// live on the `bool` side of code generation, so the fold is over
5986    /// [`Codegen::condition`] rather than over `expr`.
5987    fn logical_chain(&mut self, expr: &Expr) -> Value {
5988        let mut spine = vec![expr];
5989        let mut node = expr;
5990        while let ExprKind::Logical { lhs, .. } = &node.kind {
5991            node = lhs;
5992            if matches!(node.kind, ExprKind::Logical { .. }) {
5993                spine.push(node);
5994            }
5995        }
5996        // `node` is now the innermost left operand, which is not itself a
5997        // logical operator; emitting it first keeps the order the recursive
5998        // walk had, which is source order.
5999        let mut folded = self.condition(node);
6000        while let Some(node) = spine.pop() {
6001            let ExprKind::Logical { op, rhs, .. } = &node.kind else {
6002                unreachable!("the spine holds logical operations only");
6003            };
6004            let span = self.sp(node.range);
6005            let (level, tokens) = match op {
6006                LogicalOp::And => (prec::AND, quote_spanned! {span=> && }),
6007                LogicalOp::Or => (prec::OR, quote_spanned! {span=> || }),
6008            };
6009            let mut out = folded.at(level, span);
6010            let rhs = self.condition(rhs);
6011            let ends_with_type = rhs.ends_with_type;
6012            let rhs = rhs.at(level + 1, span);
6013            out.extend(quote_spanned! {span=> #tokens #rhs });
6014            folded = Value::new(out, level).type_end(ends_with_type);
6015        }
6016        folded
6017    }
6018
6019    fn binary(&mut self, op: BinOp, lhs: Value, rhs: Value, ty: Ty, span: Span) -> Value {
6020        if ty.is_floating() {
6021            let (level, tokens) = match op {
6022                BinOp::Add => (prec::SUM, quote_spanned! {span=> + }),
6023                BinOp::Sub => (prec::SUM, quote_spanned! {span=> - }),
6024                BinOp::Mul => (prec::PRODUCT, quote_spanned! {span=> * }),
6025                BinOp::Div => (prec::PRODUCT, quote_spanned! {span=> / }),
6026                // Sema rejects every other operator on floating operands.
6027                _ => (prec::PRODUCT, quote_spanned! {span=> % }),
6028            };
6029            let ends_with_type = rhs.ends_with_type;
6030            let mut out = lhs.at(level, span);
6031            let rhs = rhs.at(level + 1, span);
6032            // Appended in place rather than built into a fresh stream around
6033            // the left operand: a chain of a thousand would otherwise copy
6034            // the whole of it a thousand times over. See
6035            // [`Codegen::binary_chain`].
6036            out.extend(quote_spanned! {span=> #tokens #rhs });
6037            return Value::new(out, level).type_end(ends_with_type);
6038        }
6039
6040        // `+`, `-`, `*` and the shifts go through the wrapping methods:
6041        // unsigned wrap-around is defined in C, and while signed overflow is
6042        // undefined, wrapping is far more predictable than a panic in the
6043        // middle of translated code.
6044        let method = match op {
6045            BinOp::Add => Some("wrapping_add"),
6046            BinOp::Sub => Some("wrapping_sub"),
6047            BinOp::Mul => Some("wrapping_mul"),
6048            BinOp::Shl => Some("wrapping_shl"),
6049            BinOp::Shr => Some("wrapping_shr"),
6050            _ => None,
6051        };
6052        if let Some(method) = method {
6053            let mut receiver = lhs.at(prec::CALL, span);
6054            let method = Ident::new(method, span);
6055            let argument = if op.is_shift() && !rhs.bare_integer {
6056                // `wrapping_shl` takes the shift amount as a `u32` whatever the
6057                // shifted type is; a bare literal simply is one already.
6058                let amount = rhs.at(prec::CAST, span);
6059                // Belt and braces: nothing that reaches here opens with a
6060                // unary minus — a constant count was reduced to its `u32` in
6061                // [`Codegen::operands_with`] and `-x` is written
6062                // `x.wrapping_neg()` — and if one ever did, `rustc` would read
6063                // `-e as u32` as the negation of a `u32` and refuse it
6064                // (`E0600`) however it is bracketed by precedence.
6065                let amount = if starts_with_minus(&amount) {
6066                    parenthesize(amount, span)
6067                } else {
6068                    amount
6069                };
6070                let u32_ty = primitive_ty("u32", span);
6071                quote_spanned! {span=> #amount as #u32_ty }
6072            } else {
6073                rhs.at(prec::LOWEST, span)
6074            };
6075            let args = parenthesize(argument, span);
6076            receiver.extend(quote_spanned! {span=> .#method #args });
6077            return Value::new(receiver, prec::CALL);
6078        }
6079
6080        // `/` and `%` stay plain: Rust truncates towards zero and takes the
6081        // sign of the dividend, exactly as C99 does. Both panic where C is
6082        // undefined (division by zero, and `INT_MIN / -1`).
6083        let (level, tokens) = match op {
6084            BinOp::Div => (prec::PRODUCT, quote_spanned! {span=> / }),
6085            BinOp::Rem => (prec::PRODUCT, quote_spanned! {span=> % }),
6086            BinOp::BitAnd => (prec::BIT_AND, quote_spanned! {span=> & }),
6087            BinOp::BitXor => (prec::BIT_XOR, quote_spanned! {span=> ^ }),
6088            BinOp::BitOr => (prec::BIT_OR, quote_spanned! {span=> | }),
6089            _ => unreachable!("every other operator was handled above"),
6090        };
6091        let ends_with_type = rhs.ends_with_type;
6092        let mut out = lhs.at(level, span);
6093        let rhs = rhs.at(level + 1, span);
6094        out.extend(quote_spanned! {span=> #tokens #rhs });
6095        Value::new(out, level).type_end(ends_with_type)
6096    }
6097
6098    /// The value `place op= value` stores.
6099    ///
6100    /// `hoisted` is the right operand when it was evaluated ahead of the read;
6101    /// see [`Codegen::compound_rhs`].
6102    fn compound_value(
6103        &mut self,
6104        current: Value,
6105        place_ty: Ty,
6106        op: BinOp,
6107        value: &Expr,
6108        hoisted: Option<Value>,
6109        compute: Ty,
6110    ) -> Value {
6111        let span = self.sp(value.range);
6112        if place_ty.is_pointer() {
6113            // `p += n` moves by elements, not by bytes.
6114            let access = current.at(prec::CALL, span);
6115            let offset = match hoisted {
6116                Some(index) => self.offset_of_value(index, op == BinOp::Sub, span),
6117                None => self.offset_argument(value, op == BinOp::Sub, span),
6118            };
6119            let pointee = self.program.types.pointee(place_ty).unwrap_or(Ty::Void);
6120            let offset = match self.vm_scale(pointee, span) {
6121                None => offset,
6122                Some(scale) => quote_spanned! {span=> (#offset).wrapping_mul(#scale) },
6123            };
6124            return Value::new(quote_spanned! {span=> #access.offset(#offset) }, prec::CALL);
6125        }
6126        // A complex computation keeps a real operand real on *both* sides:
6127        // sema left the right one alone, and the left one — the place — is
6128        // widened only as far as the common real type when it is real too. See
6129        // [`Codegen::complex_binary`].
6130        if compute.is_complex() {
6131            let lhs_ty = if place_ty.is_complex() {
6132                compute
6133            } else {
6134                compute.complex_component()
6135            };
6136            let current = self.cast(current, place_ty, lhs_ty, span);
6137            let rhs = self.compound_operand(value, hoisted, span);
6138            let result = self.complex_binary(op, (current, lhs_ty), (rhs, value.ty), compute, span);
6139            return self.cast(result, compute, place_ty, span);
6140        }
6141        let current = self.cast(current, place_ty, compute, span);
6142        let rhs = self.compound_operand(value, hoisted, span);
6143        let result = self.binary(op, current, rhs, compute, span);
6144        self.cast(result, compute, place_ty, span)
6145    }
6146
6147    /// The right operand of a compound assignment, already hoisted or not.
6148    ///
6149    /// The left operand is a place and therefore always typed, so a constant
6150    /// right operand can stay a bare literal.
6151    fn compound_operand(&mut self, value: &Expr, hoisted: Option<Value>, span: Span) -> Value {
6152        match hoisted {
6153            Some(rhs) => rhs,
6154            None => match constant_of(value) {
6155                Some(constant) => self.bare_value(constant, value.ty, span),
6156                None => self.expr(value),
6157            },
6158        }
6159    }
6160
6161    /// Evaluates the right operand of a compound assignment ahead of the read,
6162    /// when C says it happens either wholly before it or wholly after it.
6163    ///
6164    /// `E1 op= E2` is a read, an operation and a write, and C11 6.5.16.2p3
6165    /// makes the three of them *one* evaluation with respect to an
6166    /// indeterminately sequenced function call. Writing them out as
6167    /// `E1 = E1 op E2` would read `E1`, call whatever `E2` calls, and only then
6168    /// store — which is the one order the standard rules out, and which GCC's
6169    /// `pr58943` is about. Binding `E2` to a temporary first restores it: the
6170    /// place is computed, then the call happens, then the read-modify-write.
6171    ///
6172    /// Only an operand that can call something needs it; everything else is
6173    /// left where it was written, because a temporary per `i += 1` would be
6174    /// noise.
6175    fn compound_rhs(&mut self, value: &Expr) -> (TokenStream, Option<Value>) {
6176        if !ir::calls_a_function(value) {
6177            return (TokenStream::new(), None);
6178        }
6179        let span = self.sp(value.range);
6180        let tokens = self.expr(value).at(prec::LOWEST, span);
6181        let tmp = self.temporary();
6182        (
6183            quote_spanned! {span=> let #tmp = #tokens; },
6184            Some(Value::atom(quote_spanned! {span=> #tmp })),
6185        )
6186    }
6187
6188    /// The `offset` argument for an index that has already been emitted.
6189    fn offset_of_value(&mut self, index: Value, sub: bool, span: Span) -> TokenStream {
6190        let tokens = index.at(prec::CAST, span);
6191        let isize_ty = primitive_ty("isize", span);
6192        if sub {
6193            quote_spanned! {span=> -(#tokens as #isize_ty) }
6194        } else {
6195            quote_spanned! {span=> #tokens as #isize_ty }
6196        }
6197    }
6198
6199    /// The value `++place` or `--place` stores.
6200    fn step_value(&mut self, current: Value, ty: Ty, dec: bool, span: Span) -> TokenStream {
6201        if ty.is_pointer() {
6202            let access = current.at(prec::CALL, span);
6203            let pointee = self.program.types.pointee(ty).unwrap_or(Ty::Void);
6204            let one = match (self.vm_scale(pointee, span), dec) {
6205                (None, true) => quote_spanned! {span=> -1 },
6206                (None, false) => quote_spanned! {span=> 1 },
6207                (Some(scale), true) => quote_spanned! {span=> -(#scale) },
6208                (Some(scale), false) => scale,
6209            };
6210            return quote_spanned! {span=> #access.offset(#one) };
6211        }
6212        if ty.is_floating() {
6213            let access = current.at(prec::SUM, span);
6214            let one = Literal::f64_unsuffixed(1.0);
6215            let op = if dec {
6216                quote_spanned! {span=> - }
6217            } else {
6218                quote_spanned! {span=> + }
6219            };
6220            return quote_spanned! {span=> #access #op #one };
6221        }
6222        if ty.is_complex() {
6223            // GCC's `z++` adds one to the *real* part and leaves the
6224            // imaginary one alone, which is the componentwise `z + 1`.
6225            let name = if dec { "sub_real" } else { "add_real" };
6226            let func = self.rt_complex(&format!("{name}_{}", Self::complex_suffix(ty)), span);
6227            let access = current.at(prec::LOWEST, span);
6228            let one = Literal::f64_unsuffixed(1.0);
6229            return quote_spanned! {span=> #func(#access, #one) };
6230        }
6231        if ty.is_bool() {
6232            // `b++` is `b = b + 1 != 0`, which is `true` for `++` and the
6233            // negation of `b` for `--`.
6234            let access = current.at(prec::CAST, span);
6235            let int = self.ty(Ty::Int, span);
6236            let method = Ident::new(if dec { "wrapping_sub" } else { "wrapping_add" }, span);
6237            return quote_spanned! {span=> (#access as #int).#method(1) != 0 };
6238        }
6239        let access = current.at(prec::CALL, span);
6240        let method = Ident::new(if dec { "wrapping_sub" } else { "wrapping_add" }, span);
6241        quote_spanned! {span=> #access.#method(1) }
6242    }
6243
6244    /// Emits a conversion between two scalar types.
6245    fn cast(&mut self, value: Value, from: Ty, to: Ty, span: Span) -> Value {
6246        if from == to {
6247            return value;
6248        }
6249        if from.is_complex() || to.is_complex() {
6250            return self.complex_cast(value, from, to, span);
6251        }
6252        let types = &self.program.types;
6253        let from_fn = types.is_func_pointer(from);
6254        let to_fn = types.is_func_pointer(to);
6255        if to.is_bool() {
6256            if from.is_pointer() {
6257                // Handled by the caller for the common shapes; this is the
6258                // explicit `(_Bool)p`.
6259                let tokens = value.at(prec::CALL, span);
6260                return if from_fn {
6261                    let braced = braced(tokens, span);
6262                    Value::new(quote_spanned! {span=> #braced.is_some() }, prec::CALL)
6263                } else {
6264                    Value::new(quote_spanned! {span=> !#tokens.is_null() }, prec::UNARY)
6265                };
6266            }
6267            // Converting to `_Bool` yields 0 or 1, which is what a comparison
6268            // against zero gives.
6269            let zero = self.zero_tokens(from, span);
6270            let tokens = value.at(prec::CMP + 1, span);
6271            return Value::new(quote_spanned! {span=> #tokens != #zero }, prec::CMP);
6272        }
6273        if from_fn || to_fn {
6274            // Rust has no `as` between an `Option<fn>` and anything else, so a
6275            // transmute is the honest translation of what C's cast does — but
6276            // only between two things of the same size. An integer of any
6277            // other width goes through `usize`, which is what C's own
6278            // implementation-defined conversion between a pointer and an
6279            // integer amounts to.
6280            let target = self.ty(to, span);
6281            let source = self.ty(from, span);
6282            // Two C function types the generated Rust cannot tell apart need
6283            // no transmute at all: `void (*)()` and `void (*)(void)` are
6284            // distinct types in C and one `Option<unsafe extern "C" fn()>`
6285            // here. Writing the transmute anyway would be a no-op that still
6286            // has to be inside an `unsafe` block, which a `static` initialiser
6287            // then has to grow.
6288            if from_fn && to_fn && source.to_string() == target.to_string() {
6289                return value;
6290            }
6291            let usize_ty = primitive_ty("usize", span);
6292            if to_fn && !from.is_pointer() {
6293                let tokens = value.at(prec::CAST, span);
6294                return Value::new(
6295                    quote_spanned! {span=>
6296                        ::core::mem::transmute::<#usize_ty, #target>(#tokens as #usize_ty)
6297                    },
6298                    prec::CALL,
6299                );
6300            }
6301            if from_fn && !to.is_pointer() {
6302                let tokens = value.at(prec::LOWEST, span);
6303                return Value::new(
6304                    quote_spanned! {span=>
6305                        ::core::mem::transmute::<#source, #usize_ty>(#tokens) as #target
6306                    },
6307                    prec::CAST,
6308                )
6309                .type_end(true);
6310            }
6311            let tokens = value.at(prec::LOWEST, span);
6312            return Value::new(
6313                quote_spanned! {span=>
6314                    ::core::mem::transmute::<#source, #target>(#tokens)
6315                },
6316                prec::CALL,
6317            );
6318        }
6319        let target = self.ty(to, span);
6320        if from.is_pointer() && to.is_integer() {
6321            // Rust only casts a pointer to `usize`; the rest is an ordinary
6322            // integer conversion.
6323            let tokens = value.at(prec::CAST, span);
6324            let usize_ty = primitive_ty("usize", span);
6325            return Value::new(
6326                quote_spanned! {span=> #tokens as #usize_ty as #target },
6327                prec::CAST,
6328            )
6329            .type_end(true);
6330        }
6331        if from.is_bool() && to.is_floating() {
6332            // Rust has no `bool as f64`; C's `_Bool` to floating conversion
6333            // goes through the integer value.
6334            let int = self.ty(Ty::Int, span);
6335            let tokens = value.at(prec::CAST, span);
6336            return Value::new(
6337                quote_spanned! {span=> #tokens as #int as #target },
6338                prec::CAST,
6339            )
6340            .type_end(true);
6341        }
6342        let tokens = value.at(prec::CAST, span);
6343        Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
6344    }
6345
6346    // -- places -------------------------------------------------------------
6347
6348    /// A place, ready to be read from or written to.
6349    ///
6350    /// `mutable` says whether the place is about to be assigned to or have its
6351    /// address taken, which is what decides whether a `const` pointer under it
6352    /// has to lose the qualifier: Rust refuses `&raw mut (*p).f` when `p` is a
6353    /// `*const T`, while reading through one is fine.
6354    fn place(&mut self, place: &Place, mutable: bool) -> LoweredPlace {
6355        // Even *reading* an atomic object needs a `*mut` to it:
6356        // `AtomicX::from_ptr` takes one, and a `const _Atomic int *` would
6357        // otherwise reach `&raw mut *p` through a `*const` pointer, which
6358        // Rust refuses. What C promises is enough for the cast — every object
6359        // this crate generates lives in writable storage.
6360        let atomic = matches!(place.ty, Ty::Atomic(_));
6361        let mut lowered = self.place_access(place, mutable || atomic);
6362        if lowered.bits.is_none() && self.place_underaligned(place) {
6363            lowered.unaligned = true;
6364        }
6365        if let Ty::Atomic(id) = place.ty {
6366            let inner = self.program.types.atomic_inner(id);
6367            lowered.atomic = ir::atomic_class(&self.program.types, inner, &self.options.target)
6368                .map(|c| (c, inner));
6369            // There is no unaligned atomic: the alignment of an `_Atomic` type
6370            // is its size, and sema refuses the declarations that could not
6371            // have it.
6372            if lowered.atomic.is_some() {
6373                lowered.unaligned = false;
6374            }
6375        }
6376        lowered
6377    }
6378
6379    /// Whether the place has to be reached through an unaligned load or store.
6380    ///
6381    /// Two shapes need one. A `*p` or a `p[i]` whose pointer this crate itself
6382    /// built out of a packed member is underaligned, and so is a member read
6383    /// through a pointer to a record that is: `(*(T *) &buf).f`, where `buf` is
6384    /// a `char` array, is a member access Rust would compile to an aligned load
6385    /// of a byte-aligned address. A member of a *packed* record whose own
6386    /// address is fine needs nothing — Rust knows the layout of the item it was
6387    /// given and reads such a member unaligned by itself.
6388    fn place_underaligned(&self, place: &Place) -> bool {
6389        match &place.kind {
6390            PlaceKind::Deref(_) | PlaceKind::Index { .. } => {
6391                self.place_align(place) < self.type_align(place.ty)
6392            }
6393            PlaceKind::Field { base, .. } => self.place_align(base) < self.type_align(base.ty),
6394            // A part of a complex object reached through a packed member is
6395            // no better aligned than the object is.
6396            PlaceKind::ComplexPart { .. } => self.place_align(place) < self.type_align(place.ty),
6397            _ => false,
6398        }
6399    }
6400
6401    /// The alignment code generation can count on for a place's address.
6402    ///
6403    /// Everything C promises about an object's alignment holds for a place that
6404    /// names one, so the interesting half is what this crate itself can see
6405    /// through: the address of a member sits at its offset from a base whose
6406    /// alignment is known, and a cast in between changes nothing. Anything else
6407    /// — a pointer out of a variable, a parameter, a call — is taken at C's
6408    /// word and assumed to point at something its type is aligned for.
6409    fn place_align(&self, place: &Place) -> u64 {
6410        match &place.kind {
6411            PlaceKind::Deref(ptr) => self.pointer_align(ptr),
6412            PlaceKind::Index { base, .. } => {
6413                // Every element of an array sits at a multiple of the element
6414                // size from the first, and a size is always a multiple of the
6415                // alignment, so the elements are no worse aligned than the
6416                // element type asks and no better than the array is.
6417                self.pointer_align(base).min(self.type_align(place.ty))
6418            }
6419            PlaceKind::Field {
6420                base,
6421                record,
6422                index,
6423            } => {
6424                let base_align = self.place_align(base);
6425                let offset = self.program.types.record(*record).fields[*index].offset;
6426                if offset == 0 {
6427                    base_align
6428                } else {
6429                    base_align.min(1 << offset.trailing_zeros())
6430                }
6431            }
6432            // The real part sits at the object's own address and the imaginary
6433            // one exactly one component later, which is a power of two.
6434            PlaceKind::ComplexPart { base, imag } => {
6435                let base_align = self.place_align(base);
6436                if *imag {
6437                    base_align.min(place.ty.size_bytes(&self.options.target).max(1))
6438                } else {
6439                    base_align
6440                }
6441            }
6442            // An `_Alignas` on the declaration is a promise about the object
6443            // that the wrapper really keeps.
6444            PlaceKind::Object(id) => self
6445                .object_align(*id)
6446                .unwrap_or(1)
6447                .max(self.type_align(place.ty)),
6448            _ => self.type_align(place.ty),
6449        }
6450    }
6451
6452    /// The alignment of what a pointer expression points at.
6453    fn pointer_align(&self, ptr: &Expr) -> u64 {
6454        match &ptr.kind {
6455            ExprKind::AddrOf(place) => self.place_align(place),
6456            // A pointer cast moves no bytes, and neither does the decay of an
6457            // array to its first element.
6458            ExprKind::Cast(inner) if inner.ty.is_pointer() || inner.ty.is_array() => {
6459                self.pointer_align(inner)
6460            }
6461            ExprKind::PtrOffset { ptr, .. } => self
6462                .pointer_align(ptr)
6463                .min(self.pointee_align(ptr.ty).unwrap_or(1)),
6464            _ => self.pointee_align(ptr.ty).unwrap_or(u64::MAX),
6465        }
6466    }
6467
6468    /// The alignment of the type a pointer or array type addresses.
6469    fn pointee_align(&self, ty: Ty) -> Option<u64> {
6470        let pointee = self.program.types.pointee(ty)?;
6471        (!pointee.is_void() && !pointee.is_func()).then(|| self.type_align(pointee))
6472    }
6473
6474    /// The alignment the *generated Rust type* has, which is what a `*p` in the
6475    /// expansion is checked against.
6476    fn type_align(&self, ty: Ty) -> u64 {
6477        match ty {
6478            // A packed record's item is one byte aligned however strict C says
6479            // the record is; see `ir::RecordDef::rust_align`.
6480            Ty::Record(id) => self.program.types.record(id).rust_align,
6481            Ty::Array(id) => self.type_align(self.program.types.array_type(id).elem),
6482            _ => self
6483                .program
6484                .types
6485                .size_align(ty, &self.options.target)
6486                .map_or(1, |layout| layout.align),
6487        }
6488    }
6489
6490    fn place_access(&mut self, place: &Place, mutable: bool) -> LoweredPlace {
6491        let span = self.sp(place.range);
6492        match &place.kind {
6493            PlaceKind::Object(id) if self.program.object(*id).storage.is_thread_local() => {
6494                // A thread-local object is reached through the `*mut T` inside
6495                // its cell, which is valid for as long as this thread's copy
6496                // of the object is — exactly the lifetime C gives it. The
6497                // pointer is taken once and the place is a dereference of it,
6498                // so an expression that reads the object twice still calls
6499                // `with` once.
6500                let name = self.object_ident(*id, span);
6501                let tmp = self.temporary_at(span);
6502                let cell = Ident::new("__cinrs_cell", Span::mixed_site());
6503                // The cell holds whatever wrappers the storage carries, and
6504                // the object is reached through them exactly as it is for
6505                // every other storage class.
6506                let object = parenthesize(quote_spanned! {span=> *#tmp }, span);
6507                let object = self.through_storage(*id, object, span);
6508                LoweredPlace::plain(
6509                    quote_spanned! {span=>
6510                        let #tmp = #name.with(|#cell| ::core::cell::UnsafeCell::get(#cell));
6511                    },
6512                    object,
6513                )
6514            }
6515            PlaceKind::Object(id) => {
6516                let access = self.object_access(*id, span);
6517                LoweredPlace::plain(TokenStream::new(), access)
6518            }
6519            PlaceKind::Deref(ptr) => self.deref_place(ptr, place.ty, mutable, span),
6520            PlaceKind::Index { base, index } => {
6521                let pointer = self.pointer_operand(base, place.ty, mutable, span);
6522                let offset = self.scaled_offset(place.ty, index, false, span);
6523                let tmp = self.temporary_at(span);
6524                LoweredPlace::plain(
6525                    quote_spanned! {span=> let #tmp = #pointer.offset(#offset); },
6526                    parenthesize(quote_spanned! {span=> *#tmp }, span),
6527                )
6528            }
6529            PlaceKind::Field {
6530                base,
6531                record,
6532                index,
6533            } => {
6534                let field = self.program.types.record(*record).fields[*index].clone();
6535                let lowered = self.place(base, mutable);
6536                let access = lowered.access;
6537                let Some(bits) = &field.bits else {
6538                    let name = self.c_ident(&field.name, span);
6539                    return LoweredPlace::plain(
6540                        lowered.setup,
6541                        quote_spanned! {span=> #access.#name },
6542                    );
6543                };
6544                // The accessors take `&self` and `&mut self`, and a reference
6545                // to a `static mut` is exactly what edition 2024 refuses; the
6546                // raw pointer keeps the item out of the expression.
6547                let access = if rooted_in_static(base, self.program) {
6548                    parenthesize(quote_spanned! {span=> *(&raw mut #access) }, span)
6549                } else {
6550                    access
6551                };
6552                LoweredPlace {
6553                    setup: lowered.setup,
6554                    access,
6555                    bits: Some(BitAccess {
6556                        getter: self.c_ident(&bits.getter, span),
6557                        setter: self.c_ident(&bits.setter, span),
6558                    }),
6559                    unaligned: false,
6560                    atomic: None,
6561                }
6562            }
6563            // `__real__ z` and `__imag__ z` are the two fields of the runtime's
6564            // `Complex`, which is why they are assignable: the place is a Rust
6565            // place expression like any member access.
6566            PlaceKind::ComplexPart { base, imag } => {
6567                let lowered = self.place(base, mutable);
6568                let access = lowered.access;
6569                let field = Ident::new(if *imag { "im" } else { "re" }, span);
6570                LoweredPlace::plain(lowered.setup, quote_spanned! {span=> #access.#field })
6571            }
6572            PlaceKind::Str(id) => {
6573                let pointer = self.string_pointer(*id, !mutable, span);
6574                let tmp = self.temporary_at(span);
6575                LoweredPlace::plain(
6576                    quote_spanned! {span=> let #tmp = #pointer; },
6577                    parenthesize(quote_spanned! {span=> *#tmp }, span),
6578                )
6579            }
6580            PlaceKind::Temporary(expr) => {
6581                let ty = expr.ty;
6582                let value = self.expr_at(expr, ty);
6583                let tmp = self.temporary();
6584                LoweredPlace::plain(
6585                    quote_spanned! {span=> let mut #tmp = #value; },
6586                    quote_spanned! {span=> #tmp },
6587                )
6588            }
6589            // The binding itself was made at the top of the enclosing block —
6590            // C gives the object that lifetime, and it is what lets `&(T){…}`
6591            // outlive the expression. What happens *here* is the
6592            // initialisation, so that side effects in it happen where the
6593            // literal was written and a literal in a loop is rebuilt on every
6594            // iteration.
6595            PlaceKind::CompoundLiteral { object, init } => {
6596                let name = self.object_ident(*object, span);
6597                let value = self.expr_at(init, place.ty);
6598                LoweredPlace::plain(
6599                    quote_spanned! {span=> #name = #value; },
6600                    quote_spanned! {span=> #name },
6601                )
6602            }
6603        }
6604    }
6605
6606    /// Reads a lowered place.
6607    fn read(&self, place: &LoweredPlace, span: Span) -> Value {
6608        let access = &place.access;
6609        if let Some((class, ty)) = place.atomic {
6610            let object = self.atomic_object_of(place, span);
6611            let order = self.ordering(ir::MemOrder::SeqCst, span);
6612            return self.repr_to_value(
6613                class,
6614                ty,
6615                quote_spanned! {span=> #object.load(#order) },
6616                span,
6617            );
6618        }
6619        match &place.bits {
6620            Some(bits) => {
6621                let getter = &bits.getter;
6622                Value::new(quote_spanned! {span=> #access.#getter() }, prec::CALL)
6623            }
6624            None if place.unaligned => Value::new(
6625                quote_spanned! {span=> (&raw const #access).read_unaligned() },
6626                prec::CALL,
6627            ),
6628            None => Value::atom(access.clone()),
6629        }
6630    }
6631
6632    /// The statement that stores `value` into a lowered place.
6633    fn write(&self, place: &LoweredPlace, value: TokenStream, span: Span) -> TokenStream {
6634        let access = &place.access;
6635        if let Some((class, _)) = place.atomic {
6636            let object = self.atomic_object_of(place, span);
6637            let order = self.ordering(ir::MemOrder::SeqCst, span);
6638            let value = self.value_to_repr(class, Value::new(value, prec::LOWEST), span);
6639            return quote_spanned! {span=> #object.store(#value, #order); };
6640        }
6641        match &place.bits {
6642            Some(bits) => {
6643                let setter = &bits.setter;
6644                quote_spanned! {span=> #access.#setter(#value); }
6645            }
6646            None if place.unaligned => {
6647                quote_spanned! {span=> (&raw mut #access).write_unaligned(#value); }
6648            }
6649            None => quote_spanned! {span=> #access = #value; },
6650        }
6651    }
6652
6653    /// The `&AtomicX` an `_Atomic` place is reached through.
6654    ///
6655    /// A raw pointer to the object rather than a reference to it: the object
6656    /// is a plain `static mut` or `let mut` of the underlying type, and its
6657    /// address is what `from_ptr` wants.
6658    fn atomic_object_of(&self, place: &LoweredPlace, span: Span) -> TokenStream {
6659        let access = &place.access;
6660        let class = place.atomic.expect("an atomic place").0;
6661        self.atomic_ref(class, quote_spanned! {span=> (&raw mut #access) }, span)
6662    }
6663
6664    /// `*p` as a place.
6665    fn deref_place(&mut self, ptr: &Expr, pointee: Ty, mutable: bool, span: Span) -> LoweredPlace {
6666        let simple =
6667            matches!(&ptr.kind, ExprKind::Load(p) if matches!(p.kind, PlaceKind::Object(_)));
6668        if simple {
6669            // A variable holding the pointer can be dereferenced as often as
6670            // needed, so no temporary is called for.
6671            let tokens = self.pointer_operand(ptr, pointee, mutable, span);
6672            return LoweredPlace::plain(
6673                TokenStream::new(),
6674                parenthesize(quote_spanned! {span=> *#tokens }, span),
6675            );
6676        }
6677        let value = self.pointer_operand(ptr, pointee, mutable, span);
6678        let tmp = self.temporary_at(span);
6679        LoweredPlace::plain(
6680            quote_spanned! {span=> let #tmp = #value; },
6681            parenthesize(quote_spanned! {span=> *#tmp }, span),
6682        )
6683    }
6684
6685    /// The pointer a place is built on.
6686    ///
6687    /// Writing through a `*const T` is not allowed even in `unsafe` Rust, and
6688    /// C's own `const` checking has already happened in sema, so a place that
6689    /// is about to be written to (or have its address taken) drops the
6690    /// qualifier here rather than at every use.
6691    fn pointer_operand(
6692        &mut self,
6693        ptr: &Expr,
6694        pointee: Ty,
6695        mutable: bool,
6696        span: Span,
6697    ) -> TokenStream {
6698        if mutable && self.program.types.points_to_const(ptr.ty) {
6699            let target = self.pointee_ty(pointee, span);
6700            let tokens = self.expr(ptr).at(prec::CAST, span);
6701            return parenthesize(quote_spanned! {span=> #tokens as *mut #target }, span);
6702        }
6703        self.expr(ptr).at(prec::CALL, span)
6704    }
6705
6706    /// The address of a place, as a pointer of type `want`.
6707    fn address_of(&mut self, place: &Place, want: Ty, span: Span) -> Value {
6708        // A variably modified object's binding already *is* the address of its
6709        // first element, so both the decay `a` and the array pointer `&a` are
6710        // that binding — the second one only differs in its C type.
6711        if let PlaceKind::Object(id) = &place.kind
6712            && self.program.types.is_vm(place.ty)
6713        {
6714            let name = self.object_ident(*id, span);
6715            let value = Value::atom(quote_spanned! {span=> #name });
6716            let elem = self.program.types.elem(place.ty);
6717            let natural = self.program.types.pointee(want) == elem
6718                && !self.program.types.points_to_const(want);
6719            if natural {
6720                return value;
6721            }
6722            let target = self.ty(want, span);
6723            let tokens = value.at(prec::CAST, span);
6724            return Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST)
6725                .type_end(true);
6726        }
6727        // `&*p` is `p`, and `&a[i]` is `a + i`; saying so keeps the output
6728        // free of pointless round trips through a place.
6729        match &place.kind {
6730            PlaceKind::Deref(ptr) => {
6731                let from = ptr.ty;
6732                let value = self.expr(ptr);
6733                return self.pointer_cast(value, from, want, span);
6734            }
6735            PlaceKind::Index { base, index } => {
6736                let from = base.ty;
6737                let pointer = self.expr(base).at(prec::CALL, span);
6738                let offset = self.scaled_offset(place.ty, index, false, span);
6739                let value = Value::new(
6740                    quote_spanned! {span=> #pointer.offset(#offset) },
6741                    prec::CALL,
6742                );
6743                return self.pointer_cast(value, from, want, span);
6744            }
6745            PlaceKind::Str(id) => {
6746                let konst = self.program.types.points_to_const(want);
6747                let tokens = self.string_pointer(*id, konst, span);
6748                return Value::new(tokens, prec::CALL);
6749            }
6750            _ => {}
6751        }
6752        let lowered = self.place(place, true);
6753        let access = lowered.access;
6754        let address = quote_spanned! {span=> &raw mut #access };
6755        let natural = Value::new(parenthesize(address, span), prec::ATOM);
6756        let value = self.array_or_pointer_cast(natural, place.ty, want, span);
6757        if lowered.setup.is_empty() {
6758            return value;
6759        }
6760        let setup = lowered.setup;
6761        let tokens = value.at(prec::LOWEST, span);
6762        Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
6763    }
6764
6765    /// Adjusts `&raw mut place` to the pointer type the expression wants.
6766    fn array_or_pointer_cast(&mut self, value: Value, from: Ty, want: Ty, span: Span) -> Value {
6767        if let Ty::Array(id) = from {
6768            // The address of an array is a pointer to the array; decaying it
6769            // to a pointer to the first element is a `cast`, which — unlike
6770            // `as` — cannot silently change anything else.
6771            let array = self.program.types.array_type(id);
6772            let wanted_pointee = self.program.types.pointee(want);
6773            if wanted_pointee == Some(array.elem) {
6774                let elem = self.pointee_ty(array.elem, span);
6775                let tokens = value.at(prec::CALL, span);
6776                let cast = Value::new(quote_spanned! {span=> #tokens.cast::<#elem>() }, prec::CALL);
6777                return self.constify(cast, want, span);
6778            }
6779        }
6780        let natural_mut = matches!(self.program.types.pointee(want), Some(pointee) if pointee == from)
6781            && !self.program.types.points_to_const(want);
6782        if natural_mut {
6783            return value;
6784        }
6785        let target = self.ty(want, span);
6786        let tokens = value.at(prec::CAST, span);
6787        Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
6788    }
6789
6790    /// Adds the `as *const T` that a `*mut T` needs to become a `*const T`.
6791    fn constify(&mut self, value: Value, want: Ty, span: Span) -> Value {
6792        if !self.program.types.points_to_const(want) {
6793            return value;
6794        }
6795        let target = self.ty(want, span);
6796        let tokens = value.at(prec::CAST, span);
6797        Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
6798    }
6799
6800    /// Casts a pointer value to the pointer type wanted.
6801    fn pointer_cast(&mut self, value: Value, from: Ty, want: Ty, span: Span) -> Value {
6802        if from == want {
6803            return value;
6804        }
6805        let target = self.ty(want, span);
6806        let tokens = value.at(prec::CAST, span);
6807        Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
6808    }
6809
6810    /// The pointer a string literal decays to.
6811    fn string_pointer(&mut self, id: ir::StrId, konst: bool, span: Span) -> TokenStream {
6812        let data = self.program.string(id);
6813        let element = data.elem;
6814        if element.size_bytes(&self.options.target) > 1 {
6815            // A `wchar_t`, `char16_t` or `char32_t` literal needs real storage
6816            // of that type; a `static` in the enclosing block is the only
6817            // thing with a long enough lifetime.
6818            let elem = self.ty(element, span);
6819            let mut items = TokenStream::new();
6820            for value in data.values.iter().chain(std::iter::once(&0)) {
6821                let literal =
6822                    int_literal_token(element.wrap(i128::from(*value), &self.options.target), span);
6823                items.extend(quote_spanned! {span=> #literal, });
6824            }
6825            let len = usize_literal(data.len_with_nul(), span);
6826            let name = Ident::new("__CINRS_WIDE", Span::mixed_site());
6827            let array = bracketed(items, span);
6828            let ty = bracketed(quote_spanned! {span=> #elem ; #len }, span);
6829            let pointer = if konst {
6830                quote_spanned! {span=> (&raw const #name).cast::<#elem>() }
6831            } else {
6832                quote_spanned! {span=> (&raw const #name).cast::<#elem>().cast_mut() }
6833            };
6834            return quote_spanned! {span=>
6835                { static #name: #ty = #array; #pointer }
6836            };
6837        }
6838        // A narrow or `u8"…"` literal is a Rust byte string, whose elements
6839        // are the same bytes whether C calls them `char` or `char8_t`.
6840        let mut literal = Literal::byte_string(&nul_terminated(&data.values));
6841        literal.set_span(span);
6842        let elem = self.ty(element, span);
6843        if konst {
6844            quote_spanned! {span=> #literal.as_ptr().cast::<#elem>() }
6845        } else {
6846            quote_spanned! {span=> #literal.as_ptr().cast::<#elem>().cast_mut() }
6847        }
6848    }
6849
6850    // -- literals -----------------------------------------------------------
6851
6852    fn int_literal(&self, value: i128, ty: Ty, span: Span) -> Value {
6853        if ty.is_bool() {
6854            return Value::atom(bare_int_literal(value, ty, span));
6855        }
6856        if ty == Ty::UInt128 {
6857            // The constant is the bit pattern; the literal has to spell the
6858            // `u128` it stands for rather than the `i128` those bits read as.
6859            let literal = u128_literal_token(value as u128, span);
6860            let target = self.ty(ty, span);
6861            return Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST)
6862                .type_end(true);
6863        }
6864        let literal = int_literal_token(value, span);
6865        let target = self.ty(ty, span);
6866        Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
6867    }
6868
6869    fn float_literal(&self, value: f64, ty: Ty, span: Span) -> Value {
6870        if !value.is_finite() {
6871            return Value::new(self.non_finite_literal(value, ty, span), prec::CAST).type_end(true);
6872        }
6873        let literal = float_literal_token(value, span);
6874        let target = self.ty(ty, span);
6875        Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
6876    }
6877
6878    /// An infinity or a NaN, which no Rust literal can spell.
6879    ///
6880    /// A NaN that is not the default quiet one — `__builtin_nan("0x123")`, and
6881    /// the negative NaN `-__builtin_nan("")` is — is written out bit for bit.
6882    /// `f64::NAN` is *one* NaN, and a payload and a sign are part of the value
6883    /// a program asked for; `as` between the two widths is free to lose both.
6884    fn non_finite_literal(&self, value: f64, ty: Ty, span: Span) -> TokenStream {
6885        let target = self.ty(ty, span);
6886        let f64_ty = primitive_ty("f64", span);
6887        if value.is_nan() {
6888            let bits = value.to_bits();
6889            if bits == f64::NAN.to_bits() {
6890                return quote_spanned! {span=> <#f64_ty>::NAN as #target };
6891            }
6892            if ty == Ty::Float {
6893                let f32_ty = primitive_ty("f32", span);
6894                let literal =
6895                    unsigned_hex_literal(u64::from(ir::narrow_nan_bits(bits)), "u32", span);
6896                return quote_spanned! {span=> <#f32_ty>::from_bits(#literal) };
6897            }
6898            let literal = unsigned_hex_literal(bits, "u64", span);
6899            return quote_spanned! {span=> <#f64_ty>::from_bits(#literal) as #target };
6900        }
6901        if value.is_sign_negative() {
6902            quote_spanned! {span=> -<#f64_ty>::INFINITY as #target }
6903        } else {
6904            quote_spanned! {span=> <#f64_ty>::INFINITY as #target }
6905        }
6906    }
6907
6908    /// The all-bits-zero value of a type.
6909    fn zero_tokens(&self, ty: Ty, span: Span) -> TokenStream {
6910        match ty {
6911            // The zero of an `_Atomic T` is the zero of `T`: the object is
6912            // generated as a plain `T`, and initialising it is a plain write.
6913            Ty::Atomic(id) => self.zero_tokens(self.program.types.atomic_inner(id), span),
6914            _ if ty.is_complex() => {
6915                let zero = bare_float_literal(0.0, span);
6916                self.complex_new(ty, zero.clone(), zero, span)
6917                    .at(prec::LOWEST, span)
6918            }
6919            _ if ty.is_floating() => bare_float_literal(0.0, span),
6920            _ if ty.is_integer() => bare_int_literal(0, ty, span),
6921            // A variably modified array is generated as a pointer, and the
6922            // only thing that ever asks for its zero is the hoisting a [CFG
6923            // body](crate::cfg) does before the declaration is reached.
6924            Ty::Array(_) if self.program.types.is_vm(ty) => {
6925                let step = self.ty(self.program.types.vm_step_ty(ty), span);
6926                quote_spanned! {span=> ::core::ptr::null_mut::<#step>() }
6927            }
6928            Ty::Pointer(id) => {
6929                let pointer = self.program.types.pointer_type(id);
6930                if let Ty::Func(func) = pointer.pointee {
6931                    // The signature is written out rather than left to
6932                    // inference: a null function pointer is often the whole
6933                    // expression — `((void (*)(void))0)()` — and a bare
6934                    // `Option::None` there is `E0282`.
6935                    let signature = self.fn_ty(func, span);
6936                    return quote_spanned! {span=>
6937                        ::core::option::Option::<#signature>::None
6938                    };
6939                }
6940                let pointee = self.pointee_ty(pointer.pointee, span);
6941                if pointer.konst {
6942                    quote_spanned! {span=> ::core::ptr::null::<#pointee>() }
6943                } else {
6944                    quote_spanned! {span=> ::core::ptr::null_mut::<#pointee>() }
6945                }
6946            }
6947            other => {
6948                // A zeroed aggregate: `mem::zeroed` is a `const fn`, so this
6949                // works in a `static` initialiser as well as in a body.
6950                let target = self.ty(other, span);
6951                quote_spanned! {span=> ::core::mem::zeroed::<#target>() }
6952            }
6953        }
6954    }
6955}
6956
6957/// The value a bit-field's initialiser folds to, if it folds at all.
6958///
6959/// Sema has already reduced a constant to a bare `Int` node, and the implicit
6960/// zero every unmentioned member gets is either that or [`ExprKind::Zeroed`].
6961fn constant_bits(expr: &Expr) -> Option<i128> {
6962    match &expr.kind {
6963        ExprKind::Int(value) => Some(*value),
6964        ExprKind::Zeroed if expr.ty.is_integer() => Some(0),
6965        _ => None,
6966    }
6967}
6968
6969/// Writes the low `width` bits of `value` into a run's storage bytes.
6970fn pack_bits(storage: &mut [u8], bits: &ir::BitField, value: i128) {
6971    let start = bits.offset_in_storage();
6972    for bit in 0..u64::from(bits.width) {
6973        if (value as u128) >> bit & 1 == 0 {
6974            continue;
6975        }
6976        let at = start + bit;
6977        if let Some(byte) = storage.get_mut((at / 8) as usize) {
6978            *byte |= 1 << (at % 8);
6979        }
6980    }
6981}
6982
6983/// `[0x1f, 0x00, …]`, the initialiser of a storage field.
6984fn byte_array(bytes: &[u8], span: Span) -> TokenStream {
6985    if bytes.iter().all(|byte| *byte == 0) {
6986        let len = usize_literal(bytes.len() as u64, span);
6987        return bracketed(quote_spanned! {span=> 0; #len }, span);
6988    }
6989    let mut items = TokenStream::new();
6990    for byte in bytes {
6991        let value = hex_literal(u64::from(*byte), span);
6992        items.extend(quote_spanned! {span=> #value, });
6993    }
6994    bracketed(items, span)
6995}
6996
6997/// Whether a place ultimately names an object with static storage duration.
6998///
6999/// The bit-field accessors borrow, and edition 2024 refuses a reference to a
7000/// `static mut`; a place rooted in one is reached through `&raw mut` instead.
7001/// Anything behind a pointer is already a raw dereference, so it needs nothing
7002/// — a thread-local object included, since its place is the dereference of the
7003/// pointer out of its cell.
7004///
7005/// It is also what says whether an initialiser refers to an item, which a Rust
7006/// `const` may not; see [`Codegen::const_initialisable`].
7007fn rooted_in_static(place: &Place, program: &Program) -> bool {
7008    let mut place = place;
7009    loop {
7010        match &place.kind {
7011            PlaceKind::Object(id) => {
7012                let storage = &program.object(*id).storage;
7013                return !matches!(storage, Storage::Automatic) && !storage.is_thread_local();
7014            }
7015            PlaceKind::Field { base, .. } => place = base,
7016            _ => return false,
7017        }
7018    }
7019}
7020
7021/// The Rust unsigned integer of a given width, which is what the bit-counting
7022/// builtins are defined on.
7023fn unsigned_rust_ty(width: u32, span: Span) -> TokenStream {
7024    primitive_ty(
7025        match width {
7026            0..=8 => "u8",
7027            9..=16 => "u16",
7028            17..=32 => "u32",
7029            _ => "u64",
7030        },
7031        span,
7032    )
7033}
7034
7035/// The signed counterpart, for `__builtin_clrsb`.
7036fn signed_rust_ty(width: u32, span: Span) -> TokenStream {
7037    primitive_ty(
7038        match width {
7039            0..=8 => "i8",
7040            9..=16 => "i16",
7041            17..=32 => "i32",
7042            _ => "i64",
7043        },
7044        span,
7045    )
7046}
7047
7048/// A mask of `width` low bits, inside a word of `word_bits`.
7049fn mask_of(width: u32, word_bits: u32) -> u128 {
7050    let width = width.min(word_bits);
7051    if width >= 128 {
7052        u128::MAX
7053    } else {
7054        (1u128 << width) - 1
7055    }
7056}
7057
7058/// A mask literal, written in hexadecimal at the width of its word.
7059///
7060/// A `u128` mask carries its suffix: a bare hexadecimal literal above
7061/// `u64::MAX` would be out of range for whatever `u64` the surrounding
7062/// annotation asked for, and the annotation is what makes the narrow case
7063/// readable.
7064fn word_literal(value: u128, word_bits: u32, span: Span) -> TokenStream {
7065    if word_bits <= 64 {
7066        return hex_literal(value as u64, span);
7067    }
7068    let mut literal = Literal::from_str(&format!("0x{value:x}u128"))
7069        .unwrap_or_else(|_| Literal::u128_suffixed(value));
7070    literal.set_span(span);
7071    TokenStream::from(TokenTree::Literal(literal))
7072}
7073
7074/// A `u64` literal written in hexadecimal, which is how a mask reads.
7075fn hex_literal(value: u64, span: Span) -> TokenStream {
7076    let mut literal = Literal::from_str(&format!("0x{value:x}"))
7077        .unwrap_or_else(|_| Literal::u64_unsuffixed(value));
7078    literal.set_span(span);
7079    TokenStream::from(TokenTree::Literal(literal))
7080}
7081
7082/// A state number, which is a `u32` because the state variable is.
7083fn state_literal(value: usize, span: Span) -> TokenStream {
7084    let mut literal = Literal::u32_unsuffixed(value as u32);
7085    literal.set_span(span);
7086    TokenStream::from(TokenTree::Literal(literal))
7087}
7088
7089/// Groups a switch's cases by the block they enter, keeping source order.
7090///
7091/// `case 0: case 1:` reaches the same block through two labels, and one arm
7092/// with an or-pattern is how that should read.
7093fn group_cases(cases: &[(ir::CaseRange, BlockId)]) -> Vec<(BlockId, Vec<ir::CaseRange>)> {
7094    let mut out: Vec<(BlockId, Vec<ir::CaseRange>)> = Vec::new();
7095    for (value, target) in cases {
7096        match out.iter_mut().find(|(block, _)| block == target) {
7097            Some((_, values)) => values.push(*value),
7098            None => out.push((*target, vec![*value])),
7099        }
7100    }
7101    out
7102}
7103
7104/// The Rust pattern one `case` label matches: a literal, or a range.
7105fn case_pattern(value: ir::CaseRange, ty: Ty, span: Span) -> TokenStream {
7106    let low = bare_int_literal(value.low, ty, span);
7107    if value.is_single() {
7108        return low;
7109    }
7110    let high = bare_int_literal(value.high, ty, span);
7111    quote_spanned! {span=> #low ..= #high }
7112}
7113
7114/// The precedence of the tokens [`Codegen::zero_tokens`] produces.
7115fn zero_prec(ty: Ty) -> u8 {
7116    if ty.is_arithmetic() {
7117        prec::ATOM
7118    } else {
7119        prec::CALL
7120    }
7121}
7122
7123/// `#[link_name = "…"]`, which points a renamed declaration back at its symbol.
7124fn link_name(symbol: &str, span: Span) -> TokenStream {
7125    let mut literal = Literal::string(symbol);
7126    literal.set_span(span);
7127    quote_spanned! {span=> #[link_name = #literal] }
7128}
7129
7130/// The attribute that gives a definition the C symbol `symbol`, for a unit
7131/// that asked for `#pragma cinrs export`.
7132///
7133/// `#[unsafe(no_mangle)]` is the edition-2024 spelling and is accepted in every
7134/// edition since 1.82, so one expansion works wherever it is written. It says
7135/// "the name of the item is the symbol", which is not quite always true here:
7136/// a C name that is a Rust keyword becomes `r#match`, and the five names that
7137/// cannot even be raw grow an underscore, so those go through `export_name`
7138/// instead and say the symbol outright.
7139fn export_attr(symbol: &str, item: &Ident, span: Span) -> TokenStream {
7140    if item.to_string().trim_start_matches("r#") == symbol {
7141        return quote_spanned! {span=> #[unsafe(no_mangle)] };
7142    }
7143    let mut literal = Literal::string(symbol);
7144    literal.set_span(span);
7145    quote_spanned! {span=> #[unsafe(export_name = #literal)] }
7146}
7147
7148/// Whether a static initialiser has to be wrapped in `unsafe`.
7149///
7150/// `types` is the arena, because one of the answers depends on it: a cast to
7151/// or from a function pointer is written out as a `transmute`, and that is an
7152/// unsafe call wherever it stands. `frob f[] = { abort };` with `typedef void
7153/// (*frob)();` is the shape — `execute/921110-1`.
7154fn needs_unsafe(types: &ir::Types, expr: &Expr) -> bool {
7155    let recurse = |inner| needs_unsafe(types, inner);
7156    match &expr.kind {
7157        // `mem::zeroed` is unsafe, and so is naming a `static mut`.
7158        ExprKind::Zeroed => !expr.ty.is_scalar(),
7159        // A string literal's address is safe to take; anything else with static
7160        // storage duration is a `static mut`.
7161        ExprKind::AddrOf(place) => !matches!(place.kind, PlaceKind::Str(_)),
7162        ExprKind::Cast(inner) => {
7163            let transmuted = types.is_func_pointer(expr.ty) || types.is_func_pointer(inner.ty);
7164            transmuted || recurse(inner)
7165        }
7166        // `<*mut T>::offset` is an unsafe call however safe its operand is:
7167        // `static const char *p = "foo" + 1;` — `execute/pr53084` — is the
7168        // address of a string literal, which is safe to take, plus one.
7169        ExprKind::PtrOffset { .. } => true,
7170        ExprKind::ComplexOf { re, im } => recurse(re) || recurse(im),
7171        ExprKind::RecordLit { fields, .. } => fields.iter().any(recurse),
7172        ExprKind::UnionLit { value, .. } => recurse(value),
7173        ExprKind::ArrayLit(items) => items.iter().any(recurse),
7174        ExprKind::ArrayRepeat { value, .. } => recurse(value),
7175        _ => false,
7176    }
7177}
7178
7179/// The bytes of a narrow string literal, with its terminating NUL.
7180fn nul_terminated(values: &[u32]) -> Vec<u8> {
7181    let mut bytes: Vec<u8> = values.iter().map(|v| *v as u8).collect();
7182    bytes.push(0);
7183    bytes
7184}
7185
7186// ---------------------------------------------------------------------------
7187// literal tokens
7188// ---------------------------------------------------------------------------
7189
7190/// The largest magnitude an unsuffixed literal is safe to have: Rust infers
7191/// `i32` for a literal with no other constraint.
7192const UNSUFFIXED_LIMIT: i128 = i32::MAX as i128;
7193
7194/// A `u128` literal, always suffixed: nothing else can spell a value above
7195/// `i128::MAX`.
7196fn u128_literal_token(value: u128, span: Span) -> TokenStream {
7197    let mut literal = Literal::u128_suffixed(value);
7198    literal.set_span(span);
7199    TokenStream::from(TokenTree::Literal(literal))
7200}
7201
7202/// A literal for `value`, with a Rust suffix only when inference needs one.
7203fn int_literal_token(value: i128, span: Span) -> TokenStream {
7204    if value == i128::MIN {
7205        // `-(2^127)` has no positive magnitude an `i128` can hold. Rust reads
7206        // the negation of the out-of-range literal as exactly this value,
7207        // which is how `i128::MIN` is written in Rust source too.
7208        let mut literal = Literal::from_str("170141183460469231731687303715884105728i128")
7209            .expect("a decimal literal followed by a suffix is a token");
7210        literal.set_span(span);
7211        return quote_spanned! {span=> -#literal };
7212    }
7213    let magnitude = value.unsigned_abs();
7214    let mut literal = if magnitude <= UNSUFFIXED_LIMIT as u128 {
7215        Literal::u128_unsuffixed(magnitude)
7216    } else if value >= 0 {
7217        if magnitude <= u32::MAX as u128 {
7218            Literal::u32_suffixed(magnitude as u32)
7219        } else if magnitude <= u64::MAX as u128 {
7220            Literal::u64_suffixed(magnitude as u64)
7221        } else {
7222            Literal::u128_suffixed(magnitude)
7223        }
7224    } else if magnitude <= i64::MAX as u128 {
7225        Literal::i64_suffixed(magnitude as i64)
7226    } else {
7227        Literal::i128_suffixed(magnitude as i128)
7228    };
7229    literal.set_span(span);
7230    if value < 0 {
7231        quote_spanned! {span=> -#literal }
7232    } else {
7233        TokenStream::from(TokenTree::Literal(literal))
7234    }
7235}
7236
7237/// A literal for `value` with no suffix at all, for a context that already
7238/// fixes its type.
7239fn bare_int_literal(value: i128, ty: Ty, span: Span) -> TokenStream {
7240    if ty.is_bool() {
7241        let ident = Ident::new(if value != 0 { "true" } else { "false" }, span);
7242        return quote_spanned! {span=> #ident };
7243    }
7244    if ty == Ty::UInt128 {
7245        // The value is carried as a bit pattern; `-1` in a `u128` context is
7246        // not what the constant means.
7247        let mut literal = Literal::u128_unsuffixed(value as u128);
7248        literal.set_span(span);
7249        return TokenStream::from(TokenTree::Literal(literal));
7250    }
7251    let mut literal = Literal::u128_unsuffixed(value.unsigned_abs());
7252    literal.set_span(span);
7253    if value < 0 {
7254        quote_spanned! {span=> -#literal }
7255    } else {
7256        TokenStream::from(TokenTree::Literal(literal))
7257    }
7258}
7259
7260/// The integer a bit-field's bytes are gathered into: `u64`/`i64` for a
7261/// window of 64 bits and the 128-bit primitives for a wider one.
7262///
7263/// All four take the [`core::primitive`] path, `typedef unsigned long long
7264/// u64;` being every bit as ordinary in C as `typedef unsigned __int128 u128;`.
7265fn window_ty(word_bits: u32, signed: bool, span: Span) -> TokenStream {
7266    match (word_bits, signed) {
7267        (128, false) => primitive_ty("u128", span),
7268        (128, true) => primitive_ty("i128", span),
7269        (_, false) => primitive_ty("u64", span),
7270        (_, true) => primitive_ty("i64", span),
7271    }
7272}
7273
7274/// `::core::primitive::u64` and every other primitive this code generator
7275/// writes.
7276///
7277/// **Every** bare primitive name goes through here, and none is ever written
7278/// as a bare identifier, because each of them is a name a C `typedef` can
7279/// take. `typedef _Bool bool;` is in the C23 compatibility header of half the
7280/// world's C — and in gcc.c-torture's `execute/20030714-1` — while `typedef
7281/// unsigned int u32;`, `typedef unsigned long usize;` and `typedef long long
7282/// i64;` are how a great deal of embedded C spells its types. The generated
7283/// item is then `pub type bool = bool;`, which is a cycle (`E0391`), and even
7284/// where it is not a cycle the alias shadows the primitive for the rest of the
7285/// module — so the padding of a `struct`, a bit-field accessor's window and a
7286/// pointer difference would all silently take the C type instead.
7287///
7288/// The [`core::primitive`] module exists for exactly this, and the leading
7289/// `::core` keeps it working in a crate that has renamed its own `core`.
7290fn primitive_ty(name: &str, span: Span) -> TokenStream {
7291    let ident = Ident::new(name, span);
7292    quote_spanned! {span=> ::core::primitive::#ident }
7293}
7294
7295/// Stamps every token of a stream with one span.
7296///
7297/// Only the crate path `#pragma cinrs crate` gives needs it: everything else
7298/// the generator emits is built token by token from a span it already has,
7299/// while that one is *parsed* out of a string and so arrives with call-site
7300/// spans that would send `rustc`'s complaint about a bad path to the wrong
7301/// place.
7302fn respan(tokens: TokenStream, span: Span) -> TokenStream {
7303    tokens
7304        .into_iter()
7305        .map(|tree| {
7306            let mut tree = match tree {
7307                TokenTree::Group(group) => {
7308                    TokenTree::Group(Group::new(group.delimiter(), respan(group.stream(), span)))
7309                }
7310                other => other,
7311            };
7312            tree.set_span(span);
7313            tree
7314        })
7315        .collect()
7316}
7317
7318/// A string literal for an `assert!` message, which a `const` context needs to
7319/// be a literal rather than anything formatted.
7320fn message_literal(text: &str, span: Span) -> TokenStream {
7321    let mut literal = Literal::string(text);
7322    literal.set_span(span);
7323    TokenStream::from(TokenTree::Literal(literal))
7324}
7325
7326/// An array length, which Rust counts in `usize`.
7327fn usize_literal(value: u64, span: Span) -> TokenStream {
7328    let mut literal = Literal::usize_unsuffixed(value as usize);
7329    literal.set_span(span);
7330    TokenStream::from(TokenTree::Literal(literal))
7331}
7332
7333/// The Rust floating type of a C floating type, and the mask that clears the
7334/// sign bit of its bit pattern.
7335///
7336/// `long double` is `double` here, so only the two widths exist.
7337fn float_bit_ty(ty: Ty, span: Span) -> (TokenStream, TokenStream) {
7338    if ty == Ty::Float {
7339        return (
7340            primitive_ty("f32", span),
7341            unsigned_hex_literal(0x7fff_ffff, "u32", span),
7342        );
7343    }
7344    (
7345        primitive_ty("f64", span),
7346        unsigned_hex_literal(0x7fff_ffff_ffff_ffff, "u64", span),
7347    )
7348}
7349
7350/// The quiet bit of a floating type: the leading bit of the mantissa, which is
7351/// set in a quiet NaN and clear in a signalling one.
7352fn quiet_bit_literal(ty: Ty, span: Span) -> TokenStream {
7353    if ty == Ty::Float {
7354        return unsigned_hex_literal(1 << 22, "u32", span);
7355    }
7356    unsigned_hex_literal(1 << 51, "u64", span)
7357}
7358
7359/// A hexadecimal literal with an explicit unsigned suffix.
7360fn unsigned_hex_literal(value: u64, suffix: &str, span: Span) -> TokenStream {
7361    let mut literal = Literal::from_str(&format!("0x{value:x}{suffix}"))
7362        .expect("a hexadecimal literal followed by a suffix is a token");
7363    literal.set_span(span);
7364    TokenStream::from(TokenTree::Literal(literal))
7365}
7366
7367fn float_literal_token(value: f64, span: Span) -> TokenStream {
7368    let mut literal = Literal::f64_unsuffixed(value.abs());
7369    literal.set_span(span);
7370    if value.is_sign_negative() {
7371        quote_spanned! {span=> -#literal }
7372    } else {
7373        TokenStream::from(TokenTree::Literal(literal))
7374    }
7375}
7376
7377fn bare_float_literal(value: f64, span: Span) -> TokenStream {
7378    float_literal_token(value, span)
7379}
7380
7381/// The constant an expression is, if it is one.
7382///
7383/// Sema folds conversions of constants, so a constant is always a bare `Int`
7384/// or `Float` node rather than a cast wrapping one.
7385/// The operands of a chain of comma operators, in source order.
7386///
7387/// `a, b, c` is `Comma(Comma(a, b), c)`, so this walks down the left spine
7388/// into a vector and hands it back the right way round. Iterating rather than
7389/// recursing is what lets a logical source line hold the 4095 characters C23
7390/// 5.2.5.2p1 asks for; see [`Codegen::binary_chain`].
7391fn comma_operands(expr: &Expr) -> Vec<&Expr> {
7392    let mut out = Vec::new();
7393    let mut node = expr;
7394    while let ExprKind::Comma { lhs, rhs } = &node.kind {
7395        out.push(&**rhs);
7396        node = lhs;
7397    }
7398    out.push(node);
7399    out.reverse();
7400    out
7401}
7402
7403fn constant_of(expr: &Expr) -> Option<ConstValue> {
7404    match &expr.kind {
7405        ExprKind::Int(value) => Some(ConstValue::Int(*value)),
7406        ExprKind::Float(value) if value.is_finite() => Some(ConstValue::Float(*value)),
7407        _ => None,
7408    }
7409}
7410
7411fn cmp_tokens(op: CmpOp, span: Span) -> TokenStream {
7412    match op {
7413        CmpOp::Lt => quote_spanned! {span=> < },
7414        CmpOp::Gt => quote_spanned! {span=> > },
7415        CmpOp::Le => quote_spanned! {span=> <= },
7416        CmpOp::Ge => quote_spanned! {span=> >= },
7417        CmpOp::Eq => quote_spanned! {span=> == },
7418        CmpOp::Ne => quote_spanned! {span=> != },
7419    }
7420}
7421
7422#[cfg(test)]
7423mod tests {
7424    use super::*;
7425
7426    /// What a unit spelling `names` gives each of them, as `(C, Rust)` pairs
7427    /// of everything that does not keep its own name.
7428    fn spellings(names: &[&str]) -> Vec<(String, String)> {
7429        let mut pairs: Vec<(String, String)> = unique_spellings(names.iter().copied())
7430            .into_iter()
7431            .collect();
7432        pairs.sort();
7433        pairs
7434    }
7435
7436    /// Asserts that `names` are spelled as `expected` says, and that the unit
7437    /// has no two names with one spelling.
7438    fn assert_spellings(names: &[&str], expected: &[(&str, &str)]) {
7439        let renamed = unique_spellings(names.iter().copied());
7440        let want: Vec<(String, String)> = expected
7441            .iter()
7442            .map(|(c, rust)| ((*c).to_owned(), (*rust).to_owned()))
7443            .collect();
7444        assert_eq!(spellings(names), want);
7445        let mut seen: HashMap<String, &str> = HashMap::new();
7446        for name in names {
7447            let spelling = match renamed.get(*name) {
7448                Some(unique) => unique.clone(),
7449                None => plain_spelling(name),
7450            };
7451            if let Some(other) = seen.insert(spelling.clone(), name) {
7452                assert_eq!(
7453                    other, *name,
7454                    "{other} and {name} are both spelled {spelling}"
7455                );
7456            }
7457        }
7458    }
7459
7460    #[test]
7461    fn a_name_rust_can_spell_keeps_it() {
7462        // Nothing at all is renamed in the program that has no collision,
7463        // keywords included: `match` is `r#match`, which is a token of its
7464        // own.
7465        assert_spellings(&["counter", "match", "loop", "café"], &[]);
7466    }
7467
7468    #[test]
7469    fn the_five_names_that_cannot_be_raw_grow_an_underscore() {
7470        assert_spellings(
7471            &["self", "Self", "super", "crate", "_"],
7472            &[
7473                ("Self", "Self_"),
7474                ("_", "__"),
7475                ("crate", "crate_"),
7476                ("self", "self_"),
7477                ("super", "super_"),
7478            ],
7479        );
7480    }
7481
7482    #[test]
7483    fn a_dollar_is_spelled_out() {
7484        assert_spellings(
7485            &["a$b", "$", "x$"],
7486            &[
7487                ("$", "_dollar_"),
7488                ("a$b", "a_dollar_b"),
7489                ("x$", "x_dollar_"),
7490            ],
7491        );
7492    }
7493
7494    #[test]
7495    fn a_spelling_the_program_already_uses_grows_another_underscore() {
7496        // The collision the whole mechanism exists for: `self` cannot be
7497        // `self_`, because the program has a `self_` of its own.
7498        assert_spellings(&["self", "self_"], &[("self", "self__")]);
7499        assert_spellings(&["self", "self_", "self__"], &[("self", "self___")]);
7500        assert_spellings(&["a$b", "a_dollar_b"], &[("a$b", "a_dollar_b_")]);
7501    }
7502
7503    #[test]
7504    fn the_answer_does_not_depend_on_the_order_the_names_arrive_in() {
7505        let forwards = spellings(&["self", "self_", "crate", "crate_", "a$b", "a_dollar_b"]);
7506        let backwards = spellings(&["a_dollar_b", "a$b", "crate_", "crate", "self_", "self"]);
7507        assert_eq!(forwards, backwards);
7508    }
7509
7510    #[test]
7511    fn a_name_is_spelled_the_same_way_however_often_it_is_collected() {
7512        // Every name space is collected into one list, so a tag, a member and
7513        // a local all spelled `self` arrive several times over.
7514        assert_spellings(&["self", "self", "self_", "self"], &[("self", "self__")]);
7515    }
7516}