rucc_ast/decl.rs
1//! Declarations and declarators.
2//!
3//! Design: `spec/06-lexer-and-parser.md` section 6.5.
4//!
5//! # Which way a declarator reads
6//!
7//! C declarations are inside-out. In `int (*f[3])(char)` the name is `f` and the type is built
8//! by reading outward from it: array of three, pointer to, function taking `char`, returning
9//! the `int` that the specifiers named. So a [`Declarator`] is a name plus a list of
10//! [`Derived`] steps in exactly that spoken order, and the type is built by folding the list
11//! from its end back to its start onto the specifier type. The parser produces the list by
12//! pushing while it descends into the parentheses and reversing on the way out, which is the
13//! standard trick and the reason the list is flat rather than a tree.
14//!
15//! An abstract declarator, the kind with no name in it, is the same structure with
16//! [`Declarator::name`] absent. Sharing the representation is deliberate: the two grammars are
17//! the same grammar with one production made optional, and compilers that write them twice end
18//! up accepting different things in a cast than in a parameter.
19
20use rucc_base::Symbol;
21use rucc_diag::Span;
22
23use crate::asm::AsmId;
24use crate::ast::{AttrList, DeclList, DerivedList, InitDeclaratorList, ParamList, StrId};
25use crate::expr::ExprId;
26use crate::init::InitId;
27use crate::spec::{DeclSpecsId, Quals};
28use crate::stmt::StmtId;
29
30/// How deeply declarators may nest before the parser gives up.
31///
32/// A cap rather than a recursion limit, because the thing that overflows is the stack and the
33/// input that overflows it is three lines of generated code. GCC has a limit in the same spirit
34/// and a different number.
35pub const MAX_DECLARATOR_DEPTH: usize = 200;
36
37/// A declaration in the declaration arena.
38pub type DeclId = rucc_base::Idx<Decl>;
39
40/// One declaration.
41///
42/// A declaration, not a declarator: `int a, *b = 0;` is one [`Decl::Var`] holding one specifier
43/// list and two [`InitDeclarator`]s. Keeping the grouping means a diagnostic can point at the
44/// specifiers that both declarators share, and it means the printer puts the source back
45/// together the way it was written.
46///
47/// Twenty-four bytes, set by [`Decl::Function`].
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum Decl {
50 /// A parse that did not work out. Poisoned, as [`Expr::Error`](crate::Expr::Error) is.
51 Error,
52 /// Specifiers and zero or more declarators.
53 ///
54 /// Zero is not a mistake: `struct S { int x; };` declares a tag and nothing else, and
55 /// `int;` is the same shape with a diagnostic attached.
56 Var {
57 /// What the declaration says before the first declarator.
58 specs: DeclSpecsId,
59 /// The declarators, each with its own initializer.
60 declarators: InitDeclaratorList,
61 },
62 /// A function definition, which is the one declaration with a body.
63 ///
64 /// Attributes written after the declarator go into `specs` rather than onto the declarator,
65 /// because a definition has exactly one declarator and everything on it appertains to the
66 /// same declaration however it was written.
67 Function {
68 /// The specifiers.
69 specs: DeclSpecsId,
70 /// The declarator, whose outermost derivation is the function one.
71 declarator: DeclaratorId,
72 /// The declarations between the parameter list and the body in an old-style
73 /// definition, and empty for a modern one.
74 params: DeclList,
75 /// The compound statement.
76 body: StmtId,
77 },
78 /// `static_assert(cond)` or `static_assert(cond, "message")`.
79 StaticAssert {
80 /// The condition, which must be a constant expression.
81 cond: ExprId,
82 /// The message, absent in the one-argument form C23 added.
83 message: Option<StrId>,
84 },
85 /// `asm("...")` at file scope.
86 Asm(AsmId),
87 /// `[[...]];` on its own, which C23 allows and which appertains to nothing.
88 Attributes(AttrList),
89}
90
91/// One declarator of a declaration, with whatever follows it.
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub struct InitDeclarator {
94 /// The declarator.
95 pub declarator: DeclaratorId,
96 /// The initializer, if there was one.
97 pub init: Option<InitId>,
98 /// An `asm("name")` label, which is how a declaration is given an assembler name that is
99 /// not its identifier. Common in the C library headers and in the kernel.
100 pub asm_label: Option<StrId>,
101 /// Attributes written after this declarator, which appertain to it alone and not to the
102 /// declarators beside it.
103 pub attrs: AttrList,
104 /// From the start of the declarator to the end of the initializer.
105 pub span: Span,
106}
107
108/// A declarator, in the side table.
109pub type DeclaratorId = rucc_base::Idx<Declarator>;
110
111/// A name and the steps that build its type outward from it.
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113pub struct Declarator {
114 /// The name, absent in an abstract declarator.
115 pub name: Option<Symbol>,
116 /// Just the name, for the diagnostic that points at it rather than at the whole thing.
117 pub name_span: Span,
118 /// The derivations, from the name outward, folded from the end onto the specifier type.
119 pub derived: DerivedList,
120 /// The whole declarator.
121 pub span: Span,
122}
123
124impl Declarator {
125 /// Whether this declarator has no name, which is what makes it abstract.
126 #[must_use]
127 pub const fn is_abstract(&self) -> bool {
128 self.name.is_none()
129 }
130}
131
132/// One step in a declarator, taking a type to another type.
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134pub enum Derived {
135 /// `*`, with the qualifiers that go on the pointer rather than on what it points at.
136 Pointer {
137 /// The qualifiers written after the star.
138 quals: Quals,
139 /// Attributes written after the star, which GCC allows there.
140 attrs: AttrList,
141 },
142 /// `[...]`.
143 Array {
144 /// What was between the brackets.
145 size: ArraySize,
146 /// The qualifiers in `int a[const 4]`, which are only legal on a parameter and which
147 /// qualify the pointer the parameter becomes.
148 quals: Quals,
149 /// Whether `static` was written, as in `int a[static 4]`, which promises the caller
150 /// passes at least that many elements. It changes no ABI and it is worth keeping,
151 /// because it licenses a diagnostic and it can inform alias analysis.
152 has_static: bool,
153 },
154 /// `(...)`.
155 Function {
156 /// The parameters.
157 params: ParamList,
158 /// Whether the list ended with an ellipsis.
159 variadic: bool,
160 /// Which of the four forms the list was written in.
161 kind: ParamKind,
162 },
163}
164
165/// What was written between a declarator's brackets.
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167pub enum ArraySize {
168 /// Nothing, as in `int a[]`, which is an incomplete type or a parameter depending on
169 /// where it is written.
170 Unspecified,
171 /// `*`, which is a variably-modified type in a prototype whose size is not named.
172 Star,
173 /// An expression, which is a constant in an ordinary array and anything at all in a VLA.
174 Expr(ExprId),
175}
176
177/// Which of the four shapes a function declarator's parameter list has.
178///
179/// The distinction between [`ParamKind::Void`] and [`ParamKind::Empty`] is not pedantry. Before
180/// C23, `int f()` says nothing about the parameters and `int f(void)` says there are none; in
181/// C23 they mean the same thing. Projects moving to `gnu23` hit exactly this, so the two are
182/// told apart here and diagnosed where it matters.
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum ParamKind {
185 /// A list of parameter declarations, named or abstract.
186 Prototype,
187 /// `(void)`.
188 Void,
189 /// `()`.
190 Empty,
191 /// A list of bare identifiers, which is an old-style definition's parameter list.
192 Identifiers,
193}
194
195/// One parameter of a function declarator.
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197pub struct Param {
198 /// The specifiers, absent in an old-style identifier list where the name stands alone and
199 /// its type comes from a declaration after the parenthesis.
200 pub specs: Option<DeclSpecsId>,
201 /// The declarator, which is abstract when the parameter has no name.
202 pub declarator: DeclaratorId,
203 /// Attributes written on the parameter.
204 pub attrs: AttrList,
205 /// The whole parameter.
206 pub span: Span,
207}
208
209/// One entry in a struct or union member list.
210///
211/// A member list is a list of declarations, and since C23 a static assertion is allowed to be
212/// one of them. Keeping the assertion in the list rather than in a second list beside it is what
213/// preserves the order the members were written in, which the printer needs and which a
214/// diagnostic about the member after the assertion needs too.
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum Member {
217 /// A member declaration.
218 Field(Field),
219 /// `static_assert(cond)` or `static_assert(cond, "message")` among the members.
220 StaticAssert {
221 /// The condition, which must be a constant expression.
222 cond: ExprId,
223 /// The message, absent in the one-argument form.
224 message: Option<StrId>,
225 /// The whole assertion, semicolon included.
226 span: Span,
227 },
228}
229
230/// One member of a struct or a union.
231#[derive(Debug, Clone, Copy, PartialEq, Eq)]
232pub struct Field {
233 /// The specifiers, shared by the members declared together.
234 pub specs: DeclSpecsId,
235 /// The declarator, absent for an anonymous struct or union member and for an unnamed
236 /// bit-field.
237 pub declarator: Option<DeclaratorId>,
238 /// The width, for a bit-field.
239 pub bits: Option<ExprId>,
240 /// Attributes on this member.
241 pub attrs: AttrList,
242 /// The whole member.
243 pub span: Span,
244}
245
246/// One enumerator of an enumeration.
247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
248pub struct Enumerator {
249 /// The name, which goes into the ordinary identifier namespace and not the tag one.
250 pub name: Symbol,
251 /// The `= value`, if there was one.
252 pub value: Option<ExprId>,
253 /// Attributes on this enumerator, which C23 allows.
254 pub attrs: AttrList,
255 /// The whole enumerator.
256 pub span: Span,
257}
258
259/// A type name, in the side table.
260pub type TypeNameId = rucc_base::Idx<TypeName>;
261
262/// A type written where a type is expected rather than where a declaration is.
263///
264/// The operand of a cast, of `sizeof`, of `_Generic`, of a compound literal. Specifiers plus an
265/// abstract declarator, which is a declarator like any other with no name in it.
266#[derive(Debug, Clone, Copy, PartialEq, Eq)]
267pub struct TypeName {
268 /// The specifiers.
269 pub specs: DeclSpecsId,
270 /// The abstract declarator, which is empty when the type is just its specifiers.
271 pub declarator: DeclaratorId,
272 /// The whole type name.
273 pub span: Span,
274}
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279
280 #[test]
281 fn a_declaration_is_twenty_four_bytes() {
282 // Set by the function definition, which is the only one carrying four fields. If this
283 // fails, something grew and the fix is a side table.
284 assert_eq!(size_of::<Decl>(), 24);
285 }
286
287 #[test]
288 fn a_declaration_id_is_four_bytes_even_when_optional() {
289 assert_eq!(size_of::<DeclId>(), 4);
290 assert_eq!(size_of::<Option<DeclId>>(), 4);
291 }
292
293 #[test]
294 fn a_declarator_with_no_name_is_abstract() {
295 let d = Declarator {
296 name: None,
297 name_span: Span::DUMMY,
298 derived: DerivedList::EMPTY,
299 span: Span::DUMMY,
300 };
301 assert!(d.is_abstract());
302 }
303}