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:
parent
b450b6999c
commit
f4a233434d
@ -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
|
||||
|
116
gcc/cp/except.c
116
gcc/cp/except.c
@ -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)));
|
||||
|
@ -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]:
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user