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 /* '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 object in section 'sec'. If 'sec' is NULL, it means stack based
allocation. 'flags & DIF_FIRST' is true if array '{' must be read (multi 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); t1 = pointed_type(type);
size1 = type_size(t1, &align1); 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; no_oblock = 1;
if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) || if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) ||
tok == '{') { tok == '{') {
@ -7817,6 +7839,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
s = type->ref; s = type->ref;
f = s->next; f = s->next;
n = s->c; 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; goto do_init_list;
} else if (tok == '{') { } else if (tok == '{') {
if (flags & DIF_HAVE_ELEM) 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 */ 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; extern int external_inited = 42;
void init_test(void) void init_test(void)
@ -1756,6 +1766,11 @@ void init_test(void)
int zero = 0; int zero = 0;
/* Addresses on non-weak symbols are non-zero, but not the access itself */ /* Addresses on non-weak symbols are non-zero, but not the access itself */
int linit18[2] = {&zero ? 1 : -1, zero ? -1 : 1 }; 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("sinit1=%d\n", sinit1);
printf("sinit2=%d\n", sinit2); printf("sinit2=%d\n", sinit2);
@ -1851,6 +1866,22 @@ void init_test(void)
printf("sinit23= %d %d\n", sinit23[0], sinit23[1]); printf("sinit23= %d %d\n", sinit23[0], sinit23[1]);
printf("sinit24=%d\n", sinit24); printf("sinit24=%d\n", sinit24);
printf("linit18= %d %d\n", linit18[0], linit18[1]); 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) void switch_uc(unsigned char uc)