* exception.cc (__eh_alloc, __eh_free): New fns.
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 8 Jan 1998 00:29:08 +0000 (00:29 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 8 Jan 1998 00:29:08 +0000 (00:29 +0000)
(__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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@17309 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/except.c
gcc/cp/exception.cc
gcc/cp/typeck.c

index 4f8795b..02f3a87 100644 (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
index 0c66074..36c64e1 100644 (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;
+
+         /* 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)));
index 399d2c6..0276ed7 100644 (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]:
index e706e82..9938355 100644 (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,