OSDN Git Service

* g++.old-deja/g++.benjamin/16077.C: Adjust warnings.
[pf3gnuchains/gcc-fork.git] / gcc / cp / init.c
index c0cc3f3..99812c6 100644 (file)
@@ -1,22 +1,22 @@
 /* Handle initialization things in C++.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
@@ -24,6 +24,8 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "expr.h"
@@ -32,50 +34,27 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "except.h"
 #include "toplev.h"
-#include "ggc.h"
 
-static void expand_aggr_vbase_init_1 PARAMS ((tree, tree, tree, tree));
-static void construct_virtual_bases PARAMS ((tree, tree, tree, tree, tree));
+static void construct_virtual_base (tree, tree);
 static void expand_aggr_init_1 PARAMS ((tree, tree, tree, tree, int));
 static void expand_default_init PARAMS ((tree, tree, tree, tree, int));
 static tree build_vec_delete_1 PARAMS ((tree, tree, tree, special_function_kind, int));
-static void perform_member_init PARAMS ((tree, tree, int));
-static void sort_base_init PARAMS ((tree, tree, tree *, tree *));
+static void perform_member_init (tree, tree);
 static tree build_builtin_delete_call PARAMS ((tree));
 static int member_init_ok_or_else PARAMS ((tree, tree, tree));
 static void expand_virtual_init PARAMS ((tree, tree));
-static tree sort_member_init PARAMS ((tree, tree));
+static tree sort_mem_initializers (tree, tree);
 static tree initializing_context PARAMS ((tree));
 static void expand_cleanup_for_base PARAMS ((tree, tree));
 static tree get_temp_regvar PARAMS ((tree, tree));
 static tree dfs_initialize_vtbl_ptrs PARAMS ((tree, void *));
-static tree build_default_init PARAMS ((tree));
+static tree build_default_init PARAMS ((tree, tree));
 static tree build_new_1        PARAMS ((tree));
 static tree get_cookie_size PARAMS ((tree));
 static tree build_dtor_call PARAMS ((tree, special_function_kind, int));
 static tree build_field_list PARAMS ((tree, tree, int *));
 static tree build_vtbl_address PARAMS ((tree));
 
-/* Set up local variable for this file.  MUST BE CALLED AFTER
-   INIT_DECL_PROCESSING.  */
-
-static tree BI_header_type;
-
-void init_init_processing ()
-{
-  tree fields[1];
-
-  /* Define the structure that holds header information for
-     arrays allocated via operator new.  */
-  BI_header_type = make_aggr_type (RECORD_TYPE);
-  fields[0] = build_decl (FIELD_DECL, nelts_identifier, sizetype);
-
-  finish_builtin_type (BI_header_type, "__new_cookie", fields,
-                      0, double_type_node);
-
-  ggc_add_tree_root (&BI_header_type, 1);
-}
-
 /* 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
@@ -97,10 +76,6 @@ begin_init_stmts (stmt_expr_p, compound_stmt_p)
   
   if (building_stmt_tree ())
     *compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
-  /*
-  else 
-    *compound_stmt_p = genrtl_begin_compound_stmt (has_no_scope=1);
-  */
 }
 
 /* Finish out the statement-expression begun by the previous call to
@@ -116,7 +91,10 @@ finish_init_stmts (stmt_expr, compound_stmt)
     finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
   
   if (building_stmt_tree ())
-    stmt_expr = finish_stmt_expr (stmt_expr);
+    {
+      stmt_expr = finish_stmt_expr (stmt_expr);
+      STMT_EXPR_NO_SCOPE (stmt_expr) = true;
+    }
   else
     stmt_expr = finish_global_stmt_expr (stmt_expr);
   
@@ -149,7 +127,7 @@ dfs_initialize_vtbl_ptrs (binfo, data)
       expand_virtual_init (binfo, base_ptr);
     }
 
-  SET_BINFO_MARKED (binfo);
+  BINFO_MARKED (binfo) = 1;
 
   return NULL_TREE;
 }
@@ -171,74 +149,193 @@ initialize_vtbl_ptrs (addr)
      class.  We do these in pre-order because can't find the virtual
      bases for a class until we've initialized the vtbl for that
      class.  */
-  dfs_walk_real (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs, 
-                NULL, dfs_unmarked_real_bases_queue_p, list);
-  dfs_walk (TYPE_BINFO (type), dfs_unmark,
-           dfs_marked_real_bases_queue_p, type);
+  dfs_walk_real (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs,
+                NULL, unmarkedp, list);
+  dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, type);
 }
 
-/* [dcl.init]:
+/* Return an expression for the zero-initialization of an object with
+   type T.  This expression will either be a constant (in the case
+   that T is a scalar), or a CONSTRUCTOR (in the case that T is an
+   aggregate).  In either case, the value can be used as DECL_INITIAL
+   for a decl of the indicated TYPE; it is a valid static initializer.
+   If NELTS is non-NULL, and TYPE is an ARRAY_TYPE, NELTS is the
+   number of elements in the array.  If STATIC_STORAGE_P is TRUE,
+   initializers are only generated for entities for which
+   zero-initialization does not simply mean filling the storage with
+   zero bytes.  */
 
-  To default-initialize an object of type T means:
+tree
+build_zero_init (tree type, tree nelts, bool static_storage_p)
+{
+  tree init = NULL_TREE;
 
-  --if T is a non-POD class type (clause _class_), the default construc-
-    tor  for  T is called (and the initialization is ill-formed if T has
-    no accessible default constructor);
+  /* [dcl.init]
 
-  --if T is an array type, each element is default-initialized;
+     To zero-initialization storage for an object of type T means:
 
-  --otherwise, the storage for the object is zero-initialized.
+     -- if T is a scalar type, the storage is set to the value of zero
+        converted to T.
 
-  A program that calls for default-initialization of an entity of refer-
-  ence type is ill-formed.  */
+     -- if T is a non-union class type, the storage for each nonstatic
+        data member and each base-class subobject is zero-initialized.
 
-static tree
-build_default_init (type)
-     tree type;
-{
-  tree init = NULL_TREE;
+     -- if T is a union type, the storage for its first data member is
+        zero-initialized.
 
-  if (TYPE_NEEDS_CONSTRUCTING (type))
-    /* Other code will handle running the default constructor.  We can't do
-       anything with a CONSTRUCTOR for arrays here, as that would imply
-       copy-initialization.  */
-    return NULL_TREE;
-  else if (AGGREGATE_TYPE_P (type) && !TYPE_PTRMEMFUNC_P (type))
+     -- if T is an array type, the storage for each element is
+        zero-initialized.
+
+     -- if T is a reference type, no initialization is performed.  */
+
+  if (type == error_mark_node)
+    ;
+  else if (static_storage_p && zero_init_p (type))
+    /* In order to save space, we do not explicitly build initializers
+       for items that do not need them.  GCC's semantics are that
+       items with static storage duration that are not otherwise
+       initialized are initialized to zero.  */
+    ;
+  else if (SCALAR_TYPE_P (type))
+    init = convert (type, integer_zero_node);
+  else if (CLASS_TYPE_P (type))
+    {
+      tree field;
+      tree inits;
+
+      /* Build a constructor to contain the initializations.  */
+      init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+      /* Iterate over the fields, building initializations.  */
+      inits = NULL_TREE;
+      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+       {
+         if (TREE_CODE (field) != FIELD_DECL)
+           continue;
+
+         /* Note that for class types there will be FIELD_DECLs
+            corresponding to base classes as well.  Thus, iterating
+            over TYPE_FIELDs will result in correct initialization of
+            all of the subobjects.  */
+         if (static_storage_p && !zero_init_p (TREE_TYPE (field)))
+           inits = tree_cons (field, 
+                              build_zero_init (TREE_TYPE (field),
+                                               /*nelts=*/NULL_TREE,
+                                               static_storage_p),
+                              inits);
+
+         /* For unions, only the first field is initialized.  */
+         if (TREE_CODE (type) == UNION_TYPE)
+           break;
+       }
+      CONSTRUCTOR_ELTS (init) = nreverse (inits);
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
     {
-      /* 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.  */
-      init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, NULL_TREE);
+      tree index;
+      tree max_index;
+      tree inits;
+
+      /* Build a constructor to contain the initializations.  */
+      init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+      /* Iterate over the array elements, building initializations.  */
+      inits = NULL_TREE;
+      max_index = nelts ? nelts : array_type_nelts (type);
+      for (index = size_zero_node;
+          !tree_int_cst_lt (max_index, index);
+          index = size_binop (PLUS_EXPR, index, size_one_node))
+       inits = tree_cons (index,
+                          build_zero_init (TREE_TYPE (type),
+                                           /*nelts=*/NULL_TREE,
+                                           static_storage_p),
+                          inits);
+      CONSTRUCTOR_ELTS (init) = nreverse (inits);
     }
   else if (TREE_CODE (type) == REFERENCE_TYPE)
-    /*   --if T is a reference type, no initialization is performed.  */
-    return NULL_TREE;
+    ;
   else
-    {
-      init = integer_zero_node;
-      
-      if (TREE_CODE (type) == ENUMERAL_TYPE)
-        /* We must make enumeral types the right type. */
-        init = fold (build1 (NOP_EXPR, type, init));
-    }
+    abort ();
+
+  /* In all cases, the initializer is a constant.  */
+  if (init)
+    TREE_CONSTANT (init) = 1;
 
-  init = digest_init (type, init, 0);
   return init;
 }
 
-/* Subroutine of emit_base_init.  */
+/* Build an expression for the default-initialization of an object of
+   the indicated TYPE.  If NELTS is non-NULL, and TYPE is an
+   ARRAY_TYPE, NELTS is the number of elements in the array.  If
+   initialization of TYPE requires calling constructors, this function
+   returns NULL_TREE; the caller is responsible for arranging for the
+   constructors to be called.  */
+
+static tree
+build_default_init (type, nelts)
+     tree type;
+     tree nelts;
+{
+  /* [dcl.init]:
+
+    To default-initialize an object of type T means:
+
+    --if T is a non-POD class type (clause _class_), the default construc-
+      tor  for  T is called (and the initialization is ill-formed if T has
+      no accessible default constructor);
+
+    --if T is an array type, each element is default-initialized;
+
+    --otherwise, the storage for the object is zero-initialized.
+
+    A program that calls for default-initialization of an entity of refer-
+    ence type is ill-formed.  */
+
+  /* If TYPE_NEEDS_CONSTRUCTING is true, the caller is responsible for
+     performing the initialization.  This is confusing in that some
+     non-PODs do not have TYPE_NEEDS_CONSTRUCTING set.  (For example,
+     a class with a pointer-to-data member as a non-static data member
+     does not have TYPE_NEEDS_CONSTRUCTING set.)  Therefore, we end up
+     passing non-PODs to build_zero_init below, which is contrary to
+     the semantics quoted above from [dcl.init].  
+
+     It happens, however, that the behavior of the constructor the
+     standard says we should have generated would be precisely the
+     same as that obtained by calling build_zero_init below, so things
+     work out OK.  */
+  if (TYPE_NEEDS_CONSTRUCTING (type))
+    return NULL_TREE;
+      
+  /* At this point, TYPE is either a POD class type, an array of POD
+     classes, or something even more inoccuous.  */
+  return build_zero_init (type, nelts, /*static_storage_p=*/false);
+}
+
+/* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
+   arguments.  If TREE_LIST is void_type_node, an empty initializer
+   list was given; if NULL_TREE no initializer was given.  */
 
 static void
-perform_member_init (member, init, explicit)
-     tree member, init;
-     int explicit;
+perform_member_init (tree member, tree init)
 {
   tree decl;
   tree type = TREE_TYPE (member);
+  bool explicit;
 
-  decl = build_component_ref (current_class_ref, member, NULL_TREE, explicit);
+  explicit = (init != NULL_TREE);
 
+  /* Effective C++ rule 12 requires that all data members be
+     initialized.  */
+  if (warn_ecpp && !explicit && TREE_CODE (type) != ARRAY_TYPE)
+    warning ("`%D' should be initialized in the member initialization "
+            "list", 
+            member);
+
+  if (init == void_type_node)
+    init = NULL_TREE;
+
+  /* Get an lvalue for the data member.  */
+  decl = build_class_member_access_expr (current_class_ref, member,
+                                        /*access_path=*/NULL_TREE,
+                                        /*preserve_reference=*/true);
   if (decl == error_mark_node)
     return;
 
@@ -256,11 +353,6 @@ perform_member_init (member, init, explicit)
   else if (TYPE_NEEDS_CONSTRUCTING (type)
           || (init && TYPE_HAS_CONSTRUCTOR (type)))
     {
-      /* Since `init' is already a TREE_LIST on the 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_tree_list (NULL_TREE, init);
-
       if (explicit
          && TREE_CODE (type) == ARRAY_TYPE
          && init != NULL_TREE
@@ -268,7 +360,8 @@ perform_member_init (member, init, explicit)
          && TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE)
        {
          /* Initialization of one array from another.  */
-         finish_expr_stmt (build_vec_init (decl, TREE_VALUE (init), 1));
+         finish_expr_stmt (build_vec_init (decl, NULL_TREE, TREE_VALUE (init),
+                                           /* from_array=*/1));
        }
       else
        finish_expr_stmt (build_aggr_init (decl, init, 0));
@@ -279,15 +372,15 @@ perform_member_init (member, init, explicit)
        {
          if (explicit)
            {
-             init = build_default_init (type);
+             init = build_default_init (type, /*nelts=*/NULL_TREE);
              if (TREE_CODE (type) == REFERENCE_TYPE)
-               cp_warning
+               warning
                  ("default-initialization of `%#D', which has reference type",
                   member);
            }
          /* member traversal: note it leaves init NULL */
          else if (TREE_CODE (type) == REFERENCE_TYPE)
-           cp_pedwarn ("uninitialized reference member `%D'", member);
+           pedwarn ("uninitialized reference member `%D'", member);
        }
       else if (TREE_CODE (init) == TREE_LIST)
        {
@@ -310,13 +403,14 @@ perform_member_init (member, init, explicit)
     {
       tree expr;
 
-      expr = build_component_ref (current_class_ref, member, NULL_TREE,
-                                 explicit);
+      expr = build_class_member_access_expr (current_class_ref, member,
+                                            /*access_path=*/NULL_TREE,
+                                            /*preserve_reference=*/false);
       expr = build_delete (type, expr, sfk_complete_destructor,
                           LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
 
       if (expr != error_mark_node)
-       finish_subobject (expr);
+       finish_eh_cleanup (expr);
     }
 }
 
@@ -331,6 +425,8 @@ build_field_list (t, list, uses_unions_p)
 {
   tree fields;
 
+  *uses_unions_p = 0;
+
   /* Note whether or not T is a union.  */
   if (TREE_CODE (t) == UNION_TYPE)
     *uses_unions_p = 1;
@@ -338,7 +434,7 @@ build_field_list (t, list, uses_unions_p)
   for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields))
     {
       /* Skip CONST_DECLs for enumeration constants and so forth.  */
-      if (TREE_CODE (fields) != FIELD_DECL)
+      if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
        continue;
       
       /* Keep track of whether or not any fields are unions.  */
@@ -365,79 +461,107 @@ build_field_list (t, list, uses_unions_p)
   return list;
 }
 
-/* The MEMBER_INIT_LIST is a TREE_LIST.  The TREE_PURPOSE of each list
-   gives a FIELD_DECL in T that needs initialization.  The TREE_VALUE
-   gives the initializer, or list of initializer arguments.  Sort the
-   MEMBER_INIT_LIST, returning a version that contains the same
-   information but in the order that the fields should actually be
-   initialized.  Perform error-checking in the process.  */
+/* The MEM_INITS are a TREE_LIST.  The TREE_PURPOSE of each list gives
+   a FIELD_DECL or BINFO in T that needs initialization.  The
+   TREE_VALUE gives the initializer, or list of initializer arguments.
+
+   Return a TREE_LIST containing all of the initializations required
+   for T, in the order in which they should be performed.  The output
+   list has the same format as the input.  */
 
 static tree
-sort_member_init (t, member_init_list)
-     tree t;
-     tree member_init_list;
+sort_mem_initializers (tree t, tree mem_inits)
 {
-  tree init_list;
-  tree last_field;
   tree init;
+  tree base;
+  tree sorted_inits;
+  tree next_subobject;
+  int i;
   int uses_unions_p;
 
-  /* Build up a list of the various fields, in sorted order.  */
-  init_list = nreverse (build_field_list (t, NULL_TREE, &uses_unions_p));
-
-  /* Go through the explicit initializers, adding them to the
-     INIT_LIST.  */
-  last_field = init_list;
-  for (init = member_init_list; init; init = TREE_CHAIN (init))
-    {
-      tree f;
-      tree initialized_field;
-
-      initialized_field = TREE_PURPOSE (init);
-      my_friendly_assert (TREE_CODE (initialized_field) == FIELD_DECL,
-                         20000516);
-
-      /* If the explicit initializers are in sorted order, then the
-        INITIALIZED_FIELD will be for a field following the
-        LAST_FIELD.  */
-      for (f = last_field; f; f = TREE_CHAIN (f))
-       if (TREE_PURPOSE (f) == initialized_field)
+  /* Build up a list of initializations.  The TREE_PURPOSE of entry
+     will be the subobject (a FIELD_DECL or BINFO) to initialize.  The
+     TREE_VALUE will be the constructor arguments, or NULL if no
+     explicit initialization was provided.  */
+  sorted_inits = NULL_TREE;
+  /* Process the virtual bases.  */
+  for (base = CLASSTYPE_VBASECLASSES (t); base; base = TREE_CHAIN (base))
+    sorted_inits = tree_cons (TREE_VALUE (base), NULL_TREE, sorted_inits);
+  /* Process the direct bases.  */
+  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
+    {
+      base = BINFO_BASETYPE (TYPE_BINFO (t), i);
+      if (!TREE_VIA_VIRTUAL (base))
+       sorted_inits = tree_cons (base, NULL_TREE, sorted_inits);
+    }
+  /* Process the non-static data members.  */
+  sorted_inits = build_field_list (t, sorted_inits, &uses_unions_p);
+  /* Reverse the entire list of initializations, so that they are in
+     the order that they will actually be performed.  */
+  sorted_inits = nreverse (sorted_inits);
+
+  /* If the user presented the initializers in an order different from
+     that in which they will actually occur, we issue a warning.  Keep
+     track of the next subobject which can be explicitly initialized
+     without issuing a warning.  */
+  next_subobject = sorted_inits;
+
+  /* Go through the explicit initializers, filling in TREE_PURPOSE in
+     the SORTED_INITS.  */
+  for (init = mem_inits; init; init = TREE_CHAIN (init))
+    {
+      tree subobject;
+      tree subobject_init;
+
+      subobject = TREE_PURPOSE (init);
+
+      /* If the explicit initializers are in sorted order, then
+        SUBOBJECT will be NEXT_SUBOBJECT, or something following 
+        it.  */
+      for (subobject_init = next_subobject; 
+          subobject_init; 
+          subobject_init = TREE_CHAIN (subobject_init))
+       if (TREE_PURPOSE (subobject_init) == subobject)
          break;
 
-      /* Give a warning, if appropriate.  */
-      if (warn_reorder && !f)
+      /* Issue a warning if the explicit initializer order does not
+        match that which will actually occur.  */
+      if (warn_reorder && !subobject_init)
        {
-         cp_warning_at ("member initializers for `%#D'", 
-                        TREE_PURPOSE (last_field));
-         cp_warning_at ("  and `%#D'", initialized_field);
-         warning ("  will be re-ordered to match declaration order");
+         if (TREE_CODE (TREE_PURPOSE (next_subobject)) == FIELD_DECL)
+           cp_warning_at ("`%D' will be initialized after",
+                          TREE_PURPOSE (next_subobject));
+         else
+           warning ("base `%T' will be initialized after",
+                    TREE_PURPOSE (next_subobject));
+         if (TREE_CODE (subobject) == FIELD_DECL)
+           cp_warning_at ("  `%#D'", subobject);
+         else
+           warning ("  base `%T'", subobject);
        }
 
-      /* Look again, from the beginning of the list.  We must find the
-        field on this loop.  */
-      if (!f)
+      /* Look again, from the beginning of the list.  */
+      if (!subobject_init)
        {
-         f = init_list;
-         while (TREE_PURPOSE (f) != initialized_field)
-           f = TREE_CHAIN (f);
+         subobject_init = sorted_inits;
+         while (TREE_PURPOSE (subobject_init) != subobject)
+           subobject_init = TREE_CHAIN (subobject_init);
        }
-
-      /* If there was already an explicit initializer for this field,
-        issue an error.  */
-      if (TREE_TYPE (f))
-       cp_error ("multiple initializations given for member `%D'",
-                 initialized_field);
-      else
+       
+      /* It is invalid to initialize the same subobject more than
+        once.  */
+      if (TREE_VALUE (subobject_init))
        {
-         /* Mark the field as explicitly initialized.  */
-         TREE_TYPE (f) = error_mark_node;
-         /* And insert the initializer.  */
-         TREE_VALUE (f) = TREE_VALUE (init);
+         if (TREE_CODE (subobject) == FIELD_DECL)
+           error ("multiple initializations given for `%D'", subobject);
+         else
+           error ("multiple initializations given for base `%T'", 
+                  subobject);
        }
 
-      /* Remember the location of the last explicitly initialized
-        field.  */
-      last_field = f;
+      /* Record the initialization.  */
+      TREE_VALUE (subobject_init) = TREE_VALUE (init);
+      next_subobject = subobject_init;
     }
 
   /* [class.base.init]
@@ -447,15 +571,16 @@ sort_member_init (t, member_init_list)
      anonymous unions), the ctor-initializer is ill-formed.  */
   if (uses_unions_p)
     {
-      last_field = NULL_TREE;
-      for (init = init_list; init; init = TREE_CHAIN (init))
+      tree last_field = NULL_TREE;
+      for (init = sorted_inits; init; init = TREE_CHAIN (init))
        {
          tree field;
          tree field_type;
          int done;
 
-         /* Skip uninitialized members.  */
-         if (!TREE_TYPE (init))
+         /* Skip uninitialized members and base classes.  */
+         if (!TREE_VALUE (init) 
+             || TREE_CODE (TREE_PURPOSE (init)) != FIELD_DECL)
            continue;
          /* See if this field is a member of a union, or a member of a
             structure contained in a union, etc.  */
@@ -497,7 +622,7 @@ sort_member_init (t, member_init_list)
                  if (same_type_p (last_field_type, field_type))
                    {
                      if (TREE_CODE (field_type) == UNION_TYPE)
-                       cp_error ("initializations for multiple members of `%T'",
+                       error ("initializations for multiple members of `%T'",
                                  last_field_type);
                      done = 1;
                      break;
@@ -522,231 +647,73 @@ sort_member_init (t, member_init_list)
        }
     }
 
-  return init_list;
-}
-
-/* Like sort_member_init, but used for initializers of base classes.
-   *RBASE_PTR is filled in with the initializers for non-virtual bases;
-   vbase_ptr gets the virtual bases.  */
-
-static void
-sort_base_init (t, base_init_list, rbase_ptr, vbase_ptr)
-     tree t;
-     tree base_init_list;
-     tree *rbase_ptr, *vbase_ptr;
-{
-  tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
-  int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-  int i;
-  tree x;
-  tree last;
-
-  /* For warn_reorder.  */
-  int last_pos = 0;
-  tree last_base = NULL_TREE;
-
-  tree rbases = NULL_TREE;
-  tree vbases = NULL_TREE;
-
-  /* First walk through and splice out vbase and invalid initializers.
-     Also replace types with binfos.  */
-
-  last = tree_cons (NULL_TREE, NULL_TREE, base_init_list);
-  for (x = TREE_CHAIN (last); x; x = TREE_CHAIN (x))
-    {
-      tree basetype = TREE_PURPOSE (x);
-      tree binfo = (TREE_CODE (basetype) == TREE_VEC
-                   ? basetype : binfo_or_else (basetype, t));
-      
-      if (binfo == NULL_TREE)
-       /* BASETYPE might be an inaccessible direct base (because it
-          is also an indirect base).  */
-       continue;
-
-      if (TREE_VIA_VIRTUAL (binfo))
-       {
-         /* Virtual base classes are special cases.  Their
-            initializers are recorded with this constructor, and they
-            are used when this constructor is the top-level
-            constructor called.  */
-         tree v = binfo_for_vbase (BINFO_TYPE (binfo), t);
-         vbases = tree_cons (v, TREE_VALUE (x), vbases);
-       }
-      else
-       {
-         /* Otherwise, it must be an immediate base class.  */
-         my_friendly_assert
-           (same_type_p (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo)),
-                         t), 20011113);
-
-         TREE_PURPOSE (x) = binfo;
-         TREE_CHAIN (last) = x;
-         last = x;
-       }
-    }
-  TREE_CHAIN (last) = NULL_TREE;
-
-  /* Now walk through our regular bases and make sure they're initialized.  */
-
-  for (i = 0; i < n_baseclasses; ++i)
-    {
-      /* The base for which we're currently initializing.  */
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      /* The initializer for BASE_BINFO.  */
-      tree init;
-      int pos;
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       continue;
-
-      /* We haven't found the BASE_BINFO yet.  */
-      init = NULL_TREE;
-      /* Loop through all the explicitly initialized bases, looking
-        for an appropriate initializer.  */
-      for (x = base_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos)
-       {
-         tree binfo = TREE_PURPOSE (x);
-
-         if (binfo == base_binfo && !init)
-           {
-             if (warn_reorder)
-               {
-                 if (pos < last_pos)
-                   {
-                     cp_warning_at ("base initializers for `%#T'", last_base);
-                     cp_warning_at ("  and `%#T'", BINFO_TYPE (binfo));
-                     warning ("  will be re-ordered to match inheritance order");
-                   }
-                 last_pos = pos;
-                 last_base = BINFO_TYPE (binfo);
-               }
-
-             /* Make sure we won't try to work on this init again.  */
-             TREE_PURPOSE (x) = NULL_TREE;
-             init = build_tree_list (binfo, TREE_VALUE (x));
-           }
-         else if (binfo == base_binfo)
-           {
-             cp_error ("base class `%T' already initialized", 
-                       BINFO_TYPE (binfo));
-             break;
-           }
-       }
-
-      /* If we didn't find BASE_BINFO in the list, create a dummy entry
-        so the two lists (RBASES and the list of bases) will be
-        symmetrical.  */
-      if (!init)
-       init = build_tree_list (NULL_TREE, NULL_TREE);
-      rbases = chainon (rbases, init);
-    }
-
-  *rbase_ptr = rbases;
-  *vbase_ptr = vbases;
+  return sorted_inits;
 }
 
-/* Perform whatever initializations have yet to be done on the base
-   class, and non-static data members, of the CURRENT_CLASS_TYPE.
-   These actions are given by the BASE_INIT_LIST and MEM_INIT_LIST,
-   respectively.
-
-   If there is a need for a call to a constructor, we must surround
-   that call with a pushlevel/poplevel pair, since we are technically
-   at the PARM level of scope.  */
+/* Initialize all bases and members of CURRENT_CLASS_TYPE.  MEM_INITS
+   is a TREE_LIST giving the explicit mem-initializer-list for the
+   constructor.  The TREE_PURPOSE of each entry is a subobject (a
+   FIELD_DECL or a BINFO) of the CURRENT_CLASS_TYPE.  The TREE_VALUE
+   is a TREE_LIST giving the arguments to the constructor or
+   void_type_node for an empty list of arguments.  */
 
 void
-emit_base_init (mem_init_list, base_init_list)
-     tree mem_init_list;
-     tree base_init_list;
+emit_mem_initializers (tree mem_inits)
 {
-  tree member;
-  tree rbase_init_list, vbase_init_list;
-  tree t = current_class_type;
-  tree t_binfo = TYPE_BINFO (t);
-  tree binfos = BINFO_BASETYPES (t_binfo);
-  int i;
-  int n_baseclasses = BINFO_N_BASETYPES (t_binfo);
-
-  mem_init_list = sort_member_init (t, mem_init_list);
-  sort_base_init (t, base_init_list, &rbase_init_list, &vbase_init_list);
-
-  /* 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));
-      construct_virtual_bases (t, current_class_ref, current_class_ptr,
-                              vbase_init_list, first_arg);
-    }
-
-  /* Now, perform initialization of non-virtual base classes.  */
-  for (i = 0; i < n_baseclasses; i++)
-    {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      tree init = void_list_node;
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       continue;
-
-      my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo,
-                         999);
-
-      if (TREE_PURPOSE (rbase_init_list))
-       init = TREE_VALUE (rbase_init_list);
-      else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo)))
-       {
-         init = NULL_TREE;
-         if (extra_warnings 
-             && DECL_COPY_CONSTRUCTOR_P (current_function_decl))
-           cp_warning ("base class `%#T' should be explicitly initialized in the copy constructor",
-                       BINFO_TYPE (base_binfo));
-       }
-
-      if (init != void_list_node)
+  /* Sort the mem-initializers into the order in which the
+     initializations should be performed.  */
+  mem_inits = sort_mem_initializers (current_class_type, mem_inits);
+
+  /* Initialize base classes.  */
+  while (mem_inits 
+        && TREE_CODE (TREE_PURPOSE (mem_inits)) != FIELD_DECL)
+    {
+      tree subobject = TREE_PURPOSE (mem_inits);
+      tree arguments = TREE_VALUE (mem_inits);
+
+      /* If these initializations are taking place in a copy
+        constructor, the base class should probably be explicitly
+        initialized.  */
+      if (extra_warnings && !arguments 
+         && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
+         && TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (subobject)))
+       warning ("base class `%#T' should be explicitly initialized in the "
+                "copy constructor",
+                BINFO_TYPE (subobject));
+
+      /* If an explicit -- but empty -- initializer list was present,
+        treat it just like default initialization at this point.  */
+      if (arguments == void_type_node)
+       arguments = NULL_TREE;
+
+      /* Initialize the base.  */
+      if (TREE_VIA_VIRTUAL (subobject))
+       construct_virtual_base (subobject, arguments);
+      else
        {
-         member = build_base_path (PLUS_EXPR, current_class_ptr,
-                                   base_binfo, 1);
-         expand_aggr_init_1 (base_binfo, NULL_TREE,
-                             build_indirect_ref (member, NULL), init,
+         tree base_addr;
+         
+         base_addr = build_base_path (PLUS_EXPR, current_class_ptr,
+                                      subobject, 1);
+         expand_aggr_init_1 (subobject, NULL_TREE,
+                             build_indirect_ref (base_addr, NULL), 
+                             arguments,
                              LOOKUP_NORMAL);
+         expand_cleanup_for_base (subobject, NULL_TREE);
        }
 
-      expand_cleanup_for_base (base_binfo, NULL_TREE);
-      rbase_init_list = TREE_CHAIN (rbase_init_list);
+      mem_inits = TREE_CHAIN (mem_inits);
     }
 
-  /* Initialize the vtable pointers for the class.  */
+  /* Initialize the vptrs.  */
   initialize_vtbl_ptrs (current_class_ptr);
 
-  while (mem_init_list)
+  /* Initialize the data members.  */
+  while (mem_inits)
     {
-      tree init;
-      tree member;
-      int from_init_list;
-
-      member = TREE_PURPOSE (mem_init_list);
-
-      /* See if we had a user-specified member initialization.  */
-      if (TREE_TYPE (mem_init_list))
-       {
-         init = TREE_VALUE (mem_init_list);
-         from_init_list = 1;
-       }
-      else
-       {
-         init = DECL_INITIAL (member);
-         from_init_list = 0;
-
-         /* Effective C++ rule 12.  */
-         if (warn_ecpp && init == NULL_TREE
-             && !DECL_ARTIFICIAL (member)
-             && TREE_CODE (TREE_TYPE (member)) != ARRAY_TYPE)
-           cp_warning ("`%D' should be initialized in the member initialization list", member);            
-       }
-
-      perform_member_init (member, init, from_init_list);
-      mem_init_list = TREE_CHAIN (mem_init_list);
+      perform_member_init (TREE_PURPOSE (mem_inits),
+                          TREE_VALUE (mem_inits));
+      mem_inits = TREE_CHAIN (mem_inits);
     }
 }
 
@@ -843,7 +810,7 @@ expand_virtual_init (binfo, decl)
 /* 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
+   it is a DECL which is nonzero when this base needs to be
    destroyed.  */
 
 static void
@@ -857,99 +824,70 @@ expand_cleanup_for_base (binfo, flag)
     return;
 
   /* Call the destructor.  */
-  expr = (build_scoped_method_call
-         (current_class_ref, binfo, base_dtor_identifier, NULL_TREE));
+  expr = build_special_member_call (current_class_ref, 
+                                   base_dtor_identifier,
+                                   NULL_TREE,
+                                   binfo,
+                                   LOOKUP_NORMAL | LOOKUP_NONVIRTUAL);
   if (flag)
     expr = fold (build (COND_EXPR, void_type_node,
-                       truthvalue_conversion (flag),
+                       c_common_truthvalue_conversion (flag),
                        expr, integer_zero_node));
 
-  finish_subobject (expr);
+  finish_eh_cleanup (expr);
 }
 
-/* Subroutine of `expand_aggr_vbase_init'.
-   BINFO is the binfo of the type that is being initialized.
-   INIT_LIST is the list of initializers for the virtual baseclass.  */
+/* Construct the virtual base-class VBASE passing the ARGUMENTS to its
+   constructor.  */
 
 static void
-expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
-     tree binfo, exp, addr, init_list;
+construct_virtual_base (tree vbase, tree arguments)
 {
-  tree init = purpose_member (binfo, init_list);
-  tree ref = build_indirect_ref (addr, NULL);
-
-  if (init)
-    init = TREE_VALUE (init);
-  /* Call constructors, but don't set up vtables.  */
-  expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
-}
-
-/* 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 initializations for constructors to perform.  */
-
-static void
-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 vbases;
-
-  /* If there are no virtual baseclasses, we shouldn't even be here.  */
-  my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621);
-
-  /* Now, run through the baseclasses, initializing each.  */ 
-  for (vbases = CLASSTYPE_VBASECLASSES (type); vbases;
-       vbases = TREE_CHAIN (vbases))
-    {
-      tree inner_if_stmt;
-      tree compound_stmt;
-      tree exp;
-      tree vbase;
-
-      /* 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);
-
-      /* Compute the location of the virtual base.  If we're
-        constructing virtual bases, then we must be the most derived
-        class.  Therefore, we don't have to look up the virtual base;
-        we already know where it is.  */
-      vbase = TREE_VALUE (vbases);
-      exp = build (PLUS_EXPR,
-                  TREE_TYPE (this_ptr),
-                  this_ptr,
-                  fold (build1 (NOP_EXPR, TREE_TYPE (this_ptr),
-                                BINFO_OFFSET (vbase))));
-      exp = build1 (NOP_EXPR, 
-                   build_pointer_type (BINFO_TYPE (vbase)), 
-                   exp);
-
-      expand_aggr_vbase_init_1 (vbase, this_ref, exp, init_list);
-      finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
-      finish_then_clause (inner_if_stmt);
-      finish_if_stmt ();
-      
-      expand_cleanup_for_base (vbase, flag);
-    }
+  tree inner_if_stmt;
+  tree compound_stmt;
+  tree exp;
+  tree flag;  
+
+  /* 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.  */
+  flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
+  inner_if_stmt = begin_if_stmt ();
+  finish_if_stmt_cond (flag, inner_if_stmt);
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
+
+  /* Compute the location of the virtual base.  If we're
+     constructing virtual bases, then we must be the most derived
+     class.  Therefore, we don't have to look up the virtual base;
+     we already know where it is.  */
+  exp = build (PLUS_EXPR,
+              TREE_TYPE (current_class_ptr),
+              current_class_ptr,
+              fold (build1 (NOP_EXPR, TREE_TYPE (current_class_ptr),
+                            BINFO_OFFSET (vbase))));
+  exp = build1 (NOP_EXPR, 
+               build_pointer_type (BINFO_TYPE (vbase)), 
+               exp);
+  exp = build1 (INDIRECT_REF, BINFO_TYPE (vbase), exp);
+
+  expand_aggr_init_1 (vbase, current_class_ref, exp,
+                     arguments, LOOKUP_COMPLAIN);
+  finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+  finish_then_clause (inner_if_stmt);
+  finish_if_stmt ();
+
+  expand_cleanup_for_base (vbase, flag);
 }
 
 /* Find the context in which this FIELD can be initialized.  */
@@ -982,110 +920,120 @@ member_init_ok_or_else (field, type, member_name)
 {
   if (field == error_mark_node)
     return 0;
-  if (field == NULL_TREE || initializing_context (field) != type)
+  if (!field)
     {
-      cp_error ("class `%T' does not have any field named `%D'", type,
-               member_name);
+      error ("class `%T' does not have any field named `%D'", type,
+            member_name);
+      return 0;
+    }
+  if (TREE_CODE (field) == VAR_DECL)
+    {
+      error ("`%#D' is a static data member; it can only be "
+            "initialized at its definition",
+            field);
+      return 0;
+    }
+  if (TREE_CODE (field) != FIELD_DECL)
+    {
+      error ("`%#D' is not a non-static data member of `%T'",
+            field, type);
       return 0;
     }
-  if (TREE_STATIC (field))
+  if (initializing_context (field) != type)
     {
-      cp_error ("field `%#D' is static; the only point of initialization is its definition",
-               field);
+      error ("class `%T' does not have any field named `%D'", type,
+               member_name);
       return 0;
     }
 
   return 1;
 }
 
-/* EXP is an expression of aggregate type. NAME is an IDENTIFIER_NODE
-   which names a field, or it is a _TYPE node or TYPE_DECL which names
-   a base for that type.  INIT is a parameter list for that field's or
-   base's constructor.  Check the validity of NAME, and return a
-   TREE_LIST of the base _TYPE or FIELD_DECL and the INIT. EXP is used
-   only to get its type.  If NAME is invalid, return NULL_TREE and
-   issue a diagnostic.
+/* NAME is a FIELD_DECL, an IDENTIFIER_NODE which names a field, or it
+   is a _TYPE node or TYPE_DECL which names a base for that type.
+   INIT is a parameter list for that field's or base's constructor.
+   Check the validity of NAME, and return a TREE_LIST of the base
+   _TYPE or FIELD_DECL and the INIT.  If NAME is invalid, return
+   NULL_TREE and issue a diagnostic.
 
    An old style unnamed direct single base construction is permitted,
    where NAME is NULL.  */
 
 tree
-expand_member_init (exp, name, init)
-     tree exp, name, init;
+expand_member_init (tree name, tree init)
 {
-  tree basetype = NULL_TREE, field;
-  tree type;
+  tree basetype;
+  tree field;
 
-  if (exp == NULL_TREE)
+  if (!current_class_ref)
     return NULL_TREE;
 
-  type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
-  my_friendly_assert (IS_AGGR_TYPE (type), 20011113);
-
   if (!name)
     {
       /* This is an obsolete unnamed base class initializer.  The
         parser will already have warned about its use.  */
-      switch (CLASSTYPE_N_BASECLASSES (type))
+      switch (CLASSTYPE_N_BASECLASSES (current_class_type))
        {
        case 0:
-         cp_error ("unnamed initializer for `%T', which has no base classes",
-                   type);
+         error ("unnamed initializer for `%T', which has no base classes",
+                current_class_type);
          return NULL_TREE;
        case 1:
-         basetype = TYPE_BINFO_BASETYPE (type, 0);
+         basetype = TYPE_BINFO_BASETYPE (current_class_type, 0);
          break;
        default:
-         cp_error ("unnamed initializer for `%T', which uses multiple inheritance",
-                   type);
+         error ("unnamed initializer for `%T', which uses multiple inheritance",
+                current_class_type);
          return NULL_TREE;
       }
     }
   else if (TYPE_P (name))
     {
-      basetype = name;
+      basetype = TYPE_MAIN_VARIANT (name);
       name = TYPE_NAME (name);
     }
   else if (TREE_CODE (name) == TYPE_DECL)
     basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
+  else
+    basetype = NULL_TREE;
 
   my_friendly_assert (init != NULL_TREE, 0);
 
-  if (init == void_type_node)
-    init = NULL_TREE;
-
   if (basetype)
     {
+      tree binfo;
+
       if (current_template_parms)
-       ;
-      else if (vec_binfo_member (basetype, TYPE_BINFO_BASETYPES (type)))
-       /* A direct base.  */;
-      else if (binfo_for_vbase (basetype, type))
-       /* A virtual base.  */;
-      else
+       return build_tree_list (basetype, init);
+
+      binfo = lookup_base (current_class_type, basetype, 
+                          ba_ignore, NULL);
+      if (!binfo || (!TREE_VIA_VIRTUAL (binfo)
+                    && (BINFO_INHERITANCE_CHAIN (binfo)
+                        != TYPE_BINFO (current_class_type))))
        {
-         if (TYPE_USES_VIRTUAL_BASECLASSES (type))
-           cp_error ("type `%D' is not a direct or virtual base of `%T'",
-                     name, type);
+         if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+           error ("type `%D' is not a direct or virtual base of `%T'",
+                  name, current_class_type);
          else
-           cp_error ("type `%D' is not a direct base of `%T'",
-                     name, type);
+           error ("type `%D' is not a direct base of `%T'",
+                  name, current_class_type);
          return NULL_TREE;
        }
-
-      init = build_tree_list (basetype, init);
+      return build_tree_list (binfo, init);
     }
   else
     {
-      field = lookup_field (type, name, 1, 0);
-
-      if (! member_init_ok_or_else (field, type, name))
-       return NULL_TREE;
+      if (TREE_CODE (name) == IDENTIFIER_NODE)
+       field = lookup_field (current_class_type, name, 1, false);
+      else
+       field = name;
 
-      init = build_tree_list (field, init);
+      if (member_init_ok_or_else (field, current_class_type, name))
+       return build_tree_list (field, init);
     }
 
-  return init;
+  return NULL_TREE;
 }
 
 /* This is like `expand_member_init', only it stores one aggregate
@@ -1109,8 +1057,6 @@ expand_member_init (exp, name, init)
    The virtual function table pointer cannot be set up here, because
    we do not really know its type.
 
-   Virtual baseclass pointers are also set up here.
-
    This never calls operator=().
 
    When initializing, nothing is CONST.
@@ -1162,16 +1108,14 @@ build_aggr_init (exp, init, flags)
               COMPLEX zees(1.0, 0.0)[10];
             }
          */
-         cp_error ("bad array initializer");
+         error ("bad array initializer");
          return error_mark_node;
        }
       if (cp_type_quals (type) != TYPE_UNQUALIFIED)
-       {
-         TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
-         if (init)
-           TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
-       }
-      stmt_expr = build_vec_init (exp, init,
+       TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
+      if (itype && cp_type_quals (itype) != TYPE_UNQUALIFIED)
+       TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
+      stmt_expr = build_vec_init (exp, NULL_TREE, init,
                                  init && same_type_p (TREE_TYPE (init),
                                                       TREE_TYPE (exp)));
       TREE_READONLY (exp) = was_const;
@@ -1201,6 +1145,24 @@ build_aggr_init (exp, init, flags)
   return stmt_expr;
 }
 
+/* Like build_aggr_init, but not just for aggregates.  */
+
+tree
+build_init (decl, init, flags)
+     tree decl, init;
+     int flags;
+{
+  tree expr;
+
+  if (IS_AGGR_TYPE (TREE_TYPE (decl))
+      || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+    expr = build_aggr_init (decl, init, flags);
+  else
+    expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
+
+  return expr;
+}
+
 static void
 expand_default_init (binfo, true_exp, exp, init, flags)
      tree binfo;
@@ -1233,20 +1195,26 @@ expand_default_init (binfo, true_exp, exp, init, flags)
           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 if (TREE_CODE (init) == CONSTRUCTOR 
+              && TREE_HAS_CONSTRUCTOR (init))
+       {
+         /* A brace-enclosed initializer for an aggregate.  */
+         my_friendly_assert (CP_AGGREGATE_TYPE_P (type), 20021016);
+         init = digest_init (type, init, (tree *)NULL);
+       }
       else
        init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
 
-      if (TREE_CODE (init) == TRY_CATCH_EXPR)
-       /* We need to protect the initialization of a catch parm
-          with a call to terminate(), which shows up as a TRY_CATCH_EXPR
+      if (TREE_CODE (init) == MUST_NOT_THROW_EXPR)
+       /* We need to protect the initialization of a catch parm with a
+          call to terminate(), which shows up as a MUST_NOT_THROW_EXPR
           around the TARGET_EXPR for the copy constructor.  See
-          expand_start_catch_block.  */
-       TREE_OPERAND (init, 0) = build (INIT_EXPR, TREE_TYPE (exp), exp,
-                                       TREE_OPERAND (init, 0));
+          initialize_handler_parm.  */
+       {
+         TREE_OPERAND (init, 0) = build (INIT_EXPR, TREE_TYPE (exp), exp,
+                                         TREE_OPERAND (init, 0));
+         TREE_TYPE (init) = void_type_node;
+       }
       else
        init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
       TREE_SIDE_EFFECTS (init) = 1;
@@ -1269,7 +1237,7 @@ expand_default_init (binfo, true_exp, exp, init, flags)
   else
     ctor_name = base_ctor_identifier;
 
-  rval = build_method_call (exp, ctor_name, parms, binfo, flags);
+  rval = build_special_member_call (exp, ctor_name, parms, binfo, flags);
   if (TREE_SIDE_EFFECTS (rval))
     {
       if (building_stmt_tree ())
@@ -1309,6 +1277,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
   tree type = TREE_TYPE (exp);
 
   my_friendly_assert (init != error_mark_node && type != error_mark_node, 211);
+  my_friendly_assert (building_stmt_tree (), 20021010);
 
   /* Use a function returning the desired type to initialize EXP for us.
      If the function is a constructor, and its first argument is
@@ -1323,12 +1292,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
       /* 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))
-       {
-         if (!building_stmt_tree ())
-           expand_decl_init (exp);
-       }
-      else
+      if (store_init_value (exp, init))
        finish_expr_stmt (build (INIT_EXPR, type, exp, init));
       return;
     }
@@ -1354,7 +1318,7 @@ is_aggr_type (type, or_else)
       && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
     {
       if (or_else)
-       cp_error ("`%T' is not an aggregate type", type);
+       error ("`%T' is not an aggregate type", type);
       return 0;
     }
   return 1;
@@ -1377,7 +1341,7 @@ get_aggr_from_typedef (name, or_else)
   else
     {
       if (or_else)
-       cp_error ("`%T' fails to be an aggregate typedef", name);
+       error ("`%T' fails to be an aggregate typedef", name);
       return NULL_TREE;
     }
 
@@ -1386,7 +1350,7 @@ get_aggr_from_typedef (name, or_else)
       && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
     {
       if (or_else)
-       cp_error ("type `%T' is of non-aggregate type", type);
+       error ("type `%T' is of non-aggregate type", type);
       return NULL_TREE;
     }
   return type;
@@ -1418,6 +1382,7 @@ build_member_call (type, name, parmlist)
 {
   tree t;
   tree method_name;
+  tree fns;
   int dtor = 0;
   tree basetype_path, decl;
 
@@ -1438,15 +1403,16 @@ build_member_call (type, name, parmlist)
          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);
+      return finish_call_expr (name, parmlist, /*disallow_virtual=*/true);
     }
 
   if (DECL_P (name))
     name = DECL_NAME (name);
 
   if (TREE_CODE (type) == NAMESPACE_DECL)
-    return build_x_function_call (lookup_namespace_name (type, name),
-                                 parmlist, current_class_ref);
+    return finish_call_expr (lookup_namespace_name (type, name),
+                            parmlist,
+                            /*disallow_virtual=*/true);
 
   if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
     {
@@ -1473,10 +1439,9 @@ build_member_call (type, name, parmlist)
     {
       tree ns = lookup_name (type, 0);
       if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
-       {
-         return build_x_function_call (build_offset_ref (type, name),
-                                       parmlist, current_class_ref);
-       }
+       return finish_call_expr (lookup_namespace_name (ns, name),
+                                parmlist,
+                                /*disallow_virtual=*/true);
     }
 
   if (type == NULL_TREE || ! is_aggr_type (type, 1))
@@ -1488,41 +1453,43 @@ build_member_call (type, name, parmlist)
 
   if (dtor)
     {
-      cp_error ("cannot call destructor `%T::~%T' without object", type,
+      error ("cannot call destructor `%T::~%T' without object", type,
                method_name);
       return error_mark_node;
     }
 
   decl = maybe_dummy_object (type, &basetype_path);
 
+  fns = lookup_fnfields (basetype_path, method_name, 0);
+  if (fns)
+    {
+      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+       BASELINK_FUNCTIONS (fns) = build_nt (TEMPLATE_ID_EXPR,
+                                            BASELINK_FUNCTIONS (fns),
+                                            TREE_OPERAND (name, 1));
+      return build_new_method_call (decl, fns, parmlist,
+                                   /*conversion_path=*/NULL_TREE,
+                                   LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
+    }
+
   /* Convert 'this' to the specified type to disambiguate conversion
-     to the function's context.  Apparently Standard C++ says that we
-     shouldn't do this.  */
+     to the function's context.  */
   if (decl == current_class_ref
-      && ! pedantic
+      /* ??? this is wrong, but if this conversion is invalid we need to
+        defer it until we know whether we are calling a static or
+        non-static member function.  Be conservative for now.  */
       && 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_qualified_type (type, TYPE_QUALS (oldtype));
-         decl = convert_force (build_pointer_type (newtype), olddecl, 0);
-         decl = build_indirect_ref (decl, NULL);
-       }
+      basetype_path = NULL_TREE;
+      decl = build_scoped_ref (decl, type, &basetype_path);
+      if (decl == error_mark_node)
+       return error_mark_node;
     }
 
-  if (method_name == constructor_name (type)
-      || method_name == constructor_name_full (type))
+  if (constructor_name_p (method_name, type))
     return build_functional_cast (type, parmlist);
-  if (lookup_fnfields (basetype_path, method_name, 0))
-    return build_method_call (decl, 
-                             TREE_CODE (name) == TEMPLATE_ID_EXPR
-                             ? name : method_name,
-                             parmlist, basetype_path,
-                             LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
   if (TREE_CODE (name) == IDENTIFIER_NODE
-      && ((t = lookup_field (TYPE_BINFO (type), name, 1, 0))))
+      && ((t = lookup_field (TYPE_BINFO (type), name, 1, false))))
     {
       if (t == error_mark_node)
        return error_mark_node;
@@ -1530,7 +1497,7 @@ build_member_call (type, name, parmlist)
        {
          if (is_dummy_object (decl))
            {
-             cp_error ("invalid use of non-static field `%D'", t);
+             error ("invalid use of non-static field `%D'", t);
              return error_mark_node;
            }
          decl = build (COMPONENT_REF, TREE_TYPE (t), decl, t);
@@ -1539,17 +1506,17 @@ build_member_call (type, name, parmlist)
        decl = t;
       else
        {
-         cp_error ("invalid use of member `%D'", t);
+         error ("invalid use of member `%D'", t);
          return error_mark_node;
        }
       if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl)))
-       return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, decl,
-                              parmlist, NULL_TREE);
+       return build_new_op (CALL_EXPR, LOOKUP_NORMAL, decl,
+                            parmlist, NULL_TREE);
       return build_function_call (decl, parmlist);
     }
   else
     {
-      cp_error ("no method `%T::%D'", type, name);
+      error ("no method `%T::%D'", type, name);
       return error_mark_node;
     }
 }
@@ -1634,7 +1601,7 @@ build_offset_ref (type, name)
   if (TREE_CODE (name) == BIT_NOT_EXPR)
     {
       if (! check_dtor_name (type, name))
-       cp_error ("qualified type `%T' does not match destructor name `~%T'",
+       error ("qualified type `%T' does not match destructor name `~%T'",
                  type, TREE_OPERAND (name, 0));
       name = dtor_identifier;
     }
@@ -1642,24 +1609,29 @@ build_offset_ref (type, name)
   if (!COMPLETE_TYPE_P (complete_type (type))
       && !TYPE_BEING_DEFINED (type))
     {
-      cp_error ("incomplete type `%T' does not have member `%D'", type,
+      error ("incomplete type `%T' does not have member `%D'", type,
                name);
       return error_mark_node;
     }
 
   decl = maybe_dummy_object (type, &basebinfo);
 
-  member = lookup_member (basebinfo, name, 1, 0);
-
-  if (member == error_mark_node)
-    return error_mark_node;
+  if (BASELINK_P (name) || DECL_P (name))
+    member = name;
+  else
+    {
+      member = lookup_member (basebinfo, name, 1, 0);
+      
+      if (member == error_mark_node)
+       return error_mark_node;
+    }
 
   /* A lot of this logic is now handled in lookup_member.  */
   if (member && BASELINK_P (member))
     {
       /* Go from the TREE_BASELINK to the member function info.  */
       tree fnfields = member;
-      t = TREE_VALUE (fnfields);
+      t = BASELINK_FUNCTIONS (fnfields);
 
       if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
        {
@@ -1684,7 +1656,7 @@ build_offset_ref (type, name)
          return t;
        }
 
-      if (!really_overloaded_fn (t))
+      if (TREE_CODE (t) != TEMPLATE_ID_EXPR && !really_overloaded_fn (t))
        {
          /* Get rid of a potential OVERLOAD around it */
          t = OVL_CURRENT (t);
@@ -1711,7 +1683,7 @@ build_offset_ref (type, name)
 
   if (t == NULL_TREE)
     {
-      cp_error ("`%D' is not a member of type `%T'", name, type);
+      error ("`%D' is not a member of type `%T'", name, type);
       return error_mark_node;
     }
 
@@ -1730,14 +1702,14 @@ build_offset_ref (type, name)
 
   if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t))
     {
-      cp_error ("illegal pointer to bit field `%D'", t);
+      error ("invalid pointer to bit-field `%D'", t);
       return error_mark_node;
     }
 
   /* static class functions too.  */
   if (TREE_CODE (t) == FUNCTION_DECL
       && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
-    my_friendly_abort (53);
+    abort ();
 
   /* In member functions, the form `type::name' is no longer
      equivalent to `this->type::name', at least not until
@@ -1796,7 +1768,7 @@ resolve_offset_ref (exp)
       || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE)
     {
       /* These were static members.  */
-      if (mark_addressable (member) == 0)
+      if (!cxx_mark_addressable (member))
        return error_mark_node;
       return member;
     }
@@ -1819,9 +1791,7 @@ resolve_offset_ref (exp)
   if (TREE_CODE (member) == FIELD_DECL
       && (base == current_class_ref || is_dummy_object (base)))
     {
-      tree expr;
-
-      basetype = DECL_CONTEXT (member);
+      tree binfo = NULL_TREE;
 
       /* Try to get to basetype from 'this'; if that doesn't work,
          nothing will.  */
@@ -1829,20 +1799,11 @@ resolve_offset_ref (exp)
 
       /* First convert to the intermediate base specified, if appropriate.  */
       if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
-       base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type));
-
-      /* Don't check access on the conversion; we might be after a member
-        promoted by an access- or using-declaration, and we have already
-        checked access for the member itself.  */
-      basetype = lookup_base (TREE_TYPE (base), basetype, ba_ignore, NULL);
-      expr = build_base_path (PLUS_EXPR, base, basetype, 1);
+       base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type), &binfo);
 
-      if (expr == error_mark_node)
-       return error_mark_node;
-
-      expr = build (COMPONENT_REF, TREE_TYPE (member),
-                   expr, member);
-      return convert_from_reference (expr);
+      return build_class_member_access_expr (base, member,
+                                            /*access_path=*/NULL_TREE,
+                                            /*preserve_reference=*/false);
     }
 
   /* Ensure that we have an object.  */
@@ -1859,7 +1820,7 @@ resolve_offset_ref (exp)
     {
       if (addr == error_mark_node)
        {
-         cp_error ("object missing in `%E'", exp);
+         error ("object missing in `%E'", exp);
          return error_mark_node;
        }
 
@@ -1870,15 +1831,14 @@ resolve_offset_ref (exp)
       
       member = cp_convert (ptrdiff_type_node, member);
 
-      return build1 (INDIRECT_REF, type,
-                    build (PLUS_EXPR, build_pointer_type (type),
-                           addr, member));
+      addr = build (PLUS_EXPR, build_pointer_type (type), addr, member);
+      return build_indirect_ref (addr, 0);
     }
   else if (TYPE_PTRMEMFUNC_P (TREE_TYPE (member)))
     {
       return get_member_function_from_ptrfunc (&addr, member);
     }
-  my_friendly_abort (56);
+  abort ();
   /* NOTREACHED */
   return NULL_TREE;
 }
@@ -1967,7 +1927,7 @@ build_new (placement, decl, init, use_global_new)
       nelts = integer_one_node;
 
       if (absdcl && TREE_CODE (absdcl) == CALL_EXPR)
-       my_friendly_abort (215);
+       abort ();
       while (absdcl && TREE_CODE (absdcl) == INDIRECT_REF)
        {
          last_absdcl = absdcl;
@@ -2000,7 +1960,7 @@ build_new (placement, decl, init, use_global_new)
              else
                {
                  if (build_expr_type_conversion (WANT_INT | WANT_ENUM, 
-                                                 this_nelts, 0)
+                                                 this_nelts, false)
                      == NULL_TREE)
                    pedwarn ("size in array new must have integral type");
 
@@ -2063,7 +2023,8 @@ build_new (placement, decl, init, use_global_new)
       else
        t = type;
        
-      rval = build_min_nt (NEW_EXPR, placement, t, init);
+      rval = build_min (NEW_EXPR, build_pointer_type (type), 
+                       placement, t, init);
       NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
       return rval;
     }
@@ -2112,7 +2073,7 @@ build_new (placement, decl, init, use_global_new)
   return rval;
 }
 
-/* Given a Java class, return a decl for the corresponding java.lang.Class. */
+/* Given a Java class, return a decl for the corresponding java.lang.Class.  */
 
 tree
 build_java_class_ref (type)
@@ -2195,17 +2156,16 @@ build_new_1 (exp)
   tree placement, init;
   tree type, true_type, size, rval, t;
   tree full_type;
+  tree outer_nelts = NULL_TREE;
   tree nelts = NULL_TREE;
   tree alloc_call, alloc_expr, alloc_node;
+  tree alloc_fn;
   tree cookie_expr, init_expr;
   int has_array = 0;
   enum tree_code code;
-  int use_cookie, nothrow, check_new;
+  int nothrow, check_new;
   /* Nonzero if the user wrote `::new' rather than just `new'.  */
   int globally_qualified_p;
-  /* Nonzero if we're going to call a global operator new, rather than
-     a class-specific version.  */
-  int use_global_new;
   int use_java_new = 0;
   /* If non-NULL, the number of extra bytes to allocate at the
      beginning of the storage allocated for an array-new expression in
@@ -2214,6 +2174,7 @@ build_new_1 (exp)
   /* True if the function we are calling is a placement allocation
      function.  */
   bool placement_allocation_fn_p;
+  tree args = NULL_TREE;
 
   placement = TREE_OPERAND (exp, 0);
   type = TREE_OPERAND (exp, 1);
@@ -2223,12 +2184,11 @@ build_new_1 (exp)
   if (TREE_CODE (type) == ARRAY_REF)
     {
       has_array = 1;
-      nelts = TREE_OPERAND (type, 1);
+      nelts = outer_nelts = TREE_OPERAND (type, 1);
       type = TREE_OPERAND (type, 0);
 
-      full_type = cp_build_binary_op (MINUS_EXPR, nelts, integer_one_node);
-      full_type = build_index_type (full_type);
-      full_type = build_cplus_array_type (type, full_type);
+      /* Use an incomplete array type to avoid VLA headaches.  */
+      full_type = build_cplus_array_type (type, NULL_TREE);
     }
   else
     full_type = type;
@@ -2249,10 +2209,6 @@ build_new_1 (exp)
   if (!complete_type_or_else (true_type, exp))
     return error_mark_node;
 
-  size = size_in_bytes (true_type);
-  if (has_array)
-    size = fold (cp_build_binary_op (MULT_EXPR, size, nelts));
-
   if (TREE_CODE (true_type) == VOID_TYPE)
     {
       error ("invalid type `void' for new");
@@ -2262,42 +2218,11 @@ build_new_1 (exp)
   if (abstract_virtuals_error (NULL_TREE, true_type))
     return error_mark_node;
 
-  /* Figure out whether or not we're going to use the global operator
-     new.  */
-  if (!globally_qualified_p
-      && IS_AGGR_TYPE (true_type)
-      && (has_array
-         ? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
-         : TYPE_HAS_NEW_OPERATOR (true_type)))
-    use_global_new = 0;
-  else
-    use_global_new = 1;
-
-  /* We only need cookies for arrays containing types for which we
-     need cookies.  */
-  if (!has_array || !TYPE_VEC_NEW_USES_COOKIE (true_type))
-    use_cookie = 0;
-  /* When using placement new, users may not realize that they need
-     the extra storage.  We require that the operator called be
-     the global placement operator delete[].  */
-  else if (placement && !TREE_CHAIN (placement) 
-          && same_type_p (TREE_TYPE (TREE_VALUE (placement)),
-                          ptr_type_node))
-    use_cookie = !use_global_new;
-  /* Otherwise, we need the cookie.  */
-  else
-    use_cookie = 1;
-
-  /* Compute the number of extra bytes to allocate, now that we know
-     whether or not we need the cookie.  */
-  if (use_cookie)
-    {
-      cookie_size = get_cookie_size (true_type);
-      size = size_binop (PLUS_EXPR, size, cookie_size);
-    }
+  size = size_in_bytes (true_type);
+  if (has_array)
+    size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
 
   /* Allocate the object.  */
-  
   if (! placement && TYPE_FOR_JAVA (true_type))
     {
       tree class_addr, alloc_decl;
@@ -2319,31 +2244,56 @@ build_new_1 (exp)
   else
     {
       tree fnname;
-      tree args;
 
-      args = tree_cons (NULL_TREE, size, placement);
       fnname = ansi_opname (code);
 
-      if (use_global_new)
-       alloc_call = (build_new_function_call 
-                     (lookup_function_nonclass (fnname, args),
-                      args));
+      if (!globally_qualified_p 
+         && CLASS_TYPE_P (true_type)
+         && (has_array
+             ? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
+             : TYPE_HAS_NEW_OPERATOR (true_type)))
+       {
+         /* Use a class-specific operator new.  */
+         /* If a cookie is required, add some extra space.  */
+         if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
+           {
+             cookie_size = get_cookie_size (true_type);
+             size = size_binop (PLUS_EXPR, size, cookie_size);
+           }
+         /* Create the argument list.  */
+         args = tree_cons (NULL_TREE, size, placement);
+         /* Call the function.  */
+         alloc_call = build_method_call (build_dummy_object (true_type),
+                                         fnname, args, 
+                                         TYPE_BINFO (true_type),
+                                         LOOKUP_NORMAL);
+       }
       else
-       alloc_call = build_method_call (build_dummy_object (true_type),
-                                       fnname, args, NULL_TREE,
-                                       LOOKUP_NORMAL);
+       {
+         /* Use a global operator new.  */
+         /* See if a cookie might be required.  */
+         if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
+           cookie_size = get_cookie_size (true_type);
+         else
+           cookie_size = NULL_TREE;
+
+         alloc_call = build_operator_new_call (fnname, placement, 
+                                               &size, &cookie_size);
+       }
     }
 
   if (alloc_call == error_mark_node)
     return error_mark_node;
 
-  /* The ALLOC_CALL should be a CALL_EXPR, and the first operand
-     should be the address of a known FUNCTION_DECL.  */
-  my_friendly_assert (TREE_CODE (alloc_call) == CALL_EXPR, 20000521);
-  t = TREE_OPERAND (alloc_call, 0);
-  my_friendly_assert (TREE_CODE (t) == ADDR_EXPR, 20000521);
-  t = TREE_OPERAND (t, 0);
-  my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL, 20000521);
+  /* The ALLOC_CALL should be a CALL_EXPR -- or a COMPOUND_EXPR whose
+     right-hand-side is ultimately a CALL_EXPR -- and the first
+     operand should be the address of a known FUNCTION_DECL.  */
+  t = alloc_call;
+  while (TREE_CODE (t) == COMPOUND_EXPR) 
+    t = TREE_OPERAND (t, 1);
+  alloc_fn = get_callee_fndecl (t);
+  my_friendly_assert (alloc_fn != NULL_TREE, 20020325);
+
   /* Now, check to see if this function is actually a placement
      allocation function.  This can happen even when PLACEMENT is NULL
      because we might have something like:
@@ -2355,7 +2305,8 @@ build_new_1 (exp)
      one argument, or there are variable arguments, then this is a
      placement allocation function.  */
   placement_allocation_fn_p 
-    = (type_num_arguments (TREE_TYPE (t)) > 1 || varargs_function_p (t));
+    = (type_num_arguments (TREE_TYPE (alloc_fn)) > 1 
+       || varargs_function_p (alloc_fn));
 
   /*        unless an allocation function is declared with an empty  excep-
      tion-specification  (_except.spec_),  throw(), it indicates failure to
@@ -2367,16 +2318,12 @@ build_new_1 (exp)
 
      So check for a null exception spec on the op new we just called.  */
 
-  /* The ADDR_EXPR.  */
-  t = TREE_OPERAND (alloc_call, 0);
-  /* The function.  */
-  t = TREE_OPERAND (t, 0);
-  nothrow = TYPE_NOTHROW_P (TREE_TYPE (t));
+  nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
   check_new = (flag_check_new || nothrow) && ! use_java_new;
 
   alloc_expr = alloc_call;
 
-  if (use_cookie)
+  if (cookie_size)
     /* Adjust so we're pointing to the start of the object.  */
     alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr),
                        alloc_expr, cookie_size);
@@ -2390,7 +2337,7 @@ build_new_1 (exp)
   alloc_node = TREE_OPERAND (alloc_expr, 0);
 
   /* Now initialize the cookie.  */
-  if (use_cookie)
+  if (cookie_size)
     {
       tree cookie;
 
@@ -2414,17 +2361,21 @@ build_new_1 (exp)
       init_expr = build_indirect_ref (alloc_node, NULL);
 
       if (init == void_zero_node)
-       init = build_default_init (full_type);
+       init = build_default_init (full_type, nelts);
       else if (init && pedantic && has_array)
-       cp_pedwarn ("ISO C++ forbids initialization in array new");
+       pedwarn ("ISO C++ forbids initialization in array new");
 
       if (has_array)
-       init_expr = build_vec_init (init_expr, init, 0);
+       init_expr
+         = build_vec_init (init_expr,
+                           cp_build_binary_op (MINUS_EXPR, outer_nelts,
+                                               integer_one_node),
+                           init, /*from_array=*/0);
       else if (TYPE_NEEDS_CONSTRUCTING (type))
-       init_expr = build_method_call (init_expr, 
-                                      complete_ctor_identifier,
-                                      init, TYPE_BINFO (true_type),
-                                      LOOKUP_NORMAL);
+       init_expr = build_special_member_call (init_expr, 
+                                              complete_ctor_identifier,
+                                              init, TYPE_BINFO (true_type),
+                                              LOOKUP_NORMAL);
       else
        {
          /* We are processing something like `new int (10)', which
@@ -2464,13 +2415,22 @@ build_new_1 (exp)
          tree cleanup;
          int flags = (LOOKUP_NORMAL 
                       | (globally_qualified_p * LOOKUP_GLOBAL));
+         tree delete_node;
+
+         if (cookie_size)
+           /* Subtract the padding back out to get to the pointer returned
+              from operator new.  */
+           delete_node = fold (build (MINUS_EXPR, TREE_TYPE (alloc_node),
+                                      alloc_node, cookie_size));
+         else
+           delete_node = alloc_node;
 
          /* 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;
 
-         cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
+         cleanup = build_op_delete_call (dcode, delete_node, size, flags,
                                          (placement_allocation_fn_p 
                                           ? alloc_call : NULL_TREE));
 
@@ -2491,16 +2451,23 @@ build_new_1 (exp)
             constructor, that would fix the nesting problem and we could
             do away with this complexity.  But that would complicate other
             things; in particular, it would make it difficult to bail out
-            if the allocation function returns null.  */
+            if the allocation function returns null.  Er, no, it wouldn't;
+            we just don't run the constructor.  The standard says it's
+            unspecified whether or not the args are evaluated.
+
+            FIXME FIXME FIXME inline invisible refs as refs.  That way we
+            can preevaluate value parameters.  */
 
          if (cleanup)
            {
              tree end, sentry, begin;
 
              begin = get_target_expr (boolean_true_node);
-             sentry = TREE_OPERAND (begin, 0);
+             CLEANUP_EH_ONLY (begin) = 1;
+
+             sentry = TARGET_EXPR_SLOT (begin);
 
-             TREE_OPERAND (begin, 2)
+             TARGET_EXPR_CLEANUP (begin)
                = build (COND_EXPR, void_type_node, sentry,
                         cleanup, void_zero_node);
 
@@ -2515,7 +2482,7 @@ build_new_1 (exp)
        }
     }
   else if (CP_TYPE_CONST_P (true_type))
-    cp_error ("uninitialized const in `new' of `%#T'", true_type);
+    error ("uninitialized const in `new' of `%#T'", true_type);
 
   /* Now build up the return value in reverse order.  */
 
@@ -2578,6 +2545,10 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
      This is also the containing expression returned by this function.  */
   tree controller = NULL_TREE;
 
+  /* We should only have 1-D arrays here.  */
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    abort ();
+
   if (! IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     {
       loop = integer_zero_node;
@@ -2674,10 +2645,14 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
   if (controller)
     {
       TREE_OPERAND (controller, 1) = body;
-      return controller;
+      body = controller;
     }
-  else
-    return cp_convert (void_type_node, body);
+
+  if (TREE_CODE (base) == SAVE_EXPR)
+    /* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR.  */
+    body = build (COMPOUND_EXPR, void_type_node, base, body);
+
+  return cp_convert (void_type_node, body);
 }
 
 /* Create an unnamed variable of the indicated TYPE.  */ 
@@ -2715,7 +2690,7 @@ get_temp_regvar (type, init)
   decl = create_temporary_var (type);
   if (building_stmt_tree ())
     add_decl_stmt (decl);
-  if (!building_stmt_tree ())
+  else
     SET_DECL_RTL (decl, assign_temp (type, 2, 0, 1));
   finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
 
@@ -2726,6 +2701,9 @@ get_temp_regvar (type, init)
    initialization of a vector of aggregate types.
 
    BASE is a reference to the vector, of ARRAY_TYPE.
+   MAXINDEX is the maximum index of the array (one less than the
+     number of elements).  It is only used if
+     TYPE_DOMAIN (TREE_TYPE (BASE)) == NULL_TREE.
    INIT is the (possibly NULL) initializer.
 
    FROM_ARRAY is 0 if we should init everything with INIT
@@ -2736,8 +2714,8 @@ get_temp_regvar (type, init)
    but use assignment instead of initialization.  */
 
 tree
-build_vec_init (base, init, from_array)
-     tree base, init;
+build_vec_init (base, maxindex, init, from_array)
+     tree base, init, maxindex;
      int from_array;
 {
   tree rval;
@@ -2757,16 +2735,17 @@ build_vec_init (base, init, from_array)
   tree try_block = NULL_TREE;
   tree try_body = NULL_TREE;
   int num_initialized_elts = 0;
-  tree maxindex = array_type_nelts (TREE_TYPE (base));
 
-  if (maxindex == error_mark_node)
+  if (TYPE_DOMAIN (atype))
+    maxindex = array_type_nelts (atype);
+
+  if (maxindex == NULL_TREE || maxindex == error_mark_node)
     return error_mark_node;
 
-  /* For g++.ext/arrnew.C.  */
-  if (init && TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == NULL_TREE)
-    init = digest_init (atype, init, 0);
-      
-  if (init && !TYPE_NEEDS_CONSTRUCTING (type)
+  if (init
+      && (from_array == 2
+         ? (!CLASS_TYPE_P (type) || !TYPE_HAS_COMPLEX_ASSIGN_REF (type))
+         : !TYPE_NEEDS_CONSTRUCTING (type))
       && ((TREE_CODE (init) == CONSTRUCTOR
           /* Don't do this if the CONSTRUCTOR might contain something
              that might throw and require us to clean up.  */
@@ -2779,7 +2758,6 @@ build_vec_init (base, init, from_array)
         store_constructor will handle the semantics for us.  */
 
       stmt_expr = build (INIT_EXPR, atype, base, init);
-      TREE_SIDE_EFFECTS (stmt_expr) = 1;
       return stmt_expr;
     }
 
@@ -2795,10 +2773,10 @@ build_vec_init (base, init, from_array)
        T* rval = t1;
        ptrdiff_t iterator = maxindex;
        try {
-        do {
+        for (; iterator != -1; --iterator) {
           ... initialize *t1 ...
           ++t1;
-        } while (--iterator != -1);
+        }
        } catch (...) {
          ... destroy elements that were constructed ...
        }
@@ -2898,19 +2876,20 @@ build_vec_init (base, init, from_array)
     {
       /* 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 for_stmt;
+      tree for_body;
       tree elt_init;
 
-      if_stmt = begin_if_stmt ();
-      finish_if_stmt_cond (build (NE_EXPR, boolean_type_node,
-                                 iterator, integer_minus_one_node),
-                          if_stmt);
+      for_stmt = begin_for_stmt ();
+      finish_for_init_stmt (for_stmt);
+      finish_for_cond (build (NE_EXPR, boolean_type_node,
+                             iterator, integer_minus_one_node),
+                      for_stmt);
+      finish_for_expr (build_unary_op (PREDECREMENT_EXPR, iterator, 0),
+                      for_stmt);
 
       /* Otherwise, loop through the elements.  */
-      do_stmt = begin_do_stmt ();
-      do_body = begin_compound_stmt (/*has_no_scope=*/1);
+      for_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,
@@ -2943,7 +2922,7 @@ build_vec_init (base, init, from_array)
          else if (from)
            elt_init = build_modify_expr (to, NOP_EXPR, from);
          else
-           my_friendly_abort (57);
+           abort ();
        }
       else if (TREE_CODE (type) == ARRAY_TYPE)
        {
@@ -2951,7 +2930,7 @@ build_vec_init (base, init, from_array)
            sorry
              ("cannot initialize multi-dimensional array with initializer");
          elt_init = build_vec_init (build1 (INDIRECT_REF, type, base),
-                                    0, 0);
+                                    0, 0, 0);
        }
       else
        elt_init = build_aggr_init (build1 (INDIRECT_REF, type, base), 
@@ -2975,15 +2954,8 @@ build_vec_init (base, init, from_array)
       if (base2)
        finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base2, 0));
 
-      finish_compound_stmt (/*has_no_scope=*/1, do_body);
-      finish_do_body (do_stmt);
-      finish_do_stmt (build (NE_EXPR, boolean_type_node,
-                            build_unary_op (PREDECREMENT_EXPR, iterator, 0),
-                            integer_minus_one_node),
-                     do_stmt);
-
-      finish_then_clause (if_stmt);
-      finish_if_stmt ();
+      finish_compound_stmt (/*has_no_scope=*/1, for_body);
+      finish_for_stmt (for_stmt);
     }
 
   /* Make sure to cleanup any partially constructed elements.  */
@@ -2991,12 +2963,20 @@ build_vec_init (base, init, from_array)
       && from_array != 2)
     {
       tree e;
+      tree m = cp_build_binary_op (MINUS_EXPR, maxindex, iterator);
+
+      /* Flatten multi-dimensional array since build_vec_delete only
+        expects one-dimensional array.  */
+      if (TREE_CODE (type) == ARRAY_TYPE)
+       {
+         m = cp_build_binary_op (MULT_EXPR, m,
+                                 array_type_nelts_total (type));
+         type = strip_array_types (type);
+       }
 
       finish_compound_stmt (/*has_no_scope=*/1, try_body);
       finish_cleanup_try_block (try_block);
-      e = build_vec_delete_1 (rval,
-                             cp_build_binary_op (MINUS_EXPR, maxindex, 
-                                                 iterator),
+      e = build_vec_delete_1 (rval, m,
                              type,
                              sfk_base_destructor,
                              /*use_global_delete=*/0);
@@ -3066,9 +3046,10 @@ build_dtor_call (exp, dtor_kind, flags)
       break;
 
     default:
-      my_friendly_abort (20000524);
+      abort ();
     }
-  return build_method_call (exp, name, NULL_TREE, NULL_TREE, flags);
+  return build_method_call (exp, name, NULL_TREE, 
+                           TYPE_BINFO (TREE_TYPE (exp)), flags);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
@@ -3102,11 +3083,18 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
   if (TREE_CODE (type) == POINTER_TYPE)
     {
       type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
-      if (!VOID_TYPE_P (type) && !complete_type_or_else (type, addr))
-       return error_mark_node;
       if (TREE_CODE (type) == ARRAY_TYPE)
        goto handle_array;
-      if (! IS_AGGR_TYPE (type))
+
+      if (VOID_TYPE_P (type)
+         /* We don't want to warn about delete of void*, only other
+            incomplete types.  Deleting other incomplete types
+            invokes undefined behavior, but it is not ill-formed, so
+            compile to something that would even do The Right Thing
+            (TM) should the type have a trivial dtor and no delete
+            operator.  */
+         || !complete_type_or_diagnostic (type, addr, 1)
+         || !IS_AGGR_TYPE (type))
        {
          /* Call the builtin operator delete.  */
          return build_builtin_delete_call (addr);
@@ -3120,8 +3108,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
     handle_array:
-      if (TREE_SIDE_EFFECTS (addr))
-       addr = save_expr (addr);
+      
       if (TYPE_DOMAIN (type) == NULL_TREE)
        {
          error ("unknown array size in delete");
@@ -3150,7 +3137,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
        return void_zero_node;
 
       return build_op_delete_call
-       (DELETE_EXPR, addr, c_sizeof_nowarn (type),
+       (DELETE_EXPR, addr, cxx_sizeof_nowarn (type),
         LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
         NULL_TREE);
     }
@@ -3168,7 +3155,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
        {
          /* We will use ADDR multiple times so we must save it.  */
          addr = save_expr (addr);
-         /* Delete the object. */
+         /* Delete the object.  */
          do_delete = build_builtin_delete_call (addr);
          /* Otherwise, treat this like a complete object destructor
             call.  */
@@ -3185,12 +3172,20 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
          /* Build the call.  */
          do_delete = build_op_delete_call (DELETE_EXPR,
                                            addr,
-                                           c_sizeof_nowarn (type),
+                                           cxx_sizeof_nowarn (type),
                                            LOOKUP_NORMAL,
                                            NULL_TREE);
          /* Call the complete object destructor.  */
          auto_delete = sfk_complete_destructor;
        }
+      else if (auto_delete == sfk_deleting_destructor
+              && TYPE_GETS_REG_DELETE (type))
+       {
+         /* Make sure we have access to the member op delete, even though
+            we'll actually be calling it from the destructor.  */
+         build_op_delete_call (DELETE_EXPR, addr, cxx_sizeof_nowarn (type),
+                               LOOKUP_NORMAL, NULL_TREE);
+       }
 
       expr = build_dtor_call (build_indirect_ref (addr, NULL),
                              auto_delete, flags);
@@ -3215,7 +3210,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
 /* At the beginning of a destructor, push cleanups that will call the
    destructors for our base classes and members.
 
-   Called from setup_vtbl_ptr.  */
+   Called from begin_destructor_body.  */
 
 void
 push_base_cleanups ()
@@ -3245,21 +3240,12 @@ push_base_cleanups ()
 
          if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type))
            {
-             tree base_ptr_type = build_pointer_type (base_type);
-             expr = current_class_ptr;
-                 
-             /* Convert to the basetype here, as we know the layout is
-                fixed. What is more, if we let build_method_call do it,
-                it will use the vtable, which may have been clobbered
-                by the deletion of our primary base.  */
-                  
-             expr = build1 (NOP_EXPR, base_ptr_type, expr);
-             expr = build (PLUS_EXPR, base_ptr_type, expr,
-                           BINFO_OFFSET (vbase));
-             expr = build_indirect_ref (expr, NULL);
-             expr = build_method_call (expr, base_dtor_identifier,
-                                       NULL_TREE, vbase,
-                                       LOOKUP_NORMAL);
+             expr = build_special_member_call (current_class_ref, 
+                                               base_dtor_identifier,
+                                               NULL_TREE,
+                                               vbase,
+                                               (LOOKUP_NORMAL 
+                                                | LOOKUP_NONVIRTUAL));
              expr = build (COND_EXPR, void_type_node, cond,
                            expr, void_zero_node);
              finish_decl_cleanup (NULL_TREE, expr);
@@ -3278,23 +3264,24 @@ push_base_cleanups ()
          || TREE_VIA_VIRTUAL (base_binfo))
        continue;
 
-      expr = build_scoped_method_call (current_class_ref, base_binfo,
-                                      base_dtor_identifier,
-                                      NULL_TREE);
-
+      expr = build_special_member_call (current_class_ref, 
+                                       base_dtor_identifier,
+                                       NULL_TREE, base_binfo, 
+                                       LOOKUP_NORMAL | LOOKUP_NONVIRTUAL);
       finish_decl_cleanup (NULL_TREE, expr);
     }
 
   for (member = TYPE_FIELDS (current_class_type); member;
        member = TREE_CHAIN (member))
     {
-      if (TREE_CODE (member) != FIELD_DECL)
+      if (TREE_CODE (member) != FIELD_DECL || DECL_ARTIFICIAL (member))
        continue;
       if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
        {
-         tree this_member = (build_component_ref
-                             (current_class_ref, DECL_NAME (member),
-                              NULL_TREE, 0));
+         tree this_member = (build_class_member_access_expr 
+                             (current_class_ref, member, 
+                              /*access_path=*/NULL_TREE,
+                              /*preserve_reference=*/false));
          tree this_type = TREE_TYPE (member);
          expr = build_delete (this_type, this_member,
                               sfk_complete_destructor,
@@ -3363,15 +3350,13 @@ build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete)
 
   base = stabilize_reference (base);
 
-  /* Since we can use base many times, save_expr it.  */
-  if (TREE_SIDE_EFFECTS (base))
-    base = save_expr (base);
-
   if (TREE_CODE (type) == POINTER_TYPE)
     {
       /* Step back one from start of vector, and read dimension.  */
       tree cookie_addr;
 
+      if (TREE_SIDE_EFFECTS (base))
+       base = save_expr (base);
       type = strip_array_types (TREE_TYPE (type));
       cookie_addr = build (MINUS_EXPR,
                           build_pointer_type (sizetype),
@@ -3385,6 +3370,8 @@ build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete)
       maxindex = array_type_nelts_total (type);
       type = strip_array_types (type);
       base = build_unary_op (ADDR_EXPR, base, 1);
+      if (TREE_SIDE_EFFECTS (base))
+       base = save_expr (base);
     }
   else
     {