Skip to main content

cinrs_core/
lib.rs

1//! The `cinrs` C front end.
2//!
3//! This crate holds everything the `c89!`, `c99!`, `c11!`, `c17!` and `c23!`
4//! procedural macros do — they are one pipeline parameterised by
5//! [`Standard`] — but is built on [`proc_macro2`] alone and never touches
6//! `proc_macro`. That makes the whole pipeline — input capture, lexing,
7//! preprocessing, parsing, sema and code generation — unit-testable outside a
8//! procedural macro context.
9//!
10//! The pipeline is:
11//!
12//! ```text
13//! TokenStream ──capture──▶ (C source text, SourceMap)
14//!             ──lex─────▶ Vec<lex::Token>     (byte ranges into that text)
15//!             ──pp──────▶ Vec<pp::Token>      (directives gone, macros gone)
16//!             ──parse───▶ TranslationUnit     (every node carries a range)
17//!             ──sema────▶ ir::Program         (typed, conversions explicit)
18//!             ──codegen─▶ TokenStream         (every token spanned at its C)
19//! ```
20//!
21//! A function that jumps takes one more step on the way: sema hands its body
22//! to [`cfg`](mod@cfg), which turns it into basic blocks that codegen emits as a state
23//! machine. See that module for why, and for what it costs.
24//!
25//! Which revision is being compiled reaches every pass that has an opinion
26//! about it: the [lexer](mod@lex) (which spellings are keywords, and the C23
27//! constant forms), the [preprocessor](mod@pp) (`__VA_OPT__`, `#elifdef`,
28//! `__STDC_VERSION__`), the [parser](mod@parse) (the C11 and C23 grammar) and
29//! [sema](mod@sema) (a C23 keyword used as a name in an older block). A
30//! feature from a later revision is a diagnostic naming the macro that would
31//! have it; see [`Standard::requires`].
32//!
33//! Everything downstream reports problems as [`Diagnostic`]s carrying a
34//! [`SourceRange`]; [`Diagnostics::to_token_stream`] turns those into
35//! `compile_error!` invocations whose tokens are spanned at the exact C token
36//! that caused them. That is the point of the whole design: an error — ours or
37//! `rustc`'s — must land on the C code the user wrote. The lexer takes part in
38//! that by *not* reporting: its problems ride on the tokens they were found
39//! in, and the [preprocessor](mod@pp) reports only the ones whose token
40//! survives, because a group skipped by `#if 0` may hold anything at all.
41//! A token a macro produced carries the range of the *invocation*, which is
42//! the only place the user can look; [`pp::Expansions::annotate`] adds the
43//! `in expansion of macro 'X'` note that says how it got there.
44//!
45//! Capture also hands sema a [unit id](capture::Source::unit_id) identifying
46//! the invocation, which every synthetic name the expansion needs is built
47//! from — the renamed `extern` *objects*, the mangled function-local
48//! `static`s, the names given to anonymous tags, and the module the whole
49//! expansion goes into (see [`expand`]), so that two `c99!` blocks in one Rust
50//! module never collide.
51//!
52//! # Where `#include` fits
53//!
54//! A header is another file in the same offset space, so nothing downstream of
55//! the preprocessor has to know it exists: a [`SourceRange`] identifies a file
56//! as well as a position, and a diagnostic inside a header resolves to the
57//! span of the `#include` that pulled it in, with the header's own path, line
58//! and column put into the message text.
59//!
60//! The one seam is that the preprocessor runs on a thread where a
61//! `proc_macro2::Span` cannot follow it, so it *allocates* the offsets of the
62//! files it opens and hands them back — see [`pp::Preprocessed::included`] and
63//! [`SourceMap::next_base`] — and [`analyze`] adds them to the map afterwards,
64//! in the order they were opened. The [`include`](mod@include) module is where
65//! a header name is resolved and what is bundled; the user headers that were
66//! read come back as [`Analysis::user_headers`], which [`expand`] turns into
67//! the `include_str!` items that make Cargo rebuild when one changes. C23's
68//! `#embed` takes the same route with [`Analysis::embedded_files`] and
69//! `include_bytes!`, since a resource is bytes rather than text.
70//!
71//! # Where `include_c99!` fits
72//!
73//! [`expand_include`] is [`expand`] with a `.c` file in place of the token
74//! stream: the file becomes the map's root — see
75//! [`capture::capture_c_file`] — and every pass after that is the same one.
76//! Since nothing in the `.rs` file corresponds to a position in the `.c`, that
77//! root resolves every range to the span of the macro invocation and carries
78//! its own `path:line:column` into the message, which is exactly what a header
79//! already does.
80//!
81//! # Example
82//!
83//! ```
84//! use std::str::FromStr;
85//! use cinrs_core::{expand, Options, Standard};
86//!
87//! let input = proc_macro2::TokenStream::from_str("int add(int a, int b) { return a + b; }")
88//!     .unwrap();
89//! let out = expand(input, &Options::new(Standard::C99));
90//! assert!(out.to_string().contains("extern \"C\" fn add"));
91//! ```
92
93#![warn(missing_docs)]
94
95pub mod ast;
96pub mod capture;
97pub mod cfg;
98pub mod codegen;
99pub mod complex;
100pub mod diag;
101pub mod dump;
102pub mod gnu;
103pub mod include;
104pub mod ir;
105pub mod lex;
106mod locate;
107pub mod parse;
108pub mod pp;
109pub mod regions;
110pub mod sema;
111pub mod target;
112
113use std::path::{Path, PathBuf};
114
115use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
116use quote::quote;
117
118pub use ast::TranslationUnit;
119pub use capture::{FileId, InputMode, Origin, Pos, Source, SourceMap, SourceRange, Subspan};
120pub use diag::{Diagnostic, Diagnostics, Level};
121pub use ir::{Program, Ty};
122pub use pp::Token;
123pub use target::{Arch, Env, Os, TargetModel, TargetSource, UnknownTarget};
124
125/// The environment variable that names the target the expansion is for.
126///
127/// A procedural macro cannot ask `rustc` what it is compiling for, so the
128/// crate being built says it, from its own build script:
129///
130/// ```text
131/// println!("cargo:rustc-env=CINRS_TARGET={}", std::env::var("TARGET").unwrap());
132/// ```
133///
134/// `cargo:rustc-env` reaches the very `rustc` process that runs the macro, and
135/// Cargo makes the value part of the crate's fingerprint, so changing the
136/// `--target` rebuilds. See [`target`] for the whole order of precedence.
137pub const TARGET_ENV_VAR: &str = "CINRS_TARGET";
138
139/// Which revision of the C standard to accept.
140///
141/// The variants are ordered, so a feature is gated by comparing: a construct
142/// C11 introduced is accepted when `standard >= Standard::C11`. C17 is C11
143/// with a different `__STDC_VERSION__` and adds nothing else.
144#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
145pub enum Standard {
146    /// ISO/IEC 9899:1990, the standard everyone still calls C89.
147    ///
148    /// C90 is the ISO republication of ANSI X3.159-1989 with no technical
149    /// change, so `c89!` and `c90!` are one entry point under two names.
150    C89,
151    /// ISO/IEC 9899:1999.
152    #[default]
153    C99,
154    /// ISO/IEC 9899:2011.
155    C11,
156    /// ISO/IEC 9899:2018.
157    C17,
158    /// ISO/IEC 9899:2024.
159    C23,
160}
161
162impl Standard {
163    /// The name used in diagnostics.
164    pub fn as_str(self) -> &'static str {
165        match self {
166            Standard::C89 => "C89",
167            Standard::C99 => "C99",
168            Standard::C11 => "C11",
169            Standard::C17 => "C17",
170            Standard::C23 => "C23",
171        }
172    }
173
174    /// The macro that selects this standard, as a diagnostic names it.
175    pub fn macro_name(self) -> &'static str {
176        self.macro_name_in(Dialect::Iso)
177    }
178
179    /// The macro that selects this standard in `dialect`.
180    pub fn macro_name_in(self, dialect: Dialect) -> &'static str {
181        match (dialect, self) {
182            (Dialect::Iso, Standard::C89) => "c89!",
183            (Dialect::Gnu, Standard::C89) => "gnu89!",
184            (Dialect::Iso, Standard::C99) => "c99!",
185            (Dialect::Iso, Standard::C11) => "c11!",
186            (Dialect::Iso, Standard::C17) => "c17!",
187            (Dialect::Iso, Standard::C23) => "c23!",
188            (Dialect::Gnu, Standard::C99) => "gnu99!",
189            (Dialect::Gnu, Standard::C11) => "gnu11!",
190            (Dialect::Gnu, Standard::C17) => "gnu17!",
191            (Dialect::Gnu, Standard::C23) => "gnu23!",
192        }
193    }
194
195    /// Every name the macro that selects this standard in `dialect` may be
196    /// written with, without the `!`.
197    ///
198    /// Two of them only for C89, which has two names and one entry point; the
199    /// point of the list is that [the search](capture::Origin) for an invocation
200    /// in the crate's sources knows what to look for, and `c90! { … }` has to be
201    /// found as readily as `c89! { … }`.
202    pub fn macro_names_in(self, dialect: Dialect) -> &'static [&'static str] {
203        match (dialect, self) {
204            (Dialect::Iso, Standard::C89) => &["c89", "c90"],
205            (Dialect::Gnu, Standard::C89) => &["gnu89"],
206            (Dialect::Iso, Standard::C99) => &["c99"],
207            (Dialect::Iso, Standard::C11) => &["c11"],
208            (Dialect::Iso, Standard::C17) => &["c17"],
209            (Dialect::Iso, Standard::C23) => &["c23"],
210            (Dialect::Gnu, Standard::C99) => &["gnu99"],
211            (Dialect::Gnu, Standard::C11) => &["gnu11"],
212            (Dialect::Gnu, Standard::C17) => &["gnu17"],
213            (Dialect::Gnu, Standard::C23) => &["gnu23"],
214        }
215    }
216
217    /// The same for the `include_…!` family, which is one entry point per name
218    /// of [`Standard::macro_names_in`].
219    pub fn include_macro_names_in(self, dialect: Dialect) -> &'static [&'static str] {
220        match (dialect, self) {
221            (Dialect::Iso, Standard::C89) => &["include_c89", "include_c90"],
222            (Dialect::Gnu, Standard::C89) => &["include_gnu89"],
223            (Dialect::Iso, Standard::C99) => &["include_c99"],
224            (Dialect::Iso, Standard::C11) => &["include_c11"],
225            (Dialect::Iso, Standard::C17) => &["include_c17"],
226            (Dialect::Iso, Standard::C23) => &["include_c23"],
227            (Dialect::Gnu, Standard::C99) => &["include_gnu99"],
228            (Dialect::Gnu, Standard::C11) => &["include_gnu11"],
229            (Dialect::Gnu, Standard::C17) => &["include_gnu17"],
230            (Dialect::Gnu, Standard::C23) => &["include_gnu23"],
231        }
232    }
233
234    /// The message a feature from a newer revision gets in this one.
235    ///
236    /// `what` is the subject, already quoted where it names a token:
237    /// `standard.requires("'_Static_assert'", Standard::C11)` reads
238    /// `'_Static_assert' requires C11 or later (this block is c99!)`. Saying
239    /// which macro the block is written with is the point — the fix is to
240    /// change the macro, and nothing in the C says which one it is.
241    pub fn requires(self, what: &str, needed: Standard) -> String {
242        format!(
243            "{what} requires {} or later (this block is {})",
244            needed.as_str(),
245            self.macro_name()
246        )
247    }
248}
249
250/// Whether the GNU extensions that need a plain spelling are switched on.
251///
252/// GCC draws the same line between `-std=c99` and `-std=gnu99`: everything
253/// spelled with a double underscore (`__typeof__`, `__attribute__`,
254/// `__builtin_*`, `__extension__`) is available either way, because those names
255/// are reserved and cannot collide with a user's own; only the plain spellings
256/// — `typeof`, `asm` — need the GNU dialect, and only there is a feature of a
257/// *newer* revision accepted without a diagnostic (GCC takes `_Static_assert`
258/// in `gnu99`).
259///
260/// See [`doc/gnu-extensions.md`](https://github.com/tanakh/cinrs/blob/master/doc/gnu-extensions.md)
261/// in the repository for the whole catalogue.
262#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
263pub enum Dialect {
264    /// Strict ISO C: `c89!`, `c99!`, `c11!`, `c17!`, `c23!`.
265    #[default]
266    Iso,
267    /// ISO C plus the GNU extensions: `gnu89!`, `gnu99!`, `gnu11!`, `gnu17!`,
268    /// `gnu23!`.
269    Gnu,
270}
271
272impl Dialect {
273    /// Whether this is a GNU dialect.
274    pub fn is_gnu(self) -> bool {
275        self == Dialect::Gnu
276    }
277}
278
279/// Whether the compiler supports C-variadic definitions and
280/// [`core::ffi::VaList`], which Rust stabilised in 1.99.
281///
282/// This crate is compiled by the very toolchain that will compile the code it
283/// generates, so the answer is exact rather than a guess: a `c99!` invocation
284/// that defines a variadic function, or that declares a `va_list` object, is
285/// diagnosed as needing a newer Rust instead of producing an expansion the
286/// compiler rejects with `E0658`.
287#[rustversion::since(1.99)]
288pub const C_VARIADIC_SUPPORTED: bool = true;
289/// Whether the compiler supports C-variadic definitions and
290/// [`core::ffi::VaList`], which Rust stabilised in 1.99.
291#[rustversion::before(1.99)]
292pub const C_VARIADIC_SUPPORTED: bool = false;
293
294/// Whether the complex types are available, which is this crate's `complex`
295/// feature.
296///
297/// The feature exists because the generated code for a `_Complex` value names
298/// a *runtime* type — `::cinrs::rt::Complex`, which is `num_complex::Complex`
299/// — and a build that does not want the dependency says
300/// `default-features = false` on the `cinrs` crate. It is only the default of
301/// [`Options::complex`]; the front end itself is compiled either way.
302pub const COMPLEX_SUPPORTED: bool = cfg!(feature = "complex");
303
304/// What every diagnostic about a complex type says when
305/// [`Options::complex`] is off.
306///
307/// One message, in one place, because the lexer (an imaginary constant), the
308/// parser (`__real__`) and sema (the type itself) all have to give it.
309pub const COMPLEX_UNSUPPORTED: &str = "complex types are not supported here: '_Complex' needs the 'complex' feature of the \
310     cinrs crate, which is on by default and supplies the runtime the generated code links \
311     against";
312
313/// Knobs for one macro expansion.
314///
315/// Not [`Copy`], because [`Options::include_paths`] owns its list; the front
316/// end clones it once per invocation.
317#[derive(Clone, Debug)]
318pub struct Options {
319    /// Which standard to accept.
320    pub standard: Standard,
321    /// Whether the plain-spelled GNU extensions are switched on, and whether a
322    /// feature of a newer revision is accepted silently. See [`Dialect`].
323    pub dialect: Dialect,
324    /// Accept `$` in identifiers, like GCC's `-fdollars-in-identifiers`.
325    ///
326    /// **On by default**, which is where GCC and Clang both keep it: WG14
327    /// DR027 lets an implementation put characters outside the basic source
328    /// character set into an identifier, GCC takes `$` unconditionally, and
329    /// Clang takes it with a warning that only `-pedantic-errors` promotes.
330    /// A `$` that reaches the generated Rust — which has no such spelling —
331    /// is written `_dollar_` there, and the C name is what the symbol still
332    /// links by.
333    pub dollar_in_identifiers: bool,
334    /// Directories `#include` searches, after the ones the unit itself names
335    /// with `#pragma cinrs include_path` and before the bundled headers.
336    ///
337    /// This is the programmatic way in; see [`crate::include`] for the whole
338    /// search order and for the `CINRS_INCLUDE_PATH` environment variable,
339    /// which comes last.
340    pub include_paths: Vec<PathBuf>,
341    /// Whether `#include` also searches the platform's own directories, and
342    /// where in the order they go.
343    ///
344    /// **Off by default**, which is what keeps a unit self-contained and
345    /// portable across [target models](target). [`analyze`] replaces this with
346    /// what [`include::SYSTEM_ENV_VAR`] says when the caller left it at
347    /// [`include::System::Off`], and the unit's own
348    /// `#pragma cinrs system_include` replaces it again; see
349    /// [`mod@include`] for the whole order and for the directories themselves.
350    pub system_include: include::System,
351    /// The data model the generated code is compiled for.
352    ///
353    /// Defaults to the host's, which [`analyze`] replaces with the one
354    /// [`TARGET_ENV_VAR`] names and the unit's own
355    /// `#pragma cinrs target` replaces again; see [`target`] for the order.
356    /// Whatever it ends up being, the expansion states it — the
357    /// `const _: () = { assert!(…); };` block every unit opens with is built
358    /// from *this* model, so a unit expanded for one data model and compiled
359    /// for another fails to compile.
360    ///
361    /// Setting it directly — [`Options::for_target`] is the tidy way — marks
362    /// [`Options::target_source`] `Explicit`, and the environment variable is
363    /// then left alone.
364    pub target: TargetModel,
365    /// Where [`Options::target`] came from, which the diagnostics name.
366    pub target_source: TargetSource,
367    /// Whether `va_list` and variadic *definitions* may be generated.
368    ///
369    /// Defaults to [`C_VARIADIC_SUPPORTED`], which is exactly what the
370    /// compiling toolchain can do; a test that wants to see the diagnostics an
371    /// older toolchain produces — or the code a newer one would generate — can
372    /// set it either way.
373    pub c_variadic: bool,
374    /// Whether the complex types are available.
375    ///
376    /// Defaults to [`COMPLEX_SUPPORTED`], which is this crate's `complex`
377    /// feature — the one the `cinrs` crate turns on to supply the `cinrs-rt`
378    /// runtime the generated code names. With it off, `_Complex` is a
379    /// diagnostic, `__STDC_NO_COMPLEX__` is predefined, and nothing generated
380    /// needs more than `core`. The front end carries the support either way, so
381    /// a test may set this in either direction.
382    pub complex: bool,
383}
384
385impl Default for Options {
386    fn default() -> Self {
387        Self::new(Standard::default())
388    }
389}
390
391impl Options {
392    /// Default options for `standard`, in the strict ISO dialect.
393    pub fn new(standard: Standard) -> Self {
394        Self::with_dialect(standard, Dialect::Iso)
395    }
396
397    /// Default options for `standard` in the GNU dialect — what `gnu99!` and
398    /// friends use.
399    pub fn gnu(standard: Standard) -> Self {
400        Self::with_dialect(standard, Dialect::Gnu)
401    }
402
403    /// Default options for `standard` in `dialect`.
404    pub fn with_dialect(standard: Standard, dialect: Dialect) -> Self {
405        Self {
406            standard,
407            dialect,
408            dollar_in_identifiers: true,
409            include_paths: Vec::new(),
410            system_include: include::System::Off,
411            target: TargetModel::host(),
412            target_source: TargetSource::Host,
413            c_variadic: C_VARIADIC_SUPPORTED,
414            complex: COMPLEX_SUPPORTED,
415        }
416    }
417
418    /// These options with the complex types switched on or off; see
419    /// [`Options::complex`].
420    pub fn with_complex(mut self, complex: bool) -> Self {
421        self.complex = complex;
422        self
423    }
424
425    /// These options with `target` set, and marked as the caller's choice so
426    /// that [`TARGET_ENV_VAR`] does not override it.
427    ///
428    /// What a test that wants the ILP32 or LLP64 rules uses; a unit still
429    /// overrides it with `#pragma cinrs target`.
430    pub fn for_target(mut self, target: TargetModel) -> Self {
431        self.target = target;
432        self.target_source = TargetSource::Explicit;
433        self
434    }
435
436    /// The macro that selects this entry point, as a diagnostic names it.
437    pub fn macro_name(&self) -> &'static str {
438        self.standard.macro_name_in(self.dialect)
439    }
440
441    /// The [origin](Origin) a real expansion of this entry point has: the names
442    /// the invocation may be written with, and the crate directory Cargo names.
443    ///
444    /// This is what the procedural macros hand to [`expand_with`], and the only
445    /// thing that lets capture find the invocation in the crate's sources when
446    /// the host reports no positions. [`expand`] and [`analyze`] deliberately do
447    /// not use it; see [`Origin`].
448    pub fn origin(&self) -> Origin {
449        Origin::new(self.standard.macro_names_in(self.dialect))
450    }
451
452    /// The same for the `include_…!` entry point of this standard and dialect.
453    pub fn include_origin(&self) -> Origin {
454        Origin::new(self.standard.include_macro_names_in(self.dialect))
455    }
456
457    /// How a pass gates the features of a newer revision.
458    pub fn gating(&self) -> Gating {
459        Gating {
460            standard: self.standard,
461            dialect: self.dialect,
462        }
463    }
464}
465
466/// The pair every pass needs to answer "may this block write that?".
467///
468/// A GNU dialect answers yes to everything a later revision added, exactly as
469/// GCC's `-std=gnu99` does; the strict entry points keep the diagnostic that
470/// names the macro to write instead.
471#[derive(Clone, Copy, Debug, Default)]
472pub struct Gating {
473    /// The revision the block is written in.
474    pub standard: Standard,
475    /// Whether the GNU extensions are switched on.
476    pub dialect: Dialect,
477}
478
479impl Gating {
480    /// The message a feature from a newer revision gets here, or `None` when it
481    /// is accepted.
482    pub fn requires(self, what: &str, needed: Standard) -> Option<String> {
483        if self.dialect.is_gnu() || self.standard >= needed {
484            return None;
485        }
486        Some(format!(
487            "{what} requires {} or later (this block is {})",
488            needed.as_str(),
489            self.standard.macro_name_in(self.dialect)
490        ))
491    }
492
493    /// Whether a declaration with no type specifier at all means `int`
494    /// (C89 6.5.2).
495    ///
496    /// C99 removed implicit `int` (N635) and GCC diagnoses it in every later
497    /// mode, `-std=gnu99` included, so this is one of the three places where
498    /// `gnu89!` is *older* than `gnu99!` rather than a superset of it.
499    pub fn implicit_int(self) -> bool {
500        self.standard < Standard::C99
501    }
502
503    /// Whether a call to a function nobody declared declares `extern int f();`
504    /// at file scope (C89 6.3.2.2).
505    ///
506    /// C99 removed the rule (N636); see [`Gating::implicit_int`] for why the
507    /// GNU dialect does not bring it back.
508    pub fn implicit_function_declarations(self) -> bool {
509        self.standard < Standard::C99
510    }
511
512    /// Whether an old-style (K&R) function definition may be written.
513    ///
514    /// Obsolescent from C89 onwards and *removed* by C23 (N2432), so every
515    /// entry point below `c23!` has it and the two C23 ones do not.
516    pub fn old_style_definitions(self) -> bool {
517        self.standard < Standard::C23
518    }
519
520    /// The gate message for `name`, if another entry point would have made it
521    /// a keyword.
522    ///
523    /// `nullptr`, `bool` and the rest are ordinary identifiers before C23 — the
524    /// bundled `<stdbool.h>` writes `#define bool _Bool` — so a `c11!` block
525    /// that uses one gets told what it would have meant. A GNU dialect says
526    /// nothing about those: GCC's `gnu11` has no `bool` keyword either, so
527    /// "use of undeclared identifier" is the honest answer there.
528    ///
529    /// `typeof` and `asm` are the two the *dialect* decides, so their message
530    /// names the entry point that has them.
531    pub fn newer_keyword(self, name: &str) -> Option<String> {
532        if self.dialect.is_gnu() {
533            return None;
534        }
535        let gnu = self.standard.macro_name_in(Dialect::Gnu);
536        let here = self.standard.macro_name_in(self.dialect);
537        match name {
538            "typeof" | "typeof_unqual" if self.standard < Standard::C23 => {
539                return Some(format!(
540                    "'{name}' requires a GNU dialect ({gnu}) or C23 or later \
541                     (this block is {here})"
542                ));
543            }
544            "asm" => {
545                return Some(format!(
546                    "'{name}' requires a GNU dialect ({gnu}); the spelling '__asm__' is \
547                     available everywhere (this block is {here})"
548                ));
549            }
550            _ => {}
551        }
552        let needed = crate::lex::Keyword::from_str(name, Standard::C23)?.since();
553        self.requires(&format!("'{name}'"), needed)
554    }
555}
556
557/// The result of running the front end over one macro invocation.
558pub struct Analysis {
559    /// The captured C source and its map back to Rust spans, headers and all.
560    pub source: Source,
561    /// The preprocessed C token list, ending with [`lex::TokenKind::Eof`].
562    pub tokens: Vec<Token>,
563    /// The parsed translation unit.
564    pub unit: TranslationUnit,
565    /// Everything that went wrong.
566    pub diagnostics: Diagnostics,
567    /// The macro invocations the preprocessor replaced, which later passes'
568    /// diagnostics are annotated from.
569    pub expansions: pp::Expansions,
570    /// The absolute paths of the user headers that were read, which the
571    /// expansion mentions so that Cargo rebuilds when one changes.
572    pub user_headers: Vec<PathBuf>,
573    /// The absolute paths of the resources `#embed` read, mentioned in the
574    /// expansion for the same reason.
575    pub embedded_files: Vec<PathBuf>,
576    /// The libraries `#pragma cinrs link` asked the expansion to be linked
577    /// against, each of which becomes an `extern` block of its own.
578    pub link_libraries: Vec<String>,
579    /// The functions `#pragma cinrs safe` asked to be generated without
580    /// `unsafe`; see [`sema::check_safe`].
581    pub safe_functions: Vec<pp::SafeName>,
582    /// Whether `#pragma cinrs export` asked for real C symbols.
583    pub export: bool,
584    /// Whether `#pragma cinrs no_std` said the expansion goes into a
585    /// `#![no_std]` crate, so that the storage a variable length array or
586    /// `alloca` needs comes from `alloc` rather than from `std`.
587    pub no_std: bool,
588    /// The Rust path `#pragma cinrs crate` gave the `cinrs` facade crate, if
589    /// any; see [`ir::DEFAULT_CRATE_PATH`].
590    pub crate_path: Option<String>,
591    /// The options the rest of the pipeline is to run with.
592    ///
593    /// These are the caller's, with the target model resolved: whatever
594    /// [`TARGET_ENV_VAR`] and the unit's own `#pragma cinrs target` had to say
595    /// is already in [`Options::target`], so sema and code generation must use
596    /// *these* rather than the ones they were handed.
597    pub options: Options,
598}
599
600/// Stack size for the thread the recursive passes run on.
601///
602/// Recursive descent turns nesting in the input into stack frames, and an
603/// unoptimised build of a procedural macro — which is what a `cargo build`
604/// uses — spends tens of kilobytes on each one. `rustc` runs macro expansion
605/// on an 8 MiB stack, which combined with the parser's own recursion limit
606/// would be uncomfortably tight, and a stack overflow inside a procedural
607/// macro aborts the compiler with no useful message at all. Reserving address
608/// space is free until it is touched, so the deep passes get a roomy thread of
609/// their own and the recursion limit stays the only way to run out.
610const WORKER_STACK_SIZE: usize = 64 << 20;
611
612/// Runs `f` on a thread with [`WORKER_STACK_SIZE`] of stack.
613///
614/// The argument travels through a cell rather than being captured directly so
615/// that it can be recovered and the work done in place if the thread cannot be
616/// created at all.
617fn on_large_stack<A, T>(arg: A, f: fn(A) -> T) -> T
618where
619    A: Send + 'static,
620    T: Send + 'static,
621{
622    use std::sync::{Arc, Mutex};
623
624    let cell = Arc::new(Mutex::new(Some(arg)));
625    let worker = Arc::clone(&cell);
626    let spawned = std::thread::Builder::new()
627        .name("cinrs-worker".to_owned())
628        .stack_size(WORKER_STACK_SIZE)
629        .spawn(move || {
630            let arg = worker
631                .lock()
632                .expect("the argument cell is never poisoned before use")
633                .take()
634                .expect("the argument is taken exactly once");
635            f(arg)
636        });
637    match spawned {
638        Ok(handle) => match handle.join() {
639            Ok(result) => result,
640            Err(payload) => std::panic::resume_unwind(payload),
641        },
642        Err(_) => {
643            // The thread could not be created; run here and rely on the
644            // recursion limit alone.
645            let arg = cell
646                .lock()
647                .expect("the thread never started, so nothing poisoned the cell")
648                .take()
649                .expect("the argument is still there");
650            f(arg)
651        }
652    }
653}
654
655/// Everything the lexer, preprocessor and parser need, in one `Send` bundle.
656struct FrontEndInput {
657    /// The captured C source text.
658    ctx: pp::Context,
659    /// The range the whole translation unit covers.
660    unit_range: SourceRange,
661    options: Options,
662}
663
664/// The lexer's, preprocessor's and parser's results.
665struct FrontEndOutput {
666    tokens: Vec<Token>,
667    unit: TranslationUnit,
668    diagnostics: Diagnostics,
669    expansions: pp::Expansions,
670    included: Vec<pp::IncludedFile>,
671    user_headers: Vec<PathBuf>,
672    embedded_files: Vec<PathBuf>,
673    link_libraries: Vec<String>,
674    safe_functions: Vec<pp::SafeName>,
675    export: bool,
676    no_std: bool,
677    crate_path: Option<String>,
678    /// The options with the target model resolved; see [`Analysis::options`].
679    options: Options,
680}
681
682/// Lexes, preprocesses and parses one translation unit.
683fn front_end(input: FrontEndInput) -> FrontEndOutput {
684    let FrontEndInput {
685        mut ctx,
686        unit_range,
687        mut options,
688    } = input;
689    let mut diagnostics = Diagnostics::new();
690    let mut raw = lex::lex_text(&ctx.text, ctx.base, &(&options).into());
691    // `#pragma cinrs target` has to be answered before anything else looks at
692    // the model: the predefined macros are built from it, so it cannot be a
693    // pragma like the others, handled where it stands. The scan is lexical and
694    // over the unit's own text only; see [`pp::scan_target_pragma`]. A pragma
695    // that really did change the model means the text has to be lexed again,
696    // because how wide `wchar_t` is decides what `L'…'` may hold.
697    let (target_pragmas, relex) = pp::scan_target_pragma(&raw, &mut options, &mut diagnostics);
698    ctx.target_pragmas = target_pragmas;
699    if relex {
700        raw = lex::lex_text(&ctx.text, ctx.base, &(&options).into());
701    }
702    let pp::Preprocessed {
703        tokens,
704        expansions,
705        included,
706        user_headers,
707        embedded_files,
708        link_libraries,
709        safe_functions,
710        export,
711        no_std,
712        crate_path,
713        pack_events,
714    } = pp::preprocess(&raw, &ctx, &options, &mut diagnostics);
715    let packing = pp::PackMap::new(pack_events);
716    let unit = parse::parse(&tokens, unit_range, &packing, &options, &mut diagnostics);
717    // Annotate here rather than at the end: every diagnostic is annotated
718    // exactly once, right after the pass that produced it.
719    expansions.annotate(&mut diagnostics);
720    FrontEndOutput {
721        tokens,
722        unit,
723        diagnostics,
724        expansions,
725        included,
726        user_headers,
727        embedded_files,
728        link_libraries,
729        safe_functions,
730        export,
731        no_std,
732        crate_path,
733        options,
734    }
735}
736
737/// Runs capture, lexing, preprocessing and parsing over `input`.
738///
739/// This is the entry point tests use when they want to look at the
740/// intermediate results; [`expand`] is the one the macro calls, and it adds
741/// semantic analysis and code generation on top.
742pub fn analyze(input: TokenStream, options: &Options) -> Analysis {
743    analyze_with(input, options, &Origin::unknown())
744}
745
746/// Runs capture, lexing, preprocessing and parsing over `input`, with
747/// everything the host says about the invocation itself.
748///
749/// See [`Origin`]; [`analyze`] is this with an origin that says nothing.
750pub fn analyze_with(input: TokenStream, options: &Options, origin: &Origin) -> Analysis {
751    let mut diagnostics = Diagnostics::new();
752    // Capture must stay on this thread: it handles `proc_macro2::Span`s, which
753    // are not `Send`. Everything after it works on plain byte offsets.
754    let source = capture::capture_with(input, &mut diagnostics, origin);
755    analyze_source(source, options, diagnostics)
756}
757
758/// Runs the front end over a [`Source`] that has already been captured.
759///
760/// [`analyze_with`] is this with the capture in front of it; the other caller
761/// is [`expand_include`], whose source is a `.c` file rather than a token
762/// stream.
763fn analyze_source(mut source: Source, options: &Options, mut diagnostics: Diagnostics) -> Analysis {
764    // The environment is read here rather than in `Options::new`, so that the
765    // diagnostic a bad `CINRS_TARGET` deserves has a range to sit on — the
766    // whole invocation, there being nothing in the C to point at.
767    let mut options = options.clone();
768    apply_env_target(&mut options, source.root_range(), &mut diagnostics);
769    apply_env_system_include(&mut options, source.root_range(), &mut diagnostics);
770    let file = source.map.file(source.root);
771    let arg = FrontEndInput {
772        ctx: pp::Context {
773            text: file.text().to_owned(),
774            base: file.base(),
775            file_name: file.rust_path().unwrap_or(pp::DEFAULT_FILE_NAME).to_owned(),
776            first_line: file.first_line(),
777            dir: including_directory(file.rust_path()),
778            next_base: source.map.next_base(),
779            // Filled in by `front_end`, which is where the scan runs.
780            target_pragmas: pp::TargetPragmas::default(),
781        },
782        unit_range: source.root_range(),
783        options,
784    };
785    let out = on_large_stack(arg, front_end);
786    // The preprocessor allocated the offsets; the map hands out the spans for
787    // them. Adding the files in the order they were opened is what makes a
788    // diagnostic inside a nested header point at the outermost `#include`,
789    // since the file each directive is written in is already in the map.
790    for header in &out.included {
791        let span = source.map.span(header.directive);
792        let id = source
793            .map
794            .add_included_file(header.name.clone(), header.text.clone(), span);
795        debug_assert_eq!(
796            source.map.file(id).base(),
797            header.base,
798            "the preprocessor and the source map disagree about where '{}' starts",
799            header.name
800        );
801    }
802    diagnostics.extend(out.diagnostics);
803
804    Analysis {
805        source,
806        tokens: out.tokens,
807        unit: out.unit,
808        diagnostics,
809        expansions: out.expansions,
810        user_headers: out.user_headers,
811        embedded_files: out.embedded_files,
812        link_libraries: out.link_libraries,
813        safe_functions: out.safe_functions,
814        export: out.export,
815        no_std: out.no_std,
816        crate_path: out.crate_path,
817        options: out.options,
818    }
819}
820
821/// Resolves [`TARGET_ENV_VAR`] into `options`, reporting a triple that names
822/// no machine this crate models.
823///
824/// Only when the caller left the model at the host's: an
825/// [`Options::for_target`] is a deliberate choice, and a test that sets one
826/// must not have the developer's own environment change the answer.
827fn apply_env_target(options: &mut Options, range: SourceRange, diagnostics: &mut Diagnostics) {
828    if options.target_source != TargetSource::Host {
829        return;
830    }
831    let Ok(triple) = std::env::var(TARGET_ENV_VAR) else {
832        return;
833    };
834    let triple = triple.trim().to_owned();
835    if triple.is_empty() {
836        return;
837    }
838    let source = TargetSource::Env(triple);
839    match TargetModel::from_triple(source.triple().expect("Env carries its triple")) {
840        Ok(model) => {
841            options.target = model;
842            options.target_source = source;
843        }
844        Err(unknown) => diagnostics.error(range, unknown.message(&source)),
845    }
846}
847
848/// Resolves [`include::SYSTEM_ENV_VAR`] into `options`, reporting a value that
849/// is neither a boolean nor `first`.
850///
851/// Only when the caller left the switch off, for [`apply_env_target`]'s
852/// reason: an [`Options::system_include`] the caller set is a deliberate
853/// choice, and a test that sets one must not have the developer's own
854/// environment change the answer.
855fn apply_env_system_include(
856    options: &mut Options,
857    range: SourceRange,
858    diagnostics: &mut Diagnostics,
859) {
860    if options.system_include != include::System::Off {
861        return;
862    }
863    let Ok(value) = std::env::var(include::SYSTEM_ENV_VAR) else {
864        return;
865    };
866    match include::System::from_env_value(&value) {
867        Some(mode) => options.system_include = mode,
868        None => diagnostics.error(
869            range,
870            format!(
871                "{}={value:?} is not one of '1', 'first' or '0'",
872                include::SYSTEM_ENV_VAR
873            ),
874        ),
875    }
876}
877
878/// The directory an `#include "…"` in the macro's own text searches first.
879///
880/// `Span::local_file` gives the path of the `.rs` file exactly as `rustc` was
881/// told it, which for a Cargo build is relative to the working directory
882/// `rustc` runs in. Since this code *is* that `rustc` process, resolving it
883/// against the working directory is a no-op — the relative path already works
884/// — and taking its parent gives the directory the user is writing in, which
885/// is where C looks for a quoted header. A `.rs` file at the root of the
886/// working directory has `""` as its parent, which joins to a bare name and is
887/// therefore still right.
888fn including_directory(rust_path: Option<&str>) -> Option<PathBuf> {
889    Some(Path::new(rust_path?).parent()?.to_path_buf())
890}
891
892/// Expands one `include_c99!("path")` invocation: the same translation, over a
893/// `.c` file rather than over C written inside the `.rs`.
894///
895/// The file is read and translated exactly as [string-literal
896/// input](capture::InputMode::StringLiteral) would be — every C construct is
897/// accepted, `#pragma cinrs …` inside it configures the unit, and its own
898/// directory is what its `#include "…"` searches first, as a header's is.
899///
900/// # Where a relative path is resolved
901///
902/// Against the **directory of the `.rs` file the macro is written in**, which
903/// is what `#include "…"` in a `c99!` block already does and what the author
904/// is looking at. `Span::local_file` is how that directory is found; where the
905/// compiler will not say (input built by another macro, some IDE contexts), the
906/// invocation is looked for in the crate's own sources — see [`Origin`] — and
907/// `CARGO_MANIFEST_DIR` stands in when even that finds nothing, so that a path
908/// written relative to the package still resolves. An absolute path is used as
909/// it stands.
910///
911/// # Diagnostics
912///
913/// There is no C in the `.rs` file, so there is no span to point into: every
914/// diagnostic — this crate's and `rustc`'s about the generated code — lands on
915/// the macro invocation, and a message of ours carries `path:line:column` in
916/// front of it, exactly as one inside an `#include`d header does. The file is
917/// named in the expansion with `include_str!` as well, so that editing it
918/// rebuilds the crate.
919pub fn expand_include(input: TokenStream, options: &Options) -> TokenStream {
920    let macro_name = format!("include_{}", options.macro_name());
921    let mut trees = input.into_iter();
922    let (first, second) = (trees.next(), trees.next());
923    let span = first.as_ref().map_or_else(Span::call_site, TokenTree::span);
924    let name = match (&first, &second) {
925        (Some(TokenTree::Literal(literal)), None) => capture::string_literal_value(literal),
926        _ => None,
927    };
928    let Some(name) = name else {
929        return diag::compile_error_at(
930            span,
931            &format!(
932                "{macro_name} takes one string literal naming a C file, as in \
933                 {macro_name}(\"vendor/parser.c\")"
934            ),
935        );
936    };
937
938    let path = include_path(&name, span, &first, &options.include_origin());
939    let found = match include::read_source(&path) {
940        Ok(found) => found,
941        Err(include::Error::Unreadable { path, error }) => {
942            return diag::compile_error_at(span, &format!("cannot read '{path}': {error}"));
943        }
944        Err(include::Error::NotFound { searched }) => {
945            let looked = searched.join(", ");
946            return diag::compile_error_at(
947                span,
948                &format!(
949                    "{macro_name} cannot find '{name}': there is no file at {looked}. A relative \
950                     path is resolved against the directory of the .rs file this macro is \
951                     written in"
952                ),
953            );
954        }
955    };
956
957    // The file is the unit's own text, so it is tracked like a header: editing
958    // it has to rebuild the crate that names it.
959    let tracked: Vec<PathBuf> = found.path.into_iter().collect();
960    let source = capture::capture_c_file(found.name, found.text, span);
961    let analysis = analyze_source(source, options, Diagnostics::new());
962    generate_unit(analysis, &tracked)
963}
964
965/// Where `include_c99!("name")` looks for its file.
966///
967/// The directory of the `.rs` file the invocation is written in, which is what
968/// `Span::local_file` reports and what a quoted `#include` in a `c99!` block
969/// already searches first.
970///
971/// Where the compiler will not say where that is, the invocation is looked for
972/// in the crate's own sources: an `include_…!` whose argument is this very
973/// literal, in a directory that does hold the file it names — which is the test
974/// that tells two invocations of the same name apart, and the only thing this
975/// path can be checked against. Failing that `CARGO_MANIFEST_DIR` stands in, and
976/// failing even that the path is used as written, against the working directory,
977/// which is a unit test rather than a build.
978fn include_path(name: &str, span: Span, input: &Option<TokenTree>, origin: &Origin) -> PathBuf {
979    let path = Path::new(name);
980    if path.is_absolute() {
981        return path.to_path_buf();
982    }
983    if let Some(dir) = span
984        .local_file()
985        .and_then(|rs| rs.parent().map(Path::to_path_buf))
986    {
987        return dir.join(path);
988    }
989    if let Some(tree) = input
990        && let Some(dir) =
991            capture::invocation_directory(tree, origin, |dir| dir.join(path).is_file())
992    {
993        return dir.join(path);
994    }
995    match std::env::var_os(include::MANIFEST_DIR_VAR) {
996        Some(root) => Path::new(&root).join(path),
997        None => path.to_path_buf(),
998    }
999}
1000
1001/// Expands one `c99!`-style invocation.
1002///
1003/// The result is a private module holding the unit's items plus a glob
1004/// re-export of it, so that two invocations in one Rust module are two
1005/// namespaces and cannot collide; a unit that declares nothing expands to
1006/// nothing at all.
1007///
1008/// # Where each pass runs
1009///
1010/// Capture and code generation must run on the caller's thread, because both
1011/// handle `proc_macro2::Span`s and those are deliberately not `Send`.
1012/// Everything in between — the lexer, the parser and semantic analysis —
1013/// works on byte offsets alone and runs on a thread with a large stack, where
1014/// the parser's recursion limit is the only thing that can stop it.
1015///
1016/// That leaves code generation recursing on the caller's stack, bounded by the
1017/// same limit: `parse::MAX_RECURSION_DEPTH` nested constructs. Code generation
1018/// frames are small (it allocates token streams rather than analysing
1019/// anything), and a debug build of the whole of capture plus code generation
1020/// for an expression nested to that limit fits inside a small fraction of a
1021/// megabyte — see the `codegen_of_deeply_nested_input_fits_in_a_small_stack`
1022/// test, which runs the entire expansion on a deliberately tiny thread.
1023///
1024/// # Errors
1025///
1026/// On failure the expansion holds a `compile_error!` per diagnostic *and* a
1027/// stub definition for every function whose signature was well formed, so that
1028/// Rust code calling those functions does not add a second layer of errors on
1029/// top of the real one.
1030pub fn expand(input: TokenStream, options: &Options) -> TokenStream {
1031    expand_with(input, options, &Origin::unknown())
1032}
1033
1034/// Expands one `c99!`-style invocation, with everything the host says about the
1035/// invocation itself.
1036///
1037/// This is what the procedural macros call, with [`Options::origin`]; see
1038/// [`Origin`] for what it adds and why [`expand`] — which is this with an origin
1039/// that says nothing — does not.
1040pub fn expand_with(input: TokenStream, options: &Options, origin: &Origin) -> TokenStream {
1041    generate_unit(analyze_with(input, options, origin), &[])
1042}
1043
1044/// Semantic analysis and code generation over a finished [`Analysis`].
1045///
1046/// `extra_tracking` names files the expansion must depend on that the
1047/// preprocessor did not read itself — the `.c` file [`expand_include`] was
1048/// pointed at, which is the unit's own text rather than a header of it.
1049fn generate_unit(analysis: Analysis, extra_tracking: &[PathBuf]) -> TokenStream {
1050    let Analysis {
1051        source,
1052        unit,
1053        mut diagnostics,
1054        expansions,
1055        user_headers,
1056        embedded_files,
1057        link_libraries,
1058        safe_functions,
1059        export,
1060        no_std,
1061        crate_path,
1062        // The target model the environment and the unit's own pragma settled
1063        // on; everything after the front end has to use these rather than the
1064        // options the caller handed in.
1065        options,
1066        ..
1067    } = analysis;
1068    let options = &options;
1069
1070    let unit_id = source.unit_id();
1071    let (mut program, mut sema_diagnostics) = on_large_stack(
1072        (unit, options.clone(), unit_id),
1073        |(unit, options, unit_id)| sema::analyze(&unit, &options, unit_id),
1074    );
1075    expansions.annotate(&mut sema_diagnostics);
1076    diagnostics.extend(sema_diagnostics);
1077    program.link_libraries = link_libraries;
1078    program.export = export;
1079    program.no_std = no_std;
1080    if let Some(path) = crate_path {
1081        program.crate_path = path;
1082    }
1083    // The pragmas are the preprocessor's, so the rules that depend on one can
1084    // only be checked now that the program and the pragmas are together.
1085    // `check_safe` also *applies* one, which is why it comes before code
1086    // generation reads `Function::safe`.
1087    let mut pragma_diagnostics = sema::check_pragmas(&program);
1088    pragma_diagnostics.extend(sema::check_safe(&mut program, &safe_functions));
1089    expansions.annotate(&mut pragma_diagnostics);
1090    diagnostics.extend(pragma_diagnostics);
1091
1092    // Emitted whether or not the unit compiled: a header that is being fixed
1093    // is exactly the one whose next edit has to trigger a rebuild.
1094    let mut tracked = extra_tracking.to_vec();
1095    tracked.extend(user_headers);
1096    let mut out = rebuild_tracking(&tracked, &embedded_files);
1097    if diagnostics.has_errors() {
1098        out.extend(diagnostics.to_token_stream(&source.map));
1099        out.extend(codegen::generate_stubs(&program, &source.map, options));
1100    } else {
1101        out.extend(codegen::generate(&program, &source.map, options));
1102    }
1103    in_module(out, unit_id)
1104}
1105
1106/// Wraps an expansion in a private module of its own, re-exported by a glob.
1107///
1108/// A translation unit is a namespace, and two of them written in one Rust
1109/// module are two namespaces: both may `#include "point.h"`, and each has to
1110/// generate the `struct Point` its own code refers to. Two `struct Point`
1111/// items side by side are `E0428`; two modules each holding one, glob
1112/// re-exported, are not — a glob re-export only conflicts when a name it
1113/// exports is *used* ambiguously, and only from Rust, which is exactly the
1114/// case where the user has to say which one they mean. An ordinary Rust `mod`
1115/// around the invocation is what they say it with, and what gives the unit's
1116/// items a path of their own.
1117///
1118/// The module is what makes C's own hygiene work too: a `static` function is
1119/// private to it, as C says it is, while everything with external linkage is
1120/// `pub` and glob re-exported into the module the invocation is written in, so
1121/// that Rust calls it by the name its author gave it.
1122///
1123/// There is no `use super::*`: C code never refers to a Rust item.
1124///
1125/// # The lint exemptions
1126///
1127/// The module's head carries the one `#![allow(…)]` the whole expansion
1128/// needs. A faithful translation of C trips a great many of Rust's lints, and
1129/// not one of them says anything about the C the user wrote: a parameter the
1130/// function never reads, a parenthesis C needed and Rust does not, a name
1131/// that is not `snake_case`, two declarations of one symbol that do not
1132/// match, a comparison that is always true, a statement after a `return`, an
1133/// `extern` signature Rust calls improper, arithmetic that overflows in a
1134/// branch that never runs. Clippy's lints are in the list for the same
1135/// reason. `unknown_lints` comes first so that a compiler that has not heard
1136/// of one of the newer names — `invalid_runtime_symbol_definitions`, say —
1137/// does not warn about the list itself.
1138///
1139/// It is an *inner* attribute, which is why it has to come before anything
1140/// else in the body; everything the unit generates is inside this module, and
1141/// lint levels are inherited, so one attribute covers every item, however
1142/// deeply nested, whatever the crate root denies, and for clippy as much as
1143/// for `rustc`.
1144///
1145/// One attribute per unit rather than one per item is what makes it
1146/// affordable. The list is 585 bytes and `#include <zlib.h>` generates 419
1147/// items, so the same exemption repeated on each of them was 83% of that
1148/// expansion — 245 KB of 294 KB — parsed by `rustc` and by rust-analyzer on
1149/// every build.
1150fn in_module(items: TokenStream, unit_id: u64) -> TokenStream {
1151    if items.is_empty() {
1152        // An empty translation unit expands to nothing at all, rather than to
1153        // an empty module and a glob re-export of it.
1154        return items;
1155    }
1156    let span = Span::call_site();
1157    let ident = Ident::new(&format!("__cinrs_unit_{:08x}", unit_id as u32), span);
1158    quote! {
1159        mod #ident {
1160            #![allow(
1161                unknown_lints,
1162                arithmetic_overflow,
1163                clashing_extern_declarations,
1164                dead_code,
1165                improper_ctypes,
1166                improper_ctypes_definitions,
1167                invalid_runtime_symbol_definitions,
1168                non_camel_case_types,
1169                non_snake_case,
1170                non_upper_case_globals,
1171                overflowing_literals,
1172                static_mut_refs,
1173                suspicious_runtime_symbol_definitions,
1174                unconditional_panic,
1175                unpredictable_function_pointer_comparisons,
1176                unreachable_code,
1177                unreachable_patterns,
1178                unused_assignments,
1179                unused_braces,
1180                unused_comparisons,
1181                unused_labels,
1182                unused_mut,
1183                unused_parens,
1184                unused_unsafe,
1185                unused_variables,
1186                clippy::all
1187            )]
1188
1189            #items
1190        }
1191        // The re-export needs one of its own, which the module's cannot
1192        // cover: `ambiguous_glob_reexports` is what a name two units both
1193        // export trips, and it is not a problem until Rust code uses that
1194        // name — which is an error of its own, with a message that says what
1195        // to do.
1196        #[allow(unknown_lints, ambiguous_glob_reexports, unused_imports)]
1197        pub use #ident::*;
1198    }
1199}
1200
1201/// `const _: &str = ::core::include_str!("…");` for every user header read,
1202/// and `include_bytes!` for every resource `#embed` read.
1203///
1204/// A procedural macro that reads a file has to tell the build system so, or
1205/// editing that file will not rebuild anything that included it. `include_str!`
1206/// is how a stable macro says it: `rustc` records the file as a dependency of
1207/// the crate, and Cargo re-runs the compilation when its timestamp moves. The
1208/// path is absolute so that it resolves the same from whichever module the
1209/// invocation is written in, and the item is anonymous (`const _`) so that any
1210/// number of them can coexist. An embedded resource is not text, so it takes
1211/// the byte-string form of the same trick.
1212///
1213/// Bundled headers are left out: they cannot change without the crate that
1214/// carries them changing, which Cargo already knows about.
1215///
1216/// `str` and `u8` take the [`core::primitive`] path for the same reason every
1217/// primitive the code generator writes does: these items go into the unit's
1218/// own module, where `typedef unsigned char u8;` may have put an alias of that
1219/// name.
1220fn rebuild_tracking(headers: &[PathBuf], embedded: &[PathBuf]) -> TokenStream {
1221    let span = Span::call_site();
1222    let mut out = TokenStream::new();
1223    for header in headers {
1224        let mut literal = Literal::string(&header.to_string_lossy());
1225        literal.set_span(span);
1226        let literal = TokenTree::Literal(literal);
1227        out.extend(quote! {
1228            const _: &::core::primitive::str = ::core::include_str!(#literal);
1229        });
1230    }
1231    for resource in embedded {
1232        let mut literal = Literal::string(&resource.to_string_lossy());
1233        literal.set_span(span);
1234        let literal = TokenTree::Literal(literal);
1235        out.extend(quote! {
1236            const _: &[::core::primitive::u8] = ::core::include_bytes!(#literal);
1237        });
1238    }
1239    out
1240}