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:
parent
0c6adcbe53
commit
719d96665e
3 changed files with 59 additions and 13 deletions
41
tccgen.c
41
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
|
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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue