diff options
author | Roger Sayle <roger@eyesopen.com> | 2003-04-17 01:22:51 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2003-04-17 01:22:51 +0000 |
commit | 96c6931df4d8809e4adf59a64977ac3889f6560b (patch) | |
tree | 44b4d881f76561d90d3775b429d23bd5cec3c3fa /gcc/c-semantics.c | |
parent | 3568b0ef3daa7aabadde5d9124a1a85668b0bc7e (diff) | |
download | gcc-96c6931df4d8809e4adf59a64977ac3889f6560b.zip gcc-96c6931df4d8809e4adf59a64977ac3889f6560b.tar.gz gcc-96c6931df4d8809e4adf59a64977ac3889f6560b.tar.bz2 |
re PR c/10175 (-Wunreachable-code doesn't work for single lines)
2003-04-16 Roger Sayle <roger@eyesopen.com>
* c-semantics.c (find_reachable_label): New function to find a
potentially reachable label in an expression.
(expand_unreachable_if_stmt): Similar to expand_if_stmt but
assumes the start of the IF_STMT is unreachable (dead) code.
(expand_unreachable_stmt): Similar to expand_stmt but assumes
the start of the statement list is unreachable (dead) code.
(genrtl_if_stmt): If the controlling expression of the IF
is constant, use expand_unreachable_stmt for the THEN or ELSE
clause as appropriate.
(genrtl_switch_stmt): Use expand_unreachable_stmt to expand
the body of a SWITCH statement.
(expand_stmt): The code immediately following a "return",
"break", "continue" or "goto" is unreachable.
* Makefile.in (c-semantics.o): Depend upon tree-inline.h.
* gcc.dg/Wunreachable-5.c: New test case for PR c/10175.
* gcc.c-torture/execute/medce-1.c: New test case.
* gcc.c-torture/execute/medce-2.c: New test case.
From-SVN: r65715
Diffstat (limited to 'gcc/c-semantics.c')
-rw-r--r-- | gcc/c-semantics.c | 194 |
1 files changed, 187 insertions, 7 deletions
diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index 6a81d6e..2d88144 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -39,6 +39,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "output.h" #include "timevar.h" #include "predict.h" +#include "tree-inline.h" /* If non-NULL, the address of a language-specific function for expanding statements. */ @@ -51,6 +52,11 @@ void (*lang_expand_stmt) PARAMS ((tree)); variables and labels do not require any RTL generation. */ void (*lang_expand_decl_stmt) PARAMS ((tree)); +static tree find_reachable_label_1 PARAMS ((tree *, int *, void *)); +static tree find_reachable_label PARAMS ((tree)); +static bool expand_unreachable_if_stmt PARAMS ((tree)); +static bool expand_unreachable_stmt PARAMS ((tree, int)); + /* Create an empty statement tree rooted at T. */ void @@ -409,11 +415,20 @@ genrtl_if_stmt (t) emit_line_note (input_filename, lineno); expand_start_cond (cond, 0); if (THEN_CLAUSE (t)) - expand_stmt (THEN_CLAUSE (t)); + { + if (cond && integer_zerop (cond)) + expand_unreachable_stmt (THEN_CLAUSE (t), warn_notreached); + else + expand_stmt (THEN_CLAUSE (t)); + } + if (ELSE_CLAUSE (t)) { expand_start_else (); - expand_stmt (ELSE_CLAUSE (t)); + if (cond && integer_nonzerop (cond)) + expand_unreachable_stmt (ELSE_CLAUSE (t), warn_notreached); + else + expand_stmt (ELSE_CLAUSE (t)); } expand_end_cond (); } @@ -672,7 +687,7 @@ genrtl_switch_stmt (t) emit_line_note (input_filename, lineno); expand_start_case (1, cond, TREE_TYPE (cond), "switch statement"); - expand_stmt (SWITCH_BODY (t)); + expand_unreachable_stmt (SWITCH_BODY (t), warn_notreached); expand_end_case_type (cond, SWITCH_TYPE (t)); } @@ -808,7 +823,8 @@ expand_stmt (t) case RETURN_STMT: genrtl_return_stmt (t); - break; + expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); + return; case EXPR_STMT: genrtl_expr_stmt_value (EXPR_STMT_EXPR (t), TREE_ADDRESSABLE (t), @@ -843,11 +859,13 @@ expand_stmt (t) case BREAK_STMT: genrtl_break_stmt (); - break; + expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); + return; case CONTINUE_STMT: genrtl_continue_stmt (); - break; + expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); + return; case SWITCH_STMT: genrtl_switch_stmt (t); @@ -872,7 +890,8 @@ expand_stmt (t) NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_GOTO, NOT_TAKEN); } genrtl_goto_stmt (GOTO_DESTINATION (t)); - break; + expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); + return; case ASM_STMT: genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), @@ -904,3 +923,164 @@ expand_stmt (t) t = TREE_CHAIN (t); } } + +/* If *TP is a potentially reachable label, return nonzero. */ + +static tree +find_reachable_label_1 (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees ATTRIBUTE_UNUSED; + void *data ATTRIBUTE_UNUSED; +{ + switch (TREE_CODE (*tp)) + { + case LABEL_STMT: + case CASE_LABEL: + return *tp; + + default: + break; + } + return NULL_TREE; +} + +/* Determine whether expression EXP contains a potentially + reachable label. */ +static tree +find_reachable_label (exp) + tree exp; +{ + int line = lineno; + const char *file = input_filename; + tree ret = walk_tree (&exp, find_reachable_label_1, NULL, NULL); + input_filename = file; + lineno = line; + return ret; +} + +/* Expand an unreachable if statement, T. This function returns + true if the IF_STMT contains a potentially reachable code_label. */ +static bool +expand_unreachable_if_stmt (t) + tree t; +{ + if (find_reachable_label (IF_COND (t)) != NULL_TREE) + { + genrtl_if_stmt (t); + return true; + } + + if (THEN_CLAUSE (t) && ELSE_CLAUSE (t)) + { + if (expand_unreachable_stmt (THEN_CLAUSE (t), 0)) + { + rtx label; + label = gen_label_rtx (); + emit_jump (label); + expand_unreachable_stmt (ELSE_CLAUSE (t), 0); + emit_label (label); + return true; + } + else + return expand_unreachable_stmt (ELSE_CLAUSE (t), 0); + } + else if (THEN_CLAUSE (t)) + return expand_unreachable_stmt (THEN_CLAUSE (t), 0); + else if (ELSE_CLAUSE (t)) + return expand_unreachable_stmt (ELSE_CLAUSE (t), 0); + + return false; +} + +/* Expand an unreachable statement list. This function skips all + statements preceding the first potentially reachable label and + then expands the statements normally with expand_stmt. This + function returns true if such a reachable label was found. */ +static bool +expand_unreachable_stmt (t, warn) + tree t; + int warn; +{ + int saved; + + while (t && t != error_mark_node) + { + if (warn) + switch (TREE_CODE (t)) + { + case BREAK_STMT: + case CONTINUE_STMT: + case EXPR_STMT: + case GOTO_STMT: + case IF_STMT: + case RETURN_STMT: + if (!STMT_LINENO_FOR_FN_P (t)) + lineno = STMT_LINENO (t); + warning("will never be executed"); + warn = false; + break; + + default: + break; + } + + switch (TREE_CODE (t)) + { + case GOTO_STMT: + case CONTINUE_STMT: + case BREAK_STMT: + break; + + case FILE_STMT: + input_filename = FILE_STMT_FILENAME (t); + break; + + case RETURN_STMT: + if (find_reachable_label (RETURN_STMT_EXPR (t)) != NULL_TREE) + { + expand_stmt (t); + return true; + } + break; + + case EXPR_STMT: + if (find_reachable_label (EXPR_STMT_EXPR (t)) != NULL_TREE) + { + expand_stmt (t); + return true; + } + break; + + case IF_STMT: + if (expand_unreachable_if_stmt (t)) + { + expand_stmt (TREE_CHAIN (t)); + return true; + } + break; + + case COMPOUND_STMT: + if (expand_unreachable_stmt (COMPOUND_BODY (t), warn)) + { + expand_stmt (TREE_CHAIN (t)); + return true; + } + warn = false; + break; + + case SCOPE_STMT: + saved = stmts_are_full_exprs_p (); + prep_stmt (t); + genrtl_scope_stmt (t); + current_stmt_tree ()->stmts_are_full_exprs_p = saved; + break; + + default: + expand_stmt (t); + return true; + } + t = TREE_CHAIN (t); + } + return false; +} + |