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