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}