diff options
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/except.c | 133 | ||||
-rw-r--r-- | gcc/except.h | 3 | ||||
-rw-r--r-- | gcc/tree-cfg.c | 10 | ||||
-rw-r--r-- | gcc/tree-eh.c | 91 |
5 files changed, 250 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f8784dbc5cf..461598964d0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2005-04-25 Jan Hubicka <jh@suse.cz> + + * tree-cfg.c (tree_duplicate_bb): Duplicate EH region too. + + * except.c: Include diagnostic.h + (dump_eh_tree, verify_eh_tree): New functions. + * except.h (verify_eh_tree, dump_eh_tree, verify_eh_edges): Declare. + * tree-cfg.c (tree_verify_flow_info): verify eh edges. + (dump_function_to_file): dump eh tree. + * tree-eh.c (mark_eh_edge): New function. + (mark_eh_edge_found_error): New static variable. + (verify_eh_edges): New function. + 2005-04-25 Nathan Sidwell <nathan@codesourcery.com> * tree-ssa-alias.c (fieldoff_t): Remove. diff --git a/gcc/except.c b/gcc/except.c index b70a1f764c5..2b5ec647578 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -74,6 +74,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "target.h" #include "langhooks.h" #include "cgraph.h" +#include "diagnostic.h" /* Provide defaults for stuff that may not be defined when using sjlj exceptions. */ @@ -3435,4 +3436,136 @@ output_function_exception_table (void) current_function_section (current_function_decl); } +/* Dump EH information to OUT. */ +void +dump_eh_tree (FILE *out, struct function *fun) +{ + struct eh_region *i; + int depth = 0; + static const char * const type_name[] = {"unknown", "cleanup", "try", "catch", + "allowed_exceptions", "must_not_throw", + "throw", "fixup"}; + + i = fun->eh->region_tree; + if (! i) + return; + + fprintf (out, "Eh tree:\n"); + while (1) + { + fprintf (out, " %*s %i %s", depth * 2, "", + i->region_number, type_name [(int)i->type]); + if (i->tree_label) + { + fprintf (out, " tree_label:"); + print_generic_expr (out, i->tree_label, 0); + } + fprintf (out, "\n"); + /* If there are sub-regions, process them. */ + if (i->inner) + i = i->inner, depth++; + /* If there are peers, process them. */ + else if (i->next_peer) + i = i->next_peer; + /* Otherwise, step back up the tree to the next peer. */ + else + { + do { + i = i->outer; + depth--; + if (i == NULL) + return; + } while (i->next_peer == NULL); + i = i->next_peer; + } + } +} + +/* Verify some basic invariants on EH datastructures. Could be extended to + catch more. */ +void +verify_eh_tree (struct function *fun) +{ + struct eh_region *i, *outer = NULL; + bool err = false; + int nvisited = 0; + int count = 0; + int j; + int depth = 0; + + i = fun->eh->region_tree; + if (! i) + return; + for (j = fun->eh->last_region_number; j > 0; --j) + if (fun->eh->region_array[j]) + { + count++; + if (fun->eh->region_array[j]->region_number != j) + { + error ("region_array is corrupted for region %i", i->region_number); + err = true; + } + } + + while (1) + { + if (fun->eh->region_array[i->region_number] != i) + { + error ("region_array is corrupted for region %i", i->region_number); + err = true; + } + if (i->outer != outer) + { + error ("outer block of region %i is wrong", i->region_number); + err = true; + } + if (i->may_contain_throw && outer && !outer->may_contain_throw) + { + error ("region %i may contain throw and is contained in region that may not", + i->region_number); + err = true; + } + if (depth < 0) + { + error ("negative nesting depth of region %i", i->region_number); + err = true; + } + nvisited ++; + /* If there are sub-regions, process them. */ + if (i->inner) + outer = i, i = i->inner, depth++; + /* If there are peers, process them. */ + else if (i->next_peer) + i = i->next_peer; + /* Otherwise, step back up the tree to the next peer. */ + else + { + do { + i = i->outer; + depth--; + if (i == NULL) + { + if (depth != -1) + { + error ("Tree list ends on depth %i", depth + 1); + err = true; + } + if (count != nvisited) + { + error ("array does not match the region tree"); + err = true; + } + if (err) + { + dump_eh_tree (stderr, fun); + internal_error ("verify_eh_tree failed."); + } + return; + } + outer = i->outer; + } while (i->next_peer == NULL); + i = i->next_peer; + } + } +} #include "gt-except.h" diff --git a/gcc/except.h b/gcc/except.h index 05a3417832b..06fb78d5588 100644 --- a/gcc/except.h +++ b/gcc/except.h @@ -101,9 +101,12 @@ extern void foreach_reachable_handler (int, bool, extern void collect_eh_region_array (void); extern void expand_resx_expr (tree); +extern void verify_eh_tree (struct function *); +extern void dump_eh_tree (FILE *, struct function *); /* tree-eh.c */ extern int lookup_stmt_eh_region (tree); +extern bool verify_eh_edges (tree); /* If non-NULL, this is a function that returns an expression to be executed if an unhandled exception is propagated out of a cleanup diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index d3c71abb37a..a9098cdc465 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -554,6 +554,8 @@ make_exit_edges (basic_block bb) gcc_assert (last); switch (TREE_CODE (last)) { + case RESX_EXPR: + break; case CALL_EXPR: /* If this function receives a nonlocal goto, then we need to make edges from this call site to all the nonlocal goto @@ -3761,6 +3763,8 @@ tree_verify_flow_info (void) stmt = bsi_stmt (bsi); + err |= verify_eh_edges (stmt); + if (is_ctrl_stmt (stmt)) { FOR_EACH_EDGE (e, ei, bb->succs) @@ -4729,6 +4733,7 @@ tree_duplicate_bb (basic_block bb) def_operand_p def_p; ssa_op_iter op_iter; tree stmt, copy; + int region; stmt = bsi_stmt (bsi); if (TREE_CODE (stmt) == LABEL_EXPR) @@ -4739,6 +4744,9 @@ tree_duplicate_bb (basic_block bb) copy = unshare_expr (stmt); bsi_insert_after (&bsi_tgt, copy, BSI_NEW_STMT); copy_virtual_operands (copy, stmt); + region = lookup_stmt_eh_region (stmt); + if (region >= 0) + add_stmt_to_eh_region (copy, region); /* Create new names for all the definitions created by COPY and add replacement mappings for each new name. */ @@ -4947,6 +4955,8 @@ dump_function_to_file (tree fn, FILE *file, int flags) } fprintf (file, ")\n"); + if (flags & TDF_DETAILS) + dump_eh_tree (file, DECL_STRUCT_FUNCTION (fn)); if (flags & TDF_RAW) { dump_node (fn, TDF_SLIM | flags, file); diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 90f90611d01..e21b5c51a5b 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -1746,6 +1746,97 @@ make_eh_edges (tree stmt) foreach_reachable_handler (region_nr, is_resx, make_eh_edge, stmt); } +static bool mark_eh_edge_found_error; + +/* Mark edge make_eh_edge would create for given region by setting it aux + field, output error if something goes wrong. */ +static void +mark_eh_edge (struct eh_region *region, void *data) +{ + tree stmt, lab; + basic_block src, dst; + edge e; + + stmt = data; + lab = get_eh_region_tree_label (region); + + src = bb_for_stmt (stmt); + dst = label_to_block (lab); + + e = find_edge (src, dst); + if (!e) + { + error ("EH edge %i->%i is missing %i %i.", src->index, dst->index, src, dst); + mark_eh_edge_found_error = true; + } + else if (!(e->flags & EDGE_EH)) + { + error ("EH edge %i->%i miss EH flag.", src->index, dst->index); + mark_eh_edge_found_error = true; + } + else if (e->aux) + { + /* ??? might not be mistake. */ + error ("EH edge %i->%i has duplicated regions.", src->index, dst->index); + mark_eh_edge_found_error = true; + } + else + e->aux = (void *)1; +} + +/* Verify that BB containing stmt as last stmt has precisely the edges + make_eh_edges would create. */ +bool +verify_eh_edges (tree stmt) +{ + int region_nr; + bool is_resx; + basic_block bb = bb_for_stmt (stmt); + edge_iterator ei; + edge e; + + FOR_EACH_EDGE (e, ei, bb->succs) + gcc_assert (!e->aux); + mark_eh_edge_found_error = false; + if (TREE_CODE (stmt) == RESX_EXPR) + { + region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)); + is_resx = true; + } + else + { + region_nr = lookup_stmt_eh_region (stmt); + if (region_nr < 0) + { + FOR_EACH_EDGE (e, ei, bb->succs) + if (e->flags & EDGE_EH) + { + error ("BB %i can not throw but has EH edges", bb->index); + return true; + } + return false; + } + if (!tree_could_throw_p (stmt)) + { + error ("BB %i last statement has incorrectly set region", bb->index); + return true; + } + is_resx = false; + } + + foreach_reachable_handler (region_nr, is_resx, mark_eh_edge, stmt); + FOR_EACH_EDGE (e, ei, bb->succs) + { + if ((e->flags & EDGE_EH) && !e->aux) + { + error ("Unnecesary EH edge %i->%i", bb->index, e->dest->index); + mark_eh_edge_found_error = true; + return true; + } + e->aux = NULL; + } + return mark_eh_edge_found_error; +} /* Return true if the expr can trap, as in dereferencing an invalid pointer |