1use rucc_session::{GnucVersion, OptLevel, Options, Std};
23use rucc_target::{Arch, Env, Os, TargetInfo};
24
25pub const BUILT_IN: &str = "<built-in>";
27
28pub const COMMAND_LINE: &str = "<command-line>";
30
31#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct Timestamp {
38 pub date: String,
40 pub time: String,
42}
43
44impl Timestamp {
45 pub fn now() -> Timestamp {
50 let seconds = match std::env::var("SOURCE_DATE_EPOCH").ok().and_then(|v| v.parse().ok()) {
51 Some(fixed) => fixed,
52 None => std::time::SystemTime::now()
53 .duration_since(std::time::UNIX_EPOCH)
54 .map_or(0, |d| d.as_secs() as i64),
55 };
56 Timestamp::from_unix(seconds)
57 }
58
59 pub fn from_unix(seconds: i64) -> Timestamp {
64 let days = seconds.div_euclid(86_400);
65 let rest = seconds.rem_euclid(86_400);
66 let (year, month, day) = civil_from_days(days);
67 const MONTHS: [&str; 12] =
68 ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
69 let name = MONTHS[(month - 1) as usize];
70 Timestamp {
71 date: format!("{name} {day:2} {year}"),
72 time: format!("{:02}:{:02}:{:02}", rest / 3600, (rest / 60) % 60, rest % 60),
73 }
74 }
75}
76
77fn civil_from_days(days: i64) -> (i64, u32, u32) {
83 let shifted = days + 719_468;
86 let era = shifted.div_euclid(146_097);
87 let day_of_era = shifted.rem_euclid(146_097);
88 let year_of_era =
89 (day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
90 let year = year_of_era + era * 400;
91 let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
92 let marched = (5 * day_of_year + 2) / 153;
93 let day = (day_of_year - (153 * marched + 2) / 5 + 1) as u32;
94 let month = if marched < 10 { marched + 3 } else { marched - 9 } as u32;
95 (year + i64::from(month <= 2), month, day)
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
100pub struct Predef {
101 pub std: Std,
103 pub gnu_extensions: bool,
106 pub gnuc: GnucVersion,
108 pub opt_level: OptLevel,
110 pub hosted: bool,
112 pub timestamp: Timestamp,
114 pub defines: Vec<String>,
116 pub undefines: Vec<String>,
118}
119
120impl Predef {
121 pub fn new() -> Predef {
123 Predef {
124 std: Std::default(),
125 gnu_extensions: true,
126 gnuc: GnucVersion::default(),
127 opt_level: OptLevel::O0,
128 hosted: true,
129 timestamp: Timestamp::now(),
130 defines: Vec::new(),
131 undefines: Vec::new(),
132 }
133 }
134}
135
136impl Predef {
137 pub fn for_options(opts: &Options) -> Predef {
143 Predef {
144 std: opts.std,
145 gnu_extensions: opts.gnu_extensions,
146 gnuc: opts.gnuc,
147 opt_level: opts.opt_level,
148 hosted: opts.hosted,
149 timestamp: Timestamp::now(),
150 defines: opts.defines.clone(),
151 undefines: opts.undefines.clone(),
152 }
153 }
154}
155
156impl Default for Predef {
157 fn default() -> Predef {
158 Predef::new()
159 }
160}
161
162struct Defs {
164 text: String,
165}
166
167impl Defs {
168 fn new() -> Defs {
169 Defs { text: String::new() }
170 }
171
172 fn set(&mut self, name: &str, value: &str) {
174 self.text.push_str("#define ");
175 self.text.push_str(name);
176 self.text.push(' ');
177 self.text.push_str(value);
178 self.text.push('\n');
179 }
180
181 fn flag(&mut self, name: &str) {
183 self.set(name, "1");
184 }
185
186 fn set_if(&mut self, when: bool, name: &str, value: &str) {
187 if when {
188 self.set(name, value);
189 }
190 }
191
192 fn flag_if(&mut self, when: bool, name: &str) {
193 if when {
194 self.flag(name);
195 }
196 }
197}
198
199pub(crate) fn built_in(target: &TargetInfo, opts: &Predef) -> String {
201 let mut d = Defs::new();
202 identity(&mut d, opts);
203 d.set("__DATE__", &format!("\"{}\"", opts.timestamp.date));
207 d.set("__TIME__", &format!("\"{}\"", opts.timestamp.time));
208 dialect(&mut d, opts);
209 optimization(&mut d, opts);
210 platform(&mut d, target, opts);
211 sizes(&mut d, target);
212 integers(&mut d, target);
213 floats(&mut d, target);
214 atomics(&mut d, target);
215 d.text
216}
217
218pub(crate) fn command_line(opts: &Predef) -> String {
224 let mut d = Defs::new();
225 for define in &opts.defines {
226 match define.split_once('=') {
227 Some((name, value)) => d.set(name, value),
228 None => d.flag(define),
231 }
232 }
233 for name in &opts.undefines {
234 d.text.push_str("#undef ");
235 d.text.push_str(name);
236 d.text.push('\n');
237 }
238 d.text
239}
240
241fn identity(d: &mut Defs, opts: &Predef) {
243 d.flag("__rucc__");
244 d.set("__rucc_version__", "\"0.1.0\"");
245 d.set("__rucc_major__", "0");
246 d.set("__rucc_minor__", "1");
247 d.set("__rucc_patchlevel__", "0");
248 d.set("__GNUC__", &opts.gnuc.major.to_string());
250 d.set("__GNUC_MINOR__", &opts.gnuc.minor.to_string());
251 d.set("__GNUC_PATCHLEVEL__", &opts.gnuc.patch.to_string());
252 d.set("__VERSION__", "\"rucc 0.1.0\"");
253 d.flag("__GNUC_STDC_INLINE__");
256}
257
258fn dialect(d: &mut Defs, opts: &Predef) {
260 d.flag("__STDC__");
261 d.set_if(opts.hosted, "__STDC_HOSTED__", "1");
262 d.set_if(!opts.hosted, "__STDC_HOSTED__", "0");
263 if let Some(version) = opts.std.stdc_version() {
264 d.set("__STDC_VERSION__", version);
265 }
266 d.flag_if(!opts.gnu_extensions, "__STRICT_ANSI__");
269 d.flag("__STDC_UTF_16__");
270 d.flag("__STDC_UTF_32__");
271 d.flag("__STDC_IEC_559__");
272 d.flag("__STDC_IEC_559_COMPLEX__");
273 d.set_if(opts.std == Std::C23, "__STDC_IEC_60559_BFP__", "202311L");
274 d.set("__STDC_ISO_10646__", "201706L");
275 if opts.std.has_c11() {
278 d.flag("__STDC_NO_ATOMICS__");
279 d.flag("__STDC_NO_THREADS__");
280 d.flag("__STDC_NO_COMPLEX__");
281 d.flag("__STDC_NO_VLA__");
282 }
283 d.set("__STDC_EMBED_NOT_FOUND__", "0");
288 d.set("__STDC_EMBED_FOUND__", "1");
289 d.set("__STDC_EMBED_EMPTY__", "2");
290}
291
292fn atomics(d: &mut Defs, target: &TargetInfo) {
304 d.set("__ATOMIC_RELAXED", "0");
305 d.set("__ATOMIC_CONSUME", "1");
306 d.set("__ATOMIC_ACQUIRE", "2");
307 d.set("__ATOMIC_RELEASE", "3");
308 d.set("__ATOMIC_ACQ_REL", "4");
309 d.set("__ATOMIC_SEQ_CST", "5");
310 let llong = if target.pointer_width == 64 { "2" } else { "1" };
313 for name in [
314 "BOOL", "CHAR", "CHAR8_T", "CHAR16_T", "CHAR32_T", "WCHAR_T", "SHORT", "INT", "LONG",
315 "POINTER",
316 ] {
317 d.set(&format!("__GCC_ATOMIC_{name}_LOCK_FREE"), "2");
318 }
319 d.set("__GCC_ATOMIC_LLONG_LOCK_FREE", llong);
323 d.set("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
324}
325
326fn optimization(d: &mut Defs, opts: &Predef) {
328 d.flag_if(opts.opt_level.runs_optimizer(), "__OPTIMIZE__");
329 d.flag_if(opts.opt_level.is_size(), "__OPTIMIZE_SIZE__");
330 d.flag_if(!opts.opt_level.runs_optimizer(), "__NO_INLINE__");
333}
334
335fn platform(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
337 let triple = target.triple;
338 match triple.arch {
339 Arch::X86_64 => {
340 d.flag("__x86_64__");
341 d.flag("__x86_64");
342 d.flag("__amd64__");
343 d.flag("__amd64");
344 d.flag("__SSE__");
345 d.flag("__SSE2__");
346 d.flag("__MMX__");
347 d.flag("__SSE_MATH__");
348 d.flag("__SSE2_MATH__");
349 d.flag("__k8");
350 d.flag("__k8__");
351 }
352 Arch::Aarch64 => {
353 d.flag("__aarch64__");
354 d.flag("__AARCH64EL__");
355 d.set("__ARM_ARCH", "8");
356 d.set("__ARM_ARCH_PROFILE", "'A'");
357 d.set("__ARM_64BIT_STATE", "1");
358 d.set("__ARM_ALIGN_MAX_PWR", "28");
359 d.set("__ARM_FP", "0xe");
360 d.set("__ARM_NEON", "1");
361 d.set("__ARM_FEATURE_UNALIGNED", "1");
362 d.set("__ARM_PCS_AAPCS64", "1");
363 }
364 Arch::Riscv64 => {
365 d.flag("__riscv");
366 d.set("__riscv_xlen", "64");
367 d.set("__riscv_flen", "64");
368 d.flag("__riscv_float_abi_double");
369 d.flag("__riscv_muldiv");
370 d.flag("__riscv_atomic");
371 d.flag("__riscv_compressed");
372 d.set("__riscv_cmodel_medlow", "1");
373 }
374 }
375 match triple.os {
376 Os::Linux => {
377 d.flag("__linux__");
378 d.flag("__linux");
379 d.flag("__unix__");
380 d.flag("__unix");
381 d.flag("__gnu_linux__");
382 d.flag("__ELF__");
383 if opts.gnu_extensions {
386 d.flag("linux");
387 d.flag("unix");
388 }
389 }
390 Os::Darwin => {
391 d.flag("__APPLE__");
392 d.flag("__MACH__");
393 d.flag("__unix__");
394 d.flag("__unix");
395 d.set("__APPLE_CC__", "6000");
396 d.set("__DYNAMIC__", "1");
397 if triple.arch == Arch::Aarch64 {
398 d.flag("__arm64__");
403 d.flag("__arm64");
404 }
405 if opts.gnu_extensions {
406 d.flag("unix");
407 }
408 }
409 Os::Windows => {
410 d.flag("_WIN32");
411 d.flag("__WIN32__");
412 d.flag("_WIN64");
413 d.flag("__WIN64__");
414 d.flag("__MINGW32__");
415 }
416 Os::None => {
417 d.flag("__ELF__");
420 }
421 }
422 match triple.env {
423 Env::Musl => d.flag("__musl__"),
424 Env::Gnu | Env::None | Env::Msvc => {}
425 }
426 if target.long_width == 64 && target.pointer_width == 64 {
429 d.flag("__LP64__");
430 d.flag("_LP64");
431 }
432 d.set("__USER_LABEL_PREFIX__", if triple.os == Os::Darwin { "_" } else { "" });
439
440 if !matches!(triple.os, Os::Windows) {
443 d.set("__PIC__", "2");
444 d.set("__pic__", "2");
445 }
446}
447
448fn sizes(d: &mut Defs, target: &TargetInfo) {
450 let pointer = target.pointer_width / 8;
451 let long = target.long_width / 8;
452 let long_double = target.long_double_width / 8;
453 d.set("__CHAR_BIT__", "8");
454 d.set("__SIZEOF_SHORT__", "2");
455 d.set("__SIZEOF_INT__", "4");
456 d.set("__SIZEOF_LONG__", &long.to_string());
457 d.set("__SIZEOF_LONG_LONG__", "8");
458 d.set("__SIZEOF_INT128__", "16");
459 d.set("__SIZEOF_FLOAT__", "4");
460 d.set("__SIZEOF_DOUBLE__", "8");
461 d.set("__SIZEOF_LONG_DOUBLE__", &long_double.to_string());
462 d.set("__SIZEOF_POINTER__", &pointer.to_string());
463 d.set("__SIZEOF_SIZE_T__", &pointer.to_string());
464 d.set("__SIZEOF_PTRDIFF_T__", &pointer.to_string());
465 d.set("__SIZEOF_WCHAR_T__", &wchar(target).size.to_string());
466 d.set("__SIZEOF_WINT_T__", "4");
467 d.set("__BIGGEST_ALIGNMENT__", "16");
468 d.set("__ORDER_LITTLE_ENDIAN__", "1234");
472 d.set("__ORDER_BIG_ENDIAN__", "4321");
473 d.set("__ORDER_PDP_ENDIAN__", "3412");
474 let order =
475 if target.little_endian { "__ORDER_LITTLE_ENDIAN__" } else { "__ORDER_BIG_ENDIAN__" };
476 d.set("__BYTE_ORDER__", order);
477 d.set("__FLOAT_WORD_ORDER__", order);
478 d.flag_if(!target.char_is_signed, "__CHAR_UNSIGNED__");
479}
480
481struct Wchar {
483 spelling: &'static str,
485 size: u32,
487 max: &'static str,
489 min: &'static str,
491}
492
493fn wchar(target: &TargetInfo) -> Wchar {
503 match (target.wchar_width, target.wchar_is_signed) {
504 (16, false) => Wchar { spelling: "short unsigned int", size: 2, max: "0xffff", min: "0" },
505 (16, true) => Wchar { spelling: "short int", size: 2, max: "0x7fff", min: "(-32767 - 1)" },
506 (_, false) => Wchar { spelling: "unsigned int", size: 4, max: "0xffffffffU", min: "0U" },
507 (_, true) => {
508 Wchar { spelling: "int", size: 4, max: "0x7fffffff", min: "(-__WCHAR_MAX__ - 1)" }
509 }
510 }
511}
512
513struct Wint {
515 spelling: &'static str,
517 max: &'static str,
519 min: &'static str,
521}
522
523fn wint(target: &TargetInfo) -> Wint {
530 match target.triple.os {
531 Os::Windows => Wint { spelling: "short unsigned int", max: "0xffff", min: "0" },
532 Os::Darwin => Wint { spelling: "int", max: "2147483647", min: "(-__WINT_MAX__ - 1)" },
533 _ => Wint { spelling: "unsigned int", max: "4294967295U", min: "0U" },
534 }
535}
536
537fn integers(d: &mut Defs, target: &TargetInfo) {
539 let lp64 = target.long_width == 64;
543 let wide = if lp64 { "long int" } else { "long long int" };
544 let wide_unsigned = if lp64 { "long unsigned int" } else { "long long unsigned int" };
545 let wide_suffix = if lp64 { "L" } else { "LL" };
546 let wide_max = format!("9223372036854775807{wide_suffix}");
547 let wide_umax = format!("18446744073709551615U{wide_suffix}");
548
549 d.set("__SCHAR_MAX__", "127");
550 d.set("__SHRT_MAX__", "32767");
551 d.set("__INT_MAX__", "2147483647");
552 d.set("__LONG_MAX__", if lp64 { "9223372036854775807L" } else { "2147483647L" });
553 d.set("__LONG_LONG_MAX__", "9223372036854775807LL");
554 d.set("__INTMAX_MAX__", &wide_max);
555 d.set("__UINTMAX_MAX__", &wide_umax);
556 d.set("__SIZE_MAX__", &wide_umax);
557 d.set("__PTRDIFF_MAX__", &wide_max);
558 d.set("__INTPTR_MAX__", &wide_max);
559 d.set("__UINTPTR_MAX__", &wide_umax);
560 d.set("__SIG_ATOMIC_MAX__", "2147483647");
561 d.set("__SIG_ATOMIC_MIN__", "(-__SIG_ATOMIC_MAX__ - 1)");
562 d.set("__BITINT_MAXWIDTH__", "128");
569
570 let wchar = wchar(target);
571 d.set("__WCHAR_TYPE__", wchar.spelling);
572 d.set("__WCHAR_MAX__", wchar.max);
573 d.set("__WCHAR_MIN__", wchar.min);
574 let wint = wint(target);
575 d.set("__WINT_TYPE__", wint.spelling);
576 d.set("__WINT_MAX__", wint.max);
577 d.set("__WINT_MIN__", wint.min);
578 d.set("__SIZE_TYPE__", wide_unsigned);
579 d.set("__PTRDIFF_TYPE__", wide);
580 d.set("__INTMAX_TYPE__", wide);
581 d.set("__UINTMAX_TYPE__", wide_unsigned);
582 d.set("__INTPTR_TYPE__", wide);
583 d.set("__UINTPTR_TYPE__", wide_unsigned);
584 d.set("__SIG_ATOMIC_TYPE__", "int");
585 d.set("__CHAR16_TYPE__", "short unsigned int");
586 d.set("__CHAR32_TYPE__", "unsigned int");
587 d.set("__INTMAX_C(c)", &format!("c ## {wide_suffix}"));
588 d.set("__UINTMAX_C(c)", &format!("c ## U{wide_suffix}"));
589
590 exact(d, 8, "signed char", "unsigned char", "127", "255", "");
592 exact(d, 16, "short int", "short unsigned int", "32767", "65535", "");
593 exact(d, 32, "int", "unsigned int", "2147483647", "4294967295U", "");
596 exact(d, 64, wide, wide_unsigned, &wide_max, &wide_umax, wide_suffix);
597
598 let fast_is_wide = target.triple.arch == Arch::X86_64 && lp64 && target.triple.env != Env::Musl;
609 let fast_middle = if fast_is_wide { wide } else { "int" };
610 d.set("__INT_FAST8_TYPE__", "signed char");
611 d.set("__UINT_FAST8_TYPE__", "unsigned char");
612 d.set("__INT_FAST8_MAX__", "127");
613 d.set("__UINT_FAST8_MAX__", "255");
614 for width in [16, 32] {
615 let unsigned = if fast_middle == "int" { "unsigned int" } else { wide_unsigned };
616 let max = if fast_middle == "int" { "2147483647" } else { wide_max.as_str() };
617 let umax = if fast_middle == "int" { "4294967295U" } else { wide_umax.as_str() };
618 d.set(&format!("__INT_FAST{width}_TYPE__"), fast_middle);
619 d.set(&format!("__UINT_FAST{width}_TYPE__"), unsigned);
620 d.set(&format!("__INT_FAST{width}_MAX__"), max);
621 d.set(&format!("__UINT_FAST{width}_MAX__"), umax);
622 }
623 d.set("__INT_FAST64_TYPE__", wide);
624 d.set("__UINT_FAST64_TYPE__", wide_unsigned);
625 d.set("__INT_FAST64_MAX__", &wide_max);
626 d.set("__UINT_FAST64_MAX__", &wide_umax);
627}
628
629fn exact(
631 d: &mut Defs,
632 width: u32,
633 signed: &str,
634 unsigned: &str,
635 max: &str,
636 umax: &str,
637 width_suffix: &str,
641) {
642 d.set(&format!("__INT{width}_TYPE__"), signed);
643 d.set(&format!("__UINT{width}_TYPE__"), unsigned);
644 d.set(&format!("__INT{width}_MAX__"), max);
645 d.set(&format!("__UINT{width}_MAX__"), umax);
646 d.set(&format!("__INT_LEAST{width}_TYPE__"), signed);
647 d.set(&format!("__UINT_LEAST{width}_TYPE__"), unsigned);
648 d.set(&format!("__INT_LEAST{width}_MAX__"), max);
649 d.set(&format!("__UINT_LEAST{width}_MAX__"), umax);
650 if width_suffix.is_empty() {
653 d.set(&format!("__INT{width}_C(c)"), "c");
654 d.set(&format!("__UINT{width}_C(c)"), "c ## U");
655 } else {
656 d.set(&format!("__INT{width}_C(c)"), &format!("c ## {width_suffix}"));
657 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## U{width_suffix}"));
658 }
659}
660
661fn floats(d: &mut Defs, target: &TargetInfo) {
663 d.set("__FLT_RADIX__", "2");
664 d.set("__FLT_EVAL_METHOD__", "0");
665 d.set("__FLT_MANT_DIG__", "24");
666 d.set("__FLT_DIG__", "6");
667 d.set("__FLT_MIN_EXP__", "(-125)");
668 d.set("__FLT_MIN_10_EXP__", "(-37)");
669 d.set("__FLT_MAX_EXP__", "128");
670 d.set("__FLT_MAX_10_EXP__", "38");
671 d.set("__FLT_DECIMAL_DIG__", "9");
672 d.set("__FLT_MAX__", "3.40282346638528859811704183484516925e+38F");
673 d.set("__FLT_MIN__", "1.17549435082228750796873653722224568e-38F");
674 d.set("__FLT_EPSILON__", "1.19209289550781250000000000000000000e-7F");
675 d.set("__FLT_DENORM_MIN__", "1.40129846432481707092372958328991613e-45F");
676 d.set("__FLT_HAS_DENORM__", "1");
677 d.set("__FLT_HAS_INFINITY__", "1");
678 d.set("__FLT_HAS_QUIET_NAN__", "1");
679
680 d.set("__DBL_MANT_DIG__", "53");
681 d.set("__DBL_DIG__", "15");
682 d.set("__DBL_MIN_EXP__", "(-1021)");
683 d.set("__DBL_MIN_10_EXP__", "(-307)");
684 d.set("__DBL_MAX_EXP__", "1024");
685 d.set("__DBL_MAX_10_EXP__", "308");
686 d.set("__DBL_DECIMAL_DIG__", "17");
687 d.set("__DBL_MAX__", "((double)1.79769313486231570814527423731704357e+308L)");
688 d.set("__DBL_MIN__", "((double)2.22507385850720138309023271733240406e-308L)");
689 d.set("__DBL_EPSILON__", "((double)2.22044604925031308084726333618164062e-16L)");
690 d.set("__DBL_DENORM_MIN__", "((double)4.94065645841246544176568792868221372e-324L)");
691 d.set("__DBL_HAS_DENORM__", "1");
692 d.set("__DBL_HAS_INFINITY__", "1");
693 d.set("__DBL_HAS_QUIET_NAN__", "1");
694
695 long_double(d, target);
696 d.set("__DECIMAL_DIG__", "__LDBL_DECIMAL_DIG__");
697}
698
699fn long_double(d: &mut Defs, target: &TargetInfo) {
705 if target.long_double_width == 64 {
706 d.set("__LDBL_MANT_DIG__", "53");
707 d.set("__LDBL_DIG__", "15");
708 d.set("__LDBL_MIN_EXP__", "(-1021)");
709 d.set("__LDBL_MIN_10_EXP__", "(-307)");
710 d.set("__LDBL_MAX_EXP__", "1024");
711 d.set("__LDBL_MAX_10_EXP__", "308");
712 d.set("__LDBL_DECIMAL_DIG__", "17");
713 d.set("__LDBL_MAX__", "1.79769313486231570814527423731704357e+308L");
714 d.set("__LDBL_MIN__", "2.22507385850720138309023271733240406e-308L");
715 d.set("__LDBL_EPSILON__", "2.22044604925031308084726333618164062e-16L");
716 d.set("__LDBL_DENORM_MIN__", "4.94065645841246544176568792868221372e-324L");
717 } else if target.triple.arch == Arch::X86_64 {
718 d.set("__LDBL_MANT_DIG__", "64");
719 d.set("__LDBL_DIG__", "18");
720 d.set("__LDBL_MIN_EXP__", "(-16381)");
721 d.set("__LDBL_MIN_10_EXP__", "(-4931)");
722 d.set("__LDBL_MAX_EXP__", "16384");
723 d.set("__LDBL_MAX_10_EXP__", "4932");
724 d.set("__LDBL_DECIMAL_DIG__", "21");
725 d.set("__LDBL_MAX__", "1.18973149535723176502126385303097021e+4932L");
726 d.set("__LDBL_MIN__", "3.36210314311209350626267781732175260e-4932L");
727 d.set("__LDBL_EPSILON__", "1.08420217248550443400745280086994171e-19L");
728 d.set("__LDBL_DENORM_MIN__", "3.64519953188247460252840593361941982e-4951L");
729 } else {
730 d.set("__LDBL_MANT_DIG__", "113");
731 d.set("__LDBL_DIG__", "33");
732 d.set("__LDBL_MIN_EXP__", "(-16381)");
733 d.set("__LDBL_MIN_10_EXP__", "(-4931)");
734 d.set("__LDBL_MAX_EXP__", "16384");
735 d.set("__LDBL_MAX_10_EXP__", "4932");
736 d.set("__LDBL_DECIMAL_DIG__", "36");
737 d.set("__LDBL_MAX__", "1.18973149535723176508575932662800702e+4932L");
738 d.set("__LDBL_MIN__", "3.36210314311209350626267781732175260e-4932L");
739 d.set("__LDBL_EPSILON__", "1.92592994438723585305597794258492732e-34L");
740 d.set("__LDBL_DENORM_MIN__", "6.47517511943802511092443895822764655e-4966L");
741 }
742 d.set("__LDBL_HAS_DENORM__", "1");
743 d.set("__LDBL_HAS_INFINITY__", "1");
744 d.set("__LDBL_HAS_QUIET_NAN__", "1");
745}
746
747#[cfg(test)]
748mod tests {
749 use rucc_target::Triple;
750
751 use super::*;
752
753 fn set_for(triple: &str) -> String {
754 let triple: Triple = triple.parse().expect("a triple the compiler supports");
755 built_in(&TargetInfo::new(triple), &Predef::new())
756 }
757
758 fn has(text: &str, line: &str) -> bool {
759 text.lines().any(|l| l == line)
760 }
761
762 #[test]
763 fn the_set_is_driven_by_the_target_rather_than_by_the_host() {
764 let x86 = set_for("x86_64-unknown-linux-gnu");
765 let arm = set_for("aarch64-unknown-linux-gnu");
766 assert!(has(&x86, "#define __x86_64__ 1"));
767 assert!(!has(&x86, "#define __aarch64__ 1"));
768 assert!(has(&arm, "#define __aarch64__ 1"));
769 assert!(!has(&arm, "#define __x86_64__ 1"));
770 assert!(has(&x86, "#define __linux__ 1") && has(&arm, "#define __linux__ 1"));
771 }
772
773 #[test]
774 fn windows_is_the_target_that_makes_long_thirty_two_bits() {
775 let windows = set_for("x86_64-pc-windows-msvc");
776 let linux = set_for("x86_64-unknown-linux-gnu");
777 assert!(has(&windows, "#define __SIZEOF_LONG__ 4"));
778 assert!(has(&windows, "#define __SIZE_TYPE__ long long unsigned int"));
779 assert!(has(&windows, "#define __INT64_TYPE__ long long int"));
780 assert!(!has(&windows, "#define __LP64__ 1"));
781 assert!(has(&linux, "#define __SIZEOF_LONG__ 8"));
782 assert!(has(&linux, "#define __SIZE_TYPE__ long unsigned int"));
783 assert!(has(&linux, "#define __INT64_TYPE__ long int"));
784 assert!(has(&linux, "#define __LP64__ 1"));
785 }
786
787 #[test]
788 fn wchar_t_is_the_type_that_divides_the_targets() {
789 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ int"));
791 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ unsigned int"));
792 let windows = set_for("x86_64-pc-windows-msvc");
793 assert!(has(&windows, "#define __WCHAR_TYPE__ short unsigned int"));
794 assert!(has(&windows, "#define __SIZEOF_WCHAR_T__ 2"));
795 }
796
797 #[test]
798 fn apple_spells_the_architecture_its_own_way_and_its_headers_only_know_that_spelling() {
799 let darwin = set_for("aarch64-apple-darwin");
802 assert!(has(&darwin, "#define __arm64__ 1"));
803 assert!(has(&darwin, "#define __arm64 1"));
804 assert!(has(&darwin, "#define __aarch64__ 1"), "the portable spelling stays too");
805 let linux = set_for("aarch64-unknown-linux-gnu");
806 assert!(!has(&linux, "#define __arm64__ 1"), "Apple's spelling is Apple's alone");
807 assert!(!has(&set_for("x86_64-apple-darwin"), "#define __arm64__ 1"));
808 }
809
810 #[test]
811 fn wint_t_does_not_follow_wchar_t() {
812 let darwin = set_for("aarch64-apple-darwin");
814 assert!(has(&darwin, "#define __WINT_TYPE__ int"));
815 assert!(has(&darwin, "#define __WINT_MAX__ 2147483647"));
816 assert!(has(&darwin, "#define __WCHAR_TYPE__ int"));
817 let linux = set_for("aarch64-unknown-linux-gnu");
818 assert!(has(&linux, "#define __WINT_TYPE__ unsigned int"));
819 assert!(has(&linux, "#define __WINT_MAX__ 4294967295U"));
820 assert!(has(&linux, "#define __WCHAR_TYPE__ unsigned int"), "and wchar_t is its own");
821 assert!(has(
822 &set_for("x86_64-pc-windows-msvc"),
823 "#define __WINT_TYPE__ short unsigned int"
824 ));
825 }
826
827 #[test]
828 fn a_constant_maker_gets_the_suffix_its_width_needs_and_no_other() {
829 let linux = set_for("x86_64-unknown-linux-gnu");
833 assert!(has(&linux, "#define __INT32_C(c) c"));
834 assert!(has(&linux, "#define __UINT32_C(c) c ## U"));
835 assert!(has(&linux, "#define __INT16_C(c) c"));
836 assert!(has(&linux, "#define __UINT16_C(c) c ## U"));
837 assert!(has(&linux, "#define __INT64_C(c) c ## L"));
839 assert!(has(&linux, "#define __UINT64_C(c) c ## UL"));
840 let windows = set_for("x86_64-pc-windows-msvc");
842 assert!(has(&windows, "#define __INT64_C(c) c ## LL"));
843 assert!(has(&windows, "#define __UINT64_C(c) c ## ULL"));
844 }
845
846 #[test]
847 fn the_symbol_prefix_is_defined_everywhere_including_where_it_is_empty() {
848 for triple in
853 ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
854 {
855 assert!(has(&set_for(triple), "#define __USER_LABEL_PREFIX__ "), "{triple}");
856 }
857 assert!(has(&set_for("aarch64-apple-darwin"), "#define __USER_LABEL_PREFIX__ _"));
859 }
860
861 #[test]
862 fn the_memory_orders_are_there_even_without_atomics() {
863 let linux = set_for("x86_64-unknown-linux-gnu");
868 assert!(has(&linux, "#define __ATOMIC_RELAXED 0"));
869 assert!(has(&linux, "#define __ATOMIC_SEQ_CST 5"));
870 assert!(has(&linux, "#define __STDC_NO_ATOMICS__ 1"), "and we still have no _Atomic");
871 assert!(has(&linux, "#define __GCC_ATOMIC_INT_LOCK_FREE 2"));
872 assert!(has(&linux, "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
873 assert!(has(&set_for("x86_64-pc-windows-msvc"), "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
874 }
875
876 #[test]
877 fn long_double_is_three_types_and_the_macros_say_which() {
878 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 64"));
879 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 113"));
880 assert!(has(&set_for("aarch64-apple-darwin"), "#define __LDBL_MANT_DIG__ 53"));
881 }
882
883 #[test]
884 fn the_widest_bit_int_is_said_in_every_dialect() {
885 let mut opts = Predef::new();
889 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
890 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
891 opts.std = Std::C17;
892 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
893 }
894
895 #[test]
896 fn char_signedness_is_recorded_only_when_it_is_unsigned() {
897 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
899 assert!(!has(&set_for("x86_64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
900 }
901
902 #[test]
903 fn the_dialect_decides_the_standard_macros() {
904 let mut opts = Predef::new();
905 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
906 assert!(has(&built_in(&target, &opts), "#define __STDC_VERSION__ 202311L"));
907 assert!(!has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
908 assert!(has(&built_in(&target, &opts), "#define linux 1"));
909
910 opts.gnu_extensions = false;
911 assert!(has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
912 assert!(!has(&built_in(&target, &opts), "#define linux 1"), "not a reserved name");
913
914 opts.std = Std::C89;
915 let c89 = built_in(&target, &opts);
916 assert!(!c89.contains("__STDC_VERSION__"), "C89 does not define it at all");
917 assert!(has(&c89, "#define __STDC__ 1"));
918 }
919
920 #[test]
921 fn the_optimizer_level_is_visible_to_the_preprocessor() {
922 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
923 let mut opts = Predef::new();
924 assert!(has(&built_in(&target, &opts), "#define __NO_INLINE__ 1"));
925 assert!(!built_in(&target, &opts).contains("__OPTIMIZE__"));
926
927 opts.opt_level = OptLevel::O2;
928 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE__ 1"));
929 assert!(!built_in(&target, &opts).contains("__OPTIMIZE_SIZE__"));
930
931 opts.opt_level = OptLevel::Os;
932 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE_SIZE__ 1"));
933 }
934
935 #[test]
936 fn a_command_line_define_with_no_value_is_one() {
937 let mut opts = Predef::new();
938 opts.defines = vec!["FOO".to_owned(), "BAR=2".to_owned(), "F(x)=x + 1".to_owned()];
939 opts.undefines = vec!["__linux__".to_owned()];
940 let text = command_line(&opts);
941 assert!(has(&text, "#define FOO 1"));
942 assert!(has(&text, "#define BAR 2"));
943 assert!(has(&text, "#define F(x) x + 1"));
944 assert!(text.trim_end().ends_with("#undef __linux__"));
946 }
947
948 #[test]
949 fn no_command_line_macros_is_no_file_at_all() {
950 assert!(command_line(&Predef::new()).is_empty());
951 }
952
953 #[test]
954 fn a_date_is_spelled_the_way_the_standard_fixes() {
955 let epoch = Timestamp::from_unix(0);
957 assert_eq!(epoch.date, "Jan 1 1970");
958 assert_eq!(epoch.time, "00:00:00");
959 let leap = Timestamp::from_unix(1_709_164_800);
960 assert_eq!(leap.date, "Feb 29 2024", "2024 is a leap year");
961 let late = Timestamp::from_unix(1_735_689_599);
962 assert_eq!(late.date, "Dec 31 2024");
963 assert_eq!(late.time, "23:59:59");
964 }
965
966 #[test]
967 fn a_date_before_the_epoch_still_comes_out_right() {
968 assert_eq!(Timestamp::from_unix(-1).date, "Dec 31 1969");
971 assert_eq!(Timestamp::from_unix(-1).time, "23:59:59");
972 }
973
974 #[test]
975 fn the_gnuc_version_is_a_knob_rather_than_a_constant() {
976 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
977 let mut opts = Predef::new();
978 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 4"));
979 opts.gnuc = GnucVersion { major: 15, minor: 1, patch: 0 };
980 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 15"));
981 assert!(has(&built_in(&target, &opts), "#define __GNUC_MINOR__ 1"));
982 }
983
984 #[test]
985 fn musl_and_glibc_disagree_about_the_fast_types_on_the_same_processor() {
986 let gnu = set_for("x86_64-unknown-linux-gnu");
991 let musl = set_for("x86_64-unknown-linux-musl");
992 assert!(has(&gnu, "#define __INT_FAST16_TYPE__ long int"));
993 assert!(has(&gnu, "#define __INT_FAST32_TYPE__ long int"));
994 assert!(has(&gnu, "#define __UINT_FAST16_TYPE__ long unsigned int"));
995 assert!(has(&musl, "#define __INT_FAST16_TYPE__ int"));
996 assert!(has(&musl, "#define __INT_FAST32_TYPE__ int"));
997 assert!(has(&musl, "#define __UINT_FAST16_TYPE__ unsigned int"));
998 assert!(has(&gnu, "#define __INT_FAST16_MAX__ 9223372036854775807L"));
1001 assert!(has(&musl, "#define __INT_FAST16_MAX__ 2147483647"));
1002 assert!(has(&musl, "#define __UINT_FAST16_MAX__ 4294967295U"));
1003 }
1004
1005 #[test]
1006 fn the_libc_only_moves_the_two_fast_types_it_is_allowed_to_move() {
1007 let gnu = set_for("x86_64-unknown-linux-gnu");
1010 let musl = set_for("x86_64-unknown-linux-musl");
1011 for line in [
1012 "#define __INT_FAST8_TYPE__ signed char",
1013 "#define __INT_FAST64_TYPE__ long int",
1014 "#define __INT64_TYPE__ long int",
1015 "#define __SIZE_TYPE__ long unsigned int",
1016 "#define __SIZEOF_LONG__ 8",
1017 "#define __LP64__ 1",
1018 ] {
1019 assert!(has(&gnu, line), "glibc lost {line}");
1020 assert!(has(&musl, line), "musl lost {line}");
1021 }
1022 }
1023
1024 #[test]
1025 fn a_non_x86_target_has_int_sized_fast_types_whatever_the_libc() {
1026 let arm_gnu = set_for("aarch64-unknown-linux-gnu");
1029 let arm_musl = set_for("aarch64-unknown-linux-musl");
1030 assert!(has(&arm_gnu, "#define __INT_FAST16_TYPE__ int"));
1031 assert!(has(&arm_musl, "#define __INT_FAST16_TYPE__ int"));
1032 }
1033}