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, ¶ms, 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, ¶ms, 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}