cinrs_core/codegen.rs
1//! Code generation: the typed [`ir`] becomes Rust tokens.
2//!
3//! Every token this module emits is stamped with the span of the C construct
4//! it came from, resolved through the [`SourceMap`]. That is what makes an
5//! error `rustc` raises about the *generated* code — a call with the wrong
6//! argument type, say — point at the C the user actually wrote.
7//!
8//! # Shape of the output
9//!
10//! One expansion produces, in this order: the alignment wrappers an
11//! over-aligned object needs, the `struct` and `union` items for every tag and
12//! the flexible-array companions that go with them, the `enum` aliases and
13//! their constants, the file-scope `typedef` aliases, an empty `extern` block
14//! per library the unit links, one `extern` block for everything the unit only
15//! declares, the `static mut` items, and finally the functions. A C function
16//! becomes
17//!
18//! ```text
19//! pub unsafe extern "C" fn name(mut p: ::core::ffi::c_int) -> ::core::ffi::c_int {
20//! unsafe { … }
21//! }
22//! ```
23//!
24//! `pub` is dropped for a C `static` function, which is private to the module
25//! [`crate::expand`] wraps all of this in — that module is what makes C's
26//! internal linkage mean something, and what lets two `c99!` blocks in one
27//! Rust module both `#include` the same header. `#[inline]` is added for an
28//! `inline` function, and the body is wrapped in a single `unsafe` block
29//! because edition 2024 no longer treats the body of an `unsafe fn` as an
30//! unsafe block. Nothing here carries a lint exemption of its own: everything
31//! this module generates goes inside that one module, whose head carries a
32//! single `#![allow(…)]` — an inner attribute, so every item under it
33//! inherits it — for everything a naive translation provokes: unused
34//! bindings, redundant parentheses, non-Rust naming, code a human can see is
35//! unreachable, and so on. The list, and the reasons for each entry, are with
36//! the code in `lib.rs` that wraps a unit in its module.
37//!
38//! A function the unit marked [safe](crate::sema::check_safe) —
39//! `[[cinrs::safe]]`, `__attribute__((cinrs_safe))` or `#pragma cinrs safe` —
40//! is the one exception: it is generated as `pub extern "C" fn` and its body is
41//! *not* wrapped, so `rustc` checks every operation the translation of the C
42//! needs and refuses the ones that are unsafe, with the caret on the C.
43//!
44//! A unit that asked for `#pragma cinrs export` gives everything with external
45//! linkage `#[unsafe(no_mangle)]` on top of that, so that its functions and
46//! objects are real C symbols another unit can link against — with C's own
47//! risk of two definitions of one name, which only the linker will see.
48//!
49//! # Pointers, arrays and records
50//!
51//! Pointers are raw pointers — `T *` is `*mut T`, `const T *` is `*const T`,
52//! `void *` is `*mut c_void` — and pointer arithmetic is `offset`, so nothing
53//! in the output holds a reference and none of Rust's aliasing rules are
54//! involved. Arrays are `[T; N]` and decay to a pointer through
55//! `(&raw mut a).cast::<T>()`, which is a raw pointer from the start; a `&mut`
56//! would both change the meaning and trip `static_mut_refs` on a global. A
57//! function pointer is `Option<unsafe extern "C" fn(…) -> R>`, so that a null
58//! one is representable, and a call through it unwraps first.
59//!
60//! # Places
61//!
62//! Assignment, compound assignment, `++`/`--` and `&` all go through this
63//! module's `place` lowering, which turns an [`ir::Place`] into a *setup*
64//! (statements that must run first, where the pointer arithmetic lands) plus an
65//! *access* (a Rust place expression that may be evaluated more than once).
66//! `p[i()] += 1` therefore evaluates `i()` exactly once, and `s.f`, `p->f` and
67//! `a[i][j]` are all the same three lines of code.
68//!
69//! # Bit-fields
70//!
71//! A bit-field has no address, so it is not a field of the generated item: a
72//! run of them shares one `[u8; K]`, and sema has already worked out which
73//! bytes and bits each member owns (see [`crate::sema`]'s layout). This module
74//! turns that into a pair of inherent methods per named member — plain inline
75//! integer code, no helper type — and a place whose *access* is the record
76//! rather than the member, read with `.f()` and written with `.set_f(v)`. A
77//! constant initialiser is folded into the storage bytes here, which is what
78//! lets a `static` hold one; a non-constant one becomes a zeroed literal
79//! followed by setter calls. A place rooted in a `static mut` goes through
80//! `&raw mut` first, because the accessors borrow.
81//!
82//! # Loops
83//!
84//! Every loop gets a unique Rust label so that `break` and `continue` never
85//! depend on where they sit relative to a `switch`:
86//!
87//! ```text
88//! while (c) B 'lN: while c { B } continue → continue 'lN
89//! do B while (c); 'lN: loop { 'lN_body: { B } continue → break 'lN_body
90//! if !(c) { break 'lN } }
91//! for (i;c;s) B { i; 'lN: loop { if !(c) { break 'lN }
92//! 'lN_body: { B } s; } }
93//! ```
94//!
95//! The body label exists exactly where `continue` has work to do afterwards —
96//! re-testing the condition of a `do`/`while`, or running the step of a `for`.
97//!
98//! # Switch
99//!
100//! Fallthrough is what makes `switch` interesting: control enters at one label
101//! and then runs *through* every group after it. Rust has no such construct,
102//! but labelled blocks compose into one. For groups `g0 … gN` the output is
103//!
104//! ```text
105//! 'swK: {
106//! 'swK_cN: { … 'swK_c1: { 'swK_c0: { match v { … } } g0 } g1 … }
107//! gN
108//! }
109//! ```
110//!
111//! with the dispatch `match` innermost: `break 'swK_ci` lands immediately
112//! before group *i*, and control then falls out of each enclosing block in
113//! turn, running the groups after it in order. `break` inside the switch is
114//! `break 'swK`, and the `_` arm goes to the `default:` group, or out of the
115//! whole statement when there is none.
116//!
117//! # Functions that jump
118//!
119//! Most `goto`s stay here too. [`regions`](crate::regions) has wrapped the
120//! statements a label divides in an [`ir::Region`], which is one of
121//!
122//! ```text
123//! 'done: { … break 'done; … } 'retry: loop { … continue 'retry; … break 'retry; }
124//! ```
125//!
126//! named after the C label — with the number of the label appended when Rust
127//! cannot spell the name as a label (`loop:` is a keyword) or when this module
128//! already gives that name to a loop of its own. A [`Stmt::Goto`] left inside
129//! one is the `break` or the `continue`; which it is comes from the region it
130//! stands in.
131//!
132//! A body sema lowered into a [control-flow graph](crate::cfg) instead —
133//! because it holds a jump Rust cannot make at all — is emitted as a state
134//! machine over its blocks, with the function's locals defined once at the
135//! top. Everything below the statement level is shared: the expressions,
136//! places and conversions are generated by exactly the same code in both
137//! modes.
138//!
139//! # Calls without a prototype
140//!
141//! `int f();` says nothing about the parameters (C99 6.7.5.3p14), so the item
142//! generated for it is `unsafe extern "C" fn() -> R` — that is all the
143//! declaration said. What the *call* passes is decided at the call site
144//! (6.5.2.2p6): sema has already applied the default argument promotions to
145//! every argument, and this module transmutes the callee to the signature they
146//! make before calling it,
147//!
148//! ```text
149//! ::core::mem::transmute::<unsafe extern "C" fn() -> R,
150//! unsafe extern "C" fn(T1, …, Tn) -> R>(f)(a1, …, an)
151//! ```
152//!
153//! with the `Option` unwrapped first for a function pointer, and no cast at all
154//! when there are no arguments. Reinterpreting a function pointer like this is
155//! exactly the contract C's own ABI rests on: on every ABI this crate targets
156//! the address is the same one, and the call is defined precisely when the
157//! callee really was defined with parameters of those promoted types —
158//! undefined otherwise, which is the risk the program took by leaving the
159//! prototype out. The same route is taken whenever the argument count and the
160//! parameter count disagree at all, which keeps a call checked
161//! against an empty list from being emitted against a prototype a later
162//! declaration supplied.
163//!
164//! # Variadic definitions
165//!
166//! `R f(T a, ...)` becomes `unsafe extern "C" fn f(mut a: T, __cinrs_va: ...)`.
167//! The extra parameter is the argument list as the caller left it and is never
168//! advanced; `va_start` and every `va_list` local copy it, `va_arg` is
169//! `next_arg`, `va_copy` and passing a list on are `clone`, and `va_end` is
170//! nothing at all, because the list ends when its value is dropped. See
171//! [`crate::sema`]'s `va` module for the model.
172
173use std::cell::{Cell, RefCell};
174use std::collections::{BTreeSet, HashMap, HashSet};
175use std::str::FromStr;
176
177use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
178use quote::quote_spanned;
179
180use crate::Options;
181use crate::capture::{SourceMap, SourceRange};
182use crate::cfg::{BasicBlock, BlockId, Cfg, Terminator};
183use crate::ir::{
184 self, AtomicClass, BinOp, Body, BreakTarget, Callee, CmpOp, ConstValue, Expr, ExprKind,
185 Function, LogicalOp, LoopId, NEVER_RAW, Place, PlaceKind, Program, RecordKind, Stmt, Storage,
186 Switch, Ty,
187};
188use crate::reloop;
189
190/// Generates the Rust items for a fully checked program.
191pub fn generate(program: &Program, map: &SourceMap, options: &Options) -> TokenStream {
192 let mut cg = Codegen::new(program, map, options);
193 let mut out = cg.type_items();
194 out.extend(cg.extern_block());
195 for var in &program.statics {
196 out.extend(cg.static_item(var));
197 }
198 let mut initialisers = TokenStream::new();
199 for func in &program.functions {
200 if func.body.is_some() {
201 out.extend(cg.function_item(func));
202 if let Some(kind) = func.init_kind {
203 initialisers.extend(cg.init_array_item(func, kind));
204 }
205 }
206 }
207 if !initialisers.is_empty() {
208 out.extend(cg.init_array_guard());
209 out.extend(initialisers);
210 }
211 if out.is_empty() {
212 // A unit that declares nothing expands to nothing at all — not even a
213 // module — and there is no code for the data model to be wrong about.
214 return out;
215 }
216 let mut items = cg.data_model_check();
217 if cg.uses_cleanup.get() {
218 items.extend(cg.cleanup_guard_item(Span::call_site()));
219 }
220 if cg.uses_arena.get() {
221 let span = cg.arena_span.get().unwrap_or_else(Span::call_site);
222 items.extend(cg.arena_items(span));
223 }
224 // The shims the unit needs for the intrinsics whose address it took; see
225 // [`Codegen::address_taken`]. Collected while the bodies were generated,
226 // so this has to come after them.
227 items.extend(cg.intrinsic_shim_items());
228 items.extend(out);
229 items
230}
231
232/// Generates signature-only items for a program that did not type check.
233///
234/// The bodies are `::core::unreachable!()`: the expansion also carries
235/// `compile_error!`s, so nothing here can ever run. Their purpose is to keep a
236/// Rust call site that mentions one of these functions from producing a second,
237/// unrelated "cannot find function" error on top of the real one.
238pub fn generate_stubs(program: &Program, map: &SourceMap, options: &Options) -> TokenStream {
239 let mut cg = Codegen::new(program, map, options);
240 let mut out = cg.type_items();
241 out.extend(cg.extern_block());
242 for var in &program.statics {
243 out.extend(cg.static_item(var));
244 }
245 for func in &program.functions {
246 if !func.is_extern() {
247 out.extend(cg.stub_item(func));
248 }
249 }
250 out
251}
252
253// ---------------------------------------------------------------------------
254// precedence
255// ---------------------------------------------------------------------------
256
257/// Rust's expression precedence levels, tightest last.
258///
259/// Emitted expressions carry the level they parse at so that parentheses are
260/// added exactly where they are needed and nowhere else — the generated code is
261/// meant to be read.
262mod prec {
263 /// A block-like expression (`if`, `{ … }`): usable on its own, but needing
264 /// parentheses anywhere an operator or a statement boundary follows.
265 pub const BLOCK: u8 = 0;
266 /// The weakest level an operand can be handed to without parentheses.
267 pub const LOWEST: u8 = 0;
268 pub const OR: u8 = 2;
269 pub const AND: u8 = 3;
270 pub const CMP: u8 = 4;
271 pub const BIT_OR: u8 = 5;
272 pub const BIT_XOR: u8 = 6;
273 pub const BIT_AND: u8 = 7;
274 pub const SUM: u8 = 9;
275 pub const PRODUCT: u8 = 10;
276 pub const CAST: u8 = 11;
277 pub const UNARY: u8 = 12;
278 pub const CALL: u8 = 13;
279 pub const ATOM: u8 = 14;
280}
281
282/// An emitted expression together with the precedence it parses at.
283struct Value {
284 tokens: TokenStream,
285 prec: u8,
286 /// Set when the tokens are a bare non-negative integer literal, whose Rust
287 /// type is therefore still open to inference.
288 bare_integer: bool,
289 /// Set when the tokens end with the type of an `as`.
290 ///
291 /// `x as i32 < y` does not parse: Rust reads the `<` as the start of the
292 /// generic arguments of `i32`. (`>`, `<=`, `>=` and `==` are unambiguous
293 /// and need no help.)
294 ends_with_type: bool,
295}
296
297impl Value {
298 fn new(tokens: TokenStream, prec: u8) -> Self {
299 Self {
300 tokens,
301 prec,
302 bare_integer: false,
303 ends_with_type: false,
304 }
305 }
306
307 fn atom(tokens: TokenStream) -> Self {
308 Self::new(tokens, prec::ATOM)
309 }
310
311 /// Marks the tokens as ending with the type of an `as`.
312 fn type_end(mut self, flag: bool) -> Self {
313 self.ends_with_type = flag;
314 self
315 }
316
317 /// The tokens, parenthesised if they would not survive being used as an
318 /// operand at `min`.
319 fn at(self, min: u8, span: Span) -> TokenStream {
320 if self.prec >= min {
321 return self.tokens;
322 }
323 parenthesize(self.tokens, span)
324 }
325
326 /// The tokens, parenthesised only if they are block-like.
327 ///
328 /// Used where Rust starts parsing an expression that is followed by a block
329 /// — the condition of an `if` or a `while` — and would otherwise mistake
330 /// our expression's own braces for that block.
331 fn at_condition(self, span: Span) -> TokenStream {
332 if self.prec > prec::BLOCK {
333 return self.tokens;
334 }
335 parenthesize(self.tokens, span)
336 }
337}
338
339fn parenthesize(tokens: TokenStream, span: Span) -> TokenStream {
340 let mut group = Group::new(Delimiter::Parenthesis, tokens);
341 group.set_span(span);
342 TokenStream::from(TokenTree::Group(group))
343}
344
345/// Whether an emitted expression opens with a unary minus.
346///
347/// `as` is the one operator in front of which that matters: `rustc` reads
348/// `-1 as u32` as the negation of a `u32` rather than as a cast of `-1`, and
349/// refuses it with `E0600`.
350fn starts_with_minus(tokens: &TokenStream) -> bool {
351 matches!(
352 tokens.clone().into_iter().next(),
353 Some(TokenTree::Punct(punct)) if punct.as_char() == '-'
354 )
355}
356
357fn braced(tokens: TokenStream, span: Span) -> TokenStream {
358 let mut group = Group::new(Delimiter::Brace, tokens);
359 group.set_span(span);
360 TokenStream::from(TokenTree::Group(group))
361}
362
363fn bracketed(tokens: TokenStream, span: Span) -> TokenStream {
364 let mut group = Group::new(Delimiter::Bracket, tokens);
365 group.set_span(span);
366 TokenStream::from(TokenTree::Group(group))
367}
368
369// ---------------------------------------------------------------------------
370// the Microsoft library's inline printf family, and the names it exports under
371// a different spelling
372// ---------------------------------------------------------------------------
373
374/// The library that has out-of-line definitions of the `printf` and `scanf`
375/// families for the Microsoft C runtime.
376///
377/// It is part of the MSVC toolset —
378/// `VC/Tools/MSVC/<version>/lib/<arch>/legacy_stdio_definitions.lib`, one copy
379/// per architecture — so it is there on every `*-windows-msvc` target and on no
380/// other, which is why [`TargetModel::is_msvc`](crate::TargetModel::is_msvc) and
381/// not merely Windows is what asks for it.
382const LEGACY_STDIO_DEFINITIONS: &str = "legacy_stdio_definitions";
383
384/// The names that need [`LEGACY_STDIO_DEFINITIONS`] on an MSVC target, each with
385/// the library that defines it.
386///
387/// In the Universal CRT — the Microsoft C library from Visual Studio 2015 on —
388/// the `printf` and `scanf` families are **inline functions in `<stdio.h>` and
389/// `<wchar.h>`**, written over `__stdio_common_vfprintf` and its relatives, so
390/// the import library exports no `printf` at all: an `extern "C" { fn printf(…);
391/// }` is `LNK2019: unresolved external symbol printf` at link time. Microsoft
392/// ships `legacy_stdio_definitions.lib` with out-of-line definitions for exactly
393/// that case, and it is what Rust's own `libc` crate links for the same
394/// declarations (`#[cfg_attr(all(windows, target_env = "msvc"), link(name =
395/// "legacy_stdio_definitions"))]`). See "The printf and scanf family of
396/// functions are now defined inline" in Microsoft's change history:
397/// <https://learn.microsoft.com/en-us/cpp/porting/visual-cpp-change-history-2003-2015>
398///
399/// The rule this table serves is [`Codegen::legacy_stdio_libraries`], and it is
400/// keyed on the **symbol a generated declaration links by** rather than on a
401/// header: a unit may declare `int printf(const char *, ...);` itself, or reach
402/// the function through `__builtin_printf`, and never include `<stdio.h>` at
403/// all.
404///
405/// One row per name, so that a name can be given a different answer on its own
406/// should a toolchain ever disagree: a row may name a different library, or go,
407/// and nothing else changes. What it must never become is an alias to
408/// `_snprintf`, whose truncation semantics are not C's.
409///
410/// Every name here was read out of a real copy of the library —
411/// `dumpbin`/`nm` over `legacy_stdio_definitions.lib` from MSVC 14.44.35207,
412/// x64 and x86 both — so the list is the library's own contents and not a
413/// guess. `snprintf` and `vsnprintf` are in it, which is worth saying because
414/// they are C99 additions the Microsoft library had no out-of-line form of
415/// *before* the UCRT and so, unlike the rest, never "became" inline; `libc`
416/// declares `snprintf` in the very block it links this library for. The library
417/// also holds the `_l`, `_p`, `_s` and `_snprintf` variants, which are
418/// deliberately not here: they are Microsoft's functions rather than C's, and a
419/// unit that declares one has named the platform already and can say
420/// `#pragma cinrs link "legacy_stdio_definitions"` itself.
421const LEGACY_STDIO: &[(&str, &str)] = &[
422 ("printf", LEGACY_STDIO_DEFINITIONS),
423 ("fprintf", LEGACY_STDIO_DEFINITIONS),
424 ("sprintf", LEGACY_STDIO_DEFINITIONS),
425 ("snprintf", LEGACY_STDIO_DEFINITIONS),
426 ("vprintf", LEGACY_STDIO_DEFINITIONS),
427 ("vfprintf", LEGACY_STDIO_DEFINITIONS),
428 ("vsprintf", LEGACY_STDIO_DEFINITIONS),
429 ("vsnprintf", LEGACY_STDIO_DEFINITIONS),
430 ("scanf", LEGACY_STDIO_DEFINITIONS),
431 ("fscanf", LEGACY_STDIO_DEFINITIONS),
432 ("sscanf", LEGACY_STDIO_DEFINITIONS),
433 ("vscanf", LEGACY_STDIO_DEFINITIONS),
434 ("vfscanf", LEGACY_STDIO_DEFINITIONS),
435 ("vsscanf", LEGACY_STDIO_DEFINITIONS),
436 ("wprintf", LEGACY_STDIO_DEFINITIONS),
437 ("fwprintf", LEGACY_STDIO_DEFINITIONS),
438 ("swprintf", LEGACY_STDIO_DEFINITIONS),
439 ("vwprintf", LEGACY_STDIO_DEFINITIONS),
440 ("vfwprintf", LEGACY_STDIO_DEFINITIONS),
441 ("vswprintf", LEGACY_STDIO_DEFINITIONS),
442 ("wscanf", LEGACY_STDIO_DEFINITIONS),
443 ("fwscanf", LEGACY_STDIO_DEFINITIONS),
444 ("swscanf", LEGACY_STDIO_DEFINITIONS),
445 ("vwscanf", LEGACY_STDIO_DEFINITIONS),
446 ("vfwscanf", LEGACY_STDIO_DEFINITIONS),
447 ("vswscanf", LEGACY_STDIO_DEFINITIONS),
448];
449
450/// The C functions the Microsoft C runtime exports under **another name**, each
451/// with the symbol a declaration of it has to link by on an MSVC target.
452///
453/// `LEGACY_STDIO` above is about a family the UCRT defines inline and ships an
454/// out-of-line copy of in a library of its own. This is the other shape of the
455/// same problem: the function *is* in `ucrt.lib`, under a name that is not the
456/// one C gives it, and Microsoft's own headers paper over the difference with a
457/// macro (`#define time _time64`) that cinrs's bundled headers, which are the
458/// same on every platform, do not write.
459///
460/// Every row was read out of the real import libraries with `nm` — the Windows
461/// SDK's `ucrt.lib` and the MSVC toolset's `msvcrt.lib`, 10.0.26100.0 and
462/// 14.44.35207 — and not inferred. `ucrt.lib` exports each symbol on the right
463/// and none of the C names on the left.
464///
465/// The `<time.h>` rows are **not** merely a link error, which is what makes
466/// them worth a table rather than a paragraph in the documentation. The MSVC
467/// toolset's `msvcrt.lib` holds an "alias map" object per name that defines
468/// `time` as a *weak* external for `_time32`, and the rest likewise — so a
469/// declaration of `time` does link, silently, to the **32-bit** `time_t`
470/// function. cinrs's `<time.h>` makes `time_t` 64 bits on Windows, as the UCRT
471/// does, and the two disagree in ways a program sees: `_mktime32`'s `(time_t)-1`
472/// comes back as `0x0000_0000_FFFF_FFFF`, and `_gmtime32` answers `NULL` for
473/// every date after 2038 rather than a `struct tm`. Naming `_time64` and its
474/// siblings is therefore a correctness fix and not only a convenience.
475///
476/// `hypotf` is the one `<math.h>` name with an exported equivalent: `_hypotf`
477/// is a real export with C's signature (Microsoft's `<math.h>` makes `hypotf`
478/// inline over it). `fabsf`, `frexpf` and `ldexpf` have no symbol at all in any
479/// library on an MSVC link line — they are inline over the `double` forms — and
480/// so are not here; `doc/cross-compilation.md` records them, with the
481/// workaround. The same goes for `<wchar.h>`'s `wmemcpy`, `wmemmove`, `wmemset`,
482/// `wmemcmp`, `wmemchr`, `mbsinit` and `fwide`.
483///
484/// The rule this table serves is [`Codegen::msvc_symbol`], which applies to a
485/// **declaration** and after an `__asm__("…")` label: a program that has named
486/// the symbol it wants by hand has said the last word, which is also how a unit
487/// asks for `_time32` on purpose.
488const MSVC_RENAMED: &[(&str, &str)] = &[
489 ("time", "_time64"),
490 ("difftime", "_difftime64"),
491 ("mktime", "_mktime64"),
492 ("localtime", "_localtime64"),
493 ("gmtime", "_gmtime64"),
494 ("ctime", "_ctime64"),
495 ("timespec_get", "_timespec64_get"),
496 ("hypotf", "_hypotf"),
497];
498
499// ---------------------------------------------------------------------------
500// identifiers
501// ---------------------------------------------------------------------------
502
503/// Every Rust keyword, strict and reserved, in every edition up to 2024.
504const RUST_KEYWORDS: &[&str] = &[
505 "abstract", "as", "async", "await", "become", "box", "break", "const", "continue", "crate",
506 "do", "dyn", "else", "enum", "extern", "false", "final", "fn", "for", "gen", "if", "impl",
507 "in", "let", "loop", "macro", "match", "mod", "move", "mut", "override", "priv", "pub", "ref",
508 "return", "self", "static", "struct", "super", "trait", "true", "try", "type", "typeof",
509 "unsafe", "unsized", "use", "virtual", "where", "while", "yield", "Self",
510];
511
512/// Names that a `let` binding or a parameter must not carry, whatever the C
513/// program calls them.
514///
515/// Rust resolves a binding pattern against the value namespace first: a name
516/// that already means a unit variant there is a *pattern* that matches, not a
517/// new binding, and Rust refuses the ambiguity outright with `E0530`. The four
518/// below are in scope in every Rust file through the prelude; the rest of the
519/// set is computed per translation unit in [`Codegen::new`], because a C
520/// program may name a local exactly like one of its own globals or
521/// enumerators:
522///
523/// ```c
524/// int counter;
525/// int f(int counter) { return counter; } /* two different objects */
526/// ```
527const PRELUDE_PATTERNS: &[&str] = &["Some", "None", "Ok", "Err"];
528
529/// Whether `segment` is an ordinary Rust identifier — one that can stand as a
530/// path segment spelled verbatim rather than as `r#…`.
531///
532/// Its one caller is [`is_crate_path`], whose value is pasted into the
533/// expansion as tokens; the three keywords a segment may nevertheless be are
534/// allowed there rather than here.
535fn is_path_segment(segment: &str) -> bool {
536 let mut chars = segment.chars();
537 chars
538 .next()
539 .is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
540 && chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
541 && !RUST_KEYWORDS.contains(&segment)
542 && !NEVER_RAW.contains(&segment)
543}
544
545/// Whether a string is usable as the Rust path of a crate:
546/// `#pragma cinrs crate "…"`.
547///
548/// A sequence of segments joined by `::`, optionally starting with one, where
549/// each segment is an identifier — with `crate`, `self` and `super` allowed as
550/// segments because a re-export is often reached through one. Deliberately
551/// strict: the value is pasted into the expansion as tokens, and anything else
552/// there would be a syntax error in generated code rather than a message about
553/// the pragma.
554pub fn is_crate_path(path: &str) -> bool {
555 /// The three keywords a path segment may be even though an ordinary
556 /// identifier may not.
557 const PATH_KEYWORDS: &[&str] = &["crate", "self", "super"];
558
559 let body = path.strip_prefix("::").unwrap_or(path);
560 if body.is_empty() {
561 return false;
562 }
563 body.split("::")
564 .all(|segment| PATH_KEYWORDS.contains(&segment) || is_path_segment(segment))
565}
566
567/// Turns a C identifier into the Rust identifier that stands for it, before
568/// the rest of the translation unit is taken into account.
569///
570/// C names are kept as they are, because that is what makes the expansion
571/// readable and what lets Rust call the functions by the names their author
572/// gave them. A name that collides with a Rust keyword becomes a raw
573/// identifier (`match` → `r#match`); the five names that cannot even be raw
574/// get an underscore appended instead. A `$` — which C takes as an identifier
575/// character and Rust has no spelling for — is written [`DOLLAR`].
576///
577/// The last two rules are the only ones that can hand two different C names
578/// the same Rust one, which is what [`Names`] exists to prevent: everything
579/// the generator emits goes through [`Names::ident`] rather than through this.
580fn c_ident(name: &str, span: Span) -> Ident {
581 let spelled = rust_spelling(name);
582 let name = spelled.as_ref();
583 if NEVER_RAW.contains(&name) {
584 return Ident::new(&format!("{name}_"), span);
585 }
586 if RUST_KEYWORDS.contains(&name) {
587 return Ident::new_raw(name, span);
588 }
589 Ident::new(name, span)
590}
591
592/// What a `$` in a C identifier is written as in the generated Rust.
593///
594/// `$` is an identifier character here — GCC takes it unconditionally and
595/// Clang by default, which is what WG14 DR027 allows and what
596/// [`crate::Options::dollar_in_identifiers`] switches on — and Rust has no
597/// spelling for it at all, not even a raw identifier. The C name is still what
598/// the symbol links by: an object or function that is not defined here carries
599/// it in `#[link_name]`, and one that is carries it in `#[unsafe(export_name)]`.
600pub const DOLLAR: &str = "_dollar_";
601
602/// A C identifier as Rust can spell it, which is the same string unless a `$`
603/// is in it.
604fn rust_spelling(name: &str) -> std::borrow::Cow<'_, str> {
605 if name.contains('$') {
606 std::borrow::Cow::Owned(name.replace('$', DOLLAR))
607 } else {
608 std::borrow::Cow::Borrowed(name)
609 }
610}
611
612/// Whether Rust spells `name` as something other than itself, so that another
613/// C name could be spelled the same way.
614///
615/// A keyword is not one of these: `r#match` is a token of its own and no name
616/// but `match` is written that way.
617fn respelled(name: &str) -> bool {
618 name.contains('$') || NEVER_RAW.contains(&name)
619}
620
621/// The text [`c_ident`] gives a name, without the `r#` a raw identifier is
622/// written with.
623fn plain_spelling(name: &str) -> String {
624 let spelled = rust_spelling(name);
625 if NEVER_RAW.contains(&spelled.as_ref()) {
626 return format!("{spelled}_");
627 }
628 spelled.into_owned()
629}
630
631/// The Rust spelling of every name the translation unit gives to something,
632/// made unique across the whole unit.
633///
634/// Two of the rules in [`c_ident`] change the spelling of a name, and a
635/// program is free to use the changed spelling itself:
636///
637/// ```c
638/// int f(void) { int self = 1; int self_ = 2; return self * 10 + self_; }
639/// ```
640///
641/// Both locals would be `self_`, the second binding would shadow the first,
642/// and `f` would quietly return 22 instead of 12. The same collision between
643/// two members is `E0124`, between two file-scope items `E0428`, and `a$b`
644/// next to `a_dollar_b` is the same story again.
645///
646/// So the spelling is settled once, here, for the unit as a whole. Every name
647/// the unit spells is collected — objects, functions and their parameters,
648/// tags, members, bit-field accessors, enumerators and `typedef` names, in
649/// every name space at once, because one C name must read as one Rust name
650/// wherever it appears. A name Rust spells as it is written keeps it; a name
651/// whose spelling changes takes the usual one and grows another `_` for as
652/// long as something else already has it. Nothing moves for a program that
653/// does not have the collision, which is very nearly every program.
654///
655/// Labels are left out: `'self_` is in a name space of its own, and
656/// [`Codegen::name_regions`] already keeps the labels of a function apart.
657struct Names {
658 /// The Rust spelling of each name whose spelling is not the name itself.
659 ///
660 /// Empty for a unit that writes no such name, which is the usual case.
661 renamed: HashMap<String, String>,
662}
663
664impl Names {
665 /// Works out the spellings of one translation unit.
666 fn new(program: &Program) -> Self {
667 let mut spelled: Vec<&str> = Vec::new();
668 for object in &program.objects {
669 spelled.push(&object.name);
670 match &object.storage {
671 Storage::Static { item_name, .. }
672 | Storage::ThreadLocal { item_name, .. }
673 | Storage::Extern { item_name } => spelled.push(item_name),
674 Storage::Automatic => {}
675 }
676 }
677 for func in &program.functions {
678 spelled.push(&func.name);
679 spelled.push(func.item_name());
680 spelled.extend(func.param_names.iter().flatten().map(String::as_str));
681 // The names the state-machine lowering hoists the locals under,
682 // which are what a CFG body's bindings are generated from.
683 if let Some(Body::Cfg(cfg)) = &func.body {
684 spelled.extend(cfg.locals.iter().map(|local| local.rust_name.as_str()));
685 }
686 }
687 for record in program.types.records() {
688 spelled.extend(record.tag.as_deref());
689 spelled.push(&record.rust_name);
690 for field in &record.fields {
691 spelled.push(&field.name);
692 if let Some(bits) = &field.bits {
693 spelled.push(&bits.getter);
694 spelled.push(&bits.setter);
695 }
696 }
697 for field in &record.rust_fields {
698 match field {
699 ir::RustField::Bits { name, .. }
700 | ir::RustField::Pad { name, .. }
701 | ir::RustField::Align { name, .. } => spelled.push(name),
702 ir::RustField::Member(_) => {}
703 }
704 }
705 }
706 for def in program.types.enums() {
707 spelled.extend(def.tag.as_deref());
708 spelled.push(&def.rust_name);
709 }
710 for constant in &program.enum_constants {
711 spelled.push(&constant.name);
712 spelled.push(&constant.rust_name);
713 }
714 for typedef in &program.typedefs {
715 spelled.push(&typedef.rust_name);
716 }
717
718 Self {
719 renamed: unique_spellings(spelled),
720 }
721 }
722
723 /// The Rust identifier a C name is generated as, everywhere it appears.
724 fn ident(&self, name: &str, span: Span) -> Ident {
725 match self.renamed.get(name) {
726 Some(unique) => Ident::new(unique, span),
727 None => c_ident(name, span),
728 }
729 }
730
731 /// The same as text, without the `r#` a raw identifier is written with.
732 fn spelling<'n>(&'n self, name: &'n str) -> std::borrow::Cow<'n, str> {
733 match self.renamed.get(name) {
734 Some(unique) => std::borrow::Cow::Borrowed(unique.as_str()),
735 None => std::borrow::Cow::Owned(plain_spelling(name)),
736 }
737 }
738}
739
740/// The rule [`Names`] is built on: what each name whose Rust spelling is not
741/// itself is spelled as, given everything the unit spells.
742///
743/// A name Rust writes as it stands claims that spelling first — two such
744/// names are distinct exactly when the C names are — and what is left grows
745/// another `_` for as long as something already has its spelling. The names
746/// that need one are settled in sorted order, so that the answer never
747/// depends on the order the arenas happen to be in.
748fn unique_spellings<'n>(spelled: impl IntoIterator<Item = &'n str>) -> HashMap<String, String> {
749 let mut taken: HashSet<&str> = HashSet::new();
750 let mut changing: BTreeSet<&str> = BTreeSet::new();
751 for name in spelled {
752 if respelled(name) {
753 changing.insert(name);
754 } else {
755 taken.insert(name);
756 }
757 }
758 let mut renamed: HashMap<String, String> = HashMap::new();
759 let mut assigned: HashSet<String> = HashSet::new();
760 for name in changing {
761 let mut candidate = plain_spelling(name);
762 while taken.contains(candidate.as_str()) || assigned.contains(&candidate) {
763 candidate.push('_');
764 }
765 assigned.insert(candidate.clone());
766 renamed.insert(name.to_owned(), candidate);
767 }
768 renamed
769}
770
771/// Whether `name` can stand as the label of a Rust block or loop.
772///
773/// A label is not a raw identifier, so a Rust keyword — `loop:` is a perfectly
774/// ordinary C label — cannot be one, nor can the five names that cannot even
775/// be raw. The labels this module builds itself are kept clear too, so that a
776/// `break` in a region never names a loop instead. A C label that is one of
777/// them keeps its own name with the label's number appended.
778fn is_label_name(name: &str) -> bool {
779 let mut chars = name.chars();
780 let starts = chars
781 .next()
782 .is_some_and(|c| c.is_ascii_alphabetic() || c == '_');
783 starts
784 && chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
785 && !RUST_KEYWORDS.contains(&name)
786 && !NEVER_RAW.contains(&name)
787 && !is_generated_label(name)
788}
789
790/// The labels this module gives its own loops, `switch`es, state machine and
791/// [recovered shapes](crate::reloop): `'cfg`, `'lN`, `'lN_body`, `'swN`,
792/// `'swN_cM`, `'bN` and `'rN`.
793fn is_generated_label(name: &str) -> bool {
794 fn digits(text: &str) -> bool {
795 !text.is_empty() && text.bytes().all(|b| b.is_ascii_digit())
796 }
797
798 if name == "cfg" {
799 return true;
800 }
801 if let Some(rest) = name.strip_prefix('l')
802 && digits(rest.strip_suffix("_body").unwrap_or(rest))
803 {
804 return true;
805 }
806 for prefix in ['b', 'r'] {
807 if let Some(rest) = name.strip_prefix(prefix)
808 && digits(rest)
809 {
810 return true;
811 }
812 }
813 if let Some(rest) = name.strip_prefix("sw") {
814 if digits(rest) {
815 return true;
816 }
817 if let Some((switch, case)) = rest.split_once("_c") {
818 return digits(switch) && digits(case);
819 }
820 }
821 false
822}
823
824/// Every [region](ir::Region) of a body, outermost first, with the C label it
825/// is named after.
826fn collect_regions(stmts: &[Stmt], out: &mut Vec<(ir::LabelId, String)>) {
827 for stmt in stmts {
828 match stmt {
829 Stmt::Region(region) => {
830 out.push((region.label, region.name.clone()));
831 collect_regions(®ion.body, out);
832 }
833 Stmt::Block(items) => collect_regions(items, out),
834 Stmt::Label { body, .. } | Stmt::Case { body, .. } => {
835 collect_regions(std::slice::from_ref(body), out);
836 }
837 Stmt::If {
838 then_branch,
839 else_branch,
840 ..
841 } => {
842 collect_regions(std::slice::from_ref(then_branch), out);
843 if let Some(branch) = else_branch {
844 collect_regions(std::slice::from_ref(branch), out);
845 }
846 }
847 Stmt::While { body, .. } | Stmt::DoWhile { body, .. } => {
848 collect_regions(std::slice::from_ref(body), out);
849 }
850 Stmt::For { init, body, .. } => {
851 collect_regions(init, out);
852 collect_regions(std::slice::from_ref(body), out);
853 }
854 Stmt::Switch(switch) => {
855 collect_regions(&switch.prelude, out);
856 for group in &switch.groups {
857 collect_regions(&group.body, out);
858 }
859 }
860 Stmt::SwitchTree(switch) => collect_regions(std::slice::from_ref(&switch.body), out),
861 _ => {}
862 }
863 }
864}
865
866/// The lint exemptions every generated item carries.
867///
868/// A transliteration of C is unidiomatic Rust by construction: names are not
869/// snake case, locals are `mut` whether or not they are assigned again, a
870/// `switch` leaves labels that nothing jumps to, and a function that ends in an
871/// infinite loop leaves code behind that cannot run. `unknown_lints` comes
872/// first so that the list may name a lint an older compiler has never heard of.
873///
874/// Two of them are about the `extern` block. A C program declares the library
875/// its own way — `int strlen();` with no prototype is what a C89 program
876/// writes, and an implicit declaration is exactly that — so the declaration
877/// `cinrs` generates may disagree with the one Rust's own standard library
878/// uses for the same symbol (`clashing_extern_declarations`, and Rust 1.99's
879/// deny-by-default `invalid_runtime_symbol_definitions`). Nothing is
880/// *defined*: the symbol is the C library's either way, and a call through a
881/// type with no prototype is transmuted to the signature its arguments make
882/// before it is made, which is the contract C's own ABI runs on.
883///
884/// Two more are the deny-by-default `arithmetic_overflow` and
885/// `unconditional_panic`, which fire when `rustc` can see that an operation
886/// would trap: a division whose divisor it has const-propagated to zero, a
887/// shift past the width of the type, an overflowing constant. Each of those is
888/// *undefined behaviour* in C, so the C program is valid whatever it does and
889/// the operation is very often in a branch that cannot be taken —
890/// `execute/pr97888-1` is `if (h > -173) e = d / i;` with `i` a zero the
891/// program never reaches. Refusing to compile valid C is not an option;
892/// panicking at run time if it is ever reached is a perfectly good answer to
893/// undefined behaviour, and is what the same code already does when the
894/// divisor is only zero at run time.
895/// The label a [label address](ir::ExprKind::LabelAddr) names, through any
896/// conversions around it.
897fn label_state(expr: &Expr) -> Option<ir::LabelId> {
898 match &expr.kind {
899 ExprKind::LabelAddr(id) => Some(*id),
900 ExprKind::Cast(inner) => label_state(inner),
901 _ => None,
902 }
903}
904
905/// The name of the wrapper type an object aligned to `align` is generated
906/// inside; see [`Codegen::align_wrapper_items`].
907fn align_wrapper_ident(align: u64, span: Span) -> Ident {
908 Ident::new(&format!("__cinrs_align_{align}"), span)
909}
910
911/// The length of an array type, or `None` for anything else.
912fn array_len(types: &ir::Types, ty: Ty) -> Option<u64> {
913 match ty {
914 Ty::Array(id) => Some(types.array_type(id).len),
915 _ => None,
916 }
917}
918
919/// The name of a unit's `cleanup` drop guard type, in this crate's own
920/// hygiene: nothing a C program can write reaches it.
921fn cleanup_guard_ty() -> Ident {
922 Ident::new("__cinrs_cleanup", Span::mixed_site())
923}
924
925/// The name of a unit's bump arena type, in the same hygiene; see
926/// [`Codegen::arena_items`].
927fn arena_ty() -> Ident {
928 Ident::new("__cinrs_vla_arena", Span::mixed_site())
929}
930
931/// The name of a [CFG-mode](crate::cfg) function's array of arena marks, one
932/// slot per variable length array it declares; see [`Codegen::vla_def`].
933fn vla_marks_ident() -> Ident {
934 Ident::new("__cinrs_vla_marks", Span::mixed_site())
935}
936
937// ---------------------------------------------------------------------------
938// the generator
939// ---------------------------------------------------------------------------
940
941/// How `continue` leaves a particular loop.
942#[derive(Clone, Copy, PartialEq, Eq)]
943enum ContinueStyle {
944 /// The loop re-tests its condition on its own: `continue 'l`.
945 Head,
946 /// Work remains before the next iteration: `break 'l_body`.
947 BodyLabel,
948}
949
950/// A place, ready to be read from or written to.
951struct LoweredPlace {
952 /// Statements that must run before `access` is used.
953 setup: TokenStream,
954 /// A Rust place expression that may be evaluated more than once.
955 access: TokenStream,
956 /// Set when the place is a bit-field, in which case `access` is the record
957 /// holding it and the bits are reached through the generated accessors.
958 bits: Option<BitAccess>,
959 /// Set when the object may not be aligned the way its type asks.
960 ///
961 /// C reaches such an object through a packed member or a pointer cast, and
962 /// says nothing about the load; Rust makes `*p` on an underaligned `p`
963 /// undefined behaviour, which a debug build turns into an abort. Such a
964 /// place is read and written through `read_unaligned` and
965 /// `write_unaligned` instead. See [`Codegen::place_align`].
966 unaligned: bool,
967 /// Set when the object is `_Atomic`: reading it is a sequentially
968 /// consistent load and writing it a sequentially consistent store, both
969 /// through `AtomicX::from_ptr` over its address (C11 6.5.2.4, 6.5.16).
970 ///
971 /// The [class](AtomicClass) says which atomic, and the [`Ty`] is the
972 /// object's own type with the `_Atomic` taken off — what the value the
973 /// load produces is converted to.
974 atomic: Option<(AtomicClass, Ty)>,
975}
976
977impl LoweredPlace {
978 /// An ordinary place, whose access is the value.
979 fn plain(setup: TokenStream, access: TokenStream) -> Self {
980 Self {
981 setup,
982 access,
983 bits: None,
984 unaligned: false,
985 atomic: None,
986 }
987 }
988}
989
990/// What a read-modify-write of an `_Atomic` place does to it.
991enum PlaceRmw<'a> {
992 /// `place op= value`, in the type `compute`.
993 Compound {
994 /// The operator.
995 op: BinOp,
996 /// The right operand, already converted for `compute`.
997 value: &'a Expr,
998 /// The type the operation is carried out in.
999 compute: Ty,
1000 },
1001 /// `++place` or `--place`.
1002 Step {
1003 /// Whether this decrements.
1004 dec: bool,
1005 },
1006}
1007
1008/// Which value such a read-modify-write leaves behind.
1009#[derive(Clone, Copy, PartialEq, Eq)]
1010enum RmwValue {
1011 /// None: it was written as a statement.
1012 None,
1013 /// The value from before the update, which is what `x++` is.
1014 Old,
1015 /// The value after it, which is what `++x` and `x += v` are.
1016 New,
1017}
1018
1019/// The atomic operation a compound assignment operator performs, where there
1020/// is one.
1021fn rmw_of_binop(op: BinOp) -> Option<ir::AtomicRmw> {
1022 Some(match op {
1023 BinOp::Add => ir::AtomicRmw::Add,
1024 BinOp::Sub => ir::AtomicRmw::Sub,
1025 BinOp::BitAnd => ir::AtomicRmw::And,
1026 BinOp::BitOr => ir::AtomicRmw::Or,
1027 BinOp::BitXor => ir::AtomicRmw::Xor,
1028 _ => return None,
1029 })
1030}
1031
1032/// The accessors a bit-field place is read and written through.
1033struct BitAccess {
1034 getter: Ident,
1035 setter: Ident,
1036}
1037
1038/// The unsigned word a bit-field's bytes are gathered into, and what its
1039/// accessors need to know about it.
1040///
1041/// See [`Codegen::bit_field_window`]; the word is `u64` for every bit-field
1042/// standard C allows and `u128` for the wide ones GNU's `__int128` makes
1043/// possible.
1044struct BitWindow {
1045 /// The expression that reads the overlapping bytes into the word.
1046 read: TokenStream,
1047 /// The field's bit offset inside the word.
1048 shift: u32,
1049 /// The field's bits, in place, inside the word.
1050 mask: u128,
1051 /// The word's Rust type: `u64` or `::core::primitive::u128`.
1052 word: TokenStream,
1053 /// Its width in bits, which is what a mask and a sign extension are
1054 /// written against.
1055 word_bits: u32,
1056}
1057
1058/// Where the pristine argument list of the function being generated lives.
1059#[derive(Clone, Copy, PartialEq, Eq)]
1060enum VaSource {
1061 /// There is none: the function takes no variable arguments.
1062 None,
1063 /// The synthetic `...` parameter of a variadic definition.
1064 Ellipsis,
1065 /// The function's own `va_list` parameter.
1066 Param(ir::ObjectId),
1067 /// The function's own `va_list *` parameter, whose *pointee* is the list.
1068 PtrParam(ir::ObjectId),
1069}
1070
1071struct Codegen<'a> {
1072 program: &'a Program,
1073 map: &'a SourceMap,
1074 options: &'a Options,
1075 continue_styles: HashMap<LoopId, ContinueStyle>,
1076 /// The Rust names of the locals of the function being generated, wherever
1077 /// they differ from the C ones: in [CFG mode](crate::cfg), where every
1078 /// local of the function shares one scope, and for a local whose name
1079 /// would shadow a file-scope item (see [`PRELUDE_PATTERNS`]).
1080 local_names: HashMap<ir::ObjectId, String>,
1081 /// The hidden pointer the function being generated reaches each enclosing
1082 /// object through, when it is a [lifted nested function](ir::EnvParam).
1083 ///
1084 /// It is what a call from inside one passes on: an object this function
1085 /// does not own itself arrives as a pointer, and the callee wants the same
1086 /// pointer rather than the address of a local that is not there.
1087 env: HashMap<ir::ObjectId, ir::ObjectId>,
1088 /// The names a `let` binding or a parameter must not use.
1089 reserved: HashSet<String>,
1090 /// The Rust spelling of every C name the unit gives to something; see
1091 /// [`Names`].
1092 names: Names,
1093 va_source: VaSource,
1094 ret_ty: Ty,
1095 /// Whether the function being generated is a [state
1096 /// machine](crate::cfg), in which case every local is already bound at the
1097 /// top and a definition is an assignment.
1098 in_cfg: bool,
1099 /// Whether the function being generated is [safe](Function::is_safe), so
1100 /// that its body has no `unsafe` block around it.
1101 in_safe: bool,
1102 temporaries: u32,
1103 /// Set the first time a `__int128` reaches the output, which is what
1104 /// decides whether the [data-model check](Codegen::data_model_check) has
1105 /// anything to say about `i128`'s alignment.
1106 ///
1107 /// A [`Cell`] because [`Codegen::ty`] takes `&self`; the check is built
1108 /// after every item, so it sees the final answer.
1109 uses_int128: Cell<bool>,
1110 /// Set the first time a complex type reaches the output, for the same
1111 /// reason and by the same route as [`Codegen::uses_int128`]: only a unit
1112 /// that has one asserts the layout of `Complex<f32>` and `Complex<f64>`.
1113 uses_complex: Cell<bool>,
1114 /// Whether anything in the unit needs the `cleanup` drop guard item.
1115 uses_cleanup: Cell<bool>,
1116 /// Whether any function of the unit opens with the bump arena variable
1117 /// length arrays and `alloca` allocate from, so that the unit needs the
1118 /// arena's type; see [`Codegen::arena_items`].
1119 uses_arena: Cell<bool>,
1120 /// Where the unit's first variable length array or `alloca` was written,
1121 /// which is what the arena's items are spanned with: in a `#![no_std]`
1122 /// crate that did not say `#pragma cinrs no_std`, `rustc`'s "cannot find
1123 /// `std`" then points at the C that needed it.
1124 arena_span: Cell<Option<Span>>,
1125 /// In a [CFG-mode](crate::cfg) function, the slot of the function's array
1126 /// of arena marks each variable length array's hidden frame object is;
1127 /// see [`Codegen::vla_def`].
1128 vla_slots: HashMap<ir::ObjectId, usize>,
1129 /// Every [x86 intrinsic](crate::x86) whose *address* the unit took, in the
1130 /// order it first did.
1131 ///
1132 /// An intrinsic is not a symbol, and `core::arch`'s function has the Rust
1133 /// ABI, so its address is not an `unsafe extern "C" fn` pointer and cannot
1134 /// be made into one. What C asks for is a function of that signature that
1135 /// does what the intrinsic does, which is a shim — and GCC's own headers
1136 /// are exactly that, `__always_inline__` functions whose address is
1137 /// therefore takeable. One is generated per intrinsic, private to the
1138 /// unit's module, and the same `FuncId` used twice shares it.
1139 address_taken: RefCell<Vec<ir::FuncId>>,
1140 /// The number of every label a `&&label` took the address of — the value
1141 /// of its address — over the whole unit.
1142 ///
1143 /// A [`ir::LabelId`] is unique across the translation unit, which is what
1144 /// makes one map enough: a block-scope `static void *table[] = { &&a };`
1145 /// becomes an item at module level and is generated before any function
1146 /// body, so the number cannot be looked up in the function being emitted.
1147 /// See [`Cfg::labels`].
1148 label_states: HashMap<ir::LabelId, u32>,
1149 /// The Rust label each [region](ir::Region) of the function being
1150 /// generated carries: the C label's name, unless Rust cannot spell it as a
1151 /// label or this module already gives that name to a loop.
1152 region_names: HashMap<ir::LabelId, String>,
1153 /// The regions the statement being generated stands inside, which is what
1154 /// tells a `goto` whether it leaves one or restarts it.
1155 region_kinds: HashMap<ir::LabelId, ir::RegionKind>,
1156 /// The Rust label each loop [the relooper](crate::reloop) recovered
1157 /// carries: the C label its head stands at, or `'rN`.
1158 loop_names: HashMap<u32, String>,
1159 /// The labelled blocks and loops open around the shape being generated,
1160 /// outermost first.
1161 shape_scopes: Vec<ShapeScope>,
1162 /// Numbers the labelled blocks a sequence of shapes needs, so that each
1163 /// has a name of its own within the function.
1164 shape_labels: u32,
1165 /// The labels a jump really used: one nothing named is left out, braces
1166 /// and all.
1167 used_labels: HashSet<u32>,
1168}
1169
1170/// A labelled block or loop the shape being generated stands inside.
1171///
1172/// Together they are how a jump the graph still holds is emitted: the
1173/// innermost scope whose [exit](reloop::Exit) names the target block says
1174/// whether it is a `break` or a `continue`, and of what.
1175#[derive(Clone)]
1176struct ShapeScope {
1177 /// Identifies the label in [`Codegen::used_labels`]. A loop's is
1178 /// [`u32::MAX`], which is never looked up: a loop always carries its name.
1179 id: u32,
1180 /// The name, without the tick.
1181 name: String,
1182 /// Whether arriving at `exit` is `continue` rather than `break`.
1183 repeats: bool,
1184 /// Where the jump arrives.
1185 exit: reloop::Exit,
1186}
1187
1188impl<'a> Codegen<'a> {
1189 fn new(program: &'a Program, map: &'a SourceMap, options: &'a Options) -> Self {
1190 let mut reserved: HashSet<String> =
1191 PRELUDE_PATTERNS.iter().map(|s| (*s).to_owned()).collect();
1192 // A `static mut` and a `const` are both in the value namespace, so a
1193 // binding of the same name is `E0530` rather than a shadow.
1194 for var in &program.statics {
1195 if let Some(item_name) = program.object(var.object).storage.item_name() {
1196 reserved.insert(item_name.to_owned());
1197 }
1198 }
1199 for constant in &program.enum_constants {
1200 reserved.insert(constant.rust_name.clone());
1201 }
1202 let mut label_states = HashMap::new();
1203 for func in &program.functions {
1204 if let Some(ir::Body::Cfg(cfg)) = &func.body {
1205 label_states.extend(cfg.labels.iter().map(|(id, number)| (*id, *number)));
1206 }
1207 }
1208 Self {
1209 program,
1210 map,
1211 options,
1212 continue_styles: HashMap::new(),
1213 local_names: HashMap::new(),
1214 env: HashMap::new(),
1215 reserved,
1216 names: Names::new(program),
1217 va_source: VaSource::None,
1218 ret_ty: Ty::Void,
1219 in_cfg: false,
1220 in_safe: false,
1221 temporaries: 0,
1222 uses_int128: Cell::new(false),
1223 uses_complex: Cell::new(false),
1224 uses_cleanup: Cell::new(false),
1225 uses_arena: Cell::new(false),
1226 arena_span: Cell::new(None),
1227 vla_slots: HashMap::new(),
1228 address_taken: RefCell::new(Vec::new()),
1229 label_states,
1230 region_names: HashMap::new(),
1231 region_kinds: HashMap::new(),
1232 loop_names: HashMap::new(),
1233 shape_scopes: Vec::new(),
1234 shape_labels: 0,
1235 used_labels: HashSet::new(),
1236 }
1237 }
1238
1239 /// Whether `va_list` appears anywhere in a type.
1240 fn uses_va_list(&self, ty: Ty) -> bool {
1241 match ty {
1242 Ty::VaList => true,
1243 Ty::Pointer(id) => self.uses_va_list(self.program.types.pointer_type(id).pointee),
1244 Ty::Array(id) => self.uses_va_list(self.program.types.array_type(id).elem),
1245 Ty::Func(id) => {
1246 let func = self.program.types.func_type(id);
1247 self.uses_va_list(func.ret) || func.params.iter().any(|ty| self.uses_va_list(*ty))
1248 }
1249 _ => false,
1250 }
1251 }
1252
1253 fn sp(&self, range: SourceRange) -> Span {
1254 self.map.span(range)
1255 }
1256
1257 /// The Rust identifier a C name is generated as; see [`Names`].
1258 ///
1259 /// Every name the generator writes goes through here, so that one C name
1260 /// reads as one Rust name wherever it appears — as an item, as a member,
1261 /// as a designator, in `offsetof`, in a bit-field accessor.
1262 fn c_ident(&self, name: &str, span: Span) -> Ident {
1263 self.names.ident(name, span)
1264 }
1265
1266 /// The name of the companion type a record whose flexible array member
1267 /// holds `len` elements is generated under; see [`Codegen::flexible_items`].
1268 fn flexible_ident(&self, rust_name: &str, len: u64, span: Span) -> Ident {
1269 Ident::new(
1270 &format!("__cinrs_{}_{len}", self.names.spelling(rust_name)),
1271 span,
1272 )
1273 }
1274
1275 /// The name of the item an externally linked **object** is declared under;
1276 /// see [`Program::extern_object_name`] for why an object and not a
1277 /// function.
1278 ///
1279 /// The symbol itself is what `#[link_name]` says; this is only the Rust
1280 /// side of it, and it is built out of the spelling every other C name is
1281 /// given so that two symbols never end up under one item.
1282 fn extern_object_ident(&self, symbol: &str, span: Span) -> Ident {
1283 let spelling = self.names.spelling(symbol);
1284 Ident::new(&self.program.extern_object_name(&spelling), span)
1285 }
1286
1287 /// A name no C identifier can collide with.
1288 ///
1289 /// `Span::mixed_site()` gives the identifier this crate's own hygiene, so
1290 /// even a C variable spelled `__cinrs_tmp0` refers to something else.
1291 fn temporary(&mut self) -> Ident {
1292 let name = format!("__cinrs_tmp{}", self.temporaries);
1293 self.temporaries += 1;
1294 Ident::new(&name, Span::mixed_site())
1295 }
1296
1297 /// A temporary whose *position* is the C it came from, while it still
1298 /// resolves as though it had been written at the macro's definition site.
1299 ///
1300 /// `Span::mixed_site` carries both a hygiene context and a position, and
1301 /// the position it carries is the whole invocation. That is invisible until
1302 /// a diagnostic is about an expression built out of such a name — `p[i]`
1303 /// becomes a temporary holding `p.offset(i)` and the place
1304 /// `(*__cinrs_tmp0)`, whose span `rustc` widens to cover the name as well
1305 /// and therefore to the macro call as a whole. `resolved_at` keeps
1306 /// the hygiene and takes the position from the C instead, which is where
1307 /// the caret belongs: a dereference a *safe* function may not do is
1308 /// reported on the `p[i]` that asked for it.
1309 fn temporary_at(&mut self, span: Span) -> Ident {
1310 let name = format!("__cinrs_tmp{}", self.temporaries);
1311 self.temporaries += 1;
1312 Ident::new(&name, span.resolved_at(Span::mixed_site()))
1313 }
1314
1315 /// Builds a Rust label such as `'l0`.
1316 fn label(&self, name: &str, span: Span) -> TokenStream {
1317 let mut tick = Punct::new('\'', Spacing::Joint);
1318 tick.set_span(span);
1319 let mut out = TokenStream::new();
1320 out.extend([
1321 TokenTree::Punct(tick),
1322 TokenTree::Ident(Ident::new(name, span)),
1323 ]);
1324 out
1325 }
1326
1327 // -- types --------------------------------------------------------------
1328
1329 /// The Rust type a C type maps to, always fully qualified.
1330 fn ty(&self, ty: Ty, span: Span) -> TokenStream {
1331 let name = match ty {
1332 // Only reachable on the error path, where a `compile_error!` is
1333 // already going out; the unit type keeps the stub items parseable.
1334 Ty::Void | Ty::Error => return quote_spanned! {span=> () },
1335 // `typedef _Bool bool;` is what every C23 compatibility header
1336 // writes, so the name has to be the qualified one or the alias
1337 // this unit generates for it is `pub type bool = bool;`.
1338 Ty::Bool => return primitive_ty("bool", span),
1339 Ty::Char => "c_char",
1340 Ty::SChar => "c_schar",
1341 Ty::UChar => "c_uchar",
1342 Ty::Short => "c_short",
1343 Ty::UShort => "c_ushort",
1344 Ty::Int => "c_int",
1345 Ty::UInt => "c_uint",
1346 Ty::Long => "c_long",
1347 Ty::ULong => "c_ulong",
1348 Ty::LongLong => "c_longlong",
1349 Ty::ULongLong => "c_ulonglong",
1350 // `core::ffi` has no alias for these: `__int128` is not a C type
1351 // the standard knows, and Rust's own `i128` has had its ABI since
1352 // 1.77. The `core::primitive` path rather than the bare name,
1353 // because `typedef unsigned __int128 u128;` is how real C spells
1354 // it and `pub type u128 = u128;` is a cycle.
1355 Ty::Int128 => {
1356 self.uses_int128.set(true);
1357 return primitive_ty("i128", span);
1358 }
1359 Ty::UInt128 => {
1360 self.uses_int128.set(true);
1361 return primitive_ty("u128", span);
1362 }
1363 Ty::Float => "c_float",
1364 Ty::Double => "c_double",
1365 // `core::ffi` has nothing for these, and there is nothing it could
1366 // have: a complex value is a pair, and the pair the ecosystem
1367 // already agrees on is `num_complex::Complex`, which the runtime
1368 // re-exports. See [`Codegen::rt_path`].
1369 Ty::ComplexFloat | Ty::ComplexDouble => {
1370 self.uses_complex.set(true);
1371 let component =
1372 primitive_ty(if ty == Ty::ComplexFloat { "f32" } else { "f64" }, span);
1373 let rt = self.rt_path(span);
1374 return quote_spanned! {span=> #rt::Complex<#component> };
1375 }
1376 // The lifetime is elided: `VaList` only ever appears as the type of
1377 // a parameter or of a local, where elision does the right thing.
1378 Ty::VaList => "VaList",
1379 // `core::arch`'s own `__m128i` and friends: the same name, the
1380 // same size, the same alignment and the same calling convention
1381 // as C's, which is what makes the intrinsics a name-level mapping
1382 // rather than a translation. The module is `x86_64` or `x86`
1383 // depending on the [target model](crate::target); a unit that
1384 // reaches one of these types on any other architecture never got
1385 // past the `#error` in the bundled header.
1386 Ty::Vector(vec) => {
1387 let module = self.arch_module(span);
1388 let name = Ident::new(vec.name(), span);
1389 return quote_spanned! {span=> ::core::arch::#module::#name };
1390 }
1391 Ty::Pointer(id) => {
1392 let pointer = self.program.types.pointer_type(id);
1393 if let Ty::Func(func) = pointer.pointee {
1394 // C's function pointers can be null, and Rust's cannot;
1395 // `Option` is how the two are reconciled, and it has the
1396 // same representation.
1397 let signature = self.fn_ty(func, span);
1398 return quote_spanned! {span=> ::core::option::Option<#signature> };
1399 }
1400 let pointee = self.pointee_ty(pointer.pointee, span);
1401 return if pointer.konst {
1402 quote_spanned! {span=> *const #pointee }
1403 } else {
1404 quote_spanned! {span=> *mut #pointee }
1405 };
1406 }
1407 Ty::Array(id) => {
1408 // A variably modified array's object *is* a pointer to its
1409 // first element: the elements themselves are one bump off the
1410 // function's arena, however many dimensions there are, and nothing in the
1411 // generated code ever names the array as a value. See
1412 // [`ir::VlaDef`].
1413 if self.program.types.is_vm(ty) {
1414 let step = self.ty(self.program.types.vm_step_ty(ty), span);
1415 return quote_spanned! {span=> *mut #step };
1416 }
1417 let array = self.program.types.array_type(id);
1418 let elem = self.ty(array.elem, span);
1419 let len = usize_literal(array.len, span);
1420 let inner = quote_spanned! {span=> #elem ; #len };
1421 return bracketed(inner, span);
1422 }
1423 Ty::Func(id) => return self.fn_ty(id, span),
1424 Ty::Record(id) => {
1425 let name = self.c_ident(&self.program.types.record(id).rust_name, span);
1426 return quote_spanned! {span=> #name };
1427 }
1428 Ty::Enum(id) => {
1429 let name = self.c_ident(&self.program.types.enum_def(id).rust_name, span);
1430 return quote_spanned! {span=> #name };
1431 }
1432 // An `_Atomic T` object *is* a `T` in the generated Rust: the
1433 // atomicity is in how it is reached — `AtomicX::from_ptr` over its
1434 // address — and not in what it holds. Where the two differ is
1435 // alignment, which the layout code takes from the atomic type and
1436 // the generated item carries as `#[repr(C, align(N))]`.
1437 Ty::Atomic(id) => {
1438 let inner = self.program.types.atomic_inner(id);
1439 return self.ty(inner, span);
1440 }
1441 };
1442 let ident = Ident::new(name, span);
1443 quote_spanned! {span=> ::core::ffi::#ident }
1444 }
1445
1446 /// The `core::arch` submodule the x86 intrinsics and vector types live in:
1447 /// `x86_64` for a 64-bit target and `x86` for a 32-bit one.
1448 ///
1449 /// The two modules have the same names in them — `core::arch::x86` has
1450 /// `_mm_add_epi32` too — so only the path differs between the targets.
1451 /// Anything else is unreachable: the bundled `<immintrin.h>` is an
1452 /// `#error` on a target that is neither.
1453 fn arch_module(&self, span: Span) -> Ident {
1454 let name = if self.options.target.arch == crate::target::Arch::X86 {
1455 "x86"
1456 } else {
1457 "x86_64"
1458 };
1459 Ident::new(name, span)
1460 }
1461
1462 /// The path of the runtime module the generated code calls: `::cinrs::rt`,
1463 /// or whatever `#pragma cinrs crate` said instead of `::cinrs`.
1464 ///
1465 /// It is the one thing an expansion names outside `core` (and outside the
1466 /// `alloc`/`std` a variable length array needs), and it is named in full
1467 /// because the expansion lives in a module of its own where nothing is in
1468 /// scope. See [`ir::DEFAULT_CRATE_PATH`].
1469 fn rt_path(&self, span: Span) -> TokenStream {
1470 let path = TokenStream::from_str(&self.program.crate_path)
1471 .unwrap_or_else(|_| TokenStream::from_str(ir::DEFAULT_CRATE_PATH).expect("valid"));
1472 let path = respan(path, span);
1473 quote_spanned! {span=> #path::rt }
1474 }
1475
1476 /// A function of `cinrs_rt::complex`, by name.
1477 fn rt_complex(&self, name: &str, span: Span) -> TokenStream {
1478 let rt = self.rt_path(span);
1479 let ident = Ident::new(name, span);
1480 quote_spanned! {span=> #rt::complex::#ident }
1481 }
1482
1483 /// The suffix the runtime spells a complex type's component width with.
1484 fn complex_suffix(ty: Ty) -> &'static str {
1485 if ty.complex_component() == Ty::Float {
1486 "f32"
1487 } else {
1488 "f64"
1489 }
1490 }
1491
1492 /// `unsafe extern "C" fn(…) -> R`, the type a function pointer wraps.
1493 ///
1494 /// A function type with no prototype has no parameters to write, so it
1495 /// comes out as `unsafe extern "C" fn() -> R`; what a call through one
1496 /// really passes is written at the call site instead. See
1497 /// [`Codegen::call`].
1498 fn fn_ty(&self, id: ir::FuncTyId, span: Span) -> TokenStream {
1499 let func = self.program.types.func_type(id).clone();
1500 self.fn_ptr_ty(&func.params, func.variadic, func.ret, span)
1501 }
1502
1503 // -- the heap the emulated automatic storage comes from -------------------
1504
1505 /// The crate the `Vec`s behind the bump arena of variable length arrays
1506 /// and `alloca` come from.
1507 ///
1508 /// Everything else the expansion generates is `core`-only; the arena needs
1509 /// an allocator, which is `std` in an ordinary crate and `alloc` in one
1510 /// that said `#pragma cinrs no_std` (and therefore wrote
1511 /// `extern crate alloc;` itself, since a procedural macro cannot add one).
1512 fn alloc_crate(&self, span: Span) -> Ident {
1513 let name = if self.program.no_std { "alloc" } else { "std" };
1514 Ident::new(name, span)
1515 }
1516
1517 /// `::std::vec::Vec<T>`.
1518 fn vec_ty(&self, elem: TokenStream, span: Span) -> TokenStream {
1519 let krate = self.alloc_crate(span);
1520 quote_spanned! {span=> ::#krate::vec::Vec<#elem> }
1521 }
1522
1523 /// `::std::vec::Vec::new()`.
1524 fn vec_new(&self, span: Span) -> TokenStream {
1525 let krate = self.alloc_crate(span);
1526 quote_spanned! {span=> ::#krate::vec::Vec::new() }
1527 }
1528
1529 /// `::std::vec::from_elem(value, len)`, which is what `vec![value; len]`
1530 /// expands to; a procedural macro is better off naming the function.
1531 fn vec_of(&self, value: TokenStream, len: TokenStream, span: Span) -> TokenStream {
1532 let krate = self.alloc_crate(span);
1533 quote_spanned! {span=> ::#krate::vec::from_elem(#value, #len) }
1534 }
1535
1536 /// The Rust type a *pointee* maps to.
1537 ///
1538 /// `void *` is the one place where C's `void` is not Rust's `()`: it stands
1539 /// for "some object of unknown type", which is exactly what
1540 /// [`core::ffi::c_void`] is for. Its size is one byte, so the `void *`
1541 /// arithmetic GCC allows keeps working.
1542 fn pointee_ty(&self, ty: Ty, span: Span) -> TokenStream {
1543 if ty.is_void() {
1544 let ident = Ident::new("c_void", span);
1545 return quote_spanned! {span=> ::core::ffi::#ident };
1546 }
1547 // A pointer to a variably modified type points at what is left under
1548 // the variable dimensions — `double (*)[m]` is a `*mut c_double` —
1549 // and every offset through it is scaled by the bound at run time. See
1550 // [`Codegen::vm_scale`].
1551 if self.program.types.is_vm(ty) {
1552 return self.ty(self.program.types.vm_step_ty(ty), span);
1553 }
1554 self.ty(ty, span)
1555 }
1556
1557 // -- items --------------------------------------------------------------
1558
1559 /// The `struct`, `union`, `enum` and `typedef` items of the unit.
1560 fn type_items(&mut self) -> TokenStream {
1561 let mut out = self.align_wrapper_items();
1562 for record in self.program.types.records() {
1563 if !record.emit {
1564 continue;
1565 }
1566 out.extend(self.record_item(record));
1567 }
1568 out.extend(self.flexible_items());
1569 for def in self.program.types.enums() {
1570 if !def.emit {
1571 continue;
1572 }
1573 let span = self.sp(def.range);
1574 let name = self.c_ident(&def.rust_name, span);
1575 let int = self.ty(Ty::Int, span);
1576 // C says an enumerated type is compatible with an implementation
1577 // defined integer type; every ABI this targets picks `int`.
1578 out.extend(quote_spanned! {span=> pub type #name = #int; });
1579 }
1580 for constant in &self.program.enum_constants {
1581 let span = self.sp(constant.range);
1582 let name = self.c_ident(&constant.rust_name, span);
1583 let ty = self.ty(constant.ty, span);
1584 let value = bare_int_literal(constant.value, constant.ty, span);
1585 out.extend(quote_spanned! {span=> pub const #name: #ty = #value; });
1586 }
1587 for typedef in &self.program.typedefs {
1588 // No alias is generated for `va_list`, which is what the
1589 // `typedef` in <stdarg.h> writes. `core::ffi::VaList` carries the
1590 // lifetime of the frame it reads, so `pub type va_list = VaList;`
1591 // does not even parse — and nothing needs the alias, since every
1592 // generated signature names the type directly.
1593 if self.uses_va_list(typedef.ty) {
1594 continue;
1595 }
1596 let span = self.sp(typedef.range);
1597 let name = self.c_ident(&typedef.rust_name, span);
1598 let ty = self.ty(typedef.ty, span);
1599 out.extend(quote_spanned! {span=> pub type #name = #ty; });
1600 }
1601 out
1602 }
1603
1604 /// The `#[repr(C, align(N))]` wrappers the unit's over-aligned objects are
1605 /// generated inside, one per distinct alignment.
1606 ///
1607 /// Rust can over-align a *type* and nothing else, so an object an
1608 /// `_Alignas(64)` made stricter than its type becomes
1609 ///
1610 /// ```text
1611 /// #[repr(C, align(64))] #[derive(Copy, Clone)]
1612 /// pub struct __cinrs_align_64<T>(pub T);
1613 ///
1614 /// let mut buf: __cinrs_align_64<[c_char; 256]> = __cinrs_align_64(…);
1615 /// ```
1616 ///
1617 /// and every access to `buf` goes through `buf.0` — which is also how Rust
1618 /// code that reaches such an object reads it. The C type is unchanged:
1619 /// `sizeof buf` is the array's size, and only the binding knows about the
1620 /// wrapper. See [`ir::Object::align`].
1621 fn align_wrapper_items(&self) -> TokenStream {
1622 let mut wanted: Vec<(u64, SourceRange)> = self
1623 .program
1624 .objects
1625 .iter()
1626 .filter_map(|object| Some((object.align?, object.range)))
1627 .collect();
1628 wanted.sort_by_key(|(align, _)| *align);
1629 wanted.dedup_by_key(|(align, _)| *align);
1630 let mut out = TokenStream::new();
1631 for (align, range) in wanted {
1632 let span = self.sp(range);
1633 let name = align_wrapper_ident(align, span);
1634 let literal = Literal::u64_unsuffixed(align);
1635 out.extend(quote_spanned! {span=>
1636 #[repr(C, align(#literal))]
1637 #[derive(Copy, Clone)]
1638 pub struct #name<T>(pub T);
1639 });
1640 }
1641 out
1642 }
1643
1644 /// The companion types an object with a filled-in flexible array member
1645 /// needs, one per distinct (record, length).
1646 ///
1647 /// C99 forbids initialising such a member because the object would have to
1648 /// be larger than its type; GNU C allows it for an object with static
1649 /// storage duration, and this is where that extra room comes from:
1650 ///
1651 /// ```text
1652 /// #[repr(C)] pub struct __cinrs_W_3 { pub n: c_int, pub data: [c_int; 3] }
1653 /// pub static mut w: __cinrs_W_3 = __cinrs_W_3 { n: 3, data: [1, 2, 3] };
1654 /// ```
1655 ///
1656 /// The leading layout is the record's own — the same Rust fields, in the
1657 /// same order — so `(&raw mut w).cast::<W>()` is a pointer to a `W`, which
1658 /// is what every use of the object goes through. `sizeof w` is still
1659 /// `sizeof(struct W)`, as it is in GCC. See [`ir::Object::flexible_len`].
1660 fn flexible_items(&self) -> TokenStream {
1661 let mut wanted: Vec<(ir::RecordId, u64)> = self
1662 .program
1663 .objects
1664 .iter()
1665 .filter_map(|object| match (object.flexible_len, object.ty) {
1666 (Some(len), Ty::Record(record)) => Some((record, len)),
1667 _ => None,
1668 })
1669 .collect();
1670 wanted.sort_unstable_by_key(|(record, len)| (record.0, *len));
1671 wanted.dedup_by_key(|(record, len)| (record.0, *len));
1672 let mut out = TokenStream::new();
1673 for (record, len) in wanted {
1674 let def = self.program.types.record(record);
1675 let span = self.sp(def.range);
1676 let name = self.flexible_ident(&def.rust_name, len, span);
1677 out.extend(self.record_body(def, &name, Some(len)));
1678 }
1679 out
1680 }
1681
1682 fn record_item(&self, record: &ir::RecordDef) -> TokenStream {
1683 let span = self.sp(record.range);
1684 let name = self.c_ident(&record.rust_name, span);
1685 let item = self.record_body(record, &name, None);
1686 let accessors = self.bit_field_accessors(record, span);
1687 quote_spanned! {span=> #item #accessors }
1688 }
1689
1690 /// The `struct` (or `union`) item itself, under `name`.
1691 ///
1692 /// `tail` sizes the [flexible array member](ir::Field::flexible), which is
1693 /// what makes a [companion type](Codegen::flexible_items) differ from the
1694 /// record it stands for; `None` is the record as C declared it, whose
1695 /// member is the `[T; 0]` the type says it is.
1696 fn record_body(&self, record: &ir::RecordDef, name: &Ident, tail: Option<u64>) -> TokenStream {
1697 let span = self.sp(record.range);
1698 // `Copy` is what makes a C struct behave like one: assigning it,
1699 // passing it and returning it all copy the bytes.
1700 let derives = match (record.align, record.packed) {
1701 // `__attribute__((packed))` and `#pragma pack(N)` are exactly
1702 // Rust's own `packed(N)`: every field's alignment is capped at N,
1703 // and so is the record's.
1704 (_, Some(1)) => quote_spanned! {span=> #[repr(C, packed)] #[derive(Copy, Clone)] },
1705 (_, Some(pack)) => {
1706 let pack = usize_literal(pack, span);
1707 quote_spanned! {span=>
1708 #[repr(C, packed(#pack))] #[derive(Copy, Clone)]
1709 }
1710 }
1711 // `_Alignas` or `aligned(N)` on a member, or a bit-field whose
1712 // type is stricter than any field the item really has, is honoured
1713 // by raising the *record's* alignment; sema has already placed the
1714 // members where that leaves them.
1715 (Some(align), None) => {
1716 let align = usize_literal(align, span);
1717 quote_spanned! {span=>
1718 #[repr(C, align(#align))] #[derive(Copy, Clone)]
1719 }
1720 }
1721 (None, None) => quote_spanned! {span=> #[repr(C)] #[derive(Copy, Clone)] },
1722 };
1723 let byte = primitive_ty("u8", span);
1724 if !record.complete {
1725 // A tag that is never completed can still be pointed at. An empty
1726 // body is the closest Rust has to C's incomplete type.
1727 return quote_spanned! {span=>
1728 #derives pub struct #name { _incomplete: [#byte; 0] }
1729 };
1730 }
1731 let mut fields = TokenStream::new();
1732 for rust_field in &record.rust_fields {
1733 match rust_field {
1734 ir::RustField::Member(index) => {
1735 let field = &record.fields[*index];
1736 let fspan = self.sp(field.range);
1737 let fname = self.c_ident(&field.name, fspan);
1738 let fty = match (tail, field.flexible) {
1739 (Some(len), true) => {
1740 let elem = self
1741 .program
1742 .types
1743 .elem(field.ty)
1744 .expect("a flexible member is an array");
1745 let elem = self.ty(elem, fspan);
1746 let len = usize_literal(len, fspan);
1747 bracketed(quote_spanned! {fspan=> #elem ; #len }, fspan)
1748 }
1749 _ => self.ty(field.ty, fspan),
1750 };
1751 // Members are `pub` so Rust code can build and read the
1752 // value.
1753 fields.extend(quote_spanned! {fspan=> pub #fname: #fty, });
1754 }
1755 ir::RustField::Bits { name, bytes, .. } | ir::RustField::Pad { name, bytes } => {
1756 let fname = Ident::new(name, span);
1757 let len = usize_literal(*bytes, span);
1758 fields.extend(quote_spanned! {span=> pub #fname: [#byte; #len], });
1759 }
1760 ir::RustField::Align { name, align } => {
1761 let fname = Ident::new(name, span);
1762 let unit = unsigned_rust_ty((*align * 8) as u32, span);
1763 fields.extend(quote_spanned! {span=> pub #fname: [#unit; 0], });
1764 }
1765 }
1766 }
1767 if record.rust_fields.is_empty() && record.kind == RecordKind::Union {
1768 // GCC gives an empty `union` a size of zero, and so does an empty
1769 // Rust `struct`; a Rust `union` has to have at least one field, so
1770 // this is the one place the two kinds are generated differently.
1771 fields.extend(quote_spanned! {span=> pub __cinrs_empty: [#byte; 0], });
1772 }
1773 let body = braced(fields, span);
1774 match record.kind {
1775 RecordKind::Struct => quote_spanned! {span=> #derives pub struct #name #body },
1776 RecordKind::Union => quote_spanned! {span=> #derives pub union #name #body },
1777 }
1778 }
1779
1780 /// The `impl` block holding one getter and one setter per named bit-field.
1781 ///
1782 /// The bits are not a field, so this is the only way to reach them — from
1783 /// the generated code and from Rust alike. Everything is written out
1784 /// inline: no helper type, no runtime, nothing to look up.
1785 fn bit_field_accessors(&self, record: &ir::RecordDef, span: Span) -> TokenStream {
1786 let mut methods = TokenStream::new();
1787 for field in &record.fields {
1788 let Some(bits) = &field.bits else {
1789 continue;
1790 };
1791 let fspan = self.sp(field.range);
1792 methods.extend(self.bit_field_getter(record, field, bits, fspan));
1793 methods.extend(self.bit_field_setter(record, field, bits, fspan));
1794 }
1795 if methods.is_empty() {
1796 return TokenStream::new();
1797 }
1798 let name = self.c_ident(&record.rust_name, span);
1799 quote_spanned! {span=> impl #name { #methods } }
1800 }
1801
1802 /// Reads the bytes a bit-field overlaps into one unsigned integer.
1803 ///
1804 /// The unit rule keeps a field inside one object of its own type, so eight
1805 /// bytes are enough for every type standard C allows a bit-field to have.
1806 /// GNU's `__int128` is the one that can ask for more — `unsigned __int128
1807 /// x : 70` overlaps nine or ten bytes — and the window widens to `u128`
1808 /// there. The word type and its width come back with the tokens, since the
1809 /// getter and the setter have to spell them too.
1810 fn bit_field_window(&self, bits: &ir::BitField, span: Span) -> BitWindow {
1811 let storage = Ident::new(&bits.storage, span);
1812 let start = bits.offset_in_storage();
1813 let first = start / 8;
1814 let shift = (start % 8) as u32;
1815 let count = (shift + bits.width).div_ceil(8);
1816 let word_bits: u32 = if shift + bits.width > 64 { 128 } else { 64 };
1817 let word = window_ty(word_bits, false, span);
1818 let mut read = TokenStream::new();
1819 for step in 0..count {
1820 let index = usize_literal(first + u64::from(step), span);
1821 let byte = if count == 1 {
1822 quote_spanned! {span=> self.#storage[#index] as #word }
1823 } else {
1824 quote_spanned! {span=> (self.#storage[#index] as #word) }
1825 };
1826 read.extend(if step == 0 {
1827 byte
1828 } else {
1829 let by = usize_literal(u64::from(step) * 8, span);
1830 quote_spanned! {span=> | (#byte << #by) }
1831 });
1832 }
1833 // The mask of the field's bits inside that window; the window was
1834 // chosen so that `shift + width` fits in it, which makes the shift fit
1835 // too.
1836 let mask = mask_of(shift + bits.width, word_bits) & !mask_of(shift, word_bits);
1837 BitWindow {
1838 read,
1839 shift,
1840 mask,
1841 word,
1842 word_bits,
1843 }
1844 }
1845
1846 fn bit_field_getter(
1847 &self,
1848 record: &ir::RecordDef,
1849 field: &ir::Field,
1850 bits: &ir::BitField,
1851 span: Span,
1852 ) -> TokenStream {
1853 let BitWindow {
1854 read,
1855 shift,
1856 word,
1857 word_bits,
1858 ..
1859 } = self.bit_field_window(bits, span);
1860 let ty = self.ty(field.ty, span);
1861 let name = self.c_ident(&bits.getter, span);
1862 let mask = word_literal(mask_of(bits.width, word_bits), word_bits, span);
1863 let shifted = if shift == 0 {
1864 quote_spanned! {span=> raw & #mask }
1865 } else {
1866 let by = usize_literal(u64::from(shift), span);
1867 quote_spanned! {span=> (raw >> #by) & #mask }
1868 };
1869 let value = if field.ty.is_bool() {
1870 quote_spanned! {span=> value != 0 }
1871 } else if !bits.signed || bits.width == word_bits {
1872 quote_spanned! {span=> value as #ty }
1873 } else {
1874 // Sign extension: shift the field's top bit up to the sign bit of
1875 // the window's signed counterpart and let the arithmetic shift
1876 // bring it back down.
1877 let signed = window_ty(word_bits, true, span);
1878 let by = usize_literal(u64::from(word_bits - bits.width), span);
1879 quote_spanned! {span=> (((value << #by) as #signed) >> #by) as #ty }
1880 };
1881 let body = self.accessor_body(
1882 record,
1883 quote_spanned! {span=>
1884 let raw: #word = #read;
1885 let value: #word = #shifted;
1886 #value
1887 },
1888 span,
1889 );
1890 quote_spanned! {span=>
1891 #[inline]
1892 pub fn #name(&self) -> #ty { #body }
1893 }
1894 }
1895
1896 fn bit_field_setter(
1897 &self,
1898 record: &ir::RecordDef,
1899 field: &ir::Field,
1900 bits: &ir::BitField,
1901 span: Span,
1902 ) -> TokenStream {
1903 let BitWindow {
1904 read,
1905 shift,
1906 mask,
1907 word,
1908 word_bits,
1909 } = self.bit_field_window(bits, span);
1910 let ty = self.ty(field.ty, span);
1911 let name = self.c_ident(&bits.setter, span);
1912 let storage = Ident::new(&bits.storage, span);
1913 let value = Ident::new("value", span);
1914 let field_mask = word_literal(mask, word_bits, span);
1915 let keep = word_literal(!mask & mask_of(word_bits, word_bits), word_bits, span);
1916 let shifted = if shift == 0 {
1917 quote_spanned! {span=> (#value as #word) & #field_mask }
1918 } else {
1919 let by = usize_literal(u64::from(shift), span);
1920 quote_spanned! {span=> ((#value as #word) << #by) & #field_mask }
1921 };
1922 let start = bits.offset_in_storage();
1923 let first = start / 8;
1924 let count = (shift + bits.width).div_ceil(8);
1925 let mut writes = TokenStream::new();
1926 let byte = primitive_ty("u8", span);
1927 for step in 0..count {
1928 let index = usize_literal(first + u64::from(step), span);
1929 if step == 0 {
1930 writes.extend(quote_spanned! {span=> self.#storage[#index] = raw as #byte; });
1931 } else {
1932 let by = usize_literal(u64::from(step) * 8, span);
1933 writes.extend(
1934 quote_spanned! {span=> self.#storage[#index] = (raw >> #by) as #byte; },
1935 );
1936 }
1937 }
1938 let body = self.accessor_body(
1939 record,
1940 quote_spanned! {span=>
1941 let bits: #word = #shifted;
1942 let raw: #word = #read;
1943 let raw: #word = (raw & #keep) | bits;
1944 #writes
1945 },
1946 span,
1947 );
1948 quote_spanned! {span=>
1949 #[inline]
1950 pub fn #name(&mut self, #value: #ty) { #body }
1951 }
1952 }
1953
1954 /// Wraps an accessor body in `unsafe` where reading the storage needs it,
1955 /// which is exactly when the record is a `union`.
1956 fn accessor_body(&self, record: &ir::RecordDef, body: TokenStream, span: Span) -> TokenStream {
1957 if record.kind == RecordKind::Union {
1958 let block = braced(body, span);
1959 return quote_spanned! {span=> unsafe #block };
1960 }
1961 body
1962 }
1963
1964 /// `const _: () = { assert!(…); };` — the assumptions the data model made,
1965 /// checked against the target the expansion is really compiled for.
1966 ///
1967 /// Everything this crate computes at expansion time — `sizeof`, member
1968 /// offsets, bit-field storage, the type of an integer constant, the value
1969 /// of an `#if` — comes out of a [`TargetModel`](crate::TargetModel) that
1970 /// was chosen from `CINRS_TARGET`, from `#pragma cinrs target`, or (with
1971 /// neither) from the *host*. Any of the three may be the wrong one, and a
1972 /// wrong one would leave every one of those answers quietly wrong. So the
1973 /// expansion states them: `long` is this many bytes, a pointer is that
1974 /// many, plain `char` is signed, `double` is aligned so. The generated
1975 /// code uses the `core::ffi` aliases, which follow the *target*, so a
1976 /// mismatch is a failed assertion at the caret of the C rather than a
1977 /// program that computes the wrong thing — and the message names both the
1978 /// model that was used and the knob that chose it.
1979 ///
1980 /// `__int128`'s alignment is included only where the unit has one: it is
1981 /// the one scalar whose alignment is not fixed by its width, and a unit
1982 /// that never mentions it must not be refused over it.
1983 fn data_model_check(&self) -> TokenStream {
1984 let span = self.map.span(SourceRange::at(0));
1985 let target = &self.options.target;
1986 // Every message ends with this, so that a failure says what to change
1987 // rather than only what went wrong.
1988 let chosen = format!(
1989 "Translated for {}; set CINRS_TARGET from a build script \
1990 (cargo:rustc-env=CINRS_TARGET=$TARGET) or write #pragma cinrs target.",
1991 target.describe(&self.options.target_source)
1992 );
1993 let mut body = TokenStream::new();
1994 let mut width = |ty: TokenStream, bits: u32, what: &str| {
1995 let bytes = usize_literal(u64::from(bits).div_ceil(8), span);
1996 let message = message_literal(
1997 &format!(
1998 "cinrs: {what} is {} bytes in the data model this unit was translated for, \
1999 and is not on this target. {chosen}",
2000 bits.div_ceil(8)
2001 ),
2002 span,
2003 );
2004 body.extend(quote_spanned! {span=>
2005 assert!(::core::mem::size_of::<#ty>() == #bytes, #message);
2006 });
2007 };
2008 width(
2009 quote_spanned! {span=> ::core::ffi::c_short },
2010 target.short_bits,
2011 "'short'",
2012 );
2013 width(
2014 quote_spanned! {span=> ::core::ffi::c_int },
2015 target.int_bits,
2016 "'int'",
2017 );
2018 width(
2019 quote_spanned! {span=> ::core::ffi::c_long },
2020 target.long_bits,
2021 "'long'",
2022 );
2023 width(
2024 quote_spanned! {span=> ::core::ffi::c_longlong },
2025 target.long_long_bits,
2026 "'long long'",
2027 );
2028 width(
2029 quote_spanned! {span=> *const ::core::ffi::c_void },
2030 target.ptr_bits,
2031 "a pointer",
2032 );
2033 // Plain `char`'s signedness decides what `'\xff'` is worth and how a
2034 // `char` widens, so it is an assumption like any other. `c_char` is an
2035 // alias for `i8` or `u8`, and only the unsigned one has a zero minimum.
2036 let (test, said) = if target.char_signed {
2037 (
2038 quote_spanned! {span=> ::core::ffi::c_char::MIN != 0 },
2039 "signed",
2040 )
2041 } else {
2042 (
2043 quote_spanned! {span=> ::core::ffi::c_char::MIN == 0 },
2044 "unsigned",
2045 )
2046 };
2047 let message = message_literal(
2048 &format!(
2049 "cinrs: plain 'char' is {said} in the data model this unit was translated \
2050 for, and is not on this target. {chosen}"
2051 ),
2052 span,
2053 );
2054 body.extend(quote_spanned! {span=> assert!(#test, #message); });
2055 // The one property two targets of the same *data model* differ on: the
2056 // i386 System V ABI aligns `long long` and `double` to four bytes and
2057 // the Microsoft one to eight, and every member offset the front end
2058 // computed followed whichever this model says. `c_longlong` and
2059 // `c_double` are the aliases, so the assertion follows the target.
2060 let align = usize_literal(target.max_scalar_align.min(8), span);
2061 let message = message_literal(
2062 &format!(
2063 "cinrs: 'long long' and 'double' are {}-byte aligned in the data model this \
2064 unit was translated for, and are not on this target — so every 'sizeof' and \
2065 member offset in it would be wrong. {chosen}",
2066 target.max_scalar_align.min(8)
2067 ),
2068 span,
2069 );
2070 body.extend(quote_spanned! {span=>
2071 assert!(
2072 ::core::mem::align_of::<::core::ffi::c_longlong>() == #align
2073 && ::core::mem::align_of::<::core::ffi::c_double>() == #align,
2074 #message
2075 );
2076 });
2077 if self.uses_int128.get() {
2078 let align = usize_literal(target.int128_align, span);
2079 let message = message_literal(
2080 &format!(
2081 "cinrs: '__int128' is {}-byte aligned in the data model this unit was \
2082 translated for, and is not on this target. {chosen}",
2083 target.int128_align
2084 ),
2085 span,
2086 );
2087 let i128 = primitive_ty("i128", span);
2088 body.extend(quote_spanned! {span=>
2089 assert!(::core::mem::align_of::<#i128>() == #align, #message);
2090 });
2091 }
2092 if self.uses_complex.get() {
2093 // A complex type *is* two of its component type side by side —
2094 // that is the whole reason the runtime uses a `#[repr(C)]` pair —
2095 // and every `sizeof`, member offset and array stride in the unit
2096 // was computed from that. A `Complex<f64>` that is not sixteen
2097 // bytes would make all of them wrong, so the unit says so.
2098 for (ty, name) in [
2099 (Ty::ComplexFloat, "'float _Complex'"),
2100 (Ty::ComplexDouble, "'double _Complex'"),
2101 ] {
2102 let layout = self
2103 .program
2104 .types
2105 .size_align(ty, target)
2106 .expect("a complex type has a layout");
2107 let rust = self.ty(ty, span);
2108 let size = usize_literal(layout.size, span);
2109 let align = usize_literal(layout.align, span);
2110 let message = message_literal(
2111 &format!(
2112 "cinrs: {name} is {} bytes and {}-byte aligned in the data model this \
2113 unit was translated for, and is not on this target. {chosen}",
2114 layout.size, layout.align
2115 ),
2116 span,
2117 );
2118 body.extend(quote_spanned! {span=>
2119 assert!(
2120 ::core::mem::size_of::<#rust>() == #size
2121 && ::core::mem::align_of::<#rust>() == #align,
2122 #message
2123 );
2124 });
2125 }
2126 }
2127 let block = braced(body, span);
2128 quote_spanned! {span=> const _: () = #block; }
2129 }
2130
2131 /// The `extern` block declaring everything the unit does not define, with
2132 /// the libraries the unit links beside it — one empty block each, never an
2133 /// attribute on this one; [`Codegen::link_blocks`] is why.
2134 ///
2135 /// A **function** is declared under its own C name — `pub fn crc32`, not a
2136 /// hidden one — so that the glob re-export carries it out of the unit's
2137 /// module and `#include <zlib.h>` is all Rust needs to call it. An
2138 /// **object** is not, because a glob-imported `static` changes what a `let`
2139 /// of the same name means; [`Program::extern_object_name`] is that rule and
2140 /// its reason.
2141 fn extern_block(&mut self) -> TokenStream {
2142 if !self.program.has_externs() {
2143 return TokenStream::new();
2144 }
2145 let span = self.map.span(SourceRange::at(0));
2146 let mut items = TokenStream::new();
2147 // The symbols this block links by, which is what decides whether it
2148 // needs a library of its own; see [`LEGACY_STDIO`]. Collected here
2149 // rather than asked of the program a second time, so that what the
2150 // attribute answers for and what the block declares cannot drift apart.
2151 let mut symbols: Vec<&str> = Vec::new();
2152 for id in &self.program.externs {
2153 let object = self.program.object(*id);
2154 let Storage::Extern { item_name } = &object.storage else {
2155 continue;
2156 };
2157 let ospan = self.sp(object.range);
2158 let rust_name = self.extern_object_ident(item_name, ospan);
2159 let ty = self.ty(object.ty, ospan);
2160 // An `__asm__("symbol")` label renames the declaration, which is
2161 // exactly what `#[link_name]` already says.
2162 let symbol = object.asm_label.as_deref().unwrap_or(item_name);
2163 symbols.push(symbol);
2164 let link = link_name(symbol, ospan);
2165 items.extend(quote_spanned! {ospan=> #link pub static mut #rust_name: #ty; });
2166 }
2167 for func in &self.program.functions {
2168 if !func.is_extern() {
2169 continue;
2170 }
2171 // An [x86 intrinsic](crate::x86) has no symbol: a call to it is
2172 // generated as `::core::arch::x86_64::<name>`, and declaring one
2173 // here would put a `pub fn _mm_add_ps` into the unit's module —
2174 // which the facade glob re-exports, so it would clash with a
2175 // `use core::arch::x86_64::*` in the user's own code and link
2176 // against nothing if it were ever called. The bundled
2177 // `<immintrin.h>` declares eight hundred of them; **none** of
2178 // them reaches the generated Rust.
2179 if func.intrinsic.is_some() {
2180 continue;
2181 }
2182 let fspan = self.sp(func.range);
2183 // The C name, through the same mapping every other name goes
2184 // through: a keyword becomes `r#yield`, `a$b` becomes
2185 // `a_dollar_b`, and [`Names`] has already made it unique within
2186 // the unit. It is what a call in this unit names too; see
2187 // [`Codegen::function_path`].
2188 let rust_name = self.c_ident(func.item_name(), fspan);
2189 let params = self.extern_params(func, fspan);
2190 let ret = if func.sig.ret.is_void() {
2191 TokenStream::new()
2192 } else {
2193 let ty = self.ty(func.sig.ret, fspan);
2194 quote_spanned! {fspan=> -> #ty }
2195 };
2196 // An `__asm__("symbol")` label is the program's own answer and wins;
2197 // failing that, a name the Microsoft library exports differently is
2198 // linked by the name it really has. See [`MSVC_RENAMED`].
2199 let symbol = match func.asm_label.as_deref() {
2200 Some(label) => label,
2201 None => self.msvc_symbol(&func.name),
2202 };
2203 symbols.push(symbol);
2204 let link = link_name(symbol, fspan);
2205 items.extend(quote_spanned! {fspan=> #link pub fn #rust_name(#params) #ret; });
2206 }
2207 let links = self.link_blocks(&symbols, span);
2208 quote_spanned! {span=> #links unsafe extern "C" { #items } }
2209 }
2210
2211 /// The libraries this unit links: one `#[link(name = "…")] unsafe extern "C"
2212 /// {}` — the ordinary Rust idiom for "also link this" — for every
2213 /// `#pragma cinrs link` the unit wrote, and for the library an MSVC target
2214 /// needs to resolve the `printf` family.
2215 ///
2216 /// Nothing here is needed for the C library itself, which the Rust runtime
2217 /// already links; the pragma is for the program that calls into something
2218 /// else, and [`LEGACY_STDIO`] is the one library cinrs asks for on its own
2219 /// initiative. `symbols` is what the declarations in the block next to these
2220 /// link by, which is what decides the second of those.
2221 ///
2222 /// A library named by both — `#pragma cinrs link "legacy_stdio_definitions"`
2223 /// written out by hand — is emitted once.
2224 ///
2225 /// # Why an empty block of its own, and not an attribute on the declarations
2226 ///
2227 /// Because `#[link(name = "…")]` says two things, and cinrs means only the
2228 /// first. It puts the library on the link line, and it also makes `rustc`
2229 /// reach every `static` declared *in that very block* through a `dllimport`
2230 /// on a Windows target — `native_library` is asked per foreign item, so a
2231 /// sibling block is untouched. A `dllimport` is right for an object that
2232 /// lives in another image and silently wrong for one that lives in this one:
2233 /// with the attribute on the declarations, a unit that declared
2234 /// `extern int counter;` while another exported unit of the same crate
2235 /// defined it read rubbish — 7887437 for 17, measured on Windows — and
2236 /// `lld-link` said `LNK4217: locally defined symbol imported`.
2237 ///
2238 /// For the `printf` rule that was cinrs's own doing: a unit that includes
2239 /// `<stdio.h>` never asked for a library. The pragma is the program's own
2240 /// statement, but it is no better placed to decide, because in C adding a
2241 /// `.lib` to a link line implies `__declspec(dllimport)` on nothing, and
2242 /// cinrs has no way to write that per declaration. So no generated
2243 /// declaration is a `dllimport`, which is C's own default, and a program that
2244 /// wants a DLL's *data* export — the one case the import library exposes as
2245 /// `__imp_name` alone — names that pointer itself:
2246 ///
2247 /// ```c
2248 /// #pragma cinrs link "gdi32"
2249 /// extern unsigned long *batch_limit __asm__("__imp_GdiBatchLimit");
2250 /// ```
2251 ///
2252 /// That reads the DLL's value; the same symbol declared as a plain object is
2253 /// `lld-link: error: undefined symbol: GdiBatchLimit` — loud, at link time,
2254 /// rather than a wrong value. With the attribute on the declarations even the
2255 /// pointer was out of reach: `rustc` asked for its `__imp_` in turn, and
2256 /// `lld-link` said `undefined symbol: __declspec(dllimport)
2257 /// __imp_GdiBatchLimit`. Every sentence here was measured on
2258 /// `x86_64-pc-windows-msvc`; `doc/cross-compilation.md` keeps the numbers and
2259 /// `tests/declared_names.rs` the cases.
2260 fn link_blocks(&self, symbols: &[&str], span: Span) -> TokenStream {
2261 let mut libraries: Vec<&str> = Vec::new();
2262 for name in &self.program.link_libraries {
2263 if !libraries.contains(&name.as_str()) {
2264 libraries.push(name);
2265 }
2266 }
2267 for library in self.legacy_stdio_libraries(symbols) {
2268 if !libraries.contains(&library) {
2269 libraries.push(library);
2270 }
2271 }
2272 let mut out = TokenStream::new();
2273 for name in libraries {
2274 let mut literal = Literal::string(name);
2275 literal.set_span(span);
2276 out.extend(quote_spanned! {span=> #[link(name = #literal)] unsafe extern "C" {} });
2277 }
2278 out
2279 }
2280
2281 /// The symbol a **declaration** of the C function `name` links by: the name
2282 /// itself, or, on an MSVC target, what the Microsoft C runtime exports it
2283 /// as. See [`MSVC_RENAMED`] for the table and for how each row was read out
2284 /// of a real import library.
2285 ///
2286 /// Only a declaration: a function this unit *defines* is its own symbol, and
2287 /// a C program that defines `time` has defined `time`.
2288 fn msvc_symbol<'name>(&self, name: &'name str) -> &'name str {
2289 if !self.options.target.is_msvc() {
2290 return name;
2291 }
2292 for (c_name, symbol) in MSVC_RENAMED {
2293 if *c_name == name {
2294 return symbol;
2295 }
2296 }
2297 name
2298 }
2299
2300 /// The libraries the `printf` and `scanf` declarations among `symbols` have
2301 /// to be linked against, in the order [`LEGACY_STDIO`] lists them.
2302 ///
2303 /// Empty on every target but an MSVC one: everywhere else the platform's
2304 /// library exports those functions as ordinary symbols and there is nothing
2305 /// to ask for. See [`LEGACY_STDIO`] for why the Microsoft library differs.
2306 fn legacy_stdio_libraries(&self, symbols: &[&str]) -> Vec<&'static str> {
2307 if !self.options.target.is_msvc() {
2308 return Vec::new();
2309 }
2310 let mut out: Vec<&'static str> = Vec::new();
2311 for (symbol, library) in LEGACY_STDIO {
2312 if symbols.contains(symbol) && !out.contains(library) {
2313 out.push(library);
2314 }
2315 }
2316 out
2317 }
2318
2319 fn extern_params(&self, func: &Function, span: Span) -> TokenStream {
2320 let mut params = TokenStream::new();
2321 for (index, ty) in func.sig.params.iter().enumerate() {
2322 if index > 0 {
2323 params.extend(quote_spanned! {span=> , });
2324 }
2325 let ty = self.ty(*ty, span);
2326 match func.param_names.get(index).and_then(|n| n.as_ref()) {
2327 Some(name) => {
2328 let name = self.c_ident(name, span);
2329 params.extend(quote_spanned! {span=> #name: #ty });
2330 }
2331 None => params.extend(quote_spanned! {span=> _: #ty }),
2332 }
2333 }
2334 if func.sig.variadic {
2335 if !func.sig.params.is_empty() {
2336 params.extend(quote_spanned! {span=> , });
2337 }
2338 params.extend(quote_spanned! {span=> ... });
2339 }
2340 params
2341 }
2342
2343 fn static_item(&mut self, var: &ir::StaticVar) -> TokenStream {
2344 let object = self.program.object(var.object);
2345 let span = self.sp(object.range);
2346 if object.storage.is_thread_local() {
2347 return self.thread_local_item(var);
2348 }
2349 let Storage::Static {
2350 item_name,
2351 exported,
2352 } = &object.storage
2353 else {
2354 return TokenStream::new();
2355 };
2356 let name = self.c_ident(item_name, span);
2357 let ty = self.binding_ty(var.object, self.storage_ty(var.object, span), span);
2358 let init = self.static_init(&var.init, object.ty, span);
2359 let init = self.binding_init(var.object, init, span);
2360 let (vis, export) = if *exported {
2361 let export = if self.program.export {
2362 let symbol = object.asm_label.as_deref().unwrap_or(&object.name);
2363 export_attr(symbol, &name, span)
2364 } else {
2365 TokenStream::new()
2366 };
2367 (quote_spanned! {span=> pub }, export)
2368 } else {
2369 (TokenStream::new(), TokenStream::new())
2370 };
2371 let section = match &object.section {
2372 Some(section) => {
2373 let mut literal = Literal::string(section);
2374 literal.set_span(span);
2375 quote_spanned! {span=> #[unsafe(link_section = #literal)] }
2376 }
2377 None => TokenStream::new(),
2378 };
2379 // `static mut` rather than a cell: C code assigns to globals from
2380 // anywhere, and reading or writing one directly (never taking a
2381 // reference) is what keeps edition 2024's `static_mut_refs` quiet.
2382 quote_spanned! {span=>
2383 #export
2384 #section
2385 #vis static mut #name: #ty = #init;
2386 }
2387 }
2388
2389 /// `std::thread_local! { static X: UnsafeCell<T> = const { … }; }` — the
2390 /// item a `_Thread_local` object becomes.
2391 ///
2392 /// C's thread-local object has static storage duration and one instance
2393 /// per thread, and `thread_local!` is exactly that. The cell is what makes
2394 /// the object *mutable*: `with` hands out a `&UnsafeCell<T>`, and the
2395 /// `*mut T` inside it is valid for as long as the thread's copy is, which
2396 /// is the lifetime C promises the address of such an object.
2397 ///
2398 /// The initialiser goes inside a `const` block wherever it can — that is
2399 /// the form with no lazy-initialisation flag and no destructor to register
2400 /// — and directly otherwise. Only one thing keeps it out: an initialiser
2401 /// that mentions the address of another item, which a `const` may not
2402 /// refer to (`E0013`).
2403 fn thread_local_item(&mut self, var: &ir::StaticVar) -> TokenStream {
2404 let object = self.program.object(var.object);
2405 let span = self.sp(object.range);
2406 let Storage::ThreadLocal {
2407 item_name,
2408 exported,
2409 } = &object.storage
2410 else {
2411 return TokenStream::new();
2412 };
2413 if self.program.no_std {
2414 // `sema::check_pragmas` has already said that a thread-local object
2415 // needs `std`; emitting `::std::thread_local!` anyway would add
2416 // `rustc`'s own "cannot find `std`" on top of it.
2417 return TokenStream::new();
2418 }
2419 let name = self.c_ident(item_name, span);
2420 let ty = self.binding_ty(var.object, self.storage_ty(var.object, span), span);
2421 let init = self.static_init(&var.init, object.ty, span);
2422 let init = self.binding_init(var.object, init, span);
2423 let vis = if *exported {
2424 quote_spanned! {span=> pub }
2425 } else {
2426 TokenStream::new()
2427 };
2428 let cell = quote_spanned! {span=> ::core::cell::UnsafeCell<#ty> };
2429 let value = quote_spanned! {span=> ::core::cell::UnsafeCell::new(#init) };
2430 let value = if self.const_initialisable(&var.init) {
2431 quote_spanned! {span=> const { #value } }
2432 } else {
2433 value
2434 };
2435 // The lint exemptions are the unit module's own (see
2436 // [`crate::in_module`]), and a `thread_local!` is expanded inside it
2437 // like anything else, so the `static` it generates inherits them.
2438 quote_spanned! {span=>
2439 ::std::thread_local! {
2440 #vis static #name: #cell = #value;
2441 }
2442 }
2443 }
2444
2445 /// Whether an initialiser may go inside a `const { … }` block.
2446 ///
2447 /// A Rust constant may not refer to a `static` (`E0013`), which rules out
2448 /// exactly the initialisers whose value is the address of another item: a
2449 /// pointer to a file-scope object, a function pointer, and the `static`
2450 /// that holds the characters of a wide string literal. A *narrow* literal
2451 /// is a byte string whose `as_ptr` is const, and every arithmetic constant
2452 /// is fine.
2453 ///
2454 /// This is what decides between `thread_local!`'s two forms; see
2455 /// [`Codegen::thread_local_item`].
2456 fn const_initialisable(&self, expr: &Expr) -> bool {
2457 match &expr.kind {
2458 ExprKind::FuncAddr(_) => false,
2459 ExprKind::AddrOf(place) | ExprKind::Load(place) => match &place.kind {
2460 PlaceKind::Str(id) => {
2461 let elem = self.program.string(*id).elem;
2462 elem.size_bytes(&self.options.target) == 1
2463 }
2464 _ => !rooted_in_static(place, self.program),
2465 },
2466 ExprKind::Cast(inner) => self.const_initialisable(inner),
2467 ExprKind::PtrOffset { ptr, .. } => self.const_initialisable(ptr),
2468 ExprKind::RecordLit { fields, .. } => {
2469 fields.iter().all(|f| self.const_initialisable(f))
2470 }
2471 ExprKind::UnionLit { value, .. } => self.const_initialisable(value),
2472 ExprKind::ArrayLit(items) => items.iter().all(|i| self.const_initialisable(i)),
2473 ExprKind::ArrayRepeat { value, .. } => self.const_initialisable(value),
2474 _ => true,
2475 }
2476 }
2477
2478 /// The initialiser of a `static mut`, wrapped in `unsafe` when it needs to
2479 /// be (`mem::zeroed`, or the address of another `static mut`).
2480 fn static_init(&mut self, expr: &Expr, ty: Ty, span: Span) -> TokenStream {
2481 let tokens = self.expr_at(expr, ty);
2482 if needs_unsafe(&self.program.types, expr) {
2483 let block = braced(tokens, span);
2484 return quote_spanned! {span=> unsafe #block };
2485 }
2486 tokens
2487 }
2488
2489 fn signature(&mut self, func: &Function) -> TokenStream {
2490 let span = self.sp(func.range);
2491 let name = self.c_ident(func.item_name(), span);
2492 let mut params = TokenStream::new();
2493 // A lifted nested function takes the objects it uses from the
2494 // enclosing frame as pointers, in front of everything the program
2495 // wrote; see [`ir::EnvParam`].
2496 for entry in &func.env {
2497 let object = self.program.object(entry.param);
2498 let pspan = self.sp(object.range);
2499 let pname = self.object_ident(entry.param, pspan);
2500 let pty = self.ty(object.ty, pspan);
2501 params.extend(quote_spanned! {pspan=> #pname: #pty , });
2502 }
2503 // A definition whose parameters did not check out may have fewer than
2504 // the signature says; either way the list still has to have the right
2505 // shape, so it falls back to names of our own.
2506 let named = func.params.len() == func.sig.params.len();
2507 for (index, ty) in func.sig.params.iter().enumerate() {
2508 if index > 0 {
2509 params.extend(quote_spanned! {span=> , });
2510 }
2511 if named {
2512 let id = func.params[index];
2513 let object = self.program.object(id);
2514 let pspan = self.sp(object.range);
2515 let pname = self.object_ident(id, pspan);
2516 let pty = self.ty(*ty, pspan);
2517 params.extend(quote_spanned! {pspan=> mut #pname: #pty });
2518 } else {
2519 let pname = Ident::new(&format!("__cinrs_arg{index}"), Span::mixed_site());
2520 let pty = self.ty(*ty, span);
2521 params.extend(quote_spanned! {span=> #pname: #pty });
2522 }
2523 }
2524 if func.sig.variadic {
2525 if !func.sig.params.is_empty() {
2526 params.extend(quote_spanned! {span=> , });
2527 }
2528 // The variable part of the argument list arrives as one more
2529 // parameter. It is never advanced: `va_start` and every `va_list`
2530 // local copy it, so it stays the list as the caller left it.
2531 let name = self.va_ident();
2532 params.extend(quote_spanned! {span=> #name: ... });
2533 }
2534 let ret = if func.sig.ret.is_void() {
2535 TokenStream::new()
2536 } else {
2537 let ty = self.ty(func.sig.ret, span);
2538 quote_spanned! {span=> -> #ty }
2539 };
2540 // A definition is a Rust item rather than a C symbol unless the unit
2541 // asked for real symbols, so an `__asm__("name")` label on one only
2542 // means something there — and there it names the symbol the item
2543 // takes, which is what `#[unsafe(export_name)]` says. On a *declaration*
2544 // the label is always honoured, through the `extern` block's
2545 // `#[link_name]`.
2546 let exported = !func.is_static && self.program.export;
2547 let vis = if func.is_static {
2548 TokenStream::new()
2549 } else {
2550 quote_spanned! {span=> pub }
2551 };
2552 let export = if exported {
2553 let symbol = func.asm_label.as_deref().unwrap_or(&func.name);
2554 export_attr(symbol, &name, span)
2555 } else {
2556 TokenStream::new()
2557 };
2558 // `#[inline]` is ignored on an exported function, and saying so is
2559 // `rustc`'s job rather than the user's to read: leave it out.
2560 //
2561 // `always_inline` on a function with a target feature — from
2562 // `__attribute__((target))` or `#pragma GCC target`, both of which
2563 // are in `target_features` — is `#[inline]`: rustc refuses
2564 // `#[inline(always)]` together with `#[target_feature]` ("cannot use
2565 // `#[inline(always)]` with `#[target_feature]`", rust-lang/rust#145574),
2566 // and BLAKE3's SIMD files are exactly that pairing, an `INLINE` macro
2567 // of `static inline __attribute__((always_inline))` under `#pragma GCC
2568 // target("sse4.1")`. The hint is then only a hint, and LLVM does not
2569 // always take it — so where it can, the helper drops the
2570 // `#[target_feature]` instead and keeps `#[inline(always)]`; see
2571 // [`Function::inline_helper`] for when, and why that is sound.
2572 let helper = func.inline_helper();
2573 let inline = match func.inline_hint {
2574 Some(_) if exported => TokenStream::new(),
2575 _ if helper => quote_spanned! {span=> #[inline(always)] },
2576 Some(ir::InlineHint::Always) if !func.target_features.is_empty() => {
2577 quote_spanned! {span=> #[inline] }
2578 }
2579 Some(ir::InlineHint::Always) => quote_spanned! {span=> #[inline(always)] },
2580 Some(ir::InlineHint::Never) => quote_spanned! {span=> #[inline(never)] },
2581 None if func.is_inline && !exported => quote_spanned! {span=> #[inline] },
2582 None => TokenStream::new(),
2583 };
2584 let cold = if func.cold {
2585 quote_spanned! {span=> #[cold] }
2586 } else {
2587 TokenStream::new()
2588 };
2589 let deprecated = match &func.deprecated {
2590 Some(Some(message)) => {
2591 let mut literal = Literal::string(message);
2592 literal.set_span(span);
2593 quote_spanned! {span=> #[deprecated(note = #literal)] }
2594 }
2595 Some(None) => quote_spanned! {span=> #[deprecated] },
2596 None => TokenStream::new(),
2597 };
2598 let section = match &func.section {
2599 Some(section) => {
2600 let mut literal = Literal::string(section);
2601 literal.set_span(span);
2602 quote_spanned! {span=> #[unsafe(link_section = #literal)] }
2603 }
2604 None => TokenStream::new(),
2605 };
2606 // `__attribute__((target("avx2")))`, which is the same promise
2607 // `#[target_feature(enable = "avx2")]` makes: the body may use that
2608 // instruction set, and a caller has to have checked that the
2609 // processor has it — with `__builtin_cpu_supports`, as in C.
2610 let target_feature = if helper {
2611 TokenStream::new()
2612 } else {
2613 self.target_feature_attrs(func, span)
2614 };
2615 // Everything is `extern "C"`, so that its address is a C function
2616 // pointer, except that helper, whose address nothing takes and which
2617 // could not pass a vector through the C ABI without the feature.
2618 let abi = if helper {
2619 TokenStream::new()
2620 } else {
2621 quote_spanned! {span=> extern "C" }
2622 };
2623 // A function the unit asked to be safe is generated without `unsafe`,
2624 // and its body without the `unsafe` block, so that `rustc` checks every
2625 // operation in it; see [`crate::sema::check_safe`] for what that
2626 // catches and what it refuses outright.
2627 let unsafety = if func.is_safe() {
2628 TokenStream::new()
2629 } else {
2630 quote_spanned! {span=> unsafe }
2631 };
2632 quote_spanned! {span=>
2633 #export
2634 #inline
2635 #cold
2636 #deprecated
2637 #section
2638 #target_feature
2639 #vis #unsafety #abi fn #name(#params) #ret
2640 }
2641 }
2642
2643 /// One `#[target_feature(enable = "…")]` per instruction set the function
2644 /// asked for.
2645 ///
2646 /// One attribute per name rather than one attribute with several `enable`s
2647 /// — both are legal, and this reads as the list of `-m` switches it came
2648 /// from.
2649 fn target_feature_attrs(&self, func: &Function, span: Span) -> TokenStream {
2650 let mut out = TokenStream::new();
2651 for feature in &func.target_features {
2652 let mut literal = Literal::string(feature);
2653 literal.set_span(span);
2654 out.extend(quote_spanned! {span=> #[target_feature(enable = #literal)] });
2655 }
2656 out
2657 }
2658
2659 /// The `static` that puts a `constructor` or `destructor` function into the
2660 /// table the runtime walks before `main` (or after it).
2661 ///
2662 /// ELF has `.init_array` and `.fini_array`, and Mach-O has
2663 /// `__DATA,__mod_init_func` and `__mod_term_func`; nothing else this crate
2664 /// can name has such a table, so a program that asks for one elsewhere is
2665 /// told so rather than quietly built without it.
2666 fn init_array_item(&mut self, func: &Function, kind: ir::InitKind) -> TokenStream {
2667 let span = self.sp(func.range);
2668 let name = self.c_ident(func.item_name(), span);
2669 let signature = self.function_pointer_ty(func, span);
2670 let item = Ident::new(
2671 &format!(
2672 "__CINRS_INIT_{:08x}_{}",
2673 self.program.unit_id as u32,
2674 func.item_name()
2675 ),
2676 span,
2677 );
2678 let elf = match kind {
2679 ir::InitKind::Constructor => ".init_array",
2680 ir::InitKind::Destructor => ".fini_array",
2681 };
2682 let apple = match kind {
2683 ir::InitKind::Constructor => "__DATA,__mod_init_func",
2684 ir::InitKind::Destructor => "__DATA,__mod_term_func",
2685 };
2686 let mut elf_literal = Literal::string(elf);
2687 elf_literal.set_span(span);
2688 let mut apple_literal = Literal::string(apple);
2689 apple_literal.set_span(span);
2690 // The section name is the one thing about this that is not portable,
2691 // so it is chosen at compile time rather than assumed.
2692 quote_spanned! {span=>
2693 #[used]
2694 #[cfg_attr(target_vendor = "apple", unsafe(link_section = #apple_literal))]
2695 #[cfg_attr(not(target_vendor = "apple"), unsafe(link_section = #elf_literal))]
2696 static #item: #signature = #name;
2697 }
2698 }
2699
2700 /// The one check a unit with a `constructor` or a `destructor` carries.
2701 ///
2702 /// A procedural macro is compiled for the *host*, so it cannot know which
2703 /// target the code it generates is for; the check therefore has to be part
2704 /// of the expansion. It is emitted once per unit rather than once per
2705 /// function, since it says the same thing either way.
2706 fn init_array_guard(&self) -> TokenStream {
2707 let span = self.map.span(SourceRange::at(0));
2708 quote_spanned! {span=>
2709 const _: () = {
2710 #[cfg(not(any(target_os = "linux", target_os = "android",
2711 target_os = "freebsd", target_os = "netbsd",
2712 target_os = "openbsd", target_os = "dragonfly",
2713 target_vendor = "apple")))]
2714 ::core::compile_error!(
2715 "'constructor' and 'destructor' need a target whose runtime walks an initialiser table (ELF or Mach-O)"
2716 );
2717 };
2718 }
2719 }
2720
2721 fn function_item(&mut self, func: &Function) -> TokenStream {
2722 let span = self.sp(func.range);
2723 let Some(body) = &func.body else {
2724 return TokenStream::new();
2725 };
2726 self.enter_function(func);
2727 let signature = self.signature(func);
2728 let body = match body {
2729 Body::Structured(stmts) => self.stmts(stmts),
2730 Body::Cfg(cfg) => self.cfg_body(cfg, span),
2731 };
2732 // `alloca`'s memory belongs to the function, not to the block the call
2733 // was written in, so the arena is opened here and dropped by whichever
2734 // `return` runs; a variable length array only borrows space from it
2735 // until its block ends.
2736 let arena = if func.uses_arena {
2737 self.uses_arena.set(true);
2738 let name = self.arena_ident(span);
2739 let ty = arena_ty();
2740 quote_spanned! {span=> let #name = #ty::new(); }
2741 } else {
2742 TokenStream::new()
2743 };
2744 // One `unsafe` block around the whole body: in edition 2024 the body of
2745 // an `unsafe fn` is not itself an unsafe block any more. A safe
2746 // function is exactly the one that does not get it — that block is what
2747 // would stop `rustc` checking the translation.
2748 if func.is_safe() {
2749 return quote_spanned! {span=>
2750 #signature { #arena #body }
2751 };
2752 }
2753 quote_spanned! {span=>
2754 #signature {
2755 unsafe { #arena #body }
2756 }
2757 }
2758 }
2759
2760 /// The name of the bump arena a function that declares a variable length
2761 /// array or calls `alloca` opens with, in this crate's own hygiene, for a
2762 /// use of it written at `span`.
2763 fn arena_ident(&self, span: Span) -> Ident {
2764 if self.arena_span.get().is_none() {
2765 self.arena_span.set(Some(span));
2766 }
2767 Ident::new("__cinrs_vla", Span::mixed_site())
2768 }
2769
2770 /// The bump arena's type and its frame guard: one pair of private items
2771 /// per unit that has a variable length array or an `alloca` anywhere.
2772 ///
2773 /// C gives both kinds of object automatic storage — a compiler bumps the
2774 /// stack pointer — and the emulation is the same idea on the heap, per
2775 /// function call:
2776 ///
2777 /// * the storage is a list of chunks that never move, each a `Vec<u128>`
2778 /// so that its base is 16-byte aligned, and the position is a chunk
2779 /// index and a byte offset in it. No chunk is allocated until the first
2780 /// allocation, and the arena, dropped by the `return`, frees them all;
2781 /// * `alloc` pads the position up to the alignment — by address, so that
2782 /// `aligned(64)` works in a 16-byte-aligned chunk — bumps it, and zeroes
2783 /// what it hands out: C leaves the array indeterminate, but reading
2784 /// uninitialised bytes through a raw pointer is undefined in Rust as
2785 /// well, and zeroed memory is what the translation always gave. Only
2786 /// when the current chunk is full does it go to the next one, reusing it
2787 /// if it is big enough and otherwise dropping every chunk after the
2788 /// current one — nothing above the position is live — for a new one of
2789 /// at least twice the size;
2790 /// * a variable length array's lifetime is a frame: the position before it
2791 /// was allocated, which the frame's `Drop` at the end of the block moves
2792 /// the arena back down to. The position never goes below `floor`, which
2793 /// `alloca` raises past each allocation it makes: its memory lives until
2794 /// the function returns, even out of a block whose array is given back —
2795 /// GCC's own rule;
2796 /// * a [CFG-mode](crate::cfg) function has no blocks to drop frames at, so
2797 /// it keeps one mark per variable length array in an array, and
2798 /// `redefine` moves the arena back down to a declaration's previous mark
2799 /// when the declaration is reached again, forgetting every mark taken
2800 /// after it: those arrays were declared later on the path that got here,
2801 /// so jumping back over this declaration ended their lifetimes too.
2802 ///
2803 /// Everything is in [`Cell`]s so that any number of frames can hold a
2804 /// shared borrow of the arena at once. The methods are safe: the only
2805 /// memory they touch is the arena's own.
2806 fn arena_items(&self, span: Span) -> TokenStream {
2807 let arena = arena_ty();
2808 let frame = Ident::new("__cinrs_vla_frame", Span::mixed_site());
2809 let t = Ident::new("T", Span::mixed_site());
2810 let usize_ty = primitive_ty("usize", span);
2811 let u128_ty = primitive_ty("u128", span);
2812 let u8_ty = primitive_ty("u8", span);
2813 let chunk_ty = self.vec_ty(u128_ty.clone(), span);
2814 let chunks_ty = self.vec_ty(chunk_ty, span);
2815 let empty = self.vec_new(span);
2816 let new_chunk = self.vec_of(
2817 quote_spanned! {span=> 0 },
2818 quote_spanned! {span=> size.div_ceil(::core::mem::size_of::<#u128_ty>()) },
2819 span,
2820 );
2821 let void = self.pointee_ty(Ty::Void, span);
2822 quote_spanned! {span=>
2823 #[allow(
2824 unknown_lints,
2825 elided_lifetimes_in_paths,
2826 missing_debug_implementations,
2827 single_use_lifetimes,
2828 unused_qualifications,
2829 clippy::pedantic,
2830 clippy::nursery
2831 )]
2832 struct #arena {
2833 chunks: ::core::cell::UnsafeCell<#chunks_ty>,
2834 cur: ::core::cell::Cell<#usize_ty>,
2835 top: ::core::cell::Cell<#usize_ty>,
2836 floor: ::core::cell::Cell<(#usize_ty, #usize_ty)>,
2837 }
2838 #[allow(
2839 unknown_lints,
2840 elided_lifetimes_in_paths,
2841 single_use_lifetimes,
2842 unused_qualifications,
2843 clippy::pedantic,
2844 clippy::nursery
2845 )]
2846 impl #arena {
2847 #[inline(always)]
2848 fn new() -> Self {
2849 Self {
2850 chunks: ::core::cell::UnsafeCell::new(#empty),
2851 cur: ::core::cell::Cell::new(0),
2852 top: ::core::cell::Cell::new(0),
2853 floor: ::core::cell::Cell::new((0, 0)),
2854 }
2855 }
2856 #[inline(always)]
2857 fn mark(&self) -> (#usize_ty, #usize_ty) {
2858 (self.cur.get(), self.top.get())
2859 }
2860 #[inline(always)]
2861 fn frame(&self) -> #frame<'_> {
2862 #frame(self, self.mark())
2863 }
2864 /// Moves the position back down to `mark`, but never below
2865 /// `floor` and never up.
2866 #[inline(always)]
2867 fn release(&self, mark: (#usize_ty, #usize_ty)) {
2868 let floor = self.floor.get();
2869 let to = if mark > floor { mark } else { floor };
2870 if to < self.mark() {
2871 self.cur.set(to.0);
2872 self.top.set(to.1);
2873 }
2874 }
2875 #[inline(always)]
2876 fn bytes(&self, bytes: #usize_ty, align: #usize_ty) -> *mut #u8_ty {
2877 // SAFETY: nothing else borrows the list of chunks while
2878 // this runs, and the memory written is inside a chunk.
2879 unsafe {
2880 let chunks = &mut *self.chunks.get();
2881 let top = self.top.get();
2882 if let ::core::option::Option::Some(chunk) = chunks.get_mut(self.cur.get()) {
2883 let base = chunk.as_mut_ptr().cast::<#u8_ty>();
2884 let size = chunk.len() * ::core::mem::size_of::<#u128_ty>();
2885 let start = top + (base.addr().wrapping_add(top).wrapping_neg() & (align - 1));
2886 if start <= size && bytes <= size - start {
2887 self.top.set(start + bytes);
2888 let first = base.add(start);
2889 ::core::ptr::write_bytes(first, 0, bytes);
2890 return first;
2891 }
2892 }
2893 }
2894 self.grow(bytes, align)
2895 }
2896 #[cold]
2897 #[inline(never)]
2898 fn grow(&self, bytes: #usize_ty, align: #usize_ty) -> *mut #u8_ty {
2899 let need = bytes
2900 .checked_add(align)
2901 .expect("a variable length array or alloca is larger than the address space");
2902 {
2903 // SAFETY: as in `bytes`; the chunks dropped are above
2904 // the position, where nothing is live.
2905 let chunks = unsafe { &mut *self.chunks.get() };
2906 let next = if chunks.is_empty() { 0 } else { self.cur.get() + 1 };
2907 let unit = ::core::mem::size_of::<#u128_ty>();
2908 let fits = match chunks.get(next) {
2909 ::core::option::Option::Some(chunk) => chunk.len() * unit >= need,
2910 ::core::option::Option::None => false,
2911 };
2912 if !fits {
2913 let last = match chunks.last() {
2914 ::core::option::Option::Some(chunk) => chunk.len() * unit,
2915 ::core::option::Option::None => 0,
2916 };
2917 chunks.truncate(next);
2918 let size = need.max(last.saturating_mul(2)).max(4096);
2919 chunks.push(#new_chunk);
2920 }
2921 self.cur.set(next);
2922 self.top.set(0);
2923 }
2924 self.bytes(bytes, align)
2925 }
2926 /// `count` zeroed elements of `T`.
2927 #[inline(always)]
2928 fn alloc<#t>(&self, count: #usize_ty) -> *mut #t {
2929 self.alloc_aligned::<#t>(count, 1)
2930 }
2931 /// `count` zeroed elements of `T`, the first at a multiple of
2932 /// `align` if that is stricter than `T`'s own alignment.
2933 #[inline(always)]
2934 fn alloc_aligned<#t>(&self, count: #usize_ty, align: #usize_ty) -> *mut #t {
2935 let bytes = count
2936 .checked_mul(::core::mem::size_of::<#t>())
2937 .expect("a variable length array is larger than the address space");
2938 let natural = ::core::mem::align_of::<#t>();
2939 self.bytes(bytes, if align > natural { align } else { natural })
2940 .cast::<#t>()
2941 }
2942 /// `size` zeroed bytes, 16-byte aligned, that no frame gives
2943 /// back: they live until the arena is dropped.
2944 #[inline(always)]
2945 fn alloca(&self, size: #usize_ty) -> *mut #void {
2946 let first = self.bytes(size, 16);
2947 self.floor.set(self.mark());
2948 first.cast::<#void>()
2949 }
2950 /// A CFG-mode variable length array's declaration reached:
2951 /// gives back what its previous pass took, and everything
2952 /// allocated after that, and records where this one starts.
2953 #[inline]
2954 fn redefine(
2955 &self,
2956 marks: &mut [::core::option::Option<(#usize_ty, #usize_ty)>],
2957 slot: #usize_ty,
2958 ) {
2959 if let ::core::option::Option::Some(mine) = marks[slot] {
2960 // No let chain: the user's crate may be on an
2961 // edition before 2024.
2962 for mark in marks.iter_mut() {
2963 if let ::core::option::Option::Some(other) = *mark {
2964 if other >= mine {
2965 *mark = ::core::option::Option::None;
2966 }
2967 }
2968 }
2969 self.release(mine);
2970 }
2971 marks[slot] = ::core::option::Option::Some(self.mark());
2972 }
2973 }
2974 #[allow(
2975 unknown_lints,
2976 elided_lifetimes_in_paths,
2977 missing_debug_implementations,
2978 single_use_lifetimes,
2979 clippy::pedantic,
2980 clippy::nursery
2981 )]
2982 struct #frame<'a>(&'a #arena, (#usize_ty, #usize_ty));
2983 #[allow(
2984 unknown_lints,
2985 elided_lifetimes_in_paths,
2986 single_use_lifetimes,
2987 clippy::pedantic,
2988 clippy::nursery
2989 )]
2990 impl ::core::ops::Drop for #frame<'_> {
2991 #[inline(always)]
2992 fn drop(&mut self) {
2993 self.0.release(self.1);
2994 }
2995 }
2996 }
2997 }
2998
2999 fn stub_item(&mut self, func: &Function) -> TokenStream {
3000 let span = self.sp(func.range);
3001 self.enter_function(func);
3002 let signature = self.signature(func);
3003 if func.is_safe() {
3004 return quote_spanned! {span=>
3005 #signature { ::core::unreachable!() }
3006 };
3007 }
3008 quote_spanned! {span=>
3009 #signature {
3010 unsafe { ::core::unreachable!() }
3011 }
3012 }
3013 }
3014
3015 /// Resets the per-function state before a body is generated.
3016 fn enter_function(&mut self, func: &Function) {
3017 self.ret_ty = func.sig.ret;
3018 self.in_cfg = matches!(func.body, Some(Body::Cfg(_)));
3019 self.in_safe = func.is_safe();
3020 self.temporaries = 0;
3021 self.continue_styles.clear();
3022 self.local_names.clear();
3023 self.region_names.clear();
3024 self.region_kinds.clear();
3025 self.loop_names.clear();
3026 self.shape_scopes.clear();
3027 self.used_labels.clear();
3028 self.shape_labels = 0;
3029 self.vla_slots.clear();
3030 if let Some(Body::Structured(stmts)) = &func.body {
3031 self.name_regions(stmts);
3032 }
3033 if let Some(Body::Cfg(cfg)) = &func.body
3034 && let Some(plan) = &cfg.shape
3035 {
3036 let mut taken = HashSet::new();
3037 self.name_loops(&plan.body, &mut taken);
3038 }
3039 self.env = func
3040 .env
3041 .iter()
3042 .map(|entry| (entry.owner, entry.param))
3043 .collect();
3044
3045 // Every object this function binds with a `let` or a parameter, so
3046 // that one that would shadow a file-scope item can be renamed apart
3047 // and the rename can be checked against the others. Sema's list is
3048 // what makes a local declared inside a statement expression — which no
3049 // walk over the *statements* would reach — part of it.
3050 let mut bound: Vec<ir::ObjectId> = func.env.iter().map(|entry| entry.param).collect();
3051 bound.extend(func.params.iter().copied());
3052 if let Some(Body::Cfg(cfg)) = &func.body {
3053 for local in &cfg.locals {
3054 self.local_names
3055 .insert(local.object, local.rust_name.clone());
3056 }
3057 }
3058 bound.extend(func.locals.iter().copied());
3059 self.rename_shadowing(&bound);
3060
3061 self.va_source = if func.sig.variadic {
3062 VaSource::Ellipsis
3063 } else {
3064 // A `va_list *` parameter points at the caller's list, which is
3065 // what a `va_list` local of this function starts out as — the same
3066 // thing a `va_list` parameter is, one indirection further out.
3067 func.params
3068 .iter()
3069 .find_map(|id| {
3070 let ty = self.program.object(*id).ty;
3071 if ty.is_va_list() {
3072 return Some(VaSource::Param(*id));
3073 }
3074 let pointee = self.program.types.pointee(ty)?;
3075 pointee.is_va_list().then_some(VaSource::PtrParam(*id))
3076 })
3077 .unwrap_or(VaSource::None)
3078 };
3079 }
3080
3081 /// The name a local or parameter would be generated under before the
3082 /// shadowing check.
3083 fn plain_local_name(&self, id: ir::ObjectId) -> String {
3084 match self.local_names.get(&id) {
3085 Some(name) => name.clone(),
3086 None => self.program.object(id).name.clone(),
3087 }
3088 }
3089
3090 /// Renames the bindings of the current function whose names would shadow a
3091 /// file-scope item.
3092 ///
3093 /// The new name is the C one with `_1`, `_2`, … appended, the same shape
3094 /// the [CFG lowering](crate::cfg) uses when it hoists two locals of the
3095 /// same name into one scope, and it is checked against the function's
3096 /// other bindings so that a rename never captures one of them. The check
3097 /// is against their Rust *spellings* (see [`Names`]), which is what two
3098 /// bindings collide in.
3099 fn rename_shadowing(&mut self, bound: &[ir::ObjectId]) {
3100 if self.reserved.is_empty() {
3101 return;
3102 }
3103 let mut used: HashSet<String> = bound
3104 .iter()
3105 .map(|id| {
3106 self.names
3107 .spelling(&self.plain_local_name(*id))
3108 .into_owned()
3109 })
3110 .collect();
3111 for id in bound {
3112 let base = self.plain_local_name(*id);
3113 if !self.reserved.contains(&base) {
3114 continue;
3115 }
3116 let name = (1u32..)
3117 .map(|n| format!("{base}_{n}"))
3118 .find(|c| {
3119 !used.contains(self.names.spelling(c).as_ref()) && !self.reserved.contains(c)
3120 })
3121 .expect("the sequence of candidates is unbounded");
3122 used.insert(self.names.spelling(&name).into_owned());
3123 self.local_names.insert(*id, name);
3124 }
3125 }
3126
3127 /// The name of the synthetic `...` parameter.
3128 ///
3129 /// Mixed-site hygiene keeps it distinct from a C variable of the same
3130 /// name, however unlikely one is.
3131 fn va_ident(&self) -> Ident {
3132 Ident::new("__cinrs_va", Span::mixed_site())
3133 }
3134
3135 /// A fresh copy of the argument list the function was called with.
3136 fn va_pristine(&mut self, span: Span) -> TokenStream {
3137 match self.va_source {
3138 VaSource::Param(id) => {
3139 let name = self.object_ident(id, span);
3140 quote_spanned! {span=> #name.clone() }
3141 }
3142 VaSource::PtrParam(id) => {
3143 let name = self.object_ident(id, span);
3144 quote_spanned! {span=> (*#name).clone() }
3145 }
3146 // `VaSource::None` cannot reach codegen: sema refuses a `va_list`
3147 // that has nothing to copy.
3148 _ => {
3149 let name = self.va_ident();
3150 quote_spanned! {span=> #name.clone() }
3151 }
3152 }
3153 }
3154
3155 /// The alignment an object's binding has to be wrapped in, if any.
3156 ///
3157 /// Rust has no way to over-align a binding, so an object an `_Alignas` or
3158 /// an `aligned` made stricter than its type is generated inside a
3159 /// one-field wrapper that carries the alignment; see
3160 /// [`Codegen::align_wrapper_items`] and [`ir::Object::align`].
3161 fn object_align(&self, id: ir::ObjectId) -> Option<u64> {
3162 self.program.object(id).align
3163 }
3164
3165 /// The type an object's binding is declared with.
3166 fn binding_ty(&self, id: ir::ObjectId, ty: TokenStream, span: Span) -> TokenStream {
3167 match self.object_align(id) {
3168 Some(align) => {
3169 let wrapper = align_wrapper_ident(align, span);
3170 quote_spanned! {span=> #wrapper<#ty> }
3171 }
3172 None => ty,
3173 }
3174 }
3175
3176 /// The value an object's binding is initialised with.
3177 fn binding_init(&self, id: ir::ObjectId, init: TokenStream, span: Span) -> TokenStream {
3178 match self.object_align(id) {
3179 Some(align) => {
3180 let wrapper = align_wrapper_ident(align, span);
3181 quote_spanned! {span=> #wrapper(#init) }
3182 }
3183 None => init,
3184 }
3185 }
3186
3187 /// The type an object's *storage* has, which is its own except for the
3188 /// [companion](ir::Object::flexible_len) a filled-in flexible array member
3189 /// needs.
3190 fn storage_ty(&self, id: ir::ObjectId, span: Span) -> TokenStream {
3191 let object = self.program.object(id);
3192 match (object.flexible_len, object.ty) {
3193 (Some(len), Ty::Record(record)) => {
3194 let name =
3195 self.flexible_ident(&self.program.types.record(record).rust_name, len, span);
3196 quote_spanned! {span=> #name }
3197 }
3198 _ => self.ty(object.ty, span),
3199 }
3200 }
3201
3202 /// The place expression naming an object, reaching through the alignment
3203 /// wrapper and the flexible-array companion when the binding has them.
3204 fn object_access(&self, id: ir::ObjectId, span: Span) -> TokenStream {
3205 let name = self.object_ident(id, span);
3206 self.through_storage(id, quote_spanned! {span=> #name }, span)
3207 }
3208
3209 /// Reaches the C object inside the storage its binding really has.
3210 ///
3211 /// Two wrappers can sit in between, and they compose: the
3212 /// [alignment](ir::Object::align) wrapper's one field, and the
3213 /// [flexible-array companion](ir::Object::flexible_len), whose leading
3214 /// layout is the record's and whose address is therefore a pointer to it.
3215 fn through_storage(&self, id: ir::ObjectId, base: TokenStream, span: Span) -> TokenStream {
3216 let object = self.program.object(id);
3217 let mut access = base;
3218 if object.align.is_some() {
3219 let field = Literal::usize_unsuffixed(0);
3220 access = quote_spanned! {span=> #access.#field };
3221 }
3222 if object.flexible_len.is_some() {
3223 let ty = self.ty(object.ty, span);
3224 access = parenthesize(
3225 quote_spanned! {span=> *(&raw mut #access).cast::<#ty>() },
3226 span,
3227 );
3228 }
3229 access
3230 }
3231
3232 /// Reading a `va_list` copies it: Rust's is not `Copy`, and C says a list
3233 /// passed on is indeterminate afterwards anyway.
3234 ///
3235 /// A `va_list` place is an object of its own or the `*p` of a `va_list *`
3236 /// — nothing may keep one as a member — so the only setup there can be is
3237 /// the temporary that pointer goes into. Out of line for the same reason
3238 /// [`Codegen::label_address`] is.
3239 #[inline(never)]
3240 fn va_list_load(&mut self, place: &Place, span: Span) -> Value {
3241 let lowered = self.place(place, false);
3242 let access = lowered.access;
3243 let value = Value::new(quote_spanned! {span=> #access.clone() }, prec::CALL);
3244 if lowered.setup.is_empty() {
3245 return value;
3246 }
3247 let setup = lowered.setup;
3248 let tokens = value.at(prec::LOWEST, span);
3249 Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
3250 }
3251
3252 /// GNU's `&&label`: the number the label was given among those of its
3253 /// function whose address is taken — from 1, so never a null pointer —
3254 /// cast to the pointer type the expression has. See [`crate::cfg`].
3255 ///
3256 /// Out of line — like [`Codegen::label_difference`] — because
3257 /// [`Codegen::expr_value`] recurses once per operator and every arm's
3258 /// locals are part of its frame; see
3259 /// `codegen_of_deeply_nested_input_fits_in_a_small_stack`.
3260 #[inline(never)]
3261 fn label_address(&self, id: ir::LabelId, ty: Ty, span: Span) -> Value {
3262 let state = self.label_states.get(&id).copied().unwrap_or(0);
3263 let mut literal = Literal::usize_suffixed(state as usize);
3264 literal.set_span(span);
3265 let target = self.ty(ty, span);
3266 Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
3267 }
3268
3269 /// GNU's `&&a - &&b`, folded on the two labels' numbers.
3270 #[inline(never)]
3271 fn label_difference(&self, lhs: &Expr, rhs: &Expr, ty: Ty, span: Span) -> Value {
3272 let left = self.label_state_literal(lhs, span);
3273 let right = self.label_state_literal(rhs, span);
3274 let target = self.ty(ty, span);
3275 Value::new(
3276 quote_spanned! {span=> (#left - #right) as #target },
3277 prec::CAST,
3278 )
3279 .type_end(true)
3280 }
3281
3282 /// The number a [label address](ir::ExprKind::LabelAddr) stands for, as an
3283 /// `isize` literal.
3284 fn label_state_literal(&self, expr: &Expr, span: Span) -> TokenStream {
3285 let id = label_state(expr).expect("a label address");
3286 let state = self.label_states.get(&id).copied().unwrap_or(0);
3287 let mut literal = Literal::isize_suffixed(state as isize);
3288 literal.set_span(span);
3289 quote_spanned! {span=> #literal }
3290 }
3291
3292 /// The Rust name an object is generated under.
3293 fn object_ident(&self, id: ir::ObjectId, span: Span) -> Ident {
3294 let object = self.program.object(id);
3295 match &object.storage {
3296 Storage::Automatic => match self.local_names.get(&id) {
3297 Some(name) => self.c_ident(name, span),
3298 None => self.c_ident(&object.name, span),
3299 },
3300 // A `static mut` is used as a place, never referenced, so
3301 // edition 2024's `static_mut_refs` lint has nothing to say.
3302 Storage::Static { item_name, .. } | Storage::ThreadLocal { item_name, .. } => {
3303 self.c_ident(item_name, span)
3304 }
3305 Storage::Extern { item_name } => self.extern_object_ident(item_name, span),
3306 }
3307 }
3308
3309 // -- the control-flow-graph form ----------------------------------------
3310
3311 /// Emits a [CFG](crate::cfg) body.
3312 ///
3313 /// Every local is bound at the top — Rust has no way to jump over a `let`
3314 /// — and then either the structured shapes [the relooper](crate::reloop)
3315 /// recovered, or, for a graph it gave up on, the state machine.
3316 fn cfg_body(&mut self, cfg: &Cfg, span: Span) -> TokenStream {
3317 let mut out = self.cfg_locals(cfg);
3318 match &cfg.shape {
3319 Some(plan) => {
3320 out.extend(self.shape_seq(cfg, &plan.body, &reloop::Exit::nowhere(), span))
3321 }
3322 None => out.extend(self.state_machine(cfg, span)),
3323 }
3324 out
3325 }
3326
3327 /// The `let` bindings every local of a graph-lowered function gets.
3328 fn cfg_locals(&mut self, cfg: &Cfg) -> TokenStream {
3329 let mut out = TokenStream::new();
3330 let mut slots = 0;
3331 let mut slots_span = None;
3332 for local in &cfg.locals {
3333 let object = self.program.object(local.object);
3334 let ospan = self.sp(object.range);
3335 // The hidden frame of a variable length array is a slot of one
3336 // array of arena marks, which starts out empty; the declaration
3337 // fills it where it was written, first giving back whatever a
3338 // previous pass over it took. See [`Codegen::arena_items`].
3339 if object.vla_storage {
3340 self.vla_slots.insert(local.object, slots);
3341 slots += 1;
3342 slots_span.get_or_insert(ospan);
3343 continue;
3344 }
3345 let name = self.object_ident(local.object, ospan);
3346 let (ty, init) = if object.ty.is_va_list() {
3347 // A `va_list` has no zero value; it starts out as a copy of
3348 // the list the function was called with, exactly as it does
3349 // when the declaration stays where it was written.
3350 (self.ty(object.ty, ospan), self.va_pristine(ospan))
3351 } else {
3352 (
3353 self.ty(object.ty, ospan),
3354 self.zero_tokens(object.ty, ospan),
3355 )
3356 };
3357 let ty = self.binding_ty(local.object, ty, ospan);
3358 let init = self.binding_init(local.object, init, ospan);
3359 out.extend(quote_spanned! {ospan=> let mut #name: #ty = #init; });
3360 }
3361 if let Some(span) = slots_span {
3362 let marks = vla_marks_ident();
3363 let usize_ty = primitive_ty("usize", span);
3364 let len = Literal::usize_unsuffixed(slots);
3365 out.extend(quote_spanned! {span=>
3366 let mut #marks: [::core::option::Option<(#usize_ty, #usize_ty)>; #len] =
3367 [::core::option::Option::None; #len];
3368 });
3369 }
3370 out
3371 }
3372
3373 /// The graph as a state machine, for one [the relooper](crate::reloop) gave
3374 /// up on: shapes nested deeper than `rustc` parses.
3375 ///
3376 /// Every arm of the `match` ends in `continue 'cfg` or in a `return`, so
3377 /// the loop never finishes and the function needs no value after it.
3378 fn state_machine(&mut self, cfg: &Cfg, span: Span) -> TokenStream {
3379 let state = self.state_ident();
3380 let label = self.cfg_label();
3381 let mut arms = TokenStream::new();
3382 for (index, block) in cfg.blocks.iter().enumerate() {
3383 let bspan = self.block_span(block, span);
3384 let pattern = state_literal(index, bspan);
3385 let body = self.block_tokens(block, bspan);
3386 arms.extend(quote_spanned! {bspan=> #pattern => { #body } });
3387 }
3388 arms.extend(quote_spanned! {span=> _ => ::core::unreachable!(), });
3389 let u32_ty = primitive_ty("u32", span);
3390 quote_spanned! {span=>
3391 let mut #state: #u32_ty = 0;
3392 #label: loop {
3393 match #state { #arms }
3394 }
3395 }
3396 }
3397
3398 /// The state variable, in this crate's own hygiene.
3399 fn state_ident(&self) -> Ident {
3400 Ident::new("__cinrs_state", Span::mixed_site())
3401 }
3402
3403 fn cfg_label(&self) -> TokenStream {
3404 self.label("cfg", Span::mixed_site())
3405 }
3406
3407 /// Where a block's tokens are attributed to: the first thing in it that
3408 /// came from the C source.
3409 fn block_span(&self, block: &BasicBlock, fallback: Span) -> Span {
3410 if let Some(range) = block.stmts.iter().find_map(|s| self.stmt_range(s)) {
3411 return self.sp(range);
3412 }
3413 match &block.term {
3414 Terminator::Jump { range, .. }
3415 | Terminator::Switch { range, .. }
3416 | Terminator::Return { range, .. } => self.sp(*range),
3417 Terminator::Branch { cond, .. } => self.sp(cond.range),
3418 Terminator::Unreachable | Terminator::InvalidTarget => fallback,
3419 }
3420 }
3421
3422 fn block_tokens(&mut self, block: &BasicBlock, span: Span) -> TokenStream {
3423 let mut out = self.stmts(&block.stmts);
3424 let label = self.cfg_label();
3425 match &block.term {
3426 Terminator::Jump { target, range } => {
3427 let jump = self.enter_block(*target, self.sp(*range));
3428 out.extend(quote_spanned! {span=> #jump continue #label; });
3429 }
3430 Terminator::Branch {
3431 cond,
3432 then_blk,
3433 else_blk,
3434 } => {
3435 let cspan = self.sp(cond.range);
3436 let test = self.condition(cond).at_condition(cspan);
3437 let then_tokens = self.enter_block(*then_blk, cspan);
3438 let else_tokens = self.enter_block(*else_blk, cspan);
3439 out.extend(quote_spanned! {cspan=>
3440 if #test { #then_tokens } else { #else_tokens }
3441 continue #label;
3442 });
3443 }
3444 Terminator::Switch {
3445 value,
3446 cases,
3447 default,
3448 range,
3449 } => {
3450 let sspan = self.sp(*range);
3451 let scrutinee = self.expr(value).at(prec::UNARY, sspan);
3452 let mut arms = TokenStream::new();
3453 for (target, values) in group_cases(cases) {
3454 let mut pattern = TokenStream::new();
3455 for (index, case) in values.iter().enumerate() {
3456 if index > 0 {
3457 pattern.extend(quote_spanned! {sspan=> | });
3458 }
3459 pattern.extend(case_pattern(*case, value.ty, sspan));
3460 }
3461 let enter = self.enter_block(target, sspan);
3462 arms.extend(quote_spanned! {sspan=> #pattern => { #enter } });
3463 }
3464 let enter = self.enter_block(*default, sspan);
3465 arms.extend(quote_spanned! {sspan=> _ => { #enter } });
3466 out.extend(quote_spanned! {sspan=>
3467 match #scrutinee { #arms }
3468 continue #label;
3469 });
3470 }
3471 Terminator::Return { value, range } => {
3472 let rspan = self.sp(*range);
3473 match value {
3474 Some(value) => {
3475 let ret = self.ret_ty;
3476 let tokens = self.expr_at(value, ret);
3477 out.extend(quote_spanned! {rspan=> return #tokens; });
3478 }
3479 None => out.extend(quote_spanned! {rspan=> return; }),
3480 }
3481 }
3482 Terminator::Unreachable => {
3483 out.extend(quote_spanned! {span=> ::core::unreachable!(); });
3484 }
3485 Terminator::InvalidTarget => out.extend(invalid_target(span)),
3486 }
3487 out
3488 }
3489
3490 /// The assignment that moves the state machine to `target`.
3491 fn enter_block(&self, target: BlockId, span: Span) -> TokenStream {
3492 let state = self.state_ident();
3493 let value = state_literal(target.0 as usize, span);
3494 quote_spanned! {span=> #state = #value; }
3495 }
3496
3497 // -- the structured form of the graph ------------------------------------
3498
3499 /// Names the loops [the relooper](crate::reloop) recovered, after the C
3500 /// labels their heads stand at.
3501 ///
3502 /// The same rules as [`Codegen::name_regions`]: a name Rust cannot spell
3503 /// as a label, or one this module gives its own loops and blocks, is
3504 /// replaced by `rN`, and a name two loops would share gets an underscore.
3505 fn name_loops(&mut self, seq: &reloop::Seq, taken: &mut HashSet<String>) {
3506 for shape in seq {
3507 match shape {
3508 reloop::Shape::Loop { id, name, body, .. } => {
3509 let mut candidate = match name {
3510 Some(name) => rust_spelling(name).into_owned(),
3511 None => String::new(),
3512 };
3513 if !is_label_name(&candidate) {
3514 candidate = format!("r{id}");
3515 }
3516 while taken.contains(&candidate) {
3517 candidate.push('_');
3518 }
3519 taken.insert(candidate.clone());
3520 self.loop_names.insert(*id, candidate);
3521 self.name_loops(body, taken);
3522 }
3523 reloop::Shape::Simple { arms, .. } | reloop::Shape::Dispatch { arms, .. } => {
3524 for arm in arms {
3525 self.name_loops(&arm.body, taken);
3526 }
3527 }
3528 }
3529 }
3530 }
3531
3532 /// A run of shapes, one after another.
3533 ///
3534 /// Everything before a shape stands inside a labelled block that ends
3535 /// where that shape begins, so that a jump forwards is `break` of it —
3536 /// the same shape [`regions`](crate::regions) gives an outward `goto`.
3537 /// The nesting runs the other way round from the order they are emitted
3538 /// in: the block for the *second* shape is the innermost one, so that
3539 /// breaking it lands on the second shape and breaking any of the others
3540 /// skips past what is in between.
3541 fn shape_seq(
3542 &mut self,
3543 cfg: &Cfg,
3544 seq: &reloop::Seq,
3545 fall: &reloop::Exit,
3546 span: Span,
3547 ) -> TokenStream {
3548 let Some(first) = seq.first() else {
3549 return TokenStream::new();
3550 };
3551 let exits: Vec<reloop::Exit> = seq.iter().map(reloop::Shape::exit).collect();
3552 // An irreducible region's state variable is bound before anything that
3553 // could jump into it, which is the head of the run it stands in.
3554 let mut out = TokenStream::new();
3555 for shape in seq {
3556 if let reloop::Shape::Loop {
3557 state: Some(state), ..
3558 } = shape
3559 {
3560 let name = entry_ident(*state);
3561 let u32_ty = primitive_ty("u32", span);
3562 out.extend(quote_spanned! {span=> let mut #name: #u32_ty = 0; });
3563 }
3564 }
3565 let ids: Vec<u32> = (1..seq.len())
3566 .map(|_| {
3567 let id = self.shape_labels;
3568 self.shape_labels += 1;
3569 id
3570 })
3571 .collect();
3572 for (index, id) in ids.iter().enumerate().rev() {
3573 self.shape_scopes.push(ShapeScope {
3574 id: *id,
3575 name: format!("b{id}"),
3576 repeats: false,
3577 exit: exits[index + 1].clone(),
3578 });
3579 }
3580 let mut code = self.shape(cfg, first, exits.get(1).unwrap_or(fall), span);
3581 for (index, shape) in seq.iter().enumerate().skip(1) {
3582 let scope = self.shape_scopes.pop().expect("one scope per shape");
3583 if self.used_labels.contains(&scope.id) {
3584 let label = self.label(&scope.name, span);
3585 code = quote_spanned! {span=> #label: { #code } };
3586 }
3587 code.extend(self.shape(cfg, shape, exits.get(index + 1).unwrap_or(fall), span));
3588 }
3589 out.extend(code);
3590 out
3591 }
3592
3593 /// One shape.
3594 fn shape(
3595 &mut self,
3596 cfg: &Cfg,
3597 shape: &reloop::Shape,
3598 fall: &reloop::Exit,
3599 span: Span,
3600 ) -> TokenStream {
3601 match shape {
3602 reloop::Shape::Simple { block, arms } => {
3603 self.shape_simple(cfg, *block, arms, fall, span)
3604 }
3605 reloop::Shape::Loop {
3606 id,
3607 entries,
3608 state,
3609 body,
3610 ..
3611 } => {
3612 let name = self
3613 .loop_names
3614 .get(id)
3615 .cloned()
3616 .unwrap_or_else(|| format!("r{id}"));
3617 let bspan = entries.first().map_or(span, |entry| {
3618 self.block_span(&cfg.blocks[entry.index()], span)
3619 });
3620 let head = reloop::Exit {
3621 targets: entries.clone(),
3622 state: *state,
3623 };
3624 // Leaving the loop is `break`, going round again `continue`.
3625 self.shape_scopes.push(ShapeScope {
3626 id: u32::MAX,
3627 name: name.clone(),
3628 repeats: false,
3629 exit: fall.clone(),
3630 });
3631 self.shape_scopes.push(ShapeScope {
3632 id: u32::MAX,
3633 name: name.clone(),
3634 repeats: true,
3635 exit: head.clone(),
3636 });
3637 let body = self.shape_seq(cfg, body, &head, bspan);
3638 self.shape_scopes.pop();
3639 self.shape_scopes.pop();
3640 let label = self.label(&name, bspan);
3641 quote_spanned! {bspan=> #label: loop { #body } }
3642 }
3643 reloop::Shape::Dispatch { state, arms } => {
3644 self.shape_dispatch(cfg, *state, arms, fall, span)
3645 }
3646 }
3647 }
3648
3649 /// The head of an irreducible region: which entry this turn runs.
3650 fn shape_dispatch(
3651 &mut self,
3652 cfg: &Cfg,
3653 state: u32,
3654 arms: &[reloop::Arm],
3655 fall: &reloop::Exit,
3656 span: Span,
3657 ) -> TokenStream {
3658 let Some((last, rest)) = arms.split_last() else {
3659 return TokenStream::new();
3660 };
3661 if rest.is_empty() {
3662 return self.shape_seq(cfg, &last.body, fall, span);
3663 }
3664 let name = entry_ident(state);
3665 // Two heads is the common irreducible region, and two heads is an
3666 // `if`: a `match` of `0 =>` and `_ =>` says nothing more.
3667 if rest.len() == 1 {
3668 let first = self.shape_seq(cfg, &rest[0].body, fall, span);
3669 let second = self.shape_seq(cfg, &last.body, fall, span);
3670 let zero = state_literal(0, span);
3671 return quote_spanned! {span=>
3672 if #name == #zero { #first } else { #second }
3673 };
3674 }
3675 let mut cases = TokenStream::new();
3676 for (index, arm) in rest.iter().enumerate() {
3677 let body = self.shape_seq(cfg, &arm.body, fall, span);
3678 let pattern = state_literal(index, span);
3679 cases.extend(quote_spanned! {span=> #pattern => { #body } });
3680 }
3681 let body = self.shape_seq(cfg, &last.body, fall, span);
3682 cases.extend(quote_spanned! {span=> _ => { #body } });
3683 quote_spanned! {span=> match #name { #cases } }
3684 }
3685
3686 /// A block, and the branch its terminator becomes.
3687 fn shape_simple(
3688 &mut self,
3689 cfg: &Cfg,
3690 block: BlockId,
3691 arms: &[reloop::Arm],
3692 fall: &reloop::Exit,
3693 span: Span,
3694 ) -> TokenStream {
3695 let basic = &cfg.blocks[block.index()];
3696 let span = self.block_span(basic, span);
3697 let mut out = self.stmts(&basic.stmts);
3698 match &basic.term {
3699 Terminator::Jump { target, range } => {
3700 let jspan = self.sp(*range);
3701 out.extend(self.enter_shape(cfg, arms, *target, fall, jspan));
3702 }
3703 Terminator::Branch {
3704 cond,
3705 then_blk,
3706 else_blk,
3707 } => out.extend(self.shape_branch(cfg, arms, cond, *then_blk, *else_blk, fall)),
3708 Terminator::Switch {
3709 value,
3710 cases,
3711 default,
3712 range,
3713 } => {
3714 let sspan = self.sp(*range);
3715 out.extend(self.shape_switch(cfg, arms, value, cases, *default, fall, sspan));
3716 }
3717 Terminator::Return { value, range } => {
3718 let rspan = self.sp(*range);
3719 match value {
3720 Some(value) => {
3721 let ret = self.ret_ty;
3722 let tokens = self.expr_at(value, ret);
3723 out.extend(quote_spanned! {rspan=> return #tokens; });
3724 }
3725 None => out.extend(quote_spanned! {rspan=> return; }),
3726 }
3727 }
3728 Terminator::Unreachable => {
3729 out.extend(quote_spanned! {span=> ::core::unreachable!(); });
3730 }
3731 Terminator::InvalidTarget => out.extend(invalid_target(span)),
3732 }
3733 out
3734 }
3735
3736 /// A two-way branch: `if`, with the blocks only it reaches in its arms.
3737 fn shape_branch(
3738 &mut self,
3739 cfg: &Cfg,
3740 arms: &[reloop::Arm],
3741 cond: &Expr,
3742 then_blk: BlockId,
3743 else_blk: BlockId,
3744 fall: &reloop::Exit,
3745 ) -> TokenStream {
3746 let span = self.sp(cond.range);
3747 // Both edges lead to the same block: the condition is still evaluated,
3748 // for what it does rather than for what it says.
3749 if then_blk == else_blk {
3750 let effects = self.expr_stmt(cond);
3751 let jump = self.enter_shape(cfg, arms, then_blk, fall, span);
3752 return quote_spanned! {span=> #effects #jump };
3753 }
3754 let then_tokens = self.enter_shape(cfg, arms, then_blk, fall, span);
3755 let else_tokens = self.enter_shape(cfg, arms, else_blk, fall, span);
3756 if then_tokens.is_empty() && else_tokens.is_empty() {
3757 return self.expr_stmt(cond);
3758 }
3759 if else_tokens.is_empty() {
3760 let test = self.condition(cond).at_condition(span);
3761 return quote_spanned! {span=> if #test { #then_tokens } };
3762 }
3763 if then_tokens.is_empty() {
3764 // No empty arm: the test is inverted rather than left standing
3765 // with nothing in it.
3766 let test = self.condition(cond).at(prec::UNARY, span);
3767 return quote_spanned! {span=> if !#test { #else_tokens } };
3768 }
3769 let test = self.condition(cond).at_condition(span);
3770 quote_spanned! {span=> if #test { #then_tokens } else { #else_tokens } }
3771 }
3772
3773 /// A `switch`: one `match`, with the case bodies in its arms and
3774 /// fallthrough as the code that follows it.
3775 #[allow(clippy::too_many_arguments)]
3776 fn shape_switch(
3777 &mut self,
3778 cfg: &Cfg,
3779 arms: &[reloop::Arm],
3780 value: &Expr,
3781 cases: &[(ir::CaseRange, BlockId)],
3782 default: BlockId,
3783 fall: &reloop::Exit,
3784 span: Span,
3785 ) -> TokenStream {
3786 let groups = group_cases(cases);
3787 let mut lowered: Vec<(Vec<ir::CaseRange>, TokenStream)> = Vec::new();
3788 for (target, values) in groups {
3789 let tokens = self.enter_shape(cfg, arms, target, fall, span);
3790 lowered.push((values, tokens));
3791 }
3792 let fallback = self.enter_shape(cfg, arms, default, fall, span);
3793 // One arm is no dispatch at all: every value goes the same way, and
3794 // all the `match` would do is evaluate the controlling expression.
3795 if lowered.iter().all(|(_, tokens)| tokens.is_empty()) && fallback.is_empty() {
3796 return self.expr_stmt(value);
3797 }
3798 if lowered.is_empty() {
3799 let effects = self.expr_stmt(value);
3800 return quote_spanned! {span=> #effects #fallback };
3801 }
3802 let scrutinee = self.expr(value).at(prec::UNARY, span);
3803 let mut out = TokenStream::new();
3804 for (values, tokens) in lowered {
3805 let mut pattern = TokenStream::new();
3806 for (index, case) in values.iter().enumerate() {
3807 if index > 0 {
3808 pattern.extend(quote_spanned! {span=> | });
3809 }
3810 pattern.extend(case_pattern(*case, value.ty, span));
3811 }
3812 out.extend(quote_spanned! {span=> #pattern => { #tokens } });
3813 }
3814 out.extend(quote_spanned! {span=> _ => { #fallback } });
3815 quote_spanned! {span=> match #scrutinee { #out } }
3816 }
3817
3818 /// What one edge of a terminator becomes: the shapes only it reaches,
3819 /// emitted here, or a jump to where they stand.
3820 fn enter_shape(
3821 &mut self,
3822 cfg: &Cfg,
3823 arms: &[reloop::Arm],
3824 target: BlockId,
3825 fall: &reloop::Exit,
3826 span: Span,
3827 ) -> TokenStream {
3828 match arms.iter().find(|arm| arm.entry == target) {
3829 Some(arm) => self.shape_seq(cfg, &arm.body, fall, span),
3830 None => self.goto_shape(target, fall, span),
3831 }
3832 }
3833
3834 /// The jump that reaches `target` from here.
3835 ///
3836 /// Falling out of the construct being generated is free; anything else is
3837 /// a `break` or a `continue` of the innermost labelled block or loop that
3838 /// arrives there. [`reloop::plan`] has checked that one of the two always
3839 /// applies.
3840 fn goto_shape(&mut self, target: BlockId, fall: &reloop::Exit, span: Span) -> TokenStream {
3841 if let Some(index) = fall.index_of(target) {
3842 return entry_assignment(fall, index, span);
3843 }
3844 for depth in (0..self.shape_scopes.len()).rev() {
3845 let Some(index) = self.shape_scopes[depth].exit.index_of(target) else {
3846 continue;
3847 };
3848 let scope = self.shape_scopes[depth].clone();
3849 self.used_labels.insert(scope.id);
3850 let label = self.label(&scope.name, span);
3851 let set = entry_assignment(&scope.exit, index, span);
3852 return if scope.repeats {
3853 quote_spanned! {span=> #set continue #label; }
3854 } else {
3855 quote_spanned! {span=> #set break #label; }
3856 };
3857 }
3858 unreachable!("the shapes were checked before they were generated")
3859 }
3860
3861 // -- statements ---------------------------------------------------------
3862
3863 fn stmts(&mut self, stmts: &[Stmt]) -> TokenStream {
3864 let mut out = TokenStream::new();
3865 for stmt in stmts {
3866 out.extend(self.stmt(stmt));
3867 }
3868 out
3869 }
3870
3871 /// Emits a statement as a braced block, reusing the braces C already wrote
3872 /// when it wrote a compound statement.
3873 fn block_of(&mut self, stmt: &Stmt, span: Span) -> TokenStream {
3874 match stmt {
3875 Stmt::Block(items) => {
3876 let items = self.stmts(items);
3877 braced(items, span)
3878 }
3879 other => {
3880 let tokens = self.stmt(other);
3881 braced(tokens, span)
3882 }
3883 }
3884 }
3885
3886 fn stmt(&mut self, stmt: &Stmt) -> TokenStream {
3887 match stmt {
3888 Stmt::Nop => TokenStream::new(),
3889 Stmt::Asm(asm) => self.asm_stmt(asm),
3890 Stmt::Expr(expr) => self.expr_stmt(expr),
3891 Stmt::Let { object, init, .. } => {
3892 let id = *object;
3893 let name = self.object_ident(id, self.sp(self.program.object(id).range));
3894 let object = self.program.object(id);
3895 let span = self.sp(object.range);
3896 let object_ty = object.ty;
3897 let ty = self.binding_ty(id, self.ty(object_ty, span), span);
3898 let init = self.expr_at(init, object_ty);
3899 let init = self.binding_init(id, init, span);
3900 quote_spanned! {span=> let mut #name: #ty = #init; }
3901 }
3902 Stmt::Vla(def) => self.vla_def(def),
3903 Stmt::Cleanup(def) => self.cleanup_def(def),
3904 Stmt::Block(items) => {
3905 let span = self.stmts_span(items);
3906 let items = self.stmts(items);
3907 braced(items, span)
3908 }
3909 Stmt::If {
3910 cond,
3911 then_branch,
3912 else_branch,
3913 } => {
3914 let span = self.sp(cond.range);
3915 let cond_tokens = self.condition(cond).at_condition(span);
3916 let then_tokens = self.block_of(then_branch, span);
3917 let else_tokens = match else_branch {
3918 Some(branch) => {
3919 let tokens = self.block_of(branch, span);
3920 quote_spanned! {span=> else #tokens }
3921 }
3922 None => TokenStream::new(),
3923 };
3924 quote_spanned! {span=> if #cond_tokens #then_tokens #else_tokens }
3925 }
3926 Stmt::While {
3927 id,
3928 cond,
3929 body,
3930 range,
3931 } => {
3932 let span = self.sp(*range);
3933 self.continue_styles.insert(*id, ContinueStyle::Head);
3934 let label = self.loop_label(*id, span);
3935 let body_tokens = self.block_of(body, span);
3936 // `while (1)` becomes `loop`, not `while true`: only a `loop`
3937 // tells Rust the statement never finishes, which is what a
3938 // function ending in one relies on.
3939 if ir::is_always_true(cond) {
3940 return quote_spanned! {span=> #label: loop #body_tokens };
3941 }
3942 let cond_tokens = self.condition(cond).at_condition(span);
3943 quote_spanned! {span=> #label: while #cond_tokens #body_tokens }
3944 }
3945 Stmt::DoWhile {
3946 id,
3947 body,
3948 cond,
3949 range,
3950 } => {
3951 let span = self.sp(*range);
3952 self.continue_styles.insert(*id, ContinueStyle::BodyLabel);
3953 let label = self.loop_label(*id, span);
3954 let body_label = self.loop_body_label(*id, span);
3955 let body_tokens = self.block_of(body, span);
3956 let test = if ir::is_always_true(cond) {
3957 TokenStream::new()
3958 } else {
3959 let cond_tokens = self.condition(cond).at(prec::LOWEST, span);
3960 quote_spanned! {span=> if !(#cond_tokens) { break #label; } }
3961 };
3962 quote_spanned! {span=>
3963 #label: loop {
3964 #body_label: #body_tokens
3965 #test
3966 }
3967 }
3968 }
3969 Stmt::For {
3970 id,
3971 init,
3972 cond,
3973 step,
3974 body,
3975 range,
3976 } => {
3977 let span = self.sp(*range);
3978 self.continue_styles.insert(*id, ContinueStyle::BodyLabel);
3979 let label = self.loop_label(*id, span);
3980 let body_label = self.loop_body_label(*id, span);
3981 let init_tokens = self.stmts(init);
3982 let test = match cond {
3983 Some(cond) if !ir::is_always_true(cond) => {
3984 let tokens = self.condition(cond).at(prec::LOWEST, span);
3985 quote_spanned! {span=> if !(#tokens) { break #label; } }
3986 }
3987 _ => TokenStream::new(),
3988 };
3989 let body_tokens = self.block_of(body, span);
3990 let step_tokens = match step {
3991 Some(step) => self.expr_stmt(step),
3992 None => TokenStream::new(),
3993 };
3994 // The whole loop is wrapped so that a C99 declaration in the
3995 // init clause stays scoped to the loop, as C says it is.
3996 quote_spanned! {span=>
3997 {
3998 #init_tokens
3999 #label: loop {
4000 #test
4001 #body_label: #body_tokens
4002 #step_tokens
4003 }
4004 }
4005 }
4006 }
4007 Stmt::Switch(switch) => self.switch(switch),
4008 Stmt::Region(region) => self.region(region),
4009 // The CFG lowering consumes these, and a label the structured mode
4010 // kept is where a region ends rather than anything of its own: only
4011 // the statement under it is left.
4012 Stmt::Label { body, .. } | Stmt::Case { body, .. } => self.stmt(body),
4013 // A `goto` left in a structured body leaves the region its label
4014 // stands for; see [`crate::regions`]. Anything else is consumed by
4015 // the CFG lowering, which is the only mode it is generated in.
4016 Stmt::Goto { id, range } => {
4017 let span = self.sp(*range);
4018 match self.region_kinds.get(id).copied() {
4019 Some(kind) => {
4020 let label = self.region_label(*id, span);
4021 match kind {
4022 ir::RegionKind::Block => quote_spanned! {span=> break #label; },
4023 ir::RegionKind::Loop => quote_spanned! {span=> continue #label; },
4024 }
4025 }
4026 None => TokenStream::new(),
4027 }
4028 }
4029 Stmt::GotoPtr { .. } => TokenStream::new(),
4030 Stmt::SwitchTree(switch) => self.stmt(&switch.body),
4031 Stmt::Break { target, range } => {
4032 let span = self.sp(*range);
4033 let label = match target {
4034 BreakTarget::Loop(id) => self.loop_label(*id, span),
4035 BreakTarget::Switch(id) => self.switch_label(*id, span),
4036 };
4037 quote_spanned! {span=> break #label; }
4038 }
4039 Stmt::Continue { id, range } => {
4040 let span = self.sp(*range);
4041 match self.continue_styles.get(id) {
4042 Some(ContinueStyle::BodyLabel) => {
4043 let label = self.loop_body_label(*id, span);
4044 quote_spanned! {span=> break #label; }
4045 }
4046 _ => {
4047 let label = self.loop_label(*id, span);
4048 quote_spanned! {span=> continue #label; }
4049 }
4050 }
4051 }
4052 Stmt::Return { value, range } => {
4053 let span = self.sp(*range);
4054 match value {
4055 Some(value) => {
4056 let ret = self.ret_ty;
4057 let tokens = self.expr_at(value, ret);
4058 quote_spanned! {span=> return #tokens; }
4059 }
4060 None => quote_spanned! {span=> return; },
4061 }
4062 }
4063 }
4064 }
4065
4066 /// A variable length array's definition, `T a[n];`.
4067 ///
4068 /// Two bindings after the bounds' own: the frame of the function's bump
4069 /// arena, whose `Drop` at the end of the block — on every way out of it —
4070 /// gives the space back and is the object's lifetime; and the object
4071 /// itself, a pointer to the first of the zeroed elements the arena bumps
4072 /// off. The frame stands first, so Rust drops it after anything declared
4073 /// with the array. See [`Codegen::arena_items`].
4074 ///
4075 /// In [CFG mode](crate::cfg) there are no blocks to drop a frame at, and
4076 /// the pointer is already bound at the top of the function — Rust has no
4077 /// way to jump over a `let` — so what is written here is the arena's
4078 /// `redefine` of this array's slot in the function's array of marks, which
4079 /// gives back a previous pass's space before taking the new mark, and an
4080 /// assignment.
4081 fn vla_def(&mut self, def: &ir::VlaDef) -> TokenStream {
4082 let span = self.sp(def.range);
4083 let object = self.program.object(def.object);
4084 // Whatever is left under the variable dimensions: one allocation
4085 // holds the whole object, however many of them there are.
4086 let elem = self.program.types.vm_step_ty(object.ty);
4087 let name = self.object_ident(def.object, span);
4088 let count = self.expr(&def.count).at(prec::CAST, span);
4089 let elem_ty = self.ty(elem, span);
4090 let usize_ty = primitive_ty("usize", span);
4091 let arena = self.arena_ident(span);
4092 // A requested alignment stricter than the element's pads the arena's
4093 // position up to a multiple of it before the array starts.
4094 let first = match def.align {
4095 Some(align) => {
4096 let align = Literal::usize_unsuffixed(align as usize);
4097 quote_spanned! {span=>
4098 #arena.alloc_aligned::<#elem_ty>(#count as #usize_ty, #align)
4099 }
4100 }
4101 None => quote_spanned! {span=> #arena.alloc::<#elem_ty>(#count as #usize_ty) },
4102 };
4103 if self.in_cfg {
4104 let marks = vla_marks_ident();
4105 let slot = Literal::usize_unsuffixed(self.vla_slots[&def.storage]);
4106 return quote_spanned! {span=>
4107 #arena.redefine(&mut #marks, #slot);
4108 #name = #first;
4109 };
4110 }
4111 let frame = self.object_ident(def.storage, span);
4112 quote_spanned! {span=>
4113 let #frame = #arena.frame();
4114 let mut #name: *mut #elem_ty = #first;
4115 }
4116 }
4117
4118 /// A `cleanup` attribute's drop guard, in the structured lowering.
4119 ///
4120 /// The binding stands right after the object's own, so Rust drops it
4121 /// first — and drops it on every way out of the block, which is exactly
4122 /// what GCC promises. See [`ir::CleanupDef`].
4123 fn cleanup_def(&mut self, def: &ir::CleanupDef) -> TokenStream {
4124 let span = self.sp(def.range);
4125 let guard = cleanup_guard_ty();
4126 // One binding per object, in this crate's own hygiene: the C program
4127 // cannot name it, and two guards in one block cannot collide.
4128 let name = Ident::new(
4129 &format!("__cinrs_cleanup{}", def.object.0),
4130 Span::mixed_site(),
4131 );
4132 let object = self.program.object(def.object);
4133 let place = ir::Place {
4134 kind: PlaceKind::Object(def.object),
4135 ty: object.ty,
4136 is_const: object.is_const,
4137 range: def.range,
4138 };
4139 let address = self
4140 .address_of(&place, def.param, span)
4141 .at(prec::LOWEST, span);
4142 let function = self.func_pointer(def.func, span);
4143 self.uses_cleanup.set(true);
4144 quote_spanned! {span=>
4145 let #name = #guard(#address, #function);
4146 }
4147 }
4148
4149 /// `struct __cinrs_cleanup<P, R>(P, unsafe extern "C" fn(P) -> R);` and
4150 /// its `Drop`.
4151 ///
4152 /// One item per unit — each unit is a module of its own, so two of them in
4153 /// one Rust module do not collide — generated only when something asks for
4154 /// it. It is generic over the *pointer* the function takes rather than
4155 /// over the object's type, so that a `void *`-taking cleanup (the
4156 /// `_cleanup_free_` idiom) needs nothing special, and over the return
4157 /// type, which GCC ignores.
4158 fn cleanup_guard_item(&self, span: Span) -> TokenStream {
4159 let name = cleanup_guard_ty();
4160 let p = Ident::new("P", Span::mixed_site());
4161 let r = Ident::new("R", Span::mixed_site());
4162 quote_spanned! {span=>
4163 struct #name<#p: ::core::marker::Copy, #r>(#p, unsafe extern "C" fn(#p) -> #r);
4164 impl<#p: ::core::marker::Copy, #r> ::core::ops::Drop for #name<#p, #r> {
4165 fn drop(&mut self) {
4166 unsafe {
4167 (self.1)(self.0);
4168 }
4169 }
4170 }
4171 }
4172 }
4173
4174 /// `Some(f as unsafe extern "C" fn(…) -> R)`: a function name used as a
4175 /// value.
4176 ///
4177 /// A method of its own rather than an arm of [`Codegen::expr`]'s match
4178 /// because that function is the recursion this module is bounded by, and in
4179 /// an unoptimised build every temporary of every arm has a stack slot of
4180 /// its own; see `expand.rs`'s `codegen_of_deeply_nested_input_fits_in_a_
4181 /// small_stack`.
4182 fn func_addr(&self, id: ir::FuncId, span: Span) -> Value {
4183 let function = self.program.function(id);
4184 let name = if function.intrinsic.is_some() {
4185 self.intrinsic_shim_name(id, span)
4186 } else {
4187 self.function_path(function, span)
4188 };
4189 let signature = self.function_pointer_ty(function, span);
4190 Value::new(
4191 quote_spanned! {span=> ::core::option::Option::Some(#name as #signature) },
4192 prec::CALL,
4193 )
4194 }
4195
4196 /// The name of the shim that stands for an x86 intrinsic whose address was
4197 /// taken, remembering that the unit needs it.
4198 ///
4199 /// `Span::mixed_site()` is the same hygiene the cleanup guard type uses: it
4200 /// puts the name out of reach of anything the C declares, so no
4201 /// `__cinrs_intrinsic_…` a program writes for itself can collide with it.
4202 fn intrinsic_shim_name(&self, id: ir::FuncId, span: Span) -> TokenStream {
4203 let function = self.program.function(id);
4204 {
4205 let mut wanted = self.address_taken.borrow_mut();
4206 if !wanted.contains(&id) {
4207 wanted.push(id);
4208 }
4209 }
4210 let name = Ident::new(
4211 &format!("__cinrs_intrinsic_{}", function.name),
4212 Span::mixed_site(),
4213 );
4214 quote_spanned! {span=> #name }
4215 }
4216
4217 /// One `unsafe extern "C" fn` per intrinsic whose address the unit took,
4218 /// forwarding to `core::arch`.
4219 ///
4220 /// The shim carries the intrinsic's own `#[target_feature]`, which is what
4221 /// GCC's `__always_inline__` header function carries too: without it a
4222 /// 256-bit vector could not be passed by value through the C ABI at all,
4223 /// and rustc refuses the definition. It is private to the unit's module —
4224 /// `pub` would put a name into the glob re-export that no C declared — and
4225 /// `#[inline]` so that the indirect call through it costs nothing when the
4226 /// optimiser can see the target. `#[inline(always)]` is deliberately *not*
4227 /// used: rustc refuses it together with `#[target_feature]`.
4228 fn intrinsic_shim_items(&self) -> TokenStream {
4229 let mut out = TokenStream::new();
4230 for id in self.address_taken.borrow().iter() {
4231 let function = self.program.function(*id);
4232 let Some(intr) = function.intrinsic else {
4233 continue;
4234 };
4235 let span = self.sp(function.range);
4236 let name = Ident::new(
4237 &format!("__cinrs_intrinsic_{}", function.name),
4238 Span::mixed_site(),
4239 );
4240 let mut params = TokenStream::new();
4241 let mut args = TokenStream::new();
4242 for (index, ty) in function.sig.params.iter().enumerate() {
4243 if index > 0 {
4244 params.extend(quote_spanned! {span=> , });
4245 args.extend(quote_spanned! {span=> , });
4246 }
4247 let pname = Ident::new(&format!("__cinrs_arg{index}"), Span::mixed_site());
4248 let pty = self.ty(*ty, span);
4249 params.extend(quote_spanned! {span=> #pname: #pty });
4250 // The same cast a direct call's pointer argument gets.
4251 let cast = self.intrinsic_pointer_arg(*ty, span).unwrap_or_default();
4252 args.extend(quote_spanned! {span=> #pname #cast });
4253 }
4254 let ret = if function.sig.ret.is_void() {
4255 TokenStream::new()
4256 } else {
4257 let ty = self.ty(function.sig.ret, span);
4258 quote_spanned! {span=> -> #ty }
4259 };
4260 let feature = if intr.feature.is_empty() {
4261 TokenStream::new()
4262 } else {
4263 let mut literal = Literal::string(intr.feature);
4264 literal.set_span(span);
4265 quote_spanned! {span=> #[target_feature(enable = #literal)] }
4266 };
4267 let module = self.arch_module(span);
4268 let call = Ident::new(intr.name, span);
4269 out.extend(quote_spanned! {span=>
4270 #[inline]
4271 #feature
4272 unsafe extern "C" fn #name(#params) #ret {
4273 unsafe { ::core::arch::#module::#call(#args) }
4274 }
4275 });
4276 }
4277 out
4278 }
4279
4280 /// `f as unsafe extern "C" fn(…) -> R`, the function a drop guard holds.
4281 fn func_pointer(&self, id: ir::FuncId, span: Span) -> TokenStream {
4282 let function = self.program.function(id);
4283 let name = self.function_path(function, span);
4284 let signature = self.function_pointer_ty(function, span);
4285 quote_spanned! {span=> #name as #signature }
4286 }
4287
4288 /// A span standing for a run of statements.
4289 fn stmts_span(&self, stmts: &[Stmt]) -> Span {
4290 stmts
4291 .iter()
4292 .find_map(|s| self.stmt_range(s))
4293 .map_or_else(Span::call_site, |range| self.sp(range))
4294 }
4295
4296 /// An inline assembly statement: `::core::arch::asm!`, with the operands
4297 /// sema mapped (see `sema/asm.rs`).
4298 ///
4299 /// ```text
4300 /// {
4301 /// let p = …; // each output place's setup, once
4302 /// ::core::arch::asm!("addl {o1:e}, {o0:e}",
4303 /// o0 = inout(reg) (*p).f, // the place itself
4304 /// o1 = in(reg) b,
4305 /// out("rcx") _,
4306 /// options(att_syntax));
4307 /// }
4308 /// ```
4309 ///
4310 /// An output is written straight into its place whenever that place is an
4311 /// ordinary Rust place expression: a [lowered place](LoweredPlace)'s
4312 /// access may be evaluated more than once and its setup — where the side
4313 /// effects of `a[i++]` or `f()->x` happen — runs exactly once, before the
4314 /// statement. Only a place that may be underaligned goes through a typed
4315 /// temporary, read with `read_unaligned` (for `+`) and stored back with
4316 /// `write_unaligned` after the statement: `asm!` would otherwise write it
4317 /// with an aligned store. Bit-fields and `_Atomic` objects never get here;
4318 /// sema refuses both.
4319 ///
4320 /// Inputs are emitted with [`Codegen::expr`], never bare: an `asm!`
4321 /// operand has no expected type, so an unsuffixed literal would be an
4322 /// `i32` whatever the C operand was, and the register would be read at the
4323 /// wrong width.
4324 fn asm_stmt(&mut self, asm: &ir::AsmStmt) -> TokenStream {
4325 let span = self.sp(asm.range);
4326 let mut setup = TokenStream::new();
4327 let mut store_back = TokenStream::new();
4328 let mut operands = TokenStream::new();
4329 for (index, operand) in asm.operands.iter().enumerate() {
4330 let op_span = self.sp(operand.range);
4331 let head = asm_operand_head(operand, op_span);
4332 let value = match &operand.kind {
4333 ir::AsmOperandKind::In(expr) => self.expr(expr).at(prec::LOWEST, op_span),
4334 ir::AsmOperandKind::Scratch(expr) => {
4335 let value = self.expr(expr).at(prec::LOWEST, op_span);
4336 quote_spanned! {op_span=> #value => _ }
4337 }
4338 ir::AsmOperandKind::Const(value) => asm_const_literal(*value, op_span),
4339 ir::AsmOperandKind::Out { place, .. } => {
4340 self.asm_output(place, None, index, &mut setup, &mut store_back)
4341 }
4342 ir::AsmOperandKind::InOut { input, output } => {
4343 let input = input
4344 .as_ref()
4345 .map(|expr| self.expr(expr).at(prec::LOWEST, op_span));
4346 let read_place = input.is_none();
4347 let target = self.asm_output(
4348 output,
4349 Some(read_place),
4350 index,
4351 &mut setup,
4352 &mut store_back,
4353 );
4354 match input {
4355 Some(input) => quote_spanned! {op_span=> #input => #target },
4356 None => target,
4357 }
4358 }
4359 };
4360 operands.extend(quote_spanned! {op_span=> #head #value, });
4361 }
4362 for clobber in &asm.clobbers {
4363 let name = Literal::string(clobber);
4364 operands.extend(quote_spanned! {span=> out(#name) _, });
4365 }
4366 let mut template = Literal::string(&asm.template);
4367 template.set_span(span);
4368 let call = quote_spanned! {span=>
4369 ::core::arch::asm!(#template, #operands options(att_syntax));
4370 };
4371 if setup.is_empty() && store_back.is_empty() {
4372 return call;
4373 }
4374 quote_spanned! {span=> { #setup #call #store_back } }
4375 }
4376
4377 /// Where an `asm` output goes: the place itself, or — for a place that
4378 /// may be underaligned — a temporary that is stored back afterwards.
4379 ///
4380 /// `read` is `None` for a pure output, and for an in/out operand says
4381 /// whether its input is the place's own value (GCC's `+`).
4382 fn asm_output(
4383 &mut self,
4384 place: &Place,
4385 read: Option<bool>,
4386 index: usize,
4387 setup: &mut TokenStream,
4388 store_back: &mut TokenStream,
4389 ) -> TokenStream {
4390 let span = self.sp(place.range);
4391 let lowered = self.place(place, true);
4392 setup.extend(lowered.setup.clone());
4393 if !lowered.unaligned {
4394 let access = &lowered.access;
4395 return quote_spanned! {span=> #access };
4396 }
4397 let temp = Ident::new(&format!("__cinrs_asm{index}"), span);
4398 let ty = self.ty(place.ty, span);
4399 let access = &lowered.access;
4400 // A pure output is initialised by the statement itself, exactly once.
4401 setup.extend(if read == Some(true) {
4402 quote_spanned! {span=> let mut #temp: #ty = (&raw const #access).read_unaligned(); }
4403 } else {
4404 quote_spanned! {span=> let #temp: #ty; }
4405 });
4406 store_back.extend(self.write(&lowered, quote_spanned! {span=> #temp }, span));
4407 quote_spanned! {span=> #temp }
4408 }
4409
4410 fn stmt_range(&self, stmt: &Stmt) -> Option<SourceRange> {
4411 Some(match stmt {
4412 Stmt::Expr(expr) => expr.range,
4413 Stmt::Let { object, .. } => self.program.object(*object).range,
4414 Stmt::Vla(def) => def.range,
4415 Stmt::Cleanup(def) => def.range,
4416 Stmt::If { cond, .. } => cond.range,
4417 Stmt::While { range, .. }
4418 | Stmt::DoWhile { range, .. }
4419 | Stmt::For { range, .. }
4420 | Stmt::Break { range, .. }
4421 | Stmt::Continue { range, .. }
4422 | Stmt::Return { range, .. }
4423 | Stmt::Label { range, .. }
4424 | Stmt::Case { range, .. }
4425 | Stmt::Goto { range, .. }
4426 | Stmt::GotoPtr { range, .. } => *range,
4427 Stmt::Switch(switch) => switch.range,
4428 Stmt::SwitchTree(switch) => switch.range,
4429 Stmt::Region(region) => region.range,
4430 Stmt::Asm(asm) => asm.range,
4431 Stmt::Block(items) => return items.iter().find_map(|s| self.stmt_range(s)),
4432 Stmt::Nop => return None,
4433 })
4434 }
4435
4436 fn loop_label(&self, id: LoopId, span: Span) -> TokenStream {
4437 self.label(&format!("l{}", id.0), span)
4438 }
4439
4440 fn loop_body_label(&self, id: LoopId, span: Span) -> TokenStream {
4441 self.label(&format!("l{}_body", id.0), span)
4442 }
4443
4444 fn switch_label(&self, id: ir::SwitchId, span: Span) -> TokenStream {
4445 self.label(&format!("sw{}", id.0), span)
4446 }
4447
4448 fn switch_case_label(&self, id: ir::SwitchId, index: usize, span: Span) -> TokenStream {
4449 self.label(&format!("sw{}_c{index}", id.0), span)
4450 }
4451
4452 /// The Rust label a [region](ir::Region) carries.
4453 fn region_label(&self, id: ir::LabelId, span: Span) -> TokenStream {
4454 match self.region_names.get(&id) {
4455 Some(name) => self.label(name, span),
4456 // Only a `goto` outside every region for its label, which
4457 // [`crate::regions`] does not leave behind.
4458 None => self.label(&format!("cinrs_label{}", id.0), span),
4459 }
4460 }
4461
4462 /// A labelled block or a labelled loop, and the statements inside it.
4463 ///
4464 /// The two shapes are what an outward `goto` becomes — see
4465 /// [`crate::regions`]. A loop ends with a `break` of its own so that
4466 /// falling off the end of the region leaves it; one whose body cannot
4467 /// reach its end has none, which is what lets a function ending in it need
4468 /// no `return`.
4469 fn region(&mut self, region: &ir::Region) -> TokenStream {
4470 let span = self.sp(region.range);
4471 let label = self.region_label(region.label, span);
4472 let previous = self.region_kinds.insert(region.label, region.kind);
4473 let body = self.stmts(®ion.body);
4474 match previous {
4475 Some(kind) => self.region_kinds.insert(region.label, kind),
4476 None => self.region_kinds.remove(®ion.label),
4477 };
4478 match region.kind {
4479 ir::RegionKind::Block => quote_spanned! {span=> #label: { #body } },
4480 ir::RegionKind::Loop if region.falls_out => quote_spanned! {span=>
4481 #label: loop { #body break #label; }
4482 },
4483 ir::RegionKind::Loop => quote_spanned! {span=> #label: loop { #body } },
4484 }
4485 }
4486
4487 /// Names the regions of a structured body, after the C labels they stand
4488 /// for.
4489 ///
4490 /// A name that Rust cannot spell as a label — a keyword, or one of the
4491 /// shapes this module gives a loop or a `switch` — gets the label's number
4492 /// appended, which no generated label can collide with; one it cannot
4493 /// spell at all, such as an extended identifier, gives up its own name.
4494 /// The block and the loop a label with jumps of both kinds gets are named
4495 /// once: they never overlap, and `break` and `continue` say which is meant.
4496 fn name_regions(&mut self, stmts: &[Stmt]) {
4497 let mut taken: HashSet<String> = HashSet::new();
4498 let mut found = Vec::new();
4499 collect_regions(stmts, &mut found);
4500 for (id, name) in found {
4501 if self.region_names.contains_key(&id) {
4502 continue;
4503 }
4504 let mut candidate = rust_spelling(&name).into_owned();
4505 if !is_label_name(&candidate) {
4506 candidate = format!("{candidate}_{}", id.0);
4507 }
4508 if !is_label_name(&candidate) {
4509 candidate = format!("cinrs_label{}", id.0);
4510 }
4511 while taken.contains(&candidate) {
4512 candidate.push('_');
4513 }
4514 taken.insert(candidate.clone());
4515 self.region_names.insert(id, candidate);
4516 }
4517 }
4518
4519 /// Builds the labelled-block chain described in the [module docs](self).
4520 fn switch(&mut self, switch: &Switch) -> TokenStream {
4521 let span = self.sp(switch.range);
4522 let scrutinee_ty = switch.scrutinee.ty;
4523 let scrutinee = self.expr(&switch.scrutinee).at(prec::UNARY, span);
4524
4525 let mut arms = TokenStream::new();
4526 for (index, group) in switch.groups.iter().enumerate() {
4527 if group.values.is_empty() {
4528 continue;
4529 }
4530 let label = self.switch_case_label(switch.id, index, span);
4531 let mut pattern = TokenStream::new();
4532 for (i, value) in group.values.iter().enumerate() {
4533 if i > 0 {
4534 pattern.extend(quote_spanned! {span=> | });
4535 }
4536 // A pattern takes its type from the scrutinee, so the bare
4537 // literal is both correct and the most readable form.
4538 pattern.extend(case_pattern(*value, scrutinee_ty, span));
4539 }
4540 arms.extend(quote_spanned! {span=> #pattern => break #label, });
4541 }
4542 let fallback = match switch.default_group {
4543 Some(index) => self.switch_case_label(switch.id, index, span),
4544 None => self.switch_label(switch.id, span),
4545 };
4546 arms.extend(quote_spanned! {span=> _ => break #fallback, });
4547
4548 // Anything before the first label can never be reached, but it is still
4549 // part of the program and may declare things later groups use.
4550 let prelude = self.stmts(&switch.prelude);
4551 let mut inner = quote_spanned! {span=> match #scrutinee { #arms } #prelude };
4552 for (index, group) in switch.groups.iter().enumerate() {
4553 let label = self.switch_case_label(switch.id, index, span);
4554 let body = self.stmts(&group.body);
4555 inner = quote_spanned! {span=> #label: { #inner } #body };
4556 }
4557
4558 let mut hoisted = TokenStream::new();
4559 for id in &switch.hoisted {
4560 let object = self.program.object(*id);
4561 let ospan = self.sp(object.range);
4562 let name = self.object_ident(*id, ospan);
4563 let ty = self.binding_ty(*id, self.ty(object.ty, ospan), ospan);
4564 let zero = self.zero_tokens(object.ty, ospan);
4565 let zero = self.binding_init(*id, zero, ospan);
4566 hoisted.extend(quote_spanned! {ospan=> let mut #name: #ty = #zero; });
4567 }
4568
4569 let label = self.switch_label(switch.id, span);
4570 // The extra block keeps the hoisted declarations from shadowing
4571 // anything the enclosing block declared under the same name.
4572 quote_spanned! {span=>
4573 {
4574 #hoisted
4575 #label: { #inner }
4576 }
4577 }
4578 }
4579
4580 /// Emits an expression evaluated for its side effects.
4581 fn expr_stmt(&mut self, expr: &Expr) -> TokenStream {
4582 let span = self.sp(expr.range);
4583 match &expr.kind {
4584 ExprKind::Assign { place, value } => {
4585 let lowered = self.place(place, true);
4586 let value = self.expr_at(value, self.program.types.unatomic(place.ty));
4587 let store = self.write(&lowered, value, span);
4588 let setup = &lowered.setup;
4589 quote_spanned! {span=> #setup #store }
4590 }
4591 ExprKind::CompoundAssign {
4592 place,
4593 op,
4594 value,
4595 compute,
4596 } => {
4597 let lowered = self.place(place, true);
4598 if lowered.atomic.is_some() {
4599 let kind = PlaceRmw::Compound {
4600 op: *op,
4601 value,
4602 compute: *compute,
4603 };
4604 return self.atomic_place_rmw(&lowered, kind, RmwValue::None, span);
4605 }
4606 let (hoist, rhs) = self.compound_rhs(value);
4607 let current = self.read(&lowered, span);
4608 let updated = self.compound_value(current, place.ty, *op, value, rhs, *compute);
4609 let updated = updated.at(prec::LOWEST, span);
4610 let store = self.write(&lowered, updated, span);
4611 let setup = &lowered.setup;
4612 quote_spanned! {span=> #setup #hoist #store }
4613 }
4614 ExprKind::IncDec { place, dec, .. } => {
4615 let lowered = self.place(place, true);
4616 if lowered.atomic.is_some() {
4617 let kind = PlaceRmw::Step { dec: *dec };
4618 return self.atomic_place_rmw(&lowered, kind, RmwValue::None, span);
4619 }
4620 let current = self.read(&lowered, span);
4621 let next = self.step_value(current, place.ty, *dec, span);
4622 let store = self.write(&lowered, next, span);
4623 let setup = &lowered.setup;
4624 quote_spanned! {span=> #setup #store }
4625 }
4626 ExprKind::Call { .. } => {
4627 // A call to a `_Noreturn` function does not come back, and
4628 // Rust has to be told: the call's own type is whatever the
4629 // function was declared to return, so a function that ends in
4630 // `exit(1);` would otherwise be missing its value. The
4631 // `unreachable!()` is a panic rather than
4632 // `unreachable_unchecked`, because it is *this crate* putting
4633 // it there.
4634 let diverges = ir::expr_never_returns(expr, &self.program.functions);
4635 let tokens = self.expr(expr).at(prec::LOWEST, span);
4636 if diverges {
4637 quote_spanned! {span=> #tokens; ::core::unreachable!(); }
4638 } else {
4639 quote_spanned! {span=> #tokens; }
4640 }
4641 }
4642 ExprKind::Unreachable => {
4643 quote_spanned! {span=> ::core::hint::unreachable_unchecked(); }
4644 }
4645 // A store, a `clear` and a fence have no value at all, in C or in
4646 // the Rust they become; the `let _ =` the fallback below would
4647 // wrap them in says nothing.
4648 ExprKind::Atomic(_) if expr.ty.is_void() => {
4649 let tokens = self.expr(expr).at(prec::LOWEST, span);
4650 quote_spanned! {span=> #tokens; }
4651 }
4652 ExprKind::Comma { .. } => {
4653 // A chain of comma operators is a flat sequence of statements
4654 // — and one stack frame per operand if it is walked
4655 // recursively, which a four-thousand-character logical source
4656 // line cannot afford. See [`Codegen::binary_chain`].
4657 let mut out = TokenStream::new();
4658 for operand in comma_operands(expr) {
4659 out.extend(self.expr_stmt(operand));
4660 }
4661 out
4662 }
4663 ExprKind::Cond { .. } => {
4664 // A chain of them is `if … else if … else …`, built without
4665 // recursing down the chain; see [`Codegen::cond_chain`].
4666 let mut spine = Vec::new();
4667 let mut node = expr;
4668 while let ExprKind::Cond {
4669 cond,
4670 then_expr,
4671 else_expr,
4672 } = &node.kind
4673 {
4674 let span = self.sp(node.range);
4675 let cond_tokens = self.condition(cond).at_condition(span);
4676 let then_tokens = self.expr_stmt(then_expr);
4677 spine.push((cond_tokens, then_tokens, span));
4678 node = else_expr;
4679 }
4680 let mut tokens = self.expr_stmt(node);
4681 while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
4682 tokens = quote_spanned! {span=>
4683 if #cond_tokens { #then_tokens } else { #tokens }
4684 };
4685 }
4686 tokens
4687 }
4688 // `(void)x;` evaluates and discards, which is what the fall-through
4689 // below does anyway; unwrapping keeps the output tidy.
4690 ExprKind::Cast(inner) if expr.ty.is_void() => self.expr_stmt(inner),
4691 // `va_end(ap);` is a statement that does nothing at all.
4692 ExprKind::VaEnd => TokenStream::new(),
4693 _ => {
4694 let tokens = self.expr(expr).at(prec::LOWEST, span);
4695 quote_spanned! {span=> let _ = #tokens; }
4696 }
4697 }
4698 }
4699
4700 // -- expressions --------------------------------------------------------
4701
4702 /// Emits an expression whose type the surrounding context already fixes.
4703 ///
4704 /// A constant then needs no `as`, which is the difference between
4705 /// `let mut i: c_int = 0;` and `let mut i: c_int = 0 as c_int;`. It is the
4706 /// *only* place a bare literal is emitted from, and the reason it is safe
4707 /// is that every caller writes the tokens somewhere the type is already
4708 /// stated — the annotation of a `let`, a place being assigned to, a
4709 /// parameter, a field, the return type of the function.
4710 ///
4711 /// [`Codegen::expr`] has no such promise, so nothing it produces may
4712 /// depend on inference; that is what the conditional below is about.
4713 fn expr_at(&mut self, expr: &Expr, expected: Ty) -> TokenStream {
4714 let span = self.sp(expr.range);
4715 if expr.ty == expected {
4716 match &expr.kind {
4717 ExprKind::Int(value) => return bare_int_literal(*value, expected, span),
4718 ExprKind::Float(value) if value.is_finite() => {
4719 return bare_float_literal(*value, span);
4720 }
4721 // The arms of a conditional may stay bare here, because
4722 // whatever fixes this expression's type fixes theirs — unless
4723 // the type is `void`, where the arms have no common type and
4724 // [`Codegen::expr`] emits each of them as a statement.
4725 ExprKind::Cond { .. } if !expected.is_void() => {
4726 return self.cond_chain_at(expr, expected);
4727 }
4728 _ => {}
4729 }
4730 }
4731 self.expr(expr).at(prec::LOWEST, span)
4732 }
4733
4734 fn expr(&mut self, expr: &Expr) -> Value {
4735 let value = self.expr_value(expr);
4736 // A chain of binary operators reduces each of its own nodes; see
4737 // `Codegen::binary_chain`.
4738 if matches!(expr.kind, ExprKind::Binary { .. }) {
4739 return value;
4740 }
4741 self.reduce_bits(value, expr)
4742 }
4743
4744 /// Reduces a computed value to the precision the expression is evaluated
4745 /// in, which is narrower than its type only for a wide bit-field; see
4746 /// [`ir::Expr::bits`].
4747 ///
4748 /// Only an operator whose result can leave the field's range needs it: a
4749 /// bitwise `&`, `|` or `^` of two forty-bit values is a forty-bit value
4750 /// already, and so is a quotient, a remainder or a right shift.
4751 fn reduce_bits(&mut self, value: Value, expr: &Expr) -> Value {
4752 let Some(bits) = expr.bits else {
4753 return value;
4754 };
4755 let width = expr.ty.bits(&self.options.target);
4756 let overflows = match &expr.kind {
4757 ExprKind::Binary { op, .. } => {
4758 matches!(op, BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Shl)
4759 }
4760 ExprKind::Neg(_) | ExprKind::BitNot(_) => true,
4761 _ => false,
4762 };
4763 if !overflows || !expr.ty.is_integer() || bits == 0 || bits >= width {
4764 return value;
4765 }
4766 let span = self.sp(expr.range);
4767 if expr.ty.is_signed(&self.options.target) {
4768 // Sign extension: the two shifts are what a narrower signed type
4769 // does to a value that has just overflowed out of it.
4770 let shift = Literal::u32_unsuffixed(width - bits);
4771 let tokens = value.at(prec::CALL, span);
4772 return Value::new(
4773 quote_spanned! {span=> #tokens.wrapping_shl(#shift).wrapping_shr(#shift) },
4774 prec::CALL,
4775 );
4776 }
4777 let mask = bare_int_literal(((1u128 << bits) - 1) as i128, expr.ty, span);
4778 let tokens = value.at(prec::BIT_AND, span);
4779 Value::new(quote_spanned! {span=> #tokens & #mask }, prec::BIT_AND)
4780 }
4781
4782 fn expr_value(&mut self, expr: &Expr) -> Value {
4783 let span = self.sp(expr.range);
4784 match &expr.kind {
4785 ExprKind::Int(value) => self.int_literal(*value, expr.ty, span),
4786 ExprKind::Float(value) => self.float_literal(*value, expr.ty, span),
4787 ExprKind::Zeroed => Value::new(self.zero_tokens(expr.ty, span), zero_prec(expr.ty)),
4788 // Reading a `va_list` copies it: Rust's is not `Copy`, and C says
4789 // a list passed on is indeterminate afterwards anyway.
4790 ExprKind::Load(place) if place.ty.is_va_list() => self.va_list_load(place, span),
4791 ExprKind::Load(place) => {
4792 let lowered = self.place(place, false);
4793 let value = self.read(&lowered, span);
4794 if lowered.setup.is_empty() {
4795 value
4796 } else {
4797 let setup = &lowered.setup;
4798 let tokens = value.at(prec::LOWEST, span);
4799 Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
4800 }
4801 }
4802 ExprKind::AddrOf(place) => self.address_of(place, expr.ty, span),
4803 ExprKind::FuncAddr(id) => self.func_addr(*id, span),
4804 // GNU's `&&label`. The value is the label's number, cast to the
4805 // pointer type the expression has — which is what `goto *`'s
4806 // dispatch matches on, and what lets a dispatch table be an
4807 // ordinary array of `void *`.
4808 ExprKind::LabelAddr(id) => self.label_address(*id, expr.ty, span),
4809 ExprKind::Assign { .. } => self.assign_chain(expr),
4810 ExprKind::CompoundAssign {
4811 place,
4812 op,
4813 value,
4814 compute,
4815 } => {
4816 let lowered = self.place(place, true);
4817 if lowered.atomic.is_some() {
4818 let kind = PlaceRmw::Compound {
4819 op: *op,
4820 value,
4821 compute: *compute,
4822 };
4823 let tokens = self.atomic_place_rmw(&lowered, kind, RmwValue::New, span);
4824 return Value::new(tokens, prec::BLOCK);
4825 }
4826 let (hoist, rhs) = self.compound_rhs(value);
4827 let current = self.read(&lowered, span);
4828 let updated = self.compound_value(current, place.ty, *op, value, rhs, *compute);
4829 let updated = updated.at(prec::LOWEST, span);
4830 let store = self.write(&lowered, updated, span);
4831 let read = self.read(&lowered, span).at(prec::LOWEST, span);
4832 let setup = &lowered.setup;
4833 Value::new(
4834 quote_spanned! {span=> { #setup #hoist #store #read } },
4835 prec::BLOCK,
4836 )
4837 }
4838 ExprKind::IncDec {
4839 place,
4840 dec,
4841 postfix,
4842 } => {
4843 let lowered = self.place(place, true);
4844 if lowered.atomic.is_some() {
4845 let want = if *postfix {
4846 RmwValue::Old
4847 } else {
4848 RmwValue::New
4849 };
4850 let tokens =
4851 self.atomic_place_rmw(&lowered, PlaceRmw::Step { dec: *dec }, want, span);
4852 return Value::new(tokens, prec::BLOCK);
4853 }
4854 let current = self.read(&lowered, span);
4855 let next = self.step_value(current, place.ty, *dec, span);
4856 let store = self.write(&lowered, next, span);
4857 let read = self.read(&lowered, span).at(prec::LOWEST, span);
4858 let setup = &lowered.setup;
4859 if *postfix {
4860 let tmp = self.temporary();
4861 Value::new(
4862 quote_spanned! {span=>
4863 { #setup let #tmp = #read; #store #tmp }
4864 },
4865 prec::BLOCK,
4866 )
4867 } else {
4868 Value::new(
4869 quote_spanned! {span=> { #setup #store #read } },
4870 prec::BLOCK,
4871 )
4872 }
4873 }
4874 // The three complex shapes are one call apiece: this function is
4875 // the one code generation recurses through, and every local in it
4876 // costs a slice of the stack `rustc` gives macro expansion.
4877 ExprKind::ComplexOf { re, im } => self.complex_literal(expr.ty, re, im, span),
4878 ExprKind::Neg(operand) if expr.ty.is_complex() => self.complex_neg(operand, span),
4879 ExprKind::BitNot(operand) if expr.ty.is_complex() => {
4880 self.complex_conj(operand, expr.ty, span)
4881 }
4882 ExprKind::Neg(operand) => {
4883 let value = self.expr(operand);
4884 if expr.ty.is_floating() {
4885 let ends_with_type = value.ends_with_type;
4886 let tokens = value.at(prec::UNARY, span);
4887 Value::new(quote_spanned! {span=> -#tokens }, prec::UNARY)
4888 .type_end(ends_with_type)
4889 } else {
4890 // Signed overflow is undefined in C and a panic in Rust;
4891 // wrapping is the predictable choice, and it is what
4892 // unsigned arithmetic requires anyway.
4893 let tokens = value.at(prec::CALL, span);
4894 Value::new(quote_spanned! {span=> #tokens.wrapping_neg() }, prec::CALL)
4895 }
4896 }
4897 ExprKind::BitNot(operand) => {
4898 let value = self.expr(operand);
4899 let ends_with_type = value.ends_with_type;
4900 let tokens = value.at(prec::UNARY, span);
4901 Value::new(quote_spanned! {span=> !#tokens }, prec::UNARY).type_end(ends_with_type)
4902 }
4903 ExprKind::Binary { .. } => self.binary_chain(expr),
4904 ExprKind::PtrOffset { ptr, index, sub } => {
4905 let pointee = self.program.types.pointee(ptr.ty).unwrap_or(Ty::Void);
4906 let base = self.expr(ptr).at(prec::CALL, span);
4907 let offset = self.scaled_offset(pointee, index, *sub, span);
4908 Value::new(quote_spanned! {span=> #base.offset(#offset) }, prec::CALL)
4909 }
4910 // GNU's label difference, `&&a - &&b`. Both operands are state
4911 // numbers rather than addresses, so the subtraction is done on the
4912 // numbers: `offset_from` would want two pointers into one object,
4913 // and a `static` table of such differences — which is the whole
4914 // idiom — needs an expression a `const` can fold.
4915 ExprKind::PtrDiff { lhs, rhs }
4916 if label_state(lhs).is_some() && label_state(rhs).is_some() =>
4917 {
4918 self.label_difference(lhs, rhs, expr.ty, span)
4919 }
4920 ExprKind::PtrDiff { lhs, rhs } => {
4921 let pointee = self.program.types.pointee(lhs.ty).unwrap_or(Ty::Void);
4922 let scale = self.vm_scale(pointee, span);
4923 let left = self.expr(lhs).at(prec::CALL, span);
4924 let right = self.expr(rhs).at(prec::LOWEST, span);
4925 let target = self.ty(expr.ty, span);
4926 // The difference the generated pointers give is in step-type
4927 // elements; C's is in whole ones.
4928 let difference = match scale {
4929 None => quote_spanned! {span=> #left.offset_from(#right) },
4930 Some(scale) => {
4931 quote_spanned! {span=> (#left.offset_from(#right) / (#scale)) }
4932 }
4933 };
4934 Value::new(quote_spanned! {span=> #difference as #target }, prec::CAST)
4935 .type_end(true)
4936 }
4937 ExprKind::Compare { .. } | ExprKind::Logical { .. } => {
4938 // C's comparisons and logical operators produce an `int`.
4939 let condition = self.condition(expr).at(prec::LOWEST, span);
4940 let ty = self.ty(Ty::Int, span);
4941 let parens = parenthesize(condition, span);
4942 Value::new(quote_spanned! {span=> #parens as #ty }, prec::CAST).type_end(true)
4943 }
4944 // `(void)x` and a `void`-typed conditional have no value at all:
4945 // Rust's `()` is not something `as` produces, so each of them is
4946 // emitted as the statement it is, wrapped in a block whose own
4947 // value is `()`. A conditional gets here when it is written where
4948 // a value is expected — the left operand of a comma is a
4949 // statement, but the right one is not.
4950 ExprKind::Cast(inner) if expr.ty.is_void() => {
4951 let tokens = self.expr_stmt(inner);
4952 Value::new(quote_spanned! {span=> { #tokens } }, prec::BLOCK)
4953 }
4954 ExprKind::Cond { .. } if expr.ty.is_void() => {
4955 let tokens = self.expr_stmt(expr);
4956 Value::new(quote_spanned! {span=> { #tokens } }, prec::BLOCK)
4957 }
4958 ExprKind::Cast(inner) => {
4959 let from = inner.ty;
4960 let value = self.expr(inner);
4961 self.cast(value, from, expr.ty, span)
4962 }
4963 // Both arms are emitted as expressions of their own rather than at
4964 // the conditional's type: an `if` whose arms are two bare literals
4965 // is `{integer}`, which Rust either resolves to `i32` — wrong
4966 // wherever C said `long` — or refuses to resolve at all, as it
4967 // does for the receiver of `wrapping_mul` (`E0689`). The bare form
4968 // is still used from [`Codegen::expr_at`], where the context says
4969 // what the type is.
4970 ExprKind::Cond { .. } => self.cond_chain(expr),
4971 ExprKind::Comma { lhs, rhs } => {
4972 let lhs = self.expr_stmt(lhs);
4973 let rhs = self.expr(rhs).at(prec::LOWEST, span);
4974 Value::new(quote_spanned! {span=> { #lhs #rhs } }, prec::BLOCK)
4975 }
4976 ExprKind::Call { callee, args } => self.call(callee, args, span),
4977 ExprKind::RecordLit { record, fields } => self.record_literal(*record, fields, span),
4978 ExprKind::UnionLit {
4979 record,
4980 index,
4981 value,
4982 } => self.union_literal(*record, *index, value, span),
4983 ExprKind::ArrayLit(items) => {
4984 let elem = self.program.types.elem(expr.ty).unwrap_or(Ty::Int);
4985 let mut tokens = TokenStream::new();
4986 for (index, item) in items.iter().enumerate() {
4987 if index > 0 {
4988 tokens.extend(quote_spanned! {span=> , });
4989 }
4990 tokens.extend(self.expr_at(item, elem));
4991 }
4992 Value::atom(bracketed(tokens, span))
4993 }
4994 ExprKind::ArrayRepeat { value, len } => {
4995 let elem = self.program.types.elem(expr.ty).unwrap_or(value.ty);
4996 let tokens = self.expr_at(value, elem);
4997 let len = usize_literal(*len, span);
4998 Value::atom(bracketed(quote_spanned! {span=> #tokens ; #len }, span))
4999 }
5000 // GNU's `a ?: b`. The value is held in a temporary so that the
5001 // operand is evaluated exactly once, which is the whole point.
5002 ExprKind::CondDefault { value, else_expr } => {
5003 let ty = expr.ty;
5004 let first = self.expr_at(value, ty);
5005 let other = self.expr_at(else_expr, ty);
5006 let tmp = self.temporary();
5007 let target = self.ty(ty, span);
5008 let test = if ty.is_pointer() {
5009 quote_spanned! {span=> !#tmp.is_null() }
5010 } else {
5011 let zero = self.zero_tokens(ty, span);
5012 quote_spanned! {span=> #tmp != #zero }
5013 };
5014 Value::new(
5015 quote_spanned! {span=>
5016 { let #tmp: #target = #first; if #test { #tmp } else { #other } }
5017 },
5018 prec::BLOCK,
5019 )
5020 }
5021 // GNU's statement expression, which is what a Rust block is.
5022 ExprKind::StmtExpr { stmts, value } => {
5023 let body = self.stmts(stmts);
5024 let tail = match value {
5025 Some(value) => {
5026 let ty = expr.ty;
5027 self.expr_at(value, ty)
5028 }
5029 None => TokenStream::new(),
5030 };
5031 Value::new(quote_spanned! {span=> { #body #tail } }, prec::BLOCK)
5032 }
5033 ExprKind::Builtin { op, args } => self.builtin(*op, args, span),
5034 ExprKind::Atomic(atomic) => self.atomic(atomic, span),
5035 ExprKind::VaListPristine => Value::new(self.va_pristine(span), prec::CALL),
5036 ExprKind::VaArg { ap, record } => self.va_arg(ap, record.as_deref(), expr.ty, span),
5037 // `va_end` is nothing: the list ends when its value is dropped.
5038 ExprKind::VaEnd => Value::atom(quote_spanned! {span=> () }),
5039 // C23's `unreachable()`. C says reaching it is undefined, and
5040 // saying so to Rust is what lets the optimiser use the promise —
5041 // this is the one place the expansion trusts the C program with
5042 // undefined behaviour, because the program asked for it by name.
5043 ExprKind::Unreachable => Value::new(
5044 quote_spanned! {span=> ::core::hint::unreachable_unchecked() },
5045 prec::CALL,
5046 ),
5047 }
5048 }
5049
5050 // -- complex ------------------------------------------------------------
5051
5052 /// `::cinrs::rt::Complex::<f64>::new(re, im)`.
5053 ///
5054 /// A call rather than a struct literal, and with the component type spelled
5055 /// out: `Complex { … }` at the start of an `if` condition would be read as
5056 /// the condition's block, and a bare `0.0` part would infer `f64` where the
5057 /// type is `float _Complex`. `Complex::new` is a `const fn`, so this is
5058 /// also what a `static` initialiser holds.
5059 fn complex_new(&self, ty: Ty, re: TokenStream, im: TokenStream, span: Span) -> Value {
5060 self.uses_complex.set(true);
5061 let rt = self.rt_path(span);
5062 let component = primitive_ty(if ty == Ty::ComplexFloat { "f32" } else { "f64" }, span);
5063 Value::new(
5064 quote_spanned! {span=> #rt::Complex::<#component>::new(#re, #im) },
5065 prec::CALL,
5066 )
5067 }
5068
5069 /// `__builtin_complex(re, im)`, an imaginary constant, and a folded
5070 /// complex constant: the two parts, side by side.
5071 fn complex_literal(&mut self, ty: Ty, re: &Expr, im: &Expr, span: Span) -> Value {
5072 let re = self.expr(re).at(prec::LOWEST, span);
5073 let im = self.expr(im).at(prec::LOWEST, span);
5074 self.complex_new(ty, re, im, span)
5075 }
5076
5077 /// `-z`, which is `num_complex`'s own `Neg` — both parts negated exactly.
5078 fn complex_neg(&mut self, operand: &Expr, span: Span) -> Value {
5079 let tokens = self.expr(operand).at(prec::UNARY, span);
5080 Value::new(quote_spanned! {span=> -#tokens }, prec::UNARY)
5081 }
5082
5083 /// GNU's `~z` and `__builtin_conj(z)`: the conjugate.
5084 fn complex_conj(&mut self, operand: &Expr, ty: Ty, span: Span) -> Value {
5085 let tokens = self.expr(operand).at(prec::LOWEST, span);
5086 let conj = self.rt_complex(&format!("conj_{}", Self::complex_suffix(ty)), span);
5087 Value::new(quote_spanned! {span=> #conj(#tokens) }, prec::CALL)
5088 }
5089
5090 /// `+`, `-`, `*` or `/` with at least one complex operand.
5091 ///
5092 /// Each operand arrives with the C type its tokens have, because that is
5093 /// what decides which runtime function is called: C computes a *real*
5094 /// operand componentwise rather than widening it — see `cinrs_rt::complex`
5095 /// for what that changes and why. Two complex operands add and subtract
5096 /// through `num_complex`'s own operators, which are exactly componentwise,
5097 /// and multiply and divide through Annex G.
5098 fn complex_binary(
5099 &mut self,
5100 op: BinOp,
5101 (lhs, lhs_ty): (Value, Ty),
5102 (rhs, rhs_ty): (Value, Ty),
5103 ty: Ty,
5104 span: Span,
5105 ) -> Value {
5106 self.uses_complex.set(true);
5107 let suffix = Self::complex_suffix(ty);
5108 let both = lhs_ty.is_complex() && rhs_ty.is_complex();
5109 if both && matches!(op, BinOp::Add | BinOp::Sub) {
5110 let (level, tokens) = match op {
5111 BinOp::Add => (prec::SUM, quote_spanned! {span=> + }),
5112 _ => (prec::SUM, quote_spanned! {span=> - }),
5113 };
5114 let mut out = lhs.at(level, span);
5115 let rhs = rhs.at(level + 1, span);
5116 out.extend(quote_spanned! {span=> #tokens #rhs });
5117 return Value::new(out, level);
5118 }
5119 // `<what>_<suffix>`, with the name saying which operand is the real
5120 // one: `mul_real` is `z * x` and `real_mul` is `x * z`.
5121 let name = match (op, lhs_ty.is_complex(), rhs_ty.is_complex()) {
5122 (BinOp::Add, true, false) => "add_real",
5123 (BinOp::Add, false, true) => "real_add",
5124 (BinOp::Sub, true, false) => "sub_real",
5125 (BinOp::Sub, false, true) => "real_sub",
5126 (BinOp::Mul, true, true) => "mul",
5127 (BinOp::Mul, true, false) => "mul_real",
5128 (BinOp::Mul, false, true) => "real_mul",
5129 (BinOp::Div, true, true) => "div",
5130 (BinOp::Div, true, false) => "div_real",
5131 (BinOp::Div, false, true) => "real_div",
5132 // Sema refuses every other operator on a complex operand, and one
5133 // of the two always is complex.
5134 _ => unreachable!("'{}' does not reach complex code generation", op.as_str()),
5135 };
5136 let func = self.rt_complex(&format!("{name}_{suffix}"), span);
5137 let lhs = lhs.at(prec::LOWEST, span);
5138 let rhs = rhs.at(prec::LOWEST, span);
5139 Value::new(quote_spanned! {span=> #func(#lhs, #rhs) }, prec::CALL)
5140 }
5141
5142 /// A conversion with a complex type on one side or the other
5143 /// (C99 6.3.1.6, 6.3.1.7).
5144 fn complex_cast(&mut self, value: Value, from: Ty, to: Ty, span: Span) -> Value {
5145 self.uses_complex.set(true);
5146 if from.is_complex() && to.is_complex() {
5147 let name = if to == Ty::ComplexDouble {
5148 "widen_f32"
5149 } else {
5150 "narrow_f64"
5151 };
5152 let func = self.rt_complex(name, span);
5153 let tokens = value.at(prec::LOWEST, span);
5154 return Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL);
5155 }
5156 if to.is_complex() {
5157 // A real value becomes a complex one with a zero imaginary part.
5158 let component = to.complex_component();
5159 let re = self
5160 .cast(value, from, component, span)
5161 .at(prec::LOWEST, span);
5162 let zero = bare_float_literal(0.0, span);
5163 return self.complex_new(to, re, zero, span);
5164 }
5165 // Converting a complex value to a real type discards the imaginary
5166 // part — except for `_Bool`, which asks whether *either* part is
5167 // non-zero (C99 6.3.1.2).
5168 if to.is_bool() {
5169 let func = self.rt_complex(&format!("nonzero_{}", Self::complex_suffix(from)), span);
5170 let tokens = value.at(prec::LOWEST, span);
5171 return Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL);
5172 }
5173 let tokens = value.at(prec::CALL, span);
5174 let real = Value::new(quote_spanned! {span=> #tokens.re }, prec::CALL);
5175 self.cast(real, from.complex_component(), to, span)
5176 }
5177
5178 /// `z == w` and `z != w` (C99 6.5.9p3: equal exactly when both parts are).
5179 ///
5180 /// Rust's own `==` would give the same answer — the runtime's complex type
5181 /// derives `PartialEq` — and it is *not* used, because `PartialEq::eq`
5182 /// takes `&self`: a reference to a field of a `#[repr(packed)]` record is
5183 /// `E0793`, and a packed `__complex__ float` member compared against a
5184 /// constant is exactly `gcc.c-torture/execute/20020227-1`. The runtime's
5185 /// by-value equality asks for a *copy* of each operand, which a packed
5186 /// field will give.
5187 ///
5188 /// Sema converts both operands to one complex type before this, so a
5189 /// mixed real/complex comparison never arrives here.
5190 fn complex_equality(&mut self, op: CmpOp, lhs: &Expr, rhs: &Expr, span: Span) -> Value {
5191 self.uses_complex.set(true);
5192 let name = match op {
5193 CmpOp::Eq => "eq",
5194 CmpOp::Ne => "ne",
5195 // 6.5.8p2 gives the relational operators real operands only, and
5196 // sema has already said so.
5197 other => unreachable!("{other:?} does not reach a complex comparison"),
5198 };
5199 let func = self.rt_complex(&format!("{name}_{}", Self::complex_suffix(lhs.ty)), span);
5200 let (lhs, rhs) = self.operands(lhs, rhs, BinOp::BitOr);
5201 let lhs = lhs.at(prec::LOWEST, span);
5202 let rhs = rhs.at(prec::LOWEST, span);
5203 Value::new(quote_spanned! {span=> #func(#lhs, #rhs) }, prec::CALL)
5204 }
5205
5206 /// `z != 0` as Rust's `bool`: what an `if`, a `while` and `!z` ask of a
5207 /// complex value.
5208 fn complex_condition(&mut self, expr: &Expr, span: Span) -> Value {
5209 self.uses_complex.set(true);
5210 let func = self.rt_complex(&format!("nonzero_{}", Self::complex_suffix(expr.ty)), span);
5211 let tokens = self.expr(expr).at(prec::LOWEST, span);
5212 Value::new(quote_spanned! {span=> #func(#tokens) }, prec::CALL)
5213 }
5214
5215 /// A `struct` value: one expression per member, in declaration order.
5216 ///
5217 /// Without bit-fields this is a plain Rust struct literal. With them the
5218 /// members that share a storage field have to be *packed* into it: every
5219 /// constant one is folded into the `[u8; K]` there and then, which is what
5220 /// lets a `static` — where nothing may run — hold a bit-field at all, and
5221 /// what makes the byte pattern visible in the expansion. A member whose
5222 /// value is not constant is stored afterwards through its setter, so the
5223 /// literal becomes a block.
5224 fn record_literal(&mut self, record: ir::RecordId, fields: &[Expr], span: Span) -> Value {
5225 let def = self.program.types.record(record).clone();
5226 // An initialised flexible array member makes the value the *companion*
5227 // type's rather than the record's: the tail is as long as the
5228 // initialiser, and the member's value carries that length.
5229 let tail = def
5230 .fields
5231 .iter()
5232 .position(|field| field.flexible)
5233 .and_then(|index| {
5234 Some((
5235 index,
5236 array_len(&self.program.types, fields.get(index)?.ty)?,
5237 ))
5238 })
5239 .filter(|(_, len)| *len > 0);
5240 let name = match tail {
5241 Some((_, len)) => self.flexible_ident(&def.rust_name, len, span),
5242 None => self.c_ident(&def.rust_name, span),
5243 };
5244 let mut packed: HashMap<String, Vec<u8>> = HashMap::new();
5245 let mut dynamic: Vec<usize> = Vec::new();
5246 for rust_field in &def.rust_fields {
5247 if let ir::RustField::Bits { name, bytes, .. } = rust_field {
5248 packed.insert(name.clone(), vec![0u8; *bytes as usize]);
5249 }
5250 }
5251 for (index, field) in def.fields.iter().enumerate() {
5252 let Some(bits) = &field.bits else { continue };
5253 match fields.get(index).and_then(constant_bits) {
5254 Some(value) => {
5255 if let Some(storage) = packed.get_mut(&bits.storage) {
5256 pack_bits(storage, bits, value);
5257 }
5258 }
5259 None => dynamic.push(index),
5260 }
5261 }
5262
5263 let mut items = TokenStream::new();
5264 for rust_field in &def.rust_fields {
5265 match rust_field {
5266 ir::RustField::Member(index) => {
5267 let field = &def.fields[*index];
5268 let fname = self.c_ident(&field.name, span);
5269 // The flexible member's value is longer than its own type,
5270 // and the companion's field is what it fills.
5271 let value = &fields[*index];
5272 let want = match tail {
5273 Some((flexible, _)) if flexible == *index => value.ty,
5274 _ => field.ty,
5275 };
5276 let tokens = self.expr_at(value, want);
5277 items.extend(quote_spanned! {span=> #fname: #tokens, });
5278 }
5279 ir::RustField::Bits { name, .. } => {
5280 let fname = Ident::new(name, span);
5281 let value = byte_array(&packed[name], span);
5282 items.extend(quote_spanned! {span=> #fname: #value, });
5283 }
5284 ir::RustField::Pad { name, bytes } => {
5285 let fname = Ident::new(name, span);
5286 let len = usize_literal(*bytes, span);
5287 items.extend(quote_spanned! {span=> #fname: [0; #len], });
5288 }
5289 ir::RustField::Align { name, .. } => {
5290 let fname = Ident::new(name, span);
5291 items.extend(quote_spanned! {span=> #fname: [], });
5292 }
5293 }
5294 }
5295 let body = braced(items, span);
5296 let literal = quote_spanned! {span=> #name #body };
5297 if dynamic.is_empty() {
5298 return Value::new(literal, prec::ATOM);
5299 }
5300 // The members that are not constants are stored through their setters,
5301 // in declaration order, which is one of the orders C allows.
5302 let tmp = self.temporary();
5303 let ty = self.ty(Ty::Record(record), span);
5304 let mut stores = TokenStream::new();
5305 for index in dynamic {
5306 let field = &def.fields[index];
5307 let bits = field.bits.as_ref().expect("only bit-fields are deferred");
5308 let setter = self.c_ident(&bits.setter, span);
5309 let value = self.expr_at(&fields[index], field.ty);
5310 stores.extend(quote_spanned! {span=> #tmp.#setter(#value); });
5311 }
5312 Value::new(
5313 quote_spanned! {span=>
5314 { let mut #tmp: #ty = #literal; #stores #tmp }
5315 },
5316 prec::BLOCK,
5317 )
5318 }
5319
5320 /// A `union` value, which initialises exactly one member.
5321 fn union_literal(
5322 &mut self,
5323 record: ir::RecordId,
5324 index: usize,
5325 value: &Expr,
5326 span: Span,
5327 ) -> Value {
5328 let def = self.program.types.record(record).clone();
5329 let name = self.c_ident(&def.rust_name, span);
5330 let field = &def.fields[index];
5331 let Some(bits) = &field.bits else {
5332 let fname = self.c_ident(&field.name, span);
5333 let tokens = self.expr_at(value, field.ty);
5334 let body = braced(quote_spanned! {span=> #fname: #tokens }, span);
5335 return Value::new(quote_spanned! {span=> #name #body }, prec::ATOM);
5336 };
5337 let bytes = def
5338 .rust_fields
5339 .iter()
5340 .find_map(|rust_field| match rust_field {
5341 ir::RustField::Bits { name, bytes, .. } if *name == bits.storage => Some(*bytes),
5342 _ => None,
5343 })
5344 .unwrap_or(0);
5345 let mut packed = vec![0u8; bytes as usize];
5346 let constant = constant_bits(value);
5347 if let Some(constant) = constant {
5348 pack_bits(&mut packed, bits, constant);
5349 }
5350 let storage = Ident::new(&bits.storage, span);
5351 let array = byte_array(&packed, span);
5352 let body = braced(quote_spanned! {span=> #storage: #array }, span);
5353 let literal = quote_spanned! {span=> #name #body };
5354 if constant.is_some() {
5355 return Value::new(literal, prec::ATOM);
5356 }
5357 let tmp = self.temporary();
5358 let ty = self.ty(Ty::Record(record), span);
5359 let setter = self.c_ident(&bits.setter, span);
5360 let value = self.expr_at(value, field.ty);
5361 Value::new(
5362 quote_spanned! {span=>
5363 { let mut #tmp: #ty = #literal; #tmp.#setter(#value); #tmp }
5364 },
5365 prec::BLOCK,
5366 )
5367 }
5368
5369 /// One of the builtins that becomes a fixed piece of Rust.
5370 ///
5371 /// The bit-manipulation ones are the integer methods of the same name, on
5372 /// the *unsigned* type of the operand's width — C's are defined on
5373 /// unsigned values and Rust's `leading_zeros` counts the same way. The
5374 /// overflow ones do the arithmetic in `i128` and ask whether the value
5375 /// survives the round trip through the type it is stored in, which is
5376 /// exactly "compute in infinite precision, then convert".
5377 fn builtin(&mut self, op: ir::BuiltinOp, args: &[Expr], span: Span) -> Value {
5378 use ir::BuiltinOp;
5379 let int = self.ty(Ty::Int, span);
5380 match op {
5381 BuiltinOp::ComplexProj => {
5382 let ty = args[0].ty;
5383 let func = self.rt_complex(&format!("proj_{}", Self::complex_suffix(ty)), span);
5384 let value = self.expr(&args[0]).at(prec::LOWEST, span);
5385 Value::new(quote_spanned! {span=> #func(#value) }, prec::CALL)
5386 }
5387 BuiltinOp::Discard => {
5388 let mut out = TokenStream::new();
5389 for arg in args {
5390 out.extend(self.expr_stmt(arg));
5391 }
5392 Value::new(quote_spanned! {span=> { #out } }, prec::BLOCK)
5393 }
5394 // A hint, so dropping it is always correct, and it is dropped
5395 // where emitting it would change what compiles: a safe function
5396 // has no `unsafe` block for the call to sit in, and only x86 and
5397 // AArch64 have a stable way to say it.
5398 BuiltinOp::Prefetch(packed) => {
5399 let (write, locality) = ir::prefetch_hint(packed);
5400 let arch = self.options.target.arch;
5401 let pointer = self.expr(&args[0]).at(prec::LOWEST, span);
5402 let tmp = self.temporary();
5403 let prefetch = match arch {
5404 _ if self.in_safe => TokenStream::new(),
5405 // `_mm_prefetch` has no form for writing without
5406 // `prefetchw`, which is a feature of its own, so `rw` is
5407 // not passed on. The hints are GCC's: locality 3 is
5408 // `prefetcht0`, 0 is `prefetchnta`. The `cfg` is for a
5409 // 32-bit target without SSE (`i586`), where there is
5410 // nothing to call; x86-64 always has SSE.
5411 crate::target::Arch::X86 | crate::target::Arch::X86_64 => {
5412 let module = self.arch_module(span);
5413 let hint = Ident::new(
5414 ["_MM_HINT_NTA", "_MM_HINT_T2", "_MM_HINT_T1", "_MM_HINT_T0"]
5415 [usize::from(locality)],
5416 span,
5417 );
5418 let sse = if arch == crate::target::Arch::X86 {
5419 quote_spanned! {span=> #[cfg(target_feature = "sse")] }
5420 } else {
5421 TokenStream::new()
5422 };
5423 quote_spanned! {span=>
5424 #sse
5425 ::core::arch::#module::_mm_prefetch::<{ ::core::arch::#module::#hint }>(
5426 #tmp.cast::<i8>()
5427 );
5428 }
5429 }
5430 // GCC's choice of `prfm` operation for each locality.
5431 crate::target::Arch::Aarch64 => {
5432 let kind = if write { "pst" } else { "pld" };
5433 let level = ["l1strm", "l3keep", "l2keep", "l1keep"][usize::from(locality)];
5434 let mut template = Literal::string(&format!("prfm {kind}{level}, [{{0}}]"));
5435 template.set_span(span);
5436 quote_spanned! {span=>
5437 ::core::arch::asm!(
5438 #template,
5439 in(reg) #tmp,
5440 options(nostack, preserves_flags, readonly)
5441 );
5442 }
5443 }
5444 _ => TokenStream::new(),
5445 };
5446 Value::new(
5447 quote_spanned! {span=> { let #tmp = #pointer; #prefetch } },
5448 prec::BLOCK,
5449 )
5450 }
5451 // `__builtin_cpu_supports("avx2")` asks the processor, exactly as
5452 // it does in C, and the answer is an `int` because that is what
5453 // GCC's builtin returns. Several features for one GCC name — `abm`
5454 // is LZCNT and POPCNT — are all of them or nothing.
5455 BuiltinOp::CpuSupports(row) => {
5456 let mut test = TokenStream::new();
5457 for (index, feature) in crate::x86::detect_features(row).iter().enumerate() {
5458 if index > 0 {
5459 test.extend(quote_spanned! {span=> && });
5460 }
5461 let mut literal = Literal::string(feature);
5462 literal.set_span(span);
5463 // The root path, not `std::arch`'s: `is_x86_feature_detected`
5464 // has been a `std` root macro since 1.27, which is older
5465 // than anything this crate supports.
5466 test.extend(quote_spanned! {span=> ::std::is_x86_feature_detected!(#literal) });
5467 }
5468 Value::new(quote_spanned! {span=> ((#test) as #int) }, prec::LOWEST)
5469 }
5470 // Sixteen-byte aligned bytes off the function's arena, which no
5471 // variable length array's frame gives back: they live until the
5472 // function returns. See [`Codegen::arena_items`].
5473 BuiltinOp::Alloca => {
5474 let arena = self.arena_ident(span);
5475 let size = self.expr(&args[0]).at(prec::CAST, span);
5476 let usize_ty = primitive_ty("usize", span);
5477 Value::new(
5478 quote_spanned! {span=> #arena.alloca(#size as #usize_ty) },
5479 prec::CALL,
5480 )
5481 }
5482 BuiltinOp::Bswap => {
5483 let operand = args[0].ty;
5484 let value = self.unsigned_operand(&args[0], span);
5485 let target = self.ty(operand, span);
5486 Value::new(
5487 quote_spanned! {span=> #value.swap_bytes() as #target },
5488 prec::CAST,
5489 )
5490 .type_end(true)
5491 }
5492 BuiltinOp::Popcount => {
5493 let value = self.unsigned_operand(&args[0], span);
5494 Value::new(
5495 quote_spanned! {span=> #value.count_ones() as #int },
5496 prec::CAST,
5497 )
5498 .type_end(true)
5499 }
5500 BuiltinOp::Parity => {
5501 let value = self.unsigned_operand(&args[0], span);
5502 Value::new(
5503 quote_spanned! {span=> (#value.count_ones() & 1) as #int },
5504 prec::CAST,
5505 )
5506 .type_end(true)
5507 }
5508 BuiltinOp::Clz => {
5509 let value = self.unsigned_operand(&args[0], span);
5510 Value::new(
5511 quote_spanned! {span=> #value.leading_zeros() as #int },
5512 prec::CAST,
5513 )
5514 .type_end(true)
5515 }
5516 BuiltinOp::Ctz => {
5517 let value = self.unsigned_operand(&args[0], span);
5518 Value::new(
5519 quote_spanned! {span=> #value.trailing_zeros() as #int },
5520 prec::CAST,
5521 )
5522 .type_end(true)
5523 }
5524 BuiltinOp::Ffs => {
5525 let value = self.unsigned_operand(&args[0], span);
5526 let tmp = self.temporary();
5527 Value::new(
5528 quote_spanned! {span=>
5529 { let #tmp = #value;
5530 if #tmp == 0 { 0 } else { #tmp.trailing_zeros() as #int + 1 } }
5531 },
5532 prec::BLOCK,
5533 )
5534 }
5535 // The number of leading bits that repeat the sign bit, not
5536 // counting the sign bit itself — which is what `leading_zeros` of
5537 // the value XORed with itself shifted left gives.
5538 BuiltinOp::Clrsb => {
5539 let width = args[0].ty.bits(&self.options.target);
5540 let signed = signed_rust_ty(width, span);
5541 let value = self.expr(&args[0]).at(prec::CAST, span);
5542 let tmp = self.temporary();
5543 let bits = usize_literal(u64::from(width), span);
5544 Value::new(
5545 quote_spanned! {span=>
5546 { let #tmp = #value as #signed;
5547 ((#tmp ^ (#tmp << 1)).leading_zeros() as #int)
5548 .min(#bits as #int - 1) }
5549 },
5550 prec::BLOCK,
5551 )
5552 }
5553 BuiltinOp::Overflow(bin) | BuiltinOp::OverflowP(bin) => {
5554 let store = matches!(op, BuiltinOp::Overflow(_));
5555 // The third operand carries the result type: the pointee of
5556 // the pointer the value is stored through, or the type of the
5557 // expression the `_p` forms only ask about.
5558 let result_ty = if store {
5559 self.program.types.pointee(args[2].ty).unwrap_or(Ty::Int)
5560 } else {
5561 args[2].ty
5562 };
5563 self.overflow_builtin(bin, args, store, result_ty, span)
5564 }
5565 BuiltinOp::Fabs => {
5566 let bits = self.float_bits_of(&args[0], span);
5567 let (float_ty, mask) = float_bit_ty(args[0].ty, span);
5568 Value::new(
5569 quote_spanned! {span=> <#float_ty>::from_bits(#bits & #mask) },
5570 prec::CALL,
5571 )
5572 }
5573 BuiltinOp::Copysign => {
5574 let magnitude = self.float_bits_of(&args[0], span);
5575 let sign = self.float_bits_of(&args[1], span);
5576 let (float_ty, mask) = float_bit_ty(args[0].ty, span);
5577 Value::new(
5578 quote_spanned! {span=>
5579 <#float_ty>::from_bits((#magnitude & #mask) | (#sign & !#mask))
5580 },
5581 prec::CALL,
5582 )
5583 }
5584 BuiltinOp::FloatOrder(order) => self.float_order(order, args, span),
5585 BuiltinOp::FloatClass(class) => self.float_class(class, &args[0], span),
5586 BuiltinOp::Fpclassify => {
5587 let value = self.expr(&args[5]).at(prec::CALL, span);
5588 let arms = ["Nan", "Infinite", "Normal", "Subnormal", "Zero"]
5589 .iter()
5590 .zip(args)
5591 .map(|(name, answer)| {
5592 let variant = Ident::new(name, span);
5593 let answer = self.expr_at(answer, Ty::Int);
5594 quote_spanned! {span=>
5595 ::core::num::FpCategory::#variant => #answer,
5596 }
5597 })
5598 .collect::<TokenStream>();
5599 Value::new(
5600 quote_spanned! {span=> match #value.classify() { #arms } },
5601 prec::BLOCK,
5602 )
5603 }
5604 }
5605 }
5606
5607 /// A floating operand as the unsigned integer of its own width.
5608 fn float_bits_of(&mut self, arg: &Expr, span: Span) -> TokenStream {
5609 let value = self.expr(arg).at(prec::CALL, span);
5610 parenthesize(quote_spanned! {span=> #value.to_bits() }, span)
5611 }
5612
5613 /// `__builtin_isgreater` and its relatives.
5614 ///
5615 /// Rust's floating comparisons are the quiet ones, which is exactly what
5616 /// C99 7.12.14 asks these for; the operands go into temporaries because
5617 /// two of the six mention each of them twice.
5618 fn float_order(&mut self, order: ir::FloatOrder, args: &[Expr], span: Span) -> Value {
5619 use ir::FloatOrder;
5620 let int = self.ty(Ty::Int, span);
5621 let lhs = self.expr(&args[0]).at(prec::LOWEST, span);
5622 let rhs = self.expr(&args[1]).at(prec::LOWEST, span);
5623 let (a, b) = (self.temporary(), self.temporary());
5624 let test = match order {
5625 FloatOrder::Greater => quote_spanned! {span=> #a > #b },
5626 FloatOrder::GreaterEqual => quote_spanned! {span=> #a >= #b },
5627 FloatOrder::Less => quote_spanned! {span=> #a < #b },
5628 FloatOrder::LessEqual => quote_spanned! {span=> #a <= #b },
5629 FloatOrder::LessGreater => quote_spanned! {span=> #a < #b || #a > #b },
5630 FloatOrder::Unordered => quote_spanned! {span=> #a.is_nan() || #b.is_nan() },
5631 };
5632 Value::new(
5633 quote_spanned! {span=>
5634 { let #a = #lhs; let #b = #rhs; (#test) as #int }
5635 },
5636 prec::BLOCK,
5637 )
5638 }
5639
5640 /// `__builtin_isnan` and its relatives.
5641 ///
5642 /// The predicates are `core`'s own, which are pure inspections of the bit
5643 /// pattern and so need nothing of the maths library; `issignaling` is the
5644 /// one that has no method, and is a NaN whose leading mantissa bit — the
5645 /// quiet bit — is clear.
5646 fn float_class(&mut self, class: ir::FloatClass, arg: &Expr, span: Span) -> Value {
5647 use ir::FloatClass;
5648 let int = self.ty(Ty::Int, span);
5649 let method = |name: &str| Ident::new(name, span);
5650 let test = match class {
5651 FloatClass::IsNan => Some(method("is_nan")),
5652 FloatClass::IsInf => Some(method("is_infinite")),
5653 FloatClass::IsFinite => Some(method("is_finite")),
5654 FloatClass::IsNormal => Some(method("is_normal")),
5655 FloatClass::SignBit => Some(method("is_sign_negative")),
5656 FloatClass::IsInfSign | FloatClass::IsSignaling => None,
5657 };
5658 if let Some(test) = test {
5659 let value = self.expr(arg).at(prec::CALL, span);
5660 return Value::new(quote_spanned! {span=> #value.#test() as #int }, prec::CAST)
5661 .type_end(true);
5662 }
5663 let tmp = self.temporary();
5664 let value = self.expr(arg).at(prec::LOWEST, span);
5665 if class == FloatClass::IsInfSign {
5666 return Value::new(
5667 quote_spanned! {span=>
5668 { let #tmp = #value;
5669 if #tmp.is_infinite() {
5670 if #tmp.is_sign_negative() { -1 as #int } else { 1 as #int }
5671 } else { 0 as #int } }
5672 },
5673 prec::BLOCK,
5674 );
5675 }
5676 // A signalling NaN is a NaN with the quiet bit clear: bit 51 of a
5677 // `double` and bit 22 of a `float`.
5678 let quiet = quiet_bit_literal(arg.ty, span);
5679 Value::new(
5680 quote_spanned! {span=>
5681 { let #tmp = #value;
5682 (#tmp.is_nan() && (#tmp.to_bits() & #quiet) == 0) as #int }
5683 },
5684 prec::BLOCK,
5685 )
5686 }
5687
5688 // -- atomics ------------------------------------------------------------
5689
5690 /// `::core::sync::atomic::AtomicU32`, or `AtomicPtr<c_void>`.
5691 fn atomic_path(&self, class: AtomicClass, span: Span) -> TokenStream {
5692 if matches!(class, AtomicClass::Ptr | AtomicClass::FnPtr) {
5693 let void = self.pointee_ty(Ty::Void, span);
5694 return quote_spanned! {span=>
5695 ::core::sync::atomic::AtomicPtr::<#void>
5696 };
5697 }
5698 let name = Ident::new(class.rust_name(), span);
5699 quote_spanned! {span=> ::core::sync::atomic::#name }
5700 }
5701
5702 /// The Rust type the atomic holds, which is what its `from_ptr` points at.
5703 ///
5704 /// Every pointer goes through one `AtomicPtr<c_void>`: all object pointers
5705 /// have the same representation, and the value is cast back to the C type
5706 /// it came from as it comes out. A function pointer goes through the same
5707 /// one, transmuted rather than cast.
5708 fn atomic_repr_ty(&self, class: AtomicClass, span: Span) -> TokenStream {
5709 if matches!(class, AtomicClass::Ptr | AtomicClass::FnPtr) {
5710 let void = self.pointee_ty(Ty::Void, span);
5711 return quote_spanned! {span=> *mut #void };
5712 }
5713 primitive_ty(class.repr_name(), span)
5714 }
5715
5716 /// `AtomicU32::from_ptr(p as *mut u32)`, the `&AtomicU32` everything else
5717 /// is a method call on.
5718 ///
5719 /// `from_ptr` is safe to build here for the reason C gives: the object is
5720 /// properly aligned for its own type, and the atomic's alignment is that
5721 /// type's size, which is what [`ir::Types::size_align`] gives an
5722 /// `_Atomic` and what sema checks before it accepts a pointer to a plain
5723 /// one.
5724 fn atomic_ref(&self, class: AtomicClass, ptr: TokenStream, span: Span) -> TokenStream {
5725 let path = self.atomic_path(class, span);
5726 let repr = self.atomic_repr_ty(class, span);
5727 quote_spanned! {span=> #path::from_ptr(#ptr as *mut #repr) }
5728 }
5729
5730 /// `::core::sync::atomic::Ordering::SeqCst`.
5731 fn ordering(&self, order: ir::MemOrder, span: Span) -> TokenStream {
5732 let name = Ident::new(order.rust_name(), span);
5733 quote_spanned! {span=> ::core::sync::atomic::Ordering::#name }
5734 }
5735
5736 /// The value an atomic yields, as the C type the object has.
5737 fn repr_to_value(&self, class: AtomicClass, ty: Ty, value: TokenStream, span: Span) -> Value {
5738 match class {
5739 AtomicClass::Bool => Value::atom(value),
5740 AtomicClass::Float { bytes } => {
5741 let float = primitive_ty(if bytes == 4 { "f32" } else { "f64" }, span);
5742 Value::new(
5743 quote_spanned! {span=> <#float>::from_bits(#value) },
5744 prec::CALL,
5745 )
5746 }
5747 AtomicClass::Int { .. } | AtomicClass::Ptr => {
5748 let target = self.ty(ty, span);
5749 Value::new(quote_spanned! {span=> #value as #target }, prec::CAST).type_end(true)
5750 }
5751 // `*mut c_void` to `Option<unsafe extern "C" fn(…)>`: `as` does
5752 // not go that way, and the two have the same size and the same
5753 // null, so the conversion is one `transmute` with both types
5754 // written out — an inferred one here would be a bug waiting to
5755 // happen.
5756 AtomicClass::FnPtr => {
5757 let repr = self.atomic_repr_ty(class, span);
5758 let target = self.ty(ty, span);
5759 Value::new(
5760 quote_spanned! {span=>
5761 ::core::mem::transmute::<#repr, #target>(#value)
5762 },
5763 prec::CALL,
5764 )
5765 }
5766 }
5767 }
5768
5769 /// A C value, as the Rust primitive the atomic holds. `ty` is the C type
5770 /// the value has, which only the function-pointer class needs.
5771 fn value_to_repr(&self, class: AtomicClass, ty: Ty, value: Value, span: Span) -> TokenStream {
5772 match class {
5773 AtomicClass::Bool => value.at(prec::LOWEST, span),
5774 AtomicClass::Float { bytes } => {
5775 let float = primitive_ty(if bytes == 4 { "f32" } else { "f64" }, span);
5776 let value = value.at(prec::LOWEST, span);
5777 quote_spanned! {span=> <#float>::to_bits(#value) }
5778 }
5779 AtomicClass::Int { .. } | AtomicClass::Ptr => {
5780 let repr = self.atomic_repr_ty(class, span);
5781 let value = value.at(prec::CAST, span);
5782 quote_spanned! {span=> #value as #repr }
5783 }
5784 // The other half of [`Codegen::repr_to_value`]'s transmute.
5785 AtomicClass::FnPtr => {
5786 let repr = self.atomic_repr_ty(class, span);
5787 let source = self.ty(ty, span);
5788 let value = value.at(prec::LOWEST, span);
5789 quote_spanned! {span=>
5790 ::core::mem::transmute::<#source, #repr>(#value)
5791 }
5792 }
5793 }
5794 }
5795
5796 /// `match … { Ok(v) | Err(v) => v }`, which is how the old value is taken
5797 /// out of a `fetch_update` that never says no.
5798 fn either_way(&mut self, result: TokenStream, span: Span) -> TokenStream {
5799 let value = self.temporary();
5800 quote_spanned! {span=>
5801 match #result {
5802 ::core::result::Result::Ok(#value) | ::core::result::Result::Err(#value) => #value,
5803 }
5804 }
5805 }
5806
5807 /// The compare-exchange loop an operation Rust has no method for becomes,
5808 /// whose value is the **old** one.
5809 ///
5810 /// `updated` is the new value written in terms of `current`, and is
5811 /// recomputed on every attempt, which is exactly what C's "read, modify,
5812 /// write, atomically" comes to when the processor has no single
5813 /// instruction for it — a `fetch_nand`, a `*=` on an atomic object, a
5814 /// pointer that moves by elements.
5815 ///
5816 /// Written out rather than left to `Atomic::fetch_update`: that method is
5817 /// being renamed to `try_update`, and the old name is deprecated on newer
5818 /// toolchains while the new one does not exist on the oldest this crate
5819 /// supports. The loop is what it does anyway.
5820 fn atomic_cas_loop(
5821 &mut self,
5822 object: &TokenStream,
5823 current: &Ident,
5824 updated: TokenStream,
5825 order: ir::MemOrder,
5826 span: Span,
5827 ) -> TokenStream {
5828 let success = self.ordering(order, span);
5829 let failure = self.ordering(order.failure_order(), span);
5830 let slot = self.temporary();
5831 let fresh = self.temporary();
5832 let seen = self.temporary();
5833 quote_spanned! {span=>
5834 {
5835 let #slot = #object;
5836 let mut #current = #slot.load(#failure);
5837 loop {
5838 let #fresh = #updated;
5839 match #slot.compare_exchange_weak(#current, #fresh, #success, #failure) {
5840 ::core::result::Result::Ok(_) => break #current,
5841 ::core::result::Result::Err(#seen) => #current = #seen,
5842 }
5843 }
5844 }
5845 }
5846 }
5847
5848 /// One of the atomic builtins; see [`ir::AtomicExpr`].
5849 fn atomic(&mut self, atomic: &ir::AtomicExpr, span: Span) -> Value {
5850 let class = atomic.class;
5851 let success = self.ordering(atomic.success, span);
5852 if let ir::AtomicOp::Fence { signal } = atomic.op {
5853 // C11 7.17.4p2 makes a relaxed fence a no-op, and Rust's `fence`
5854 // panics on one rather than saying so.
5855 if atomic.success == ir::MemOrder::Relaxed {
5856 return Value::atom(quote_spanned! {span=> () });
5857 }
5858 let name = Ident::new(if signal { "compiler_fence" } else { "fence" }, span);
5859 return Value::new(
5860 quote_spanned! {span=> ::core::sync::atomic::#name(#success) },
5861 prec::CALL,
5862 );
5863 }
5864 let ptr = match &atomic.ptr {
5865 Some(ptr) => self.expr(ptr).at(prec::CAST, span),
5866 None => return Value::atom(quote_spanned! {span=> () }),
5867 };
5868 let object = self.atomic_ref(class, ptr, span);
5869 let ty = atomic.value_ty;
5870 match atomic.op {
5871 ir::AtomicOp::Fence { .. } => unreachable!("handled above"),
5872 ir::AtomicOp::Load => self.repr_to_value(
5873 class,
5874 ty,
5875 quote_spanned! {span=> #object.load(#success) },
5876 span,
5877 ),
5878 ir::AtomicOp::Store => {
5879 let value = self.atomic_operand(atomic, span);
5880 Value::new(
5881 quote_spanned! {span=> #object.store(#value, #success) },
5882 prec::CALL,
5883 )
5884 }
5885 ir::AtomicOp::Exchange => {
5886 let value = self.atomic_operand(atomic, span);
5887 self.repr_to_value(
5888 class,
5889 ty,
5890 quote_spanned! {span=> #object.swap(#value, #success) },
5891 span,
5892 )
5893 }
5894 ir::AtomicOp::Clear => Value::new(
5895 quote_spanned! {span=> #object.store(0, #success) },
5896 prec::CALL,
5897 ),
5898 // GCC sets the byte to `__GCC_ATOMIC_TEST_AND_SET_TRUEVAL`, which
5899 // is 1, and answers whether it was already set.
5900 ir::AtomicOp::TestAndSet => Value::new(
5901 quote_spanned! {span=> #object.swap(1, #success) != 0 },
5902 prec::CMP,
5903 ),
5904 ir::AtomicOp::CompareExchange { weak } => {
5905 self.compare_exchange(atomic, object, weak, span)
5906 }
5907 ir::AtomicOp::SyncCompareSwap { value_is_old } => {
5908 self.sync_compare_swap(atomic, object, value_is_old, span)
5909 }
5910 ir::AtomicOp::Rmw { op, returns_new } => {
5911 self.atomic_rmw(atomic, object, op, returns_new, span)
5912 }
5913 }
5914 }
5915
5916 /// The value operand of an atomic builtin, as the atomic's own type.
5917 fn atomic_operand(&mut self, atomic: &ir::AtomicExpr, span: Span) -> TokenStream {
5918 let Some(value) = &atomic.value else {
5919 return quote_spanned! {span=> () };
5920 };
5921 let value = self.expr(value);
5922 self.value_to_repr(atomic.class, atomic.value_ty, value, span)
5923 }
5924
5925 /// `__atomic_compare_exchange_n`, which writes the value it observed back
5926 /// through `expected` when it fails and answers whether it succeeded.
5927 fn compare_exchange(
5928 &mut self,
5929 atomic: &ir::AtomicExpr,
5930 object: TokenStream,
5931 weak: bool,
5932 span: Span,
5933 ) -> Value {
5934 let class = atomic.class;
5935 let ty = atomic.value_ty;
5936 let expected = match &atomic.expected {
5937 Some(expected) => self.expr(expected).at(prec::CALL, span),
5938 None => return Value::atom(quote_spanned! {span=> false }),
5939 };
5940 let desired = self.atomic_operand(atomic, span);
5941 let slot = self.temporary();
5942 let seen = self.temporary();
5943 let current = self.value_to_repr(
5944 class,
5945 ty,
5946 Value::atom(quote_spanned! {span=> *#slot }),
5947 span,
5948 );
5949 let method = Ident::new(
5950 if weak {
5951 "compare_exchange_weak"
5952 } else {
5953 "compare_exchange"
5954 },
5955 span,
5956 );
5957 let success = self.ordering(atomic.success, span);
5958 let failure = self.ordering(atomic.failure, span);
5959 let observed = self
5960 .repr_to_value(class, ty, quote_spanned! {span=> #seen }, span)
5961 .at(prec::LOWEST, span);
5962 Value::new(
5963 quote_spanned! {span=>
5964 {
5965 let #slot = #expected;
5966 match #object.#method(#current, #desired, #success, #failure) {
5967 ::core::result::Result::Ok(_) => true,
5968 ::core::result::Result::Err(#seen) => {
5969 *#slot = #observed;
5970 false
5971 }
5972 }
5973 }
5974 },
5975 prec::BLOCK,
5976 )
5977 }
5978
5979 /// `__sync_bool_compare_and_swap` and `__sync_val_compare_and_swap`, whose
5980 /// expected value is a value and which write nothing back.
5981 fn sync_compare_swap(
5982 &mut self,
5983 atomic: &ir::AtomicExpr,
5984 object: TokenStream,
5985 value_is_old: bool,
5986 span: Span,
5987 ) -> Value {
5988 let class = atomic.class;
5989 let ty = atomic.value_ty;
5990 let expected = match &atomic.expected {
5991 Some(expected) => {
5992 let value = self.expr(expected);
5993 self.value_to_repr(class, ty, value, span)
5994 }
5995 None => return Value::atom(quote_spanned! {span=> false }),
5996 };
5997 let desired = self.atomic_operand(atomic, span);
5998 let seq = self.ordering(ir::MemOrder::SeqCst, span);
5999 let call = quote_spanned! {span=>
6000 #object.compare_exchange(#expected, #desired, #seq, #seq)
6001 };
6002 if !value_is_old {
6003 return Value::new(quote_spanned! {span=> #call.is_ok() }, prec::CALL);
6004 }
6005 let old = self.either_way(call, span);
6006 self.repr_to_value(class, ty, parenthesize(old, span), span)
6007 }
6008
6009 /// The `fetch_add` family, and the compare-exchange loops the ones Rust
6010 /// has no method for turn into.
6011 fn atomic_rmw(
6012 &mut self,
6013 atomic: &ir::AtomicExpr,
6014 object: TokenStream,
6015 op: ir::AtomicRmw,
6016 returns_new: bool,
6017 span: Span,
6018 ) -> Value {
6019 let class = atomic.class;
6020 let ty = atomic.value_ty;
6021 let success = self.ordering(atomic.success, span);
6022 let operand = self.temporary();
6023 let old = self.temporary();
6024 // A pointer moves by *bytes*: the scaling C11 wants for
6025 // `atomic_fetch_add` is already in the operand, put there by sema.
6026 if class == AtomicClass::Ptr {
6027 let delta = match &atomic.value {
6028 Some(value) => self.expr(value).at(prec::CAST, span),
6029 None => quote_spanned! {span=> 0 },
6030 };
6031 let isize_ty = primitive_ty("isize", span);
6032 let signed = if op == ir::AtomicRmw::Sub {
6033 quote_spanned! {span=> -(#delta as #isize_ty) }
6034 } else {
6035 quote_spanned! {span=> #delta as #isize_ty }
6036 };
6037 let step = self.temporary();
6038 let updated = self.atomic_cas_loop(
6039 &object,
6040 &step,
6041 quote_spanned! {span=> #step.wrapping_byte_offset(#operand) },
6042 atomic.success,
6043 span,
6044 );
6045 let tail = if returns_new {
6046 quote_spanned! {span=> #old.wrapping_byte_offset(#operand) }
6047 } else {
6048 quote_spanned! {span=> #old }
6049 };
6050 let tail = self
6051 .repr_to_value(class, ty, tail, span)
6052 .at(prec::LOWEST, span);
6053 return Value::new(
6054 quote_spanned! {span=>
6055 {
6056 let #operand: #isize_ty = #signed;
6057 let #old = #updated;
6058 #tail
6059 }
6060 },
6061 prec::BLOCK,
6062 );
6063 }
6064 let value = self.atomic_operand(atomic, span);
6065 let repr = self.atomic_repr_ty(class, span);
6066 // `fetch_nand` exists for `AtomicBool` and for nothing else, so an
6067 // integer nand is the compare-exchange loop Rust would have written.
6068 let update = match op.rust_method() {
6069 Some(method) if op != ir::AtomicRmw::Nand || class == AtomicClass::Bool => {
6070 let method = Ident::new(method, span);
6071 quote_spanned! {span=> #object.#method(#operand, #success) }
6072 }
6073 _ if class == AtomicClass::Bool => {
6074 let method = Ident::new("fetch_nand", span);
6075 quote_spanned! {span=> #object.#method(#operand, #success) }
6076 }
6077 _ => {
6078 let current = self.temporary();
6079 self.atomic_cas_loop(
6080 &object,
6081 ¤t,
6082 quote_spanned! {span=> !(#current & #operand) },
6083 atomic.success,
6084 span,
6085 )
6086 }
6087 };
6088 let combined = self.atomic_combine(op, &old, &operand, span);
6089 let tail = if returns_new {
6090 combined
6091 } else {
6092 quote_spanned! {span=> #old }
6093 };
6094 let tail = self
6095 .repr_to_value(class, ty, tail, span)
6096 .at(prec::LOWEST, span);
6097 Value::new(
6098 quote_spanned! {span=>
6099 {
6100 let #operand: #repr = #value;
6101 let #old = #update;
6102 #tail
6103 }
6104 },
6105 prec::BLOCK,
6106 )
6107 }
6108
6109 /// The read-modify-write an `x += v`, `x++` or `--x` on an `_Atomic`
6110 /// object performs.
6111 ///
6112 /// C11 6.5.16.2p3 and 6.5.2.4p2 make each of them *one* atomic
6113 /// read-modify-write, not a load and a store, so none of them may go
6114 /// through [`Codegen::read`] and [`Codegen::write`]. The five operators an
6115 /// atomic has a method for become that method; everything else — `*=`,
6116 /// `<<=`, a floating object, a pointer that moves by elements — becomes
6117 /// the `fetch_update` loop the method would have been.
6118 ///
6119 /// The right operand is always evaluated into a temporary first: the
6120 /// update is written twice when the value of the expression is the new
6121 /// one, and C evaluates it once.
6122 fn atomic_place_rmw(
6123 &mut self,
6124 lowered: &LoweredPlace,
6125 kind: PlaceRmw<'_>,
6126 want: RmwValue,
6127 span: Span,
6128 ) -> TokenStream {
6129 let (class, ty) = lowered.atomic.expect("an atomic place");
6130 let object = self.atomic_object_of(lowered, span);
6131 let setup = &lowered.setup;
6132 let operand = self.temporary();
6133 let old = self.temporary();
6134 let success = self.ordering(ir::MemOrder::SeqCst, span);
6135 // The one shape that is a plain `fetch_*`: an integer object whose
6136 // operator is one of the five, computed in the object's own type, so
6137 // that no widening happens between the read and the write.
6138 let method = match (class, &kind) {
6139 (
6140 AtomicClass::Int { .. },
6141 PlaceRmw::Compound {
6142 op,
6143 compute,
6144 value: _,
6145 },
6146 ) if *compute == ty => rmw_of_binop(*op),
6147 (AtomicClass::Int { .. }, PlaceRmw::Step { dec }) => Some(if *dec {
6148 ir::AtomicRmw::Sub
6149 } else {
6150 ir::AtomicRmw::Add
6151 }),
6152 _ => None,
6153 };
6154 if let Some(op) = method.filter(|op| op.rust_method().is_some()) {
6155 let repr = self.atomic_repr_ty(class, span);
6156 let value = match &kind {
6157 PlaceRmw::Compound { value, compute, .. } => {
6158 let tokens = self.expr_at(value, *compute);
6159 self.value_to_repr(class, ty, Value::new(tokens, prec::LOWEST), span)
6160 }
6161 PlaceRmw::Step { .. } => quote_spanned! {span=> 1 },
6162 };
6163 let name = Ident::new(op.rust_method().expect("filtered"), span);
6164 let tail = self.atomic_rmw_tail((class, ty), op, &old, &operand, want, span);
6165 return quote_spanned! {span=>
6166 { #setup
6167 let #operand: #repr = #value;
6168 let #old = #object.#name(#operand, #success);
6169 #tail }
6170 };
6171 }
6172 // The general form: a compare-exchange loop over the very expression
6173 // an ordinary compound assignment would have stored.
6174 let hoisted = match &kind {
6175 PlaceRmw::Compound { value, compute, .. } => {
6176 let tokens = self.expr_at(value, *compute);
6177 let rhs_ty = self.ty(*compute, span);
6178 Some(quote_spanned! {span=> let #operand: #rhs_ty = #tokens; })
6179 }
6180 PlaceRmw::Step { .. } => None,
6181 };
6182 let param = self.temporary();
6183 let current = self.repr_to_value(class, ty, quote_spanned! {span=> #param }, span);
6184 let updated = self.apply_place_rmw(&kind, current, ty, &operand, span);
6185 let updated = self.value_to_repr(class, ty, updated, span);
6186 let loop_result =
6187 self.atomic_cas_loop(&object, ¶m, updated, ir::MemOrder::SeqCst, span);
6188 let tail = match want {
6189 RmwValue::None => TokenStream::new(),
6190 RmwValue::Old => self
6191 .repr_to_value(class, ty, quote_spanned! {span=> #old }, span)
6192 .at(prec::LOWEST, span),
6193 RmwValue::New => {
6194 let previous = self.repr_to_value(class, ty, quote_spanned! {span=> #old }, span);
6195 let value = self.apply_place_rmw(&kind, previous, ty, &operand, span);
6196 value.at(prec::LOWEST, span)
6197 }
6198 };
6199 quote_spanned! {span=>
6200 { #setup #hoisted
6201 let #old = #loop_result;
6202 #tail }
6203 }
6204 }
6205
6206 /// The new value of an atomic place, from the old one.
6207 fn apply_place_rmw(
6208 &mut self,
6209 kind: &PlaceRmw<'_>,
6210 current: Value,
6211 ty: Ty,
6212 operand: &Ident,
6213 span: Span,
6214 ) -> Value {
6215 match kind {
6216 PlaceRmw::Compound { op, value, compute } => {
6217 let rhs = Value::atom(quote_spanned! {span=> #operand });
6218 self.compound_value(current, ty, *op, value, Some(rhs), *compute)
6219 }
6220 PlaceRmw::Step { dec } => {
6221 Value::new(self.step_value(current, ty, *dec, span), prec::LOWEST)
6222 }
6223 }
6224 }
6225
6226 /// The value a `fetch_*` on a place ends with: nothing, the old value or
6227 /// the new one.
6228 ///
6229 /// `atomic` is the place's [class](AtomicClass) and the C type behind it,
6230 /// which is what the value the atomic returned is converted back to.
6231 fn atomic_rmw_tail(
6232 &mut self,
6233 atomic: (AtomicClass, Ty),
6234 op: ir::AtomicRmw,
6235 old: &Ident,
6236 operand: &Ident,
6237 want: RmwValue,
6238 span: Span,
6239 ) -> TokenStream {
6240 let (class, ty) = atomic;
6241 let value = match want {
6242 RmwValue::None => return TokenStream::new(),
6243 RmwValue::Old => quote_spanned! {span=> #old },
6244 RmwValue::New => self.atomic_combine(op, old, operand, span),
6245 };
6246 self.repr_to_value(class, ty, value, span)
6247 .at(prec::LOWEST, span)
6248 }
6249
6250 /// The new value a `…_fetch` form answers with, computed from the old one
6251 /// the atomic returned and the operand.
6252 fn atomic_combine(
6253 &self,
6254 op: ir::AtomicRmw,
6255 old: &Ident,
6256 operand: &Ident,
6257 span: Span,
6258 ) -> TokenStream {
6259 match op {
6260 // Wrapping, because C's atomic arithmetic is modular even for the
6261 // signed types — the atomic instruction has no other behaviour.
6262 ir::AtomicRmw::Add => quote_spanned! {span=> #old.wrapping_add(#operand) },
6263 ir::AtomicRmw::Sub => quote_spanned! {span=> #old.wrapping_sub(#operand) },
6264 ir::AtomicRmw::And => quote_spanned! {span=> (#old & #operand) },
6265 ir::AtomicRmw::Or => quote_spanned! {span=> (#old | #operand) },
6266 ir::AtomicRmw::Xor => quote_spanned! {span=> (#old ^ #operand) },
6267 ir::AtomicRmw::Nand => quote_spanned! {span=> !(#old & #operand) },
6268 }
6269 }
6270
6271 /// The operand of a bit-manipulation builtin, as the unsigned integer of
6272 /// its own width.
6273 fn unsigned_operand(&mut self, arg: &Expr, span: Span) -> TokenStream {
6274 let width = arg.ty.bits(&self.options.target);
6275 let target = unsigned_rust_ty(width, span);
6276 let value = self.expr(arg).at(prec::CAST, span);
6277 parenthesize(quote_spanned! {span=> #value as #target }, span)
6278 }
6279
6280 /// `__builtin_add_overflow(a, b, &r)` and its relatives.
6281 ///
6282 /// The arithmetic happens in an `i128`, which is what "infinite precision"
6283 /// comes to while both operands are at most 64 bits wide — sema refuses a
6284 /// wider one. The *result* type may still be 128 bits, and that is the one
6285 /// thing that changes how the answer is checked: the general test asks
6286 /// whether the narrowed value converts back to what infinite precision
6287 /// gave, and a 128-bit conversion is a reinterpretation that always does.
6288 /// A signed 128-bit result therefore never overflows, and an unsigned one
6289 /// overflows exactly when the exact answer was negative.
6290 fn overflow_builtin(
6291 &mut self,
6292 op: BinOp,
6293 args: &[Expr],
6294 store: bool,
6295 result_ty: Ty,
6296 span: Span,
6297 ) -> Value {
6298 let method = match op {
6299 BinOp::Add => "wrapping_add",
6300 BinOp::Sub => "wrapping_sub",
6301 _ => "wrapping_mul",
6302 };
6303 let method = Ident::new(method, span);
6304 let checked = match op {
6305 BinOp::Add => "checked_add",
6306 BinOp::Sub => "checked_sub",
6307 _ => "checked_mul",
6308 };
6309 let checked = Ident::new(checked, span);
6310 let lhs = self.expr(&args[0]).at(prec::CAST, span);
6311 let rhs = self.expr(&args[1]).at(prec::CAST, span);
6312 let target = self.ty(result_ty, span);
6313 let a = self.temporary();
6314 let b = self.temporary();
6315 let wide = self.temporary();
6316 let narrow = self.temporary();
6317 // Pathed, because `typedef __int128 i128;` is a name a C unit may take.
6318 let i128 = primitive_ty("i128", span);
6319 let compute = quote_spanned! {span=>
6320 let #a: #i128 = #lhs as #i128;
6321 let #b: #i128 = #rhs as #i128;
6322 let #wide: #i128 = #a.#method(#b);
6323 let #narrow: #target = #wide as #target;
6324 };
6325 // The value overflows exactly when the wrapped result no longer equals
6326 // what infinite precision gave — and `i128` itself can only overflow
6327 // on a multiplication, where the answer is certainly out of range.
6328 let fits = match result_ty {
6329 // Both 128-bit conversions are reinterpretations, so the general
6330 // test below is vacuous there; what is left is the sign.
6331 Ty::Int128 => quote_spanned! {span=> false },
6332 Ty::UInt128 => quote_spanned! {span=> #wide < 0 },
6333 _ => quote_spanned! {span=> (#narrow as #i128) != #wide },
6334 };
6335 let flag = quote_spanned! {span=>
6336 #a.#checked(#b).is_none() || #fits
6337 };
6338 if !store {
6339 // The `_p` forms still evaluate their third operand.
6340 let third = self.expr_stmt(&args[2]);
6341 return Value::new(
6342 quote_spanned! {span=> { #third #compute #flag } },
6343 prec::BLOCK,
6344 );
6345 }
6346 let place = self.expr(&args[2]).at(prec::CALL, span);
6347 let out = self.temporary();
6348 Value::new(
6349 quote_spanned! {span=>
6350 { #compute let #out = #place; *#out = #narrow; #flag }
6351 },
6352 prec::BLOCK,
6353 )
6354 }
6355
6356 /// `va_arg(ap, T)`: reads the next argument and advances the list.
6357 ///
6358 /// `VaArgSafe` — the bound `next_arg` needs — is implemented for the
6359 /// primitives the `core::ffi` aliases stand for, so the C type can be
6360 /// asked for by name. A function pointer is the exception: `Option<fn>` is
6361 /// not one of them, so the argument is read as a `void *` and transmuted,
6362 /// which is what it is.
6363 ///
6364 /// A `struct` or a `union` is not a primitive at all, and is rebuilt from
6365 /// the registers the ABI passed it in — one `next_arg` per
6366 /// [eightbyte](ir::Eightbyte), which `sema` has already classified. The
6367 /// words are gathered into a `[u64; N]`, whose bytes are exactly the
6368 /// object's, and read back out of it: `read_unaligned` rather than a
6369 /// `transmute`, because the record may be *shorter* than the words that
6370 /// carried it — `struct { char x[13]; }` arrives in two of them — and
6371 /// because `[u64; N]` is eight-byte aligned while a record holding an
6372 /// `__int128` wants sixteen.
6373 fn va_arg(
6374 &mut self,
6375 ap: &Place,
6376 record: Option<&[ir::Eightbyte]>,
6377 ty: Ty,
6378 span: Span,
6379 ) -> Value {
6380 let access = self.place(ap, true).access;
6381 if let Some(classes) = record {
6382 let target = self.ty(ty, span);
6383 let u64_ty = primitive_ty("u64", span);
6384 let f64_ty = primitive_ty("f64", span);
6385 let words = classes.iter().map(|class| match class {
6386 ir::Eightbyte::Int => quote_spanned! {span=> #access.next_arg::<#u64_ty>() },
6387 ir::Eightbyte::Sse => {
6388 quote_spanned! {span=> #access.next_arg::<#f64_ty>().to_bits() }
6389 }
6390 // The ABI passes an eightbyte nothing reaches in no register,
6391 // so there is nothing to read and nothing the record can see.
6392 ir::Eightbyte::None => quote_spanned! {span=> 0 },
6393 });
6394 let count = Literal::usize_unsuffixed(classes.len());
6395 let value = self.temporary();
6396 return Value::new(
6397 quote_spanned! {span=>
6398 {
6399 let #value: [#u64_ty; #count] = [#(#words),*];
6400 ::core::ptr::read_unaligned(#value.as_ptr().cast::<#target>())
6401 }
6402 },
6403 prec::BLOCK,
6404 );
6405 }
6406 if self.program.types.is_func_pointer(ty) {
6407 let target = self.ty(ty, span);
6408 let void = self.pointee_ty(Ty::Void, span);
6409 return Value::new(
6410 quote_spanned! {span=>
6411 ::core::mem::transmute::<*mut #void, #target>(
6412 #access.next_arg::<*mut #void>()
6413 )
6414 },
6415 prec::CALL,
6416 );
6417 }
6418 let target = self.ty(ty, span);
6419 Value::new(
6420 quote_spanned! {span=> #access.next_arg::<#target>() },
6421 prec::CALL,
6422 )
6423 }
6424
6425 /// The argument of `offset`, which is always an `isize`.
6426 /// How far one element of a variably modified pointee is, in units of the
6427 /// [step type](ir::Types::vm_step_ty) the generated pointer points at.
6428 ///
6429 /// `double (*p)[m]` is a `*mut c_double` in the expansion, so `p + 1` has
6430 /// to move by `m` of them, and `double (*p)[n][3]` by `n` of the `[f64; 3]`
6431 /// it points at. Everything C says about such a pointer follows from
6432 /// scaling every offset by this product; `None` is the ordinary case,
6433 /// where Rust's own pointer arithmetic already has the right stride.
6434 fn vm_scale(&self, pointee: Ty, span: Span) -> Option<TokenStream> {
6435 if !self.program.types.is_vm(pointee) {
6436 return None;
6437 }
6438 let isize_ty = primitive_ty("isize", span);
6439 let mut product: Option<TokenStream> = None;
6440 for dim in self.program.types.vm_dims(pointee).iter().rev() {
6441 let factor = match dim {
6442 ir::VmDim::Fixed(len) => {
6443 let literal = Literal::isize_unsuffixed(*len as isize);
6444 quote_spanned! {span=> #literal }
6445 }
6446 ir::VmDim::Len(id) => {
6447 let name = self.object_ident(*id, span);
6448 quote_spanned! {span=> #name as #isize_ty }
6449 }
6450 // Sema refuses every expression that would need a bound it
6451 // never evaluated, so nothing reaches here.
6452 ir::VmDim::Unknown => quote_spanned! {span=> 1 },
6453 };
6454 product = Some(match product {
6455 None => factor,
6456 Some(left) => quote_spanned! {span=> (#left).wrapping_mul(#factor) },
6457 });
6458 }
6459 product
6460 }
6461
6462 /// An offset in elements, scaled for a [variably
6463 /// modified](Codegen::vm_scale) pointee.
6464 fn scaled_offset(&mut self, pointee: Ty, index: &Expr, sub: bool, span: Span) -> TokenStream {
6465 let Some(scale) = self.vm_scale(pointee, span) else {
6466 return self.offset_argument(index, sub, span);
6467 };
6468 let isize_ty = primitive_ty("isize", span);
6469 // A constant subscript comes out of `offset_argument` as a bare
6470 // literal, whose type `wrapping_mul` would have nothing to infer from.
6471 let offset = match &index.kind {
6472 ExprKind::Int(value) => {
6473 let value = if sub { -*value } else { *value };
6474 let literal = int_literal_token(value, span);
6475 quote_spanned! {span=> (#literal as #isize_ty) }
6476 }
6477 _ => {
6478 let inner = self.offset_argument(index, sub, span);
6479 quote_spanned! {span=> (#inner) }
6480 }
6481 };
6482 quote_spanned! {span=> #offset.wrapping_mul(#scale) }
6483 }
6484
6485 fn offset_argument(&mut self, index: &Expr, sub: bool, span: Span) -> TokenStream {
6486 if let ExprKind::Int(value) = &index.kind {
6487 let value = if sub { value.wrapping_neg() } else { *value };
6488 let literal = int_literal_token(value, span);
6489 // A small literal is left bare, and Rust infers the `isize`
6490 // `offset` wants. A larger one carries a suffix of its own —
6491 // `u64`, or `i128` — which is then the wrong type rather than an
6492 // open one, so it is converted. (`int a[2]; a[1L << 40]` is
6493 // undefined in C, and this is what `as` makes of it.)
6494 if value.unsigned_abs() > UNSUFFIXED_LIMIT as u128 {
6495 let isize_ty = primitive_ty("isize", span);
6496 return quote_spanned! {span=> (#literal as #isize_ty) };
6497 }
6498 return literal;
6499 }
6500 let tokens = self.expr(index).at(prec::CAST, span);
6501 let isize_ty = primitive_ty("isize", span);
6502 if sub {
6503 quote_spanned! {span=> -(#tokens as #isize_ty) }
6504 } else {
6505 quote_spanned! {span=> #tokens as #isize_ty }
6506 }
6507 }
6508
6509 fn call(&mut self, callee: &Callee, args: &[Expr], span: Span) -> Value {
6510 // An [x86 intrinsic](crate::x86) is not a symbol: the call is the
6511 // function of the same name in `core::arch`, with the immediate
6512 // operands moved into a turbofish.
6513 if let Callee::Direct(id) = callee
6514 && let Some(intr) = self.program.function(*id).intrinsic
6515 {
6516 return self.intrinsic_call(intr, *id, args, span);
6517 }
6518 let sig = self.callee_signature(callee);
6519 // A call through a function type with *no prototype* passes as many
6520 // arguments as it was given, each with the default argument promotions
6521 // applied, and the callee reads them as though the prototype had said
6522 // so (C99 6.5.2.2p6). Rust has no such call, so the reinterpretation is
6523 // written out: the callee is transmuted to the signature the promoted
6524 // arguments make, and that signature is called.
6525 //
6526 // It is the same contract C's own ABI relies on — the program is
6527 // defined only if the function really does take parameters of those
6528 // types, and undefined otherwise — and on every ABI this crate targets
6529 // a function pointer transmuted this way is the same address. Sema has
6530 // already applied the promotions, so `arg.ty` is the parameter type to
6531 // write.
6532 //
6533 // The argument *types* are compared as well as their number, because a
6534 // declaration with no prototype may be completed by a definition that
6535 // has one after the call was written: `int *h(); … h(j(), n); … int
6536 // *h(unsigned, int) { … }` — `execute/pr103209` — leaves the call
6537 // holding arguments the definition's parameters do not have. The call
6538 // was checked against the type in scope where it stands, which is the
6539 // one with no prototype, so the reinterpretation is what C says
6540 // happens there too. Where the prototype *was* in scope, sema has
6541 // already converted every argument to its parameter's type and the
6542 // comparison is an equality that holds.
6543 let reinterpreted = !sig.variadic
6544 && (args.len() != sig.params.len()
6545 || args.iter().zip(&sig.params).any(|(arg, param)| {
6546 arg.ty != *param && !arg.ty.is_error() && !param.is_error()
6547 }));
6548 let promoted: Vec<Ty> = if reinterpreted {
6549 args.iter().map(|arg| arg.ty).collect()
6550 } else {
6551 Vec::new()
6552 };
6553 let params = if reinterpreted {
6554 &promoted
6555 } else {
6556 &sig.params
6557 };
6558
6559 let mut target = match callee {
6560 Callee::Direct(id) => {
6561 let function = self.program.function(*id);
6562 let path = self.function_path(function, span);
6563 if reinterpreted {
6564 // A function *item* is not a function pointer, so the `as`
6565 // coercion has to be written before it can be transmuted.
6566 let source = self.function_pointer_ty(function, span);
6567 parenthesize(quote_spanned! {span=> #path as #source }, span)
6568 } else {
6569 path
6570 }
6571 }
6572 Callee::Indirect(expr) => {
6573 let value = self.expr(expr).at(prec::CALL, span);
6574 // C's function pointers may be null and Rust's may not, so the
6575 // `Option` has to come off before the call.
6576 parenthesize(
6577 quote_spanned! {span=> #value.expect("null function pointer") },
6578 span,
6579 )
6580 }
6581 };
6582 if reinterpreted {
6583 let source = self.fn_ptr_ty(&sig.params, sig.variadic, sig.ret, span);
6584 let wanted = self.fn_ptr_ty(params, false, sig.ret, span);
6585 target = parenthesize(
6586 quote_spanned! {span=>
6587 ::core::mem::transmute::<#source, #wanted>(#target)
6588 },
6589 span,
6590 );
6591 }
6592
6593 // A lifted nested function's hidden arguments come first, and one
6594 // written argument after them needs the comma the loop would only put
6595 // between two of its own.
6596 let mut tokens = self.env_arguments(callee, span);
6597 let hidden = !tokens.is_empty();
6598 for (index, arg) in args.iter().enumerate() {
6599 if index > 0 || hidden {
6600 tokens.extend(quote_spanned! {span=> , });
6601 }
6602 match params.get(index) {
6603 // A parameter's type is what the argument is written at, so a
6604 // constant needs no `as`.
6605 Some(expected) => tokens.extend(self.expr_at(arg, *expected)),
6606 // An argument matched by `...` has no parameter to take its
6607 // type from, and Rust gives an unsuffixed literal in that
6608 // position `i32` (or `f64`), whatever C says it is: `%ld` with
6609 // a bare `-1` would read four bytes of an eight-byte
6610 // argument. The type has to be written out.
6611 None => {
6612 let arg_span = self.sp(arg.range);
6613 tokens.extend(self.expr(arg).at(prec::LOWEST, arg_span));
6614 }
6615 }
6616 }
6617 let call = parenthesize(tokens, span);
6618 Value::new(quote_spanned! {span=> #target #call }, prec::CALL)
6619 }
6620
6621 /// A call to an x86 intrinsic: `::core::arch::x86_64::_mm_slli_epi32::<{
6622 /// 3i32 }>(v)`.
6623 ///
6624 /// Everything about it lines up by construction — the bundled header's
6625 /// prototype was generated from the very signature `rustc` will check the
6626 /// call against — so there is none of the reinterpreting an ordinary call
6627 /// may need. Two things are not a plain transliteration:
6628 ///
6629 /// * the operands Intel requires to be integer constant expressions are
6630 /// `const` generics in `core::arch`, so they move out of the argument
6631 /// list into a turbofish. Sema has already folded each one to an
6632 /// [`ExprKind::Int`] and reported the ones it could not (see
6633 /// [`crate::x86::Intrinsic::imm`]);
6634 /// * the literal carries the `const` parameter's own type, and is wrapped
6635 /// in a block, so that a negative value is still a const argument Rust
6636 /// parses;
6637 /// * a pointer argument is cast with `as *const _` or `as *mut _` (see
6638 /// [`Codegen::intrinsic_pointer_arg`]), because the header spells a
6639 /// memory operand `void *` where GCC's does and `core::arch` types it.
6640 fn intrinsic_call(
6641 &mut self,
6642 intr: &'static crate::x86::Intrinsic,
6643 id: ir::FuncId,
6644 args: &[Expr],
6645 span: Span,
6646 ) -> Value {
6647 let module = self.arch_module(span);
6648 let name = Ident::new(intr.name, span);
6649 let mut generics = TokenStream::new();
6650 for (index, imm) in intr.imm.iter().enumerate() {
6651 if index > 0 {
6652 generics.extend(quote_spanned! {span=> , });
6653 }
6654 let value = match args.get(usize::from(imm.index)).map(|arg| &arg.kind) {
6655 Some(ExprKind::Int(value)) => *value,
6656 // Unreachable: sema folds every immediate and reports the ones
6657 // it cannot, and a unit with an error generates stubs rather
6658 // than this. A zero keeps the expansion parseable.
6659 _ => 0,
6660 };
6661 let literal = suffixed_int_literal(value, imm.rust_ty, span);
6662 generics.extend(quote_spanned! {span=> { #literal } });
6663 }
6664 let turbofish = if generics.is_empty() {
6665 TokenStream::new()
6666 } else {
6667 quote_spanned! {span=> ::<#generics> }
6668 };
6669
6670 let mut tokens = TokenStream::new();
6671 let mut written = 0usize;
6672 for (index, arg) in args.iter().enumerate() {
6673 if intr.immediate_at(index).is_some() {
6674 continue;
6675 }
6676 if written > 0 {
6677 tokens.extend(quote_spanned! {span=> , });
6678 }
6679 written += 1;
6680 let param = self.program.function(id).sig.params.get(index).copied();
6681 match param.and_then(|ty| self.intrinsic_pointer_arg(ty, span)) {
6682 Some(cast) => {
6683 let value = self.expr(arg).at(prec::CAST, span);
6684 tokens.extend(quote_spanned! {span=> #value #cast });
6685 }
6686 None => tokens.extend(self.expr_at(arg, arg.ty)),
6687 }
6688 }
6689 let call = parenthesize(tokens, span);
6690 Value::new(
6691 quote_spanned! {span=> ::core::arch::#module::#name #turbofish #call },
6692 prec::CALL,
6693 )
6694 }
6695
6696 /// The cast an intrinsic's pointer argument gets: `as *const _` when the
6697 /// C parameter points at `const`, `as *mut _` otherwise, and `None` for a
6698 /// parameter that is not a pointer.
6699 ///
6700 /// The header declares a memory operand `void *` wherever GCC's does, so
6701 /// that `_mm512_loadu_si512(p)` takes an `int *` as it does in GCC, while
6702 /// `core::arch` types it (`*const __m512i`); rustc infers the `_` from
6703 /// that. Every pointer parameter gets the cast, typed or not — for a
6704 /// typed one it is the identity, and one rule is simpler to state.
6705 fn intrinsic_pointer_arg(&self, param: Ty, span: Span) -> Option<TokenStream> {
6706 let Ty::Pointer(pointer) = param else {
6707 return None;
6708 };
6709 Some(if self.program.types.pointer_type(pointer).konst {
6710 quote_spanned! {span=> as *const _ }
6711 } else {
6712 quote_spanned! {span=> as *mut _ }
6713 })
6714 }
6715
6716 /// The hidden arguments a call to a lifted nested function opens with.
6717 ///
6718 /// Each one is the address of the object the callee wants: the enclosing
6719 /// function passes `&raw mut x` for a local of its own, and a function
6720 /// that was itself passed the pointer passes that on. Nothing else has a
6721 /// hidden argument, so this is empty for every ordinary call.
6722 fn env_arguments(&self, callee: &Callee, span: Span) -> TokenStream {
6723 let Callee::Direct(id) = callee else {
6724 return TokenStream::new();
6725 };
6726 let mut tokens = TokenStream::new();
6727 for (index, entry) in self.program.function(*id).env.iter().enumerate() {
6728 if index > 0 {
6729 tokens.extend(quote_spanned! {span=> , });
6730 }
6731 match self.env.get(&entry.owner) {
6732 // The caller was handed the pointer itself; it passes it on.
6733 Some(param) => {
6734 let name = self.object_ident(*param, span);
6735 tokens.extend(quote_spanned! {span=> #name });
6736 }
6737 // The object is the caller's own.
6738 None => {
6739 let object = self.program.object(entry.owner);
6740 let name = self.object_access(entry.owner, span);
6741 tokens.extend(if object.is_const {
6742 quote_spanned! {span=> &raw const #name }
6743 } else {
6744 quote_spanned! {span=> &raw mut #name }
6745 });
6746 }
6747 }
6748 }
6749 tokens
6750 }
6751
6752 /// The signature a call goes through: the callee's own for a direct call,
6753 /// and the pointed-to function type for an indirect one.
6754 fn callee_signature(&self, callee: &Callee) -> ir::Signature {
6755 match callee {
6756 Callee::Direct(id) => self.program.function(*id).sig.clone(),
6757 Callee::Indirect(expr) => match self.program.types.pointee(expr.ty) {
6758 Some(Ty::Func(id)) => {
6759 let func = self.program.types.func_type(id);
6760 ir::Signature {
6761 ret: func.ret,
6762 params: func.params.clone(),
6763 variadic: func.variadic,
6764 prototyped: func.prototyped,
6765 }
6766 }
6767 // Only reachable on the error path, where a `compile_error!` is
6768 // already going out.
6769 _ => ir::Signature {
6770 ret: Ty::Void,
6771 params: Vec::new(),
6772 variadic: false,
6773 prototyped: true,
6774 },
6775 },
6776 }
6777 }
6778
6779 /// `unsafe extern "C" fn(P…) -> R`, written out from its pieces.
6780 fn fn_ptr_ty(&self, params: &[Ty], variadic: bool, ret: Ty, span: Span) -> TokenStream {
6781 let mut list = TokenStream::new();
6782 for (index, param) in params.iter().enumerate() {
6783 if index > 0 {
6784 list.extend(quote_spanned! {span=> , });
6785 }
6786 list.extend(self.ty(*param, span));
6787 }
6788 if variadic {
6789 if !params.is_empty() {
6790 list.extend(quote_spanned! {span=> , });
6791 }
6792 list.extend(quote_spanned! {span=> ... });
6793 }
6794 let list = parenthesize(list, span);
6795 let ret = if ret.is_void() {
6796 TokenStream::new()
6797 } else {
6798 let ty = self.ty(ret, span);
6799 quote_spanned! {span=> -> #ty }
6800 };
6801 quote_spanned! {span=> unsafe extern "C" fn #list #ret }
6802 }
6803
6804 /// The path a call to `function` uses.
6805 ///
6806 /// One name whether the unit defines the function or only declares it: the
6807 /// item in the `extern` block carries the C name as well (see
6808 /// [`Codegen::extern_block`]), and a lifted nested function carries the name
6809 /// it was lifted under.
6810 fn function_path(&self, function: &Function, span: Span) -> TokenStream {
6811 let name = self.c_ident(function.item_name(), span);
6812 quote_spanned! {span=> #name }
6813 }
6814
6815 /// `unsafe extern "C" fn(…) -> R` for a named function, which is what its
6816 /// address has to be cast to.
6817 fn function_pointer_ty(&self, function: &Function, span: Span) -> TokenStream {
6818 let sig = &function.sig;
6819 self.fn_ptr_ty(&sig.params, sig.variadic, sig.ret, span)
6820 }
6821
6822 /// Emits an expression as a Rust `bool`, the way C tests a scalar against
6823 /// zero.
6824 fn condition(&mut self, expr: &Expr) -> Value {
6825 let span = self.sp(expr.range);
6826 match &expr.kind {
6827 ExprKind::Compare { op, lhs, rhs } => {
6828 if let Some(value) = self.null_test(*op, lhs, rhs, span) {
6829 return value;
6830 }
6831 if lhs.ty.is_complex() && rhs.ty.is_complex() {
6832 return self.complex_equality(*op, lhs, rhs, span);
6833 }
6834 let (lhs, rhs) = self.operands(lhs, rhs, BinOp::BitOr);
6835 let left_min = if *op == CmpOp::Lt && lhs.ends_with_type {
6836 prec::CAST + 1
6837 } else {
6838 prec::CMP + 1
6839 };
6840 let ends_with_type = rhs.ends_with_type;
6841 let lhs = lhs.at(left_min, span);
6842 let rhs = rhs.at(prec::CMP + 1, span);
6843 let op = cmp_tokens(*op, span);
6844 Value::new(quote_spanned! {span=> #lhs #op #rhs }, prec::CMP)
6845 .type_end(ends_with_type)
6846 }
6847 ExprKind::Logical { .. } => self.logical_chain(expr),
6848 ExprKind::Int(value) => {
6849 let ident = Ident::new(if *value != 0 { "true" } else { "false" }, span);
6850 Value::atom(quote_spanned! {span=> #ident })
6851 }
6852 _ if expr.ty.is_bool() => self.expr(expr),
6853 _ if expr.ty.is_complex() => self.complex_condition(expr, span),
6854 _ if expr.ty.is_pointer() => self.not_null(expr, span),
6855 _ => {
6856 let ty = expr.ty;
6857 let value = self.expr(expr).at(prec::CMP + 1, span);
6858 let zero = self.zero_tokens(ty, span);
6859 Value::new(quote_spanned! {span=> #value != #zero }, prec::CMP)
6860 }
6861 }
6862 }
6863
6864 /// `p != NULL` reads better as `!p.is_null()`, and that is also the only
6865 /// form that works for a function pointer.
6866 fn null_test(&mut self, op: CmpOp, lhs: &Expr, rhs: &Expr, span: Span) -> Option<Value> {
6867 if !matches!(op, CmpOp::Eq | CmpOp::Ne) {
6868 return None;
6869 }
6870 let (pointer, _) = match (&lhs.kind, &rhs.kind) {
6871 (ExprKind::Zeroed, _) if rhs.ty.is_pointer() => (rhs, lhs),
6872 (_, ExprKind::Zeroed) if lhs.ty.is_pointer() => (lhs, rhs),
6873 _ => return None,
6874 };
6875 let test = self.is_null(pointer, span);
6876 if op == CmpOp::Eq {
6877 return Some(test);
6878 }
6879 let tokens = test.at(prec::UNARY, span);
6880 Some(Value::new(quote_spanned! {span=> !#tokens }, prec::UNARY))
6881 }
6882
6883 /// `p.is_null()`, or `{ p }.is_some()` for a function pointer.
6884 fn is_null(&mut self, expr: &Expr, span: Span) -> Value {
6885 if self.program.types.is_func_pointer(expr.ty) {
6886 let tokens = self.copied_receiver(expr, span);
6887 return Value::new(quote_spanned! {span=> #tokens.is_none() }, prec::CALL);
6888 }
6889 let tokens = self.expr(expr).at(prec::CALL, span);
6890 Value::new(quote_spanned! {span=> #tokens.is_null() }, prec::CALL)
6891 }
6892
6893 fn not_null(&mut self, expr: &Expr, span: Span) -> Value {
6894 if self.program.types.is_func_pointer(expr.ty) {
6895 let tokens = self.copied_receiver(expr, span);
6896 return Value::new(quote_spanned! {span=> #tokens.is_some() }, prec::CALL);
6897 }
6898 let tokens = self.expr(expr).at(prec::CALL, span);
6899 Value::new(quote_spanned! {span=> !#tokens.is_null() }, prec::UNARY)
6900 }
6901
6902 /// A receiver for a method that takes `&self`.
6903 ///
6904 /// `Option::is_some` borrows, and borrowing a `static mut` is an error in
6905 /// edition 2024; a block copies the value out first. Only a place that
6906 /// really is a `static mut` needs it, so an ordinary local keeps reading
6907 /// as one.
6908 fn copied_receiver(&mut self, expr: &Expr, span: Span) -> TokenStream {
6909 if self.reads_a_static(expr) {
6910 let tokens = self.expr(expr).at(prec::LOWEST, span);
6911 return braced(tokens, span);
6912 }
6913 self.expr(expr).at(prec::CALL, span)
6914 }
6915
6916 /// Whether an expression reads an object with static storage duration,
6917 /// which is what a shared reference may not be taken to.
6918 fn reads_a_static(&self, expr: &Expr) -> bool {
6919 let ExprKind::Load(place) = &expr.kind else {
6920 return false;
6921 };
6922 let mut place = place;
6923 loop {
6924 match &place.kind {
6925 PlaceKind::Object(id) => {
6926 let storage = &self.program.object(*id).storage;
6927 // A thread-local object is a `*mut T` out of its cell, so
6928 // it is behind a raw pointer like anything else below.
6929 return !matches!(storage, Storage::Automatic) && !storage.is_thread_local();
6930 }
6931 PlaceKind::Field { base, .. } => place = base,
6932 // Anything reached through a pointer is behind a raw pointer
6933 // already, so no reference to the static itself is created.
6934 _ => return false,
6935 }
6936 }
6937 }
6938
6939 /// Emits the operands of a binary operation.
6940 ///
6941 /// Both operands already have the result type, so a constant one can be
6942 /// left as a bare literal and take its Rust type from the other side —
6943 /// `n == 0` rather than `n == 0 as ::core::ffi::c_int`. That only works
6944 /// while the other side actually has a type to give, and never for the
6945 /// receiver of a method call, where a bare integer literal followed by a
6946 /// `.` would not survive being printed back out as text.
6947 fn operands(&mut self, lhs: &Expr, rhs: &Expr, op: BinOp) -> (Value, Value) {
6948 self.operands_with(None, lhs, rhs, op)
6949 }
6950
6951 /// [`Codegen::operands`] with the left operand possibly already emitted.
6952 ///
6953 /// `folded` is what [`Codegen::binary_chain`] has built so far. It is only
6954 /// ever a binary operation, and [`constant_of`] answers `None` for one, so
6955 /// the bare-literal reasoning below is unaffected by it.
6956 fn operands_with(
6957 &mut self,
6958 folded: Option<Value>,
6959 lhs: &Expr,
6960 rhs: &Expr,
6961 op: BinOp,
6962 ) -> (Value, Value) {
6963 let uses_method = matches!(
6964 op,
6965 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Shl | BinOp::Shr
6966 );
6967 let lhs_constant = constant_of(lhs);
6968 let rhs_constant = constant_of(rhs);
6969
6970 // At most one side may be bare, and it is never the left one where a
6971 // method call follows.
6972 let lhs_bare = lhs_constant.is_some() && !uses_method && rhs_constant.is_none();
6973 let lhs_value = match (folded, lhs_constant) {
6974 (Some(value), _) => value,
6975 (None, Some(value)) if lhs_bare => self.bare_value(value, lhs.ty, self.sp(lhs.range)),
6976 (None, _) => self.expr(lhs),
6977 };
6978 let rhs_value = match rhs_constant {
6979 // The shift amount is converted to `u32` whatever its C type is,
6980 // so a constant there never needs the other operand's help — and
6981 // it is reduced to *that* `u32` here rather than left as the C
6982 // value. Every count a program may legitimately write is under
6983 // the width and so unchanged; the ones that are not are undefined
6984 // in C, and writing them out as they stand is what `rustc`
6985 // refuses. A negative one is `-64 as u32`, which it reads as the
6986 // negation of a `u32` (`E0600`, `execute/pr98681`) even
6987 // parenthesised, and one above `u32::MAX` is a literal out of
6988 // range. `wrapping_shl` masks the count by the width, exactly as
6989 // the hardware does.
6990 Some(ConstValue::Int(value)) if op.is_shift() => self.bare_value(
6991 ConstValue::Int(i128::from(value as u32)),
6992 Ty::UInt,
6993 self.sp(rhs.range),
6994 ),
6995 Some(value) if op.is_shift() => self.bare_value(value, rhs.ty, self.sp(rhs.range)),
6996 Some(value) if !lhs_bare => self.bare_value(value, rhs.ty, self.sp(rhs.range)),
6997 _ => self.expr(rhs),
6998 };
6999 (lhs_value, rhs_value)
7000 }
7001
7002 /// A constant emitted without its `as`, for a context that will supply the
7003 /// type.
7004 fn bare_value(&mut self, value: ConstValue, ty: Ty, span: Span) -> Value {
7005 match value {
7006 ConstValue::Int(v) => {
7007 let tokens = bare_int_literal(v, ty, span);
7008 let mut out = Value::new(tokens, if v < 0 { prec::UNARY } else { prec::ATOM });
7009 out.bare_integer = v >= 0 && !ty.is_bool();
7010 out
7011 }
7012 ConstValue::Float(v) => Value::new(
7013 bare_float_literal(v, span),
7014 if v.is_sign_negative() {
7015 prec::UNARY
7016 } else {
7017 prec::ATOM
7018 },
7019 ),
7020 // A complex constant is never *bare*: it has to name its own type,
7021 // and [`constant_of`] answers `None` for one so that nothing asks.
7022 ConstValue::Complex(re, im) => {
7023 let re = bare_float_literal(re, span);
7024 let im = bare_float_literal(im, span);
7025 self.complex_new(ty, re, im, span)
7026 }
7027 }
7028 }
7029
7030 /// A chain of conditional operators, folded without recursing down it.
7031 ///
7032 /// `a ? b : c ? d : e` is right-associative, so unlike the chains
7033 /// [`Codegen::binary_chain`] handles this one really is nesting: what
7034 /// comes out is `if … { … } else { if … }`, one level per operator, and
7035 /// that is as it should be. What must not be one level per operator is
7036 /// the *walk*, which runs on the eight mebibytes `rustc` gives macro
7037 /// expansion.
7038 ///
7039 /// The condition and the `then` arm of each level are emitted on the way
7040 /// down and the tree is built on the way back up, which is the order the
7041 /// recursive walk had — so the tokens, and the numbering of any
7042 /// temporaries in them, are exactly what it produced.
7043 fn cond_chain(&mut self, expr: &Expr) -> Value {
7044 let mut spine = Vec::new();
7045 let mut node = expr;
7046 while let ExprKind::Cond {
7047 cond,
7048 then_expr,
7049 else_expr,
7050 } = &node.kind
7051 {
7052 let span = self.sp(node.range);
7053 let cond_tokens = self.condition(cond).at_condition(span);
7054 let then_tokens = self.expr(then_expr).at(prec::LOWEST, span);
7055 spine.push((cond_tokens, then_tokens, span));
7056 node = else_expr;
7057 }
7058 // The innermost `else` is parenthesised against the span of the
7059 // conditional it belongs to, which is the innermost one on the spine.
7060 let inner = spine
7061 .last()
7062 .map_or_else(|| self.sp(expr.range), |(_, _, span)| *span);
7063 let mut tokens = self.expr(node).at(prec::LOWEST, inner);
7064 while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
7065 tokens = quote_spanned! {span=>
7066 if #cond_tokens { #then_tokens } else { #tokens }
7067 };
7068 }
7069 Value::new(tokens, prec::BLOCK)
7070 }
7071
7072 /// [`Codegen::cond_chain`] where the surrounding context fixes the type.
7073 ///
7074 /// The chain ends wherever a level's own type is no longer `expected`,
7075 /// which is where [`Codegen::expr_at`] would have stopped treating the
7076 /// arms as bare anyway.
7077 fn cond_chain_at(&mut self, expr: &Expr, expected: Ty) -> TokenStream {
7078 let mut spine = Vec::new();
7079 let mut node = expr;
7080 while let ExprKind::Cond {
7081 cond,
7082 then_expr,
7083 else_expr,
7084 } = &node.kind
7085 {
7086 if node.ty != expected {
7087 break;
7088 }
7089 let span = self.sp(node.range);
7090 let cond_tokens = self.condition(cond).at_condition(span);
7091 let then_tokens = self.expr_at(then_expr, expected);
7092 spine.push((cond_tokens, then_tokens, span));
7093 node = else_expr;
7094 }
7095 let mut tokens = self.expr_at(node, expected);
7096 while let Some((cond_tokens, then_tokens, span)) = spine.pop() {
7097 tokens = quote_spanned! {span=>
7098 if #cond_tokens { #then_tokens } else { #tokens }
7099 };
7100 }
7101 tokens
7102 }
7103
7104 /// A chain of assignments, folded without recursing down it.
7105 ///
7106 /// `a = b = c` is right-associative, so this is nesting in the same way
7107 /// [`Codegen::cond_chain`] is, and the same bargain applies: the shape of
7108 /// the output is unchanged and only the walk is flattened. Each place is
7109 /// lowered on the way down — which is where the recursive walk lowered it,
7110 /// and therefore where it took any temporary it needed — and the blocks
7111 /// are built on the way back up, innermost first, exactly as the
7112 /// recursion unwound.
7113 fn assign_chain(&mut self, expr: &Expr) -> Value {
7114 let mut spine = Vec::new();
7115 let mut node = expr;
7116 while let ExprKind::Assign { place, value } = &node.kind {
7117 let span = self.sp(node.range);
7118 let lowered = self.place(place, true);
7119 spine.push((lowered, self.program.types.unatomic(place.ty), span));
7120 node = value;
7121 }
7122 let (_, innermost, _) = spine
7123 .last()
7124 .expect("assign_chain is only entered on an assignment");
7125 let mut tokens = self.expr_at(node, *innermost);
7126 while let Some((lowered, ty, span)) = spine.pop() {
7127 // The value of an assignment to an *atomic* object is the value
7128 // stored and not what the object holds afterwards: another thread
7129 // may have changed it already, and reading it back would be a
7130 // second atomic operation C never asked for.
7131 if lowered.atomic.is_some() {
7132 let tmp = self.temporary();
7133 let target = self.ty(ty, span);
7134 let store = self.write(&lowered, quote_spanned! {span=> #tmp }, span);
7135 let setup = &lowered.setup;
7136 tokens = quote_spanned! {span=>
7137 { #setup let #tmp: #target = #tokens; #store #tmp }
7138 };
7139 continue;
7140 }
7141 let store = self.write(&lowered, tokens, span);
7142 // The value of an assignment is the value stored, which for a
7143 // place is exactly what reading it back gives — including for a
7144 // bit-field, where reading back is what truncates.
7145 let read = self.read(&lowered, span).at(prec::LOWEST, span);
7146 let setup = &lowered.setup;
7147 tokens = quote_spanned! {span=> { #setup #store #read } };
7148 }
7149 Value::new(tokens, prec::BLOCK)
7150 }
7151
7152 /// A chain of binary operators, folded without recursing down it.
7153 ///
7154 /// `a + b + c + …` is left-associative, so the tree it leaves behind is
7155 /// one node per operand with the whole of the rest hanging off its left.
7156 /// Walking that recursively is one stack frame per operand — and code
7157 /// generation runs on the caller's thread, which is the eight mebibytes
7158 /// `rustc` gives macro expansion, where a chain of about eight hundred is
7159 /// a "fatal runtime error: stack overflow" with no diagnostic at all.
7160 ///
7161 /// C23 5.2.5.2p1 asks every implementation to accept a logical source
7162 /// line of 4095 characters, which is well past that, so the spine is
7163 /// collected into a vector and folded back up in a loop: one frame,
7164 /// however long the chain. The tokens that come out are the same ones the
7165 /// recursive walk produced, and in the same order — `a.wrapping_add(b)
7166 /// .wrapping_add(c)` is a receiver chain, which is *flat*, so neither is
7167 /// the output deeply nested.
7168 ///
7169 /// Nesting — `a + (b + (c + …))`, which is one level of parentheses per
7170 /// operand — still costs a frame per level, and is what
7171 /// `parse::MAX_RECURSION_DEPTH` bounds.
7172 fn binary_chain(&mut self, expr: &Expr) -> Value {
7173 let mut spine = vec![expr];
7174 let mut node = expr;
7175 while let ExprKind::Binary { lhs, .. } = &node.kind {
7176 node = lhs;
7177 if matches!(node.kind, ExprKind::Binary { .. }) {
7178 spine.push(node);
7179 }
7180 }
7181 let mut folded = None;
7182 while let Some(node) = spine.pop() {
7183 let ExprKind::Binary { op, lhs, rhs } = &node.kind else {
7184 unreachable!("the spine holds binary operations only");
7185 };
7186 let span = self.sp(node.range);
7187 let (lhs_value, rhs_value) = self.operands_with(folded, lhs, rhs, *op);
7188 let value = if node.ty.is_complex() {
7189 self.complex_binary(*op, (lhs_value, lhs.ty), (rhs_value, rhs.ty), node.ty, span)
7190 } else {
7191 self.binary(*op, lhs_value, rhs_value, node.ty, span)
7192 };
7193 folded = Some(self.reduce_bits(value, node));
7194 }
7195 folded.expect("the chain has at least the node it started from")
7196 }
7197
7198 /// A chain of `&&` or `||`, folded without recursing down it.
7199 ///
7200 /// The same shape and the same reason as [`Codegen::binary_chain`]; these
7201 /// live on the `bool` side of code generation, so the fold is over
7202 /// [`Codegen::condition`] rather than over `expr`.
7203 fn logical_chain(&mut self, expr: &Expr) -> Value {
7204 let mut spine = vec![expr];
7205 let mut node = expr;
7206 while let ExprKind::Logical { lhs, .. } = &node.kind {
7207 node = lhs;
7208 if matches!(node.kind, ExprKind::Logical { .. }) {
7209 spine.push(node);
7210 }
7211 }
7212 // `node` is now the innermost left operand, which is not itself a
7213 // logical operator; emitting it first keeps the order the recursive
7214 // walk had, which is source order.
7215 let mut folded = self.condition(node);
7216 while let Some(node) = spine.pop() {
7217 let ExprKind::Logical { op, rhs, .. } = &node.kind else {
7218 unreachable!("the spine holds logical operations only");
7219 };
7220 let span = self.sp(node.range);
7221 let (level, tokens) = match op {
7222 LogicalOp::And => (prec::AND, quote_spanned! {span=> && }),
7223 LogicalOp::Or => (prec::OR, quote_spanned! {span=> || }),
7224 };
7225 let mut out = folded.at(level, span);
7226 let rhs = self.condition(rhs);
7227 let ends_with_type = rhs.ends_with_type;
7228 let rhs = rhs.at(level + 1, span);
7229 out.extend(quote_spanned! {span=> #tokens #rhs });
7230 folded = Value::new(out, level).type_end(ends_with_type);
7231 }
7232 folded
7233 }
7234
7235 fn binary(&mut self, op: BinOp, lhs: Value, rhs: Value, ty: Ty, span: Span) -> Value {
7236 if ty.is_floating() {
7237 let (level, tokens) = match op {
7238 BinOp::Add => (prec::SUM, quote_spanned! {span=> + }),
7239 BinOp::Sub => (prec::SUM, quote_spanned! {span=> - }),
7240 BinOp::Mul => (prec::PRODUCT, quote_spanned! {span=> * }),
7241 BinOp::Div => (prec::PRODUCT, quote_spanned! {span=> / }),
7242 // Sema rejects every other operator on floating operands.
7243 _ => (prec::PRODUCT, quote_spanned! {span=> % }),
7244 };
7245 let ends_with_type = rhs.ends_with_type;
7246 let mut out = lhs.at(level, span);
7247 let rhs = rhs.at(level + 1, span);
7248 // Appended in place rather than built into a fresh stream around
7249 // the left operand: a chain of a thousand would otherwise copy
7250 // the whole of it a thousand times over. See
7251 // [`Codegen::binary_chain`].
7252 out.extend(quote_spanned! {span=> #tokens #rhs });
7253 return Value::new(out, level).type_end(ends_with_type);
7254 }
7255
7256 // `+`, `-`, `*` and the shifts go through the wrapping methods:
7257 // unsigned wrap-around is defined in C, and while signed overflow is
7258 // undefined, wrapping is far more predictable than a panic in the
7259 // middle of translated code.
7260 let method = match op {
7261 BinOp::Add => Some("wrapping_add"),
7262 BinOp::Sub => Some("wrapping_sub"),
7263 BinOp::Mul => Some("wrapping_mul"),
7264 BinOp::Shl => Some("wrapping_shl"),
7265 BinOp::Shr => Some("wrapping_shr"),
7266 _ => None,
7267 };
7268 if let Some(method) = method {
7269 let mut receiver = lhs.at(prec::CALL, span);
7270 let method = Ident::new(method, span);
7271 let argument = if op.is_shift() && !rhs.bare_integer {
7272 // `wrapping_shl` takes the shift amount as a `u32` whatever the
7273 // shifted type is; a bare literal simply is one already.
7274 let amount = rhs.at(prec::CAST, span);
7275 // Belt and braces: nothing that reaches here opens with a
7276 // unary minus — a constant count was reduced to its `u32` in
7277 // [`Codegen::operands_with`] and `-x` is written
7278 // `x.wrapping_neg()` — and if one ever did, `rustc` would read
7279 // `-e as u32` as the negation of a `u32` and refuse it
7280 // (`E0600`) however it is bracketed by precedence.
7281 let amount = if starts_with_minus(&amount) {
7282 parenthesize(amount, span)
7283 } else {
7284 amount
7285 };
7286 let u32_ty = primitive_ty("u32", span);
7287 quote_spanned! {span=> #amount as #u32_ty }
7288 } else {
7289 rhs.at(prec::LOWEST, span)
7290 };
7291 let args = parenthesize(argument, span);
7292 receiver.extend(quote_spanned! {span=> .#method #args });
7293 return Value::new(receiver, prec::CALL);
7294 }
7295
7296 // `/` and `%` stay plain: Rust truncates towards zero and takes the
7297 // sign of the dividend, exactly as C99 does. Both panic where C is
7298 // undefined (division by zero, and `INT_MIN / -1`).
7299 let (level, tokens) = match op {
7300 BinOp::Div => (prec::PRODUCT, quote_spanned! {span=> / }),
7301 BinOp::Rem => (prec::PRODUCT, quote_spanned! {span=> % }),
7302 BinOp::BitAnd => (prec::BIT_AND, quote_spanned! {span=> & }),
7303 BinOp::BitXor => (prec::BIT_XOR, quote_spanned! {span=> ^ }),
7304 BinOp::BitOr => (prec::BIT_OR, quote_spanned! {span=> | }),
7305 _ => unreachable!("every other operator was handled above"),
7306 };
7307 let ends_with_type = rhs.ends_with_type;
7308 let mut out = lhs.at(level, span);
7309 let rhs = rhs.at(level + 1, span);
7310 out.extend(quote_spanned! {span=> #tokens #rhs });
7311 Value::new(out, level).type_end(ends_with_type)
7312 }
7313
7314 /// The value `place op= value` stores.
7315 ///
7316 /// `hoisted` is the right operand when it was evaluated ahead of the read;
7317 /// see [`Codegen::compound_rhs`].
7318 fn compound_value(
7319 &mut self,
7320 current: Value,
7321 place_ty: Ty,
7322 op: BinOp,
7323 value: &Expr,
7324 hoisted: Option<Value>,
7325 compute: Ty,
7326 ) -> Value {
7327 let span = self.sp(value.range);
7328 if place_ty.is_pointer() {
7329 // `p += n` moves by elements, not by bytes.
7330 let access = current.at(prec::CALL, span);
7331 let offset = match hoisted {
7332 Some(index) => self.offset_of_value(index, op == BinOp::Sub, span),
7333 None => self.offset_argument(value, op == BinOp::Sub, span),
7334 };
7335 let pointee = self.program.types.pointee(place_ty).unwrap_or(Ty::Void);
7336 let offset = match self.vm_scale(pointee, span) {
7337 None => offset,
7338 Some(scale) => quote_spanned! {span=> (#offset).wrapping_mul(#scale) },
7339 };
7340 return Value::new(quote_spanned! {span=> #access.offset(#offset) }, prec::CALL);
7341 }
7342 // A complex computation keeps a real operand real on *both* sides:
7343 // sema left the right one alone, and the left one — the place — is
7344 // widened only as far as the common real type when it is real too. See
7345 // [`Codegen::complex_binary`].
7346 if compute.is_complex() {
7347 let lhs_ty = if place_ty.is_complex() {
7348 compute
7349 } else {
7350 compute.complex_component()
7351 };
7352 let current = self.cast(current, place_ty, lhs_ty, span);
7353 let rhs = self.compound_operand(value, hoisted, span);
7354 let result = self.complex_binary(op, (current, lhs_ty), (rhs, value.ty), compute, span);
7355 return self.cast(result, compute, place_ty, span);
7356 }
7357 let current = self.cast(current, place_ty, compute, span);
7358 let rhs = self.compound_operand(value, hoisted, span);
7359 let result = self.binary(op, current, rhs, compute, span);
7360 self.cast(result, compute, place_ty, span)
7361 }
7362
7363 /// The right operand of a compound assignment, already hoisted or not.
7364 ///
7365 /// The left operand is a place and therefore always typed, so a constant
7366 /// right operand can stay a bare literal.
7367 fn compound_operand(&mut self, value: &Expr, hoisted: Option<Value>, span: Span) -> Value {
7368 match hoisted {
7369 Some(rhs) => rhs,
7370 None => match constant_of(value) {
7371 Some(constant) => self.bare_value(constant, value.ty, span),
7372 None => self.expr(value),
7373 },
7374 }
7375 }
7376
7377 /// Evaluates the right operand of a compound assignment ahead of the read,
7378 /// when C says it happens either wholly before it or wholly after it.
7379 ///
7380 /// `E1 op= E2` is a read, an operation and a write, and C11 6.5.16.2p3
7381 /// makes the three of them *one* evaluation with respect to an
7382 /// indeterminately sequenced function call. Writing them out as
7383 /// `E1 = E1 op E2` would read `E1`, call whatever `E2` calls, and only then
7384 /// store — which is the one order the standard rules out, and which GCC's
7385 /// `pr58943` is about. Binding `E2` to a temporary first restores it: the
7386 /// place is computed, then the call happens, then the read-modify-write.
7387 ///
7388 /// Only an operand that can call something needs it; everything else is
7389 /// left where it was written, because a temporary per `i += 1` would be
7390 /// noise.
7391 fn compound_rhs(&mut self, value: &Expr) -> (TokenStream, Option<Value>) {
7392 if !ir::calls_a_function(value) {
7393 return (TokenStream::new(), None);
7394 }
7395 let span = self.sp(value.range);
7396 let tokens = self.expr(value).at(prec::LOWEST, span);
7397 let tmp = self.temporary();
7398 (
7399 quote_spanned! {span=> let #tmp = #tokens; },
7400 Some(Value::atom(quote_spanned! {span=> #tmp })),
7401 )
7402 }
7403
7404 /// The `offset` argument for an index that has already been emitted.
7405 fn offset_of_value(&mut self, index: Value, sub: bool, span: Span) -> TokenStream {
7406 let tokens = index.at(prec::CAST, span);
7407 let isize_ty = primitive_ty("isize", span);
7408 if sub {
7409 quote_spanned! {span=> -(#tokens as #isize_ty) }
7410 } else {
7411 quote_spanned! {span=> #tokens as #isize_ty }
7412 }
7413 }
7414
7415 /// The value `++place` or `--place` stores.
7416 fn step_value(&mut self, current: Value, ty: Ty, dec: bool, span: Span) -> TokenStream {
7417 if ty.is_pointer() {
7418 let access = current.at(prec::CALL, span);
7419 let pointee = self.program.types.pointee(ty).unwrap_or(Ty::Void);
7420 let one = match (self.vm_scale(pointee, span), dec) {
7421 (None, true) => quote_spanned! {span=> -1 },
7422 (None, false) => quote_spanned! {span=> 1 },
7423 (Some(scale), true) => quote_spanned! {span=> -(#scale) },
7424 (Some(scale), false) => scale,
7425 };
7426 return quote_spanned! {span=> #access.offset(#one) };
7427 }
7428 if ty.is_floating() {
7429 let access = current.at(prec::SUM, span);
7430 let one = Literal::f64_unsuffixed(1.0);
7431 let op = if dec {
7432 quote_spanned! {span=> - }
7433 } else {
7434 quote_spanned! {span=> + }
7435 };
7436 return quote_spanned! {span=> #access #op #one };
7437 }
7438 if ty.is_complex() {
7439 // GCC's `z++` adds one to the *real* part and leaves the
7440 // imaginary one alone, which is the componentwise `z + 1`.
7441 let name = if dec { "sub_real" } else { "add_real" };
7442 let func = self.rt_complex(&format!("{name}_{}", Self::complex_suffix(ty)), span);
7443 let access = current.at(prec::LOWEST, span);
7444 let one = Literal::f64_unsuffixed(1.0);
7445 return quote_spanned! {span=> #func(#access, #one) };
7446 }
7447 if ty.is_bool() {
7448 // `b++` is `b = b + 1 != 0`, which is `true` for `++` and the
7449 // negation of `b` for `--`.
7450 let access = current.at(prec::CAST, span);
7451 let int = self.ty(Ty::Int, span);
7452 let method = Ident::new(if dec { "wrapping_sub" } else { "wrapping_add" }, span);
7453 return quote_spanned! {span=> (#access as #int).#method(1) != 0 };
7454 }
7455 let access = current.at(prec::CALL, span);
7456 let method = Ident::new(if dec { "wrapping_sub" } else { "wrapping_add" }, span);
7457 quote_spanned! {span=> #access.#method(1) }
7458 }
7459
7460 /// Emits a conversion between two scalar types.
7461 fn cast(&mut self, value: Value, from: Ty, to: Ty, span: Span) -> Value {
7462 if from == to {
7463 return value;
7464 }
7465 if from.is_complex() || to.is_complex() {
7466 return self.complex_cast(value, from, to, span);
7467 }
7468 let types = &self.program.types;
7469 let from_fn = types.is_func_pointer(from);
7470 let to_fn = types.is_func_pointer(to);
7471 if to.is_bool() {
7472 if from.is_pointer() {
7473 // Handled by the caller for the common shapes; this is the
7474 // explicit `(_Bool)p`.
7475 let tokens = value.at(prec::CALL, span);
7476 return if from_fn {
7477 let braced = braced(tokens, span);
7478 Value::new(quote_spanned! {span=> #braced.is_some() }, prec::CALL)
7479 } else {
7480 Value::new(quote_spanned! {span=> !#tokens.is_null() }, prec::UNARY)
7481 };
7482 }
7483 // Converting to `_Bool` yields 0 or 1, which is what a comparison
7484 // against zero gives.
7485 let zero = self.zero_tokens(from, span);
7486 let tokens = value.at(prec::CMP + 1, span);
7487 return Value::new(quote_spanned! {span=> #tokens != #zero }, prec::CMP);
7488 }
7489 if from_fn || to_fn {
7490 // Rust has no `as` between an `Option<fn>` and anything else, so a
7491 // transmute is the honest translation of what C's cast does — but
7492 // only between two things of the same size. An integer of any
7493 // other width goes through `usize`, which is what C's own
7494 // implementation-defined conversion between a pointer and an
7495 // integer amounts to.
7496 let target = self.ty(to, span);
7497 let source = self.ty(from, span);
7498 // Two C function types the generated Rust cannot tell apart need
7499 // no transmute at all: `void (*)()` and `void (*)(void)` are
7500 // distinct types in C and one `Option<unsafe extern "C" fn()>`
7501 // here. Writing the transmute anyway would be a no-op that still
7502 // has to be inside an `unsafe` block, which a `static` initialiser
7503 // then has to grow.
7504 if from_fn && to_fn && source.to_string() == target.to_string() {
7505 return value;
7506 }
7507 let usize_ty = primitive_ty("usize", span);
7508 if to_fn && !from.is_pointer() {
7509 let tokens = value.at(prec::CAST, span);
7510 return Value::new(
7511 quote_spanned! {span=>
7512 ::core::mem::transmute::<#usize_ty, #target>(#tokens as #usize_ty)
7513 },
7514 prec::CALL,
7515 );
7516 }
7517 if from_fn && !to.is_pointer() {
7518 let tokens = value.at(prec::LOWEST, span);
7519 return Value::new(
7520 quote_spanned! {span=>
7521 ::core::mem::transmute::<#source, #usize_ty>(#tokens) as #target
7522 },
7523 prec::CAST,
7524 )
7525 .type_end(true);
7526 }
7527 let tokens = value.at(prec::LOWEST, span);
7528 return Value::new(
7529 quote_spanned! {span=>
7530 ::core::mem::transmute::<#source, #target>(#tokens)
7531 },
7532 prec::CALL,
7533 );
7534 }
7535 let target = self.ty(to, span);
7536 if from.is_pointer() && to.is_integer() {
7537 // Rust only casts a pointer to `usize`; the rest is an ordinary
7538 // integer conversion.
7539 let tokens = value.at(prec::CAST, span);
7540 let usize_ty = primitive_ty("usize", span);
7541 return Value::new(
7542 quote_spanned! {span=> #tokens as #usize_ty as #target },
7543 prec::CAST,
7544 )
7545 .type_end(true);
7546 }
7547 if from.is_bool() && to.is_floating() {
7548 // Rust has no `bool as f64`; C's `_Bool` to floating conversion
7549 // goes through the integer value.
7550 let int = self.ty(Ty::Int, span);
7551 let tokens = value.at(prec::CAST, span);
7552 return Value::new(
7553 quote_spanned! {span=> #tokens as #int as #target },
7554 prec::CAST,
7555 )
7556 .type_end(true);
7557 }
7558 let tokens = value.at(prec::CAST, span);
7559 Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
7560 }
7561
7562 // -- places -------------------------------------------------------------
7563
7564 /// A place, ready to be read from or written to.
7565 ///
7566 /// `mutable` says whether the place is about to be assigned to or have its
7567 /// address taken, which is what decides whether a `const` pointer under it
7568 /// has to lose the qualifier: Rust refuses `&raw mut (*p).f` when `p` is a
7569 /// `*const T`, while reading through one is fine.
7570 fn place(&mut self, place: &Place, mutable: bool) -> LoweredPlace {
7571 // Even *reading* an atomic object needs a `*mut` to it:
7572 // `AtomicX::from_ptr` takes one, and a `const _Atomic int *` would
7573 // otherwise reach `&raw mut *p` through a `*const` pointer, which
7574 // Rust refuses. What C promises is enough for the cast — every object
7575 // this crate generates lives in writable storage.
7576 let atomic = matches!(place.ty, Ty::Atomic(_));
7577 let mut lowered = self.place_access(place, mutable || atomic);
7578 if lowered.bits.is_none() && self.place_underaligned(place) {
7579 lowered.unaligned = true;
7580 }
7581 if let Ty::Atomic(id) = place.ty {
7582 let inner = self.program.types.atomic_inner(id);
7583 lowered.atomic = ir::atomic_class(&self.program.types, inner, &self.options.target)
7584 .map(|c| (c, inner));
7585 // There is no unaligned atomic: the alignment of an `_Atomic` type
7586 // is its size, and sema refuses the declarations that could not
7587 // have it.
7588 if lowered.atomic.is_some() {
7589 lowered.unaligned = false;
7590 }
7591 }
7592 lowered
7593 }
7594
7595 /// Whether the place has to be reached through an unaligned load or store.
7596 ///
7597 /// Two shapes need one. A `*p` or a `p[i]` whose pointer this crate itself
7598 /// built out of a packed member is underaligned, and so is a member read
7599 /// through a pointer to a record that is: `(*(T *) &buf).f`, where `buf` is
7600 /// a `char` array, is a member access Rust would compile to an aligned load
7601 /// of a byte-aligned address. A member of a *packed* record whose own
7602 /// address is fine needs nothing — Rust knows the layout of the item it was
7603 /// given and reads such a member unaligned by itself.
7604 fn place_underaligned(&self, place: &Place) -> bool {
7605 match &place.kind {
7606 PlaceKind::Deref(_) | PlaceKind::Index { .. } => {
7607 self.place_align(place) < self.type_align(place.ty)
7608 }
7609 PlaceKind::Field { base, .. } => self.place_align(base) < self.type_align(base.ty),
7610 // A part of a complex object reached through a packed member is
7611 // no better aligned than the object is.
7612 PlaceKind::ComplexPart { .. } => self.place_align(place) < self.type_align(place.ty),
7613 _ => false,
7614 }
7615 }
7616
7617 /// The alignment code generation can count on for a place's address.
7618 ///
7619 /// Everything C promises about an object's alignment holds for a place that
7620 /// names one, so the interesting half is what this crate itself can see
7621 /// through: the address of a member sits at its offset from a base whose
7622 /// alignment is known, and a cast in between changes nothing. Anything else
7623 /// — a pointer out of a variable, a parameter, a call — is taken at C's
7624 /// word and assumed to point at something its type is aligned for.
7625 fn place_align(&self, place: &Place) -> u64 {
7626 match &place.kind {
7627 PlaceKind::Deref(ptr) => self.pointer_align(ptr),
7628 PlaceKind::Index { base, .. } => {
7629 // Every element of an array sits at a multiple of the element
7630 // size from the first, and a size is always a multiple of the
7631 // alignment, so the elements are no worse aligned than the
7632 // element type asks and no better than the array is.
7633 self.pointer_align(base).min(self.type_align(place.ty))
7634 }
7635 PlaceKind::Field {
7636 base,
7637 record,
7638 index,
7639 } => {
7640 let base_align = self.place_align(base);
7641 let offset = self.program.types.record(*record).fields[*index].offset;
7642 if offset == 0 {
7643 base_align
7644 } else {
7645 base_align.min(1 << offset.trailing_zeros())
7646 }
7647 }
7648 // The real part sits at the object's own address and the imaginary
7649 // one exactly one component later, which is a power of two.
7650 PlaceKind::ComplexPart { base, imag } => {
7651 let base_align = self.place_align(base);
7652 if *imag {
7653 base_align.min(place.ty.size_bytes(&self.options.target).max(1))
7654 } else {
7655 base_align
7656 }
7657 }
7658 // An `_Alignas` on the declaration is a promise about the object
7659 // that the wrapper really keeps.
7660 PlaceKind::Object(id) => self
7661 .object_align(*id)
7662 .unwrap_or(1)
7663 .max(self.type_align(place.ty)),
7664 _ => self.type_align(place.ty),
7665 }
7666 }
7667
7668 /// The alignment of what a pointer expression points at.
7669 fn pointer_align(&self, ptr: &Expr) -> u64 {
7670 match &ptr.kind {
7671 ExprKind::AddrOf(place) => self.place_align(place),
7672 // A pointer cast moves no bytes, and neither does the decay of an
7673 // array to its first element.
7674 ExprKind::Cast(inner) if inner.ty.is_pointer() || inner.ty.is_array() => {
7675 let from = self.pointer_align(inner);
7676 // ...but a cast *to* a pointer to an under-aligned `typedef`
7677 // takes back the promise: `*(const xxh_unalign64 *) p`.
7678 match &ptr.ty {
7679 Ty::Pointer(id) => match self.program.types.pointer_type(*id).align {
7680 Some(align) => from.min(align),
7681 None => from,
7682 },
7683 _ => from,
7684 }
7685 }
7686 ExprKind::PtrOffset { ptr, .. } => self
7687 .pointer_align(ptr)
7688 .min(self.pointee_align(ptr.ty).unwrap_or(1)),
7689 _ => self.pointee_align(ptr.ty).unwrap_or(u64::MAX),
7690 }
7691 }
7692
7693 /// The alignment of the type a pointer or array type addresses.
7694 fn pointee_align(&self, ty: Ty) -> Option<u64> {
7695 // A pointer to an under-aligned `typedef` (`xxh_unalign64 *`) promises
7696 // only the `typedef`'s alignment; see `ir::PointerType::align`.
7697 if let Ty::Pointer(id) = ty
7698 && let Some(align) = self.program.types.pointer_type(id).align
7699 {
7700 return Some(align);
7701 }
7702 let pointee = self.program.types.pointee(ty)?;
7703 (!pointee.is_void() && !pointee.is_func()).then(|| self.type_align(pointee))
7704 }
7705
7706 /// The alignment the *generated Rust type* has, which is what a `*p` in the
7707 /// expansion is checked against.
7708 fn type_align(&self, ty: Ty) -> u64 {
7709 match ty {
7710 // A packed record's item is one byte aligned however strict C says
7711 // the record is; see `ir::RecordDef::rust_align`.
7712 Ty::Record(id) => self.program.types.record(id).rust_align,
7713 Ty::Array(id) => self.type_align(self.program.types.array_type(id).elem),
7714 _ => self
7715 .program
7716 .types
7717 .size_align(ty, &self.options.target)
7718 .map_or(1, |layout| layout.align),
7719 }
7720 }
7721
7722 fn place_access(&mut self, place: &Place, mutable: bool) -> LoweredPlace {
7723 let span = self.sp(place.range);
7724 match &place.kind {
7725 PlaceKind::Object(id) if self.program.object(*id).storage.is_thread_local() => {
7726 // A thread-local object is reached through the `*mut T` inside
7727 // its cell, which is valid for as long as this thread's copy
7728 // of the object is — exactly the lifetime C gives it. The
7729 // pointer is taken once and the place is a dereference of it,
7730 // so an expression that reads the object twice still calls
7731 // `with` once.
7732 let name = self.object_ident(*id, span);
7733 let tmp = self.temporary_at(span);
7734 let cell = Ident::new("__cinrs_cell", Span::mixed_site());
7735 // The cell holds whatever wrappers the storage carries, and
7736 // the object is reached through them exactly as it is for
7737 // every other storage class.
7738 let object = parenthesize(quote_spanned! {span=> *#tmp }, span);
7739 let object = self.through_storage(*id, object, span);
7740 LoweredPlace::plain(
7741 quote_spanned! {span=>
7742 let #tmp = #name.with(|#cell| ::core::cell::UnsafeCell::get(#cell));
7743 },
7744 object,
7745 )
7746 }
7747 PlaceKind::Object(id) => {
7748 let access = self.object_access(*id, span);
7749 LoweredPlace::plain(TokenStream::new(), access)
7750 }
7751 PlaceKind::Deref(ptr) => self.deref_place(ptr, place.ty, mutable, span),
7752 PlaceKind::Index { base, index } => {
7753 let pointer = self.pointer_operand(base, place.ty, mutable, span);
7754 let offset = self.scaled_offset(place.ty, index, false, span);
7755 let tmp = self.temporary_at(span);
7756 LoweredPlace::plain(
7757 quote_spanned! {span=> let #tmp = #pointer.offset(#offset); },
7758 parenthesize(quote_spanned! {span=> *#tmp }, span),
7759 )
7760 }
7761 PlaceKind::Field {
7762 base,
7763 record,
7764 index,
7765 } => {
7766 let field = self.program.types.record(*record).fields[*index].clone();
7767 let lowered = self.place(base, mutable);
7768 let access = lowered.access;
7769 let Some(bits) = &field.bits else {
7770 let name = self.c_ident(&field.name, span);
7771 return LoweredPlace::plain(
7772 lowered.setup,
7773 quote_spanned! {span=> #access.#name },
7774 );
7775 };
7776 // The accessors take `&self` and `&mut self`, and a reference
7777 // to a `static mut` is exactly what edition 2024 refuses; the
7778 // raw pointer keeps the item out of the expression.
7779 let access = if rooted_in_static(base, self.program) {
7780 parenthesize(quote_spanned! {span=> *(&raw mut #access) }, span)
7781 } else {
7782 access
7783 };
7784 LoweredPlace {
7785 setup: lowered.setup,
7786 access,
7787 bits: Some(BitAccess {
7788 getter: self.c_ident(&bits.getter, span),
7789 setter: self.c_ident(&bits.setter, span),
7790 }),
7791 unaligned: false,
7792 atomic: None,
7793 }
7794 }
7795 // `__real__ z` and `__imag__ z` are the two fields of the runtime's
7796 // `Complex`, which is why they are assignable: the place is a Rust
7797 // place expression like any member access.
7798 PlaceKind::ComplexPart { base, imag } => {
7799 let lowered = self.place(base, mutable);
7800 let access = lowered.access;
7801 let field = Ident::new(if *imag { "im" } else { "re" }, span);
7802 LoweredPlace::plain(lowered.setup, quote_spanned! {span=> #access.#field })
7803 }
7804 PlaceKind::Str(id) => {
7805 let pointer = self.string_pointer(*id, !mutable, span);
7806 let tmp = self.temporary_at(span);
7807 LoweredPlace::plain(
7808 quote_spanned! {span=> let #tmp = #pointer; },
7809 parenthesize(quote_spanned! {span=> *#tmp }, span),
7810 )
7811 }
7812 PlaceKind::Temporary(expr) => {
7813 let ty = expr.ty;
7814 let value = self.expr_at(expr, ty);
7815 let tmp = self.temporary();
7816 LoweredPlace::plain(
7817 quote_spanned! {span=> let mut #tmp = #value; },
7818 quote_spanned! {span=> #tmp },
7819 )
7820 }
7821 // The binding itself was made at the top of the enclosing block —
7822 // C gives the object that lifetime, and it is what lets `&(T){…}`
7823 // outlive the expression. What happens *here* is the
7824 // initialisation, so that side effects in it happen where the
7825 // literal was written and a literal in a loop is rebuilt on every
7826 // iteration.
7827 PlaceKind::CompoundLiteral { object, init } => {
7828 let name = self.object_ident(*object, span);
7829 let value = self.expr_at(init, place.ty);
7830 LoweredPlace::plain(
7831 quote_spanned! {span=> #name = #value; },
7832 quote_spanned! {span=> #name },
7833 )
7834 }
7835 }
7836 }
7837
7838 /// Reads a lowered place.
7839 fn read(&self, place: &LoweredPlace, span: Span) -> Value {
7840 let access = &place.access;
7841 if let Some((class, ty)) = place.atomic {
7842 let object = self.atomic_object_of(place, span);
7843 let order = self.ordering(ir::MemOrder::SeqCst, span);
7844 return self.repr_to_value(
7845 class,
7846 ty,
7847 quote_spanned! {span=> #object.load(#order) },
7848 span,
7849 );
7850 }
7851 match &place.bits {
7852 Some(bits) => {
7853 let getter = &bits.getter;
7854 Value::new(quote_spanned! {span=> #access.#getter() }, prec::CALL)
7855 }
7856 None if place.unaligned => Value::new(
7857 quote_spanned! {span=> (&raw const #access).read_unaligned() },
7858 prec::CALL,
7859 ),
7860 None => Value::atom(access.clone()),
7861 }
7862 }
7863
7864 /// The statement that stores `value` into a lowered place.
7865 fn write(&self, place: &LoweredPlace, value: TokenStream, span: Span) -> TokenStream {
7866 let access = &place.access;
7867 if let Some((class, ty)) = place.atomic {
7868 let object = self.atomic_object_of(place, span);
7869 let order = self.ordering(ir::MemOrder::SeqCst, span);
7870 let value = self.value_to_repr(class, ty, Value::new(value, prec::LOWEST), span);
7871 return quote_spanned! {span=> #object.store(#value, #order); };
7872 }
7873 match &place.bits {
7874 Some(bits) => {
7875 let setter = &bits.setter;
7876 quote_spanned! {span=> #access.#setter(#value); }
7877 }
7878 None if place.unaligned => {
7879 quote_spanned! {span=> (&raw mut #access).write_unaligned(#value); }
7880 }
7881 None => quote_spanned! {span=> #access = #value; },
7882 }
7883 }
7884
7885 /// The `&AtomicX` an `_Atomic` place is reached through.
7886 ///
7887 /// A raw pointer to the object rather than a reference to it: the object
7888 /// is a plain `static mut` or `let mut` of the underlying type, and its
7889 /// address is what `from_ptr` wants.
7890 fn atomic_object_of(&self, place: &LoweredPlace, span: Span) -> TokenStream {
7891 let access = &place.access;
7892 let class = place.atomic.expect("an atomic place").0;
7893 self.atomic_ref(class, quote_spanned! {span=> (&raw mut #access) }, span)
7894 }
7895
7896 /// `*p` as a place.
7897 fn deref_place(&mut self, ptr: &Expr, pointee: Ty, mutable: bool, span: Span) -> LoweredPlace {
7898 let simple =
7899 matches!(&ptr.kind, ExprKind::Load(p) if matches!(p.kind, PlaceKind::Object(_)));
7900 if simple {
7901 // A variable holding the pointer can be dereferenced as often as
7902 // needed, so no temporary is called for.
7903 let tokens = self.pointer_operand(ptr, pointee, mutable, span);
7904 return LoweredPlace::plain(
7905 TokenStream::new(),
7906 parenthesize(quote_spanned! {span=> *#tokens }, span),
7907 );
7908 }
7909 let value = self.pointer_operand(ptr, pointee, mutable, span);
7910 let tmp = self.temporary_at(span);
7911 LoweredPlace::plain(
7912 quote_spanned! {span=> let #tmp = #value; },
7913 parenthesize(quote_spanned! {span=> *#tmp }, span),
7914 )
7915 }
7916
7917 /// The pointer a place is built on.
7918 ///
7919 /// Writing through a `*const T` is not allowed even in `unsafe` Rust, and
7920 /// C's own `const` checking has already happened in sema, so a place that
7921 /// is about to be written to (or have its address taken) drops the
7922 /// qualifier here rather than at every use.
7923 fn pointer_operand(
7924 &mut self,
7925 ptr: &Expr,
7926 pointee: Ty,
7927 mutable: bool,
7928 span: Span,
7929 ) -> TokenStream {
7930 if mutable && self.program.types.points_to_const(ptr.ty) {
7931 let target = self.pointee_ty(pointee, span);
7932 let tokens = self.expr(ptr).at(prec::CAST, span);
7933 return parenthesize(quote_spanned! {span=> #tokens as *mut #target }, span);
7934 }
7935 self.expr(ptr).at(prec::CALL, span)
7936 }
7937
7938 /// The address of a place, as a pointer of type `want`.
7939 fn address_of(&mut self, place: &Place, want: Ty, span: Span) -> Value {
7940 // A variably modified object's binding already *is* the address of its
7941 // first element, so both the decay `a` and the array pointer `&a` are
7942 // that binding — the second one only differs in its C type.
7943 if let PlaceKind::Object(id) = &place.kind
7944 && self.program.types.is_vm(place.ty)
7945 {
7946 let name = self.object_ident(*id, span);
7947 let value = Value::atom(quote_spanned! {span=> #name });
7948 let elem = self.program.types.elem(place.ty);
7949 let natural = self.program.types.pointee(want) == elem
7950 && !self.program.types.points_to_const(want);
7951 if natural {
7952 return value;
7953 }
7954 let target = self.ty(want, span);
7955 let tokens = value.at(prec::CAST, span);
7956 return Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST)
7957 .type_end(true);
7958 }
7959 // `&*p` is `p`, and `&a[i]` is `a + i`; saying so keeps the output
7960 // free of pointless round trips through a place.
7961 match &place.kind {
7962 PlaceKind::Deref(ptr) => {
7963 let from = ptr.ty;
7964 let value = self.expr(ptr);
7965 return self.pointer_cast(value, from, want, span);
7966 }
7967 PlaceKind::Index { base, index } => {
7968 let from = base.ty;
7969 let pointer = self.expr(base).at(prec::CALL, span);
7970 let offset = self.scaled_offset(place.ty, index, false, span);
7971 let value = Value::new(
7972 quote_spanned! {span=> #pointer.offset(#offset) },
7973 prec::CALL,
7974 );
7975 return self.pointer_cast(value, from, want, span);
7976 }
7977 PlaceKind::Str(id) => {
7978 let konst = self.program.types.points_to_const(want);
7979 let tokens = self.string_pointer(*id, konst, span);
7980 return Value::new(tokens, prec::CALL);
7981 }
7982 _ => {}
7983 }
7984 let lowered = self.place(place, true);
7985 let access = lowered.access;
7986 let address = quote_spanned! {span=> &raw mut #access };
7987 let natural = Value::new(parenthesize(address, span), prec::ATOM);
7988 let value = self.array_or_pointer_cast(natural, place.ty, want, span);
7989 if lowered.setup.is_empty() {
7990 return value;
7991 }
7992 let setup = lowered.setup;
7993 let tokens = value.at(prec::LOWEST, span);
7994 Value::new(quote_spanned! {span=> { #setup #tokens } }, prec::BLOCK)
7995 }
7996
7997 /// Adjusts `&raw mut place` to the pointer type the expression wants.
7998 fn array_or_pointer_cast(&mut self, value: Value, from: Ty, want: Ty, span: Span) -> Value {
7999 if let Ty::Array(id) = from {
8000 // The address of an array is a pointer to the array; decaying it
8001 // to a pointer to the first element is a `cast`, which — unlike
8002 // `as` — cannot silently change anything else.
8003 let array = self.program.types.array_type(id);
8004 let wanted_pointee = self.program.types.pointee(want);
8005 if wanted_pointee == Some(array.elem) {
8006 let elem = self.pointee_ty(array.elem, span);
8007 let tokens = value.at(prec::CALL, span);
8008 let cast = Value::new(quote_spanned! {span=> #tokens.cast::<#elem>() }, prec::CALL);
8009 return self.constify(cast, want, span);
8010 }
8011 }
8012 let natural_mut = matches!(self.program.types.pointee(want), Some(pointee) if pointee == from)
8013 && !self.program.types.points_to_const(want);
8014 if natural_mut {
8015 return value;
8016 }
8017 let target = self.ty(want, span);
8018 let tokens = value.at(prec::CAST, span);
8019 Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
8020 }
8021
8022 /// Adds the `as *const T` that a `*mut T` needs to become a `*const T`.
8023 fn constify(&mut self, value: Value, want: Ty, span: Span) -> Value {
8024 if !self.program.types.points_to_const(want) {
8025 return value;
8026 }
8027 let target = self.ty(want, span);
8028 let tokens = value.at(prec::CAST, span);
8029 Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
8030 }
8031
8032 /// Casts a pointer value to the pointer type wanted.
8033 fn pointer_cast(&mut self, value: Value, from: Ty, want: Ty, span: Span) -> Value {
8034 if from == want {
8035 return value;
8036 }
8037 let target = self.ty(want, span);
8038 let tokens = value.at(prec::CAST, span);
8039 Value::new(quote_spanned! {span=> #tokens as #target }, prec::CAST).type_end(true)
8040 }
8041
8042 /// The pointer a string literal decays to.
8043 fn string_pointer(&mut self, id: ir::StrId, konst: bool, span: Span) -> TokenStream {
8044 let data = self.program.string(id);
8045 let element = data.elem;
8046 if element.size_bytes(&self.options.target) > 1 {
8047 // A `wchar_t`, `char16_t` or `char32_t` literal needs real storage
8048 // of that type; a `static` in the enclosing block is the only
8049 // thing with a long enough lifetime.
8050 let elem = self.ty(element, span);
8051 let mut items = TokenStream::new();
8052 for value in data.values.iter().chain(std::iter::once(&0)) {
8053 let literal =
8054 int_literal_token(element.wrap(i128::from(*value), &self.options.target), span);
8055 items.extend(quote_spanned! {span=> #literal, });
8056 }
8057 let len = usize_literal(data.len_with_nul(), span);
8058 let name = Ident::new("__CINRS_WIDE", Span::mixed_site());
8059 let array = bracketed(items, span);
8060 let ty = bracketed(quote_spanned! {span=> #elem ; #len }, span);
8061 let pointer = if konst {
8062 quote_spanned! {span=> (&raw const #name).cast::<#elem>() }
8063 } else {
8064 quote_spanned! {span=> (&raw const #name).cast::<#elem>().cast_mut() }
8065 };
8066 return quote_spanned! {span=>
8067 { static #name: #ty = #array; #pointer }
8068 };
8069 }
8070 // A narrow or `u8"…"` literal is a Rust byte string, whose elements
8071 // are the same bytes whether C calls them `char` or `char8_t`.
8072 let mut literal = Literal::byte_string(&nul_terminated(&data.values));
8073 literal.set_span(span);
8074 let elem = self.ty(element, span);
8075 if konst {
8076 quote_spanned! {span=> #literal.as_ptr().cast::<#elem>() }
8077 } else {
8078 quote_spanned! {span=> #literal.as_ptr().cast::<#elem>().cast_mut() }
8079 }
8080 }
8081
8082 // -- literals -----------------------------------------------------------
8083
8084 fn int_literal(&self, value: i128, ty: Ty, span: Span) -> Value {
8085 if ty.is_bool() {
8086 return Value::atom(bare_int_literal(value, ty, span));
8087 }
8088 if ty == Ty::UInt128 {
8089 // The constant is the bit pattern; the literal has to spell the
8090 // `u128` it stands for rather than the `i128` those bits read as.
8091 let literal = u128_literal_token(value as u128, span);
8092 let target = self.ty(ty, span);
8093 return Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST)
8094 .type_end(true);
8095 }
8096 let literal = int_literal_token(value, span);
8097 let target = self.ty(ty, span);
8098 Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
8099 }
8100
8101 fn float_literal(&self, value: f64, ty: Ty, span: Span) -> Value {
8102 if !value.is_finite() {
8103 return Value::new(self.non_finite_literal(value, ty, span), prec::CAST).type_end(true);
8104 }
8105 let literal = float_literal_token(value, span);
8106 let target = self.ty(ty, span);
8107 Value::new(quote_spanned! {span=> #literal as #target }, prec::CAST).type_end(true)
8108 }
8109
8110 /// An infinity or a NaN, which no Rust literal can spell.
8111 ///
8112 /// A NaN that is not the default quiet one — `__builtin_nan("0x123")`, and
8113 /// the negative NaN `-__builtin_nan("")` is — is written out bit for bit.
8114 /// `f64::NAN` is *one* NaN, and a payload and a sign are part of the value
8115 /// a program asked for; `as` between the two widths is free to lose both.
8116 fn non_finite_literal(&self, value: f64, ty: Ty, span: Span) -> TokenStream {
8117 let target = self.ty(ty, span);
8118 let f64_ty = primitive_ty("f64", span);
8119 if value.is_nan() {
8120 let bits = value.to_bits();
8121 if bits == f64::NAN.to_bits() {
8122 return quote_spanned! {span=> <#f64_ty>::NAN as #target };
8123 }
8124 if ty == Ty::Float {
8125 let f32_ty = primitive_ty("f32", span);
8126 let literal =
8127 unsigned_hex_literal(u64::from(ir::narrow_nan_bits(bits)), "u32", span);
8128 return quote_spanned! {span=> <#f32_ty>::from_bits(#literal) };
8129 }
8130 let literal = unsigned_hex_literal(bits, "u64", span);
8131 return quote_spanned! {span=> <#f64_ty>::from_bits(#literal) as #target };
8132 }
8133 if value.is_sign_negative() {
8134 quote_spanned! {span=> -<#f64_ty>::INFINITY as #target }
8135 } else {
8136 quote_spanned! {span=> <#f64_ty>::INFINITY as #target }
8137 }
8138 }
8139
8140 /// The all-bits-zero value of a type.
8141 fn zero_tokens(&self, ty: Ty, span: Span) -> TokenStream {
8142 match ty {
8143 // The zero of an `_Atomic T` is the zero of `T`: the object is
8144 // generated as a plain `T`, and initialising it is a plain write.
8145 Ty::Atomic(id) => self.zero_tokens(self.program.types.atomic_inner(id), span),
8146 _ if ty.is_complex() => {
8147 let zero = bare_float_literal(0.0, span);
8148 self.complex_new(ty, zero.clone(), zero, span)
8149 .at(prec::LOWEST, span)
8150 }
8151 _ if ty.is_floating() => bare_float_literal(0.0, span),
8152 _ if ty.is_integer() => bare_int_literal(0, ty, span),
8153 // A variably modified array is generated as a pointer, and the
8154 // only thing that ever asks for its zero is the hoisting a [CFG
8155 // body](crate::cfg) does before the declaration is reached.
8156 Ty::Array(_) if self.program.types.is_vm(ty) => {
8157 let step = self.ty(self.program.types.vm_step_ty(ty), span);
8158 quote_spanned! {span=> ::core::ptr::null_mut::<#step>() }
8159 }
8160 Ty::Pointer(id) => {
8161 let pointer = self.program.types.pointer_type(id);
8162 if let Ty::Func(func) = pointer.pointee {
8163 // The signature is written out rather than left to
8164 // inference: a null function pointer is often the whole
8165 // expression — `((void (*)(void))0)()` — and a bare
8166 // `Option::None` there is `E0282`.
8167 let signature = self.fn_ty(func, span);
8168 return quote_spanned! {span=>
8169 ::core::option::Option::<#signature>::None
8170 };
8171 }
8172 let pointee = self.pointee_ty(pointer.pointee, span);
8173 if pointer.konst {
8174 quote_spanned! {span=> ::core::ptr::null::<#pointee>() }
8175 } else {
8176 quote_spanned! {span=> ::core::ptr::null_mut::<#pointee>() }
8177 }
8178 }
8179 other => {
8180 // A zeroed aggregate: `mem::zeroed` is a `const fn`, so this
8181 // works in a `static` initialiser as well as in a body.
8182 let target = self.ty(other, span);
8183 quote_spanned! {span=> ::core::mem::zeroed::<#target>() }
8184 }
8185 }
8186 }
8187}
8188
8189/// The value a bit-field's initialiser folds to, if it folds at all.
8190///
8191/// Sema has already reduced a constant to a bare `Int` node, and the implicit
8192/// zero every unmentioned member gets is either that or [`ExprKind::Zeroed`].
8193fn constant_bits(expr: &Expr) -> Option<i128> {
8194 match &expr.kind {
8195 ExprKind::Int(value) => Some(*value),
8196 ExprKind::Zeroed if expr.ty.is_integer() => Some(0),
8197 _ => None,
8198 }
8199}
8200
8201/// Writes the low `width` bits of `value` into a run's storage bytes.
8202fn pack_bits(storage: &mut [u8], bits: &ir::BitField, value: i128) {
8203 let start = bits.offset_in_storage();
8204 for bit in 0..u64::from(bits.width) {
8205 if (value as u128) >> bit & 1 == 0 {
8206 continue;
8207 }
8208 let at = start + bit;
8209 if let Some(byte) = storage.get_mut((at / 8) as usize) {
8210 *byte |= 1 << (at % 8);
8211 }
8212 }
8213}
8214
8215/// `[0x1f, 0x00, …]`, the initialiser of a storage field.
8216fn byte_array(bytes: &[u8], span: Span) -> TokenStream {
8217 if bytes.iter().all(|byte| *byte == 0) {
8218 let len = usize_literal(bytes.len() as u64, span);
8219 return bracketed(quote_spanned! {span=> 0; #len }, span);
8220 }
8221 let mut items = TokenStream::new();
8222 for byte in bytes {
8223 let value = hex_literal(u64::from(*byte), span);
8224 items.extend(quote_spanned! {span=> #value, });
8225 }
8226 bracketed(items, span)
8227}
8228
8229/// Whether a place ultimately names an object with static storage duration.
8230///
8231/// The bit-field accessors borrow, and edition 2024 refuses a reference to a
8232/// `static mut`; a place rooted in one is reached through `&raw mut` instead.
8233/// Anything behind a pointer is already a raw dereference, so it needs nothing
8234/// — a thread-local object included, since its place is the dereference of the
8235/// pointer out of its cell.
8236///
8237/// It is also what says whether an initialiser refers to an item, which a Rust
8238/// `const` may not; see [`Codegen::const_initialisable`].
8239fn rooted_in_static(place: &Place, program: &Program) -> bool {
8240 let mut place = place;
8241 loop {
8242 match &place.kind {
8243 PlaceKind::Object(id) => {
8244 let storage = &program.object(*id).storage;
8245 return !matches!(storage, Storage::Automatic) && !storage.is_thread_local();
8246 }
8247 PlaceKind::Field { base, .. } => place = base,
8248 _ => return false,
8249 }
8250 }
8251}
8252
8253/// The Rust unsigned integer of a given width, which is what the bit-counting
8254/// builtins are defined on.
8255fn unsigned_rust_ty(width: u32, span: Span) -> TokenStream {
8256 primitive_ty(
8257 match width {
8258 0..=8 => "u8",
8259 9..=16 => "u16",
8260 17..=32 => "u32",
8261 _ => "u64",
8262 },
8263 span,
8264 )
8265}
8266
8267/// The signed counterpart, for `__builtin_clrsb`.
8268fn signed_rust_ty(width: u32, span: Span) -> TokenStream {
8269 primitive_ty(
8270 match width {
8271 0..=8 => "i8",
8272 9..=16 => "i16",
8273 17..=32 => "i32",
8274 _ => "i64",
8275 },
8276 span,
8277 )
8278}
8279
8280/// A mask of `width` low bits, inside a word of `word_bits`.
8281fn mask_of(width: u32, word_bits: u32) -> u128 {
8282 let width = width.min(word_bits);
8283 if width >= 128 {
8284 u128::MAX
8285 } else {
8286 (1u128 << width) - 1
8287 }
8288}
8289
8290/// A mask literal, written in hexadecimal at the width of its word.
8291///
8292/// A `u128` mask carries its suffix: a bare hexadecimal literal above
8293/// `u64::MAX` would be out of range for whatever `u64` the surrounding
8294/// annotation asked for, and the annotation is what makes the narrow case
8295/// readable.
8296fn word_literal(value: u128, word_bits: u32, span: Span) -> TokenStream {
8297 if word_bits <= 64 {
8298 return hex_literal(value as u64, span);
8299 }
8300 let mut literal = Literal::from_str(&format!("0x{value:x}u128"))
8301 .unwrap_or_else(|_| Literal::u128_suffixed(value));
8302 literal.set_span(span);
8303 TokenStream::from(TokenTree::Literal(literal))
8304}
8305
8306/// A `u64` literal written in hexadecimal, which is how a mask reads.
8307fn hex_literal(value: u64, span: Span) -> TokenStream {
8308 let mut literal = Literal::from_str(&format!("0x{value:x}"))
8309 .unwrap_or_else(|_| Literal::u64_unsuffixed(value));
8310 literal.set_span(span);
8311 TokenStream::from(TokenTree::Literal(literal))
8312}
8313
8314/// The variable that says which entry of an irreducible region control is
8315/// going to, in this crate's own hygiene.
8316///
8317/// One per region rather than one per function; see [`crate::reloop`].
8318fn entry_ident(state: u32) -> Ident {
8319 Ident::new(&format!("__cinrs_entry{state}"), Span::mixed_site())
8320}
8321
8322/// The store that says which entry of a dispatch is meant, or nothing at all
8323/// when the jump has only one place to arrive.
8324fn entry_assignment(exit: &reloop::Exit, index: usize, span: Span) -> TokenStream {
8325 let Some(state) = exit.state else {
8326 return TokenStream::new();
8327 };
8328 let name = entry_ident(state);
8329 let value = state_literal(index, span);
8330 quote_spanned! {span=> #name = #value; }
8331}
8332
8333/// A state number, which is a `u32` because the state variable is.
8334/// The `default` of a computed `goto`'s dispatch: a value that is no label's
8335/// number, which is undefined behaviour in C.
8336///
8337/// A build with debug assertions — the user's, since `cfg!` is expanded in
8338/// their crate — panics, which catches the bug; any other build assumes it
8339/// away, as GCC does, which is what lets the `match` be a bare jump table.
8340fn invalid_target(span: Span) -> TokenStream {
8341 quote_spanned! {span=>
8342 if ::core::cfg!(debug_assertions) {
8343 ::core::unreachable!()
8344 } else {
8345 unsafe { ::core::hint::unreachable_unchecked() }
8346 }
8347 }
8348}
8349
8350fn state_literal(value: usize, span: Span) -> TokenStream {
8351 let mut literal = Literal::u32_unsuffixed(value as u32);
8352 literal.set_span(span);
8353 TokenStream::from(TokenTree::Literal(literal))
8354}
8355
8356/// Groups a switch's cases by the block they enter, keeping source order.
8357///
8358/// `case 0: case 1:` reaches the same block through two labels, and one arm
8359/// with an or-pattern is how that should read.
8360fn group_cases(cases: &[(ir::CaseRange, BlockId)]) -> Vec<(BlockId, Vec<ir::CaseRange>)> {
8361 let mut out: Vec<(BlockId, Vec<ir::CaseRange>)> = Vec::new();
8362 for (value, target) in cases {
8363 match out.iter_mut().find(|(block, _)| block == target) {
8364 Some((_, values)) => values.push(*value),
8365 None => out.push((*target, vec![*value])),
8366 }
8367 }
8368 out
8369}
8370
8371/// The Rust pattern one `case` label matches: a literal, or a range.
8372fn case_pattern(value: ir::CaseRange, ty: Ty, span: Span) -> TokenStream {
8373 let low = bare_int_literal(value.low, ty, span);
8374 if value.is_single() {
8375 return low;
8376 }
8377 let high = bare_int_literal(value.high, ty, span);
8378 quote_spanned! {span=> #low ..= #high }
8379}
8380
8381/// The precedence of the tokens [`Codegen::zero_tokens`] produces.
8382fn zero_prec(ty: Ty) -> u8 {
8383 if ty.is_arithmetic() {
8384 prec::ATOM
8385 } else {
8386 prec::CALL
8387 }
8388}
8389
8390/// `#[link_name = "…"]`, which points a renamed declaration back at its symbol.
8391fn link_name(symbol: &str, span: Span) -> TokenStream {
8392 let mut literal = Literal::string(symbol);
8393 literal.set_span(span);
8394 quote_spanned! {span=> #[link_name = #literal] }
8395}
8396
8397/// The attribute that gives a definition the C symbol `symbol`, for a unit
8398/// that asked for `#pragma cinrs export`.
8399///
8400/// `#[unsafe(no_mangle)]` is the edition-2024 spelling and is accepted in every
8401/// edition since 1.82, so one expansion works wherever it is written. It says
8402/// "the name of the item is the symbol", which is not quite always true here:
8403/// a C name that is a Rust keyword becomes `r#match`, and the five names that
8404/// cannot even be raw grow an underscore, so those go through `export_name`
8405/// instead and say the symbol outright.
8406fn export_attr(symbol: &str, item: &Ident, span: Span) -> TokenStream {
8407 if item.to_string().trim_start_matches("r#") == symbol {
8408 return quote_spanned! {span=> #[unsafe(no_mangle)] };
8409 }
8410 let mut literal = Literal::string(symbol);
8411 literal.set_span(span);
8412 quote_spanned! {span=> #[unsafe(export_name = #literal)] }
8413}
8414
8415/// Whether a static initialiser has to be wrapped in `unsafe`.
8416///
8417/// `types` is the arena, because one of the answers depends on it: a cast to
8418/// or from a function pointer is written out as a `transmute`, and that is an
8419/// unsafe call wherever it stands. `frob f[] = { abort };` with `typedef void
8420/// (*frob)();` is the shape — `execute/921110-1`.
8421fn needs_unsafe(types: &ir::Types, expr: &Expr) -> bool {
8422 let recurse = |inner| needs_unsafe(types, inner);
8423 match &expr.kind {
8424 // `mem::zeroed` is unsafe, and so is naming a `static mut`.
8425 ExprKind::Zeroed => !expr.ty.is_scalar(),
8426 // A string literal's address is safe to take; anything else with static
8427 // storage duration is a `static mut`.
8428 ExprKind::AddrOf(place) => !matches!(place.kind, PlaceKind::Str(_)),
8429 ExprKind::Cast(inner) => {
8430 let transmuted = types.is_func_pointer(expr.ty) || types.is_func_pointer(inner.ty);
8431 transmuted || recurse(inner)
8432 }
8433 // `<*mut T>::offset` is an unsafe call however safe its operand is:
8434 // `static const char *p = "foo" + 1;` — `execute/pr53084` — is the
8435 // address of a string literal, which is safe to take, plus one.
8436 ExprKind::PtrOffset { .. } => true,
8437 ExprKind::ComplexOf { re, im } => recurse(re) || recurse(im),
8438 ExprKind::RecordLit { fields, .. } => fields.iter().any(recurse),
8439 ExprKind::UnionLit { value, .. } => recurse(value),
8440 ExprKind::ArrayLit(items) => items.iter().any(recurse),
8441 ExprKind::ArrayRepeat { value, .. } => recurse(value),
8442 _ => false,
8443 }
8444}
8445
8446/// The bytes of a narrow string literal, with its terminating NUL.
8447fn nul_terminated(values: &[u32]) -> Vec<u8> {
8448 let mut bytes: Vec<u8> = values.iter().map(|v| *v as u8).collect();
8449 bytes.push(0);
8450 bytes
8451}
8452
8453// ---------------------------------------------------------------------------
8454// literal tokens
8455// ---------------------------------------------------------------------------
8456
8457/// The largest magnitude an unsuffixed literal is safe to have: Rust infers
8458/// `i32` for a literal with no other constraint.
8459const UNSUFFIXED_LIMIT: i128 = i32::MAX as i128;
8460
8461/// A `u128` literal, always suffixed: nothing else can spell a value above
8462/// `i128::MAX`.
8463fn u128_literal_token(value: u128, span: Span) -> TokenStream {
8464 let mut literal = Literal::u128_suffixed(value);
8465 literal.set_span(span);
8466 TokenStream::from(TokenTree::Literal(literal))
8467}
8468
8469/// A literal for `value`, with a Rust suffix only when inference needs one.
8470fn int_literal_token(value: i128, span: Span) -> TokenStream {
8471 if value == i128::MIN {
8472 // `-(2^127)` has no positive magnitude an `i128` can hold. Rust reads
8473 // the negation of the out-of-range literal as exactly this value,
8474 // which is how `i128::MIN` is written in Rust source too.
8475 let mut literal = Literal::from_str("170141183460469231731687303715884105728i128")
8476 .expect("a decimal literal followed by a suffix is a token");
8477 literal.set_span(span);
8478 return quote_spanned! {span=> -#literal };
8479 }
8480 let magnitude = value.unsigned_abs();
8481 let mut literal = if magnitude <= UNSUFFIXED_LIMIT as u128 {
8482 Literal::u128_unsuffixed(magnitude)
8483 } else if value >= 0 {
8484 if magnitude <= u32::MAX as u128 {
8485 Literal::u32_suffixed(magnitude as u32)
8486 } else if magnitude <= u64::MAX as u128 {
8487 Literal::u64_suffixed(magnitude as u64)
8488 } else {
8489 Literal::u128_suffixed(magnitude)
8490 }
8491 } else if magnitude <= i64::MAX as u128 {
8492 Literal::i64_suffixed(magnitude as i64)
8493 } else {
8494 Literal::i128_suffixed(magnitude as i128)
8495 };
8496 literal.set_span(span);
8497 if value < 0 {
8498 quote_spanned! {span=> -#literal }
8499 } else {
8500 TokenStream::from(TokenTree::Literal(literal))
8501 }
8502}
8503
8504/// A literal for `value` with no suffix at all, for a context that already
8505/// fixes its type.
8506fn bare_int_literal(value: i128, ty: Ty, span: Span) -> TokenStream {
8507 if ty.is_bool() {
8508 let ident = Ident::new(if value != 0 { "true" } else { "false" }, span);
8509 return quote_spanned! {span=> #ident };
8510 }
8511 if ty == Ty::UInt128 {
8512 // The value is carried as a bit pattern; `-1` in a `u128` context is
8513 // not what the constant means.
8514 let mut literal = Literal::u128_unsuffixed(value as u128);
8515 literal.set_span(span);
8516 return TokenStream::from(TokenTree::Literal(literal));
8517 }
8518 let mut literal = Literal::u128_unsuffixed(value.unsigned_abs());
8519 literal.set_span(span);
8520 if value < 0 {
8521 quote_spanned! {span=> -#literal }
8522 } else {
8523 TokenStream::from(TokenTree::Literal(literal))
8524 }
8525}
8526
8527/// The integer a bit-field's bytes are gathered into: `u64`/`i64` for a
8528/// window of 64 bits and the 128-bit primitives for a wider one.
8529///
8530/// All four take the [`core::primitive`] path, `typedef unsigned long long
8531/// u64;` being every bit as ordinary in C as `typedef unsigned __int128 u128;`.
8532fn window_ty(word_bits: u32, signed: bool, span: Span) -> TokenStream {
8533 match (word_bits, signed) {
8534 (128, false) => primitive_ty("u128", span),
8535 (128, true) => primitive_ty("i128", span),
8536 (_, false) => primitive_ty("u64", span),
8537 (_, true) => primitive_ty("i64", span),
8538 }
8539}
8540
8541/// `::core::primitive::u64` and every other primitive this code generator
8542/// writes.
8543///
8544/// **Every** bare primitive name goes through here, and none is ever written
8545/// as a bare identifier, because each of them is a name a C `typedef` can
8546/// take. `typedef _Bool bool;` is in the C23 compatibility header of half the
8547/// world's C — and in gcc.c-torture's `execute/20030714-1` — while `typedef
8548/// unsigned int u32;`, `typedef unsigned long usize;` and `typedef long long
8549/// i64;` are how a great deal of embedded C spells its types. The generated
8550/// item is then `pub type bool = bool;`, which is a cycle (`E0391`), and even
8551/// where it is not a cycle the alias shadows the primitive for the rest of the
8552/// module — so the padding of a `struct`, a bit-field accessor's window and a
8553/// pointer difference would all silently take the C type instead.
8554///
8555/// The [`core::primitive`] module exists for exactly this, and the leading
8556/// `::core` keeps it working in a crate that has renamed its own `core`.
8557fn primitive_ty(name: &str, span: Span) -> TokenStream {
8558 let ident = Ident::new(name, span);
8559 quote_spanned! {span=> ::core::primitive::#ident }
8560}
8561
8562/// Stamps every token of a stream with one span.
8563///
8564/// Only the crate path `#pragma cinrs crate` gives needs it: everything else
8565/// the generator emits is built token by token from a span it already has,
8566/// while that one is *parsed* out of a string and so arrives with call-site
8567/// spans that would send `rustc`'s complaint about a bad path to the wrong
8568/// place.
8569fn respan(tokens: TokenStream, span: Span) -> TokenStream {
8570 tokens
8571 .into_iter()
8572 .map(|tree| {
8573 let mut tree = match tree {
8574 TokenTree::Group(group) => {
8575 TokenTree::Group(Group::new(group.delimiter(), respan(group.stream(), span)))
8576 }
8577 other => other,
8578 };
8579 tree.set_span(span);
8580 tree
8581 })
8582 .collect()
8583}
8584
8585/// A string literal for an `assert!` message, which a `const` context needs to
8586/// be a literal rather than anything formatted.
8587fn message_literal(text: &str, span: Span) -> TokenStream {
8588 let mut literal = Literal::string(text);
8589 literal.set_span(span);
8590 TokenStream::from(TokenTree::Literal(literal))
8591}
8592
8593/// An array length, which Rust counts in `usize`.
8594fn usize_literal(value: u64, span: Span) -> TokenStream {
8595 let mut literal = Literal::usize_unsuffixed(value as usize);
8596 literal.set_span(span);
8597 TokenStream::from(TokenTree::Literal(literal))
8598}
8599
8600/// An integer literal with the Rust suffix `ty` names: `3i32`, `7u32`.
8601///
8602/// It is what an x86 intrinsic's immediate operand becomes, where the type of
8603/// `core::arch`'s `const` parameter has to be written out because a const
8604/// argument is not inferred from the parameter.
8605/// The head of an `asm!` operand, up to its expression: `o0 = lateout(reg)`,
8606/// `inout("eax")`, `o2 = const`.
8607fn asm_operand_head(operand: &ir::AsmOperand, span: Span) -> TokenStream {
8608 let dir = match &operand.kind {
8609 ir::AsmOperandKind::In(_) => "in",
8610 ir::AsmOperandKind::Out { late: true, .. } => "lateout",
8611 ir::AsmOperandKind::Out { late: false, .. } => "out",
8612 ir::AsmOperandKind::InOut { .. } | ir::AsmOperandKind::Scratch(_) => "inout",
8613 ir::AsmOperandKind::Const(_) => "const",
8614 };
8615 let dir = Ident::new(dir, span);
8616 let reg = match (&operand.kind, operand.reg) {
8617 (ir::AsmOperandKind::Const(_), _) => TokenStream::new(),
8618 (_, ir::AsmReg::Class(class)) => {
8619 let class = Ident::new(class, span);
8620 quote_spanned! {span=> (#class) }
8621 }
8622 (_, ir::AsmReg::Explicit(name)) => {
8623 let mut name = Literal::string(name);
8624 name.set_span(span);
8625 quote_spanned! {span=> (#name) }
8626 }
8627 };
8628 match &operand.name {
8629 Some(name) => {
8630 let name = Ident::new(name, span);
8631 quote_spanned! {span=> #name = #dir #reg }
8632 }
8633 None => quote_spanned! {span=> #dir #reg },
8634 }
8635}
8636
8637/// The value of an `asm!` `const` operand: an `i64` literal, or a `u64` one
8638/// for a value only that holds, so that no inference default narrows it.
8639fn asm_const_literal(value: i128, span: Span) -> TokenStream {
8640 let mut literal = if i64::try_from(value).is_ok() {
8641 Literal::i64_suffixed(value as i64)
8642 } else {
8643 Literal::u64_suffixed(value as u64)
8644 };
8645 literal.set_span(span);
8646 TokenStream::from(TokenTree::Literal(literal))
8647}
8648
8649fn suffixed_int_literal(value: i128, ty: &str, span: Span) -> TokenStream {
8650 let mut literal = match ty {
8651 // An unsigned `const` parameter takes the bit pattern the C constant
8652 // was reduced to, which is what a mask written as `-1` means.
8653 "u32" => Literal::u32_suffixed(value as u32),
8654 "u64" => Literal::u64_suffixed(value as u64),
8655 "i64" => Literal::i64_suffixed(value as i64),
8656 // `i32` is what every immediate operand in `core::arch` is.
8657 _ => Literal::i32_suffixed(value as i32),
8658 };
8659 literal.set_span(span);
8660 TokenStream::from(TokenTree::Literal(literal))
8661}
8662
8663/// The Rust floating type of a C floating type, and the mask that clears the
8664/// sign bit of its bit pattern.
8665///
8666/// `long double` is `double` here, so only the two widths exist.
8667fn float_bit_ty(ty: Ty, span: Span) -> (TokenStream, TokenStream) {
8668 if ty == Ty::Float {
8669 return (
8670 primitive_ty("f32", span),
8671 unsigned_hex_literal(0x7fff_ffff, "u32", span),
8672 );
8673 }
8674 (
8675 primitive_ty("f64", span),
8676 unsigned_hex_literal(0x7fff_ffff_ffff_ffff, "u64", span),
8677 )
8678}
8679
8680/// The quiet bit of a floating type: the leading bit of the mantissa, which is
8681/// set in a quiet NaN and clear in a signalling one.
8682fn quiet_bit_literal(ty: Ty, span: Span) -> TokenStream {
8683 if ty == Ty::Float {
8684 return unsigned_hex_literal(1 << 22, "u32", span);
8685 }
8686 unsigned_hex_literal(1 << 51, "u64", span)
8687}
8688
8689/// A hexadecimal literal with an explicit unsigned suffix.
8690fn unsigned_hex_literal(value: u64, suffix: &str, span: Span) -> TokenStream {
8691 let mut literal = Literal::from_str(&format!("0x{value:x}{suffix}"))
8692 .expect("a hexadecimal literal followed by a suffix is a token");
8693 literal.set_span(span);
8694 TokenStream::from(TokenTree::Literal(literal))
8695}
8696
8697fn float_literal_token(value: f64, span: Span) -> TokenStream {
8698 let mut literal = Literal::f64_unsuffixed(value.abs());
8699 literal.set_span(span);
8700 if value.is_sign_negative() {
8701 quote_spanned! {span=> -#literal }
8702 } else {
8703 TokenStream::from(TokenTree::Literal(literal))
8704 }
8705}
8706
8707fn bare_float_literal(value: f64, span: Span) -> TokenStream {
8708 float_literal_token(value, span)
8709}
8710
8711/// The constant an expression is, if it is one.
8712///
8713/// Sema folds conversions of constants, so a constant is always a bare `Int`
8714/// or `Float` node rather than a cast wrapping one.
8715/// The operands of a chain of comma operators, in source order.
8716///
8717/// `a, b, c` is `Comma(Comma(a, b), c)`, so this walks down the left spine
8718/// into a vector and hands it back the right way round. Iterating rather than
8719/// recursing is what lets a logical source line hold the 4095 characters C23
8720/// 5.2.5.2p1 asks for; see [`Codegen::binary_chain`].
8721fn comma_operands(expr: &Expr) -> Vec<&Expr> {
8722 let mut out = Vec::new();
8723 let mut node = expr;
8724 while let ExprKind::Comma { lhs, rhs } = &node.kind {
8725 out.push(&**rhs);
8726 node = lhs;
8727 }
8728 out.push(node);
8729 out.reverse();
8730 out
8731}
8732
8733fn constant_of(expr: &Expr) -> Option<ConstValue> {
8734 match &expr.kind {
8735 ExprKind::Int(value) => Some(ConstValue::Int(*value)),
8736 ExprKind::Float(value) if value.is_finite() => Some(ConstValue::Float(*value)),
8737 _ => None,
8738 }
8739}
8740
8741fn cmp_tokens(op: CmpOp, span: Span) -> TokenStream {
8742 match op {
8743 CmpOp::Lt => quote_spanned! {span=> < },
8744 CmpOp::Gt => quote_spanned! {span=> > },
8745 CmpOp::Le => quote_spanned! {span=> <= },
8746 CmpOp::Ge => quote_spanned! {span=> >= },
8747 CmpOp::Eq => quote_spanned! {span=> == },
8748 CmpOp::Ne => quote_spanned! {span=> != },
8749 }
8750}
8751
8752#[cfg(test)]
8753mod tests {
8754 use super::*;
8755
8756 /// What a unit spelling `names` gives each of them, as `(C, Rust)` pairs
8757 /// of everything that does not keep its own name.
8758 fn spellings(names: &[&str]) -> Vec<(String, String)> {
8759 let mut pairs: Vec<(String, String)> = unique_spellings(names.iter().copied())
8760 .into_iter()
8761 .collect();
8762 pairs.sort();
8763 pairs
8764 }
8765
8766 /// Asserts that `names` are spelled as `expected` says, and that the unit
8767 /// has no two names with one spelling.
8768 fn assert_spellings(names: &[&str], expected: &[(&str, &str)]) {
8769 let renamed = unique_spellings(names.iter().copied());
8770 let want: Vec<(String, String)> = expected
8771 .iter()
8772 .map(|(c, rust)| ((*c).to_owned(), (*rust).to_owned()))
8773 .collect();
8774 assert_eq!(spellings(names), want);
8775 let mut seen: HashMap<String, &str> = HashMap::new();
8776 for name in names {
8777 let spelling = match renamed.get(*name) {
8778 Some(unique) => unique.clone(),
8779 None => plain_spelling(name),
8780 };
8781 if let Some(other) = seen.insert(spelling.clone(), name) {
8782 assert_eq!(
8783 other, *name,
8784 "{other} and {name} are both spelled {spelling}"
8785 );
8786 }
8787 }
8788 }
8789
8790 #[test]
8791 fn a_name_rust_can_spell_keeps_it() {
8792 // Nothing at all is renamed in the program that has no collision,
8793 // keywords included: `match` is `r#match`, which is a token of its
8794 // own.
8795 assert_spellings(&["counter", "match", "loop", "café"], &[]);
8796 }
8797
8798 #[test]
8799 fn the_five_names_that_cannot_be_raw_grow_an_underscore() {
8800 assert_spellings(
8801 &["self", "Self", "super", "crate", "_"],
8802 &[
8803 ("Self", "Self_"),
8804 ("_", "__"),
8805 ("crate", "crate_"),
8806 ("self", "self_"),
8807 ("super", "super_"),
8808 ],
8809 );
8810 }
8811
8812 #[test]
8813 fn a_dollar_is_spelled_out() {
8814 assert_spellings(
8815 &["a$b", "$", "x$"],
8816 &[
8817 ("$", "_dollar_"),
8818 ("a$b", "a_dollar_b"),
8819 ("x$", "x_dollar_"),
8820 ],
8821 );
8822 }
8823
8824 #[test]
8825 fn a_spelling_the_program_already_uses_grows_another_underscore() {
8826 // The collision the whole mechanism exists for: `self` cannot be
8827 // `self_`, because the program has a `self_` of its own.
8828 assert_spellings(&["self", "self_"], &[("self", "self__")]);
8829 assert_spellings(&["self", "self_", "self__"], &[("self", "self___")]);
8830 assert_spellings(&["a$b", "a_dollar_b"], &[("a$b", "a_dollar_b_")]);
8831 }
8832
8833 #[test]
8834 fn the_answer_does_not_depend_on_the_order_the_names_arrive_in() {
8835 let forwards = spellings(&["self", "self_", "crate", "crate_", "a$b", "a_dollar_b"]);
8836 let backwards = spellings(&["a_dollar_b", "a$b", "crate_", "crate", "self_", "self"]);
8837 assert_eq!(forwards, backwards);
8838 }
8839
8840 #[test]
8841 fn a_name_is_spelled_the_same_way_however_often_it_is_collected() {
8842 // Every name space is collected into one list, so a tag, a member and
8843 // a local all spelled `self` arrive several times over.
8844 assert_spellings(&["self", "self", "self_", "self"], &[("self", "self__")]);
8845 }
8846}