Skip to main content

cinrs_core/
pp.rs

1//! The C99 preprocessor: translation phase 4.
2//!
3//! The preprocessor sits between the [lexer](crate::lex) and the
4//! [parser](crate::parse). It consumes the lexer's tokens together with their
5//! `bol` / `preceded_by_space` flags, executes the directives it finds and
6//! replaces macro invocations, and hands the parser a [`Token`] list that
7//! contains no `#` directives at all.
8//!
9//! # Token origin
10//!
11//! Every token the preprocessor emits carries an [`Origin`]:
12//!
13//! * [`Origin::Source`] — the token was written where it is, and its
14//!   [`Token::range`] is its own.
15//! * [`Origin::Expansion`] — the token came out of a macro's replacement list,
16//!   and its range is the range of the *invocation*, not of the `#define`.
17//!
18//! That distinction is the whole point. A diagnostic — ours or `rustc`'s on
19//! the code we generate — must land on something the user wrote, and the
20//! `#define` is not where the mistake is being made. Tokens that came from a
21//! macro *argument* keep their own ranges, because the argument *was* written
22//! at the call site; only the replacement list's own tokens, and the tokens
23//! `#` and `##` synthesise, are re-pointed at the invocation.
24//!
25//! A procedural macro cannot emit secondary spans, so the "which macro was
26//! that?" half of the story is appended to the message instead:
27//! [`Expansions::annotate`] adds `note: in expansion of macro 'X'` to every
28//! diagnostic that lands inside an invocation.
29//!
30//! # Hide sets
31//!
32//! Macro replacement follows Dave Prosser's algorithm, the one the standard's
33//! rescanning rules were written from. Each token carries a *hide set*: the
34//! names of the macros whose expansion it came out of. A name is not replaced
35//! again while it is in its own hide set, which is what stops
36//!
37//! ```c
38//! #define foo (4 + foo)
39//! ```
40//!
41//! from running forever while still letting `foo` be replaced somewhere else.
42//! For a function-like macro the hide set of the result is
43//! `(HS(name) ∩ HS(')')) ∪ {name}`, which is what makes the standard's
44//! `f(2 * (f)(z))` example come out right.
45//!
46//! # The `# #` rule
47//!
48//! Rust's own lexer refuses `##` in raw-token mode ("reserved multi-hash
49//! token"), so a `c99!` block written as raw Rust tokens cannot spell the
50//! token-pasting operator. It can spell `a # # b`, and in a *replacement list*
51//! a `#` immediately followed by another `#` is ill-formed C anyway — `#` must
52//! be followed by a macro parameter — so this preprocessor reads two adjacent
53//! `#` tokens in a replacement list as the `##` operator. The rule applies in
54//! every input mode, so a macro written with `# #` means the same thing whether
55//! it is passed as raw tokens or inside a string literal.
56//!
57//! # `#include`
58//!
59//! A header is read at the point the directive is reached, lexed, and pushed
60//! onto a stack of open files; the tokens it produces are the tokens the
61//! parser sees next. Each file has its own text, its own line numbering and
62//! its own idea of what `__FILE__` says, and each is placed in a range of the
63//! global offset space of its own, so that a position identifies both a file
64//! and a place in it. The [`Preprocessed::included`] list is what a caller
65//! adds to its [source map](crate::SourceMap) afterwards, in the order the
66//! files were opened; the preprocessor cannot do it itself, because it runs on
67//! a thread where a `proc_macro2::Span` cannot follow it.
68//!
69//! Where a header is looked for — and why the system directories are never
70//! looked in — is [`crate::include`]. Reading one twice is avoided the two
71//! usual ways: `#pragma once`, and the classic include-guard optimisation. A
72//! file that includes itself with neither eventually nests too deeply and is
73//! reported.
74//!
75//! A conditional group a header leaves open ends with the header rather than
76//! running on into whatever included it, and is reported against the file that
77//! opened it.
78//!
79//! ## The `cinrs` pragmas
80//!
81//! ```c
82//! #pragma cinrs target "i686-unknown-linux-gnu"
83//! #pragma cinrs include_path "vendor/include"
84//! #pragma cinrs system_include first
85//! #pragma cinrs link "mylib"
86//! #pragma cinrs export
87//! #pragma cinrs safe gcd fact
88//! #pragma cinrs no_std
89//! #pragma cinrs crate "crate::vendor::cinrs"
90//! ```
91//!
92//! `target` picks the data model the unit is translated for, overriding
93//! `CINRS_TARGET`; `include_path` adds a directory to the search path (relative
94//! paths resolve against `CARGO_MANIFEST_DIR`); `system_include` puts the
95//! platform's own include directories on that path, after the bundled headers
96//! or — with `first` — before them (see [`crate::include`]); `link` adds
97//! `#[link(name = "mylib")]` on an `extern` block of its own; `export` gives
98//! everything with external linkage a real C symbol, so that another unit can
99//! link to it; `safe` generates those functions without `unsafe`, so that
100//! `rustc` checks them (see [`crate::sema::check_safe`]); `no_std` takes the
101//! `Vec` a variable length array or `alloca` needs from `alloc` rather than
102//! from `std`; and `crate` says where the `cinrs` facade crate is, for the
103//! generated code that names the runtime. Being
104//! directives rather than attributes or macro arguments is what makes them
105//! mean the same thing in raw-token and in string-literal input. An unknown
106//! `#pragma cinrs` option is an error; every other pragma is ignored, as
107//! 6.10.6 asks. `doc/pragmas.md` is the reference page.
108//!
109//! `target` is the one that cannot be handled where it stands: the predefined
110//! macros are built from the model before the first directive is read, so
111//! [`scan_target_pragma`] finds it *lexically*, before preprocessing, and the
112//! handler here only checks that what it finds agrees. Which is why the pragma
113//! has to be written in the unit's own text, ahead of any `#include` or `#if`;
114//! anywhere else is a diagnostic rather than a silent half-measure.
115//!
116//! # What the later revisions add
117//!
118//! `__VA_OPT__(…)`, `#elifdef` and `#elifndef` are C23's, and are accepted in
119//! a [`Standard::C23`] block; an older one is told which macro would have
120//! them. `true` and `false` are keywords there too, so an `#if` reads them as
121//! 1 and 0 rather than turning them into 0 like any other identifier (C23
122//! 6.10.1p6). `#embed` and `__has_embed` are C23's as well: the directive is
123//! replaced by the bytes of a file, written as a comma-separated list of
124//! `unsigned char` values, and the resource is reported in
125//! [`Preprocessed::embedded_files`] so that editing it rebuilds the crate.
126//!
127//! # Predefined macros
128//!
129//! | Macro | Value |
130//! | --- | --- |
131//! | `__STDC__` | `1` |
132//! | `__STDC_HOSTED__` | `1` |
133//! | `__STDC_VERSION__` | the revision: `199901L`, `201112L`, `201710L` or `202311L`; undefined in `c89!` and `gnu89!` |
134//! | `__cinrs__` | `1` |
135//! | `__FILE__` | the invoking `.rs` file's path, or `"<c99!>"` |
136//! | `__LINE__` | the line of the invoking `.rs` file |
137//! | `__DATE__` | `"??? ?? ????"` |
138//! | `__TIME__` | `"??:??:??"` |
139//!
140//! `__FILE__` and `__LINE__` are computed from the position they are *used*
141//! at, so inside a header they name the header and the line in it, and a macro
142//! defined in `<assert.h>` that mentions them reports the line the assertion
143//! is written on.
144//!
145//! `__DATE__` and `__TIME__` are deliberately fixed placeholders: a build has
146//! to be reproducible, and a macro that expanded to the wall clock would make
147//! the generated code differ between two builds of the same source.
148//!
149//! `__LINE__` is a line of the `.rs` file the invocation is written in
150//! whenever the compiler tells us where that is — the captured C text
151//! remembers which line of its `.rs` file it starts on — and a line inside the
152//! C text itself otherwise (a `TokenStream` built from a string in a unit
153//! test, for instance).
154//!
155//! ## `#line`
156//!
157//! `#line N` and `#line N "name"` (6.10.4), and GCC's `# N "name" flags…` line
158//! marker, do what they say: the line after the directive is line N, counting
159//! up per physical line from there, and `__FILE__` is the given name until the
160//! next directive or the end of that file. The macro-expanded form is
161//! supported too — `#line line`, with `line` a macro — and the numbering is
162//! per file, so a `#line` inside a header ends with the header. In the
163//! macro's own text a `#line` replaces the `.rs`-line convention above from
164//! the next line to the end of the block, which is exactly what a program that
165//! writes one is asking for.
166//!
167//! **Nothing else moves.** A diagnostic — this crate's or `rustc`'s — still
168//! points at the token that was really written, in the file it was really
169//! written in, because that is the position the user can look at; making the
170//! caret land on the C is the reason the whole pipeline carries spans.
171//! `__BASE_FILE__` names the file the translation unit started in and is not
172//! affected either; `__FILE_NAME__` is `__FILE__` without the directory, so it
173//! is.
174//!
175//! On top of those comes a small, deliberately short set of target
176//! description macros derived from the machine this crate was compiled for and
177//! from [`TargetModel`]: the architecture
178//! (`__x86_64__`, `__aarch64__`, …), the operating system (`__linux__`,
179//! `__unix__`, `_WIN32`, `__APPLE__`, …), the data model (`__LP64__`,
180//! `__ILP32__`, `__CHAR_UNSIGNED__`, `__SIZEOF_INT__` and friends,
181//! `__CHAR_BIT__`) and the byte order (`__BYTE_ORDER__`). Nothing about the
182//! *language* is described that way — there is no `__GNUC__` — because
183//! claiming a compiler's identity would invite headers to use its extensions.
184
185use std::collections::{HashMap, HashSet};
186use std::sync::Arc;
187
188use crate::capture::{Pos, SourceRange};
189use crate::diag::{Diagnostic, Diagnostics};
190use crate::include;
191use crate::lex::{
192    self, IntLit, Keyword, LexOptions, LongKind, NumBase, Punct, StrKind, StrLit, TokenKind,
193};
194use crate::target::{Env, Os, TargetModel, TargetSource};
195use crate::{Dialect, Gating, Options, Standard};
196
197// ---------------------------------------------------------------------------
198// the tokens the parser sees
199// ---------------------------------------------------------------------------
200
201/// One macro expansion a token came out of.
202#[derive(Clone, PartialEq, Eq, Debug)]
203pub struct Expansion {
204    /// The macro's name.
205    pub name: String,
206    /// The range of the invocation: the name for an object-like macro, the
207    /// name through the closing `)` for a function-like one.
208    pub invocation: SourceRange,
209    /// Where the macro's name was written in its `#define`.
210    pub definition: SourceRange,
211    /// The expansion this one was produced inside, if any.
212    pub parent: Option<Arc<Expansion>>,
213}
214
215/// Where a preprocessed token came from.
216#[derive(Clone, PartialEq, Eq, Debug, Default)]
217pub enum Origin {
218    /// The token was written where [`Token::range`] says it was.
219    #[default]
220    Source,
221    /// The token came out of a macro's replacement list; [`Token::range`] is
222    /// the range of the invocation.
223    Expansion(Arc<Expansion>),
224}
225
226impl Origin {
227    /// The expansion this token came out of, if any.
228    pub fn expansion(&self) -> Option<&Arc<Expansion>> {
229        match self {
230            Origin::Source => None,
231            Origin::Expansion(e) => Some(e),
232        }
233    }
234}
235
236/// A preprocessed C token: what the parser consumes.
237///
238/// Deliberately shaped like [`lex::Token`] minus the flags the preprocessor
239/// needed and plus the [`Origin`] it produced, so that the parser's view of a
240/// token did not have to change.
241#[derive(Clone, PartialEq, Debug)]
242pub struct Token {
243    /// What the token is.
244    pub kind: TokenKind,
245    /// Where to blame: the token's own range, or the range of the macro
246    /// invocation it came out of.
247    pub range: SourceRange,
248    /// How the token got here.
249    pub origin: Origin,
250}
251
252impl Token {
253    /// The keyword this token is, if any.
254    pub fn keyword(&self) -> Option<lex::Keyword> {
255        match &self.kind {
256            TokenKind::Keyword(k) => Some(*k),
257            _ => None,
258        }
259    }
260
261    /// Whether this token is the given punctuator.
262    pub fn is_punct(&self, p: Punct) -> bool {
263        self.kind == TokenKind::Punct(p)
264    }
265
266    /// Whether this token is the given keyword.
267    pub fn is_keyword(&self, k: lex::Keyword) -> bool {
268        self.kind == TokenKind::Keyword(k)
269    }
270
271    /// Whether this token ends the input.
272    pub fn is_eof(&self) -> bool {
273        self.kind == TokenKind::Eof
274    }
275
276    /// The identifier this token is, if any.
277    pub fn ident(&self) -> Option<&str> {
278        match &self.kind {
279            TokenKind::Ident(name) => Some(name),
280            _ => None,
281        }
282    }
283}
284
285// ---------------------------------------------------------------------------
286// the expansion map
287// ---------------------------------------------------------------------------
288
289/// Every macro invocation the preprocessor replaced, so that a diagnostic
290/// landing inside one can say which macro it was.
291///
292/// A procedural macro has exactly one span per diagnostic and no way to add a
293/// second one, so the extra context has to travel in the message text.
294#[derive(Clone, Default, Debug)]
295pub struct Expansions {
296    /// One entry per expansion, in the order they happened, which puts an
297    /// outer macro before the inner ones it produced.
298    entries: Vec<ExpansionSite>,
299}
300
301/// Where one macro was invoked, and where it was defined.
302#[derive(Clone, Debug)]
303struct ExpansionSite {
304    invocation: SourceRange,
305    name: String,
306    definition: SourceRange,
307}
308
309impl Expansions {
310    fn record(&mut self, range: SourceRange, name: &str, definition: SourceRange) {
311        self.entries.push(ExpansionSite {
312            invocation: range,
313            name: name.to_owned(),
314            definition,
315        });
316    }
317
318    /// The macro whose invocation most tightly encloses `pos`.
319    fn enclosing(&self, pos: Pos) -> Option<&ExpansionSite> {
320        let mut best: Option<&ExpansionSite> = None;
321        for entry in &self.entries {
322            if entry.invocation.start > pos || entry.invocation.end < pos {
323                continue;
324            }
325            // The narrowest invocation wins; ties go to the one recorded
326            // first, which is the outermost of a nest sharing one range.
327            match best {
328                Some(b) if b.invocation.len() <= entry.invocation.len() => {}
329                _ => best = Some(entry),
330            }
331        }
332        best
333    }
334
335    /// Adds `note: in expansion of macro 'X', defined at line N` to every
336    /// diagnostic that landed inside a macro invocation.
337    ///
338    /// Called once per pass, on the diagnostics that pass produced, so that no
339    /// diagnostic is ever annotated twice.
340    pub fn annotate(&self, diags: &mut Diagnostics) {
341        if self.entries.is_empty() {
342            return;
343        }
344        for diag in diags.items_mut() {
345            if let Some(site) = self.enclosing(diag.range.start) {
346                diag.notes.push(crate::diag::Note {
347                    message: format!("in expansion of macro '{}', defined", site.name),
348                    range: Some(site.definition),
349                });
350            }
351        }
352    }
353
354    /// Whether any macro was expanded at all.
355    pub fn is_empty(&self) -> bool {
356        self.entries.is_empty()
357    }
358}
359
360// ---------------------------------------------------------------------------
361// hide sets
362// ---------------------------------------------------------------------------
363
364/// The set of macro names a token must not be replaced by again.
365///
366/// Tiny by construction — a handful of names at most — so a sorted vector
367/// behind an `Arc` beats a hash set, and the `None` case makes the common
368/// "no hide set at all" free.
369#[derive(Clone, Default, PartialEq, Eq, Debug)]
370struct HideSet(Option<Arc<Vec<String>>>);
371
372impl HideSet {
373    fn contains(&self, name: &str) -> bool {
374        match &self.0 {
375            None => false,
376            Some(names) => names.iter().any(|n| n == name),
377        }
378    }
379
380    fn add(&self, name: &str) -> HideSet {
381        if self.contains(name) {
382            return self.clone();
383        }
384        let mut names = match &self.0 {
385            None => Vec::with_capacity(1),
386            Some(names) => (**names).clone(),
387        };
388        names.push(name.to_owned());
389        HideSet(Some(Arc::new(names)))
390    }
391
392    /// The names in both sets, which is what a function-like macro's result
393    /// hides (6.10.3.4, via Prosser).
394    fn intersect(&self, other: &HideSet) -> HideSet {
395        let (Some(a), Some(b)) = (&self.0, &other.0) else {
396            return HideSet::default();
397        };
398        let names: Vec<String> = a.iter().filter(|n| b.contains(n)).cloned().collect();
399        if names.is_empty() {
400            HideSet::default()
401        } else {
402            HideSet(Some(Arc::new(names)))
403        }
404    }
405
406    /// Every name of `other`, added to this set.
407    fn union(&self, other: &HideSet) -> HideSet {
408        let Some(names) = &other.0 else {
409            return self.clone();
410        };
411        let mut out = self.clone();
412        for name in names.iter() {
413            out = out.add(name);
414        }
415        out
416    }
417}
418
419// ---------------------------------------------------------------------------
420// the preprocessor's own token
421// ---------------------------------------------------------------------------
422
423/// A token inside the preprocessor: the lexer's, plus a hide set and an origin.
424#[derive(Clone, Debug)]
425struct PTok {
426    kind: TokenKind,
427    range: SourceRange,
428    bol: bool,
429    space: bool,
430    origin: Origin,
431    hide: HideSet,
432    errors: Vec<Diagnostic>,
433}
434
435impl PTok {
436    fn from_lexed(tok: &lex::Token) -> Self {
437        Self {
438            kind: tok.kind.clone(),
439            range: tok.range,
440            bol: tok.bol,
441            space: tok.preceded_by_space,
442            origin: Origin::Source,
443            hide: HideSet::default(),
444            errors: tok.errors.clone(),
445        }
446    }
447
448    fn is_eof(&self) -> bool {
449        self.kind == TokenKind::Eof
450    }
451
452    fn is_punct(&self, p: Punct) -> bool {
453        self.kind == TokenKind::Punct(p)
454    }
455
456    fn name(&self) -> Option<&str> {
457        self.kind.macro_name()
458    }
459
460    fn spelling(&self) -> &str {
461        self.kind.spelling()
462    }
463}
464
465// ---------------------------------------------------------------------------
466// macro definitions
467// ---------------------------------------------------------------------------
468
469/// A macro the preprocessor synthesises rather than stores tokens for.
470#[derive(Clone, Copy, PartialEq, Eq, Debug)]
471enum Builtin {
472    /// `__LINE__`, whose value depends on where it is used.
473    Line,
474    /// `__FILE__`, likewise: inside an `#include`d file it names the header.
475    File,
476    /// `__FILE_NAME__` — GNU's `__FILE__` without the directory.
477    FileName,
478    /// `__INCLUDE_LEVEL__` — how many `#include`s deep the use is.
479    IncludeLevel,
480    /// `__COUNTER__` — a fresh integer at every use.
481    Counter,
482}
483
484/// One `#define`.
485#[derive(Debug)]
486struct MacroDef {
487    /// The parameter names, or `None` for an object-like macro.
488    params: Option<Vec<String>>,
489    /// Whether the parameter list ended with `...`.
490    variadic: bool,
491    /// The name GNU's `#define log(fmt, args...)` gave the variable arguments,
492    /// which is then another spelling of `__VA_ARGS__`.
493    va_name: Option<String>,
494    /// The replacement list.
495    body: Vec<PTok>,
496    /// Where the macro's name was written.
497    name_range: SourceRange,
498    /// Whether this macro was built in rather than written by the user.
499    predefined: bool,
500    /// The value this macro computes, for the ones that are not just tokens.
501    builtin: Option<Builtin>,
502}
503
504impl MacroDef {
505    /// Whether two definitions are the same one, as 6.10.3p2 requires:
506    /// the same kind, the same parameter spellings, and replacement lists that
507    /// agree token for token *and* on where the white space was.
508    fn same_as(&self, other: &MacroDef) -> bool {
509        if self.params != other.params
510            || self.variadic != other.variadic
511            || self.va_name != other.va_name
512        {
513            return false;
514        }
515        if self.body.len() != other.body.len() {
516            return false;
517        }
518        self.body
519            .iter()
520            .zip(&other.body)
521            .enumerate()
522            .all(|(i, (a, b))| a.spelling() == b.spelling() && (i == 0 || a.space == b.space))
523    }
524
525    /// The index of the parameter `name` stands for, `__VA_ARGS__` included.
526    fn param_index(&self, name: &str) -> Option<usize> {
527        let params = self.params.as_ref()?;
528        if let Some(i) = params.iter().position(|p| p == name) {
529            return Some(i);
530        }
531        let variable = name == VA_ARGS || self.va_name.as_deref() == Some(name);
532        (self.variadic && variable).then_some(params.len())
533    }
534
535    /// The index the variable arguments occupy, if there are any.
536    fn va_index(&self) -> Option<usize> {
537        self.variadic
538            .then(|| self.params.as_ref().map_or(0, Vec::len))
539    }
540}
541
542/// The pieces of a parsed macro parameter list.
543struct ParamList {
544    params: Vec<String>,
545    variadic: bool,
546    va_name: Option<String>,
547    /// How many tokens the list occupied, including its parentheses.
548    used: usize,
549}
550
551const VA_ARGS: &str = "__VA_ARGS__";
552
553/// C23's conditional-expansion operator (6.10.5.2).
554const VA_OPT: &str = "__VA_OPT__";
555
556/// C99's `_Pragma` operator (6.10.9).
557const PRAGMA_OPERATOR: &str = "_Pragma";
558
559/// Undoes what `#` did: `L"a\"b\\c"` becomes `a"b\c`.
560fn destringize(text: &str) -> String {
561    let inner = text
562        .strip_prefix("L\"")
563        .or_else(|| text.strip_prefix('"'))
564        .and_then(|rest| rest.strip_suffix('"'))
565        .unwrap_or(text);
566    let mut out = String::with_capacity(inner.len());
567    let mut chars = inner.chars();
568    while let Some(c) = chars.next() {
569        if c != '\\' {
570            out.push(c);
571            continue;
572        }
573        match chars.next() {
574            Some(next @ ('"' | '\\')) => out.push(next),
575            Some(next) => {
576                out.push('\\');
577                out.push(next);
578            }
579            None => out.push('\\'),
580        }
581    }
582    out
583}
584
585// ---------------------------------------------------------------------------
586// limits
587// ---------------------------------------------------------------------------
588
589/// How deeply argument pre-expansion may nest.
590///
591/// Hide sets already make runaway recursion impossible, but a macro whose
592/// arguments are themselves deeply nested invocations turns into recursion in
593/// *this* code, which runs inside a compiler that must not be taken down by a
594/// stack overflow.
595const MAX_EXPANSION_DEPTH: u32 = 200;
596
597/// How deeply `#include` may nest.
598///
599/// A header that includes itself is the ordinary way to reach this, and it is
600/// always a mistake — the include guard that would have stopped it is missing.
601/// The limit is a count of open files rather than a recursion limit: the
602/// preprocessor reads a nested file iteratively, so nothing here is at risk of
603/// a stack overflow, but a program that never stops including is still a
604/// program that never finishes compiling.
605const MAX_INCLUDE_DEPTH: usize = 200;
606
607/// `__STDC_EMBED_NOT_FOUND__`, the answer `__has_embed` gives for a resource
608/// that is not there or that carries a parameter this does not have.
609const EMBED_NOT_FOUND: u128 = 0;
610/// `__STDC_EMBED_FOUND__`: the resource exists and has at least one byte.
611const EMBED_FOUND: u128 = 1;
612/// `__STDC_EMBED_EMPTY__`: the resource exists and `#embed` would produce
613/// nothing from it.
614const EMBED_EMPTY: u128 = 2;
615
616/// How many tokens one translation unit's macro expansion may produce.
617///
618/// `#define A B B` repeated thirty times is a legal program whose expansion
619/// does not fit in memory. Refusing it with a diagnostic beats spending the
620/// rest of the build on it.
621const MAX_EXPANDED_TOKENS: usize = 4_000_000;
622
623// ---------------------------------------------------------------------------
624// entry point
625// ---------------------------------------------------------------------------
626
627/// What the preprocessor needs to know about the text it is running over.
628#[derive(Clone, Debug)]
629pub struct Context {
630    /// The C source text, which `#error` and `#include <…>` read back
631    /// verbatim.
632    pub text: String,
633    /// The global offset of `text`'s first byte.
634    pub base: Pos,
635    /// What `__FILE__` expands to.
636    pub file_name: String,
637    /// The line `text`'s own line 1 sits on; see the [module docs](self).
638    pub first_line: usize,
639    /// The directory an `#include "…"` written in this text looks in first —
640    /// the directory of the invoking `.rs` file. `None` when the compiler will
641    /// not say where that is.
642    pub dir: Option<std::path::PathBuf>,
643    /// The global offset the first `#include`d file is placed at.
644    ///
645    /// The preprocessor allocates the offsets of the files it opens, because
646    /// it runs where a [`SourceMap`](crate::SourceMap) cannot follow it; see
647    /// [`crate::SourceMap::next_base`].
648    pub next_base: Pos,
649    /// The `#pragma cinrs target` directives [`scan_target_pragma`] already
650    /// read out of `text`, so that the preprocessor does not report one twice
651    /// and can tell a header's from the unit's own.
652    pub target_pragmas: TargetPragmas,
653}
654
655impl Context {
656    /// A context for `text` with nothing known about where it came from.
657    pub fn new(text: impl Into<String>, base: Pos) -> Self {
658        let text = text.into();
659        // One byte of gap, exactly as `SourceMap::add_file` leaves, so that the
660        // end of one file is never the start of the next.
661        let next_base = base
662            .saturating_add(text.len() as Pos)
663            .saturating_add(FILE_GAP);
664        Self {
665            text,
666            base,
667            file_name: DEFAULT_FILE_NAME.to_owned(),
668            first_line: 1,
669            dir: None,
670            next_base,
671            target_pragmas: TargetPragmas::default(),
672        }
673    }
674}
675
676/// The gap left between two files in the global offset space.
677///
678/// It must match [`crate::SourceMap`]'s, since the preprocessor allocates the
679/// offsets and the map hands out the spans for them.
680const FILE_GAP: Pos = 1;
681
682/// What `__FILE__` expands to when the compiler will not say where the
683/// invocation is.
684pub const DEFAULT_FILE_NAME: &str = "<c99!>";
685
686/// One file `#include` brought in, for the caller to add to its source map.
687#[derive(Clone, Debug)]
688pub struct IncludedFile {
689    /// What diagnostics call it: `include/foo.h`, or `<cinrs>/stdio.h` for a
690    /// bundled header.
691    pub name: String,
692    /// Its text.
693    pub text: String,
694    /// The global offset its text starts at.
695    pub base: Pos,
696    /// The `#include` directive that pulled it in, which is where a diagnostic
697    /// inside it points.
698    pub directive: SourceRange,
699}
700
701/// What `#embed`'s parameters asked for (C23 6.10.3.2–6.10.3.5).
702#[derive(Clone, Debug, Default)]
703struct EmbedParams {
704    /// `limit(N)`: at most this many bytes of the resource.
705    limit: Option<usize>,
706    /// `prefix(…)`: tokens before the bytes, when there are any.
707    prefix: Vec<PTok>,
708    /// `suffix(…)`: tokens after them, likewise.
709    suffix: Vec<PTok>,
710    /// `if_empty(…)`: the whole expansion when there are none.
711    if_empty: Vec<PTok>,
712}
713
714/// One function `#pragma cinrs safe` named.
715///
716/// The pragma is the spelling that works in every entry point and in
717/// string-literal input, so it names its functions rather than being written on
718/// one; whether a name is a function of this unit at all is
719/// [sema's](crate::sema::check_safe) question, and the range is what its
720/// diagnostic points at.
721#[derive(Clone, Debug)]
722pub struct SafeName {
723    /// The identifier as written.
724    pub name: String,
725    /// Where it was written.
726    pub range: SourceRange,
727}
728
729/// Everything one run of the preprocessor produced.
730#[derive(Debug)]
731pub struct Preprocessed {
732    /// The token list, always ending with [`TokenKind::Eof`].
733    pub tokens: Vec<Token>,
734    /// The macro invocations that were replaced.
735    pub expansions: Expansions,
736    /// The files `#include` opened, in the order they were opened, which is
737    /// also the order they must be added to a source map: a file is always
738    /// listed after the one whose directive pulled it in.
739    pub included: Vec<IncludedFile>,
740    /// The absolute paths of the *user* headers that were read, for rebuild
741    /// tracking. A bundled header cannot change without the crate changing, so
742    /// it is not listed.
743    pub user_headers: Vec<std::path::PathBuf>,
744    /// The absolute paths of the resources `#embed` read, for the same reason
745    /// and by the same route — except that they are bytes rather than text, so
746    /// the expansion tracks them with `include_bytes!`.
747    pub embedded_files: Vec<std::path::PathBuf>,
748    /// The libraries `#pragma cinrs link` asked for, in the order asked.
749    pub link_libraries: Vec<String>,
750    /// The functions `#pragma cinrs safe` named, in the order named.
751    pub safe_functions: Vec<SafeName>,
752    /// Whether `#pragma cinrs export` asked for real C symbols.
753    pub export: bool,
754    /// Whether `#pragma cinrs no_std` said the expansion goes into a
755    /// `#![no_std]` crate.
756    pub no_std: bool,
757    /// The Rust path `#pragma cinrs crate` gave the `cinrs` facade crate,
758    /// which the generated code names when it needs the runtime.
759    pub crate_path: Option<String>,
760    /// Every `#pragma pack` the unit wrote, as `(token index, alignment)`.
761    ///
762    /// A pragma is not a token, so the change is recorded against the position
763    /// in [`Preprocessed::tokens`] it takes effect at; [`PackMap`] answers what
764    /// was in force where a `struct` was defined.
765    pub pack_events: Vec<(usize, Option<u32>)>,
766}
767
768/// What `#pragma pack` asked for, at every point of the token list.
769#[derive(Clone, Debug, Default)]
770pub struct PackMap {
771    events: Vec<(usize, Option<u32>)>,
772}
773
774impl PackMap {
775    /// Builds the map from the preprocessor's events, which are in order.
776    pub fn new(events: Vec<(usize, Option<u32>)>) -> Self {
777        Self { events }
778    }
779
780    /// Whether any `#pragma pack` was written at all.
781    pub fn is_empty(&self) -> bool {
782        self.events.is_empty()
783    }
784
785    /// The maximum member alignment in force at token `index`.
786    pub fn at(&self, index: usize) -> Option<u32> {
787        let at = self.events.partition_point(|(pos, _)| *pos <= index);
788        self.events[..at].last().and_then(|(_, value)| *value)
789    }
790}
791
792/// Runs the preprocessor over a lexed translation unit.
793///
794/// The returned list always ends with [`TokenKind::Eof`]. Problems the lexer
795/// found are reported here: what is wrong with a token itself only when that
796/// token survives, and what is wrong with the *text* — its spelling, and the
797/// comments before it — as soon as the token is read. Neither is reported for a
798/// group skipped by `#if 0`, whose text is never read at all and may hold
799/// anything.
800pub fn preprocess(
801    tokens: &[lex::Token],
802    ctx: &Context,
803    options: &Options,
804    diags: &mut Diagnostics,
805) -> Preprocessed {
806    let mut pp = Pp::new(tokens, ctx, options, diags);
807    pp.run();
808    Preprocessed {
809        tokens: pp.out,
810        expansions: pp.expansions,
811        included: pp.included,
812        user_headers: pp.user_headers,
813        embedded_files: pp.embedded_files,
814        link_libraries: pp.link_libraries,
815        safe_functions: pp.safe_functions,
816        export: pp.export,
817        no_std: pp.no_std,
818        crate_path: pp.crate_path,
819        pack_events: pp.pack_events,
820    }
821}
822
823/// What [`scan_target_pragma`] found, which the preprocessor needs in order
824/// not to report the same directive twice.
825#[derive(Clone, Debug, Default)]
826pub struct TargetPragmas {
827    /// Where each `#pragma cinrs target` in the unit's own text begins — the
828    /// offset of its `#`, which is where the preprocessor's own range for a
829    /// directive starts too.
830    pub at: Vec<Pos>,
831    /// Whether one of them really chose the model. False when there was none,
832    /// and false when there was one that has already been reported.
833    pub applied: bool,
834}
835
836impl TargetPragmas {
837    /// Whether the directive at `range` is one the scan read.
838    fn scanned(&self, range: SourceRange) -> bool {
839        self.at.contains(&range.start)
840    }
841}
842
843/// Finds `#pragma cinrs target "<triple>"` in a freshly lexed unit and puts the
844/// model it names into `options`.
845///
846/// This runs *before* the preprocessor, and has to. Everything the
847/// preprocessor does with the model — the hundred-odd predefined macros, and
848/// therefore which branch every `#if` and every bundled header takes — is
849/// settled when it starts, so a pragma handled where it stands would arrive
850/// too late to mean what it says. Reading it lexically is the price: the
851/// directive is recognised by its shape, in the unit's own text, whether or
852/// not a conditional group would later have skipped it, and a second one
853/// naming a different triple is an error rather than a last-one-wins.
854///
855/// The preprocessor sees the same directives again during the real run —
856/// `Pp::target_pragma` is where — which is what catches the two cases this
857/// scan cannot serve: a `target` pragma the scan never read, because it is in
858/// a header or came out of `_Pragma`, and one written after an `#include` or
859/// an `#if` that the old model had already answered.
860///
861/// The caller must lex the text again when the model changed: how wide
862/// `wchar_t` is decides what `L'…'` may hold.
863pub fn scan_target_pragma(
864    tokens: &[lex::Token],
865    options: &mut Options,
866    diags: &mut Diagnostics,
867) -> (TargetPragmas, bool) {
868    let mut found = TargetPragmas::default();
869    let mut chosen: Option<(String, SourceRange)> = None;
870    let mut failed = false;
871    for (i, hash) in tokens.iter().enumerate() {
872        // `# pragma cinrs target "…"`, the directive spelled out; the lexer
873        // marks the token that begins a logical line.
874        if !hash.bol || !hash.is_punct(Punct::Hash) {
875            continue;
876        }
877        // Five tokens are enough for `pragma cinrs target "…"` and the one
878        // trailing token the diagnostic complains about; a `#define` whose
879        // replacement list runs to a hundred is not walked to the end just to
880        // discover it is not this.
881        let words: Vec<&lex::Token> = tokens[i + 1..]
882            .iter()
883            .take_while(|t| !t.bol && !matches!(t.kind, TokenKind::Eof))
884            .take(5)
885            .collect();
886        let [pragma, cinrs, option, rest @ ..] = words.as_slice() else {
887            continue;
888        };
889        if pragma.ident() != Some("pragma")
890            || cinrs.ident() != Some("cinrs")
891            || option.ident() != Some("target")
892        {
893            continue;
894        }
895        found.at.push(hash.range.start);
896        let range = SourceRange::new(hash.range.start, option.range.end);
897        let Some(triple) = target_pragma_triple(rest, range, diags) else {
898            failed = true;
899            continue;
900        };
901        match &chosen {
902            // The same triple twice says the same thing twice, which is no
903            // mistake at all.
904            Some((first, _)) if *first == triple => {}
905            Some((first, _)) => {
906                diags.error(
907                    range,
908                    format!(
909                        "this unit is already translated for '{first}' by an earlier \
910                         #pragma cinrs target"
911                    ),
912                );
913                failed = true;
914            }
915            None => chosen = Some((triple, range)),
916        }
917    }
918    let Some((triple, range)) = chosen.filter(|_| !failed) else {
919        return (found, false);
920    };
921    let source = TargetSource::Pragma(triple);
922    match TargetModel::from_triple(source.triple().expect("Pragma carries its triple")) {
923        Ok(model) => {
924            let relex = options.target != model;
925            options.target = model;
926            options.target_source = source;
927            found.applied = true;
928            (found, relex)
929        }
930        Err(unknown) => {
931            diags.error(range, unknown.message(&source));
932            (found, false)
933        }
934    }
935}
936
937/// The one string literal `#pragma cinrs target` takes, as the pre-scan reads
938/// it. The messages match [`Pp::pragma_string`]'s, since the same mistake must
939/// read the same whichever pass notices it.
940fn target_pragma_triple(
941    rest: &[&lex::Token],
942    range: SourceRange,
943    diags: &mut Diagnostics,
944) -> Option<String> {
945    let Some(tok) = rest.first() else {
946        diags.error(range, "#pragma cinrs target needs a string literal");
947        return None;
948    };
949    let TokenKind::Str(lit) = &tok.kind else {
950        diags.error(
951            tok.range,
952            format!(
953                "#pragma cinrs target needs a string literal, found {}",
954                tok.kind.describe()
955            ),
956        );
957        return None;
958    };
959    let Some(bytes) = lit.as_bytes() else {
960        diags.error(
961            tok.range,
962            "#pragma cinrs target does not take a wide string literal",
963        );
964        return None;
965    };
966    let value = String::from_utf8_lossy(&bytes).into_owned();
967    if value.is_empty() {
968        diags.error(tok.range, "#pragma cinrs target was given an empty string");
969        return None;
970    }
971    if let Some(extra) = rest.get(1) {
972        diags.error(
973            extra.range,
974            format!(
975                "unexpected {} after #pragma cinrs target",
976                extra.kind.describe()
977            ),
978        );
979    }
980    Some(value)
981}
982
983// ---------------------------------------------------------------------------
984// the machine
985// ---------------------------------------------------------------------------
986
987/// One `#if` / `#ifdef` / `#ifndef` group.
988struct Cond {
989    /// Where the directive that opened the group is.
990    range: SourceRange,
991    /// Whether the enclosing group was itself being processed.
992    outer_active: bool,
993    /// Whether a branch has already been taken.
994    taken: bool,
995    /// Whether the branch now open is being processed.
996    active: bool,
997    /// Whether `#else` has been seen.
998    seen_else: bool,
999}
1000
1001/// What one `#line` — or one GCC line marker — did to a file's numbering.
1002///
1003/// See [`Pp::line_directive`]. Only `__LINE__` and `__FILE__` are affected:
1004/// a diagnostic still points at the token that was really written, which is the
1005/// whole point of this crate.
1006struct LineDirective {
1007    /// The zero-based index of the *physical* line the directive is written on.
1008    at: usize,
1009    /// The number the next physical line is given.
1010    line: usize,
1011    /// What `__FILE__` says from that line on: the name the directive gave, or
1012    /// the one in force when it was written.
1013    name: String,
1014}
1015
1016/// One file the preprocessor has read, kept for as long as positions inside it
1017/// can still be reported.
1018struct FileEntry {
1019    /// The text, which `#error` and `#include` read back verbatim.
1020    text: String,
1021    /// The global offset of its first byte.
1022    base: Pos,
1023    /// File-local byte offsets at which each line starts.
1024    line_starts: Vec<u32>,
1025    /// The line of the enclosing `.rs` file its own line 1 sits on; 1 for a
1026    /// header, which counts its own lines.
1027    first_line: usize,
1028    /// What `__FILE__` says inside it.
1029    name: String,
1030    /// The `#line` directives it has executed so far, in the order they were
1031    /// reached — which is the order of their positions, since a file is only
1032    /// ever read forwards.
1033    lines: Vec<LineDirective>,
1034}
1035
1036impl FileEntry {
1037    fn new(text: String, base: Pos, first_line: usize, name: String) -> Self {
1038        let mut line_starts = vec![0u32];
1039        for (i, b) in text.bytes().enumerate() {
1040            if b == b'\n' {
1041                line_starts.push(i as u32 + 1);
1042            }
1043        }
1044        Self {
1045            text,
1046            base,
1047            line_starts,
1048            first_line: first_line.max(1),
1049            name,
1050            lines: Vec::new(),
1051        }
1052    }
1053
1054    /// The zero-based index of the physical line `local` sits on.
1055    fn physical_line(&self, local: Pos) -> usize {
1056        self.line_starts
1057            .partition_point(|start| *start <= local)
1058            .saturating_sub(1)
1059    }
1060
1061    /// The `#line` in force on physical line `index`, if there is one.
1062    ///
1063    /// A directive takes effect on the line *after* itself, so its own line
1064    /// still counts the way the one before it did.
1065    fn directive_for(&self, index: usize) -> Option<&LineDirective> {
1066        let after = self.lines.partition_point(|d| d.at < index);
1067        self.lines[..after].last()
1068    }
1069
1070    /// The line `local` sits on, counted the way `__LINE__` counts.
1071    fn line_of(&self, local: Pos) -> usize {
1072        let index = self.physical_line(local);
1073        match self.directive_for(index) {
1074            // The directive named the line after itself; every line after that
1075            // one counts up from there.
1076            Some(d) => d.line + (index - d.at - 1),
1077            None => self.first_line + index,
1078        }
1079    }
1080
1081    /// The name `__FILE__` reports for `local`.
1082    fn name_of(&self, local: Pos) -> &str {
1083        match self.directive_for(self.physical_line(local)) {
1084            Some(d) => &d.name,
1085            None => &self.name,
1086        }
1087    }
1088}
1089
1090/// A file that is open: being read right now, or waiting for the `#include`
1091/// inside it to finish.
1092struct OpenFile {
1093    /// The whole file, lexed once.
1094    input: Vec<PTok>,
1095    /// Where in `input` the next unread token is.
1096    pos: usize,
1097    /// Where an `#include "…"` written in it looks first.
1098    origin: include::Origin,
1099    /// The search entry it was found under, which is where an `#include_next`
1100    /// written in it goes on *after*. `None` for the unit's own text and for a
1101    /// header no search found.
1102    found_in: Option<include::Entry>,
1103    /// What identifies it for `#pragma once` and the include-guard
1104    /// optimisation: its canonical path, or the name of a bundled header.
1105    key: String,
1106    /// How many conditional groups were open when it was entered, so that one
1107    /// it leaves unterminated is reported against it rather than leaking into
1108    /// the file that included it.
1109    cond_base: usize,
1110}
1111
1112struct Pp<'a> {
1113    /// Every file read so far, in the order they were opened.
1114    files: Vec<FileEntry>,
1115    /// The files being read, outermost first.
1116    open: Vec<OpenFile>,
1117    /// Tokens produced by macro replacement, innermost last.
1118    pending: Vec<PTok>,
1119    out: Vec<Token>,
1120    macros: HashMap<String, Arc<MacroDef>>,
1121    conds: Vec<Cond>,
1122    diags: &'a mut Diagnostics,
1123    expansions: Expansions,
1124    /// Lexer problems already reported, so that a macro used twice does not
1125    /// report the same bad token in its body twice.
1126    reported: HashSet<(Pos, Pos, String)>,
1127    /// The global offset of the root file, where anything with no position of
1128    /// its own is reported.
1129    base: Pos,
1130    lex_options: LexOptions,
1131    /// How a construct of a newer revision is gated, and whether the plain GNU
1132    /// spellings are on.
1133    gating: Gating,
1134    depth: u32,
1135    /// Tokens still allowed to come out of macro replacement.
1136    budget: usize,
1137    /// Set once the budget ran out; stops all further replacement.
1138    aborted: bool,
1139    // -- `#include` ---------------------------------------------------------
1140    /// Where the next included file's text is placed.
1141    next_base: Pos,
1142    /// The included files, for the caller's source map.
1143    included: Vec<IncludedFile>,
1144    /// The directories headers are looked for in.
1145    search: include::SearchPaths,
1146    /// The files `#pragma once` has closed for good.
1147    once: HashSet<String>,
1148    /// The stacks `#pragma push_macro("X")` pushed, by macro name.
1149    macro_stacks: HashMap<String, Vec<Option<Arc<MacroDef>>>>,
1150    /// The identifiers `#pragma GCC poison` made unusable.
1151    poisoned: HashSet<String>,
1152    /// The next value `__COUNTER__` expands to.
1153    counter: u64,
1154    /// The member alignment `#pragma pack` is currently asking for.
1155    pack: Option<u32>,
1156    /// What `#pragma pack(push)` saved.
1157    pack_stack: Vec<Option<u32>>,
1158    /// Every change of that value, by the index in `out` it takes effect at.
1159    pack_events: Vec<(usize, Option<u32>)>,
1160    /// The name of the outermost file, which `__BASE_FILE__` reports.
1161    base_file: String,
1162    /// The include guard of a file that has one: its name, and the macro that
1163    /// makes reading it again pointless.
1164    guards: HashMap<String, String>,
1165    /// The absolute paths of the user headers that were read.
1166    user_headers: Vec<std::path::PathBuf>,
1167    /// The absolute paths of the resources `#embed` read.
1168    embedded_files: Vec<std::path::PathBuf>,
1169    /// The libraries `#pragma cinrs link` asked for.
1170    link_libraries: Vec<String>,
1171    /// The functions `#pragma cinrs safe` named.
1172    safe_functions: Vec<SafeName>,
1173    /// Set by `#pragma cinrs export`.
1174    export: bool,
1175    /// Set by `#pragma cinrs no_std`.
1176    no_std: bool,
1177    /// The Rust path `#pragma cinrs crate` gave the facade crate.
1178    crate_path: Option<String>,
1179    /// Where the data model in force came from, which is what a
1180    /// `#pragma cinrs target` the scan never read is reported against.
1181    target_source: TargetSource,
1182    /// The data model in force, which is what the platform's own include
1183    /// directories are chosen from — and refused for, on a cross build.
1184    target: crate::target::TargetModel,
1185    /// The `target` pragmas [`scan_target_pragma`] already dealt with.
1186    target_pragmas: TargetPragmas,
1187    /// Whether anything has yet been decided *by* the data model: a header
1188    /// opened, or an `#if` evaluated. A `#pragma cinrs target` after that
1189    /// point cannot mean what it says, so it is reported.
1190    model_observed: bool,
1191}
1192
1193impl<'a> Pp<'a> {
1194    fn new(
1195        tokens: &[lex::Token],
1196        ctx: &'a Context,
1197        options: &Options,
1198        diags: &'a mut Diagnostics,
1199    ) -> Self {
1200        let root = FileEntry::new(
1201            ctx.text.clone(),
1202            ctx.base,
1203            ctx.first_line,
1204            ctx.file_name.clone(),
1205        );
1206        let mut input: Vec<PTok> = tokens.iter().map(PTok::from_lexed).collect();
1207        if input.is_empty() {
1208            input.push(eof_token(ctx.base));
1209        }
1210        let mut pp = Pp {
1211            files: vec![root],
1212            open: vec![OpenFile {
1213                input,
1214                pos: 0,
1215                origin: match &ctx.dir {
1216                    Some(dir) => include::Origin::Dir(dir.clone()),
1217                    None => include::Origin::Unknown,
1218                },
1219                found_in: None,
1220                key: ctx.file_name.clone(),
1221                cond_base: 0,
1222            }],
1223            pending: Vec::new(),
1224            out: Vec::new(),
1225            macros: HashMap::new(),
1226            conds: Vec::new(),
1227            diags,
1228            expansions: Expansions::default(),
1229            reported: HashSet::new(),
1230            base: ctx.base,
1231            lex_options: options.into(),
1232            gating: options.gating(),
1233            depth: 0,
1234            budget: MAX_EXPANDED_TOKENS,
1235            aborted: false,
1236            next_base: ctx.next_base,
1237            included: Vec::new(),
1238            search: include::SearchPaths::new(&options.include_paths),
1239            once: HashSet::new(),
1240            macro_stacks: HashMap::new(),
1241            poisoned: HashSet::new(),
1242            counter: 0,
1243            pack: None,
1244            pack_stack: Vec::new(),
1245            pack_events: Vec::new(),
1246            base_file: ctx.file_name.clone(),
1247            guards: HashMap::new(),
1248            user_headers: Vec::new(),
1249            embedded_files: Vec::new(),
1250            link_libraries: Vec::new(),
1251            safe_functions: Vec::new(),
1252            export: false,
1253            no_std: false,
1254            crate_path: None,
1255            target_source: options.target_source.clone(),
1256            target: options.target,
1257            target_pragmas: ctx.target_pragmas.clone(),
1258            model_observed: false,
1259        };
1260        pp.define_predefined(options);
1261        // The crate-wide switch, which `#pragma cinrs system_include` in the
1262        // unit turns on again with the mode it wants. Reported against the
1263        // whole unit, there being nothing in the C to point at — the same
1264        // place a bad `CINRS_TARGET` is reported.
1265        if options.system_include.is_on() {
1266            let range = SourceRange::new(ctx.base, ctx.base + ctx.text.len() as Pos);
1267            pp.enable_system_include(options.system_include, range);
1268        }
1269        pp
1270    }
1271
1272    // -- reading ------------------------------------------------------------
1273
1274    /// The file being read.
1275    fn cur(&self) -> &OpenFile {
1276        self.open
1277            .last()
1278            .expect("the root file is only closed when the run ends")
1279    }
1280
1281    fn cur_mut(&mut self) -> &mut OpenFile {
1282        self.open
1283            .last_mut()
1284            .expect("the root file is only closed when the run ends")
1285    }
1286
1287    /// The file's next token, which is its end-of-file token once it has run
1288    /// out.
1289    fn ahead(&self) -> &PTok {
1290        let file = self.cur();
1291        &file.input[file.pos]
1292    }
1293
1294    /// The next token without consuming it, or `None` when replacement output
1295    /// has run out and the caller may not read the file itself.
1296    fn peek(&self, allow_input: bool) -> Option<&PTok> {
1297        if let Some(t) = self.pending.last() {
1298            return Some(t);
1299        }
1300        allow_input.then(|| self.ahead())
1301    }
1302
1303    /// The next token, consumed.
1304    ///
1305    /// Reading never crosses a file boundary: at the end of an `#include`d
1306    /// file this keeps answering with that file's end-of-file token, so that a
1307    /// macro invocation left unfinished there is reported instead of quietly
1308    /// swallowing what follows the directive. [`Pp::run`] is what closes a
1309    /// file.
1310    ///
1311    /// Reading a token out of the file is also where what is wrong with its
1312    /// *text* is reported, whatever becomes of the token itself: the comment
1313    /// before it was written, and an ill-formed universal character name is
1314    /// ill-formed where it stands (6.4.3p2), so neither waits to see whether
1315    /// the token reaches the output, is the name of a macro that replaces it,
1316    /// or is an argument the macro drops. Every UCN in Clang's own
1317    /// `C99/n717.c` is written as the argument of a macro that expands to
1318    /// nothing, and each one still has to be diagnosed. What is wrong with the
1319    /// *token* waits: a stray `\` or `$` is a preprocessing token like any
1320    /// other until something tries to parse it (6.4p3). Nothing here runs over
1321    /// a skipped group — [`Pp::run`] discards those tokens without reading
1322    /// them — and `Pp::reported` keeps a token that is read and then also
1323    /// emitted, or read twice, to one diagnostic.
1324    fn bump(&mut self, allow_input: bool) -> Option<PTok> {
1325        if let Some(t) = self.pending.pop() {
1326            return Some(t);
1327        }
1328        if !allow_input {
1329            return None;
1330        }
1331        let tok = self.ahead().clone();
1332        if !tok.is_eof() {
1333            self.cur_mut().pos += 1;
1334        }
1335        self.report_lexical_errors(&tok);
1336        Some(tok)
1337    }
1338
1339    /// Whether the file's next token opens a directive.
1340    fn at_directive(&self) -> bool {
1341        let tok = self.ahead();
1342        tok.bol && tok.is_punct(Punct::Hash)
1343    }
1344
1345    fn skipping(&self) -> bool {
1346        self.conds.last().is_some_and(|c| !c.active)
1347    }
1348
1349    // -- the main loop ------------------------------------------------------
1350
1351    fn run(&mut self) {
1352        loop {
1353            // Directives, the end of a file and skipped groups are all
1354            // properties of the *file*, so they are only looked at once
1355            // everything macro replacement produced has been dealt with.
1356            if self.pending.is_empty() {
1357                if self.ahead().is_eof() {
1358                    if self.open.len() > 1 {
1359                        self.close_file();
1360                        continue;
1361                    }
1362                    self.finish();
1363                    return;
1364                }
1365                if self.at_directive() {
1366                    self.directive();
1367                    continue;
1368                }
1369                if self.skipping() {
1370                    // A skipped group is not even lexically C: discard its
1371                    // tokens without looking at them, and without reporting
1372                    // anything.
1373                    self.cur_mut().pos += 1;
1374                    continue;
1375                }
1376            }
1377            let Some(tok) = self.bump(true) else {
1378                unreachable!("reading the file is always allowed here");
1379            };
1380            if tok.is_eof() {
1381                // Handled above; nothing puts an end-of-file token into the
1382                // replacement output.
1383                continue;
1384            }
1385            if tok.name().is_some() && self.try_expand(&tok, true) {
1386                continue;
1387            }
1388            if tok.name() == Some(PRAGMA_OPERATOR) && self.pragma_operator(&tok) {
1389                continue;
1390            }
1391            self.emit(tok);
1392        }
1393    }
1394
1395    /// C99's `_Pragma ( string-literal )`, which is a pragma written where an
1396    /// expression could go — and therefore the only way a *macro* can produce
1397    /// one.
1398    ///
1399    /// Returns whether it really was one: the name on its own is an ordinary
1400    /// identifier.
1401    fn pragma_operator(&mut self, tok: &PTok) -> bool {
1402        if !self.peek(true).is_some_and(|t| t.is_punct(Punct::LParen)) {
1403            return false;
1404        }
1405        self.require_standard(Standard::C99, "'_Pragma'", tok.range);
1406        self.bump(true);
1407        let literal = self.bump(true);
1408        let Some(text) = literal.as_ref().and_then(|t| match &t.kind {
1409            TokenKind::Str(lit) => Some(destringize(&lit.text)),
1410            _ => None,
1411        }) else {
1412            self.diags
1413                .error(tok.range, "'_Pragma' takes one string literal");
1414            return true;
1415        };
1416        if !self.bump(true).is_some_and(|t| t.is_punct(Punct::RParen)) {
1417            self.diags.error(tok.range, "missing ')' after '_Pragma'");
1418            return true;
1419        }
1420        // The destringized text is a directive line without its `#pragma`, so
1421        // it is lexed and handed to the same code the directive uses. The
1422        // tokens are placed at the `_Pragma` itself, which is where a
1423        // diagnostic about them belongs.
1424        let tokens: Vec<PTok> = lex::lex_text(&text, tok.range.start, &self.lex_options)
1425            .iter()
1426            .filter(|t| !matches!(t.kind, TokenKind::Eof))
1427            .map(PTok::from_lexed)
1428            .collect();
1429        self.pragma(&tokens, tok.range);
1430        true
1431    }
1432
1433    /// Leaves an `#include`d file, reporting the conditionals it left open.
1434    fn close_file(&mut self) {
1435        // A header's own end-of-file token goes nowhere — only the unit's
1436        // reaches the output — so this is the last chance to say what the text
1437        // at the end of it did wrong. An `#include`d file that ends in a `//`
1438        // comment is the case: there is no token after it to carry the
1439        // diagnostic anywhere else.
1440        if !self.skipping() {
1441            let eof = self.ahead().clone();
1442            self.report_lexical_errors(&eof);
1443        }
1444        let base = self.cur().cond_base;
1445        for cond in self.conds.drain(base..).collect::<Vec<_>>() {
1446            self.diags
1447                .error(cond.range, "unterminated conditional directive");
1448        }
1449        self.open.pop();
1450    }
1451
1452    /// Reports what never closed and emits the end-of-input token.
1453    fn finish(&mut self) {
1454        // A conditional the unit never closed is an error, and the group it
1455        // opened is still a skipped one: what the lexer found in the text it
1456        // swallowed is not reported, exactly as inside a closed `#if 0`.
1457        let skipped = self.skipping();
1458        for cond in std::mem::take(&mut self.conds) {
1459            self.diags
1460                .error(cond.range, "unterminated conditional directive");
1461        }
1462        let file = self.cur();
1463        let mut eof = file.input[file.input.len() - 1].clone();
1464        if skipped {
1465            eof.errors.clear();
1466        }
1467        self.emit(eof);
1468    }
1469
1470    fn emit(&mut self, mut tok: PTok) {
1471        self.report_errors(&tok);
1472        if matches!(tok.kind, TokenKind::Error(_)) {
1473            // Not a C token at all: reported above, and dropped so that the
1474            // parser never has to have an opinion about it.
1475            return;
1476        }
1477        // The GNU keywords are recognised *here*, on the way to the parser,
1478        // rather than in the lexer: until this point `__attribute__` is an
1479        // ordinary identifier, so `#define __attribute__(x)` — which every
1480        // portability header writes — defines and expands a macro of that
1481        // name, and `#ifdef __restrict` answers about the name that was
1482        // written.
1483        if let TokenKind::Ident(name) = &tok.kind {
1484            if self.poisoned.contains(name) {
1485                let range = tok.range;
1486                let name = name.clone();
1487                self.diags.error(
1488                    range,
1489                    format!("attempt to use the poisoned identifier '{name}'"),
1490                );
1491            }
1492            if let Some(keyword) = gnu_keyword(name, self.gating.dialect) {
1493                tok.kind = TokenKind::Keyword(keyword);
1494            }
1495        }
1496        self.out.push(Token {
1497            kind: tok.kind,
1498            range: tok.range,
1499            origin: tok.origin,
1500        });
1501    }
1502
1503    /// Reports the problems the lexer attached to a token that survived.
1504    fn report_errors(&mut self, tok: &PTok) {
1505        self.report_token_diags(tok, false);
1506    }
1507
1508    /// Reports only what is wrong with the *text* a token was formed from — its
1509    /// spelling, and the comments before it — which stands whether or not the
1510    /// token goes anywhere; see [`Diagnostic::lexical`].
1511    fn report_lexical_errors(&mut self, tok: &PTok) {
1512        self.report_token_diags(tok, true);
1513    }
1514
1515    fn report_token_diags(&mut self, tok: &PTok, lexical_only: bool) {
1516        for diag in &tok.errors {
1517            if lexical_only && !diag.lexical {
1518                continue;
1519            }
1520            let key = (diag.range.start, diag.range.end, diag.message.clone());
1521            if self.reported.insert(key) {
1522                self.diags.push(diag.clone());
1523            }
1524        }
1525    }
1526
1527    /// The file a position is in.
1528    ///
1529    /// Every file ever opened stays in `files`, and their bases only ever
1530    /// increase, so a position identifies one of them even after it has been
1531    /// left — which is what a diagnostic about a macro defined in a header
1532    /// that was closed long ago needs.
1533    fn file_at(&self, pos: Pos) -> &FileEntry {
1534        &self.files[self.file_index(pos)]
1535    }
1536
1537    /// The index in `files` of the file a position is in.
1538    fn file_index(&self, pos: Pos) -> usize {
1539        self.files
1540            .partition_point(|f| f.base <= pos)
1541            .saturating_sub(1)
1542    }
1543
1544    /// A position's offset within its own file.
1545    fn local_pos(file: &FileEntry, pos: Pos) -> Pos {
1546        pos.saturating_sub(file.base).min(file.text.len() as Pos)
1547    }
1548
1549    /// The line number `__LINE__` reports for a position.
1550    fn line_of(&self, pos: Pos) -> usize {
1551        let file = self.file_at(pos);
1552        file.line_of(Self::local_pos(file, pos))
1553    }
1554
1555    /// The name `__FILE__` reports for a position.
1556    fn file_name_of(&self, pos: Pos) -> &str {
1557        let file = self.file_at(pos);
1558        file.name_of(Self::local_pos(file, pos))
1559    }
1560
1561    /// The verbatim source text between two positions.
1562    fn raw_text(&self, from: Pos, to: Pos) -> &str {
1563        let file = self.file_at(from);
1564        let start = from.saturating_sub(file.base) as usize;
1565        let end = to.saturating_sub(file.base) as usize;
1566        file.text.get(start..end).unwrap_or("")
1567    }
1568}
1569
1570/// The GNU keyword an identifier spells, if it spells one.
1571///
1572/// Everything with a leading double underscore is available in every entry
1573/// point, exactly as it is in GCC's `-std=c99`: the names are reserved, so
1574/// nothing a program may legally call its own is taken away. The two *plain*
1575/// spellings GCC keeps for its `gnu*` modes — `typeof` and `asm` — need a GNU
1576/// dialect, and `typeof` is already a keyword of its own in `c23!`.
1577fn gnu_keyword(name: &str, dialect: Dialect) -> Option<Keyword> {
1578    let keyword = match name {
1579        "__inline" | "__inline__" => Keyword::InlineGnu,
1580        "__const" | "__const__" => Keyword::Const,
1581        "__signed" | "__signed__" => Keyword::Signed,
1582        "__volatile" | "__volatile__" => Keyword::Volatile,
1583        "__restrict" | "__restrict__" => Keyword::RestrictGnu,
1584        "__complex__" | "__complex" => Keyword::Complex,
1585        "__attribute" | "__attribute__" => Keyword::Attribute,
1586        "__extension__" => Keyword::Extension,
1587        "__alignof" | "__alignof__" => Keyword::AlignofGnu,
1588        "__typeof" | "__typeof__" => Keyword::TypeofGnu,
1589        "__typeof_unqual__" | "__typeof_unqual" => Keyword::TypeofUnqualGnu,
1590        "__asm" | "__asm__" => Keyword::Asm,
1591        "__label__" => Keyword::Label,
1592        "__auto_type" => Keyword::AutoType,
1593        "__thread" => Keyword::ThreadGnu,
1594        "__int128" => Keyword::Int128,
1595        "__real" | "__real__" => Keyword::RealGnu,
1596        "__imag" | "__imag__" => Keyword::ImagGnu,
1597        "asm" if dialect.is_gnu() => Keyword::Asm,
1598        "typeof" if dialect.is_gnu() => Keyword::TypeofGnu,
1599        _ => return None,
1600    };
1601    Some(keyword)
1602}
1603
1604/// The end-of-file token an empty file still has to produce.
1605fn eof_token(base: Pos) -> PTok {
1606    PTok {
1607        kind: TokenKind::Eof,
1608        range: SourceRange::at(base),
1609        bol: true,
1610        space: true,
1611        origin: Origin::Source,
1612        hide: HideSet::default(),
1613        errors: Vec::new(),
1614    }
1615}
1616
1617// ---------------------------------------------------------------------------
1618// macro replacement
1619// ---------------------------------------------------------------------------
1620
1621/// The arguments of one function-like invocation.
1622struct Args {
1623    /// The arguments as written.
1624    raw: Vec<Vec<PTok>>,
1625    /// The arguments after full macro replacement, computed on demand: an
1626    /// argument used only by `#` or `##` must never be expanded, and expanding
1627    /// an unused one could report an error the program does not contain.
1628    expanded: Vec<Option<Vec<PTok>>>,
1629}
1630
1631impl Args {
1632    fn new(raw: Vec<Vec<PTok>>) -> Self {
1633        Self {
1634            expanded: vec![None; raw.len()],
1635            raw,
1636        }
1637    }
1638
1639    fn get(&self, index: usize) -> &[PTok] {
1640        self.raw.get(index).map_or(&[], Vec::as_slice)
1641    }
1642}
1643
1644/// One element of a replacement list under construction.
1645///
1646/// The placemarker is the standard's own device (6.10.3.3p2): it stands where
1647/// an empty argument was, so that `a ## b` with an empty `b` pastes into `a`
1648/// rather than into whatever came next.
1649enum Piece {
1650    Tok(PTok),
1651    Placemarker,
1652}
1653
1654impl Pp<'_> {
1655    /// Replaces `tok` if it invokes a macro, pushing the result back onto the
1656    /// stream so that it is rescanned.
1657    ///
1658    /// `allow_input` says whether the `(` of a function-like invocation may be
1659    /// read from the file. It is false while an argument is being
1660    /// pre-expanded, where the standard says the argument behaves as if it
1661    /// were the whole rest of the file.
1662    fn try_expand(&mut self, tok: &PTok, allow_input: bool) -> bool {
1663        if self.aborted {
1664            return false;
1665        }
1666        let Some(name) = tok.name() else {
1667            return false;
1668        };
1669        if tok.hide.contains(name) {
1670            // Painted blue: the token was produced by this very macro, and the
1671            // hide set travels with it, so it stays unreplaceable for good.
1672            return false;
1673        }
1674        let Some(def) = self.macros.get(name).cloned() else {
1675            return false;
1676        };
1677        let name = name.to_owned();
1678
1679        if let Some(builtin) = def.builtin {
1680            let value = self.builtin_token(builtin, tok, &def, &name);
1681            self.push_pending(vec![value], tok.space);
1682            return true;
1683        }
1684
1685        let Some(params) = &def.params else {
1686            let hide = tok.hide.add(&name);
1687            let exp = self.expansion_of(&name, tok.range, &def, tok);
1688            let mut args = Args::new(Vec::new());
1689            let body = self.subst(&def, &mut args, &hide, tok.range, &exp);
1690            self.push_pending(body, tok.space);
1691            if !def.predefined {
1692                self.expansions.record(tok.range, &name, def.name_range);
1693            }
1694            return true;
1695        };
1696
1697        // A function-like macro's name is only an invocation when the very
1698        // next token is `(`.
1699        if !self
1700            .peek(allow_input)
1701            .is_some_and(|t| t.is_punct(Punct::LParen))
1702        {
1703            return false;
1704        }
1705        let params = params.clone();
1706        self.bump(allow_input);
1707
1708        let Some((mut raw, rparen)) = self.collect_args(&def, &params, tok.range, allow_input)
1709        else {
1710            return true;
1711        };
1712        let invocation = tok.range.join(rparen.range);
1713        if !self.check_arity(&def, &params, raw.len(), &name, invocation) {
1714            return true;
1715        }
1716        if def.variadic {
1717            // C99 asks for one more argument than there are parameters; GCC
1718            // and everyone who writes `LOG("done")` disagree, so `...` is
1719            // allowed to match nothing and `__VA_ARGS__` is then empty.
1720            while raw.len() <= params.len() {
1721                raw.push(Vec::new());
1722            }
1723        }
1724
1725        let hide = tok.hide.intersect(&rparen.hide).add(&name);
1726        let exp = self.expansion_of(&name, invocation, &def, tok);
1727        let mut args = Args::new(raw);
1728        let body = self.subst(&def, &mut args, &hide, invocation, &exp);
1729        self.push_pending(body, tok.space);
1730        if !def.predefined {
1731            self.expansions.record(invocation, &name, def.name_range);
1732        }
1733        true
1734    }
1735
1736    fn expansion_of(
1737        &self,
1738        name: &str,
1739        invocation: SourceRange,
1740        def: &MacroDef,
1741        tok: &PTok,
1742    ) -> Arc<Expansion> {
1743        Arc::new(Expansion {
1744            name: name.to_owned(),
1745            invocation,
1746            definition: def.name_range,
1747            parent: tok.origin.expansion().cloned(),
1748        })
1749    }
1750
1751    /// Pushes replacement output back onto the stream, innermost first.
1752    fn push_pending(&mut self, mut toks: Vec<PTok>, space: bool) {
1753        if self.budget < toks.len() {
1754            if !self.aborted {
1755                let range = toks.first().map_or(SourceRange::at(self.base), |t| t.range);
1756                self.diags
1757                    .error(range, "macro expansion produced too many tokens");
1758                self.aborted = true;
1759            }
1760            return;
1761        }
1762        self.budget -= toks.len();
1763        if let Some(first) = toks.first_mut() {
1764            // The replacement stands where the invocation did, so it inherits
1765            // its spacing — and it can never open a directive.
1766            first.space = space;
1767            first.bol = false;
1768        }
1769        self.pending.extend(toks.into_iter().rev());
1770    }
1771
1772    /// Collects a function-like invocation's arguments, returning them
1773    /// together with the `)` that closed the list.
1774    fn collect_args(
1775        &mut self,
1776        def: &MacroDef,
1777        params: &[String],
1778        name_range: SourceRange,
1779        allow_input: bool,
1780    ) -> Option<(Vec<Vec<PTok>>, PTok)> {
1781        let mut args: Vec<Vec<PTok>> = vec![Vec::new()];
1782        let mut depth = 0u32;
1783        loop {
1784            // Running out of tokens is the same failure whether the file ended
1785            // or the argument being pre-expanded did.
1786            let Some(tok) = self.bump(allow_input).filter(|t| !t.is_eof()) else {
1787                self.diags.error(
1788                    name_range,
1789                    "unterminated argument list of a function-like macro",
1790                );
1791                return None;
1792            };
1793            if tok.is_punct(Punct::LParen) {
1794                depth += 1;
1795            } else if tok.is_punct(Punct::RParen) {
1796                if depth == 0 {
1797                    // `f()` for a macro that takes nothing is no argument at
1798                    // all, rather than one empty one.
1799                    if !def.variadic && params.is_empty() && args.len() == 1 && args[0].is_empty() {
1800                        args.clear();
1801                    }
1802                    return Some((args, tok));
1803                }
1804                depth -= 1;
1805            } else if tok.is_punct(Punct::Comma)
1806                && depth == 0
1807                && (!def.variadic || args.len() <= params.len())
1808            {
1809                args.push(Vec::new());
1810                continue;
1811            }
1812            args.last_mut()
1813                .expect("the argument list is never empty")
1814                .push(tok);
1815        }
1816    }
1817
1818    /// Checks the number of arguments against the parameter list, reporting a
1819    /// mismatch at the invocation and answering whether to go on.
1820    ///
1821    /// An invocation whose arity is wrong expands to nothing: the error has
1822    /// been reported, and substituting made-up arguments would only add
1823    /// syntax errors on top of it.
1824    fn check_arity(
1825        &mut self,
1826        def: &MacroDef,
1827        params: &[String],
1828        given: usize,
1829        name: &str,
1830        invocation: SourceRange,
1831    ) -> bool {
1832        let wanted = params.len();
1833        let ok = if def.variadic {
1834            given >= wanted
1835        } else {
1836            given == wanted
1837        };
1838        if ok {
1839            return true;
1840        }
1841        let message = if given < wanted {
1842            let least = if def.variadic { "at least " } else { "" };
1843            format!("macro '{name}' requires {least}{wanted} arguments, but only {given} given")
1844        } else {
1845            format!("macro '{name}' passed {given} arguments, but takes just {wanted}")
1846        };
1847        self.diags.push(
1848            Diagnostic::error(invocation, message)
1849                .with_note_at(def.name_range, format!("macro '{name}' defined")),
1850        );
1851        false
1852    }
1853
1854    /// Builds a replacement list: the standard's `subst`, placemarkers and all.
1855    fn subst(
1856        &mut self,
1857        def: &MacroDef,
1858        args: &mut Args,
1859        hide: &HideSet,
1860        invocation: SourceRange,
1861        exp: &Arc<Expansion>,
1862    ) -> Vec<PTok> {
1863        // `__VA_OPT__` is resolved first, so that everything below sees an
1864        // ordinary replacement list.
1865        let expanded;
1866        let body: &[PTok] = match expand_va_opt(def, args) {
1867            Some(tokens) => {
1868                expanded = tokens;
1869                &expanded
1870            }
1871            None => &def.body,
1872        };
1873        let mut pieces: Vec<Piece> = Vec::with_capacity(body.len());
1874        let mut i = 0;
1875        while i < body.len() {
1876            let tok = &body[i];
1877
1878            // `# parameter` — stringification.
1879            if def.params.is_some()
1880                && tok.is_punct(Punct::Hash)
1881                && let Some(next) = body.get(i + 1)
1882                && let Some(index) = next.name().and_then(|n| def.param_index(n))
1883            {
1884                let kind = self.stringify(args.get(index));
1885                pieces.push(Piece::Tok(self.synthetic(kind, tok, invocation, exp)));
1886                i += 2;
1887                continue;
1888            }
1889
1890            // GNU's comma elision, `printf(fmt, ## __VA_ARGS__)`: the `##`
1891            // between a comma and the variable arguments deletes the comma
1892            // when the invocation passed none, and does nothing at all when it
1893            // passed some — the arguments are then macro-replaced as usual,
1894            // which is what makes it different from an ordinary paste.
1895            // `__VA_OPT__` is C23's way of saying the same thing.
1896            if tok.is_punct(Punct::Comma)
1897                && body.get(i + 1).is_some_and(|t| t.is_punct(Punct::HashHash))
1898                && let Some(index) = body
1899                    .get(i + 2)
1900                    .and_then(PTok::name)
1901                    .and_then(|n| def.param_index(n))
1902                && Some(index) == def.va_index()
1903            {
1904                if !args.get(index).is_empty() {
1905                    let mut comma = tok.clone();
1906                    comma.range = invocation;
1907                    comma.origin = Origin::Expansion(exp.clone());
1908                    pieces.push(Piece::Tok(comma));
1909                    let arg = self.expanded_arg(args, index);
1910                    pieces.extend(arg.into_iter().map(Piece::Tok));
1911                }
1912                i += 3;
1913                continue;
1914            }
1915
1916            // `## something` — pasting.
1917            if tok.is_punct(Punct::HashHash)
1918                && let Some(next) = body.get(i + 1)
1919            {
1920                let rhs = paste_operand(def, args, next);
1921                self.paste_pieces(&mut pieces, rhs, invocation, exp);
1922                i += 2;
1923                continue;
1924            }
1925
1926            // A parameter: `##` on either side keeps it unexpanded.
1927            if let Some(index) = tok.name().and_then(|n| def.param_index(n)) {
1928                let raw = body.get(i + 1).is_some_and(|t| t.is_punct(Punct::HashHash));
1929                if raw {
1930                    let arg = args.get(index).to_vec();
1931                    if arg.is_empty() {
1932                        pieces.push(Piece::Placemarker);
1933                    } else {
1934                        pieces.extend(arg.into_iter().map(Piece::Tok));
1935                    }
1936                } else {
1937                    let arg = self.expanded_arg(args, index);
1938                    pieces.extend(arg.into_iter().map(Piece::Tok));
1939                }
1940                i += 1;
1941                continue;
1942            }
1943
1944            let mut copy = tok.clone();
1945            // The replacement list was written in the `#define`, but it stands
1946            // where the invocation is, and that is where a diagnostic belongs.
1947            copy.range = invocation;
1948            copy.origin = Origin::Expansion(exp.clone());
1949            pieces.push(Piece::Tok(copy));
1950            i += 1;
1951        }
1952
1953        pieces
1954            .into_iter()
1955            .filter_map(|p| match p {
1956                Piece::Tok(mut t) => {
1957                    t.hide = t.hide.union(hide);
1958                    Some(t)
1959                }
1960                Piece::Placemarker => None,
1961            })
1962            .collect()
1963    }
1964
1965    /// Pastes the last piece built so far onto the first of `rhs`.
1966    fn paste_pieces(
1967        &mut self,
1968        pieces: &mut Vec<Piece>,
1969        mut rhs: Vec<Piece>,
1970        invocation: SourceRange,
1971        exp: &Arc<Expansion>,
1972    ) {
1973        if rhs.is_empty() {
1974            return;
1975        }
1976        let head = rhs.remove(0);
1977        let left = pieces.pop();
1978        let joined = match (left, head) {
1979            (None, head) => head,
1980            (Some(Piece::Placemarker), head) => head,
1981            (Some(left), Piece::Placemarker) => left,
1982            (Some(Piece::Tok(l)), Piece::Tok(r)) => match self.paste(&l, &r, invocation) {
1983                Some(kind) => Piece::Tok(self.synthetic(kind, &l, invocation, exp)),
1984                None => {
1985                    // Already reported; keep both halves so that the rest of
1986                    // the expansion still makes some kind of sense.
1987                    pieces.push(Piece::Tok(l));
1988                    Piece::Tok(r)
1989                }
1990            },
1991        };
1992        pieces.push(joined);
1993        pieces.extend(rhs);
1994    }
1995
1996    /// Concatenates two spellings and lexes the result.
1997    fn paste(&mut self, lhs: &PTok, rhs: &PTok, invocation: SourceRange) -> Option<TokenKind> {
1998        let text = format!("{}{}", lhs.spelling(), rhs.spelling());
1999        if text.is_empty() {
2000            return None;
2001        }
2002        let tokens = lex::lex_text(&text, 0, &self.lex_options);
2003        let valid = tokens.len() == 2
2004            && tokens[0].errors.is_empty()
2005            && !matches!(tokens[0].kind, TokenKind::Error(_))
2006            && tokens[0].range.end as usize == text.len();
2007        if !valid {
2008            self.diags.error(
2009                invocation,
2010                format!(
2011                    "pasting '{}' and '{}' does not give a valid token",
2012                    lhs.spelling(),
2013                    rhs.spelling()
2014                ),
2015            );
2016            return None;
2017        }
2018        Some(tokens[0].kind.clone())
2019    }
2020
2021    /// A token that `#` or `##` made up, standing at the invocation.
2022    fn synthetic(
2023        &self,
2024        kind: TokenKind,
2025        like: &PTok,
2026        invocation: SourceRange,
2027        exp: &Arc<Expansion>,
2028    ) -> PTok {
2029        PTok {
2030            kind,
2031            range: invocation,
2032            bol: false,
2033            space: like.space,
2034            origin: Origin::Expansion(exp.clone()),
2035            hide: like.hide.clone(),
2036            errors: Vec::new(),
2037        }
2038    }
2039
2040    /// An argument after full macro replacement, computed once.
2041    fn expanded_arg(&mut self, args: &mut Args, index: usize) -> Vec<PTok> {
2042        if let Some(Some(done)) = args.expanded.get(index) {
2043            return done.clone();
2044        }
2045        let raw = args.get(index).to_vec();
2046        let done = self.expand_sequence(raw);
2047        if let Some(slot) = args.expanded.get_mut(index) {
2048            *slot = Some(done.clone());
2049        }
2050        done
2051    }
2052
2053    /// Fully replaces the macros in a self-contained token sequence.
2054    ///
2055    /// "Self-contained" is the point: 6.10.3.1 says an argument is expanded as
2056    /// if it were the whole rest of the file, so a function-like macro name at
2057    /// its end does not reach out for a `(` that follows the invocation.
2058    fn expand_sequence(&mut self, toks: Vec<PTok>) -> Vec<PTok> {
2059        if toks.is_empty() {
2060            return toks;
2061        }
2062        self.depth += 1;
2063        if self.depth > MAX_EXPANSION_DEPTH {
2064            self.depth -= 1;
2065            if !self.aborted {
2066                let range = toks[0].range;
2067                self.diags.error(range, "macro arguments nest too deeply");
2068                self.aborted = true;
2069            }
2070            return toks;
2071        }
2072        let saved = std::mem::replace(&mut self.pending, toks.into_iter().rev().collect());
2073        let mut out = Vec::new();
2074        while let Some(tok) = self.pending.pop() {
2075            if tok.name().is_some() && self.try_expand(&tok, false) {
2076                continue;
2077            }
2078            out.push(tok);
2079        }
2080        self.pending = saved;
2081        self.depth -= 1;
2082        out
2083    }
2084
2085    /// The token a built-in macro stands for at this use.
2086    fn builtin_token(&mut self, builtin: Builtin, tok: &PTok, def: &MacroDef, name: &str) -> PTok {
2087        let kind = match builtin {
2088            Builtin::Line => {
2089                let line = self.line_of(tok.range.start) as u128;
2090                TokenKind::Int(IntLit {
2091                    value: line,
2092                    base: NumBase::Decimal,
2093                    unsigned: false,
2094                    long: LongKind::None,
2095                    text: line.to_string(),
2096                })
2097            }
2098            // Both of these read the position of the *use*, which is what
2099            // makes `assert(x)` — whose `__FILE__` and `__LINE__` are written
2100            // in <assert.h> — report the line the assertion is on.
2101            Builtin::File => {
2102                let file = self.file_name_of(tok.range.start).to_owned();
2103                string_token_kind(&file)
2104            }
2105            Builtin::FileName => {
2106                let file = self.file_name_of(tok.range.start);
2107                let base = file
2108                    .rsplit_once(['/', '\\'])
2109                    .map_or(file, |(_, base)| base)
2110                    .to_owned();
2111                string_token_kind(&base)
2112            }
2113            Builtin::IncludeLevel => int_token_kind((self.open.len() - 1) as u128),
2114            Builtin::Counter => {
2115                let value = self.counter;
2116                self.counter += 1;
2117                int_token_kind(u128::from(value))
2118            }
2119        };
2120        let exp = self.expansion_of(name, tok.range, def, tok);
2121        PTok {
2122            kind,
2123            range: tok.range,
2124            bol: false,
2125            space: tok.space,
2126            origin: Origin::Expansion(exp),
2127            hide: tok.hide.add(name),
2128            errors: Vec::new(),
2129        }
2130    }
2131}
2132
2133/// Wraps `text` in quotes and re-lexes it as a C string literal.
2134///
2135/// Falling back to the raw bytes cannot normally happen — everything this is
2136/// handed was built to be a string literal — but a decoded value has to come
2137/// out either way.
2138fn relex_string(text: String, options: &LexOptions) -> TokenKind {
2139    let tokens = lex::lex_text(&text, 0, options);
2140    if tokens.len() == 2
2141        && tokens[0].errors.is_empty()
2142        && matches!(tokens[0].kind, TokenKind::Str(_))
2143        && tokens[0].range.end as usize == text.len()
2144    {
2145        return tokens[0].kind.clone();
2146    }
2147    let inner = text.trim_matches('"');
2148    TokenKind::Str(StrLit {
2149        kind: StrKind::Narrow,
2150        values: inner.bytes().map(u32::from).collect(),
2151        text,
2152    })
2153}
2154
2155impl Pp<'_> {
2156    /// Turns an argument into the string literal `#` makes of it (6.10.3.2).
2157    ///
2158    /// White space between tokens becomes exactly one space and leading and
2159    /// trailing white space is dropped. A `"` or `\` is escaped only where the
2160    /// standard says it is — *inside* a character constant or a string literal
2161    /// — which is why `str(: @\n)` comes out as `": @\n"`, backslash intact,
2162    /// while `str("a\0b")` comes out as `"\"a\\0b\""`.
2163    ///
2164    /// The text is then lexed back, so the literal's decoded value is whatever
2165    /// a C compiler would make of the literal that was written.
2166    fn stringify(&self, arg: &[PTok]) -> TokenKind {
2167        let mut text = String::from('"');
2168        for (i, tok) in arg.iter().enumerate() {
2169            if i > 0 && tok.space {
2170                text.push(' ');
2171            }
2172            let quoted = matches!(tok.kind, TokenKind::Char(_) | TokenKind::Str(_));
2173            for c in tok.spelling().chars() {
2174                if quoted && (c == '"' || c == '\\') {
2175                    text.push('\\');
2176                }
2177                text.push(c);
2178            }
2179        }
2180        text.push('"');
2181        relex_string(text, &self.lex_options)
2182    }
2183}
2184
2185/// The pieces the right-hand operand of `##` contributes.
2186///
2187/// A parameter here is *never* macro-replaced first (6.10.3.3p1), and an empty
2188/// argument leaves a placemarker so that the paste happens to whatever is on
2189/// the other side rather than to whatever comes next.
2190fn paste_operand(def: &MacroDef, args: &Args, tok: &PTok) -> Vec<Piece> {
2191    let Some(index) = tok.name().and_then(|n| def.param_index(n)) else {
2192        return vec![Piece::Tok(tok.clone())];
2193    };
2194    let arg = args.get(index);
2195    if arg.is_empty() {
2196        return vec![Piece::Placemarker];
2197    }
2198    arg.iter().cloned().map(Piece::Tok).collect()
2199}
2200
2201/// The largest line number `#line` may name (C99 6.10.4p3).
2202const MAX_LINE_NUMBER: u64 = 2_147_483_647;
2203
2204/// The value of a `digit-sequence` token, which is what `#line` takes.
2205///
2206/// A *digit sequence* is not an integer constant: `#line 010` is line ten, not
2207/// line eight, and `#line 0x10`, `#line 1u` and `#line 1.0` are none of the
2208/// three. Reading the spelling rather than the lexer's value is what says so.
2209/// A sequence too long for the range check below comes back saturated, so it is
2210/// reported as out of range rather than as not a number at all.
2211fn digit_sequence(kind: &TokenKind) -> Option<u64> {
2212    let TokenKind::Int(lit) = kind else {
2213        return None;
2214    };
2215    if lit.text.is_empty() || !lit.text.bytes().all(|b| b.is_ascii_digit()) {
2216        return None;
2217    }
2218    Some(lit.text.parse::<u64>().unwrap_or(u64::MAX))
2219}
2220
2221/// Whether a `#line`'s operands are already one of the two forms 6.10.4 gives,
2222/// in which case they are used as they stand rather than macro-replaced first.
2223fn is_line_form(rest: &[PTok]) -> bool {
2224    let Some(first) = rest.first() else {
2225        return false;
2226    };
2227    if digit_sequence(&first.kind).is_none() {
2228        return false;
2229    }
2230    match rest.len() {
2231        1 => true,
2232        2 => matches!(&rest[1].kind, TokenKind::Str(lit) if lit.kind == StrKind::Narrow),
2233        _ => false,
2234    }
2235}
2236
2237/// The decimal integer token a built-in macro expands to.
2238fn int_token_kind(value: u128) -> TokenKind {
2239    TokenKind::Int(IntLit {
2240        value,
2241        base: NumBase::Decimal,
2242        unsigned: false,
2243        long: LongKind::None,
2244        text: value.to_string(),
2245    })
2246}
2247
2248/// The narrow string literal token a predefined macro expands to.
2249fn string_token_kind(value: &str) -> TokenKind {
2250    TokenKind::Str(StrLit {
2251        kind: StrKind::Narrow,
2252        values: value.bytes().map(u32::from).collect(),
2253        text: quote_c_string(value),
2254    })
2255}
2256
2257/// Wraps `text` in quotes, escaping what a C string literal cannot hold plain.
2258fn quote_c_string(text: &str) -> String {
2259    let mut out = String::with_capacity(text.len() + 2);
2260    out.push('"');
2261    for c in text.chars() {
2262        if c == '"' || c == '\\' {
2263            out.push('\\');
2264        }
2265        out.push(c);
2266    }
2267    out.push('"');
2268    out
2269}
2270
2271// ---------------------------------------------------------------------------
2272// directives
2273// ---------------------------------------------------------------------------
2274
2275impl Pp<'_> {
2276    /// Executes the directive the file's next token opens.
2277    fn directive(&mut self) {
2278        let hash = self.ahead().clone();
2279        self.cur_mut().pos += 1;
2280        let start = self.cur().pos;
2281        while !self.ahead().is_eof() && !self.ahead().bol {
2282            self.cur_mut().pos += 1;
2283        }
2284        let file = self.cur();
2285        let line: Vec<PTok> = file.input[start..file.pos].to_vec();
2286        // The line is read here rather than through `Pp::bump`, so what is
2287        // wrong with its text is reported here too — most of all on the `#`
2288        // itself, which carries the comments of the line above it and is the
2289        // one token of a directive that can never carry anything else. Only
2290        // when the group is being processed: the text before an `#endif` that
2291        // closes a skipped group is inside it, and a skipped group may hold
2292        // anything at all.
2293        if !self.skipping() {
2294            self.report_lexical_errors(&hash);
2295            for tok in &line {
2296                self.report_lexical_errors(tok);
2297            }
2298        }
2299
2300        let Some(first) = line.first() else {
2301            // The null directive, which does nothing at all.
2302            return;
2303        };
2304        let range = hash.range.join(first.range);
2305        let Some(name) = first.name() else {
2306            if matches!(first.kind, TokenKind::Int(_)) {
2307                // A GCC line marker, `# 42 "file.h" 1 3 4`: `#line` without the
2308                // keyword, with flags saying whether the compiler is entering
2309                // or leaving a file. The numbering is all this needs from it.
2310                if !self.skipping() {
2311                    self.line_directive(&line, range, true);
2312                }
2313                return;
2314            }
2315            if !self.skipping() {
2316                self.diags.error(
2317                    range,
2318                    format!(
2319                        "invalid preprocessing directive after '#': {}",
2320                        first.kind.describe()
2321                    ),
2322                );
2323            }
2324            return;
2325        };
2326        let rest = &line[1..];
2327
2328        match name {
2329            "if" => self.open_cond(range, |pp| pp.eval_condition(rest, range)),
2330            "ifdef" | "ifndef" => {
2331                let want = name == "ifdef";
2332                self.open_cond(range, |pp| {
2333                    pp.macro_name_operand(rest, range, name)
2334                        .is_some_and(|n| pp.macros.contains_key(&n) == want)
2335                });
2336            }
2337            "elif" => self.elif(range, "elif", |pp| pp.eval_condition(rest, range)),
2338            // C23's `#elifdef` / `#elifndef`, which say what
2339            // `#elif defined(X)` says.
2340            "elifdef" | "elifndef" => {
2341                self.require_standard(Standard::C23, &format!("'#{name}'"), range);
2342                let want = name == "elifdef";
2343                self.elif(range, name, |pp| {
2344                    pp.macro_name_operand(rest, range, name)
2345                        .is_some_and(|n| pp.macros.contains_key(&n) == want)
2346                });
2347            }
2348            "else" => self.else_(rest, range),
2349            "endif" => self.endif(range),
2350            _ if self.skipping() => {
2351                // Inside a skipped group only the conditionals are tracked;
2352                // everything else is text, and text is not our business.
2353            }
2354            "define" => self.define(rest, range),
2355            "undef" => self.undef(rest, range),
2356            "include" => self.include(&line, range, false),
2357            // GNU's `#include_next`: the same search, taken up again after the
2358            // directory the file writing it was found in. A platform's
2359            // `<limits.h>` ends with one to reach the next `limits.h` on the
2360            // path rather than itself.
2361            "include_next" => self.include(&line, range, true),
2362            "error" => {
2363                let text = self.directive_text(&line, 1);
2364                let message = if text.is_empty() {
2365                    "#error".to_owned()
2366                } else {
2367                    format!("#error {text}")
2368                };
2369                self.diags.error(range, message);
2370            }
2371            "warning" => {
2372                let text = self.directive_text(&line, 1);
2373                self.diags.warning(range, format!("#warning {text}"));
2374            }
2375            "pragma" => self.pragma(rest, range),
2376            "embed" => {
2377                self.require_standard(Standard::C23, "'#embed'", range);
2378                self.embed(rest, range);
2379            }
2380            "line" => self.line_directive(rest, range, false),
2381            // `#ident "string"` and `#sccs` put a string into a section of the
2382            // object file that nothing here has; GCC ignores them too when the
2383            // target has no such section.
2384            "ident" | "sccs" => {}
2385            other => {
2386                self.diags
2387                    .error(range, format!("invalid preprocessing directive #{other}"));
2388            }
2389        }
2390    }
2391
2392    /// `#line` (C99 6.10.4), and GCC's `# 42 "file.h" 1 3 4` line marker.
2393    ///
2394    /// Both say the same thing: the line after the directive is line N, and
2395    /// `__FILE__` is the name that follows until the next directive or the end
2396    /// of the file. The marker's trailing flags — which of "entering",
2397    /// "returning", "system header" and "extern C" applies — describe an
2398    /// `#include` that has already happened elsewhere, so they are read and
2399    /// dropped.
2400    ///
2401    /// **Only `__LINE__` and `__FILE__` move.** A diagnostic still points at
2402    /// the token that was really written, in the file it was really written
2403    /// in, because that is the position the user can look at — the whole
2404    /// reason this crate maps every token back to a `proc_macro2::Span`. A
2405    /// `#line` in generated C therefore renumbers what the *program* observes
2406    /// without hiding where the compiler found it.
2407    fn line_directive(&mut self, rest: &[PTok], range: SourceRange, marker: bool) {
2408        let what = if marker { "line marker" } else { "#line" };
2409        // 6.10.4p5: a `#line` matching neither of the two forms the grammar
2410        // gives has its tokens macro-replaced first, and the result must then
2411        // match one of them. c-testsuite's `00152` is `#line line`, with
2412        // `line` a macro for 1000.
2413        let expanded: Vec<PTok>;
2414        let toks: &[PTok] = if marker || is_line_form(rest) {
2415            rest
2416        } else {
2417            expanded = self.expand_sequence(rest.to_vec());
2418            &expanded
2419        };
2420
2421        let Some(first) = toks.first() else {
2422            self.diags
2423                .error(range, format!("'{what}' requires a line number"));
2424            return;
2425        };
2426        let Some(digits) = digit_sequence(&first.kind) else {
2427            self.diags.error(
2428                first.range,
2429                format!(
2430                    "'{what}' requires a decimal line number, found {}",
2431                    first.kind.describe()
2432                ),
2433            );
2434            return;
2435        };
2436        // 6.10.4p3: the digit sequence shall not specify zero, nor a number
2437        // greater than 2147483647.
2438        if digits == 0 || digits > MAX_LINE_NUMBER {
2439            self.diags.error(
2440                first.range,
2441                format!(
2442                    "the line number of '{what}' must be between 1 and {MAX_LINE_NUMBER}, \
2443                     not {digits}"
2444                ),
2445            );
2446            return;
2447        }
2448
2449        let mut used = 1;
2450        let mut name = None;
2451        if let Some(tok) = toks.get(1) {
2452            match &tok.kind {
2453                TokenKind::Str(lit) if lit.kind == StrKind::Narrow => {
2454                    name = Some(
2455                        lit.values
2456                            .iter()
2457                            .map(|v| char::from_u32(*v).unwrap_or('\u{fffd}'))
2458                            .collect::<String>(),
2459                    );
2460                    used = 2;
2461                }
2462                _ if marker => {}
2463                _ => {
2464                    self.diags.error(
2465                        tok.range,
2466                        format!(
2467                            "the file name of '{what}' must be an ordinary string literal, \
2468                             found {}",
2469                            tok.kind.describe()
2470                        ),
2471                    );
2472                    return;
2473                }
2474            }
2475        }
2476        // A marker's flags are digits the compiler that wrote it understood;
2477        // anything else on a `#line` is what GCC calls "extra tokens at end of
2478        // directive" and, like GCC, warns about rather than refuses.
2479        if !marker && toks.len() > used {
2480            self.diags.warning(
2481                toks[used].range,
2482                format!("extra tokens at the end of '{what}'"),
2483            );
2484        }
2485        self.set_line(range.start, digits as usize, name);
2486    }
2487
2488    /// Records what a `#line` did to the file it was written in.
2489    fn set_line(&mut self, pos: Pos, line: usize, name: Option<String>) {
2490        let index = self.file_index(pos);
2491        let local = Self::local_pos(&self.files[index], pos);
2492        let file = &mut self.files[index];
2493        let at = file.physical_line(local);
2494        // Without a name of its own the directive keeps whichever one is in
2495        // force, which may itself have come from an earlier `#line`.
2496        let name = match name {
2497            Some(name) => name,
2498            None => file.name_of(local).to_owned(),
2499        };
2500        // The list is searched by binary search, so it has to stay sorted. A
2501        // file is only ever read forwards, so this drops nothing in practice.
2502        while file.lines.last().is_some_and(|d| d.at >= at) {
2503            file.lines.pop();
2504        }
2505        file.lines.push(LineDirective { at, line, name });
2506    }
2507
2508    /// The raw source text of a directive line from its `skip`-th token on.
2509    ///
2510    /// `#error` has to reproduce what was written rather than a rendering of
2511    /// the tokens, and `#include <stdio.h>` will need the same thing: a
2512    /// header name in angle brackets is not one token either.
2513    fn directive_text(&self, line: &[PTok], skip: usize) -> String {
2514        let Some(first) = line.get(skip) else {
2515            return String::new();
2516        };
2517        let last = line.last().unwrap_or(first);
2518        self.raw_text(first.range.start, last.range.end)
2519            .trim()
2520            .to_owned()
2521    }
2522
2523    /// `#pragma`.
2524    ///
2525    /// Every pragma this implementation does not know is silently ignored,
2526    /// which is what 6.10.6 asks for — with one exception: a `#pragma cinrs`
2527    /// is addressed to *us*, so an option we do not know is a mistake worth
2528    /// reporting rather than a hint some other compiler might understand.
2529    ///
2530    /// The ones it does know configure the unit:
2531    ///
2532    /// ```c
2533    /// #pragma cinrs include_path "vendor/include"
2534    /// #pragma cinrs link "m"
2535    /// #pragma cinrs export
2536    /// #pragma cinrs safe gcd fact
2537    /// #pragma cinrs no_std
2538    /// #pragma cinrs crate "crate::vendor::cinrs"
2539    /// ```
2540    ///
2541    /// They are directives rather than macro arguments or attributes so that
2542    /// they read the same, and mean the same, in raw-token and in
2543    /// string-literal input.
2544    fn pragma(&mut self, rest: &[PTok], range: SourceRange) {
2545        match rest.first().and_then(PTok::name) {
2546            Some("once") => {
2547                let key = self.cur_key();
2548                self.once.insert(key);
2549            }
2550            Some("cinrs") => self.cinrs_pragma(&rest[1..], range),
2551            Some("pack") => self.pack_pragma(&rest[1..], range),
2552            Some("push_macro") => self.push_macro_pragma(&rest[1..], range, true),
2553            Some("pop_macro") => self.push_macro_pragma(&rest[1..], range, false),
2554            Some("GCC") => self.gcc_pragma(&rest[1..], range),
2555            // `#pragma message`, `#pragma region` / `#pragma endregion`,
2556            // `#pragma weak` and everything else are ignored, which 6.10.6 is
2557            // explicit about. `weak` is the one worth knowing about: it asks
2558            // for weak linkage, which stable Rust cannot express at all, so
2559            // ignoring it is the same answer `__attribute__((weak))` gets —
2560            // see `doc/gnu-extensions.md`.
2561            _ => {}
2562        }
2563    }
2564
2565    /// `#pragma GCC …`.
2566    fn gcc_pragma(&mut self, rest: &[PTok], range: SourceRange) {
2567        match rest.first().and_then(PTok::name) {
2568            // A program that poisons a name means it never to be written
2569            // again, and honouring that costs one lookup per identifier.
2570            Some("poison") => {
2571                for tok in &rest[1..] {
2572                    match tok.name() {
2573                        Some(name) => {
2574                            self.poisoned.insert(name.to_owned());
2575                        }
2576                        None => self.diags.error(
2577                            tok.range,
2578                            format!(
2579                                "'#pragma GCC poison' takes identifiers, found {}",
2580                                tok.kind.describe()
2581                            ),
2582                        ),
2583                    }
2584                }
2585            }
2586            Some("error") => {
2587                let text = self.pragma_message(&rest[1..]);
2588                self.diags.error(range, format!("#pragma GCC error {text}"));
2589            }
2590            Some("warning") => {
2591                let text = self.pragma_message(&rest[1..]);
2592                self.diags
2593                    .warning(range, format!("#pragma GCC warning {text}"));
2594            }
2595            // `diagnostic push/pop/ignored/warning/error`, `system_header`,
2596            // `visibility` and the rest: there are no warnings of ours to
2597            // suppress and no visibility to set, so they are accepted and
2598            // ignored.
2599            _ => {}
2600        }
2601    }
2602
2603    /// The text of a pragma that carries a message.
2604    fn pragma_message(&self, rest: &[PTok]) -> String {
2605        match rest.first() {
2606            Some(tok) => tok.spelling().to_owned(),
2607            None => String::new(),
2608        }
2609    }
2610
2611    /// `#pragma push_macro("X")` and `#pragma pop_macro("X")`.
2612    ///
2613    /// MSVC's, and in GCC since 4.4: a header that has to redefine a macro for
2614    /// a few lines saves the old definition and puts it back. c-testsuite's
2615    /// `00206` is exactly that, and it is the reason this is here.
2616    fn push_macro_pragma(&mut self, rest: &[PTok], range: SourceRange, push: bool) {
2617        let what = if push { "push_macro" } else { "pop_macro" };
2618        // The name is a *string literal*, which is then read as an identifier.
2619        let inner = match rest {
2620            [tok] if tok.is_punct(Punct::LParen) => None,
2621            _ => rest
2622                .iter()
2623                .find_map(|tok| match &tok.kind {
2624                    TokenKind::Str(lit) => lit.as_bytes(),
2625                    _ => None,
2626                })
2627                .map(|bytes| String::from_utf8_lossy(&bytes).into_owned()),
2628        };
2629        let Some(name) = inner.filter(|name| !name.is_empty()) else {
2630            self.diags.error(
2631                range,
2632                format!("#pragma {what} needs a string literal naming a macro"),
2633            );
2634            return;
2635        };
2636        if push {
2637            let saved = self.macros.get(&name).cloned();
2638            self.macro_stacks.entry(name).or_default().push(saved);
2639            return;
2640        }
2641        match self.macro_stacks.get_mut(&name).and_then(Vec::pop) {
2642            Some(Some(def)) => {
2643                self.macros.insert(name, def);
2644            }
2645            Some(None) => {
2646                self.macros.remove(&name);
2647            }
2648            // GCC ignores a `pop_macro` with nothing pushed.
2649            None => {}
2650        }
2651    }
2652
2653    /// `#pragma pack(…)`, which changes the alignment a record's members are
2654    /// laid out with until the next one.
2655    ///
2656    /// The value in effect where a `struct` is *defined* is what applies to it;
2657    /// [`Preprocessed::pack_events`] carries the changes to the parser, which
2658    /// records the one each specifier saw.
2659    fn pack_pragma(&mut self, rest: &[PTok], range: SourceRange) {
2660        let bad = |pp: &mut Self, at: SourceRange| {
2661            pp.diags.error(
2662                at,
2663                "#pragma pack expects '(N)', '(push, N)', '(push)', '(pop)' or '()', \
2664                 where N is a power of two up to 16",
2665            );
2666        };
2667        if !rest.first().is_some_and(|t| t.is_punct(Punct::LParen))
2668            || !rest.last().is_some_and(|t| t.is_punct(Punct::RParen))
2669            || rest.len() < 2
2670        {
2671            bad(self, range);
2672            return;
2673        }
2674        let inner = &rest[1..rest.len() - 1];
2675        let value = |pp: &mut Self, tok: &PTok| -> Option<u32> {
2676            let TokenKind::Int(lit) = &tok.kind else {
2677                bad(pp, tok.range);
2678                return None;
2679            };
2680            let n = u32::try_from(lit.value)
2681                .ok()
2682                .filter(|n| n.is_power_of_two() && *n <= 16);
2683            if n.is_none() {
2684                bad(pp, tok.range);
2685            }
2686            n
2687        };
2688        let next = match inner {
2689            [] => Some(None),
2690            [tok] if tok.name() == Some("pop") => match self.pack_stack.pop() {
2691                Some(value) => Some(value),
2692                None => {
2693                    self.diags
2694                        .error(range, "#pragma pack(pop) with nothing pushed");
2695                    return;
2696                }
2697            },
2698            [tok] if tok.name() == Some("push") => {
2699                self.pack_stack.push(self.pack);
2700                Some(self.pack)
2701            }
2702            [tok] => value(self, tok).map(Some),
2703            [push, comma, tok] if push.name() == Some("push") && comma.is_punct(Punct::Comma) => {
2704                self.pack_stack.push(self.pack);
2705                value(self, tok).map(Some)
2706            }
2707            _ => {
2708                bad(self, range);
2709                return;
2710            }
2711        };
2712        let Some(next) = next else { return };
2713        self.pack = next;
2714        let at = self.out.len();
2715        self.pack_events.push((at, next));
2716    }
2717
2718    /// The identity of the file being read, for `#pragma once`.
2719    fn cur_key(&self) -> String {
2720        self.cur().key.clone()
2721    }
2722
2723    /// The `#pragma cinrs` options, for the diagnostics that list them.
2724    const OPTIONS: &'static str = "'target', 'include_path', 'system_include', 'link', \
2725                                   'export', 'safe', 'no_std' and 'crate'";
2726
2727    /// `#pragma cinrs …`.
2728    fn cinrs_pragma(&mut self, rest: &[PTok], range: SourceRange) {
2729        let Some(option) = rest.first() else {
2730            self.diags.error(
2731                range,
2732                format!("#pragma cinrs needs an option: {}", Self::OPTIONS),
2733            );
2734            return;
2735        };
2736        let name = option.name().unwrap_or_default();
2737        match name {
2738            // The scan before preprocessing already read this one and applied
2739            // it; all that is left is to say so when it cannot have worked.
2740            "target" => self.target_pragma(range),
2741            "include_path" | "link" | "crate" => {
2742                let Some(value) = self.pragma_string(&rest[1..], option.range, name) else {
2743                    return;
2744                };
2745                match name {
2746                    "include_path" => self.search.add_pragma(&value),
2747                    "link" => {
2748                        if !self.link_libraries.contains(&value) {
2749                            self.link_libraries.push(value);
2750                        }
2751                    }
2752                    _ => self.crate_pragma(value, rest[1].range),
2753                }
2754            }
2755            // A list of function names rather than one string: the spelling of
2756            // `[[cinrs::safe]]` that every entry point has, since `[[…]]` is
2757            // C23's and `__attribute__` cannot be written where the function
2758            // is not.
2759            "safe" => self.safe_pragma(&rest[1..], option.range),
2760            "system_include" => self.system_include_pragma(&rest[1..], option.range),
2761            // Unit-wide and argument-less: everything with external linkage
2762            // becomes a real C symbol, and the `Vec` a variable length array
2763            // or `alloca` needs comes from `alloc` rather than from `std`.
2764            "export" | "no_std" => {
2765                if let Some(extra) = rest.get(1) {
2766                    self.diags.error(
2767                        extra.range,
2768                        format!(
2769                            "unexpected {} after #pragma cinrs {name}, which takes no argument",
2770                            extra.kind.describe()
2771                        ),
2772                    );
2773                }
2774                if name == "export" {
2775                    self.export = true;
2776                } else {
2777                    self.no_std = true;
2778                }
2779            }
2780            other => {
2781                let what = if other.is_empty() {
2782                    option.kind.describe().to_owned()
2783                } else {
2784                    format!("'{other}'")
2785                };
2786                self.diags.error(
2787                    option.range,
2788                    format!(
2789                        "unknown #pragma cinrs option {what}; the options are {}",
2790                        Self::OPTIONS
2791                    ),
2792                );
2793            }
2794        }
2795    }
2796
2797    /// `#pragma cinrs target "<triple>"`, seen a second time.
2798    ///
2799    /// [`scan_target_pragma`] read every one in the unit's own text before
2800    /// this pass began and either applied it or reported it, so there is
2801    /// nothing left to do — except in the two cases the scan cannot serve, and
2802    /// where silence would mean translating for the wrong machine:
2803    ///
2804    /// * the directive is one the scan never saw, because it is in a *header*
2805    ///   or came out of `_Pragma`, so the model it names was never applied;
2806    /// * it stands after an `#include` or an `#if`, both of which had already
2807    ///   been answered with the old model.
2808    ///
2809    /// A `target` inside a group `#if 0` skips is the mirror image — the scan
2810    /// applied it and this pass never sees it — which the module
2811    /// documentation says, and which is why this is the only pragma read
2812    /// twice.
2813    fn target_pragma(&mut self, range: SourceRange) {
2814        if !self.target_pragmas.scanned(range) {
2815            let now = match self.target_source.triple() {
2816                Some(triple) => format!("for '{triple}'"),
2817                None => format!("for the model {} named", self.target_source.as_str()),
2818            };
2819            self.diags.error(
2820                range,
2821                format!(
2822                    "'#pragma cinrs target' is read before preprocessing, so it has to be a \
2823                     directive in the unit's own text: a header's comes too late, and one \
2824                     out of '_Pragma' is never seen. This unit is being translated {now}"
2825                ),
2826            );
2827            return;
2828        }
2829        // The scan read this one. If it did not like it, it has said so
2830        // already and a second message would only get in the way.
2831        if !self.target_pragmas.applied {
2832            return;
2833        }
2834        if self.model_observed {
2835            self.diags.error(
2836                range,
2837                "'#pragma cinrs target' must come before every '#include' and '#if', which \
2838                 were already answered with the previous data model",
2839            );
2840        }
2841    }
2842
2843    /// `#pragma cinrs safe f g h`, which asks for those functions to be
2844    /// generated without `unsafe`.
2845    ///
2846    /// It takes identifiers rather than a string so that it reads like the C it
2847    /// is naming, and any number of them, since a unit that marks one function
2848    /// usually marks several. A name that is not a function defined here is a
2849    /// mistake, and [`crate::sema::check_safe`] — which is the only pass that
2850    /// knows what the unit defines — says so.
2851    fn safe_pragma(&mut self, rest: &[PTok], range: SourceRange) {
2852        if rest.is_empty() {
2853            self.diags.error(
2854                range,
2855                "#pragma cinrs safe needs the name of at least one function",
2856            );
2857            return;
2858        }
2859        for tok in rest {
2860            match tok.name() {
2861                Some(name) => self.safe_functions.push(SafeName {
2862                    name: name.to_owned(),
2863                    range: tok.range,
2864                }),
2865                None => self.diags.error(
2866                    tok.range,
2867                    format!(
2868                        "#pragma cinrs safe takes function names, found {}",
2869                        tok.kind.describe()
2870                    ),
2871                ),
2872            }
2873        }
2874    }
2875
2876    /// `#pragma cinrs system_include` and `#pragma cinrs system_include first`,
2877    /// which put the platform's own include directories on the search path.
2878    ///
2879    /// Plain, they go *after* the bundled headers: the bundled `<stdio.h>`
2880    /// still wins, and only a header cinrs does not carry — `<sys/stat.h>`,
2881    /// `<pthread.h>`, `<dirent.h>` — comes from the platform. With `first`
2882    /// they go before, which is how a unit asks for the platform's own
2883    /// `<stdio.h>` and so for the real `FILE`.
2884    ///
2885    /// A bare word rather than a string, like `safe`'s function names, so that
2886    /// it reads as the switch it is; and like every other pragma this one is
2887    /// answered where it stands, so it has to come before the `#include`s it
2888    /// is meant to change.
2889    fn system_include_pragma(&mut self, rest: &[PTok], range: SourceRange) {
2890        let mode = match rest.first() {
2891            None => include::System::Last,
2892            Some(tok) if tok.name() == Some("first") => include::System::First,
2893            Some(tok) => {
2894                let what = match tok.name() {
2895                    Some(name) => format!("'{name}'"),
2896                    None => tok.kind.describe().to_owned(),
2897                };
2898                self.diags.error(
2899                    tok.range,
2900                    format!(
2901                        "unexpected {what} after #pragma cinrs system_include, which takes \
2902                         either nothing or 'first'"
2903                    ),
2904                );
2905                return;
2906            }
2907        };
2908        if let Some(extra) = rest.get(1) {
2909            self.diags.error(
2910                extra.range,
2911                format!(
2912                    "unexpected {} after #pragma cinrs system_include first",
2913                    extra.kind.describe()
2914                ),
2915            );
2916        }
2917        // Which directories the platform's headers live in is read off the
2918        // data model, so the model is settled from here on; see
2919        // `Pp::target_pragma`.
2920        self.model_observed = true;
2921        self.enable_system_include(mode, range);
2922    }
2923
2924    /// Works out the platform's own include directories and puts them on the
2925    /// path, or says why there are none to put there.
2926    ///
2927    /// The one thing that can go wrong is a cross build with no
2928    /// [`include::SYSTEM_PATH_ENV_VAR`]: the default directories are the
2929    /// *host*'s, and a header laid out for another machine is worse than no
2930    /// header at all. See [`include::system_directories`].
2931    fn enable_system_include(&mut self, mode: include::System, range: SourceRange) {
2932        match include::system_directories(&self.target, &self.target_source) {
2933            Ok(dirs) => self.search.enable_system(mode, dirs),
2934            Err(message) => self.diags.error(range, message),
2935        }
2936    }
2937
2938    /// `#pragma cinrs crate "::my_cinrs"`, which says where the `cinrs` facade
2939    /// crate is to be found.
2940    ///
2941    /// The generated code names it only where it needs the runtime — today
2942    /// that is a complex type, and nothing else — but it has to name it in
2943    /// full, because the expansion goes into a module of its own and cannot
2944    /// rely on anything being in scope there. The default is `::cinrs`; a
2945    /// dependency renamed in `Cargo.toml`, or one reached through a re-export,
2946    /// needs this.
2947    fn crate_pragma(&mut self, path: String, range: SourceRange) {
2948        if !crate::codegen::is_crate_path(&path) {
2949            self.diags.error(
2950                range,
2951                format!(
2952                    "'{path}' is not usable as a Rust path to a crate; write something like \
2953                     '::my_cinrs' or 'crate::vendor::cinrs'"
2954                ),
2955            );
2956            return;
2957        }
2958        if let Some(previous) = &self.crate_path
2959            && *previous != path
2960        {
2961            self.diags.error(
2962                range,
2963                format!(
2964                    "this unit already reaches the cinrs crate as '{previous}', by an earlier \
2965                     #pragma cinrs crate"
2966                ),
2967            );
2968            return;
2969        }
2970        self.crate_path = Some(path);
2971    }
2972
2973    /// The single string literal a `#pragma cinrs` option takes.
2974    fn pragma_string(&mut self, rest: &[PTok], range: SourceRange, option: &str) -> Option<String> {
2975        let Some(tok) = rest.first() else {
2976            self.diags.error(
2977                range,
2978                format!("#pragma cinrs {option} needs a string literal"),
2979            );
2980            return None;
2981        };
2982        let TokenKind::Str(lit) = &tok.kind else {
2983            self.diags.error(
2984                tok.range,
2985                format!(
2986                    "#pragma cinrs {option} needs a string literal, found {}",
2987                    tok.kind.describe()
2988                ),
2989            );
2990            return None;
2991        };
2992        let Some(bytes) = lit.as_bytes() else {
2993            self.diags.error(
2994                tok.range,
2995                format!("#pragma cinrs {option} does not take a wide string literal"),
2996            );
2997            return None;
2998        };
2999        let value = String::from_utf8_lossy(&bytes).into_owned();
3000        if value.is_empty() {
3001            self.diags.error(
3002                tok.range,
3003                format!("#pragma cinrs {option} was given an empty string"),
3004            );
3005            return None;
3006        }
3007        if let Some(extra) = rest.get(1) {
3008            self.diags.error(
3009                extra.range,
3010                format!(
3011                    "unexpected {} after #pragma cinrs {option}",
3012                    extra.kind.describe()
3013                ),
3014            );
3015        }
3016        Some(value)
3017    }
3018
3019    // -- #include -----------------------------------------------------------
3020
3021    /// `#include <name>`, `#include "name"` and `#include MACRO` — and, with
3022    /// `next`, GNU's `#include_next`, which is the same thing looked for from
3023    /// the entry after the one the current file was found under.
3024    fn include(&mut self, line: &[PTok], range: SourceRange, next: bool) {
3025        // A header reads the model — every bundled one branches on `_WIN32`
3026        // or on `__SIZEOF_POINTER__` — so once one is opened the model is
3027        // settled; see `Pp::target_pragma`.
3028        self.model_observed = true;
3029        let Some((name, form)) = self.header_name(line, range) else {
3030            return;
3031        };
3032        if self.open.len() >= MAX_INCLUDE_DEPTH {
3033            self.diags.error(
3034                range,
3035                format!("#include nested too deeply (more than {MAX_INCLUDE_DEPTH} files)"),
3036            );
3037            return;
3038        }
3039        let origin = self.cur().origin.clone();
3040        let looked = if next {
3041            let current = self.cur().found_in.clone();
3042            include::resolve_next(&name, &origin, current.as_ref(), &self.search)
3043        } else {
3044            include::resolve(&name, form, &origin, &self.search)
3045        };
3046        let found = match looked {
3047            Ok(found) => found,
3048            Err(include::Error::Unreadable { path, error }) => {
3049                self.diags
3050                    .error(range, format!("cannot read '{path}': {error}"));
3051                return;
3052            }
3053            Err(include::Error::NotFound { searched }) => {
3054                let quoted = match form {
3055                    include::Form::Angled => format!("<{name}>"),
3056                    include::Form::Quoted => format!("\"{name}\""),
3057                };
3058                let message = match (next, searched.is_empty()) {
3059                    (false, _) => {
3060                        format!("{quoted} file not found; searched: {}", searched.join(", "))
3061                    }
3062                    (true, true) => format!(
3063                        "{quoted} file not found by #include_next; there is nothing after the \
3064                         place this file was found in"
3065                    ),
3066                    (true, false) => format!(
3067                        "{quoted} file not found by #include_next; searched: {}",
3068                        searched.join(", ")
3069                    ),
3070                };
3071                self.diags.error(range, message);
3072                return;
3073            }
3074        };
3075
3076        // The two ways a file already read can be skipped without reading it
3077        // again: it said `#pragma once`, or it is wrapped in an include guard
3078        // whose macro is still defined.
3079        if self.once.contains(&found.key) {
3080            return;
3081        }
3082        if let Some(guard) = self.guards.get(&found.key)
3083            && self.macros.contains_key(guard)
3084        {
3085            return;
3086        }
3087        if let Some(path) = &found.path
3088            && !self.user_headers.contains(path)
3089        {
3090            self.user_headers.push(path.clone());
3091        }
3092        self.open_file(found, range);
3093    }
3094
3095    // -- #embed -------------------------------------------------------------
3096
3097    /// `#embed "resource"` and `#embed <resource>` (C23 6.10.3, N3017).
3098    ///
3099    /// The directive is replaced by the bytes of the resource, written as a
3100    /// comma-separated list of integer constants in the range of `unsigned
3101    /// char` — so that `unsigned char logo[] = {\n#embed "logo.png"\n};` is an
3102    /// array of the file. The four standard parameters shape the list:
3103    /// `limit(N)` takes only the first N bytes, `prefix(…)` and `suffix(…)`
3104    /// bracket a *non-empty* list, and `if_empty(…)` replaces an empty one.
3105    ///
3106    /// The tokens go through the ordinary pending queue, so they are rescanned
3107    /// for macros exactly as any other replacement is — and are charged
3108    /// against [`MAX_EXPANDED_TOKENS`] like any others, which puts the ceiling
3109    /// on a resource near two megabytes.
3110    fn embed(&mut self, rest: &[PTok], range: SourceRange) {
3111        let Some((name, form, after)) = self.embed_operand(rest, range) else {
3112            return;
3113        };
3114        let Some(params) = self.embed_parameters(&rest[after..], range, true) else {
3115            return;
3116        };
3117        let origin = self.cur().origin.clone();
3118        let found = match include::resolve_embed(&name, form, &origin, &self.search) {
3119            Ok(found) => found,
3120            Err(include::Error::Unreadable { path, error }) => {
3121                self.diags
3122                    .error(range, format!("cannot read '{path}': {error}"));
3123                return;
3124            }
3125            Err(include::Error::NotFound { searched }) => {
3126                let quoted = match form {
3127                    include::Form::Angled => format!("<{name}>"),
3128                    include::Form::Quoted => format!("\"{name}\""),
3129                };
3130                // There are no bundled resources, so unlike `#include` the
3131                // list of places looked in really can be empty.
3132                let where_ = if searched.is_empty() {
3133                    "there is nowhere to look; name a directory with \
3134                     `#pragma cinrs include_path`"
3135                        .to_owned()
3136                } else {
3137                    format!("searched: {}", searched.join(", "))
3138                };
3139                self.diags.error(
3140                    range,
3141                    format!("{quoted} resource not found for #embed; {where_}"),
3142                );
3143                return;
3144            }
3145        };
3146        if !self.embedded_files.contains(&found.path) {
3147            self.embedded_files.push(found.path.clone());
3148        }
3149
3150        let take = params.limit.unwrap_or(found.bytes.len());
3151        let bytes = &found.bytes[..take.min(found.bytes.len())];
3152        let mut out: Vec<PTok> = Vec::new();
3153        if bytes.is_empty() {
3154            // 6.10.3.2: `if_empty` stands for the whole expansion, and the
3155            // prefix and suffix are not emitted at all.
3156            out.extend(params.if_empty);
3157        } else {
3158            out.extend(params.prefix);
3159            for (i, byte) in bytes.iter().enumerate() {
3160                if i > 0 {
3161                    out.push(self.embed_token(TokenKind::Punct(Punct::Comma), range));
3162                }
3163                out.push(self.embed_token(int_token_kind(u128::from(*byte)), range));
3164            }
3165            out.extend(params.suffix);
3166        }
3167        self.push_pending(out, true);
3168    }
3169
3170    /// The resource name an `#embed` names, how it was spelled, and how many
3171    /// of the directive's tokens it took.
3172    fn embed_operand(
3173        &mut self,
3174        rest: &[PTok],
3175        range: SourceRange,
3176    ) -> Option<(String, include::Form, usize)> {
3177        if let Some(found) = self.embed_name_of(rest) {
3178            return Some(found);
3179        }
3180        // 6.10.3p1 allows the whole operand to come out of a macro, exactly as
3181        // `#include`'s does.
3182        if !rest.is_empty() {
3183            let expanded = self.expand_sequence(rest.to_vec());
3184            if let Some((name, form, _)) = self.embed_name_of(&expanded) {
3185                // A macro cannot be followed by parameters here: the whole run
3186                // was replaced, so there is nothing of the original left to
3187                // read them from.
3188                return Some((name, form, rest.len()));
3189            }
3190        }
3191        self.diags
3192            .error(range, "#embed expects \"RESOURCE\" or <RESOURCE>");
3193        None
3194    }
3195
3196    /// Reads a resource name off the front of a token run.
3197    fn embed_name_of(&self, toks: &[PTok]) -> Option<(String, include::Form, usize)> {
3198        match &toks.first()?.kind {
3199            // A quoted name is *not* a string literal's value: no escape
3200            // sequence is processed, so the spelling between the quotes is it.
3201            TokenKind::Str(lit) if lit.kind == lex::StrKind::Narrow => {
3202                let spelling = lit.text.as_str();
3203                let name = spelling
3204                    .strip_prefix('"')
3205                    .and_then(|s| s.strip_suffix('"'))
3206                    .unwrap_or(spelling);
3207                (!name.is_empty()).then(|| (name.to_owned(), include::Form::Quoted, 1))
3208            }
3209            TokenKind::Punct(Punct::Lt) => {
3210                let close = toks[1..].iter().position(|t| t.is_punct(Punct::Gt))? + 1;
3211                let raw = self
3212                    .raw_text(toks[0].range.end, toks[close].range.start)
3213                    .trim()
3214                    .to_owned();
3215                let name = if raw.is_empty() {
3216                    // The tokens came out of a macro and have no source text
3217                    // of their own; their spellings are the name.
3218                    let mut spelled = String::new();
3219                    for (i, tok) in toks[1..close].iter().enumerate() {
3220                        if i > 0 && tok.space {
3221                            spelled.push(' ');
3222                        }
3223                        spelled.push_str(tok.spelling());
3224                    }
3225                    spelled
3226                } else {
3227                    raw
3228                };
3229                (!name.is_empty()).then(|| (name, include::Form::Angled, close + 1))
3230            }
3231            _ => None,
3232        }
3233    }
3234
3235    /// Reads `#embed`'s parameters, which follow the resource name.
3236    ///
3237    /// `report` says whether a parameter this implementation does not have is
3238    /// a diagnostic. It is for the *directive*, and is not for `__has_embed`:
3239    /// 6.10.1p5 answers "not found" for a parameter it cannot honour, which is
3240    /// how a program asks whether one is supported before writing it.
3241    fn embed_parameters(
3242        &mut self,
3243        mut rest: &[PTok],
3244        range: SourceRange,
3245        report: bool,
3246    ) -> Option<EmbedParams> {
3247        let mut params = EmbedParams::default();
3248        while let Some(first) = rest.first() {
3249            let Some(name) = first.name() else {
3250                if report {
3251                    self.diags.error(
3252                        first.range,
3253                        format!(
3254                            "expected an #embed parameter, found {}",
3255                            first.kind.describe()
3256                        ),
3257                    );
3258                }
3259                return None;
3260            };
3261            if rest.get(1).is_none_or(|t| !t.is_punct(Punct::LParen)) {
3262                if report {
3263                    self.diags.error(
3264                        first.range,
3265                        format!("#embed parameter '{name}' takes an argument list"),
3266                    );
3267                }
3268                return None;
3269            }
3270            // The matching `)`, counting nested parentheses.
3271            let mut depth = 0usize;
3272            let mut close = None;
3273            for (i, tok) in rest[1..].iter().enumerate() {
3274                if tok.is_punct(Punct::LParen) {
3275                    depth += 1;
3276                } else if tok.is_punct(Punct::RParen) {
3277                    depth -= 1;
3278                    if depth == 0 {
3279                        close = Some(i + 1);
3280                        break;
3281                    }
3282                }
3283            }
3284            let Some(close) = close else {
3285                if report {
3286                    self.diags.error(
3287                        first.range,
3288                        format!("unterminated argument list for '{name}'"),
3289                    );
3290                }
3291                return None;
3292            };
3293            let inner = &rest[2..close];
3294            // GCC spells every one of them both ways; the reserved form is
3295            // what a header uses so as not to collide with a user's macro.
3296            let plain = name
3297                .strip_prefix("__")
3298                .and_then(|n| n.strip_suffix("__"))
3299                .unwrap_or(name);
3300            match plain {
3301                "limit" => {
3302                    if inner.is_empty() {
3303                        if report {
3304                            self.diags
3305                                .error(first.range, "#embed 'limit' takes a constant expression");
3306                        }
3307                        return None;
3308                    }
3309                    let value = self.eval_expression(inner, range)?;
3310                    if value < 0 {
3311                        if report {
3312                            self.diags
3313                                .error(first.range, "#embed 'limit' cannot be negative");
3314                        }
3315                        return None;
3316                    }
3317                    params.limit = Some(usize::try_from(value).unwrap_or(usize::MAX));
3318                }
3319                "prefix" => params.prefix = inner.to_vec(),
3320                "suffix" => params.suffix = inner.to_vec(),
3321                "if_empty" => params.if_empty = inner.to_vec(),
3322                _ => {
3323                    if report {
3324                        self.diags
3325                            .error(first.range, format!("unknown #embed parameter '{name}'"));
3326                    }
3327                    return None;
3328                }
3329            }
3330            rest = &rest[close + 1..];
3331        }
3332        Some(params)
3333    }
3334
3335    /// One token of an `#embed` expansion, standing where the directive was.
3336    fn embed_token(&self, kind: TokenKind, range: SourceRange) -> PTok {
3337        PTok {
3338            kind,
3339            range,
3340            bol: false,
3341            space: true,
3342            origin: Origin::Source,
3343            hide: HideSet::default(),
3344            errors: Vec::new(),
3345        }
3346    }
3347
3348    /// Places a header's text in the offset space and starts reading it.
3349    fn open_file(&mut self, found: include::Resolved, directive: SourceRange) {
3350        let base = self.next_base;
3351        self.next_base = base
3352            .saturating_add(found.text.len() as Pos)
3353            .saturating_add(FILE_GAP);
3354        let mut input: Vec<PTok> = lex::lex_text(&found.text, base, &self.lex_options)
3355            .iter()
3356            .map(PTok::from_lexed)
3357            .collect();
3358        if input.is_empty() {
3359            input.push(eof_token(base));
3360        }
3361        if let Some(guard) = detect_include_guard(&input) {
3362            self.guards.insert(found.key.clone(), guard);
3363        }
3364        self.included.push(IncludedFile {
3365            name: found.name.clone(),
3366            text: found.text.clone(),
3367            base,
3368            directive,
3369        });
3370        self.files
3371            .push(FileEntry::new(found.text, base, 1, found.name));
3372        self.open.push(OpenFile {
3373            input,
3374            pos: 0,
3375            origin: found.origin,
3376            found_in: found.found_in,
3377            key: found.key,
3378            cond_base: self.conds.len(),
3379        });
3380    }
3381
3382    /// The header name an `#include` names, and how it was spelled.
3383    ///
3384    /// `<stdio.h>` is not one token, so the name comes from the source text
3385    /// the directive covers rather than from the tokens. 6.10.2p4 also allows
3386    /// the whole thing to come out of a macro, which is what the second half
3387    /// handles: there is no source text to read then, so the name is rebuilt
3388    /// from the spellings of the tokens the macro produced.
3389    fn header_name(
3390        &mut self,
3391        line: &[PTok],
3392        range: SourceRange,
3393    ) -> Option<(String, include::Form)> {
3394        let text = self.directive_text(line, 1);
3395        if let Some(found) = parse_header_name(&text) {
3396            return Some(found);
3397        }
3398        if line.len() <= 1 {
3399            self.diags
3400                .error(range, "#include expects \"FILENAME\" or <FILENAME>");
3401            return None;
3402        }
3403        // `#include MACRO`: replace, then read the result back as text.
3404        let expanded = self.expand_sequence(line[1..].to_vec());
3405        let mut spelled = String::new();
3406        for (i, tok) in expanded.iter().enumerate() {
3407            if i > 0 && tok.space {
3408                spelled.push(' ');
3409            }
3410            spelled.push_str(tok.spelling());
3411        }
3412        if let Some(found) = parse_header_name(&spelled) {
3413            return Some(found);
3414        }
3415        self.diags.error(
3416            range,
3417            "#include expects \"FILENAME\" or <FILENAME>".to_owned(),
3418        );
3419        None
3420    }
3421
3422    /// Reads the single macro name a directive takes.
3423    fn macro_name_operand(
3424        &mut self,
3425        rest: &[PTok],
3426        range: SourceRange,
3427        directive: &str,
3428    ) -> Option<String> {
3429        let Some(first) = rest.first() else {
3430            self.diags
3431                .error(range, format!("no macro name given in #{directive}"));
3432            return None;
3433        };
3434        let Some(name) = first.name() else {
3435            self.diags.error(
3436                first.range,
3437                format!(
3438                    "macro name must be an identifier, found {}",
3439                    first.kind.describe()
3440                ),
3441            );
3442            return None;
3443        };
3444        if name == "defined" {
3445            self.diags.error(
3446                first.range,
3447                format!("'defined' cannot be used as a macro name in #{directive}"),
3448            );
3449            return None;
3450        }
3451        Some(name.to_owned())
3452    }
3453
3454    // -- conditionals -------------------------------------------------------
3455
3456    /// Opens a conditional group, evaluating its controlling condition only
3457    /// when the enclosing group is being processed.
3458    fn open_cond(&mut self, range: SourceRange, test: impl FnOnce(&mut Self) -> bool) {
3459        let outer_active = !self.skipping();
3460        let value = outer_active && test(self);
3461        self.conds.push(Cond {
3462            range,
3463            outer_active,
3464            taken: value,
3465            active: outer_active && value,
3466            seen_else: false,
3467        });
3468    }
3469
3470    /// Opens the next branch of a conditional group.
3471    ///
3472    /// `test` is only run when the branch could be taken at all, which is what
3473    /// makes `#elif 1/N` after a branch that already ran harmless — and what
3474    /// keeps `#elifdef` from reporting a missing name in a group nothing will
3475    /// read.
3476    fn elif(&mut self, range: SourceRange, directive: &str, test: impl FnOnce(&mut Self) -> bool) {
3477        let Some(cond) = self.conds.last() else {
3478            self.diags.error(range, format!("#{directive} without #if"));
3479            return;
3480        };
3481        if cond.seen_else {
3482            let seen = cond.range;
3483            self.diags.push(
3484                Diagnostic::error(range, format!("#{directive} after #else"))
3485                    .with_note_at(seen, "the conditional started"),
3486            );
3487            return;
3488        }
3489        let (outer_active, taken) = (cond.outer_active, cond.taken);
3490        let value = outer_active && !taken && test(self);
3491        let cond = self
3492            .conds
3493            .last_mut()
3494            .expect("the stack was not touched in between");
3495        cond.active = value;
3496        cond.taken |= value;
3497    }
3498
3499    /// Reports a directive the block's own standard does not have.
3500    fn require_standard(&mut self, needed: Standard, what: &str, range: SourceRange) {
3501        if let Some(message) = self.gating.requires(what, needed) {
3502            self.diags.error(range, message);
3503        }
3504    }
3505
3506    fn else_(&mut self, rest: &[PTok], range: SourceRange) {
3507        let Some(cond) = self.conds.last_mut() else {
3508            self.diags.error(range, "#else without #if");
3509            return;
3510        };
3511        if cond.seen_else {
3512            let seen = cond.range;
3513            self.diags.push(
3514                Diagnostic::error(range, "#else after #else")
3515                    .with_note_at(seen, "the conditional started"),
3516            );
3517            return;
3518        }
3519        cond.seen_else = true;
3520        cond.active = cond.outer_active && !cond.taken;
3521        cond.taken = true;
3522        let active = cond.active;
3523        if active && !rest.is_empty() {
3524            self.diags
3525                .warning(range, "extra tokens at the end of #else");
3526        }
3527    }
3528
3529    fn endif(&mut self, range: SourceRange) {
3530        if self.conds.pop().is_none() {
3531            self.diags.error(range, "#endif without #if");
3532        }
3533    }
3534
3535    // -- #define / #undef ---------------------------------------------------
3536
3537    fn undef(&mut self, rest: &[PTok], range: SourceRange) {
3538        if let Some(name) = self.macro_name_operand(rest, range, "undef") {
3539            self.macros.remove(&name);
3540        }
3541    }
3542
3543    fn define(&mut self, rest: &[PTok], range: SourceRange) {
3544        let Some(name_tok) = rest.first() else {
3545            self.diags.error(range, "no macro name given in #define");
3546            return;
3547        };
3548        let Some(name) = name_tok.name().map(str::to_owned) else {
3549            self.diags.error(
3550                name_tok.range,
3551                format!(
3552                    "macro name must be an identifier, found {}",
3553                    name_tok.kind.describe()
3554                ),
3555            );
3556            return;
3557        };
3558        if name == "defined" {
3559            self.diags
3560                .error(name_tok.range, "'defined' cannot be used as a macro name");
3561            return;
3562        }
3563        if name == VA_ARGS {
3564            self.diags.error(
3565                name_tok.range,
3566                "'__VA_ARGS__' can only appear in the replacement list of a variadic macro",
3567            );
3568            return;
3569        }
3570
3571        // A `(` *immediately* after the name — no white space — makes the
3572        // macro function-like; `#define f (x)` is object-like and expands to
3573        // `(x)`.
3574        let mut rest = &rest[1..];
3575        let function_like = rest
3576            .first()
3577            .is_some_and(|t| t.is_punct(Punct::LParen) && !t.space);
3578        let (params, variadic, va_name) = if function_like {
3579            let Some(parsed) = self.parse_params(rest, range) else {
3580                return;
3581            };
3582            rest = &rest[parsed.used..];
3583            (Some(parsed.params), parsed.variadic, parsed.va_name)
3584        } else {
3585            (None, false, None)
3586        };
3587
3588        let body = fuse_hash_hash(rest);
3589        let def = MacroDef {
3590            params,
3591            variadic,
3592            va_name,
3593            body,
3594            name_range: name_tok.range,
3595            predefined: false,
3596            builtin: None,
3597        };
3598        if !self.check_body(&def, &name, range) {
3599            return;
3600        }
3601
3602        if let Some(previous) = self.macros.get(&name)
3603            && !previous.predefined
3604            && !previous.same_as(&def)
3605        {
3606            self.diags.push(
3607                Diagnostic::error(name_tok.range, format!("macro '{name}' redefined"))
3608                    .with_note_at(
3609                        previous.name_range,
3610                        format!("previous definition of '{name}' is"),
3611                    ),
3612            );
3613            return;
3614        }
3615        self.macros.insert(name, Arc::new(def));
3616    }
3617
3618    /// Parses `( a, b, ... )`, or GNU's `( a, rest... )`.
3619    fn parse_params(&mut self, rest: &[PTok], range: SourceRange) -> Option<ParamList> {
3620        let mut params: Vec<String> = Vec::new();
3621        let mut variadic = false;
3622        let mut va_name = None;
3623        let mut i = 1; // past the `(`
3624        if rest.get(i).is_some_and(|t| t.is_punct(Punct::RParen)) {
3625            return Some(ParamList {
3626                params,
3627                variadic,
3628                va_name,
3629                used: i + 1,
3630            });
3631        }
3632        loop {
3633            let Some(tok) = rest.get(i) else {
3634                self.diags
3635                    .error(range, "missing ')' in the parameter list of a macro");
3636                return None;
3637            };
3638            if tok.is_punct(Punct::Ellipsis) {
3639                self.require_standard(Standard::C99, "a variadic macro", tok.range);
3640                variadic = true;
3641                i += 1;
3642                break;
3643            }
3644            let Some(name) = tok.name() else {
3645                self.diags.error(
3646                    tok.range,
3647                    format!(
3648                        "expected a macro parameter name, found {}",
3649                        tok.kind.describe()
3650                    ),
3651                );
3652                return None;
3653            };
3654            if name == VA_ARGS {
3655                self.diags.error(
3656                    tok.range,
3657                    "'__VA_ARGS__' cannot be used as a macro parameter name",
3658                );
3659                return None;
3660            }
3661            if params.iter().any(|p| p == name) {
3662                self.diags
3663                    .error(tok.range, format!("duplicate macro parameter '{name}'"));
3664                return None;
3665            }
3666            // GNU's named variable arguments: `args...` makes `args` another
3667            // spelling of `__VA_ARGS__` rather than one more parameter.
3668            if rest.get(i + 1).is_some_and(|t| t.is_punct(Punct::Ellipsis)) {
3669                self.require_standard(Standard::C99, "a variadic macro", tok.range);
3670                variadic = true;
3671                va_name = Some(name.to_owned());
3672                i += 2;
3673                break;
3674            }
3675            params.push(name.to_owned());
3676            i += 1;
3677            match rest.get(i) {
3678                Some(t) if t.is_punct(Punct::Comma) => i += 1,
3679                Some(t) if t.is_punct(Punct::RParen) => break,
3680                Some(t) => {
3681                    self.diags.error(
3682                        t.range,
3683                        format!(
3684                            "expected ',' or ')' in a macro parameter list, found {}",
3685                            t.kind.describe()
3686                        ),
3687                    );
3688                    return None;
3689                }
3690                None => {
3691                    self.diags
3692                        .error(range, "missing ')' in the parameter list of a macro");
3693                    return None;
3694                }
3695            }
3696        }
3697        match rest.get(i) {
3698            Some(t) if t.is_punct(Punct::RParen) => Some(ParamList {
3699                params,
3700                variadic,
3701                va_name,
3702                used: i + 1,
3703            }),
3704            _ => {
3705                self.diags
3706                    .error(range, "missing ')' in the parameter list of a macro");
3707                None
3708            }
3709        }
3710    }
3711
3712    /// Checks the constraints a replacement list has to satisfy.
3713    fn check_body(&mut self, def: &MacroDef, name: &str, range: SourceRange) -> bool {
3714        let body = &def.body;
3715        if let Some(first) = body.first()
3716            && first.is_punct(Punct::HashHash)
3717        {
3718            self.diags.error(
3719                first.range,
3720                "'##' cannot appear at the start of a macro replacement list",
3721            );
3722            return false;
3723        }
3724        if let Some(last) = body.last()
3725            && last.is_punct(Punct::HashHash)
3726            && body.len() > 1
3727        {
3728            self.diags.error(
3729                last.range,
3730                "'##' cannot appear at the end of a macro replacement list",
3731            );
3732            return false;
3733        }
3734        for (i, tok) in body.iter().enumerate() {
3735            if def.params.is_some() && tok.is_punct(Punct::Hash) {
3736                let ok = body
3737                    .get(i + 1)
3738                    .and_then(PTok::name)
3739                    .is_some_and(|n| def.param_index(n).is_some());
3740                if !ok {
3741                    self.diags
3742                        .error(tok.range, "'#' must be followed by a macro parameter");
3743                    return false;
3744                }
3745            }
3746            if tok.name() == Some(VA_ARGS) && def.param_index(VA_ARGS).is_none() {
3747                self.diags.error(
3748                    tok.range,
3749                    "'__VA_ARGS__' can only appear in the replacement list of a variadic macro",
3750                );
3751                return false;
3752            }
3753            if tok.name() == Some(VA_OPT) && !self.check_va_opt(def, body, i) {
3754                return false;
3755            }
3756        }
3757        let _ = (name, range);
3758        true
3759    }
3760
3761    /// Checks one `__VA_OPT__` in a replacement list.
3762    ///
3763    /// It has to be in a variadic macro, it has to be followed by a balanced
3764    /// `( … )`, its contents may neither begin nor end with `##` (C23
3765    /// 6.10.5.2p1, for the same reason a replacement list may not — there is
3766    /// nothing on that side to paste to), and — since the standard says so and
3767    /// since the expansion here is a single pass — it may not hold another
3768    /// one.
3769    fn check_va_opt(&mut self, def: &MacroDef, body: &[PTok], at: usize) -> bool {
3770        let tok = &body[at];
3771        if def.param_index(VA_ARGS).is_none() {
3772            self.diags.error(
3773                tok.range,
3774                "'__VA_OPT__' can only appear in the replacement list of a variadic macro",
3775            );
3776            return false;
3777        }
3778        self.require_standard(Standard::C23, "'__VA_OPT__'", tok.range);
3779        if !body.get(at + 1).is_some_and(|t| t.is_punct(Punct::LParen)) {
3780            self.diags
3781                .error(tok.range, "'__VA_OPT__' must be followed by '('");
3782            return false;
3783        }
3784        let mut depth = 0i32;
3785        let mut contents: Vec<&PTok> = Vec::new();
3786        for tok in &body[at + 1..] {
3787            if tok.is_punct(Punct::LParen) {
3788                depth += 1;
3789                // The `(` that opens the argument is not part of it.
3790                if depth == 1 {
3791                    continue;
3792                }
3793            } else if tok.is_punct(Punct::RParen) {
3794                depth -= 1;
3795                if depth == 0 {
3796                    return self.check_va_opt_contents(&contents);
3797                }
3798            } else if tok.name() == Some(VA_OPT) {
3799                self.diags
3800                    .error(tok.range, "'__VA_OPT__' cannot be nested inside another");
3801                return false;
3802            }
3803            contents.push(tok);
3804        }
3805        self.diags.error(
3806            tok.range,
3807            "unterminated '__VA_OPT__(' in a macro definition",
3808        );
3809        false
3810    }
3811
3812    /// C23 6.10.5.2p1 for the token sequence inside a `__VA_OPT__( … )`.
3813    fn check_va_opt_contents(&mut self, contents: &[&PTok]) -> bool {
3814        for (end, tok) in [("start", contents.first()), ("end", contents.last())] {
3815            if let Some(tok) = tok
3816                && tok.is_punct(Punct::HashHash)
3817            {
3818                self.diags.error(
3819                    tok.range,
3820                    format!("'##' cannot appear at the {end} of a '__VA_OPT__' argument"),
3821                );
3822                return false;
3823            }
3824        }
3825        true
3826    }
3827}
3828
3829/// Replaces every `__VA_OPT__( … )` in a replacement list with its contents,
3830/// or with nothing when the invocation passed no variable arguments (C23
3831/// 6.10.5.2).
3832///
3833/// Doing it before substitution rather than during it is what makes the rest
3834/// of the rules fall out: the contents are ordinary replacement-list tokens
3835/// afterwards, so `#` and `##` next to them, and the parameters inside them,
3836/// are handled by the code that was already there. `None` means the
3837/// replacement list has no `__VA_OPT__` and can be used as it stands.
3838fn expand_va_opt(def: &MacroDef, args: &Args) -> Option<Vec<PTok>> {
3839    let params = def.params.as_ref()?;
3840    if !def.variadic || !def.body.iter().any(|t| t.name() == Some(VA_OPT)) {
3841        return None;
3842    }
3843    // The variable arguments are the one past the named parameters; `subst`
3844    // is only reached once `try_expand` has padded the list out to that.
3845    let present = !args.get(params.len()).is_empty();
3846    let body = &def.body;
3847    let mut out: Vec<PTok> = Vec::with_capacity(body.len());
3848    let mut i = 0;
3849    while i < body.len() {
3850        let is_va_opt = body[i].name() == Some(VA_OPT)
3851            && body.get(i + 1).is_some_and(|t| t.is_punct(Punct::LParen));
3852        if !is_va_opt {
3853            out.push(body[i].clone());
3854            i += 1;
3855            continue;
3856        }
3857        let space = body[i].space;
3858        let mut depth = 0i32;
3859        let mut inner: Vec<PTok> = Vec::new();
3860        let mut j = i + 1;
3861        while j < body.len() {
3862            let tok = &body[j];
3863            j += 1;
3864            if tok.is_punct(Punct::LParen) {
3865                depth += 1;
3866                if depth == 1 {
3867                    continue;
3868                }
3869            } else if tok.is_punct(Punct::RParen) {
3870                depth -= 1;
3871                if depth == 0 {
3872                    break;
3873                }
3874            }
3875            inner.push(tok.clone());
3876        }
3877        if present {
3878            if let Some(first) = inner.first_mut() {
3879                // The expansion stands where `__VA_OPT__` did, spacing and all.
3880                first.space = space;
3881            }
3882            out.extend(inner);
3883        }
3884        i = j;
3885    }
3886    Some(out)
3887}
3888
3889/// Reads `<name>` or `"name"` out of the text of an `#include` directive.
3890///
3891/// The name is taken verbatim, which is what 6.4.7 asks for: a `\` in a header
3892/// name is a directory separator on the platforms that use one, not the start
3893/// of an escape sequence. Anything after the closing delimiter is ignored, the
3894/// way every compiler ignores it.
3895fn parse_header_name(text: &str) -> Option<(String, include::Form)> {
3896    let text = text.trim();
3897    let (form, close) = match text.as_bytes().first()? {
3898        b'<' => (include::Form::Angled, '>'),
3899        b'"' => (include::Form::Quoted, '"'),
3900        _ => return None,
3901    };
3902    let rest = &text[1..];
3903    let end = rest.find(close)?;
3904    let name = &rest[..end];
3905    (!name.is_empty()).then(|| (name.to_owned(), form))
3906}
3907
3908/// The macro an include guard is built on, if a file is nothing but one.
3909///
3910/// The classic optimisation (6.10.2, and every compiler since 1987): a file
3911/// whose whole contents are
3912///
3913/// ```c
3914/// #ifndef GUARD
3915/// #define GUARD
3916/// …
3917/// #endif
3918/// ```
3919///
3920/// need not be read again while `GUARD` is defined, because reading it would
3921/// produce nothing. Recognising it is what keeps a header included from twenty
3922/// places from being lexed twenty times — and, here, from taking twenty copies
3923/// of its text into the source map.
3924fn detect_include_guard(toks: &[PTok]) -> Option<String> {
3925    // `#ifndef NAME`, with nothing else on the line.
3926    if !(toks.first()?.bol && toks[0].is_punct(Punct::Hash)) {
3927        return None;
3928    }
3929    if toks.get(1)?.name()? != "ifndef" {
3930        return None;
3931    }
3932    let name = toks.get(2)?.name()?.to_owned();
3933    let after_ifndef = toks.get(3)?;
3934    if !after_ifndef.bol && !after_ifndef.is_eof() {
3935        return None;
3936    }
3937    // `#define NAME` immediately after it.
3938    if !after_ifndef.is_punct(Punct::Hash)
3939        || toks.get(4)?.name()? != "define"
3940        || toks.get(5)?.name()? != name
3941    {
3942        return None;
3943    }
3944
3945    // The `#endif` that closes it must be the last thing in the file.
3946    let mut depth = 0i32;
3947    let mut i = 0;
3948    while i < toks.len() && !toks[i].is_eof() {
3949        if toks[i].bol && toks[i].is_punct(Punct::Hash) {
3950            match toks.get(i + 1).and_then(PTok::name) {
3951                Some("if" | "ifdef" | "ifndef") => depth += 1,
3952                Some("endif") => {
3953                    depth -= 1;
3954                    if depth == 0 {
3955                        let mut j = i + 2;
3956                        while toks.get(j).is_some_and(|t| !t.bol && !t.is_eof()) {
3957                            j += 1;
3958                        }
3959                        return toks.get(j).is_none_or(PTok::is_eof).then_some(name);
3960                    }
3961                }
3962                _ => {}
3963            }
3964        }
3965        i += 1;
3966    }
3967    None
3968}
3969
3970/// Applies the [`# #` rule](self#the----rule) to a replacement list.
3971fn fuse_hash_hash(rest: &[PTok]) -> Vec<PTok> {
3972    let mut body: Vec<PTok> = Vec::with_capacity(rest.len());
3973    let mut i = 0;
3974    while i < rest.len() {
3975        if rest[i].is_punct(Punct::Hash)
3976            && let Some(next) = rest.get(i + 1)
3977            && next.is_punct(Punct::Hash)
3978            && !next.bol
3979        {
3980            let mut fused = rest[i].clone();
3981            fused.kind = TokenKind::Punct(Punct::HashHash);
3982            fused.range = fused.range.join(next.range);
3983            body.push(fused);
3984            i += 2;
3985            continue;
3986        }
3987        body.push(rest[i].clone());
3988        i += 1;
3989    }
3990    if let Some(first) = body.first_mut() {
3991        // Leading white space is not part of a replacement list, and 6.10.3p2
3992        // compares two definitions on where their white space is.
3993        first.space = false;
3994    }
3995    body
3996}
3997
3998// ---------------------------------------------------------------------------
3999// #if expressions
4000// ---------------------------------------------------------------------------
4001
4002/// A value in an `#if` expression: `intmax_t` or `uintmax_t`, which C99 6.10.1
4003/// fixes as the only two types such an expression has.
4004#[derive(Clone, Copy, PartialEq, Eq, Debug)]
4005struct Val {
4006    /// The value, held signed but normalised to whichever type `unsigned` says.
4007    v: i128,
4008    unsigned: bool,
4009}
4010
4011impl Val {
4012    fn signed(v: i128) -> Val {
4013        Val {
4014            v: v as i64 as i128,
4015            unsigned: false,
4016        }
4017    }
4018
4019    fn make(v: i128, unsigned: bool) -> Val {
4020        if unsigned {
4021            Val {
4022                v: (v as u64) as i128,
4023                unsigned,
4024            }
4025        } else {
4026            Val::signed(v)
4027        }
4028    }
4029
4030    fn boolean(b: bool) -> Val {
4031        Val::signed(i128::from(b))
4032    }
4033
4034    fn is_true(self) -> bool {
4035        self.v != 0
4036    }
4037
4038    /// The value as it takes part in an operation of the given signedness.
4039    fn as_operand(self, unsigned: bool) -> i128 {
4040        if unsigned && self.v < 0 {
4041            self.v + (1i128 << 64)
4042        } else {
4043            self.v
4044        }
4045    }
4046}
4047
4048impl Pp<'_> {
4049    /// Evaluates the controlling expression of an `#if` or `#elif`.
4050    fn eval_condition(&mut self, line: &[PTok], range: SourceRange) -> bool {
4051        // An `#if` may read `__SIZEOF_LONG__` or `_WIN32`, so from here on the
4052        // data model has been committed to; see `Pp::target_pragma`.
4053        self.model_observed = true;
4054        if line.is_empty() {
4055            self.diags.error(range, "#if with no expression");
4056            return false;
4057        }
4058        self.eval_expression(line, range)
4059            .is_some_and(|value| value != 0)
4060    }
4061
4062    /// Evaluates a constant expression with the preprocessor's own arithmetic.
4063    ///
4064    /// `None` says something was wrong and has been reported. This is what
4065    /// `#if` asks a question of, and what `#embed`'s `limit(…)` parameter is.
4066    fn eval_expression(&mut self, line: &[PTok], range: SourceRange) -> Option<i128> {
4067        let prepared = self.resolve_defined(line, range)?;
4068        let expanded = self.expand_sequence(prepared);
4069        for tok in &expanded {
4070            let tok = tok.clone();
4071            self.report_errors(&tok);
4072        }
4073        let mut eval = Eval {
4074            toks: &expanded,
4075            pos: 0,
4076            fallback: range,
4077            errors: Vec::new(),
4078            depth: 0,
4079        };
4080        let value = eval.expression(true);
4081        if eval.errors.is_empty()
4082            && eval.pos < eval.toks.len()
4083            && let Some(tok) = eval.toks.get(eval.pos)
4084        {
4085            let found = tok.kind.describe();
4086            eval.errors.push(Diagnostic::error(
4087                tok.range,
4088                format!("unexpected {found} in a preprocessor expression"),
4089            ));
4090        }
4091        let failed = !eval.errors.is_empty();
4092        for diag in eval.errors {
4093            self.diags.push(diag);
4094        }
4095        (!failed).then_some(value.v)
4096    }
4097
4098    /// Replaces every `defined X` and `defined(X)` with `1` or `0`.
4099    ///
4100    /// This happens before macro replacement, as 6.10.1p1 requires: the
4101    /// operand of `defined` is a name, not something a macro may rewrite.
4102    fn resolve_defined(&mut self, line: &[PTok], range: SourceRange) -> Option<Vec<PTok>> {
4103        let mut out = Vec::with_capacity(line.len());
4104        let mut i = 0;
4105        while i < line.len() {
4106            let tok = &line[i];
4107            // The `__has_…` family is answered here too, for the same reason
4108            // `defined` is: their operands are names and header names, not
4109            // things a macro may rewrite.
4110            if let Some(name) = tok.name()
4111                && name.starts_with("__has_")
4112            {
4113                let (value, end) = self.has_operator(name, line, i)?;
4114                let mut answer = tok.clone();
4115                answer.kind = int_token_kind(value);
4116                answer.hide = answer.hide.add(name);
4117                answer.errors.clear();
4118                out.push(answer);
4119                i = end;
4120                continue;
4121            }
4122            if tok.name() != Some("defined") {
4123                out.push(tok.clone());
4124                i += 1;
4125                continue;
4126            }
4127            let parenthesised = line.get(i + 1).is_some_and(|t| t.is_punct(Punct::LParen));
4128            let name_at = if parenthesised { i + 2 } else { i + 1 };
4129            let Some(name) = line.get(name_at).and_then(PTok::name) else {
4130                self.diags.error(
4131                    tok.range,
4132                    "operator 'defined' requires an identifier as its operand",
4133                );
4134                return None;
4135            };
4136            let defined = self.macros.contains_key(name);
4137            let mut end = name_at + 1;
4138            if parenthesised {
4139                if !line.get(end).is_some_and(|t| t.is_punct(Punct::RParen)) {
4140                    self.diags.error(range, "missing ')' after 'defined'");
4141                    return None;
4142                }
4143                end += 1;
4144            }
4145            let mut value = tok.clone();
4146            value.kind = TokenKind::Int(IntLit {
4147                value: u128::from(defined),
4148                base: NumBase::Decimal,
4149                unsigned: false,
4150                long: LongKind::None,
4151                text: u8::from(defined).to_string(),
4152            });
4153            // Already answered: nothing here may be replaced again.
4154            value.hide = value.hide.add("defined");
4155            value.errors.clear();
4156            out.push(value);
4157            i = end;
4158        }
4159        Some(out)
4160    }
4161
4162    /// Answers one `__has_…(…)` operator, returning its value and the index
4163    /// just past its closing `)`.
4164    ///
4165    /// Everything here is answered from `cinrs`'s own tables (see
4166    /// [`crate::gnu`]) rather than from GCC's, which is the point: a program
4167    /// that writes `#if __has_attribute(cleanup)` must be told *no*, because
4168    /// this implementation does not have it.
4169    fn has_operator(&mut self, name: &str, line: &[PTok], at: usize) -> Option<(u128, usize)> {
4170        let range = line[at].range;
4171        if !line.get(at + 1).is_some_and(|t| t.is_punct(Punct::LParen)) {
4172            // An identifier that is not an invocation is an ordinary one, and
4173            // 6.10.1p4 turns it into 0 like any other.
4174            return Some((0, at + 1));
4175        }
4176        let mut depth = 0i32;
4177        let mut end = at + 1;
4178        while end < line.len() {
4179            if line[end].is_punct(Punct::LParen) {
4180                depth += 1;
4181            } else if line[end].is_punct(Punct::RParen) {
4182                depth -= 1;
4183                if depth == 0 {
4184                    end += 1;
4185                    break;
4186                }
4187            }
4188            end += 1;
4189        }
4190        if depth != 0 {
4191            self.diags
4192                .error(range, format!("missing ')' after '{name}'"));
4193            return None;
4194        }
4195        let inner = &line[at + 2..end - 1];
4196        let value = match name {
4197            // The header name is spelled as it is in an `#include`, so it is
4198            // read out of the source text rather than out of the tokens.
4199            "__has_include" | "__has_include_next" => {
4200                let Some((header, form)) = self.operand_header_name(inner) else {
4201                    self.diags.error(
4202                        range,
4203                        format!("'{name}' expects \"FILENAME\" or <FILENAME>"),
4204                    );
4205                    return None;
4206                };
4207                // `__has_include_next` asks the question `#include_next`
4208                // answers: is there one *after* the place this file was found
4209                // in? Where there is no next place there is no next header,
4210                // and the answer is a plain no.
4211                let origin = self.cur().origin.clone();
4212                let found = if name == "__has_include_next" {
4213                    let current = self.cur().found_in.clone();
4214                    include::resolve_next(&header, &origin, current.as_ref(), &self.search)
4215                } else {
4216                    include::resolve(&header, form, &origin, &self.search)
4217                };
4218                u128::from(found.is_ok())
4219            }
4220            "__has_attribute" | "__has_declspec_attribute" => u128::from(
4221                inner
4222                    .first()
4223                    .and_then(PTok::name)
4224                    .is_some_and(crate::gnu::has_attribute),
4225            ),
4226            "__has_c_attribute" => inner
4227                .first()
4228                .and_then(PTok::name)
4229                .map_or(0, |n| u128::from(crate::gnu::has_c_attribute(n))),
4230            "__has_builtin" => u128::from(
4231                inner
4232                    .first()
4233                    .and_then(PTok::name)
4234                    .is_some_and(crate::gnu::has_builtin),
4235            ),
4236            "__has_feature" | "__has_extension" => u128::from(
4237                inner
4238                    .first()
4239                    .and_then(PTok::name)
4240                    .is_some_and(crate::gnu::has_feature),
4241            ),
4242            // C23 6.10.1p5: not found, found and empty, spelled with the same
4243            // three macros `<stdembed.h>` would have. Parameters after the
4244            // resource name are read so that an unknown one answers "not
4245            // found", which is what the clause asks for.
4246            "__has_embed" => {
4247                let Some((resource, form, after)) = self.embed_name_of(inner) else {
4248                    self.diags.error(
4249                        range,
4250                        format!("'{name}' expects \"RESOURCE\" or <RESOURCE>"),
4251                    );
4252                    return None;
4253                };
4254                let params = self.embed_parameters(&inner[after..], range, false);
4255                let origin = self.cur().origin.clone();
4256                match (
4257                    params,
4258                    include::resolve_embed(&resource, form, &origin, &self.search),
4259                ) {
4260                    (Some(params), Ok(found)) => {
4261                        let take = params.limit.unwrap_or(found.bytes.len());
4262                        if take == 0 || found.bytes.is_empty() {
4263                            EMBED_EMPTY
4264                        } else {
4265                            EMBED_FOUND
4266                        }
4267                    }
4268                    _ => EMBED_NOT_FOUND,
4269                }
4270            }
4271            _ => 0,
4272        };
4273        Some((value, end))
4274    }
4275
4276    /// The header name written inside `__has_include(…)`.
4277    fn operand_header_name(&mut self, inner: &[PTok]) -> Option<(String, include::Form)> {
4278        let first = inner.first()?;
4279        let last = inner.last()?;
4280        let text = self.raw_text(first.range.start, last.range.end).trim();
4281        if let Some(found) = parse_header_name(text) {
4282            return Some(found);
4283        }
4284        // The name came out of a macro, so there is no source text to read: it
4285        // is rebuilt from the spellings, exactly as `#include MACRO` is.
4286        let expanded = self.expand_sequence(inner.to_vec());
4287        let mut spelled = String::new();
4288        for (i, tok) in expanded.iter().enumerate() {
4289            if i > 0 && tok.space {
4290                spelled.push(' ');
4291            }
4292            spelled.push_str(tok.spelling());
4293        }
4294        parse_header_name(&spelled)
4295    }
4296}
4297
4298/// A recursive-descent evaluator over preprocessing tokens.
4299///
4300/// Separate from the parser's constant evaluator on purpose: this one works on
4301/// tokens rather than on an AST, has no types beyond `intmax_t`/`uintmax_t`,
4302/// turns every leftover identifier into `0`, and must not evaluate the
4303/// unreached arm of `&&`, `||` or `?:` — `#if defined(N) && 10/N` is a
4304/// perfectly ordinary thing to write.
4305struct Eval<'a> {
4306    toks: &'a [PTok],
4307    pos: usize,
4308    /// Where to report something that has no token of its own.
4309    fallback: SourceRange,
4310    errors: Vec<Diagnostic>,
4311    /// How deep the parentheses and `?:` are, so that `#if ((((…))))` becomes
4312    /// a diagnostic rather than a stack overflow inside a compiler.
4313    depth: u32,
4314}
4315
4316/// How deeply an `#if` expression may nest; the parser's own limit, for the
4317/// same reason.
4318const MAX_EVAL_DEPTH: u32 = 200;
4319
4320impl Eval<'_> {
4321    fn peek(&self) -> Option<&PTok> {
4322        self.toks.get(self.pos)
4323    }
4324
4325    fn at(&self, p: Punct) -> bool {
4326        self.peek().is_some_and(|t| t.is_punct(p))
4327    }
4328
4329    fn eat(&mut self, p: Punct) -> bool {
4330        if self.at(p) {
4331            self.pos += 1;
4332            return true;
4333        }
4334        false
4335    }
4336
4337    fn range(&self) -> SourceRange {
4338        self.peek().map_or(self.fallback, |t| t.range)
4339    }
4340
4341    fn error(&mut self, range: SourceRange, message: impl Into<String>) {
4342        self.errors.push(Diagnostic::error(range, message));
4343    }
4344
4345    /// `expr , expr` — the comma operator, which `#if` does allow.
4346    fn expression(&mut self, eval: bool) -> Val {
4347        self.depth += 1;
4348        if self.depth > MAX_EVAL_DEPTH {
4349            let range = self.range();
4350            self.error(range, "this preprocessor expression nests too deeply");
4351            // Consume the rest so that the caller's loops all terminate.
4352            self.pos = self.toks.len();
4353            self.depth -= 1;
4354            return Val::signed(0);
4355        }
4356        let mut value = self.conditional(eval);
4357        while self.eat(Punct::Comma) {
4358            value = self.conditional(eval);
4359        }
4360        self.depth -= 1;
4361        value
4362    }
4363
4364    fn conditional(&mut self, eval: bool) -> Val {
4365        let cond = self.binary(0, eval);
4366        if !self.eat(Punct::Question) {
4367            return cond;
4368        }
4369        let take_then = cond.is_true();
4370        let then_value = self.expression(eval && take_then);
4371        if !self.eat(Punct::Colon) {
4372            let range = self.range();
4373            self.error(range, "expected ':' in a preprocessor expression");
4374            return cond;
4375        }
4376        let else_value = self.conditional(eval && !take_then);
4377        let (a, b) = (then_value, else_value);
4378        let unsigned = a.unsigned || b.unsigned;
4379        let picked = if take_then { a } else { b };
4380        Val::make(picked.as_operand(unsigned), unsigned)
4381    }
4382
4383    /// Precedence climbing over the binary operators.
4384    fn binary(&mut self, min_prec: u8, eval: bool) -> Val {
4385        let mut lhs = self.unary(eval);
4386        loop {
4387            let Some((op, prec)) = self.peek().and_then(|t| binary_op(&t.kind)) else {
4388                return lhs;
4389            };
4390            if prec < min_prec {
4391                return lhs;
4392            }
4393            let op_range = self.range();
4394            self.pos += 1;
4395            // `&&` and `||` do not evaluate their right operand when the left
4396            // one already decides the answer.
4397            let rhs_eval = match op {
4398                BinOp::LogAnd => eval && lhs.is_true(),
4399                BinOp::LogOr => eval && !lhs.is_true(),
4400                _ => eval,
4401            };
4402            let rhs = self.binary(prec + 1, rhs_eval);
4403            lhs = self.apply(op, lhs, rhs, op_range, eval);
4404        }
4405    }
4406
4407    fn apply(&mut self, op: BinOp, a: Val, b: Val, range: SourceRange, eval: bool) -> Val {
4408        use BinOp::*;
4409        if op == LogAnd {
4410            return Val::boolean(a.is_true() && b.is_true());
4411        }
4412        if op == LogOr {
4413            return Val::boolean(a.is_true() || b.is_true());
4414        }
4415        // The usual arithmetic conversions, in the only shape they have here:
4416        // if either operand is unsigned, both are.
4417        let unsigned = a.unsigned || b.unsigned;
4418        let (x, y) = (a.as_operand(unsigned), b.as_operand(unsigned));
4419        match op {
4420            Eq => Val::boolean(x == y),
4421            Ne => Val::boolean(x != y),
4422            Lt => Val::boolean(x < y),
4423            Gt => Val::boolean(x > y),
4424            Le => Val::boolean(x <= y),
4425            Ge => Val::boolean(x >= y),
4426            Add => Val::make(x.wrapping_add(y), unsigned),
4427            Sub => Val::make(x.wrapping_sub(y), unsigned),
4428            Mul => Val::make(x.wrapping_mul(y), unsigned),
4429            Div | Rem => {
4430                if y == 0 {
4431                    if eval {
4432                        self.error(range, "division by zero in a preprocessor expression");
4433                    }
4434                    return Val::make(0, unsigned);
4435                }
4436                let v = if op == Div {
4437                    x.wrapping_div(y)
4438                } else {
4439                    x.wrapping_rem(y)
4440                };
4441                Val::make(v, unsigned)
4442            }
4443            BitAnd => Val::make(x & y, unsigned),
4444            BitOr => Val::make(x | y, unsigned),
4445            BitXor => Val::make(x ^ y, unsigned),
4446            Shl => Val::make(x.wrapping_shl((y as u64 & 63) as u32), unsigned),
4447            Shr => {
4448                let count = (y as u64 & 63) as u32;
4449                if unsigned {
4450                    Val::make(((x as u64) >> count) as i128, unsigned)
4451                } else {
4452                    Val::make((x as i64 >> count) as i128, unsigned)
4453                }
4454            }
4455            LogAnd | LogOr => unreachable!("handled above"),
4456        }
4457    }
4458
4459    fn unary(&mut self, eval: bool) -> Val {
4460        let range = self.range();
4461        if self.eat(Punct::Plus) {
4462            return self.unary(eval);
4463        }
4464        if self.eat(Punct::Minus) {
4465            let v = self.unary(eval);
4466            return Val::make(v.as_operand(v.unsigned).wrapping_neg(), v.unsigned);
4467        }
4468        if self.eat(Punct::Tilde) {
4469            let v = self.unary(eval);
4470            return Val::make(!v.as_operand(v.unsigned), v.unsigned);
4471        }
4472        if self.eat(Punct::Bang) {
4473            let v = self.unary(eval);
4474            return Val::boolean(!v.is_true());
4475        }
4476        if self.eat(Punct::LParen) {
4477            let v = self.expression(eval);
4478            if !self.eat(Punct::RParen) {
4479                let at = self.range();
4480                self.error(at, "expected ')' in a preprocessor expression");
4481            }
4482            return v;
4483        }
4484        self.primary(range)
4485    }
4486
4487    fn primary(&mut self, range: SourceRange) -> Val {
4488        let Some(tok) = self.peek() else {
4489            self.error(range, "expected a value in a preprocessor expression");
4490            return Val::signed(0);
4491        };
4492        let value = match &tok.kind {
4493            TokenKind::Int(lit) => {
4494                // An `#if` has only `intmax_t` and `uintmax_t`; a constant is
4495                // unsigned when it says so or when it does not fit signed.
4496                let unsigned = lit.unsigned || lit.value > i64::MAX as u128;
4497                let too_large = lit.value > u64::MAX as u128;
4498                let value = Val::make((lit.value & u128::from(u64::MAX)) as i128, unsigned);
4499                if too_large {
4500                    let range = tok.range;
4501                    self.error(
4502                        range,
4503                        "integer constant is too large for a preprocessor expression",
4504                    );
4505                }
4506                value
4507            }
4508            TokenKind::Char(lit) => Val::signed(i128::from(lit.value)),
4509            TokenKind::Float(_) => {
4510                let range = tok.range;
4511                self.error(
4512                    range,
4513                    "a floating constant is not allowed in a preprocessor expression",
4514                );
4515                Val::signed(0)
4516            }
4517            TokenKind::Str(_) => {
4518                let range = tok.range;
4519                self.error(
4520                    range,
4521                    "a string literal is not allowed in a preprocessor expression",
4522                );
4523                Val::signed(0)
4524            }
4525            // C23 6.10.1p6: `true` and `false` are keywords there, and an
4526            // `#if` reads them as 1 and 0. Before C23 they are identifiers,
4527            // and the rule below turns them into 0 like any other.
4528            TokenKind::Keyword(lex::Keyword::True) => Val::signed(1),
4529            TokenKind::Keyword(lex::Keyword::False) => Val::signed(0),
4530            // 6.10.1p4: every identifier still standing after macro
4531            // replacement is replaced by 0.
4532            TokenKind::Ident(_) | TokenKind::Keyword(_) => Val::signed(0),
4533            other => {
4534                let range = tok.range;
4535                let found = other.describe();
4536                self.error(
4537                    range,
4538                    format!("unexpected {found} in a preprocessor expression"),
4539                );
4540                Val::signed(0)
4541            }
4542        };
4543        self.pos += 1;
4544        value
4545    }
4546}
4547
4548/// The binary operators an `#if` expression may use.
4549#[derive(Clone, Copy, PartialEq, Eq, Debug)]
4550enum BinOp {
4551    LogOr,
4552    LogAnd,
4553    BitOr,
4554    BitXor,
4555    BitAnd,
4556    Eq,
4557    Ne,
4558    Lt,
4559    Gt,
4560    Le,
4561    Ge,
4562    Shl,
4563    Shr,
4564    Add,
4565    Sub,
4566    Mul,
4567    Div,
4568    Rem,
4569}
4570
4571/// The operator a token is, with its binding power (tightest last).
4572fn binary_op(kind: &TokenKind) -> Option<(BinOp, u8)> {
4573    let TokenKind::Punct(p) = kind else {
4574        return None;
4575    };
4576    Some(match p {
4577        Punct::PipePipe => (BinOp::LogOr, 1),
4578        Punct::AmpAmp => (BinOp::LogAnd, 2),
4579        Punct::Pipe => (BinOp::BitOr, 3),
4580        Punct::Caret => (BinOp::BitXor, 4),
4581        Punct::Amp => (BinOp::BitAnd, 5),
4582        Punct::EqEq => (BinOp::Eq, 6),
4583        Punct::Ne => (BinOp::Ne, 6),
4584        Punct::Lt => (BinOp::Lt, 7),
4585        Punct::Gt => (BinOp::Gt, 7),
4586        Punct::Le => (BinOp::Le, 7),
4587        Punct::Ge => (BinOp::Ge, 7),
4588        Punct::Shl => (BinOp::Shl, 8),
4589        Punct::Shr => (BinOp::Shr, 8),
4590        Punct::Plus => (BinOp::Add, 9),
4591        Punct::Minus => (BinOp::Sub, 9),
4592        Punct::Star => (BinOp::Mul, 10),
4593        Punct::Slash => (BinOp::Div, 10),
4594        Punct::Percent => (BinOp::Rem, 10),
4595        _ => return None,
4596    })
4597}
4598
4599// ---------------------------------------------------------------------------
4600// predefined macros
4601// ---------------------------------------------------------------------------
4602
4603impl Standard {
4604    /// The value of `__STDC_VERSION__` for this revision, or `None` where the
4605    /// revision has none.
4606    ///
4607    /// C89 as published had no `__STDC_VERSION__` at all — Amendment 1 added
4608    /// it in 1995 — so `c89!` and `gnu89!` leave the macro undefined, which is
4609    /// what `gcc -std=c89` does and what a program testing
4610    /// `#ifdef __STDC_VERSION__` is looking for. `__STDC__` is still `1`.
4611    pub fn stdc_version(self) -> Option<&'static str> {
4612        Some(match self {
4613            Standard::C89 => return None,
4614            Standard::C99 => "199901L",
4615            Standard::C11 => "201112L",
4616            Standard::C17 => "201710L",
4617            Standard::C23 => "202311L",
4618        })
4619    }
4620}
4621
4622impl Pp<'_> {
4623    fn define_predefined(&mut self, options: &Options) {
4624        self.define_object("__STDC__", "1");
4625        self.define_object("__STDC_HOSTED__", "1");
4626        if let Some(version) = options.standard.stdc_version() {
4627            self.define_object("__STDC_VERSION__", version);
4628        }
4629        self.define_object("__cinrs__", "1");
4630        // C11 6.10.8.3 makes four parts of the language optional and gives an
4631        // implementation a macro to say it left each one out. Two of them
4632        // depend on how this expansion was configured rather than on the
4633        // crate: complex arithmetic is absent when the `complex` feature is
4634        // off, in which case `_Complex` is a diagnostic and saying so turns
4635        // the gap into a conforming omission that a portable program can take
4636        // the other branch on; threads are absent on the targets whose C
4637        // library `<threads.h>` does not model, where that header is an
4638        // `#error` and the macro is what a program tests instead of hitting
4639        // it. The other two are *not* among them: `_Atomic`,
4640        // `<stdatomic.h>` and the `__atomic_*` builtins are all here, and so
4641        // are variable length arrays and the variably modified types built on
4642        // them — `int a[n][m]`, `int (*p)[n]`, `typedef int T[n]` and the
4643        // parameter forms — so neither `__STDC_NO_ATOMICS__` nor
4644        // `__STDC_NO_VLA__` is defined.
4645        //
4646        // `__STDC_IEC_559_COMPLEX__` is never defined either way: it claims
4647        // the whole of Annex G, and cinrs implements G.5.1's arithmetic
4648        // without claiming the rest of it.
4649        if !options.complex {
4650            self.define_object("__STDC_NO_COMPLEX__", "1");
4651        }
4652        if !threads_available(&options.target) {
4653            self.define_object("__STDC_NO_THREADS__", "1");
4654        }
4655        self.define_atomic_macros(options.target.max_scalar_align.min(8));
4656        // C11 7.28p2: these two say that `char16_t` and `char32_t` really are
4657        // UTF-16 and UTF-32, which is what the lexer encodes `u"…"` and `U"…"`
4658        // as. The value is the standard's own: the ISO/IEC 10646 revision the
4659        // encodings come from.
4660        self.define_object("__STDC_UTF_16__", "1");
4661        self.define_object("__STDC_UTF_32__", "1");
4662        // C23 6.10.1p5's three answers for `__has_embed`. GCC predefines them
4663        // in every mode it has, because a program that tests `__has_embed`
4664        // wants to compare against them whichever `-std=` it is compiled with.
4665        self.define_object("__STDC_EMBED_NOT_FOUND__", "0");
4666        self.define_object("__STDC_EMBED_FOUND__", "1");
4667        self.define_object("__STDC_EMBED_EMPTY__", "2");
4668        // Only a strict entry point is `-std=c99`; a GNU one is `-std=gnu99`.
4669        if !options.dialect.is_gnu() {
4670            self.define_object("__STRICT_ANSI__", "1");
4671        }
4672        // The GNU extensions this crate implements are the ones a program
4673        // guards with `#if defined(__GNUC__) && __GNUC__ >= 4`, so claiming
4674        // 4.2.1 is what makes those guards take the branch that uses them.
4675        // Clang set the same precedent for the same reason.
4676        self.define_object("__GNUC__", "4");
4677        self.define_object("__GNUC_MINOR__", "2");
4678        self.define_object("__GNUC_PATCHLEVEL__", "1");
4679        self.define_string(
4680            "__VERSION__",
4681            &format!("cinrs {}", env!("CARGO_PKG_VERSION")),
4682        );
4683        // Fixed placeholders: a build has to give the same output twice.
4684        self.define_string("__DATE__", "??? ?? ????");
4685        self.define_string("__TIME__", "??:??:??");
4686        self.define_string("__TIMESTAMP__", "??? ??? ?? ??:??:?? ????");
4687        let base_file = self.base_file.clone();
4688        self.define_string("__BASE_FILE__", &base_file);
4689        self.define_builtin("__LINE__", Builtin::Line);
4690        self.define_builtin("__FILE__", Builtin::File);
4691        self.define_builtin("__FILE_NAME__", Builtin::FileName);
4692        self.define_builtin("__INCLUDE_LEVEL__", Builtin::IncludeLevel);
4693        self.define_builtin("__COUNTER__", Builtin::Counter);
4694        // GCC's `__builtin_LINE()`, `__builtin_FILE()` and
4695        // `__builtin_FUNCTION()` say what `__LINE__`, `__FILE__` and
4696        // `__func__` say; being macros rather than builtins is what makes
4697        // them report the *use* rather than the definition, exactly as GCC's
4698        // do for a default argument.
4699        self.define_function("__builtin_LINE", "__LINE__");
4700        self.define_function("__builtin_FILE", "__FILE__");
4701        self.define_function("__builtin_FUNCTION", "__func__");
4702        for (name, value) in target_macros(&options.target) {
4703            self.define_object(name, &value);
4704        }
4705    }
4706
4707    /// The macros GCC predefines for the atomic builtins, in every mode.
4708    ///
4709    /// The six `__ATOMIC_*` values are the argument the `__atomic_*` family
4710    /// takes, and their numbering is GCC's own — `<stdatomic.h>`'s
4711    /// `memory_order` enumeration has the same values, because a program may
4712    /// pass either to either. The `__GCC_ATOMIC_*_LOCK_FREE` family answers
4713    /// `2`, "always lock free", for every type there is a Rust atomic of, and
4714    /// `<stdatomic.h>`'s `ATOMIC_*_LOCK_FREE` macros are defined from these.
4715    fn define_atomic_macros(&mut self, max_atomic: u64) {
4716        for (name, value) in [
4717            ("__ATOMIC_RELAXED", "0"),
4718            ("__ATOMIC_CONSUME", "1"),
4719            ("__ATOMIC_ACQUIRE", "2"),
4720            ("__ATOMIC_RELEASE", "3"),
4721            ("__ATOMIC_ACQ_REL", "4"),
4722            ("__ATOMIC_SEQ_CST", "5"),
4723        ] {
4724            self.define_object(name, value);
4725        }
4726        for name in [
4727            "__GCC_ATOMIC_BOOL_LOCK_FREE",
4728            "__GCC_ATOMIC_CHAR_LOCK_FREE",
4729            "__GCC_ATOMIC_CHAR8_T_LOCK_FREE",
4730            "__GCC_ATOMIC_CHAR16_T_LOCK_FREE",
4731            "__GCC_ATOMIC_CHAR32_T_LOCK_FREE",
4732            "__GCC_ATOMIC_WCHAR_T_LOCK_FREE",
4733            "__GCC_ATOMIC_SHORT_LOCK_FREE",
4734            "__GCC_ATOMIC_INT_LOCK_FREE",
4735            "__GCC_ATOMIC_LONG_LOCK_FREE",
4736            "__GCC_ATOMIC_LLONG_LOCK_FREE",
4737            "__GCC_ATOMIC_POINTER_LOCK_FREE",
4738        ] {
4739            self.define_object(name, "2");
4740        }
4741        // What `__atomic_test_and_set` writes, which GCC also predefines.
4742        self.define_object("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
4743        // The `__sync_*` family's own advertisement, which a program tests
4744        // before writing one of them. Eight bytes only where an eight-byte
4745        // object is aligned well enough for a lock-free instruction; see
4746        // `TargetModel::max_scalar_align`.
4747        for width in [1u64, 2, 4, 8] {
4748            if width <= max_atomic {
4749                self.define_object(
4750                    match width {
4751                        1 => "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1",
4752                        2 => "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2",
4753                        4 => "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4",
4754                        _ => "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8",
4755                    },
4756                    "1",
4757                );
4758            }
4759        }
4760    }
4761
4762    /// Defines a predefined function-like macro that takes no arguments.
4763    fn define_function(&mut self, name: &str, body: &str) {
4764        let tokens = lex::lex_text(body, self.base, &self.lex_options);
4765        let body: Vec<PTok> = tokens
4766            .iter()
4767            .filter(|t| !matches!(t.kind, TokenKind::Eof))
4768            .map(PTok::from_lexed)
4769            .collect();
4770        self.macros.insert(
4771            name.to_owned(),
4772            Arc::new(MacroDef {
4773                params: Some(Vec::new()),
4774                variadic: false,
4775                va_name: None,
4776                body,
4777                name_range: SourceRange::at(self.base),
4778                predefined: true,
4779                builtin: None,
4780            }),
4781        );
4782    }
4783
4784    /// Defines a predefined object-like macro from the C text of its body.
4785    fn define_object(&mut self, name: &str, body: &str) {
4786        let tokens = lex::lex_text(body, self.base, &self.lex_options);
4787        let body: Vec<PTok> = tokens
4788            .iter()
4789            .filter(|t| !matches!(t.kind, TokenKind::Eof))
4790            .map(PTok::from_lexed)
4791            .collect();
4792        self.insert_predefined(name, body, None);
4793    }
4794
4795    /// Defines a predefined macro whose body is one string literal.
4796    fn define_string(&mut self, name: &str, value: &str) {
4797        let kind = string_token_kind(value);
4798        let body = vec![PTok {
4799            kind,
4800            range: SourceRange::at(self.base),
4801            bol: false,
4802            space: false,
4803            origin: Origin::Source,
4804            hide: HideSet::default(),
4805            errors: Vec::new(),
4806        }];
4807        self.insert_predefined(name, body, None);
4808    }
4809
4810    fn define_builtin(&mut self, name: &str, builtin: Builtin) {
4811        self.insert_predefined(name, Vec::new(), Some(builtin));
4812    }
4813
4814    fn insert_predefined(&mut self, name: &str, body: Vec<PTok>, builtin: Option<Builtin>) {
4815        self.macros.insert(
4816            name.to_owned(),
4817            Arc::new(MacroDef {
4818                params: None,
4819                variadic: false,
4820                va_name: None,
4821                body,
4822                name_range: SourceRange::at(self.base),
4823                predefined: true,
4824                builtin,
4825            }),
4826        );
4827    }
4828}
4829
4830/// Whether the bundled `<threads.h>` declares anything on this target, which
4831/// is what decides `__STDC_NO_THREADS__` (C11 6.10.8.3).
4832///
4833/// The C11 thread types are blocks of bytes whose size belongs to the C
4834/// library rather than to C, so the header models the two libraries whose
4835/// layouts it knows — glibc and musl, both on Linux — and refuses everywhere
4836/// else: Apple's libSystem and the Microsoft UCRT have no `<threads.h>` at
4837/// all, and the BSDs, bionic and uClibc each lay the objects out their own
4838/// way. Where it refuses, the macro says so, which is what lets a portable
4839/// program take the other branch instead of hitting the `#error`.
4840fn threads_available(target: &TargetModel) -> bool {
4841    target.os == Os::Linux && matches!(target.env, Env::Gnu | Env::Musl)
4842}
4843
4844/// The target description macros, every one of them derived from `target`.
4845///
4846/// Nothing here reads a `cfg!`: the model may be the host's or may be a
4847/// `CINRS_TARGET` away, and a macro that answered for the host while `sizeof`
4848/// answered for the target would send a header down the wrong branch — which
4849/// is exactly how the bundled `<errno.h>`, `<stdio.h>`, `<time.h>` and
4850/// `<wchar.h>` choose their platform, through `_WIN32` and `__APPLE__`.
4851///
4852/// Deliberately short. Anything a real header would test for that is not here
4853/// simply comes out as 0 in an `#if`, which is the behaviour a C program
4854/// written for an unknown compiler expects; claiming to *be* GCC or Clang
4855/// would invite code paths built on extensions this crate does not have.
4856fn target_macros(target: &TargetModel) -> Vec<(&'static str, String)> {
4857    // The architecture, the operating system and the object format; see
4858    // `TargetModel::macros`.
4859    let mut out: Vec<(&'static str, String)> = target.macros();
4860    let flag = |out: &mut Vec<(&'static str, String)>, name: &'static str| {
4861        out.push((name, "1".to_owned()))
4862    };
4863
4864    // The data model, which is exactly what `TargetModel` describes.
4865    if target.ptr_bits == 64 && target.long_bits == 64 {
4866        flag(&mut out, "__LP64__");
4867        flag(&mut out, "_LP64");
4868    } else if target.ptr_bits == 32 && target.int_bits == 32 && target.long_bits == 32 {
4869        flag(&mut out, "__ILP32__");
4870        flag(&mut out, "_ILP32");
4871    }
4872    if !target.char_signed {
4873        flag(&mut out, "__CHAR_UNSIGNED__");
4874    }
4875    out.push(("__CHAR_BIT__", "8".to_owned()));
4876    out.push(("__SIZEOF_SHORT__", (target.short_bits / 8).to_string()));
4877    out.push(("__SIZEOF_INT__", (target.int_bits / 8).to_string()));
4878    out.push(("__SIZEOF_LONG__", (target.long_bits / 8).to_string()));
4879    out.push((
4880        "__SIZEOF_LONG_LONG__",
4881        (target.long_long_bits / 8).to_string(),
4882    ));
4883    out.push(("__SIZEOF_POINTER__", (target.ptr_bits / 8).to_string()));
4884    // The macro a program tests before writing `__int128`. GCC defines it
4885    // exactly where the type exists, which is on the 64-bit architectures, so
4886    // a program guarding on it takes the other branch on an ILP32 target
4887    // rather than meeting the diagnostic.
4888    if target.has_int128 {
4889        out.push(("__SIZEOF_INT128__", "16".to_owned()));
4890    }
4891
4892    // Byte order, spelled the way GCC spells it.
4893    out.push(("__ORDER_LITTLE_ENDIAN__", "1234".to_owned()));
4894    out.push(("__ORDER_BIG_ENDIAN__", "4321".to_owned()));
4895    out.push((
4896        "__BYTE_ORDER__",
4897        if target.big_endian {
4898            "4321".to_owned()
4899        } else {
4900            "1234".to_owned()
4901        },
4902    ));
4903    limit_macros(target, &mut out);
4904    out
4905}
4906
4907/// The largest value a signed type of `bits` bits holds, as a decimal string.
4908fn signed_max(bits: u32) -> String {
4909    ((1u128 << (bits - 1)) - 1).to_string()
4910}
4911
4912/// The largest value an unsigned type of `bits` bits holds.
4913fn unsigned_max(bits: u32) -> String {
4914    (u128::MAX >> (128 - bits)).to_string()
4915}
4916
4917/// GCC's `__INT_MAX__`, `__SIZE_TYPE__` and the rest of that family.
4918///
4919/// A great deal of portable C is written against these rather than against
4920/// `<limits.h>` and `<stdint.h>`, because they are available before any header
4921/// is included and are what those headers are written in terms of. GCC's own
4922/// torture suite uses `__INT_MAX__` in ninety-five files and `__SIZE_TYPE__`
4923/// in seventy, and a program that tests one of them and finds it undefined
4924/// does not fail to compile — it silently takes the wrong branch, which is
4925/// worse. So the whole family is defined here, from the same
4926/// [`TargetModel`] everything else is derived from.
4927///
4928/// The spellings of the *types* are GCC's own (`long unsigned int` rather than
4929/// `unsigned long`), because a program may paste one into a `typedef` and
4930/// diff the result, and the suffixes on the *values* are the ones that give
4931/// each constant the type its name says it has.
4932///
4933/// What is deliberately absent: `__OPTIMIZE__` (nothing here optimises) and
4934/// the `__INT8_C`-style function-like macros, which take an argument.
4935/// `__SIZEOF_INT128__` is not here but among the data-model macros, and only
4936/// on a target that has `__int128` at all.
4937fn limit_macros(target: &TargetModel, out: &mut Vec<(&'static str, String)>) {
4938    let int_bits = target.int_bits;
4939    let long_bits = target.long_bits;
4940    let llong_bits = target.long_long_bits;
4941    let ptr_bits = target.ptr_bits;
4942
4943    // `size_t`, `ptrdiff_t` and `intptr_t` are the *narrowest* standard type
4944    // as wide as a pointer, which is how GCC picks them: `unsigned int` on
4945    // i686, `long unsigned int` on LP64, `long long unsigned int` on 64-bit
4946    // Windows, where `long` is only 32 bits.
4947    let (ptr_signed, ptr_unsigned, ptr_suffix) = if int_bits >= ptr_bits {
4948        ("int", "unsigned int", "")
4949    } else if long_bits >= ptr_bits {
4950        ("long int", "long unsigned int", "L")
4951    } else {
4952        ("long long int", "long long unsigned int", "LL")
4953    };
4954    // `intmax_t` is the widest standard integer type there is, which is
4955    // `long long` unless `long` is just as wide — GCC says `long int` on LP64
4956    // and `long long int` on i686 and on Windows. It does *not* follow the
4957    // pointer: an ILP32 target still has a 64-bit `intmax_t`, and C99 6.10.1
4958    // makes it the type all `#if` arithmetic is done in.
4959    let (max_signed, max_unsigned, max_suffix) = if long_bits >= llong_bits {
4960        ("long int", "long unsigned int", "L")
4961    } else {
4962        ("long long int", "long long unsigned int", "LL")
4963    };
4964    let max_bits = long_bits.max(llong_bits);
4965
4966    let mut push = |name: &'static str, value: String| out.push((name, value));
4967
4968    // The limits of the standard integer types.
4969    push("__SCHAR_MAX__", signed_max(8));
4970    push("__SHRT_MAX__", signed_max(target.short_bits));
4971    push("__INT_MAX__", signed_max(int_bits));
4972    push("__LONG_MAX__", format!("{}L", signed_max(long_bits)));
4973    push("__LONG_LONG_MAX__", format!("{}LL", signed_max(llong_bits)));
4974
4975    // Their widths, which C23 added to <limits.h> and GCC has always had.
4976    // The two compilers do not spell the same set: GCC has
4977    // `__LONG_LONG_WIDTH__` and `__SCHAR_WIDTH__`, Clang has `__LLONG_WIDTH__`
4978    // and `__BOOL_WIDTH__`, and code in the wild tests whichever its author's
4979    // compiler had — `clang/test/C/drs/dr2xx.c` `#error`s out on
4980    // `__LLONG_WIDTH__` alone. So the *union* is defined, and the two
4981    // spellings of one width are one value by construction.
4982    push("__BOOL_WIDTH__", "1".to_owned());
4983    push("__SCHAR_WIDTH__", "8".to_owned());
4984    push("__SHRT_WIDTH__", target.short_bits.to_string());
4985    push("__INT_WIDTH__", int_bits.to_string());
4986    push("__LONG_WIDTH__", long_bits.to_string());
4987    push("__LONG_LONG_WIDTH__", llong_bits.to_string());
4988    push("__LLONG_WIDTH__", llong_bits.to_string());
4989
4990    // The library types, and how wide each is.
4991    push("__SIZE_TYPE__", ptr_unsigned.to_owned());
4992    push(
4993        "__SIZE_MAX__",
4994        format!("{}U{ptr_suffix}", unsigned_max(ptr_bits)),
4995    );
4996    push("__SIZE_WIDTH__", ptr_bits.to_string());
4997    push("__SIZEOF_SIZE_T__", (ptr_bits / 8).to_string());
4998    push("__PTRDIFF_TYPE__", ptr_signed.to_owned());
4999    push(
5000        "__PTRDIFF_MAX__",
5001        format!("{}{ptr_suffix}", signed_max(ptr_bits)),
5002    );
5003    push("__PTRDIFF_WIDTH__", ptr_bits.to_string());
5004    push("__SIZEOF_PTRDIFF_T__", (ptr_bits / 8).to_string());
5005    push("__INTMAX_TYPE__", max_signed.to_owned());
5006    push(
5007        "__INTMAX_MAX__",
5008        format!("{}{max_suffix}", signed_max(max_bits)),
5009    );
5010    push("__INTMAX_WIDTH__", max_bits.to_string());
5011    push("__SIZEOF_INTMAX__", (max_bits / 8).to_string());
5012    push("__UINTMAX_TYPE__", max_unsigned.to_owned());
5013    push(
5014        "__UINTMAX_MAX__",
5015        format!("{}U{max_suffix}", unsigned_max(max_bits)),
5016    );
5017    push("__UINTMAX_WIDTH__", max_bits.to_string());
5018    push("__INTPTR_TYPE__", ptr_signed.to_owned());
5019    push(
5020        "__INTPTR_MAX__",
5021        format!("{}{ptr_suffix}", signed_max(ptr_bits)),
5022    );
5023    push("__INTPTR_WIDTH__", ptr_bits.to_string());
5024    push("__UINTPTR_TYPE__", ptr_unsigned.to_owned());
5025    push(
5026        "__UINTPTR_MAX__",
5027        format!("{}U{ptr_suffix}", unsigned_max(ptr_bits)),
5028    );
5029    push("__UINTPTR_WIDTH__", ptr_bits.to_string());
5030    push("__POINTER_WIDTH__", ptr_bits.to_string());
5031
5032    // `wchar_t` and `wint_t`, which the bundled <stddef.h> and <wchar.h>
5033    // typedef from these very macros. Windows makes both 16 bits, Arm makes
5034    // `wchar_t` unsigned, and Apple makes `wint_t` an `int`.
5035    let wchar_bits = target.wchar_bits;
5036    let (wchar_type, wchar_max, wchar_min) = if target.wchar_signed {
5037        (
5038            if wchar_bits == 16 { "short int" } else { "int" },
5039            signed_max(wchar_bits),
5040            format!("(-{}-1)", signed_max(wchar_bits)),
5041        )
5042    } else {
5043        (
5044            if wchar_bits == 16 {
5045                "short unsigned int"
5046            } else {
5047                "unsigned int"
5048            },
5049            unsigned_max(wchar_bits),
5050            "0".to_owned(),
5051        )
5052    };
5053    push("__WCHAR_TYPE__", wchar_type.to_owned());
5054    push("__WCHAR_MAX__", wchar_max);
5055    push("__WCHAR_MIN__", wchar_min);
5056    push("__WCHAR_WIDTH__", wchar_bits.to_string());
5057    push("__SIZEOF_WCHAR_T__", (wchar_bits / 8).to_string());
5058    if !target.wchar_signed {
5059        push("__WCHAR_UNSIGNED__", "1".to_owned());
5060    }
5061    let wint_bits = target.wint_bits;
5062    push(
5063        "__WINT_TYPE__",
5064        match (target.wint_signed, wint_bits) {
5065            (true, 16) => "short int",
5066            (true, _) => "int",
5067            (false, 16) => "short unsigned int",
5068            (false, _) => "unsigned int",
5069        }
5070        .to_owned(),
5071    );
5072    push("__WINT_WIDTH__", wint_bits.to_string());
5073    push("__SIZEOF_WINT_T__", (wint_bits / 8).to_string());
5074    push("__SIG_ATOMIC_TYPE__", "int".to_owned());
5075    push("__SIG_ATOMIC_MAX__", signed_max(int_bits));
5076    push(
5077        "__SIG_ATOMIC_MIN__",
5078        format!("(-{}-1)", signed_max(int_bits)),
5079    );
5080    push("__SIG_ATOMIC_WIDTH__", int_bits.to_string());
5081    push("__CHAR16_TYPE__", "short unsigned int".to_owned());
5082    push("__CHAR32_TYPE__", "unsigned int".to_owned());
5083
5084    // The floating types. `long double` is `double` here, and the values are
5085    // the ones `include/float.h` gives.
5086    push("__SIZEOF_FLOAT__", "4".to_owned());
5087    push("__SIZEOF_DOUBLE__", "8".to_owned());
5088    push("__SIZEOF_LONG_DOUBLE__", "8".to_owned());
5089    // Everything `<float.h>` says about a floating type, under the names GCC
5090    // gives it: a great deal of portable C tests `__DBL_MIN_EXP__` rather than
5091    // including the header, and a program that finds one of these undefined
5092    // does not fail to compile — it silently takes the wrong branch.
5093    // `execute/ieee/pr30704` is exactly that.
5094    push("__FLT_RADIX__", "2".to_owned());
5095    push("__FLT_EVAL_METHOD__", "0".to_owned());
5096    push("__FLT_MANT_DIG__", "24".to_owned());
5097    push("__FLT_DIG__", "6".to_owned());
5098    push("__FLT_MIN_EXP__", "(-125)".to_owned());
5099    push("__FLT_MIN_10_EXP__", "(-37)".to_owned());
5100    push("__FLT_MAX_EXP__", "128".to_owned());
5101    push("__FLT_MAX_10_EXP__", "38".to_owned());
5102    push("__FLT_DECIMAL_DIG__", "9".to_owned());
5103    push("__FLT_MAX__", "3.40282346638528859812e+38F".to_owned());
5104    push("__FLT_NORM_MAX__", "3.40282346638528859812e+38F".to_owned());
5105    push("__FLT_MIN__", "1.17549435082228750797e-38F".to_owned());
5106    push("__FLT_EPSILON__", "1.19209289550781250000e-7F".to_owned());
5107    push(
5108        "__FLT_DENORM_MIN__",
5109        "1.40129846432481707092e-45F".to_owned(),
5110    );
5111    push("__FLT_HAS_DENORM__", "1".to_owned());
5112    push("__FLT_HAS_INFINITY__", "1".to_owned());
5113    push("__FLT_HAS_QUIET_NAN__", "1".to_owned());
5114    push("__FLT_IS_IEC_60559__", "1".to_owned());
5115    push("__DBL_MANT_DIG__", "53".to_owned());
5116    push("__DBL_DIG__", "15".to_owned());
5117    push("__DBL_MIN_EXP__", "(-1021)".to_owned());
5118    push("__DBL_MIN_10_EXP__", "(-307)".to_owned());
5119    push("__DBL_MAX_EXP__", "1024".to_owned());
5120    push("__DBL_MAX_10_EXP__", "308".to_owned());
5121    push("__DBL_DECIMAL_DIG__", "17".to_owned());
5122    push("__DBL_MAX__", "1.79769313486231570815e+308".to_owned());
5123    push("__DBL_NORM_MAX__", "1.79769313486231570815e+308".to_owned());
5124    push("__DBL_MIN__", "2.22507385850720138309e-308".to_owned());
5125    push("__DBL_EPSILON__", "2.22044604925031308085e-16".to_owned());
5126    push(
5127        "__DBL_DENORM_MIN__",
5128        "4.94065645841246544177e-324".to_owned(),
5129    );
5130    push("__DBL_HAS_DENORM__", "1".to_owned());
5131    push("__DBL_HAS_INFINITY__", "1".to_owned());
5132    push("__DBL_HAS_QUIET_NAN__", "1".to_owned());
5133    push("__DBL_IS_IEC_60559__", "1".to_owned());
5134    // `long double` is `double` here — there is no portable Rust type with the
5135    // layout of an x87 extended double — so its family repeats `double`'s with
5136    // the suffix that gives each constant the type its name says it has, which
5137    // is what the bundled `<float.h>` does too.
5138    push("__LDBL_MANT_DIG__", "53".to_owned());
5139    push("__LDBL_DIG__", "15".to_owned());
5140    push("__LDBL_MIN_EXP__", "(-1021)".to_owned());
5141    push("__LDBL_MIN_10_EXP__", "(-307)".to_owned());
5142    push("__LDBL_MAX_EXP__", "1024".to_owned());
5143    push("__LDBL_MAX_10_EXP__", "308".to_owned());
5144    push("__LDBL_DECIMAL_DIG__", "17".to_owned());
5145    push("__DECIMAL_DIG__", "17".to_owned());
5146    push("__LDBL_MAX__", "1.79769313486231570815e+308L".to_owned());
5147    push(
5148        "__LDBL_NORM_MAX__",
5149        "1.79769313486231570815e+308L".to_owned(),
5150    );
5151    push("__LDBL_MIN__", "2.22507385850720138309e-308L".to_owned());
5152    push("__LDBL_EPSILON__", "2.22044604925031308085e-16L".to_owned());
5153    push(
5154        "__LDBL_DENORM_MIN__",
5155        "4.94065645841246544177e-324L".to_owned(),
5156    );
5157    push("__LDBL_HAS_DENORM__", "1".to_owned());
5158    push("__LDBL_HAS_INFINITY__", "1".to_owned());
5159    push("__LDBL_HAS_QUIET_NAN__", "1".to_owned());
5160    push("__LDBL_IS_IEC_60559__", "1".to_owned());
5161
5162    // The exact-width types of <stdint.h>, which GCC's own <stdint.h> is
5163    // written in terms of. `int64_t` follows `long` wherever `long` is 64
5164    // bits, exactly as GCC has it.
5165    let (i64_type, u64_type, s64, u64) = if long_bits == 64 {
5166        ("long int", "long unsigned int", "L", "UL")
5167    } else {
5168        ("long long int", "long long unsigned int", "LL", "ULL")
5169    };
5170    let widths: [(
5171        &'static str,
5172        &'static str,
5173        &'static str,
5174        &'static str,
5175        &'static str,
5176        u32,
5177    ); 4] = [
5178        ("8", "signed char", "unsigned char", "", "", 8),
5179        ("16", "short int", "short unsigned int", "", "", 16),
5180        ("32", "int", "unsigned int", "", "U", 32),
5181        ("64", i64_type, u64_type, s64, u64, 64),
5182    ];
5183    // The names have to be `'static`, so the four sets are written out rather
5184    // than built; the values still come from the loop above.
5185    const EXACT: [[&str; 8]; 4] = [
5186        [
5187            "__INT8_TYPE__",
5188            "__UINT8_TYPE__",
5189            "__INT8_MAX__",
5190            "__UINT8_MAX__",
5191            "__INT_LEAST8_TYPE__",
5192            "__UINT_LEAST8_TYPE__",
5193            "__INT_LEAST8_MAX__",
5194            "__UINT_LEAST8_MAX__",
5195        ],
5196        [
5197            "__INT16_TYPE__",
5198            "__UINT16_TYPE__",
5199            "__INT16_MAX__",
5200            "__UINT16_MAX__",
5201            "__INT_LEAST16_TYPE__",
5202            "__UINT_LEAST16_TYPE__",
5203            "__INT_LEAST16_MAX__",
5204            "__UINT_LEAST16_MAX__",
5205        ],
5206        [
5207            "__INT32_TYPE__",
5208            "__UINT32_TYPE__",
5209            "__INT32_MAX__",
5210            "__UINT32_MAX__",
5211            "__INT_LEAST32_TYPE__",
5212            "__UINT_LEAST32_TYPE__",
5213            "__INT_LEAST32_MAX__",
5214            "__UINT_LEAST32_MAX__",
5215        ],
5216        [
5217            "__INT64_TYPE__",
5218            "__UINT64_TYPE__",
5219            "__INT64_MAX__",
5220            "__UINT64_MAX__",
5221            "__INT_LEAST64_TYPE__",
5222            "__UINT_LEAST64_TYPE__",
5223            "__INT_LEAST64_MAX__",
5224            "__UINT_LEAST64_MAX__",
5225        ],
5226    ];
5227    for (names, (_, signed, unsigned, s_suffix, u_suffix, bits)) in EXACT.iter().zip(widths) {
5228        let smax = format!("{}{s_suffix}", signed_max(bits));
5229        let umax = format!("{}{u_suffix}", unsigned_max(bits));
5230        for at in [0, 4] {
5231            out.push((names[at], signed.to_owned()));
5232            out.push((names[at + 1], unsigned.to_owned()));
5233            out.push((names[at + 2], smax.clone()));
5234            out.push((names[at + 3], umax.clone()));
5235        }
5236    }
5237
5238    // How wide each of those is. The `least` widths are exact by
5239    // construction; the `fast` ones follow the choice `include/stdint.h`
5240    // makes for the typedefs, so the macro and a `sizeof` on the type give
5241    // one answer. (`__BITINT_MAXWIDTH__` is deliberately absent: it is the
5242    // signal that `_BitInt` exists, and here it does not.)
5243    let fast_mid = if ptr_bits == 64 { "64" } else { "32" };
5244    for (name, value) in [
5245        ("__INT_LEAST8_WIDTH__", "8"),
5246        ("__INT_LEAST16_WIDTH__", "16"),
5247        ("__INT_LEAST32_WIDTH__", "32"),
5248        ("__INT_LEAST64_WIDTH__", "64"),
5249        ("__INT_FAST8_WIDTH__", "8"),
5250        ("__INT_FAST16_WIDTH__", fast_mid),
5251        ("__INT_FAST32_WIDTH__", fast_mid),
5252        ("__INT_FAST64_WIDTH__", "64"),
5253    ] {
5254        out.push((name, value.to_owned()));
5255    }
5256}