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
This commit is contained in:
herman ten brugge 2020-09-18 19:20:57 +02:00
parent 6d819d7267
commit 5c6356ff8e
2 changed files with 56 additions and 0 deletions

View File

@ -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)

View File

@ -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)