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
This commit is contained in:
Jason Merrill 1997-11-10 15:03:49 -05:00
parent 26f578a228
commit c7ae64f2cc
9 changed files with 169 additions and 55 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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);
resume_momentary (yes);
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");
error ("invalid catch parameter");
}
/* This is cheap, but we want to maintain the data
structures. */
expand_eh_region_start ();
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));

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -1224,6 +1224,7 @@ expand_leftover_cleanups ()
}
}
do_pending_stack_adjust ();
free (entry);
}
}

View File

@ -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