diff options
-rw-r--r-- | gcc/cp/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/cp/except.c | 116 | ||||
-rw-r--r-- | gcc/cp/exception.cc | 46 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 21 |
4 files changed, 150 insertions, 46 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4f8795b491c..02f3a8762c1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 0c66074888f..36c64e12d65 100644 --- a/gcc/cp/except.c +++ b/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; + + /* 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. */ - /* 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); + 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))); diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc index 399d2c60dbc..0276ed7dad8 100644 --- a/gcc/cp/exception.cc +++ b/gcc/cp/exception.cc @@ -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]: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index e706e82d61c..99383555662 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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, |