summaryrefslogtreecommitdiff
path: root/gcc/except.c
diff options
context:
space:
mode:
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>2001-11-16 12:48:18 +0000
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>2001-11-16 12:48:18 +0000
commit5c15c916aff6315891f1893507081ab0f95ab007 (patch)
treec7687b57540a26d0d6218620d0cb0c8f6e8282d9 /gcc/except.c
parent2c014dab777d1b6dbea1b5ed3de478e100664d92 (diff)
downloadgcc-5c15c916aff6315891f1893507081ab0f95ab007.tar.gz
* except.c: Support for catching a list of types with a single handler
(struct eh_region): Change type and filter to lists for catch regions. (mark_eh_region): Mark the filter list for GC also. (expand_start_catch): Always build a list if argument not NULL and register each type of the list through add_type_for_runtime. (duplicate_eh_region_1): Change type into type_list for catch regions. (assign_filter_values): Assign a filter to each type associated with a catch region. Assign filter for NULL types in a unique entry in the filter list. (build_post_landing_pads): Emit compare and jump for each filter of the list associated with a catch region. (reachable_next_level): When the type thrown is known, stop the search as soon as one type within a catch list matches. Also, a handler is potentially reachable only if at least one of the types it catches has not been previously caught. (collect_one_action_chain): Retrieve the filter for a NULL type list from the first filter list entry. For non NULL type lists, add an action record for every filter assigned. * except.h: Reflect changes in comment before expand_start_catch. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@47087 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/except.c')
-rw-r--r--gcc/except.c193
1 files changed, 154 insertions, 39 deletions
diff --git a/gcc/except.c b/gcc/except.c
index 62f626b4ef6..7ddb80734e8 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -148,13 +148,13 @@ struct eh_region
rtx continue_label;
} try;
- /* The list through the catch handlers, the type object
- matched, and a pointer to the generated code. */
+ /* The list through the catch handlers, the list of type objects
+ matched, and the list of associated filters. */
struct {
struct eh_region *next_catch;
struct eh_region *prev_catch;
- tree type;
- int filter;
+ tree type_list;
+ tree filter_list;
} catch;
/* A tree_list of allowed types. */
@@ -485,7 +485,8 @@ mark_eh_region (region)
ggc_mark_rtx (region->u.try.continue_label);
break;
case ERT_CATCH:
- ggc_mark_tree (region->u.catch.type);
+ ggc_mark_tree (region->u.catch.type_list);
+ ggc_mark_tree (region->u.catch.filter_list);
break;
case ERT_ALLOWED_EXCEPTIONS:
ggc_mark_tree (region->u.allowed.type_list);
@@ -767,26 +768,44 @@ expand_start_all_catch ()
emit_jump (region->u.try.continue_label);
}
-/* Begin a catch clause. TYPE is the type caught, or null if this is
- a catch-all clause. */
+/* Begin a catch clause. TYPE is the type caught, a list of such types, or
+ null if this is a catch-all clause. Providing a type list enables to
+ associate the catch region with potentially several exception types, which
+ is useful e.g. for Ada. */
void
-expand_start_catch (type)
- tree type;
+expand_start_catch (type_or_list)
+ tree type_or_list;
{
struct eh_region *t, *c, *l;
+ tree type_list;
if (! doing_eh (0))
return;
- if (type)
- add_type_for_runtime (type);
+ type_list = type_or_list;
+
+ if (type_or_list)
+ {
+ /* Ensure to always end up with a type list to normalize further
+ processing, then register each type against the runtime types
+ map. */
+ tree type_node;
+
+ if (TREE_CODE (type_or_list) != TREE_LIST)
+ type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
+
+ type_node = type_list;
+ for (; type_node; type_node = TREE_CHAIN (type_node))
+ add_type_for_runtime (TREE_VALUE (type_node));
+ }
+
expand_eh_region_start ();
t = cfun->eh->try_region;
c = cfun->eh->cur_region;
c->type = ERT_CATCH;
- c->u.catch.type = type;
+ c->u.catch.type_list = type_list;
c->label = gen_label_rtx ();
l = t->u.try.last_catch;
@@ -1348,7 +1367,7 @@ duplicate_eh_region_1 (o, map)
break;
case ERT_CATCH:
- n->u.catch.type = o->u.catch.type;
+ n->u.catch.type_list = o->u.catch.type_list;
break;
case ERT_ALLOWED_EXCEPTIONS:
@@ -1693,7 +1712,36 @@ assign_filter_values ()
switch (r->type)
{
case ERT_CATCH:
- r->u.catch.filter = add_ttypes_entry (ttypes, r->u.catch.type);
+ /* Whatever type_list is (NULL or true list), we build a list
+ of filters for the region. */
+ r->u.catch.filter_list = NULL_TREE;
+
+ if (r->u.catch.type_list != NULL)
+ {
+ /* Get a filter value for each of the types caught and store
+ them in the region's dedicated list. */
+ tree tp_node = r->u.catch.type_list;
+
+ for (;tp_node; tp_node = TREE_CHAIN (tp_node))
+ {
+ int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
+ tree flt_node = build_int_2 (flt, 0);
+
+ r->u.catch.filter_list
+ = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
+ }
+ }
+ else
+ {
+ /* Get a filter value for the NULL list also since it will need
+ an action record anyway. */
+ int flt = add_ttypes_entry (ttypes, NULL);
+ tree flt_node = build_int_2 (flt, 0);
+
+ r->u.catch.filter_list
+ = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
+ }
+
break;
case ERT_ALLOWED_EXCEPTIONS:
@@ -1747,13 +1795,27 @@ build_post_landing_pads ()
for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
{
/* ??? _Unwind_ForcedUnwind wants no match here. */
- if (c->u.catch.type == NULL)
+ if (c->u.catch.type_list == NULL)
emit_jump (c->label);
else
- emit_cmp_and_jump_insns (cfun->eh->filter,
- GEN_INT (c->u.catch.filter),
- EQ, NULL_RTX, word_mode, 0,
- c->label);
+ {
+ /* Need for one cmp/jump per type caught. Each type
+ list entry has a matching entry in the filter list
+ (see assign_filter_values). */
+ tree tp_node = c->u.catch.type_list;
+ tree flt_node = c->u.catch.filter_list;
+
+ for (; tp_node; )
+ {
+ emit_cmp_and_jump_insns
+ (cfun->eh->filter,
+ GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)),
+ EQ, NULL_RTX, word_mode, 0, c->label);
+
+ tp_node = TREE_CHAIN (tp_node);
+ flt_node = TREE_CHAIN (flt_node);
+ }
+ }
}
}
@@ -2568,7 +2630,7 @@ reachable_next_level (region, type_thrown, info)
/* A catch-all handler ends the search. */
/* ??? _Unwind_ForcedUnwind will want outer cleanups
to be run as well. */
- if (c->u.catch.type == NULL)
+ if (c->u.catch.type_list == NULL)
{
add_reachable_handler (info, region, c);
return RNL_CAUGHT;
@@ -2576,14 +2638,20 @@ reachable_next_level (region, type_thrown, info)
if (type_thrown)
{
- /* If we have a type match, end the search. */
- if (c->u.catch.type == type_thrown
- || (lang_eh_type_covers
- && (*lang_eh_type_covers) (c->u.catch.type,
- type_thrown)))
+ /* If we have a at least one type match, end the search. */
+ tree tp_node = c->u.catch.type_list;
+
+ for (; tp_node; tp_node = TREE_CHAIN (tp_node))
{
- add_reachable_handler (info, region, c);
- return RNL_CAUGHT;
+ tree type = TREE_VALUE (tp_node);
+
+ if (type == type_thrown
+ || (lang_eh_type_covers
+ && (*lang_eh_type_covers) (type, type_thrown)))
+ {
+ add_reachable_handler (info, region, c);
+ return RNL_CAUGHT;
+ }
}
/* If we have definitive information of a match failure,
@@ -2592,19 +2660,49 @@ reachable_next_level (region, type_thrown, info)
return RNL_NOT_CAUGHT;
}
+ /* At this point, we either don't know what type is thrown or
+ don't have front-end assistance to help deciding if it is
+ covered by one of the types in the list for this region.
+
+ We'd then like to add this region to the list of reachable
+ handlers since it is indeed potentially reachable based on the
+ information we have.
+
+ Actually, this handler is for sure not reachable if all the
+ types it matches have already been caught. That is, it is only
+ potentially reachable if at least one of the types it catches
+ has not been previously caught. */
+
if (! info)
ret = RNL_MAYBE_CAUGHT;
-
- /* A type must not have been previously caught. */
- else if (! check_handled (info->types_caught, c->u.catch.type))
+ else
{
- add_reachable_handler (info, region, c);
- info->types_caught = tree_cons (NULL, c->u.catch.type,
- info->types_caught);
+ tree tp_node = c->u.catch.type_list;
+ bool maybe_reachable = false;
- /* ??? If the catch type is a base class of every allowed
- type, then we know we can stop the search. */
- ret = RNL_MAYBE_CAUGHT;
+ /* Compute the potential reachability of this handler and
+ update the list of types caught at the same time. */
+ for (; tp_node; tp_node = TREE_CHAIN (tp_node))
+ {
+ tree type = TREE_VALUE (tp_node);
+
+ if (! check_handled (info->types_caught, type))
+ {
+ info->types_caught
+ = tree_cons (NULL, type, info->types_caught);
+
+ maybe_reachable = true;
+ }
+ }
+
+ if (maybe_reachable)
+ {
+ add_reachable_handler (info, region, c);
+
+ /* ??? If the catch type is a base class of every allowed
+ type, then we know we can stop the search. */
+ ret = RNL_MAYBE_CAUGHT;
+ }
}
}
@@ -3144,10 +3242,21 @@ collect_one_action_chain (ar_hash, region)
next = -3;
for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch)
{
- if (c->u.catch.type == NULL)
- next = add_action_record (ar_hash, c->u.catch.filter, 0);
+ if (c->u.catch.type_list == NULL)
+ {
+ /* Retrieve the filter from the head of the filter list
+ where we have stored it (see assign_filter_values). */
+ int filter
+ = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
+
+ next = add_action_record (ar_hash, filter, 0);
+ }
else
{
+ /* Once the outer search is done, trigger an action record for
+ each filter we have. */
+ tree flt_node;
+
if (next == -3)
{
next = collect_one_action_chain (ar_hash, region->outer);
@@ -3162,7 +3271,13 @@ collect_one_action_chain (ar_hash, region)
else if (next <= 0)
next = add_action_record (ar_hash, 0, 0);
}
- next = add_action_record (ar_hash, c->u.catch.filter, next);
+
+ flt_node = c->u.catch.filter_list;
+ for (; flt_node; flt_node = TREE_CHAIN (flt_node))
+ {
+ int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
+ next = add_action_record (ar_hash, filter, next);
+ }
}
}
return next;