aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@gcc.gnu.org>1997-11-10 15:03:49 -0500
committerJason Merrill <jason@gcc.gnu.org>1997-11-10 15:03:49 -0500
commitc7ae64f2cc5733e40bfb3ca6a58a63ece97691e3 (patch)
treebcf117ed27d06a44b18a74813ec3d1623001099e
parent26f578a2286268f9ec2815978264f2647d6516ff (diff)
downloadgcc-c7ae64f2cc5733e40bfb3ca6a58a63ece97691e3.zip
gcc-c7ae64f2cc5733e40bfb3ca6a58a63ece97691e3.tar.gz
gcc-c7ae64f2cc5733e40bfb3ca6a58a63ece97691e3.tar.bz2
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
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/cp/ChangeLog21
-rw-r--r--gcc/cp/Make-lang.in8
-rw-r--r--gcc/cp/except.c132
-rw-r--r--gcc/cp/exception.cc21
-rw-r--r--gcc/cp/init.c12
-rw-r--r--gcc/cp/tree.c8
-rw-r--r--gcc/except.c1
-rw-r--r--gcc/stmt.c13
9 files changed, 168 insertions, 54 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 689259e..3322230 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+Mon Nov 10 03:02:19 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * 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 d4eed7b..b96f7b2 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 <jason@yorick.cygnus.com>
+
+ 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 <kenner@vlsi1.ultra.nyu.edu>
+
+ * Make-lang.in (c++.distdir): Make inc subdirectory.
+
Fri Nov 7 11:57:28 1997 Jason Merrill <jason@yorick.cygnus.com>
* decl2.c (finish_file): Put back some code.
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 78123ef..a1e5794 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 b95e8ab..e4cff1f 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 4099d47..2d1ae08 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 1ae838c..09a3de1 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 c681651..9d2589f 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 bf9cebf..29adf3b 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 b7a2c52..97a8d48 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