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
This commit is contained in:
grischka 2021-05-15 18:40:16 +02:00
parent 0c6adcbe53
commit 719d96665e
3 changed files with 59 additions and 13 deletions

View file

@ -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 don't consume them as initializer value (which would commit them
to some anonymous symbol). */ to some anonymous symbol). */
tok != TOK_LSTR && tok != TOK_STR && 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); parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST);
nocode_wanted = ncw_prev;
flags |= DIF_HAVE_ELEM; flags |= DIF_HAVE_ELEM;
} }
if ((flags & DIF_HAVE_ELEM) && if (type->t & VT_ARRAY) {
!(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) {
no_oblock = 1; no_oblock = 1;
if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) || if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) ||
tok == '{') { tok == '{') {
@ -8258,6 +8260,14 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
} }
if (!no_oblock) if (!no_oblock)
skip('}'); 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) { } else if ((type->t & VT_BTYPE) == VT_STRUCT) {
no_oblock = 1; no_oblock = 1;
if ((flags & DIF_FIRST) || tok == '{') { 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; n = s->c;
size1 = 1; size1 = 1;
goto do_init_list; goto do_init_list;
} else if (tok == '{') { } else if (tok == '{') {
if (flags & DIF_HAVE_ELEM) if (flags & DIF_HAVE_ELEM)
skip(';'); skip(';');
next(); next();
decl_initializer(p, type, c, flags & ~DIF_HAVE_ELEM); decl_initializer(p, type, c, flags & ~DIF_HAVE_ELEM);
skip('}'); 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 /* 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 this on anything than an array if DIF_SIZE_ONLY (and even then
only on the outermost level, so no recursion would be needed), 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 But GNU C supports it, so we need to recurse even into
subfields of structs and arrays when DIF_SIZE_ONLY is set. */ subfields of structs and arrays when DIF_SIZE_ONLY is set. */
/* just skip expression */ /* just skip expression */
skip_or_save_block(NULL); if (flags & DIF_HAVE_ELEM)
vpop();
else
skip_or_save_block(NULL);
} else { } else {
if (!(flags & DIF_HAVE_ELEM)) { if (!(flags & DIF_HAVE_ELEM)) {
/* This should happen only when we haven't parsed /* 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"); expect("string constant");
parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST); parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST);
} }
init_putv:
if (!p->sec && (flags & DIF_CLEAR) /* container was already zero'd */ if (!p->sec && (flags & DIF_CLEAR) /* container was already zero'd */
&& (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST && (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST
&& vtop->c.i == 0 && vtop->c.i == 0

View file

@ -342,6 +342,35 @@ test_zero_init (void)
test_correct_filling (&d.a); test_correct_filling (&d.a);
return 0; 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() int main()
{ {
@ -373,5 +402,6 @@ int main()
test_multi_relocs(); test_multi_relocs();
test_zero_init(); test_zero_init();
test_init_ranges(); test_init_ranges();
test_init_struct_from_struct();
return 0; return 0;
} }

View file

@ -55,3 +55,4 @@ sea_fill0: okay
sea_fill1: okay sea_fill1: okay
sea_fill2: okay sea_fill2: okay
1438 1438
test_init_struct_from_struct: 1 2 3 4 - 1 2 3 4 - 3 4 5 6