From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jason Merrill To: Thomas Weise Cc: egcs-bugs@cygnus.com, egcs@cygnus.com Subject: Re: EH unwind bug Date: Wed, 03 Dec 1997 00:21:00 -0000 Message-id: References: <347B076D.6F1CEC10.cygnus.egcs.bugs@zaphod.wh9.tu-dresden.de> <34844A93.5E91@zaphod.wh9.tu-dresden.de> X-SW-Source: 1997-12/msg00163.html >>>>> Thomas Weise 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 * 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 * 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 ----