diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 9d220b804..30b7cfd88 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -647,6 +647,7 @@ int is_math_op (int op) __attribute__((const)); int is_logic (int op) __attribute__((const)); int has_function_call (expr_t *e) __attribute__((pure)); +int is_function_call (expr_t *e) __attribute__((pure)); int is_nil (expr_t *e) __attribute__((pure)); int is_string_val (expr_t *e) __attribute__((pure)); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index df684e288..92281b3c4 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -216,9 +216,10 @@ get_type (expr_t *e) convert_name (e); switch (e->type) { case ex_branch: - case ex_labelref: type = e->e.branch.ret_type; break; + case ex_labelref: + return &type_void; case ex_memset: return e->e.memset.type; case ex_error: @@ -504,6 +505,7 @@ copy_expr (expr_t *e) n = new_expr (); *n = *e; n->e.branch.target = copy_expr (e->e.branch.target); + n->e.branch.index = copy_expr (e->e.branch.index); n->e.branch.test = copy_expr (e->e.branch.test); n->e.branch.args = copy_expr (e->e.branch.args); return n; @@ -1658,6 +1660,12 @@ has_function_call (expr_t *e) internal_error (e, "invalid expression type"); } +int +is_function_call (expr_t *e) +{ + return e->type == ex_branch && e->e.branch.type == pr_branch_call; +} + expr_t * asx_expr (int op, expr_t *e1, expr_t *e2) { @@ -2116,12 +2124,7 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) append_expr (call, e); } e = expr_file_line (call_expr (fexpr, args, ftype->t.func.type), fexpr); - append_expr (call, e); - if (!is_void(ftype->t.func.type)) { - call->e.block.result = new_ret_expr (ftype->t.func.type); - } else if (options.traditional) { - call->e.block.result = new_ret_expr (&type_float); - } + call->e.block.result = e; return call; } diff --git a/tools/qfcc/source/expr_obj.c b/tools/qfcc/source/expr_obj.c index 33eadb742..0e8a8d53e 100644 --- a/tools/qfcc/source/expr_obj.c +++ b/tools/qfcc/source/expr_obj.c @@ -248,6 +248,9 @@ message_expr (expr_t *receiver, keywordarg_t *message) if (call->type == ex_error) return receiver; - call->e.block.result = new_ret_expr (return_type); + if (!is_function_call (call->e.block.result)) { + internal_error (call, "unexpected block result type"); + } + call->e.block.result->e.branch.ret_type = return_type; return call; } diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 51a7a4ac9..bfba55950 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1071,6 +1071,9 @@ expr_call_v6p (sblock_t *sblock, expr_t *call, operand_t **op) sblock = statement_subexpr (sblock, func, &s->opa); s->opb = arguments[0]; s->opc = arguments[1]; + if (op) { + *op = return_operand (call->e.branch.ret_type, call); + } sblock_add_statement (sblock, s); sblock->next = new_sblock (); return sblock->next; @@ -1118,6 +1121,16 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) return sblock->next; } +static sblock_t * +expr_branch (sblock_t *sblock, expr_t *e, operand_t **op) +{ + if (e->e.branch.type != pr_branch_call) { + internal_error (e, "unexpected branch type in expression: %d", + e->e.branch.type); + } + return expr_call (sblock, e, op); +} + static sblock_t * statement_branch (sblock_t *sblock, expr_t *e) { @@ -1618,6 +1631,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) [ex_alias] = expr_alias, [ex_address] = expr_address, [ex_assign] = expr_assign, + [ex_branch] = expr_branch, }; if (!e) { *op = 0; @@ -1804,6 +1818,11 @@ statement_block (sblock_t *sblock, expr_t *e) sblock = sblock->next; } sblock = statement_slist (sblock, e->e.block.head); + if (e->e.block.is_call) { + // for a fuction call, the call expresion is in only the result, not + // the actual block + sblock = statement_slist (sblock, e->e.block.result); + } return sblock; } diff --git a/tools/qfcc/test/Makemodule.am b/tools/qfcc/test/Makemodule.am index 4eb260e81..1f310048a 100644 --- a/tools/qfcc/test/Makemodule.am +++ b/tools/qfcc/test/Makemodule.am @@ -53,6 +53,7 @@ test_progs_dat=\ tools/qfcc/test/structstruct.dat \ tools/qfcc/test/swap.dat \ tools/qfcc/test/triangle.dat \ + tools/qfcc/test/twice-called.dat \ tools/qfcc/test/typedef.dat \ tools/qfcc/test/typelinker.dat \ tools/qfcc/test/unaryminus.dat \ @@ -605,6 +606,16 @@ tools/qfcc/test/triangle.run: $(qfcc_test_run_deps) include $(triangle_dep) # am--include-marker r_depfiles_remade += $(triangle_dep) +tools_qfcc_test_twice_called_dat_SOURCES=tools/qfcc/test/twice-called.r +twice_called_obj=$(tools_qfcc_test_twice_called_dat_SOURCES:.r=.o) +twice_called_dep=$(call qcautodep,$(tools_qfcc_test_twice_called_dat_SOURCES)) +tools/qfcc/test/twice-called.dat$(EXEEXT): $(twice_called_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(twice_called_obj) +tools/qfcc/test/twice-called.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ 100000 100000 1.00005 50002.4961 +include $(twice_called_dep) # am--include-marker +r_depfiles_remade += $(twice_called_dep) + tools_qfcc_test_typedef_dat_SOURCES=tools/qfcc/test/typedef.r typedef_obj=$(tools_qfcc_test_typedef_dat_SOURCES:.r=.o) typedef_dep=$(call qcautodep,$(tools_qfcc_test_typedef_dat_SOURCES)) diff --git a/tools/qfcc/test/twice-called.r b/tools/qfcc/test/twice-called.r new file mode 100644 index 000000000..9542af0f6 --- /dev/null +++ b/tools/qfcc/test/twice-called.r @@ -0,0 +1,28 @@ +#include "test-harness.h" + +int counter; + +int +function (void) +{ + return ++counter; +} + +int +main (void) +{ + int ret = 0; + counter = 0; + //function (); + //if (counter != 1) { + //printf ("discarded return not called only once\n"); + // ret = 1; + //} + counter = 0; + printf ("function: %d\n", function ()); + if (counter != 1) { + //printf ("used return not called only once\n"); + ret = 1; + } + return ret; +}