1use rucc_base::float::Format;
23use rucc_session::{GnucVersion, OptLevel, Options, Std};
24use rucc_target::{Arch, Env, Os, TargetInfo};
25
26pub const BUILT_IN: &str = "<built-in>";
28
29pub const COMMAND_LINE: &str = "<command-line>";
31
32#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Timestamp {
39 pub date: String,
41 pub time: String,
43}
44
45impl Timestamp {
46 pub fn now() -> Timestamp {
51 let seconds = match std::env::var("SOURCE_DATE_EPOCH").ok().and_then(|v| v.parse().ok()) {
52 Some(fixed) => fixed,
53 None => std::time::SystemTime::now()
54 .duration_since(std::time::UNIX_EPOCH)
55 .map_or(0, |d| d.as_secs() as i64),
56 };
57 Timestamp::from_unix(seconds)
58 }
59
60 pub fn from_unix(seconds: i64) -> Timestamp {
65 let days = seconds.div_euclid(86_400);
66 let rest = seconds.rem_euclid(86_400);
67 let (year, month, day) = civil_from_days(days);
68 const MONTHS: [&str; 12] =
69 ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
70 let name = MONTHS[(month - 1) as usize];
71 Timestamp {
72 date: format!("{name} {day:2} {year}"),
73 time: format!("{:02}:{:02}:{:02}", rest / 3600, (rest / 60) % 60, rest % 60),
74 }
75 }
76}
77
78fn civil_from_days(days: i64) -> (i64, u32, u32) {
84 let shifted = days + 719_468;
87 let era = shifted.div_euclid(146_097);
88 let day_of_era = shifted.rem_euclid(146_097);
89 let year_of_era =
90 (day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
91 let year = year_of_era + era * 400;
92 let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
93 let marched = (5 * day_of_year + 2) / 153;
94 let day = (day_of_year - (153 * marched + 2) / 5 + 1) as u32;
95 let month = if marched < 10 { marched + 3 } else { marched - 9 } as u32;
96 (year + i64::from(month <= 2), month, day)
97}
98
99#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct Predef {
102 pub std: Std,
104 pub gnu_extensions: bool,
107 pub gnu89_inline: bool,
111 pub gnuc: GnucVersion,
113 pub opt_level: OptLevel,
115 pub hosted: bool,
117 pub timestamp: Timestamp,
119 pub defines: Vec<String>,
121 pub undefines: Vec<String>,
123}
124
125impl Predef {
126 pub fn new() -> Predef {
128 Predef {
129 std: Std::default(),
130 gnu_extensions: true,
131 gnu89_inline: false,
132 gnuc: GnucVersion::default(),
133 opt_level: OptLevel::O0,
134 hosted: true,
135 timestamp: Timestamp::now(),
136 defines: Vec::new(),
137 undefines: Vec::new(),
138 }
139 }
140}
141
142impl Predef {
143 pub fn for_options(opts: &Options) -> Predef {
149 Predef {
150 std: opts.std,
151 gnu_extensions: opts.gnu_extensions,
152 gnu89_inline: opts.gnu89_inline,
153 gnuc: opts.gnuc,
154 opt_level: opts.opt_level,
155 hosted: opts.hosted,
156 timestamp: Timestamp::now(),
157 defines: opts.defines.clone(),
158 undefines: opts.undefines.clone(),
159 }
160 }
161}
162
163impl Default for Predef {
164 fn default() -> Predef {
165 Predef::new()
166 }
167}
168
169struct Defs {
171 text: String,
172}
173
174impl Defs {
175 fn new() -> Defs {
176 Defs { text: String::new() }
177 }
178
179 fn set(&mut self, name: &str, value: &str) {
181 self.text.push_str("#define ");
182 self.text.push_str(name);
183 self.text.push(' ');
184 self.text.push_str(value);
185 self.text.push('\n');
186 }
187
188 fn flag(&mut self, name: &str) {
190 self.set(name, "1");
191 }
192
193 fn set_if(&mut self, when: bool, name: &str, value: &str) {
194 if when {
195 self.set(name, value);
196 }
197 }
198
199 fn flag_if(&mut self, when: bool, name: &str) {
200 if when {
201 self.flag(name);
202 }
203 }
204}
205
206pub(crate) fn built_in(target: &TargetInfo, opts: &Predef) -> String {
208 let mut d = Defs::new();
209 identity(&mut d, target, opts);
210 d.set("__DATE__", &format!("\"{}\"", opts.timestamp.date));
214 d.set("__TIME__", &format!("\"{}\"", opts.timestamp.time));
215 dialect(&mut d, opts);
216 optimization(&mut d, opts);
217 platform(&mut d, target, opts);
218 sizes(&mut d, target);
219 integers(&mut d, target);
220 floats(&mut d, target);
221 atomics(&mut d, target);
222 d.text
223}
224
225pub(crate) fn command_line(opts: &Predef) -> String {
231 let mut d = Defs::new();
232 for define in &opts.defines {
233 match define.split_once('=') {
234 Some((name, value)) => d.set(name, value),
235 None => d.flag(define),
238 }
239 }
240 for name in &opts.undefines {
241 d.text.push_str("#undef ");
242 d.text.push_str(name);
243 d.text.push('\n');
244 }
245 d.text
246}
247
248fn identity(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
250 d.flag("__rucc__");
251 d.set("__rucc_version__", "\"0.1.0\"");
252 d.set("__rucc_major__", "0");
253 d.set("__rucc_minor__", "1");
254 d.set("__rucc_patchlevel__", "0");
255 d.set("__GNUC__", &opts.gnuc.major.to_string());
257 d.set("__GNUC_MINOR__", &opts.gnuc.minor.to_string());
258 d.set("__GNUC_PATCHLEVEL__", &opts.gnuc.patch.to_string());
259 d.set("__VERSION__", "\"rucc 0.1.0\"");
260 let gnu_inline = opts.gnu89_inline || opts.std == Std::C89;
269 d.flag_if(gnu_inline, "__GNUC_GNU_INLINE__");
270 d.flag_if(!gnu_inline, "__GNUC_STDC_INLINE__");
271 d.set("__GNUC_EXECUTION_CHARSET_NAME", "\"UTF-8\"");
276 let wide = if target.wchar_width == 16 { "\"UTF-16LE\"" } else { "\"UTF-32LE\"" };
277 d.set("__GNUC_WIDE_EXECUTION_CHARSET_NAME", wide);
278 d.set("__GXX_ABI_VERSION", "1021");
283}
284
285fn dialect(d: &mut Defs, opts: &Predef) {
287 d.flag("__STDC__");
288 d.set_if(opts.hosted, "__STDC_HOSTED__", "1");
289 d.set_if(!opts.hosted, "__STDC_HOSTED__", "0");
290 if let Some(version) = opts.std.stdc_version() {
291 d.set("__STDC_VERSION__", version);
292 }
293 d.flag_if(!opts.gnu_extensions, "__STRICT_ANSI__");
296 d.flag("__STDC_UTF_16__");
297 d.flag("__STDC_UTF_32__");
298 d.flag("__STDC_IEC_559__");
299 d.flag("__STDC_IEC_559_COMPLEX__");
300 d.set_if(opts.std == Std::C23, "__STDC_IEC_60559_BFP__", "202311L");
301 d.set("__STDC_ISO_10646__", "201706L");
302 d.set_if(opts.std == Std::C23, "__CHAR8_TYPE__", "unsigned char");
308 if opts.std.has_c11() {
320 d.flag("__STDC_NO_ATOMICS__");
321 d.flag("__STDC_NO_THREADS__");
322 d.flag("__STDC_NO_COMPLEX__");
323 }
324 d.set("__STDC_EMBED_NOT_FOUND__", "0");
329 d.set("__STDC_EMBED_FOUND__", "1");
330 d.set("__STDC_EMBED_EMPTY__", "2");
331}
332
333fn atomics(d: &mut Defs, target: &TargetInfo) {
345 d.set("__ATOMIC_RELAXED", "0");
346 d.set("__ATOMIC_CONSUME", "1");
347 d.set("__ATOMIC_ACQUIRE", "2");
348 d.set("__ATOMIC_RELEASE", "3");
349 d.set("__ATOMIC_ACQ_REL", "4");
350 d.set("__ATOMIC_SEQ_CST", "5");
351 let llong = if target.pointer_width == 64 { "2" } else { "1" };
354 for name in [
355 "BOOL", "CHAR", "CHAR8_T", "CHAR16_T", "CHAR32_T", "WCHAR_T", "SHORT", "INT", "LONG",
356 "POINTER",
357 ] {
358 d.set(&format!("__GCC_ATOMIC_{name}_LOCK_FREE"), "2");
359 }
360 d.set("__GCC_ATOMIC_LLONG_LOCK_FREE", llong);
364 d.set("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
365 for width in [1, 2, 4, 8] {
369 d.flag(&format!("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_{width}"));
370 }
371 if target.triple.arch == Arch::X86_64 {
376 d.set("__ATOMIC_HLE_ACQUIRE", "65536");
377 d.set("__ATOMIC_HLE_RELEASE", "131072");
378 }
379}
380
381fn optimization(d: &mut Defs, opts: &Predef) {
383 d.flag_if(opts.opt_level.runs_optimizer(), "__OPTIMIZE__");
384 d.flag_if(opts.opt_level.is_size(), "__OPTIMIZE_SIZE__");
385 d.flag_if(!opts.opt_level.runs_optimizer(), "__NO_INLINE__");
388 d.set("__FINITE_MATH_ONLY__", "0");
394}
395
396fn platform(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
398 let triple = target.triple;
399 match triple.arch {
400 Arch::X86_64 => {
401 d.flag("__x86_64__");
402 d.flag("__x86_64");
403 d.flag("__amd64__");
404 d.flag("__amd64");
405 d.flag("__SSE__");
406 d.flag("__SSE2__");
407 d.flag("__MMX__");
408 d.flag("__SSE_MATH__");
409 d.flag("__SSE2_MATH__");
410 d.flag("__k8");
411 d.flag("__k8__");
412 d.flag("__FXSR__");
415 d.flag("__code_model_small__");
416 d.flag("__MMX_WITH_SSE__");
421 }
422 Arch::Aarch64 => {
423 d.flag("__aarch64__");
424 d.flag("__AARCH64EL__");
425 d.set("__ARM_ARCH", "8");
426 d.set("__ARM_ARCH_PROFILE", "'A'");
427 d.set("__ARM_64BIT_STATE", "1");
428 d.set("__ARM_ALIGN_MAX_PWR", "28");
429 d.set("__ARM_FP", "0xe");
430 d.set("__ARM_NEON", "1");
431 d.set("__ARM_FEATURE_UNALIGNED", "1");
432 d.set("__ARM_PCS_AAPCS64", "1");
433 }
434 Arch::Riscv64 => {
435 d.flag("__riscv");
436 d.set("__riscv_xlen", "64");
437 d.set("__riscv_flen", "64");
438 d.flag("__riscv_float_abi_double");
439 d.flag("__riscv_muldiv");
440 d.flag("__riscv_atomic");
441 d.flag("__riscv_compressed");
442 d.set("__riscv_cmodel_medlow", "1");
443 }
444 }
445 match triple.os {
446 Os::Linux => {
447 d.flag("__linux__");
448 d.flag("__linux");
449 d.flag("__unix__");
450 d.flag("__unix");
451 d.flag("__gnu_linux__");
452 d.flag("__ELF__");
453 if opts.gnu_extensions {
456 d.flag("linux");
457 d.flag("unix");
458 }
459 }
460 Os::Darwin => {
461 d.flag("__APPLE__");
462 d.flag("__MACH__");
463 d.flag("__unix__");
464 d.flag("__unix");
465 d.set("__APPLE_CC__", "6000");
466 d.set("__DYNAMIC__", "1");
467 if triple.arch == Arch::Aarch64 {
468 d.flag("__arm64__");
473 d.flag("__arm64");
474 }
475 if opts.gnu_extensions {
476 d.flag("unix");
477 }
478 }
479 Os::Windows => {
480 d.flag("_WIN32");
481 d.flag("__WIN32__");
482 d.flag("_WIN64");
483 d.flag("__WIN64__");
484 d.flag("__MINGW32__");
485 }
486 Os::None => {
487 d.flag("__ELF__");
490 }
491 }
492 match triple.env {
493 Env::Musl => d.flag("__musl__"),
494 Env::Gnu | Env::None | Env::Msvc => {}
495 }
496 if target.long_width == 64 && target.pointer_width == 64 {
499 d.flag("__LP64__");
500 d.flag("_LP64");
501 }
502 d.set("__USER_LABEL_PREFIX__", if triple.os == Os::Darwin { "_" } else { "" });
509 d.set("__REGISTER_PREFIX__", "");
513
514 if !matches!(triple.os, Os::Windows) {
517 d.set("__PIC__", "2");
518 d.set("__pic__", "2");
519 }
520}
521
522fn sizes(d: &mut Defs, target: &TargetInfo) {
524 let pointer = target.pointer_width / 8;
525 d.set("__GCC_CONSTRUCTIVE_SIZE", "64");
530 d.set("__GCC_DESTRUCTIVE_SIZE", "64");
531 let long = target.long_width / 8;
532 let long_double = target.long_double_width / 8;
533 d.set("__CHAR_BIT__", "8");
534 d.set("__SIZEOF_SHORT__", "2");
535 d.set("__SIZEOF_INT__", "4");
536 d.set("__SIZEOF_LONG__", &long.to_string());
537 d.set("__SIZEOF_LONG_LONG__", "8");
538 d.set("__SIZEOF_INT128__", "16");
539 d.set("__SIZEOF_FLOAT__", "4");
540 d.set("__SIZEOF_DOUBLE__", "8");
541 d.set("__SIZEOF_LONG_DOUBLE__", &long_double.to_string());
542 d.set("__SIZEOF_POINTER__", &pointer.to_string());
543 d.set("__SIZEOF_SIZE_T__", &pointer.to_string());
544 d.set("__SIZEOF_PTRDIFF_T__", &pointer.to_string());
545 d.set("__SIZEOF_WCHAR_T__", &wchar(target).size.to_string());
546 d.set("__SIZEOF_WINT_T__", "4");
547 d.set("__BIGGEST_ALIGNMENT__", "16");
548 d.set("__ORDER_LITTLE_ENDIAN__", "1234");
552 d.set("__ORDER_BIG_ENDIAN__", "4321");
553 d.set("__ORDER_PDP_ENDIAN__", "3412");
554 let order =
555 if target.little_endian { "__ORDER_LITTLE_ENDIAN__" } else { "__ORDER_BIG_ENDIAN__" };
556 d.set("__BYTE_ORDER__", order);
557 d.set("__FLOAT_WORD_ORDER__", order);
558 d.flag_if(!target.char_is_signed, "__CHAR_UNSIGNED__");
559}
560
561struct Wchar {
563 spelling: &'static str,
565 size: u32,
567 max: &'static str,
569 min: &'static str,
571}
572
573fn wchar(target: &TargetInfo) -> Wchar {
583 match (target.wchar_width, target.wchar_is_signed) {
584 (16, false) => Wchar { spelling: "short unsigned int", size: 2, max: "0xffff", min: "0" },
585 (16, true) => Wchar { spelling: "short int", size: 2, max: "0x7fff", min: "(-32767 - 1)" },
586 (_, false) => Wchar { spelling: "unsigned int", size: 4, max: "0xffffffffU", min: "0U" },
587 (_, true) => {
588 Wchar { spelling: "int", size: 4, max: "0x7fffffff", min: "(-__WCHAR_MAX__ - 1)" }
589 }
590 }
591}
592
593struct Wint {
595 spelling: &'static str,
597 max: &'static str,
599 min: &'static str,
601 width: u32,
603}
604
605fn wint(target: &TargetInfo) -> Wint {
612 match target.triple.os {
613 Os::Windows => Wint { spelling: "short unsigned int", max: "0xffff", min: "0", width: 16 },
614 Os::Darwin => {
615 Wint { spelling: "int", max: "0x7fffffff", min: "(-__WINT_MAX__ - 1)", width: 32 }
616 }
617 _ => Wint { spelling: "unsigned int", max: "0xffffffffU", min: "0U", width: 32 },
618 }
619}
620
621fn integers(d: &mut Defs, target: &TargetInfo) {
623 let lp64 = target.long_width == 64;
627 let wide = if lp64 { "long int" } else { "long long int" };
628 let wide_unsigned = if lp64 { "long unsigned int" } else { "long long unsigned int" };
629 let wide_suffix = if lp64 { "L" } else { "LL" };
630 let wide_max = format!("0x7fffffffffffffff{wide_suffix}");
631 let wide_umax = format!("0xffffffffffffffffU{wide_suffix}");
632
633 d.set("__SCHAR_MAX__", "0x7f");
634 d.set("__SHRT_MAX__", "0x7fff");
635 d.set("__INT_MAX__", "0x7fffffff");
636 d.set("__LONG_MAX__", if lp64 { "0x7fffffffffffffffL" } else { "0x7fffffffL" });
637 d.set("__LONG_LONG_MAX__", "0x7fffffffffffffffLL");
638 d.set("__INTMAX_MAX__", &wide_max);
639 d.set("__UINTMAX_MAX__", &wide_umax);
640 d.set("__SIZE_MAX__", &wide_umax);
641 d.set("__PTRDIFF_MAX__", &wide_max);
642 d.set("__INTPTR_MAX__", &wide_max);
643 d.set("__UINTPTR_MAX__", &wide_umax);
644 d.set("__SIG_ATOMIC_MAX__", "0x7fffffff");
645 d.set("__SIG_ATOMIC_MIN__", "(-__SIG_ATOMIC_MAX__ - 1)");
646 d.set("__BITINT_MAXWIDTH__", "128");
653
654 let wchar = wchar(target);
655 d.set("__WCHAR_TYPE__", wchar.spelling);
656 d.set("__WCHAR_MAX__", wchar.max);
657 d.set("__WCHAR_MIN__", wchar.min);
658 let wint = wint(target);
659 d.set("__WINT_TYPE__", wint.spelling);
660 d.set("__WINT_MAX__", wint.max);
661 d.set("__WINT_MIN__", wint.min);
662 d.set("__SIZE_TYPE__", wide_unsigned);
663 d.set("__PTRDIFF_TYPE__", wide);
664 d.set("__INTMAX_TYPE__", wide);
665 d.set("__UINTMAX_TYPE__", wide_unsigned);
666 d.set("__INTPTR_TYPE__", wide);
667 d.set("__UINTPTR_TYPE__", wide_unsigned);
668 d.set("__SIG_ATOMIC_TYPE__", "int");
669 d.set("__CHAR16_TYPE__", "short unsigned int");
670 d.set("__CHAR32_TYPE__", "unsigned int");
671 d.set("__INTMAX_C(c)", &format!("c ## {wide_suffix}"));
672 d.set("__UINTMAX_C(c)", &format!("c ## U{wide_suffix}"));
673
674 exact(d, 8, "signed char", "unsigned char", "0x7f", "0xff", "");
676 exact(d, 16, "short int", "short unsigned int", "0x7fff", "0xffff", "");
677 exact(d, 32, "int", "unsigned int", "0x7fffffff", "0xffffffffU", "");
680 exact(d, 64, wide, wide_unsigned, &wide_max, &wide_umax, wide_suffix);
681
682 let fast_is_wide = target.triple.arch == Arch::X86_64 && lp64 && target.triple.env != Env::Musl;
693 let fast_middle = if fast_is_wide { wide } else { "int" };
694 d.set("__INT_FAST8_TYPE__", "signed char");
695 d.set("__UINT_FAST8_TYPE__", "unsigned char");
696 d.set("__INT_FAST8_MAX__", "0x7f");
697 d.set("__UINT_FAST8_MAX__", "0xff");
698 for width in [16, 32] {
699 let unsigned = if fast_middle == "int" { "unsigned int" } else { wide_unsigned };
700 let max = if fast_middle == "int" { "0x7fffffff" } else { wide_max.as_str() };
701 let umax = if fast_middle == "int" { "0xffffffffU" } else { wide_umax.as_str() };
702 d.set(&format!("__INT_FAST{width}_TYPE__"), fast_middle);
703 d.set(&format!("__UINT_FAST{width}_TYPE__"), unsigned);
704 d.set(&format!("__INT_FAST{width}_MAX__"), max);
705 d.set(&format!("__UINT_FAST{width}_MAX__"), umax);
706 }
707 d.set("__INT_FAST64_TYPE__", wide);
708 d.set("__UINT_FAST64_TYPE__", wide_unsigned);
709 d.set("__INT_FAST64_MAX__", &wide_max);
710 d.set("__UINT_FAST64_MAX__", &wide_umax);
711
712 widths(d, target, &wchar, &wint, if fast_is_wide { 64 } else { 32 });
713}
714
715fn widths(d: &mut Defs, target: &TargetInfo, wchar: &Wchar, wint: &Wint, fast_middle: u32) {
726 let pointer = target.pointer_width;
727 d.set("__SCHAR_WIDTH__", "8");
728 d.set("__SHRT_WIDTH__", "16");
729 d.set("__INT_WIDTH__", "32");
730 d.set("__LONG_WIDTH__", &target.long_width.to_string());
731 d.set("__LONG_LONG_WIDTH__", "64");
732 d.set("__INTMAX_WIDTH__", "64");
733 d.set("__INTPTR_WIDTH__", &pointer.to_string());
734 d.set("__PTRDIFF_WIDTH__", &pointer.to_string());
735 d.set("__SIZE_WIDTH__", &pointer.to_string());
736 d.set("__SIG_ATOMIC_WIDTH__", "32");
737 d.set("__WCHAR_WIDTH__", &(wchar.size * 8).to_string());
738 d.set("__WINT_WIDTH__", &wint.width.to_string());
739 for width in [8, 16, 32, 64] {
740 d.set(&format!("__INT_LEAST{width}_WIDTH__"), &width.to_string());
741 }
742 d.set("__INT_FAST8_WIDTH__", "8");
743 d.set("__INT_FAST16_WIDTH__", &fast_middle.to_string());
744 d.set("__INT_FAST32_WIDTH__", &fast_middle.to_string());
745 d.set("__INT_FAST64_WIDTH__", "64");
746}
747
748fn exact(
750 d: &mut Defs,
751 width: u32,
752 signed: &str,
753 unsigned: &str,
754 max: &str,
755 umax: &str,
756 width_suffix: &str,
760) {
761 d.set(&format!("__INT{width}_TYPE__"), signed);
762 d.set(&format!("__UINT{width}_TYPE__"), unsigned);
763 d.set(&format!("__INT{width}_MAX__"), max);
764 d.set(&format!("__UINT{width}_MAX__"), umax);
765 d.set(&format!("__INT_LEAST{width}_TYPE__"), signed);
766 d.set(&format!("__UINT_LEAST{width}_TYPE__"), unsigned);
767 d.set(&format!("__INT_LEAST{width}_MAX__"), max);
768 d.set(&format!("__UINT_LEAST{width}_MAX__"), umax);
769 let unsigned_after_promotion = width >= 32;
779 let u = if unsigned_after_promotion { "U" } else { "" };
780 if width_suffix.is_empty() && u.is_empty() {
781 d.set(&format!("__INT{width}_C(c)"), "c");
782 d.set(&format!("__UINT{width}_C(c)"), "c");
783 } else if width_suffix.is_empty() {
784 d.set(&format!("__INT{width}_C(c)"), "c");
785 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}"));
786 } else {
787 d.set(&format!("__INT{width}_C(c)"), &format!("c ## {width_suffix}"));
788 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}{width_suffix}"));
789 }
790}
791
792struct Characteristics {
798 mant_dig: &'static str,
799 dig: &'static str,
800 min_exp: &'static str,
801 min_10_exp: &'static str,
802 max_exp: &'static str,
803 max_10_exp: &'static str,
804 decimal_dig: &'static str,
805 max: &'static str,
806 min: &'static str,
807 epsilon: &'static str,
808 denorm_min: &'static str,
809 is_iec_60559: &'static str,
812}
813
814const HALF: Characteristics = Characteristics {
816 mant_dig: "11",
817 dig: "3",
818 min_exp: "(-13)",
819 min_10_exp: "(-4)",
820 max_exp: "16",
821 max_10_exp: "4",
822 decimal_dig: "5",
823 max: "6.55040000000000000000000000000000000e+4",
824 min: "6.10351562500000000000000000000000000e-5",
825 epsilon: "9.76562500000000000000000000000000000e-4",
826 denorm_min: "5.96046447753906250000000000000000000e-8",
827 is_iec_60559: "1",
828};
829
830const BFLOAT16: Characteristics = Characteristics {
832 mant_dig: "8",
833 dig: "2",
834 min_exp: "(-125)",
835 min_10_exp: "(-37)",
836 max_exp: "128",
837 max_10_exp: "38",
838 decimal_dig: "4",
839 max: "3.38953138925153547590470800371487867e+38",
840 min: "1.17549435082228750796873653722224568e-38",
841 epsilon: "7.81250000000000000000000000000000000e-3",
842 denorm_min: "9.18354961579912115600575419704879436e-41",
843 is_iec_60559: "0",
844};
845
846const SINGLE: Characteristics = Characteristics {
848 mant_dig: "24",
849 dig: "6",
850 min_exp: "(-125)",
851 min_10_exp: "(-37)",
852 max_exp: "128",
853 max_10_exp: "38",
854 decimal_dig: "9",
855 max: "3.40282346638528859811704183484516925e+38",
856 min: "1.17549435082228750796873653722224568e-38",
857 epsilon: "1.19209289550781250000000000000000000e-7",
858 denorm_min: "1.40129846432481707092372958328991613e-45",
859 is_iec_60559: "1",
860};
861
862const DOUBLE: Characteristics = Characteristics {
865 mant_dig: "53",
866 dig: "15",
867 min_exp: "(-1021)",
868 min_10_exp: "(-307)",
869 max_exp: "1024",
870 max_10_exp: "308",
871 decimal_dig: "17",
872 max: "1.79769313486231570814527423731704357e+308",
873 min: "2.22507385850720138309023271733240406e-308",
874 epsilon: "2.22044604925031308084726333618164062e-16",
875 denorm_min: "4.94065645841246544176568792868221372e-324",
876 is_iec_60559: "1",
877};
878
879const X87: Characteristics = Characteristics {
881 mant_dig: "64",
882 dig: "18",
883 min_exp: "(-16381)",
884 min_10_exp: "(-4931)",
885 max_exp: "16384",
886 max_10_exp: "4932",
887 decimal_dig: "21",
888 max: "1.18973149535723176502126385303097021e+4932",
889 min: "3.36210314311209350626267781732175260e-4932",
890 epsilon: "1.08420217248550443400745280086994171e-19",
891 denorm_min: "3.64519953188247460252840593361941982e-4951",
892 is_iec_60559: "1",
893};
894
895const QUAD: Characteristics = Characteristics {
898 mant_dig: "113",
899 dig: "33",
900 min_exp: "(-16381)",
901 min_10_exp: "(-4931)",
902 max_exp: "16384",
903 max_10_exp: "4932",
904 decimal_dig: "36",
905 max: "1.18973149535723176508575932662800702e+4932",
906 min: "3.36210314311209350626267781732175260e-4932",
907 epsilon: "1.92592994438723585305597794258492732e-34",
908 denorm_min: "6.47517511943802511092443895822764655e-4966",
909 is_iec_60559: "1",
910};
911
912const fn characteristics(format: Format) -> &'static Characteristics {
915 match format {
916 Format::Half => &HALF,
917 Format::BFloat16 => &BFLOAT16,
918 Format::Single => &SINGLE,
919 Format::Double => &DOUBLE,
920 Format::X87Extended => &X87,
921 Format::Quad => &QUAD,
922 }
923}
924
925fn floats(d: &mut Defs, target: &TargetInfo) {
936 d.set("__FLT_RADIX__", "2");
937 d.set("__GCC_IEC_559", "2");
942 d.set("__FLT_EVAL_METHOD__", "0");
947 d.set("__FLT_EVAL_METHOD_C99__", "0");
948 d.set("__FLT_EVAL_METHOD_TS_18661_3__", "0");
949
950 family(d, "FLT", &SINGLE, |value| format!("{value}F"));
951 family(d, "DBL", &DOUBLE, |value| format!("((double){value}L)"));
954 family(d, "LDBL", characteristics(target.long_double_format), |value| format!("{value}L"));
955
956 family(d, "FLT16", &HALF, |value| format!("{value}F16"));
957 family(d, "FLT32", &SINGLE, |value| format!("{value}F32"));
958 family(d, "FLT64", &DOUBLE, |value| format!("{value}F64"));
959 family(d, "FLT128", &QUAD, |value| format!("{value}F128"));
960 family(d, "FLT32X", &DOUBLE, |value| format!("{value}F32x"));
961 family(d, "FLT64X", characteristics(target.float64x_format), |value| format!("{value}F64x"));
962
963 d.set("__DECIMAL_DIG__", characteristics(target.long_double_format).decimal_dig);
968}
969
970fn family(d: &mut Defs, prefix: &str, c: &Characteristics, write: impl Fn(&str) -> String) {
976 d.set(&format!("__{prefix}_MANT_DIG__"), c.mant_dig);
977 d.set(&format!("__{prefix}_DIG__"), c.dig);
978 d.set(&format!("__{prefix}_MIN_EXP__"), c.min_exp);
979 d.set(&format!("__{prefix}_MIN_10_EXP__"), c.min_10_exp);
980 d.set(&format!("__{prefix}_MAX_EXP__"), c.max_exp);
981 d.set(&format!("__{prefix}_MAX_10_EXP__"), c.max_10_exp);
982 d.set(&format!("__{prefix}_DECIMAL_DIG__"), c.decimal_dig);
983 d.set(&format!("__{prefix}_MAX__"), &write(c.max));
984 d.set(&format!("__{prefix}_NORM_MAX__"), &write(c.max));
985 d.set(&format!("__{prefix}_MIN__"), &write(c.min));
986 d.set(&format!("__{prefix}_EPSILON__"), &write(c.epsilon));
987 d.set(&format!("__{prefix}_DENORM_MIN__"), &write(c.denorm_min));
988 d.set(&format!("__{prefix}_IS_IEC_60559__"), c.is_iec_60559);
989 d.set(&format!("__{prefix}_HAS_DENORM__"), "1");
990 d.set(&format!("__{prefix}_HAS_INFINITY__"), "1");
991 d.set(&format!("__{prefix}_HAS_QUIET_NAN__"), "1");
992}
993
994#[cfg(test)]
995mod tests {
996 use rucc_target::Triple;
997
998 use super::*;
999
1000 fn set_for(triple: &str) -> String {
1001 let triple: Triple = triple.parse().expect("a triple the compiler supports");
1002 built_in(&TargetInfo::new(triple), &Predef::new())
1003 }
1004
1005 fn has(text: &str, line: &str) -> bool {
1006 text.lines().any(|l| l == line)
1007 }
1008
1009 #[test]
1010 fn the_set_is_driven_by_the_target_rather_than_by_the_host() {
1011 let x86 = set_for("x86_64-unknown-linux-gnu");
1012 let arm = set_for("aarch64-unknown-linux-gnu");
1013 assert!(has(&x86, "#define __x86_64__ 1"));
1014 assert!(!has(&x86, "#define __aarch64__ 1"));
1015 assert!(has(&arm, "#define __aarch64__ 1"));
1016 assert!(!has(&arm, "#define __x86_64__ 1"));
1017 assert!(has(&x86, "#define __linux__ 1") && has(&arm, "#define __linux__ 1"));
1018 }
1019
1020 #[test]
1021 fn windows_is_the_target_that_makes_long_thirty_two_bits() {
1022 let windows = set_for("x86_64-pc-windows-msvc");
1023 let linux = set_for("x86_64-unknown-linux-gnu");
1024 assert!(has(&windows, "#define __SIZEOF_LONG__ 4"));
1025 assert!(has(&windows, "#define __SIZE_TYPE__ long long unsigned int"));
1026 assert!(has(&windows, "#define __INT64_TYPE__ long long int"));
1027 assert!(!has(&windows, "#define __LP64__ 1"));
1028 assert!(has(&linux, "#define __SIZEOF_LONG__ 8"));
1029 assert!(has(&linux, "#define __SIZE_TYPE__ long unsigned int"));
1030 assert!(has(&linux, "#define __INT64_TYPE__ long int"));
1031 assert!(has(&linux, "#define __LP64__ 1"));
1032 }
1033
1034 #[test]
1035 fn wchar_t_is_the_type_that_divides_the_targets() {
1036 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ int"));
1038 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ unsigned int"));
1039 let windows = set_for("x86_64-pc-windows-msvc");
1040 assert!(has(&windows, "#define __WCHAR_TYPE__ short unsigned int"));
1041 assert!(has(&windows, "#define __SIZEOF_WCHAR_T__ 2"));
1042 }
1043
1044 #[test]
1045 fn apple_spells_the_architecture_its_own_way_and_its_headers_only_know_that_spelling() {
1046 let darwin = set_for("aarch64-apple-darwin");
1049 assert!(has(&darwin, "#define __arm64__ 1"));
1050 assert!(has(&darwin, "#define __arm64 1"));
1051 assert!(has(&darwin, "#define __aarch64__ 1"), "the portable spelling stays too");
1052 let linux = set_for("aarch64-unknown-linux-gnu");
1053 assert!(!has(&linux, "#define __arm64__ 1"), "Apple's spelling is Apple's alone");
1054 assert!(!has(&set_for("x86_64-apple-darwin"), "#define __arm64__ 1"));
1055 }
1056
1057 #[test]
1058 fn every_limit_is_spelled_in_hexadecimal_the_way_gcc_spells_it() {
1059 let linux = set_for("x86_64-unknown-linux-gnu");
1066 for line in [
1067 "#define __SCHAR_MAX__ 0x7f",
1068 "#define __SHRT_MAX__ 0x7fff",
1069 "#define __INT_MAX__ 0x7fffffff",
1070 "#define __LONG_MAX__ 0x7fffffffffffffffL",
1071 "#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL",
1072 "#define __INTMAX_MAX__ 0x7fffffffffffffffL",
1073 "#define __UINTMAX_MAX__ 0xffffffffffffffffUL",
1074 "#define __SIZE_MAX__ 0xffffffffffffffffUL",
1075 "#define __PTRDIFF_MAX__ 0x7fffffffffffffffL",
1076 "#define __SIG_ATOMIC_MAX__ 0x7fffffff",
1077 "#define __INT8_MAX__ 0x7f",
1078 "#define __UINT8_MAX__ 0xff",
1079 "#define __INT16_MAX__ 0x7fff",
1080 "#define __UINT16_MAX__ 0xffff",
1081 "#define __INT32_MAX__ 0x7fffffff",
1082 "#define __UINT32_MAX__ 0xffffffffU",
1083 "#define __INT64_MAX__ 0x7fffffffffffffffL",
1084 "#define __UINT64_MAX__ 0xffffffffffffffffUL",
1085 "#define __INT_FAST8_MAX__ 0x7f",
1086 "#define __UINT_FAST8_MAX__ 0xff",
1087 ] {
1088 assert!(has(&linux, line), "{line}");
1089 }
1090 let windows = set_for("x86_64-pc-windows-msvc");
1093 assert!(has(&windows, "#define __LONG_MAX__ 0x7fffffffL"));
1094 assert!(has(&windows, "#define __INTMAX_MAX__ 0x7fffffffffffffffLL"));
1095 assert!(has(&windows, "#define __UINTMAX_MAX__ 0xffffffffffffffffULL"));
1096 }
1097
1098 #[test]
1099 fn wint_t_does_not_follow_wchar_t() {
1100 let darwin = set_for("aarch64-apple-darwin");
1102 assert!(has(&darwin, "#define __WINT_TYPE__ int"));
1103 assert!(has(&darwin, "#define __WINT_MAX__ 0x7fffffff"));
1104 assert!(has(&darwin, "#define __WCHAR_TYPE__ int"));
1105 let linux = set_for("aarch64-unknown-linux-gnu");
1106 assert!(has(&linux, "#define __WINT_TYPE__ unsigned int"));
1107 assert!(has(&linux, "#define __WINT_MAX__ 0xffffffffU"));
1108 assert!(has(&linux, "#define __WCHAR_TYPE__ unsigned int"), "and wchar_t is its own");
1109 assert!(has(
1110 &set_for("x86_64-pc-windows-msvc"),
1111 "#define __WINT_TYPE__ short unsigned int"
1112 ));
1113 }
1114
1115 #[test]
1116 fn the_widths_say_what_the_type_holds_and_follow_the_target_that_changes_it() {
1117 let linux = set_for("x86_64-unknown-linux-gnu");
1121 assert_eq!(linux.lines().filter(|line| line.contains("_WIDTH__")).count(), 20);
1122 assert!(has(&linux, "#define __LONG_WIDTH__ 64"));
1123 assert!(has(&linux, "#define __SIZE_WIDTH__ 64"));
1124 assert!(has(&linux, "#define __WCHAR_WIDTH__ 32"));
1125 assert!(has(&linux, "#define __INT_LEAST16_WIDTH__ 16"));
1126 assert!(has(&linux, "#define __INT_FAST16_WIDTH__ 64"));
1129 assert!(has(&set_for("x86_64-unknown-linux-musl"), "#define __INT_FAST16_WIDTH__ 32"));
1130 let windows = set_for("x86_64-pc-windows-msvc");
1133 assert!(has(&windows, "#define __LONG_WIDTH__ 32"));
1134 assert!(has(&windows, "#define __WINT_WIDTH__ 16"));
1135 assert!(has(&windows, "#define __SIZE_WIDTH__ 64"));
1136 assert!(has(&windows, "#define __INTMAX_WIDTH__ 64"));
1137 }
1138
1139 #[test]
1140 fn a_constant_maker_gets_the_suffix_its_width_needs_and_no_other() {
1141 let linux = set_for("x86_64-unknown-linux-gnu");
1145 assert!(has(&linux, "#define __INT32_C(c) c"));
1146 assert!(has(&linux, "#define __UINT32_C(c) c ## U"));
1147 assert!(has(&linux, "#define __INT16_C(c) c"));
1148 assert!(has(&linux, "#define __UINT16_C(c) c"));
1151 assert!(has(&linux, "#define __UINT8_C(c) c"));
1152 assert!(has(&linux, "#define __INT64_C(c) c ## L"));
1154 assert!(has(&linux, "#define __UINT64_C(c) c ## UL"));
1155 let windows = set_for("x86_64-pc-windows-msvc");
1157 assert!(has(&windows, "#define __INT64_C(c) c ## LL"));
1158 assert!(has(&windows, "#define __UINT64_C(c) c ## ULL"));
1159 }
1160
1161 #[test]
1162 fn the_symbol_prefix_is_defined_everywhere_including_where_it_is_empty() {
1163 for triple in
1168 ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
1169 {
1170 assert!(has(&set_for(triple), "#define __USER_LABEL_PREFIX__ "), "{triple}");
1171 }
1172 assert!(has(&set_for("aarch64-apple-darwin"), "#define __USER_LABEL_PREFIX__ _"));
1174 }
1175
1176 #[test]
1180 fn the_toolchain_macros_gcc_defines_are_defined_with_gccs_values() {
1181 let linux = set_for("x86_64-unknown-linux-gnu");
1182 for line in [
1183 "#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"",
1184 "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"",
1185 "#define __GXX_ABI_VERSION 1021",
1186 "#define __REGISTER_PREFIX__ ",
1187 "#define __FINITE_MATH_ONLY__ 0",
1188 "#define __GCC_IEC_559 2",
1189 "#define __GCC_CONSTRUCTIVE_SIZE 64",
1190 "#define __GCC_DESTRUCTIVE_SIZE 64",
1191 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1",
1192 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1",
1193 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1",
1194 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1",
1195 "#define __ATOMIC_HLE_ACQUIRE 65536",
1196 "#define __ATOMIC_HLE_RELEASE 131072",
1197 "#define __FXSR__ 1",
1198 "#define __MMX_WITH_SSE__ 1",
1199 "#define __code_model_small__ 1",
1200 ] {
1201 assert!(has(&linux, line), "{line}");
1202 }
1203 assert!(!linux.contains("__GCC_IEC_559_COMPLEX"));
1206 let arm = set_for("aarch64-unknown-linux-gnu");
1208 for name in ["__ATOMIC_HLE_ACQUIRE", "__FXSR__", "__MMX_WITH_SSE__", "__code_model_small__"]
1209 {
1210 assert!(!arm.contains(name), "{name}");
1211 }
1212 assert!(has(&arm, "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1"));
1213 let windows = set_for("x86_64-pc-windows-msvc");
1215 assert!(has(&windows, "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-16LE\""));
1216 }
1217
1218 #[test]
1219 fn the_memory_orders_are_there_even_without_atomics() {
1220 let linux = set_for("x86_64-unknown-linux-gnu");
1225 assert!(has(&linux, "#define __ATOMIC_RELAXED 0"));
1226 assert!(has(&linux, "#define __ATOMIC_SEQ_CST 5"));
1227 assert!(has(&linux, "#define __STDC_NO_ATOMICS__ 1"), "and we still have no _Atomic");
1228 assert!(has(&linux, "#define __GCC_ATOMIC_INT_LOCK_FREE 2"));
1229 assert!(has(&linux, "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1230 assert!(has(&set_for("x86_64-pc-windows-msvc"), "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1231 }
1232
1233 #[test]
1234 fn long_double_is_three_types_and_the_macros_say_which() {
1235 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 64"));
1236 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 113"));
1237 assert!(has(&set_for("aarch64-apple-darwin"), "#define __LDBL_MANT_DIG__ 53"));
1238 }
1239
1240 #[test]
1241 fn the_extended_floating_types_have_the_limits_their_formats_have() {
1242 let linux = set_for("x86_64-unknown-linux-gnu");
1245 assert!(has(&linux, "#define __FLT16_MANT_DIG__ 11"));
1246 assert!(has(&linux, "#define __FLT32_MANT_DIG__ 24"));
1247 assert!(has(&linux, "#define __FLT64_MANT_DIG__ 53"));
1248 assert!(has(&linux, "#define __FLT128_MANT_DIG__ 113"));
1249 assert!(has(&linux, "#define __FLT32X_MANT_DIG__ 53"));
1250 assert!(has(&linux, "#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16"));
1253 assert!(has(
1254 &linux,
1255 "#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x"
1256 ));
1257 assert!(!linux.contains("__FLT128X_"));
1260 }
1261
1262 #[test]
1263 fn float64x_keeps_the_width_that_long_double_loses_on_apple() {
1264 let linux = set_for("x86_64-unknown-linux-gnu");
1267 assert!(has(&linux, "#define __FLT64X_MANT_DIG__ 64"));
1268 assert!(has(&linux, "#define __LDBL_MANT_DIG__ 64"));
1269 let mac = set_for("aarch64-apple-darwin");
1270 assert!(has(&mac, "#define __FLT64X_MANT_DIG__ 113"));
1271 assert!(has(&mac, "#define __LDBL_MANT_DIG__ 53"));
1272 let windows = set_for("x86_64-pc-windows-msvc");
1273 assert!(has(&windows, "#define __FLT64X_MANT_DIG__ 64"));
1274 assert!(has(&windows, "#define __LDBL_MANT_DIG__ 53"));
1275 }
1276
1277 #[test]
1278 fn the_largest_value_of_a_binary_format_is_also_its_largest_normal_one() {
1279 let linux = set_for("x86_64-unknown-linux-gnu");
1282 for prefix in ["FLT", "DBL", "LDBL", "FLT16", "FLT32", "FLT64", "FLT128", "FLT32X"] {
1283 let value = |suffix: &str| {
1284 let name = format!("#define __{prefix}_{suffix}__ ");
1285 let line = linux
1286 .lines()
1287 .find(|line| line.starts_with(&name))
1288 .unwrap_or_else(|| panic!("__{prefix}_{suffix}__ is defined"));
1289 line[name.len()..].to_owned()
1290 };
1291 assert_eq!(value("MAX"), value("NORM_MAX"), "__{prefix}_NORM_MAX__");
1292 }
1293 }
1294
1295 #[test]
1296 fn the_widest_bit_int_is_said_in_every_dialect() {
1297 let mut opts = Predef::new();
1301 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1302 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1303 opts.std = Std::C17;
1304 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1305 }
1306
1307 #[test]
1308 fn char_signedness_is_recorded_only_when_it_is_unsigned() {
1309 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
1311 assert!(!has(&set_for("x86_64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
1312 }
1313
1314 #[test]
1315 fn the_dialect_decides_the_standard_macros() {
1316 let mut opts = Predef::new();
1317 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1318 assert!(has(&built_in(&target, &opts), "#define __STDC_VERSION__ 202311L"));
1319 assert!(!has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
1320 assert!(has(&built_in(&target, &opts), "#define linux 1"));
1321
1322 opts.gnu_extensions = false;
1323 assert!(has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
1324 assert!(!has(&built_in(&target, &opts), "#define linux 1"), "not a reserved name");
1325
1326 opts.std = Std::C89;
1327 let c89 = built_in(&target, &opts);
1328 assert!(!c89.contains("__STDC_VERSION__"), "C89 does not define it at all");
1329 assert!(has(&c89, "#define __STDC__ 1"));
1330 }
1331
1332 #[test]
1335 fn the_only_things_claimed_missing_are_the_ones_that_are_missing() {
1336 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1337 let opts = Predef::new();
1338 let set = built_in(&target, &opts);
1339 assert!(has(&set, "#define __STDC_NO_ATOMICS__ 1"), "there is no stdatomic.h to include");
1340 assert!(has(&set, "#define __STDC_NO_THREADS__ 1"), "nor a threads.h");
1341 assert!(has(&set, "#define __STDC_NO_COMPLEX__ 1"), "the arithmetic is not lowered");
1342 assert!(!set.contains("__STDC_NO_VLA__"), "variable length arrays work");
1343 }
1344
1345 #[test]
1349 fn the_type_behind_char8_t_is_defined_in_c23_and_in_no_dialect_before_it() {
1350 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1351 let mut opts = Predef::new();
1352 assert!(has(&built_in(&target, &opts), "#define __CHAR8_TYPE__ unsigned char"));
1353
1354 for older in [Std::C17, Std::C11, Std::C99, Std::C89] {
1355 opts.std = older;
1356 assert!(!built_in(&target, &opts).contains("__CHAR8_TYPE__"), "{older:?}");
1357 }
1358 }
1359
1360 #[test]
1361 fn the_optimizer_level_is_visible_to_the_preprocessor() {
1362 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1363 let mut opts = Predef::new();
1364 assert!(has(&built_in(&target, &opts), "#define __NO_INLINE__ 1"));
1365 assert!(!built_in(&target, &opts).contains("__OPTIMIZE__"));
1366
1367 opts.opt_level = OptLevel::O2;
1368 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE__ 1"));
1369 assert!(!built_in(&target, &opts).contains("__OPTIMIZE_SIZE__"));
1370
1371 opts.opt_level = OptLevel::Os;
1372 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE_SIZE__ 1"));
1373 }
1374
1375 #[test]
1376 fn a_command_line_define_with_no_value_is_one() {
1377 let mut opts = Predef::new();
1378 opts.defines = vec!["FOO".to_owned(), "BAR=2".to_owned(), "F(x)=x + 1".to_owned()];
1379 opts.undefines = vec!["__linux__".to_owned()];
1380 let text = command_line(&opts);
1381 assert!(has(&text, "#define FOO 1"));
1382 assert!(has(&text, "#define BAR 2"));
1383 assert!(has(&text, "#define F(x) x + 1"));
1384 assert!(text.trim_end().ends_with("#undef __linux__"));
1386 }
1387
1388 #[test]
1389 fn no_command_line_macros_is_no_file_at_all() {
1390 assert!(command_line(&Predef::new()).is_empty());
1391 }
1392
1393 #[test]
1394 fn a_date_is_spelled_the_way_the_standard_fixes() {
1395 let epoch = Timestamp::from_unix(0);
1397 assert_eq!(epoch.date, "Jan 1 1970");
1398 assert_eq!(epoch.time, "00:00:00");
1399 let leap = Timestamp::from_unix(1_709_164_800);
1400 assert_eq!(leap.date, "Feb 29 2024", "2024 is a leap year");
1401 let late = Timestamp::from_unix(1_735_689_599);
1402 assert_eq!(late.date, "Dec 31 2024");
1403 assert_eq!(late.time, "23:59:59");
1404 }
1405
1406 #[test]
1407 fn a_date_before_the_epoch_still_comes_out_right() {
1408 assert_eq!(Timestamp::from_unix(-1).date, "Dec 31 1969");
1411 assert_eq!(Timestamp::from_unix(-1).time, "23:59:59");
1412 }
1413
1414 #[test]
1415 fn the_gnuc_version_is_a_knob_rather_than_a_constant() {
1416 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1417 let mut opts = Predef::new();
1418 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 7"));
1419 opts.gnuc = GnucVersion { major: 15, minor: 1, patch: 0 };
1420 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 15"));
1421 assert!(has(&built_in(&target, &opts), "#define __GNUC_MINOR__ 1"));
1422 }
1423
1424 #[test]
1431 fn one_of_the_two_inline_macros_is_defined_and_three_things_can_pick_which() {
1432 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1433 let gnu = "#define __GNUC_GNU_INLINE__ 1";
1434 let stdc = "#define __GNUC_STDC_INLINE__ 1";
1435
1436 let mut opts = Predef::new();
1437 assert!(has(&built_in(&target, &opts), stdc));
1438 assert!(!has(&built_in(&target, &opts), gnu));
1439
1440 opts.gnu89_inline = true;
1441 assert!(has(&built_in(&target, &opts), gnu));
1442 assert!(!has(&built_in(&target, &opts), stdc));
1443
1444 let mut opts = Predef::new();
1446 opts.std = Std::C89;
1447 assert!(has(&built_in(&target, &opts), gnu));
1448 assert!(!has(&built_in(&target, &opts), stdc));
1449 }
1450
1451 #[test]
1452 fn musl_and_glibc_disagree_about_the_fast_types_on_the_same_processor() {
1453 let gnu = set_for("x86_64-unknown-linux-gnu");
1458 let musl = set_for("x86_64-unknown-linux-musl");
1459 assert!(has(&gnu, "#define __INT_FAST16_TYPE__ long int"));
1460 assert!(has(&gnu, "#define __INT_FAST32_TYPE__ long int"));
1461 assert!(has(&gnu, "#define __UINT_FAST16_TYPE__ long unsigned int"));
1462 assert!(has(&musl, "#define __INT_FAST16_TYPE__ int"));
1463 assert!(has(&musl, "#define __INT_FAST32_TYPE__ int"));
1464 assert!(has(&musl, "#define __UINT_FAST16_TYPE__ unsigned int"));
1465 assert!(has(&gnu, "#define __INT_FAST16_MAX__ 0x7fffffffffffffffL"));
1468 assert!(has(&musl, "#define __INT_FAST16_MAX__ 0x7fffffff"));
1469 assert!(has(&musl, "#define __UINT_FAST16_MAX__ 0xffffffffU"));
1470 }
1471
1472 #[test]
1473 fn the_libc_only_moves_the_two_fast_types_it_is_allowed_to_move() {
1474 let gnu = set_for("x86_64-unknown-linux-gnu");
1477 let musl = set_for("x86_64-unknown-linux-musl");
1478 for line in [
1479 "#define __INT_FAST8_TYPE__ signed char",
1480 "#define __INT_FAST64_TYPE__ long int",
1481 "#define __INT64_TYPE__ long int",
1482 "#define __SIZE_TYPE__ long unsigned int",
1483 "#define __SIZEOF_LONG__ 8",
1484 "#define __LP64__ 1",
1485 ] {
1486 assert!(has(&gnu, line), "glibc lost {line}");
1487 assert!(has(&musl, line), "musl lost {line}");
1488 }
1489 }
1490
1491 #[test]
1492 fn a_non_x86_target_has_int_sized_fast_types_whatever_the_libc() {
1493 let arm_gnu = set_for("aarch64-unknown-linux-gnu");
1496 let arm_musl = set_for("aarch64-unknown-linux-musl");
1497 assert!(has(&arm_gnu, "#define __INT_FAST16_TYPE__ int"));
1498 assert!(has(&arm_musl, "#define __INT_FAST16_TYPE__ int"));
1499 }
1500}