Allow to initialize struct flexible array member

This commit is contained in:
Rui Ueyama 2020-09-20 16:16:00 +09:00
parent 824543bb2f
commit cd688a89b8
3 changed files with 59 additions and 3 deletions

View File

@ -243,6 +243,7 @@ struct Type {
// Struct
Member *members;
bool is_flexible;
// Function type
Type *return_ty;

45
parse.c
View File

@ -256,8 +256,16 @@ static Initializer *new_initializer(Type *ty, bool is_flexible) {
init->children = calloc(len, sizeof(Initializer *));
for (Member *mem = ty->members; mem; mem = mem->next)
init->children[mem->idx] = new_initializer(mem->ty, false);
for (Member *mem = ty->members; mem; mem = mem->next) {
if (is_flexible && ty->is_flexible && !mem->next) {
Initializer *child = calloc(1, sizeof(Initializer));
child->ty = mem->ty;
child->is_flexible = true;
init->children[mem->idx] = child;
} else {
init->children[mem->idx] = new_initializer(mem->ty, false);
}
}
return init;
}
@ -814,9 +822,38 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) {
init->expr = assign(rest, tok);
}
static Type *copy_struct_type(Type *ty) {
ty = copy_type(ty);
Member head = {};
Member *cur = &head;
for (Member *mem = ty->members; mem; mem = mem->next) {
Member *m = calloc(1, sizeof(Member));
*m = *mem;
cur = cur->next = m;
}
ty->members = head.next;
return ty;
}
static Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty) {
Initializer *init = new_initializer(ty, true);
initializer2(rest, tok, init);
if ((ty->kind == TY_STRUCT || ty->kind == TY_UNION) && ty->is_flexible) {
ty = copy_struct_type(ty);
Member *mem = ty->members;
while (mem->next)
mem = mem->next;
mem->ty = init->children[mem->idx]->ty;
ty->size += mem->ty->size;
*new_ty = ty;
return init;
}
*new_ty = init->ty;
return init;
}
@ -1709,8 +1746,10 @@ static void struct_members(Token **rest, Token *tok, Type *ty) {
// If the last element is an array of incomplete type, it's
// called a "flexible array member". It should behave as if
// if were a zero-sized array.
if (cur != &head && cur->ty->kind == TY_ARRAY && cur->ty->array_len < 0)
if (cur != &head && cur->ty->kind == TY_ARRAY && cur->ty->array_len < 0) {
cur->ty = array_of(cur->ty->base, 0);
ty->is_flexible = true;
}
*rest = tok->next;
ty->members = head.next;

View File

@ -28,6 +28,14 @@ struct {int a[2];} g41[2] = {1, 2, 3, 4};
char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0};
char *g44 = {"foo"};
typedef char T60[];
T60 g60 = {1, 2, 3};
T60 g61 = {1, 2, 3, 4, 5, 6};
typedef struct { char a, b[]; } T65;
T65 g65 = {'f','o','o',0};
T65 g66 = {'f','o','o','b','a','r',0};
int main() {
ASSERT(1, ({ int x[3]={1,2,3}; x[0]; }));
ASSERT(2, ({ int x[3]={1,2,3}; x[1]; }));
@ -165,6 +173,14 @@ int main() {
ASSERT(1, ({ union {int a; char b;} x={1,}; x.a; }));
ASSERT(2, ({ enum {x,y,z,}; z; }));
ASSERT(3, sizeof(g60));
ASSERT(6, sizeof(g61));
ASSERT(4, sizeof(g65));
ASSERT(7, sizeof(g66));
ASSERT(0, strcmp(g65.b, "oo"));
ASSERT(0, strcmp(g66.b, "oobar"));
printf("OK\n");
return 0;
}