struct-init: Correctly parse unnamed member initializers
For union U { struct {int a,b}; int c; }; union U u = {{ 1, 2, }}; The unnamed first member of union U needs to actually exist in the structure so initializer parsing isn't confused about the double braces. That means also the a and b members must be part of _that_, not of union U directly. Which in turn means we need to do a bit more work for field lookup. See the testcase extension for more things that need to work.
This commit is contained in:
parent
21da73c383
commit
9e86ebee94
3 changed files with 78 additions and 21 deletions
72
tccgen.c
72
tccgen.c
|
@ -3181,6 +3181,22 @@ static void parse_attribute(AttributeDef *ad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Sym * find_field (CType *type, int v)
|
||||||
|
{
|
||||||
|
Sym *s = type->ref;
|
||||||
|
v |= SYM_FIELD;
|
||||||
|
while ((s = s->next) != NULL) {
|
||||||
|
if ((s->v & SYM_FIELD) && (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
|
||||||
|
Sym *ret = find_field (&s->type, v);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (s->v == v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
|
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
|
||||||
static void struct_decl(CType *type, AttributeDef *ad, int u)
|
static void struct_decl(CType *type, AttributeDef *ad, int u)
|
||||||
{
|
{
|
||||||
|
@ -3404,13 +3420,40 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
|
if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
|
/* An anonymous struct/union. Adjust member offsets
|
||||||
|
to reflect the real offset of our containing struct.
|
||||||
|
Also set the offset of this anon member inside
|
||||||
|
the outer struct to be zero. Via this it
|
||||||
|
works when accessing the field offset directly
|
||||||
|
(from base object), as well as when recursing
|
||||||
|
members in initializer handling. */
|
||||||
|
int v2 = btype.ref->v;
|
||||||
|
if (!(v2 & SYM_FIELD) &&
|
||||||
|
(v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||||
|
Sym **pps;
|
||||||
|
/* This happens only with MS extensions. The
|
||||||
|
anon member has a named struct type, so it
|
||||||
|
potentially is shared with other references.
|
||||||
|
We need to unshare members so we can modify
|
||||||
|
them. */
|
||||||
|
ass = type1.ref;
|
||||||
|
type1.ref = sym_push(anon_sym++ | SYM_FIELD,
|
||||||
|
&type1.ref->type, 0,
|
||||||
|
type1.ref->c);
|
||||||
|
pps = &type1.ref->next;
|
||||||
|
while ((ass = ass->next) != NULL) {
|
||||||
|
*pps = sym_push(ass->v, &ass->type, 0, ass->c);
|
||||||
|
pps = &((*pps)->next);
|
||||||
|
}
|
||||||
|
*pps = NULL;
|
||||||
|
}
|
||||||
ass = type1.ref;
|
ass = type1.ref;
|
||||||
while ((ass = ass->next) != NULL) {
|
while ((ass = ass->next) != NULL)
|
||||||
ss = sym_push(ass->v, &ass->type, 0, offset + ass->c);
|
ass->c += offset;
|
||||||
*ps = ss;
|
offset = 0;
|
||||||
ps = &ss->next;
|
v = anon_sym++;
|
||||||
}
|
}
|
||||||
} else if (v) {
|
if (v) {
|
||||||
ss = sym_push(v | SYM_FIELD, &type1, 0, offset);
|
ss = sym_push(v | SYM_FIELD, &type1, 0, offset);
|
||||||
*ps = ss;
|
*ps = ss;
|
||||||
ps = &ss->next;
|
ps = &ss->next;
|
||||||
|
@ -4536,13 +4579,7 @@ ST_FUNC void unary(void)
|
||||||
next();
|
next();
|
||||||
if (tok == TOK_CINT || tok == TOK_CUINT)
|
if (tok == TOK_CINT || tok == TOK_CUINT)
|
||||||
expect("field name");
|
expect("field name");
|
||||||
s = vtop->type.ref;
|
s = find_field(&vtop->type, tok);
|
||||||
/* find field */
|
|
||||||
tok |= SYM_FIELD;
|
|
||||||
while ((s = s->next) != NULL) {
|
|
||||||
if (s->v == tok)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!s)
|
if (!s)
|
||||||
tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc));
|
tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc));
|
||||||
/* add field offset to pointer */
|
/* add field offset to pointer */
|
||||||
|
@ -5729,14 +5766,7 @@ static void decl_designator(CType *type, Section *sec, unsigned long c,
|
||||||
struct_field:
|
struct_field:
|
||||||
if ((type->t & VT_BTYPE) != VT_STRUCT)
|
if ((type->t & VT_BTYPE) != VT_STRUCT)
|
||||||
expect("struct/union type");
|
expect("struct/union type");
|
||||||
s = type->ref;
|
f = find_field(type, l);
|
||||||
l |= SYM_FIELD;
|
|
||||||
f = s->next;
|
|
||||||
while (f) {
|
|
||||||
if (f->v == l)
|
|
||||||
break;
|
|
||||||
f = f->next;
|
|
||||||
}
|
|
||||||
if (!f)
|
if (!f)
|
||||||
expect("field");
|
expect("field");
|
||||||
if (!notfirst)
|
if (!notfirst)
|
||||||
|
|
|
@ -77,6 +77,25 @@ struct SU {
|
||||||
};
|
};
|
||||||
struct SU gsu = {5,6};
|
struct SU gsu = {5,6};
|
||||||
|
|
||||||
|
/* Unnamed struct/union members aren't ISO C, but it's a widely accepted
|
||||||
|
extension. See below for further extensions to that under -fms-extension.*/
|
||||||
|
union UV {
|
||||||
|
struct {u8 a,b;};
|
||||||
|
struct S s;
|
||||||
|
};
|
||||||
|
union UV guv = {{6,5}};
|
||||||
|
union UV guv2 = {{.b = 7, .a = 8}};
|
||||||
|
union UV guv3 = {.b = 8, .a = 7};
|
||||||
|
|
||||||
|
/* Under -fms-extensions also the following is valid:
|
||||||
|
union UV2 {
|
||||||
|
struct Anon {u8 a,b;}; // unnamed member, but tagged struct, ...
|
||||||
|
struct S s;
|
||||||
|
};
|
||||||
|
struct Anon gan = { 10, 11 }; // ... which makes it available here.
|
||||||
|
union UV2 guv4 = {{4,3}}; // and the other inits from above as well
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
void print_ (const char *name, const u8 *p, long size)
|
void print_ (const char *name, const u8 *p, long size)
|
||||||
{
|
{
|
||||||
|
@ -144,6 +163,10 @@ int main()
|
||||||
print(sinit16);
|
print(sinit16);
|
||||||
print(gw);
|
print(gw);
|
||||||
print(gsu);
|
print(gsu);
|
||||||
|
print(guv);
|
||||||
|
print(guv.b);
|
||||||
|
print(guv2);
|
||||||
|
print(guv3);
|
||||||
foo(&gw);
|
foo(&gw);
|
||||||
//printf("q: %s\n", q);
|
//printf("q: %s\n", q);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -13,6 +13,10 @@ gv3: 7 8 9 a 68 6f 68 6f 0 0 0 0 0 0 0 0 0 0 0 0 31 32
|
||||||
sinit16: 1 0 0 0 2 0 0 0
|
sinit16: 1 0 0 0 2 0 0 0
|
||||||
gw: 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
gw: 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||||
gsu: 5 6
|
gsu: 5 6
|
||||||
|
guv: 6 5 0 0
|
||||||
|
guv.b: 5
|
||||||
|
guv2: 8 7 0 0
|
||||||
|
guv3: 7 8 0 0
|
||||||
ls: 1 2 3 4
|
ls: 1 2 3 4
|
||||||
ls2: 1 2 3 4
|
ls2: 1 2 3 4
|
||||||
lt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a
|
lt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a
|
||||||
|
|
Loading…
Reference in a new issue