exception.cc (__eh_alloc, __eh_free): New fns.

* exception.cc (__eh_alloc, __eh_free): New fns.
	(__cp_push_exception, __cp_pop_exception): Use them.
	(__uncatch_exception): Call terminate here if no exception.
	* except.c (build_terminate_handler): New fn.
	(expand_start_catch_block): Use it.
	(expand_exception_blocks): Likewise.
	(alloc_eh_object): New fn.
	(expand_throw): Use it.  Protect exception init with terminate.
	* typeck.c (build_modify_expr): Remove code that ignores trivial
	methods.

From-SVN: r17309
This commit is contained in:
Jason Merrill 1998-01-08 00:29:08 +00:00 committed by Jason Merrill
parent b450b6999c
commit f4a233434d
4 changed files with 150 additions and 46 deletions

View File

@ -1,3 +1,16 @@
Wed Jan 7 23:47:13 1998 Jason Merrill <jason@yorick.cygnus.com>
* exception.cc (__eh_alloc, __eh_free): New fns.
(__cp_push_exception, __cp_pop_exception): Use them.
(__uncatch_exception): Call terminate here if no exception.
* except.c (build_terminate_handler): New fn.
(expand_start_catch_block): Use it.
(expand_exception_blocks): Likewise.
(alloc_eh_object): New fn.
(expand_throw): Use it. Protect exception init with terminate.
* typeck.c (build_modify_expr): Remove code that ignores trivial
methods.
Mon Dec 22 11:36:27 1997 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* call.c (add_builtin_candidate): Add default case in enumeration

View File

@ -477,6 +477,18 @@ push_eh_cleanup ()
resume_momentary (yes);
}
/* Build up a call to terminate on the function obstack, for use as an
exception handler. */
tree
build_terminate_handler ()
{
int yes = suspend_momentary ();
tree term = build_function_call (Terminate, NULL_TREE);
resume_momentary (yes);
return term;
}
/* 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
matter. If typename is NULL, that means its a "catch (...)" or catch
@ -582,15 +594,12 @@ expand_start_catch_block (declspecs, declarator)
must call terminate. See eh23.C. */
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
{
int yes = suspend_momentary ();
tree term = build_function_call (Terminate, NULL_TREE);
resume_momentary (yes);
/* 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, term);
init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
build_terminate_handler ());
}
/* Let `cp_finish_decl' know that this initializer is ok. */
@ -854,7 +863,7 @@ expand_exception_blocks ()
catch_clauses = NULL_RTX;
if (exceptions_via_longjmp == 0)
expand_eh_region_end (build_function_call (Terminate, NULL_TREE));
expand_eh_region_end (build_terminate_handler ());
expand_leftover_cleanups ();
@ -914,6 +923,41 @@ end_anon_func ()
pop_cp_function_context (NULL_TREE);
}
/* Return a pointer to a buffer for an exception object of type TYPE. */
tree
alloc_eh_object (type)
tree type;
{
tree fn, exp;
fn = get_identifier ("__eh_alloc");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
/* Declare __eh_alloc (size_t), as defined in exception.cc. */
tree tmp;
push_obstacks_nochange ();
end_temporary_allocation ();
tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
fn = build_lang_decl (FUNCTION_DECL, fn,
build_function_type (ptr_type_node, tmp));
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
pushdecl_top_level (fn);
make_function_rtl (fn);
assemble_external (fn);
pop_obstacks ();
}
exp = build_function_call (fn, expr_tree_cons
(NULL_TREE, size_in_bytes (type), NULL_TREE));
exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
return exp;
}
/* Expand a throw statement. This follows the following
algorithm:
@ -965,17 +1009,61 @@ expand_throw (exp)
}
else
{
tree object;
tree object, ptr;
/* Make a copy of the thrown object. WP 15.1.5 */
exp = build_new (NULL_TREE, TREE_TYPE (exp),
build_expr_list (NULL_TREE, exp),
0);
/* OK, this is kind of wacky. The WP says that we call
terminate
when the exception handling mechanism, after completing
evaluation of the expression to be thrown but before the
exception is caught (_except.throw_), calls a user function
that exits via an uncaught exception.
So we have to protect the actual initialization of the
exception object with terminate(), but evaluate the expression
first. We also expand the call to __eh_alloc
first. Since there could be temps in the expression, we need
to handle that, too. */
expand_start_target_temps ();
#if 0
/* Unfortunately, this doesn't work. */
preexpand_calls (exp);
#else
/* Store the throw expression into a temp. This can be less
efficient than storing it into the allocated space directly, but
oh well. To do this efficiently we would need to insinuate
ourselves into expand_call. */
if (TREE_SIDE_EFFECTS (exp))
{
tree temp = build (VAR_DECL, TREE_TYPE (exp));
DECL_ARTIFICIAL (temp) = 1;
layout_decl (temp, 0);
DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
expand_expr (build (INIT_EXPR, TREE_TYPE (exp), temp, exp),
NULL_RTX, VOIDmode, 0);
expand_decl_cleanup (NULL_TREE, maybe_build_cleanup (temp));
exp = temp;
}
#endif
/* Allocate the space for the exception. */
ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
expand_expr (ptr, const0_rtx, VOIDmode, 0);
expand_eh_region_start ();
object = build_indirect_ref (ptr, NULL_PTR);
exp = build_modify_expr (object, INIT_EXPR, exp);
if (exp == error_mark_node)
error (" in thrown expression");
object = build_indirect_ref (exp, NULL_PTR);
expand_expr (exp, const0_rtx, VOIDmode, 0);
expand_eh_region_end (build_terminate_handler ());
expand_end_target_temps ();
throw_type = build_eh_type (object);
if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
@ -988,6 +1076,8 @@ expand_throw (exp)
/* Pretend it's a normal function. */
cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
}
exp = ptr;
}
if (cleanup == NULL_TREE)
@ -1021,8 +1111,6 @@ expand_throw (exp)
pop_obstacks ();
}
/* The throw expression is a full-expression. */
exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
(NULL_TREE, throw_type, expr_tree_cons
(NULL_TREE, cleanup, NULL_TREE)));

View File

@ -29,6 +29,7 @@
#include "typeinfo"
#include "exception"
#include <stddef.h>
/* Define terminate, unexpected, set_terminate, set_unexpected as
well as the default terminate func and default unexpected func. */
@ -108,13 +109,37 @@ __cp_exception_info (void)
return *__get_eh_info ();
}
/* Allocate a buffer for a cp_eh_info and an exception object of size SIZE,
and return a pointer to the beginning of the object's space. */
extern "C" void * malloc (size_t);
extern "C" void *
__eh_alloc (size_t size)
{
void *p = malloc (size);
if (p == 0)
terminate ();
return p;
}
/* Free the memory for an cp_eh_info and associated exception, given
a pointer to the cp_eh_info. */
extern "C" void free (void *);
extern "C" void
__eh_free (void *p)
{
free (p);
}
/* Compiler hook to push a new exception onto the stack.
Used by expand_throw(). */
extern "C" void
__cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
{
cp_eh_info *p = new cp_eh_info;
cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
p->value = value;
p->type = type;
p->cleanup = cleanup;
@ -155,23 +180,22 @@ __cp_pop_exception (cp_eh_info *p)
*q = p->next;
if (p->cleanup)
/* 3 is a magic value for destructors; see build_delete(). */
p->cleanup (p->value, 3);
else if (__is_pointer (p->type))
/* do nothing; pointers are passed directly in p->value. */;
else
delete p->value;
/* 2 is a magic value for destructors; see build_delete(). */
p->cleanup (p->value, 2);
delete p;
if (! __is_pointer (p->type))
__eh_free (p->value);
__eh_free (p);
}
extern "C" void
__uncatch_exception (void)
{
cp_eh_info *p = __cp_exception_info ();
if (p)
p->caught = false;
/* otherwise __throw will call terminate(); don't crash here. */
if (p == 0)
terminate ();
p->caught = false;
}
/* As per [except.unexpected]:

View File

@ -5844,14 +5844,6 @@ build_modify_expr (lhs, modifycode, rhs)
{
if (! IS_AGGR_TYPE (lhstype))
/* Do the default thing */;
else if (! TYPE_HAS_CONSTRUCTOR (lhstype))
{
cp_error ("`%T' has no constructors", lhstype);
return error_mark_node;
}
else if (TYPE_HAS_TRIVIAL_INIT_REF (lhstype)
&& TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
/* Do the default thing */;
else
{
result = build_method_call (lhs, ctor_identifier,
@ -5867,19 +5859,6 @@ build_modify_expr (lhs, modifycode, rhs)
/* `operator=' is not an inheritable operator. */
if (! IS_AGGR_TYPE (lhstype))
/* Do the default thing */;
else if (! TYPE_HAS_ASSIGNMENT (lhstype))
{
cp_error ("`%T' does not define operator=", lhstype);
return error_mark_node;
}
else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (lhstype)
&& TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
{
build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
lhs, rhs, make_node (NOP_EXPR));
/* Do the default thing */;
}
else
{
result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,