Skip to main content

rucc_ast/
spec.rs

1//! Declaration specifiers: what a declaration says before the declarator.
2//!
3//! Design: `spec/06-lexer-and-parser.md` sections 6.5 and 6.6.
4//!
5//! A declaration is a pile of specifiers followed by a list of declarators, and the specifiers
6//! may be written in any order: `unsigned static const long int` is a legal, if unpleasant,
7//! spelling of `static const unsigned long`. So they are accumulated into a record rather than
8//! kept as a sequence, with one exception. The keywords that name a built-in type are kept as
9//! the multiset that was written, in [`Builtin`], and turned into a type by [`Builtin::resolve`]
10//! rather than at the moment they are read, because `long` on its own and `long` before `int`
11//! and `long` after `long` are the same keyword doing three different jobs.
12//!
13//! [`DeclSpecs`] lives in a side table and is not size-capped, unlike the arena nodes.
14
15use rucc_base::Symbol;
16use rucc_diag::Span;
17
18use crate::ast::{AttrList, EnumeratorList, MemberList};
19use crate::decl::TypeNameId;
20use crate::expr::ExprId;
21
22/// A set of declaration specifiers, in the side table.
23pub type DeclSpecsId = rucc_base::Idx<DeclSpecs>;
24
25/// Everything a declaration says before its first declarator.
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub struct DeclSpecs {
28    /// The storage class, of which there may be at most one.
29    pub storage: Option<StorageClass>,
30    /// Whether `_Thread_local` was written, which is separate because it is the one storage
31    /// class specifier that may be combined with another.
32    pub thread_local: bool,
33    /// What type was named.
34    pub ty: TypeSpec,
35    /// The qualifiers, which may be written before or after the type.
36    pub quals: Quals,
37    /// `inline` and `_Noreturn`.
38    pub func: FuncSpecs,
39    /// `alignas`, of which there may be several, of which the strictest wins. Only the first is
40    /// kept here; the rest are in the side table alongside it.
41    pub align: Option<AlignSpec>,
42    /// Attributes that appertain to the declaration as a whole.
43    pub attrs: AttrList,
44    /// From the first specifier to the last.
45    pub span: Span,
46}
47
48impl DeclSpecs {
49    /// A specifier list with nothing in it, which is what the parser starts from.
50    #[must_use]
51    pub const fn empty(span: Span) -> DeclSpecs {
52        DeclSpecs {
53            storage: None,
54            thread_local: false,
55            ty: TypeSpec::None,
56            quals: Quals::NONE,
57            func: FuncSpecs::NONE,
58            align: None,
59            attrs: AttrList::EMPTY,
60            span,
61        }
62    }
63
64    /// Whether this declares type names rather than objects.
65    #[must_use]
66    pub const fn is_typedef(&self) -> bool {
67        matches!(self.storage, Some(StorageClass::Typedef))
68    }
69}
70
71/// A storage class specifier.
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum StorageClass {
74    /// `typedef`, which the grammar treats as a storage class and which declares no object.
75    Typedef,
76    /// `extern`.
77    Extern,
78    /// `static`.
79    Static,
80    /// `auto`, the old one that means nothing, not the C23 type specifier.
81    Auto,
82    /// `register`.
83    Register,
84    /// `constexpr`, new in C23.
85    Constexpr,
86}
87
88impl StorageClass {
89    /// The keyword, for the printer and for diagnostics.
90    #[must_use]
91    pub const fn spelling(self) -> &'static str {
92        match self {
93            StorageClass::Typedef => "typedef",
94            StorageClass::Extern => "extern",
95            StorageClass::Static => "static",
96            StorageClass::Auto => "auto",
97            StorageClass::Register => "register",
98            StorageClass::Constexpr => "constexpr",
99        }
100    }
101}
102
103/// The type qualifiers, as a set.
104///
105/// `_Atomic` is here because it can be written in qualifier position, where it qualifies
106/// whatever the declarator arrives at. `_Atomic(T)`, with parentheses, is a different thing and
107/// is [`TypeSpec::Atomic`], because it constructs a type that may not have the same alignment
108/// as `T`. Both spellings mean the same in the end and the difference matters to the parser.
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
110pub struct Quals(u8);
111
112impl Quals {
113    /// No qualifiers.
114    pub const NONE: Quals = Quals(0);
115    /// `const`.
116    pub const CONST: Quals = Quals(1);
117    /// `volatile`.
118    pub const VOLATILE: Quals = Quals(2);
119    /// `restrict`, which is only a keyword from C99.
120    pub const RESTRICT: Quals = Quals(4);
121    /// `_Atomic` without parentheses.
122    pub const ATOMIC: Quals = Quals(8);
123
124    /// Whether every qualifier in `other` is set here.
125    #[inline]
126    #[must_use]
127    pub const fn has(self, other: Quals) -> bool {
128        self.0 & other.0 == other.0
129    }
130
131    /// This set with `other` added.
132    #[inline]
133    #[must_use]
134    pub const fn with(self, other: Quals) -> Quals {
135        Quals(self.0 | other.0)
136    }
137
138    /// Whether nothing is qualified.
139    #[inline]
140    #[must_use]
141    pub const fn is_none(self) -> bool {
142        self.0 == 0
143    }
144}
145
146/// The function specifiers, as a set.
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
148pub struct FuncSpecs(u8);
149
150impl FuncSpecs {
151    /// Neither.
152    pub const NONE: FuncSpecs = FuncSpecs(0);
153    /// `inline`.
154    pub const INLINE: FuncSpecs = FuncSpecs(1);
155    /// `_Noreturn`, which C23 deprecated in favour of the attribute and which every real
156    /// header still uses.
157    pub const NORETURN: FuncSpecs = FuncSpecs(2);
158
159    /// Whether every specifier in `other` is set here.
160    #[inline]
161    #[must_use]
162    pub const fn has(self, other: FuncSpecs) -> bool {
163        self.0 & other.0 == other.0
164    }
165
166    /// This set with `other` added.
167    #[inline]
168    #[must_use]
169    pub const fn with(self, other: FuncSpecs) -> FuncSpecs {
170        FuncSpecs(self.0 | other.0)
171    }
172
173    /// Whether neither was written.
174    #[inline]
175    #[must_use]
176    pub const fn is_none(self) -> bool {
177        self.0 == 0
178    }
179}
180
181/// An `alignas` specifier, which takes either a type or a constant expression.
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub enum AlignSpec {
184    /// `alignas(T)`, which means the alignment of `T`.
185    Type(TypeNameId),
186    /// `alignas(N)`.
187    Expr(ExprId),
188}
189
190/// What type a declaration named.
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
192pub enum TypeSpec {
193    /// Nothing was written, which is `int` before C23 with a warning and an error in it.
194    None,
195    /// One or more of the keywords that name a built-in type.
196    Builtin(Builtin),
197    /// `struct` or `union`, with or without a tag, with or without a body.
198    Record {
199        /// Which of the two.
200        kind: RecordKind,
201        /// The tag, absent for an anonymous one.
202        tag: Option<Symbol>,
203        /// The members, absent when this is a reference to a tag rather than a definition. An
204        /// empty list is a definition of an empty structure, which is a GNU extension, so the
205        /// difference between `struct S;` and `struct S {};` has to survive.
206        fields: Option<MemberList>,
207        /// Attributes on the tag itself, which GCC allows both before and after the body.
208        attrs: AttrList,
209    },
210    /// `enum`, with C23's optional underlying type.
211    Enum {
212        /// The tag, absent for an anonymous one.
213        tag: Option<Symbol>,
214        /// The enumerators, absent when this is a reference rather than a definition.
215        enumerators: Option<EnumeratorList>,
216        /// The `: T` that C23 added, which fixes the representation instead of leaving it to
217        /// the implementation.
218        underlying: Option<TypeNameId>,
219        /// Attributes on the tag itself.
220        attrs: AttrList,
221    },
222    /// An identifier the parser's scope stack said was a typedef name.
223    Typedef(Symbol),
224    /// `typeof` or `typeof_unqual`, or their `__typeof__` spellings.
225    Typeof {
226        /// Whether the qualifiers come off, which is what `typeof_unqual` is for.
227        unqual: bool,
228        /// The operand, which is an expression or a type name and in the expression case is
229        /// never evaluated.
230        operand: TypeofArg,
231    },
232    /// `_BitInt(N)`.
233    BitInt(ExprId),
234    /// `_Atomic(T)`, the type constructor rather than the qualifier.
235    Atomic(TypeNameId),
236    /// `auto` used as a type specifier, which C23 added and which is told apart from the
237    /// storage class by whether any other type specifier is present.
238    Auto,
239}
240
241/// Which of the two record kinds.
242#[derive(Debug, Clone, Copy, PartialEq, Eq)]
243pub enum RecordKind {
244    /// `struct`.
245    Struct,
246    /// `union`.
247    Union,
248}
249
250impl RecordKind {
251    /// The keyword, for the printer and for diagnostics.
252    #[must_use]
253    pub const fn spelling(self) -> &'static str {
254        match self {
255            RecordKind::Struct => "struct",
256            RecordKind::Union => "union",
257        }
258    }
259}
260
261/// What a `typeof` was applied to.
262#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub enum TypeofArg {
264    /// An expression, which is not evaluated.
265    Expr(ExprId),
266    /// A type name.
267    Type(TypeNameId),
268}
269
270/// The keywords naming a built-in type, as the multiset that was written.
271///
272/// Kept rather than resolved, because the parser reads one keyword at a time and cannot tell
273/// what `long` will turn out to mean until the specifier list ends. [`Builtin::add`] catches a
274/// keyword written twice, at the place it is written, and [`Builtin::resolve`] catches a
275/// combination that names no type once there are no more keywords coming.
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
277pub struct Builtin {
278    /// Which keywords were written.
279    pub set: BuiltinSet,
280    /// How many times `long` was written, since it is the one that may repeat.
281    pub longs: u8,
282}
283
284/// The set of built-in type keywords, without the count of `long`.
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
286pub struct BuiltinSet(u32);
287
288impl BuiltinSet {
289    /// Nothing.
290    pub const NONE: BuiltinSet = BuiltinSet(0);
291    /// `void`.
292    pub const VOID: BuiltinSet = BuiltinSet(1 << 0);
293    /// `bool`, in either spelling.
294    pub const BOOL: BuiltinSet = BuiltinSet(1 << 1);
295    /// `char`.
296    pub const CHAR: BuiltinSet = BuiltinSet(1 << 2);
297    /// `short`.
298    pub const SHORT: BuiltinSet = BuiltinSet(1 << 3);
299    /// `int`.
300    pub const INT: BuiltinSet = BuiltinSet(1 << 4);
301    /// `long`, however many times it was written.
302    pub const LONG: BuiltinSet = BuiltinSet(1 << 5);
303    /// `signed`.
304    pub const SIGNED: BuiltinSet = BuiltinSet(1 << 6);
305    /// `unsigned`.
306    pub const UNSIGNED: BuiltinSet = BuiltinSet(1 << 7);
307    /// `float`.
308    pub const FLOAT: BuiltinSet = BuiltinSet(1 << 8);
309    /// `double`.
310    pub const DOUBLE: BuiltinSet = BuiltinSet(1 << 9);
311    /// `_Complex`.
312    pub const COMPLEX: BuiltinSet = BuiltinSet(1 << 10);
313    /// `_Imaginary`.
314    pub const IMAGINARY: BuiltinSet = BuiltinSet(1 << 11);
315    /// `__int128`.
316    pub const INT128: BuiltinSet = BuiltinSet(1 << 12);
317    /// `_Float16`.
318    pub const FLOAT16: BuiltinSet = BuiltinSet(1 << 13);
319    /// `_Float32`.
320    pub const FLOAT32: BuiltinSet = BuiltinSet(1 << 14);
321    /// `_Float64`.
322    pub const FLOAT64: BuiltinSet = BuiltinSet(1 << 15);
323    /// `_Float128`, whose `__float128` spelling is the same type.
324    pub const FLOAT128: BuiltinSet = BuiltinSet(1 << 16);
325    /// `_Float32x`.
326    pub const FLOAT32X: BuiltinSet = BuiltinSet(1 << 17);
327    /// `_Float64x`.
328    pub const FLOAT64X: BuiltinSet = BuiltinSet(1 << 18);
329    /// `_Float128x`.
330    pub const FLOAT128X: BuiltinSet = BuiltinSet(1 << 19);
331    /// `__float80`.
332    pub const FLOAT80: BuiltinSet = BuiltinSet(1 << 20);
333    /// `_Decimal32`.
334    pub const DECIMAL32: BuiltinSet = BuiltinSet(1 << 21);
335    /// `_Decimal64`.
336    pub const DECIMAL64: BuiltinSet = BuiltinSet(1 << 22);
337    /// `_Decimal128`.
338    pub const DECIMAL128: BuiltinSet = BuiltinSet(1 << 23);
339
340    /// Everything that names a decimal floating type.
341    const DECIMALS: BuiltinSet =
342        BuiltinSet(Self::DECIMAL32.0 | Self::DECIMAL64.0 | Self::DECIMAL128.0);
343    /// Everything that names one of the `_FloatN` and `_FloatNx` types.
344    const EXTENDED: BuiltinSet = BuiltinSet(
345        Self::FLOAT16.0
346            | Self::FLOAT32.0
347            | Self::FLOAT64.0
348            | Self::FLOAT128.0
349            | Self::FLOAT32X.0
350            | Self::FLOAT64X.0
351            | Self::FLOAT128X.0
352            | Self::FLOAT80.0,
353    );
354    /// Everything that can be part of a standard integer type.
355    const INTEGER: BuiltinSet =
356        BuiltinSet(Self::SHORT.0 | Self::INT.0 | Self::LONG.0 | Self::SIGNED.0 | Self::UNSIGNED.0);
357
358    /// Whether every keyword in `other` is set here.
359    #[inline]
360    #[must_use]
361    pub const fn has(self, other: BuiltinSet) -> bool {
362        self.0 & other.0 == other.0
363    }
364
365    /// Whether any keyword in `other` is set here.
366    #[inline]
367    #[must_use]
368    pub const fn has_any(self, other: BuiltinSet) -> bool {
369        self.0 & other.0 != 0
370    }
371
372    /// This set with `other` added.
373    #[inline]
374    #[must_use]
375    pub const fn with(self, other: BuiltinSet) -> BuiltinSet {
376        BuiltinSet(self.0 | other.0)
377    }
378
379    /// This set with everything in `other` taken out.
380    #[inline]
381    #[must_use]
382    pub const fn without(self, other: BuiltinSet) -> BuiltinSet {
383        BuiltinSet(self.0 & !other.0)
384    }
385
386    /// Whether nothing was written.
387    #[inline]
388    #[must_use]
389    pub const fn is_none(self) -> bool {
390        self.0 == 0
391    }
392}
393
394/// Why a built-in type keyword could not be added.
395#[derive(Debug, Clone, Copy, PartialEq, Eq)]
396pub enum BuiltinError {
397    /// The keyword was already written, and it is not `long`.
398    Duplicate,
399    /// A third `long`, which no type has.
400    TooManyLongs,
401}
402
403impl Builtin {
404    /// Nothing written yet.
405    pub const NONE: Builtin = Builtin { set: BuiltinSet::NONE, longs: 0 };
406
407    /// This with one more keyword.
408    ///
409    /// `long` is the only keyword that may be written twice, so everything else is a duplicate
410    /// the second time and is reported at the keyword rather than at the end of the specifier
411    /// list, which is where the second half of the checking happens.
412    ///
413    /// # Errors
414    ///
415    /// [`BuiltinError::Duplicate`] for a repeat, and [`BuiltinError::TooManyLongs`] for a third
416    /// `long`.
417    pub const fn add(self, which: BuiltinSet) -> Result<Builtin, BuiltinError> {
418        if which.0 == BuiltinSet::LONG.0 {
419            if self.longs >= 2 {
420                return Err(BuiltinError::TooManyLongs);
421            }
422            return Ok(Builtin { set: self.set.with(which), longs: self.longs + 1 });
423        }
424        if self.set.has(which) {
425            return Err(BuiltinError::Duplicate);
426        }
427        Ok(Builtin { set: self.set.with(which), longs: self.longs })
428    }
429
430    /// Whether any built-in keyword has been written.
431    #[must_use]
432    pub const fn is_none(self) -> bool {
433        self.set.is_none()
434    }
435
436    /// The type this combination of keywords names, and `None` if it names no type.
437    ///
438    /// The table is the one in 6.7.2 plus the GNU and C23 rows: `_Complex` and `_Imaginary` on
439    /// the floating types, `_Complex` on the integer ones which GCC also allows, `__int128`
440    /// with a sign, and the `_FloatN` and `_DecimalN` families which stand alone.
441    #[must_use]
442    pub fn resolve(self) -> Option<Basic> {
443        let set = self.set;
444        let longs = self.longs;
445
446        let complexity = match (set.has(BuiltinSet::COMPLEX), set.has(BuiltinSet::IMAGINARY)) {
447            (true, true) => return None,
448            (true, false) => Complexity::Complex,
449            (false, true) => Complexity::Imaginary,
450            (false, false) => Complexity::Real,
451        };
452        let set = set.without(BuiltinSet::COMPLEX.with(BuiltinSet::IMAGINARY));
453        let basic = |scalar| Some(Basic { scalar, complexity });
454        let real = |scalar| {
455            if complexity == Complexity::Real { Some(Basic { scalar, complexity }) } else { None }
456        };
457
458        if set.has(BuiltinSet::SIGNED) && set.has(BuiltinSet::UNSIGNED) {
459            return None;
460        }
461        let unsigned = set.has(BuiltinSet::UNSIGNED);
462        let signs = BuiltinSet::SIGNED.with(BuiltinSet::UNSIGNED);
463
464        // Everything below is "these keywords and nothing else", which is what makes `void int`
465        // and `char short` fail here rather than needing a rule each.
466        if set.has(BuiltinSet::VOID) {
467            return if set == BuiltinSet::VOID && longs == 0 { real(Scalar::Void) } else { None };
468        }
469        if set.has(BuiltinSet::BOOL) {
470            return if set == BuiltinSet::BOOL && longs == 0 { real(Scalar::Bool) } else { None };
471        }
472        if set.has(BuiltinSet::CHAR) {
473            if set.without(signs) != BuiltinSet::CHAR || longs != 0 {
474                return None;
475            }
476            return real(match (set.has(BuiltinSet::SIGNED), unsigned) {
477                (true, _) => Scalar::SignedChar,
478                (_, true) => Scalar::UnsignedChar,
479                _ => Scalar::Char,
480            });
481        }
482        if set.has(BuiltinSet::INT128) {
483            if set.without(signs) != BuiltinSet::INT128 || longs != 0 {
484                return None;
485            }
486            return real(if unsigned { Scalar::UnsignedInt128 } else { Scalar::Int128 });
487        }
488        if set.has_any(BuiltinSet::DECIMALS) {
489            if longs != 0 || complexity != Complexity::Real {
490                return None;
491            }
492            return match set {
493                s if s == BuiltinSet::DECIMAL32 => real(Scalar::Decimal32),
494                s if s == BuiltinSet::DECIMAL64 => real(Scalar::Decimal64),
495                s if s == BuiltinSet::DECIMAL128 => real(Scalar::Decimal128),
496                _ => None,
497            };
498        }
499        if set.has_any(BuiltinSet::EXTENDED) {
500            if longs != 0 {
501                return None;
502            }
503            return match set {
504                s if s == BuiltinSet::FLOAT16 => basic(Scalar::Float16),
505                s if s == BuiltinSet::FLOAT32 => basic(Scalar::Float32),
506                s if s == BuiltinSet::FLOAT64 => basic(Scalar::Float64),
507                s if s == BuiltinSet::FLOAT128 => basic(Scalar::Float128),
508                s if s == BuiltinSet::FLOAT32X => basic(Scalar::Float32x),
509                s if s == BuiltinSet::FLOAT64X => basic(Scalar::Float64x),
510                s if s == BuiltinSet::FLOAT128X => basic(Scalar::Float128x),
511                s if s == BuiltinSet::FLOAT80 => basic(Scalar::Float80),
512                _ => None,
513            };
514        }
515        if set.has(BuiltinSet::FLOAT) {
516            return if set == BuiltinSet::FLOAT && longs == 0 {
517                basic(Scalar::Float)
518            } else {
519                None
520            };
521        }
522        if set.has(BuiltinSet::DOUBLE) {
523            if set.without(BuiltinSet::LONG) != BuiltinSet::DOUBLE {
524                return None;
525            }
526            return match longs {
527                0 => basic(Scalar::Double),
528                1 => basic(Scalar::LongDouble),
529                _ => None,
530            };
531        }
532        if set.is_none() {
533            return None;
534        }
535        // What is left is the standard integer types, where `int` is implied by any of the
536        // others and every combination is legal except `short long`.
537        if !BuiltinSet::INTEGER.has(set) {
538            return None;
539        }
540        if set.has(BuiltinSet::SHORT) {
541            if longs != 0 {
542                return None;
543            }
544            return basic(if unsigned { Scalar::UnsignedShort } else { Scalar::Short });
545        }
546        match longs {
547            0 => basic(if unsigned { Scalar::UnsignedInt } else { Scalar::Int }),
548            1 => basic(if unsigned { Scalar::UnsignedLong } else { Scalar::Long }),
549            2 => basic(if unsigned { Scalar::UnsignedLongLong } else { Scalar::LongLong }),
550            _ => None,
551        }
552    }
553}
554
555/// A built-in type, once the keywords have been read together.
556#[derive(Debug, Clone, Copy, PartialEq, Eq)]
557pub struct Basic {
558    /// The type itself.
559    pub scalar: Scalar,
560    /// Whether `_Complex` or `_Imaginary` was written.
561    pub complexity: Complexity,
562}
563
564/// Whether a built-in type is real, complex or imaginary.
565#[derive(Debug, Clone, Copy, PartialEq, Eq)]
566pub enum Complexity {
567    /// Neither keyword.
568    Real,
569    /// `_Complex`.
570    Complex,
571    /// `_Imaginary`, which GCC parses and has never implemented.
572    Imaginary,
573}
574
575/// A built-in type named by keywords, with the sign folded in.
576///
577/// `char` is here three times because plain `char` is a third type distinct from both
578/// `signed char` and `unsigned char`, however it is represented on the target.
579#[derive(Debug, Clone, Copy, PartialEq, Eq)]
580pub enum Scalar {
581    /// `void`.
582    Void,
583    /// `bool`.
584    Bool,
585    /// `char`.
586    Char,
587    /// `signed char`.
588    SignedChar,
589    /// `unsigned char`.
590    UnsignedChar,
591    /// `short`.
592    Short,
593    /// `unsigned short`.
594    UnsignedShort,
595    /// `int`.
596    Int,
597    /// `unsigned int`.
598    UnsignedInt,
599    /// `long`.
600    Long,
601    /// `unsigned long`.
602    UnsignedLong,
603    /// `long long`.
604    LongLong,
605    /// `unsigned long long`.
606    UnsignedLongLong,
607    /// `__int128`.
608    Int128,
609    /// `unsigned __int128`.
610    UnsignedInt128,
611    /// `float`.
612    Float,
613    /// `double`.
614    Double,
615    /// `long double`.
616    LongDouble,
617    /// `_Float16`.
618    Float16,
619    /// `_Float32`.
620    Float32,
621    /// `_Float64`.
622    Float64,
623    /// `_Float128`.
624    Float128,
625    /// `_Float32x`.
626    Float32x,
627    /// `_Float64x`.
628    Float64x,
629    /// `_Float128x`.
630    Float128x,
631    /// `__float80`.
632    Float80,
633    /// `_Decimal32`.
634    Decimal32,
635    /// `_Decimal64`.
636    Decimal64,
637    /// `_Decimal128`.
638    Decimal128,
639}
640
641#[cfg(test)]
642mod tests {
643    use super::*;
644
645    fn resolve(keywords: &[BuiltinSet]) -> Option<Basic> {
646        let mut b = Builtin::NONE;
647        for &k in keywords {
648            b = b.add(k).expect("keyword rejected");
649        }
650        b.resolve()
651    }
652
653    fn real(keywords: &[BuiltinSet]) -> Option<Scalar> {
654        resolve(keywords).filter(|b| b.complexity == Complexity::Real).map(|b| b.scalar)
655    }
656
657    #[test]
658    fn the_plain_integer_spellings() {
659        assert_eq!(real(&[BuiltinSet::INT]), Some(Scalar::Int));
660        assert_eq!(real(&[BuiltinSet::SIGNED]), Some(Scalar::Int));
661        assert_eq!(real(&[BuiltinSet::UNSIGNED]), Some(Scalar::UnsignedInt));
662        assert_eq!(real(&[BuiltinSet::SIGNED, BuiltinSet::INT]), Some(Scalar::Int));
663        assert_eq!(real(&[BuiltinSet::SHORT]), Some(Scalar::Short));
664        assert_eq!(real(&[BuiltinSet::SHORT, BuiltinSet::INT]), Some(Scalar::Short));
665        assert_eq!(
666            real(&[BuiltinSet::UNSIGNED, BuiltinSet::SHORT, BuiltinSet::INT]),
667            Some(Scalar::UnsignedShort)
668        );
669    }
670
671    #[test]
672    fn long_counts_rather_than_repeats() {
673        assert_eq!(real(&[BuiltinSet::LONG]), Some(Scalar::Long));
674        assert_eq!(real(&[BuiltinSet::LONG, BuiltinSet::LONG]), Some(Scalar::LongLong));
675        assert_eq!(
676            real(&[BuiltinSet::UNSIGNED, BuiltinSet::LONG, BuiltinSet::LONG, BuiltinSet::INT]),
677            Some(Scalar::UnsignedLongLong)
678        );
679        let three = Builtin::NONE
680            .add(BuiltinSet::LONG)
681            .and_then(|b| b.add(BuiltinSet::LONG))
682            .and_then(|b| b.add(BuiltinSet::LONG));
683        assert_eq!(three, Err(BuiltinError::TooManyLongs));
684    }
685
686    #[test]
687    fn a_repeated_keyword_is_caught_where_it_is_written() {
688        let twice = Builtin::NONE.add(BuiltinSet::INT).and_then(|b| b.add(BuiltinSet::INT));
689        assert_eq!(twice, Err(BuiltinError::Duplicate));
690    }
691
692    #[test]
693    fn plain_char_is_its_own_type() {
694        assert_eq!(real(&[BuiltinSet::CHAR]), Some(Scalar::Char));
695        assert_eq!(real(&[BuiltinSet::SIGNED, BuiltinSet::CHAR]), Some(Scalar::SignedChar));
696        assert_eq!(real(&[BuiltinSet::UNSIGNED, BuiltinSet::CHAR]), Some(Scalar::UnsignedChar));
697        assert_eq!(real(&[BuiltinSet::CHAR, BuiltinSet::INT]), None);
698        assert_eq!(real(&[BuiltinSet::CHAR, BuiltinSet::LONG]), None);
699    }
700
701    #[test]
702    fn long_double_is_a_double_with_one_long() {
703        assert_eq!(real(&[BuiltinSet::DOUBLE]), Some(Scalar::Double));
704        assert_eq!(real(&[BuiltinSet::LONG, BuiltinSet::DOUBLE]), Some(Scalar::LongDouble));
705        assert_eq!(real(&[BuiltinSet::LONG, BuiltinSet::LONG, BuiltinSet::DOUBLE]), None);
706        assert_eq!(real(&[BuiltinSet::LONG, BuiltinSet::FLOAT]), None);
707        assert_eq!(real(&[BuiltinSet::DOUBLE, BuiltinSet::INT]), None);
708    }
709
710    #[test]
711    fn complex_is_a_modifier_and_not_a_type() {
712        assert_eq!(
713            resolve(&[BuiltinSet::COMPLEX, BuiltinSet::DOUBLE]),
714            Some(Basic { scalar: Scalar::Double, complexity: Complexity::Complex })
715        );
716        assert_eq!(
717            resolve(&[BuiltinSet::LONG, BuiltinSet::DOUBLE, BuiltinSet::IMAGINARY]),
718            Some(Basic { scalar: Scalar::LongDouble, complexity: Complexity::Imaginary })
719        );
720        // GCC accepts a complex integer type, so this is not an error here either.
721        assert_eq!(
722            resolve(&[BuiltinSet::COMPLEX, BuiltinSet::INT]),
723            Some(Basic { scalar: Scalar::Int, complexity: Complexity::Complex })
724        );
725        assert_eq!(resolve(&[BuiltinSet::COMPLEX, BuiltinSet::IMAGINARY, BuiltinSet::FLOAT]), None);
726        // There is no complex decimal type in any dialect.
727        assert_eq!(resolve(&[BuiltinSet::COMPLEX, BuiltinSet::DECIMAL64]), None);
728    }
729
730    #[test]
731    fn the_extended_types_stand_alone_or_with_complex() {
732        assert_eq!(real(&[BuiltinSet::FLOAT128]), Some(Scalar::Float128));
733        assert_eq!(
734            resolve(&[BuiltinSet::COMPLEX, BuiltinSet::FLOAT128]),
735            Some(Basic { scalar: Scalar::Float128, complexity: Complexity::Complex })
736        );
737        assert_eq!(real(&[BuiltinSet::FLOAT32X]), Some(Scalar::Float32x));
738        assert_eq!(real(&[BuiltinSet::FLOAT128X]), Some(Scalar::Float128x));
739        assert_eq!(real(&[BuiltinSet::FLOAT16, BuiltinSet::INT]), None);
740        assert_eq!(real(&[BuiltinSet::FLOAT32, BuiltinSet::FLOAT64]), None);
741    }
742
743    #[test]
744    fn the_wide_integers_take_a_sign_and_nothing_else() {
745        assert_eq!(real(&[BuiltinSet::INT128]), Some(Scalar::Int128));
746        assert_eq!(real(&[BuiltinSet::UNSIGNED, BuiltinSet::INT128]), Some(Scalar::UnsignedInt128));
747        assert_eq!(real(&[BuiltinSet::INT128, BuiltinSet::INT]), None);
748    }
749
750    #[test]
751    fn void_and_bool_take_nothing() {
752        assert_eq!(real(&[BuiltinSet::VOID]), Some(Scalar::Void));
753        assert_eq!(real(&[BuiltinSet::BOOL]), Some(Scalar::Bool));
754        assert_eq!(real(&[BuiltinSet::VOID, BuiltinSet::INT]), None);
755        assert_eq!(real(&[BuiltinSet::UNSIGNED, BuiltinSet::BOOL]), None);
756    }
757
758    #[test]
759    fn two_signs_name_no_type() {
760        assert_eq!(real(&[BuiltinSet::SIGNED, BuiltinSet::UNSIGNED]), None);
761    }
762
763    #[test]
764    fn no_keywords_at_all_names_no_type() {
765        assert_eq!(Builtin::NONE.resolve(), None);
766        assert!(Builtin::NONE.is_none());
767    }
768
769    #[test]
770    fn short_and_long_do_not_go_together() {
771        assert_eq!(real(&[BuiltinSet::SHORT, BuiltinSet::LONG]), None);
772    }
773
774    #[test]
775    fn qualifier_sets_add_up() {
776        let q = Quals::NONE.with(Quals::CONST).with(Quals::VOLATILE);
777        assert!(q.has(Quals::CONST));
778        assert!(q.has(Quals::VOLATILE));
779        assert!(!q.has(Quals::RESTRICT));
780        assert!(Quals::NONE.is_none());
781        assert!(!q.is_none());
782    }
783
784    #[test]
785    fn function_specifier_sets_add_up() {
786        let f = FuncSpecs::NONE.with(FuncSpecs::INLINE);
787        assert!(f.has(FuncSpecs::INLINE));
788        assert!(!f.has(FuncSpecs::NORETURN));
789        assert!(FuncSpecs::NONE.is_none());
790    }
791}