This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Fix EH redirection wrt nested try


On Fri, May 8, 2009 at 9:40 PM, Jan Hubicka <hubicka@ucw.cz> wrote:
> Hi,
> this patch fix problem with EH redirection in the following testcase:
>
> struct A
> {
> ?~A();
> ?void foo();
> };
>
> void bar()
> {
> ?A a;
>
> ?try
> ?{
> ? ?A b;
>
> ? ?try
> ? ?{
> ? ? ?b.foo();
> ? ?}
> ? ?catch (int) {}
> ?}
> ?catch (int) {}
> }
>
> The CFG is build in a way that the edge from b.foo points to the inner TRY
> block, the associated cleanup and there is outer cleanup. find_reachable_region
> is able to work out that the outer TRY block is not going to be taken.
>
> Problem however here is that after redirection, we do not copy the outer TRY
> block (as it is not going to be taken) and we have cascaded cleanups.
> There is code in foreach_reachable_handler skipping cleanups up to next TRY
> so the outer cleanup is skipped.
>
> This patch solves the problem by making foreach_reachable_handler to skip the
> cleanups to first TRY that may throw, so we don't have such disappearing edge.
>
> There is also need to update prev_try pointer here when try is going to disappear.
>
> Bootstrapped/regtested x86_64-linux, OK?

Ok if you also add the testcase to the C++ torture.

Thanks,
Richard.

> Honza
> ? ? ? ?PR middle-end/40043
> ? ? ? ?* except.c (copy_eh_region): Always set prev_try.
> ? ? ? ?(redirect_eh_edge_to_label): Find outer try.
> ? ? ? ?(foreach_reachable_handler): When looking for prev try
> ? ? ? ?handle case where previous try is not going to be taken.
> Index: except.c
> ===================================================================
> *** except.c ? ?(revision 147279)
> --- except.c ? ?(working copy)
> *************** copy_eh_region (struct eh_region *old, s
> *** 1410,1418 ****
> ? ? ?{
> ? ? ? ?gcc_assert (old->type != ERT_TRY);
> ? ? ? ?r = copy_eh_region_1 (old, new_outer);
> ! ? ? ? if (r->type == ERT_CLEANUP && prev_try_map)
> ? ? ? ? ?{
> ! ? ? ? ? gcc_assert (r->u.cleanup.prev_try);
> ? ? ? ? ? ?r->u.cleanup.prev_try = prev_try_map;
> ? ? ? ?}
> ? ? ? ?return r;
> --- 1410,1418 ----
> ? ? ?{
> ? ? ? ?gcc_assert (old->type != ERT_TRY);
> ? ? ? ?r = copy_eh_region_1 (old, new_outer);
> ! ? ? ? if (r->type == ERT_CLEANUP)
> ? ? ? ? ?{
> ! ? ? ? ? gcc_assert (r->u.cleanup.prev_try || !prev_try_map);
> ? ? ? ? ? ?r->u.cleanup.prev_try = prev_try_map;
> ? ? ? ?}
> ? ? ? ?return r;
> *************** struct eh_region *
> *** 1477,1483 ****
> ?redirect_eh_edge_to_label (edge e, tree new_dest_label, bool is_resx,
> ? ? ? ? ? ? ? ? ? ? ? ? ? bool inlinable_call, int region_number)
> ?{
> ! ? struct eh_region *outer, *prev_try_map = NULL;
> ? ?struct eh_region *region;
> ? ?VEC (eh_region, heap) * trace = NULL;
> ? ?int i;
> --- 1477,1483 ----
> ?redirect_eh_edge_to_label (edge e, tree new_dest_label, bool is_resx,
> ? ? ? ? ? ? ? ? ? ? ? ? ? bool inlinable_call, int region_number)
> ?{
> ! ? struct eh_region *outer, *prev_try_map;
> ? ?struct eh_region *region;
> ? ?VEC (eh_region, heap) * trace = NULL;
> ? ?int i;
> *************** redirect_eh_edge_to_label (edge e, tree
> *** 1539,1544 ****
> --- 1539,1545 ----
> ? ? ? ?}
> ? ? ? ?outer = VEC_index (eh_region, trace, start_here)->outer;
> ? ? ? ?gcc_assert (start_here >= 0);
> + ? ? ? prev_try_map = find_prev_try (outer);
>
> ? ? ? ?/* And now do the dirty job! ?*/
> ? ? ? ?for (i = start_here; i >= 0; i--)
> *************** foreach_reachable_handler (int region_nu
> *** 3120,3127 ****
> ? ? ? ? to the next outer cleanup region, so the flow graph will be
> ? ? ? ? accurate. ?*/
> ? ? ? ?if (region->type == ERT_CLEANUP)
> ! ? ? ? region = region->u.cleanup.prev_try;
> ! ? ? ? else
> ? ? ? ?region = region->outer;
> ? ? ?}
> ?}
> --- 3121,3140 ----
> ? ? ? ? to the next outer cleanup region, so the flow graph will be
> ? ? ? ? accurate. ?*/
> ? ? ? ?if (region->type == ERT_CLEANUP)
> ! ? ? ? ? {
> ! ? ? ? ? enum reachable_code code = RNL_NOT_CAUGHT;
> ! ? ? ? ? region = region->u.cleanup.prev_try;
> ! ? ? ? ? /* Continue looking for outer TRY region until we find one
> ! ? ? ? ? ? ?that might cath something. ?*/
> ! ? ? ? ? ? while (region
> ! ? ? ? ? ? ? ? ?&& (code = reachable_next_level (region, type_thrown, &info,
> ! ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? inlinable_call || is_resx))
> ! ? ? ? ? ? ? ? ? ? ?== RNL_NOT_CAUGHT)
> ! ? ? ? ? ? region = find_prev_try (region->outer);
> ! ? ? ? ? if (code >= RNL_CAUGHT)
> ! ? ? ? ? ? break;
> ! ? ? ? }
> ! ? ? ? if (region)
> ? ? ? ?region = region->outer;
> ? ? ?}
> ?}
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]