[qfcc] Treat { } as nil for initializing compound types

This commit is contained in:
Bill Currie 2020-02-27 20:30:07 +09:00
parent 7c9072aebf
commit b4aebc120e
6 changed files with 93 additions and 8 deletions

View File

@ -614,7 +614,7 @@ void convert_int (expr_t *e);
void convert_short (expr_t *e);
void convert_short_int (expr_t *e);
void convert_double (expr_t *e);
void convert_nil (expr_t *e, struct type_s *t);
expr_t *convert_nil (expr_t *e, struct type_s *t);
expr_t *test_expr (expr_t *e);
void backpatch (ex_list_t *list, expr_t *label);

View File

@ -287,6 +287,21 @@ def_to_ddef (def_t *def, ddef_t *ddef, int aux)
ddef->s_name = ReuseString (def->name);
}
static int
zero_memory (expr_t *local_expr, def_t *def, type_t *zero_type,
int init_size, int init_offset)
{
int zero_size = type_size (zero_type);
expr_t *zero = convert_nil (new_nil_expr (), zero_type);
expr_t *dst;
for (; init_offset < init_size + 1 - zero_size; init_offset += zero_size) {
dst = new_pointer_expr (init_offset, zero_type, def);
append_expr (local_expr, assign_expr (unary_expr ('.', dst), zero));
}
return init_offset;
}
static void
init_elements (struct def_s *def, expr_t *eles)
{
@ -298,6 +313,39 @@ init_elements (struct def_s *def, expr_t *eles)
base_offset = def->offset;
if (def->local && local_expr)
base_offset = 0;
if (eles->type == ex_nil) {
if (def->local && local_expr) {
// memset to 0
int init_size = type_size (def->type);
int init_offset = 0;
if (options.code.progsversion != PROG_ID_VERSION) {
init_offset = zero_memory (local_expr, def, &type_zero,
init_size, init_offset);
}
// probably won't happen any time soon, but who knows...
if (options.code.progsversion != PROG_ID_VERSION
&& init_size - init_offset >= type_size (&type_quaternion)) {
init_offset = zero_memory (local_expr, def, &type_quaternion,
init_size, init_offset);
}
if (init_size - init_offset >= type_size (&type_vector)) {
init_offset = zero_memory (local_expr, def, &type_vector,
init_size, init_offset);
}
if (options.code.progsversion != PROG_ID_VERSION
&& init_size - init_offset >= type_size (&type_double)) {
init_offset = zero_memory (local_expr, def, &type_double,
init_size, init_offset);
}
if (init_size - init_offset >= type_size (type_default)) {
zero_memory (local_expr, def, type_default,
init_size, init_offset);
}
}
// it's a global, so already initialized to 0
return;
}
if (is_array (def->type)) {
type_t *array_type = def->type->t.array.type;
int array_size = def->type->t.array.size;
@ -334,8 +382,11 @@ init_elements (struct def_s *def, expr_t *eles)
}
for (count = 0, e = eles->e.block.head; e; count++, e = e->next) {
convert_name (e);
if (e->type == ex_nil && count < num_elements)
if (e->type == ex_nil && count < num_elements
&& !(is_array (elements[count].type)
|| is_struct (elements[count].type))) {
convert_nil (e, elements[count].type);
}
if (e->type == ex_error) {
free (elements);
return;
@ -349,7 +400,8 @@ init_elements (struct def_s *def, expr_t *eles)
for (i = 0, e = eles->e.block.head; i < count; i++, e = e->next) {
g = D_POINTER (pr_type_t, &elements[i]);
c = constant_expr (e);
if (c->type == ex_block) {
// nil will not survive as nil to this point if array or struct
if (c->type == ex_block || c->type == ex_nil) {
if (!is_array (elements[i].type)
&& !is_struct (elements[i].type)) {
error (e, "type mismatch in initializer");
@ -567,15 +619,18 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
convert_name (init);
if (init->type == ex_error)
return;
if (init->type == ex_nil)
convert_nil (init, sym->type);
if ((is_array (sym->type) || is_struct (sym->type)
|| sym->type == &type_vector || sym->type == &type_quaternion)
&& init->type == ex_block && !init->e.block.result) {
&& ((init->type == ex_block && !init->e.block.result)
|| init->type == ex_nil)) {
init_elements (sym->s.def, init);
sym->s.def->initialized = 1;
} else {
type_t *init_type = get_type (init);
type_t *init_type;
if (init->type == ex_nil) {
convert_nil (init, sym->type);
}
init_type = get_type (init);
if (!type_assignable (sym->type, init_type)) {
error (init, "type mismatch in initializer");
return;

View File

@ -1325,11 +1325,12 @@ convert_double (expr_t *e)
e->e.value = new_float_val (float_val);
}
void
expr_t *
convert_nil (expr_t *e, type_t *t)
{
e->type = ex_value;
e->e.value = new_nil_val (t);
return e;
}
int

View File

@ -1065,6 +1065,13 @@ opt_initializer
var_initializer
: '=' expr { $$ = $2; }
| '=' '{' element_list optional_comma '}' { $$ = $3; }
| '=' '{' '}'
{
if (is_scalar ($<spec>-1.type)) {
error (0, "empty scalar initializer");
}
$$ = new_nil_expr ();
}
;
optional_state_expr

View File

@ -48,6 +48,7 @@ test_progs_dat=\
return-ivar.dat \
sendv.dat \
state.dat \
struct-nil-init.dat \
structarray.dat \
structlive.dat \
structptr.dat \
@ -301,6 +302,15 @@ state.run: Makefile build-run
include ./$(DEPDIR)/state.Qo # am--include-marker
r_depfiles_remade += ./$(DEPDIR)/state.Qo
struct_nil_init_dat_SOURCES=struct-nil-init.r
struct_nil_init_obj=$(struct_nil_init_dat_SOURCES:.r=.qfo)
struct-nil-init.dat$(EXEEXT): $(struct_nil_init_obj) $(QFCC_DEP)
$(QFCC) $(QCFLAGS) -o $@ $(struct_nil_init_obj)
struct-nil-init.run: Makefile build-run
@$(srcdir)/build-run $@
include ./$(DEPDIR)/struct-nil-init.Qo # am--include-marker
r_depfiles_remade += ./$(DEPDIR)/struct-nil-init.Qo
structarray_dat_SOURCES=structarray.r
structarray_obj=$(structarray_dat_SOURCES:.r=.qfo)
structarray.dat$(EXEEXT): $(structarray_obj) $(QFCC_DEP)

View File

@ -0,0 +1,12 @@
#pragma bug die
struct foo {
quaternion x;
double y;
};
int main()
{
struct foo bar = { };
return bar.y; // to survive and prevail
}