1use rucc_base::float::{Float, Format, ParseError, Status};
83use rucc_session::Std;
84use rucc_target::TargetInfo;
85use rucc_tuple::Arch;
86use rucc_types::{IntKind, int_width};
87
88use crate::remarks::Remarks;
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92pub struct IntConstant {
93 pub value: u128,
97 pub ty: IntConstantType,
99 pub remarks: Remarks,
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum IntConstantType {
106 Standard(IntKind),
108 BitInt {
110 signed: bool,
112 width: u32,
114 },
115}
116
117impl IntConstantType {
118 #[must_use]
124 pub const fn suffix(self) -> &'static str {
125 match self {
126 IntConstantType::Standard(kind) => match kind {
127 IntKind::UInt | IntKind::UInt128 => "u",
128 IntKind::Long => "l",
129 IntKind::ULong => "ul",
130 IntKind::LongLong => "ll",
131 IntKind::ULongLong => "ull",
132 _ => "",
133 },
134 IntConstantType::BitInt { signed: true, .. } => "wb",
135 IntConstantType::BitInt { signed: false, .. } => "uwb",
136 }
137 }
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145pub enum IntError {
146 Floating,
148 InvalidSuffix,
150 InvalidOctalDigit,
152 NoDigits,
154 TooLarge,
157}
158
159impl IntError {
160 #[must_use]
165 pub const fn message(self) -> &'static str {
166 match self {
167 IntError::Floating => "not an integer constant",
168 IntError::InvalidSuffix => "invalid suffix on integer constant",
169 IntError::InvalidOctalDigit => "invalid digit in octal constant",
170 IntError::NoDigits => "no digits in integer constant",
171 IntError::TooLarge => "integer constant is too large to be represented in any type",
172 }
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
178pub struct FloatConstant {
179 pub value: Float,
181 pub ty: FloatConstantType,
183 pub imaginary: bool,
186 pub remarks: Remarks,
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
196pub enum FloatConstantType {
197 Float,
199 Double,
201 LongDouble,
203 Float16,
205 Float32,
207 Float64,
209 Float128,
212 Float32x,
215 Float64x,
218 Float80,
222}
223
224impl FloatConstantType {
225 #[must_use]
231 pub fn format(self, target: &TargetInfo) -> Format {
232 match self {
233 FloatConstantType::Float | FloatConstantType::Float32 => Format::Single,
234 FloatConstantType::Double
235 | FloatConstantType::Float64
236 | FloatConstantType::Float32x => Format::Double,
237 FloatConstantType::LongDouble => target.long_double_format,
238 FloatConstantType::Float16 => Format::Half,
239 FloatConstantType::Float128 => Format::Quad,
240 FloatConstantType::Float64x if target.tuple.arch() == Arch::X86_64 => {
241 Format::X87Extended
242 }
243 FloatConstantType::Float64x => Format::Quad,
244 FloatConstantType::Float80 => Format::X87Extended,
245 }
246 }
247
248 #[must_use]
253 pub const fn name(self) -> &'static str {
254 match self {
255 FloatConstantType::Float => "float",
256 FloatConstantType::Double => "double",
257 FloatConstantType::LongDouble => "long double",
258 FloatConstantType::Float16 => "_Float16",
259 FloatConstantType::Float32 => "_Float32",
260 FloatConstantType::Float64 => "_Float64",
261 FloatConstantType::Float128 => "_Float128",
262 FloatConstantType::Float32x => "_Float32x",
263 FloatConstantType::Float64x => "_Float64x",
264 FloatConstantType::Float80 => "__float80",
265 }
266 }
267
268 #[must_use]
274 pub const fn suffix(self) -> &'static str {
275 match self {
276 FloatConstantType::Float => "f",
277 FloatConstantType::Double => "",
278 FloatConstantType::LongDouble => "l",
279 FloatConstantType::Float16 => "f16",
280 FloatConstantType::Float32 => "f32",
281 FloatConstantType::Float64 => "f64",
282 FloatConstantType::Float128 => "f128",
283 FloatConstantType::Float32x => "f32x",
284 FloatConstantType::Float64x => "f64x",
285 FloatConstantType::Float80 => "w",
286 }
287 }
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
295pub enum FloatError {
296 Integer,
298 InvalidSuffix,
300 MissingExponent,
304 NoExponentDigits,
306 NoDigits,
308 TooManyPoints,
310 DecimalFloat,
313 UnsupportedType,
316}
317
318impl FloatError {
319 #[must_use]
321 pub const fn message(self) -> &'static str {
322 match self {
323 FloatError::Integer => "not a floating constant",
324 FloatError::InvalidSuffix => "invalid suffix on floating constant",
325 FloatError::MissingExponent => "hexadecimal floating constants require an exponent",
326 FloatError::NoExponentDigits => "exponent has no digits",
327 FloatError::NoDigits => "no digits in floating constant",
328 FloatError::TooManyPoints => "too many decimal points in number",
329 FloatError::DecimalFloat => "decimal floating constants are not supported yet",
330 FloatError::UnsupportedType => {
331 "the type of this floating constant is not supported on this target"
332 }
333 }
334 }
335}
336
337pub fn integer(text: &str, std: Std, target: &TargetInfo) -> Result<IntConstant, IntError> {
344 let bytes = text.as_bytes();
345 let (base, start) = base_of(bytes);
346 if is_floating(bytes, base) {
347 return Err(IntError::Floating);
348 }
349 let mut remarks = Remarks::NONE;
350 if base == 2 && std < Std::C23 {
351 remarks = remarks.with(Remarks::BINARY);
352 }
353
354 let mut value: u128 = 0;
355 let mut digits = 0;
356 let mut index = start;
357 while index < bytes.len() {
358 let byte = bytes[index];
359 if byte == b'\'' {
360 if digits == 0 || index + 1 >= bytes.len() || digit(bytes[index + 1], base).is_none() {
364 return Err(IntError::InvalidSuffix);
365 }
366 if std < Std::C23 {
367 remarks = remarks.with(Remarks::SEPARATORS);
368 }
369 index += 1;
370 continue;
371 }
372 let Some(digit) = digit(byte, base) else {
373 break;
374 };
375 value = value
376 .checked_mul(u128::from(base))
377 .and_then(|shifted| shifted.checked_add(u128::from(digit)))
378 .ok_or(IntError::TooLarge)?;
379 digits += 1;
380 index += 1;
381 }
382 if digits == 0 {
383 return Err(IntError::NoDigits);
386 }
387 if base == 8 && bytes[start..index].iter().any(|&byte| byte == b'8' || byte == b'9') {
388 return Err(IntError::InvalidOctalDigit);
389 }
390
391 let suffix = suffix_of(&bytes[index..])?;
392 if suffix.length == Some(Length::LongLong) && std == Std::C89 {
393 remarks = remarks.with(Remarks::LONG_LONG);
394 }
395 if suffix.length == Some(Length::BitInt) {
396 if std < Std::C23 {
397 remarks = remarks.with(Remarks::BIT_INT);
398 }
399 return Ok(IntConstant { value, ty: bit_int(value, suffix.unsigned), remarks });
400 }
401
402 let candidates = candidates(base, suffix, std);
403 let kind = candidates
404 .iter()
405 .copied()
406 .find(|&kind| fits(value, kind, target))
407 .ok_or(IntError::TooLarge)?;
408 if base == 10 && !suffix.unsigned && !signed_standard(kind) {
409 remarks = remarks.with(Remarks::UNSIGNED);
410 }
411 Ok(IntConstant { value, ty: IntConstantType::Standard(kind), remarks })
412}
413
414fn base_of(bytes: &[u8]) -> (u32, usize) {
420 match bytes {
421 [b'0', b'x' | b'X', ..] => (16, 2),
422 [b'0', b'b' | b'B', ..] => (2, 2),
423 [b'0', next, ..] if next.is_ascii_digit() => (8, 1),
424 _ => (10, 0),
425 }
426}
427
428fn is_floating(bytes: &[u8], base: u32) -> bool {
438 let exponent = if base == 16 { *b"pP" } else { *b"eE" };
439 bytes.iter().any(|&byte| byte == b'.' || exponent.contains(&byte))
440}
441
442fn digit(byte: u8, base: u32) -> Option<u32> {
447 char::from(byte).to_digit(if base == 8 { 10 } else { base })
448}
449
450#[derive(Debug, Clone, Copy, PartialEq, Eq)]
452enum Length {
453 Long,
455 LongLong,
457 BitInt,
459}
460
461#[derive(Debug, Clone, Copy, PartialEq, Eq)]
463struct Suffix {
464 unsigned: bool,
466 length: Option<Length>,
468}
469
470fn suffix_of(mut rest: &[u8]) -> Result<Suffix, IntError> {
472 let mut suffix = Suffix { unsigned: false, length: None };
473 while let Some(&byte) = rest.first() {
474 let taken = match byte {
475 b'u' | b'U' if !suffix.unsigned => {
476 suffix.unsigned = true;
477 1
478 }
479 b'l' | b'L' if suffix.length.is_none() => {
482 if rest.get(1) == Some(&byte) {
483 suffix.length = Some(Length::LongLong);
484 2
485 } else {
486 suffix.length = Some(Length::Long);
487 1
488 }
489 }
490 b'w' | b'W' if suffix.length.is_none() => {
491 let second = if byte == b'w' { b'b' } else { b'B' };
492 if rest.get(1) != Some(&second) {
493 return Err(IntError::InvalidSuffix);
494 }
495 suffix.length = Some(Length::BitInt);
496 2
497 }
498 _ => return Err(IntError::InvalidSuffix),
499 };
500 rest = &rest[taken..];
501 }
502 Ok(suffix)
503}
504
505fn bit_int(value: u128, unsigned: bool) -> IntConstantType {
511 let used = 128 - value.leading_zeros();
512 let width = if unsigned { used.max(1) } else { used + 1 };
513 IntConstantType::BitInt { signed: !unsigned, width: width.max(if unsigned { 1 } else { 2 }) }
514}
515
516fn signed_standard(kind: IntKind) -> bool {
519 matches!(kind, IntKind::Int | IntKind::Long | IntKind::LongLong)
520}
521
522fn fits(value: u128, kind: IntKind, target: &TargetInfo) -> bool {
524 let width = int_width(kind, target);
525 let bits = if kind.is_signed(false) { width - 1 } else { width };
528 bits >= 128 || value >> bits == 0
531}
532
533fn candidates(base: u32, suffix: Suffix, std: Std) -> &'static [IntKind] {
540 use IntKind::{Int, Int128, Long, LongLong, UInt, UInt128, ULong, ULongLong};
541
542 let decimal = base == 10;
543 let c89 = std == Std::C89;
544 match (suffix.unsigned, suffix.length) {
545 (false, None) if decimal && c89 => &[Int, Long, ULong, Int128, UInt128],
546 (false, None) if decimal => &[Int, Long, LongLong, Int128],
547 (false, None) if c89 => &[Int, UInt, Long, ULong, Int128, UInt128],
548 (false, None) => &[Int, UInt, Long, ULong, LongLong, ULongLong, Int128, UInt128],
549
550 (true, None) if c89 => &[UInt, ULong, UInt128],
551 (true, None) => &[UInt, ULong, ULongLong, UInt128],
552
553 (false, Some(Length::Long)) if decimal && c89 => &[Long, ULong, Int128, UInt128],
554 (false, Some(Length::Long)) if decimal => &[Long, LongLong, Int128],
555 (false, Some(Length::Long)) if c89 => &[Long, ULong, Int128, UInt128],
556 (false, Some(Length::Long)) => &[Long, ULong, LongLong, ULongLong, Int128, UInt128],
557
558 (true, Some(Length::Long)) if c89 => &[ULong, UInt128],
559 (true, Some(Length::Long)) => &[ULong, ULongLong, UInt128],
560
561 (false, Some(Length::LongLong)) if decimal => &[LongLong, Int128],
562 (false, Some(Length::LongLong)) => &[LongLong, ULongLong, Int128, UInt128],
563 (true, Some(Length::LongLong)) => &[ULongLong, UInt128],
564
565 (_, Some(Length::BitInt)) => &[],
567 }
568}
569
570pub fn floating(text: &str, std: Std, target: &TargetInfo) -> Result<FloatConstant, FloatError> {
577 let bytes = text.as_bytes();
578 let (base, _) = base_of(bytes);
579 if !is_floating(bytes, base) {
580 return Err(FloatError::Integer);
581 }
582 let hex = base == 16;
585 let base = if hex { 16 } else { 10 };
586 let mut remarks = Remarks::NONE;
587 if hex && std < Std::C99 {
588 remarks = remarks.with(Remarks::HEX_FLOAT);
589 }
590
591 let mut index = if hex { 2 } else { 0 };
592 let mut digits = 0;
593 let mut point = false;
594 let mut separators = false;
595 while index < bytes.len() {
596 let byte = bytes[index];
597 if byte == b'\'' {
598 if digits == 0 || !next_is_digit(bytes, index, base) {
599 return Err(FloatError::InvalidSuffix);
600 }
601 separators = true;
602 } else if byte == b'.' {
603 if point {
604 return Err(FloatError::TooManyPoints);
605 }
606 point = true;
607 } else if digit(byte, base).is_some() {
608 digits += 1;
609 } else {
610 break;
611 }
612 index += 1;
613 }
614 if digits == 0 {
615 return Err(FloatError::NoDigits);
616 }
617
618 let marker = if hex { *b"pP" } else { *b"eE" };
619 if index < bytes.len() && marker.contains(&bytes[index]) {
620 index += 1;
621 if matches!(bytes.get(index), Some(b'+' | b'-')) {
622 index += 1;
623 }
624 let mut exponent_digits = 0;
625 while index < bytes.len() {
626 let byte = bytes[index];
627 if byte == b'\'' {
628 if exponent_digits == 0 || !next_is_digit(bytes, index, 10) {
629 return Err(FloatError::InvalidSuffix);
630 }
631 separators = true;
632 } else if byte.is_ascii_digit() {
633 exponent_digits += 1;
634 } else {
635 break;
636 }
637 index += 1;
638 }
639 if exponent_digits == 0 {
640 return Err(FloatError::NoExponentDigits);
641 }
642 } else if hex {
643 return Err(FloatError::MissingExponent);
646 }
647 if separators && std < Std::C23 {
648 remarks = remarks.with(Remarks::SEPARATORS);
649 }
650
651 let suffix = float_suffix(&bytes[index..], target)?;
652 remarks = remarks.with(suffix.remarks);
653 let (value, status) =
654 Float::parse(&text[..index], suffix.ty.format(target)).map_err(|error| match error {
655 ParseError::NoDigits => FloatError::NoDigits,
658 ParseError::NoExponentDigits => FloatError::NoExponentDigits,
659 ParseError::Invalid => FloatError::InvalidSuffix,
660 })?;
661 if status.has(Status::OVERFLOW) {
662 remarks = remarks.with(Remarks::OUT_OF_RANGE);
663 }
664 if status.has(Status::UNDERFLOW) && value.is_zero() {
667 remarks = remarks.with(Remarks::TRUNCATED);
668 }
669 Ok(FloatConstant { value, ty: suffix.ty, imaginary: suffix.imaginary, remarks })
670}
671
672fn next_is_digit(bytes: &[u8], index: usize, base: u32) -> bool {
674 bytes.get(index + 1).is_some_and(|&next| digit(next, base).is_some())
675}
676
677struct FloatSuffix {
679 ty: FloatConstantType,
681 imaginary: bool,
683 remarks: Remarks,
685}
686
687fn float_suffix(mut rest: &[u8], target: &TargetInfo) -> Result<FloatSuffix, FloatError> {
694 let mut ty = None;
695 let mut imaginary = false;
696 let mut remarks = Remarks::NONE;
697 while let Some(&byte) = rest.first() {
698 let taken = match byte {
699 b'i' | b'j' | b'I' | b'J' if !imaginary => {
700 imaginary = true;
701 remarks = remarks.with(Remarks::IMAGINARY);
702 1
703 }
704 _ if ty.is_some() => return Err(FloatError::InvalidSuffix),
706 b'f' | b'F' => {
707 let (named, taken, extra) = float_n(rest)?;
708 ty = Some(named);
709 remarks = remarks.with(extra);
710 taken
711 }
712 b'l' | b'L' => {
713 ty = Some(FloatConstantType::LongDouble);
714 1
715 }
716 b'q' | b'Q' => {
717 ty = Some(FloatConstantType::Float128);
718 remarks = remarks.with(Remarks::EXTENDED_SUFFIX);
719 1
720 }
721 b'w' | b'W' => {
722 if target.tuple.arch() != Arch::X86_64 {
724 return Err(FloatError::UnsupportedType);
725 }
726 ty = Some(FloatConstantType::Float80);
727 remarks = remarks.with(Remarks::EXTENDED_SUFFIX);
728 1
729 }
730 b'd' | b'D' => {
731 let second = rest.get(1).copied();
732 let decimal = if byte == b'd' {
733 matches!(second, Some(b'f' | b'd' | b'l'))
734 } else {
735 matches!(second, Some(b'F' | b'D' | b'L'))
736 };
737 if decimal {
738 return Err(FloatError::DecimalFloat);
739 }
740 ty = Some(FloatConstantType::Double);
741 remarks = remarks.with(Remarks::DOUBLE_SUFFIX);
742 1
743 }
744 _ => return Err(FloatError::InvalidSuffix),
745 };
746 rest = &rest[taken..];
747 }
748 Ok(FloatSuffix { ty: ty.unwrap_or(FloatConstantType::Double), imaginary, remarks })
749}
750
751fn float_n(rest: &[u8]) -> Result<(FloatConstantType, usize, Remarks), FloatError> {
756 let mut end = 1;
757 while rest.get(end).is_some_and(u8::is_ascii_digit) {
758 end += 1;
759 }
760 if end == 1 {
761 return Ok((FloatConstantType::Float, 1, Remarks::NONE));
762 }
763 let extended = rest.get(end) == Some(&b'x');
766 let ty = match (&rest[1..end], extended) {
767 (b"16", false) => FloatConstantType::Float16,
768 (b"32", false) => FloatConstantType::Float32,
769 (b"64", false) => FloatConstantType::Float64,
770 (b"128", false) => FloatConstantType::Float128,
771 (b"32", true) => FloatConstantType::Float32x,
772 (b"64", true) => FloatConstantType::Float64x,
773 (b"128", true) => return Err(FloatError::UnsupportedType),
776 _ => return Err(FloatError::InvalidSuffix),
777 };
778 Ok((ty, end + usize::from(extended), Remarks::EXTENDED_SUFFIX))
779}
780
781#[cfg(test)]
782mod tests {
783 use rucc_target::Triple;
784
785 use super::*;
786
787 fn linux() -> TargetInfo {
788 TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a known triple"))
789 }
790
791 fn aarch64() -> TargetInfo {
792 TargetInfo::new("aarch64-unknown-linux-gnu".parse::<Triple>().expect("a known triple"))
793 }
794
795 fn c23(text: &str) -> Result<IntConstant, IntError> {
797 integer(text, Std::C23, &linux())
798 }
799
800 fn kind(text: &str, std: Std) -> IntKind {
802 match integer(text, std, &linux()).expect("a valid constant").ty {
803 IntConstantType::Standard(kind) => kind,
804 IntConstantType::BitInt { .. } => panic!("{text} is a _BitInt constant"),
805 }
806 }
807
808 #[test]
809 fn a_constant_in_each_base_has_the_value_it_says() {
810 assert_eq!(c23("0").expect("zero").value, 0);
811 assert_eq!(c23("42").expect("decimal").value, 42);
812 assert_eq!(c23("0777").expect("octal").value, 0o777);
813 assert_eq!(c23("0xdeadBEEF").expect("hex").value, 0xdead_beef);
814 assert_eq!(c23("0b1010").expect("binary").value, 0b1010);
815 assert_eq!(c23("0X10").expect("upper case prefix").value, 16);
816 assert_eq!(c23("0u").expect("zero with a suffix").value, 0);
819 }
820
821 #[test]
822 fn digit_separators_are_stripped_and_reported_before_c23() {
823 let value = c23("1'000'000").expect("a C23 constant");
824 assert_eq!(value.value, 1_000_000);
825 assert!(value.remarks.is_none());
826 assert_eq!(c23("0x1'0").expect("hex with a separator").value, 16);
827
828 let older = integer("1'000", Std::C17, &linux()).expect("still converted");
829 assert!(older.remarks.has(Remarks::SEPARATORS));
830 assert_eq!(older.value, 1000);
831 }
832
833 #[test]
834 fn the_type_of_a_decimal_constant_walks_the_signed_types_only() {
835 assert_eq!(kind("2147483647", Std::C23), IntKind::Int);
837 assert_eq!(kind("2147483648", Std::C23), IntKind::Long);
838 assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
839 assert_eq!(kind("9223372036854775807", Std::C23), IntKind::Long);
840 assert_eq!(kind("9223372036854775808", Std::C23), IntKind::Int128);
843 assert_eq!(kind("18446744073709551615", Std::C23), IntKind::Int128);
844 let large = c23("18446744073709551615").expect("fits __int128");
845 assert!(large.remarks.has(Remarks::UNSIGNED));
846 }
847
848 #[test]
849 fn a_constant_in_another_base_may_be_unsigned_without_saying_so() {
850 assert_eq!(kind("0xffffffff", Std::C23), IntKind::UInt);
853 assert_eq!(kind("0x7fffffff", Std::C23), IntKind::Int);
854 assert_eq!(kind("0x80000000", Std::C23), IntKind::UInt);
855 assert_eq!(kind("0x100000000", Std::C23), IntKind::Long);
856 assert_eq!(kind("0xffffffffffffffff", Std::C23), IntKind::ULong);
857 assert_eq!(kind("0777", Std::C23), IntKind::Int);
858 assert_eq!(kind("0b1010", Std::C23), IntKind::Int);
859 assert!(c23("0xffffffff").expect("a constant").remarks.is_none());
861 }
862
863 #[test]
864 fn c89_has_unsigned_long_in_the_decimal_list_and_no_long_long_in_any() {
865 assert_eq!(kind("18446744073709551615", Std::C89), IntKind::ULong);
868 assert_eq!(kind("18446744073709551615", Std::C99), IntKind::Int128);
869 let old = integer("18446744073709551615", Std::C89, &linux()).expect("a C89 constant");
870 assert!(old.remarks.has(Remarks::UNSIGNED));
871 let long_long = integer("1ll", Std::C89, &linux()).expect("an extension");
873 assert!(long_long.remarks.has(Remarks::LONG_LONG));
874 assert_eq!(kind("1ll", Std::C89), IntKind::LongLong);
875 assert!(integer("1ll", Std::C99, &linux()).expect("standard").remarks.is_none());
876 }
877
878 #[test]
879 fn a_suffix_narrows_the_list_it_does_not_pick_the_type() {
880 assert_eq!(kind("1u", Std::C23), IntKind::UInt);
881 assert_eq!(kind("1l", Std::C23), IntKind::Long);
882 assert_eq!(kind("1ul", Std::C23), IntKind::ULong);
883 assert_eq!(kind("1ll", Std::C23), IntKind::LongLong);
884 assert_eq!(kind("1llu", Std::C23), IntKind::ULongLong);
885 assert_eq!(kind("4294967296u", Std::C23), IntKind::ULong);
888 assert_eq!(kind("0xffffffffu", Std::C23), IntKind::UInt);
889 }
890
891 #[test]
892 fn the_letters_of_a_suffix_may_be_in_either_case_but_not_both() {
893 for text in ["1u", "1U", "1l", "1L", "1ll", "1LL", "1ul", "1lu", "1uL", "1LLU", "1llu"] {
894 assert!(c23(text).is_ok(), "{text} is a constant in both compilers");
895 }
896 for text in ["1lL", "1Ll", "1uu", "1lul", "1z", "1uz", "1f", "1x", "1_000"] {
897 assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
898 }
899 }
900
901 #[test]
902 fn a_bit_int_constant_has_the_narrowest_type_that_holds_it() {
903 let cases = [
905 ("0wb", true, 2),
906 ("1wb", true, 2),
907 ("3wb", true, 3),
908 ("42wb", true, 7),
909 ("255wb", true, 9),
910 ("0uwb", false, 1),
911 ("1uwb", false, 1),
912 ("255uwb", false, 8),
913 ("256uwb", false, 9),
914 ("0xffffffffffffffffuwb", false, 64),
915 ];
916 for (text, signed, width) in cases {
917 let constant = c23(text).expect("a _BitInt constant");
918 assert_eq!(
919 constant.ty,
920 IntConstantType::BitInt { signed, width },
921 "{text} is the wrong width"
922 );
923 }
924 for text in ["1uwb", "1wbu", "1UWB", "1WBu", "1uWB"] {
926 assert!(c23(text).is_ok(), "{text} is a constant in clang");
927 }
928 for text in ["1wB", "1Wb", "1lwb", "1wbl", "1wbwb"] {
929 assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
930 }
931 let older = integer("1wb", Std::C17, &linux()).expect("clang accepts it everywhere");
933 assert!(older.remarks.has(Remarks::BIT_INT));
934 }
935
936 #[test]
937 fn a_binary_constant_is_an_extension_before_c23() {
938 assert!(c23("0b1").expect("standard in C23").remarks.is_none());
939 let older = integer("0b1", Std::C17, &linux()).expect("both compilers accept it");
940 assert!(older.remarks.has(Remarks::BINARY));
941 }
942
943 #[test]
944 fn an_octal_constant_names_the_digit_that_is_not_one() {
945 assert_eq!(c23("08"), Err(IntError::InvalidOctalDigit));
946 assert_eq!(c23("0778"), Err(IntError::InvalidOctalDigit));
947 assert_eq!(c23("09"), Err(IntError::InvalidOctalDigit));
948 assert_eq!(c23("9").expect("decimal").value, 9);
950 }
951
952 #[test]
953 fn a_prefix_with_no_digits_after_it_is_not_a_constant() {
954 assert_eq!(c23("0x"), Err(IntError::NoDigits));
955 assert_eq!(c23("0b"), Err(IntError::NoDigits));
956 }
957
958 #[test]
959 fn a_constant_larger_than_any_type_is_refused_rather_than_wrapped() {
960 assert_eq!(c23("340282366920938463463374607431768211456"), Err(IntError::TooLarge));
964 assert_eq!(c23("0x100000000000000000000000000000000"), Err(IntError::TooLarge));
965 assert_eq!(c23("170141183460469231731687303715884105728"), Err(IntError::TooLarge));
968 assert_eq!(kind("0x80000000000000000000000000000000", Std::C23), IntKind::UInt128);
970 assert_eq!(kind("0xffffffffffffffffffffffffffffffff", Std::C23), IntKind::UInt128);
971 }
972
973 #[test]
974 fn a_floating_constant_is_handed_back_rather_than_refused() {
975 for text in ["1.0", ".5", "1.", "1e5", "1E-5", "1e", "0x1p3", "0x1.8p+1", "1.5e3"] {
976 assert_eq!(c23(text), Err(IntError::Floating), "{text} belongs to the other path");
977 }
978 assert_eq!(c23("08e5"), Err(IntError::Floating));
981 assert_eq!(c23("0xe5").expect("hex digits").value, 0xe5);
984 assert_eq!(c23("1f"), Err(IntError::InvalidSuffix));
985 }
986
987 #[test]
988 fn the_type_comes_from_the_target_and_not_from_the_host() {
989 let windows =
992 TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().expect("a known triple"));
993 let on_windows = integer("4294967295", Std::C23, &windows).expect("a constant");
994 assert_eq!(on_windows.ty, IntConstantType::Standard(IntKind::LongLong));
995 assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
996 }
997
998 fn float(text: &str) -> Result<FloatConstant, FloatError> {
1000 floating(text, Std::C23, &linux())
1001 }
1002
1003 fn bits(text: &str) -> u128 {
1005 float(text).expect("a valid constant").value.to_bits()
1006 }
1007
1008 #[test]
1009 fn a_constant_with_no_suffix_is_a_double() {
1010 let constant = float("1.5").expect("a constant");
1011 assert_eq!(constant.ty, FloatConstantType::Double);
1012 assert!(!constant.imaginary);
1013 assert!(constant.remarks.is_none());
1014 assert_eq!(constant.value.to_bits(), 0x3ff8_0000_0000_0000);
1015 assert_eq!(bits("0.1"), 0x3fb9_9999_9999_999a);
1016 assert_eq!(bits(".5"), 0x3fe0_0000_0000_0000);
1017 assert_eq!(bits("1."), 0x3ff0_0000_0000_0000);
1018 assert_eq!(bits("1e5"), 0x40f8_6a00_0000_0000);
1019 assert_eq!(bits("0x1p3"), 0x4020_0000_0000_0000);
1020 assert_eq!(bits("08e5"), 0x4128_6a00_0000_0000);
1023 }
1024
1025 #[test]
1026 fn the_suffix_names_the_type_rather_than_narrowing_a_list() {
1027 let cases = [
1029 ("1.0", FloatConstantType::Double),
1030 ("1.0f", FloatConstantType::Float),
1031 ("1.0F", FloatConstantType::Float),
1032 ("1.0l", FloatConstantType::LongDouble),
1033 ("1.0L", FloatConstantType::LongDouble),
1034 ("1.0d", FloatConstantType::Double),
1035 ("1.0q", FloatConstantType::Float128),
1036 ("1.0w", FloatConstantType::Float80),
1037 ("1.0f16", FloatConstantType::Float16),
1038 ("1.0F16", FloatConstantType::Float16),
1039 ("1.0f32", FloatConstantType::Float32),
1040 ("1.0f64", FloatConstantType::Float64),
1041 ("1.0f128", FloatConstantType::Float128),
1042 ("1.0f32x", FloatConstantType::Float32x),
1043 ("1.0F64x", FloatConstantType::Float64x),
1044 ];
1045 for (text, ty) in cases {
1046 assert_eq!(float(text).expect("a constant").ty, ty, "{text} has the wrong type");
1047 }
1048 }
1049
1050 #[test]
1051 fn each_type_is_converted_in_the_format_the_target_has_for_it() {
1052 assert_eq!(bits("0.1f"), 0x3dcc_cccd);
1056 assert_eq!(bits("0.1f16"), 0x2e66);
1057 assert_eq!(bits("0.1f32x"), 0x3fb9_9999_9999_999a);
1058 assert_eq!(bits("0.1f64x"), 0x3ffb_cccc_cccc_cccc_cccd);
1059 assert_eq!(bits("0.1w"), 0x3ffb_cccc_cccc_cccc_cccd);
1060 assert_eq!(bits("0.1l"), 0x3ffb_cccc_cccc_cccc_cccd);
1061 assert_eq!(bits("0.1q"), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
1062 assert_eq!(bits("0.1f128"), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
1063 assert_eq!(bits("1.0l"), 0x3fff_8000_0000_0000_0000);
1064 }
1065
1066 #[test]
1067 fn the_format_comes_from_the_target_and_not_from_the_host() {
1068 let arm = floating("1.0l", Std::C23, &aarch64()).expect("a constant");
1071 assert_eq!(arm.value.to_bits(), 0x3fff_0000_0000_0000_0000_0000_0000_0000);
1072 assert_eq!(bits("1.0l"), 0x3fff_8000_0000_0000_0000);
1073 let arm_wide = floating("0.1f64x", Std::C23, &aarch64()).expect("a constant");
1075 assert_eq!(arm_wide.value.to_bits(), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
1076 let windows =
1078 TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().expect("a known triple"));
1079 let on_windows = floating("1.0l", Std::C23, &windows).expect("a constant");
1080 assert_eq!(on_windows.value.to_bits(), 0x3ff0_0000_0000_0000);
1081 }
1082
1083 #[test]
1084 fn the_case_rules_of_a_floating_suffix_are_not_uniform() {
1085 for text in ["1.0f", "1.0F", "1.0L", "1.0Q", "1.0W", "1.0F32", "1.0f64x", "1.0F64x"] {
1089 assert!(float(text).is_ok(), "{text} is a constant in gcc");
1090 }
1091 for text in ["1.0F32X", "1.0f32X", "1.0f16x", "1.0ff", "1.0fl", "1.0lf", "1.0fF", "1.0LL"] {
1092 assert_eq!(float(text), Err(FloatError::InvalidSuffix), "{text} is not");
1093 }
1094 }
1095
1096 #[test]
1097 fn an_imaginary_suffix_may_sit_on_either_side_of_the_type() {
1098 for text in ["1.0i", "1.0j", "1.0I", "1.0J", "1.0if", "1.0fi", "1.0Li", "1.0iL", "1.0f16i"]
1099 {
1100 let constant = float(text).expect("a constant in gcc");
1101 assert!(constant.imaginary, "{text} is imaginary");
1102 assert!(constant.remarks.has(Remarks::IMAGINARY));
1103 }
1104 assert_eq!(float("1.0ii"), Err(FloatError::InvalidSuffix));
1105 assert_eq!(float("1.0ij"), Err(FloatError::InvalidSuffix));
1106 assert!(!float("1.0f").expect("a constant").imaginary);
1107 }
1108
1109 #[test]
1110 fn a_decimal_floating_constant_is_recognised_and_refused() {
1111 for text in ["1.0df", "1.0dd", "1.0dl", "1.0DF", "1.0DD", "1.0DL"] {
1113 assert_eq!(float(text), Err(FloatError::DecimalFloat), "{text} is a decimal float");
1114 }
1115 for text in ["1.0Df", "1.0dF", "1.0dD", "1.0Dl"] {
1118 assert_eq!(float(text), Err(FloatError::InvalidSuffix), "{text} is neither");
1119 }
1120 let long_way = float("1.0d").expect("a GCC extension");
1122 assert_eq!(long_way.ty, FloatConstantType::Double);
1123 assert!(long_way.remarks.has(Remarks::DOUBLE_SUFFIX));
1124 }
1125
1126 #[test]
1127 fn a_type_the_target_does_not_have_is_refused_by_name() {
1128 assert_eq!(float("1.0f128x"), Err(FloatError::UnsupportedType));
1131 assert_eq!(floating("1.0w", Std::C23, &aarch64()), Err(FloatError::UnsupportedType));
1133 assert!(float("1.0w").is_ok());
1134 }
1135
1136 #[test]
1137 fn a_hexadecimal_constant_needs_an_exponent_and_a_decimal_one_does_not() {
1138 assert_eq!(float("0x1.8"), Err(FloatError::MissingExponent));
1141 assert_eq!(bits("0x1.8p0"), 0x3ff8_0000_0000_0000);
1142 assert_eq!(bits("0x.8p1"), 0x3ff0_0000_0000_0000);
1143 assert_eq!(bits("1.5"), 0x3ff8_0000_0000_0000);
1144 for text in ["1.0e", "1e+", "1e-", "0x1p", "0x1p+"] {
1145 assert_eq!(float(text), Err(FloatError::NoExponentDigits), "{text} has no exponent");
1146 }
1147 assert_eq!(float("1.2.3"), Err(FloatError::TooManyPoints));
1148 }
1149
1150 #[test]
1151 fn an_integer_constant_is_handed_back_rather_than_refused() {
1152 for text in ["1", "0", "0x10", "1u", "0777", "1wb", "0b1", "0xe5", "1f"] {
1153 assert_eq!(float(text), Err(FloatError::Integer), "{text} belongs to the other path");
1154 }
1155 }
1156
1157 #[test]
1158 fn a_value_past_the_range_of_its_type_is_still_a_constant() {
1159 let large = float("1e400").expect("a constant gcc compiles");
1160 assert!(large.value.is_infinite());
1161 assert!(large.remarks.has(Remarks::OUT_OF_RANGE));
1162 let small = float("1e-400").expect("a constant gcc compiles");
1163 assert!(small.value.is_zero());
1164 assert!(small.remarks.has(Remarks::TRUNCATED));
1165 assert!(float("1e39f").expect("a constant").remarks.has(Remarks::OUT_OF_RANGE));
1167 assert!(float("1e-46f").expect("a constant").remarks.has(Remarks::TRUNCATED));
1168 assert!(float("1e-4951l").expect("a constant").remarks.has(Remarks::TRUNCATED));
1169 let subnormal = float("1e-320").expect("a constant");
1171 assert!(!subnormal.value.is_zero());
1172 assert!(subnormal.remarks.is_none());
1173 }
1174
1175 #[test]
1176 fn the_dialect_decides_what_a_constant_is_worth_saying_about() {
1177 let old = floating("0x1p3", Std::C89, &linux()).expect("gcc compiles it anyway");
1179 assert!(old.remarks.has(Remarks::HEX_FLOAT));
1180 assert!(floating("0x1p3", Std::C99, &linux()).expect("standard").remarks.is_none());
1181 assert_eq!(bits("1'0.5"), 0x4025_0000_0000_0000);
1183 assert_eq!(bits("1.0e1'0"), 0x4202_a05f_2000_0000);
1184 assert!(float("0x1'0p0").expect("a C23 constant").remarks.is_none());
1185 let older = floating("1'0.5", Std::C17, &linux()).expect("still converted");
1186 assert!(older.remarks.has(Remarks::SEPARATORS));
1187 for text in ["1.0q", "1.0w", "1.0f16", "1.0f32x"] {
1189 let constant = floating(text, Std::C89, &linux()).expect("gcc accepts it in C89");
1190 assert!(constant.remarks.has(Remarks::EXTENDED_SUFFIX), "{text} is not standard");
1191 }
1192 assert!(float("1.0f").expect("a constant").remarks.is_none());
1193 }
1194}