Initialize excess array elements with zero

This commit is contained in:
Rui Ueyama 2020-09-18 13:36:43 +09:00
parent 22dd560ecf
commit ae0a37dc4b
4 changed files with 31 additions and 4 deletions

View File

@ -131,6 +131,7 @@ typedef enum {
ND_VAR, // Variable
ND_NUM, // Integer
ND_CAST, // Type cast
ND_MEMZERO, // Zero-clear a stack variable
} NodeKind;
// AST node type

View File

@ -212,6 +212,13 @@ static void gen_expr(Node *node) {
gen_expr(node->lhs);
cast(node->lhs->ty, node->ty);
return;
case ND_MEMZERO:
// `rep stosb` is equivalent to `memset(%rdi, %al, %rcx)`.
println(" mov $%d, %%rcx", node->var->ty->size);
println(" lea %d(%%rbp), %%rdi", node->var->offset);
println(" mov $0, %%al");
println(" rep stosb");
return;
case ND_COND: {
int c = count();
gen_expr(node->cond);

19
parse.c
View File

@ -609,7 +609,7 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) {
if (init->ty->kind == TY_ARRAY) {
tok = skip(tok, "{");
for (int i = 0; i < init->ty->array_len; i++) {
for (int i = 0; i < init->ty->array_len && !equal(tok, "}"); i++) {
if (i > 0)
tok = skip(tok, ",");
initializer2(&tok, tok, init->children[i]);
@ -647,9 +647,11 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, Token
return node;
}
if (!init->expr)
return new_node(ND_NULL_EXPR, tok);
Node *lhs = init_desg_expr(desg, tok);
Node *rhs = init->expr;
return new_binary(ND_ASSIGN, lhs, rhs, tok);
return new_binary(ND_ASSIGN, lhs, init->expr, tok);
}
// A variable definition with an initializer is a shorthand notation
@ -665,7 +667,16 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, Token
static Node *lvar_initializer(Token **rest, Token *tok, Obj *var) {
Initializer *init = initializer(rest, tok, var->ty);
InitDesg desg = {NULL, 0, var};
return create_lvar_init(init, var->ty, &desg, tok);
// If a partial initializer list is given, the standard requires
// that unspecified elements are set to 0. Here, we simply
// zero-initialize the entire memory region of a variable before
// initializing it with user-supplied values.
Node *lhs = new_node(ND_MEMZERO, tok);
lhs->var = var;
Node *rhs = create_lvar_init(init, var->ty, &desg, tok);
return new_binary(ND_COMMA, lhs, rhs, tok);
}
// Returns true if a given token represents a type.

View File

@ -10,6 +10,14 @@ int main() {
ASSERT(4, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][0]; }));
ASSERT(6, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][2]; }));
ASSERT(0, ({ int x[3]={}; x[0]; }));
ASSERT(0, ({ int x[3]={}; x[1]; }));
ASSERT(0, ({ int x[3]={}; x[2]; }));
ASSERT(2, ({ int x[2][3]={{1,2}}; x[0][1]; }));
ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][0]; }));
ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][2]; }));
printf("OK\n");
return 0;
}