From 5c6356ff8e8ad57c8d5ad8220d665dfba02290cf Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Fri, 18 Sep 2020 19:20:57 +0200 Subject: [PATCH] default-initialization of bitfields The code: struct bf_SS {unsigned int bit:1,bits31:31; }; void func(void) { struct bf_SS bf_finit = { .bit = 1 }; } will not init bits31 to 0. tccgen.c: - check_bf: New function to check if bitfield is present in struct/union - decl_initializer: Call check_bf and set value to 0 is bitfield found tests/tcctest.c: - Add struct bitfield test code --- tccgen.c | 25 +++++++++++++++++++++++++ tests/tcctest.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/tccgen.c b/tccgen.c index 0be3a52a..c46adfd1 100644 --- a/tccgen.c +++ b/tccgen.c @@ -7651,6 +7651,23 @@ static void init_putv(CType *type, Section *sec, unsigned long c) } } +/* Check for bitfield in struct/union recursive */ +static int check_bf(Sym *f) +{ + while (f->next) { + f = f->next; + if ((f->type.t & VT_BITFIELD) || + ((f->type.t & VT_BTYPE) == VT_STRUCT && check_bf(f->type.ref))) + return 1; + if (f->type.t & VT_ARRAY) { + Sym *r = f->type.ref; + if (((r->type.t & VT_BTYPE) == VT_STRUCT && check_bf(r->type.ref))) + return 1; + } + } + return 0; +} + /* 't' contains the type and storage info. 'c' is the offset of the object in section 'sec'. If 'sec' is NULL, it means stack based allocation. 'flags & DIF_FIRST' is true if array '{' must be read (multi @@ -7688,6 +7705,11 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, t1 = pointed_type(type); size1 = type_size(t1, &align1); + if (!(flags & DIF_SIZE_ONLY) && + (s->type.t & VT_BTYPE) == VT_STRUCT && check_bf (s->type.ref)) + /* If there is a bitfield in array clear it */ + init_putz(sec, c, size1 * n); + no_oblock = 1; if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) || tok == '{') { @@ -7817,6 +7839,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, s = type->ref; f = s->next; n = s->c; + if (!(flags & DIF_SIZE_ONLY) && check_bf (s)) + /* If there is a bitfield in struct/union clear it */ + init_putz(sec, c, n); goto do_init_list; } else if (tok == '{') { if (flags & DIF_HAVE_ELEM) diff --git a/tests/tcctest.c b/tests/tcctest.c index 4696779d..f72b6519 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -1737,6 +1737,16 @@ int sinit23[2] = { "astring" ? sizeof("astring") : -1, int sinit24 = 2 || 1 / 0; /* exception in constant but unevaluated context */ +/* bitfield init */ +struct bf_SS {unsigned int bit:1,bits31:31; }; +struct bf_SS bf_init = { .bit = 1 }; +struct bfn_SS {int a,b; struct bf_SS c; int d,e; }; +struct bfn_SS bfn_init = { .c.bit = 1 }; +struct bfa_SS {int a,b; struct bf_SS c[3]; int d,e; }; +struct bfa_SS bfa_init = { .c[1].bit = 1 }; +struct bf_SS bfaa_init[3] = { [1].bit = 1 }; +struct bf_SS bfaa_vinit[] = { [2].bit = 1 }; + extern int external_inited = 42; void init_test(void) @@ -1756,6 +1766,11 @@ void init_test(void) int zero = 0; /* Addresses on non-weak symbols are non-zero, but not the access itself */ int linit18[2] = {&zero ? 1 : -1, zero ? -1 : 1 }; + struct bf_SS bf_finit = { .bit = 1 }; + struct bfn_SS bfn_finit = { .c.bit = 1 }; + struct bfa_SS bfa_finit = { .c[1].bit = 1 }; + struct bf_SS bfaa_finit[3] = { [1].bit = 1 }; + struct bf_SS bfaa_fvinit[] = { [2].bit = 1 }; printf("sinit1=%d\n", sinit1); printf("sinit2=%d\n", sinit2); @@ -1851,6 +1866,22 @@ void init_test(void) printf("sinit23= %d %d\n", sinit23[0], sinit23[1]); printf("sinit24=%d\n", sinit24); printf("linit18= %d %d\n", linit18[0], linit18[1]); + printf ("bf1: %u %u\n", bf_init.bit, bf_init.bits31); + printf ("bf2: %u %u\n", bf_finit.bit, bf_finit.bits31); + printf ("bf3: %u %u\n", bfn_init.c.bit, bfn_init.c.bits31); + printf ("bf4: %u %u\n", bfn_finit.c.bit, bfn_finit.c.bits31); + for (i = 0; i < 3; i++) + printf ("bf5[%d]: %u %u\n", i, bfa_init.c[i].bit, bfa_init.c[i].bits31); + for (i = 0; i < 3; i++) + printf ("bf6[%d]: %u %u\n", i, bfa_finit.c[i].bit, bfa_finit.c[i].bits31); + for (i = 0; i < 3; i++) + printf ("bf7[%d]: %u %u\n", i, bfaa_init[i].bit, bfaa_init[i].bits31); + for (i = 0; i < 3; i++) + printf ("bf8[%d]: %u %u\n", i, bfaa_finit[i].bit, bfaa_finit[i].bits31); + for (i = 0; i < 3; i++) + printf ("bf9[%d]: %u %u\n", i, bfaa_vinit[i].bit, bfaa_vinit[i].bits31); + for (i = 0; i < 3; i++) + printf ("bf10[%d]: %u %u\n", i, bfaa_fvinit[i].bit, bfaa_fvinit[i].bits31); } void switch_uc(unsigned char uc) -- 2.11.4.GIT