tree-cfg.c (tree_duplicate_bb): Duplicate EH region too.
* 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. From-SVN: r98724
This commit is contained in:
parent
2845f02a6f
commit
cc7220fd0e
@ -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>
|
2005-04-25 Nathan Sidwell <nathan@codesourcery.com>
|
||||||
|
|
||||||
* tree-ssa-alias.c (fieldoff_t): Remove.
|
* tree-ssa-alias.c (fieldoff_t): Remove.
|
||||||
|
133
gcc/except.c
133
gcc/except.c
@ -74,6 +74,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "langhooks.h"
|
#include "langhooks.h"
|
||||||
#include "cgraph.h"
|
#include "cgraph.h"
|
||||||
|
#include "diagnostic.h"
|
||||||
|
|
||||||
/* Provide defaults for stuff that may not be defined when using
|
/* Provide defaults for stuff that may not be defined when using
|
||||||
sjlj exceptions. */
|
sjlj exceptions. */
|
||||||
@ -3435,4 +3436,136 @@ output_function_exception_table (void)
|
|||||||
current_function_section (current_function_decl);
|
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"
|
#include "gt-except.h"
|
||||||
|
@ -101,9 +101,12 @@ extern void foreach_reachable_handler (int, bool,
|
|||||||
|
|
||||||
extern void collect_eh_region_array (void);
|
extern void collect_eh_region_array (void);
|
||||||
extern void expand_resx_expr (tree);
|
extern void expand_resx_expr (tree);
|
||||||
|
extern void verify_eh_tree (struct function *);
|
||||||
|
extern void dump_eh_tree (FILE *, struct function *);
|
||||||
|
|
||||||
/* tree-eh.c */
|
/* tree-eh.c */
|
||||||
extern int lookup_stmt_eh_region (tree);
|
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
|
/* If non-NULL, this is a function that returns an expression to be
|
||||||
executed if an unhandled exception is propagated out of a cleanup
|
executed if an unhandled exception is propagated out of a cleanup
|
||||||
|
@ -554,6 +554,8 @@ make_exit_edges (basic_block bb)
|
|||||||
gcc_assert (last);
|
gcc_assert (last);
|
||||||
switch (TREE_CODE (last))
|
switch (TREE_CODE (last))
|
||||||
{
|
{
|
||||||
|
case RESX_EXPR:
|
||||||
|
break;
|
||||||
case CALL_EXPR:
|
case CALL_EXPR:
|
||||||
/* If this function receives a nonlocal goto, then we need to
|
/* If this function receives a nonlocal goto, then we need to
|
||||||
make edges from this call site to all the nonlocal goto
|
make edges from this call site to all the nonlocal goto
|
||||||
@ -3761,6 +3763,8 @@ tree_verify_flow_info (void)
|
|||||||
|
|
||||||
stmt = bsi_stmt (bsi);
|
stmt = bsi_stmt (bsi);
|
||||||
|
|
||||||
|
err |= verify_eh_edges (stmt);
|
||||||
|
|
||||||
if (is_ctrl_stmt (stmt))
|
if (is_ctrl_stmt (stmt))
|
||||||
{
|
{
|
||||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||||
@ -4729,6 +4733,7 @@ tree_duplicate_bb (basic_block bb)
|
|||||||
def_operand_p def_p;
|
def_operand_p def_p;
|
||||||
ssa_op_iter op_iter;
|
ssa_op_iter op_iter;
|
||||||
tree stmt, copy;
|
tree stmt, copy;
|
||||||
|
int region;
|
||||||
|
|
||||||
stmt = bsi_stmt (bsi);
|
stmt = bsi_stmt (bsi);
|
||||||
if (TREE_CODE (stmt) == LABEL_EXPR)
|
if (TREE_CODE (stmt) == LABEL_EXPR)
|
||||||
@ -4739,6 +4744,9 @@ tree_duplicate_bb (basic_block bb)
|
|||||||
copy = unshare_expr (stmt);
|
copy = unshare_expr (stmt);
|
||||||
bsi_insert_after (&bsi_tgt, copy, BSI_NEW_STMT);
|
bsi_insert_after (&bsi_tgt, copy, BSI_NEW_STMT);
|
||||||
copy_virtual_operands (copy, 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
|
/* Create new names for all the definitions created by COPY and
|
||||||
add replacement mappings for each new name. */
|
add replacement mappings for each new name. */
|
||||||
@ -4947,6 +4955,8 @@ dump_function_to_file (tree fn, FILE *file, int flags)
|
|||||||
}
|
}
|
||||||
fprintf (file, ")\n");
|
fprintf (file, ")\n");
|
||||||
|
|
||||||
|
if (flags & TDF_DETAILS)
|
||||||
|
dump_eh_tree (file, DECL_STRUCT_FUNCTION (fn));
|
||||||
if (flags & TDF_RAW)
|
if (flags & TDF_RAW)
|
||||||
{
|
{
|
||||||
dump_node (fn, TDF_SLIM | flags, file);
|
dump_node (fn, TDF_SLIM | flags, file);
|
||||||
|
@ -1746,6 +1746,97 @@ make_eh_edges (tree stmt)
|
|||||||
foreach_reachable_handler (region_nr, is_resx, make_eh_edge, 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
|
/* Return true if the expr can trap, as in dereferencing an invalid pointer
|
||||||
|
Loading…
Reference in New Issue
Block a user