+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.
+
2003-04-16 Richard Henderson <rth@redhat.com>
* rtl.h (MEM_ALIAS_SET): Update documentation.
#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. */
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
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 ();
}
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));
}
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),
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);
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),
t = TREE_CHAIN (t);
}
}
+\f
+/* 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;
+}
+