1use rucc_base::float::{Float, Format, ParseError, Status};
85use rucc_session::Std;
86use rucc_target::TargetInfo;
87use rucc_tuple::Arch;
88use rucc_types::{IntKind, int_width};
89
90use crate::remarks::Remarks;
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub struct IntConstant {
95 pub value: u128,
99 pub ty: IntConstantType,
102 pub imaginary: bool,
105 pub remarks: Remarks,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum IntConstantType {
112 Standard(IntKind),
114 BitInt {
116 signed: bool,
118 width: u32,
120 },
121}
122
123impl IntConstantType {
124 #[must_use]
130 pub const fn suffix(self) -> &'static str {
131 match self {
132 IntConstantType::Standard(kind) => match kind {
133 IntKind::UInt | IntKind::UInt128 => "u",
134 IntKind::Long => "l",
135 IntKind::ULong => "ul",
136 IntKind::LongLong => "ll",
137 IntKind::ULongLong => "ull",
138 _ => "",
139 },
140 IntConstantType::BitInt { signed: true, .. } => "wb",
141 IntConstantType::BitInt { signed: false, .. } => "uwb",
142 }
143 }
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
151pub enum IntError {
152 Floating,
154 InvalidSuffix,
156 InvalidOctalDigit,
158 NoDigits,
160 TooLarge,
163}
164
165impl IntError {
166 #[must_use]
171 pub const fn message(self) -> &'static str {
172 match self {
173 IntError::Floating => "not an integer constant",
174 IntError::InvalidSuffix => "invalid suffix on integer constant",
175 IntError::InvalidOctalDigit => "invalid digit in octal constant",
176 IntError::NoDigits => "no digits in integer constant",
177 IntError::TooLarge => "integer constant is too large to be represented in any type",
178 }
179 }
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub struct FloatConstant {
185 pub value: Float,
187 pub ty: FloatConstantType,
189 pub imaginary: bool,
192 pub remarks: Remarks,
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202pub enum FloatConstantType {
203 Float,
205 Double,
207 LongDouble,
209 Float16,
211 Float32,
213 Float64,
215 Float128,
218 Float32x,
221 Float64x,
224 Float80,
228}
229
230impl FloatConstantType {
231 #[must_use]
237 pub fn format(self, target: &TargetInfo) -> Format {
238 match self {
239 FloatConstantType::Float | FloatConstantType::Float32 => Format::Single,
240 FloatConstantType::Double
241 | FloatConstantType::Float64
242 | FloatConstantType::Float32x => Format::Double,
243 FloatConstantType::LongDouble => target.long_double_format,
244 FloatConstantType::Float16 => Format::Half,
245 FloatConstantType::Float128 => Format::Quad,
246 FloatConstantType::Float64x if target.tuple.arch() == Arch::X86_64 => {
247 Format::X87Extended
248 }
249 FloatConstantType::Float64x => Format::Quad,
250 FloatConstantType::Float80 => Format::X87Extended,
251 }
252 }
253
254 #[must_use]
259 pub const fn name(self) -> &'static str {
260 match self {
261 FloatConstantType::Float => "float",
262 FloatConstantType::Double => "double",
263 FloatConstantType::LongDouble => "long double",
264 FloatConstantType::Float16 => "_Float16",
265 FloatConstantType::Float32 => "_Float32",
266 FloatConstantType::Float64 => "_Float64",
267 FloatConstantType::Float128 => "_Float128",
268 FloatConstantType::Float32x => "_Float32x",
269 FloatConstantType::Float64x => "_Float64x",
270 FloatConstantType::Float80 => "__float80",
271 }
272 }
273
274 #[must_use]
280 pub const fn suffix(self) -> &'static str {
281 match self {
282 FloatConstantType::Float => "f",
283 FloatConstantType::Double => "",
284 FloatConstantType::LongDouble => "l",
285 FloatConstantType::Float16 => "f16",
286 FloatConstantType::Float32 => "f32",
287 FloatConstantType::Float64 => "f64",
288 FloatConstantType::Float128 => "f128",
289 FloatConstantType::Float32x => "f32x",
290 FloatConstantType::Float64x => "f64x",
291 FloatConstantType::Float80 => "w",
292 }
293 }
294}
295
296#[derive(Debug, Clone, Copy, PartialEq, Eq)]
301pub enum FloatError {
302 Integer,
304 InvalidSuffix,
306 MissingExponent,
310 NoExponentDigits,
312 NoDigits,
314 TooManyPoints,
316 DecimalFloat,
319 UnsupportedType,
322}
323
324impl FloatError {
325 #[must_use]
327 pub const fn message(self) -> &'static str {
328 match self {
329 FloatError::Integer => "not a floating constant",
330 FloatError::InvalidSuffix => "invalid suffix on floating constant",
331 FloatError::MissingExponent => "hexadecimal floating constants require an exponent",
332 FloatError::NoExponentDigits => "exponent has no digits",
333 FloatError::NoDigits => "no digits in floating constant",
334 FloatError::TooManyPoints => "too many decimal points in number",
335 FloatError::DecimalFloat => "decimal floating constants are not supported yet",
336 FloatError::UnsupportedType => "unsupported non-standard suffix on floating constant",
340 }
341 }
342}
343
344pub fn integer(text: &str, std: Std, target: &TargetInfo) -> Result<IntConstant, IntError> {
351 let bytes = text.as_bytes();
352 let (base, start) = base_of(bytes);
353 if is_floating(bytes, base) {
354 return Err(IntError::Floating);
355 }
356 let mut remarks = Remarks::NONE;
357 if base == 2 && std < Std::C23 {
358 remarks = remarks.with(Remarks::BINARY);
359 }
360
361 let mut value: u128 = 0;
362 let mut digits = 0;
363 let mut index = start;
364 while index < bytes.len() {
365 let byte = bytes[index];
366 if byte == b'\'' {
367 if digits == 0 || index + 1 >= bytes.len() || digit(bytes[index + 1], base).is_none() {
371 return Err(IntError::InvalidSuffix);
372 }
373 if std < Std::C23 {
374 remarks = remarks.with(Remarks::SEPARATORS);
375 }
376 index += 1;
377 continue;
378 }
379 let Some(digit) = digit(byte, base) else {
380 break;
381 };
382 value = value
383 .checked_mul(u128::from(base))
384 .and_then(|shifted| shifted.checked_add(u128::from(digit)))
385 .ok_or(IntError::TooLarge)?;
386 digits += 1;
387 index += 1;
388 }
389 if digits == 0 {
390 return Err(IntError::NoDigits);
393 }
394 if base == 8 && bytes[start..index].iter().any(|&byte| byte == b'8' || byte == b'9') {
395 return Err(IntError::InvalidOctalDigit);
396 }
397
398 let suffix = suffix_of(&bytes[index..])?;
399 if suffix.length == Some(Length::LongLong) && std == Std::C89 {
400 remarks = remarks.with(Remarks::LONG_LONG);
401 }
402 if suffix.imaginary {
403 remarks = remarks.with(Remarks::IMAGINARY);
404 }
405 if suffix.length == Some(Length::BitInt) {
406 if std < Std::C23 {
407 remarks = remarks.with(Remarks::BIT_INT);
408 }
409 let ty = bit_int(value, suffix.unsigned);
410 return Ok(IntConstant { value, ty, imaginary: false, remarks });
411 }
412
413 let candidates = candidates(base, suffix, std);
414 let kind = candidates
415 .iter()
416 .copied()
417 .find(|&kind| fits(value, kind, target))
418 .ok_or(IntError::TooLarge)?;
419 if base == 10 && !suffix.unsigned && !signed_standard(kind) {
420 remarks = remarks.with(Remarks::UNSIGNED);
421 }
422 Ok(IntConstant {
423 value,
424 ty: IntConstantType::Standard(kind),
425 imaginary: suffix.imaginary,
426 remarks,
427 })
428}
429
430fn base_of(bytes: &[u8]) -> (u32, usize) {
436 match bytes {
437 [b'0', b'x' | b'X', ..] => (16, 2),
438 [b'0', b'b' | b'B', ..] => (2, 2),
439 [b'0', next, ..] if next.is_ascii_digit() => (8, 1),
440 _ => (10, 0),
441 }
442}
443
444fn is_floating(bytes: &[u8], base: u32) -> bool {
454 let exponent = if base == 16 { *b"pP" } else { *b"eE" };
455 bytes.iter().any(|&byte| byte == b'.' || exponent.contains(&byte))
456}
457
458fn digit(byte: u8, base: u32) -> Option<u32> {
463 char::from(byte).to_digit(if base == 8 { 10 } else { base })
464}
465
466#[derive(Debug, Clone, Copy, PartialEq, Eq)]
468enum Length {
469 Long,
471 LongLong,
473 BitInt,
475}
476
477#[derive(Debug, Clone, Copy, PartialEq, Eq)]
479struct Suffix {
480 unsigned: bool,
482 length: Option<Length>,
484 imaginary: bool,
486}
487
488fn suffix_of(mut rest: &[u8]) -> Result<Suffix, IntError> {
490 let mut suffix = Suffix { unsigned: false, length: None, imaginary: false };
491 while let Some(&byte) = rest.first() {
492 let taken = match byte {
493 b'u' | b'U' if !suffix.unsigned => {
494 suffix.unsigned = true;
495 1
496 }
497 b'i' | b'j' | b'I' | b'J' if !suffix.imaginary => {
500 suffix.imaginary = true;
501 1
502 }
503 b'l' | b'L' if suffix.length.is_none() => {
506 if rest.get(1) == Some(&byte) {
507 suffix.length = Some(Length::LongLong);
508 2
509 } else {
510 suffix.length = Some(Length::Long);
511 1
512 }
513 }
514 b'w' | b'W' if suffix.length.is_none() => {
515 let second = if byte == b'w' { b'b' } else { b'B' };
516 if rest.get(1) != Some(&second) {
517 return Err(IntError::InvalidSuffix);
518 }
519 suffix.length = Some(Length::BitInt);
520 2
521 }
522 _ => return Err(IntError::InvalidSuffix),
523 };
524 rest = &rest[taken..];
525 }
526 if suffix.imaginary && suffix.length == Some(Length::BitInt) {
530 return Err(IntError::InvalidSuffix);
531 }
532 Ok(suffix)
533}
534
535fn bit_int(value: u128, unsigned: bool) -> IntConstantType {
541 let used = 128 - value.leading_zeros();
542 let width = if unsigned { used.max(1) } else { used + 1 };
543 IntConstantType::BitInt { signed: !unsigned, width: width.max(if unsigned { 1 } else { 2 }) }
544}
545
546fn signed_standard(kind: IntKind) -> bool {
549 matches!(kind, IntKind::Int | IntKind::Long | IntKind::LongLong)
550}
551
552fn fits(value: u128, kind: IntKind, target: &TargetInfo) -> bool {
554 let width = int_width(kind, target);
555 let bits = if kind.is_signed(false) { width - 1 } else { width };
558 bits >= 128 || value >> bits == 0
561}
562
563fn candidates(base: u32, suffix: Suffix, std: Std) -> &'static [IntKind] {
570 use IntKind::{Int, Int128, Long, LongLong, UInt, UInt128, ULong, ULongLong};
571
572 let decimal = base == 10;
573 let c89 = std == Std::C89;
574 match (suffix.unsigned, suffix.length) {
575 (false, None) if decimal && c89 => &[Int, Long, ULong, Int128, UInt128],
576 (false, None) if decimal => &[Int, Long, LongLong, Int128],
577 (false, None) if c89 => &[Int, UInt, Long, ULong, Int128, UInt128],
578 (false, None) => &[Int, UInt, Long, ULong, LongLong, ULongLong, Int128, UInt128],
579
580 (true, None) if c89 => &[UInt, ULong, UInt128],
581 (true, None) => &[UInt, ULong, ULongLong, UInt128],
582
583 (false, Some(Length::Long)) if decimal && c89 => &[Long, ULong, Int128, UInt128],
584 (false, Some(Length::Long)) if decimal => &[Long, LongLong, Int128],
585 (false, Some(Length::Long)) if c89 => &[Long, ULong, Int128, UInt128],
586 (false, Some(Length::Long)) => &[Long, ULong, LongLong, ULongLong, Int128, UInt128],
587
588 (true, Some(Length::Long)) if c89 => &[ULong, UInt128],
589 (true, Some(Length::Long)) => &[ULong, ULongLong, UInt128],
590
591 (false, Some(Length::LongLong)) if decimal => &[LongLong, Int128],
592 (false, Some(Length::LongLong)) => &[LongLong, ULongLong, Int128, UInt128],
593 (true, Some(Length::LongLong)) => &[ULongLong, UInt128],
594
595 (_, Some(Length::BitInt)) => &[],
597 }
598}
599
600pub fn floating(text: &str, std: Std, target: &TargetInfo) -> Result<FloatConstant, FloatError> {
607 let bytes = text.as_bytes();
608 let (base, _) = base_of(bytes);
609 if !is_floating(bytes, base) {
610 return Err(FloatError::Integer);
611 }
612 let hex = base == 16;
615 let base = if hex { 16 } else { 10 };
616 let mut remarks = Remarks::NONE;
617 if hex && std < Std::C99 {
618 remarks = remarks.with(Remarks::HEX_FLOAT);
619 }
620
621 let mut index = if hex { 2 } else { 0 };
622 let mut digits = 0;
623 let mut point = false;
624 let mut separators = false;
625 while index < bytes.len() {
626 let byte = bytes[index];
627 if byte == b'\'' {
628 if digits == 0 || !next_is_digit(bytes, index, base) {
629 return Err(FloatError::InvalidSuffix);
630 }
631 separators = true;
632 } else if byte == b'.' {
633 if point {
634 return Err(FloatError::TooManyPoints);
635 }
636 point = true;
637 } else if digit(byte, base).is_some() {
638 digits += 1;
639 } else {
640 break;
641 }
642 index += 1;
643 }
644 if digits == 0 {
645 return Err(FloatError::NoDigits);
646 }
647
648 let marker = if hex { *b"pP" } else { *b"eE" };
649 if index < bytes.len() && marker.contains(&bytes[index]) {
650 index += 1;
651 if matches!(bytes.get(index), Some(b'+' | b'-')) {
652 index += 1;
653 }
654 let mut exponent_digits = 0;
655 while index < bytes.len() {
656 let byte = bytes[index];
657 if byte == b'\'' {
658 if exponent_digits == 0 || !next_is_digit(bytes, index, 10) {
659 return Err(FloatError::InvalidSuffix);
660 }
661 separators = true;
662 } else if byte.is_ascii_digit() {
663 exponent_digits += 1;
664 } else {
665 break;
666 }
667 index += 1;
668 }
669 if exponent_digits == 0 {
670 return Err(FloatError::NoExponentDigits);
671 }
672 } else if hex {
673 return Err(FloatError::MissingExponent);
676 }
677 if separators && std < Std::C23 {
678 remarks = remarks.with(Remarks::SEPARATORS);
679 }
680
681 let suffix = float_suffix(&bytes[index..], target)?;
682 remarks = remarks.with(suffix.remarks);
683 let (value, status) =
684 Float::parse(&text[..index], suffix.ty.format(target)).map_err(|error| match error {
685 ParseError::NoDigits => FloatError::NoDigits,
688 ParseError::NoExponentDigits => FloatError::NoExponentDigits,
689 ParseError::Invalid => FloatError::InvalidSuffix,
690 })?;
691 if status.has(Status::OVERFLOW) {
692 remarks = remarks.with(Remarks::OUT_OF_RANGE);
693 }
694 if status.has(Status::UNDERFLOW) && value.is_zero() {
697 remarks = remarks.with(Remarks::TRUNCATED);
698 }
699 Ok(FloatConstant { value, ty: suffix.ty, imaginary: suffix.imaginary, remarks })
700}
701
702fn next_is_digit(bytes: &[u8], index: usize, base: u32) -> bool {
704 bytes.get(index + 1).is_some_and(|&next| digit(next, base).is_some())
705}
706
707struct FloatSuffix {
709 ty: FloatConstantType,
711 imaginary: bool,
713 remarks: Remarks,
715}
716
717fn float_suffix(mut rest: &[u8], target: &TargetInfo) -> Result<FloatSuffix, FloatError> {
724 let mut ty = None;
725 let mut imaginary = false;
726 let mut remarks = Remarks::NONE;
727 while let Some(&byte) = rest.first() {
728 let taken = match byte {
729 b'i' | b'j' | b'I' | b'J' if !imaginary => {
730 imaginary = true;
731 remarks = remarks.with(Remarks::IMAGINARY);
732 1
733 }
734 _ if ty.is_some() => return Err(FloatError::InvalidSuffix),
736 b'f' | b'F' => {
737 let (named, taken, extra) = float_n(rest, target)?;
738 ty = Some(named);
739 remarks = remarks.with(extra);
740 taken
741 }
742 b'l' | b'L' => {
743 ty = Some(FloatConstantType::LongDouble);
744 1
745 }
746 b'q' | b'Q' => {
747 if !target.has_float128 {
749 return Err(FloatError::UnsupportedType);
750 }
751 ty = Some(FloatConstantType::Float128);
752 remarks = remarks.with(Remarks::EXTENDED_SUFFIX);
753 1
754 }
755 b'w' | b'W' => {
756 if target.tuple.arch() != Arch::X86_64 {
758 return Err(FloatError::UnsupportedType);
759 }
760 ty = Some(FloatConstantType::Float80);
761 remarks = remarks.with(Remarks::EXTENDED_SUFFIX);
762 1
763 }
764 b'd' | b'D' => {
765 let second = rest.get(1).copied();
766 let decimal = if byte == b'd' {
767 matches!(second, Some(b'f' | b'd' | b'l'))
768 } else {
769 matches!(second, Some(b'F' | b'D' | b'L'))
770 };
771 if decimal {
772 return Err(FloatError::DecimalFloat);
773 }
774 ty = Some(FloatConstantType::Double);
775 remarks = remarks.with(Remarks::DOUBLE_SUFFIX);
776 1
777 }
778 _ => return Err(FloatError::InvalidSuffix),
779 };
780 rest = &rest[taken..];
781 }
782 Ok(FloatSuffix { ty: ty.unwrap_or(FloatConstantType::Double), imaginary, remarks })
783}
784
785fn float_n(
790 rest: &[u8],
791 target: &TargetInfo,
792) -> Result<(FloatConstantType, usize, Remarks), FloatError> {
793 let mut end = 1;
794 while rest.get(end).is_some_and(u8::is_ascii_digit) {
795 end += 1;
796 }
797 if end == 1 {
798 return Ok((FloatConstantType::Float, 1, Remarks::NONE));
799 }
800 let extended = rest.get(end) == Some(&b'x');
803 let ty = match (&rest[1..end], extended) {
804 (b"16", false) if !target.has_float16 => return Err(FloatError::UnsupportedType),
808 (b"128", false) if !target.has_float128 => return Err(FloatError::UnsupportedType),
809 (b"64", true) if target.float64x_format.is_none() => {
810 return Err(FloatError::UnsupportedType);
811 }
812 (b"16", false) => FloatConstantType::Float16,
813 (b"32", false) => FloatConstantType::Float32,
814 (b"64", false) => FloatConstantType::Float64,
815 (b"128", false) => FloatConstantType::Float128,
816 (b"32", true) => FloatConstantType::Float32x,
817 (b"64", true) => FloatConstantType::Float64x,
818 (b"128", true) => return Err(FloatError::UnsupportedType),
821 _ => return Err(FloatError::InvalidSuffix),
822 };
823 Ok((ty, end + usize::from(extended), Remarks::EXTENDED_SUFFIX))
824}
825
826#[cfg(test)]
827mod tests {
828 use rucc_target::Triple;
829
830 use super::*;
831
832 fn linux() -> TargetInfo {
833 TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a known triple"))
834 }
835
836 fn aarch64() -> TargetInfo {
837 TargetInfo::new("aarch64-unknown-linux-gnu".parse::<Triple>().expect("a known triple"))
838 }
839
840 fn c23(text: &str) -> Result<IntConstant, IntError> {
842 integer(text, Std::C23, &linux())
843 }
844
845 fn kind(text: &str, std: Std) -> IntKind {
847 match integer(text, std, &linux()).expect("a valid constant").ty {
848 IntConstantType::Standard(kind) => kind,
849 IntConstantType::BitInt { .. } => panic!("{text} is a _BitInt constant"),
850 }
851 }
852
853 #[test]
854 fn a_constant_in_each_base_has_the_value_it_says() {
855 assert_eq!(c23("0").expect("zero").value, 0);
856 assert_eq!(c23("42").expect("decimal").value, 42);
857 assert_eq!(c23("0777").expect("octal").value, 0o777);
858 assert_eq!(c23("0xdeadBEEF").expect("hex").value, 0xdead_beef);
859 assert_eq!(c23("0b1010").expect("binary").value, 0b1010);
860 assert_eq!(c23("0X10").expect("upper case prefix").value, 16);
861 assert_eq!(c23("0u").expect("zero with a suffix").value, 0);
864 }
865
866 #[test]
867 fn digit_separators_are_stripped_and_reported_before_c23() {
868 let value = c23("1'000'000").expect("a C23 constant");
869 assert_eq!(value.value, 1_000_000);
870 assert!(value.remarks.is_none());
871 assert_eq!(c23("0x1'0").expect("hex with a separator").value, 16);
872
873 let older = integer("1'000", Std::C17, &linux()).expect("still converted");
874 assert!(older.remarks.has(Remarks::SEPARATORS));
875 assert_eq!(older.value, 1000);
876 }
877
878 #[test]
879 fn the_type_of_a_decimal_constant_walks_the_signed_types_only() {
880 assert_eq!(kind("2147483647", Std::C23), IntKind::Int);
882 assert_eq!(kind("2147483648", Std::C23), IntKind::Long);
883 assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
884 assert_eq!(kind("9223372036854775807", Std::C23), IntKind::Long);
885 assert_eq!(kind("9223372036854775808", Std::C23), IntKind::Int128);
888 assert_eq!(kind("18446744073709551615", Std::C23), IntKind::Int128);
889 let large = c23("18446744073709551615").expect("fits __int128");
890 assert!(large.remarks.has(Remarks::UNSIGNED));
891 }
892
893 #[test]
894 fn a_constant_in_another_base_may_be_unsigned_without_saying_so() {
895 assert_eq!(kind("0xffffffff", Std::C23), IntKind::UInt);
898 assert_eq!(kind("0x7fffffff", Std::C23), IntKind::Int);
899 assert_eq!(kind("0x80000000", Std::C23), IntKind::UInt);
900 assert_eq!(kind("0x100000000", Std::C23), IntKind::Long);
901 assert_eq!(kind("0xffffffffffffffff", Std::C23), IntKind::ULong);
902 assert_eq!(kind("0777", Std::C23), IntKind::Int);
903 assert_eq!(kind("0b1010", Std::C23), IntKind::Int);
904 assert!(c23("0xffffffff").expect("a constant").remarks.is_none());
906 }
907
908 #[test]
909 fn c89_has_unsigned_long_in_the_decimal_list_and_no_long_long_in_any() {
910 assert_eq!(kind("18446744073709551615", Std::C89), IntKind::ULong);
913 assert_eq!(kind("18446744073709551615", Std::C99), IntKind::Int128);
914 let old = integer("18446744073709551615", Std::C89, &linux()).expect("a C89 constant");
915 assert!(old.remarks.has(Remarks::UNSIGNED));
916 let long_long = integer("1ll", Std::C89, &linux()).expect("an extension");
918 assert!(long_long.remarks.has(Remarks::LONG_LONG));
919 assert_eq!(kind("1ll", Std::C89), IntKind::LongLong);
920 assert!(integer("1ll", Std::C99, &linux()).expect("standard").remarks.is_none());
921 }
922
923 #[test]
924 fn a_suffix_narrows_the_list_it_does_not_pick_the_type() {
925 assert_eq!(kind("1u", Std::C23), IntKind::UInt);
926 assert_eq!(kind("1l", Std::C23), IntKind::Long);
927 assert_eq!(kind("1ul", Std::C23), IntKind::ULong);
928 assert_eq!(kind("1ll", Std::C23), IntKind::LongLong);
929 assert_eq!(kind("1llu", Std::C23), IntKind::ULongLong);
930 assert_eq!(kind("4294967296u", Std::C23), IntKind::ULong);
933 assert_eq!(kind("0xffffffffu", Std::C23), IntKind::UInt);
934 }
935
936 #[test]
937 fn the_letters_of_a_suffix_may_be_in_either_case_but_not_both() {
938 for text in ["1u", "1U", "1l", "1L", "1ll", "1LL", "1ul", "1lu", "1uL", "1LLU", "1llu"] {
939 assert!(c23(text).is_ok(), "{text} is a constant in both compilers");
940 }
941 for text in ["1lL", "1Ll", "1uu", "1lul", "1z", "1uz", "1f", "1x", "1_000"] {
942 assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
943 }
944 }
945
946 #[test]
947 fn a_bit_int_constant_has_the_narrowest_type_that_holds_it() {
948 let cases = [
950 ("0wb", true, 2),
951 ("1wb", true, 2),
952 ("3wb", true, 3),
953 ("42wb", true, 7),
954 ("255wb", true, 9),
955 ("0uwb", false, 1),
956 ("1uwb", false, 1),
957 ("255uwb", false, 8),
958 ("256uwb", false, 9),
959 ("0xffffffffffffffffuwb", false, 64),
960 ];
961 for (text, signed, width) in cases {
962 let constant = c23(text).expect("a _BitInt constant");
963 assert_eq!(
964 constant.ty,
965 IntConstantType::BitInt { signed, width },
966 "{text} is the wrong width"
967 );
968 }
969 for text in ["1uwb", "1wbu", "1UWB", "1WBu", "1uWB"] {
971 assert!(c23(text).is_ok(), "{text} is a constant in clang");
972 }
973 for text in ["1wB", "1Wb", "1lwb", "1wbl", "1wbwb"] {
974 assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
975 }
976 let older = integer("1wb", Std::C17, &linux()).expect("clang accepts it everywhere");
978 assert!(older.remarks.has(Remarks::BIT_INT));
979 }
980
981 #[test]
982 fn a_binary_constant_is_an_extension_before_c23() {
983 assert!(c23("0b1").expect("standard in C23").remarks.is_none());
984 let older = integer("0b1", Std::C17, &linux()).expect("both compilers accept it");
985 assert!(older.remarks.has(Remarks::BINARY));
986 }
987
988 #[test]
989 fn an_octal_constant_names_the_digit_that_is_not_one() {
990 assert_eq!(c23("08"), Err(IntError::InvalidOctalDigit));
991 assert_eq!(c23("0778"), Err(IntError::InvalidOctalDigit));
992 assert_eq!(c23("09"), Err(IntError::InvalidOctalDigit));
993 assert_eq!(c23("9").expect("decimal").value, 9);
995 }
996
997 #[test]
998 fn a_prefix_with_no_digits_after_it_is_not_a_constant() {
999 assert_eq!(c23("0x"), Err(IntError::NoDigits));
1000 assert_eq!(c23("0b"), Err(IntError::NoDigits));
1001 }
1002
1003 #[test]
1004 fn a_constant_larger_than_any_type_is_refused_rather_than_wrapped() {
1005 assert_eq!(c23("340282366920938463463374607431768211456"), Err(IntError::TooLarge));
1009 assert_eq!(c23("0x100000000000000000000000000000000"), Err(IntError::TooLarge));
1010 assert_eq!(c23("170141183460469231731687303715884105728"), Err(IntError::TooLarge));
1013 assert_eq!(kind("0x80000000000000000000000000000000", Std::C23), IntKind::UInt128);
1015 assert_eq!(kind("0xffffffffffffffffffffffffffffffff", Std::C23), IntKind::UInt128);
1016 }
1017
1018 #[test]
1019 fn a_floating_constant_is_handed_back_rather_than_refused() {
1020 for text in ["1.0", ".5", "1.", "1e5", "1E-5", "1e", "0x1p3", "0x1.8p+1", "1.5e3"] {
1021 assert_eq!(c23(text), Err(IntError::Floating), "{text} belongs to the other path");
1022 }
1023 assert_eq!(c23("08e5"), Err(IntError::Floating));
1026 assert_eq!(c23("0xe5").expect("hex digits").value, 0xe5);
1029 assert_eq!(c23("1f"), Err(IntError::InvalidSuffix));
1030 }
1031
1032 #[test]
1033 fn the_type_comes_from_the_target_and_not_from_the_host() {
1034 let windows =
1037 TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().expect("a known triple"));
1038 let on_windows = integer("4294967295", Std::C23, &windows).expect("a constant");
1039 assert_eq!(on_windows.ty, IntConstantType::Standard(IntKind::LongLong));
1040 assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
1041 }
1042
1043 fn float(text: &str) -> Result<FloatConstant, FloatError> {
1045 floating(text, Std::C23, &linux())
1046 }
1047
1048 fn bits(text: &str) -> u128 {
1050 float(text).expect("a valid constant").value.to_bits()
1051 }
1052
1053 #[test]
1054 fn a_constant_with_no_suffix_is_a_double() {
1055 let constant = float("1.5").expect("a constant");
1056 assert_eq!(constant.ty, FloatConstantType::Double);
1057 assert!(!constant.imaginary);
1058 assert!(constant.remarks.is_none());
1059 assert_eq!(constant.value.to_bits(), 0x3ff8_0000_0000_0000);
1060 assert_eq!(bits("0.1"), 0x3fb9_9999_9999_999a);
1061 assert_eq!(bits(".5"), 0x3fe0_0000_0000_0000);
1062 assert_eq!(bits("1."), 0x3ff0_0000_0000_0000);
1063 assert_eq!(bits("1e5"), 0x40f8_6a00_0000_0000);
1064 assert_eq!(bits("0x1p3"), 0x4020_0000_0000_0000);
1065 assert_eq!(bits("08e5"), 0x4128_6a00_0000_0000);
1068 }
1069
1070 #[test]
1071 fn the_suffix_names_the_type_rather_than_narrowing_a_list() {
1072 let cases = [
1074 ("1.0", FloatConstantType::Double),
1075 ("1.0f", FloatConstantType::Float),
1076 ("1.0F", FloatConstantType::Float),
1077 ("1.0l", FloatConstantType::LongDouble),
1078 ("1.0L", FloatConstantType::LongDouble),
1079 ("1.0d", FloatConstantType::Double),
1080 ("1.0q", FloatConstantType::Float128),
1081 ("1.0w", FloatConstantType::Float80),
1082 ("1.0f16", FloatConstantType::Float16),
1083 ("1.0F16", FloatConstantType::Float16),
1084 ("1.0f32", FloatConstantType::Float32),
1085 ("1.0f64", FloatConstantType::Float64),
1086 ("1.0f128", FloatConstantType::Float128),
1087 ("1.0f32x", FloatConstantType::Float32x),
1088 ("1.0F64x", FloatConstantType::Float64x),
1089 ];
1090 for (text, ty) in cases {
1091 assert_eq!(float(text).expect("a constant").ty, ty, "{text} has the wrong type");
1092 }
1093 }
1094
1095 #[test]
1096 fn each_type_is_converted_in_the_format_the_target_has_for_it() {
1097 assert_eq!(bits("0.1f"), 0x3dcc_cccd);
1101 assert_eq!(bits("0.1f16"), 0x2e66);
1102 assert_eq!(bits("0.1f32x"), 0x3fb9_9999_9999_999a);
1103 assert_eq!(bits("0.1f64x"), 0x3ffb_cccc_cccc_cccc_cccd);
1104 assert_eq!(bits("0.1w"), 0x3ffb_cccc_cccc_cccc_cccd);
1105 assert_eq!(bits("0.1l"), 0x3ffb_cccc_cccc_cccc_cccd);
1106 assert_eq!(bits("0.1q"), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
1107 assert_eq!(bits("0.1f128"), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
1108 assert_eq!(bits("1.0l"), 0x3fff_8000_0000_0000_0000);
1109 }
1110
1111 #[test]
1112 fn the_format_comes_from_the_target_and_not_from_the_host() {
1113 let arm = floating("1.0l", Std::C23, &aarch64()).expect("a constant");
1116 assert_eq!(arm.value.to_bits(), 0x3fff_0000_0000_0000_0000_0000_0000_0000);
1117 assert_eq!(bits("1.0l"), 0x3fff_8000_0000_0000_0000);
1118 let arm_wide = floating("0.1f64x", Std::C23, &aarch64()).expect("a constant");
1120 assert_eq!(arm_wide.value.to_bits(), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
1121 let windows =
1123 TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().expect("a known triple"));
1124 let on_windows = floating("1.0l", Std::C23, &windows).expect("a constant");
1125 assert_eq!(on_windows.value.to_bits(), 0x3ff0_0000_0000_0000);
1126 }
1127
1128 #[test]
1129 fn the_case_rules_of_a_floating_suffix_are_not_uniform() {
1130 for text in ["1.0f", "1.0F", "1.0L", "1.0Q", "1.0W", "1.0F32", "1.0f64x", "1.0F64x"] {
1134 assert!(float(text).is_ok(), "{text} is a constant in gcc");
1135 }
1136 for text in ["1.0F32X", "1.0f32X", "1.0f16x", "1.0ff", "1.0fl", "1.0lf", "1.0fF", "1.0LL"] {
1137 assert_eq!(float(text), Err(FloatError::InvalidSuffix), "{text} is not");
1138 }
1139 }
1140
1141 #[test]
1142 fn an_imaginary_suffix_may_sit_on_either_side_of_the_type() {
1143 for text in ["1.0i", "1.0j", "1.0I", "1.0J", "1.0if", "1.0fi", "1.0Li", "1.0iL", "1.0f16i"]
1144 {
1145 let constant = float(text).expect("a constant in gcc");
1146 assert!(constant.imaginary, "{text} is imaginary");
1147 assert!(constant.remarks.has(Remarks::IMAGINARY));
1148 }
1149 assert_eq!(float("1.0ii"), Err(FloatError::InvalidSuffix));
1150 assert_eq!(float("1.0ij"), Err(FloatError::InvalidSuffix));
1151 assert!(!float("1.0f").expect("a constant").imaginary);
1152 }
1153
1154 #[test]
1155 fn a_decimal_floating_constant_is_recognised_and_refused() {
1156 for text in ["1.0df", "1.0dd", "1.0dl", "1.0DF", "1.0DD", "1.0DL"] {
1158 assert_eq!(float(text), Err(FloatError::DecimalFloat), "{text} is a decimal float");
1159 }
1160 for text in ["1.0Df", "1.0dF", "1.0dD", "1.0Dl"] {
1163 assert_eq!(float(text), Err(FloatError::InvalidSuffix), "{text} is neither");
1164 }
1165 let long_way = float("1.0d").expect("a GCC extension");
1167 assert_eq!(long_way.ty, FloatConstantType::Double);
1168 assert!(long_way.remarks.has(Remarks::DOUBLE_SUFFIX));
1169 }
1170
1171 #[test]
1172 fn a_type_the_target_does_not_have_is_refused_by_name() {
1173 assert_eq!(float("1.0f128x"), Err(FloatError::UnsupportedType));
1176 assert_eq!(floating("1.0w", Std::C23, &aarch64()), Err(FloatError::UnsupportedType));
1178 assert!(float("1.0w").is_ok());
1179 }
1180
1181 #[test]
1182 fn a_suffix_goes_where_the_type_it_names_goes() {
1183 let arm =
1189 TargetInfo::for_tuple("armv7-linux-gnueabihf".parse().expect("a row in the table"));
1190 let i686 = TargetInfo::for_tuple("i686-linux-gnu".parse().expect("a row in the table"));
1191 for text in ["1.0f16", "1.0f128", "1.0q", "1.0f64x"] {
1192 assert_eq!(
1193 floating(text, Std::C23, &arm),
1194 Err(FloatError::UnsupportedType),
1195 "{text} on armv7"
1196 );
1197 assert!(float(text).is_ok(), "{text} on x86-64");
1198 }
1199 assert_eq!(
1200 floating("1.0f16", Std::C23, &i686),
1201 Err(FloatError::UnsupportedType),
1202 "the half is the one i686 has no format for"
1203 );
1204 assert!(floating("1.0f128", Std::C23, &i686).is_ok());
1205 for text in ["1.0f32", "1.0f64", "1.0f32x"] {
1207 assert!(floating(text, Std::C23, &arm).is_ok(), "{text} on armv7");
1208 }
1209 }
1210
1211 #[test]
1212 fn a_hexadecimal_constant_needs_an_exponent_and_a_decimal_one_does_not() {
1213 assert_eq!(float("0x1.8"), Err(FloatError::MissingExponent));
1216 assert_eq!(bits("0x1.8p0"), 0x3ff8_0000_0000_0000);
1217 assert_eq!(bits("0x.8p1"), 0x3ff0_0000_0000_0000);
1218 assert_eq!(bits("1.5"), 0x3ff8_0000_0000_0000);
1219 for text in ["1.0e", "1e+", "1e-", "0x1p", "0x1p+"] {
1220 assert_eq!(float(text), Err(FloatError::NoExponentDigits), "{text} has no exponent");
1221 }
1222 assert_eq!(float("1.2.3"), Err(FloatError::TooManyPoints));
1223 }
1224
1225 #[test]
1226 fn an_integer_constant_is_handed_back_rather_than_refused() {
1227 for text in ["1", "0", "0x10", "1u", "0777", "1wb", "0b1", "0xe5", "1f"] {
1228 assert_eq!(float(text), Err(FloatError::Integer), "{text} belongs to the other path");
1229 }
1230 }
1231
1232 #[test]
1233 fn a_value_past_the_range_of_its_type_is_still_a_constant() {
1234 let large = float("1e400").expect("a constant gcc compiles");
1235 assert!(large.value.is_infinite());
1236 assert!(large.remarks.has(Remarks::OUT_OF_RANGE));
1237 let small = float("1e-400").expect("a constant gcc compiles");
1238 assert!(small.value.is_zero());
1239 assert!(small.remarks.has(Remarks::TRUNCATED));
1240 assert!(float("1e39f").expect("a constant").remarks.has(Remarks::OUT_OF_RANGE));
1242 assert!(float("1e-46f").expect("a constant").remarks.has(Remarks::TRUNCATED));
1243 assert!(float("1e-4951l").expect("a constant").remarks.has(Remarks::TRUNCATED));
1244 let subnormal = float("1e-320").expect("a constant");
1246 assert!(!subnormal.value.is_zero());
1247 assert!(subnormal.remarks.is_none());
1248 }
1249
1250 #[test]
1251 fn the_dialect_decides_what_a_constant_is_worth_saying_about() {
1252 let old = floating("0x1p3", Std::C89, &linux()).expect("gcc compiles it anyway");
1254 assert!(old.remarks.has(Remarks::HEX_FLOAT));
1255 assert!(floating("0x1p3", Std::C99, &linux()).expect("standard").remarks.is_none());
1256 assert_eq!(bits("1'0.5"), 0x4025_0000_0000_0000);
1258 assert_eq!(bits("1.0e1'0"), 0x4202_a05f_2000_0000);
1259 assert!(float("0x1'0p0").expect("a C23 constant").remarks.is_none());
1260 let older = floating("1'0.5", Std::C17, &linux()).expect("still converted");
1261 assert!(older.remarks.has(Remarks::SEPARATORS));
1262 for text in ["1.0q", "1.0w", "1.0f16", "1.0f32x"] {
1264 let constant = floating(text, Std::C89, &linux()).expect("gcc accepts it in C89");
1265 assert!(constant.remarks.has(Remarks::EXTENDED_SUFFIX), "{text} is not standard");
1266 }
1267 assert!(float("1.0f").expect("a constant").remarks.is_none());
1268 }
1269}