summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/except.c133
-rw-r--r--gcc/except.h3
-rw-r--r--gcc/tree-cfg.c10
-rw-r--r--gcc/tree-eh.c91
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