1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
//! 6.7.9 Initialization
use super::PureAnalyzer;
use crate::data::{ast, error::SemanticError, hir::*, types, Location, Type};
impl PureAnalyzer {
pub(super) fn parse_initializer(
&mut self,
init: ast::Initializer,
ctype: &Type,
location: Location,
) -> Initializer {
use ast::Initializer::{Aggregate, Scalar};
// initializer_list
let mut expr = match init {
Aggregate(list) => return self.check_aggregate_overflow(list, ctype, location),
Scalar(expr) => self.expr(*expr),
};
// The only time (that I know of) that an expression will initialize a non-scalar
// is for character literals.
let is_char_array = match ctype {
Type::Array(inner, _) => inner.is_char(),
_ => false,
};
// See section 6.7.9 of the C11 standard:
// The initializer for a scalar shall be a single expression, optionally enclosed in braces.
// The initial value of the object is that of the expression (after conversion)
if !is_char_array {
expr = expr
.rval()
// if ctype is not a scalar, this will report an error, so we don't have to handle it specially
.implicit_cast(ctype, &mut self.error_handler);
}
if !expr.lval && self.scope.is_global() && ctype.is_pointer() {
expr = Expr {
lval: false,
location: expr.location,
ctype: expr.ctype.clone(),
expr: ExprType::StaticRef(Box::new(expr)),
};
}
Initializer::Scalar(Box::new(expr))
}
fn check_aggregate_overflow(
&mut self,
list: Vec<ast::Initializer>,
ctype: &Type,
location: Location,
) -> Initializer {
let len = list.len();
let mut iter = list.into_iter().peekable();
let init = self.aggregate_initializer(&mut iter, ctype, location);
let leftover = iter.count();
if leftover > 0 {
self.err(SemanticError::TooManyMembers(len - leftover, len), location);
}
init
}
// handle char[][3] = {{1,2,3}}, but also = {1,2,3} and {{1}, 2, 3}
// NOTE: this does NOT consume {} except for sub-elements
// see p17: "Each brace-enclosed initializer list has an associated current object"
// For each subobject of the enclosing object (`type_at`), initialize it, possibly recursively.
fn aggregate_initializer(
&mut self,
list: &mut std::iter::Peekable<impl Iterator<Item = ast::Initializer>>,
elem_type: &Type,
location: Location,
) -> Initializer {
use ast::Initializer::{Aggregate, Scalar};
let mut elems = vec![];
if list.peek().is_none() {
self.err(SemanticError::EmptyInitializer, location);
return Initializer::InitializerList(elems);
}
// char [][3] = {1};
while let Some(elem) = list.peek() {
let inner = elem_type.type_at(elems.len()).unwrap_or_else(|err| {
// int a[1] = {1, 2};
self.err(err, location);
Type::Error
});
// int a[][3] = {{1,2,3}}
// ^
// initializer is aggregate, type errors will be caught later
// If the initializer of a subaggregate or contained union begins with a left brace,
// the initializers enclosed by that brace and its matching right brace initialize
// the elements or members of the subaggregate or the contained union.
let next = match elem {
Aggregate(_) => match list.next() {
Some(Aggregate(inner_list)) => {
self.check_aggregate_overflow(inner_list, &inner, location)
}
_ => unreachable!(),
},
Scalar(_) => {
// int a[][3] = {1,2,3}
// ^
// type is aggregate and initializer is scalar
// see if we can short circuit int[][3] -> int[3]
if inner != Type::Error && !inner.is_scalar() {
// Note: this element is _not_ consumed
self.aggregate_initializer(list, &inner, location)
// type is scalar and initializer is scalar
// int a[][3] = {{1,2,3}}
} else {
let expr = match list.next() {
Some(Scalar(expr)) => self
.expr(*expr)
.rval()
.implicit_cast(&inner, &mut self.error_handler),
_ => unreachable!(),
};
Initializer::Scalar(Box::new(expr))
}
}
};
elems.push(next);
// Otherwise, only enough initializers from the list are taken
// to account for the elements or members of the subaggregate
// or the first member of the contained union;
// any remaining initializers are left to initialize the next
// element or member of the aggregate of which the current
// subaggregate or contained union is a part.
if elems.len() == elem_type.type_len() {
break;
}
}
Initializer::InitializerList(elems)
}
}
impl Type {
/// Given a type, return the maximum number of initializers for that type
fn type_len(&self) -> usize {
use types::ArrayType;
match self {
ty if ty.is_scalar() => 1,
Type::Array(_, ArrayType::Fixed(size)) => *size as usize,
Type::Array(_, ArrayType::Unbounded) => 0,
Type::Struct(st) | Type::Union(st) => st.members().len(),
Type::Function { .. } | Type::Error => 1,
_ => unimplemented!("type checking for {}", self),
}
}
/// Given a type and an index,
/// return the type expected at that index in the initializer.
///
/// e.g. if `struct s { int i; float f; };` is in scope,
/// `type_at(s, 0)` will be `int` and `type_at(s, 1)` will be `float`
fn type_at(&self, index: usize) -> Result<Type, SemanticError> {
match self {
ty if ty.is_scalar() => {
if index == 0 {
Ok(ty.clone())
} else {
Err(SemanticError::AggregateInitializingScalar(
ty.clone(),
index + 1,
))
}
}
Type::Array(inner, _) => Ok((**inner).clone()),
Type::Struct(struct_type) => {
let symbols = struct_type.members();
symbols.get(index).map_or_else(
|| Err(SemanticError::TooManyMembers(symbols.len(), index)),
|symbol| Ok(symbol.ctype.clone()),
)
}
Type::Union(struct_type) => {
if index != 0 {
return Err("can only initialize first member of an enum".into());
}
let members = struct_type.members();
Ok(members
.first()
.map(|m| m.ctype.clone())
.unwrap_or(Type::Error))
}
Type::Function { .. } | Type::Error => Ok(Type::Error),
_ => unimplemented!("type checking for aggregate initializers of type {}", self),
}
}
}
#[cfg(test)]
mod test {
use super::super::test::*;
use super::*;
use crate::data::Locatable;
#[test]
fn test_initializers() {
// scalars
assert!(decl("int i = 3;").is_ok());
// bounded and unbounded arrays
let parsed = [
decl("int a[] = {1, 2, 3};"),
decl("int a[3] = {1, 2, 3};"),
// possibly with trailing commas
decl("int a[] = {1, 2, 3,};"),
decl("int a[3] = {1, 2, 3,};"),
// or nested
decl("int a[][3] = {{1, 2, 3}};"),
decl("int a[][3] = {{1, 2, 3,}};"),
decl("int a[][3] = {{1, 2, 3,},};"),
decl("int a[1][3] = {{1, 2, 3,},};"),
// with misleading braces
decl("int a[][3] = {1, 2, 3};"),
decl("int a[][3] = {1, 2, 3,};"),
];
for res in &parsed {
match res.as_ref() {
Ok(Declaration {
init: Some(Initializer::InitializerList(_)),
..
}) => {}
Ok(other) => panic!("expected initializer list, got declaration: {}", other),
Err(Locatable { data, .. }) => {
panic!("expected initializer list, got error: {}", data)
}
};
}
for err in &[
"int i = {};",
"int a[] = {};",
"int i = {1, 2};",
"int a[][3] = {{}};",
"int a[2] = {{1, 2}};",
] {
assert!(decl(err).is_err(), "{} should be an error", err);
}
}
#[test]
fn test_initializers_more() {
assert_same("int a[][3] = {1,2,3};", "int a[][3] = {{ 1, 2, 3 }};");
assert_same(
"int a[][3] = {1,2,3,4};",
"int a[][3] = {{ 1, 2, 3 }, { 4 } };",
);
assert_same(
"struct { int i; float f; } s = {1, 1.2};",
"struct { int i; float f; } s = {(int)1, (float)1.2};",
);
assert_errs_decls("struct s { int *p; } s = { 1.0 }", 1, 0, 1);
}
}