Append a new sblock for return when necessary.

If the final block ends in a conditional statement, appending return to the
block will hide the conditional statement from the flow analyzer. This may
cause the conditional statement's destination node be become unreachable
according to the analyzer and thus eliminated. The label for the branch
then loses its target sblock and thus the code generator will produce a
zero-distance jump resulting in an infinite loop.

Thus, if the final block ends in a conditional statement (or, for
completeness, a call statement), append a new empty block before adding the
return statement.
This commit is contained in:
Bill Currie 2012-12-21 20:03:28 +09:00
parent cb39cfc9ae
commit 7701393bd4
3 changed files with 33 additions and 2 deletions

View file

@ -1512,7 +1512,7 @@ remove_dead_blocks (sblock_t *blocks)
static void static void
check_final_block (sblock_t *sblock) check_final_block (sblock_t *sblock)
{ {
statement_t *s; statement_t *s = 0;
symbol_t *return_symbol = 0; symbol_t *return_symbol = 0;
def_t *return_def = 0; def_t *return_def = 0;
operand_t *return_operand = 0; operand_t *return_operand = 0;
@ -1531,6 +1531,12 @@ check_final_block (sblock_t *sblock)
} }
if (current_func->sym->type->t.func.type != &type_void) if (current_func->sym->type->t.func.type != &type_void)
warning (0, "control reaches end of non-void function"); warning (0, "control reaches end of non-void function");
if (s && s->type >= st_func) {
// func and flow end blocks, so we need to add a new block to take the
// return
sblock->next = new_sblock ();
sblock = sblock->next;
}
if (options.traditional || options.code.progsversion == PROG_ID_VERSION) { if (options.traditional || options.code.progsversion == PROG_ID_VERSION) {
return_symbol = make_symbol (".return", &type_param, pr.symtab->space, return_symbol = make_symbol (".return", &type_param, pr.symtab->space,
sc_extern); sc_extern);

View file

@ -29,7 +29,8 @@ test_progs_dat=\
structlive.dat \ structlive.dat \
structptr.dat \ structptr.dat \
vecinit.dat \ vecinit.dat \
while.dat while.dat \
voidfor.dat
fail_progs_dat=\ fail_progs_dat=\
$E $E
@ -120,6 +121,13 @@ while.dat: $(while_obj) $(QFCC_DEP)
while.run: Makefile build-run while.run: Makefile build-run
$(srcdir)/build-run $@ $(srcdir)/build-run $@
voidfor_dat_SOURCES=voidfor.r
voidfor_obj=$(voidfor_dat_SOURCES:.r=.qfo)
voidfor.dat: $(voidfor_obj) $(QFCC_DEP)
$(QFCC) $(QCFLAGS) -o $@ $(voidfor_obj)
voidfor.run: Makefile build-run
$(srcdir)/build-run $@
include ./$(DEPDIR)/*.Qo include ./$(DEPDIR)/*.Qo
EXTRA_DIST= test-bi.h build-run EXTRA_DIST= test-bi.h build-run

17
tools/qfcc/test/voidfor.r Normal file
View file

@ -0,0 +1,17 @@
void bar ()
{
}
void foo ()
{
int i;
for (i = 0; i < 11; i++)
bar ();
}
int main ()
{
foo ();
return 0;
}