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