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]

Fix EH redirection wrt nested try


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?

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]