Skip to main content

rucc_ast/
init.rs

1//! Initializers.
2//!
3//! Design: `spec/06-lexer-and-parser.md` section 6.2 and `spec/07-types-and-semantics.md`.
4//!
5//! An initializer is either an expression or a braced list of initializers, and a braced list
6//! may say where each of its elements goes. Nothing here works out where they actually go: the
7//! rules for walking a partly-designated brace list over a struct containing an array of unions
8//! are semantic and they live in `spec/07-types-and-semantics.md`. What is kept here is exactly
9//! what was written, brace for brace, because the diagnostics for getting it wrong have to
10//! quote it.
11
12use rucc_base::Symbol;
13use rucc_diag::Span;
14
15use crate::ast::{DesignatorList, InitItemList};
16use crate::expr::ExprId;
17
18/// An initializer, in the side table.
19pub type InitId = rucc_base::Idx<Init>;
20
21/// What an object is initialized with.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum Init {
24    /// A single expression, as in `int x = 1;`.
25    Expr(ExprId),
26    /// A braced list, which may be empty. `{}` is C23 and `{ 0 }` is how everybody used to
27    /// write it, and they are not the same spelling even though they mean the same thing.
28    List(InitItemList),
29}
30
31/// One element of a braced initializer list.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct InitItem {
34    /// The designators before the `=`, and an empty list when the element just follows the one
35    /// before it.
36    pub designators: DesignatorList,
37    /// The initializer for this element, which may itself be a braced list.
38    pub init: InitId,
39    /// From the first designator to the end of the initializer.
40    pub span: Span,
41}
42
43/// One step of a designation, or of a `__builtin_offsetof` member path.
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum Designator {
46    /// `.name`.
47    Field(Symbol),
48    /// `[index]`.
49    Index(ExprId),
50    /// `[lo ... hi]`, GNU's range, which initializes a run of elements with one value.
51    Range {
52        /// The first index.
53        lo: ExprId,
54        /// The last index, which is included.
55        hi: ExprId,
56    },
57    /// `name:`, the form GCC had before C99 and still accepts, with a warning under
58    /// `-pedantic`. Kept apart from [`Designator::Field`] so the printer puts back what was
59    /// written and so the diagnostic can point at the right thing.
60    ObsoleteField(Symbol),
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn an_initializer_is_twelve_bytes() {
69        assert_eq!(size_of::<Init>(), 12);
70    }
71
72    #[test]
73    fn a_designator_is_twelve_bytes() {
74        // Set by the GNU range, which is the only one with two operands.
75        assert_eq!(size_of::<Designator>(), 12);
76    }
77}