From 0344c0b6a0d0436ff27a702a1f9232cf39d3c5c9 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Thu, 11 Apr 2019 00:30:41 +0200 Subject: [PATCH] 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. --- tccgen.c | 67 +++++++------------------------------- tests/tests2/90_struct-init.c | 13 ++++++++ tests/tests2/90_struct-init.expect | 4 +++ 3 files changed, 29 insertions(+), 55 deletions(-) diff --git a/tccgen.c b/tccgen.c index 223a1a77..544ec83f 100644 --- a/tccgen.c +++ b/tccgen.c @@ -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; } diff --git a/tests/tests2/90_struct-init.c b/tests/tests2/90_struct-init.c index d931e237..48401c1d 100644 --- a/tests/tests2/90_struct-init.c +++ b/tests/tests2/90_struct-init.c @@ -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); diff --git a/tests/tests2/90_struct-init.expect b/tests/tests2/90_struct-init.expect index e366121a..46248afa 100644 --- a/tests/tests2/90_struct-init.expect +++ b/tests/tests2/90_struct-init.expect @@ -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 -- 2.11.4.GIT