Skip to main content

rucc_pp/
predef.rs

1//! The predefined macro set, generated from the target description.
2//!
3//! Design: `spec/04-driver-and-cli.md` section 4.5.
4//!
5//! The set is built as text and then read by the directive engine, which is what GCC does and
6//! is not laziness. Constructing a few hundred `MacroDef` values by hand would need its own
7//! parser for macro bodies, would not exercise the one that already exists, and could not be
8//! read by a person checking a limit against the psABI. A file of `#define` lines can be
9//! printed by `-dM`, diffed against GCC's output, and understood at a glance.
10//!
11//! Two synthetic files come out of this, and they are the two GCC names in a diagnostic:
12//! `<built-in>` for the generated set and `<command-line>` for `-D` and `-U`. Keeping them
13//! apart is what lets "`FOO` redefined" point at the command line rather than at a line
14//! nobody wrote.
15//!
16//! The decision that everything else follows from is in section 4.5: we define `__GNUC__`,
17//! which means glibc's headers, the kernel's headers and every autoconf probe take the GNU
18//! path. The version claimed is deliberately conservative and is a knob, because claiming too
19//! high a version means headers use extensions we do not have, and the matrix in `rucc-gnu`
20//! is the list of promises the claim makes.
21
22use rucc_base::float::Format;
23use rucc_session::{GnucVersion, OptLevel, Options, Pic, Std};
24use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
25use rucc_tuple::{self as tuple};
26
27/// The name a diagnostic about the generated set points at.
28pub const BUILT_IN: &str = "<built-in>";
29
30/// The name a diagnostic about `-D` or `-U` points at.
31pub const COMMAND_LINE: &str = "<command-line>";
32
33/// The translation date, as `__DATE__` and `__TIME__` spell it.
34///
35/// Fixed for the whole translation unit, which is what the standard requires and what makes
36/// the two macros ordinary object-like macros rather than something the expander has to know
37/// about.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct Timestamp {
40    /// `Mmm dd yyyy`, with the day space padded, which is the format the standard fixes.
41    pub date: String,
42    /// `hh:mm:ss`.
43    pub time: String,
44}
45
46impl Timestamp {
47    /// The current time, or `SOURCE_DATE_EPOCH` when the build asked for a reproducible one.
48    ///
49    /// Reading the environment here rather than in the driver is what GCC does, and it keeps
50    /// the variable working for an embedder who never goes through a command line.
51    pub fn now() -> Timestamp {
52        let seconds = match std::env::var("SOURCE_DATE_EPOCH").ok().and_then(|v| v.parse().ok()) {
53            Some(fixed) => fixed,
54            None => std::time::SystemTime::now()
55                .duration_since(std::time::UNIX_EPOCH)
56                .map_or(0, |d| d.as_secs() as i64),
57        };
58        Timestamp::from_unix(seconds)
59    }
60
61    /// The time `seconds` after the epoch, in UTC.
62    ///
63    /// UTC rather than local time, because a compiler whose output depends on the machine's
64    /// time zone is a compiler whose output is not reproducible.
65    pub fn from_unix(seconds: i64) -> Timestamp {
66        let days = seconds.div_euclid(86_400);
67        let rest = seconds.rem_euclid(86_400);
68        let (year, month, day) = civil_from_days(days);
69        const MONTHS: [&str; 12] =
70            ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
71        let name = MONTHS[(month - 1) as usize];
72        Timestamp {
73            date: format!("{name} {day:2} {year}"),
74            time: format!("{:02}:{:02}:{:02}", rest / 3600, (rest / 60) % 60, rest % 60),
75        }
76    }
77}
78
79/// The year, month and day `days` after 1970-01-01.
80///
81/// Howard Hinnant's civil calendar algorithm, which is a handful of divisions and no table.
82/// It is here rather than in a dependency because the whole workspace has no dependencies,
83/// and a date conversion is not a good reason to acquire the first one.
84fn civil_from_days(days: i64) -> (i64, u32, u32) {
85    // Shift the epoch to 0000-03-01, so that a leap day is the last day of the year and the
86    // month lengths become a repeating pattern that one division can invert.
87    let shifted = days + 719_468;
88    let era = shifted.div_euclid(146_097);
89    let day_of_era = shifted.rem_euclid(146_097);
90    let year_of_era =
91        (day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
92    let year = year_of_era + era * 400;
93    let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
94    let marched = (5 * day_of_year + 2) / 153;
95    let day = (day_of_year - (153 * marched + 2) / 5 + 1) as u32;
96    let month = if marched < 10 { marched + 3 } else { marched - 9 } as u32;
97    (year + i64::from(month <= 2), month, day)
98}
99
100/// Everything the predefined set is built from that is not the target.
101#[derive(Debug, Clone, PartialEq, Eq)]
102pub struct Predef {
103    /// The dialect, which decides `__STDC_VERSION__`.
104    pub std: Std,
105    /// Whether the GNU extensions are on, which is `-std=gnu23` rather than `-std=c23`. It
106    /// decides `__STRICT_ANSI__` and the unarmoured `linux` and `unix` macros.
107    pub gnu_extensions: bool,
108    /// Whether the unit is under GNU's reading of `inline`, which is `-fgnu89-inline`. It decides
109    /// which of `__GNUC_GNU_INLINE__` and `__GNUC_STDC_INLINE__` is defined, and the C89 dialects
110    /// are under that reading whatever it says.
111    pub gnu89_inline: bool,
112    /// The GCC release claimed.
113    pub gnuc: GnucVersion,
114    /// Decides `__OPTIMIZE__`, `__OPTIMIZE_SIZE__` and `__NO_INLINE__`.
115    pub opt_level: OptLevel,
116    /// Whether there is a standard library, which is `-ffreestanding` turned around.
117    pub hosted: bool,
118    /// Which link the output is for, from `-fPIC` and `-fPIE`. It decides `__PIE__`, since
119    /// `__PIC__` is defined either way and says only that there are no absolute addresses.
120    pub pic: Pic,
121    /// `__DATE__` and `__TIME__`.
122    pub timestamp: Timestamp,
123    /// The glibc release the headers are, as the minor number alone, when they are ours.
124    ///
125    /// `__GLIBC_MINOR__` and nothing else: `__GLIBC__` is 2 in the tree itself, which is how Zig's
126    /// own patched `features.h` has it, and a version the compiler supplied and a version the
127    /// header supplied would be two answers to one question.
128    pub glibc_minor: Option<u32>,
129    /// `-D` in command line order. `FOO` means `FOO=1`, as GCC has it.
130    pub defines: Vec<String>,
131    /// `-U` in command line order, applied after the defines.
132    pub undefines: Vec<String>,
133}
134
135impl Predef {
136    /// The default dialect, `gnu23`, at `-O0`.
137    pub fn new() -> Predef {
138        Predef {
139            std: Std::default(),
140            gnu_extensions: true,
141            gnu89_inline: false,
142            gnuc: GnucVersion::default(),
143            opt_level: OptLevel::O0,
144            hosted: true,
145            pic: Pic::Executable,
146            timestamp: Timestamp::now(),
147            glibc_minor: None,
148            defines: Vec::new(),
149            undefines: Vec::new(),
150        }
151    }
152}
153
154impl Predef {
155    /// The set the command line asked for.
156    ///
157    /// The mapping lives here rather than in the driver because it is the definition of what
158    /// each flag means to the macro set, and the driver's job is to parse a command line, not
159    /// to know that `-ffreestanding` is `__STDC_HOSTED__` being zero.
160    pub fn for_options(opts: &Options) -> Predef {
161        Predef {
162            std: opts.std,
163            gnu_extensions: opts.gnu_extensions,
164            gnu89_inline: opts.gnu89_inline,
165            gnuc: opts.gnuc,
166            opt_level: opts.opt_level,
167            hosted: opts.hosted,
168            pic: opts.pic,
169            timestamp: Timestamp::now(),
170            glibc_minor: opts.glibc_minor,
171            defines: opts.defines.clone(),
172            undefines: opts.undefines.clone(),
173        }
174    }
175}
176
177impl Default for Predef {
178    fn default() -> Predef {
179        Predef::new()
180    }
181}
182
183/// A file of `#define` lines being built up.
184struct Defs {
185    text: String,
186}
187
188impl Defs {
189    fn new() -> Defs {
190        Defs { text: String::new() }
191    }
192
193    /// `#define name value`.
194    fn set(&mut self, name: &str, value: &str) {
195        self.text.push_str("#define ");
196        self.text.push_str(name);
197        self.text.push(' ');
198        self.text.push_str(value);
199        self.text.push('\n');
200    }
201
202    /// `#define name 1`, which is what a macro that is only ever tested for needs.
203    fn flag(&mut self, name: &str) {
204        self.set(name, "1");
205    }
206
207    fn set_if(&mut self, when: bool, name: &str, value: &str) {
208        if when {
209            self.set(name, value);
210        }
211    }
212
213    fn flag_if(&mut self, when: bool, name: &str) {
214        if when {
215            self.flag(name);
216        }
217    }
218}
219
220/// The whole predefined set for a target, as the text of a file.
221pub(crate) fn built_in(target: &TargetInfo, opts: &Predef) -> String {
222    let mut d = Defs::new();
223    identity(&mut d, target, opts);
224    // `__DATE__` and `__TIME__` are fixed for the whole translation unit, which is what the
225    // standard asks for, so they are ordinary object-like macros and the expander needs to
226    // know nothing about them.
227    d.set("__DATE__", &format!("\"{}\"", opts.timestamp.date));
228    d.set("__TIME__", &format!("\"{}\"", opts.timestamp.time));
229    dialect(&mut d, opts);
230    optimization(&mut d, opts);
231    platform(&mut d, target, opts);
232    sizes(&mut d, target);
233    integers(&mut d, target);
234    floats(&mut d, target);
235    atomics(&mut d, target);
236    d.text
237}
238
239/// `-D` and `-U`, as the text of a file.
240///
241/// Empty when there are none, so that the caller can skip adding a file that would say
242/// nothing. The undefines come last whatever order they were written in, because `-U` beats
243/// `-D` in GCC no matter which side of it the `-D` was on.
244pub(crate) fn command_line(opts: &Predef) -> String {
245    let mut d = Defs::new();
246    for define in &opts.defines {
247        match define.split_once('=') {
248            Some((name, value)) => d.set(name, value),
249            // `-DFOO` is `-DFOO=1`. A macro nobody gave a value to is one that is only ever
250            // tested for, and giving it an empty body would break `#if FOO`.
251            None => d.flag(define),
252        }
253    }
254    for name in &opts.undefines {
255        d.text.push_str("#undef ");
256        d.text.push_str(name);
257        d.text.push('\n');
258    }
259    d.text
260}
261
262/// Who the compiler says it is.
263fn identity(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
264    d.flag("__rucc__");
265    d.set("__rucc_version__", "\"0.1.0\"");
266    d.set("__rucc_major__", "0");
267    d.set("__rucc_minor__", "1");
268    d.set("__rucc_patchlevel__", "0");
269    // The promise from section 4.5. Everything in the matrix hangs off this line.
270    d.set("__GNUC__", &opts.gnuc.major.to_string());
271    d.set("__GNUC_MINOR__", &opts.gnuc.minor.to_string());
272    d.set("__GNUC_PATCHLEVEL__", &opts.gnuc.patch.to_string());
273    d.set("__VERSION__", "\"rucc 0.1.0\"");
274    // Not `__clang__`, deliberately. Section 4.5 says so, and a header that takes the Clang
275    // path expects Clang's extension surface rather than GCC's.
276    //
277    // Which of the two readings of `inline` is in force, which a header reads to decide how to
278    // write its own inline definitions: glibc's `__extern_inline` is `extern __inline` under the
279    // one and adds `__attribute__ ((__gnu_inline__))` under the other. C99 changed the meaning of
280    // the keyword and gcc follows the dialect, so the C89 ones keep GNU's reading and every
281    // dialect after them takes C's until `-fgnu89-inline` says otherwise.
282    let gnu_inline = opts.gnu89_inline || opts.std == Std::C89;
283    d.flag_if(gnu_inline, "__GNUC_GNU_INLINE__");
284    d.flag_if(!gnu_inline, "__GNUC_STDC_INLINE__");
285    // The charsets a literal is converted to. Both are fixed here rather than settable, since
286    // there is no `-fexec-charset` to set them with, and both are what gcc answers with none.
287    // The wide one follows `wchar_t`, which is sixteen bits on Windows and thirty two
288    // everywhere else, so it is the one target fact in this function.
289    d.set("__GNUC_EXECUTION_CHARSET_NAME", "\"UTF-8\"");
290    let wide = if target.wchar_width == 16 { "\"UTF-16LE\"" } else { "\"UTF-32LE\"" };
291    d.set("__GNUC_WIDE_EXECUTION_CHARSET_NAME", wide);
292    // The C++ ABI this would be if it compiled C++, which gcc defines in C as well. It is not
293    // a claim about this compiler so much as a number headers read: libstdc++ is not the only
294    // thing that tests it, and a C header shared with a C++ one reaches it through `extern
295    // "C"` guards. The value is gcc 16's.
296    d.set("__GXX_ABI_VERSION", "1021");
297}
298
299/// What the dialect flags say.
300fn dialect(d: &mut Defs, opts: &Predef) {
301    d.flag("__STDC__");
302    d.set_if(opts.hosted, "__STDC_HOSTED__", "1");
303    d.set_if(!opts.hosted, "__STDC_HOSTED__", "0");
304    if let Some(version) = opts.std.stdc_version() {
305        d.set("__STDC_VERSION__", version);
306    }
307    // Defined exactly when the extensions are off, which is the whole difference between
308    // `-std=c23` and `-std=gnu23` as far as the preprocessor is concerned.
309    d.flag_if(!opts.gnu_extensions, "__STRICT_ANSI__");
310    d.flag("__STDC_UTF_16__");
311    d.flag("__STDC_UTF_32__");
312    d.flag("__STDC_IEC_559__");
313    d.flag("__STDC_IEC_559_COMPLEX__");
314    // TS 18661-1's date, in every dialect, which is gcc 16's answer rather than the standard's.
315    // C23 folded that document into Annex F and gave the macro a date of its own, so 202311L is
316    // the value C23 asks for, and writing it is what a reading of the standard alone produces.
317    // It also breaks every translation unit that reaches glibc. `<stdc-predef.h>` is included
318    // ahead of the first line of the file and defines this name as 201404L whenever
319    // `__GCC_IEC_559` is positive, which it is here, so a different value is a redefinition with
320    // a different body and that is a diagnostic on a line the program never wrote. The cost is
321    // not only noise: sqlite's configure runs its feature tests through autosetup's `cctest
322    // -nooutput 1`, which reads any output at all as a failed test, and the readline completion
323    // test failed for no other reason than this warning.
324    d.set("__STDC_IEC_60559_BFP__", "201404L");
325    // The same date for the complex half, which is the other name `<stdc-predef.h>` writes and
326    // which was missing here. Withholding it looked like the careful answer and was not one, for
327    // two reasons. `__STDC_NO_COMPLEX__` is defined, so there is no complex arithmetic for the
328    // claim to be about and a program that reads one of these has already been told there is
329    // none. And the library makes the claim anyway: the `#else` in `<stdc-predef.h>` is reached
330    // by a compiler that says nothing about its intent, and it presumes an older compiler that
331    // meant yes. Saying nothing therefore does not withhold anything, it only makes the value
332    // arrive from somewhere else.
333    d.set("__STDC_IEC_60559_COMPLEX__", "201404L");
334    d.set("__STDC_ISO_10646__", "201706L");
335    // The type behind `char8_t`, which C23 added and no dialect before it has. It sits here
336    // rather than next to `__CHAR16_TYPE__` and `__CHAR32_TYPE__` because those two are the
337    // same in every dialect and this one is not, which is the whole reason a header can test
338    // for it: gcc's own `stdatomic.h` writes `atomic_char8_t` under `#ifdef __CHAR8_TYPE__`
339    // and gets it in C23 and not in C17.
340    d.set_if(opts.std == Std::C23, "__CHAR8_TYPE__", "unsigned char");
341    // C11 made these conditional features, and a header that sees `__STDC_VERSION__` at
342    // 201112 with no `__STDC_NO_ATOMICS__` next to it will use `_Atomic`. Each one here is a
343    // claim not to have something, so each one is only correct while it stays true: atomics
344    // because there is no `stdatomic.h` to include, threads because there is no `threads.h`,
345    // and complex because the arithmetic is not lowered.
346    //
347    // Variable length arrays are not on this list, because they work. Claiming otherwise is
348    // not a harmless overstatement of caution: glibc's `regex.h` writes the bound of
349    // `regexec`'s match array as `_REGEX_NELTS (__nmatch)`, which is the parameter when the
350    // dialect has them and nothing at all when a compiler says it does not, so the claim
351    // silently changes a declaration in a header rather than turning something off.
352    if opts.std.has_c11() {
353        d.flag("__STDC_NO_ATOMICS__");
354        d.flag("__STDC_NO_THREADS__");
355        d.flag("__STDC_NO_COMPLEX__");
356    }
357    // What `__has_embed` answers with. They are defined in every dialect and not only in C23,
358    // because the operator is answerable in every dialect and a header that writes
359    // `#if __has_embed(...) == __STDC_EMBED_FOUND__` under `-std=gnu17` would otherwise be
360    // comparing against zero and taking the not found branch on a resource that is there.
361    d.set("__STDC_EMBED_NOT_FOUND__", "0");
362    d.set("__STDC_EMBED_FOUND__", "1");
363    d.set("__STDC_EMBED_EMPTY__", "2");
364}
365
366/// The memory orders and the lock free answers.
367///
368/// These are here whether or not `_Atomic` is, and `__STDC_NO_ATOMICS__` does not turn them
369/// off, because they are the numbering the `__atomic` builtins take rather than a promise
370/// about the language. musl's `stdatomic.h` writes `memory_order_relaxed = __ATOMIC_RELAXED`
371/// with no test around it at all, so a compiler without them prints an enumerator whose value
372/// is an identifier.
373///
374/// Two means always lock free, and every integer type gets a two on all three targets, which
375/// are all sixty four bit machines. `long long` is the one that would change on a thirty two
376/// bit target, where a double word load is an instruction the machine may or may not have.
377fn atomics(d: &mut Defs, target: &TargetInfo) {
378    d.set("__ATOMIC_RELAXED", "0");
379    d.set("__ATOMIC_CONSUME", "1");
380    d.set("__ATOMIC_ACQUIRE", "2");
381    d.set("__ATOMIC_RELEASE", "3");
382    d.set("__ATOMIC_ACQ_REL", "4");
383    d.set("__ATOMIC_SEQ_CST", "5");
384    // The gate is the machine word rather than `long`, because Windows has a thirty two bit
385    // `long` on a sixty four bit machine and its `long long` is still one instruction.
386    let llong = if target.pointer_width == 64 { "2" } else { "1" };
387    for name in [
388        "BOOL", "CHAR", "CHAR8_T", "CHAR16_T", "CHAR32_T", "WCHAR_T", "SHORT", "INT", "LONG",
389        "POINTER",
390    ] {
391        d.set(&format!("__GCC_ATOMIC_{name}_LOCK_FREE"), "2");
392    }
393    // The one that is not always two: a target whose word is thirty two bits wide can only
394    // promise `long long` is lock free if it has a double word instruction, and the honest
395    // answer there is sometimes rather than always.
396    d.set("__GCC_ATOMIC_LLONG_LOCK_FREE", llong);
397    d.set("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
398    // What `__sync_bool_compare_and_swap` works on, one macro per width in bytes. Every target
399    // here has the instruction at all four, and glibc reads these rather than the `__atomic_*`
400    // set because they are the older question and the answer is the same one.
401    for width in [1, 2, 4, 8] {
402        d.flag(&format!("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_{width}"));
403    }
404    // The two flag bits an x86 memory order can carry, for the hardware lock elision prefixes.
405    // They are numbers a program passes back to a builtin rather than a claim that the prefix
406    // is emitted, and a program that computes one on a machine where the macro is missing gets
407    // a preprocessor error rather than a slower atomic.
408    if target.tuple.arch() == tuple::Arch::X86_64 {
409        d.set("__ATOMIC_HLE_ACQUIRE", "65536");
410        d.set("__ATOMIC_HLE_RELEASE", "131072");
411    }
412}
413
414/// What the optimizer level says.
415fn optimization(d: &mut Defs, opts: &Predef) {
416    d.flag_if(opts.opt_level.runs_optimizer(), "__OPTIMIZE__");
417    d.flag_if(opts.opt_level.is_size(), "__OPTIMIZE_SIZE__");
418    // glibc's headers test this before deciding whether to define a function as an inline
419    // wrapper, so getting it wrong changes what a program links against.
420    d.flag_if(!opts.opt_level.runs_optimizer(), "__NO_INLINE__");
421    // Zero, and zero until there is a `-ffast-math` to make it one. glibc's `math.h` reads it
422    // to decide whether to declare the `__*_finite` aliases, so it has to be defined rather
423    // than merely not claimed: a header testing `#if __FINITE_MATH_ONLY__ > 0` on a compiler
424    // that leaves it undefined takes the same branch, but one writing `#if
425    // !__FINITE_MATH_ONLY__` is a different question and gcc gives it an answer.
426    d.set("__FINITE_MATH_ONLY__", "0");
427}
428
429/// The architecture, the operating system and the object format.
430fn platform(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
431    // The macros a target with no backend predefines are not written down here. They are a
432    // header's whole view of the machine, a wrong one is a header taking a branch written for
433    // another processor, and there is nothing cheap that would catch it. The driver takes a three
434    // field triple, so a target this cannot spell is one nobody can ask for yet rather than a
435    // hole in what it answers.
436    let Some(triple) = Triple::from_tuple(target.tuple) else {
437        return;
438    };
439    match triple.arch {
440        Arch::X86_64 => {
441            d.flag("__x86_64__");
442            d.flag("__x86_64");
443            d.flag("__amd64__");
444            d.flag("__amd64");
445            d.flag("__SSE__");
446            d.flag("__SSE2__");
447            d.flag("__MMX__");
448            d.flag("__SSE_MATH__");
449            d.flag("__SSE2_MATH__");
450            d.flag("__k8");
451            d.flag("__k8__");
452            // FXSAVE and FXRSTOR, which every x86-64 has, and the small code model, which is
453            // the default and the only one a program gets without being told otherwise.
454            d.flag("__FXSR__");
455            d.flag("__code_model_small__");
456            // The MMX registers are not used on x86-64: the sixty four bit operations go
457            // through SSE instead. gcc's own `xmmintrin.h` reads this to decide how to write
458            // `_mm_maskmove_si64`, so a compiler that leaves it undefined is handed a
459            // different function body than gcc is, which is what the header sweep found.
460            d.flag("__MMX_WITH_SSE__");
461        }
462        Arch::Aarch64 => {
463            d.flag("__aarch64__");
464            d.flag("__AARCH64EL__");
465            d.set("__ARM_ARCH", "8");
466            d.set("__ARM_ARCH_PROFILE", "'A'");
467            d.set("__ARM_64BIT_STATE", "1");
468            d.set("__ARM_ALIGN_MAX_PWR", "28");
469            d.set("__ARM_FP", "0xe");
470            d.set("__ARM_NEON", "1");
471            d.set("__ARM_FEATURE_UNALIGNED", "1");
472            d.set("__ARM_PCS_AAPCS64", "1");
473        }
474        Arch::Riscv64 => {
475            d.flag("__riscv");
476            d.set("__riscv_xlen", "64");
477            d.set("__riscv_flen", "64");
478            d.flag("__riscv_float_abi_double");
479            d.flag("__riscv_muldiv");
480            d.flag("__riscv_atomic");
481            d.flag("__riscv_compressed");
482            d.set("__riscv_cmodel_medlow", "1");
483        }
484    }
485    match triple.os {
486        Os::Linux => {
487            d.flag("__linux__");
488            d.flag("__linux");
489            d.flag("__unix__");
490            d.flag("__unix");
491            d.flag("__gnu_linux__");
492            d.flag("__ELF__");
493            // The unarmoured spellings are not reserved identifiers, so a strict mode may not
494            // define them. Autoconf still tests for `linux`, which is why they exist at all.
495            if opts.gnu_extensions {
496                d.flag("linux");
497                d.flag("unix");
498            }
499        }
500        Os::Darwin => {
501            d.flag("__APPLE__");
502            d.flag("__MACH__");
503            d.flag("__unix__");
504            d.flag("__unix");
505            d.set("__APPLE_CC__", "6000");
506            d.set("__DYNAMIC__", "1");
507            if triple.arch == Arch::Aarch64 {
508                // Apple's own spelling of the architecture, which its headers use rather than
509                // __aarch64__. sys/cdefs.h tests for it by name and reaches an #error called
510                // "Unsupported architecture" without it, so every system header on this
511                // platform fails on the first include until these two are here.
512                d.flag("__arm64__");
513                d.flag("__arm64");
514            }
515            if opts.gnu_extensions {
516                d.flag("unix");
517            }
518        }
519        Os::Windows => {
520            d.flag("_WIN32");
521            d.flag("__WIN32__");
522            d.flag("_WIN64");
523            d.flag("__WIN64__");
524            d.flag("__MINGW32__");
525            windows_spellings(d, opts);
526        }
527        Os::None => {
528            // Freestanding. `__ELF__` still holds, because the object format is a property of
529            // the target rather than of having an operating system under it.
530            d.flag("__ELF__");
531        }
532    }
533    match triple.env {
534        Env::Musl => d.flag("__musl__"),
535        Env::Gnu | Env::None | Env::Msvc => {}
536    }
537    // The version of the libc's headers, and only when they are the tree we bundle. One tree serves
538    // every glibc release with the differences written as `#if __GLIBC_MINOR__ >= n` inside the
539    // files, so the release is the part of it the target supplies and the compiler is what supplies
540    // it. Zig patches the same macro into the same tree the same way, which is where the spelling
541    // comes from rather than from a scheme of ours: `__GLIBC_PREREQ` reads it and so does every
542    // autoconf probe ever written.
543    //
544    // The condition is the whole of it and it is not here. A host glibc defines this macro in its
545    // own `features.h` and so does a tree the user named, and a second definition with a different
546    // value is a warning on every compilation, so the driver decides and this writes down what it
547    // decided.
548    if let Some(minor) = opts.glibc_minor {
549        d.set("__GLIBC_MINOR__", &minor.to_string());
550    }
551    // LP64 is the model everywhere except Windows, and a great deal of code tests for it
552    // rather than testing pointer and long widths separately.
553    if target.long_width == 64 && target.pointer_width == 64 {
554        d.flag("__LP64__");
555        d.flag("_LP64");
556    }
557    // What the assembler prepends to a C name to get the symbol. Mach-O keeps the leading
558    // underscore that every a.out toolchain had and ELF dropped it. It has to be defined even
559    // where it is empty, because of how it is used: glibc writes `__asm__ (__ASMNAME (name))`
560    // and that stringifies `__USER_LABEL_PREFIX__`, so a compiler that leaves it undefined
561    // does not get an error, it gets the name of the macro as the string and renames the
562    // function.
563    d.set("__USER_LABEL_PREFIX__", if triple.os == Os::Darwin { "_" } else { "" });
564    // Its counterpart, what the assembler puts in front of a register name. Empty on every
565    // target here, since all three assemble in a syntax that does not mark registers, and
566    // defined anyway for the same reason as the line above: it is used inside a stringize.
567    d.set("__REGISTER_PREFIX__", "");
568
569    // Position independent code is the default on the ELF targets and on Apple's, which is
570    // what a distribution build expects. The value 2 is GCC's for `-fPIC` rather than `-fpic`.
571    //
572    // Both are defined whichever link the output is for, because `__PIC__` says there are no
573    // absolute addresses in the text and that is true either way. What says which link it is is
574    // `__PIE__`, and a program reads it to find out whether a name it exports is one something
575    // else may replace. gcc defines it under `-fPIE` and under the default on a distribution
576    // where the default is an executable, which is the default here too.
577    if !matches!(triple.os, Os::Windows) {
578        d.set("__PIC__", "2");
579        d.set("__pic__", "2");
580        if opts.pic == Pic::Executable {
581            d.set("__PIE__", "2");
582            d.set("__pie__", "2");
583        }
584    }
585}
586
587/// The five spellings a Windows header writes a calling convention and an attribute in.
588///
589/// `int __cdecl f(void);` is the second declaration in mingw-w64's `stdio.h` and it stops a parser
590/// that has never heard of `__cdecl`, which reads it as the name being declared and then finds a
591/// second one. None of the five is a keyword, though: gcc defines every one of them as a macro over
592/// the GNU spelling of the same thing, which is why they are keywords on Windows and nowhere else
593/// without anything in its lexer being told what the target is. `-dM -E` on a mingw-w64 gcc prints
594/// exactly the lines below.
595///
596/// `__declspec(x)` being the GNU spelling of its argument is the part worth saying out loud, since
597/// it means `__declspec(dllimport)` and `__attribute__((dllimport))` cannot come to mean different
598/// things: there is one attribute and two ways of writing it, and everything that reads attributes
599/// reads both.
600///
601/// On x86-64 all four conventions name the one convention the target has, so the attributes go
602/// where every attribute nothing implements goes, which is left on the declaration. On i386 they
603/// differ over who pops the arguments and the choice is written into the symbol name, which is
604/// document 06.5 and is that target's work when there is one.
605fn windows_spellings(d: &mut Defs, opts: &Predef) {
606    for name in ["cdecl", "stdcall", "fastcall", "thiscall"] {
607        d.set(&format!("__{name}"), &format!("__attribute__((__{name}__))"));
608        // The single underscore spellings are not in the reserved namespace, so an implementation
609        // may not take them in a strict ISO mode and gcc does not.
610        if opts.gnu_extensions {
611            d.set(&format!("_{name}"), &format!("__attribute__((__{name}__))"));
612        }
613    }
614    d.set("__declspec(x)", "__attribute__((x))");
615}
616
617/// `__CHAR_BIT__`, the `__SIZEOF_*__` family and the alignment macros.
618fn sizes(d: &mut Defs, target: &TargetInfo) {
619    let pointer = target.pointer_width / 8;
620    // The two hardware interference sizes, which say how far apart two objects have to be for
621    // a write to one not to invalidate the other's cache line, and how close together two have
622    // to be to share one. A cache line is sixty four bytes on every target here, so the two
623    // answers are the same number and gcc gives the same number as well.
624    d.set("__GCC_CONSTRUCTIVE_SIZE", "64");
625    d.set("__GCC_DESTRUCTIVE_SIZE", "64");
626    let long = target.long_width / 8;
627    let long_double = target.long_double_width / 8;
628    d.set("__CHAR_BIT__", "8");
629    d.set("__SIZEOF_SHORT__", "2");
630    d.set("__SIZEOF_INT__", "4");
631    d.set("__SIZEOF_LONG__", &long.to_string());
632    d.set("__SIZEOF_LONG_LONG__", "8");
633    d.set("__SIZEOF_INT128__", "16");
634    d.set("__SIZEOF_FLOAT__", "4");
635    d.set("__SIZEOF_DOUBLE__", "8");
636    d.set("__SIZEOF_LONG_DOUBLE__", &long_double.to_string());
637    d.set("__SIZEOF_POINTER__", &pointer.to_string());
638    d.set("__SIZEOF_SIZE_T__", &pointer.to_string());
639    d.set("__SIZEOF_PTRDIFF_T__", &pointer.to_string());
640    d.set("__SIZEOF_WCHAR_T__", &wchar(target).size.to_string());
641    d.set("__SIZEOF_WINT_T__", "4");
642    d.set("__BIGGEST_ALIGNMENT__", "16");
643    // The `__BYTE_ORDER__` family, which the kernel and every serialisation library read.
644    // The names of the orders are defined whichever one is in force, because code compares
645    // against both.
646    d.set("__ORDER_LITTLE_ENDIAN__", "1234");
647    d.set("__ORDER_BIG_ENDIAN__", "4321");
648    d.set("__ORDER_PDP_ENDIAN__", "3412");
649    let order =
650        if target.little_endian { "__ORDER_LITTLE_ENDIAN__" } else { "__ORDER_BIG_ENDIAN__" };
651    d.set("__BYTE_ORDER__", order);
652    d.set("__FLOAT_WORD_ORDER__", order);
653    d.flag_if(!target.char_is_signed, "__CHAR_UNSIGNED__");
654}
655
656/// How `wchar_t` is spelled on a target, and what it holds.
657struct Wchar {
658    /// The C type it is a name for.
659    spelling: &'static str,
660    /// Its width in bytes.
661    size: u32,
662    /// `__WCHAR_MAX__`.
663    max: &'static str,
664    /// `__WCHAR_MIN__`.
665    min: &'static str,
666}
667
668/// `wchar_t` is the type that divides the targets most and is written down least.
669///
670/// Windows makes it 16 bits so that a wide string is UTF-16. AArch64 Linux makes it unsigned,
671/// following the psABI's rule for plain `char`, while x86-64 Linux makes it signed. Code that
672/// compares a `wchar_t` against a negative value is correct on one and not on the other.
673///
674/// The width and the signedness come from the target description rather than from another match
675/// on the triple, because the lexer needs the same two facts to convert a wide literal and the
676/// two answers have to be the same one.
677fn wchar(target: &TargetInfo) -> Wchar {
678    match (target.wchar_width, target.wchar_is_signed) {
679        (16, false) => Wchar { spelling: "short unsigned int", size: 2, max: "0xffff", min: "0" },
680        (16, true) => Wchar { spelling: "short int", size: 2, max: "0x7fff", min: "(-32767 - 1)" },
681        (_, false) => Wchar { spelling: "unsigned int", size: 4, max: "0xffffffffU", min: "0U" },
682        (_, true) => {
683            Wchar { spelling: "int", size: 4, max: "0x7fffffff", min: "(-__WCHAR_MAX__ - 1)" }
684        }
685    }
686}
687
688/// How `wint_t` is spelled on a target, and what it holds.
689struct Wint {
690    /// The C type it is a name for.
691    spelling: &'static str,
692    /// `__WINT_MAX__`.
693    max: &'static str,
694    /// `__WINT_MIN__`.
695    min: &'static str,
696    /// `__WINT_WIDTH__`, which follows the spelling rather than `__SIZEOF_WINT_T__`.
697    width: u32,
698}
699
700/// `wint_t` does not follow `wchar_t`, and Darwin is where that shows.
701///
702/// Apple makes it a signed `int`, so that `WEOF` is negative the way `EOF` is, while Linux
703/// makes it `unsigned int` and gives `WEOF` the value `0xffffffff`. The SDK's `arm/_types.h`
704/// spells `__darwin_wint_t` as `__WINT_TYPE__` and nothing else, so getting this wrong changes
705/// the signedness of every wide character function's argument on that platform.
706fn wint(target: &TargetInfo) -> Wint {
707    match target.tuple.os() {
708        tuple::Os::Windows => {
709            Wint { spelling: "short unsigned int", max: "0xffff", min: "0", width: 16 }
710        }
711        os if os.is_darwin() => {
712            Wint { spelling: "int", max: "0x7fffffff", min: "(-__WINT_MAX__ - 1)", width: 32 }
713        }
714        _ => Wint { spelling: "unsigned int", max: "0xffffffffU", min: "0U", width: 32 },
715    }
716}
717
718/// The integer type names, their limits, and the exact width family.
719fn integers(d: &mut Defs, target: &TargetInfo) {
720    // The one fact everything below turns on: which type is 64 bits wide. On LP64 it is
721    // `long`, and on Windows LLP64 it is `long long`, and every `size_t`, `intmax_t` and
722    // `int64_t` spelling follows from that.
723    let lp64 = target.long_width == 64;
724    let wide = if lp64 { "long int" } else { "long long int" };
725    let wide_unsigned = if lp64 { "long unsigned int" } else { "long long unsigned int" };
726    let wide_suffix = if lp64 { "L" } else { "LL" };
727    let wide_max = format!("0x7fffffffffffffff{wide_suffix}");
728    let wide_umax = format!("0xffffffffffffffffU{wide_suffix}");
729
730    d.set("__SCHAR_MAX__", "0x7f");
731    d.set("__SHRT_MAX__", "0x7fff");
732    d.set("__INT_MAX__", "0x7fffffff");
733    d.set("__LONG_MAX__", if lp64 { "0x7fffffffffffffffL" } else { "0x7fffffffL" });
734    d.set("__LONG_LONG_MAX__", "0x7fffffffffffffffLL");
735    d.set("__INTMAX_MAX__", &wide_max);
736    d.set("__UINTMAX_MAX__", &wide_umax);
737    d.set("__SIZE_MAX__", &wide_umax);
738    d.set("__PTRDIFF_MAX__", &wide_max);
739    d.set("__INTPTR_MAX__", &wide_max);
740    d.set("__UINTPTR_MAX__", &wide_umax);
741    d.set("__SIG_ATOMIC_MAX__", "0x7fffffff");
742    d.set("__SIG_ATOMIC_MIN__", "(-__SIG_ATOMIC_MAX__ - 1)");
743    // The widest `_BitInt` this compiler builds, which is narrower than gcc 16's sixty five
744    // thousand five hundred and thirty five because a folded constant here is a hundred and
745    // twenty eight bits wide. A program that reads this macro to decide what to write gets an
746    // answer it can rely on, which is the point of saying a number smaller than gcc's rather
747    // than saying gcc's and refusing what it asked for. `MAX_BIT_INT_WIDTH` in `rucc-sema` is
748    // the same number and has to be changed with it.
749    d.set("__BITINT_MAXWIDTH__", "128");
750
751    let wchar = wchar(target);
752    d.set("__WCHAR_TYPE__", wchar.spelling);
753    d.set("__WCHAR_MAX__", wchar.max);
754    d.set("__WCHAR_MIN__", wchar.min);
755    let wint = wint(target);
756    d.set("__WINT_TYPE__", wint.spelling);
757    d.set("__WINT_MAX__", wint.max);
758    d.set("__WINT_MIN__", wint.min);
759    d.set("__SIZE_TYPE__", wide_unsigned);
760    d.set("__PTRDIFF_TYPE__", wide);
761    d.set("__INTMAX_TYPE__", wide);
762    d.set("__UINTMAX_TYPE__", wide_unsigned);
763    d.set("__INTPTR_TYPE__", wide);
764    d.set("__UINTPTR_TYPE__", wide_unsigned);
765    d.set("__SIG_ATOMIC_TYPE__", "int");
766    d.set("__CHAR16_TYPE__", "short unsigned int");
767    d.set("__CHAR32_TYPE__", "unsigned int");
768    d.set("__INTMAX_C(c)", &format!("c ## {wide_suffix}"));
769    d.set("__UINTMAX_C(c)", &format!("c ## U{wide_suffix}"));
770
771    // The exact width family, which is what a freestanding `stdint.h` is written out of.
772    exact(d, 8, "signed char", "unsigned char", "0x7f", "0xff", "");
773    exact(d, 16, "short int", "short unsigned int", "0x7fff", "0xffff", "");
774    // No suffix. An `int` needs none, and the `U` on the unsigned side is added by `exact`
775    // rather than being part of the width.
776    exact(d, 32, "int", "unsigned int", "0x7fffffff", "0xffffffffU", "");
777    exact(d, 64, wide, wide_unsigned, &wide_max, &wide_umax, wide_suffix);
778
779    // The fast types. GCC makes the 16 and 32 bit ones `long` on x86-64 glibc and `int`
780    // everywhere else, and a header that computes a printf format from the type name notices
781    // the difference.
782    //
783    // musl is the reason this is not simply a question of the architecture. musl defines
784    // `int_fast16_t` and `int_fast32_t` as `int32_t` on every target it supports, GCC built
785    // for a musl target agrees with it, and GCC built for glibc on the same processor does
786    // not. The place it shows is `stdatomic.h`, which GCC ships and writes directly out of
787    // these macros: `typedef _Atomic __INT_FAST16_TYPE__ atomic_int_fast16_t;`. Get this wrong
788    // and every atomic fast type in the program is the wrong width.
789    let fast_is_wide = target.tuple.arch() == tuple::Arch::X86_64
790        && lp64
791        && target.tuple.env() != tuple::Env::Musl;
792    let fast_middle = if fast_is_wide { wide } else { "int" };
793    d.set("__INT_FAST8_TYPE__", "signed char");
794    d.set("__UINT_FAST8_TYPE__", "unsigned char");
795    d.set("__INT_FAST8_MAX__", "0x7f");
796    d.set("__UINT_FAST8_MAX__", "0xff");
797    for width in [16, 32] {
798        let unsigned = if fast_middle == "int" { "unsigned int" } else { wide_unsigned };
799        let max = if fast_middle == "int" { "0x7fffffff" } else { wide_max.as_str() };
800        let umax = if fast_middle == "int" { "0xffffffffU" } else { wide_umax.as_str() };
801        d.set(&format!("__INT_FAST{width}_TYPE__"), fast_middle);
802        d.set(&format!("__UINT_FAST{width}_TYPE__"), unsigned);
803        d.set(&format!("__INT_FAST{width}_MAX__"), max);
804        d.set(&format!("__UINT_FAST{width}_MAX__"), umax);
805    }
806    d.set("__INT_FAST64_TYPE__", wide);
807    d.set("__UINT_FAST64_TYPE__", wide_unsigned);
808    d.set("__INT_FAST64_MAX__", &wide_max);
809    d.set("__UINT_FAST64_MAX__", &wide_umax);
810
811    widths(d, target, &wchar, &wint, if fast_is_wide { 64 } else { 32 });
812}
813
814/// The widths, which C23's `limits.h` and `stdint.h` are written out of.
815///
816/// Twenty macros and not a few more: there is no `__INT8_WIDTH__`, because the width of an
817/// exact width type is in its name and gcc does not define one, and there is no unsigned member
818/// of any of these pairs, because a signed type and its unsigned counterpart have the same
819/// width and `UINTMAX_WIDTH` is written `__INTMAX_WIDTH__` in every header that needs it.
820///
821/// Each of these says how many value bits and sign bits the type has, which is not the same as
822/// how many bits it occupies. They agree for every type on every target here, and the day one of
823/// them does not, this is the family that has to say the smaller number.
824fn widths(d: &mut Defs, target: &TargetInfo, wchar: &Wchar, wint: &Wint, fast_middle: u32) {
825    let pointer = target.pointer_width;
826    d.set("__SCHAR_WIDTH__", "8");
827    d.set("__SHRT_WIDTH__", "16");
828    d.set("__INT_WIDTH__", "32");
829    d.set("__LONG_WIDTH__", &target.long_width.to_string());
830    d.set("__LONG_LONG_WIDTH__", "64");
831    d.set("__INTMAX_WIDTH__", "64");
832    d.set("__INTPTR_WIDTH__", &pointer.to_string());
833    d.set("__PTRDIFF_WIDTH__", &pointer.to_string());
834    d.set("__SIZE_WIDTH__", &pointer.to_string());
835    d.set("__SIG_ATOMIC_WIDTH__", "32");
836    d.set("__WCHAR_WIDTH__", &(wchar.size * 8).to_string());
837    d.set("__WINT_WIDTH__", &wint.width.to_string());
838    for width in [8, 16, 32, 64] {
839        d.set(&format!("__INT_LEAST{width}_WIDTH__"), &width.to_string());
840    }
841    d.set("__INT_FAST8_WIDTH__", "8");
842    d.set("__INT_FAST16_WIDTH__", &fast_middle.to_string());
843    d.set("__INT_FAST32_WIDTH__", &fast_middle.to_string());
844    d.set("__INT_FAST64_WIDTH__", "64");
845}
846
847/// One width of the exact and least families, which are the same types.
848fn exact(
849    d: &mut Defs,
850    width: u32,
851    signed: &str,
852    unsigned: &str,
853    max: &str,
854    umax: &str,
855    // The suffix the width needs and nothing more, so `""`, `"L"` or `"LL"`. The `U` that
856    // makes a constant unsigned is added below and is not part of this, because a caller that
857    // wrote it here would produce `UU` on the unsigned macro and a stray `U` on the signed one.
858    width_suffix: &str,
859) {
860    d.set(&format!("__INT{width}_TYPE__"), signed);
861    d.set(&format!("__UINT{width}_TYPE__"), unsigned);
862    d.set(&format!("__INT{width}_MAX__"), max);
863    d.set(&format!("__UINT{width}_MAX__"), umax);
864    d.set(&format!("__INT_LEAST{width}_TYPE__"), signed);
865    d.set(&format!("__UINT_LEAST{width}_TYPE__"), unsigned);
866    d.set(&format!("__INT_LEAST{width}_MAX__"), max);
867    d.set(&format!("__UINT_LEAST{width}_MAX__"), umax);
868    // The constant makers. `__INT8_C(1)` is `1` and not `1 ## `, because a paste with nothing
869    // on the right is not a token the expander should have to think about.
870    //
871    // The `U` goes on only where the type is still unsigned after promotion. `uint8_t` and
872    // `uint16_t` are narrower than `int`, so an integer promotion turns them into a signed
873    // `int` and `UINT8_C(1)` has that type in gcc and in the standard's own words. Writing
874    // `1U` there is not a harmless extra: `UINT8_C(1) - 2` comes out as four billion odd
875    // instead of minus one, and a `_Generic` on it picks the unsigned arm. Every target this
876    // compiler has makes `int` thirty two bits, which is what makes the width enough to decide.
877    let unsigned_after_promotion = width >= 32;
878    let u = if unsigned_after_promotion { "U" } else { "" };
879    if width_suffix.is_empty() && u.is_empty() {
880        d.set(&format!("__INT{width}_C(c)"), "c");
881        d.set(&format!("__UINT{width}_C(c)"), "c");
882    } else if width_suffix.is_empty() {
883        d.set(&format!("__INT{width}_C(c)"), "c");
884        d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}"));
885    } else {
886        d.set(&format!("__INT{width}_C(c)"), &format!("c ## {width_suffix}"));
887        d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}{width_suffix}"));
888    }
889}
890
891/// What a header needs to know about one floating format, as the text the macros expand to.
892///
893/// The four values are written to the digit gcc writes them to rather than rounded to something
894/// tidier, because a header carrying its own copy of a limit compares the two spellings and a
895/// difference in the last place is a difference.
896struct Characteristics {
897    mant_dig: &'static str,
898    dig: &'static str,
899    min_exp: &'static str,
900    min_10_exp: &'static str,
901    max_exp: &'static str,
902    max_10_exp: &'static str,
903    decimal_dig: &'static str,
904    max: &'static str,
905    /// The largest value with a full significand, which is `max` for every format whose values
906    /// all have one and is smaller for the double-double, whose largest values do not.
907    ///
908    /// A double-double's high half can be as large as a `double` gets while its low half is
909    /// nowhere near, and the sum is then a number above anything the format can write with a
910    /// hundred and six significand bits behind it. So `LDBL_MAX` on PowerPC is `DBL_MAX` and
911    /// `LDBL_NORM_MAX` is a bit under half of it, and a program that reaches for the largest
912    /// value it can compute with wants the second.
913    norm_max: &'static str,
914    min: &'static str,
915    epsilon: &'static str,
916    denorm_min: &'static str,
917    /// Whether the format is one IEC 60559 describes, which every one of them is but the brain
918    /// float, whose significand is a `float`'s with sixteen bits cut off the end of it, and the
919    /// double-double, which is not a binary floating point format in IEC 60559's sense at all.
920    is_iec_60559: &'static str,
921}
922
923/// IEEE binary16, which is `_Float16`.
924const HALF: Characteristics = Characteristics {
925    mant_dig: "11",
926    dig: "3",
927    min_exp: "(-13)",
928    min_10_exp: "(-4)",
929    max_exp: "16",
930    max_10_exp: "4",
931    decimal_dig: "5",
932    max: "6.55040000000000000000000000000000000e+4",
933    norm_max: "6.55040000000000000000000000000000000e+4",
934    min: "6.10351562500000000000000000000000000e-5",
935    epsilon: "9.76562500000000000000000000000000000e-4",
936    denorm_min: "5.96046447753906250000000000000000000e-8",
937    is_iec_60559: "1",
938};
939
940/// The brain float, which nothing here names yet and which every format table has a row for.
941const BFLOAT16: Characteristics = Characteristics {
942    mant_dig: "8",
943    dig: "2",
944    min_exp: "(-125)",
945    min_10_exp: "(-37)",
946    max_exp: "128",
947    max_10_exp: "38",
948    decimal_dig: "4",
949    max: "3.38953138925153547590470800371487867e+38",
950    norm_max: "3.38953138925153547590470800371487867e+38",
951    min: "1.17549435082228750796873653722224568e-38",
952    epsilon: "7.81250000000000000000000000000000000e-3",
953    denorm_min: "9.18354961579912115600575419704879436e-41",
954    is_iec_60559: "0",
955};
956
957/// IEEE binary32, which is `float` and `_Float32`.
958const SINGLE: Characteristics = Characteristics {
959    mant_dig: "24",
960    dig: "6",
961    min_exp: "(-125)",
962    min_10_exp: "(-37)",
963    max_exp: "128",
964    max_10_exp: "38",
965    decimal_dig: "9",
966    max: "3.40282346638528859811704183484516925e+38",
967    norm_max: "3.40282346638528859811704183484516925e+38",
968    min: "1.17549435082228750796873653722224568e-38",
969    epsilon: "1.19209289550781250000000000000000000e-7",
970    denorm_min: "1.40129846432481707092372958328991613e-45",
971    is_iec_60559: "1",
972};
973
974/// IEEE binary64, which is `double`, `_Float64`, `_Float32x` and `long double` on Apple and
975/// on Windows.
976const DOUBLE: Characteristics = Characteristics {
977    mant_dig: "53",
978    dig: "15",
979    min_exp: "(-1021)",
980    min_10_exp: "(-307)",
981    max_exp: "1024",
982    max_10_exp: "308",
983    decimal_dig: "17",
984    max: "1.79769313486231570814527423731704357e+308",
985    norm_max: "1.79769313486231570814527423731704357e+308",
986    min: "2.22507385850720138309023271733240406e-308",
987    epsilon: "2.22044604925031308084726333618164062e-16",
988    denorm_min: "4.94065645841246544176568792868221372e-324",
989    is_iec_60559: "1",
990};
991
992/// The x87 eighty bit format, which on x86-64 is both `long double` and `_Float64x`.
993const X87: Characteristics = Characteristics {
994    mant_dig: "64",
995    dig: "18",
996    min_exp: "(-16381)",
997    min_10_exp: "(-4931)",
998    max_exp: "16384",
999    max_10_exp: "4932",
1000    decimal_dig: "21",
1001    max: "1.18973149535723176502126385303097021e+4932",
1002    norm_max: "1.18973149535723176502126385303097021e+4932",
1003    min: "3.36210314311209350626267781732175260e-4932",
1004    epsilon: "1.08420217248550443400745280086994171e-19",
1005    denorm_min: "3.64519953188247460252840593361941982e-4951",
1006    is_iec_60559: "1",
1007};
1008
1009/// IEEE binary128, which is `_Float128`, `_Float64x` off x86 and `long double` on AArch64 and
1010/// RISC-V Linux.
1011const QUAD: Characteristics = Characteristics {
1012    mant_dig: "113",
1013    dig: "33",
1014    min_exp: "(-16381)",
1015    min_10_exp: "(-4931)",
1016    max_exp: "16384",
1017    max_10_exp: "4932",
1018    decimal_dig: "36",
1019    max: "1.18973149535723176508575932662800702e+4932",
1020    norm_max: "1.18973149535723176508575932662800702e+4932",
1021    min: "3.36210314311209350626267781732175260e-4932",
1022    epsilon: "1.92592994438723585305597794258492732e-34",
1023    denorm_min: "6.47517511943802511092443895822764655e-4966",
1024    is_iec_60559: "1",
1025};
1026
1027/// IBM double-double, which is `long double` on 64-bit PowerPC.
1028///
1029/// The row that does not follow from a precision and an exponent range, because the format has
1030/// neither. `MANT_DIG` is 106 and `DIG` is 31, which are the figures near the top of the
1031/// significand and not everywhere. `MAX` is a little above `DBL_MAX`, since the high half can be
1032/// `DBL_MAX` and the low half then adds to it, and `NORM_MAX` is about half of that, so this is
1033/// the one row where the two are different numbers. `EPSILON` is the same number as `DENORM_MIN`,
1034/// two to the minus one thousand and seventy four, because the smallest value that changes a
1035/// double-double near one is a subnormal in the low half rather than one unit in the last place
1036/// of anything. `MIN` is two to the minus nine hundred and sixty nine rather than `DBL_MIN`,
1037/// because below that the low half has no room left to be normal in.
1038///
1039/// Every value here is what the reference compiler prints for `powerpc64le-linux-gnu`, checked
1040/// rather than derived, on the same terms as the data layouts in `rucc-abi`. The format is one
1041/// where deriving them is how the four wrong numbers in those layouts happened.
1042const DOUBLE_DOUBLE: Characteristics = Characteristics {
1043    mant_dig: "106",
1044    dig: "31",
1045    min_exp: "(-968)",
1046    min_10_exp: "(-291)",
1047    max_exp: "1024",
1048    max_10_exp: "308",
1049    decimal_dig: "33",
1050    max: "1.79769313486231580793728971405301e+308",
1051    norm_max: "8.98846567431157953864652595394501e+307",
1052    min: "2.00416836000897277799610805135016e-292",
1053    epsilon: "4.94065645841246544176568792868221e-324",
1054    denorm_min: "4.94065645841246544176568792868221e-324",
1055    is_iec_60559: "0",
1056};
1057
1058/// The row of the table a format has, so that a type the target chooses the format of can look
1059/// its own limits up rather than have them written out again per architecture.
1060const fn characteristics(format: Format) -> &'static Characteristics {
1061    match format {
1062        Format::Half => &HALF,
1063        Format::BFloat16 => &BFLOAT16,
1064        Format::Single => &SINGLE,
1065        Format::Double => &DOUBLE,
1066        Format::X87Extended => &X87,
1067        Format::Quad => &QUAD,
1068        Format::DoubleDouble => &DOUBLE_DOUBLE,
1069    }
1070}
1071
1072/// The `float.h` characteristics.
1073///
1074/// Nine families of them, which is `float`, `double` and `long double` and the six C23 named
1075/// them after. Two of the nine have a format the target decides: `long double`, which is x87 on
1076/// x86-64 Linux, quad on AArch64 and RISC-V Linux and a `double` on Apple and on Windows, and
1077/// `_Float64x`, which is the widest format the processor has and so does not follow `long
1078/// double` down on the targets that shrink it.
1079///
1080/// Three more have a target that decides whether they are there at all. `_Float64x` is missing
1081/// on a machine with nothing wider than a `double`, and `_Float16` and `_Float128` are missing
1082/// wherever the machine has no such format, which is four of the seven rows for the half and one
1083/// of them for the quad.
1084///
1085/// `__FLT128X_*__` is deliberately missing. `_Float128x` is a type no target gcc supports has,
1086/// so gcc defines nothing for it and neither does this.
1087fn floats(d: &mut Defs, target: &TargetInfo) {
1088    d.set("__FLT_RADIX__", "2");
1089    // Real arithmetic follows IEC 60559 in every format on every target here, which is what the
1090    // value two says. The complex one beside it says the same about complex arithmetic, and gcc
1091    // gives both the value two on every target this compiler has. These two are read rather than
1092    // tested: glibc's `<stdc-predef.h>` asks what the compiler intended and writes the
1093    // `__STDC_IEC_559` family from the answer, and a compiler that says nothing is presumed to
1094    // have meant yes. So the choice is not between claiming and not claiming, it is between
1095    // saying so and having it said for us.
1096    d.set("__GCC_IEC_559", "2");
1097    d.set("__GCC_IEC_559_COMPLEX", "2");
1098    // Every operation is done in the type of its operands, which is what SSE2 and the AArch64
1099    // and RISC-V floating units all do. The other two names are the same answer asked under the
1100    // rules of C99 and of TS 18661-3, which are the same rules for a target with no excess
1101    // precision to have, and glibc's `<math.h>` reads the last of the three.
1102    d.set("__FLT_EVAL_METHOD__", "0");
1103    d.set("__FLT_EVAL_METHOD_C99__", "0");
1104    d.set("__FLT_EVAL_METHOD_TS_18661_3__", "0");
1105
1106    family(d, "FLT", &SINGLE, |value| format!("{value}F"));
1107    // gcc writes the `double` values as `long double` constants cast back down, which is exact
1108    // in every format `long double` has and is the one family whose values are not a suffix.
1109    family(d, "DBL", &DOUBLE, |value| format!("((double){value}L)"));
1110    family(d, "LDBL", characteristics(target.long_double_format), |value| format!("{value}L"));
1111
1112    // The two named types that are not on every machine, each written where the type is and left
1113    // out where it is not. A program reads `__FLT128_MANT_DIG__` to find out whether it may write
1114    // the type, which is what glibc's `<float.h>` and `<math.h>` do, so the macros and the type
1115    // have to agree or the header asks for something the compiler will refuse.
1116    if target.has_float16 {
1117        family(d, "FLT16", &HALF, |value| format!("{value}F16"));
1118    }
1119    family(d, "FLT32", &SINGLE, |value| format!("{value}F32"));
1120    family(d, "FLT64", &DOUBLE, |value| format!("{value}F64"));
1121    if target.has_float128 {
1122        family(d, "FLT128", &QUAD, |value| format!("{value}F128"));
1123    }
1124    family(d, "FLT32X", &DOUBLE, |value| format!("{value}F32x"));
1125    // Nothing at all on a target whose widest format is a `double`, which is what gcc does
1126    // there: `_Float64x` is not a type on that machine and the family that describes it is not a
1127    // set of macros with a smaller answer in them.
1128    if let Some(format) = target.float64x_format {
1129        family(d, "FLT64X", characteristics(format), |value| format!("{value}F64x"));
1130    }
1131
1132    // The number itself rather than the name of the other macro. The value is the same either
1133    // way, since `long double` is the widest format here, but the two are not the same thing to
1134    // read: `-dM` prints what the macro is, and a program that undefines `__LDBL_DECIMAL_DIG__`
1135    // takes this one with it. gcc writes the number.
1136    d.set("__DECIMAL_DIG__", characteristics(target.long_double_format).decimal_dig);
1137}
1138
1139/// One family of `float.h` macros, named `__{prefix}_*__`.
1140///
1141/// `write` turns a value into the constant its macro expands to, which is a suffix for every
1142/// family but `double`.
1143fn family(d: &mut Defs, prefix: &str, c: &Characteristics, write: impl Fn(&str) -> String) {
1144    d.set(&format!("__{prefix}_MANT_DIG__"), c.mant_dig);
1145    d.set(&format!("__{prefix}_DIG__"), c.dig);
1146    d.set(&format!("__{prefix}_MIN_EXP__"), c.min_exp);
1147    d.set(&format!("__{prefix}_MIN_10_EXP__"), c.min_10_exp);
1148    d.set(&format!("__{prefix}_MAX_EXP__"), c.max_exp);
1149    d.set(&format!("__{prefix}_MAX_10_EXP__"), c.max_10_exp);
1150    d.set(&format!("__{prefix}_DECIMAL_DIG__"), c.decimal_dig);
1151    d.set(&format!("__{prefix}_MAX__"), &write(c.max));
1152    d.set(&format!("__{prefix}_NORM_MAX__"), &write(c.norm_max));
1153    d.set(&format!("__{prefix}_MIN__"), &write(c.min));
1154    d.set(&format!("__{prefix}_EPSILON__"), &write(c.epsilon));
1155    d.set(&format!("__{prefix}_DENORM_MIN__"), &write(c.denorm_min));
1156    d.set(&format!("__{prefix}_IS_IEC_60559__"), c.is_iec_60559);
1157    d.set(&format!("__{prefix}_HAS_DENORM__"), "1");
1158    d.set(&format!("__{prefix}_HAS_INFINITY__"), "1");
1159    d.set(&format!("__{prefix}_HAS_QUIET_NAN__"), "1");
1160}
1161
1162#[cfg(test)]
1163mod tests {
1164    use rucc_target::Triple;
1165
1166    use super::*;
1167
1168    fn set_for(triple: &str) -> String {
1169        let triple: Triple = triple.parse().expect("a triple the compiler supports");
1170        built_in(&TargetInfo::new(triple), &Predef::new())
1171    }
1172
1173    /// The same, for a machine the three field triple cannot spell.
1174    fn set_for_tuple(tuple: &str) -> String {
1175        let target = TargetInfo::for_tuple(tuple.parse().expect("a row in the target table"));
1176        built_in(&target, &Predef::new())
1177    }
1178
1179    fn has(text: &str, line: &str) -> bool {
1180        text.lines().any(|l| l == line)
1181    }
1182
1183    #[test]
1184    fn the_set_is_driven_by_the_target_rather_than_by_the_host() {
1185        let x86 = set_for("x86_64-unknown-linux-gnu");
1186        let arm = set_for("aarch64-unknown-linux-gnu");
1187        assert!(has(&x86, "#define __x86_64__ 1"));
1188        assert!(!has(&x86, "#define __aarch64__ 1"));
1189        assert!(has(&arm, "#define __aarch64__ 1"));
1190        assert!(!has(&arm, "#define __x86_64__ 1"));
1191        assert!(has(&x86, "#define __linux__ 1") && has(&arm, "#define __linux__ 1"));
1192    }
1193
1194    #[test]
1195    fn windows_is_the_target_that_makes_long_thirty_two_bits() {
1196        let windows = set_for("x86_64-pc-windows-msvc");
1197        let linux = set_for("x86_64-unknown-linux-gnu");
1198        assert!(has(&windows, "#define __SIZEOF_LONG__ 4"));
1199        assert!(has(&windows, "#define __SIZE_TYPE__ long long unsigned int"));
1200        assert!(has(&windows, "#define __INT64_TYPE__ long long int"));
1201        assert!(!has(&windows, "#define __LP64__ 1"));
1202        assert!(has(&linux, "#define __SIZEOF_LONG__ 8"));
1203        assert!(has(&linux, "#define __SIZE_TYPE__ long unsigned int"));
1204        assert!(has(&linux, "#define __INT64_TYPE__ long int"));
1205        assert!(has(&linux, "#define __LP64__ 1"));
1206    }
1207
1208    #[test]
1209    fn windows_spells_a_calling_convention_and_an_attribute_as_macros() {
1210        // The second declaration in mingw-w64's stdio.h is `int __cdecl __mingw_sscanf(...)`, so
1211        // a Windows target where these are missing reads no header at all.
1212        let windows = set_for("x86_64-pc-windows-gnu");
1213        assert!(has(&windows, "#define __cdecl __attribute__((__cdecl__))"));
1214        assert!(has(&windows, "#define __stdcall __attribute__((__stdcall__))"));
1215        assert!(has(&windows, "#define __fastcall __attribute__((__fastcall__))"));
1216        assert!(has(&windows, "#define __thiscall __attribute__((__thiscall__))"));
1217        assert!(has(&windows, "#define _cdecl __attribute__((__cdecl__))"));
1218        assert!(has(&windows, "#define __declspec(x) __attribute__((x))"));
1219        let linux = set_for("x86_64-unknown-linux-gnu");
1220        assert!(!has(&linux, "#define __cdecl __attribute__((__cdecl__))"));
1221        assert!(!has(&linux, "#define __declspec(x) __attribute__((x))"));
1222    }
1223
1224    #[test]
1225    fn a_strict_mode_keeps_the_spellings_that_are_not_the_implementations_to_take() {
1226        // `_cdecl` is a name a program may use and `__cdecl` is not, so gcc defines the first
1227        // only where the extensions are on and the second everywhere.
1228        let mut opts = Predef::new();
1229        opts.gnu_extensions = false;
1230        let triple: Triple = "x86_64-pc-windows-gnu".parse().expect("a triple");
1231        let strict = built_in(&TargetInfo::new(triple), &opts);
1232        assert!(has(&strict, "#define __cdecl __attribute__((__cdecl__))"));
1233        assert!(!has(&strict, "#define _cdecl __attribute__((__cdecl__))"));
1234    }
1235
1236    #[test]
1237    fn wchar_t_is_the_type_that_divides_the_targets() {
1238        // Signed on x86-64 Linux, unsigned on AArch64 Linux, and sixteen bits on Windows.
1239        assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ int"));
1240        assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ unsigned int"));
1241        let windows = set_for("x86_64-pc-windows-msvc");
1242        assert!(has(&windows, "#define __WCHAR_TYPE__ short unsigned int"));
1243        assert!(has(&windows, "#define __SIZEOF_WCHAR_T__ 2"));
1244    }
1245
1246    #[test]
1247    fn apple_spells_the_architecture_its_own_way_and_its_headers_only_know_that_spelling() {
1248        // sys/cdefs.h reaches #error "Unsupported architecture" without these, which is the
1249        // first line of the first header of every program on the platform.
1250        let darwin = set_for("aarch64-apple-darwin");
1251        assert!(has(&darwin, "#define __arm64__ 1"));
1252        assert!(has(&darwin, "#define __arm64 1"));
1253        assert!(has(&darwin, "#define __aarch64__ 1"), "the portable spelling stays too");
1254        let linux = set_for("aarch64-unknown-linux-gnu");
1255        assert!(!has(&linux, "#define __arm64__ 1"), "Apple's spelling is Apple's alone");
1256        assert!(!has(&set_for("x86_64-apple-darwin"), "#define __arm64__ 1"));
1257    }
1258
1259    #[test]
1260    fn every_limit_is_spelled_in_hexadecimal_the_way_gcc_spells_it() {
1261        // The value was never in question and the spelling is, because these macros reach a
1262        // program's text. glibc's `limits.h` writes `#define INT_MAX __INT_MAX__`, openssl
1263        // writes `((unsigned int)INT_MAX + 1)`, and `-E` over that header printed a decimal
1264        // number where gcc printed a hexadecimal one. The type is the same either way here,
1265        // which is why the suffixes are unchanged: `0x7fffffff` and `2147483647` are both
1266        // `int`, and `0xffffffffffffffffUL` and its decimal twin are both `unsigned long`.
1267        let linux = set_for("x86_64-unknown-linux-gnu");
1268        for line in [
1269            "#define __SCHAR_MAX__ 0x7f",
1270            "#define __SHRT_MAX__ 0x7fff",
1271            "#define __INT_MAX__ 0x7fffffff",
1272            "#define __LONG_MAX__ 0x7fffffffffffffffL",
1273            "#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL",
1274            "#define __INTMAX_MAX__ 0x7fffffffffffffffL",
1275            "#define __UINTMAX_MAX__ 0xffffffffffffffffUL",
1276            "#define __SIZE_MAX__ 0xffffffffffffffffUL",
1277            "#define __PTRDIFF_MAX__ 0x7fffffffffffffffL",
1278            "#define __SIG_ATOMIC_MAX__ 0x7fffffff",
1279            "#define __INT8_MAX__ 0x7f",
1280            "#define __UINT8_MAX__ 0xff",
1281            "#define __INT16_MAX__ 0x7fff",
1282            "#define __UINT16_MAX__ 0xffff",
1283            "#define __INT32_MAX__ 0x7fffffff",
1284            "#define __UINT32_MAX__ 0xffffffffU",
1285            "#define __INT64_MAX__ 0x7fffffffffffffffL",
1286            "#define __UINT64_MAX__ 0xffffffffffffffffUL",
1287            "#define __INT_FAST8_MAX__ 0x7f",
1288            "#define __UINT_FAST8_MAX__ 0xff",
1289        ] {
1290            assert!(has(&linux, line), "{line}");
1291        }
1292        // Windows, where `long` is thirty two bits, so the wide suffix moves and the narrow
1293        // `long` limit is not the same number.
1294        let windows = set_for("x86_64-pc-windows-msvc");
1295        assert!(has(&windows, "#define __LONG_MAX__ 0x7fffffffL"));
1296        assert!(has(&windows, "#define __INTMAX_MAX__ 0x7fffffffffffffffLL"));
1297        assert!(has(&windows, "#define __UINTMAX_MAX__ 0xffffffffffffffffULL"));
1298    }
1299
1300    #[test]
1301    fn wint_t_does_not_follow_wchar_t() {
1302        // Apple makes it signed so that WEOF is negative the way EOF is. Linux does not.
1303        let darwin = set_for("aarch64-apple-darwin");
1304        assert!(has(&darwin, "#define __WINT_TYPE__ int"));
1305        assert!(has(&darwin, "#define __WINT_MAX__ 0x7fffffff"));
1306        assert!(has(&darwin, "#define __WCHAR_TYPE__ int"));
1307        let linux = set_for("aarch64-unknown-linux-gnu");
1308        assert!(has(&linux, "#define __WINT_TYPE__ unsigned int"));
1309        assert!(has(&linux, "#define __WINT_MAX__ 0xffffffffU"));
1310        assert!(has(&linux, "#define __WCHAR_TYPE__ unsigned int"), "and wchar_t is its own");
1311        assert!(has(
1312            &set_for("x86_64-pc-windows-msvc"),
1313            "#define __WINT_TYPE__ short unsigned int"
1314        ));
1315    }
1316
1317    #[test]
1318    fn the_widths_say_what_the_type_holds_and_follow_the_target_that_changes_it() {
1319        // Twenty of them, which is gcc's set: no exact width member, since the width of an
1320        // `int32_t` is in its name, and no unsigned member, since a header that wants
1321        // `UINTMAX_WIDTH` writes `__INTMAX_WIDTH__`.
1322        let linux = set_for("x86_64-unknown-linux-gnu");
1323        assert_eq!(linux.lines().filter(|line| line.contains("_WIDTH__")).count(), 20);
1324        assert!(has(&linux, "#define __LONG_WIDTH__ 64"));
1325        assert!(has(&linux, "#define __SIZE_WIDTH__ 64"));
1326        assert!(has(&linux, "#define __WCHAR_WIDTH__ 32"));
1327        assert!(has(&linux, "#define __INT_LEAST16_WIDTH__ 16"));
1328        // x86-64 glibc is where `int_fast16_t` is a `long`, and the width has to say so or a
1329        // program that switches on it picks the wrong branch.
1330        assert!(has(&linux, "#define __INT_FAST16_WIDTH__ 64"));
1331        assert!(has(&set_for("x86_64-unknown-linux-musl"), "#define __INT_FAST16_WIDTH__ 32"));
1332        // Windows has a thirty two bit `long` and a sixteen bit `wint_t`, and the pointer
1333        // sized types stay sixty four bits wide whatever `long` does.
1334        let windows = set_for("x86_64-pc-windows-msvc");
1335        assert!(has(&windows, "#define __LONG_WIDTH__ 32"));
1336        assert!(has(&windows, "#define __WINT_WIDTH__ 16"));
1337        assert!(has(&windows, "#define __SIZE_WIDTH__ 64"));
1338        assert!(has(&windows, "#define __INTMAX_WIDTH__ 64"));
1339    }
1340
1341    #[test]
1342    fn a_constant_maker_gets_the_suffix_its_width_needs_and_no_other() {
1343        // Found by diffing `-dM` against the system compiler. The 32 bit row was passing `U`
1344        // as its width suffix, which put a `U` on the signed macro and two on the unsigned
1345        // one, and `UINT32_C(1)` expanded to `1UU`, which is not a token.
1346        let linux = set_for("x86_64-unknown-linux-gnu");
1347        assert!(has(&linux, "#define __INT32_C(c) c"));
1348        assert!(has(&linux, "#define __UINT32_C(c) c ## U"));
1349        assert!(has(&linux, "#define __INT16_C(c) c"));
1350        // No `U` on the two narrow ones, because `uint8_t` and `uint16_t` promote to a
1351        // signed `int` and the constant has that type. gcc leaves it off for the same reason.
1352        assert!(has(&linux, "#define __UINT16_C(c) c"));
1353        assert!(has(&linux, "#define __UINT8_C(c) c"));
1354        // The wide ones do take a suffix, and the `U` goes in front of it.
1355        assert!(has(&linux, "#define __INT64_C(c) c ## L"));
1356        assert!(has(&linux, "#define __UINT64_C(c) c ## UL"));
1357        // Windows has a thirty two bit `long`, so its sixty four bit constants are `long long`.
1358        let windows = set_for("x86_64-pc-windows-msvc");
1359        assert!(has(&windows, "#define __INT64_C(c) c ## LL"));
1360        assert!(has(&windows, "#define __UINT64_C(c) c ## ULL"));
1361    }
1362
1363    #[test]
1364    fn the_symbol_prefix_is_defined_everywhere_including_where_it_is_empty() {
1365        // Empty is not the same as absent, because glibc stringifies it. Leaving it undefined
1366        // turns `__asm__ (__ASMNAME ("__xpg_strerror_r"))` into an asm name of
1367        // "__USER_LABEL_PREFIX__" "__xpg_strerror_r", which renames the function instead of
1368        // failing, and that is a bug found at link time or later.
1369        for triple in
1370            ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
1371        {
1372            assert!(has(&set_for(triple), "#define __USER_LABEL_PREFIX__ "), "{triple}");
1373        }
1374        // Mach-O keeps the underscore that ELF dropped.
1375        assert!(has(&set_for("aarch64-apple-darwin"), "#define __USER_LABEL_PREFIX__ _"));
1376    }
1377
1378    /// The set gcc defines that headers read and that are true here. Written out one line at a
1379    /// time rather than counted, because the value is the whole point of each of them: a header
1380    /// asking `#if __FINITE_MATH_ONLY__` wants the number and not the existence.
1381    #[test]
1382    fn the_toolchain_macros_gcc_defines_are_defined_with_gccs_values() {
1383        let linux = set_for("x86_64-unknown-linux-gnu");
1384        for line in [
1385            "#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"",
1386            "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"",
1387            "#define __GXX_ABI_VERSION 1021",
1388            "#define __REGISTER_PREFIX__ ",
1389            "#define __FINITE_MATH_ONLY__ 0",
1390            "#define __GCC_IEC_559 2",
1391            "#define __GCC_IEC_559_COMPLEX 2",
1392            "#define __GCC_CONSTRUCTIVE_SIZE 64",
1393            "#define __GCC_DESTRUCTIVE_SIZE 64",
1394            "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1",
1395            "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1",
1396            "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1",
1397            "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1",
1398            "#define __ATOMIC_HLE_ACQUIRE 65536",
1399            "#define __ATOMIC_HLE_RELEASE 131072",
1400            "#define __FXSR__ 1",
1401            "#define __MMX_WITH_SSE__ 1",
1402            "#define __code_model_small__ 1",
1403        ] {
1404            assert!(has(&linux, line), "{line}");
1405        }
1406        // The five that are the processor's rather than the compiler's stay on the processor.
1407        let arm = set_for("aarch64-unknown-linux-gnu");
1408        for name in ["__ATOMIC_HLE_ACQUIRE", "__FXSR__", "__MMX_WITH_SSE__", "__code_model_small__"]
1409        {
1410            assert!(!arm.contains(name), "{name}");
1411        }
1412        assert!(has(&arm, "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1"));
1413        // A wide character is sixteen bits on Windows, so a wide string is UTF-16 there.
1414        let windows = set_for("x86_64-pc-windows-msvc");
1415        assert!(has(&windows, "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-16LE\""));
1416    }
1417
1418    #[test]
1419    fn the_memory_orders_are_there_even_without_atomics() {
1420        // musl's stdatomic.h writes `memory_order_relaxed = __ATOMIC_RELAXED` with no test
1421        // around it, so these are not a promise about `_Atomic`, they are the numbering the
1422        // builtins take, and a compiler without them prints an enumerator whose value is an
1423        // identifier.
1424        let linux = set_for("x86_64-unknown-linux-gnu");
1425        assert!(has(&linux, "#define __ATOMIC_RELAXED 0"));
1426        assert!(has(&linux, "#define __ATOMIC_SEQ_CST 5"));
1427        assert!(has(&linux, "#define __STDC_NO_ATOMICS__ 1"), "and we still have no _Atomic");
1428        assert!(has(&linux, "#define __GCC_ATOMIC_INT_LOCK_FREE 2"));
1429        assert!(has(&linux, "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1430        assert!(has(&set_for("x86_64-pc-windows-msvc"), "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1431    }
1432
1433    #[test]
1434    fn long_double_is_three_types_and_the_macros_say_which() {
1435        assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 64"));
1436        assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 113"));
1437        assert!(has(&set_for("aarch64-apple-darwin"), "#define __LDBL_MANT_DIG__ 53"));
1438    }
1439
1440    #[test]
1441    fn the_extended_floating_types_have_the_limits_their_formats_have() {
1442        // Every one of these but `_Float64x` is the same format on every target, which is the
1443        // point of the interchange types, so the limits are the same everywhere too.
1444        let linux = set_for("x86_64-unknown-linux-gnu");
1445        assert!(has(&linux, "#define __FLT16_MANT_DIG__ 11"));
1446        assert!(has(&linux, "#define __FLT32_MANT_DIG__ 24"));
1447        assert!(has(&linux, "#define __FLT64_MANT_DIG__ 53"));
1448        assert!(has(&linux, "#define __FLT128_MANT_DIG__ 113"));
1449        assert!(has(&linux, "#define __FLT32X_MANT_DIG__ 53"));
1450        // Each family writes its values with its own suffix, so a header that assigns one to an
1451        // object of the type gets the type back rather than a conversion.
1452        assert!(has(&linux, "#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16"));
1453        assert!(has(
1454            &linux,
1455            "#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x"
1456        ));
1457        // `_Float128x` is a type no target has, so gcc defines nothing for it and neither
1458        // does this.
1459        assert!(!linux.contains("__FLT128X_"));
1460    }
1461
1462    #[test]
1463    fn the_family_for_a_named_type_is_written_where_the_type_is_and_nowhere_else() {
1464        // gcc 13's rows, measured with the cross compilers: the half is on x86-64, AArch64 and
1465        // RISC-V, and the quad is on every one of the seven but armv7. A program asks the macro
1466        // to find out whether it may write the type, so a row where the two disagree is a header
1467        // that asks for a type the compiler then refuses.
1468        let has_family = |target: &str, prefix: &str| {
1469            set_for_tuple(target).contains(&format!("#define __{prefix}_MANT_DIG__ "))
1470        };
1471        assert!(has_family("x86_64-linux-gnu", "FLT16"));
1472        assert!(has_family("aarch64-linux-gnu", "FLT16"));
1473        assert!(has_family("riscv64-linux-gnu", "FLT16"));
1474        assert!(!has_family("i686-linux-gnu", "FLT16"));
1475        assert!(!has_family("s390x-linux-gnu", "FLT16"));
1476        assert!(!has_family("armv7-linux-gnueabihf", "FLT16"));
1477
1478        assert!(has_family("i686-linux-gnu", "FLT128"));
1479        assert!(has_family("s390x-linux-gnu", "FLT128"));
1480        assert!(!has_family("armv7-linux-gnueabihf", "FLT128"));
1481
1482        // The families every machine has are still there on the machine that has least, and so
1483        // is `_Float64x` on the machines that have a format for it.
1484        let arm = set_for_tuple("armv7-linux-gnueabihf");
1485        for prefix in ["FLT", "DBL", "LDBL", "FLT32", "FLT64", "FLT32X"] {
1486            assert!(arm.contains(&format!("#define __{prefix}_MANT_DIG__ ")), "__{prefix}_");
1487        }
1488        assert!(!arm.contains("__FLT64X_"));
1489    }
1490
1491    #[test]
1492    fn float64x_keeps_the_width_that_long_double_loses_on_apple() {
1493        // The two are the same eighty bit x87 format on x86-64 and part company everywhere
1494        // else, because `_Float64x` follows the processor and `long double` follows the ABI.
1495        let linux = set_for("x86_64-unknown-linux-gnu");
1496        assert!(has(&linux, "#define __FLT64X_MANT_DIG__ 64"));
1497        assert!(has(&linux, "#define __LDBL_MANT_DIG__ 64"));
1498        let mac = set_for("aarch64-apple-darwin");
1499        assert!(has(&mac, "#define __FLT64X_MANT_DIG__ 113"));
1500        assert!(has(&mac, "#define __LDBL_MANT_DIG__ 53"));
1501        let windows = set_for("x86_64-pc-windows-msvc");
1502        assert!(has(&windows, "#define __FLT64X_MANT_DIG__ 64"));
1503        assert!(has(&windows, "#define __LDBL_MANT_DIG__ 53"));
1504    }
1505
1506    #[test]
1507    fn the_largest_value_of_an_ieee_format_is_also_its_largest_normal_one() {
1508        // `NORM_MAX` is only ever smaller than `MAX` for a format that holds values above its
1509        // largest normal one, and no IEEE encoding does. The double-double does, which is why
1510        // the two are separate fields now, and no target here has one.
1511        let linux = set_for("x86_64-unknown-linux-gnu");
1512        for prefix in ["FLT", "DBL", "LDBL", "FLT16", "FLT32", "FLT64", "FLT128", "FLT32X"] {
1513            let value = |suffix: &str| {
1514                let name = format!("#define __{prefix}_{suffix}__ ");
1515                let line = linux
1516                    .lines()
1517                    .find(|line| line.starts_with(&name))
1518                    .unwrap_or_else(|| panic!("__{prefix}_{suffix}__ is defined"));
1519                line[name.len()..].to_owned()
1520            };
1521            assert_eq!(value("MAX"), value("NORM_MAX"), "__{prefix}_NORM_MAX__");
1522        }
1523    }
1524
1525    #[test]
1526    fn the_double_double_is_the_row_where_the_largest_value_is_not_the_largest_normal_one() {
1527        // No target here has a double-double `long double`, so this asks the row rather than the
1528        // macros. It is the reason `norm_max` is a field: a program that wants the largest value
1529        // it can still compute a full significand with wants `NORM_MAX`, and on PowerPC that is
1530        // a bit under half of `MAX`.
1531        let c = characteristics(Format::DoubleDouble);
1532        assert_ne!(c.max, c.norm_max);
1533        // `NORM_MAX` is two to the one thousand and twenty three, which is about half of `MAX`,
1534        // and `MAX` is a shade above `DBL_MAX` because the high half can be `DBL_MAX` and the low
1535        // half then adds to it. Both are what the reference prints.
1536        assert!(c.norm_max.starts_with("8.98846567431157953864652595394501e+307"));
1537        assert!(c.max.starts_with("1.7976931348623158"));
1538        // Epsilon is the odd one. The smallest value that changes a double-double near one is a
1539        // subnormal in the low half rather than one unit in the last place of anything, so it is
1540        // the same number as this format's own `DENORM_MIN`, which no other row can say.
1541        assert_eq!(c.epsilon, c.denorm_min);
1542        for format in [Format::Half, Format::Single, Format::Double, Format::X87Extended] {
1543            assert_ne!(characteristics(format).epsilon, characteristics(format).denorm_min);
1544        }
1545        // And it is not an IEC 60559 format, which only the brain float can also say.
1546        assert_eq!(c.is_iec_60559, "0");
1547    }
1548
1549    #[test]
1550    fn the_widest_bit_int_is_said_in_every_dialect() {
1551        // gcc defines it under `-std=c17` as well as `-std=c23`, and a header that reaches for
1552        // `_BitInt` tests the macro rather than the version, so an absent one reads as a
1553        // compiler without the type at all.
1554        let mut opts = Predef::new();
1555        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1556        assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1557        opts.std = Std::C17;
1558        assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1559    }
1560
1561    #[test]
1562    fn char_signedness_is_recorded_only_when_it_is_unsigned() {
1563        // Which is how GCC does it: the macro exists to mark the unusual case.
1564        assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
1565        assert!(!has(&set_for("x86_64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
1566    }
1567
1568    #[test]
1569    fn the_dialect_decides_the_standard_macros() {
1570        let mut opts = Predef::new();
1571        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1572        assert!(has(&built_in(&target, &opts), "#define __STDC_VERSION__ 202311L"));
1573        assert!(!has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
1574        assert!(has(&built_in(&target, &opts), "#define linux 1"));
1575
1576        opts.gnu_extensions = false;
1577        assert!(has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
1578        assert!(!has(&built_in(&target, &opts), "#define linux 1"), "not a reserved name");
1579
1580        opts.std = Std::C89;
1581        let c89 = built_in(&target, &opts);
1582        assert!(!c89.contains("__STDC_VERSION__"), "C89 does not define it at all");
1583        assert!(has(&c89, "#define __STDC__ 1"));
1584    }
1585
1586    /// The conditional feature macros are claims not to have something, and a claim that is
1587    /// not true changes what a header declares rather than turning anything off.
1588    #[test]
1589    fn the_only_things_claimed_missing_are_the_ones_that_are_missing() {
1590        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1591        let opts = Predef::new();
1592        let set = built_in(&target, &opts);
1593        assert!(has(&set, "#define __STDC_NO_ATOMICS__ 1"), "there is no stdatomic.h to include");
1594        assert!(has(&set, "#define __STDC_NO_THREADS__ 1"), "nor a threads.h");
1595        assert!(has(&set, "#define __STDC_NO_COMPLEX__ 1"), "the arithmetic is not lowered");
1596        assert!(!set.contains("__STDC_NO_VLA__"), "variable length arrays work");
1597    }
1598
1599    /// gcc's own `stdatomic.h` declares `atomic_char8_t` under `#ifdef __CHAR8_TYPE__`, so a
1600    /// compiler that defines it in C17 declares a type gcc does not and one that never defines
1601    /// it is missing one in C23. Both were caught by preprocessing that header both ways.
1602    #[test]
1603    fn the_type_behind_char8_t_is_defined_in_c23_and_in_no_dialect_before_it() {
1604        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1605        let mut opts = Predef::new();
1606        assert!(has(&built_in(&target, &opts), "#define __CHAR8_TYPE__ unsigned char"));
1607
1608        for older in [Std::C17, Std::C11, Std::C99, Std::C89] {
1609            opts.std = older;
1610            assert!(!built_in(&target, &opts).contains("__CHAR8_TYPE__"), "{older:?}");
1611        }
1612    }
1613
1614    /// glibc's `<stdc-predef.h>` is read before the first line of every translation unit and
1615    /// writes `#define __STDC_IEC_60559_BFP__ 201404L` whenever `__GCC_IEC_559` is positive.
1616    /// Any other value here is a redefinition with a different body, which is a warning the
1617    /// program did not ask for and which a configure script reads as a failed feature test.
1618    #[test]
1619    fn the_ieee_annex_macro_carries_the_value_glibcs_own_header_writes() {
1620        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1621        let mut opts = Predef::new();
1622        for std in [Std::C23, Std::C17, Std::C11, Std::C99, Std::C89] {
1623            opts.std = std;
1624            let set = built_in(&target, &opts);
1625            assert!(has(&set, "#define __STDC_IEC_60559_BFP__ 201404L"), "{std:?}");
1626            assert!(has(&set, "#define __STDC_IEC_60559_COMPLEX__ 201404L"), "{std:?}");
1627            // The two the library reads to decide whether to write the four above itself.
1628            assert!(has(&set, "#define __GCC_IEC_559 2"), "{std:?}");
1629            assert!(has(&set, "#define __GCC_IEC_559_COMPLEX 2"), "{std:?}");
1630        }
1631    }
1632
1633    #[test]
1634    fn the_optimizer_level_is_visible_to_the_preprocessor() {
1635        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1636        let mut opts = Predef::new();
1637        assert!(has(&built_in(&target, &opts), "#define __NO_INLINE__ 1"));
1638        assert!(!built_in(&target, &opts).contains("__OPTIMIZE__"));
1639
1640        opts.opt_level = OptLevel::O2;
1641        assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE__ 1"));
1642        assert!(!built_in(&target, &opts).contains("__OPTIMIZE_SIZE__"));
1643
1644        opts.opt_level = OptLevel::Os;
1645        assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE_SIZE__ 1"));
1646    }
1647
1648    #[test]
1649    fn a_command_line_define_with_no_value_is_one() {
1650        let mut opts = Predef::new();
1651        opts.defines = vec!["FOO".to_owned(), "BAR=2".to_owned(), "F(x)=x + 1".to_owned()];
1652        opts.undefines = vec!["__linux__".to_owned()];
1653        let text = command_line(&opts);
1654        assert!(has(&text, "#define FOO 1"));
1655        assert!(has(&text, "#define BAR 2"));
1656        assert!(has(&text, "#define F(x) x + 1"));
1657        // The undefine comes last, because `-U` beats `-D` whichever side of it it was on.
1658        assert!(text.trim_end().ends_with("#undef __linux__"));
1659    }
1660
1661    #[test]
1662    fn no_command_line_macros_is_no_file_at_all() {
1663        assert!(command_line(&Predef::new()).is_empty());
1664    }
1665
1666    #[test]
1667    fn a_date_is_spelled_the_way_the_standard_fixes() {
1668        // The epoch itself, and a day that needs the space padding the format asks for.
1669        let epoch = Timestamp::from_unix(0);
1670        assert_eq!(epoch.date, "Jan  1 1970");
1671        assert_eq!(epoch.time, "00:00:00");
1672        let leap = Timestamp::from_unix(1_709_164_800);
1673        assert_eq!(leap.date, "Feb 29 2024", "2024 is a leap year");
1674        let late = Timestamp::from_unix(1_735_689_599);
1675        assert_eq!(late.date, "Dec 31 2024");
1676        assert_eq!(late.time, "23:59:59");
1677    }
1678
1679    #[test]
1680    fn a_date_before_the_epoch_still_comes_out_right() {
1681        // Not because anyone compiles in 1969, but because the arithmetic that gets this
1682        // wrong is the same arithmetic that gets a time zone offset wrong.
1683        assert_eq!(Timestamp::from_unix(-1).date, "Dec 31 1969");
1684        assert_eq!(Timestamp::from_unix(-1).time, "23:59:59");
1685    }
1686
1687    #[test]
1688    fn the_gnuc_version_is_a_knob_rather_than_a_constant() {
1689        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1690        let mut opts = Predef::new();
1691        assert!(has(&built_in(&target, &opts), "#define __GNUC__ 7"));
1692        opts.gnuc = GnucVersion { major: 15, minor: 1, patch: 0 };
1693        assert!(has(&built_in(&target, &opts), "#define __GNUC__ 15"));
1694        assert!(has(&built_in(&target, &opts), "#define __GNUC_MINOR__ 1"));
1695    }
1696
1697    /// Which of the two inline macros is defined, over the two things that decide it.
1698    ///
1699    /// Exactly one of them is defined at a time, which is what a header reads: glibc's
1700    /// `__extern_inline` writes `extern __inline` under one and adds `__gnu_inline__` under the
1701    /// other, so both being defined or neither being defined is a header taking a path it was
1702    /// never meant to take.
1703    #[test]
1704    fn one_of_the_two_inline_macros_is_defined_and_three_things_can_pick_which() {
1705        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1706        let gnu = "#define __GNUC_GNU_INLINE__ 1";
1707        let stdc = "#define __GNUC_STDC_INLINE__ 1";
1708
1709        let mut opts = Predef::new();
1710        assert!(has(&built_in(&target, &opts), stdc));
1711        assert!(!has(&built_in(&target, &opts), gnu));
1712
1713        opts.gnu89_inline = true;
1714        assert!(has(&built_in(&target, &opts), gnu));
1715        assert!(!has(&built_in(&target, &opts), stdc));
1716
1717        // The dialect on its own, which is where the older reading came from.
1718        let mut opts = Predef::new();
1719        opts.std = Std::C89;
1720        assert!(has(&built_in(&target, &opts), gnu));
1721        assert!(!has(&built_in(&target, &opts), stdc));
1722    }
1723
1724    #[test]
1725    fn musl_and_glibc_disagree_about_the_fast_types_on_the_same_processor() {
1726        // The same x86-64 machine, two libcs, two answers. GCC built for glibc says `long int`
1727        // and GCC built for musl says `int`, because musl defines `int_fast16_t` as `int32_t`
1728        // everywhere. It shows in `stdatomic.h`, which GCC writes out of these macros, so
1729        // getting it wrong makes every atomic fast type the wrong width.
1730        let gnu = set_for("x86_64-unknown-linux-gnu");
1731        let musl = set_for("x86_64-unknown-linux-musl");
1732        assert!(has(&gnu, "#define __INT_FAST16_TYPE__ long int"));
1733        assert!(has(&gnu, "#define __INT_FAST32_TYPE__ long int"));
1734        assert!(has(&gnu, "#define __UINT_FAST16_TYPE__ long unsigned int"));
1735        assert!(has(&musl, "#define __INT_FAST16_TYPE__ int"));
1736        assert!(has(&musl, "#define __INT_FAST32_TYPE__ int"));
1737        assert!(has(&musl, "#define __UINT_FAST16_TYPE__ unsigned int"));
1738        // The limits have to move with the types or a header that checks them stops agreeing
1739        // with the header that uses them.
1740        assert!(has(&gnu, "#define __INT_FAST16_MAX__ 0x7fffffffffffffffL"));
1741        assert!(has(&musl, "#define __INT_FAST16_MAX__ 0x7fffffff"));
1742        assert!(has(&musl, "#define __UINT_FAST16_MAX__ 0xffffffffU"));
1743    }
1744
1745    #[test]
1746    fn the_libc_only_moves_the_two_fast_types_it_is_allowed_to_move() {
1747        // 8 and 64 are the same on both, and so is everything outside the fast family. A libc
1748        // is not a processor and this is the whole of what it is permitted to change here.
1749        let gnu = set_for("x86_64-unknown-linux-gnu");
1750        let musl = set_for("x86_64-unknown-linux-musl");
1751        for line in [
1752            "#define __INT_FAST8_TYPE__ signed char",
1753            "#define __INT_FAST64_TYPE__ long int",
1754            "#define __INT64_TYPE__ long int",
1755            "#define __SIZE_TYPE__ long unsigned int",
1756            "#define __SIZEOF_LONG__ 8",
1757            "#define __LP64__ 1",
1758        ] {
1759            assert!(has(&gnu, line), "glibc lost {line}");
1760            assert!(has(&musl, line), "musl lost {line}");
1761        }
1762    }
1763
1764    #[test]
1765    fn a_non_x86_target_has_int_sized_fast_types_whatever_the_libc() {
1766        // The `long` answer was always specific to x86-64. aarch64 glibc says `int` too, so
1767        // adding the libc axis must not have turned into a second way to say x86-64.
1768        let arm_gnu = set_for("aarch64-unknown-linux-gnu");
1769        let arm_musl = set_for("aarch64-unknown-linux-musl");
1770        assert!(has(&arm_gnu, "#define __INT_FAST16_TYPE__ int"));
1771        assert!(has(&arm_musl, "#define __INT_FAST16_TYPE__ int"));
1772    }
1773}