| @@ -3181,6 +3181,22 @@ static void parse_attribute(AttributeDef *ad) · 3180 unmodified lines |
| 3181 | 3181 | } |
| 3182 | 3182 | } |
| 3183 | 3183 | |
| 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 | + |
| 3184 | 3200 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
| 3185 | 3201 | static void struct_decl(CType *type, AttributeDef *ad, int u) |
| 3186 | 3202 | { |
| @@ -3404,13 +3420,40 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 217 unmodified lines |
| 3404 | 3420 | #endif |
| 3405 | 3421 | } |
| 3406 | 3422 | 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 | + } |
| 3407 | 3450 | 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) { |
| 3414 | 3457 | ss = sym_push(v | SYM_FIELD, &type1, 0, offset); |
| 3415 | 3458 | *ps = ss; |
| 3416 | 3459 | ps = &ss->next; |
| @@ -4536,13 +4579,7 @@ ST_FUNC void unary(void) · 1119 unmodified lines |
| 4536 | 4579 | next(); |
| 4537 | 4580 | if (tok == TOK_CINT || tok == TOK_CUINT) |
| 4538 | 4581 | 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); |
| 4546 | 4583 | if (!s) |
| 4547 | 4584 | tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc)); |
| 4548 | 4585 | /* add field offset to pointer */ |
| @@ -5729,14 +5766,7 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, · 1180 unmodified lines |
| 5729 | 5766 | struct_field: |
| 5730 | 5767 | if ((type->t & VT_BTYPE) != VT_STRUCT) |
| 5731 | 5768 | 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); |
| 5740 | 5770 | if (!f) |
| 5741 | 5771 | expect("field"); |
| 5742 | 5772 | if (!notfirst) |