rucc_lex/remarks.rs
1//! What a constant or a literal did that somebody might want to hear about.
2//!
3//! Design: `spec/06-lexer-and-parser.md` section 6.1.
4//!
5//! The conversions in [`crate::number`] and [`crate::literal`] never decide that something is a
6//! warning. They convert what they were given, in the dialect they were told, and report what
7//! the constant did along with the value, because the caller is the one holding the span and
8//! the flags that say whether `-pedantic` is on and whether warnings are errors. A conversion
9//! that decided for itself would have to be told about every warning flag in the driver.
10
11/// What a constant does that the dialect being compiled has an opinion about, or that happened
12/// to it on the way to a value.
13///
14/// A bitmask rather than a list, because a constant may earn several and a `Vec` per constant
15/// on a file full of them is a cost with nothing to show for it. Every one of these is legal
16/// in the dialect this compiler defaults to, so none of them is an error here: the caller
17/// decides what `-pedantic`, `-Woverflow` and `-Werror` make of them.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
19pub struct Remarks(u32);
20
21impl Remarks {
22 /// Nothing to say.
23 pub const NONE: Remarks = Remarks(0);
24 /// A `0b` constant before C23, where it is a GNU extension both compilers accept.
25 pub const BINARY: Remarks = Remarks(1);
26 /// A digit separator before C23, which neither compiler accepts there.
27 pub const SEPARATORS: Remarks = Remarks(2);
28 /// A `wb` suffix before C23.
29 pub const BIT_INT: Remarks = Remarks(4);
30 /// An `ll` suffix under `-std=c89`, where GCC says "use of C99 long long integer constant".
31 pub const LONG_LONG: Remarks = Remarks(8);
32 /// A decimal constant with no `u` suffix that fits no signed type, so it became an unsigned
33 /// one. GCC says "integer constant is so large that it is unsigned", and it is worth saying
34 /// because the constant's arithmetic is now unsigned and its negation is not negative.
35 pub const UNSIGNED: Remarks = Remarks(16);
36 /// A hexadecimal floating constant before C99, where GCC says "use of C99 hexadecimal
37 /// floating constant".
38 pub const HEX_FLOAT: Remarks = Remarks(32);
39 /// A suffix that names a type ISO C does not have: `q`, `w`, or one of the `_FloatN` and
40 /// `_FloatNx` ones. GCC says "non-standard suffix on floating constant", and separately
41 /// that ISO C does not support the type.
42 pub const EXTENDED_SUFFIX: Remarks = Remarks(64);
43 /// A `d` suffix, which is a `double` written the long way. GCC gives this one its own
44 /// wording, "suffix for double constant is a GCC extension", and gives it in every dialect
45 /// rather than only under `-pedantic`.
46 pub const DOUBLE_SUFFIX: Remarks = Remarks(128);
47 /// An `i` or `j` suffix. GCC says "imaginary constants are a GCC extension", in every
48 /// dialect, because no version of C has a spelling for one.
49 pub const IMAGINARY: Remarks = Remarks(256);
50 /// A value too large for its type, which became an infinity. GCC says "floating constant
51 /// exceeds range of 'double'" and names the type.
52 pub const OUT_OF_RANGE: Remarks = Remarks(512);
53 /// A nonzero value too small for its type, which became a zero. GCC says "floating constant
54 /// truncated to zero", and it is worth saying because the program now divides by zero where
55 /// it meant to divide by something very small.
56 pub const TRUNCATED: Remarks = Remarks(1024);
57 /// A character constant holding more than one character, whose value GCC builds by shifting
58 /// them together and which the standard leaves implementation defined. GCC says
59 /// "multi-character character constant".
60 pub const MULTICHARACTER: Remarks = Remarks(2048);
61 /// A character constant holding more characters than its type has room for, so the ones at
62 /// the front are gone. GCC says "character constant too long for its type", and says it
63 /// instead of the multi-character remark rather than as well as it.
64 pub const TOO_LONG: Remarks = Remarks(4096);
65 /// An escape whose letter means nothing, which is the letter itself and a warning in both
66 /// compilers. GCC says "unknown escape sequence".
67 pub const UNKNOWN_ESCAPE: Remarks = Remarks(8192);
68 /// `\e`, the escape character, which both compilers have and no standard does. GCC says
69 /// "non-ISO-standard escape sequence".
70 pub const NON_ISO_ESCAPE: Remarks = Remarks(16384);
71 /// A `\x` escape whose value does not fit the element it is written in, so it was truncated.
72 /// GCC says "hex escape sequence out of range".
73 pub const HEX_ESCAPE_OUT_OF_RANGE: Remarks = Remarks(32768);
74 /// An octal escape whose value does not fit the element it is written in. GCC gives this its
75 /// own wording, "octal escape sequence out of range", which is why it is its own flag.
76 pub const OCTAL_ESCAPE_OUT_OF_RANGE: Remarks = Remarks(65536);
77 /// A universal character name before C99, where GCC says "universal character names are
78 /// only valid in C++ and C99" and converts it anyway.
79 pub const UCN: Remarks = Remarks(131_072);
80
81 /// Whether every remark in `other` is set here.
82 #[inline]
83 #[must_use]
84 pub const fn has(self, other: Remarks) -> bool {
85 self.0 & other.0 == other.0
86 }
87
88 /// This set with `other` added.
89 #[inline]
90 #[must_use]
91 pub const fn with(self, other: Remarks) -> Remarks {
92 Remarks(self.0 | other.0)
93 }
94
95 /// Whether there is nothing to say.
96 #[inline]
97 #[must_use]
98 pub const fn is_none(self) -> bool {
99 self.0 == 0
100 }
101}