OSDN Git Service

1999-11-25 Mark Mitchell <mark@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / init.c
index e96f7e5..1361b96 100644 (file)
@@ -1,5 +1,5 @@
 /* Handle initialization things in C++.
-   Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-98, 1999 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -31,42 +31,23 @@ Boston, MA 02111-1307, USA.  */
 #include "except.h"
 #include "expr.h"
 #include "toplev.h"
-
-extern void compiler_error ();
-
-/* In C++, structures with well-defined constructors are initialized by
-   those constructors, unasked.  CURRENT_BASE_INIT_LIST
-   holds a list of stmts for a BASE_INIT term in the grammar.
-   This list has one element for each base class which must be
-   initialized.  The list elements are [basename, init], with
-   type basetype.  This allows the possibly anachronistic form
-   (assuming d : a, b, c) "d (int a) : c(a+5), b (a-4), a (a+3)"
-   where each successive term can be handed down the constructor
-   line.  Perhaps this was not intended.  */
-tree current_base_init_list, current_member_init_list;
+#include "ggc.h"
 
 static void expand_aggr_vbase_init_1 PROTO((tree, tree, tree, tree));
-static void expand_aggr_vbase_init PROTO((tree, tree, tree, tree));
-static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int,
-                                     int));
-static void expand_default_init PROTO((tree, tree, tree, tree, int,
-                                      int));
-static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, tree,
-                                     int));
+static void construct_virtual_bases PROTO((tree, tree, tree, tree, tree));
+static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int));
+static void expand_default_init PROTO((tree, tree, tree, tree, int));
+static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, int));
 static void perform_member_init PROTO((tree, tree, tree, int));
 static void sort_base_init PROTO((tree, tree *, tree *));
 static tree build_builtin_delete_call PROTO((tree));
-static tree build_array_eh_cleanup PROTO((tree, tree, tree));
-static int member_init_ok_or_else PROTO((tree, tree, char *));
+static int member_init_ok_or_else PROTO((tree, tree, const char *));
 static void expand_virtual_init PROTO((tree, tree));
 static tree sort_member_init PROTO((tree));
-static tree build_partial_cleanup_for PROTO((tree));
 static tree initializing_context PROTO((tree));
-
-/* Cache the identifier nodes for the magic field of a new cookie.  */
-static tree nc_nelts_field_id;
-
-static tree minus_one;
+static tree build_java_class_ref PROTO((tree));
+static void expand_cleanup_for_base PROTO((tree, tree));
+static tree get_temp_regvar PROTO((tree, tree));
 
 /* Set up local variable for this file.  MUST BE CALLED AFTER
    INIT_DECL_PROCESSING.  */
@@ -77,16 +58,23 @@ void init_init_processing ()
 {
   tree fields[1];
 
-  minus_one = build_int_2 (-1, -1);
+  minus_one_node = build_int_2 (-1, -1);
 
   /* Define the structure that holds header information for
      arrays allocated via operator new.  */
   BI_header_type = make_lang_type (RECORD_TYPE);
-  nc_nelts_field_id = get_identifier ("nelts");
-  fields[0] = build_lang_field_decl (FIELD_DECL, nc_nelts_field_id, sizetype);
+  nelts_identifier = get_identifier ("nelts");
+  fields[0] = build_lang_decl (FIELD_DECL, nelts_identifier, sizetype);
+
+  /* Use the biggest alignment supported by the target to prevent operator
+     new from returning misaligned pointers. */
+  TYPE_ALIGN (BI_header_type) = BIGGEST_ALIGNMENT;
   finish_builtin_type (BI_header_type, "__new_cookie", fields,
-                      0, double_type_node);
+                      0, BI_header_type);
   BI_header_size = size_in_bytes (BI_header_type);
+
+  ggc_add_tree_root (&BI_header_type, 1);
+  ggc_add_tree_root (&BI_header_size, 1);
 }
 
 /* Subroutine of emit_base_init.  For BINFO, initialize all the
@@ -154,18 +142,24 @@ perform_member_init (member, name, init, explicit)
   tree decl;
   tree type = TREE_TYPE (member);
 
-  expand_start_target_temps ();
+  decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
 
-  if (TYPE_NEEDS_CONSTRUCTING (type)
-      || (init && TYPE_HAS_CONSTRUCTOR (type)))
+  /* Deal with this here, as we will get confused if we try to call the
+     assignment op for an anonymous union.  This can happen in a
+     synthesized copy constructor.  */
+  if (ANON_AGGR_TYPE_P (type))
+    {
+      init = build (INIT_EXPR, type, decl, TREE_VALUE (init));
+      finish_expr_stmt (init);
+    }
+  else if (TYPE_NEEDS_CONSTRUCTING (type)
+          || (init && TYPE_HAS_CONSTRUCTOR (type)))
     {
       /* Since `init' is already a TREE_LIST on the current_member_init_list,
         only build it into one if we aren't already a list.  */
       if (init != NULL_TREE && TREE_CODE (init) != TREE_LIST)
        init = build_expr_list (NULL_TREE, init);
 
-      decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
-
       if (explicit
          && TREE_CODE (type) == ARRAY_TYPE
          && init != NULL_TREE
@@ -173,11 +167,12 @@ perform_member_init (member, name, init, explicit)
          && TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE)
        {
          /* Initialization of one array from another.  */
-         expand_vec_init (TREE_OPERAND (decl, 1), decl,
-                          array_type_nelts (type), TREE_VALUE (init), 1);
+         finish_expr_stmt 
+           (build_vec_init (TREE_OPERAND (decl, 1), decl,
+                            array_type_nelts (type), TREE_VALUE (init), 1));
        }
       else
-       expand_aggr_init (decl, init, 0, 0);
+       finish_expr_stmt (build_aggr_init (decl, init, 0));
     }
   else
     {
@@ -187,13 +182,21 @@ perform_member_init (member, name, init, explicit)
            {
              /* default-initialization.  */
              if (AGGREGATE_TYPE_P (type))
-               init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
-             else if (TREE_CODE (type) == REFERENCE_TYPE)
                {
-                 cp_error ("default-initialization of `%#D', which has reference type",
-                           member);
-                 init = error_mark_node;
+                 /* This is a default initialization of an aggregate,
+                    but not one of non-POD class type.  We cleverly
+                    notice that the initialization rules in such a
+                    case are the same as for initialization with an
+                    empty brace-initialization list.  We don't want
+                    to call build_modify_expr as that will go looking
+                    for constructors and such.  */
+                 tree e = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+                 TREE_SIDE_EFFECTS (e) = 1;
+                 finish_expr_stmt (build (INIT_EXPR, type, decl, e));
                }
+             else if (TREE_CODE (type) == REFERENCE_TYPE)
+               cp_error ("default-initialization of `%#D', which has reference type",
+                         member);
              else
                init = integer_zero_node;
            }
@@ -214,36 +217,21 @@ perform_member_init (member, name, init, explicit)
            init = TREE_VALUE (init);
        }
 
-      /* We only build this with a null init if we got it from the
-        current_member_init_list.  */
-      if (init || explicit)
-       {
-         decl = build_component_ref (current_class_ref, name, NULL_TREE,
-                                     explicit);
-         expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
-       }
+      if (init)
+       finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
     }
 
-  expand_end_target_temps ();
-  free_temp_slots ();
-
   if (TYPE_NEEDS_DESTRUCTOR (type))
     {
       tree expr;
 
-      /* All cleanups must be on the function_obstack.  */
-      push_obstacks_nochange ();
-      resume_temporary_allocation ();
-
       expr = build_component_ref (current_class_ref, name, NULL_TREE,
                                  explicit);
       expr = build_delete (type, expr, integer_zero_node,
                           LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
 
       if (expr != error_mark_node)
-       add_partial_entry (expr);
-
-      pop_obstacks ();
+       finish_subobject (expr);
     }
 }
 
@@ -277,16 +265,13 @@ sort_member_init (t)
            continue;
          name = TREE_PURPOSE (x);
 
-#if 0
-         /* This happens in templates, since the IDENTIFIER is replaced
-             with the COMPONENT_REF in tsubst_expr.  */
-         field = (TREE_CODE (name) == COMPONENT_REF
-                  ? TREE_OPERAND (name, 1) : IDENTIFIER_CLASS_VALUE (name));
-#else
-         /* Let's find out when this happens.  */
-         my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 348);
-         field = IDENTIFIER_CLASS_VALUE (name);
-#endif
+         if (TREE_CODE (name) == IDENTIFIER_NODE)
+           field = IDENTIFIER_CLASS_VALUE (name);
+         else
+           {
+             my_friendly_assert (TREE_CODE (name) == FIELD_DECL, 348); 
+             field = name;
+           }
 
          /* If one member shadows another, get the outermost one.  */
          if (TREE_CODE (field) == TREE_LIST)
@@ -480,17 +465,6 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
   *vbase_ptr = vbases;
 }
 
-/* Perform partial cleanups for a base for exception handling.  */
-
-static tree
-build_partial_cleanup_for (binfo)
-     tree binfo;
-{
-  return build_scoped_method_call
-    (current_class_ref, binfo, dtor_identifier,
-     build_expr_list (NULL_TREE, integer_zero_node));
-}
-
 /* Perform whatever initializations have yet to be done on the base
    class of the class variable.  These actions are in the global
    variable CURRENT_BASE_INIT_LIST.  Such an action could be
@@ -509,12 +483,9 @@ build_partial_cleanup_for (binfo)
    Note that emit_base_init does *not* initialize virtual base
    classes.  That is done specially, elsewhere.  */
 
-extern tree base_init_expr, rtl_expr_chain;
-
-void
-emit_base_init (t, immediately)
+tree
+emit_base_init (t)
      tree t;
-     int immediately;
 {
   tree member;
   tree mem_init_list;
@@ -522,27 +493,8 @@ emit_base_init (t, immediately)
   tree t_binfo = TYPE_BINFO (t);
   tree binfos = BINFO_BASETYPES (t_binfo);
   int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  tree expr = NULL_TREE;
-
-  if (! immediately)
-    {
-      int momentary;
-      do_pending_stack_adjust ();
-      /* Make the RTL_EXPR node temporary, not momentary,
-        so that rtl_expr_chain doesn't become garbage.  */
-      momentary = suspend_momentary ();
-      expr = make_node (RTL_EXPR);
-      resume_momentary (momentary);
-      start_sequence_for_rtl_expr (expr); 
-    }
-
-  if (write_symbols == NO_DEBUG)
-    /* As a matter of principle, `start_sequence' should do this.  */
-    emit_note (0, -1);
-  else
-    /* Always emit a line number note so we can step into constructors.  */
-    emit_line_note_force (DECL_SOURCE_FILE (current_function_decl),
-                         DECL_SOURCE_LINE (current_function_decl));
+  tree stmt_expr;
+  tree compound_stmt;
 
   mem_init_list = sort_member_init (t);
   current_member_init_list = NULL_TREE;
@@ -550,14 +502,15 @@ emit_base_init (t, immediately)
   sort_base_init (t, &rbase_init_list, &vbase_init_list);
   current_base_init_list = NULL_TREE;
 
+  begin_init_stmts (&stmt_expr, &compound_stmt);
+  
+  /* First, initialize the virtual base classes, if we are
+     constructing the most-derived object.  */
   if (TYPE_USES_VIRTUAL_BASECLASSES (t))
     {
       tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
-
-      expand_start_cond (first_arg, 0);
-      expand_aggr_vbase_init (t_binfo, current_class_ref, current_class_ptr,
-                             vbase_init_list);
-      expand_end_cond ();
+      construct_virtual_bases (t, current_class_ref, current_class_ptr,
+                              vbase_init_list, first_arg);
     }
 
   /* Now, perform initialization of non-virtual base classes.  */
@@ -584,29 +537,13 @@ emit_base_init (t, immediately)
 
       if (init != void_list_node)
        {
-         expand_start_target_temps ();
-
          member = convert_pointer_to_real (base_binfo, current_class_ptr);
          expand_aggr_init_1 (base_binfo, NULL_TREE,
                              build_indirect_ref (member, NULL_PTR), init,
-                             BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_NORMAL);
-
-         expand_end_target_temps ();
-         free_temp_slots ();
-       }
-
-      if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
-       {
-         tree expr;
-
-         /* All cleanups must be on the function_obstack.  */
-         push_obstacks_nochange ();
-         resume_temporary_allocation ();
-         expr = build_partial_cleanup_for (base_binfo);
-         pop_obstacks ();
-         add_partial_entry (expr);
+                             LOOKUP_NORMAL);
        }
 
+      expand_cleanup_for_base (base_binfo, NULL_TREE);
       rbase_init_list = TREE_CHAIN (rbase_init_list);
     }
 
@@ -637,15 +574,8 @@ emit_base_init (t, immediately)
          init = TREE_VALUE (mem_init_list);
          from_init_list = 1;
 
-#if 0
-         if (TREE_CODE (name) == COMPONENT_REF)
-           name = DECL_NAME (TREE_OPERAND (name, 1));
-#else
-         /* Also see if it's ever a COMPONENT_REF here.  If it is, we
-            need to do `expand_assignment (name, init, 0, 0);' and
-            a continue.  */
-         my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 349);
-#endif
+         my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE
+                             || TREE_CODE (name) == FIELD_DECL, 349);
        }
       else
        {
@@ -674,9 +604,11 @@ emit_base_init (t, immediately)
        {
          name = TREE_PURPOSE (mem_init_list);
          init = TREE_VALUE (mem_init_list);
-         /* XXX: this may need the COMPONENT_REF operand 0 check if
-            it turns out we actually get them.  */
-         field = IDENTIFIER_CLASS_VALUE (name);
+
+         if (TREE_CODE (name) == IDENTIFIER_NODE)
+           field = IDENTIFIER_CLASS_VALUE (name);
+         else
+           field = name;
 
          /* If one member shadows another, get the outermost one.  */
          if (TREE_CODE (field) == TREE_LIST)
@@ -686,43 +618,19 @@ emit_base_init (t, immediately)
                cp_error ("field `%D' not in immediate context", field);
            }
 
-#if 0
-         /* It turns out if you have an anonymous union in the
-            class, a member from it can end up not being on the
-            list of fields (rather, the type is), and therefore
-            won't be seen by the for loop above.  */
-
-         /* The code in this for loop is derived from a general loop
-            which had this check in it.  Theoretically, we've hit
-            every initialization for the list of members in T, so
-            we shouldn't have anything but these left in this list.  */
-         my_friendly_assert (DECL_FIELD_CONTEXT (field) != t, 351);
-#endif
-
          perform_member_init (field, name, init, 1);
        }
       mem_init_list = TREE_CHAIN (mem_init_list);
     }
 
-  if (! immediately)
-    {
-      do_pending_stack_adjust ();
-      my_friendly_assert (base_init_expr == 0, 207);
-      base_init_expr = expr;
-      TREE_TYPE (expr) = void_type_node;
-      RTL_EXPR_RTL (expr) = const0_rtx;
-      RTL_EXPR_SEQUENCE (expr) = get_insns ();
-      rtl_expr_chain = tree_cons (NULL_TREE, expr, rtl_expr_chain);
-      end_sequence ();
-      TREE_SIDE_EFFECTS (expr) = 1;
-    }
-
   /* All the implicit try blocks we built up will be zapped
      when we come to a real binding contour boundary.  */
+  return finish_init_stmts (stmt_expr, compound_stmt);
 }
 
 /* Check that all fields are properly initialized after
-   an assignment to `this'.  */
+   an assignment to `this'.  Called only when such an assignment
+   is actually noted.  */
 
 void
 check_base_init (t)
@@ -752,9 +660,9 @@ expand_virtual_init (binfo, decl)
   /* This code is crusty.  Should be simple, like:
      vtbl = BINFO_VTABLE (binfo);
      */
-  vtype = DECL_CONTEXT (CLASSTYPE_VFIELD (type));
+  vtype = DECL_CONTEXT (TYPE_VFIELD (type));
   vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
-  vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)), binfo));
+  vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo));
   assemble_external (vtbl);
   TREE_USED (vtbl) = 1;
   vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
@@ -765,7 +673,35 @@ expand_virtual_init (binfo, decl)
 
   /* Have to convert VTBL since array sizes may be different.  */
   vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
-  expand_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
+  finish_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
+}
+
+/* If an exception is thrown in a constructor, those base classes already
+   constructed must be destroyed.  This function creates the cleanup
+   for BINFO, which has just been constructed.  If FLAG is non-NULL,
+   it is a DECL which is non-zero when this base needs to be
+   destroyed.  */
+
+static void
+expand_cleanup_for_base (binfo, flag)
+     tree binfo;
+     tree flag;
+{
+  tree expr;
+
+  if (!TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
+    return;
+
+  /* Call the destructor.  */
+  expr = (build_scoped_method_call
+         (current_class_ref, binfo, dtor_identifier,
+          build_expr_list (NULL_TREE, integer_zero_node)));
+  if (flag)
+    expr = fold (build (COND_EXPR, void_type_node,
+                       truthvalue_conversion (flag),
+                       expr, integer_zero_node));
+
+  finish_subobject (expr);
 }
 
 /* Subroutine of `expand_aggr_vbase_init'.
@@ -779,47 +715,75 @@ expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
   tree init = purpose_member (binfo, init_list);
   tree ref = build_indirect_ref (addr, NULL_PTR);
 
-  expand_start_target_temps ();
-
   if (init)
     init = TREE_VALUE (init);
   /* Call constructors, but don't set up vtables.  */
-  expand_aggr_init_1 (binfo, exp, ref, init, 0, LOOKUP_COMPLAIN);
-
-  expand_end_target_temps ();
-  free_temp_slots ();
+  expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
 }
 
-/* Initialize this object's virtual base class pointers.  This must be
-   done only at the top-level of the object being constructed.
-
-   INIT_LIST is list of initialization for constructor to perform.  */
+/* Construct the virtual base-classes of THIS_REF (whose address is
+   THIS_PTR).  The object has the indicated TYPE.  The construction
+   actually takes place only if FLAG is non-zero.  INIT_LIST is list
+   of initialization for constructor to perform.  */
 
 static void
-expand_aggr_vbase_init (binfo, exp, addr, init_list)
-     tree binfo;
-     tree exp;
-     tree addr;
+construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
+     tree type;
+     tree this_ref;
+     tree this_ptr;
      tree init_list;
+     tree flag;
 {
-  tree type = BINFO_TYPE (binfo);
-
-  if (TYPE_USES_VIRTUAL_BASECLASSES (type))
-    {
-      tree result = init_vbase_pointers (type, addr);
-      tree vbases;
-
-      if (result)
-       expand_expr_stmt (build_compound_expr (result));
-
-      for (vbases = CLASSTYPE_VBASECLASSES (type); vbases;
-          vbases = TREE_CHAIN (vbases))
-       {
-         tree tmp = purpose_member (vbases, result);
-         expand_aggr_vbase_init_1 (vbases, exp,
-                                   TREE_OPERAND (TREE_VALUE (tmp), 0),
-                                   init_list);
-       }
+  tree vbases;
+  tree result;
+  tree if_stmt;
+
+  /* If there are no virtual baseclasses, we shouldn't even be here.  */
+  my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621);
+
+  /* First set the pointers in our object that tell us where to find
+     our virtual baseclasses.  */
+  if_stmt = begin_if_stmt ();
+  finish_if_stmt_cond (flag, if_stmt);
+  result = init_vbase_pointers (type, this_ptr);
+  if (result)
+    finish_expr_stmt (build_compound_expr (result));
+  finish_then_clause (if_stmt);
+  finish_if_stmt ();
+
+  /* Now, run through the baseclasses, initializing each.  */ 
+  for (vbases = CLASSTYPE_VBASECLASSES (type); vbases;
+       vbases = TREE_CHAIN (vbases))
+    {
+      tree tmp = purpose_member (vbases, result);
+      tree inner_if_stmt;
+      tree compound_stmt;
+
+      /* If there are virtual base classes with destructors, we need to
+        emit cleanups to destroy them if an exception is thrown during
+        the construction process.  These exception regions (i.e., the
+        period during which the cleanups must occur) begin from the time
+        the construction is complete to the end of the function.  If we
+        create a conditional block in which to initialize the
+        base-classes, then the cleanup region for the virtual base begins
+        inside a block, and ends outside of that block.  This situation
+        confuses the sjlj exception-handling code.  Therefore, we do not
+        create a single conditional block, but one for each
+        initialization.  (That way the cleanup regions always begin
+        in the outer block.)  We trust the back-end to figure out
+        that the FLAG will not change across initializations, and
+        avoid doing multiple tests.  */
+      inner_if_stmt = begin_if_stmt ();
+      finish_if_stmt_cond (flag, inner_if_stmt);
+      compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
+      expand_aggr_vbase_init_1 (vbases, this_ref,
+                               TREE_OPERAND (TREE_VALUE (tmp), 0),
+                               init_list);
+      finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+      finish_then_clause (inner_if_stmt);
+      finish_if_stmt ();
+      
+      expand_cleanup_for_base (vbases, flag);
     }
 }
 
@@ -833,7 +797,7 @@ initializing_context (field)
 
   /* Anonymous union members can be initialized in the first enclosing
      non-anonymous union context.  */
-  while (t && ANON_UNION_TYPE_P (t))
+  while (t && ANON_AGGR_TYPE_P (t))
     t = TYPE_CONTEXT (t);
   return t;
 }
@@ -849,7 +813,7 @@ static int
 member_init_ok_or_else (field, type, member_name)
      tree field;
      tree type;
-     char *member_name;
+     const char *member_name;
 {
   if (field == error_mark_node)
     return 0;
@@ -899,7 +863,7 @@ expand_member_init (exp, name, init)
 
   if (name && TREE_CODE (name) == TYPE_DECL)
     {
-      basetype = TREE_TYPE (name);
+      basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
       name = DECL_NAME (name);
     }
 
@@ -998,6 +962,43 @@ expand_member_init (exp, name, init)
     }
 }
 
+/* We are about to generate some complex initialization code.
+   Conceptually, it is all a single expression.  However, we may want
+   to include conditionals, loops, and other such statement-level
+   constructs.  Therefore, we build the initialization code inside a
+   statement-expression.  This function starts such an expression.
+   STMT_EXPR_P and COMPOUND_STMT_P are filled in by this function;
+   pass them back to finish_init_stmts when the expression is
+   complete.  */
+
+void
+begin_init_stmts (stmt_expr_p, compound_stmt_p)
+     tree *stmt_expr_p;
+     tree *compound_stmt_p;
+{
+  *stmt_expr_p = begin_stmt_expr ();
+  *compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
+}
+
+/* Finish out the statement-expression begun by the previous call to
+   begin_init_stmts.  Returns the statement-expression itself.  */
+
+tree
+finish_init_stmts (stmt_expr, compound_stmt)
+     tree stmt_expr;
+     tree compound_stmt;
+{
+  finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+  stmt_expr = finish_stmt_expr (stmt_expr);
+
+  /* To avoid spurious warnings about unused values, we set 
+     TREE_USED.  */
+  if (stmt_expr)
+    TREE_USED (stmt_expr) = 1;
+
+  return stmt_expr;
+}
+
 /* This is like `expand_member_init', only it stores one aggregate
    value into another.
 
@@ -1036,18 +1037,20 @@ expand_member_init (exp, name, init)
    A constructor or a conversion operator may have to be used to
    perform the initialization, but not both, as it would be ambiguous.  */
 
-void
-expand_aggr_init (exp, init, alias_this, flags)
+tree
+build_aggr_init (exp, init, flags)
      tree exp, init;
-     int alias_this;
      int flags;
 {
+  tree stmt_expr;
+  tree compound_stmt;
+  int destroy_temps;
   tree type = TREE_TYPE (exp);
   int was_const = TREE_READONLY (exp);
   int was_volatile = TREE_THIS_VOLATILE (exp);
 
   if (init == error_mark_node)
-    return;
+    return error_mark_node;
 
   TREE_READONLY (exp) = 0;
   TREE_THIS_VOLATILE (exp) = 0;
@@ -1060,7 +1063,7 @@ expand_aggr_init (exp, init, alias_this, flags)
       /* Must arrange to initialize each element of EXP
         from elements of INIT.  */
       tree itype = init ? TREE_TYPE (init) : NULL_TREE;
-      if (TYPE_READONLY (TREE_TYPE (type)) || TYPE_VOLATILE (TREE_TYPE (type)))
+      if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED)
        {
          TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
          if (init)
@@ -1081,45 +1084,43 @@ expand_aggr_init (exp, init, alias_this, flags)
             }
          */
          error ("bad array initializer");
-         return;
+         return error_mark_node;
        }
-      expand_vec_init (exp, exp, array_type_nelts (type), init,
-                      init && comptypes (TREE_TYPE (init), TREE_TYPE (exp), 1));
+      stmt_expr = build_vec_init (exp, exp, array_type_nelts (type), init,
+                                 init && same_type_p (TREE_TYPE (init),
+                                                      TREE_TYPE (exp)));
       TREE_READONLY (exp) = was_const;
       TREE_THIS_VOLATILE (exp) = was_volatile;
       TREE_TYPE (exp) = type;
       if (init)
        TREE_TYPE (init) = itype;
-      return;
+      return stmt_expr;
     }
 
   if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
     /* just know that we've seen something for this node */
     TREE_USED (exp) = 1;
 
-#if 0
-  /* If initializing from a GNU C CONSTRUCTOR, consider the elts in the
-     constructor as parameters to an implicit GNU C++ constructor.  */
-  if (init && TREE_CODE (init) == CONSTRUCTOR
-      && TYPE_HAS_CONSTRUCTOR (type)
-      && TREE_TYPE (init) == type)
-    init = CONSTRUCTOR_ELTS (init);
-#endif
-
   TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
+  begin_init_stmts (&stmt_expr, &compound_stmt);
+  destroy_temps = stmts_are_full_exprs_p;
+  stmts_are_full_exprs_p = 0;
   expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
-                     init, alias_this, LOOKUP_NORMAL|flags);
+                     init, LOOKUP_NORMAL|flags);
+  stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
+  stmts_are_full_exprs_p = destroy_temps;
   TREE_TYPE (exp) = type;
   TREE_READONLY (exp) = was_const;
   TREE_THIS_VOLATILE (exp) = was_volatile;
+
+  return stmt_expr;
 }
 
 static void
-expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
+expand_default_init (binfo, true_exp, exp, init, flags)
      tree binfo;
      tree true_exp, exp;
      tree init;
-     int alias_this;
      int flags;
 {
   tree type = TREE_TYPE (exp);
@@ -1140,14 +1141,17 @@ expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
       if (true_exp != exp)
        abort ();
 
-      /* We special-case TARGET_EXPRs here to avoid an error about
-        private copy constructors for temporaries bound to reference vars.
-        If the TARGET_EXPR represents a call to a function that has
-        permission to create such objects, a reference can bind directly
-        to the return value.  An object variable must be initialized
-        via the copy constructor, even if the call is elided.  */
-      if (! (TREE_CODE (exp) == VAR_DECL && DECL_ARTIFICIAL (exp)
-            && TREE_CODE (init) == TARGET_EXPR && TREE_TYPE (init) == type))
+      if (flags & DIRECT_BIND)
+       /* Do nothing.  We hit this in two cases:  Reference initialization,
+          where we aren't initializing a real variable, so we don't want
+          to run a new constructor; and catching an exception, where we
+          have already built up the constructor call so we could wrap it
+          in an exception region.  */;
+      else if (TREE_CODE (init) == CONSTRUCTOR)
+       /* A brace-enclosed initializer has whatever type is
+          required.  There's no need to convert it.  */
+       ;
+      else
        init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
 
       if (TREE_CODE (init) == TRY_CATCH_EXPR)
@@ -1160,7 +1164,7 @@ expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
       else
        init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
       TREE_SIDE_EFFECTS (init) = 1;
-      expand_expr_stmt (init);
+      finish_expr_stmt (init);
       return;
     }
 
@@ -1177,16 +1181,16 @@ expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
   if (TYPE_USES_VIRTUAL_BASECLASSES (type))
     {
       if (true_exp == exp)
-       parms = expr_tree_cons (NULL_TREE, integer_one_node, parms);
+       parms = tree_cons (NULL_TREE, integer_one_node, parms);
       else
-       parms = expr_tree_cons (NULL_TREE, integer_zero_node, parms);
+       parms = tree_cons (NULL_TREE, integer_zero_node, parms);
       flags |= LOOKUP_HAS_IN_CHARGE;
     }
 
   rval = build_method_call (exp, ctor_identifier,
                            parms, binfo, flags);
   if (TREE_SIDE_EFFECTS (rval))
-    expand_expr_stmt (rval);
+    finish_expr_stmt (rval);
 }
 
 /* This function is responsible for initializing EXP with INIT
@@ -1212,11 +1216,10 @@ expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
    its description.  */
 
 static void
-expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
+expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
      tree binfo;
      tree true_exp, exp;
      tree init;
-     int alias_this;
      int flags;
 {
   tree type = TREE_TYPE (exp);
@@ -1233,21 +1236,22 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
       && TREE_CODE (init) == CONSTRUCTOR
       && TREE_HAS_CONSTRUCTOR (init))
     {
-      tree t = store_init_value (exp, init);
-      if (!t)
+      /* If store_init_value returns NULL_TREE, the INIT has been
+        record in the DECL_INITIAL for EXP.  That means there's
+        nothing more we have to do.  */
+      if (!store_init_value (exp, init))
        {
-         expand_decl_init (exp);
-         return;
+         if (!building_stmt_tree ())
+           expand_decl_init (exp);
        }
-      t = build (INIT_EXPR, type, exp, init);
-      TREE_SIDE_EFFECTS (t) = 1;
-      expand_expr_stmt (t);
+      else
+       finish_expr_stmt (build (INIT_EXPR, type, exp, init));
       return;
     }
 
   /* We know that expand_default_init can handle everything we want
      at this point.  */
-  expand_default_init (binfo, true_exp, exp, init, alias_this, flags);
+  expand_default_init (binfo, true_exp, exp, init, flags);
 }
 
 /* Report an error if NAME is not the name of a user-defined,
@@ -1364,7 +1368,6 @@ build_member_call (type, name, parmlist)
   tree t;
   tree method_name;
   int dtor = 0;
-  int dont_use_this = 0;
   tree basetype_path, decl;
 
   if (TREE_CODE (name) == TEMPLATE_ID_EXPR
@@ -1372,7 +1375,18 @@ build_member_call (type, name, parmlist)
     {
       /* 'name' already refers to the decls from the namespace, since we
         hit do_identifier for template_ids.  */
-      my_friendly_assert (is_overloaded_fn (TREE_OPERAND (name, 0)), 980519);
+      method_name = TREE_OPERAND (name, 0);
+      /* FIXME: Since we don't do independent names right yet, the
+        name might also be a LOOKUP_EXPR. Once we resolve this to a
+        real decl earlier, this can go. This may happen during
+        tsubst'ing.  */
+      if (TREE_CODE (method_name) == LOOKUP_EXPR)
+       {
+         method_name = lookup_namespace_name 
+           (type, TREE_OPERAND (method_name, 0));
+         TREE_OPERAND (name, 0) = method_name;
+       }
+      my_friendly_assert (is_overloaded_fn (method_name), 980519);
       return build_x_function_call (name, parmlist, current_class_ref);
     }
 
@@ -1383,10 +1397,17 @@ build_member_call (type, name, parmlist)
     return build_x_function_call (lookup_namespace_name (type, name),
                                  parmlist, current_class_ref);
 
-  if (TREE_CODE (name) != TEMPLATE_ID_EXPR)
-    method_name = name;
+  if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+    {
+      method_name = TREE_OPERAND (name, 0);
+      if (TREE_CODE (method_name) == COMPONENT_REF)
+       method_name = TREE_OPERAND (method_name, 1);
+      if (is_overloaded_fn (method_name))
+       method_name = DECL_NAME (OVL_CURRENT (method_name));
+      TREE_OPERAND (name, 0) = method_name;
+    }
   else
-    method_name = TREE_OPERAND (name, 0);
+    method_name = name;
 
   if (TREE_CODE (method_name) == BIT_NOT_EXPR)
     {
@@ -1420,42 +1441,29 @@ build_member_call (type, name, parmlist)
       return error_mark_node;
     }
 
-  /* No object?  Then just fake one up, and let build_method_call
-     figure out what to do.  */
-  if (current_class_type == 0
-      || get_base_distance (type, current_class_type, 0, &basetype_path) == -1)
-    dont_use_this = 1;
+  decl = maybe_dummy_object (type, &basetype_path);
 
-  if (dont_use_this)
-    {
-      basetype_path = TYPE_BINFO (type);
-      decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
-    }
-  else if (current_class_ptr == 0)
-    {
-      dont_use_this = 1;
-      decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
-    }
-  else
+  /* Convert 'this' to the specified type to disambiguate conversion
+     to the function's context.  Apparently Standard C++ says that we
+     shouldn't do this.  */
+  if (decl == current_class_ref
+      && ! pedantic
+      && ACCESSIBLY_UNIQUELY_DERIVED_P (type, current_class_type))
     {
       tree olddecl = current_class_ptr;
       tree oldtype = TREE_TYPE (TREE_TYPE (olddecl));
       if (oldtype != type)
        {
-         tree newtype = build_type_variant (type, TYPE_READONLY (oldtype),
-                                            TYPE_VOLATILE (oldtype));
+         tree newtype = build_qualified_type (type, TYPE_QUALS (oldtype));
          decl = convert_force (build_pointer_type (newtype), olddecl, 0);
+         decl = build_indirect_ref (decl, NULL_PTR);
        }
-      else
-       decl = olddecl;
     }
 
-  decl = build_indirect_ref (decl, NULL_PTR);
-
   if (method_name == constructor_name (type)
       || method_name == constructor_name_full (type))
     return build_functional_cast (type, parmlist);
-  if ((t = lookup_fnfields (basetype_path, method_name, 0)))
+  if (lookup_fnfields (basetype_path, method_name, 0))
     return build_method_call (decl, 
                              TREE_CODE (name) == TEMPLATE_ID_EXPR
                              ? name : method_name,
@@ -1468,7 +1476,7 @@ build_member_call (type, name, parmlist)
        return error_mark_node;
       if (TREE_CODE (t) == FIELD_DECL)
        {
-         if (dont_use_this)
+         if (is_dummy_object (decl))
            {
              cp_error ("invalid use of non-static field `%D'", t);
              return error_mark_node;
@@ -1508,7 +1516,8 @@ tree
 build_offset_ref (type, name)
      tree type, name;
 {
-  tree decl, fnfields, fields, t = error_mark_node;
+  tree decl, t = error_mark_node;
+  tree member;
   tree basebinfo = NULL_TREE;
   tree orig_name = name;
 
@@ -1566,55 +1575,27 @@ build_offset_ref (type, name)
     name = ctor_identifier;
 #endif
 
-  if (TYPE_SIZE (complete_type (type)) == 0)
+  if (TYPE_SIZE (complete_type (type)) == 0
+      && !TYPE_BEING_DEFINED (type))
     {
-      if (type == current_class_type)
-       t = IDENTIFIER_CLASS_VALUE (name);
-      else
-       t = NULL_TREE;
-      if (t == 0)
-       {
-         cp_error ("incomplete type `%T' does not have member `%D'", type,
-                     name);
-         return error_mark_node;
-       }
-      if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == VAR_DECL
-         || TREE_CODE (t) == CONST_DECL)
-       {
-         mark_used (t);
-         return t;
-       }
-      if (TREE_CODE (t) == FIELD_DECL)
-       sorry ("use of member in incomplete aggregate type");
-      else if (TREE_CODE (t) == FUNCTION_DECL)
-       sorry ("use of member function in incomplete aggregate type");
-      else
-       my_friendly_abort (52);
+      cp_error ("incomplete type `%T' does not have member `%D'", type,
+               name);
       return error_mark_node;
     }
 
-  if (current_class_type == 0
-      || get_base_distance (type, current_class_type, 0, &basebinfo) == -1)
-    {
-      basebinfo = TYPE_BINFO (type);
-      decl = build1 (NOP_EXPR, type, error_mark_node);
-    }
-  else if (current_class_ptr == 0)
-    decl = build1 (NOP_EXPR, type, error_mark_node);
-  else
-    decl = current_class_ref;
+  decl = maybe_dummy_object (type, &basebinfo);
 
-  fnfields = lookup_fnfields (basebinfo, name, 1);
-  fields = lookup_field (basebinfo, name, 0, 0);
+  member = lookup_member (basebinfo, name, 1, 0);
 
-  if (fields == error_mark_node || fnfields == error_mark_node)
+  if (member == error_mark_node)
     return error_mark_node;
 
   /* A lot of this logic is now handled in lookup_field and
      lookup_fnfield.  */
-  if (fnfields)
+  if (member && BASELINK_P (member))
     {
       /* Go from the TREE_BASELINK to the member function info.  */
+      tree fnfields = member;
       t = TREE_VALUE (fnfields);
 
       if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
@@ -1632,7 +1613,7 @@ build_offset_ref (type, name)
            t = ovl_cons (t, NULL_TREE);
          
          return build (OFFSET_REF, 
-                       build_offset_type (type, unknown_type_node),
+                       unknown_type_node,
                        decl,
                        build (TEMPLATE_ID_EXPR, 
                               TREE_TYPE (t),
@@ -1642,54 +1623,24 @@ build_offset_ref (type, name)
 
       if (!really_overloaded_fn (t))
        {
-         tree access;
-
          /* Get rid of a potential OVERLOAD around it */
          t = OVL_CURRENT (t);
 
          /* unique functions are handled easily.  */
          basebinfo = TREE_PURPOSE (fnfields);
-         access = compute_access (basebinfo, t);
-         if (access == access_protected_node)
-           {
-             cp_error_at ("member function `%#D' is protected", t);
-             error ("in this context");
-             return error_mark_node;
-           }
-         if (access == access_private_node)
-           {
-             cp_error_at ("member function `%#D' is private", t);
-             error ("in this context");
-             return error_mark_node;
-           }
+         if (!enforce_access (basebinfo, t))
+           return error_mark_node;
          mark_used (t);
+         if (DECL_STATIC_FUNCTION_P (t))
+           return t;
          return build (OFFSET_REF, TREE_TYPE (t), decl, t);
        }
 
-      /* FNFIELDS is most likely allocated on the search_obstack,
-        which will go away after this class scope.  If we need
-        to save this value for later (i.e. for use as an initializer
-        for a static variable), then do so here.
-
-        ??? The smart thing to do for the case of saving initializers
-        is to resolve them before we're done with this scope.  */
-      if (!TREE_PERMANENT (fnfields)
-         && ! allocation_temporary_p ())
-       fnfields = copy_list (fnfields);
-
-      t = build_tree_list (error_mark_node, fnfields);
-      TREE_TYPE (t) = build_offset_type (type, unknown_type_node);
-      return t;
+      TREE_TYPE (fnfields) = unknown_type_node;
+      return build (OFFSET_REF, unknown_type_node, decl, fnfields);
     }
 
-  /* Now that we know we are looking for a field, see if we
-     have access to that field.  Lookup_field will give us the
-     error message.  */
-
-  t = lookup_field (basebinfo, name, 1, 0);
-
-  if (t == error_mark_node)
-    return error_mark_node;
+  t = member;
 
   if (t == NULL_TREE)
     {
@@ -1710,7 +1661,7 @@ build_offset_ref (type, name)
       return convert_from_reference (t);
     }
 
-  if (TREE_CODE (t) == FIELD_DECL && DECL_BIT_FIELD (t))
+  if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t))
     {
       cp_error ("illegal pointer to bit field `%D'", t);
       return error_mark_node;
@@ -1739,12 +1690,6 @@ resolve_offset_ref (exp)
   tree member;
   tree basetype, addr;
 
-  if (TREE_CODE (exp) == TREE_LIST)
-    {
-      cp_pedwarn ("assuming & on overloaded member function");
-      return build_unary_op (ADDR_EXPR, exp, 0);
-    }
-
   if (TREE_CODE (exp) == OFFSET_REF)
     {
       member = TREE_OPERAND (exp, 1);
@@ -1763,10 +1708,24 @@ resolve_offset_ref (exp)
       base = current_class_ref;
     }
 
+  if (BASELINK_P (member))
+    {
+      if (! flag_ms_extensions)
+       cp_pedwarn ("assuming & on overloaded member function");
+      return build_unary_op (ADDR_EXPR, exp, 0);
+    }
+
+  if (TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE)
+    {
+      if (! flag_ms_extensions)
+       cp_pedwarn ("assuming & on `%E'", member);
+      return build_unary_op (ADDR_EXPR, exp, 0);
+    }
+
   if ((TREE_CODE (member) == VAR_DECL
-       && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member)))
-      || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE
-      || TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE)
+       && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member))
+       && ! TYPE_PTRMEM_P (TREE_TYPE (member)))
+      || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE)
     {
       /* These were static members.  */
       if (mark_addressable (member) == 0)
@@ -1794,11 +1753,10 @@ resolve_offset_ref (exp)
 
   /* The first case is really just a reference to a member of `this'.  */
   if (TREE_CODE (member) == FIELD_DECL
-      && (base == current_class_ref
-         || (TREE_CODE (base) == NOP_EXPR
-             && TREE_OPERAND (base, 0) == error_mark_node)))
+      && (base == current_class_ref || is_dummy_object (base)))
     {
-      tree basetype_path, access;
+      tree basetype_path;
+      tree expr;
 
       if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
        basetype = TYPE_OFFSET_BASETYPE (type);
@@ -1814,40 +1772,28 @@ resolve_offset_ref (exp)
        }
       /* Kludge: we need to use basetype_path now, because
         convert_pointer_to will bash it.  */
-      access = compute_access (basetype_path, member);
+      enforce_access (basetype_path, member);
       addr = convert_pointer_to (basetype, base);
-      if (access == access_public_node)
-       return build (COMPONENT_REF, TREE_TYPE (member),
-                     build_indirect_ref (addr, NULL_PTR), member);
-      if (access == access_protected_node)
-       {
-         cp_error_at ("member `%D' is protected", member);
-         error ("in this context");
-         return error_mark_node;
-       }
-      if (access == access_private_node)
-       {
-         cp_error_at ("member `%D' is private", member);
-         error ("in this context");
-         return error_mark_node;
-       }
-      my_friendly_abort (55);
+
+      /* Even in the case of illegal access, we form the
+        COMPONENT_REF; that will allow better error recovery than
+        just feeding back error_mark_node.  */
+      expr = build (COMPONENT_REF, TREE_TYPE (member),
+                   build_indirect_ref (addr, NULL_PTR), member);
+      return convert_from_reference (expr);
     }
 
   /* Ensure that we have an object.  */
-  if (TREE_CODE (base) == NOP_EXPR
-      && TREE_OPERAND (base, 0) == error_mark_node)
+  if (is_dummy_object (base))
     addr = error_mark_node;
   else
-    {
-      /* If this is a reference to a member function, then return the
-        address of the member function (which may involve going
-        through the object's vtable), otherwise, return an expression
-        for the dereferenced pointer-to-member construct.  */
-      addr = build_unary_op (ADDR_EXPR, base, 0);
-    }
+    /* If this is a reference to a member function, then return the
+       address of the member function (which may involve going
+       through the object's vtable), otherwise, return an expression
+       for the dereferenced pointer-to-member construct.  */
+    addr = build_unary_op (ADDR_EXPR, base, 0);
 
-  if (TREE_CODE (TREE_TYPE (member)) == OFFSET_TYPE)
+  if (TYPE_PTRMEM_P (TREE_TYPE (member)))
     {
       if (addr == error_mark_node)
        {
@@ -1855,17 +1801,15 @@ resolve_offset_ref (exp)
          return error_mark_node;
        }
 
-      basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (member));
+      basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
       addr = convert_pointer_to (basetype, addr);
-      member = cp_convert (ptrdiff_type_node,
-                          build_unary_op (ADDR_EXPR, member, 0));
+      member = cp_convert (ptrdiff_type_node, member);
       
       /* Pointer to data members are offset by one, so that a null
         pointer with a real value of 0 is distinguishable from an
         offset of the first member of a structure.  */
       member = build_binary_op (MINUS_EXPR, member,
-                               cp_convert (ptrdiff_type_node, integer_one_node),
-                               0);
+                               cp_convert (ptrdiff_type_node, integer_one_node));
 
       return build1 (INDIRECT_REF, type,
                     build (PLUS_EXPR, build_pointer_type (type),
@@ -1887,28 +1831,14 @@ decl_constant_value (decl)
      tree decl;
 {
   if (! TREE_THIS_VOLATILE (decl)
-#if 0
-      /* These may be necessary for C, but they break C++.  */
-      ! TREE_PUBLIC (decl)
-      /* Don't change a variable array bound or initial value to a constant
-        in a place where a variable is invalid.  */
-      && ! pedantic
-#endif /* 0 */
-      && DECL_INITIAL (decl) != 0
+      && DECL_INITIAL (decl)
       && DECL_INITIAL (decl) != error_mark_node
       /* This is invalid if initial value is not constant.
         If it has either a function call, a memory reference,
         or a variable, then re-evaluating it could give different results.  */
       && TREE_CONSTANT (DECL_INITIAL (decl))
       /* Check for cases where this is sub-optimal, even though valid.  */
-      && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR
-#if 0
-      /* We must allow this to work outside of functions so that
-        static constants can be used for array sizes.  */
-      && current_function_decl != 0
-      && DECL_MODE (decl) != BLKmode
-#endif
-      )
+      && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR)
     return DECL_INITIAL (decl);
   return decl;
 }
@@ -1921,11 +1851,9 @@ static tree
 build_builtin_delete_call (addr)
      tree addr;
 {
-  tree BID = get_first_fn
-    (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) DELETE_EXPR]));
-
-  assemble_external (BID);
-  return build_call (BID, void_type_node, build_expr_list (NULL_TREE, addr));
+  mark_used (global_delete_fndecl);
+  return build_call (global_delete_fndecl, 
+                    void_type_node, build_expr_list (NULL_TREE, addr));
 }
 \f
 /* Generate a C++ "new" expression. DECL is either a TREE_LIST
@@ -1966,8 +1894,6 @@ build_new (placement, decl, init, use_global_new)
   tree nelts = NULL_TREE, t;
   int has_array = 0;
 
-  tree pending_sizes = NULL_TREE;
-
   if (decl == error_mark_node)
     return error_mark_node;
 
@@ -1975,14 +1901,10 @@ build_new (placement, decl, init, use_global_new)
     {
       tree absdcl = TREE_VALUE (decl);
       tree last_absdcl = NULL_TREE;
-      int old_immediate_size_expand = 0;
 
       if (current_function_decl
          && DECL_CONSTRUCTOR_P (current_function_decl))
-       {
-         old_immediate_size_expand = immediate_size_expand;
-         immediate_size_expand = 0;
-       }
+       my_friendly_assert (immediate_size_expand == 0, 19990926);
 
       nelts = integer_one_node;
 
@@ -2019,6 +1941,11 @@ build_new (placement, decl, init, use_global_new)
                }
              else
                {
+                 int flags = pedantic ? WANT_INT : (WANT_INT | WANT_ENUM);
+                 if (build_expr_type_conversion (flags, this_nelts, 0)
+                     == NULL_TREE)
+                   pedwarn ("size in array new must have integral type");
+
                  this_nelts = save_expr (cp_convert (sizetype, this_nelts));
                  absdcl = TREE_OPERAND (absdcl, 0);
                  if (this_nelts == integer_zero_node)
@@ -2027,7 +1954,7 @@ build_new (placement, decl, init, use_global_new)
                      nelts = integer_zero_node;
                    }
                  else
-                   nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
+                   nelts = build_binary_op (MULT_EXPR, nelts, this_nelts);
                }
            }
          else
@@ -2041,17 +1968,7 @@ build_new (placement, decl, init, use_global_new)
 
       type = groktypename (decl);
       if (! type || type == error_mark_node)
-       {
-         immediate_size_expand = old_immediate_size_expand;
-         return error_mark_node;
-       }
-
-      if (current_function_decl
-         && DECL_CONSTRUCTOR_P (current_function_decl))
-       {
-         pending_sizes = get_pending_sizes ();
-         immediate_size_expand = old_immediate_size_expand;
-       }
+       return error_mark_node;
     }
   else if (TREE_CODE (decl) == IDENTIFIER_NODE)
     {
@@ -2126,25 +2043,20 @@ build_new (placement, decl, init, use_global_new)
   rval = build (NEW_EXPR, build_pointer_type (type), placement, t, init);
   NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
   TREE_SIDE_EFFECTS (rval) = 1;
+  rval = build_new_1 (rval);
+  if (rval == error_mark_node)
+    return error_mark_node;
 
   /* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain.  */
   rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval);
   TREE_NO_UNUSED_WARNING (rval) = 1;
 
-  if (pending_sizes)
-    rval = build_compound_expr (chainon (pending_sizes,
-                                        build_expr_list (NULL_TREE, rval)));
-
   return rval;
 }
 
-/* If non-NULL, a POINTER_TYPE equivalent to (java::lang::Class*). */
-
-static tree jclass_node = NULL_TREE;
-
 /* Given a Java class, return a decl for the corresponding java.lang.Class. */
 
-tree
+static tree
 build_java_class_ref (type)
      tree type;
 {
@@ -2163,8 +2075,6 @@ build_java_class_ref (type)
   class_decl = IDENTIFIER_GLOBAL_VALUE (name);
   if (class_decl == NULL_TREE)
     {
-      push_obstacks_nochange ();
-      end_temporary_allocation ();
       class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node));
       TREE_STATIC (class_decl) = 1;
       DECL_EXTERNAL (class_decl) = 1;
@@ -2173,7 +2083,6 @@ build_java_class_ref (type)
       DECL_IGNORED_P (class_decl) = 1;
       pushdecl_top_level (class_decl);
       make_decl_rtl (class_decl, NULL_PTR, 1);
-      pop_obstacks ();
     }
   return class_decl;
 }
@@ -2208,7 +2117,7 @@ build_new_1 (exp)
     }
   true_type = type;
 
-  if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
+  if (CP_TYPE_QUALS (type))
     type = TYPE_MAIN_VARIANT (type);
 
   /* If our base type is an array, then make sure we know how many elements
@@ -2216,16 +2125,16 @@ build_new_1 (exp)
   while (TREE_CODE (true_type) == ARRAY_TYPE)
     {
       tree this_nelts = array_type_nelts_top (true_type);
-      nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
+      nelts = build_binary_op (MULT_EXPR, nelts, this_nelts);
       true_type = TREE_TYPE (true_type);
     }
 
-  if (!complete_type_or_else (true_type))
+  if (!complete_type_or_else (true_type, exp))
     return error_mark_node;
 
   if (has_array)
     size = fold (build_binary_op (MULT_EXPR, size_in_bytes (true_type),
-                                 nelts, 1));
+                                 nelts));
   else
     size = size_in_bytes (type);
 
@@ -2235,40 +2144,26 @@ build_new_1 (exp)
       return error_mark_node;
     }
 
-  if (TYPE_LANG_SPECIFIC (true_type)
-      && CLASSTYPE_ABSTRACT_VIRTUALS (true_type))
-    {
-      abstract_virtuals_error (NULL_TREE, true_type);
-      return error_mark_node;
-    }
+  if (abstract_virtuals_error (NULL_TREE, true_type))
+    return error_mark_node;
 
-  if (TYPE_LANG_SPECIFIC (true_type) && IS_SIGNATURE (true_type))
-    {
-      signature_error (NULL_TREE, true_type);
-      return error_mark_node;
-    }
+  /* When we allocate an array, and the corresponding deallocation
+     function takes a second argument of type size_t, and that's the
+     "usual deallocation function", we allocate some extra space at
+     the beginning of the array to store the size of the array.
 
-#if 1
-  /* Get a little extra space to store a couple of things before the new'ed
-     array, if this isn't the default placement new.  */
+     Well, that's what we should do.  For backwards compatibility, we
+     have to do this whenever there's a two-argument array-delete
+     operator. 
 
+     FIXME: For -fnew-abi, we don't have to maintain backwards
+     compatibility and we should fix this.  */
   use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type)
                && ! (placement && ! TREE_CHAIN (placement)
                      && TREE_TYPE (TREE_VALUE (placement)) == ptr_type_node));
-#else
-  /* Get a little extra space to store a couple of things before the new'ed
-     array, if this is either non-placement new or new (nothrow).  */
-  
-  use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type)
-               && (! placement || nothrow));
-#endif
 
   if (use_cookie)
-    {
-      tree extra = BI_header_size;
-
-      size = size_binop (PLUS_EXPR, size, extra);
-    }
+    size = size_binop (PLUS_EXPR, size, BI_header_size);
 
   if (has_array)
     {
@@ -2280,18 +2175,7 @@ build_new_1 (exp)
 
   /* Allocate the object.  */
   
-  if (! has_array && ! placement && flag_this_is_variable > 0
-      && TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
-    {
-      if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST)
-       rval = NULL_TREE;
-      else
-       {
-         error ("constructors take parameter lists");
-         return error_mark_node;
-       }
-    }
-  else if (! placement && TYPE_FOR_JAVA (true_type))
+  if (! placement && TYPE_FOR_JAVA (true_type))
     {
       tree class_addr, alloc_decl;
       tree class_decl = build_java_class_ref (true_type);
@@ -2310,20 +2194,10 @@ build_new_1 (exp)
     }
   else
     {
-      int susp;
-
-      if (flag_exceptions)
-       /* We will use RVAL when generating an exception handler for
-          this new-expression, so we must save it.  */
-       susp = suspend_momentary ();
-
       rval = build_op_new_call
-       (code, true_type, expr_tree_cons (NULL_TREE, size, placement),
+       (code, true_type, tree_cons (NULL_TREE, size, placement),
         LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL));
       rval = cp_convert (build_pointer_type (true_type), rval);
-
-      if (flag_exceptions)
-       resume_momentary (susp);
     }
 
   /*        unless an allocation function is declared with an empty  excep-
@@ -2343,10 +2217,7 @@ build_new_1 (exp)
       tree t = TREE_OPERAND (rval, 0);
       /* The function.  */
       t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
-      t = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (t));
-
-      if (t && TREE_VALUE (t) == NULL_TREE)
-       nothrow = 1;
+      nothrow = TYPE_NOTHROW_P (TREE_TYPE (t));
     }
   check_new = (flag_check_new || nothrow) && ! use_java_new;
 
@@ -2367,19 +2238,18 @@ build_new_1 (exp)
       tree extra = BI_header_size;
       tree cookie, exp1;
       rval = convert (string_type_node, rval); /* for ptr arithmetic */
-      rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra, 1));
+      rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra));
       /* Store header info.  */
       cookie = build_indirect_ref (build (MINUS_EXPR,
                                          build_pointer_type (BI_header_type),
                                          rval, extra), NULL_PTR);
       exp1 = build (MODIFY_EXPR, void_type_node,
-                   build_component_ref (cookie, nc_nelts_field_id,
+                   build_component_ref (cookie, nelts_identifier,
                                         NULL_TREE, 0),
                    nelts);
-      TREE_SIDE_EFFECTS (exp1) = 1;
       rval = cp_convert (build_pointer_type (true_type), rval);
       rval = build_compound_expr
-       (expr_tree_cons (NULL_TREE, exp1,
+       (tree_cons (NULL_TREE, exp1,
                         build_expr_list (NULL_TREE, rval)));
     }
 
@@ -2395,12 +2265,26 @@ build_new_1 (exp)
       if (! TYPE_NEEDS_CONSTRUCTING (type)
          && ! IS_AGGR_TYPE (type) && ! has_array)
        {
-         /* New 2.0 interpretation: `new int (10)' means
-            allocate an int, and initialize it with 10.  */
+         /* We are processing something like `new int (10)', which
+            means allocate an int, and initialize it with 10.  */
          tree deref;
+         tree deref_type;
 
+         /* At present RVAL is a temporary variable, created to hold
+            the value from the call to `operator new'.  We transform
+            it to (*RVAL = INIT, RVAL).  */
          rval = save_expr (rval);
          deref = build_indirect_ref (rval, NULL_PTR);
+
+         /* Even for something like `new const int (10)' we must
+            allow the expression to be non-const while we do the
+            initialization.  */
+         deref_type = TREE_TYPE (deref);
+         if (CP_TYPE_CONST_P (deref_type))
+           TREE_TYPE (deref) 
+             = cp_build_qualified_type (deref_type,
+                                        CP_TYPE_QUALS (deref_type) 
+                                        & ~TYPE_QUAL_CONST);
          TREE_READONLY (deref) = 0;
 
          if (TREE_CHAIN (init) != NULL_TREE)
@@ -2430,7 +2314,7 @@ build_new_1 (exp)
 
          if (rval && TYPE_USES_VIRTUAL_BASECLASSES (true_type))
            {
-             init = expr_tree_cons (NULL_TREE, integer_one_node, init);
+             init = tree_cons (NULL_TREE, integer_one_node, init);
              flags |= LOOKUP_HAS_IN_CHARGE;
            }
 
@@ -2455,39 +2339,39 @@ build_new_1 (exp)
          TREE_HAS_CONSTRUCTOR (rval) = 1;
        }
       else
-       rval = build (VEC_INIT_EXPR, TREE_TYPE (rval),
-                     save_expr (rval), init, nelts);
-
-      /* If any part of the object initialization terminates by throwing
-        an exception and the new-expression does not contain a
-        new-placement, then the deallocation function is called to free
-        the memory in which the object was being constructed.  */
+       rval = (build_vec_init
+               (NULL_TREE, 
+                save_expr (rval),
+                build_binary_op (MINUS_EXPR, nelts, integer_one_node),
+                init,
+                /*from_array=*/0));
+
+      /* If any part of the object initialization terminates by throwing an
+        exception and a suitable deallocation function can be found, the
+        deallocation function is called to free the memory in which the
+        object was being constructed, after which the exception continues
+        to propagate in the context of the new-expression. If no
+        unambiguous matching deallocation function can be found,
+        propagating the exception does not cause the object's memory to be
+        freed.  */
       if (flag_exceptions && alloc_expr && ! use_java_new)
        {
          enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
          tree cleanup, fn = NULL_TREE;
          int flags = LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL);
 
-         /* All cleanups must last longer than normal.  */
-         int yes = suspend_momentary ();
+         /* The Standard is unclear here, but the right thing to do
+             is to use the same method for finding deallocation
+             functions that we use for finding allocation functions.  */
+         flags |= LOOKUP_SPECULATIVELY;
 
-         if (placement)
-           {
-             flags |= LOOKUP_SPECULATIVELY;
-
-             /* We expect alloc_expr to look like a TARGET_EXPR around
-                a NOP_EXPR around the CALL_EXPR we want.  */
-             fn = TREE_OPERAND (alloc_expr, 1);
-             fn = TREE_OPERAND (fn, 0);
-           }
-
-         /* Copy size to the saveable obstack.  */
-         size = copy_node (size);
+         /* We expect alloc_expr to look like a TARGET_EXPR around
+            a NOP_EXPR around the CALL_EXPR we want.  */
+         fn = TREE_OPERAND (alloc_expr, 1);
+         fn = TREE_OPERAND (fn, 0);
 
          cleanup = build_op_delete_call (dcode, alloc_node, size, flags, fn);
 
-         resume_momentary (yes);
-
          /* Ack!  First we allocate the memory.  Then we set our sentry
             variable to true, and expand a cleanup that deletes the memory
             if sentry is true.  Then we run the constructor and store the
@@ -2495,43 +2379,29 @@ build_new_1 (exp)
 
          if (cleanup)
            {
-#if 0
-             /* Disable this until flow is fixed so that it doesn't
-                think the initialization of sentry is a dead write.  */
              tree end, sentry, begin, buf, t = TREE_TYPE (rval);
 
              begin = get_target_expr (boolean_true_node);
              sentry = TREE_OPERAND (begin, 0);
 
-             yes = suspend_momentary ();
              TREE_OPERAND (begin, 2)
                = build (COND_EXPR, void_type_node, sentry,
                         cleanup, void_zero_node);
-             resume_momentary (yes);
 
              rval = get_target_expr (rval);
 
              end = build (MODIFY_EXPR, TREE_TYPE (sentry),
                           sentry, boolean_false_node);
-             TREE_SIDE_EFFECTS (end) = 1;
 
              buf = TREE_OPERAND (rval, 0);
 
              rval = build (COMPOUND_EXPR, t, begin,
                            build (COMPOUND_EXPR, t, rval,
                                   build (COMPOUND_EXPR, t, end, buf)));
-#else
-             /* FIXME: this is a workaround for a crash due to overlapping
-                exception regions.  Cleanups shouldn't really happen here.  */
-             rval = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (rval), rval);
-
-             rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup);
-             rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
-#endif
            }
        }
     }
-  else if (TYPE_READONLY (true_type))
+  else if (CP_TYPE_CONST_P (true_type))
     cp_error ("uninitialized const in `new' of `%#T'", true_type);
 
  done:
@@ -2546,7 +2416,7 @@ build_new_1 (exp)
     {
       /* Did we modify the storage?  */
       tree ifexp = build_binary_op (NE_EXPR, alloc_node,
-                                   integer_zero_node, 1);
+                                   integer_zero_node);
       rval = build_conditional_expr (ifexp, rval, alloc_node);
     }
 
@@ -2563,10 +2433,9 @@ build_new_1 (exp)
 }
 \f
 static tree
-build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
-                   use_global_delete)
+build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
      tree base, maxindex, type;
-     tree auto_delete_vec, auto_delete;
+     tree auto_delete_vec;
      int use_global_delete;
 {
   tree virtual_size;
@@ -2601,7 +2470,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
   /* The below is short by BI_header_size */
   virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
 
-  tbase = build_decl (VAR_DECL, NULL_TREE, ptype);
+  tbase = create_temporary_var (ptype);
   tbase_init = build_modify_expr (tbase, NOP_EXPR,
                                  fold (build (PLUS_EXPR, ptype,
                                               base,
@@ -2610,53 +2479,32 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
   controller = build (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (controller) = 1;
 
-  if (auto_delete != integer_zero_node
-      && auto_delete != integer_two_node)
-    {
-      tree base_tbd = cp_convert (ptype,
-                                 build_binary_op (MINUS_EXPR,
-                                                  cp_convert (ptr_type_node, base),
-                                                  BI_header_size,
-                                                  1));
-      /* This is the real size */
-      virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
-      body = build_expr_list (NULL_TREE,
-                             build_x_delete (ptype, base_tbd,
-                                             2 | use_global_delete,
-                                             virtual_size));
-      body = build (COND_EXPR, void_type_node,
-                   build (BIT_AND_EXPR, integer_type_node,
-                          auto_delete, integer_one_node),
-                   body, integer_zero_node);
-    }
-  else
-    body = NULL_TREE;
+  body = NULL_TREE;
 
-  body = expr_tree_cons (NULL_TREE,
-                   build_delete (ptype, tbase, auto_delete,
+  body = tree_cons (NULL_TREE,
+                   build_delete (ptype, tbase, integer_two_node,
                                  LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1),
                    body);
 
-  body = expr_tree_cons (NULL_TREE,
+  body = tree_cons (NULL_TREE,
                    build_modify_expr (tbase, NOP_EXPR, build (MINUS_EXPR, ptype, tbase, size_exp)),
                    body);
 
-  body = expr_tree_cons (NULL_TREE,
+  body = tree_cons (NULL_TREE,
                    build (EXIT_EXPR, void_type_node,
                           build (EQ_EXPR, boolean_type_node, base, tbase)),
                    body);
 
   loop = build (LOOP_EXPR, void_type_node, build_compound_expr (body));
 
-  loop = expr_tree_cons (NULL_TREE, tbase_init,
-                   expr_tree_cons (NULL_TREE, loop, NULL_TREE));
+  loop = tree_cons (NULL_TREE, tbase_init,
+                   tree_cons (NULL_TREE, loop, NULL_TREE));
   loop = build_compound_expr (loop);
 
  no_destructor:
   /* If the delete flag is one, or anything else with the low bit set,
      delete the storage.  */
-  if (auto_delete_vec == integer_zero_node
-      || auto_delete_vec == integer_two_node)
+  if (auto_delete_vec == integer_zero_node)
     deallocate_expr = integer_zero_node;
   else
     {
@@ -2673,34 +2521,35 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
          base_tbd = cp_convert (ptype,
                                 build_binary_op (MINUS_EXPR,
                                                  cp_convert (string_type_node, base),
-                                                 BI_header_size,
-                                                 1));
+                                                 BI_header_size));
          /* True size with header.  */
          virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
        }
-      deallocate_expr = build_x_delete (ptype, base_tbd,
+      deallocate_expr = build_x_delete (base_tbd,
                                        2 | use_global_delete,
                                        virtual_size);
-      if (auto_delete_vec != integer_one_node)
-       deallocate_expr = build (COND_EXPR, void_type_node,
-                                build (BIT_AND_EXPR, integer_type_node,
-                                       auto_delete_vec, integer_one_node),
-                                deallocate_expr, integer_zero_node);
+      deallocate_expr = fold (build (COND_EXPR, void_type_node,
+                                    fold (build (BIT_AND_EXPR,
+                                                 integer_type_node,
+                                                 auto_delete_vec,
+                                                 integer_one_node)),
+                                    deallocate_expr, integer_zero_node));
     }
 
   if (loop && deallocate_expr != integer_zero_node)
     {
-      body = expr_tree_cons (NULL_TREE, loop,
-                       expr_tree_cons (NULL_TREE, deallocate_expr, NULL_TREE));
+      body = tree_cons (NULL_TREE, loop,
+                       tree_cons (NULL_TREE, deallocate_expr, NULL_TREE));
       body = build_compound_expr (body);
     }
   else
     body = loop;
 
   /* Outermost wrapper: If pointer is null, punt.  */
-  body = build (COND_EXPR, void_type_node,
-               build (NE_EXPR, boolean_type_node, base, integer_zero_node),
-               body, integer_zero_node);
+  body = fold (build (COND_EXPR, void_type_node,
+                     fold (build (NE_EXPR, boolean_type_node, base,
+                                  integer_zero_node)),
+                     body, integer_zero_node));
   body = build1 (NOP_EXPR, void_type_node, body);
 
   if (controller)
@@ -2712,26 +2561,53 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
     return cp_convert (void_type_node, body);
 }
 
-/* Build a tree to cleanup partially built arrays.
-   BASE is that starting address of the array.
-   COUNT is the count of objects that have been built, that need destroying.
-   TYPE is the type of elements in the array.  */
+tree
+create_temporary_var (type)
+     tree type;
+{
+  tree decl;
+  decl = build_decl (VAR_DECL, NULL_TREE, type);
+  TREE_USED (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_SOURCE_FILE (decl) = input_filename;
+  DECL_SOURCE_LINE (decl) = lineno;
+  DECL_IGNORED_P (decl) = 1;
+  DECL_CONTEXT (decl) = current_function_decl;
+
+  return decl;
+}
+
+/* Create a new temporary variable of the indicated TYPE, initialized
+   to INIT.
+
+   It is not entered into current_binding_level, because that breaks
+   things when it comes time to do final cleanups (which take place
+   "outside" the binding contour of the function).  */
 
 static tree
-build_array_eh_cleanup (base, count, type)
-     tree base, count, type;
+get_temp_regvar (type, init)
+     tree type, init;
 {
-  tree expr = build_vec_delete_1 (base, count, type, integer_two_node,
-                                 integer_zero_node, 0);
-  return expr;
+  tree decl;
+
+  decl = create_temporary_var (type);
+  if (building_stmt_tree ())
+    add_decl_stmt (decl);
+  if (!building_stmt_tree ())
+    DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
+  finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
+
+  return decl;
 }
 
-/* `expand_vec_init' performs initialization of a vector of aggregate
-   types.
+/* `build_vec_init' returns tree structure that performs
+   initialization of a vector of aggregate types.
 
    DECL is passed only for error reporting, and provides line number
    and source file name information.
-   BASE is the space where the vector will be.
+   BASE is the space where the vector will be.  For a vector of Ts,
+     the type of BASE is `T*'.
    MAXINDEX is the maximum index of the array (one less than the
            number of elements).
    INIT is the (possibly NULL) initializer.
@@ -2744,130 +2620,187 @@ build_array_eh_cleanup (base, count, type)
    but use assignment instead of initialization.  */
 
 tree
-expand_vec_init (decl, base, maxindex, init, from_array)
+build_vec_init (decl, base, maxindex, init, from_array)
      tree decl, base, maxindex, init;
      int from_array;
 {
   tree rval;
-  tree iterator, base2 = NULL_TREE;
-  tree type = TREE_TYPE (TREE_TYPE (base));
+  tree base2 = NULL_TREE;
   tree size;
+  tree itype = NULL_TREE;
+  tree iterator;
+  /* The type of an element in the array.  */
+  tree type;
+  /* The type of a pointer to an element in the array.  */
+  tree ptype;
+  tree stmt_expr;
+  tree compound_stmt;
+  int destroy_temps;
+  tree try_block = NULL_TREE;
+  tree try_body;
+  int num_initialized_elts = 0;
 
   maxindex = cp_convert (ptrdiff_type_node, maxindex);
   if (maxindex == error_mark_node)
     return error_mark_node;
 
-  if (current_function_decl == NULL_TREE)
-    {
-      rval = make_tree_vec (3);
-      TREE_VEC_ELT (rval, 0) = base;
-      TREE_VEC_ELT (rval, 1) = maxindex;
-      TREE_VEC_ELT (rval, 2) = init;
-      return rval;
-    }
-
+  type = TREE_TYPE (TREE_TYPE (base));
+  ptype = build_pointer_type (type);
   size = size_in_bytes (type);
 
-  /* Set to zero in case size is <= 0.  Optimizer will delete this if
-     it is not needed.  */
-  rval = get_temp_regvar (build_pointer_type (type),
-                         cp_convert (build_pointer_type (type), null_pointer_node));
-  base = default_conversion (base);
-  base = cp_convert (build_pointer_type (type), base);
-  expand_assignment (rval, base, 0, 0);
-  base = get_temp_regvar (build_pointer_type (type), base);
-
-  if (init != NULL_TREE
-      && TREE_CODE (init) == CONSTRUCTOR
-      && (! decl || TREE_TYPE (init) == TREE_TYPE (decl)))
-    {
-      /* Initialization of array from {...}.  */
-      tree elts = CONSTRUCTOR_ELTS (init);
-      tree baseref = build1 (INDIRECT_REF, type, base);
-      tree baseinc = build (PLUS_EXPR, build_pointer_type (type), base, size);
-      int host_i = TREE_INT_CST_LOW (maxindex);
-
-      if (IS_AGGR_TYPE (type))
-       {
-         while (elts)
-           {
-             host_i -= 1;
-             expand_aggr_init (baseref, TREE_VALUE (elts), 0, 0);
-
-             expand_assignment (base, baseinc, 0, 0);
-             elts = TREE_CHAIN (elts);
-           }
-         /* Initialize any elements by default if possible.  */
-         if (host_i >= 0)
-           {
-             if (TYPE_NEEDS_CONSTRUCTING (type) == 0)
-               {
-                 if (obey_regdecls)
-                   use_variable (DECL_RTL (base));
-                 goto done_init;
-               }
+  /* The code we are generating looks like:
+
+       T* t1 = (T*) base;
+       T* rval = base;
+       ptrdiff_t iterator = maxindex;
+       try {
+         ... initializations from CONSTRUCTOR ...
+         if (iterator != -1) {
+          do {
+            ... initialize *base ...
+            ++base;
+          } while (--iterator != -1);
+        }
+       } catch (...) {
+         ... destroy elements that were constructed ...
+       }
+       
+     We can omit the try and catch blocks if we know that the
+     initialization will never throw an exception, or if the array
+     elements do not have destructors.  If we have a CONSTRUCTOR to
+     give us initialization information, we emit code to initialize
+     each of the elements before the loop in the try block, and then
+     iterate over fewer elements.  We can omit the loop completely if
+     the elements of the array do not have constructors.  
+
+     We actually wrap the entire body of the above in a STMT_EXPR, for
+     tidiness.  
+
+     When copying from array to another, when the array elements have
+     only trivial copy constructors, we should use __builtin_memcpy
+     rather than generating a loop.  That way, we could take advantage
+     of whatever cleverness the back-end has for dealing with copies
+     of blocks of memory.  */
+
+  begin_init_stmts (&stmt_expr, &compound_stmt);
+  destroy_temps = stmts_are_full_exprs_p;
+  stmts_are_full_exprs_p = 0;
+  rval = get_temp_regvar (ptype, 
+                         cp_convert (ptype, default_conversion (base)));
+  base = get_temp_regvar (ptype, rval);
+  iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
+
+  /* Protect the entire array initialization so that we can destroy
+     the partially constructed array if an exception is thrown.  */
+  if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
+    {
+      try_block = begin_try_block ();
+      try_body = begin_compound_stmt (/*has_no_scope=*/1);
+    }
+
+  if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR
+      && (!decl || same_type_p (TREE_TYPE (init), TREE_TYPE (decl))))
+    {
+      /* Do non-default initialization resulting from brace-enclosed
+        initializers.  */
+
+      tree elts;
+      from_array = 0;
+
+      for (elts = CONSTRUCTOR_ELTS (init); elts; elts = TREE_CHAIN (elts))
+       {
+         tree elt = TREE_VALUE (elts);
+         tree baseref = build1 (INDIRECT_REF, type, base);
+
+         num_initialized_elts++;
+
+         if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE)
+           finish_expr_stmt (build_aggr_init (baseref, elt, 0));
+         else
+           finish_expr_stmt (build_modify_expr (baseref, NOP_EXPR,
+                                                elt));
 
-             iterator = get_temp_regvar (ptrdiff_type_node,
-                                         build_int_2 (host_i, 0));
-             init = NULL_TREE;
-             goto init_by_default;
-           }
+         finish_expr_stmt (build_modify_expr 
+                           (base, 
+                            NOP_EXPR,
+                            build (PLUS_EXPR, build_pointer_type (type),
+                                   base, size)));
+         finish_expr_stmt (build_modify_expr
+                           (iterator,
+                            NOP_EXPR,
+                            build (MINUS_EXPR, ptrdiff_type_node,
+                                   iterator, integer_one_node)));
        }
-      else
-       while (elts)
-         {
-           expand_assignment (baseref, TREE_VALUE (elts), 0, 0);
 
-           expand_assignment (base, baseinc, 0, 0);
-           elts = TREE_CHAIN (elts);
-         }
-
-      if (obey_regdecls)
-       use_variable (DECL_RTL (base));
+      /* Clear out INIT so that we don't get confused below.  */
+      init = NULL_TREE;
     }
-  else
+  else if (from_array)
     {
-      tree itype;
-
-      iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
-
-    init_by_default:
-      itype = NULL_TREE;
-
-      /* If initializing one array from another,
-        initialize element by element.  */
-      if (from_array)
+      /* If initializing one array from another, initialize element by
+        element.  We rely upon the below calls the do argument
+        checking.  */ 
+      if (decl == NULL_TREE)
        {
-         /* We rely upon the below calls the do argument checking */
-         if (decl == NULL_TREE)
-           {
-             sorry ("initialization of array from dissimilar array type");
-             return error_mark_node;
-           }
-         if (init)
-           {
-             base2 = default_conversion (init);
-             itype = TREE_TYPE (base2);
-             base2 = get_temp_regvar (itype, base2);
-             itype = TREE_TYPE (itype);
-           }
-         else if (TYPE_LANG_SPECIFIC (type)
-                  && TYPE_NEEDS_CONSTRUCTING (type)
-                  && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
-           {
-             error ("initializer ends prematurely");
-             return error_mark_node;
-           }
+         sorry ("initialization of array from dissimilar array type");
+         return error_mark_node;
        }
+      if (init)
+       {
+         base2 = default_conversion (init);
+         itype = TREE_TYPE (base2);
+         base2 = get_temp_regvar (itype, base2);
+         itype = TREE_TYPE (itype);
+       }
+      else if (TYPE_LANG_SPECIFIC (type)
+              && TYPE_NEEDS_CONSTRUCTING (type)
+              && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+       {
+         error ("initializer ends prematurely");
+         return error_mark_node;
+       }
+    }
 
-      expand_start_cond (build (GE_EXPR, boolean_type_node,
-                               iterator, integer_zero_node), 0);
-      if (TYPE_NEEDS_DESTRUCTOR (type))
-       expand_eh_region_start ();
-      expand_start_loop_continue_elsewhere (1);
-
-      /* The initialization of each array element is a full-expression.  */
-      expand_start_target_temps ();
+  /* Now, default-initialize any remaining elements.  We don't need to
+     do that if a) the type does not need constructing, or b) we've
+     already initialized all the elements.
+
+     We do need to keep going if we're copying an array.  */
+
+  if (from_array
+      || (TYPE_NEEDS_CONSTRUCTING (type)
+         && !(TREE_CODE (maxindex) == INTEGER_CST
+              && num_initialized_elts == TREE_INT_CST_LOW (maxindex) + 1)))
+    {
+      /* If the ITERATOR is equal to -1, then we don't have to loop;
+        we've already initialized all the elements.  */
+      tree if_stmt;
+      tree do_stmt;
+      tree do_body;
+      tree elt_init;
+
+      if_stmt = begin_if_stmt ();
+      finish_if_stmt_cond (build (NE_EXPR, boolean_type_node,
+                                 iterator, minus_one_node),
+                          if_stmt);
+
+      /* Otherwise, loop through the elements.  */
+      do_stmt = begin_do_stmt ();
+      do_body = begin_compound_stmt (/*has_no_scope=*/1);
+
+      /* When we're not building a statement-tree, things are a little
+        complicated.  If, when we recursively call build_aggr_init,
+        an expression containing a TARGET_EXPR is expanded, then it
+        may get a cleanup.  Then, the result of that expression is
+        passed to finish_expr_stmt, which will call
+        expand_start_target_temps/expand_end_target_temps.  However,
+        the latter call will not cause the cleanup to run because
+        that block will still be on the block stack.  So, we call
+        expand_start_target_temps here manually; the corresponding
+        call to expand_end_target_temps below will cause the cleanup
+        to be performed.  */
+      if (!building_stmt_tree ())
+       expand_start_target_temps ();
 
       if (from_array)
        {
@@ -2880,11 +2813,11 @@ expand_vec_init (decl, base, maxindex, init, from_array)
            from = NULL_TREE;
 
          if (from_array == 2)
-           expand_expr_stmt (build_modify_expr (to, NOP_EXPR, from));
+           elt_init = build_modify_expr (to, NOP_EXPR, from);
          else if (TYPE_NEEDS_CONSTRUCTING (type))
-           expand_aggr_init (to, from, 0, 0);
+           elt_init = build_aggr_init (to, from, 0);
          else if (from)
-           expand_assignment (to, from, 0, 0);
+           elt_init = build_modify_expr (to, NOP_EXPR, from);
          else
            my_friendly_abort (57);
        }
@@ -2892,71 +2825,80 @@ expand_vec_init (decl, base, maxindex, init, from_array)
        {
          if (init != 0)
            sorry ("cannot initialize multi-dimensional array with initializer");
-         expand_vec_init (decl, build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), base),
-                          array_type_nelts (type), 0, 0);
+         elt_init = (build_vec_init 
+                     (decl, 
+                      build1 (NOP_EXPR, 
+                              build_pointer_type (TREE_TYPE (type)),
+                              base),
+                      array_type_nelts (type), 0, 0));
        }
       else
-       expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0, 0);
-
-      expand_assignment (base,
-                        build (PLUS_EXPR, build_pointer_type (type), base, size),
-                        0, 0);
-      if (base2)
-       expand_assignment (base2,
-                          build (PLUS_EXPR, build_pointer_type (type), base2, size), 0, 0);
-
-      /* Cleanup any temporaries needed for the initial value.  */
-      expand_end_target_temps ();
-
-      expand_loop_continue_here ();
-      expand_exit_loop_if_false (0, build (NE_EXPR, boolean_type_node,
-                                          build (PREDECREMENT_EXPR, ptrdiff_type_node, iterator, integer_one_node), minus_one));
-
-      if (obey_regdecls)
+       elt_init = build_aggr_init (build1 (INDIRECT_REF, type, base), 
+                                   init, 0);
+      
+      /* The initialization of each array element is a
+        full-expression.  */
+      if (!building_stmt_tree ())
        {
-         use_variable (DECL_RTL (base));
-         if (base2)
-           use_variable (DECL_RTL (base2));
+         finish_expr_stmt (elt_init);
+         expand_end_target_temps ();
        }
-      expand_end_loop ();
-      if (TYPE_NEEDS_DESTRUCTOR (type) && flag_exceptions)
+      else
        {
-         /* We have to ensure that this can live to the cleanup
-            expansion time, since we know it is only ever needed
-            once, generate code now.  */
-         push_obstacks_nochange ();
-         resume_temporary_allocation ();
-         {
-           tree e1, cleanup = make_node (RTL_EXPR);
-           TREE_TYPE (cleanup) = void_type_node;
-           RTL_EXPR_RTL (cleanup) = const0_rtx;
-           TREE_SIDE_EFFECTS (cleanup) = 1;
-           do_pending_stack_adjust ();
-           start_sequence_for_rtl_expr (cleanup);
-
-           e1 = build_array_eh_cleanup
-             (rval,
-              build_binary_op (MINUS_EXPR, maxindex, iterator, 1),
-              type);
-           expand_expr (e1, const0_rtx, VOIDmode, EXPAND_NORMAL);
-           do_pending_stack_adjust ();
-           RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
-           end_sequence ();
-
-           cleanup = protect_with_terminate (cleanup);
-           expand_eh_region_end (cleanup);
-         }
-         pop_obstacks ();
+         stmts_are_full_exprs_p = 1;
+         finish_expr_stmt (elt_init);
+         stmts_are_full_exprs_p = 0;
        }
-      expand_end_cond ();
-      if (obey_regdecls)
-       use_variable (DECL_RTL (iterator));
-    }
- done_init:
 
-  if (obey_regdecls)
-    use_variable (DECL_RTL (rval));
-  return rval;
+      finish_expr_stmt (build_modify_expr
+                       (base,
+                        NOP_EXPR,
+                        build (PLUS_EXPR, build_pointer_type (type), 
+                               base, size)));
+      if (base2)
+       finish_expr_stmt (build_modify_expr
+                         (base2,
+                          NOP_EXPR,
+                          build (PLUS_EXPR, build_pointer_type (type), 
+                                 base2, size)));
+
+      finish_compound_stmt (/*has_no_scope=*/1, do_body);
+      finish_do_body (do_stmt);
+      finish_do_stmt (build (NE_EXPR, boolean_type_node,
+                            build (PREDECREMENT_EXPR, 
+                                   ptrdiff_type_node, 
+                                   iterator,
+                                   integer_one_node), 
+                            minus_one_node),
+                     do_stmt);
+
+      finish_then_clause (if_stmt);
+      finish_if_stmt ();
+    }
+
+  /* Make sure to cleanup any partially constructed elements.  */
+  if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
+    {
+      tree e;
+
+      finish_compound_stmt (/*has_no_scope=*/1, try_body);
+      finish_cleanup_try_block (try_block);
+      e = build_vec_delete_1 (rval,
+                             build_binary_op (MINUS_EXPR, maxindex, 
+                                              iterator),
+                             type,
+                             /*auto_delete_vec=*/integer_zero_node,
+                             /*use_global_delete=*/0);
+      finish_cleanup (e, try_block);
+    }
+
+  /* The value of the array initialization is the address of the
+     first element in the array.  */
+  finish_expr_stmt (rval);
+
+  stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
+  stmts_are_full_exprs_p = destroy_temps;
+  return stmt_expr;
 }
 
 /* Free up storage of type TYPE, at address ADDR.
@@ -2974,8 +2916,8 @@ expand_vec_init (decl, base, maxindex, init, from_array)
    This does not call any destructors.  */
 
 tree
-build_x_delete (type, addr, which_delete, virtual_size)
-     tree type, addr;
+build_x_delete (addr, which_delete, virtual_size)
+     tree addr;
      int which_delete;
      tree virtual_size;
 {
@@ -3023,7 +2965,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
   if (TREE_CODE (type) == POINTER_TYPE)
     {
       type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
-      if (!complete_type_or_else (type))
+      if (type != void_type_node && !complete_type_or_else (type, addr))
        return error_mark_node;
       if (TREE_CODE (type) == ARRAY_TYPE)
        goto handle_array;
@@ -3050,8 +2992,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
          return error_mark_node;
        }
       return build_vec_delete (addr, array_type_nelts (type),
-                              auto_delete, integer_two_node,
-                              use_global_delete);
+                              auto_delete, use_global_delete);
     }
   else
     {
@@ -3121,7 +3062,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
        ifexp = integer_one_node;
       else
        /* Handle deleting a null pointer.  */
-       ifexp = fold (build_binary_op (NE_EXPR, addr, integer_zero_node, 1));
+       ifexp = fold (build_binary_op (NE_EXPR, addr, integer_zero_node));
 
       if (ifexp != integer_one_node)
        expr = build (COND_EXPR, void_type_node,
@@ -3139,6 +3080,10 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
       tree parent_auto_delete = auto_delete;
       tree cond;
 
+      /* Set this again before we call anything, as we might get called
+        recursively.  */
+      TYPE_HAS_DESTRUCTOR (type) = 1;
+
       /* If we have member delete or vbases, we call delete in
         finish_function.  */
       if (auto_delete == integer_zero_node)
@@ -3171,7 +3116,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
          expr = build_scoped_method_call
            (ref, base_binfo, dtor_identifier,
             build_expr_list (NULL_TREE, this_auto_delete));
-         exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+         exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
        }
 
       /* Take care of the remaining baseclasses.  */
@@ -3186,7 +3131,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
            (ref, base_binfo, dtor_identifier,
             build_expr_list (NULL_TREE, integer_zero_node));
 
-         exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+         exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
        }
 
       for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
@@ -3198,7 +3143,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
              tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
              tree this_type = TREE_TYPE (member);
              expr = build_delete (this_type, this_member, integer_two_node, flags, 0);
-             exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+             exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
            }
        }
 
@@ -3225,7 +3170,7 @@ build_vbase_delete (type, decl)
     {
       tree this_addr = convert_force (build_pointer_type (BINFO_TYPE (vbases)),
                                      addr, 0);
-      result = expr_tree_cons (NULL_TREE,
+      result = tree_cons (NULL_TREE,
                          build_delete (TREE_TYPE (this_addr), this_addr,
                                        integer_zero_node,
                                        LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
@@ -3241,7 +3186,6 @@ build_vbase_delete (type, decl)
    BASE is the expression that should yield the store to be deleted.
    This function expands (or synthesizes) these calls itself.
    AUTO_DELETE_VEC says whether the container (vector) should be deallocated.
-   AUTO_DELETE say whether each item in the container should be deallocated.
 
    This also calls delete for virtual baseclasses of elements of the vector.
 
@@ -3253,10 +3197,9 @@ build_vbase_delete (type, decl)
    be worth bothering.)  */
 
 tree
-build_vec_delete (base, maxindex, auto_delete_vec, auto_delete,
-                 use_global_delete)
+build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete)
      tree base, maxindex;
-     tree auto_delete_vec, auto_delete;
+     tree auto_delete_vec;
      int use_global_delete;
 {
   tree type;
@@ -3278,7 +3221,7 @@ build_vec_delete (base, maxindex, auto_delete_vec, auto_delete,
       tree cookie_addr = build (MINUS_EXPR, build_pointer_type (BI_header_type),
                                base, BI_header_size);
       tree cookie = build_indirect_ref (cookie_addr, NULL_PTR);
-      maxindex = build_component_ref (cookie, nc_nelts_field_id, NULL_TREE, 0);
+      maxindex = build_component_ref (cookie, nelts_identifier, NULL_TREE, 0);
       do
        type = TREE_TYPE (type);
       while (TREE_CODE (type) == ARRAY_TYPE);
@@ -3298,6 +3241,6 @@ build_vec_delete (base, maxindex, auto_delete_vec, auto_delete,
       return error_mark_node;
     }
 
-  return build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
+  return build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
                             use_global_delete);
 }