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, Math, OptLevel, Options, Pic, Std};
24use rucc_target::{Arch, Env, Isa, 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 /// Whether an operation may raise an exception the program looks at, from `-ftrapping-math`.
130 pub trapping_math: bool,
131 /// The rest of the `-ffast-math` family. Each licence has a macro of its own and the family
132 /// together decides `__FAST_MATH__` and whether the arithmetic is still IEC 60559's.
133 pub math: Math,
134 /// Whether an exception may unwind through this unit, from `-fexceptions`.
135 pub exceptions: bool,
136 /// `-D` in command line order. `FOO` means `FOO=1`, as GCC has it.
137 pub defines: Vec<String>,
138 /// `-U` in command line order, applied after the defines.
139 pub undefines: Vec<String>,
140 /// The instruction set extensions the unit is built for, which decides `__SSE4_2__` and the
141 /// rest of that family on x86-64 and nothing anywhere else.
142 pub isa: Isa,
143}
144
145impl Predef {
146 /// The default dialect, `gnu23`, at `-O0`.
147 pub fn new() -> Predef {
148 Predef {
149 std: Std::default(),
150 gnu_extensions: true,
151 gnu89_inline: false,
152 gnuc: GnucVersion::default(),
153 opt_level: OptLevel::O0,
154 hosted: true,
155 pic: Pic::Executable,
156 timestamp: Timestamp::now(),
157 glibc_minor: None,
158 trapping_math: true,
159 math: Math::default(),
160 exceptions: false,
161 defines: Vec::new(),
162 undefines: Vec::new(),
163 isa: Isa::baseline(),
164 }
165 }
166}
167
168impl Predef {
169 /// The set the command line asked for.
170 ///
171 /// The mapping lives here rather than in the driver because it is the definition of what
172 /// each flag means to the macro set, and the driver's job is to parse a command line, not
173 /// to know that `-ffreestanding` is `__STDC_HOSTED__` being zero.
174 pub fn for_options(opts: &Options) -> Predef {
175 Predef {
176 std: opts.std,
177 gnu_extensions: opts.gnu_extensions,
178 gnu89_inline: opts.gnu89_inline,
179 gnuc: opts.gnuc,
180 opt_level: opts.opt_level,
181 hosted: opts.hosted,
182 pic: opts.pic,
183 timestamp: Timestamp::now(),
184 glibc_minor: opts.glibc_minor,
185 trapping_math: opts.trapping_math,
186 math: opts.math,
187 exceptions: opts.exceptions,
188 defines: opts.defines.clone(),
189 undefines: opts.undefines.clone(),
190 isa: opts.isa,
191 }
192 }
193}
194
195impl Default for Predef {
196 fn default() -> Predef {
197 Predef::new()
198 }
199}
200
201/// A file of `#define` lines being built up.
202struct Defs {
203 text: String,
204}
205
206impl Defs {
207 fn new() -> Defs {
208 Defs { text: String::new() }
209 }
210
211 /// `#define name value`.
212 fn set(&mut self, name: &str, value: &str) {
213 self.text.push_str("#define ");
214 self.text.push_str(name);
215 self.text.push(' ');
216 self.text.push_str(value);
217 self.text.push('\n');
218 }
219
220 /// `#define name 1`, which is what a macro that is only ever tested for needs.
221 fn flag(&mut self, name: &str) {
222 self.set(name, "1");
223 }
224
225 fn set_if(&mut self, when: bool, name: &str, value: &str) {
226 if when {
227 self.set(name, value);
228 }
229 }
230
231 fn flag_if(&mut self, when: bool, name: &str) {
232 if when {
233 self.flag(name);
234 }
235 }
236}
237
238/// The whole predefined set for a target, as the text of a file.
239pub(crate) fn built_in(target: &TargetInfo, opts: &Predef) -> String {
240 let mut d = Defs::new();
241 identity(&mut d, target, opts);
242 // `__DATE__` and `__TIME__` are fixed for the whole translation unit, which is what the
243 // standard asks for, so they are ordinary object-like macros and the expander needs to
244 // know nothing about them.
245 d.set("__DATE__", &format!("\"{}\"", opts.timestamp.date));
246 d.set("__TIME__", &format!("\"{}\"", opts.timestamp.time));
247 dialect(&mut d, target, opts);
248 optimization(&mut d, opts);
249 platform(&mut d, target, opts);
250 sizes(&mut d, target);
251 integers(&mut d, target);
252 floats(&mut d, target, opts);
253 atomics(&mut d, target);
254 d.text
255}
256
257/// `-D` and `-U`, as the text of a file.
258///
259/// Empty when there are none, so that the caller can skip adding a file that would say
260/// nothing. The undefines come last whatever order they were written in, because `-U` beats
261/// `-D` in GCC no matter which side of it the `-D` was on.
262pub(crate) fn command_line(opts: &Predef) -> String {
263 let mut d = Defs::new();
264 for define in &opts.defines {
265 match define.split_once('=') {
266 Some((name, value)) => d.set(name, value),
267 // `-DFOO` is `-DFOO=1`. A macro nobody gave a value to is one that is only ever
268 // tested for, and giving it an empty body would break `#if FOO`.
269 None => d.flag(define),
270 }
271 }
272 for name in &opts.undefines {
273 d.text.push_str("#undef ");
274 d.text.push_str(name);
275 d.text.push('\n');
276 }
277 d.text
278}
279
280/// What this compiler says its own version is.
281///
282/// Read from the manifest at build time rather than written here, because a number written in a
283/// second place is a number that goes stale: these five macros said 0.1.0 through sixty seven
284/// releases. A program testing `__rucc_major__` for a feature was told the answer for a version
285/// nobody has run since, and a build log recording `__VERSION__` recorded the wrong compiler.
286const VERSION: &str = env!("CARGO_PKG_VERSION");
287
288/// One dotted field of a version, as the digits at the front of it.
289///
290/// `0.10.68-rc.1` has a patch level of 68 and not of `68-rc`, and a field that is not there at all
291/// is zero, which is what a two field version means by its third. Neither shape is one this
292/// workspace publishes, and a macro that expands to something no `#if` can read is worse than a
293/// macro that is approximately right.
294fn field(version: &str, n: usize) -> &str {
295 let part = version.split('.').nth(n).unwrap_or("0");
296 let digits = part.trim_start_matches(|c: char| !c.is_ascii_digit());
297 let end = digits.find(|c: char| !c.is_ascii_digit()).unwrap_or(digits.len());
298 if end == 0 { "0" } else { &digits[..end] }
299}
300
301/// Who the compiler says it is.
302fn identity(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
303 d.flag("__rucc__");
304 d.set("__rucc_version__", &format!("\"{VERSION}\""));
305 d.set("__rucc_major__", field(VERSION, 0));
306 d.set("__rucc_minor__", field(VERSION, 1));
307 d.set("__rucc_patchlevel__", field(VERSION, 2));
308 // The promise from section 4.5. Everything in the matrix hangs off this line.
309 d.set("__GNUC__", &opts.gnuc.major.to_string());
310 d.set("__GNUC_MINOR__", &opts.gnuc.minor.to_string());
311 d.set("__GNUC_PATCHLEVEL__", &opts.gnuc.patch.to_string());
312 d.set("__VERSION__", &format!("\"rucc {VERSION}\""));
313 // Not `__clang__`, deliberately. Section 4.5 says so, and a header that takes the Clang
314 // path expects Clang's extension surface rather than GCC's.
315 //
316 // Which of the two readings of `inline` is in force, which a header reads to decide how to
317 // write its own inline definitions: glibc's `__extern_inline` is `extern __inline` under the
318 // one and adds `__attribute__ ((__gnu_inline__))` under the other. C99 changed the meaning of
319 // the keyword and gcc follows the dialect, so the C89 ones keep GNU's reading and every
320 // dialect after them takes C's until `-fgnu89-inline` says otherwise.
321 let gnu_inline = opts.gnu89_inline || opts.std == Std::C89;
322 d.flag_if(gnu_inline, "__GNUC_GNU_INLINE__");
323 d.flag_if(!gnu_inline, "__GNUC_STDC_INLINE__");
324 // The charsets a literal is converted to. Both are fixed here rather than settable, since
325 // there is no `-fexec-charset` to set them with, and both are what gcc answers with none.
326 // The wide one follows `wchar_t`, which is sixteen bits on Windows and thirty two
327 // everywhere else, so it is the one target fact in this function.
328 d.set("__GNUC_EXECUTION_CHARSET_NAME", "\"UTF-8\"");
329 let wide = if target.wchar_width == 16 { "\"UTF-16LE\"" } else { "\"UTF-32LE\"" };
330 d.set("__GNUC_WIDE_EXECUTION_CHARSET_NAME", wide);
331 // The C++ ABI this would be if it compiled C++, which gcc defines in C as well. It is not
332 // a claim about this compiler so much as a number headers read: libstdc++ is not the only
333 // thing that tests it, and a C header shared with a C++ one reaches it through `extern
334 // "C"` guards. The value is gcc 16's.
335 d.set("__GXX_ABI_VERSION", "1021");
336}
337
338/// What the dialect flags say.
339fn dialect(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
340 d.flag("__STDC__");
341 d.set_if(opts.hosted, "__STDC_HOSTED__", "1");
342 d.set_if(!opts.hosted, "__STDC_HOSTED__", "0");
343 if let Some(version) = opts.std.stdc_version() {
344 d.set("__STDC_VERSION__", version);
345 }
346 // Defined exactly when the extensions are off, which is the whole difference between
347 // `-std=c23` and `-std=gnu23` as far as the preprocessor is concerned.
348 d.flag_if(!opts.gnu_extensions, "__STRICT_ANSI__");
349 d.flag("__STDC_UTF_16__");
350 d.flag("__STDC_UTF_32__");
351 // What glibc's `<pthread.h>` reads to spell `pthread_cleanup_push` with a `cleanup` attribute
352 // rather than with `setjmp`, and gcc defines it in C for `-fexceptions` and for
353 // `-fnon-call-exceptions` alone.
354 d.flag_if(opts.exceptions, "__EXCEPTIONS");
355 // Only while the arithmetic is IEC 60559's, which a fast math licence ends. glibc's
356 // `<stdc-predef.h>` writes the same four from `__GCC_IEC_559` and writes none of them when that
357 // is zero, so saying them here under `-ffast-math` would be the redefinition described below
358 // with the opposite sign.
359 let iec = opts.math.iec_559(opts.trapping_math);
360 d.flag_if(iec, "__STDC_IEC_559__");
361 d.flag_if(iec, "__STDC_IEC_559_COMPLEX__");
362 // TS 18661-1's date, in every dialect, which is gcc 16's answer rather than the standard's.
363 // C23 folded that document into Annex F and gave the macro a date of its own, so 202311L is
364 // the value C23 asks for, and writing it is what a reading of the standard alone produces.
365 // It also breaks every translation unit that reaches glibc. `<stdc-predef.h>` is included
366 // ahead of the first line of the file and defines this name as 201404L whenever
367 // `__GCC_IEC_559` is positive, which it is here, so a different value is a redefinition with
368 // a different body and that is a diagnostic on a line the program never wrote. The cost is
369 // not only noise: sqlite's configure runs its feature tests through autosetup's `cctest
370 // -nooutput 1`, which reads any output at all as a failed test, and the readline completion
371 // test failed for no other reason than this warning.
372 d.set_if(iec, "__STDC_IEC_60559_BFP__", "201404L");
373 // The same date for the complex half, which is the other name `<stdc-predef.h>` writes and
374 // which was missing here. Withholding it looked like the careful answer and was not one, for
375 // two reasons. `__STDC_NO_COMPLEX__` is defined, so there is no complex arithmetic for the
376 // claim to be about and a program that reads one of these has already been told there is
377 // none. And the library makes the claim anyway: the `#else` in `<stdc-predef.h>` is reached
378 // by a compiler that says nothing about its intent, and it presumes an older compiler that
379 // meant yes. Saying nothing therefore does not withhold anything, it only makes the value
380 // arrive from somewhere else.
381 d.set_if(iec, "__STDC_IEC_60559_COMPLEX__", "201404L");
382 // A promise that every `wchar_t` holds a UCS code point in every locale, which glibc's
383 // `<stdc-predef.h>` makes and Apple's library does not: a Mac `wchar_t` in a legacy locale
384 // is not Unicode, and clang for Apple leaves the macro out for that reason. A program that
385 // reads it to skip `mbstowcs` is the one that would be wrong.
386 let apple = matches!(target.tuple.os(), tuple::Os::MacOs | tuple::Os::IOs);
387 d.set_if(!apple, "__STDC_ISO_10646__", "201706L");
388 // The type behind `char8_t`, which C23 added and no dialect before it has. It sits here
389 // rather than next to `__CHAR16_TYPE__` and `__CHAR32_TYPE__` because those two are the
390 // same in every dialect and this one is not, which is the whole reason a header can test
391 // for it: gcc's own `stdatomic.h` writes `atomic_char8_t` under `#ifdef __CHAR8_TYPE__`
392 // and gets it in C23 and not in C17.
393 d.set_if(opts.std >= Std::C23, "__CHAR8_TYPE__", "unsigned char");
394 // C11 made these conditional features, and a header that sees `__STDC_VERSION__` at
395 // 201112 with no `__STDC_NO_ATOMICS__` next to it will use `_Atomic`. Each one here is a
396 // claim not to have something, so each one is only correct while it stays true: atomics
397 // because there is no `stdatomic.h` to include, threads because there is no `threads.h`,
398 // and complex because the arithmetic is not lowered.
399 //
400 // Variable length arrays are not on this list, because they work. Claiming otherwise is
401 // not a harmless overstatement of caution: glibc's `regex.h` writes the bound of
402 // `regexec`'s match array as `_REGEX_NELTS (__nmatch)`, which is the parameter when the
403 // dialect has them and nothing at all when a compiler says it does not, so the claim
404 // silently changes a declaration in a header rather than turning something off.
405 if opts.std.has_c11() {
406 d.flag("__STDC_NO_ATOMICS__");
407 d.flag("__STDC_NO_THREADS__");
408 d.flag("__STDC_NO_COMPLEX__");
409 }
410 // What `__has_embed` answers with. They are defined in every dialect and not only in C23,
411 // because the operator is answerable in every dialect and a header that writes
412 // `#if __has_embed(...) == __STDC_EMBED_FOUND__` under `-std=gnu17` would otherwise be
413 // comparing against zero and taking the not found branch on a resource that is there.
414 d.set("__STDC_EMBED_NOT_FOUND__", "0");
415 d.set("__STDC_EMBED_FOUND__", "1");
416 d.set("__STDC_EMBED_EMPTY__", "2");
417}
418
419/// The memory orders and the lock free answers.
420///
421/// These are here whether or not `_Atomic` is, and `__STDC_NO_ATOMICS__` does not turn them
422/// off, because they are the numbering the `__atomic` builtins take rather than a promise
423/// about the language. musl's `stdatomic.h` writes `memory_order_relaxed = __ATOMIC_RELAXED`
424/// with no test around it at all, so a compiler without them prints an enumerator whose value
425/// is an identifier.
426///
427/// Two means always lock free, and every integer type gets a two on all three targets, which
428/// are all sixty four bit machines. `long long` is the one that would change on a thirty two
429/// bit target, where a double word load is an instruction the machine may or may not have.
430fn atomics(d: &mut Defs, target: &TargetInfo) {
431 d.set("__ATOMIC_RELAXED", "0");
432 d.set("__ATOMIC_CONSUME", "1");
433 d.set("__ATOMIC_ACQUIRE", "2");
434 d.set("__ATOMIC_RELEASE", "3");
435 d.set("__ATOMIC_ACQ_REL", "4");
436 d.set("__ATOMIC_SEQ_CST", "5");
437 // The gate is the machine word rather than `long`, because Windows has a thirty two bit
438 // `long` on a sixty four bit machine and its `long long` is still one instruction.
439 let llong = if target.pointer_width == 64 { "2" } else { "1" };
440 for name in [
441 "BOOL", "CHAR", "CHAR8_T", "CHAR16_T", "CHAR32_T", "WCHAR_T", "SHORT", "INT", "LONG",
442 "POINTER",
443 ] {
444 d.set(&format!("__GCC_ATOMIC_{name}_LOCK_FREE"), "2");
445 }
446 // The one that is not always two: a target whose word is thirty two bits wide can only
447 // promise `long long` is lock free if it has a double word instruction, and the honest
448 // answer there is sometimes rather than always.
449 d.set("__GCC_ATOMIC_LLONG_LOCK_FREE", llong);
450 d.set("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
451 // What `__sync_bool_compare_and_swap` works on, one macro per width in bytes. Every target
452 // here has the instruction at all four, and glibc reads these rather than the `__atomic_*`
453 // set because they are the older question and the answer is the same one.
454 for width in [1, 2, 4, 8] {
455 d.flag(&format!("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_{width}"));
456 }
457 // The two flag bits an x86 memory order can carry, for the hardware lock elision prefixes.
458 // They are numbers a program passes back to a builtin rather than a claim that the prefix
459 // is emitted, and a program that computes one on a machine where the macro is missing gets
460 // a preprocessor error rather than a slower atomic.
461 if target.tuple.arch() == tuple::Arch::X86_64 {
462 d.set("__ATOMIC_HLE_ACQUIRE", "65536");
463 d.set("__ATOMIC_HLE_RELEASE", "131072");
464 }
465}
466
467/// What the optimizer level says.
468fn optimization(d: &mut Defs, opts: &Predef) {
469 d.flag_if(opts.opt_level.runs_optimizer(), "__OPTIMIZE__");
470 d.flag_if(opts.opt_level.is_size(), "__OPTIMIZE_SIZE__");
471 // glibc's headers test this before deciding whether to define a function as an inline
472 // wrapper, so getting it wrong changes what a program links against.
473 d.flag_if(!opts.opt_level.runs_optimizer(), "__NO_INLINE__");
474 // Zero, and one under `-ffinite-math-only`, which `-ffast-math` implies. glibc's `math.h`
475 // reads it to decide whether to declare the `__*_finite` aliases, so it has to be defined
476 // rather than merely not claimed: a header testing `#if __FINITE_MATH_ONLY__ > 0` on a
477 // compiler that leaves it undefined takes the same branch, but one writing `#if
478 // !__FINITE_MATH_ONLY__` is a different question and gcc gives it an answer.
479 let math = &opts.math;
480 let trapping = opts.trapping_math;
481 d.set("__FINITE_MATH_ONLY__", if math.finite_only { "1" } else { "0" });
482 // One macro per licence, each defined only when it was given, which is how gcc 16 spells
483 // them. `__FAST_MATH__` is all of them at once and is worked out rather than remembered from
484 // the flag, so `-ffast-math -ftrapping-math` does not claim it, and regrouping is the one gcc
485 // drops unless nothing could tell it happened.
486 d.flag_if(math.fast(trapping), "__FAST_MATH__");
487 d.flag_if(!math.errno, "__NO_MATH_ERRNO__");
488 d.flag_if(!trapping, "__NO_TRAPPING_MATH__");
489 d.flag_if(!math.signed_zeros, "__NO_SIGNED_ZEROS__");
490 d.flag_if(math.reciprocal, "__RECIPROCAL_MATH__");
491 d.flag_if(math.associative(trapping), "__ASSOCIATIVE_MATH__");
492}
493
494/// The architecture, the operating system and the object format.
495fn platform(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
496 // The macros a target with no backend predefines are not written down here. They are a
497 // header's whole view of the machine, a wrong one is a header taking a branch written for
498 // another processor, and there is nothing cheap that would catch it. The driver takes a three
499 // field triple, so a target this cannot spell is one nobody can ask for yet rather than a
500 // hole in what it answers.
501 let Some(triple) = Triple::from_tuple(target.tuple) else {
502 return;
503 };
504 match triple.arch {
505 Arch::X86_64 => {
506 d.flag("__x86_64__");
507 d.flag("__x86_64");
508 d.flag("__amd64__");
509 d.flag("__amd64");
510 // One macro per extension the unit is built for, which is `__SSE__`, `__SSE2__`,
511 // `__MMX__` and `__FXSR__` for the baseline every x86-64 has, and `__SSE4_2__` and
512 // its relatives for what `-march=` and `-msse4.2` add. Only the extensions this
513 // compiler has the intrinsics for get one, see `rucc_target::isa`.
514 for name in opts.isa.macros() {
515 d.flag(&name);
516 }
517 d.flag("__SSE_MATH__");
518 d.flag("__SSE2_MATH__");
519 d.flag("__k8");
520 d.flag("__k8__");
521 // The small code model, which is the default and the only one a program gets without
522 // being told otherwise.
523 d.flag("__code_model_small__");
524 // The MMX registers are not used on x86-64: the sixty four bit operations go
525 // through SSE instead. gcc's own `xmmintrin.h` reads this to decide how to write
526 // `_mm_maskmove_si64`, so a compiler that leaves it undefined is handed a
527 // different function body than gcc is, which is what the header sweep found.
528 d.flag("__MMX_WITH_SSE__");
529 }
530 Arch::Aarch64 => {
531 d.flag("__aarch64__");
532 d.flag("__AARCH64EL__");
533 d.set("__ARM_ARCH", "8");
534 d.set("__ARM_ARCH_PROFILE", "'A'");
535 d.set("__ARM_64BIT_STATE", "1");
536 d.set("__ARM_ALIGN_MAX_PWR", "28");
537 d.set("__ARM_FP", "0xe");
538 d.set("__ARM_NEON", "1");
539 d.set("__ARM_FEATURE_UNALIGNED", "1");
540 d.set("__ARM_PCS_AAPCS64", "1");
541 // The rest of what gcc says for a plain Armv8-A. Every one is an instruction the
542 // base architecture has, so none of them depends on a `-march` this compiler does
543 // not take yet, and a program that tests one to choose `__builtin_clz` or a
544 // hardware divide over a portable loop takes the same branch it takes under gcc.
545 d.set("__ARM_ARCH_8A", "1");
546 d.set("__ARM_ARCH_ISA_A64", "1");
547 d.set("__ARM_FEATURE_CLZ", "1");
548 d.set("__ARM_FEATURE_FMA", "1");
549 d.set("__ARM_FEATURE_IDIV", "1");
550 d.set("__ARM_FEATURE_NUMERIC_MAXMIN", "1");
551 d.set("__ARM_ALIGN_MAX_STACK_PWR", "16");
552 d.set("__ARM_SIZEOF_MINIMAL_ENUM", "4");
553 d.set("__ARM_SIZEOF_WCHAR_T", "4");
554 d.set("__AARCH64_CMODEL_SMALL__", "1");
555 // A fused multiply add is one instruction here, and glibc's `math.h` turns these
556 // into `FP_FAST_FMA` and `FP_FAST_FMAF`, which a program reads to decide whether
557 // calling `fma` is cheaper than writing the product and the sum apart.
558 for name in ["", "F", "F32", "F64", "F32x"] {
559 d.set(&format!("__FP_FAST_FMA{name}"), "1");
560 }
561 }
562 Arch::Riscv64 => {
563 d.flag("__riscv");
564 d.set("__riscv_xlen", "64");
565 d.set("__riscv_flen", "64");
566 d.flag("__riscv_float_abi_double");
567 d.flag("__riscv_muldiv");
568 d.flag("__riscv_atomic");
569 d.flag("__riscv_compressed");
570 d.set("__riscv_cmodel_medlow", "1");
571 }
572 }
573 match triple.os {
574 Os::Linux => {
575 d.flag("__linux__");
576 d.flag("__linux");
577 d.flag("__unix__");
578 d.flag("__unix");
579 d.flag("__gnu_linux__");
580 d.flag("__ELF__");
581 // The unarmoured spellings are not reserved identifiers, so a strict mode may not
582 // define them. Autoconf still tests for `linux`, which is why they exist at all.
583 if opts.gnu_extensions {
584 d.flag("linux");
585 d.flag("unix");
586 }
587 }
588 Os::Darwin => {
589 // No `__unix__`, `__unix` or `unix`. clang for Apple defines none of them, and code
590 // that tests `__unix__` before `__APPLE__` takes the path written for Linux, where
591 // it reaches for `<linux/...>` headers or `/proc` and fails at build time or at
592 // run time. What a Mac is identified by is `__APPLE__` and `__MACH__`.
593 d.flag("__APPLE__");
594 d.flag("__MACH__");
595 d.set("__APPLE_CC__", "6000");
596 d.set("__DYNAMIC__", "1");
597 if triple.arch == Arch::Aarch64 {
598 // Apple's own spelling of the architecture, which its headers use rather than
599 // __aarch64__. sys/cdefs.h tests for it by name and reaches an #error called
600 // "Unsupported architecture" without it, so every system header on this
601 // platform fails on the first include until these two are here.
602 d.flag("__arm64__");
603 d.flag("__arm64");
604 // Older Apple spellings that the SDK still reads. `arm/arch.h` sets its own
605 // `_ARM_ARCH_*` family from `__ARM64_ARCH_8__`, and a header that tests
606 // `__ARM_NEON__` rather than `__ARM_NEON` is taking the portable path without
607 // the Advanced SIMD one. clang defines all three for every Apple arm64 target.
608 d.flag("__ARM64_ARCH_8__");
609 d.flag("__ARM_NEON__");
610 d.flag("__AARCH64_SIMD__");
611 }
612 // clang says this on every little endian target and gcc says it on none, which is
613 // why it is here rather than beside the byte order macros. Apple's headers were
614 // written for clang alone, and `CFByteOrder.h` and `architecture/byte_order.h` both
615 // choose their swaps from it.
616 d.flag("__LITTLE_ENDIAN__");
617 deployment_target(d, target);
618 }
619 Os::Windows => {
620 // Every spelling gcc has for this platform, because the mingw-w64 tree reads more
621 // than one of them and a missing one is a declaration that quietly is not there.
622 // `winuser.h` guards `EndTask` with `#ifdef WINNT` and `rpcdcep.h` guards six
623 // declarations with `#ifndef WINNT`, so a compiler that leaves it undefined
624 // preprocesses `windows.h` to a different set of functions than gcc does, which is
625 // what the token comparison against a real mingw install found.
626 d.flag("_WIN32");
627 d.flag("__WIN32");
628 d.flag("__WIN32__");
629 d.flag("__WINNT");
630 d.flag("__WINNT__");
631 d.flag("__MINGW32__");
632 // Not the machine word: `_WIN64` says the pointer is sixty four bits wide, and
633 // i686-w64-mingw32-gcc defines neither it nor `__MINGW64__`.
634 if target.pointer_width == 64 {
635 d.flag("_WIN64");
636 d.flag("__WIN64");
637 d.flag("__WIN64__");
638 d.flag("__MINGW64__");
639 }
640 // Which kind of exception machinery the platform has, and on this one there is only
641 // the one: a table the operating system reads rather than anything the prologue
642 // registers. mingw's `setjmp.h` reads this to choose the two argument `_setjmp`,
643 // whose second argument is `__builtin_frame_address(0)` and becomes the frame
644 // `longjmp` asks `RtlUnwindEx` to unwind to. That is the same address the function's
645 // own unwind record reports, because the record names the frame pointer with an
646 // offset of zero and the prologue leaves the pointer holding the body's stack
647 // pointer, so the number the builtin answers with and the number the walk arrives at
648 // are the same number by construction. Only for the architecture whose records this
649 // compiler writes: x86_64-w64-mingw32-gcc defines it and i686-w64-mingw32-gcc does
650 // not, because a thirty two bit Windows unwinds some other way.
651 if triple.arch == Arch::X86_64 && target.pointer_width == 64 {
652 d.flag("__SEH__");
653 }
654 // Which C runtime the headers are configured for. The sysroot this compiler fetches
655 // is built `--with-default-msvcrt=msvcrt` to match the link line, which names
656 // `libmsvcrt.a`, and gcc defines this for the same tree.
657 d.flag("__MSVCRT__");
658 // The widest integer the compiler has, which is what Microsoft's headers ask
659 // instead of asking about `long long`.
660 d.set("_INTEGRAL_MAX_BITS", "64");
661 // The unarmoured three, which are not reserved identifiers, so a strict mode may
662 // not define them and gcc does not. Windows code tests all three anyway, the same
663 // way portable Unix code still tests `linux`.
664 if opts.gnu_extensions {
665 d.flag("WIN32");
666 d.flag("WINNT");
667 if target.pointer_width == 64 {
668 d.flag("WIN64");
669 }
670 }
671 windows_spellings(d, opts);
672 }
673 Os::None => {
674 // Freestanding. `__ELF__` still holds, because the object format is a property of
675 // the target rather than of having an operating system under it.
676 d.flag("__ELF__");
677 }
678 }
679 match triple.env {
680 Env::Musl => d.flag("__musl__"),
681 Env::Gnu | Env::None | Env::Msvc => {}
682 }
683 // The version of the libc's headers, and only when they are the tree we bundle. One tree serves
684 // every glibc release with the differences written as `#if __GLIBC_MINOR__ >= n` inside the
685 // files, so the release is the part of it the target supplies and the compiler is what supplies
686 // it. Zig patches the same macro into the same tree the same way, which is where the spelling
687 // comes from rather than from a scheme of ours: `__GLIBC_PREREQ` reads it and so does every
688 // autoconf probe ever written.
689 //
690 // The condition is the whole of it and it is not here. A host glibc defines this macro in its
691 // own `features.h` and so does a tree the user named, and a second definition with a different
692 // value is a warning on every compilation, so the driver decides and this writes down what it
693 // decided.
694 if let Some(minor) = opts.glibc_minor {
695 d.set("__GLIBC_MINOR__", &minor.to_string());
696 }
697 // LP64 is the model everywhere except Windows, and a great deal of code tests for it
698 // rather than testing pointer and long widths separately.
699 if target.long_width == 64 && target.pointer_width == 64 {
700 d.flag("__LP64__");
701 d.flag("_LP64");
702 }
703 // What the assembler prepends to a C name to get the symbol. Mach-O keeps the leading
704 // underscore that every a.out toolchain had and ELF dropped it. It has to be defined even
705 // where it is empty, because of how it is used: glibc writes `__asm__ (__ASMNAME (name))`
706 // and that stringifies `__USER_LABEL_PREFIX__`, so a compiler that leaves it undefined
707 // does not get an error, it gets the name of the macro as the string and renames the
708 // function.
709 d.set("__USER_LABEL_PREFIX__", if triple.os == Os::Darwin { "_" } else { "" });
710 // Its counterpart, what the assembler puts in front of a register name. Empty on every
711 // target here, since all three assemble in a syntax that does not mark registers, and
712 // defined anyway for the same reason as the line above: it is used inside a stringize.
713 d.set("__REGISTER_PREFIX__", "");
714
715 // Position independent code is the default on the ELF targets and on Apple's, which is
716 // what a distribution build expects. The value 2 is GCC's for `-fPIC` rather than `-fpic`.
717 //
718 // Both are defined whichever link the output is for, because `__PIC__` says there are no
719 // absolute addresses in the text and that is true either way. What says which link it is is
720 // `__PIE__`, and a program reads it to find out whether a name it exports is one something
721 // else may replace. gcc defines it under `-fPIE` and under the default on a distribution
722 // where the default is an executable, which is the default here too.
723 if !matches!(triple.os, Os::Windows) {
724 d.set("__PIC__", "2");
725 d.set("__pic__", "2");
726 if opts.pic == Pic::Executable {
727 d.set("__PIE__", "2");
728 d.set("__pie__", "2");
729 }
730 }
731}
732
733/// The five spellings a Windows header writes a calling convention and an attribute in.
734///
735/// `int __cdecl f(void);` is the second declaration in mingw-w64's `stdio.h` and it stops a parser
736/// that has never heard of `__cdecl`, which reads it as the name being declared and then finds a
737/// second one. None of the five is a keyword, though: gcc defines every one of them as a macro over
738/// the GNU spelling of the same thing, which is why they are keywords on Windows and nowhere else
739/// without anything in its lexer being told what the target is. `-dM -E` on a mingw-w64 gcc prints
740/// exactly the lines below.
741///
742/// `__declspec(x)` being the GNU spelling of its argument is the part worth saying out loud, since
743/// it means `__declspec(dllimport)` and `__attribute__((dllimport))` cannot come to mean different
744/// things: there is one attribute and two ways of writing it, and everything that reads attributes
745/// reads both.
746///
747/// On x86-64 all four conventions name the one convention the target has, so the attributes go
748/// where every attribute nothing implements goes, which is left on the declaration. On i386 they
749/// differ over who pops the arguments and the choice is written into the symbol name, which is
750/// document 06.5 and is that target's work when there is one.
751/// The deployment target, which is the oldest release of the OS the program is promised to run
752/// on. `Availability.h` reads it through `__ENVIRONMENT_OS_VERSION_MIN_REQUIRED__` and the older
753/// per platform spelling, and turns it into `__MAC_OS_X_VERSION_MIN_REQUIRED`, which the whole
754/// SDK tests to decide which declarations exist and which are marked unavailable. Without it
755/// every one of those tests sees no version at all.
756///
757/// The version comes from the tuple, as in `aarch64-macos.13`, where `-mmacosx-version-min=`
758/// also puts it. With none given this is 11.0 on macOS, the first release that ran on Apple
759/// silicon, and 14.0 on iOS, the oldest a current SDK builds for. The oldest answer is the one
760/// that cannot hand a program a declaration the machine it runs on does not have. The encoding
761/// is two digits each for the major, minor and patch numbers, so 13.4 is 130400.
762fn deployment_target(d: &mut Defs, target: &TargetInfo) {
763 let (platform, default) = match target.tuple.os() {
764 tuple::Os::MacOs => ("MAC_OS_X", tuple::Version::new(11, 0)),
765 tuple::Os::IOs => ("IPHONE_OS", tuple::Version::new(14, 0)),
766 _ => return,
767 };
768 let version = target.tuple.os_version().unwrap_or(default);
769 let encoded = version.major_part() * 10000
770 + version.minor_part().unwrap_or(0) * 100
771 + version.patch_part().unwrap_or(0);
772 d.set(&format!("__ENVIRONMENT_{platform}_VERSION_MIN_REQUIRED__"), &encoded.to_string());
773 d.set("__ENVIRONMENT_OS_VERSION_MIN_REQUIRED__", &encoded.to_string());
774}
775
776fn windows_spellings(d: &mut Defs, opts: &Predef) {
777 for name in ["cdecl", "stdcall", "fastcall", "thiscall"] {
778 d.set(&format!("__{name}"), &format!("__attribute__((__{name}__))"));
779 // The single underscore spellings are not in the reserved namespace, so an implementation
780 // may not take them in a strict ISO mode and gcc does not.
781 if opts.gnu_extensions {
782 d.set(&format!("_{name}"), &format!("__attribute__((__{name}__))"));
783 }
784 }
785 d.set("__declspec(x)", "__attribute__((x))");
786}
787
788/// `__CHAR_BIT__`, the `__SIZEOF_*__` family and the alignment macros.
789fn sizes(d: &mut Defs, target: &TargetInfo) {
790 let pointer = target.pointer_width / 8;
791 // The two hardware interference sizes, which say how far apart two objects have to be for
792 // a write to one not to invalidate the other's cache line, and how close together two have
793 // to be to share one. A cache line is sixty four bytes on every target here, and x86-64
794 // gives that for both. Arm cores have been built with lines up to 256 bytes, so gcc and
795 // clang both give 256 for the distance that has to be safe on any of them.
796 // Apple's cores are the exception that is known exactly, a 128 byte line, and clang for
797 // Apple says 128.
798 let destructive = match (target.tuple.arch(), target.tuple.os()) {
799 (tuple::Arch::Aarch64, tuple::Os::MacOs | tuple::Os::IOs) => "128",
800 (tuple::Arch::Aarch64, _) => "256",
801 _ => "64",
802 };
803 d.set("__GCC_CONSTRUCTIVE_SIZE", "64");
804 d.set("__GCC_DESTRUCTIVE_SIZE", destructive);
805 let long = target.long_width / 8;
806 let long_double = target.long_double_width / 8;
807 d.set("__CHAR_BIT__", "8");
808 d.set("__SIZEOF_SHORT__", "2");
809 d.set("__SIZEOF_INT__", "4");
810 d.set("__SIZEOF_LONG__", &long.to_string());
811 d.set("__SIZEOF_LONG_LONG__", "8");
812 d.set("__SIZEOF_INT128__", "16");
813 d.set("__SIZEOF_FLOAT__", "4");
814 d.set("__SIZEOF_DOUBLE__", "8");
815 d.set("__SIZEOF_LONG_DOUBLE__", &long_double.to_string());
816 // Where the type has its old name and nowhere else, which is gcc's rule and the reason the
817 // macro is the one portable code tests before it writes `__float128`. PowerPC also says
818 // `__FLOAT128__`, which gcc defines there and not on x86.
819 if target.type_names().iter().any(|&(name, _)| name == "__float128") {
820 d.set("__SIZEOF_FLOAT128__", "16");
821 if target.tuple.arch() == tuple::Arch::PowerPc64 {
822 d.set("__FLOAT128__", "1");
823 }
824 }
825 d.set("__SIZEOF_POINTER__", &pointer.to_string());
826 d.set("__SIZEOF_SIZE_T__", &pointer.to_string());
827 d.set("__SIZEOF_PTRDIFF_T__", &pointer.to_string());
828 d.set("__SIZEOF_WCHAR_T__", &wchar(target).size.to_string());
829 // From the spelling rather than from a constant, because Windows makes `wint_t` a
830 // `short unsigned int` and this said four bytes there while `__WINT_WIDTH__` said sixteen
831 // bits two hundred lines away.
832 d.set("__SIZEOF_WINT_T__", &(wint(target).width / 8).to_string());
833 // The alignment of the most aligned scalar, which is `max_align_t`'s. That is sixteen where
834 // `long double` is sixteen bytes and eight on Apple arm64, where it is a `double`. What
835 // `aligned` with no argument gives is a separate number and is sixteen on every target,
836 // clang for Apple included.
837 let biggest = match (target.tuple.arch(), target.tuple.os()) {
838 (tuple::Arch::Aarch64, tuple::Os::MacOs | tuple::Os::IOs) => "8",
839 _ => "16",
840 };
841 d.set("__BIGGEST_ALIGNMENT__", biggest);
842 // The `__BYTE_ORDER__` family, which the kernel and every serialisation library read.
843 // The names of the orders are defined whichever one is in force, because code compares
844 // against both.
845 d.set("__ORDER_LITTLE_ENDIAN__", "1234");
846 d.set("__ORDER_BIG_ENDIAN__", "4321");
847 d.set("__ORDER_PDP_ENDIAN__", "3412");
848 let order =
849 if target.little_endian { "__ORDER_LITTLE_ENDIAN__" } else { "__ORDER_BIG_ENDIAN__" };
850 d.set("__BYTE_ORDER__", order);
851 d.set("__FLOAT_WORD_ORDER__", order);
852 d.flag_if(!target.char_is_signed, "__CHAR_UNSIGNED__");
853}
854
855/// How `wchar_t` is spelled on a target, and what it holds.
856struct Wchar {
857 /// The C type it is a name for.
858 spelling: &'static str,
859 /// Its width in bytes.
860 size: u32,
861 /// `__WCHAR_MAX__`.
862 max: &'static str,
863 /// `__WCHAR_MIN__`.
864 min: &'static str,
865}
866
867/// `wchar_t` is the type that divides the targets most and is written down least.
868///
869/// Windows makes it 16 bits so that a wide string is UTF-16. AArch64 Linux makes it unsigned,
870/// following the psABI's rule for plain `char`, while x86-64 Linux makes it signed. Code that
871/// compares a `wchar_t` against a negative value is correct on one and not on the other.
872///
873/// The width and the signedness come from the target description rather than from another match
874/// on the triple, because the lexer needs the same two facts to convert a wide literal and the
875/// two answers have to be the same one.
876fn wchar(target: &TargetInfo) -> Wchar {
877 match (target.wchar_width, target.wchar_is_signed) {
878 (16, false) => Wchar { spelling: "short unsigned int", size: 2, max: "0xffff", min: "0" },
879 (16, true) => Wchar { spelling: "short int", size: 2, max: "0x7fff", min: "(-32767 - 1)" },
880 (_, false) => Wchar { spelling: "unsigned int", size: 4, max: "0xffffffffU", min: "0U" },
881 (_, true) => {
882 Wchar { spelling: "int", size: 4, max: "0x7fffffff", min: "(-__WCHAR_MAX__ - 1)" }
883 }
884 }
885}
886
887/// How `wint_t` is spelled on a target, and what it holds.
888struct Wint {
889 /// The C type it is a name for.
890 spelling: &'static str,
891 /// `__WINT_MAX__`.
892 max: &'static str,
893 /// `__WINT_MIN__`.
894 min: &'static str,
895 /// `__WINT_WIDTH__`, which follows the spelling rather than `__SIZEOF_WINT_T__`.
896 width: u32,
897}
898
899/// `wint_t` does not follow `wchar_t`, and Darwin is where that shows.
900///
901/// Apple makes it a signed `int`, so that `WEOF` is negative the way `EOF` is, while Linux
902/// makes it `unsigned int` and gives `WEOF` the value `0xffffffff`. The SDK's `arm/_types.h`
903/// spells `__darwin_wint_t` as `__WINT_TYPE__` and nothing else, so getting this wrong changes
904/// the signedness of every wide character function's argument on that platform.
905fn wint(target: &TargetInfo) -> Wint {
906 match target.tuple.os() {
907 tuple::Os::Windows => {
908 Wint { spelling: "short unsigned int", max: "0xffff", min: "0", width: 16 }
909 }
910 os if os.is_darwin() => {
911 Wint { spelling: "int", max: "0x7fffffff", min: "(-__WINT_MAX__ - 1)", width: 32 }
912 }
913 _ => Wint { spelling: "unsigned int", max: "0xffffffffU", min: "0U", width: 32 },
914 }
915}
916
917/// The integer type names, their limits, and the exact width family.
918fn integers(d: &mut Defs, target: &TargetInfo) {
919 // The one fact everything below turns on: which type is 64 bits wide. On LP64 it is
920 // `long`, and on Windows LLP64 it is `long long`, and every `size_t`, `intmax_t` and
921 // `int64_t` spelling follows from that.
922 let lp64 = target.long_width == 64;
923 let wide = if lp64 { "long int" } else { "long long int" };
924 let wide_unsigned = if lp64 { "long unsigned int" } else { "long long unsigned int" };
925 let wide_suffix = if lp64 { "L" } else { "LL" };
926 let wide_max = format!("0x7fffffffffffffff{wide_suffix}");
927 let wide_umax = format!("0xffffffffffffffffU{wide_suffix}");
928 // Apple is LP64 and still makes `int64_t` a `long long`, which `<sys/_types/_int64_t.h>`
929 // writes out by hand. The exact, least and fast sixty four bit types follow it, while
930 // `intmax_t`, `intptr_t` and `size_t` stay `long`. Saying `long` here gave a freestanding
931 // `stdint.h` an `int64_t` that the SDK's own typedef then redefined as a different type.
932 let apple = matches!(target.tuple.os(), tuple::Os::MacOs | tuple::Os::IOs);
933 let (int64, uint64, int64_suffix) = if apple {
934 ("long long int", "long long unsigned int", "LL")
935 } else {
936 (wide, wide_unsigned, wide_suffix)
937 };
938 let int64_max = format!("0x7fffffffffffffff{int64_suffix}");
939 let int64_umax = format!("0xffffffffffffffffU{int64_suffix}");
940
941 d.set("__SCHAR_MAX__", "0x7f");
942 d.set("__SHRT_MAX__", "0x7fff");
943 d.set("__INT_MAX__", "0x7fffffff");
944 d.set("__LONG_MAX__", if lp64 { "0x7fffffffffffffffL" } else { "0x7fffffffL" });
945 d.set("__LONG_LONG_MAX__", "0x7fffffffffffffffLL");
946 d.set("__INTMAX_MAX__", &wide_max);
947 d.set("__UINTMAX_MAX__", &wide_umax);
948 d.set("__SIZE_MAX__", &wide_umax);
949 d.set("__PTRDIFF_MAX__", &wide_max);
950 d.set("__INTPTR_MAX__", &wide_max);
951 d.set("__UINTPTR_MAX__", &wide_umax);
952 d.set("__SIG_ATOMIC_MAX__", "0x7fffffff");
953 d.set("__SIG_ATOMIC_MIN__", "(-__SIG_ATOMIC_MAX__ - 1)");
954 // The widest `_BitInt` this compiler builds, which is narrower than gcc 16's sixty five
955 // thousand five hundred and thirty five because a folded constant here is a hundred and
956 // twenty eight bits wide. A program that reads this macro to decide what to write gets an
957 // answer it can rely on, which is the point of saying a number smaller than gcc's rather
958 // than saying gcc's and refusing what it asked for. `MAX_BIT_INT_WIDTH` in `rucc-sema` is
959 // the same number and has to be changed with it.
960 d.set("__BITINT_MAXWIDTH__", "128");
961
962 let wchar = wchar(target);
963 d.set("__WCHAR_TYPE__", wchar.spelling);
964 d.set("__WCHAR_MAX__", wchar.max);
965 d.set("__WCHAR_MIN__", wchar.min);
966 let wint = wint(target);
967 d.set("__WINT_TYPE__", wint.spelling);
968 d.set("__WINT_MAX__", wint.max);
969 d.set("__WINT_MIN__", wint.min);
970 d.set("__SIZE_TYPE__", wide_unsigned);
971 d.set("__PTRDIFF_TYPE__", wide);
972 d.set("__INTMAX_TYPE__", wide);
973 d.set("__UINTMAX_TYPE__", wide_unsigned);
974 d.set("__INTPTR_TYPE__", wide);
975 d.set("__UINTPTR_TYPE__", wide_unsigned);
976 d.set("__SIG_ATOMIC_TYPE__", "int");
977 d.set("__CHAR16_TYPE__", "short unsigned int");
978 d.set("__CHAR32_TYPE__", "unsigned int");
979 d.set("__INTMAX_C(c)", &format!("c ## {wide_suffix}"));
980 d.set("__UINTMAX_C(c)", &format!("c ## U{wide_suffix}"));
981
982 // The exact width family, which is what a freestanding `stdint.h` is written out of.
983 exact(d, 8, "signed char", "unsigned char", "0x7f", "0xff", "");
984 exact(d, 16, "short int", "short unsigned int", "0x7fff", "0xffff", "");
985 // No suffix. An `int` needs none, and the `U` on the unsigned side is added by `exact`
986 // rather than being part of the width.
987 exact(d, 32, "int", "unsigned int", "0x7fffffff", "0xffffffffU", "");
988 exact(d, 64, int64, uint64, &int64_max, &int64_umax, int64_suffix);
989
990 // The fast types. GCC makes the 16 and 32 bit ones `long` on sixty four bit glibc, which
991 // is what glibc's `stdint.h` says under `__WORDSIZE == 64` whatever the processor, and
992 // `int` everywhere else. A header that computes a printf format from the type name notices
993 // the difference. gcc for aarch64, riscv64, powerpc64le and s390x all say `long int`.
994 //
995 // musl is the reason this is not simply a question of the architecture. musl defines
996 // `int_fast16_t` and `int_fast32_t` as `int32_t` on every target it supports, GCC built
997 // for a musl target agrees with it, and GCC built for glibc on the same processor does
998 // not. The place it shows is `stdatomic.h`, which GCC ships and writes directly out of
999 // these macros: `typedef _Atomic __INT_FAST16_TYPE__ atomic_int_fast16_t;`. Get this wrong
1000 // and every atomic fast type in the program is the wrong width.
1001 let fast_is_wide =
1002 target.tuple.os() == tuple::Os::Linux && lp64 && target.tuple.env() != tuple::Env::Musl;
1003 let fast_middle = if fast_is_wide { wide } else { "int" };
1004 // Windows is the exception in the other direction, and it is only the 16 bit one. mingw's
1005 // `stdint.h` makes `int_fast16_t` a `short` and gcc for that target says the same, while
1006 // `int_fast32_t` there is the `int` it is nearly everywhere, so the two cannot share an
1007 // answer on this platform the way they do on the others. The measurement is the mingw tree,
1008 // which is the only Windows header tree this compiler fetches, and the msvc environment is
1009 // given the same answer because nothing compiles against a tree of Microsoft's yet. Apple's
1010 // `stdint.h` is the same shape, `int16_t` for the 16 bit one and `int32_t` for the other.
1011 let fast16_is_short =
1012 matches!(target.tuple.os(), tuple::Os::Windows | tuple::Os::MacOs | tuple::Os::IOs);
1013 d.set("__INT_FAST8_TYPE__", "signed char");
1014 d.set("__UINT_FAST8_TYPE__", "unsigned char");
1015 d.set("__INT_FAST8_MAX__", "0x7f");
1016 d.set("__UINT_FAST8_MAX__", "0xff");
1017 for width in [16, 32] {
1018 let (signed, unsigned, max, umax) = if width == 16 && fast16_is_short {
1019 ("short int", "short unsigned int", "0x7fff", "0xffff")
1020 } else if fast_middle == "int" {
1021 ("int", "unsigned int", "0x7fffffff", "0xffffffffU")
1022 } else {
1023 (wide, wide_unsigned, wide_max.as_str(), wide_umax.as_str())
1024 };
1025 d.set(&format!("__INT_FAST{width}_TYPE__"), signed);
1026 d.set(&format!("__UINT_FAST{width}_TYPE__"), unsigned);
1027 d.set(&format!("__INT_FAST{width}_MAX__"), max);
1028 d.set(&format!("__UINT_FAST{width}_MAX__"), umax);
1029 }
1030 d.set("__INT_FAST64_TYPE__", int64);
1031 d.set("__UINT_FAST64_TYPE__", uint64);
1032 d.set("__INT_FAST64_MAX__", &int64_max);
1033 d.set("__UINT_FAST64_MAX__", &int64_umax);
1034
1035 let fast32 = if fast_is_wide { 64 } else { 32 };
1036 widths(d, target, &wchar, &wint, if fast16_is_short { 16 } else { fast32 }, fast32);
1037}
1038
1039/// The widths, which C23's `limits.h` and `stdint.h` are written out of.
1040///
1041/// Twenty macros and not a few more: there is no `__INT8_WIDTH__`, because the width of an
1042/// exact width type is in its name and gcc does not define one, and there is no unsigned member
1043/// of any of these pairs, because a signed type and its unsigned counterpart have the same
1044/// width and `UINTMAX_WIDTH` is written `__INTMAX_WIDTH__` in every header that needs it.
1045///
1046/// Each of these says how many value bits and sign bits the type has, which is not the same as
1047/// how many bits it occupies. They agree for every type on every target here, and the day one of
1048/// them does not, this is the family that has to say the smaller number.
1049fn widths(d: &mut Defs, target: &TargetInfo, wchar: &Wchar, wint: &Wint, fast16: u32, fast32: u32) {
1050 let pointer = target.pointer_width;
1051 d.set("__SCHAR_WIDTH__", "8");
1052 d.set("__SHRT_WIDTH__", "16");
1053 d.set("__INT_WIDTH__", "32");
1054 d.set("__LONG_WIDTH__", &target.long_width.to_string());
1055 d.set("__LONG_LONG_WIDTH__", "64");
1056 d.set("__INTMAX_WIDTH__", "64");
1057 d.set("__INTPTR_WIDTH__", &pointer.to_string());
1058 d.set("__PTRDIFF_WIDTH__", &pointer.to_string());
1059 d.set("__SIZE_WIDTH__", &pointer.to_string());
1060 d.set("__SIG_ATOMIC_WIDTH__", "32");
1061 d.set("__WCHAR_WIDTH__", &(wchar.size * 8).to_string());
1062 d.set("__WINT_WIDTH__", &wint.width.to_string());
1063 for width in [8, 16, 32, 64] {
1064 d.set(&format!("__INT_LEAST{width}_WIDTH__"), &width.to_string());
1065 }
1066 d.set("__INT_FAST8_WIDTH__", "8");
1067 d.set("__INT_FAST16_WIDTH__", &fast16.to_string());
1068 d.set("__INT_FAST32_WIDTH__", &fast32.to_string());
1069 d.set("__INT_FAST64_WIDTH__", "64");
1070}
1071
1072/// One width of the exact and least families, which are the same types.
1073fn exact(
1074 d: &mut Defs,
1075 width: u32,
1076 signed: &str,
1077 unsigned: &str,
1078 max: &str,
1079 umax: &str,
1080 // The suffix the width needs and nothing more, so `""`, `"L"` or `"LL"`. The `U` that
1081 // makes a constant unsigned is added below and is not part of this, because a caller that
1082 // wrote it here would produce `UU` on the unsigned macro and a stray `U` on the signed one.
1083 width_suffix: &str,
1084) {
1085 d.set(&format!("__INT{width}_TYPE__"), signed);
1086 d.set(&format!("__UINT{width}_TYPE__"), unsigned);
1087 d.set(&format!("__INT{width}_MAX__"), max);
1088 d.set(&format!("__UINT{width}_MAX__"), umax);
1089 d.set(&format!("__INT_LEAST{width}_TYPE__"), signed);
1090 d.set(&format!("__UINT_LEAST{width}_TYPE__"), unsigned);
1091 d.set(&format!("__INT_LEAST{width}_MAX__"), max);
1092 d.set(&format!("__UINT_LEAST{width}_MAX__"), umax);
1093 // The constant makers. `__INT8_C(1)` is `1` and not `1 ## `, because a paste with nothing
1094 // on the right is not a token the expander should have to think about.
1095 //
1096 // The `U` goes on only where the type is still unsigned after promotion. `uint8_t` and
1097 // `uint16_t` are narrower than `int`, so an integer promotion turns them into a signed
1098 // `int` and `UINT8_C(1)` has that type in gcc and in the standard's own words. Writing
1099 // `1U` there is not a harmless extra: `UINT8_C(1) - 2` comes out as four billion odd
1100 // instead of minus one, and a `_Generic` on it picks the unsigned arm. Every target this
1101 // compiler has makes `int` thirty two bits, which is what makes the width enough to decide.
1102 let unsigned_after_promotion = width >= 32;
1103 let u = if unsigned_after_promotion { "U" } else { "" };
1104 if width_suffix.is_empty() && u.is_empty() {
1105 d.set(&format!("__INT{width}_C(c)"), "c");
1106 d.set(&format!("__UINT{width}_C(c)"), "c");
1107 } else if width_suffix.is_empty() {
1108 d.set(&format!("__INT{width}_C(c)"), "c");
1109 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}"));
1110 } else {
1111 d.set(&format!("__INT{width}_C(c)"), &format!("c ## {width_suffix}"));
1112 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}{width_suffix}"));
1113 }
1114}
1115
1116/// What a header needs to know about one floating format, as the text the macros expand to.
1117///
1118/// The four values are written to the digit gcc writes them to rather than rounded to something
1119/// tidier, because a header carrying its own copy of a limit compares the two spellings and a
1120/// difference in the last place is a difference.
1121struct Characteristics {
1122 mant_dig: &'static str,
1123 dig: &'static str,
1124 min_exp: &'static str,
1125 min_10_exp: &'static str,
1126 max_exp: &'static str,
1127 max_10_exp: &'static str,
1128 decimal_dig: &'static str,
1129 max: &'static str,
1130 /// The largest value with a full significand, which is `max` for every format whose values
1131 /// all have one and is smaller for the double-double, whose largest values do not.
1132 ///
1133 /// A double-double's high half can be as large as a `double` gets while its low half is
1134 /// nowhere near, and the sum is then a number above anything the format can write with a
1135 /// hundred and six significand bits behind it. So `LDBL_MAX` on PowerPC is `DBL_MAX` and
1136 /// `LDBL_NORM_MAX` is a bit under half of it, and a program that reaches for the largest
1137 /// value it can compute with wants the second.
1138 norm_max: &'static str,
1139 min: &'static str,
1140 epsilon: &'static str,
1141 denorm_min: &'static str,
1142 /// Whether the format is one IEC 60559 describes, which every one of them is but the brain
1143 /// float, whose significand is a `float`'s with sixteen bits cut off the end of it, and the
1144 /// double-double, which is not a binary floating point format in IEC 60559's sense at all.
1145 is_iec_60559: &'static str,
1146}
1147
1148/// IEEE binary16, which is `_Float16`.
1149const HALF: Characteristics = Characteristics {
1150 mant_dig: "11",
1151 dig: "3",
1152 min_exp: "(-13)",
1153 min_10_exp: "(-4)",
1154 max_exp: "16",
1155 max_10_exp: "4",
1156 decimal_dig: "5",
1157 max: "6.55040000000000000000000000000000000e+4",
1158 norm_max: "6.55040000000000000000000000000000000e+4",
1159 min: "6.10351562500000000000000000000000000e-5",
1160 epsilon: "9.76562500000000000000000000000000000e-4",
1161 denorm_min: "5.96046447753906250000000000000000000e-8",
1162 is_iec_60559: "1",
1163};
1164
1165/// The brain float, which nothing here names yet and which every format table has a row for.
1166const BFLOAT16: Characteristics = Characteristics {
1167 mant_dig: "8",
1168 dig: "2",
1169 min_exp: "(-125)",
1170 min_10_exp: "(-37)",
1171 max_exp: "128",
1172 max_10_exp: "38",
1173 decimal_dig: "4",
1174 max: "3.38953138925153547590470800371487867e+38",
1175 norm_max: "3.38953138925153547590470800371487867e+38",
1176 min: "1.17549435082228750796873653722224568e-38",
1177 epsilon: "7.81250000000000000000000000000000000e-3",
1178 denorm_min: "9.18354961579912115600575419704879436e-41",
1179 is_iec_60559: "0",
1180};
1181
1182/// IEEE binary32, which is `float` and `_Float32`.
1183const SINGLE: Characteristics = Characteristics {
1184 mant_dig: "24",
1185 dig: "6",
1186 min_exp: "(-125)",
1187 min_10_exp: "(-37)",
1188 max_exp: "128",
1189 max_10_exp: "38",
1190 decimal_dig: "9",
1191 max: "3.40282346638528859811704183484516925e+38",
1192 norm_max: "3.40282346638528859811704183484516925e+38",
1193 min: "1.17549435082228750796873653722224568e-38",
1194 epsilon: "1.19209289550781250000000000000000000e-7",
1195 denorm_min: "1.40129846432481707092372958328991613e-45",
1196 is_iec_60559: "1",
1197};
1198
1199/// IEEE binary64, which is `double`, `_Float64`, `_Float32x` and `long double` on Apple and
1200/// on Windows.
1201const DOUBLE: Characteristics = Characteristics {
1202 mant_dig: "53",
1203 dig: "15",
1204 min_exp: "(-1021)",
1205 min_10_exp: "(-307)",
1206 max_exp: "1024",
1207 max_10_exp: "308",
1208 decimal_dig: "17",
1209 max: "1.79769313486231570814527423731704357e+308",
1210 norm_max: "1.79769313486231570814527423731704357e+308",
1211 min: "2.22507385850720138309023271733240406e-308",
1212 epsilon: "2.22044604925031308084726333618164062e-16",
1213 denorm_min: "4.94065645841246544176568792868221372e-324",
1214 is_iec_60559: "1",
1215};
1216
1217/// The x87 eighty bit format, which on x86-64 is both `long double` and `_Float64x`.
1218const X87: Characteristics = Characteristics {
1219 mant_dig: "64",
1220 dig: "18",
1221 min_exp: "(-16381)",
1222 min_10_exp: "(-4931)",
1223 max_exp: "16384",
1224 max_10_exp: "4932",
1225 decimal_dig: "21",
1226 max: "1.18973149535723176502126385303097021e+4932",
1227 norm_max: "1.18973149535723176502126385303097021e+4932",
1228 min: "3.36210314311209350626267781732175260e-4932",
1229 epsilon: "1.08420217248550443400745280086994171e-19",
1230 denorm_min: "3.64519953188247460252840593361941982e-4951",
1231 is_iec_60559: "1",
1232};
1233
1234/// IEEE binary128, which is `_Float128`, `_Float64x` off x86 and `long double` on AArch64 and
1235/// RISC-V Linux.
1236const QUAD: Characteristics = Characteristics {
1237 mant_dig: "113",
1238 dig: "33",
1239 min_exp: "(-16381)",
1240 min_10_exp: "(-4931)",
1241 max_exp: "16384",
1242 max_10_exp: "4932",
1243 decimal_dig: "36",
1244 max: "1.18973149535723176508575932662800702e+4932",
1245 norm_max: "1.18973149535723176508575932662800702e+4932",
1246 min: "3.36210314311209350626267781732175260e-4932",
1247 epsilon: "1.92592994438723585305597794258492732e-34",
1248 denorm_min: "6.47517511943802511092443895822764655e-4966",
1249 is_iec_60559: "1",
1250};
1251
1252/// IBM double-double, which is `long double` on 64-bit PowerPC.
1253///
1254/// The row that does not follow from a precision and an exponent range, because the format has
1255/// neither. `MANT_DIG` is 106 and `DIG` is 31, which are the figures near the top of the
1256/// significand and not everywhere. `MAX` is a little above `DBL_MAX`, since the high half can be
1257/// `DBL_MAX` and the low half then adds to it, and `NORM_MAX` is about half of that, so this is
1258/// the one row where the two are different numbers. `EPSILON` is the same number as `DENORM_MIN`,
1259/// two to the minus one thousand and seventy four, because the smallest value that changes a
1260/// double-double near one is a subnormal in the low half rather than one unit in the last place
1261/// of anything. `MIN` is two to the minus nine hundred and sixty nine rather than `DBL_MIN`,
1262/// because below that the low half has no room left to be normal in.
1263///
1264/// Every value here is what the reference compiler prints for `powerpc64le-linux-gnu`, checked
1265/// rather than derived, on the same terms as the data layouts in `rucc-abi`. The format is one
1266/// where deriving them is how the four wrong numbers in those layouts happened.
1267const DOUBLE_DOUBLE: Characteristics = Characteristics {
1268 mant_dig: "106",
1269 dig: "31",
1270 min_exp: "(-968)",
1271 min_10_exp: "(-291)",
1272 max_exp: "1024",
1273 max_10_exp: "308",
1274 decimal_dig: "33",
1275 max: "1.79769313486231580793728971405301e+308",
1276 norm_max: "8.98846567431157953864652595394501e+307",
1277 min: "2.00416836000897277799610805135016e-292",
1278 epsilon: "4.94065645841246544176568792868221e-324",
1279 denorm_min: "4.94065645841246544176568792868221e-324",
1280 is_iec_60559: "0",
1281};
1282
1283/// The row of the table a format has, so that a type the target chooses the format of can look
1284/// its own limits up rather than have them written out again per architecture.
1285const fn characteristics(format: Format) -> &'static Characteristics {
1286 match format {
1287 Format::Half => &HALF,
1288 Format::BFloat16 => &BFLOAT16,
1289 Format::Single => &SINGLE,
1290 Format::Double => &DOUBLE,
1291 Format::X87Extended => &X87,
1292 Format::Quad => &QUAD,
1293 Format::DoubleDouble => &DOUBLE_DOUBLE,
1294 // No target has a decimal `long double` or `_Float64x`, which are the two rows a target
1295 // chooses, and the decimal types have `__DEC*` macros of their own rather than a row here.
1296 Format::Decimal32 | Format::Decimal64 | Format::Decimal128 => {
1297 panic!("a binary type's format is never a decimal one")
1298 }
1299 }
1300}
1301
1302/// The `float.h` characteristics.
1303///
1304/// Nine families of them, which is `float`, `double` and `long double` and the six C23 named
1305/// them after. Two of the nine have a format the target decides: `long double`, which is x87 on
1306/// x86-64 Linux, quad on AArch64 and RISC-V Linux and a `double` on Apple and on Windows, and
1307/// `_Float64x`, which is the widest format the processor has and so does not follow `long
1308/// double` down on the targets that shrink it.
1309///
1310/// Three more have a target that decides whether they are there at all. `_Float64x` is missing
1311/// on a machine with nothing wider than a `double`, and `_Float16` and `_Float128` are missing
1312/// wherever the machine has no such format, which is four of the seven rows for the half and one
1313/// of them for the quad.
1314///
1315/// `__FLT128X_*__` is deliberately missing. `_Float128x` is a type no target gcc supports has,
1316/// so gcc defines nothing for it and neither does this.
1317fn floats(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
1318 d.set("__FLT_RADIX__", "2");
1319 // Real arithmetic follows IEC 60559 in every format on every target here, which is what the
1320 // value two says. The complex one beside it says the same about complex arithmetic, and gcc
1321 // gives both the value two on every target this compiler has. These two are read rather than
1322 // tested: glibc's `<stdc-predef.h>` asks what the compiler intended and writes the
1323 // `__STDC_IEC_559` family from the answer, and a compiler that says nothing is presumed to
1324 // have meant yes. So the choice is not between claiming and not claiming, it is between
1325 // saying so and having it said for us. Zero for both once a fast math licence is given,
1326 // which is gcc's answer and what keeps glibc from claiming the family on our behalf.
1327 let iec = if opts.math.iec_559(opts.trapping_math) { "2" } else { "0" };
1328 d.set("__GCC_IEC_559", iec);
1329 d.set("__GCC_IEC_559_COMPLEX", iec);
1330 // Every operation is done in the type of its operands, which is what SSE2 and the AArch64
1331 // and RISC-V floating units all do. The other two names are the same answer asked under the
1332 // rules of C99 and of TS 18661-3, which are the same rules for a target with no excess
1333 // precision to have, and glibc's `<math.h>` reads the last of the three.
1334 d.set("__FLT_EVAL_METHOD__", "0");
1335 d.set("__FLT_EVAL_METHOD_C99__", "0");
1336 d.set("__FLT_EVAL_METHOD_TS_18661_3__", "0");
1337
1338 family(d, "FLT", &SINGLE, |value| format!("{value}F"));
1339 // gcc writes the `double` values as `long double` constants cast back down, which is exact
1340 // in every format `long double` has and is the one family whose values are not a suffix.
1341 family(d, "DBL", &DOUBLE, |value| format!("((double){value}L)"));
1342 family(d, "LDBL", characteristics(target.long_double_format), |value| format!("{value}L"));
1343
1344 // The two named types that are not on every machine, each written where the type is and left
1345 // out where it is not. A program reads `__FLT128_MANT_DIG__` to find out whether it may write
1346 // the type, which is what glibc's `<float.h>` and `<math.h>` do, so the macros and the type
1347 // have to agree or the header asks for something the compiler will refuse.
1348 if target.has_float16 {
1349 family(d, "FLT16", &HALF, |value| format!("{value}F16"));
1350 }
1351 family(d, "FLT32", &SINGLE, |value| format!("{value}F32"));
1352 family(d, "FLT64", &DOUBLE, |value| format!("{value}F64"));
1353 if target.has_float128 {
1354 family(d, "FLT128", &QUAD, |value| format!("{value}F128"));
1355 }
1356 family(d, "FLT32X", &DOUBLE, |value| format!("{value}F32x"));
1357 // Nothing at all on a target whose widest format is a `double`, which is what gcc does
1358 // there: `_Float64x` is not a type on that machine and the family that describes it is not a
1359 // set of macros with a smaller answer in them.
1360 if let Some(format) = target.float64x_format {
1361 family(d, "FLT64X", characteristics(format), |value| format!("{value}F64x"));
1362 }
1363
1364 // The number itself rather than the name of the other macro. The value is the same either
1365 // way, since `long double` is the widest format here, but the two are not the same thing to
1366 // read: `-dM` prints what the macro is, and a program that undefines `__LDBL_DECIMAL_DIG__`
1367 // takes this one with it. gcc writes the number.
1368 d.set("__DECIMAL_DIG__", characteristics(target.long_double_format).decimal_dig);
1369 if target.has_decimal_float {
1370 decimals(d);
1371 }
1372}
1373
1374/// The limits of the three decimal types, on the one target that has them.
1375///
1376/// Written out rather than worked out, because each is a fact of the interchange format and the
1377/// three rows are all there will ever be. The spellings are gcc's, down to the parentheses around a
1378/// negative exponent and the suffix on every constant. `__DEC64X_*` is not here: `_Decimal64x` has
1379/// a suffix of its own the lexer does not read yet, so the macros would be constants nothing can
1380/// use. `__DEC_EVAL_METHOD__` is 2 because it is 2 in gcc, and a program that reads it is asking
1381/// what gcc would do.
1382fn decimals(d: &mut Defs) {
1383 let rows = [
1384 ("32", "DF", "7", "(-94)", "97", "1E-95", "9.999999E96", "1E-6", "0.000001E-95"),
1385 (
1386 "64",
1387 "DD",
1388 "16",
1389 "(-382)",
1390 "385",
1391 "1E-383",
1392 "9.999999999999999E384",
1393 "1E-15",
1394 "0.000000000000001E-383",
1395 ),
1396 (
1397 "128",
1398 "DL",
1399 "34",
1400 "(-6142)",
1401 "6145",
1402 "1E-6143",
1403 "9.999999999999999999999999999999999E6144",
1404 "1E-33",
1405 "0.000000000000000000000000000000001E-6143",
1406 ),
1407 ];
1408 for (bits, suffix, mant_dig, min_exp, max_exp, min, max, epsilon, subnormal_min) in rows {
1409 d.set(&format!("__DEC{bits}_MANT_DIG__"), mant_dig);
1410 d.set(&format!("__DEC{bits}_MIN_EXP__"), min_exp);
1411 d.set(&format!("__DEC{bits}_MAX_EXP__"), max_exp);
1412 d.set(&format!("__DEC{bits}_MIN__"), &format!("{min}{suffix}"));
1413 d.set(&format!("__DEC{bits}_MAX__"), &format!("{max}{suffix}"));
1414 d.set(&format!("__DEC{bits}_EPSILON__"), &format!("{epsilon}{suffix}"));
1415 d.set(&format!("__DEC{bits}_SUBNORMAL_MIN__"), &format!("{subnormal_min}{suffix}"));
1416 }
1417 d.set("__DEC_EVAL_METHOD__", "2");
1418}
1419
1420/// One family of `float.h` macros, named `__{prefix}_*__`.
1421///
1422/// `write` turns a value into the constant its macro expands to, which is a suffix for every
1423/// family but `double`.
1424fn family(d: &mut Defs, prefix: &str, c: &Characteristics, write: impl Fn(&str) -> String) {
1425 d.set(&format!("__{prefix}_MANT_DIG__"), c.mant_dig);
1426 d.set(&format!("__{prefix}_DIG__"), c.dig);
1427 d.set(&format!("__{prefix}_MIN_EXP__"), c.min_exp);
1428 d.set(&format!("__{prefix}_MIN_10_EXP__"), c.min_10_exp);
1429 d.set(&format!("__{prefix}_MAX_EXP__"), c.max_exp);
1430 d.set(&format!("__{prefix}_MAX_10_EXP__"), c.max_10_exp);
1431 d.set(&format!("__{prefix}_DECIMAL_DIG__"), c.decimal_dig);
1432 d.set(&format!("__{prefix}_MAX__"), &write(c.max));
1433 d.set(&format!("__{prefix}_NORM_MAX__"), &write(c.norm_max));
1434 d.set(&format!("__{prefix}_MIN__"), &write(c.min));
1435 d.set(&format!("__{prefix}_EPSILON__"), &write(c.epsilon));
1436 d.set(&format!("__{prefix}_DENORM_MIN__"), &write(c.denorm_min));
1437 d.set(&format!("__{prefix}_IS_IEC_60559__"), c.is_iec_60559);
1438 d.set(&format!("__{prefix}_HAS_DENORM__"), "1");
1439 d.set(&format!("__{prefix}_HAS_INFINITY__"), "1");
1440 d.set(&format!("__{prefix}_HAS_QUIET_NAN__"), "1");
1441}
1442
1443#[cfg(test)]
1444mod tests {
1445 use rucc_target::Triple;
1446
1447 use super::*;
1448
1449 fn set_for(triple: &str) -> String {
1450 let triple: Triple = triple.parse().expect("a triple the compiler supports");
1451 built_in(&TargetInfo::new(triple), &Predef::new())
1452 }
1453
1454 /// The same, for a machine the three field triple cannot spell.
1455 fn set_for_tuple(tuple: &str) -> String {
1456 let target = TargetInfo::for_tuple(tuple.parse().expect("a row in the target table"));
1457 built_in(&target, &Predef::new())
1458 }
1459
1460 fn has(text: &str, line: &str) -> bool {
1461 text.lines().any(|l| l == line)
1462 }
1463
1464 #[test]
1465 fn the_version_macros_say_the_version_this_compiler_was_built_at() {
1466 // They said 0.1.0 through sixty seven releases, because the number was written here as
1467 // well as in the manifest, so a program asking which rucc it was is now told.
1468 let text = set_for("x86_64-unknown-linux-gnu");
1469 assert!(has(&text, &format!("#define __rucc_version__ \"{VERSION}\"")), "{text}");
1470 assert!(has(&text, &format!("#define __VERSION__ \"rucc {VERSION}\"")), "{text}");
1471 assert!(has(&text, &format!("#define __rucc_major__ {}", field(VERSION, 0))));
1472 assert!(has(&text, &format!("#define __rucc_minor__ {}", field(VERSION, 1))));
1473 assert!(has(&text, &format!("#define __rucc_patchlevel__ {}", field(VERSION, 2))));
1474
1475 // And what each of them expands to is something an `#if` can read, which is the whole
1476 // reason the three numbers are separate macros from the string.
1477 for n in 0..3 {
1478 assert!(field(VERSION, n).parse::<u32>().is_ok(), "{}", field(VERSION, n));
1479 }
1480 }
1481
1482 #[test]
1483 fn a_version_field_is_the_digits_at_the_front_of_it() {
1484 assert_eq!(
1485 (field("0.10.68", 0), field("0.10.68", 1), field("0.10.68", 2)),
1486 ("0", "10", "68")
1487 );
1488
1489 // A pre-release suffix belongs to the string and not to the number an `#if` compares, and
1490 // a field that is not there at all is what a two field version means by its third.
1491 assert_eq!(field("0.10.68-rc.1", 2), "68");
1492 assert_eq!(field("1.0", 2), "0");
1493 assert_eq!(field("", 0), "0");
1494 }
1495
1496 #[test]
1497 fn the_set_is_driven_by_the_target_rather_than_by_the_host() {
1498 let x86 = set_for("x86_64-unknown-linux-gnu");
1499 let arm = set_for("aarch64-unknown-linux-gnu");
1500 assert!(has(&x86, "#define __x86_64__ 1"));
1501 assert!(!has(&x86, "#define __aarch64__ 1"));
1502 assert!(has(&arm, "#define __aarch64__ 1"));
1503 assert!(!has(&arm, "#define __x86_64__ 1"));
1504 assert!(has(&x86, "#define __linux__ 1") && has(&arm, "#define __linux__ 1"));
1505 }
1506
1507 #[test]
1508 fn windows_is_the_target_that_makes_long_thirty_two_bits() {
1509 let windows = set_for("x86_64-pc-windows-msvc");
1510 let linux = set_for("x86_64-unknown-linux-gnu");
1511 assert!(has(&windows, "#define __SIZEOF_LONG__ 4"));
1512 assert!(has(&windows, "#define __SIZE_TYPE__ long long unsigned int"));
1513 assert!(has(&windows, "#define __INT64_TYPE__ long long int"));
1514 assert!(!has(&windows, "#define __LP64__ 1"));
1515 assert!(has(&linux, "#define __SIZEOF_LONG__ 8"));
1516 assert!(has(&linux, "#define __SIZE_TYPE__ long unsigned int"));
1517 assert!(has(&linux, "#define __INT64_TYPE__ long int"));
1518 assert!(has(&linux, "#define __LP64__ 1"));
1519 }
1520
1521 #[test]
1522 fn windows_spells_a_calling_convention_and_an_attribute_as_macros() {
1523 // The second declaration in mingw-w64's stdio.h is `int __cdecl __mingw_sscanf(...)`, so
1524 // a Windows target where these are missing reads no header at all.
1525 let windows = set_for("x86_64-pc-windows-gnu");
1526 assert!(has(&windows, "#define __cdecl __attribute__((__cdecl__))"));
1527 assert!(has(&windows, "#define __stdcall __attribute__((__stdcall__))"));
1528 assert!(has(&windows, "#define __fastcall __attribute__((__fastcall__))"));
1529 assert!(has(&windows, "#define __thiscall __attribute__((__thiscall__))"));
1530 assert!(has(&windows, "#define _cdecl __attribute__((__cdecl__))"));
1531 assert!(has(&windows, "#define __declspec(x) __attribute__((x))"));
1532 let linux = set_for("x86_64-unknown-linux-gnu");
1533 assert!(!has(&linux, "#define __cdecl __attribute__((__cdecl__))"));
1534 assert!(!has(&linux, "#define __declspec(x) __attribute__((x))"));
1535 }
1536
1537 #[test]
1538 fn a_strict_mode_keeps_the_spellings_that_are_not_the_implementations_to_take() {
1539 // `_cdecl` is a name a program may use and `__cdecl` is not, so gcc defines the first
1540 // only where the extensions are on and the second everywhere.
1541 let mut opts = Predef::new();
1542 opts.gnu_extensions = false;
1543 let triple: Triple = "x86_64-pc-windows-gnu".parse().expect("a triple");
1544 let strict = built_in(&TargetInfo::new(triple), &opts);
1545 assert!(has(&strict, "#define __cdecl __attribute__((__cdecl__))"));
1546 assert!(!has(&strict, "#define _cdecl __attribute__((__cdecl__))"));
1547 }
1548
1549 #[test]
1550 fn wchar_t_is_the_type_that_divides_the_targets() {
1551 // Signed on x86-64 Linux, unsigned on AArch64 Linux, and sixteen bits on Windows.
1552 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ int"));
1553 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ unsigned int"));
1554 let windows = set_for("x86_64-pc-windows-msvc");
1555 assert!(has(&windows, "#define __WCHAR_TYPE__ short unsigned int"));
1556 assert!(has(&windows, "#define __SIZEOF_WCHAR_T__ 2"));
1557 }
1558
1559 #[test]
1560 fn apple_spells_the_architecture_its_own_way_and_its_headers_only_know_that_spelling() {
1561 // sys/cdefs.h reaches #error "Unsupported architecture" without these, which is the
1562 // first line of the first header of every program on the platform.
1563 let darwin = set_for("aarch64-apple-darwin");
1564 assert!(has(&darwin, "#define __arm64__ 1"));
1565 assert!(has(&darwin, "#define __arm64 1"));
1566 assert!(has(&darwin, "#define __aarch64__ 1"), "the portable spelling stays too");
1567 let linux = set_for("aarch64-unknown-linux-gnu");
1568 assert!(!has(&linux, "#define __arm64__ 1"), "Apple's spelling is Apple's alone");
1569 assert!(!has(&set_for("x86_64-apple-darwin"), "#define __arm64__ 1"));
1570 }
1571
1572 #[test]
1573 fn every_limit_is_spelled_in_hexadecimal_the_way_gcc_spells_it() {
1574 // The value was never in question and the spelling is, because these macros reach a
1575 // program's text. glibc's `limits.h` writes `#define INT_MAX __INT_MAX__`, openssl
1576 // writes `((unsigned int)INT_MAX + 1)`, and `-E` over that header printed a decimal
1577 // number where gcc printed a hexadecimal one. The type is the same either way here,
1578 // which is why the suffixes are unchanged: `0x7fffffff` and `2147483647` are both
1579 // `int`, and `0xffffffffffffffffUL` and its decimal twin are both `unsigned long`.
1580 let linux = set_for("x86_64-unknown-linux-gnu");
1581 for line in [
1582 "#define __SCHAR_MAX__ 0x7f",
1583 "#define __SHRT_MAX__ 0x7fff",
1584 "#define __INT_MAX__ 0x7fffffff",
1585 "#define __LONG_MAX__ 0x7fffffffffffffffL",
1586 "#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL",
1587 "#define __INTMAX_MAX__ 0x7fffffffffffffffL",
1588 "#define __UINTMAX_MAX__ 0xffffffffffffffffUL",
1589 "#define __SIZE_MAX__ 0xffffffffffffffffUL",
1590 "#define __PTRDIFF_MAX__ 0x7fffffffffffffffL",
1591 "#define __SIG_ATOMIC_MAX__ 0x7fffffff",
1592 "#define __INT8_MAX__ 0x7f",
1593 "#define __UINT8_MAX__ 0xff",
1594 "#define __INT16_MAX__ 0x7fff",
1595 "#define __UINT16_MAX__ 0xffff",
1596 "#define __INT32_MAX__ 0x7fffffff",
1597 "#define __UINT32_MAX__ 0xffffffffU",
1598 "#define __INT64_MAX__ 0x7fffffffffffffffL",
1599 "#define __UINT64_MAX__ 0xffffffffffffffffUL",
1600 "#define __INT_FAST8_MAX__ 0x7f",
1601 "#define __UINT_FAST8_MAX__ 0xff",
1602 ] {
1603 assert!(has(&linux, line), "{line}");
1604 }
1605 // Windows, where `long` is thirty two bits, so the wide suffix moves and the narrow
1606 // `long` limit is not the same number.
1607 let windows = set_for("x86_64-pc-windows-msvc");
1608 assert!(has(&windows, "#define __LONG_MAX__ 0x7fffffffL"));
1609 assert!(has(&windows, "#define __INTMAX_MAX__ 0x7fffffffffffffffLL"));
1610 assert!(has(&windows, "#define __UINTMAX_MAX__ 0xffffffffffffffffULL"));
1611 }
1612
1613 #[test]
1614 fn apple_says_what_clang_for_apple_says_and_not_what_linux_does() {
1615 // Each line is the value clang 17 prints for `-target arm64-apple-macos11 -dM`.
1616 let darwin = set_for("aarch64-apple-darwin");
1617 for line in [
1618 "#define __INT64_TYPE__ long long int",
1619 "#define __UINT64_TYPE__ long long unsigned int",
1620 "#define __INT64_MAX__ 0x7fffffffffffffffLL",
1621 "#define __UINT64_MAX__ 0xffffffffffffffffULL",
1622 "#define __INT64_C(c) c ## LL",
1623 "#define __UINT64_C(c) c ## ULL",
1624 "#define __INT_LEAST64_TYPE__ long long int",
1625 "#define __INT_FAST64_TYPE__ long long int",
1626 "#define __UINT_FAST64_MAX__ 0xffffffffffffffffULL",
1627 // `intmax_t` and `size_t` stay `long` on Apple, which is why they are not the same
1628 // type as `int64_t` there.
1629 "#define __INTMAX_TYPE__ long int",
1630 "#define __SIZE_TYPE__ long unsigned int",
1631 "#define __BIGGEST_ALIGNMENT__ 8",
1632 "#define __GCC_DESTRUCTIVE_SIZE 128",
1633 ] {
1634 assert!(has(&darwin, line), "{line}");
1635 }
1636 for name in ["__unix__", "__unix", "unix", "__STDC_ISO_10646__"] {
1637 assert!(!darwin.contains(&format!("#define {name} ")), "{name}");
1638 }
1639 // The same processor under Linux keeps every one of them.
1640 let linux = set_for("aarch64-unknown-linux-gnu");
1641 assert!(has(&linux, "#define __INT64_TYPE__ long int"));
1642 assert!(has(&linux, "#define __BIGGEST_ALIGNMENT__ 16"));
1643 assert!(has(&linux, "#define __unix__ 1"));
1644 assert!(linux.contains("#define __STDC_ISO_10646__ "));
1645 // And an Intel Mac takes Apple's `int64_t` with its own alignment.
1646 let intel = set_for("x86_64-apple-darwin");
1647 assert!(has(&intel, "#define __INT64_TYPE__ long long int"));
1648 assert!(has(&intel, "#define __BIGGEST_ALIGNMENT__ 16"));
1649 assert!(!intel.contains("#define __unix__ "));
1650 }
1651
1652 #[test]
1653 fn wint_t_does_not_follow_wchar_t() {
1654 // Apple makes it signed so that WEOF is negative the way EOF is. Linux does not.
1655 let darwin = set_for("aarch64-apple-darwin");
1656 assert!(has(&darwin, "#define __WINT_TYPE__ int"));
1657 assert!(has(&darwin, "#define __WINT_MAX__ 0x7fffffff"));
1658 assert!(has(&darwin, "#define __WCHAR_TYPE__ int"));
1659 let linux = set_for("aarch64-unknown-linux-gnu");
1660 assert!(has(&linux, "#define __WINT_TYPE__ unsigned int"));
1661 assert!(has(&linux, "#define __WINT_MAX__ 0xffffffffU"));
1662 assert!(has(&linux, "#define __WCHAR_TYPE__ unsigned int"), "and wchar_t is its own");
1663 assert!(has(
1664 &set_for("x86_64-pc-windows-msvc"),
1665 "#define __WINT_TYPE__ short unsigned int"
1666 ));
1667 }
1668
1669 #[test]
1670 fn the_widths_say_what_the_type_holds_and_follow_the_target_that_changes_it() {
1671 // Twenty of them, which is gcc's set: no exact width member, since the width of an
1672 // `int32_t` is in its name, and no unsigned member, since a header that wants
1673 // `UINTMAX_WIDTH` writes `__INTMAX_WIDTH__`.
1674 let linux = set_for("x86_64-unknown-linux-gnu");
1675 assert_eq!(linux.lines().filter(|line| line.contains("_WIDTH__")).count(), 20);
1676 assert!(has(&linux, "#define __LONG_WIDTH__ 64"));
1677 assert!(has(&linux, "#define __SIZE_WIDTH__ 64"));
1678 assert!(has(&linux, "#define __WCHAR_WIDTH__ 32"));
1679 assert!(has(&linux, "#define __INT_LEAST16_WIDTH__ 16"));
1680 // x86-64 glibc is where `int_fast16_t` is a `long`, and the width has to say so or a
1681 // program that switches on it picks the wrong branch.
1682 assert!(has(&linux, "#define __INT_FAST16_WIDTH__ 64"));
1683 assert!(has(&set_for("x86_64-unknown-linux-musl"), "#define __INT_FAST16_WIDTH__ 32"));
1684 // Windows has a thirty two bit `long` and a sixteen bit `wint_t`, and the pointer
1685 // sized types stay sixty four bits wide whatever `long` does.
1686 let windows = set_for("x86_64-pc-windows-msvc");
1687 assert!(has(&windows, "#define __LONG_WIDTH__ 32"));
1688 assert!(has(&windows, "#define __WINT_WIDTH__ 16"));
1689 assert!(has(&windows, "#define __SIZE_WIDTH__ 64"));
1690 assert!(has(&windows, "#define __INTMAX_WIDTH__ 64"));
1691 }
1692
1693 #[test]
1694 fn a_constant_maker_gets_the_suffix_its_width_needs_and_no_other() {
1695 // Found by diffing `-dM` against the system compiler. The 32 bit row was passing `U`
1696 // as its width suffix, which put a `U` on the signed macro and two on the unsigned
1697 // one, and `UINT32_C(1)` expanded to `1UU`, which is not a token.
1698 let linux = set_for("x86_64-unknown-linux-gnu");
1699 assert!(has(&linux, "#define __INT32_C(c) c"));
1700 assert!(has(&linux, "#define __UINT32_C(c) c ## U"));
1701 assert!(has(&linux, "#define __INT16_C(c) c"));
1702 // No `U` on the two narrow ones, because `uint8_t` and `uint16_t` promote to a
1703 // signed `int` and the constant has that type. gcc leaves it off for the same reason.
1704 assert!(has(&linux, "#define __UINT16_C(c) c"));
1705 assert!(has(&linux, "#define __UINT8_C(c) c"));
1706 // The wide ones do take a suffix, and the `U` goes in front of it.
1707 assert!(has(&linux, "#define __INT64_C(c) c ## L"));
1708 assert!(has(&linux, "#define __UINT64_C(c) c ## UL"));
1709 // Windows has a thirty two bit `long`, so its sixty four bit constants are `long long`.
1710 let windows = set_for("x86_64-pc-windows-msvc");
1711 assert!(has(&windows, "#define __INT64_C(c) c ## LL"));
1712 assert!(has(&windows, "#define __UINT64_C(c) c ## ULL"));
1713 }
1714
1715 #[test]
1716 fn the_symbol_prefix_is_defined_everywhere_including_where_it_is_empty() {
1717 // Empty is not the same as absent, because glibc stringifies it. Leaving it undefined
1718 // turns `__asm__ (__ASMNAME ("__xpg_strerror_r"))` into an asm name of
1719 // "__USER_LABEL_PREFIX__" "__xpg_strerror_r", which renames the function instead of
1720 // failing, and that is a bug found at link time or later.
1721 for triple in
1722 ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
1723 {
1724 assert!(has(&set_for(triple), "#define __USER_LABEL_PREFIX__ "), "{triple}");
1725 }
1726 // Mach-O keeps the underscore that ELF dropped.
1727 assert!(has(&set_for("aarch64-apple-darwin"), "#define __USER_LABEL_PREFIX__ _"));
1728 }
1729
1730 /// `-ffast-math` as gcc 16 spells it on x86-64 Linux: one macro per licence, the finite promise
1731 /// as a one, and the IEC 60559 family gone from both the compiler's lines and the ones glibc
1732 /// would write from `__GCC_IEC_559`.
1733 #[test]
1734 fn fast_math_defines_what_gcc_16_defines_for_it() {
1735 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().expect("a triple"));
1736 let mut opts = Predef::new();
1737 opts.trapping_math = opts.math.set_fast(true);
1738 let fast = built_in(&target, &opts);
1739 for line in [
1740 "#define __FAST_MATH__ 1",
1741 "#define __FINITE_MATH_ONLY__ 1",
1742 "#define __NO_MATH_ERRNO__ 1",
1743 "#define __NO_TRAPPING_MATH__ 1",
1744 "#define __NO_SIGNED_ZEROS__ 1",
1745 "#define __RECIPROCAL_MATH__ 1",
1746 "#define __ASSOCIATIVE_MATH__ 1",
1747 "#define __GCC_IEC_559 0",
1748 "#define __GCC_IEC_559_COMPLEX 0",
1749 ] {
1750 assert!(has(&fast, line), "{line}");
1751 }
1752 for name in ["__STDC_IEC_559__", "__STDC_IEC_559_COMPLEX__", "__STDC_IEC_60559_BFP__"] {
1753 assert!(!fast.contains(&format!("#define {name} ")), "{name}");
1754 }
1755
1756 // `-ffast-math -ftrapping-math` keeps the members that do not need trapping off and
1757 // loses the name for the whole, and regrouping with it, which is gcc's answer.
1758 opts.trapping_math = true;
1759 let trapping = built_in(&target, &opts);
1760 assert!(has(&trapping, "#define __NO_MATH_ERRNO__ 1"));
1761 assert!(has(&trapping, "#define __GCC_IEC_559 0"));
1762 for name in ["__FAST_MATH__", "__NO_TRAPPING_MATH__", "__ASSOCIATIVE_MATH__"] {
1763 assert!(!trapping.contains(&format!("#define {name} ")), "{name}");
1764 }
1765
1766 // And none of it by default.
1767 let plain = built_in(&target, &Predef::new());
1768 for name in ["__FAST_MATH__", "__NO_MATH_ERRNO__", "__NO_TRAPPING_MATH__"] {
1769 assert!(!plain.contains(&format!("#define {name} ")), "{name}");
1770 }
1771 assert!(has(&plain, "#define __STDC_IEC_559__ 1"));
1772 }
1773
1774 /// `__EXCEPTIONS` is the one macro `-fexceptions` adds in C, and it is not there without it.
1775 #[test]
1776 fn exceptions_are_announced_to_the_headers_that_ask() {
1777 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().expect("a triple"));
1778 let mut opts = Predef::new();
1779 assert!(!built_in(&target, &opts).contains("__EXCEPTIONS"));
1780 opts.exceptions = true;
1781 assert!(has(&built_in(&target, &opts), "#define __EXCEPTIONS 1"));
1782 }
1783
1784 /// The set gcc defines that headers read and that are true here. Written out one line at a
1785 /// time rather than counted, because the value is the whole point of each of them: a header
1786 /// asking `#if __FINITE_MATH_ONLY__` wants the number and not the existence.
1787 #[test]
1788 fn the_toolchain_macros_gcc_defines_are_defined_with_gccs_values() {
1789 let linux = set_for("x86_64-unknown-linux-gnu");
1790 for line in [
1791 "#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"",
1792 "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"",
1793 "#define __GXX_ABI_VERSION 1021",
1794 "#define __REGISTER_PREFIX__ ",
1795 "#define __FINITE_MATH_ONLY__ 0",
1796 "#define __GCC_IEC_559 2",
1797 "#define __GCC_IEC_559_COMPLEX 2",
1798 "#define __GCC_CONSTRUCTIVE_SIZE 64",
1799 "#define __GCC_DESTRUCTIVE_SIZE 64",
1800 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1",
1801 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1",
1802 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1",
1803 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1",
1804 "#define __ATOMIC_HLE_ACQUIRE 65536",
1805 "#define __ATOMIC_HLE_RELEASE 131072",
1806 "#define __FXSR__ 1",
1807 "#define __MMX_WITH_SSE__ 1",
1808 "#define __code_model_small__ 1",
1809 ] {
1810 assert!(has(&linux, line), "{line}");
1811 }
1812 // The five that are the processor's rather than the compiler's stay on the processor.
1813 let arm = set_for("aarch64-unknown-linux-gnu");
1814 for name in ["__ATOMIC_HLE_ACQUIRE", "__FXSR__", "__MMX_WITH_SSE__", "__code_model_small__"]
1815 {
1816 assert!(!arm.contains(name), "{name}");
1817 }
1818 assert!(has(&arm, "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1"));
1819 // A wide character is sixteen bits on Windows, so a wide string is UTF-16 there.
1820 let windows = set_for("x86_64-pc-windows-msvc");
1821 assert!(has(&windows, "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-16LE\""));
1822 }
1823
1824 #[test]
1825 fn the_extensions_the_unit_is_built_for_are_macros() {
1826 // tamnd/rucc#2003. The baseline is four macros and SSE4.2 is six more, which is gcc 16's
1827 // `-msse4.2 -dM` output, and the unit's set is what decides it rather than the target.
1828 let triple: Triple = "x86_64-unknown-linux-gnu".parse().expect("a triple");
1829 let mut choices = rucc_target::Choices::new();
1830 choices.read("sse4.2").expect("a name gcc knows");
1831 let opts = Predef { isa: choices.over(Isa::baseline()), ..Predef::new() };
1832 let text = built_in(&TargetInfo::new(triple), &opts);
1833 for name in
1834 ["SSE", "SSE2", "MMX", "FXSR", "SSE3", "SSSE3", "SSE4_1", "SSE4_2", "POPCNT", "CRC32"]
1835 {
1836 assert!(has(&text, &format!("#define __{name}__ 1")), "{name}");
1837 }
1838 let plain = set_for("x86_64-unknown-linux-gnu");
1839 assert!(has(&plain, "#define __SSE2__ 1"));
1840 for name in ["__SSE3__", "__SSE4_2__", "__POPCNT__", "__CRC32__"] {
1841 assert!(!plain.contains(name), "{name}");
1842 }
1843 // AArch64 has none of them whatever the set says, since the set is an x86-64 one.
1844 let arm: Triple = "aarch64-unknown-linux-gnu".parse().expect("a triple");
1845 assert!(!built_in(&TargetInfo::new(arm), &opts).contains("__SSE"));
1846 }
1847
1848 #[test]
1849 fn the_memory_orders_are_there_even_without_atomics() {
1850 // musl's stdatomic.h writes `memory_order_relaxed = __ATOMIC_RELAXED` with no test
1851 // around it, so these are not a promise about `_Atomic`, they are the numbering the
1852 // builtins take, and a compiler without them prints an enumerator whose value is an
1853 // identifier.
1854 let linux = set_for("x86_64-unknown-linux-gnu");
1855 assert!(has(&linux, "#define __ATOMIC_RELAXED 0"));
1856 assert!(has(&linux, "#define __ATOMIC_SEQ_CST 5"));
1857 assert!(has(&linux, "#define __STDC_NO_ATOMICS__ 1"), "and we still have no _Atomic");
1858 assert!(has(&linux, "#define __GCC_ATOMIC_INT_LOCK_FREE 2"));
1859 assert!(has(&linux, "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1860 assert!(has(&set_for("x86_64-pc-windows-msvc"), "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1861 }
1862
1863 #[test]
1864 fn long_double_is_three_types_and_the_macros_say_which() {
1865 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 64"));
1866 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 113"));
1867 assert!(has(&set_for("aarch64-apple-darwin"), "#define __LDBL_MANT_DIG__ 53"));
1868 }
1869
1870 #[test]
1871 fn the_size_of_float128_is_defined_where_gcc_has_the_name() {
1872 let line = "#define __SIZEOF_FLOAT128__ 16";
1873 assert!(has(&set_for("x86_64-unknown-linux-gnu"), line));
1874 assert!(has(&set_for_tuple("i686-linux-gnu"), line));
1875 let power = set_for_tuple("powerpc64le-linux-gnu");
1876 assert!(has(&power, line));
1877 assert!(has(&power, "#define __FLOAT128__ 1"));
1878 assert!(!set_for("x86_64-unknown-linux-gnu").contains("__FLOAT128__"));
1879 assert!(!set_for("aarch64-unknown-linux-gnu").contains("__SIZEOF_FLOAT128__"));
1880 }
1881
1882 #[test]
1883 fn the_extended_floating_types_have_the_limits_their_formats_have() {
1884 // Every one of these but `_Float64x` is the same format on every target, which is the
1885 // point of the interchange types, so the limits are the same everywhere too.
1886 let linux = set_for("x86_64-unknown-linux-gnu");
1887 assert!(has(&linux, "#define __FLT16_MANT_DIG__ 11"));
1888 assert!(has(&linux, "#define __FLT32_MANT_DIG__ 24"));
1889 assert!(has(&linux, "#define __FLT64_MANT_DIG__ 53"));
1890 assert!(has(&linux, "#define __FLT128_MANT_DIG__ 113"));
1891 assert!(has(&linux, "#define __FLT32X_MANT_DIG__ 53"));
1892 // Each family writes its values with its own suffix, so a header that assigns one to an
1893 // object of the type gets the type back rather than a conversion.
1894 assert!(has(&linux, "#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16"));
1895 assert!(has(
1896 &linux,
1897 "#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x"
1898 ));
1899 // `_Float128x` is a type no target has, so gcc defines nothing for it and neither
1900 // does this.
1901 assert!(!linux.contains("__FLT128X_"));
1902 }
1903
1904 #[test]
1905 fn the_family_for_a_named_type_is_written_where_the_type_is_and_nowhere_else() {
1906 // gcc 13's rows, measured with the cross compilers: the half is on x86-64, AArch64 and
1907 // RISC-V, and the quad is on every one of the seven but armv7. A program asks the macro
1908 // to find out whether it may write the type, so a row where the two disagree is a header
1909 // that asks for a type the compiler then refuses.
1910 let has_family = |target: &str, prefix: &str| {
1911 set_for_tuple(target).contains(&format!("#define __{prefix}_MANT_DIG__ "))
1912 };
1913 assert!(has_family("x86_64-linux-gnu", "FLT16"));
1914 assert!(has_family("aarch64-linux-gnu", "FLT16"));
1915 assert!(has_family("riscv64-linux-gnu", "FLT16"));
1916 assert!(!has_family("i686-linux-gnu", "FLT16"));
1917 assert!(!has_family("s390x-linux-gnu", "FLT16"));
1918 assert!(!has_family("armv7-linux-gnueabihf", "FLT16"));
1919
1920 assert!(has_family("i686-linux-gnu", "FLT128"));
1921 assert!(has_family("s390x-linux-gnu", "FLT128"));
1922 assert!(!has_family("armv7-linux-gnueabihf", "FLT128"));
1923
1924 // The families every machine has are still there on the machine that has least, and so
1925 // is `_Float64x` on the machines that have a format for it.
1926 let arm = set_for_tuple("armv7-linux-gnueabihf");
1927 for prefix in ["FLT", "DBL", "LDBL", "FLT32", "FLT64", "FLT32X"] {
1928 assert!(arm.contains(&format!("#define __{prefix}_MANT_DIG__ ")), "__{prefix}_");
1929 }
1930 assert!(!arm.contains("__FLT64X_"));
1931 }
1932
1933 #[test]
1934 fn float64x_keeps_the_width_that_long_double_loses_on_apple() {
1935 // The two are the same eighty bit x87 format on x86-64 and part company everywhere
1936 // else, because `_Float64x` follows the processor and `long double` follows the ABI.
1937 let linux = set_for("x86_64-unknown-linux-gnu");
1938 assert!(has(&linux, "#define __FLT64X_MANT_DIG__ 64"));
1939 assert!(has(&linux, "#define __LDBL_MANT_DIG__ 64"));
1940 let mac = set_for("aarch64-apple-darwin");
1941 assert!(has(&mac, "#define __FLT64X_MANT_DIG__ 113"));
1942 assert!(has(&mac, "#define __LDBL_MANT_DIG__ 53"));
1943 let windows = set_for("x86_64-pc-windows-msvc");
1944 assert!(has(&windows, "#define __FLT64X_MANT_DIG__ 64"));
1945 assert!(has(&windows, "#define __LDBL_MANT_DIG__ 53"));
1946 }
1947
1948 #[test]
1949 fn the_largest_value_of_an_ieee_format_is_also_its_largest_normal_one() {
1950 // `NORM_MAX` is only ever smaller than `MAX` for a format that holds values above its
1951 // largest normal one, and no IEEE encoding does. The double-double does, which is why
1952 // the two are separate fields now, and no target here has one.
1953 let linux = set_for("x86_64-unknown-linux-gnu");
1954 for prefix in ["FLT", "DBL", "LDBL", "FLT16", "FLT32", "FLT64", "FLT128", "FLT32X"] {
1955 let value = |suffix: &str| {
1956 let name = format!("#define __{prefix}_{suffix}__ ");
1957 let line = linux
1958 .lines()
1959 .find(|line| line.starts_with(&name))
1960 .unwrap_or_else(|| panic!("__{prefix}_{suffix}__ is defined"));
1961 line[name.len()..].to_owned()
1962 };
1963 assert_eq!(value("MAX"), value("NORM_MAX"), "__{prefix}_NORM_MAX__");
1964 }
1965 }
1966
1967 #[test]
1968 fn the_double_double_is_the_row_where_the_largest_value_is_not_the_largest_normal_one() {
1969 // No target here has a double-double `long double`, so this asks the row rather than the
1970 // macros. It is the reason `norm_max` is a field: a program that wants the largest value
1971 // it can still compute a full significand with wants `NORM_MAX`, and on PowerPC that is
1972 // a bit under half of `MAX`.
1973 let c = characteristics(Format::DoubleDouble);
1974 assert_ne!(c.max, c.norm_max);
1975 // `NORM_MAX` is two to the one thousand and twenty three, which is about half of `MAX`,
1976 // and `MAX` is a shade above `DBL_MAX` because the high half can be `DBL_MAX` and the low
1977 // half then adds to it. Both are what the reference prints.
1978 assert!(c.norm_max.starts_with("8.98846567431157953864652595394501e+307"));
1979 assert!(c.max.starts_with("1.7976931348623158"));
1980 // Epsilon is the odd one. The smallest value that changes a double-double near one is a
1981 // subnormal in the low half rather than one unit in the last place of anything, so it is
1982 // the same number as this format's own `DENORM_MIN`, which no other row can say.
1983 assert_eq!(c.epsilon, c.denorm_min);
1984 for format in [Format::Half, Format::Single, Format::Double, Format::X87Extended] {
1985 assert_ne!(characteristics(format).epsilon, characteristics(format).denorm_min);
1986 }
1987 // And it is not an IEC 60559 format, which only the brain float can also say.
1988 assert_eq!(c.is_iec_60559, "0");
1989 }
1990
1991 #[test]
1992 fn the_widest_bit_int_is_said_in_every_dialect() {
1993 // gcc defines it under `-std=c17` as well as `-std=c23`, and a header that reaches for
1994 // `_BitInt` tests the macro rather than the version, so an absent one reads as a
1995 // compiler without the type at all.
1996 let mut opts = Predef::new();
1997 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1998 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1999 opts.std = Std::C17;
2000 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
2001 }
2002
2003 #[test]
2004 fn char_signedness_is_recorded_only_when_it_is_unsigned() {
2005 // Which is how GCC does it: the macro exists to mark the unusual case.
2006 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
2007 assert!(!has(&set_for("x86_64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
2008 }
2009
2010 #[test]
2011 fn the_dialect_decides_the_standard_macros() {
2012 let mut opts = Predef::new();
2013 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
2014 assert!(has(&built_in(&target, &opts), "#define __STDC_VERSION__ 202311L"));
2015 assert!(!has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
2016 assert!(has(&built_in(&target, &opts), "#define linux 1"));
2017
2018 opts.gnu_extensions = false;
2019 assert!(has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
2020 assert!(!has(&built_in(&target, &opts), "#define linux 1"), "not a reserved name");
2021
2022 opts.std = Std::C89;
2023 let c89 = built_in(&target, &opts);
2024 assert!(!c89.contains("__STDC_VERSION__"), "C89 does not define it at all");
2025 assert!(has(&c89, "#define __STDC__ 1"));
2026 }
2027
2028 /// The conditional feature macros are claims not to have something, and a claim that is
2029 /// not true changes what a header declares rather than turning anything off.
2030 #[test]
2031 fn the_only_things_claimed_missing_are_the_ones_that_are_missing() {
2032 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
2033 let opts = Predef::new();
2034 let set = built_in(&target, &opts);
2035 assert!(has(&set, "#define __STDC_NO_ATOMICS__ 1"), "there is no stdatomic.h to include");
2036 assert!(has(&set, "#define __STDC_NO_THREADS__ 1"), "nor a threads.h");
2037 assert!(has(&set, "#define __STDC_NO_COMPLEX__ 1"), "the arithmetic is not lowered");
2038 assert!(!set.contains("__STDC_NO_VLA__"), "variable length arrays work");
2039 }
2040
2041 /// gcc's own `stdatomic.h` declares `atomic_char8_t` under `#ifdef __CHAR8_TYPE__`, so a
2042 /// compiler that defines it in C17 declares a type gcc does not and one that never defines
2043 /// it is missing one in C23. Both were caught by preprocessing that header both ways.
2044 #[test]
2045 fn the_type_behind_char8_t_is_defined_in_c23_and_in_no_dialect_before_it() {
2046 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
2047 let mut opts = Predef::new();
2048 assert!(has(&built_in(&target, &opts), "#define __CHAR8_TYPE__ unsigned char"));
2049
2050 for older in [Std::C17, Std::C11, Std::C99, Std::C89] {
2051 opts.std = older;
2052 assert!(!built_in(&target, &opts).contains("__CHAR8_TYPE__"), "{older:?}");
2053 }
2054 }
2055
2056 /// glibc's `<stdc-predef.h>` is read before the first line of every translation unit and
2057 /// writes `#define __STDC_IEC_60559_BFP__ 201404L` whenever `__GCC_IEC_559` is positive.
2058 /// Any other value here is a redefinition with a different body, which is a warning the
2059 /// program did not ask for and which a configure script reads as a failed feature test.
2060 #[test]
2061 fn the_ieee_annex_macro_carries_the_value_glibcs_own_header_writes() {
2062 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
2063 let mut opts = Predef::new();
2064 for std in [Std::C23, Std::C17, Std::C11, Std::C99, Std::C89] {
2065 opts.std = std;
2066 let set = built_in(&target, &opts);
2067 assert!(has(&set, "#define __STDC_IEC_60559_BFP__ 201404L"), "{std:?}");
2068 assert!(has(&set, "#define __STDC_IEC_60559_COMPLEX__ 201404L"), "{std:?}");
2069 // The two the library reads to decide whether to write the four above itself.
2070 assert!(has(&set, "#define __GCC_IEC_559 2"), "{std:?}");
2071 assert!(has(&set, "#define __GCC_IEC_559_COMPLEX 2"), "{std:?}");
2072 }
2073 }
2074
2075 #[test]
2076 fn the_optimizer_level_is_visible_to_the_preprocessor() {
2077 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
2078 let mut opts = Predef::new();
2079 assert!(has(&built_in(&target, &opts), "#define __NO_INLINE__ 1"));
2080 assert!(!built_in(&target, &opts).contains("__OPTIMIZE__"));
2081
2082 opts.opt_level = OptLevel::O2;
2083 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE__ 1"));
2084 assert!(!built_in(&target, &opts).contains("__OPTIMIZE_SIZE__"));
2085
2086 opts.opt_level = OptLevel::Os;
2087 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE_SIZE__ 1"));
2088 }
2089
2090 #[test]
2091 fn a_command_line_define_with_no_value_is_one() {
2092 let mut opts = Predef::new();
2093 opts.defines = vec!["FOO".to_owned(), "BAR=2".to_owned(), "F(x)=x + 1".to_owned()];
2094 opts.undefines = vec!["__linux__".to_owned()];
2095 let text = command_line(&opts);
2096 assert!(has(&text, "#define FOO 1"));
2097 assert!(has(&text, "#define BAR 2"));
2098 assert!(has(&text, "#define F(x) x + 1"));
2099 // The undefine comes last, because `-U` beats `-D` whichever side of it it was on.
2100 assert!(text.trim_end().ends_with("#undef __linux__"));
2101 }
2102
2103 #[test]
2104 fn no_command_line_macros_is_no_file_at_all() {
2105 assert!(command_line(&Predef::new()).is_empty());
2106 }
2107
2108 #[test]
2109 fn a_date_is_spelled_the_way_the_standard_fixes() {
2110 // The epoch itself, and a day that needs the space padding the format asks for.
2111 let epoch = Timestamp::from_unix(0);
2112 assert_eq!(epoch.date, "Jan 1 1970");
2113 assert_eq!(epoch.time, "00:00:00");
2114 let leap = Timestamp::from_unix(1_709_164_800);
2115 assert_eq!(leap.date, "Feb 29 2024", "2024 is a leap year");
2116 let late = Timestamp::from_unix(1_735_689_599);
2117 assert_eq!(late.date, "Dec 31 2024");
2118 assert_eq!(late.time, "23:59:59");
2119 }
2120
2121 #[test]
2122 fn a_date_before_the_epoch_still_comes_out_right() {
2123 // Not because anyone compiles in 1969, but because the arithmetic that gets this
2124 // wrong is the same arithmetic that gets a time zone offset wrong.
2125 assert_eq!(Timestamp::from_unix(-1).date, "Dec 31 1969");
2126 assert_eq!(Timestamp::from_unix(-1).time, "23:59:59");
2127 }
2128
2129 #[test]
2130 fn the_gnuc_version_is_a_knob_rather_than_a_constant() {
2131 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
2132 let mut opts = Predef::new();
2133 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 16"));
2134 opts.gnuc = GnucVersion { major: 15, minor: 1, patch: 0 };
2135 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 15"));
2136 assert!(has(&built_in(&target, &opts), "#define __GNUC_MINOR__ 1"));
2137 }
2138
2139 /// Which of the two inline macros is defined, over the two things that decide it.
2140 ///
2141 /// Exactly one of them is defined at a time, which is what a header reads: glibc's
2142 /// `__extern_inline` writes `extern __inline` under one and adds `__gnu_inline__` under the
2143 /// other, so both being defined or neither being defined is a header taking a path it was
2144 /// never meant to take.
2145 #[test]
2146 fn one_of_the_two_inline_macros_is_defined_and_three_things_can_pick_which() {
2147 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
2148 let gnu = "#define __GNUC_GNU_INLINE__ 1";
2149 let stdc = "#define __GNUC_STDC_INLINE__ 1";
2150
2151 let mut opts = Predef::new();
2152 assert!(has(&built_in(&target, &opts), stdc));
2153 assert!(!has(&built_in(&target, &opts), gnu));
2154
2155 opts.gnu89_inline = true;
2156 assert!(has(&built_in(&target, &opts), gnu));
2157 assert!(!has(&built_in(&target, &opts), stdc));
2158
2159 // The dialect on its own, which is where the older reading came from.
2160 let mut opts = Predef::new();
2161 opts.std = Std::C89;
2162 assert!(has(&built_in(&target, &opts), gnu));
2163 assert!(!has(&built_in(&target, &opts), stdc));
2164 }
2165
2166 #[test]
2167 fn a_darwin_target_says_its_deployment_target_as_the_sdk_reads_it() {
2168 let default = set_for("aarch64-apple-darwin");
2169 assert!(has(&default, "#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 110000"));
2170 assert!(has(&default, "#define __ENVIRONMENT_OS_VERSION_MIN_REQUIRED__ 110000"));
2171 let pinned = set_for_tuple("aarch64-macos.13.4");
2172 assert!(has(&pinned, "#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 130400"));
2173 assert!(has(&pinned, "#define __ENVIRONMENT_OS_VERSION_MIN_REQUIRED__ 130400"));
2174 let linux = set_for("aarch64-unknown-linux-gnu");
2175 assert!(!linux.contains("VERSION_MIN_REQUIRED"));
2176 }
2177
2178 #[test]
2179 fn apple_arm64_has_the_older_spellings_its_sdk_reads() {
2180 let darwin = set_for("aarch64-apple-darwin");
2181 for line in [
2182 "#define __ARM64_ARCH_8__ 1",
2183 "#define __ARM_NEON__ 1",
2184 "#define __AARCH64_SIMD__ 1",
2185 "#define __LITTLE_ENDIAN__ 1",
2186 ] {
2187 assert!(has(&darwin, line), "{line}");
2188 }
2189 // gcc defines none of them for Linux, and a header that tests `__LITTLE_ENDIAN__` there
2190 // is one written for clang that gcc users already build without it.
2191 let linux = set_for("aarch64-unknown-linux-gnu");
2192 assert!(!linux.contains("__ARM_NEON__"));
2193 assert!(!linux.contains("#define __LITTLE_ENDIAN__"));
2194 }
2195
2196 #[test]
2197 fn sixty_four_bit_glibc_makes_the_fast_types_long_on_every_processor() {
2198 // glibc's `stdint.h` picks `long` under `__WORDSIZE == 64` and never asks which
2199 // processor it is on, and gcc for aarch64, riscv64 and powerpc64le all agree.
2200 for triple in ["aarch64-unknown-linux-gnu", "riscv64-unknown-linux-gnu"] {
2201 let set = set_for(triple);
2202 assert!(has(&set, "#define __INT_FAST16_TYPE__ long int"), "{triple}");
2203 assert!(has(&set, "#define __UINT_FAST32_TYPE__ long unsigned int"), "{triple}");
2204 assert!(has(&set, "#define __INT_FAST32_WIDTH__ 64"), "{triple}");
2205 }
2206 assert!(has(&set_for("aarch64-unknown-linux-musl"), "#define __INT_FAST16_TYPE__ int"));
2207 // Apple's `stdint.h` makes the 16 bit one `int16_t` and the 32 bit one `int32_t`.
2208 let darwin = set_for("aarch64-apple-darwin");
2209 assert!(has(&darwin, "#define __INT_FAST16_TYPE__ short int"));
2210 assert!(has(&darwin, "#define __INT_FAST32_TYPE__ int"));
2211 }
2212
2213 #[test]
2214 fn armv8_a_says_what_the_base_architecture_has() {
2215 let arm = set_for("aarch64-unknown-linux-gnu");
2216 for line in [
2217 "#define __ARM_ARCH_ISA_A64 1",
2218 "#define __ARM_FEATURE_CLZ 1",
2219 "#define __ARM_FEATURE_IDIV 1",
2220 "#define __ARM_FEATURE_FMA 1",
2221 "#define __FP_FAST_FMA 1",
2222 "#define __GCC_DESTRUCTIVE_SIZE 256",
2223 ] {
2224 assert!(has(&arm, line), "{line}");
2225 }
2226 let x86 = set_for("x86_64-unknown-linux-gnu");
2227 assert!(!x86.contains("__ARM_FEATURE_CLZ"));
2228 assert!(!x86.contains("__FP_FAST_FMA"));
2229 assert!(has(&x86, "#define __GCC_DESTRUCTIVE_SIZE 64"));
2230 }
2231
2232 #[test]
2233 fn musl_and_glibc_disagree_about_the_fast_types_on_the_same_processor() {
2234 // The same x86-64 machine, two libcs, two answers. GCC built for glibc says `long int`
2235 // and GCC built for musl says `int`, because musl defines `int_fast16_t` as `int32_t`
2236 // everywhere. It shows in `stdatomic.h`, which GCC writes out of these macros, so
2237 // getting it wrong makes every atomic fast type the wrong width.
2238 let gnu = set_for("x86_64-unknown-linux-gnu");
2239 let musl = set_for("x86_64-unknown-linux-musl");
2240 assert!(has(&gnu, "#define __INT_FAST16_TYPE__ long int"));
2241 assert!(has(&gnu, "#define __INT_FAST32_TYPE__ long int"));
2242 assert!(has(&gnu, "#define __UINT_FAST16_TYPE__ long unsigned int"));
2243 assert!(has(&musl, "#define __INT_FAST16_TYPE__ int"));
2244 assert!(has(&musl, "#define __INT_FAST32_TYPE__ int"));
2245 assert!(has(&musl, "#define __UINT_FAST16_TYPE__ unsigned int"));
2246 // The limits have to move with the types or a header that checks them stops agreeing
2247 // with the header that uses them.
2248 assert!(has(&gnu, "#define __INT_FAST16_MAX__ 0x7fffffffffffffffL"));
2249 assert!(has(&musl, "#define __INT_FAST16_MAX__ 0x7fffffff"));
2250 assert!(has(&musl, "#define __UINT_FAST16_MAX__ 0xffffffffU"));
2251 }
2252
2253 #[test]
2254 fn the_libc_only_moves_the_two_fast_types_it_is_allowed_to_move() {
2255 // 8 and 64 are the same on both, and so is everything outside the fast family. A libc
2256 // is not a processor and this is the whole of what it is permitted to change here.
2257 let gnu = set_for("x86_64-unknown-linux-gnu");
2258 let musl = set_for("x86_64-unknown-linux-musl");
2259 for line in [
2260 "#define __INT_FAST8_TYPE__ signed char",
2261 "#define __INT_FAST64_TYPE__ long int",
2262 "#define __INT64_TYPE__ long int",
2263 "#define __SIZE_TYPE__ long unsigned int",
2264 "#define __SIZEOF_LONG__ 8",
2265 "#define __LP64__ 1",
2266 ] {
2267 assert!(has(&gnu, line), "glibc lost {line}");
2268 assert!(has(&musl, line), "musl lost {line}");
2269 }
2270 }
2271
2272 #[test]
2273 fn windows_is_the_one_target_where_the_two_middle_fast_types_differ_from_each_other() {
2274 // mingw's `stdint.h` declares `int_fast16_t` a `short` and `int_fast32_t` an `int`, and
2275 // x86_64-w64-mingw32-gcc says the same, so this is the one platform where the pair does
2276 // not share an answer.
2277 let windows = set_for("x86_64-pc-windows-gnu");
2278 assert!(has(&windows, "#define __INT_FAST16_TYPE__ short int"));
2279 assert!(has(&windows, "#define __UINT_FAST16_TYPE__ short unsigned int"));
2280 assert!(has(&windows, "#define __INT_FAST16_MAX__ 0x7fff"));
2281 assert!(has(&windows, "#define __UINT_FAST16_MAX__ 0xffff"));
2282 assert!(has(&windows, "#define __INT_FAST16_WIDTH__ 16"));
2283 assert!(has(&windows, "#define __INT_FAST32_TYPE__ int"));
2284 assert!(has(&windows, "#define __UINT_FAST32_TYPE__ unsigned int"));
2285 assert!(has(&windows, "#define __INT_FAST32_WIDTH__ 32"));
2286 // The two ends of the family are the same as everywhere.
2287 assert!(has(&windows, "#define __INT_FAST8_TYPE__ signed char"));
2288 assert!(has(&windows, "#define __INT_FAST64_TYPE__ long long int"));
2289 }
2290
2291 #[test]
2292 fn windows_answers_to_every_name_gcc_gives_it() {
2293 // The mingw tree reads more than one spelling of the platform and a missing one is a
2294 // declaration that quietly is not there: `winuser.h` guards `EndTask` with `#ifdef
2295 // WINNT` and `rpcdcep.h` guards six `I_Rpc` declarations with `#ifndef WINNT`.
2296 let windows = set_for("x86_64-pc-windows-gnu");
2297 let every = "_WIN32 __WIN32 __WIN32__ __WINNT __WINNT__ __MINGW32__ \
2298 _WIN64 __WIN64 __WIN64__ __MINGW64__ __MSVCRT__ __SEH__ WIN32 WIN64 WINNT";
2299 for name in every.split_whitespace() {
2300 assert!(has(&windows, &format!("#define {name} 1")), "no {name}");
2301 }
2302 assert!(has(&windows, "#define _INTEGRAL_MAX_BITS 64"));
2303 }
2304
2305 #[test]
2306 fn a_thirty_two_bit_windows_is_not_told_its_pointer_is_sixty_four_bits_wide() {
2307 // `_WIN64` is about the pointer rather than the processor, and i686-w64-mingw32-gcc
2308 // defines neither it nor `__MINGW64__`, nor `__SEH__`, since the unwind records this
2309 // compiler writes are the sixty four bit format and a thirty two bit Windows unwinds
2310 // some other way. The target is made by hand because the three field triple has no
2311 // 32-bit row yet, so `i686-windows-gnu` predefines nothing at all and there is no other
2312 // way to reach this arm.
2313 let mut target = TargetInfo::new("x86_64-pc-windows-gnu".parse().expect("a triple"));
2314 target.pointer_width = 32;
2315 let windows = built_in(&target, &Predef::new());
2316 assert!(has(&windows, "#define _WIN32 1"));
2317 assert!(has(&windows, "#define __MINGW32__ 1"));
2318 for name in ["_WIN64", "__WIN64", "__WIN64__", "__MINGW64__", "__SEH__", "WIN64"] {
2319 assert!(!has(&windows, &format!("#define {name} 1")), "{name} on a 32 bit target");
2320 }
2321 }
2322
2323 #[test]
2324 fn the_three_unreserved_windows_names_need_the_gnu_dialect() {
2325 // `WIN32`, `WIN64` and `WINNT` are in the user's namespace, so gcc drops all three under
2326 // `-std=c11` and keeps the underscored ones. Windows code tests them anyway, the same
2327 // way portable Unix code still tests `linux`.
2328 let triple: Triple = "x86_64-pc-windows-gnu".parse().expect("a triple");
2329 let mut opts = Predef::new();
2330 opts.gnu_extensions = false;
2331 let strict = built_in(&TargetInfo::new(triple), &opts);
2332 for name in ["WIN32", "WIN64", "WINNT"] {
2333 assert!(!has(&strict, &format!("#define {name} 1")), "{name} under -std=c11");
2334 }
2335 assert!(has(&strict, "#define _WIN32 1"));
2336 assert!(has(&strict, "#define __WINNT__ 1"));
2337 }
2338}