static void clear_blocks_annotations (void);
static void make_blocks (tree);
static void factor_computed_gotos (void);
-static tree tree_block_label (basic_block bb);
/* Edges. */
static void make_edges (void);
make_edges (void)
{
basic_block bb;
- edge e;
/* Create an edge from entry to the first block with executable
statements in it. */
make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
}
- /* If there is a fallthru edge to exit out of the last block, transform it
- to a return statement. */
- for (e = EXIT_BLOCK_PTR->prev_bb->succ; e; e = e->succ_next)
- if (e->flags & EDGE_FALLTHRU)
- break;
-
- if (e && e->dest == EXIT_BLOCK_PTR)
- {
- block_stmt_iterator bsi;
- basic_block ret_bb = EXIT_BLOCK_PTR->prev_bb;
- tree x;
-
- /* If E->SRC ends with a call that has an abnormal edge (for EH or
- nonlocal goto), then we will need to split the edge to insert
- an explicit return statement. */
- if (e != ret_bb->succ || e->succ_next)
- {
- ret_bb = split_edge (e);
- e = ret_bb->succ;
- }
- e->flags &= ~EDGE_FALLTHRU;
-
- x = build (RETURN_EXPR, void_type_node, NULL_TREE);
- bsi = bsi_last (ret_bb);
- bsi_insert_after (&bsi, x, BSI_NEW_STMT);
- }
-
/* We do not care about fake edges, so remove any that the CFG
builder inserted for completeness. */
remove_fake_edges ();
basic_block
label_to_block (tree dest)
{
- return VARRAY_BB (label_to_block_map, LABEL_DECL_UID (dest));
+ int uid = LABEL_DECL_UID (dest);
+
+ /* We would die hard when faced by undefined label. Emit label to
+ very first basic block. This will hopefully make even the dataflow
+ and undefined variable warnings quite right. */
+ if ((errorcount || sorrycount) && uid < 0)
+ {
+ block_stmt_iterator bsi = bsi_start (BASIC_BLOCK (0));
+ tree stmt;
+
+ stmt = build1 (LABEL_EXPR, void_type_node, dest);
+ bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
+ uid = LABEL_DECL_UID (dest);
+ }
+ return VARRAY_BB (label_to_block_map, uid);
}
/* A GOTO to a local label creates normal edges. */
if (simple_goto_p (goto_t))
{
- make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+ edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+#ifdef USE_MAPPED_LOCATION
+ e->goto_locus = EXPR_LOCATION (goto_t);
+#else
+ e->goto_locus = EXPR_LOCUS (goto_t);
+#endif
bsi_remove (&last);
return;
}
}
}
+/* Given LABEL return the first label in the same basic block. */
+static tree
+main_block_label (tree label)
+{
+ basic_block bb = label_to_block (label);
+
+ /* label_to_block possibly inserted undefined label into the chain. */
+ if (!label_for_bb[bb->index])
+ label_for_bb[bb->index] = label;
+ return label_for_bb[bb->index];
+}
+
/* Cleanup redundant labels. This is a three-steo process:
1) Find the leading label for each block.
2) Redirect all references to labels to the leading labels.
case COND_EXPR:
{
tree true_branch, false_branch;
- basic_block true_bb, false_bb;
true_branch = COND_EXPR_THEN (stmt);
false_branch = COND_EXPR_ELSE (stmt);
- true_bb = label_to_block (GOTO_DESTINATION (true_branch));
- false_bb = label_to_block (GOTO_DESTINATION (false_branch));
- GOTO_DESTINATION (true_branch) = label_for_bb[true_bb->index];
- GOTO_DESTINATION (false_branch) = label_for_bb[false_bb->index];
+ GOTO_DESTINATION (true_branch)
+ = main_block_label (GOTO_DESTINATION (true_branch));
+ GOTO_DESTINATION (false_branch)
+ = main_block_label (GOTO_DESTINATION (false_branch));
break;
}
/* Replace all destination labels. */
for (i = 0; i < n; ++i)
- {
- tree label = CASE_LABEL (TREE_VEC_ELT (vec, i));
-
- CASE_LABEL (TREE_VEC_ELT (vec, i)) =
- label_for_bb[label_to_block (label)->index];
- }
+ CASE_LABEL (TREE_VEC_ELT (vec, i))
+ = main_block_label (CASE_LABEL (TREE_VEC_ELT (vec, i)));
break;
}
/* We have to handle GOTO_EXPRs until they're removed, and we don't
remove them until after we've created the CFG edges. */
case GOTO_EXPR:
- {
- tree label = GOTO_DESTINATION (stmt);
- if (! computed_goto_p (stmt))
- GOTO_DESTINATION (stmt) =
- label_for_bb[label_to_block (label)->index];
- break;
- }
+ if (! computed_goto_p (stmt))
+ {
+ GOTO_DESTINATION (stmt)
+ = main_block_label (GOTO_DESTINATION (stmt));
+ break;
+ }
default:
break;
tree labels = SWITCH_LABELS (stmt);
int old_size = TREE_VEC_LENGTH (labels);
int i, j, new_size = old_size;
+ tree default_label = TREE_VEC_ELT (labels, old_size - 1);
/* Look for possible opportunities to merge cases.
Ignore the last element of the label vector because it
if (! base_case)
abort ();
- type = TREE_TYPE (CASE_LOW (base_case));
base_label = CASE_LABEL (base_case);
+
+ /* Discard cases that have the same destination as the
+ default case. */
+ if (base_label == default_label)
+ {
+ TREE_VEC_ELT (labels, i) = NULL_TREE;
+ i++;
+ continue;
+ }
+
+ type = TREE_TYPE (CASE_LOW (base_case));
base_high = CASE_HIGH (base_case) ?
CASE_HIGH (base_case) : CASE_LOW (base_case);
static bool
remove_useless_stmts_warn_notreached (tree stmt)
{
- if (EXPR_LOCUS (stmt))
+ if (EXPR_HAS_LOCATION (stmt))
{
- warning ("%Hwill never be executed", EXPR_LOCUS (stmt));
+ location_t loc = EXPR_LOCATION (stmt);
+ warning ("%Hwill never be executed", &loc);
return true;
}
phi = phi_nodes (bb);
while (phi)
{
- tree next = TREE_CHAIN (phi);
+ tree next = PHI_CHAIN (phi);
remove_phi_node (phi, NULL_TREE, bb);
phi = next;
}
remove_bb (basic_block bb)
{
block_stmt_iterator i;
- location_t *loc = NULL;
+ source_locus loc = 0;
if (dump_file)
{
jump threading, thus resulting in bogus warnings. Not great,
since this way we lose warnings for gotos in the original
program that are indeed unreachable. */
- if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_LOCUS (stmt) && !loc)
+ if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_HAS_LOCATION (stmt) && !loc)
+#ifdef USE_MAPPED_LOCATION
+ loc = EXPR_LOCATION (stmt);
+#else
loc = EXPR_LOCUS (stmt);
+#endif
}
/* If requested, give a warning that the first statement in the
loop above, so the last statement we process is the first statement
in the block. */
if (warn_notreached && loc)
+#ifdef USE_MAPPED_LOCATION
+ warning ("%Hwill never be executed", &loc);
+#else
warning ("%Hwill never be executed", loc);
+#endif
remove_phi_nodes_and_edges_for_unreachable_block (bb);
}
tree phi, val1, val2;
int n1, n2;
- for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
+ for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
{
n1 = phi_arg_from_edge (phi, e1);
n2 = phi_arg_from_edge (phi, e2);
basic_block bb;
block_stmt_iterator last;
edge e;
- tree stmt, label, forward;
+ tree stmt, label;
FOR_EACH_BB (bb)
{
if (e->flags & EDGE_FALLTHRU)
break;
- if (!e
- || e->dest == bb->next_bb)
+ if (!e || e->dest == bb->next_bb)
continue;
if (e->dest == EXIT_BLOCK_PTR)
label = tree_block_label (e->dest);
- /* If this is a goto to a goto, jump to the final destination.
- Handles unfactoring of the computed jumps.
- ??? Why bother putting this back together when rtl is just
- about to take it apart again? */
- forward = last_and_only_stmt (e->dest);
- if (forward
- && TREE_CODE (forward) == GOTO_EXPR)
- label = GOTO_DESTINATION (forward);
-
- bsi_insert_after (&last,
- build1 (GOTO_EXPR, void_type_node, label),
- BSI_NEW_STMT);
+ stmt = build1 (GOTO_EXPR, void_type_node, label);
+#ifdef USE_MAPPED_LOCATION
+ SET_EXPR_LOCATION (stmt, e->goto_locus);
+#else
+ SET_EXPR_LOCUS (stmt, e->goto_locus);
+#endif
+ bsi_insert_after (&last, stmt, BSI_NEW_STMT);
e->flags &= ~EDGE_FALLTHRU;
}
}
-
-/* Remove all the blocks and edges that make up the flowgraph. */
+/* Remove block annotations and other datastructures. */
void
-delete_tree_cfg (void)
+delete_tree_cfg_annotations (void)
{
+ basic_block bb;
if (n_basic_blocks > 0)
free_blocks_annotations ();
- free_basic_block_vars ();
- basic_block_info = NULL;
label_to_block_map = NULL;
free_rbi_pool ();
+ FOR_EACH_BB (bb)
+ bb->rbi = NULL;
}
/* Find all the PHI arguments on the original edge, and change them to
the new edge. Do it before redirection, so that the argument does not
get removed. */
- for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
+ for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
{
num_elem = PHI_NUM_ARGS (phi);
for (i = 0; i < num_elem; i++)
properly noticed as such. */
static tree
-verify_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
+verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
{
tree t = *tp, x;
if (TYPE_P (t))
*walk_subtrees = 0;
+
+ /* Check operand N for being valid GIMPLE and give error MSG if not.
+ We check for constants explicitly since they are not considered
+ gimple invariants if they overflowed. */
+#define CHECK_OP(N, MSG) \
+ do { if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, N))) != 'c' \
+ && !is_gimple_val (TREE_OPERAND (t, N))) \
+ { error (MSG); return TREE_OPERAND (t, N); }} while (0)
switch (TREE_CODE (t))
{
&& is_gimple_reg (TREE_OPERAND (x, 0)))
{
error ("GIMPLE register modified with BIT_FIELD_REF");
- return *tp;
+ return t;
}
break;
case ADDR_EXPR:
- x = TREE_OPERAND (t, 0);
- while (TREE_CODE (x) == ARRAY_REF
- || TREE_CODE (x) == COMPONENT_REF
- || TREE_CODE (x) == REALPART_EXPR
- || TREE_CODE (x) == IMAGPART_EXPR)
- x = TREE_OPERAND (x, 0);
+ /* Skip any references (they will be checked when we recurse down the
+ tree) and ensure that any variable used as a prefix is marked
+ addressable. */
+ for (x = TREE_OPERAND (t, 0);
+ (handled_component_p (x)
+ || TREE_CODE (x) == REALPART_EXPR
+ || TREE_CODE (x) == IMAGPART_EXPR);
+ x = TREE_OPERAND (x, 0))
+ ;
+
if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
return NULL;
if (!TREE_ADDRESSABLE (x))
case BIT_NOT_EXPR:
case NON_LVALUE_EXPR:
case TRUTH_NOT_EXPR:
- x = TREE_OPERAND (t, 0);
- /* We check for constants explicitly since they are not considered
- gimple invariants if they overflowed. */
- if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c'
- && !is_gimple_val (x))
- {
- error ("Invalid operand to unary operator");
- return x;
- }
+ CHECK_OP (0, "Invalid operand to unary operator");
break;
case REALPART_EXPR:
case IMAGPART_EXPR:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ case BIT_FIELD_REF:
+ case VIEW_CONVERT_EXPR:
+ /* We have a nest of references. Verify that each of the operands
+ that determine where to reference is either a constant or a variable,
+ verify that the base is valid, and then show we've already checked
+ the subtrees. */
+ while (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR
+ || handled_component_p (t))
+ {
+ if (TREE_CODE (t) == COMPONENT_REF && TREE_OPERAND (t, 2))
+ CHECK_OP (2, "Invalid COMPONENT_REF offset operator");
+ else if (TREE_CODE (t) == ARRAY_REF
+ || TREE_CODE (t) == ARRAY_RANGE_REF)
+ {
+ CHECK_OP (1, "Invalid array index.");
+ if (TREE_OPERAND (t, 2))
+ CHECK_OP (2, "Invalid array lower bound.");
+ if (TREE_OPERAND (t, 3))
+ CHECK_OP (3, "Invalid array stride.");
+ }
+ else if (TREE_CODE (t) == BIT_FIELD_REF)
+ {
+ CHECK_OP (1, "Invalid operand to BIT_FIELD_REF");
+ CHECK_OP (2, "Invalid operand to BIT_FIELD_REF");
+ }
+
+ t = TREE_OPERAND (t, 0);
+ }
+
+ if (TREE_CODE_CLASS (TREE_CODE (t)) != 'c'
+ && !is_gimple_lvalue (t))
+ {
+ error ("Invalid reference prefix.");
+ return t;
+ }
+ *walk_subtrees = 0;
break;
case LT_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_AND_EXPR:
- x = TREE_OPERAND (t, 0);
- /* We check for constants explicitly since they are not considered
- gimple invariants if they overflowed. */
- if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c'
- && !is_gimple_val (x))
- {
- error ("Invalid operand to binary operator");
- return x;
- }
- x = TREE_OPERAND (t, 1);
- /* We check for constants explicitly since they are not considered
- gimple invariants if they overflowed. */
- if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c'
- && !is_gimple_val (x))
- {
- error ("Invalid operand to binary operator");
- return x;
- }
+ CHECK_OP (0, "Invalid operand to binary operator");
+ CHECK_OP (1, "Invalid operand to binary operator");
break;
default:
break;
}
return NULL;
+
+#undef CHECK_OP
}
TODO: Implement type checking. */
static bool
-verify_stmt (tree stmt)
+verify_stmt (tree stmt, bool last_in_block)
{
tree addr;
if (!is_gimple_stmt (stmt))
{
error ("Is not a valid GIMPLE statement.");
- debug_generic_stmt (stmt);
- return true;
+ goto fail;
}
addr = walk_tree (&stmt, verify_expr, NULL, NULL);
return true;
}
+ /* If the statement is marked as part of an EH region, then it is
+ expected that the statement could throw. Verify that when we
+ have optimizations that simplify statements such that we prove
+ that they cannot throw, that we update other data structures
+ to match. */
+ if (lookup_stmt_eh_region (stmt) >= 0)
+ {
+ if (!tree_could_throw_p (stmt))
+ {
+ error ("Statement marked for throw, but doesn't.");
+ goto fail;
+ }
+ if (!last_in_block && tree_can_throw_internal (stmt))
+ {
+ error ("Statement marked for throw in middle of block.");
+ goto fail;
+ }
+ }
+
return false;
+
+ fail:
+ debug_generic_stmt (stmt);
+ return true;
}
|| TREE_CODE (t) == SSA_NAME)
return true;
- while ((TREE_CODE (t) == ARRAY_REF
+ while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
/* We check for constants explicitly since they are not considered
gimple invariants if they overflowed. */
&& (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 1))) == 'c'
tree phi;
int i;
- for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+ for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
{
int phi_num_args = PHI_NUM_ARGS (phi);
}
}
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
{
tree stmt = bsi_stmt (bsi);
- err |= verify_stmt (stmt);
+ bsi_next (&bsi);
+ err |= verify_stmt (stmt, bsi_end_p (bsi));
addr = walk_tree (&stmt, verify_node_sharing, htab, NULL);
if (addr)
{
case SWITCH_EXPR:
{
+ tree prev;
edge e;
size_t i, n;
tree vec;
label_bb->aux = (void *)1;
}
+ /* Verify that the case labels are sorted. */
+ prev = TREE_VEC_ELT (vec, 0);
+ for (i = 1; i < n - 1; ++i)
+ {
+ tree c = TREE_VEC_ELT (vec, i);
+ if (! CASE_LOW (c))
+ {
+ error ("Found default case not at end of case vector");
+ err = 1;
+ continue;
+ }
+ if (! tree_int_cst_lt (CASE_LOW (prev), CASE_LOW (c)))
+ {
+ error ("Case labels not sorted:\n ");
+ print_generic_expr (stderr, prev, 0);
+ fprintf (stderr," is greater than ");
+ print_generic_expr (stderr, c, 0);
+ fprintf (stderr," but comes before it.\n");
+ err = 1;
+ }
+ prev = c;
+ }
+ if (CASE_LOW (TREE_VEC_ELT (vec, n - 1)))
+ {
+ error ("No default case found at end of case vector");
+ err = 1;
+ }
+
for (e = bb->succ; e; e = e->succ_next)
{
if (!e->dest->aux)
{
edge e;
basic_block dummy, bb;
- tree phi, new_phi, var;
+ tree phi, new_phi, var, prev, next;
dummy = fallthru->src;
bb = fallthru->dest;
/* If we redirected a branch we must create new phi nodes at the
start of BB. */
- for (phi = phi_nodes (dummy); phi; phi = TREE_CHAIN (phi))
+ for (phi = phi_nodes (dummy); phi; phi = PHI_CHAIN (phi))
{
var = PHI_RESULT (phi);
new_phi = create_phi_node (var, bb);
SSA_NAME_DEF_STMT (var) = new_phi;
- PHI_RESULT (phi) = make_ssa_name (SSA_NAME_VAR (var), phi);
+ SET_PHI_RESULT (phi, make_ssa_name (SSA_NAME_VAR (var), phi));
add_phi_arg (&new_phi, PHI_RESULT (phi), fallthru);
}
- /* Ensure that the PHI node chains are in the same order. */
- set_phi_nodes (bb, nreverse (phi_nodes (bb)));
+ /* Ensure that the PHI node chain is in the same order. */
+ prev = NULL;
+ for (phi = phi_nodes (bb); phi; phi = next)
+ {
+ next = PHI_CHAIN (phi);
+ PHI_CHAIN (phi) = prev;
+ prev = phi;
+ }
+ set_phi_nodes (bb, prev);
/* Add the arguments we have stored on edges. */
for (e = bb->pred; e; e = e->pred_next)
for (phi = phi_nodes (bb), var = PENDING_STMT (e);
phi;
- phi = TREE_CHAIN (phi), var = TREE_CHAIN (var))
+ phi = PHI_CHAIN (phi), var = TREE_CHAIN (var))
add_phi_arg (&phi, TREE_VALUE (var), e);
PENDING_STMT (e) = NULL;
dest = dest->succ->dest)
{
/* An infinite loop detected. We redirect the edge anyway, so
- that the loop is shrinked into single basic block. */
+ that the loop is shrunk into single basic block. */
if (!bb_ann (dest)->forwardable)
break;
/* Update PHI nodes. We know that the new argument should
have the same value as the argument associated with LAST.
Otherwise we would have changed our target block above. */
- for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
+ for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
{
arg = phi_arg_from_edge (phi, last);
if (arg < 0)
/* Return a non-special label in the head of basic block BLOCK.
Create one if it doesn't exist. */
-static tree
+tree
tree_block_label (basic_block bb)
{
block_stmt_iterator i, s = bsi_start (bb);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
+ tree copy;
if (TREE_CODE (stmt) == LABEL_EXPR)
continue;
- bsi_insert_after (&bsi_tgt, unshare_expr (stmt), BSI_NEW_STMT);
+ copy = unshare_expr (stmt);
+
+ /* Copy also the virtual operands. */
+ get_stmt_ann (copy);
+ copy_virtual_operands (copy, stmt);
+
+ bsi_insert_after (&bsi_tgt, copy, BSI_NEW_STMT);
}
return new_bb;
return blocks_split;
}
+bool
+tree_purge_dead_eh_edges (basic_block bb)
+{
+ bool changed = false;
+ edge e, next;
+ tree stmt = last_stmt (bb);
+
+ if (stmt && tree_can_throw_internal (stmt))
+ return false;
+
+ for (e = bb->succ; e ; e = next)
+ {
+ next = e->succ_next;
+ if (e->flags & EDGE_EH)
+ {
+ ssa_remove_edge (e);
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+bool
+tree_purge_all_dead_eh_edges (bitmap blocks)
+{
+ bool changed = false;
+ size_t i;
+
+ EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i,
+ { changed |= tree_purge_dead_eh_edges (BASIC_BLOCK (i)); });
+
+ return changed;
+}
struct cfg_hooks tree_cfg_hooks = {
"tree",
struct tree_opt_pass pass_split_crit_edges =
{
- NULL, /* name */
+ "crited", /* name */
NULL, /* gate */
split_critical_edges, /* execute */
NULL, /* sub */
PROP_no_crit_edges, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ TODO_dump_func, /* todo_flags_finish */
};
\f
/* Emit return warnings. */
static void
execute_warn_function_return (void)
{
+#ifdef USE_MAPPED_LOCATION
+ source_location location;
+#else
location_t *locus;
+#endif
tree last;
edge e;
if (TREE_THIS_VOLATILE (cfun->decl)
&& EXIT_BLOCK_PTR->pred != NULL)
{
+#ifdef USE_MAPPED_LOCATION
+ location = UNKNOWN_LOCATION;
+#else
locus = NULL;
+#endif
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
{
last = last_stmt (e->src);
if (TREE_CODE (last) == RETURN_EXPR
+#ifdef USE_MAPPED_LOCATION
+ && (location = EXPR_LOCATION (last)) != UNKNOWN_LOCATION)
+#else
&& (locus = EXPR_LOCUS (last)) != NULL)
+#endif
break;
}
+#ifdef USE_MAPPED_LOCATION
+ if (location == UNKNOWN_LOCATION)
+ location = cfun->function_end_locus;
+ warning ("%H`noreturn' function does return", &location);
+#else
if (!locus)
locus = &cfun->function_end_locus;
warning ("%H`noreturn' function does return", locus);
+#endif
}
/* If we see "return;" in some basic block, then we do reach the end
if (TREE_CODE (last) == RETURN_EXPR
&& TREE_OPERAND (last, 0) == NULL)
{
+#ifdef USE_MAPPED_LOCATION
+ location = EXPR_LOCATION (last);
+ if (location == UNKNOWN_LOCATION)
+ location = cfun->function_end_locus;
+ warning ("%Hcontrol reaches end of non-void function", &location);
+#else
locus = EXPR_LOCUS (last);
if (!locus)
locus = &cfun->function_end_locus;
warning ("%Hcontrol reaches end of non-void function", locus);
+#endif
break;
}
}
NULL, /* next */
0, /* static_pass_number */
0, /* tv_id */
- PROP_ssa, /* properties_required */
+ PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */