From 80424f6ad56fcb5670a4d27f8750781aa709e992 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 28 Jan 2011 11:45:19 +0900 Subject: [PATCH] Ensure functions are always properly terminated. Control that reaches the end of a function must see a return statement. --- tools/qfcc/source/function.c | 2 +- tools/qfcc/source/statements.c | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index cff3b5730..7fd3ad715 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -617,7 +617,7 @@ emit_function (function_t *f, expr_t *e) //statement_t *s; f->code = pr.code->size; - printf ("%s %d\n", f->name, f->code); + //printf ("%s %d\n", f->name, f->code); sblock = make_statements (e); //for (/**/; sblock; sblock = sblock->next) { // printf ("block %p\n", sblock); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index c513d135d..44f6c0df9 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -43,6 +43,7 @@ #include "diagnostic.h" #include "expr.h" +#include "function.h" #include "options.h" #include "qc-parse.h" #include "qfcc.h" @@ -843,6 +844,40 @@ remove_dead_blocks (sblock_t *blocks) } while (did_something); } +static void +check_final_block (sblock_t *sblock) +{ + statement_t *s; + symbol_t *return_symbol = 0; + operand_t *return_operand = 0; + const char *return_opcode = ""; + + if (!sblock) + return; + while (sblock->next) + sblock = sblock->next; + s = (statement_t *) sblock->tail; + if (!strcmp (s->opcode, "")) + return; // the end of function is the end of a loop + if (!strncmp (s->opcode, "sym->type->t.func.type != &type_void) + warning (0, "control reaches end of non-void function"); + if (options.traditional || options.code.progsversion == PROG_ID_VERSION) { + expr_t *e = new_ret_expr (current_func->sym->type->t.func.type); + return_symbol = e->e.expr.e1->e.expr.e1->e.symbol;//FIXME ick + return_opcode = ""; + } + if (return_symbol) { + return_operand = new_operand (op_symbol); + return_operand->type = ev_void; + return_operand->o.symbol = return_symbol; + } + s = new_statement (return_opcode); + s->opa = return_operand; + sblock_add_statement (sblock, s); +} + sblock_t * make_statements (expr_t *e) { @@ -851,6 +886,7 @@ make_statements (expr_t *e) statement_slist (sblock, e); // print_flow (sblock); remove_dead_blocks (sblock); + check_final_block (sblock); // print_flow (sblock); return sblock; }