1use rucc_base::float::Format;
23use rucc_session::{GnucVersion, OptLevel, Options, Pic, Std};
24use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
25use rucc_tuple::{self as tuple};
26
27pub const BUILT_IN: &str = "<built-in>";
29
30pub const COMMAND_LINE: &str = "<command-line>";
32
33#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct Timestamp {
40 pub date: String,
42 pub time: String,
44}
45
46impl Timestamp {
47 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 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
79fn civil_from_days(days: i64) -> (i64, u32, u32) {
85 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#[derive(Debug, Clone, PartialEq, Eq)]
102pub struct Predef {
103 pub std: Std,
105 pub gnu_extensions: bool,
108 pub gnu89_inline: bool,
112 pub gnuc: GnucVersion,
114 pub opt_level: OptLevel,
116 pub hosted: bool,
118 pub pic: Pic,
121 pub timestamp: Timestamp,
123 pub defines: Vec<String>,
125 pub undefines: Vec<String>,
127}
128
129impl Predef {
130 pub fn new() -> Predef {
132 Predef {
133 std: Std::default(),
134 gnu_extensions: true,
135 gnu89_inline: false,
136 gnuc: GnucVersion::default(),
137 opt_level: OptLevel::O0,
138 hosted: true,
139 pic: Pic::Executable,
140 timestamp: Timestamp::now(),
141 defines: Vec::new(),
142 undefines: Vec::new(),
143 }
144 }
145}
146
147impl Predef {
148 pub fn for_options(opts: &Options) -> Predef {
154 Predef {
155 std: opts.std,
156 gnu_extensions: opts.gnu_extensions,
157 gnu89_inline: opts.gnu89_inline,
158 gnuc: opts.gnuc,
159 opt_level: opts.opt_level,
160 hosted: opts.hosted,
161 pic: opts.pic,
162 timestamp: Timestamp::now(),
163 defines: opts.defines.clone(),
164 undefines: opts.undefines.clone(),
165 }
166 }
167}
168
169impl Default for Predef {
170 fn default() -> Predef {
171 Predef::new()
172 }
173}
174
175struct Defs {
177 text: String,
178}
179
180impl Defs {
181 fn new() -> Defs {
182 Defs { text: String::new() }
183 }
184
185 fn set(&mut self, name: &str, value: &str) {
187 self.text.push_str("#define ");
188 self.text.push_str(name);
189 self.text.push(' ');
190 self.text.push_str(value);
191 self.text.push('\n');
192 }
193
194 fn flag(&mut self, name: &str) {
196 self.set(name, "1");
197 }
198
199 fn set_if(&mut self, when: bool, name: &str, value: &str) {
200 if when {
201 self.set(name, value);
202 }
203 }
204
205 fn flag_if(&mut self, when: bool, name: &str) {
206 if when {
207 self.flag(name);
208 }
209 }
210}
211
212pub(crate) fn built_in(target: &TargetInfo, opts: &Predef) -> String {
214 let mut d = Defs::new();
215 identity(&mut d, target, opts);
216 d.set("__DATE__", &format!("\"{}\"", opts.timestamp.date));
220 d.set("__TIME__", &format!("\"{}\"", opts.timestamp.time));
221 dialect(&mut d, opts);
222 optimization(&mut d, opts);
223 platform(&mut d, target, opts);
224 sizes(&mut d, target);
225 integers(&mut d, target);
226 floats(&mut d, target);
227 atomics(&mut d, target);
228 d.text
229}
230
231pub(crate) fn command_line(opts: &Predef) -> String {
237 let mut d = Defs::new();
238 for define in &opts.defines {
239 match define.split_once('=') {
240 Some((name, value)) => d.set(name, value),
241 None => d.flag(define),
244 }
245 }
246 for name in &opts.undefines {
247 d.text.push_str("#undef ");
248 d.text.push_str(name);
249 d.text.push('\n');
250 }
251 d.text
252}
253
254fn identity(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
256 d.flag("__rucc__");
257 d.set("__rucc_version__", "\"0.1.0\"");
258 d.set("__rucc_major__", "0");
259 d.set("__rucc_minor__", "1");
260 d.set("__rucc_patchlevel__", "0");
261 d.set("__GNUC__", &opts.gnuc.major.to_string());
263 d.set("__GNUC_MINOR__", &opts.gnuc.minor.to_string());
264 d.set("__GNUC_PATCHLEVEL__", &opts.gnuc.patch.to_string());
265 d.set("__VERSION__", "\"rucc 0.1.0\"");
266 let gnu_inline = opts.gnu89_inline || opts.std == Std::C89;
275 d.flag_if(gnu_inline, "__GNUC_GNU_INLINE__");
276 d.flag_if(!gnu_inline, "__GNUC_STDC_INLINE__");
277 d.set("__GNUC_EXECUTION_CHARSET_NAME", "\"UTF-8\"");
282 let wide = if target.wchar_width == 16 { "\"UTF-16LE\"" } else { "\"UTF-32LE\"" };
283 d.set("__GNUC_WIDE_EXECUTION_CHARSET_NAME", wide);
284 d.set("__GXX_ABI_VERSION", "1021");
289}
290
291fn dialect(d: &mut Defs, opts: &Predef) {
293 d.flag("__STDC__");
294 d.set_if(opts.hosted, "__STDC_HOSTED__", "1");
295 d.set_if(!opts.hosted, "__STDC_HOSTED__", "0");
296 if let Some(version) = opts.std.stdc_version() {
297 d.set("__STDC_VERSION__", version);
298 }
299 d.flag_if(!opts.gnu_extensions, "__STRICT_ANSI__");
302 d.flag("__STDC_UTF_16__");
303 d.flag("__STDC_UTF_32__");
304 d.flag("__STDC_IEC_559__");
305 d.flag("__STDC_IEC_559_COMPLEX__");
306 d.set_if(opts.std == Std::C23, "__STDC_IEC_60559_BFP__", "202311L");
307 d.set("__STDC_ISO_10646__", "201706L");
308 d.set_if(opts.std == Std::C23, "__CHAR8_TYPE__", "unsigned char");
314 if opts.std.has_c11() {
326 d.flag("__STDC_NO_ATOMICS__");
327 d.flag("__STDC_NO_THREADS__");
328 d.flag("__STDC_NO_COMPLEX__");
329 }
330 d.set("__STDC_EMBED_NOT_FOUND__", "0");
335 d.set("__STDC_EMBED_FOUND__", "1");
336 d.set("__STDC_EMBED_EMPTY__", "2");
337}
338
339fn atomics(d: &mut Defs, target: &TargetInfo) {
351 d.set("__ATOMIC_RELAXED", "0");
352 d.set("__ATOMIC_CONSUME", "1");
353 d.set("__ATOMIC_ACQUIRE", "2");
354 d.set("__ATOMIC_RELEASE", "3");
355 d.set("__ATOMIC_ACQ_REL", "4");
356 d.set("__ATOMIC_SEQ_CST", "5");
357 let llong = if target.pointer_width == 64 { "2" } else { "1" };
360 for name in [
361 "BOOL", "CHAR", "CHAR8_T", "CHAR16_T", "CHAR32_T", "WCHAR_T", "SHORT", "INT", "LONG",
362 "POINTER",
363 ] {
364 d.set(&format!("__GCC_ATOMIC_{name}_LOCK_FREE"), "2");
365 }
366 d.set("__GCC_ATOMIC_LLONG_LOCK_FREE", llong);
370 d.set("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
371 for width in [1, 2, 4, 8] {
375 d.flag(&format!("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_{width}"));
376 }
377 if target.tuple.arch() == tuple::Arch::X86_64 {
382 d.set("__ATOMIC_HLE_ACQUIRE", "65536");
383 d.set("__ATOMIC_HLE_RELEASE", "131072");
384 }
385}
386
387fn optimization(d: &mut Defs, opts: &Predef) {
389 d.flag_if(opts.opt_level.runs_optimizer(), "__OPTIMIZE__");
390 d.flag_if(opts.opt_level.is_size(), "__OPTIMIZE_SIZE__");
391 d.flag_if(!opts.opt_level.runs_optimizer(), "__NO_INLINE__");
394 d.set("__FINITE_MATH_ONLY__", "0");
400}
401
402fn platform(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
404 let Some(triple) = Triple::from_tuple(target.tuple) else {
410 return;
411 };
412 match triple.arch {
413 Arch::X86_64 => {
414 d.flag("__x86_64__");
415 d.flag("__x86_64");
416 d.flag("__amd64__");
417 d.flag("__amd64");
418 d.flag("__SSE__");
419 d.flag("__SSE2__");
420 d.flag("__MMX__");
421 d.flag("__SSE_MATH__");
422 d.flag("__SSE2_MATH__");
423 d.flag("__k8");
424 d.flag("__k8__");
425 d.flag("__FXSR__");
428 d.flag("__code_model_small__");
429 d.flag("__MMX_WITH_SSE__");
434 }
435 Arch::Aarch64 => {
436 d.flag("__aarch64__");
437 d.flag("__AARCH64EL__");
438 d.set("__ARM_ARCH", "8");
439 d.set("__ARM_ARCH_PROFILE", "'A'");
440 d.set("__ARM_64BIT_STATE", "1");
441 d.set("__ARM_ALIGN_MAX_PWR", "28");
442 d.set("__ARM_FP", "0xe");
443 d.set("__ARM_NEON", "1");
444 d.set("__ARM_FEATURE_UNALIGNED", "1");
445 d.set("__ARM_PCS_AAPCS64", "1");
446 }
447 Arch::Riscv64 => {
448 d.flag("__riscv");
449 d.set("__riscv_xlen", "64");
450 d.set("__riscv_flen", "64");
451 d.flag("__riscv_float_abi_double");
452 d.flag("__riscv_muldiv");
453 d.flag("__riscv_atomic");
454 d.flag("__riscv_compressed");
455 d.set("__riscv_cmodel_medlow", "1");
456 }
457 }
458 match triple.os {
459 Os::Linux => {
460 d.flag("__linux__");
461 d.flag("__linux");
462 d.flag("__unix__");
463 d.flag("__unix");
464 d.flag("__gnu_linux__");
465 d.flag("__ELF__");
466 if opts.gnu_extensions {
469 d.flag("linux");
470 d.flag("unix");
471 }
472 }
473 Os::Darwin => {
474 d.flag("__APPLE__");
475 d.flag("__MACH__");
476 d.flag("__unix__");
477 d.flag("__unix");
478 d.set("__APPLE_CC__", "6000");
479 d.set("__DYNAMIC__", "1");
480 if triple.arch == Arch::Aarch64 {
481 d.flag("__arm64__");
486 d.flag("__arm64");
487 }
488 if opts.gnu_extensions {
489 d.flag("unix");
490 }
491 }
492 Os::Windows => {
493 d.flag("_WIN32");
494 d.flag("__WIN32__");
495 d.flag("_WIN64");
496 d.flag("__WIN64__");
497 d.flag("__MINGW32__");
498 }
499 Os::None => {
500 d.flag("__ELF__");
503 }
504 }
505 match triple.env {
506 Env::Musl => d.flag("__musl__"),
507 Env::Gnu | Env::None | Env::Msvc => {}
508 }
509 if target.long_width == 64 && target.pointer_width == 64 {
512 d.flag("__LP64__");
513 d.flag("_LP64");
514 }
515 d.set("__USER_LABEL_PREFIX__", if triple.os == Os::Darwin { "_" } else { "" });
522 d.set("__REGISTER_PREFIX__", "");
526
527 if !matches!(triple.os, Os::Windows) {
536 d.set("__PIC__", "2");
537 d.set("__pic__", "2");
538 if opts.pic == Pic::Executable {
539 d.set("__PIE__", "2");
540 d.set("__pie__", "2");
541 }
542 }
543}
544
545fn sizes(d: &mut Defs, target: &TargetInfo) {
547 let pointer = target.pointer_width / 8;
548 d.set("__GCC_CONSTRUCTIVE_SIZE", "64");
553 d.set("__GCC_DESTRUCTIVE_SIZE", "64");
554 let long = target.long_width / 8;
555 let long_double = target.long_double_width / 8;
556 d.set("__CHAR_BIT__", "8");
557 d.set("__SIZEOF_SHORT__", "2");
558 d.set("__SIZEOF_INT__", "4");
559 d.set("__SIZEOF_LONG__", &long.to_string());
560 d.set("__SIZEOF_LONG_LONG__", "8");
561 d.set("__SIZEOF_INT128__", "16");
562 d.set("__SIZEOF_FLOAT__", "4");
563 d.set("__SIZEOF_DOUBLE__", "8");
564 d.set("__SIZEOF_LONG_DOUBLE__", &long_double.to_string());
565 d.set("__SIZEOF_POINTER__", &pointer.to_string());
566 d.set("__SIZEOF_SIZE_T__", &pointer.to_string());
567 d.set("__SIZEOF_PTRDIFF_T__", &pointer.to_string());
568 d.set("__SIZEOF_WCHAR_T__", &wchar(target).size.to_string());
569 d.set("__SIZEOF_WINT_T__", "4");
570 d.set("__BIGGEST_ALIGNMENT__", "16");
571 d.set("__ORDER_LITTLE_ENDIAN__", "1234");
575 d.set("__ORDER_BIG_ENDIAN__", "4321");
576 d.set("__ORDER_PDP_ENDIAN__", "3412");
577 let order =
578 if target.little_endian { "__ORDER_LITTLE_ENDIAN__" } else { "__ORDER_BIG_ENDIAN__" };
579 d.set("__BYTE_ORDER__", order);
580 d.set("__FLOAT_WORD_ORDER__", order);
581 d.flag_if(!target.char_is_signed, "__CHAR_UNSIGNED__");
582}
583
584struct Wchar {
586 spelling: &'static str,
588 size: u32,
590 max: &'static str,
592 min: &'static str,
594}
595
596fn wchar(target: &TargetInfo) -> Wchar {
606 match (target.wchar_width, target.wchar_is_signed) {
607 (16, false) => Wchar { spelling: "short unsigned int", size: 2, max: "0xffff", min: "0" },
608 (16, true) => Wchar { spelling: "short int", size: 2, max: "0x7fff", min: "(-32767 - 1)" },
609 (_, false) => Wchar { spelling: "unsigned int", size: 4, max: "0xffffffffU", min: "0U" },
610 (_, true) => {
611 Wchar { spelling: "int", size: 4, max: "0x7fffffff", min: "(-__WCHAR_MAX__ - 1)" }
612 }
613 }
614}
615
616struct Wint {
618 spelling: &'static str,
620 max: &'static str,
622 min: &'static str,
624 width: u32,
626}
627
628fn wint(target: &TargetInfo) -> Wint {
635 match target.tuple.os() {
636 tuple::Os::Windows => {
637 Wint { spelling: "short unsigned int", max: "0xffff", min: "0", width: 16 }
638 }
639 os if os.is_darwin() => {
640 Wint { spelling: "int", max: "0x7fffffff", min: "(-__WINT_MAX__ - 1)", width: 32 }
641 }
642 _ => Wint { spelling: "unsigned int", max: "0xffffffffU", min: "0U", width: 32 },
643 }
644}
645
646fn integers(d: &mut Defs, target: &TargetInfo) {
648 let lp64 = target.long_width == 64;
652 let wide = if lp64 { "long int" } else { "long long int" };
653 let wide_unsigned = if lp64 { "long unsigned int" } else { "long long unsigned int" };
654 let wide_suffix = if lp64 { "L" } else { "LL" };
655 let wide_max = format!("0x7fffffffffffffff{wide_suffix}");
656 let wide_umax = format!("0xffffffffffffffffU{wide_suffix}");
657
658 d.set("__SCHAR_MAX__", "0x7f");
659 d.set("__SHRT_MAX__", "0x7fff");
660 d.set("__INT_MAX__", "0x7fffffff");
661 d.set("__LONG_MAX__", if lp64 { "0x7fffffffffffffffL" } else { "0x7fffffffL" });
662 d.set("__LONG_LONG_MAX__", "0x7fffffffffffffffLL");
663 d.set("__INTMAX_MAX__", &wide_max);
664 d.set("__UINTMAX_MAX__", &wide_umax);
665 d.set("__SIZE_MAX__", &wide_umax);
666 d.set("__PTRDIFF_MAX__", &wide_max);
667 d.set("__INTPTR_MAX__", &wide_max);
668 d.set("__UINTPTR_MAX__", &wide_umax);
669 d.set("__SIG_ATOMIC_MAX__", "0x7fffffff");
670 d.set("__SIG_ATOMIC_MIN__", "(-__SIG_ATOMIC_MAX__ - 1)");
671 d.set("__BITINT_MAXWIDTH__", "128");
678
679 let wchar = wchar(target);
680 d.set("__WCHAR_TYPE__", wchar.spelling);
681 d.set("__WCHAR_MAX__", wchar.max);
682 d.set("__WCHAR_MIN__", wchar.min);
683 let wint = wint(target);
684 d.set("__WINT_TYPE__", wint.spelling);
685 d.set("__WINT_MAX__", wint.max);
686 d.set("__WINT_MIN__", wint.min);
687 d.set("__SIZE_TYPE__", wide_unsigned);
688 d.set("__PTRDIFF_TYPE__", wide);
689 d.set("__INTMAX_TYPE__", wide);
690 d.set("__UINTMAX_TYPE__", wide_unsigned);
691 d.set("__INTPTR_TYPE__", wide);
692 d.set("__UINTPTR_TYPE__", wide_unsigned);
693 d.set("__SIG_ATOMIC_TYPE__", "int");
694 d.set("__CHAR16_TYPE__", "short unsigned int");
695 d.set("__CHAR32_TYPE__", "unsigned int");
696 d.set("__INTMAX_C(c)", &format!("c ## {wide_suffix}"));
697 d.set("__UINTMAX_C(c)", &format!("c ## U{wide_suffix}"));
698
699 exact(d, 8, "signed char", "unsigned char", "0x7f", "0xff", "");
701 exact(d, 16, "short int", "short unsigned int", "0x7fff", "0xffff", "");
702 exact(d, 32, "int", "unsigned int", "0x7fffffff", "0xffffffffU", "");
705 exact(d, 64, wide, wide_unsigned, &wide_max, &wide_umax, wide_suffix);
706
707 let fast_is_wide = target.tuple.arch() == tuple::Arch::X86_64
718 && lp64
719 && target.tuple.env() != tuple::Env::Musl;
720 let fast_middle = if fast_is_wide { wide } else { "int" };
721 d.set("__INT_FAST8_TYPE__", "signed char");
722 d.set("__UINT_FAST8_TYPE__", "unsigned char");
723 d.set("__INT_FAST8_MAX__", "0x7f");
724 d.set("__UINT_FAST8_MAX__", "0xff");
725 for width in [16, 32] {
726 let unsigned = if fast_middle == "int" { "unsigned int" } else { wide_unsigned };
727 let max = if fast_middle == "int" { "0x7fffffff" } else { wide_max.as_str() };
728 let umax = if fast_middle == "int" { "0xffffffffU" } else { wide_umax.as_str() };
729 d.set(&format!("__INT_FAST{width}_TYPE__"), fast_middle);
730 d.set(&format!("__UINT_FAST{width}_TYPE__"), unsigned);
731 d.set(&format!("__INT_FAST{width}_MAX__"), max);
732 d.set(&format!("__UINT_FAST{width}_MAX__"), umax);
733 }
734 d.set("__INT_FAST64_TYPE__", wide);
735 d.set("__UINT_FAST64_TYPE__", wide_unsigned);
736 d.set("__INT_FAST64_MAX__", &wide_max);
737 d.set("__UINT_FAST64_MAX__", &wide_umax);
738
739 widths(d, target, &wchar, &wint, if fast_is_wide { 64 } else { 32 });
740}
741
742fn widths(d: &mut Defs, target: &TargetInfo, wchar: &Wchar, wint: &Wint, fast_middle: u32) {
753 let pointer = target.pointer_width;
754 d.set("__SCHAR_WIDTH__", "8");
755 d.set("__SHRT_WIDTH__", "16");
756 d.set("__INT_WIDTH__", "32");
757 d.set("__LONG_WIDTH__", &target.long_width.to_string());
758 d.set("__LONG_LONG_WIDTH__", "64");
759 d.set("__INTMAX_WIDTH__", "64");
760 d.set("__INTPTR_WIDTH__", &pointer.to_string());
761 d.set("__PTRDIFF_WIDTH__", &pointer.to_string());
762 d.set("__SIZE_WIDTH__", &pointer.to_string());
763 d.set("__SIG_ATOMIC_WIDTH__", "32");
764 d.set("__WCHAR_WIDTH__", &(wchar.size * 8).to_string());
765 d.set("__WINT_WIDTH__", &wint.width.to_string());
766 for width in [8, 16, 32, 64] {
767 d.set(&format!("__INT_LEAST{width}_WIDTH__"), &width.to_string());
768 }
769 d.set("__INT_FAST8_WIDTH__", "8");
770 d.set("__INT_FAST16_WIDTH__", &fast_middle.to_string());
771 d.set("__INT_FAST32_WIDTH__", &fast_middle.to_string());
772 d.set("__INT_FAST64_WIDTH__", "64");
773}
774
775fn exact(
777 d: &mut Defs,
778 width: u32,
779 signed: &str,
780 unsigned: &str,
781 max: &str,
782 umax: &str,
783 width_suffix: &str,
787) {
788 d.set(&format!("__INT{width}_TYPE__"), signed);
789 d.set(&format!("__UINT{width}_TYPE__"), unsigned);
790 d.set(&format!("__INT{width}_MAX__"), max);
791 d.set(&format!("__UINT{width}_MAX__"), umax);
792 d.set(&format!("__INT_LEAST{width}_TYPE__"), signed);
793 d.set(&format!("__UINT_LEAST{width}_TYPE__"), unsigned);
794 d.set(&format!("__INT_LEAST{width}_MAX__"), max);
795 d.set(&format!("__UINT_LEAST{width}_MAX__"), umax);
796 let unsigned_after_promotion = width >= 32;
806 let u = if unsigned_after_promotion { "U" } else { "" };
807 if width_suffix.is_empty() && u.is_empty() {
808 d.set(&format!("__INT{width}_C(c)"), "c");
809 d.set(&format!("__UINT{width}_C(c)"), "c");
810 } else if width_suffix.is_empty() {
811 d.set(&format!("__INT{width}_C(c)"), "c");
812 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}"));
813 } else {
814 d.set(&format!("__INT{width}_C(c)"), &format!("c ## {width_suffix}"));
815 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}{width_suffix}"));
816 }
817}
818
819struct Characteristics {
825 mant_dig: &'static str,
826 dig: &'static str,
827 min_exp: &'static str,
828 min_10_exp: &'static str,
829 max_exp: &'static str,
830 max_10_exp: &'static str,
831 decimal_dig: &'static str,
832 max: &'static str,
833 norm_max: &'static str,
842 min: &'static str,
843 epsilon: &'static str,
844 denorm_min: &'static str,
845 is_iec_60559: &'static str,
849}
850
851const HALF: Characteristics = Characteristics {
853 mant_dig: "11",
854 dig: "3",
855 min_exp: "(-13)",
856 min_10_exp: "(-4)",
857 max_exp: "16",
858 max_10_exp: "4",
859 decimal_dig: "5",
860 max: "6.55040000000000000000000000000000000e+4",
861 norm_max: "6.55040000000000000000000000000000000e+4",
862 min: "6.10351562500000000000000000000000000e-5",
863 epsilon: "9.76562500000000000000000000000000000e-4",
864 denorm_min: "5.96046447753906250000000000000000000e-8",
865 is_iec_60559: "1",
866};
867
868const BFLOAT16: Characteristics = Characteristics {
870 mant_dig: "8",
871 dig: "2",
872 min_exp: "(-125)",
873 min_10_exp: "(-37)",
874 max_exp: "128",
875 max_10_exp: "38",
876 decimal_dig: "4",
877 max: "3.38953138925153547590470800371487867e+38",
878 norm_max: "3.38953138925153547590470800371487867e+38",
879 min: "1.17549435082228750796873653722224568e-38",
880 epsilon: "7.81250000000000000000000000000000000e-3",
881 denorm_min: "9.18354961579912115600575419704879436e-41",
882 is_iec_60559: "0",
883};
884
885const SINGLE: Characteristics = Characteristics {
887 mant_dig: "24",
888 dig: "6",
889 min_exp: "(-125)",
890 min_10_exp: "(-37)",
891 max_exp: "128",
892 max_10_exp: "38",
893 decimal_dig: "9",
894 max: "3.40282346638528859811704183484516925e+38",
895 norm_max: "3.40282346638528859811704183484516925e+38",
896 min: "1.17549435082228750796873653722224568e-38",
897 epsilon: "1.19209289550781250000000000000000000e-7",
898 denorm_min: "1.40129846432481707092372958328991613e-45",
899 is_iec_60559: "1",
900};
901
902const DOUBLE: Characteristics = Characteristics {
905 mant_dig: "53",
906 dig: "15",
907 min_exp: "(-1021)",
908 min_10_exp: "(-307)",
909 max_exp: "1024",
910 max_10_exp: "308",
911 decimal_dig: "17",
912 max: "1.79769313486231570814527423731704357e+308",
913 norm_max: "1.79769313486231570814527423731704357e+308",
914 min: "2.22507385850720138309023271733240406e-308",
915 epsilon: "2.22044604925031308084726333618164062e-16",
916 denorm_min: "4.94065645841246544176568792868221372e-324",
917 is_iec_60559: "1",
918};
919
920const X87: Characteristics = Characteristics {
922 mant_dig: "64",
923 dig: "18",
924 min_exp: "(-16381)",
925 min_10_exp: "(-4931)",
926 max_exp: "16384",
927 max_10_exp: "4932",
928 decimal_dig: "21",
929 max: "1.18973149535723176502126385303097021e+4932",
930 norm_max: "1.18973149535723176502126385303097021e+4932",
931 min: "3.36210314311209350626267781732175260e-4932",
932 epsilon: "1.08420217248550443400745280086994171e-19",
933 denorm_min: "3.64519953188247460252840593361941982e-4951",
934 is_iec_60559: "1",
935};
936
937const QUAD: Characteristics = Characteristics {
940 mant_dig: "113",
941 dig: "33",
942 min_exp: "(-16381)",
943 min_10_exp: "(-4931)",
944 max_exp: "16384",
945 max_10_exp: "4932",
946 decimal_dig: "36",
947 max: "1.18973149535723176508575932662800702e+4932",
948 norm_max: "1.18973149535723176508575932662800702e+4932",
949 min: "3.36210314311209350626267781732175260e-4932",
950 epsilon: "1.92592994438723585305597794258492732e-34",
951 denorm_min: "6.47517511943802511092443895822764655e-4966",
952 is_iec_60559: "1",
953};
954
955const DOUBLE_DOUBLE: Characteristics = Characteristics {
971 mant_dig: "106",
972 dig: "31",
973 min_exp: "(-968)",
974 min_10_exp: "(-291)",
975 max_exp: "1024",
976 max_10_exp: "308",
977 decimal_dig: "33",
978 max: "1.79769313486231580793728971405301e+308",
979 norm_max: "8.98846567431157953864652595394501e+307",
980 min: "2.00416836000897277799610805135016e-292",
981 epsilon: "4.94065645841246544176568792868221e-324",
982 denorm_min: "4.94065645841246544176568792868221e-324",
983 is_iec_60559: "0",
984};
985
986const fn characteristics(format: Format) -> &'static Characteristics {
989 match format {
990 Format::Half => &HALF,
991 Format::BFloat16 => &BFLOAT16,
992 Format::Single => &SINGLE,
993 Format::Double => &DOUBLE,
994 Format::X87Extended => &X87,
995 Format::Quad => &QUAD,
996 Format::DoubleDouble => &DOUBLE_DOUBLE,
997 }
998}
999
1000fn floats(d: &mut Defs, target: &TargetInfo) {
1011 d.set("__FLT_RADIX__", "2");
1012 d.set("__GCC_IEC_559", "2");
1017 d.set("__FLT_EVAL_METHOD__", "0");
1022 d.set("__FLT_EVAL_METHOD_C99__", "0");
1023 d.set("__FLT_EVAL_METHOD_TS_18661_3__", "0");
1024
1025 family(d, "FLT", &SINGLE, |value| format!("{value}F"));
1026 family(d, "DBL", &DOUBLE, |value| format!("((double){value}L)"));
1029 family(d, "LDBL", characteristics(target.long_double_format), |value| format!("{value}L"));
1030
1031 family(d, "FLT16", &HALF, |value| format!("{value}F16"));
1032 family(d, "FLT32", &SINGLE, |value| format!("{value}F32"));
1033 family(d, "FLT64", &DOUBLE, |value| format!("{value}F64"));
1034 family(d, "FLT128", &QUAD, |value| format!("{value}F128"));
1035 family(d, "FLT32X", &DOUBLE, |value| format!("{value}F32x"));
1036 if let Some(format) = target.float64x_format {
1040 family(d, "FLT64X", characteristics(format), |value| format!("{value}F64x"));
1041 }
1042
1043 d.set("__DECIMAL_DIG__", characteristics(target.long_double_format).decimal_dig);
1048}
1049
1050fn family(d: &mut Defs, prefix: &str, c: &Characteristics, write: impl Fn(&str) -> String) {
1055 d.set(&format!("__{prefix}_MANT_DIG__"), c.mant_dig);
1056 d.set(&format!("__{prefix}_DIG__"), c.dig);
1057 d.set(&format!("__{prefix}_MIN_EXP__"), c.min_exp);
1058 d.set(&format!("__{prefix}_MIN_10_EXP__"), c.min_10_exp);
1059 d.set(&format!("__{prefix}_MAX_EXP__"), c.max_exp);
1060 d.set(&format!("__{prefix}_MAX_10_EXP__"), c.max_10_exp);
1061 d.set(&format!("__{prefix}_DECIMAL_DIG__"), c.decimal_dig);
1062 d.set(&format!("__{prefix}_MAX__"), &write(c.max));
1063 d.set(&format!("__{prefix}_NORM_MAX__"), &write(c.norm_max));
1064 d.set(&format!("__{prefix}_MIN__"), &write(c.min));
1065 d.set(&format!("__{prefix}_EPSILON__"), &write(c.epsilon));
1066 d.set(&format!("__{prefix}_DENORM_MIN__"), &write(c.denorm_min));
1067 d.set(&format!("__{prefix}_IS_IEC_60559__"), c.is_iec_60559);
1068 d.set(&format!("__{prefix}_HAS_DENORM__"), "1");
1069 d.set(&format!("__{prefix}_HAS_INFINITY__"), "1");
1070 d.set(&format!("__{prefix}_HAS_QUIET_NAN__"), "1");
1071}
1072
1073#[cfg(test)]
1074mod tests {
1075 use rucc_target::Triple;
1076
1077 use super::*;
1078
1079 fn set_for(triple: &str) -> String {
1080 let triple: Triple = triple.parse().expect("a triple the compiler supports");
1081 built_in(&TargetInfo::new(triple), &Predef::new())
1082 }
1083
1084 fn has(text: &str, line: &str) -> bool {
1085 text.lines().any(|l| l == line)
1086 }
1087
1088 #[test]
1089 fn the_set_is_driven_by_the_target_rather_than_by_the_host() {
1090 let x86 = set_for("x86_64-unknown-linux-gnu");
1091 let arm = set_for("aarch64-unknown-linux-gnu");
1092 assert!(has(&x86, "#define __x86_64__ 1"));
1093 assert!(!has(&x86, "#define __aarch64__ 1"));
1094 assert!(has(&arm, "#define __aarch64__ 1"));
1095 assert!(!has(&arm, "#define __x86_64__ 1"));
1096 assert!(has(&x86, "#define __linux__ 1") && has(&arm, "#define __linux__ 1"));
1097 }
1098
1099 #[test]
1100 fn windows_is_the_target_that_makes_long_thirty_two_bits() {
1101 let windows = set_for("x86_64-pc-windows-msvc");
1102 let linux = set_for("x86_64-unknown-linux-gnu");
1103 assert!(has(&windows, "#define __SIZEOF_LONG__ 4"));
1104 assert!(has(&windows, "#define __SIZE_TYPE__ long long unsigned int"));
1105 assert!(has(&windows, "#define __INT64_TYPE__ long long int"));
1106 assert!(!has(&windows, "#define __LP64__ 1"));
1107 assert!(has(&linux, "#define __SIZEOF_LONG__ 8"));
1108 assert!(has(&linux, "#define __SIZE_TYPE__ long unsigned int"));
1109 assert!(has(&linux, "#define __INT64_TYPE__ long int"));
1110 assert!(has(&linux, "#define __LP64__ 1"));
1111 }
1112
1113 #[test]
1114 fn wchar_t_is_the_type_that_divides_the_targets() {
1115 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ int"));
1117 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ unsigned int"));
1118 let windows = set_for("x86_64-pc-windows-msvc");
1119 assert!(has(&windows, "#define __WCHAR_TYPE__ short unsigned int"));
1120 assert!(has(&windows, "#define __SIZEOF_WCHAR_T__ 2"));
1121 }
1122
1123 #[test]
1124 fn apple_spells_the_architecture_its_own_way_and_its_headers_only_know_that_spelling() {
1125 let darwin = set_for("aarch64-apple-darwin");
1128 assert!(has(&darwin, "#define __arm64__ 1"));
1129 assert!(has(&darwin, "#define __arm64 1"));
1130 assert!(has(&darwin, "#define __aarch64__ 1"), "the portable spelling stays too");
1131 let linux = set_for("aarch64-unknown-linux-gnu");
1132 assert!(!has(&linux, "#define __arm64__ 1"), "Apple's spelling is Apple's alone");
1133 assert!(!has(&set_for("x86_64-apple-darwin"), "#define __arm64__ 1"));
1134 }
1135
1136 #[test]
1137 fn every_limit_is_spelled_in_hexadecimal_the_way_gcc_spells_it() {
1138 let linux = set_for("x86_64-unknown-linux-gnu");
1145 for line in [
1146 "#define __SCHAR_MAX__ 0x7f",
1147 "#define __SHRT_MAX__ 0x7fff",
1148 "#define __INT_MAX__ 0x7fffffff",
1149 "#define __LONG_MAX__ 0x7fffffffffffffffL",
1150 "#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL",
1151 "#define __INTMAX_MAX__ 0x7fffffffffffffffL",
1152 "#define __UINTMAX_MAX__ 0xffffffffffffffffUL",
1153 "#define __SIZE_MAX__ 0xffffffffffffffffUL",
1154 "#define __PTRDIFF_MAX__ 0x7fffffffffffffffL",
1155 "#define __SIG_ATOMIC_MAX__ 0x7fffffff",
1156 "#define __INT8_MAX__ 0x7f",
1157 "#define __UINT8_MAX__ 0xff",
1158 "#define __INT16_MAX__ 0x7fff",
1159 "#define __UINT16_MAX__ 0xffff",
1160 "#define __INT32_MAX__ 0x7fffffff",
1161 "#define __UINT32_MAX__ 0xffffffffU",
1162 "#define __INT64_MAX__ 0x7fffffffffffffffL",
1163 "#define __UINT64_MAX__ 0xffffffffffffffffUL",
1164 "#define __INT_FAST8_MAX__ 0x7f",
1165 "#define __UINT_FAST8_MAX__ 0xff",
1166 ] {
1167 assert!(has(&linux, line), "{line}");
1168 }
1169 let windows = set_for("x86_64-pc-windows-msvc");
1172 assert!(has(&windows, "#define __LONG_MAX__ 0x7fffffffL"));
1173 assert!(has(&windows, "#define __INTMAX_MAX__ 0x7fffffffffffffffLL"));
1174 assert!(has(&windows, "#define __UINTMAX_MAX__ 0xffffffffffffffffULL"));
1175 }
1176
1177 #[test]
1178 fn wint_t_does_not_follow_wchar_t() {
1179 let darwin = set_for("aarch64-apple-darwin");
1181 assert!(has(&darwin, "#define __WINT_TYPE__ int"));
1182 assert!(has(&darwin, "#define __WINT_MAX__ 0x7fffffff"));
1183 assert!(has(&darwin, "#define __WCHAR_TYPE__ int"));
1184 let linux = set_for("aarch64-unknown-linux-gnu");
1185 assert!(has(&linux, "#define __WINT_TYPE__ unsigned int"));
1186 assert!(has(&linux, "#define __WINT_MAX__ 0xffffffffU"));
1187 assert!(has(&linux, "#define __WCHAR_TYPE__ unsigned int"), "and wchar_t is its own");
1188 assert!(has(
1189 &set_for("x86_64-pc-windows-msvc"),
1190 "#define __WINT_TYPE__ short unsigned int"
1191 ));
1192 }
1193
1194 #[test]
1195 fn the_widths_say_what_the_type_holds_and_follow_the_target_that_changes_it() {
1196 let linux = set_for("x86_64-unknown-linux-gnu");
1200 assert_eq!(linux.lines().filter(|line| line.contains("_WIDTH__")).count(), 20);
1201 assert!(has(&linux, "#define __LONG_WIDTH__ 64"));
1202 assert!(has(&linux, "#define __SIZE_WIDTH__ 64"));
1203 assert!(has(&linux, "#define __WCHAR_WIDTH__ 32"));
1204 assert!(has(&linux, "#define __INT_LEAST16_WIDTH__ 16"));
1205 assert!(has(&linux, "#define __INT_FAST16_WIDTH__ 64"));
1208 assert!(has(&set_for("x86_64-unknown-linux-musl"), "#define __INT_FAST16_WIDTH__ 32"));
1209 let windows = set_for("x86_64-pc-windows-msvc");
1212 assert!(has(&windows, "#define __LONG_WIDTH__ 32"));
1213 assert!(has(&windows, "#define __WINT_WIDTH__ 16"));
1214 assert!(has(&windows, "#define __SIZE_WIDTH__ 64"));
1215 assert!(has(&windows, "#define __INTMAX_WIDTH__ 64"));
1216 }
1217
1218 #[test]
1219 fn a_constant_maker_gets_the_suffix_its_width_needs_and_no_other() {
1220 let linux = set_for("x86_64-unknown-linux-gnu");
1224 assert!(has(&linux, "#define __INT32_C(c) c"));
1225 assert!(has(&linux, "#define __UINT32_C(c) c ## U"));
1226 assert!(has(&linux, "#define __INT16_C(c) c"));
1227 assert!(has(&linux, "#define __UINT16_C(c) c"));
1230 assert!(has(&linux, "#define __UINT8_C(c) c"));
1231 assert!(has(&linux, "#define __INT64_C(c) c ## L"));
1233 assert!(has(&linux, "#define __UINT64_C(c) c ## UL"));
1234 let windows = set_for("x86_64-pc-windows-msvc");
1236 assert!(has(&windows, "#define __INT64_C(c) c ## LL"));
1237 assert!(has(&windows, "#define __UINT64_C(c) c ## ULL"));
1238 }
1239
1240 #[test]
1241 fn the_symbol_prefix_is_defined_everywhere_including_where_it_is_empty() {
1242 for triple in
1247 ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
1248 {
1249 assert!(has(&set_for(triple), "#define __USER_LABEL_PREFIX__ "), "{triple}");
1250 }
1251 assert!(has(&set_for("aarch64-apple-darwin"), "#define __USER_LABEL_PREFIX__ _"));
1253 }
1254
1255 #[test]
1259 fn the_toolchain_macros_gcc_defines_are_defined_with_gccs_values() {
1260 let linux = set_for("x86_64-unknown-linux-gnu");
1261 for line in [
1262 "#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"",
1263 "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"",
1264 "#define __GXX_ABI_VERSION 1021",
1265 "#define __REGISTER_PREFIX__ ",
1266 "#define __FINITE_MATH_ONLY__ 0",
1267 "#define __GCC_IEC_559 2",
1268 "#define __GCC_CONSTRUCTIVE_SIZE 64",
1269 "#define __GCC_DESTRUCTIVE_SIZE 64",
1270 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1",
1271 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1",
1272 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1",
1273 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1",
1274 "#define __ATOMIC_HLE_ACQUIRE 65536",
1275 "#define __ATOMIC_HLE_RELEASE 131072",
1276 "#define __FXSR__ 1",
1277 "#define __MMX_WITH_SSE__ 1",
1278 "#define __code_model_small__ 1",
1279 ] {
1280 assert!(has(&linux, line), "{line}");
1281 }
1282 assert!(!linux.contains("__GCC_IEC_559_COMPLEX"));
1285 let arm = set_for("aarch64-unknown-linux-gnu");
1287 for name in ["__ATOMIC_HLE_ACQUIRE", "__FXSR__", "__MMX_WITH_SSE__", "__code_model_small__"]
1288 {
1289 assert!(!arm.contains(name), "{name}");
1290 }
1291 assert!(has(&arm, "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1"));
1292 let windows = set_for("x86_64-pc-windows-msvc");
1294 assert!(has(&windows, "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-16LE\""));
1295 }
1296
1297 #[test]
1298 fn the_memory_orders_are_there_even_without_atomics() {
1299 let linux = set_for("x86_64-unknown-linux-gnu");
1304 assert!(has(&linux, "#define __ATOMIC_RELAXED 0"));
1305 assert!(has(&linux, "#define __ATOMIC_SEQ_CST 5"));
1306 assert!(has(&linux, "#define __STDC_NO_ATOMICS__ 1"), "and we still have no _Atomic");
1307 assert!(has(&linux, "#define __GCC_ATOMIC_INT_LOCK_FREE 2"));
1308 assert!(has(&linux, "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1309 assert!(has(&set_for("x86_64-pc-windows-msvc"), "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1310 }
1311
1312 #[test]
1313 fn long_double_is_three_types_and_the_macros_say_which() {
1314 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 64"));
1315 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 113"));
1316 assert!(has(&set_for("aarch64-apple-darwin"), "#define __LDBL_MANT_DIG__ 53"));
1317 }
1318
1319 #[test]
1320 fn the_extended_floating_types_have_the_limits_their_formats_have() {
1321 let linux = set_for("x86_64-unknown-linux-gnu");
1324 assert!(has(&linux, "#define __FLT16_MANT_DIG__ 11"));
1325 assert!(has(&linux, "#define __FLT32_MANT_DIG__ 24"));
1326 assert!(has(&linux, "#define __FLT64_MANT_DIG__ 53"));
1327 assert!(has(&linux, "#define __FLT128_MANT_DIG__ 113"));
1328 assert!(has(&linux, "#define __FLT32X_MANT_DIG__ 53"));
1329 assert!(has(&linux, "#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16"));
1332 assert!(has(
1333 &linux,
1334 "#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x"
1335 ));
1336 assert!(!linux.contains("__FLT128X_"));
1339 }
1340
1341 #[test]
1342 fn float64x_keeps_the_width_that_long_double_loses_on_apple() {
1343 let linux = set_for("x86_64-unknown-linux-gnu");
1346 assert!(has(&linux, "#define __FLT64X_MANT_DIG__ 64"));
1347 assert!(has(&linux, "#define __LDBL_MANT_DIG__ 64"));
1348 let mac = set_for("aarch64-apple-darwin");
1349 assert!(has(&mac, "#define __FLT64X_MANT_DIG__ 113"));
1350 assert!(has(&mac, "#define __LDBL_MANT_DIG__ 53"));
1351 let windows = set_for("x86_64-pc-windows-msvc");
1352 assert!(has(&windows, "#define __FLT64X_MANT_DIG__ 64"));
1353 assert!(has(&windows, "#define __LDBL_MANT_DIG__ 53"));
1354 }
1355
1356 #[test]
1357 fn the_largest_value_of_an_ieee_format_is_also_its_largest_normal_one() {
1358 let linux = set_for("x86_64-unknown-linux-gnu");
1362 for prefix in ["FLT", "DBL", "LDBL", "FLT16", "FLT32", "FLT64", "FLT128", "FLT32X"] {
1363 let value = |suffix: &str| {
1364 let name = format!("#define __{prefix}_{suffix}__ ");
1365 let line = linux
1366 .lines()
1367 .find(|line| line.starts_with(&name))
1368 .unwrap_or_else(|| panic!("__{prefix}_{suffix}__ is defined"));
1369 line[name.len()..].to_owned()
1370 };
1371 assert_eq!(value("MAX"), value("NORM_MAX"), "__{prefix}_NORM_MAX__");
1372 }
1373 }
1374
1375 #[test]
1376 fn the_double_double_is_the_row_where_the_largest_value_is_not_the_largest_normal_one() {
1377 let c = characteristics(Format::DoubleDouble);
1382 assert_ne!(c.max, c.norm_max);
1383 assert!(c.norm_max.starts_with("8.98846567431157953864652595394501e+307"));
1387 assert!(c.max.starts_with("1.7976931348623158"));
1388 assert_eq!(c.epsilon, c.denorm_min);
1392 for format in [Format::Half, Format::Single, Format::Double, Format::X87Extended] {
1393 assert_ne!(characteristics(format).epsilon, characteristics(format).denorm_min);
1394 }
1395 assert_eq!(c.is_iec_60559, "0");
1397 }
1398
1399 #[test]
1400 fn the_widest_bit_int_is_said_in_every_dialect() {
1401 let mut opts = Predef::new();
1405 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1406 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1407 opts.std = Std::C17;
1408 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1409 }
1410
1411 #[test]
1412 fn char_signedness_is_recorded_only_when_it_is_unsigned() {
1413 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
1415 assert!(!has(&set_for("x86_64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
1416 }
1417
1418 #[test]
1419 fn the_dialect_decides_the_standard_macros() {
1420 let mut opts = Predef::new();
1421 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1422 assert!(has(&built_in(&target, &opts), "#define __STDC_VERSION__ 202311L"));
1423 assert!(!has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
1424 assert!(has(&built_in(&target, &opts), "#define linux 1"));
1425
1426 opts.gnu_extensions = false;
1427 assert!(has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
1428 assert!(!has(&built_in(&target, &opts), "#define linux 1"), "not a reserved name");
1429
1430 opts.std = Std::C89;
1431 let c89 = built_in(&target, &opts);
1432 assert!(!c89.contains("__STDC_VERSION__"), "C89 does not define it at all");
1433 assert!(has(&c89, "#define __STDC__ 1"));
1434 }
1435
1436 #[test]
1439 fn the_only_things_claimed_missing_are_the_ones_that_are_missing() {
1440 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1441 let opts = Predef::new();
1442 let set = built_in(&target, &opts);
1443 assert!(has(&set, "#define __STDC_NO_ATOMICS__ 1"), "there is no stdatomic.h to include");
1444 assert!(has(&set, "#define __STDC_NO_THREADS__ 1"), "nor a threads.h");
1445 assert!(has(&set, "#define __STDC_NO_COMPLEX__ 1"), "the arithmetic is not lowered");
1446 assert!(!set.contains("__STDC_NO_VLA__"), "variable length arrays work");
1447 }
1448
1449 #[test]
1453 fn the_type_behind_char8_t_is_defined_in_c23_and_in_no_dialect_before_it() {
1454 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1455 let mut opts = Predef::new();
1456 assert!(has(&built_in(&target, &opts), "#define __CHAR8_TYPE__ unsigned char"));
1457
1458 for older in [Std::C17, Std::C11, Std::C99, Std::C89] {
1459 opts.std = older;
1460 assert!(!built_in(&target, &opts).contains("__CHAR8_TYPE__"), "{older:?}");
1461 }
1462 }
1463
1464 #[test]
1465 fn the_optimizer_level_is_visible_to_the_preprocessor() {
1466 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1467 let mut opts = Predef::new();
1468 assert!(has(&built_in(&target, &opts), "#define __NO_INLINE__ 1"));
1469 assert!(!built_in(&target, &opts).contains("__OPTIMIZE__"));
1470
1471 opts.opt_level = OptLevel::O2;
1472 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE__ 1"));
1473 assert!(!built_in(&target, &opts).contains("__OPTIMIZE_SIZE__"));
1474
1475 opts.opt_level = OptLevel::Os;
1476 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE_SIZE__ 1"));
1477 }
1478
1479 #[test]
1480 fn a_command_line_define_with_no_value_is_one() {
1481 let mut opts = Predef::new();
1482 opts.defines = vec!["FOO".to_owned(), "BAR=2".to_owned(), "F(x)=x + 1".to_owned()];
1483 opts.undefines = vec!["__linux__".to_owned()];
1484 let text = command_line(&opts);
1485 assert!(has(&text, "#define FOO 1"));
1486 assert!(has(&text, "#define BAR 2"));
1487 assert!(has(&text, "#define F(x) x + 1"));
1488 assert!(text.trim_end().ends_with("#undef __linux__"));
1490 }
1491
1492 #[test]
1493 fn no_command_line_macros_is_no_file_at_all() {
1494 assert!(command_line(&Predef::new()).is_empty());
1495 }
1496
1497 #[test]
1498 fn a_date_is_spelled_the_way_the_standard_fixes() {
1499 let epoch = Timestamp::from_unix(0);
1501 assert_eq!(epoch.date, "Jan 1 1970");
1502 assert_eq!(epoch.time, "00:00:00");
1503 let leap = Timestamp::from_unix(1_709_164_800);
1504 assert_eq!(leap.date, "Feb 29 2024", "2024 is a leap year");
1505 let late = Timestamp::from_unix(1_735_689_599);
1506 assert_eq!(late.date, "Dec 31 2024");
1507 assert_eq!(late.time, "23:59:59");
1508 }
1509
1510 #[test]
1511 fn a_date_before_the_epoch_still_comes_out_right() {
1512 assert_eq!(Timestamp::from_unix(-1).date, "Dec 31 1969");
1515 assert_eq!(Timestamp::from_unix(-1).time, "23:59:59");
1516 }
1517
1518 #[test]
1519 fn the_gnuc_version_is_a_knob_rather_than_a_constant() {
1520 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1521 let mut opts = Predef::new();
1522 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 7"));
1523 opts.gnuc = GnucVersion { major: 15, minor: 1, patch: 0 };
1524 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 15"));
1525 assert!(has(&built_in(&target, &opts), "#define __GNUC_MINOR__ 1"));
1526 }
1527
1528 #[test]
1535 fn one_of_the_two_inline_macros_is_defined_and_three_things_can_pick_which() {
1536 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1537 let gnu = "#define __GNUC_GNU_INLINE__ 1";
1538 let stdc = "#define __GNUC_STDC_INLINE__ 1";
1539
1540 let mut opts = Predef::new();
1541 assert!(has(&built_in(&target, &opts), stdc));
1542 assert!(!has(&built_in(&target, &opts), gnu));
1543
1544 opts.gnu89_inline = true;
1545 assert!(has(&built_in(&target, &opts), gnu));
1546 assert!(!has(&built_in(&target, &opts), stdc));
1547
1548 let mut opts = Predef::new();
1550 opts.std = Std::C89;
1551 assert!(has(&built_in(&target, &opts), gnu));
1552 assert!(!has(&built_in(&target, &opts), stdc));
1553 }
1554
1555 #[test]
1556 fn musl_and_glibc_disagree_about_the_fast_types_on_the_same_processor() {
1557 let gnu = set_for("x86_64-unknown-linux-gnu");
1562 let musl = set_for("x86_64-unknown-linux-musl");
1563 assert!(has(&gnu, "#define __INT_FAST16_TYPE__ long int"));
1564 assert!(has(&gnu, "#define __INT_FAST32_TYPE__ long int"));
1565 assert!(has(&gnu, "#define __UINT_FAST16_TYPE__ long unsigned int"));
1566 assert!(has(&musl, "#define __INT_FAST16_TYPE__ int"));
1567 assert!(has(&musl, "#define __INT_FAST32_TYPE__ int"));
1568 assert!(has(&musl, "#define __UINT_FAST16_TYPE__ unsigned int"));
1569 assert!(has(&gnu, "#define __INT_FAST16_MAX__ 0x7fffffffffffffffL"));
1572 assert!(has(&musl, "#define __INT_FAST16_MAX__ 0x7fffffff"));
1573 assert!(has(&musl, "#define __UINT_FAST16_MAX__ 0xffffffffU"));
1574 }
1575
1576 #[test]
1577 fn the_libc_only_moves_the_two_fast_types_it_is_allowed_to_move() {
1578 let gnu = set_for("x86_64-unknown-linux-gnu");
1581 let musl = set_for("x86_64-unknown-linux-musl");
1582 for line in [
1583 "#define __INT_FAST8_TYPE__ signed char",
1584 "#define __INT_FAST64_TYPE__ long int",
1585 "#define __INT64_TYPE__ long int",
1586 "#define __SIZE_TYPE__ long unsigned int",
1587 "#define __SIZEOF_LONG__ 8",
1588 "#define __LP64__ 1",
1589 ] {
1590 assert!(has(&gnu, line), "glibc lost {line}");
1591 assert!(has(&musl, line), "musl lost {line}");
1592 }
1593 }
1594
1595 #[test]
1596 fn a_non_x86_target_has_int_sized_fast_types_whatever_the_libc() {
1597 let arm_gnu = set_for("aarch64-unknown-linux-gnu");
1600 let arm_musl = set_for("aarch64-unknown-linux-musl");
1601 assert!(has(&arm_gnu, "#define __INT_FAST16_TYPE__ int"));
1602 assert!(has(&arm_musl, "#define __INT_FAST16_TYPE__ int"));
1603 }
1604}