Skip to main content

rucc_lex/
number.rs

1//! Integer constants: the value, and the type the standard's table walk gives it.
2//!
3//! Design: `spec/06-lexer-and-parser.md` section 6.1.
4//!
5//! This is the second piece of phase 7. A preprocessing number is a loose thing, deliberately
6//! looser than a constant, so `1.2.3` and `0x1p+3` are both one pp-token and only here does
7//! anyone ask what they mean. What comes back is a value and a type, and both of them are
8//! places a compiler quietly goes wrong.
9//!
10//! The value is accumulated in a `u128` with every step checked, so a constant too large to
11//! represent is a diagnostic rather than a number the program did not write. gcc 13.3 does not
12//! do that: its accumulator is sixty four bits, and `18446744073709551616` compiles to zero of
13//! type `int` after a warning nobody reads. That is not a behaviour worth reproducing, so ours
14//! is the only measured difference here that is deliberate: past a hundred and twenty eight
15//! bits the constant is refused. clang refuses it too, one bit earlier.
16//!
17//! The type is the standard's table walk, 6.4.4.1p5: a candidate list chosen by the base and
18//! the suffix, walked in order, and the first type that holds the value wins. The list is not
19//! the same in every dialect. C89 puts `unsigned long` in the list for a decimal constant with
20//! no suffix, which is what makes `18446744073709551615` an `unsigned long` under `-std=c89`
21//! and something wider under `-std=c99`, and gcc says so in as many words: "this decimal
22//! constant is unsigned only in ISO C90". Both compilers keep `long long` out of the C89 lists
23//! and accept it when the suffix asks for it.
24//!
25//! `__int128` is on the end of every list, which is what gcc does and clang does not.
26//! `9223372036854775808` is an `__int128` in gcc 13.3 and an `unsigned long long` in clang,
27//! and the difference is visible to a program: negate it and gcc gives a negative number.
28//! We follow gcc, because the alternative silently turns a signed constant unsigned.
29//!
30//! The rest was measured the same way, by writing the constant and asking `_Generic` what it
31//! is, on gcc 13.3 on x86-64 Linux and on clang:
32//!
33//! The suffix letters may be in either case but not both, so `1ll` and `1LL` are constants and
34//! `1lL` is not, and the same rule holds for `wb`. The unsigned suffix may come before or after
35//! the length suffix. `wb` does not combine with `l` at all.
36//!
37//! Binary constants are accepted in every dialect by both compilers, as an extension before
38//! C23. Digit separators are C23 only in both. `_BitInt` constants are C23 in the standard,
39//! clang accepts them in every dialect, and gcc 13.3 has no `_BitInt` at all.
40//!
41//! A `wb` constant has the narrowest type that holds it, which for a signed one includes the
42//! sign bit and is never less than two: `1wb` is `_BitInt(2)`, `42wb` is `_BitInt(7)`, `255uwb`
43//! is `unsigned _BitInt(8)` and `0uwb` is `unsigned _BitInt(1)`. Measured against clang, since
44//! gcc 13.3 cannot say.
45
46use rucc_session::Std;
47use rucc_target::TargetInfo;
48use rucc_types::{IntKind, int_width};
49
50/// A converted integer constant.
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub struct IntConstant {
53    /// The value, which is never negative: a minus sign is an operator and not part of the
54    /// constant, which is why `-2147483648` is a `long` on a 32-bit `int` and the reason
55    /// `INT_MIN` is spelled the way it is in `limits.h`.
56    pub value: u128,
57    /// The type the table walk arrived at.
58    pub ty: IntConstantType,
59    /// What is worth saying about the constant, for the caller that holds the span.
60    pub remarks: Remarks,
61}
62
63/// The type of an integer constant.
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum IntConstantType {
66    /// One of the integer kinds, chosen by the table walk.
67    Standard(IntKind),
68    /// A `_BitInt` of exactly the width it takes to hold the value.
69    BitInt {
70        /// Whether the `u` suffix was there.
71        signed: bool,
72        /// The width in bits, including the sign bit when there is one.
73        width: u32,
74    },
75}
76
77/// Why a preprocessing number is not an integer constant.
78///
79/// [`IntError::Floating`] is not a diagnostic. It means the spelling belongs to the floating
80/// path, and it is an error here so that the caller cannot forget to ask.
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum IntError {
83    /// This is a floating constant. Nothing is wrong with it.
84    Floating,
85    /// The characters after the digits are not a suffix.
86    InvalidSuffix,
87    /// An `8` or a `9` in a constant that started with `0`.
88    InvalidOctalDigit,
89    /// `0x` or `0b` with no digits after it.
90    NoDigits,
91    /// Larger than any integer type, or than the hundred and twenty eight bits the value is
92    /// accumulated in.
93    TooLarge,
94}
95
96impl IntError {
97    /// What to print, in GCC's words where GCC has any.
98    ///
99    /// The offending character is not in the message, because the caller has the spelling and
100    /// the span and can say `invalid suffix "ux" on integer constant` the way GCC does.
101    #[must_use]
102    pub const fn message(self) -> &'static str {
103        match self {
104            IntError::Floating => "not an integer constant",
105            IntError::InvalidSuffix => "invalid suffix on integer constant",
106            IntError::InvalidOctalDigit => "invalid digit in octal constant",
107            IntError::NoDigits => "no digits in integer constant",
108            IntError::TooLarge => "integer constant is too large to be represented in any type",
109        }
110    }
111}
112
113/// What a constant does that the dialect being compiled has an opinion about.
114///
115/// A bitmask rather than a list, because a constant may earn several and a `Vec` per constant
116/// on a file full of them is a cost with nothing to show for it. Every one of these is legal
117/// in the dialect this compiler defaults to, so none of them is an error here: the caller
118/// decides what `-pedantic` and `-Werror` make of them.
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
120pub struct Remarks(u8);
121
122impl Remarks {
123    /// Nothing to say.
124    pub const NONE: Remarks = Remarks(0);
125    /// A `0b` constant before C23, where it is a GNU extension both compilers accept.
126    pub const BINARY: Remarks = Remarks(1);
127    /// A digit separator before C23, which neither compiler accepts there.
128    pub const SEPARATORS: Remarks = Remarks(2);
129    /// A `wb` suffix before C23.
130    pub const BIT_INT: Remarks = Remarks(4);
131    /// An `ll` suffix under `-std=c89`, where GCC says "use of C99 long long integer constant".
132    pub const LONG_LONG: Remarks = Remarks(8);
133    /// A decimal constant with no `u` suffix that fits no signed type, so it became an unsigned
134    /// one. GCC says "integer constant is so large that it is unsigned", and it is worth saying
135    /// because the constant's arithmetic is now unsigned and its negation is not negative.
136    pub const UNSIGNED: Remarks = Remarks(16);
137
138    /// Whether every remark in `other` is set here.
139    #[inline]
140    #[must_use]
141    pub const fn has(self, other: Remarks) -> bool {
142        self.0 & other.0 == other.0
143    }
144
145    /// This set with `other` added.
146    #[inline]
147    #[must_use]
148    pub const fn with(self, other: Remarks) -> Remarks {
149        Remarks(self.0 | other.0)
150    }
151
152    /// Whether there is nothing to say.
153    #[inline]
154    #[must_use]
155    pub const fn is_none(self) -> bool {
156        self.0 == 0
157    }
158}
159
160/// Converts the spelling of a preprocessing number into an integer constant.
161///
162/// # Errors
163///
164/// [`IntError`], one case of which is that the spelling is a floating constant rather than a
165/// malformed integer one.
166pub fn integer(text: &str, std: Std, target: &TargetInfo) -> Result<IntConstant, IntError> {
167    let bytes = text.as_bytes();
168    let (base, start) = base_of(bytes);
169    if floating(bytes, base) {
170        return Err(IntError::Floating);
171    }
172    let mut remarks = Remarks::NONE;
173    if base == 2 && std < Std::C23 {
174        remarks = remarks.with(Remarks::BINARY);
175    }
176
177    let mut value: u128 = 0;
178    let mut digits = 0;
179    let mut index = start;
180    while index < bytes.len() {
181        let byte = bytes[index];
182        if byte == b'\'' {
183            // A separator is only a separator between two digits. The scanner keeps one in the
184            // number only when an identifier character follows, so a trailing one arrives here
185            // as a suffix instead and is refused as one.
186            if digits == 0 || index + 1 >= bytes.len() || digit(bytes[index + 1], base).is_none() {
187                return Err(IntError::InvalidSuffix);
188            }
189            if std < Std::C23 {
190                remarks = remarks.with(Remarks::SEPARATORS);
191            }
192            index += 1;
193            continue;
194        }
195        let Some(digit) = digit(byte, base) else {
196            break;
197        };
198        value = value
199            .checked_mul(u128::from(base))
200            .and_then(|shifted| shifted.checked_add(u128::from(digit)))
201            .ok_or(IntError::TooLarge)?;
202        digits += 1;
203        index += 1;
204    }
205    if digits == 0 {
206        // `0x` with nothing after it, which GCC reports as an invalid suffix because it read
207        // the `0` as the constant. The distinction is not worth a worse message than this.
208        return Err(IntError::NoDigits);
209    }
210    if base == 8 && bytes[start..index].iter().any(|&byte| byte == b'8' || byte == b'9') {
211        return Err(IntError::InvalidOctalDigit);
212    }
213
214    let suffix = suffix_of(&bytes[index..])?;
215    if suffix.length == Some(Length::LongLong) && std == Std::C89 {
216        remarks = remarks.with(Remarks::LONG_LONG);
217    }
218    if suffix.length == Some(Length::BitInt) {
219        if std < Std::C23 {
220            remarks = remarks.with(Remarks::BIT_INT);
221        }
222        return Ok(IntConstant { value, ty: bit_int(value, suffix.unsigned), remarks });
223    }
224
225    let candidates = candidates(base, suffix, std);
226    let kind = candidates
227        .iter()
228        .copied()
229        .find(|&kind| fits(value, kind, target))
230        .ok_or(IntError::TooLarge)?;
231    if base == 10 && !suffix.unsigned && !signed_standard(kind) {
232        remarks = remarks.with(Remarks::UNSIGNED);
233    }
234    Ok(IntConstant { value, ty: IntConstantType::Standard(kind), remarks })
235}
236
237/// The base a spelling is written in, and where its digits start.
238///
239/// A leading `0` means octal only when a digit follows, so `0u` is a decimal zero with a
240/// suffix and `08` is an octal constant with a digit that does not exist. That is the split
241/// GCC makes, and it is what turns `08` into a message about octal rather than about a suffix.
242fn base_of(bytes: &[u8]) -> (u32, usize) {
243    match bytes {
244        [b'0', b'x' | b'X', ..] => (16, 2),
245        [b'0', b'b' | b'B', ..] => (2, 2),
246        [b'0', next, ..] if next.is_ascii_digit() => (8, 1),
247        _ => (10, 0),
248    }
249}
250
251/// Whether the spelling is a floating constant rather than an integer one.
252///
253/// A point anywhere, an `e` exponent in a decimal constant, or a `p` exponent in a hexadecimal
254/// one. `1e` and `1e+` are floating constants with no exponent digits, which is a diagnostic
255/// the floating path gives, and `1f` is an integer constant with a suffix that does not exist,
256/// which is one this path gives. Both compilers split them exactly there.
257///
258/// A leading zero does not survive an exponent: `08e5` is the floating constant eight hundred
259/// thousand and not an octal constant with a digit that does not exist.
260fn floating(bytes: &[u8], base: u32) -> bool {
261    let exponent = if base == 16 { *b"pP" } else { *b"eE" };
262    bytes.iter().any(|&byte| byte == b'.' || exponent.contains(&byte))
263}
264
265/// The value of a digit in the given base, and [`None`] when the byte is not one.
266///
267/// An octal constant reads `8` and `9` as digits, so that a constant holding one ends at the
268/// suffix and the error can name the digit rather than complain about the suffix.
269fn digit(byte: u8, base: u32) -> Option<u32> {
270    char::from(byte).to_digit(if base == 8 { 10 } else { base })
271}
272
273/// The length part of a suffix.
274#[derive(Debug, Clone, Copy, PartialEq, Eq)]
275enum Length {
276    /// `l` or `L`.
277    Long,
278    /// `ll` or `LL`.
279    LongLong,
280    /// `wb` or `WB`.
281    BitInt,
282}
283
284/// A parsed suffix.
285#[derive(Debug, Clone, Copy, PartialEq, Eq)]
286struct Suffix {
287    /// Whether `u` or `U` was there.
288    unsigned: bool,
289    /// The length part, when there was one.
290    length: Option<Length>,
291}
292
293/// Reads the suffix, which may hold each part once and in either order.
294fn suffix_of(mut rest: &[u8]) -> Result<Suffix, IntError> {
295    let mut suffix = Suffix { unsigned: false, length: None };
296    while let Some(&byte) = rest.first() {
297        let taken = match byte {
298            b'u' | b'U' if !suffix.unsigned => {
299                suffix.unsigned = true;
300                1
301            }
302            // The two letters have to agree about case, so `1ll` and `1LL` are constants and
303            // `1lL` is not. Both compilers refuse the mixed spelling in every dialect.
304            b'l' | b'L' if suffix.length.is_none() => {
305                if rest.get(1) == Some(&byte) {
306                    suffix.length = Some(Length::LongLong);
307                    2
308                } else {
309                    suffix.length = Some(Length::Long);
310                    1
311                }
312            }
313            b'w' | b'W' if suffix.length.is_none() => {
314                let second = if byte == b'w' { b'b' } else { b'B' };
315                if rest.get(1) != Some(&second) {
316                    return Err(IntError::InvalidSuffix);
317                }
318                suffix.length = Some(Length::BitInt);
319                2
320            }
321            _ => return Err(IntError::InvalidSuffix),
322        };
323        rest = &rest[taken..];
324    }
325    Ok(suffix)
326}
327
328/// The type of a `wb` constant, which is the narrowest one that holds the value.
329///
330/// The sign bit counts, so a signed one is never narrower than two bits: `1wb` is
331/// `_BitInt(2)`. An unsigned zero is `unsigned _BitInt(1)`, because a width of zero is not a
332/// type. Measured against clang.
333fn bit_int(value: u128, unsigned: bool) -> IntConstantType {
334    let used = 128 - value.leading_zeros();
335    let width = if unsigned { used.max(1) } else { used + 1 };
336    IntConstantType::BitInt { signed: !unsigned, width: width.max(if unsigned { 1 } else { 2 }) }
337}
338
339/// Whether `kind` is one of the standard signed types, which is what decides the remark about
340/// a decimal constant having gone unsigned.
341fn signed_standard(kind: IntKind) -> bool {
342    matches!(kind, IntKind::Int | IntKind::Long | IntKind::LongLong)
343}
344
345/// Whether the value fits in `kind` on this target.
346fn fits(value: u128, kind: IntKind, target: &TargetInfo) -> bool {
347    let width = int_width(kind, target);
348    // Signedness here never depends on what plain `char` is, because no candidate list holds a
349    // character type.
350    let bits = if kind.is_signed(false) { width - 1 } else { width };
351    // `unsigned __int128` holds every value the accumulator can, and shifting a `u128` by all
352    // of its bits is not a shift, so the widest type is answered without one.
353    bits >= 128 || value >> bits == 0
354}
355
356/// The candidate list for a base and a suffix, in the order the standard walks it.
357///
358/// `__int128` and `unsigned __int128` are on the end of every list, which is what gcc does:
359/// `9223372036854775808` is an `__int128` there and an `unsigned long long` in clang. Both
360/// compilers put `long long` out of reach in C89 unless the suffix asks for it, and C89 is
361/// also the dialect that offers `unsigned long` for a decimal constant with no suffix at all.
362fn candidates(base: u32, suffix: Suffix, std: Std) -> &'static [IntKind] {
363    use IntKind::{Int, Int128, Long, LongLong, UInt, UInt128, ULong, ULongLong};
364
365    let decimal = base == 10;
366    let c89 = std == Std::C89;
367    match (suffix.unsigned, suffix.length) {
368        (false, None) if decimal && c89 => &[Int, Long, ULong, Int128, UInt128],
369        (false, None) if decimal => &[Int, Long, LongLong, Int128],
370        (false, None) if c89 => &[Int, UInt, Long, ULong, Int128, UInt128],
371        (false, None) => &[Int, UInt, Long, ULong, LongLong, ULongLong, Int128, UInt128],
372
373        (true, None) if c89 => &[UInt, ULong, UInt128],
374        (true, None) => &[UInt, ULong, ULongLong, UInt128],
375
376        (false, Some(Length::Long)) if decimal && c89 => &[Long, ULong, Int128, UInt128],
377        (false, Some(Length::Long)) if decimal => &[Long, LongLong, Int128],
378        (false, Some(Length::Long)) if c89 => &[Long, ULong, Int128, UInt128],
379        (false, Some(Length::Long)) => &[Long, ULong, LongLong, ULongLong, Int128, UInt128],
380
381        (true, Some(Length::Long)) if c89 => &[ULong, UInt128],
382        (true, Some(Length::Long)) => &[ULong, ULongLong, UInt128],
383
384        (false, Some(Length::LongLong)) if decimal => &[LongLong, Int128],
385        (false, Some(Length::LongLong)) => &[LongLong, ULongLong, Int128, UInt128],
386        (true, Some(Length::LongLong)) => &[ULongLong, UInt128],
387
388        // A `wb` constant never reaches here: its type comes from the value alone.
389        (_, Some(Length::BitInt)) => &[],
390    }
391}
392
393#[cfg(test)]
394mod tests {
395    use rucc_target::Triple;
396
397    use super::*;
398
399    fn linux() -> TargetInfo {
400        TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a known triple"))
401    }
402
403    /// The value and the type of a constant in the default dialect.
404    fn c23(text: &str) -> Result<IntConstant, IntError> {
405        integer(text, Std::C23, &linux())
406    }
407
408    /// The type of a constant in the given dialect, on x86-64 Linux.
409    fn kind(text: &str, std: Std) -> IntKind {
410        match integer(text, std, &linux()).expect("a valid constant").ty {
411            IntConstantType::Standard(kind) => kind,
412            IntConstantType::BitInt { .. } => panic!("{text} is a _BitInt constant"),
413        }
414    }
415
416    #[test]
417    fn a_constant_in_each_base_has_the_value_it_says() {
418        assert_eq!(c23("0").expect("zero").value, 0);
419        assert_eq!(c23("42").expect("decimal").value, 42);
420        assert_eq!(c23("0777").expect("octal").value, 0o777);
421        assert_eq!(c23("0xdeadBEEF").expect("hex").value, 0xdead_beef);
422        assert_eq!(c23("0b1010").expect("binary").value, 0b1010);
423        assert_eq!(c23("0X10").expect("upper case prefix").value, 16);
424        // A leading zero with nothing after it is a decimal zero rather than an octal one with
425        // no digits, which is the split that lets `0u` through and stops `08`.
426        assert_eq!(c23("0u").expect("zero with a suffix").value, 0);
427    }
428
429    #[test]
430    fn digit_separators_are_stripped_and_reported_before_c23() {
431        let value = c23("1'000'000").expect("a C23 constant");
432        assert_eq!(value.value, 1_000_000);
433        assert!(value.remarks.is_none());
434        assert_eq!(c23("0x1'0").expect("hex with a separator").value, 16);
435
436        let older = integer("1'000", Std::C17, &linux()).expect("still converted");
437        assert!(older.remarks.has(Remarks::SEPARATORS));
438        assert_eq!(older.value, 1000);
439    }
440
441    #[test]
442    fn the_type_of_a_decimal_constant_walks_the_signed_types_only() {
443        // Measured with `_Generic` on gcc 13.3, x86-64 Linux.
444        assert_eq!(kind("2147483647", Std::C23), IntKind::Int);
445        assert_eq!(kind("2147483648", Std::C23), IntKind::Long);
446        assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
447        assert_eq!(kind("9223372036854775807", Std::C23), IntKind::Long);
448        // Past `long long` gcc reaches for `__int128` rather than for an unsigned type, and
449        // says so: the constant is so large that it is unsigned.
450        assert_eq!(kind("9223372036854775808", Std::C23), IntKind::Int128);
451        assert_eq!(kind("18446744073709551615", Std::C23), IntKind::Int128);
452        let large = c23("18446744073709551615").expect("fits __int128");
453        assert!(large.remarks.has(Remarks::UNSIGNED));
454    }
455
456    #[test]
457    fn a_constant_in_another_base_may_be_unsigned_without_saying_so() {
458        // This is the split that surprises people: `4294967295` is a `long` and `0xffffffff`
459        // is an `unsigned int`, because only the decimal list is signed types alone.
460        assert_eq!(kind("0xffffffff", Std::C23), IntKind::UInt);
461        assert_eq!(kind("0x7fffffff", Std::C23), IntKind::Int);
462        assert_eq!(kind("0x80000000", Std::C23), IntKind::UInt);
463        assert_eq!(kind("0x100000000", Std::C23), IntKind::Long);
464        assert_eq!(kind("0xffffffffffffffff", Std::C23), IntKind::ULong);
465        assert_eq!(kind("0777", Std::C23), IntKind::Int);
466        assert_eq!(kind("0b1010", Std::C23), IntKind::Int);
467        // And no remark, because nothing about it is surprising enough to say.
468        assert!(c23("0xffffffff").expect("a constant").remarks.is_none());
469    }
470
471    #[test]
472    fn c89_has_unsigned_long_in_the_decimal_list_and_no_long_long_in_any() {
473        // gcc under `-std=c89 -pedantic`: "this decimal constant is unsigned only in ISO C90",
474        // and eight bytes rather than sixteen.
475        assert_eq!(kind("18446744073709551615", Std::C89), IntKind::ULong);
476        assert_eq!(kind("18446744073709551615", Std::C99), IntKind::Int128);
477        let old = integer("18446744073709551615", Std::C89, &linux()).expect("a C89 constant");
478        assert!(old.remarks.has(Remarks::UNSIGNED));
479        // The suffix still reaches `long long`, with the remark gcc prints for it.
480        let long_long = integer("1ll", Std::C89, &linux()).expect("an extension");
481        assert!(long_long.remarks.has(Remarks::LONG_LONG));
482        assert_eq!(kind("1ll", Std::C89), IntKind::LongLong);
483        assert!(integer("1ll", Std::C99, &linux()).expect("standard").remarks.is_none());
484    }
485
486    #[test]
487    fn a_suffix_narrows_the_list_it_does_not_pick_the_type() {
488        assert_eq!(kind("1u", Std::C23), IntKind::UInt);
489        assert_eq!(kind("1l", Std::C23), IntKind::Long);
490        assert_eq!(kind("1ul", Std::C23), IntKind::ULong);
491        assert_eq!(kind("1ll", Std::C23), IntKind::LongLong);
492        assert_eq!(kind("1llu", Std::C23), IntKind::ULongLong);
493        // The suffix is a floor rather than an answer: `4294967296u` is an `unsigned long`
494        // because `unsigned int` cannot hold it.
495        assert_eq!(kind("4294967296u", Std::C23), IntKind::ULong);
496        assert_eq!(kind("0xffffffffu", Std::C23), IntKind::UInt);
497    }
498
499    #[test]
500    fn the_letters_of_a_suffix_may_be_in_either_case_but_not_both() {
501        for text in ["1u", "1U", "1l", "1L", "1ll", "1LL", "1ul", "1lu", "1uL", "1LLU", "1llu"] {
502            assert!(c23(text).is_ok(), "{text} is a constant in both compilers");
503        }
504        for text in ["1lL", "1Ll", "1uu", "1lul", "1z", "1uz", "1f", "1x", "1_000"] {
505            assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
506        }
507    }
508
509    #[test]
510    fn a_bit_int_constant_has_the_narrowest_type_that_holds_it() {
511        // Measured against clang, which is the only one of the two that has the type.
512        let cases = [
513            ("0wb", true, 2),
514            ("1wb", true, 2),
515            ("3wb", true, 3),
516            ("42wb", true, 7),
517            ("255wb", true, 9),
518            ("0uwb", false, 1),
519            ("1uwb", false, 1),
520            ("255uwb", false, 8),
521            ("256uwb", false, 9),
522            ("0xffffffffffffffffuwb", false, 64),
523        ];
524        for (text, signed, width) in cases {
525            let constant = c23(text).expect("a _BitInt constant");
526            assert_eq!(
527                constant.ty,
528                IntConstantType::BitInt { signed, width },
529                "{text} is the wrong width"
530            );
531        }
532        // Either order, either case, and never with a length suffix.
533        for text in ["1uwb", "1wbu", "1UWB", "1WBu", "1uWB"] {
534            assert!(c23(text).is_ok(), "{text} is a constant in clang");
535        }
536        for text in ["1wB", "1Wb", "1lwb", "1wbl", "1wbwb"] {
537            assert_eq!(c23(text), Err(IntError::InvalidSuffix), "{text} is not");
538        }
539        // Before C23 it is still converted, and still worth a word.
540        let older = integer("1wb", Std::C17, &linux()).expect("clang accepts it everywhere");
541        assert!(older.remarks.has(Remarks::BIT_INT));
542    }
543
544    #[test]
545    fn a_binary_constant_is_an_extension_before_c23() {
546        assert!(c23("0b1").expect("standard in C23").remarks.is_none());
547        let older = integer("0b1", Std::C17, &linux()).expect("both compilers accept it");
548        assert!(older.remarks.has(Remarks::BINARY));
549    }
550
551    #[test]
552    fn an_octal_constant_names_the_digit_that_is_not_one() {
553        assert_eq!(c23("08"), Err(IntError::InvalidOctalDigit));
554        assert_eq!(c23("0778"), Err(IntError::InvalidOctalDigit));
555        assert_eq!(c23("09"), Err(IntError::InvalidOctalDigit));
556        // A `9` elsewhere is fine, and the message is only for constants that began with `0`.
557        assert_eq!(c23("9").expect("decimal").value, 9);
558    }
559
560    #[test]
561    fn a_prefix_with_no_digits_after_it_is_not_a_constant() {
562        assert_eq!(c23("0x"), Err(IntError::NoDigits));
563        assert_eq!(c23("0b"), Err(IntError::NoDigits));
564    }
565
566    #[test]
567    fn a_constant_larger_than_any_type_is_refused_rather_than_wrapped() {
568        // gcc accumulates in sixty four bits and silently gives this the value zero and the
569        // type `int` after a warning. That is the one measured behaviour here we refuse to
570        // reproduce, and clang refuses it too.
571        assert_eq!(c23("340282366920938463463374607431768211456"), Err(IntError::TooLarge));
572        assert_eq!(c23("0x100000000000000000000000000000000"), Err(IntError::TooLarge));
573        // 2^127 fits in the accumulator and in no signed type, and the decimal list has no
574        // unsigned one to fall back to.
575        assert_eq!(c23("170141183460469231731687303715884105728"), Err(IntError::TooLarge));
576        // The same value written in hex reaches `unsigned __int128`, because that list has it.
577        assert_eq!(kind("0x80000000000000000000000000000000", Std::C23), IntKind::UInt128);
578        assert_eq!(kind("0xffffffffffffffffffffffffffffffff", Std::C23), IntKind::UInt128);
579    }
580
581    #[test]
582    fn a_floating_constant_is_handed_back_rather_than_refused() {
583        for text in ["1.0", ".5", "1.", "1e5", "1E-5", "1e", "0x1p3", "0x1.8p+1", "1.5e3"] {
584            assert_eq!(c23(text), Err(IntError::Floating), "{text} belongs to the other path");
585        }
586        // A leading zero does not make this an octal constant with a digit that does not
587        // exist. gcc compiles it, as eight hundred thousand.
588        assert_eq!(c23("08e5"), Err(IntError::Floating));
589        // A hexadecimal `e` is a digit, not an exponent, and `1f` is an integer with a suffix
590        // that does not exist rather than a float. Both compilers split them there.
591        assert_eq!(c23("0xe5").expect("hex digits").value, 0xe5);
592        assert_eq!(c23("1f"), Err(IntError::InvalidSuffix));
593    }
594
595    #[test]
596    fn the_type_comes_from_the_target_and_not_from_the_host() {
597        // `4294967295` is a `long` where `long` is sixty four bits and a `long long` where it
598        // is thirty two. A compiler that asked its own platform gets one of these wrong.
599        let windows =
600            TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().expect("a known triple"));
601        let on_windows = integer("4294967295", Std::C23, &windows).expect("a constant");
602        assert_eq!(on_windows.ty, IntConstantType::Standard(IntKind::LongLong));
603        assert_eq!(kind("4294967295", Std::C23), IntKind::Long);
604    }
605}