Fix more struct inits

anonymous struct members were somewhat broken as the testcase
demonstrates.  The reason is the jumping through hoops to fiddle
with the offsets I once introduced to avoid having to track
a cumulative offset.  That's now not necessary anymore and actively
harmful, doing the obvious thing is now better.
This commit is contained in:
Michael Matz 2019-04-11 00:30:41 +02:00
parent 94846d3eef
commit 0344c0b6a0
3 changed files with 29 additions and 55 deletions

View File

@ -3588,7 +3588,7 @@ redo:
goto redo;
}
static Sym * find_field (CType *type, int v)
static Sym * find_field (CType *type, int v, int *cumofs)
{
Sym *s = type->ref;
v |= SYM_FIELD;
@ -3596,9 +3596,11 @@ static Sym * find_field (CType *type, int v)
if ((s->v & SYM_FIELD) &&
(s->type.t & VT_BTYPE) == VT_STRUCT &&
(s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
Sym *ret = find_field (&s->type, v);
if (ret)
Sym *ret = find_field (&s->type, v, cumofs);
if (ret) {
*cumofs += s->c;
return ret;
}
}
if (s->v == v)
break;
@ -3606,18 +3608,6 @@ static Sym * find_field (CType *type, int v)
return s;
}
static void struct_add_offset (Sym *s, int offset)
{
while ((s = s->next) != NULL) {
if ((s->v & SYM_FIELD) &&
(s->type.t & VT_BTYPE) == VT_STRUCT &&
(s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
struct_add_offset(s->type.ref, offset);
} else
s->c += offset;
}
}
static void struct_layout(CType *type, AttributeDef *ad)
{
int size, align, maxalign, offset, c, bit_pos, bit_size;
@ -3767,41 +3757,7 @@ static void struct_layout(CType *type, AttributeDef *ad)
printf("\n");
#endif
if (f->v & SYM_FIRST_ANOM && (f->type.t & VT_BTYPE) == VT_STRUCT) {
Sym *ass;
/* 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 = f->type.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 = f->type.ref;
f->type.ref = sym_push(anon_sym++ | SYM_FIELD,
&f->type.ref->type, 0,
f->type.ref->c);
pps = &f->type.ref->next;
while ((ass = ass->next) != NULL) {
*pps = sym_push(ass->v, &ass->type, 0, ass->c);
pps = &((*pps)->next);
}
*pps = NULL;
}
struct_add_offset(f->type.ref, offset);
f->c = 0;
} else {
f->c = offset;
}
f->c = offset;
f->r = 0;
}
@ -5331,7 +5287,7 @@ special_math_val:
inc(1, tok);
next();
} else if (tok == '.' || tok == TOK_ARROW || tok == TOK_CDOUBLE) {
int qualifiers;
int qualifiers, cumofs = 0;
/* field */
if (tok == TOK_ARROW)
indir();
@ -5346,12 +5302,12 @@ special_math_val:
next();
if (tok == TOK_CINT || tok == TOK_CUINT)
expect("field name");
s = find_field(&vtop->type, tok);
s = find_field(&vtop->type, tok, &cumofs);
if (!s)
tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc));
/* add field offset to pointer */
vtop->type = char_pointer_type; /* change type to 'char *' */
vpushi(s->c);
vpushi(cumofs + s->c);
gen_op('+');
/* change type to field type, and set to lvalue */
vtop->type = s->type;
@ -6674,19 +6630,20 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
c += index * elem_size;
nb_elems = index_last - index + 1;
} else {
int cumofs = 0;
next();
l = tok;
struct_field:
next();
if ((type->t & VT_BTYPE) != VT_STRUCT)
expect("struct/union type");
f = find_field(type, l);
f = find_field(type, l, &cumofs);
if (!f)
expect("field");
if (cur_field)
*cur_field = f;
type = &f->type;
c += f->c;
c += cumofs + f->c;
}
cur_field = NULL;
}

View File

@ -87,6 +87,13 @@ union UV guv = {{6,5}};
union UV guv2 = {{.b = 7, .a = 8}};
union UV guv3 = {.b = 8, .a = 7};
struct SSU {
int y;
struct { int x; };
};
struct SSU gssu1 = { .y = 5, .x = 3 };
struct SSU gssu2 = { 5, 3 };
/* Under -fms-extensions also the following is valid:
union UV2 {
struct Anon {u8 a,b;}; // unnamed member, but tagged struct, ...
@ -166,6 +173,8 @@ void foo (struct W *w, struct pkthdr *phdr_)
int elt = 0x42;
/* Range init, overlapping */
struct T lt2 = { { [1 ... 5] = 9, [6 ... 10] = elt, [4 ... 7] = elt+1 }, 1 };
struct SSU lssu1 = { 5, 3 };
struct SSU lssu2 = { .y = 5, .x = 3 };
print(ls);
print(ls2);
print(lt);
@ -182,6 +191,8 @@ void foo (struct W *w, struct pkthdr *phdr_)
print(lv2);
print(lv3);
print(lt2);
print(lssu1);
print(lssu2);
print(flow);
}
#endif
@ -272,6 +283,8 @@ int main()
print(guv.b);
print(guv2);
print(guv3);
print(gssu1);
print(gssu2);
print(phdr);
foo(&gw, &phdr);
//printf("q: %s\n", q);

View File

@ -17,6 +17,8 @@ guv: 6 5 0 0
guv.b: 5
guv2: 8 7 0 0
guv3: 7 8 0 0
gssu1: 5 0 0 0 3 0 0 0
gssu2: 5 0 0 0 3 0 0 0
phdr: 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0
ls: 1 2 3 4
ls2: 1 2 3 4
@ -34,6 +36,8 @@ lv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e
lv2: 1 2 3 4 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30
lv3: 7 8 9 a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32
lt2: 0 9 9 9 43 43 43 43 42 42 42 0 0 0 0 0 1
lssu1: 5 0 0 0 3 0 0 0
lssu2: 5 0 0 0 3 0 0 0
flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0
one
two