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