From: Jason Merrill Date: Mon, 10 Nov 1997 20:03:49 +0000 (-0500) Subject: stmt.c (expand_decl_cleanup_no_eh): New fn. X-Git-Tag: releases/libf2c-0.5.21~612 X-Git-Url: https://gcc.gnu.org/git/?a=commitdiff_plain;h=c7ae64f2cc5733e40bfb3ca6a58a63ece97691e3;p=gcc.git stmt.c (expand_decl_cleanup_no_eh): New fn. * stmt.c (expand_decl_cleanup_no_eh): New fn. * except.c (expand_leftover_cleanups): do_pending_stack_adjust. Complete nested exception support. * except.c (do_pop_exception): Split out... (push_eh_cleanup): From here. Handle the EH region by hand. (expand_start_catch_block): Add a new level for the catch parm. Move the rethrow region outside the two cleanup regions. Protect the initializer for the catch parm with terminate. (expand_end_catch_block): Likewise. End the region for the eh_cleanup. * exception.cc (__cp_pop_exception): Now takes two parms. Handle popping off the middle of the stack. * tree.c (lvalue_p, real_lvalue_p): Handle TRY_CATCH_EXPR, WITH_CLEANUP_EXPR, and UNSAVE_EXPR. (build_cplus_new): Only wrap CALL_EXPRs. * init.c (expand_default_init): Handle a TRY_CATCH_EXPR around the constructor call. From-SVN: r16419 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 689259e3d1fa..33222307c4f9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +Mon Nov 10 03:02:19 1997 Jason Merrill + + * stmt.c (expand_decl_cleanup_no_eh): New fn. + + * except.c (expand_leftover_cleanups): do_pending_stack_adjust. + Mon Nov 10 00:05:56 1997 Jeffrey A Law (law@cygnus.com) * alias.c (MAX_ALIAS_LOOP_PASSES): Define. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d4eed7b8f496..b96f7b27434c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -4,6 +4,27 @@ Sun Nov 9 01:29:55 1997 Jim Wilson (wilson@cygnus.com) * init.c (build_vec_delete_1): Delete build_block and add_block_current_level calls. +Mon Nov 10 03:04:20 1997 Jason Merrill + + Complete nested exception support. + * except.c (do_pop_exception): Split out... + (push_eh_cleanup): From here. Handle the EH region by hand. + (expand_start_catch_block): Add a new level for the catch parm. + Move the rethrow region outside the two cleanup regions. + Protect the initializer for the catch parm with terminate. + (expand_end_catch_block): Likewise. End the region for the eh_cleanup. + * exception.cc (__cp_pop_exception): Now takes two parms. Handle + popping off the middle of the stack. + * tree.c (lvalue_p, real_lvalue_p): Handle TRY_CATCH_EXPR, + WITH_CLEANUP_EXPR, and UNSAVE_EXPR. + (build_cplus_new): Only wrap CALL_EXPRs. + * init.c (expand_default_init): Handle a TRY_CATCH_EXPR around + the constructor call. + +Sun Nov 9 18:00:26 1997 Richard Kenner + + * Make-lang.in (c++.distdir): Make inc subdirectory. + Fri Nov 7 11:57:28 1997 Jason Merrill * decl2.c (finish_file): Put back some code. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 78123ef40b05..a1e5794492dd 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -1,5 +1,5 @@ # Top level makefile fragment for GNU C++. -# Copyright (C) 1994, 1995 Free Software Foundation, Inc. +# Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc. #This file is part of GNU CC. @@ -265,8 +265,14 @@ c++.stage4: stage4-start # distribution anyway. It then copies the files to the distdir directory. c++.distdir: mkdir tmp/cp + mkdir tmp/cp/inc cd cp ; $(MAKE) $(FLAGS_TO_PASS) $(CXX_FLAGS_TO_PASS) parse.c hash.h cd cp; \ for file in *[0-9a-zA-Z+]; do \ $(LN) $$file ../tmp/cp; \ done + cd cp/inc; \ + for file in *[0-9a-zA-Z+]; do \ + ln $$file ../../tmp/cp/inc >/dev/null 2>&1 \ + || cp $$file ../../tmp/cp/inc; \ + done diff --git a/gcc/cp/except.c b/gcc/cp/except.c index b95e8ab776af..e4cff1f823b9 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -461,26 +461,31 @@ build_eh_type (exp) return build_eh_type_type (TREE_TYPE (exp)); } -/* This routine creates the cleanup for the current exception. */ +/* Build up a call to __cp_pop_exception, to destroy the exception object + for the current catch block. HANDLER is either true or false, telling + the library whether or not it is being called from an exception handler; + if it is, it avoids destroying the object on rethrow. */ -static void -push_eh_cleanup () +static tree +do_pop_exception (handler) + tree handler; { - /* All cleanups must last longer than normal. */ - int yes = suspend_momentary (); tree fn, cleanup; - fn = get_identifier ("__cp_pop_exception"); if (IDENTIFIER_GLOBAL_VALUE (fn)) fn = IDENTIFIER_GLOBAL_VALUE (fn); else { - /* Declare void __cp_pop_exception (void), as defined in exception.cc. */ + /* Declare void __cp_pop_exception (void *), + as defined in exception.cc. */ push_obstacks_nochange (); end_temporary_allocation (); - fn = build_lang_decl (FUNCTION_DECL, fn, - build_function_type (void_type_node, - void_list_node)); + 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; @@ -491,12 +496,26 @@ push_eh_cleanup () } /* Arrange to do a dynamically scoped cleanup upon exit from this region. */ - cleanup = build_function_call (fn, NULL_TREE); - expand_decl_cleanup (NULL_TREE, cleanup); + 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))); +} + +/* This routine creates the cleanup for the current exception. */ +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); -} + /* 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 is the variable to place the object in or NULL if the variable doesn't @@ -530,7 +549,18 @@ expand_start_catch_block (declspecs, declarator) if (! doing_eh (1)) return; - /* Create a binding level for the parm. */ + /* If we are not doing setjmp/longjmp EH, because we are reordered + out of line, we arrange to rethrow in the outer context so as to + skip through the terminate region we are nested in, should we + encounter an exception in the catch handler. We also need to do + this because we are not physically within the try block, if any, + that contains this catch block. + + Matches the end in expand_end_catch_block. */ + expand_eh_region_start (); + + /* Create a binding level for the eh_info and the exception object + cleanup. */ pushlevel (0); expand_start_bindings (0); @@ -543,23 +573,17 @@ expand_start_catch_block (declspecs, declarator) if (declspecs) { - tree exp; - rtx call_rtx, return_value_rtx; - tree init_type; - decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE); if (decl == NULL_TREE) - { - error ("invalid catch parameter"); - - /* This is cheap, but we want to maintain the data - structures. */ - - expand_eh_region_start (); + error ("invalid catch parameter"); + } - return; - } + if (decl) + { + tree exp; + rtx call_rtx, return_value_rtx; + tree init_type; /* Make sure we mark the catch param as used, otherwise we'll get a warning about an unused ((anonymous)). */ @@ -592,37 +616,44 @@ expand_start_catch_block (declspecs, declarator) push_eh_cleanup (); - init = convert_from_reference (save_expr (make_tree (init_type, call_rtx))); + /* Create a binding level for the parm. */ + pushlevel (0); + expand_start_bindings (0); + + init = convert_from_reference (make_tree (init_type, call_rtx)); + + /* If the constructor for the catch parm exits via an exception, we + must call terminate. See eh23.C. */ + if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + { + /* Generate the copy constructor call directly so we can wrap it. + See also expand_default_init. */ + init = ocp_convert (TREE_TYPE (decl), init, + CONV_IMPLICIT|CONV_FORCE_TEMP, 0); + init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init, + TerminateFunctionCall); + } - /* Do we need the below two lines? */ /* Let `cp_finish_decl' know that this initializer is ok. */ DECL_INITIAL (decl) = init; decl = pushdecl (decl); + cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); } else { push_eh_cleanup (); + /* Create a binding level for the parm. */ + pushlevel (0); + expand_start_bindings (0); + /* Fall into the catch all section. */ } init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node); expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL); - /* If we are not doing setjmp/longjmp EH, because we are reordered - out of line, we arrange to rethrow in the outer context so as to - skip through the terminate region we are nested in, should we - encounter an exception in the catch handler. - - If we are doing setjmp/longjmp EH, we need to skip through the EH - object cleanup region. This isn't quite right, as we really need - to clean the object up, but we cannot do that until we track - multiple EH objects. - - Matches the end in expand_end_catch_block. */ - expand_eh_region_start (); - emit_line_note (input_filename, lineno); } @@ -642,6 +673,17 @@ expand_end_catch_block () if (! doing_eh (1)) return; + /* Cleanup the EH parameter. */ + 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); + t = make_node (RTL_EXPR); TREE_TYPE (t) = void_type_node; RTL_EXPR_RTL (t) = const0_rtx; @@ -672,7 +714,7 @@ expand_end_catch_block () RTL_EXPR_SEQUENCE (t) = get_insns (); end_sequence (); - /* Matches the start in expand_start_catch_block. */ + /* For the rethrow region. */ expand_eh_region_end (t); /* Fall to outside the try statement when done executing handler and @@ -682,10 +724,6 @@ expand_end_catch_block () expand_leftover_cleanups (); - /* Cleanup the EH parameter. */ - expand_end_bindings (getdecls (), kept_level_p (), 0); - poplevel (kept_level_p (), 1, 0); - /* label we emit to jump to if this catch block didn't match. */ /* This the closing } in the `if (eq) {' of the documentation. */ emit_label (pop_label_entry (&false_label_stack)); diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc index 4099d4776203..2d1ae0812470 100644 --- a/gcc/cp/exception.cc +++ b/gcc/cp/exception.cc @@ -118,12 +118,26 @@ __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int)) } /* Compiler hook to pop an exception that has been finalized. Used by - push_eh_cleanup(). */ + 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 (void) +__cp_pop_exception (cp_eh_info *p, bool handler) { - cp_eh_info *p = __eh_info; + cp_eh_info **q = &__eh_info; + + if (handler && p == *q) + return; + + for (; *q; q = &((*q)->next)) + if (*q == p) + break; + + if (! *q) + terminate (); + + *q = p->next; if (p->cleanup) /* 3 is a magic value for destructors; see build_delete(). */ @@ -133,7 +147,6 @@ __cp_pop_exception (void) else delete p->value; - __eh_info = p->next; delete p; } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1ae838cc2734..09a3de18c14e 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1266,7 +1266,17 @@ expand_default_init (binfo, true_exp, exp, init, alias_this, flags) && TREE_CODE (init) == TARGET_EXPR && TREE_TYPE (init) == type)) init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags); - expand_assignment (exp, init, 0, 0); + if (TREE_CODE (init) == TRY_CATCH_EXPR) + /* We need to protect the initialization of a catch parm + with a call to terminate(), which shows up as a TRY_CATCH_EXPR + around the TARGET_EXPR for the copy constructor. See + expand_start_catch_block. */ + TREE_OPERAND (init, 0) = build (INIT_EXPR, TREE_TYPE (exp), exp, + TREE_OPERAND (init, 0)); + else + init = build (INIT_EXPR, TREE_TYPE (exp), exp, init); + TREE_SIDE_EFFECTS (init) = 1; + expand_expr_stmt (init); return; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c681651ebf1f..9d2589fec6dc 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -78,6 +78,9 @@ real_lvalue_p (ref) case PREDECREMENT_EXPR: case COMPONENT_REF: case SAVE_EXPR: + case UNSAVE_EXPR: + case TRY_CATCH_EXPR: + case WITH_CLEANUP_EXPR: return real_lvalue_p (TREE_OPERAND (ref, 0)); case STRING_CST: @@ -152,6 +155,9 @@ lvalue_p (ref) case IMAGPART_EXPR: case COMPONENT_REF: case SAVE_EXPR: + case UNSAVE_EXPR: + case TRY_CATCH_EXPR: + case WITH_CLEANUP_EXPR: return lvalue_p (TREE_OPERAND (ref, 0)); case STRING_CST: @@ -238,7 +244,7 @@ build_cplus_new (type, init) tree slot; tree rval; - if (TREE_CODE (init) == TARGET_EXPR || init == error_mark_node) + if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != NEW_EXPR) return init; slot = build (VAR_DECL, type); diff --git a/gcc/except.c b/gcc/except.c index bf9cebffca9f..29adf3b66c91 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -1224,6 +1224,7 @@ expand_leftover_cleanups () } } + do_pending_stack_adjust (); free (entry); } } diff --git a/gcc/stmt.c b/gcc/stmt.c index b7a2c52f43c2..97a8d48a0794 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -4012,6 +4012,19 @@ expand_decl_cleanup (decl, cleanup) return 1; } +/* Like expand_decl_cleanup, but suppress generating an exception handler + to perform the cleanup. */ + +int +expand_decl_cleanup_no_eh (decl, cleanup) + tree decl, cleanup; +{ + int save_eh = using_eh_for_cleanups_p; + using_eh_for_cleanups_p = 0; + expand_decl_cleanup (decl, cleanup); + using_eh_for_cleanups_p = save_eh; +} + /* Arrange for the top element of the dynamic cleanup chain to be popped if we exit the current binding contour. DECL is the associated declaration, if any, otherwise NULL_TREE. If the