EH unwind bug

Jason Merrill jason@cygnus.com
Tue Dec 2 19:23:00 GMT 1997


>>>>> Thomas Weise <tom@zaphod.wh9.tu-dresden.de> writes:

> I've assigned this patch to egcs971201 and it fixes the testcase.
> Unfortunately I get a new internal error, please see the testcase below.

How about this instead?

Tue Dec  2 01:42:33 1997  Jason Merrill  <jason@yorick.cygnus.com>

	* except.c (expand_fixup_region_end): New fn.
	(expand_fixup_region_start): Likewise.
	(expand_eh_region_start_tree): Store cleanup into finalization here.
	* stmt.c (expand_cleanups): Use them to protect fixups.

Tue Dec  2 01:37:19 1997  Jason Merrill  <jason@yorick.cygnus.com>

	* exception.cc (__cp_pop_exception): Lose handler arg.
	* except.c (do_pop_exception): Likewise.
	(push_eh_cleanup): Let the cleanup mechanism supply the handler.
	(expand_end_catch_block): Likewise.

Index: except.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/except.c,v
retrieving revision 1.33
diff -c -r1.33 except.c
*** except.c	1997/11/25 09:32:06	1.33
--- except.c	1997/12/02 09:59:15
***************
*** 1013,1018 ****
--- 1013,1019 ----
      }
  
    expand_eh_region_start_for_decl (decl);
+   ehstack.top->entry->finalization = cleanup;
  
    return 0;
  }
***************
*** 1138,1143 ****
--- 1139,1195 ----
      }
  }
  
+ /* End the EH region for a goto fixup.  We only need them in the region-based
+    EH scheme.  */
+ 
+ void
+ expand_fixup_region_start ()
+ {
+   if (! doing_eh (0) || exceptions_via_longjmp)
+     return;
+ 
+   expand_eh_region_start ();
+ }
+ 
+ /* End the EH region for a goto fixup.  CLEANUP is the cleanup we just
+    expanded; to avoid running it twice if it throws, we look through the
+    ehqueue for a matching region and rethrow from its outer_context.  */
+ 
+ void
+ expand_fixup_region_end (cleanup)
+      tree cleanup;
+ {
+   tree t;
+   struct eh_node *node;
+   int yes;
+ 
+   if (! doing_eh (0) || exceptions_via_longjmp)
+     return;
+ 
+   for (node = ehstack.top; node && node->entry->finalization != cleanup; )
+     node = node->chain;
+   if (node == 0)
+     for (node = ehqueue.head; node && node->entry->finalization != cleanup; )
+       node = node->chain;
+   if (node == 0)
+     abort ();
+ 
+   yes = suspend_momentary ();
+ 
+   t = build (RTL_EXPR, void_type_node, NULL_RTX, const0_rtx);
+   TREE_SIDE_EFFECTS (t) = 1;
+   do_pending_stack_adjust ();
+   start_sequence_for_rtl_expr (t);
+   expand_internal_throw (node->entry->outer_context);
+   do_pending_stack_adjust ();
+   RTL_EXPR_SEQUENCE (t) = get_insns ();
+   end_sequence ();
+ 
+   resume_momentary (yes);
+ 
+   expand_eh_region_end (t);
+ }
+ 
  /* If we are using the setjmp/longjmp EH codegen method, we emit a
     call to __sjthrow.
  
Index: stmt.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/stmt.c,v
retrieving revision 1.131
diff -c -r1.131 stmt.c
*** stmt.c	1997/11/10 20:08:36	1.131
--- stmt.c	1997/12/02 04:11:35
***************
*** 4227,4233 ****
--- 4229,4242 ----
  		   the target.  Though the cleanups are expanded multiple
  		   times, the control paths are non-overlapping so the
  		   cleanups will not be executed twice.  */
+ 
+ 		/* We may need to protect fixups with rethrow regions.  */
+ 		int protect = (in_fixup && ! TREE_ADDRESSABLE (tail));
+ 		if (protect)
+ 		  expand_fixup_region_start ();
  		expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
+ 		if (protect)
+ 		  expand_fixup_region_end (TREE_VALUE (tail));
  		free_temp_slots ();
  	      }
  	  }
Index: cp/exception.cc
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/cp/exception.cc,v
retrieving revision 1.10
diff -c -r1.10 exception.cc
*** cp/exception.cc	1997/11/25 06:15:39	1.10
--- cp/exception.cc	1997/12/02 10:04:24
***************
*** 126,142 ****
  
  /* Compiler hook to pop an exception that has been finalized.  Used by
     push_eh_cleanup().  P is the info for the exception caught by the
!    current catch block, and HANDLER determines if we've been called from
!    an exception handler; if so, we avoid destroying the object on rethrow.  */
  
  extern "C" void
! __cp_pop_exception (cp_eh_info *p, bool handler)
  {
    cp_eh_info **q = &__eh_info;
  
    --p->handlers;
  
!   if (p->handlers > 0 || (handler && p == *q))
      return;
  
    for (; *q; q = &((*q)->next))
--- 126,145 ----
  
  /* Compiler hook to pop an exception that has been finalized.  Used by
     push_eh_cleanup().  P is the info for the exception caught by the
!    current catch block.  */
  
  extern "C" void
! __cp_pop_exception (cp_eh_info *p)
  {
    cp_eh_info **q = &__eh_info;
  
    --p->handlers;
  
!   /* Don't really pop if there are still active handlers for our exception,
!      or if our exception is being rethrown (i.e. if the active exception is
!      our exception and it is uncaught).  */
!   if (p->handlers != 0
!       || (p == *q && !p->caught))
      return;
  
    for (; *q; q = &((*q)->next))
Index: cp/except.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/cp/except.c,v
retrieving revision 1.138
diff -c -r1.138 except.c
*** cp/except.c	1997/11/27 20:55:03	1.138
--- cp/except.c	1997/12/02 03:27:09
***************
*** 440,447 ****
     if it is, it avoids destroying the object on rethrow.  */
  
  static tree
! do_pop_exception (handler)
!      tree handler;
  {
    tree fn, cleanup;
    fn = get_identifier ("__cp_pop_exception");
--- 440,446 ----
     if it is, it avoids destroying the object on rethrow.  */
  
  static tree
! do_pop_exception ()
  {
    tree fn, cleanup;
    fn = get_identifier ("__cp_pop_exception");
***************
*** 456,464 ****
        fn = build_lang_decl
  	(FUNCTION_DECL, fn,
  	 build_function_type (void_type_node, tree_cons
! 			      (NULL_TREE, ptr_type_node, tree_cons
! 			       (NULL_TREE, boolean_type_node,
! 				void_list_node))));
        DECL_EXTERNAL (fn) = 1;
        TREE_PUBLIC (fn) = 1;
        DECL_ARTIFICIAL (fn) = 1;
--- 455,461 ----
        fn = build_lang_decl
  	(FUNCTION_DECL, fn,
  	 build_function_type (void_type_node, tree_cons
! 			      (NULL_TREE, ptr_type_node, void_list_node)));
        DECL_EXTERNAL (fn) = 1;
        TREE_PUBLIC (fn) = 1;
        DECL_ARTIFICIAL (fn) = 1;
***************
*** 471,478 ****
    /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
    cleanup = lookup_name (get_identifier ("__exception_info"), 0);
    cleanup = build_function_call (fn, expr_tree_cons
! 				 (NULL_TREE, cleanup, expr_tree_cons
! 				  (NULL_TREE, handler, NULL_TREE)));
    return cleanup;
  }
  
--- 468,474 ----
    /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
    cleanup = lookup_name (get_identifier ("__exception_info"), 0);
    cleanup = build_function_call (fn, expr_tree_cons
! 				 (NULL_TREE, cleanup, NULL_TREE));
    return cleanup;
  }
  
***************
*** 481,497 ****
  static void
  push_eh_cleanup ()
  {
!   /* All cleanups must last longer than normal.  */
!   int yes = suspend_momentary ();
!   expand_decl_cleanup_no_eh (NULL_TREE, do_pop_exception (boolean_false_node));
!   resume_momentary (yes);
  
    expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
  	       const0_rtx, VOIDmode, EXPAND_NORMAL);
  
!   /* We don't destroy the exception object on rethrow, so we can't use
!      the normal cleanup mechanism for it.  */
!   expand_eh_region_start ();
  }
  
  /* call this to start a catch block. Typename is the typename, and identifier
--- 477,491 ----
  static void
  push_eh_cleanup ()
  {
!   int yes;
  
    expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
  	       const0_rtx, VOIDmode, EXPAND_NORMAL);
  
!   yes = suspend_momentary ();
!   /* All cleanups must last longer than normal.  */
!   expand_decl_cleanup (NULL_TREE, do_pop_exception ());
!   resume_momentary (yes);
  }
  
  /* call this to start a catch block. Typename is the typename, and identifier
***************
*** 657,665 ****
    expand_end_bindings (getdecls (), kept_level_p (), 0);
    poplevel (kept_level_p (), 1, 0);
        
-   /* Matches push_eh_cleanup.  */
-   expand_eh_region_end (do_pop_exception (boolean_true_node));
- 
    /* Cleanup the EH object.  */
    expand_end_bindings (getdecls (), kept_level_p (), 0);
    poplevel (kept_level_p (), 1, 0);
--- 651,656 ----



More information about the Gcc-bugs mailing list