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
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121pub enum IntError {
122 Floating,
124 InvalidSuffix,
126 InvalidOctalDigit,
128 NoDigits,
130 TooLarge,
133}
134
135impl IntError {
136 #[must_use]
141 pub const fn message(self) -> &'static str {
142 match self {
143 IntError::Floating => "not an integer constant",
144 IntError::InvalidSuffix => "invalid suffix on integer constant",
145 IntError::InvalidOctalDigit => "invalid digit in octal constant",
146 IntError::NoDigits => "no digits in integer constant",
147 IntError::TooLarge => "integer constant is too large to be represented in any type",
148 }
149 }
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub struct FloatConstant {
155 pub value: Float,
157 pub ty: FloatConstantType,
159 pub imaginary: bool,
162 pub remarks: Remarks,
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub enum FloatConstantType {
173 Float,
175 Double,
177 LongDouble,
179 Float16,
181 Float32,
183 Float64,
185 Float128,
188 Float32x,
191 Float64x,
194 Float80,
198}
199
200impl FloatConstantType {
201 #[must_use]
207 pub fn format(self, target: &TargetInfo) -> Format {
208 match self {
209 FloatConstantType::Float | FloatConstantType::Float32 => Format::Single,
210 FloatConstantType::Double
211 | FloatConstantType::Float64
212 | FloatConstantType::Float32x => Format::Double,
213 FloatConstantType::LongDouble => target.long_double_format,
214 FloatConstantType::Float16 => Format::Half,
215 FloatConstantType::Float128 => Format::Quad,
216 FloatConstantType::Float64x if target.triple.arch == Arch::X86_64 => {
217 Format::X87Extended
218 }
219 FloatConstantType::Float64x => Format::Quad,
220 FloatConstantType::Float80 => Format::X87Extended,
221 }
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq)]
230pub enum FloatError {
231 Integer,
233 InvalidSuffix,
235 MissingExponent,
239 NoExponentDigits,
241 NoDigits,
243 TooManyPoints,
245 DecimalFloat,
248 UnsupportedType,
251}
252
253impl FloatError {
254 #[must_use]
256 pub const fn message(self) -> &'static str {
257 match self {
258 FloatError::Integer => "not a floating constant",
259 FloatError::InvalidSuffix => "invalid suffix on floating constant",
260 FloatError::MissingExponent => "hexadecimal floating constants require an exponent",
261 FloatError::NoExponentDigits => "exponent has no digits",
262 FloatError::NoDigits => "no digits in floating constant",
263 FloatError::TooManyPoints => "too many decimal points in number",
264 FloatError::DecimalFloat => "decimal floating constants are not supported yet",
265 FloatError::UnsupportedType => {
266 "the type of this floating constant is not supported on this target"
267 }
268 }
269 }
270}
271
272pub fn integer(text: &str, std: Std, target: &TargetInfo) -> Result<IntConstant, IntError> {
279 let bytes = text.as_bytes();
280 let (base, start) = base_of(bytes);
281 if is_floating(bytes, base) {
282 return Err(IntError::Floating);
283 }
284 let mut remarks = Remarks::NONE;
285 if base == 2 && std < Std::C23 {
286 remarks = remarks.with(Remarks::BINARY);
287 }
288
289 let mut value: u128 = 0;
290 let mut digits = 0;
291 let mut index = start;
292 while index < bytes.len() {
293 let byte = bytes[index];
294 if byte == b'\'' {
295 if digits == 0 || index + 1 >= bytes.len() || digit(bytes[index + 1], base).is_none() {
299 return Err(IntError::InvalidSuffix);
300 }
301 if std < Std::C23 {
302 remarks = remarks.with(Remarks::SEPARATORS);
303 }
304 index += 1;
305 continue;
306 }
307 let Some(digit) = digit(byte, base) else {
308 break;
309 };
310 value = value
311 .checked_mul(u128::from(base))
312 .and_then(|shifted| shifted.checked_add(u128::from(digit)))
313 .ok_or(IntError::TooLarge)?;
314 digits += 1;
315 index += 1;
316 }
317 if digits == 0 {
318 return Err(IntError::NoDigits);
321 }
322 if base == 8 && bytes[start..index].iter().any(|&byte| byte == b'8' || byte == b'9') {
323 return Err(IntError::InvalidOctalDigit);
324 }
325
326 let suffix = suffix_of(&bytes[index..])?;
327 if suffix.length == Some(Length::LongLong) && std == Std::C89 {
328 remarks = remarks.with(Remarks::LONG_LONG);
329 }
330 if suffix.length == Some(Length::BitInt) {
331 if std < Std::C23 {
332 remarks = remarks.with(Remarks::BIT_INT);
333 }
334 return Ok(IntConstant { value, ty: bit_int(value, suffix.unsigned), remarks });
335 }
336
337 let candidates = candidates(base, suffix, std);
338 let kind = candidates
339 .iter()
340 .copied()
341 .find(|&kind| fits(value, kind, target))
342 .ok_or(IntError::TooLarge)?;
343 if base == 10 && !suffix.unsigned && !signed_standard(kind) {
344 remarks = remarks.with(Remarks::UNSIGNED);
345 }
346 Ok(IntConstant { value, ty: IntConstantType::Standard(kind), remarks })
347}
348
349fn base_of(bytes: &[u8]) -> (u32, usize) {
355 match bytes {
356 [b'0', b'x' | b'X', ..] => (16, 2),
357 [b'0', b'b' | b'B', ..] => (2, 2),
358 [b'0', next, ..] if next.is_ascii_digit() => (8, 1),
359 _ => (10, 0),
360 }
361}
362
363fn is_floating(bytes: &[u8], base: u32) -> bool {
373 let exponent = if base == 16 { *b"pP" } else { *b"eE" };
374 bytes.iter().any(|&byte| byte == b'.' || exponent.contains(&byte))
375}
376
377fn digit(byte: u8, base: u32) -> Option<u32> {
382 char::from(byte).to_digit(if base == 8 { 10 } else { base })
383}
384
385#[derive(Debug, Clone, Copy, PartialEq, Eq)]
387enum Length {
388 Long,
390 LongLong,
392 BitInt,
394}
395
396#[derive(Debug, Clone, Copy, PartialEq, Eq)]
398struct Suffix {
399 unsigned: bool,
401 length: Option<Length>,
403}
404
405fn suffix_of(mut rest: &[u8]) -> Result<Suffix, IntError> {
407 let mut suffix = Suffix { unsigned: false, length: None };
408 while let Some(&byte) = rest.first() {
409 let taken = match byte {
410 b'u' | b'U' if !suffix.unsigned => {
411 suffix.unsigned = true;
412 1
413 }
414 b'l' | b'L' if suffix.length.is_none() => {
417 if rest.get(1) == Some(&byte) {
418 suffix.length = Some(Length::LongLong);
419 2
420 } else {
421 suffix.length = Some(Length::Long);
422 1
423 }
424 }
425 b'w' | b'W' if suffix.length.is_none() => {
426 let second = if byte == b'w' { b'b' } else { b'B' };
427 if rest.get(1) != Some(&second) {
428 return Err(IntError::InvalidSuffix);
429 }
430 suffix.length = Some(Length::BitInt);
431 2
432 }
433 _ => return Err(IntError::InvalidSuffix),
434 };
435 rest = &rest[taken..];
436 }
437 Ok(suffix)
438}
439
440fn bit_int(value: u128, unsigned: bool) -> IntConstantType {
446 let used = 128 - value.leading_zeros();
447 let width = if unsigned { used.max(1) } else { used + 1 };
448 IntConstantType::BitInt { signed: !unsigned, width: width.max(if unsigned { 1 } else { 2 }) }
449}
450
451fn signed_standard(kind: IntKind) -> bool {
454 matches!(kind, IntKind::Int | IntKind::Long | IntKind::LongLong)
455}
456
457fn fits(value: u128, kind: IntKind, target: &TargetInfo) -> bool {
459 let width = int_width(kind, target);
460 let bits = if kind.is_signed(false) { width - 1 } else { width };
463 bits >= 128 || value >> bits == 0
466}
467
468fn candidates(base: u32, suffix: Suffix, std: Std) -> &'static [IntKind] {
475 use IntKind::{Int, Int128, Long, LongLong, UInt, UInt128, ULong, ULongLong};
476
477 let decimal = base == 10;
478 let c89 = std == Std::C89;
479 match (suffix.unsigned, suffix.length) {
480 (false, None) if decimal && c89 => &[Int, Long, ULong, Int128, UInt128],
481 (false, None) if decimal => &[Int, Long, LongLong, Int128],
482 (false, None) if c89 => &[Int, UInt, Long, ULong, Int128, UInt128],
483 (false, None) => &[Int, UInt, Long, ULong, LongLong, ULongLong, Int128, UInt128],
484
485 (true, None) if c89 => &[UInt, ULong, UInt128],
486 (true, None) => &[UInt, ULong, ULongLong, UInt128],
487
488 (false, Some(Length::Long)) if decimal && c89 => &[Long, ULong, Int128, UInt128],
489 (false, Some(Length::Long)) if decimal => &[Long, LongLong, Int128],
490 (false, Some(Length::Long)) if c89 => &[Long, ULong, Int128, UInt128],
491 (false, Some(Length::Long)) => &[Long, ULong, LongLong, ULongLong, Int128, UInt128],
492
493 (true, Some(Length::Long)) if c89 => &[ULong, UInt128],
494 (true, Some(Length::Long)) => &[ULong, ULongLong, UInt128],
495
496 (false, Some(Length::LongLong)) if decimal => &[LongLong, Int128],
497 (false, Some(Length::LongLong)) => &[LongLong, ULongLong, Int128, UInt128],
498 (true, Some(Length::LongLong)) => &[ULongLong, UInt128],
499
500 (_, Some(Length::BitInt)) => &[],
502 }
503}
504
505pub fn floating(text: &str, std: Std, target: &TargetInfo) -> Result<FloatConstant, FloatError> {
512 let bytes = text.as_bytes();
513 let (base, _) = base_of(bytes);
514 if !is_floating(bytes, base) {
515 return Err(FloatError::Integer);
516 }
517 let hex = base == 16;
520 let base = if hex { 16 } else { 10 };
521 let mut remarks = Remarks::NONE;
522 if hex && std < Std::C99 {
523 remarks = remarks.with(Remarks::HEX_FLOAT);
524 }
525
526 let mut index = if hex { 2 } else { 0 };
527 let mut digits = 0;
528 let mut point = false;
529 let mut separators = false;
530 while index < bytes.len() {
531 let byte = bytes[index];
532 if byte == b'\'' {
533 if digits == 0 || !next_is_digit(bytes, index, base) {
534 return Err(FloatError::InvalidSuffix);
535 }
536 separators = true;
537 } else if byte == b'.' {
538 if point {
539 return Err(FloatError::TooManyPoints);
540 }
541 point = true;
542 } else if digit(byte, base).is_some() {
543 digits += 1;
544 } else {
545 break;
546 }
547 index += 1;
548 }
549 if digits == 0 {
550 return Err(FloatError::NoDigits);
551 }
552
553 let marker = if hex { *b"pP" } else { *b"eE" };
554 if index < bytes.len() && marker.contains(&bytes[index]) {
555 index += 1;
556 if matches!(bytes.get(index), Some(b'+' | b'-')) {
557 index += 1;
558 }
559 let mut exponent_digits = 0;
560 while index < bytes.len() {
561 let byte = bytes[index];
562 if byte == b'\'' {
563 if exponent_digits == 0 || !next_is_digit(bytes, index, 10) {
564 return Err(FloatError::InvalidSuffix);
565 }
566 separators = true;
567 } else if byte.is_ascii_digit() {
568 exponent_digits += 1;
569 } else {
570 break;
571 }
572 index += 1;
573 }
574 if exponent_digits == 0 {
575 return Err(FloatError::NoExponentDigits);
576 }
577 } else if hex {
578 return Err(FloatError::MissingExponent);
581 }
582 if separators && std < Std::C23 {
583 remarks = remarks.with(Remarks::SEPARATORS);
584 }
585
586 let suffix = float_suffix(&bytes[index..], target)?;
587 remarks = remarks.with(suffix.remarks);
588 let (value, status) =
589 Float::parse(&text[..index], suffix.ty.format(target)).map_err(|error| match error {
590 ParseError::NoDigits => FloatError::NoDigits,
593 ParseError::NoExponentDigits => FloatError::NoExponentDigits,
594 ParseError::Invalid => FloatError::InvalidSuffix,
595 })?;
596 if status.has(Status::OVERFLOW) {
597 remarks = remarks.with(Remarks::OUT_OF_RANGE);
598 }
599 if status.has(Status::UNDERFLOW) && value.is_zero() {
602 remarks = remarks.with(Remarks::TRUNCATED);
603 }
604 Ok(FloatConstant { value, ty: suffix.ty, imaginary: suffix.imaginary, remarks })
605}
606
607fn next_is_digit(bytes: &[u8], index: usize, base: u32) -> bool {
609 bytes.get(index + 1).is_some_and(|&next| digit(next, base).is_some())
610}
611
612struct FloatSuffix {
614 ty: FloatConstantType,
616 imaginary: bool,
618 remarks: Remarks,
620}
621
622fn float_suffix(mut rest: &[u8], target: &TargetInfo) -> Result<FloatSuffix, FloatError> {
629 let mut ty = None;
630 let mut imaginary = false;
631 let mut remarks = Remarks::NONE;
632 while let Some(&byte) = rest.first() {
633 let taken = match byte {
634 b'i' | b'j' | b'I' | b'J' if !imaginary => {
635 imaginary = true;
636 remarks = remarks.with(Remarks::IMAGINARY);
637 1
638 }
639 _ if ty.is_some() => return Err(FloatError::InvalidSuffix),
641 b'f' | b'F' => {
642 let (named, taken, extra) = float_n(rest)?;
643 ty = Some(named);
644 remarks = remarks.with(extra);
645 taken
646 }
647 b'l' | b'L' => {
648 ty = Some(FloatConstantType::LongDouble);
649 1
650 }
651 b'q' | b'Q' => {
652 ty = Some(FloatConstantType::Float128);
653 remarks = remarks.with(Remarks::EXTENDED_SUFFIX);
654 1
655 }
656 b'w' | b'W' => {
657 if target.triple.arch != Arch::X86_64 {
659 return Err(FloatError::UnsupportedType);
660 }
661 ty = Some(FloatConstantType::Float80);
662 remarks = remarks.with(Remarks::EXTENDED_SUFFIX);
663 1
664 }
665 b'd' | b'D' => {
666 let second = rest.get(1).copied();
667 let decimal = if byte == b'd' {
668 matches!(second, Some(b'f' | b'd' | b'l'))
669 } else {
670 matches!(second, Some(b'F' | b'D' | b'L'))
671 };
672 if decimal {
673 return Err(FloatError::DecimalFloat);
674 }
675 ty = Some(FloatConstantType::Double);
676 remarks = remarks.with(Remarks::DOUBLE_SUFFIX);
677 1
678 }
679 _ => return Err(FloatError::InvalidSuffix),
680 };
681 rest = &rest[taken..];
682 }
683 Ok(FloatSuffix { ty: ty.unwrap_or(FloatConstantType::Double), imaginary, remarks })
684}
685
686fn float_n(rest: &[u8]) -> Result<(FloatConstantType, usize, Remarks), FloatError> {
691 let mut end = 1;
692 while rest.get(end).is_some_and(u8::is_ascii_digit) {
693 end += 1;
694 }
695 if end == 1 {
696 return Ok((FloatConstantType::Float, 1, Remarks::NONE));
697 }
698 let extended = rest.get(end) == Some(&b'x');
701 let ty = match (&rest[1..end], extended) {
702 (b"16", false) => FloatConstantType::Float16,
703 (b"32", false) => FloatConstantType::Float32,
704 (b"64", false) => FloatConstantType::Float64,
705 (b"128", false) => FloatConstantType::Float128,
706 (b"32", true) => FloatConstantType::Float32x,
707 (b"64", true) => FloatConstantType::Float64x,
708 (b"128", true) => return Err(FloatError::UnsupportedType),
711 _ => return Err(FloatError::InvalidSuffix),
712 };
713 Ok((ty, end + usize::from(extended), Remarks::EXTENDED_SUFFIX))
714}
715
716#[cfg(test)]
717mod tests {
718 use rucc_target::Triple;
719
720 use super::*;
721
722 fn linux() -> TargetInfo {
723 TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a known triple"))
724 }
725
726 fn aarch64() -> TargetInfo {
727 TargetInfo::new("aarch64-unknown-linux-gnu".parse::<Triple>().expect("a known triple"))
728 }
729
730 fn c23(text: &str) -> Result<IntConstant, IntError> {
732 integer(text, Std::C23, &linux())
733 }
734
735 fn kind(text: &str, std: Std) -> IntKind {
737 match integer(text, std, &linux()).expect("a valid constant").ty {
738 IntConstantType::Standard(kind) => kind,
739 IntConstantType::BitInt { .. } => panic!("{text} is a _BitInt constant"),
740 }
741 }
742
743 #[test]
744 fn a_constant_in_each_base_has_the_value_it_says() {
745 assert_eq!(c23("0").expect("zero").value, 0);
746 assert_eq!(c23("42").expect("decimal").value, 42);
747 assert_eq!(c23("0777").expect("octal").value, 0o777);
748 assert_eq!(c23("0xdeadBEEF").expect("hex").value, 0xdead_beef);
749 assert_eq!(c23("0b1010").expect("binary").value, 0b1010);
750 assert_eq!(c23("0X10").expect("upper case prefix").value, 16);
751 assert_eq!(c23("0u").expect("zero with a suffix").value, 0);
754 }
755
756 #[test]
757 fn digit_separators_are_stripped_and_reported_before_c23() {
758 let value = c23("1'000'000").expect("a C23 constant");
759 assert_eq!(value.value, 1_000_000);
760 assert!(value.remarks.is_none());
761 assert_eq!(c23("0x1'0").expect("hex with a separator").value, 16);
762
763 let older = integer("1'000", Std::C17, &linux()).expect("still converted");
764 assert!(older.remarks.has(Remarks::SEPARATORS));
765 assert_eq!(older.value, 1000);
766 }
767
768 #[test]
769 fn the_type_of_a_decimal_constant_walks_the_signed_types_only() {
770 assert_eq!(kind("2147483647", Std::C23), IntKind::Int);
772 assert_eq!(kind("2147483648", Std::C23), IntKind::Long);
773 assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
774 assert_eq!(kind("9223372036854775807", Std::C23), IntKind::Long);
775 assert_eq!(kind("9223372036854775808", Std::C23), IntKind::Int128);
778 assert_eq!(kind("18446744073709551615", Std::C23), IntKind::Int128);
779 let large = c23("18446744073709551615").expect("fits __int128");
780 assert!(large.remarks.has(Remarks::UNSIGNED));
781 }
782
783 #[test]
784 fn a_constant_in_another_base_may_be_unsigned_without_saying_so() {
785 assert_eq!(kind("0xffffffff", Std::C23), IntKind::UInt);
788 assert_eq!(kind("0x7fffffff", Std::C23), IntKind::Int);
789 assert_eq!(kind("0x80000000", Std::C23), IntKind::UInt);
790 assert_eq!(kind("0x100000000", Std::C23), IntKind::Long);
791 assert_eq!(kind("0xffffffffffffffff", Std::C23), IntKind::ULong);
792 assert_eq!(kind("0777", Std::C23), IntKind::Int);
793 assert_eq!(kind("0b1010", Std::C23), IntKind::Int);
794 assert!(c23("0xffffffff").expect("a constant").remarks.is_none());
796 }
797
798 #[test]
799 fn c89_has_unsigned_long_in_the_decimal_list_and_no_long_long_in_any() {
800 assert_eq!(kind("18446744073709551615", Std::C89), IntKind::ULong);
803 assert_eq!(kind("18446744073709551615", Std::C99), IntKind::Int128);
804 let old = integer("18446744073709551615", Std::C89, &linux()).expect("a C89 constant");
805 assert!(old.remarks.has(Remarks::UNSIGNED));
806 let long_long = integer("1ll", Std::C89, &linux()).expect("an extension");
808 assert!(long_long.remarks.has(Remarks::LONG_LONG));
809 assert_eq!(kind("1ll", Std::C89), IntKind::LongLong);
810 assert!(integer("1ll", Std::C99, &linux()).expect("standard").remarks.is_none());
811 }
812
813 #[test]
814 fn a_suffix_narrows_the_list_it_does_not_pick_the_type() {
815 assert_eq!(kind("1u", Std::C23), IntKind::UInt);
816 assert_eq!(kind("1l", Std::C23), IntKind::Long);
817 assert_eq!(kind("1ul", Std::C23), IntKind::ULong);
818 assert_eq!(kind("1ll", Std::C23), IntKind::LongLong);
819 assert_eq!(kind("1llu", Std::C23), IntKind::ULongLong);
820 assert_eq!(kind("4294967296u", Std::C23), IntKind::ULong);
823 assert_eq!(kind("0xffffffffu", Std::C23), IntKind::UInt);
824 }
825
826 #[test]
827 fn the_letters_of_a_suffix_may_be_in_either_case_but_not_both() {
828 for text in ["1u", "1U", "1l", "1L", "1ll", "1LL", "1ul", "1lu", "1uL", "1LLU", "1llu"] {
829 assert!(c23(text).is_ok(), "{text} is a constant in both compilers");
830 }
831 for text in ["1lL", "1Ll", "1uu", "1lul", "1z", "1uz", "1f", "1x", "1_000"] {
832 assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
833 }
834 }
835
836 #[test]
837 fn a_bit_int_constant_has_the_narrowest_type_that_holds_it() {
838 let cases = [
840 ("0wb", true, 2),
841 ("1wb", true, 2),
842 ("3wb", true, 3),
843 ("42wb", true, 7),
844 ("255wb", true, 9),
845 ("0uwb", false, 1),
846 ("1uwb", false, 1),
847 ("255uwb", false, 8),
848 ("256uwb", false, 9),
849 ("0xffffffffffffffffuwb", false, 64),
850 ];
851 for (text, signed, width) in cases {
852 let constant = c23(text).expect("a _BitInt constant");
853 assert_eq!(
854 constant.ty,
855 IntConstantType::BitInt { signed, width },
856 "{text} is the wrong width"
857 );
858 }
859 for text in ["1uwb", "1wbu", "1UWB", "1WBu", "1uWB"] {
861 assert!(c23(text).is_ok(), "{text} is a constant in clang");
862 }
863 for text in ["1wB", "1Wb", "1lwb", "1wbl", "1wbwb"] {
864 assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
865 }
866 let older = integer("1wb", Std::C17, &linux()).expect("clang accepts it everywhere");
868 assert!(older.remarks.has(Remarks::BIT_INT));
869 }
870
871 #[test]
872 fn a_binary_constant_is_an_extension_before_c23() {
873 assert!(c23("0b1").expect("standard in C23").remarks.is_none());
874 let older = integer("0b1", Std::C17, &linux()).expect("both compilers accept it");
875 assert!(older.remarks.has(Remarks::BINARY));
876 }
877
878 #[test]
879 fn an_octal_constant_names_the_digit_that_is_not_one() {
880 assert_eq!(c23("08"), Err(IntError::InvalidOctalDigit));
881 assert_eq!(c23("0778"), Err(IntError::InvalidOctalDigit));
882 assert_eq!(c23("09"), Err(IntError::InvalidOctalDigit));
883 assert_eq!(c23("9").expect("decimal").value, 9);
885 }
886
887 #[test]
888 fn a_prefix_with_no_digits_after_it_is_not_a_constant() {
889 assert_eq!(c23("0x"), Err(IntError::NoDigits));
890 assert_eq!(c23("0b"), Err(IntError::NoDigits));
891 }
892
893 #[test]
894 fn a_constant_larger_than_any_type_is_refused_rather_than_wrapped() {
895 assert_eq!(c23("340282366920938463463374607431768211456"), Err(IntError::TooLarge));
899 assert_eq!(c23("0x100000000000000000000000000000000"), Err(IntError::TooLarge));
900 assert_eq!(c23("170141183460469231731687303715884105728"), Err(IntError::TooLarge));
903 assert_eq!(kind("0x80000000000000000000000000000000", Std::C23), IntKind::UInt128);
905 assert_eq!(kind("0xffffffffffffffffffffffffffffffff", Std::C23), IntKind::UInt128);
906 }
907
908 #[test]
909 fn a_floating_constant_is_handed_back_rather_than_refused() {
910 for text in ["1.0", ".5", "1.", "1e5", "1E-5", "1e", "0x1p3", "0x1.8p+1", "1.5e3"] {
911 assert_eq!(c23(text), Err(IntError::Floating), "{text} belongs to the other path");
912 }
913 assert_eq!(c23("08e5"), Err(IntError::Floating));
916 assert_eq!(c23("0xe5").expect("hex digits").value, 0xe5);
919 assert_eq!(c23("1f"), Err(IntError::InvalidSuffix));
920 }
921
922 #[test]
923 fn the_type_comes_from_the_target_and_not_from_the_host() {
924 let windows =
927 TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().expect("a known triple"));
928 let on_windows = integer("4294967295", Std::C23, &windows).expect("a constant");
929 assert_eq!(on_windows.ty, IntConstantType::Standard(IntKind::LongLong));
930 assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
931 }
932
933 fn float(text: &str) -> Result<FloatConstant, FloatError> {
935 floating(text, Std::C23, &linux())
936 }
937
938 fn bits(text: &str) -> u128 {
940 float(text).expect("a valid constant").value.to_bits()
941 }
942
943 #[test]
944 fn a_constant_with_no_suffix_is_a_double() {
945 let constant = float("1.5").expect("a constant");
946 assert_eq!(constant.ty, FloatConstantType::Double);
947 assert!(!constant.imaginary);
948 assert!(constant.remarks.is_none());
949 assert_eq!(constant.value.to_bits(), 0x3ff8_0000_0000_0000);
950 assert_eq!(bits("0.1"), 0x3fb9_9999_9999_999a);
951 assert_eq!(bits(".5"), 0x3fe0_0000_0000_0000);
952 assert_eq!(bits("1."), 0x3ff0_0000_0000_0000);
953 assert_eq!(bits("1e5"), 0x40f8_6a00_0000_0000);
954 assert_eq!(bits("0x1p3"), 0x4020_0000_0000_0000);
955 assert_eq!(bits("08e5"), 0x4128_6a00_0000_0000);
958 }
959
960 #[test]
961 fn the_suffix_names_the_type_rather_than_narrowing_a_list() {
962 let cases = [
964 ("1.0", FloatConstantType::Double),
965 ("1.0f", FloatConstantType::Float),
966 ("1.0F", FloatConstantType::Float),
967 ("1.0l", FloatConstantType::LongDouble),
968 ("1.0L", FloatConstantType::LongDouble),
969 ("1.0d", FloatConstantType::Double),
970 ("1.0q", FloatConstantType::Float128),
971 ("1.0w", FloatConstantType::Float80),
972 ("1.0f16", FloatConstantType::Float16),
973 ("1.0F16", FloatConstantType::Float16),
974 ("1.0f32", FloatConstantType::Float32),
975 ("1.0f64", FloatConstantType::Float64),
976 ("1.0f128", FloatConstantType::Float128),
977 ("1.0f32x", FloatConstantType::Float32x),
978 ("1.0F64x", FloatConstantType::Float64x),
979 ];
980 for (text, ty) in cases {
981 assert_eq!(float(text).expect("a constant").ty, ty, "{text} has the wrong type");
982 }
983 }
984
985 #[test]
986 fn each_type_is_converted_in_the_format_the_target_has_for_it() {
987 assert_eq!(bits("0.1f"), 0x3dcc_cccd);
991 assert_eq!(bits("0.1f16"), 0x2e66);
992 assert_eq!(bits("0.1f32x"), 0x3fb9_9999_9999_999a);
993 assert_eq!(bits("0.1f64x"), 0x3ffb_cccc_cccc_cccc_cccd);
994 assert_eq!(bits("0.1w"), 0x3ffb_cccc_cccc_cccc_cccd);
995 assert_eq!(bits("0.1l"), 0x3ffb_cccc_cccc_cccc_cccd);
996 assert_eq!(bits("0.1q"), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
997 assert_eq!(bits("0.1f128"), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
998 assert_eq!(bits("1.0l"), 0x3fff_8000_0000_0000_0000);
999 }
1000
1001 #[test]
1002 fn the_format_comes_from_the_target_and_not_from_the_host() {
1003 let arm = floating("1.0l", Std::C23, &aarch64()).expect("a constant");
1006 assert_eq!(arm.value.to_bits(), 0x3fff_0000_0000_0000_0000_0000_0000_0000);
1007 assert_eq!(bits("1.0l"), 0x3fff_8000_0000_0000_0000);
1008 let arm_wide = floating("0.1f64x", Std::C23, &aarch64()).expect("a constant");
1010 assert_eq!(arm_wide.value.to_bits(), 0x3ffb_9999_9999_9999_9999_9999_9999_999a);
1011 let windows =
1013 TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().expect("a known triple"));
1014 let on_windows = floating("1.0l", Std::C23, &windows).expect("a constant");
1015 assert_eq!(on_windows.value.to_bits(), 0x3ff0_0000_0000_0000);
1016 }
1017
1018 #[test]
1019 fn the_case_rules_of_a_floating_suffix_are_not_uniform() {
1020 for text in ["1.0f", "1.0F", "1.0L", "1.0Q", "1.0W", "1.0F32", "1.0f64x", "1.0F64x"] {
1024 assert!(float(text).is_ok(), "{text} is a constant in gcc");
1025 }
1026 for text in ["1.0F32X", "1.0f32X", "1.0f16x", "1.0ff", "1.0fl", "1.0lf", "1.0fF", "1.0LL"] {
1027 assert_eq!(float(text), Err(FloatError::InvalidSuffix), "{text} is not");
1028 }
1029 }
1030
1031 #[test]
1032 fn an_imaginary_suffix_may_sit_on_either_side_of_the_type() {
1033 for text in ["1.0i", "1.0j", "1.0I", "1.0J", "1.0if", "1.0fi", "1.0Li", "1.0iL", "1.0f16i"]
1034 {
1035 let constant = float(text).expect("a constant in gcc");
1036 assert!(constant.imaginary, "{text} is imaginary");
1037 assert!(constant.remarks.has(Remarks::IMAGINARY));
1038 }
1039 assert_eq!(float("1.0ii"), Err(FloatError::InvalidSuffix));
1040 assert_eq!(float("1.0ij"), Err(FloatError::InvalidSuffix));
1041 assert!(!float("1.0f").expect("a constant").imaginary);
1042 }
1043
1044 #[test]
1045 fn a_decimal_floating_constant_is_recognised_and_refused() {
1046 for text in ["1.0df", "1.0dd", "1.0dl", "1.0DF", "1.0DD", "1.0DL"] {
1048 assert_eq!(float(text), Err(FloatError::DecimalFloat), "{text} is a decimal float");
1049 }
1050 for text in ["1.0Df", "1.0dF", "1.0dD", "1.0Dl"] {
1053 assert_eq!(float(text), Err(FloatError::InvalidSuffix), "{text} is neither");
1054 }
1055 let long_way = float("1.0d").expect("a GCC extension");
1057 assert_eq!(long_way.ty, FloatConstantType::Double);
1058 assert!(long_way.remarks.has(Remarks::DOUBLE_SUFFIX));
1059 }
1060
1061 #[test]
1062 fn a_type_the_target_does_not_have_is_refused_by_name() {
1063 assert_eq!(float("1.0f128x"), Err(FloatError::UnsupportedType));
1066 assert_eq!(floating("1.0w", Std::C23, &aarch64()), Err(FloatError::UnsupportedType));
1068 assert!(float("1.0w").is_ok());
1069 }
1070
1071 #[test]
1072 fn a_hexadecimal_constant_needs_an_exponent_and_a_decimal_one_does_not() {
1073 assert_eq!(float("0x1.8"), Err(FloatError::MissingExponent));
1076 assert_eq!(bits("0x1.8p0"), 0x3ff8_0000_0000_0000);
1077 assert_eq!(bits("0x.8p1"), 0x3ff0_0000_0000_0000);
1078 assert_eq!(bits("1.5"), 0x3ff8_0000_0000_0000);
1079 for text in ["1.0e", "1e+", "1e-", "0x1p", "0x1p+"] {
1080 assert_eq!(float(text), Err(FloatError::NoExponentDigits), "{text} has no exponent");
1081 }
1082 assert_eq!(float("1.2.3"), Err(FloatError::TooManyPoints));
1083 }
1084
1085 #[test]
1086 fn an_integer_constant_is_handed_back_rather_than_refused() {
1087 for text in ["1", "0", "0x10", "1u", "0777", "1wb", "0b1", "0xe5", "1f"] {
1088 assert_eq!(float(text), Err(FloatError::Integer), "{text} belongs to the other path");
1089 }
1090 }
1091
1092 #[test]
1093 fn a_value_past_the_range_of_its_type_is_still_a_constant() {
1094 let large = float("1e400").expect("a constant gcc compiles");
1095 assert!(large.value.is_infinite());
1096 assert!(large.remarks.has(Remarks::OUT_OF_RANGE));
1097 let small = float("1e-400").expect("a constant gcc compiles");
1098 assert!(small.value.is_zero());
1099 assert!(small.remarks.has(Remarks::TRUNCATED));
1100 assert!(float("1e39f").expect("a constant").remarks.has(Remarks::OUT_OF_RANGE));
1102 assert!(float("1e-46f").expect("a constant").remarks.has(Remarks::TRUNCATED));
1103 assert!(float("1e-4951l").expect("a constant").remarks.has(Remarks::TRUNCATED));
1104 let subnormal = float("1e-320").expect("a constant");
1106 assert!(!subnormal.value.is_zero());
1107 assert!(subnormal.remarks.is_none());
1108 }
1109
1110 #[test]
1111 fn the_dialect_decides_what_a_constant_is_worth_saying_about() {
1112 let old = floating("0x1p3", Std::C89, &linux()).expect("gcc compiles it anyway");
1114 assert!(old.remarks.has(Remarks::HEX_FLOAT));
1115 assert!(floating("0x1p3", Std::C99, &linux()).expect("standard").remarks.is_none());
1116 assert_eq!(bits("1'0.5"), 0x4025_0000_0000_0000);
1118 assert_eq!(bits("1.0e1'0"), 0x4202_a05f_2000_0000);
1119 assert!(float("0x1'0p0").expect("a C23 constant").remarks.is_none());
1120 let older = floating("1'0.5", Std::C17, &linux()).expect("still converted");
1121 assert!(older.remarks.has(Remarks::SEPARATORS));
1122 for text in ["1.0q", "1.0w", "1.0f16", "1.0f32x"] {
1124 let constant = floating(text, Std::C89, &linux()).expect("gcc accepts it in C89");
1125 assert!(constant.remarks.has(Remarks::EXTENDED_SUFFIX), "{text} is not standard");
1126 }
1127 assert!(float("1.0f").expect("a constant").remarks.is_none());
1128 }
1129}