summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/except.c116
-rw-r--r--gcc/cp/exception.cc46
-rw-r--r--gcc/cp/typeck.c21
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,