History

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.

Michael Matz committed 10 years ago

Commit 9e86ebe1 parent 21da73c3 files · +78 −21Browse files

Unified · Split

3 files
  1. tccgen.c +51 −21
  2. tests/tests2/86-struct-init.c +23 −0
  3. tests/tests2/86-struct-init.expect +4 −0
tccgen.c+51−21
@@ -3181,6 +3181,22 @@ static void parse_attribute(AttributeDef *ad) · 3180 unmodified lines
31813181 }
31823182 }
31833183
3184+static Sym * find_field (CType *type, int v)
3185+{
3186+ Sym *s = type->ref;
3187+ v |= SYM_FIELD;
3188+ while ((s = s->next) != NULL) {
3189+ if ((s->v & SYM_FIELD) && (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
3190+ Sym *ret = find_field (&s->type, v);
3191+ if (ret)
3192+ return ret;
3193+ }
3194+ if (s->v == v)
3195+ break;
3196+ }
3197+ return s;
3198+}
3199+
31843200 /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
31853201 static void struct_decl(CType *type, AttributeDef *ad, int u)
31863202 {
@@ -3404,13 +3420,40 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 217 unmodified lines
34043420 #endif
34053421 }
34063422 if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
3423+ /* An anonymous struct/union. Adjust member offsets
3424+ to reflect the real offset of our containing struct.
3425+ Also set the offset of this anon member inside
3426+ the outer struct to be zero. Via this it
3427+ works when accessing the field offset directly
3428+ (from base object), as well as when recursing
3429+ members in initializer handling. */
3430+ int v2 = btype.ref->v;
3431+ if (!(v2 & SYM_FIELD) &&
3432+ (v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
3433+ Sym **pps;
3434+ /* This happens only with MS extensions. The
3435+ anon member has a named struct type, so it
3436+ potentially is shared with other references.
3437+ We need to unshare members so we can modify
3438+ them. */
3439+ ass = type1.ref;
3440+ type1.ref = sym_push(anon_sym++ | SYM_FIELD,
3441+ &type1.ref->type, 0,
3442+ type1.ref->c);
3443+ pps = &type1.ref->next;
3444+ while ((ass = ass->next) != NULL) {
3445+ *pps = sym_push(ass->v, &ass->type, 0, ass->c);
3446+ pps = &((*pps)->next);
3447+ }
3448+ *pps = NULL;
3449+ }
34073450 ass = type1.ref;
3408− while ((ass = ass->next) != NULL) {
3409− ss = sym_push(ass->v, &ass->type, 0, offset + ass->c);
3410− *ps = ss;
3411− ps = &ss->next;
3412− }
3413− } else if (v) {
3451+ while ((ass = ass->next) != NULL)
3452+ ass->c += offset;
3453+ offset = 0;
3454+ v = anon_sym++;
3455+ }
3456+ if (v) {
34143457 ss = sym_push(v | SYM_FIELD, &type1, 0, offset);
34153458 *ps = ss;
34163459 ps = &ss->next;
@@ -4536,13 +4579,7 @@ ST_FUNC void unary(void) · 1119 unmodified lines
45364579 next();
45374580 if (tok == TOK_CINT || tok == TOK_CUINT)
45384581 expect("field name");
4539− s = vtop->type.ref;
4540− /* find field */
4541− tok |= SYM_FIELD;
4542− while ((s = s->next) != NULL) {
4543− if (s->v == tok)
4544− break;
4545− }
4582+ s = find_field(&vtop->type, tok);
45464583 if (!s)
45474584 tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc));
45484585 /* add field offset to pointer */
@@ -5729,14 +5766,7 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, · 1180 unmodified lines
57295766 struct_field:
57305767 if ((type->t & VT_BTYPE) != VT_STRUCT)
57315768 expect("struct/union type");
5732− s = type->ref;
5733− l |= SYM_FIELD;
5734− f = s->next;
5735− while (f) {
5736− if (f->v == l)
5737− break;
5738− f = f->next;
5739− }
5769+ f = find_field(type, l);
57405770 if (!f)
57415771 expect("field");
57425772 if (!notfirst)
tests/tests2/86-struct-init.c+23−0
@@ -77,6 +77,25 @@ struct SU { · 76 unmodified lines
7777 };
7878 struct SU gsu = {5,6};
7979
80+/* Unnamed struct/union members aren't ISO C, but it's a widely accepted
81+ extension. See below for further extensions to that under -fms-extension.*/
82+union UV {
83+ struct {u8 a,b;};
84+ struct S s;
85+};
86+union UV guv = {{6,5}};
87+union UV guv2 = {{.b = 7, .a = 8}};
88+union UV guv3 = {.b = 8, .a = 7};
89+
90+/* Under -fms-extensions also the following is valid:
91+union UV2 {
92+ struct Anon {u8 a,b;}; // unnamed member, but tagged struct, ...
93+ struct S s;
94+};
95+struct Anon gan = { 10, 11 }; // ... which makes it available here.
96+union UV2 guv4 = {{4,3}}; // and the other inits from above as well
97+*/
98+
8099 #include <stdio.h>
81100 void print_ (const char *name, const u8 *p, long size)
82101 {
@@ -144,6 +163,10 @@ int main() · 61 unmodified lines
144163 print(sinit16);
145164 print(gw);
146165 print(gsu);
166+ print(guv);
167+ print(guv.b);
168+ print(guv2);
169+ print(guv3);
147170 foo(&gw);
148171 //printf("q: %s\n", q);
149172 return 0;
tests/tests2/86-struct-init.expect+4−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 · 12 unmodified lines
1313 sinit16: 1 0 0 0 2 0 0 0
1414 gw: 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1515 gsu: 5 6
16+guv: 6 5 0 0
17+guv.b: 5
18+guv2: 8 7 0 0
19+guv3: 7 8 0 0
1620 ls: 1 2 3 4
1721 ls2: 1 2 3 4
1822 lt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t