From 719d96665e1ac404b78d4a90eeae36d7e4159108 Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 15 May 2021 18:40:16 +0200 Subject: [PATCH] tccgen: Allow struct init from struct Example: struct S {int x,y;} a = {1, 2}, b = {3, 4}, c[] = {a, b}, // new d[] = {b, (struct S){5,6}}; // new --- tccgen.c | 41 ++++++++++++++++++++++++++------------ tests/tests2/90_struct-init.c | 30 ++++++++++++++++++++++++++++ tests/tests2/90_struct-init.expect | 1 + 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/tccgen.c b/tccgen.c index 778d7d51..c5be6594 100644 --- a/tccgen.c +++ b/tccgen.c @@ -8124,20 +8124,22 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f don't consume them as initializer value (which would commit them to some anonymous symbol). */ tok != TOK_LSTR && tok != TOK_STR && - !(flags & DIF_SIZE_ONLY)) { + (!(flags & DIF_SIZE_ONLY) + /* a struct may be initialized from a struct of same type, as in + struct {int x,y;} a = {1,2}, b = {3,4}, c[] = {a,b}; + In that case we need to parse the element in order to check + it for compatibility below */ + || (type->t & VT_BTYPE) == VT_STRUCT) + ) { + int ncw_prev = nocode_wanted; + if ((flags & DIF_SIZE_ONLY) && !p->sec) + ++nocode_wanted; parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST); + nocode_wanted = ncw_prev; flags |= DIF_HAVE_ELEM; } - if ((flags & DIF_HAVE_ELEM) && - !(type->t & VT_ARRAY) && - /* Use i_c_parameter_t, to strip toplevel qualifiers. - The source type might have VT_CONSTANT set, which is - of course assignable to non-const elements. */ - is_compatible_unqualified_types(type, &vtop->type)) { - goto init_putv; - - } else if (type->t & VT_ARRAY) { + if (type->t & VT_ARRAY) { no_oblock = 1; if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) || tok == '{') { @@ -8258,6 +8260,14 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f } if (!no_oblock) skip('}'); + + } else if ((flags & DIF_HAVE_ELEM) + /* Use i_c_parameter_t, to strip toplevel qualifiers. + The source type might have VT_CONSTANT set, which is + of course assignable to non-const elements. */ + && is_compatible_unqualified_types(type, &vtop->type)) { + goto one_elem; + } else if ((type->t & VT_BTYPE) == VT_STRUCT) { no_oblock = 1; if ((flags & DIF_FIRST) || tok == '{') { @@ -8269,13 +8279,15 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f n = s->c; size1 = 1; goto do_init_list; + } else if (tok == '{') { if (flags & DIF_HAVE_ELEM) skip(';'); next(); decl_initializer(p, type, c, flags & ~DIF_HAVE_ELEM); skip('}'); - } else if ((flags & DIF_SIZE_ONLY)) { + + } else one_elem: if ((flags & DIF_SIZE_ONLY)) { /* If we supported only ISO C we wouldn't have to accept calling this on anything than an array if DIF_SIZE_ONLY (and even then only on the outermost level, so no recursion would be needed), @@ -8283,7 +8295,11 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f But GNU C supports it, so we need to recurse even into subfields of structs and arrays when DIF_SIZE_ONLY is set. */ /* just skip expression */ - skip_or_save_block(NULL); + if (flags & DIF_HAVE_ELEM) + vpop(); + else + skip_or_save_block(NULL); + } else { if (!(flags & DIF_HAVE_ELEM)) { /* This should happen only when we haven't parsed @@ -8293,7 +8309,6 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f expect("string constant"); parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST); } - init_putv: if (!p->sec && (flags & DIF_CLEAR) /* container was already zero'd */ && (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST && vtop->c.i == 0 diff --git a/tests/tests2/90_struct-init.c b/tests/tests2/90_struct-init.c index 1dae3c92..de8505d9 100644 --- a/tests/tests2/90_struct-init.c +++ b/tests/tests2/90_struct-init.c @@ -342,6 +342,35 @@ test_zero_init (void) test_correct_filling (&d.a); return 0; } + +void test_init_struct_from_struct(void) +{ + int i = 0; + struct S {int x,y;} + a = {1,2}, + b = {3,4}, + c[] = {a,b}, + d[] = {++i, ++i, ++i, ++i}, + e[] = {b, (struct S){5,6}} + ; + + printf("%s: %d %d %d %d - %d %d %d %d - %d %d %d %d\n", + __FUNCTION__, + c[0].x, + c[0].y, + c[1].x, + c[1].y, + d[0].x, + d[0].y, + d[1].x, + d[1].y, + e[0].x, + e[0].y, + e[1].x, + e[1].y + ); +} + int main() { @@ -373,5 +402,6 @@ int main() test_multi_relocs(); test_zero_init(); test_init_ranges(); + test_init_struct_from_struct(); return 0; } diff --git a/tests/tests2/90_struct-init.expect b/tests/tests2/90_struct-init.expect index 1b7b171e..45c8cf42 100644 --- a/tests/tests2/90_struct-init.expect +++ b/tests/tests2/90_struct-init.expect @@ -55,3 +55,4 @@ sea_fill0: okay sea_fill1: okay sea_fill2: okay 1438 +test_init_struct_from_struct: 1 2 3 4 - 1 2 3 4 - 3 4 5 6 -- 2.11.4.GIT