* tree-cfg.c (tree_duplicate_bb): Duplicate EH region too.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 25 Apr 2005 17:24:28 +0000 (17:24 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 25 Apr 2005 17:24:28 +0000 (17:24 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@98724 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/except.c
gcc/except.h
gcc/tree-cfg.c
gcc/tree-eh.c

index f8784db..4615989 100644 (file)
@@ -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.
index b70a1f7..2b5ec64 100644 (file)
@@ -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"
index 05a3417..06fb78d 100644 (file)
@@ -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
index d3c71ab..a9098cd 100644 (file)
@@ -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);
index 90f9061..e21b5c5 100644 (file)
@@ -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;
+}
 
 \f
 /* Return true if the expr can trap, as in dereferencing an invalid pointer