]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/cp/init.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / cp / init.c
index 1e08908910ab46b518d8b282cd9470e17cb31437..d31c10037a70ee3a1b55da0e90acebdcaa0d7cc1 100644 (file)
@@ -1,29 +1,31 @@
 /* Handle initialization things in C++.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   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)
+the Free Software Foundation; either version 3, 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
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* High-level class interface.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "expr.h"
@@ -32,49 +34,26 @@ 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 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 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 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_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);
-}
+#include "target.h"
+
+static bool begin_init_stmts (tree *, tree *);
+static tree finish_init_stmts (bool, tree, tree);
+static void construct_virtual_base (tree, tree);
+static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
+static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
+static tree build_vec_delete_1 (tree, tree, tree, special_function_kind, int);
+static void perform_member_init (tree, tree);
+static tree build_builtin_delete_call (tree);
+static int member_init_ok_or_else (tree, tree, tree);
+static void expand_virtual_init (tree, tree);
+static tree sort_mem_initializers (tree, tree);
+static tree initializing_context (tree);
+static void expand_cleanup_for_base (tree, tree);
+static tree get_temp_regvar (tree, tree);
+static tree dfs_initialize_vtbl_ptrs (tree, void *);
+static tree build_dtor_call (tree, special_function_kind, int);
+static tree build_field_list (tree, tree, int *);
+static tree build_vtbl_address (tree);
 
 /* We are about to generate some complex initialization code.
    Conceptually, it is all a single expression.  However, we may want
@@ -85,44 +64,28 @@ void init_init_processing ()
    pass them back to finish_init_stmts when the expression is
    complete.  */
 
-void
-begin_init_stmts (stmt_expr_p, compound_stmt_p)
-     tree *stmt_expr_p;
-     tree *compound_stmt_p;
+static bool
+begin_init_stmts (tree *stmt_expr_p, tree *compound_stmt_p)
 {
-  if (building_stmt_tree ())
-    *stmt_expr_p = begin_stmt_expr ();
-  else
-    *stmt_expr_p = begin_global_stmt_expr ();
-  
-  if (building_stmt_tree ())
-    *compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
+  bool is_global = !building_stmt_tree ();
+
+  *stmt_expr_p = begin_stmt_expr ();
+  *compound_stmt_p = begin_compound_stmt (BCS_NO_SCOPE);
+
+  return is_global;
 }
 
 /* Finish out the statement-expression begun by the previous call to
    begin_init_stmts.  Returns the statement-expression itself.  */
 
-tree
-finish_init_stmts (stmt_expr, compound_stmt)
-     tree stmt_expr;
-     tree compound_stmt;
+static tree
+finish_init_stmts (bool is_global, tree stmt_expr, tree compound_stmt)
+{
+  finish_compound_stmt (compound_stmt);
 
-{  
-  if (building_stmt_tree ())
-    finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
-  
-  if (building_stmt_tree ())
-    {
-      stmt_expr = finish_stmt_expr (stmt_expr);
-      STMT_EXPR_NO_SCOPE (stmt_expr) = true;
-    }
-  else
-    stmt_expr = finish_global_stmt_expr (stmt_expr);
-  
-  /* To avoid spurious warnings about unused values, we set 
-     TREE_USED.  */
-  if (stmt_expr)
-    TREE_USED (stmt_expr) = 1;
+  stmt_expr = finish_stmt_expr (stmt_expr, true);
+
+  gcc_assert (!building_stmt_tree () == is_global);
 
   return stmt_expr;
 }
@@ -134,12 +97,12 @@ finish_init_stmts (stmt_expr, compound_stmt)
    TREE_LIST whose TREE_VALUE is the this ptr expression.  */
 
 static tree
-dfs_initialize_vtbl_ptrs (binfo, data)
-     tree binfo;
-     void *data;
+dfs_initialize_vtbl_ptrs (tree binfo, void *data)
 {
-  if ((!BINFO_PRIMARY_P (binfo) || TREE_VIA_VIRTUAL (binfo))
-      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+  if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo)))
+    return dfs_skip_bases;
+
+  if (!BINFO_PRIMARY_P (binfo) || BINFO_VIRTUAL_P (binfo))
     {
       tree base_ptr = TREE_VALUE ((tree) data);
 
@@ -148,8 +111,6 @@ dfs_initialize_vtbl_ptrs (binfo, data)
       expand_virtual_init (binfo, base_ptr);
     }
 
-  SET_BINFO_MARKED (binfo);
-
   return NULL_TREE;
 }
 
@@ -157,8 +118,7 @@ dfs_initialize_vtbl_ptrs (binfo, data)
    ADDR.  */
 
 void
-initialize_vtbl_ptrs (addr)
-     tree addr;
+initialize_vtbl_ptrs (tree addr)
 {
   tree list;
   tree type;
@@ -167,184 +127,420 @@ initialize_vtbl_ptrs (addr)
   list = build_tree_list (type, addr);
 
   /* Walk through the hierarchy, initializing the vptr in each base
-     class.  We do these in pre-order because can't find the virtual
+     class.  We do these in pre-order because we 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_once (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs, NULL, list);
 }
 
-/* Types containing pointers to data members cannot be
-   zero-initialized with zeros, because the NULL value for such
-   pointers is -1.
-
-   TYPE is a type that requires such zero initialization.  The
-   returned value is the initializer.  */
+/* 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), or NULL (in the case that T does not require
+   initialization).  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.  */
 
 tree
-build_forced_zero_init (type)
-     tree type;
+build_zero_init (tree type, tree nelts, bool static_storage_p)
 {
-  tree init = NULL;
+  tree init = NULL_TREE;
 
-  if (AGGREGATE_TYPE_P (type) && !TYPE_PTRMEMFUNC_P (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);
+  /* [dcl.init]
+
+     To zero-initialize an object of type T means:
+
+     -- if T is a scalar type, the storage is set to the value of zero
+       converted to T.
+
+     -- if T is a non-union class type, the storage for each nonstatic
+       data member and each base-class subobject is zero-initialized.
+
+     -- if T is a union type, the storage for its first data member is
+       zero-initialized.
+
+     -- if T is an array type, the storage for each element is
+       zero-initialized.
+
+     -- if T is a reference type, no initialization is performed.  */
+
+  gcc_assert (nelts == NULL_TREE || TREE_CODE (nelts) == INTEGER_CST);
+
+  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;
+      VEC(constructor_elt,gc) *v = NULL;
+
+      /* Iterate over the fields, building initializations.  */
+      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)))
+           {
+             tree value = build_zero_init (TREE_TYPE (field),
+                                           /*nelts=*/NULL_TREE,
+                                           static_storage_p);
+             if (value)
+               CONSTRUCTOR_APPEND_ELT(v, field, value);
+           }
+
+         /* For unions, only the first field is initialized.  */
+         if (TREE_CODE (type) == UNION_TYPE)
+           break;
+       }
+
+      /* Build a constructor to contain the initializations.  */
+      init = build_constructor (type, v);
     }
-  else if (TREE_CODE (type) == REFERENCE_TYPE)
-    /*   --if T is a reference type, no initialization is performed.  */
-    return NULL_TREE;
-  else
+  else if (TREE_CODE (type) == ARRAY_TYPE)
     {
-      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));
+      tree max_index;
+      VEC(constructor_elt,gc) *v = NULL;
+
+      /* Iterate over the array elements, building initializations.  */
+      if (nelts)
+       max_index = fold_build2 (MINUS_EXPR, TREE_TYPE (nelts),
+                                nelts, integer_one_node);
+      else
+       max_index = array_type_nelts (type);
+
+      /* If we have an error_mark here, we should just return error mark
+        as we don't know the size of the array yet.  */
+      if (max_index == error_mark_node)
+       return error_mark_node;
+      gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
+
+      /* A zero-sized array, which is accepted as an extension, will
+        have an upper bound of -1.  */
+      if (!tree_int_cst_equal (max_index, integer_minus_one_node))
+       {
+         constructor_elt *ce;
+
+         v = VEC_alloc (constructor_elt, gc, 1);
+         ce = VEC_quick_push (constructor_elt, v, NULL);
+
+         /* If this is a one element array, we just use a regular init.  */
+         if (tree_int_cst_equal (size_zero_node, max_index))
+           ce->index = size_zero_node;
+         else
+           ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
+                               max_index);
+
+         ce->value = build_zero_init (TREE_TYPE (type),
+                                      /*nelts=*/NULL_TREE,
+                                      static_storage_p);
+       }
+
+      /* Build a constructor to contain the initializations.  */
+      init = build_constructor (type, v);
     }
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    init = fold_convert (type, integer_zero_node);
+  else
+    gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
 
-  init = digest_init (type, init, 0);
+  /* In all cases, the initializer is a constant.  */
+  if (init)
+    TREE_CONSTANT (init) = 1;
 
   return init;
 }
 
-/* [dcl.init]:
+/* Return a suitable initializer for value-initializing an object of type
+   TYPE, as described in [dcl.init].  */
+
+tree
+build_value_init (tree type)
+{
+  /* [dcl.init]
 
-  To default-initialize an object of type T means:
+     To value-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 a class type (clause 9) with a user-provided constructor
+       (12.1), then the default constructor 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;
+     - if T is a non-union class type without a user-provided constructor,
+       then every non-static data member and base-class component of T is
+       value-initialized;92)
 
-  --otherwise, the storage for the object is zero-initialized.
+     - if T is an array type, then each element is value-initialized;
 
-  A program that calls for default-initialization of an entity of refer-
-  ence type is ill-formed.  */
+     - otherwise, the object is zero-initialized.
 
-static tree
-build_default_init (type)
-     tree type;
+     A program that calls for default-initialization or
+     value-initialization of an entity of reference type is ill-formed.
+
+     92) Value-initialization for such a class object may be implemented by
+     zero-initializing the object and then calling the default
+     constructor.  */
+
+  if (CLASS_TYPE_P (type))
+    {
+      if (type_has_user_provided_constructor (type))
+       return build_aggr_init_expr
+         (type,
+          build_special_member_call (NULL_TREE, complete_ctor_identifier,
+                                     NULL_TREE, type, LOOKUP_NORMAL,
+                                     tf_warning_or_error));
+      else if (TREE_CODE (type) != UNION_TYPE && TYPE_NEEDS_CONSTRUCTING (type))
+       {
+         /* This is a class that needs constructing, but doesn't have
+            a user-provided constructor.  So we need to zero-initialize
+            the object and then call the implicitly defined ctor.
+            This will be handled in simplify_aggr_init_expr.  */
+         tree ctor = build_special_member_call
+           (NULL_TREE, complete_ctor_identifier,
+            NULL_TREE, type, LOOKUP_NORMAL, tf_warning_or_error);
+
+         ctor = build_aggr_init_expr (type, ctor);
+         AGGR_INIT_ZERO_FIRST (ctor) = 1;
+         return ctor;
+       }
+    }
+  return build_value_init_noctor (type);
+}
+
+/* Like build_value_init, but don't call the constructor for TYPE.  Used
+   for base initializers.  */
+
+tree
+build_value_init_noctor (tree type)
 {
-  tree init = NULL_TREE;
+  if (CLASS_TYPE_P (type))
+    {
+      gcc_assert (!TYPE_NEEDS_CONSTRUCTING (type));
+       
+      if (TREE_CODE (type) != UNION_TYPE)
+       {
+         tree field;
+         VEC(constructor_elt,gc) *v = NULL;
 
-  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;
+         /* Iterate over the fields, building initializations.  */
+         for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+           {
+             tree ftype, value;
+
+             if (TREE_CODE (field) != FIELD_DECL)
+               continue;
+
+             ftype = TREE_TYPE (field);
+
+             if (TREE_CODE (ftype) == REFERENCE_TYPE)
+               error ("value-initialization of reference");
+
+             /* We could skip vfields and fields of types with
+                user-defined constructors, but I think that won't improve
+                performance at all; it should be simpler in general just
+                to zero out the entire object than try to only zero the
+                bits that actually need it.  */
+
+             /* 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.  */
+             value = build_value_init (ftype);
+
+             if (value)
+               CONSTRUCTOR_APPEND_ELT(v, field, value);
+           }
+
+         /* Build a constructor to contain the zero- initializations.  */
+         return build_constructor (type, v);
+       }
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      VEC(constructor_elt,gc) *v = NULL;
+
+      /* Iterate over the array elements, building initializations.  */
+      tree max_index = array_type_nelts (type);
+
+      /* If we have an error_mark here, we should just return error mark
+        as we don't know the size of the array yet.  */
+      if (max_index == error_mark_node)
+       return error_mark_node;
+      gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
+
+      /* A zero-sized array, which is accepted as an extension, will
+        have an upper bound of -1.  */
+      if (!tree_int_cst_equal (max_index, integer_minus_one_node))
+       {
+         constructor_elt *ce;
+
+         v = VEC_alloc (constructor_elt, gc, 1);
+         ce = VEC_quick_push (constructor_elt, v, NULL);
+
+         /* If this is a one element array, we just use a regular init.  */
+         if (tree_int_cst_equal (size_zero_node, max_index))
+           ce->index = size_zero_node;
+         else
+           ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
+                               max_index);
 
-  return build_forced_zero_init (type);
+         ce->value = build_value_init (TREE_TYPE (type));
+
+         /* The gimplifier can't deal with a RANGE_EXPR of TARGET_EXPRs.  */
+         gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR
+                     && TREE_CODE (ce->value) != AGGR_INIT_EXPR);
+       }
+
+      /* Build a constructor to contain the initializations.  */
+      return build_constructor (type, v);
+    }
+
+  return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
 }
 
-/* Subroutine of emit_base_init.  */
+/* 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);
 
-  decl = build_component_ref (current_class_ref, member, NULL_TREE, explicit);
-
+  /* Effective C++ rule 12 requires that all data members be
+     initialized.  */
+  if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE)
+    warning (OPT_Weffc__, "%J%qD should be initialized in the member initialization "
+            "list", current_function_decl, member);
+
+  /* Get an lvalue for the data member.  */
+  decl = build_class_member_access_expr (current_class_ref, member,
+                                        /*access_path=*/NULL_TREE,
+                                        /*preserve_reference=*/true,
+                                        tf_warning_or_error);
   if (decl == error_mark_node)
     return;
 
+  if (init == void_type_node)
+    {
+      /* mem() means value-initialization.  */
+      if (TREE_CODE (type) == ARRAY_TYPE)
+       {
+         init = build_vec_init (decl, NULL_TREE, NULL_TREE,
+                                /*explicit_value_init_p=*/true,
+                                /* from_array=*/0,
+                                tf_warning_or_error);
+         finish_expr_stmt (init);
+       }
+      else
+       {
+         if (TREE_CODE (type) == REFERENCE_TYPE)
+           permerror (input_location, "%Jvalue-initialization of %q#D, "
+                                      "which has reference type",
+                      current_function_decl, member);
+         else
+           {
+             init = build2 (INIT_EXPR, type, decl, build_value_init (type));
+             finish_expr_stmt (init);
+           }
+       }
+    }
   /* Deal with this here, as we will get confused if we try to call the
      assignment op for an anonymous union.  This can happen in a
      synthesized copy constructor.  */
-  if (ANON_AGGR_TYPE_P (type))
+  else if (ANON_AGGR_TYPE_P (type))
     {
       if (init)
        {
-         init = build (INIT_EXPR, type, decl, TREE_VALUE (init));
+         init = build2 (INIT_EXPR, type, decl, TREE_VALUE (init));
          finish_expr_stmt (init);
        }
     }
-  else if (TYPE_NEEDS_CONSTRUCTING (type)
-          || (init && TYPE_HAS_CONSTRUCTOR (type)))
+  else if (TYPE_NEEDS_CONSTRUCTING (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
+      if (init != NULL_TREE
          && TREE_CODE (type) == ARRAY_TYPE
-         && init != NULL_TREE
          && TREE_CHAIN (init) == NULL_TREE
          && 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),
+                                           /*explicit_value_init_p=*/false,
+                                           /* from_array=*/1,
+                                            tf_warning_or_error));
        }
       else
-       finish_expr_stmt (build_aggr_init (decl, init, 0));
+       {
+         if (CP_TYPE_CONST_P (type)
+             && init == NULL_TREE
+             && !type_has_user_provided_default_constructor (type))
+           /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a
+              vtable; still give this diagnostic.  */
+           permerror (input_location, "%Juninitialized member %qD with %<const%> type %qT",
+                      current_function_decl, member, type);
+         finish_expr_stmt (build_aggr_init (decl, init, 0, 
+                                            tf_warning_or_error));
+       }
     }
   else
     {
       if (init == NULL_TREE)
        {
-         if (explicit)
-           {
-             init = build_default_init (type);
-             if (TREE_CODE (type) == REFERENCE_TYPE)
-               warning
-                 ("default-initialization of `%#D', which has reference type",
-                  member);
-           }
          /* member traversal: note it leaves init NULL */
-         else if (TREE_CODE (type) == REFERENCE_TYPE)
-           pedwarn ("uninitialized reference member `%D'", member);
+         if (TREE_CODE (type) == REFERENCE_TYPE)
+           permerror (input_location, "%Juninitialized reference member %qD",
+                      current_function_decl, member);
+         else if (CP_TYPE_CONST_P (type))
+           permerror (input_location, "%Juninitialized member %qD with %<const%> type %qT",
+                      current_function_decl, member, type);
        }
       else if (TREE_CODE (init) == TREE_LIST)
-       {
-         /* There was an explicit member initialization.  Do some
-            work in that case.  */
-         if (TREE_CHAIN (init))
-           {
-             warning ("initializer list treated as compound expression");
-             init = build_compound_expr (init);
-           }
-         else
-           init = TREE_VALUE (init);
-       }
+       /* There was an explicit member initialization.  Do some work
+          in that case.  */
+       init = build_x_compound_expr_from_list (init, "member initializer");
 
       if (init)
-       finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
+       finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
+                                               tf_warning_or_error));
     }
 
   if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
     {
       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,
+                                            tf_warning_or_error);
       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);
     }
 }
 
 /* Returns a TREE_LIST containing (as the TREE_PURPOSE of each node) all
    the FIELD_DECLs on the TYPE_FIELDS list for T, in reverse order.  */
 
-static tree 
-build_field_list (t, list, uses_unions_p)
-     tree t;
-     tree list;
-     int *uses_unions_p;
+static tree
+build_field_list (tree t, tree list, int *uses_unions_p)
 {
   tree fields;
 
@@ -357,9 +553,9 @@ 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.  */
       if (TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
        *uses_unions_p = 1;
@@ -373,7 +569,7 @@ build_field_list (t, list, uses_unions_p)
             initialize the entire aggregate.  */
          list = tree_cons (fields, NULL_TREE, list);
          /* And now add the fields in the anonymous aggregate.  */
-         list = build_field_list (TREE_TYPE (fields), list, 
+         list = build_field_list (TREE_TYPE (fields), list,
                                   uses_unions_p);
        }
       /* Add this field.  */
@@ -384,79 +580,113 @@ 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, binfo, base_binfo;
+  tree sorted_inits;
+  tree next_subobject;
+  VEC(tree,gc) *vbases;
+  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 (vbases = CLASSTYPE_VBASECLASSES (t), i = 0;
+       VEC_iterate (tree, vbases, i, base); i++)
+    sorted_inits = tree_cons (base, NULL_TREE, sorted_inits);
+
+  /* Process the direct bases.  */
+  for (binfo = TYPE_BINFO (t), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
+    if (!BINFO_VIRTUAL_P (base_binfo))
+      sorted_inits = tree_cons (base_binfo, 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.
+        ??? Are all these on the correct lines?  */
+      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)
+           warning (OPT_Wreorder, "%q+D will be initialized after",
+                    TREE_PURPOSE (next_subobject));
+         else
+           warning (OPT_Wreorder, "base %qT will be initialized after",
+                    TREE_PURPOSE (next_subobject));
+         if (TREE_CODE (subobject) == FIELD_DECL)
+           warning (OPT_Wreorder, "  %q+#D", subobject);
+         else
+           warning (OPT_Wreorder, "  base %qT", subobject);
+         warning (OPT_Wreorder, "%J  when initialized here", current_function_decl);
        }
 
-      /* 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))
-       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 ("%Jmultiple initializations given for %qD",
+                  current_function_decl, subobject);
+         else
+           error ("%Jmultiple initializations given for base %qT",
+                  current_function_decl, 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]
@@ -466,15 +696,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.  */
@@ -516,8 +747,8 @@ sort_member_init (t, member_init_list)
                  if (same_type_p (last_field_type, field_type))
                    {
                      if (TREE_CODE (field_type) == UNION_TYPE)
-                       error ("initializations for multiple members of `%T'",
-                                 last_field_type);
+                       error ("%Jinitializations for multiple members of %qT",
+                              current_function_decl, last_field_type);
                      done = 1;
                      break;
                    }
@@ -527,7 +758,7 @@ sort_member_init (t, member_init_list)
 
                  last_field_type = TYPE_CONTEXT (last_field_type);
                }
-             
+
              /* If we've reached the outermost class, then we're
                 done.  */
              if (same_type_p (field_type, t))
@@ -541,231 +772,79 @@ 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)
-           {
-             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))
-           warning ("base class `%#T' should be explicitly initialized in the copy constructor",
-                       BINFO_TYPE (base_binfo));
-       }
+  /* We will already have issued an error message about the fact that
+     the type is incomplete.  */
+  if (!COMPLETE_TYPE_P (current_class_type))
+    return;
 
-      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);
+
+  in_base_initializer = 1;
+
+  /* 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 there
+        is a user-defined constructor in the base class (other than the
+        default constructor, which will be called anyway).  */
+      if (extra_warnings && !arguments
+         && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
+         && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
+       warning (OPT_Wextra, "%Jbase class %q#T should be explicitly initialized in the "
+                "copy constructor",
+                current_function_decl, BINFO_TYPE (subobject));
+
+      /* Initialize the base.  */
+      if (BINFO_VIRTUAL_P (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,
-                             LOOKUP_NORMAL);
+         tree base_addr;
+
+         base_addr = build_base_path (PLUS_EXPR, current_class_ptr,
+                                      subobject, 1);
+         expand_aggr_init_1 (subobject, NULL_TREE,
+                             cp_build_indirect_ref (base_addr, NULL,
+                                                     tf_warning_or_error),
+                             arguments,
+                             LOOKUP_NORMAL,
+                              tf_warning_or_error);
+         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);
     }
+  in_base_initializer = 0;
 
-  /* 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)
-           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);
     }
 }
 
@@ -773,21 +852,19 @@ emit_base_init (mem_init_list, base_init_list)
    assigned to the vptr) for BINFO.  */
 
 static tree
-build_vtbl_address (binfo)
-     tree binfo;
+build_vtbl_address (tree binfo)
 {
   tree binfo_for = binfo;
   tree vtbl;
 
-  if (BINFO_VPTR_INDEX (binfo) && TREE_VIA_VIRTUAL (binfo)
-      && BINFO_PRIMARY_P (binfo))
+  if (BINFO_VPTR_INDEX (binfo) && BINFO_VIRTUAL_P (binfo))
     /* If this is a virtual primary base, then the vtable we want to store
        is that for the base this is being used as the primary base of.  We
        can't simply skip the initialization, because we may be expanding the
        inits of a subobject constructor where the virtual base layout
        can be different.  */
-    while (BINFO_PRIMARY_BASE_OF (binfo_for))
-      binfo_for = BINFO_PRIMARY_BASE_OF (binfo_for);
+    while (BINFO_PRIMARY_P (binfo_for))
+      binfo_for = BINFO_INHERITANCE_CHAIN (binfo_for);
 
   /* Figure out what vtable BINFO's vtable is based on, and mark it as
      used.  */
@@ -796,12 +873,9 @@ build_vtbl_address (binfo)
   TREE_USED (vtbl) = 1;
 
   /* Now compute the address to use when initializing the vptr.  */
-  vtbl = BINFO_VTABLE (binfo_for);
+  vtbl = unshare_expr (BINFO_VTABLE (binfo_for));
   if (TREE_CODE (vtbl) == VAR_DECL)
-    {
-      vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
-      TREE_CONSTANT (vtbl) = 1;
-    }
+    vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
 
   return vtbl;
 }
@@ -813,8 +887,7 @@ build_vtbl_address (binfo)
    multiple inheritance, this might mean "C's A" if C : A, B.  */
 
 static void
-expand_virtual_init (binfo, decl)
-     tree binfo, decl;
+expand_virtual_init (tree binfo, tree decl)
 {
   tree vtbl, vtbl_ptr;
   tree vtt_index;
@@ -832,43 +905,44 @@ expand_virtual_init (binfo, decl)
 
       /* Compute the value to use, when there's a VTT.  */
       vtt_parm = current_vtt_parm;
-      vtbl2 = build (PLUS_EXPR, 
-                    TREE_TYPE (vtt_parm), 
-                    vtt_parm,
-                    vtt_index);
-      vtbl2 = build1 (INDIRECT_REF, TREE_TYPE (vtbl), vtbl2);
+      vtbl2 = build2 (POINTER_PLUS_EXPR,
+                     TREE_TYPE (vtt_parm),
+                     vtt_parm,
+                     vtt_index);
+      vtbl2 = cp_build_indirect_ref (vtbl2, NULL, tf_warning_or_error);
+      vtbl2 = convert (TREE_TYPE (vtbl), vtbl2);
 
       /* The actual initializer is the VTT value only in the subobject
         constructor.  In maybe_clone_body we'll substitute NULL for
         the vtt_parm in the case of the non-subobject constructor.  */
-      vtbl = build (COND_EXPR, 
-                   TREE_TYPE (vtbl), 
-                   build (EQ_EXPR, boolean_type_node,
-                          current_in_charge_parm, integer_zero_node),
-                   vtbl2, 
-                   vtbl);
+      vtbl = build3 (COND_EXPR,
+                    TREE_TYPE (vtbl),
+                    build2 (EQ_EXPR, boolean_type_node,
+                            current_in_charge_parm, integer_zero_node),
+                    vtbl2,
+                    vtbl);
     }
 
   /* Compute the location of the vtpr.  */
-  vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL),
+  vtbl_ptr = build_vfield_ref (cp_build_indirect_ref (decl, NULL, 
+                                                      tf_warning_or_error),
                               TREE_TYPE (binfo));
-  my_friendly_assert (vtbl_ptr != error_mark_node, 20010730);
+  gcc_assert (vtbl_ptr != error_mark_node);
 
   /* Assign the vtable to the vptr.  */
   vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
-  finish_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
+  finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl,
+                                         tf_warning_or_error));
 }
 
 /* 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
-expand_cleanup_for_base (binfo, flag)
-     tree binfo;
-     tree flag;
+expand_cleanup_for_base (tree binfo, tree flag)
 {
   tree expr;
 
@@ -876,106 +950,66 @@ 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,
+                                    tf_warning_or_error);
   if (flag)
-    expr = fold (build (COND_EXPR, void_type_node,
-                       truthvalue_conversion (flag),
-                       expr, integer_zero_node));
-
-  finish_subobject (expr);
-}
-
-/* Subroutine of `expand_aggr_vbase_init'.
-   BINFO is the binfo of the type that is being initialized.
-   INIT_LIST is the list of initializers for the virtual baseclass.  */
-
-static void
-expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
-     tree binfo, exp, addr, init_list;
-{
-  tree init = purpose_member (binfo, init_list);
-  tree ref = build_indirect_ref (addr, NULL);
+    expr = fold_build3 (COND_EXPR, void_type_node,
+                       c_common_truthvalue_conversion (input_location, flag),
+                       expr, integer_zero_node);
 
-  if (init)
-    init = TREE_VALUE (init);
-  /* Call constructors, but don't set up vtables.  */
-  expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
+  finish_eh_cleanup (expr);
 }
 
-/* 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.  */
+/* Construct the virtual base-class VBASE passing the ARGUMENTS to its
+   constructor.  */
 
 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;
+construct_virtual_base (tree vbase, tree arguments)
 {
-  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 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);
+
+  /* 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 = convert_to_base_statically (current_class_ref, vbase);
+
+  expand_aggr_init_1 (vbase, current_class_ref, exp, arguments,
+                     LOOKUP_COMPLAIN, tf_warning_or_error);
+  finish_then_clause (inner_if_stmt);
+  finish_if_stmt (inner_if_stmt);
+
+  expand_cleanup_for_base (vbase, flag);
 }
 
 /* Find the context in which this FIELD can be initialized.  */
 
 static tree
-initializing_context (field)
-     tree field;
+initializing_context (tree field)
 {
   tree t = DECL_CONTEXT (field);
 
@@ -990,73 +1024,78 @@ initializing_context (field)
    is erroneous.  FIELD is the member we decided to initialize.
    TYPE is the type for which the initialization is being performed.
    FIELD must be a member of TYPE.
-   
+
    MEMBER_NAME is the name of the member.  */
 
 static int
-member_init_ok_or_else (field, type, member_name)
-     tree field;
-     tree type;
-     tree member_name;
+member_init_ok_or_else (tree field, tree type, tree member_name)
 {
   if (field == error_mark_node)
     return 0;
-  if (field == NULL_TREE || initializing_context (field) != type)
+  if (!field)
     {
-      error ("class `%T' does not have any field named `%D'", type,
-               member_name);
+      error ("class %qT does not have any field named %qD", type,
+            member_name);
+      return 0;
+    }
+  if (TREE_CODE (field) == VAR_DECL)
+    {
+      error ("%q#D is a static data member; it can only be "
+            "initialized at its definition",
+            field);
       return 0;
     }
-  if (TREE_STATIC (field))
+  if (TREE_CODE (field) != FIELD_DECL)
     {
-      error ("field `%#D' is static; the only point of initialization is its definition",
-               field);
+      error ("%q#D is not a non-static data member of %qT",
+            field, type);
+      return 0;
+    }
+  if (initializing_context (field) != type)
+    {
+      error ("class %qT does not have any field named %qD", 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.
+   Check the validity of NAME, and return either the base _TYPE, base
+   binfo, or the FIELD_DECL of the member.  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 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 (BINFO_N_BASE_BINFOS (TYPE_BINFO (current_class_type)))
        {
        case 0:
-         error ("unnamed initializer for `%T', which has no base classes",
-                   type);
+         error ("unnamed initializer for %qT, which has no base classes",
+                current_class_type);
          return NULL_TREE;
        case 1:
-         basetype = TYPE_BINFO_BASETYPE (type, 0);
+         basetype = BINFO_TYPE
+           (BINFO_BASE_BINFO (TYPE_BINFO (current_class_type), 0));
          break;
        default:
-         error ("unnamed initializer for `%T', which uses multiple inheritance",
-                   type);
+         error ("unnamed initializer for %qT, which uses multiple inheritance",
+                current_class_type);
          return NULL_TREE;
       }
     }
@@ -1067,47 +1106,70 @@ expand_member_init (exp, name, init)
     }
   else if (TREE_CODE (name) == TYPE_DECL)
     basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
-
-  my_friendly_assert (init != NULL_TREE, 0);
-
-  if (init == void_type_node)
-    init = NULL_TREE;
+  else
+    basetype = NULL_TREE;
 
   if (basetype)
     {
+      tree class_binfo;
+      tree direct_binfo;
+      tree virtual_binfo;
+      int i;
+
       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 basetype;
+
+      class_binfo = TYPE_BINFO (current_class_type);
+      direct_binfo = NULL_TREE;
+      virtual_binfo = NULL_TREE;
+
+      /* Look for a direct base.  */
+      for (i = 0; BINFO_BASE_ITERATE (class_binfo, i, direct_binfo); ++i)
+       if (SAME_BINFO_TYPE_P (BINFO_TYPE (direct_binfo), basetype))
+         break;
+
+      /* Look for a virtual base -- unless the direct base is itself
+        virtual.  */
+      if (!direct_binfo || !BINFO_VIRTUAL_P (direct_binfo))
+       virtual_binfo = binfo_for_vbase (basetype, current_class_type);
+
+      /* [class.base.init]
+
+        If a mem-initializer-id is ambiguous because it designates
+        both a direct non-virtual base class and an inherited virtual
+        base class, the mem-initializer is ill-formed.  */
+      if (direct_binfo && virtual_binfo)
+       {
+         error ("%qD is both a direct base and an indirect virtual base",
+                basetype);
+         return NULL_TREE;
+       }
+
+      if (!direct_binfo && !virtual_binfo)
        {
-         if (TYPE_USES_VIRTUAL_BASECLASSES (type))
-           error ("type `%D' is not a direct or virtual base of `%T'",
-                     name, type);
+         if (CLASSTYPE_VBASECLASSES (current_class_type))
+           error ("type %qT is not a direct or virtual base of %qT",
+                  basetype, current_class_type);
          else
-           error ("type `%D' is not a direct base of `%T'",
-                     name, type);
+           error ("type %qT is not a direct base of %qT",
+                  basetype, current_class_type);
          return NULL_TREE;
        }
 
-      init = build_tree_list (basetype, init);
+      return direct_binfo ? direct_binfo : virtual_binfo;
     }
   else
     {
       if (TREE_CODE (name) == IDENTIFIER_NODE)
-       field = lookup_field (type, name, 1, 0);
+       field = lookup_field (current_class_type, name, 1, false);
       else
        field = name;
 
-      if (! member_init_ok_or_else (field, type, name))
-       return NULL_TREE;
-
-      init = build_tree_list (field, init);
+      if (member_init_ok_or_else (field, current_class_type, name))
+       return field;
     }
 
-  return init;
+  return NULL_TREE;
 }
 
 /* This is like `expand_member_init', only it stores one aggregate
@@ -1131,8 +1193,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.
@@ -1144,9 +1204,7 @@ expand_member_init (exp, name, init)
    perform the initialization, but not both, as it would be ambiguous.  */
 
 tree
-build_aggr_init (exp, init, flags)
-     tree exp, init;
-     int flags;
+build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
 {
   tree stmt_expr;
   tree compound_stmt;
@@ -1154,6 +1212,7 @@ build_aggr_init (exp, init, flags)
   tree type = TREE_TYPE (exp);
   int was_const = TREE_READONLY (exp);
   int was_volatile = TREE_THIS_VOLATILE (exp);
+  int is_global;
 
   if (init == error_mark_node)
     return error_mark_node;
@@ -1166,34 +1225,28 @@ build_aggr_init (exp, init, flags)
 
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
-      /* Must arrange to initialize each element of EXP
-        from elements of INIT.  */
-      tree itype = init ? TREE_TYPE (init) : NULL_TREE;
-      
-      if (init && !itype)
+      tree itype;
+
+      /* An array may not be initialized use the parenthesized
+        initialization form -- unless the initializer is "()".  */
+      if (init && TREE_CODE (init) == TREE_LIST)
        {
-         /* Handle bad initializers like:
-            class COMPLEX {
-            public:
-              double re, im;
-              COMPLEX(double r = 0.0, double i = 0.0) {re = r; im = i;};
-              ~COMPLEX() {};
-            };
-
-            int main(int argc, char **argv) {
-              COMPLEX zees(1.0, 0.0)[10];
-            }
-         */
-         error ("bad array initializer");
+          if (complain & tf_error)
+            error ("bad array initializer");
          return error_mark_node;
        }
+      /* Must arrange to initialize each element of EXP
+        from elements of INIT.  */
+      itype = init ? TREE_TYPE (init) : NULL_TREE;
       if (cp_type_quals (type) != TYPE_UNQUALIFIED)
        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, init,
-                                 init && same_type_p (TREE_TYPE (init),
-                                                      TREE_TYPE (exp)));
+       itype = TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
+      stmt_expr = build_vec_init (exp, NULL_TREE, init,
+                                 /*explicit_value_init_p=*/false,
+                                 itype && same_type_p (itype,
+                                                       TREE_TYPE (exp)),
+                                  complain);
       TREE_READONLY (exp) = was_const;
       TREE_THIS_VOLATILE (exp) = was_volatile;
       TREE_TYPE (exp) = type;
@@ -1203,18 +1256,16 @@ build_aggr_init (exp, init, flags)
     }
 
   if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
-    /* just know that we've seen something for this node */
+    /* Just know that we've seen something for this node.  */
     TREE_USED (exp) = 1;
 
-  TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
-  begin_init_stmts (&stmt_expr, &compound_stmt);
+  is_global = begin_init_stmts (&stmt_expr, &compound_stmt);
   destroy_temps = stmts_are_full_exprs_p ();
   current_stmt_tree ()->stmts_are_full_exprs_p = 0;
   expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
-                     init, LOOKUP_NORMAL|flags);
-  stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
+                     init, LOOKUP_NORMAL|flags, complain);
+  stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt);
   current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
-  TREE_TYPE (exp) = type;
   TREE_READONLY (exp) = was_const;
   TREE_THIS_VOLATILE (exp) = was_volatile;
 
@@ -1222,11 +1273,8 @@ build_aggr_init (exp, init, flags)
 }
 
 static void
-expand_default_init (binfo, true_exp, exp, init, flags)
-     tree binfo;
-     tree true_exp, exp;
-     tree init;
-     int flags;
+expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
+                     tsubst_flags_t complain)
 {
   tree type = TREE_TYPE (exp);
   tree ctor_name;
@@ -1244,8 +1292,7 @@ expand_default_init (binfo, true_exp, exp, init, flags)
       && (flags & LOOKUP_ONLYCONVERTING))
     {
       /* Base subobjects should only get direct-initialization.  */
-      if (true_exp != exp)
-       abort ();
+      gcc_assert (true_exp == exp);
 
       if (flags & DIRECT_BIND)
        /* Do nothing.  We hit this in two cases:  Reference initialization,
@@ -1253,22 +1300,27 @@ 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
+      else if (BRACE_ENCLOSED_INITIALIZER_P (init)
+              && CP_AGGREGATE_TYPE_P (type))
+       {
+         /* A brace-enclosed initializer for an aggregate.  */
+         init = digest_init (type, init);
+       }
+      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) = build2 (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);
+       init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
       TREE_SIDE_EFFECTS (init) = 1;
       finish_expr_stmt (init);
       return;
@@ -1289,14 +1341,10 @@ 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,
+                                    complain);
   if (TREE_SIDE_EFFECTS (rval))
-    {
-      if (building_stmt_tree ())
-       finish_expr_stmt (rval);
-      else
-       genrtl_expr_stmt (rval);
-    }
+    finish_expr_stmt (convert_to_void (rval, NULL, complain));
 }
 
 /* This function is responsible for initializing EXP with INIT
@@ -1316,19 +1364,17 @@ expand_default_init (binfo, true_exp, exp, init, flags)
    from TRUE_EXP.  In constructors, we don't know anything about
    the value being initialized.
 
-   FLAGS is just passes to `build_method_call'.  See that function for
-   its description.  */
+   FLAGS is just passed to `build_new_method_call'.  See that function
+   for its description.  */
 
 static void
-expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
-     tree binfo;
-     tree true_exp, exp;
-     tree init;
-     int flags;
+expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
+                    tsubst_flags_t complain)
 {
   tree type = TREE_TYPE (exp);
 
-  my_friendly_assert (init != error_mark_node && type != error_mark_node, 211);
+  gcc_assert (init != error_mark_node && type != error_mark_node);
+  gcc_assert (building_stmt_tree ());
 
   /* Use a function returning the desired type to initialize EXP for us.
      If the function is a constructor, and its first argument is
@@ -1337,84 +1383,69 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
      as TARGET_EXPRs.  */
 
   if (init && TREE_CODE (exp) == VAR_DECL
-      && TREE_CODE (init) == CONSTRUCTOR
-      && TREE_HAS_CONSTRUCTOR (init))
+      && COMPOUND_LITERAL_P (init))
     {
       /* If store_init_value returns NULL_TREE, the INIT has been
-        record in the DECL_INITIAL for EXP.  That means there's
+        recorded as the DECL_INITIAL for EXP.  That means there's
         nothing more we have to do.  */
-      if (!store_init_value (exp, init))
+      init = store_init_value (exp, init);
+      if (init)
+       finish_expr_stmt (init);
+      return;
+    }
+
+  /* If an explicit -- but empty -- initializer list was present,
+     that's value-initialization.  */
+  if (init == void_type_node)
+    {
+      /* If there's a user-provided constructor, we just call that.  */
+      if (type_has_user_provided_constructor (type))
+       /* Fall through.  */;
+      /* If there isn't, but we still need to call the constructor,
+        zero out the object first.  */
+      else if (TYPE_NEEDS_CONSTRUCTING (type))
        {
-         if (!building_stmt_tree ())
-           expand_decl_init (exp);
+         init = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
+         init = build2 (INIT_EXPR, type, exp, init);
+         finish_expr_stmt (init);
+         /* And then call the constructor.  */
        }
+      /* If we don't need to mess with the constructor at all,
+        then just zero out the object and we're done.  */
       else
-       finish_expr_stmt (build (INIT_EXPR, type, exp, init));
-      return;
+       {
+         init = build2 (INIT_EXPR, type, exp, build_value_init_noctor (type));
+         finish_expr_stmt (init);
+         return;
+       }
+      init = NULL_TREE;
     }
 
   /* We know that expand_default_init can handle everything we want
      at this point.  */
-  expand_default_init (binfo, true_exp, exp, init, flags);
+  expand_default_init (binfo, true_exp, exp, init, flags, complain);
 }
 
-/* Report an error if TYPE is not a user-defined, aggregate type.  If
+/* Report an error if TYPE is not a user-defined, class type.  If
    OR_ELSE is nonzero, give an error message.  */
 
 int
-is_aggr_type (type, or_else)
-     tree type;
-     int or_else;
+is_class_type (tree type, int or_else)
 {
   if (type == error_mark_node)
     return 0;
 
-  if (! IS_AGGR_TYPE (type)
-      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
-      && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
+  if (! CLASS_TYPE_P (type))
     {
       if (or_else)
-       error ("`%T' is not an aggregate type", type);
+       error ("%qT is not a class type", type);
       return 0;
     }
   return 1;
 }
 
-/* Like is_aggr_typedef, but returns typedef if successful.  */
-
-tree
-get_aggr_from_typedef (name, or_else)
-     tree name;
-     int or_else;
-{
-  tree type;
-
-  if (name == error_mark_node)
-    return NULL_TREE;
-
-  if (IDENTIFIER_HAS_TYPE_VALUE (name))
-    type = IDENTIFIER_TYPE_VALUE (name);
-  else
-    {
-      if (or_else)
-       error ("`%T' fails to be an aggregate typedef", name);
-      return NULL_TREE;
-    }
-
-  if (! IS_AGGR_TYPE (type)
-      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
-      && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
-    {
-      if (or_else)
-       error ("type `%T' is of non-aggregate type", type);
-      return NULL_TREE;
-    }
-  return type;
-}
-
 tree
-get_type_value (name)
-     tree name;
+get_type_value (tree name)
 {
   if (name == error_mark_node)
     return NULL_TREE;
@@ -1425,157 +1456,11 @@ get_type_value (name)
     return NULL_TREE;
 }
 
-\f
-/* This code could just as well go in `class.c', but is placed here for
-   modularity.  */
-
-/* For an expression of the form TYPE :: NAME (PARMLIST), build
-   the appropriate function call.  */
-
-tree
-build_member_call (type, name, parmlist)
-     tree type, name, parmlist;
-{
-  tree t;
-  tree method_name;
-  int dtor = 0;
-  tree basetype_path, decl;
-
-  if (TREE_CODE (name) == TEMPLATE_ID_EXPR
-      && TREE_CODE (type) == NAMESPACE_DECL)
-    {
-      /* 'name' already refers to the decls from the namespace, since we
-        hit do_identifier for template_ids.  */
-      method_name = TREE_OPERAND (name, 0);
-      /* FIXME: Since we don't do independent names right yet, the
-        name might also be a LOOKUP_EXPR. Once we resolve this to a
-        real decl earlier, this can go. This may happen during
-        tsubst'ing.  */
-      if (TREE_CODE (method_name) == LOOKUP_EXPR)
-       {
-         method_name = lookup_namespace_name 
-           (type, TREE_OPERAND (method_name, 0));
-         TREE_OPERAND (name, 0) = method_name;
-       }
-      my_friendly_assert (is_overloaded_fn (method_name), 980519);
-      return build_x_function_call (name, parmlist, current_class_ref);
-    }
-
-  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);
-
-  if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-    {
-      method_name = TREE_OPERAND (name, 0);
-      if (TREE_CODE (method_name) == COMPONENT_REF)
-       method_name = TREE_OPERAND (method_name, 1);
-      if (is_overloaded_fn (method_name))
-       method_name = DECL_NAME (OVL_CURRENT (method_name));
-      TREE_OPERAND (name, 0) = method_name;
-    }
-  else
-    method_name = name;
-
-  if (TREE_CODE (method_name) == BIT_NOT_EXPR)
-    {
-      method_name = TREE_OPERAND (method_name, 0);
-      dtor = 1;
-    }
-
-  /* This shouldn't be here, and build_member_call shouldn't appear in
-     parse.y!  (mrs)  */
-  if (type && TREE_CODE (type) == IDENTIFIER_NODE
-      && get_aggr_from_typedef (type, 0) == 0)
-    {
-      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);
-       }
-    }
-
-  if (type == NULL_TREE || ! is_aggr_type (type, 1))
-    return error_mark_node;
-
-  /* An operator we did not like.  */
-  if (name == NULL_TREE)
-    return error_mark_node;
-
-  if (dtor)
-    {
-      error ("cannot call destructor `%T::~%T' without object", type,
-               method_name);
-      return error_mark_node;
-    }
-
-  decl = maybe_dummy_object (type, &basetype_path);
-
-  /* Convert 'this' to the specified type to disambiguate conversion
-     to the function's context.  */
-  if (decl == current_class_ref
-      && 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);
-       }
-    }
-
-  if (method_name == constructor_name (type)
-      || method_name == constructor_name_full (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))))
-    {
-      if (t == error_mark_node)
-       return error_mark_node;
-      if (TREE_CODE (t) == FIELD_DECL)
-       {
-         if (is_dummy_object (decl))
-           {
-             error ("invalid use of non-static field `%D'", t);
-             return error_mark_node;
-           }
-         decl = build (COMPONENT_REF, TREE_TYPE (t), decl, t);
-       }
-      else if (TREE_CODE (t) == VAR_DECL)
-       decl = t;
-      else
-       {
-         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_function_call (decl, parmlist);
-    }
-  else
-    {
-      error ("no method `%T::%D'", type, name);
-      return error_mark_node;
-    }
-}
-
-/* Build a reference to a member of an aggregate.  This is not a
-   C++ `&', but really something which can have its address taken,
-   and then act as a pointer to member, for example TYPE :: FIELD
-   can have its address taken by saying & TYPE :: FIELD.
+/* Build a reference to a member of an aggregate.  This is not a C++
+   `&', but really something which can have its address taken, and
+   then act as a pointer to member, for example TYPE :: FIELD can have
+   its address taken by saying & TYPE :: FIELD.  ADDRESS_P is true if
+   this expression is the operand of "&".
 
    @@ Prints out lousy diagnostics for operator <typename>
    @@ fields.
@@ -1583,335 +1468,228 @@ build_member_call (type, name, parmlist)
    @@ This function should be rewritten and placed in search.c.  */
 
 tree
-build_offset_ref (type, name)
-     tree type, name;
+build_offset_ref (tree type, tree member, bool address_p)
 {
-  tree decl, t = error_mark_node;
-  tree member;
+  tree decl;
   tree basebinfo = NULL_TREE;
-  tree orig_name = name;
 
   /* class templates can come in as TEMPLATE_DECLs here.  */
-  if (TREE_CODE (name) == TEMPLATE_DECL)
-    return name;
-
-  if (processing_template_decl || uses_template_parms (type))
-    return build_min_nt (SCOPE_REF, type, name);
-
-  if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-    {
-      /* If the NAME is a TEMPLATE_ID_EXPR, we are looking at
-        something like `a.template f<int>' or the like.  For the most
-        part, we treat this just like a.f.  We do remember, however,
-        the template-id that was used.  */
-      name = TREE_OPERAND (orig_name, 0);
-
-      if (DECL_P (name))
-       name = DECL_NAME (name);
-      else
-       {
-         if (TREE_CODE (name) == LOOKUP_EXPR)
-           /* This can happen during tsubst'ing.  */
-           name = TREE_OPERAND (name, 0);
-         else
-           {
-             if (TREE_CODE (name) == COMPONENT_REF)
-               name = TREE_OPERAND (name, 1);
-             if (TREE_CODE (name) == OVERLOAD)
-               name = DECL_NAME (OVL_CURRENT (name));
-           }
-       }
-
-      my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0);
-    }
+  if (TREE_CODE (member) == TEMPLATE_DECL)
+    return member;
 
-  if (type == NULL_TREE)
-    return error_mark_node;
-  
-  /* Handle namespace names fully here.  */
-  if (TREE_CODE (type) == NAMESPACE_DECL)
-    {
-      t = lookup_namespace_name (type, name);
-      if (t == error_mark_node)
-        return t;
-      if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
-        /* Reconstruct the TEMPLATE_ID_EXPR.  */
-        t = build (TEMPLATE_ID_EXPR, TREE_TYPE (t),
-                   t, TREE_OPERAND (orig_name, 1));
-      if (! type_unknown_p (t))
-       {
-         mark_used (t);
-         t = convert_from_reference (t);
-       }
-      return t;
-    }
+  if (dependent_type_p (type) || type_dependent_expression_p (member))
+    return build_qualified_name (NULL_TREE, type, member,
+                                /*template_p=*/false);
 
-  if (! is_aggr_type (type, 1))
+  gcc_assert (TYPE_P (type));
+  if (! is_class_type (type, 1))
     return error_mark_node;
 
-  if (TREE_CODE (name) == BIT_NOT_EXPR)
-    {
-      if (! check_dtor_name (type, name))
-       error ("qualified type `%T' does not match destructor name `~%T'",
-                 type, TREE_OPERAND (name, 0));
-      name = dtor_identifier;
-    }
+  gcc_assert (DECL_P (member) || BASELINK_P (member));
+  /* Callers should call mark_used before this point.  */
+  gcc_assert (!DECL_P (member) || TREE_USED (member));
 
   if (!COMPLETE_TYPE_P (complete_type (type))
       && !TYPE_BEING_DEFINED (type))
     {
-      error ("incomplete type `%T' does not have member `%D'", type,
-               name);
+      error ("incomplete type %qT does not have member %qD", type, member);
       return error_mark_node;
     }
 
-  decl = maybe_dummy_object (type, &basebinfo);
+  /* Entities other than non-static members need no further
+     processing.  */
+  if (TREE_CODE (member) == TYPE_DECL)
+    return member;
+  if (TREE_CODE (member) == VAR_DECL || TREE_CODE (member) == CONST_DECL)
+    return convert_from_reference (member);
 
-  member = lookup_member (basebinfo, name, 1, 0);
+  if (TREE_CODE (member) == FIELD_DECL && DECL_C_BIT_FIELD (member))
+    {
+      error ("invalid pointer to bit-field %qD", member);
+      return error_mark_node;
+    }
 
-  if (member == error_mark_node)
-    return error_mark_node;
+  /* Set up BASEBINFO for member lookup.  */
+  decl = maybe_dummy_object (type, &basebinfo);
 
   /* A lot of this logic is now handled in lookup_member.  */
-  if (member && BASELINK_P (member))
+  if (BASELINK_P (member))
     {
       /* Go from the TREE_BASELINK to the member function info.  */
-      tree fnfields = member;
-      t = TREE_VALUE (fnfields);
-
-      if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
-       {
-         /* The FNFIELDS are going to contain functions that aren't
-            necessarily templates, and templates that don't
-            necessarily match the explicit template parameters.  We
-            save all the functions, and the explicit parameters, and
-            then figure out exactly what to instantiate with what
-            arguments in instantiate_type.  */
-
-         if (TREE_CODE (t) != OVERLOAD)
-           /* The code in instantiate_type which will process this
-              expects to encounter OVERLOADs, not raw functions.  */
-           t = ovl_cons (t, NULL_TREE);
-
-          t = build (TEMPLATE_ID_EXPR, TREE_TYPE (t), t,
-                    TREE_OPERAND (orig_name, 1));
-         t = build (OFFSET_REF, unknown_type_node, decl, t);
-          
-          PTRMEM_OK_P (t) = 1;
-                 
-         return t;
-       }
+      tree t = BASELINK_FUNCTIONS (member);
 
-      if (!really_overloaded_fn (t))
+      if (TREE_CODE (t) != TEMPLATE_ID_EXPR && !really_overloaded_fn (t))
        {
-         /* Get rid of a potential OVERLOAD around it */
+         /* Get rid of a potential OVERLOAD around it */
          t = OVL_CURRENT (t);
 
-         /* unique functions are handled easily.  */
-         if (!enforce_access (basebinfo, t))
-           return error_mark_node;
-         mark_used (t);
+         /* Unique functions are handled easily.  */
+
+         /* For non-static member of base class, we need a special rule
+            for access checking [class.protected]:
+
+              If the access is to form a pointer to member, the
+              nested-name-specifier shall name the derived class
+              (or any class derived from that class).  */
+         if (address_p && DECL_P (t)
+             && DECL_NONSTATIC_MEMBER_P (t))
+           perform_or_defer_access_check (TYPE_BINFO (type), t, t);
+         else
+           perform_or_defer_access_check (basebinfo, t, t);
+
          if (DECL_STATIC_FUNCTION_P (t))
            return t;
-         t = build (OFFSET_REF, TREE_TYPE (t), decl, t);
-         PTRMEM_OK_P (t) = 1;
-         return t;
+         member = t;
        }
-
-      TREE_TYPE (fnfields) = unknown_type_node;
-      
-      t = build (OFFSET_REF, unknown_type_node, decl, fnfields);
-      PTRMEM_OK_P (t) = 1;
-      return t;
+      else
+       TREE_TYPE (member) = unknown_type_node;
     }
+  else if (address_p && TREE_CODE (member) == FIELD_DECL)
+    /* We need additional test besides the one in
+       check_accessibility_of_qualified_id in case it is
+       a pointer to non-static member.  */
+    perform_or_defer_access_check (TYPE_BINFO (type), member, member);
 
-  t = member;
-
-  if (t == NULL_TREE)
+  if (!address_p)
     {
-      error ("`%D' is not a member of type `%T'", name, type);
-      return error_mark_node;
-    }
+      /* If MEMBER is non-static, then the program has fallen afoul of
+        [expr.prim]:
 
-  if (TREE_CODE (t) == TYPE_DECL)
-    {
-      TREE_USED (t) = 1;
-      return t;
-    }
-  /* static class members and class-specific enum
-     values can be returned without further ado.  */
-  if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == CONST_DECL)
-    {
-      mark_used (t);
-      return convert_from_reference (t);
-    }
+          An id-expression that denotes a nonstatic data member or
+          nonstatic member function of a class can only be used:
 
-  if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t))
-    {
-      error ("illegal pointer to bit-field `%D'", t);
-      return error_mark_node;
-    }
+          -- as part of a class member access (_expr.ref_) in which the
+          object-expression refers to the member's class or a class
+          derived from that class, or
 
-  /* static class functions too.  */
-  if (TREE_CODE (t) == FUNCTION_DECL
-      && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
-    abort ();
+          -- to form a pointer to member (_expr.unary.op_), or
 
-  /* In member functions, the form `type::name' is no longer
-     equivalent to `this->type::name', at least not until
-     resolve_offset_ref.  */
-  t = build (OFFSET_REF, build_offset_type (type, TREE_TYPE (t)), decl, t);
-  PTRMEM_OK_P (t) = 1;
-  return t;
-}
+          -- in the body of a nonstatic member function of that class or
+          of a class derived from that class (_class.mfct.nonstatic_), or
 
-/* If a OFFSET_REF made it through to here, then it did
-   not have its address taken.  */
-
-tree
-resolve_offset_ref (exp)
-     tree exp;
-{
-  tree type = TREE_TYPE (exp);
-  tree base = NULL_TREE;
-  tree member;
-  tree basetype, addr;
-
-  if (TREE_CODE (exp) == OFFSET_REF)
-    {
-      member = TREE_OPERAND (exp, 1);
-      base = TREE_OPERAND (exp, 0);
-    }
-  else
-    {
-      my_friendly_assert (TREE_CODE (type) == OFFSET_TYPE, 214);
-      if (TYPE_OFFSET_BASETYPE (type) != current_class_type)
+          -- in a mem-initializer for a constructor for that class or for
+          a class derived from that class (_class.base.init_).  */
+      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (member))
+       {
+         /* Build a representation of the qualified name suitable
+            for use as the operand to "&" -- even though the "&" is
+            not actually present.  */
+         member = build2 (OFFSET_REF, TREE_TYPE (member), decl, member);
+         /* In Microsoft mode, treat a non-static member function as if
+            it were a pointer-to-member.  */
+         if (flag_ms_extensions)
+           {
+             PTRMEM_OK_P (member) = 1;
+             return cp_build_unary_op (ADDR_EXPR, member, 0, 
+                                        tf_warning_or_error);
+           }
+         error ("invalid use of non-static member function %qD",
+                TREE_OPERAND (member, 1));
+         return error_mark_node;
+       }
+      else if (TREE_CODE (member) == FIELD_DECL)
        {
-         error ("object missing in use of pointer-to-member construct");
+         error ("invalid use of non-static data member %qD", member);
          return error_mark_node;
        }
-      member = exp;
-      type = TREE_TYPE (type);
-      base = current_class_ref;
-    }
-
-  if (BASELINK_P (member) || TREE_CODE (member) == TEMPLATE_ID_EXPR)
-    return build_unary_op (ADDR_EXPR, exp, 0);
-  
-  if (TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE)
-    {
-      if (!flag_ms_extensions)
-        /* A single non-static member, make sure we don't allow a
-           pointer-to-member.  */
-        exp = ovl_cons (member, NULL_TREE);
-      
-      return build_unary_op (ADDR_EXPR, exp, 0);
-    }
-  
-  if ((TREE_CODE (member) == VAR_DECL
-       && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member))
-       && ! TYPE_PTRMEM_P (TREE_TYPE (member)))
-      || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE)
-    {
-      /* These were static members.  */
-      if (mark_addressable (member) == 0)
-       return error_mark_node;
       return member;
     }
 
-  if (TREE_CODE (TREE_TYPE (member)) == POINTER_TYPE
-      && TREE_CODE (TREE_TYPE (TREE_TYPE (member))) == METHOD_TYPE)
-    return member;
+  member = build2 (OFFSET_REF, TREE_TYPE (member), decl, member);
+  PTRMEM_OK_P (member) = 1;
+  return member;
+}
 
-  /* Syntax error can cause a member which should
-     have been seen as static to be grok'd as non-static.  */
-  if (TREE_CODE (member) == FIELD_DECL && current_class_ref == NULL_TREE)
-    {
-      cp_error_at ("member `%D' is non-static but referenced as a static member",
-                  member);
-      error ("at this point in file");
-      return error_mark_node;
-    }
+/* If DECL is a scalar enumeration constant or variable with a
+   constant initializer, return the initializer (or, its initializers,
+   recursively); otherwise, return DECL.  If INTEGRAL_P, the
+   initializer is only returned if DECL is an integral
+   constant-expression.  */
 
-  /* The first case is really just a reference to a member of `this'.  */
-  if (TREE_CODE (member) == FIELD_DECL
-      && (base == current_class_ref || is_dummy_object (base)))
+static tree
+constant_value_1 (tree decl, bool integral_p)
+{
+  while (TREE_CODE (decl) == CONST_DECL
+        || (integral_p
+            ? DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+            : (TREE_CODE (decl) == VAR_DECL
+               && CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))))
     {
-      tree binfo = TYPE_BINFO (current_class_type);
-
-      /* Try to get to basetype from 'this'; if that doesn't work,
-         nothing will.  */
-      base = current_class_ref;
-
-      /* First convert to the intermediate base specified, if appropriate.  */
-      if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
+      tree init;
+      /* Static data members in template classes may have
+        non-dependent initializers.  References to such non-static
+        data members are not value-dependent, so we must retrieve the
+        initializer here.  The DECL_INITIAL will have the right type,
+        but will not have been folded because that would prevent us
+        from performing all appropriate semantic checks at
+        instantiation time.  */
+      if (DECL_CLASS_SCOPE_P (decl)
+         && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
+         && uses_template_parms (CLASSTYPE_TI_ARGS
+                                 (DECL_CONTEXT (decl))))
        {
-         binfo = binfo_or_else (TYPE_OFFSET_BASETYPE (type),
-                                current_class_type);
-         if (!binfo)
-           return error_mark_node;
-         base = build_base_path (PLUS_EXPR, base, binfo, 1);
+         ++processing_template_decl;
+         init = fold_non_dependent_expr (DECL_INITIAL (decl));
+         --processing_template_decl;
        }
-
-      return build_component_ref (base, member, binfo, 1);
-    }
-
-  /* Ensure that we have an object.  */
-  if (is_dummy_object (base))
-    addr = error_mark_node;
-  else
-    /* If this is a reference to a member function, then return the
-       address of the member function (which may involve going
-       through the object's vtable), otherwise, return an expression
-       for the dereferenced pointer-to-member construct.  */
-    addr = build_unary_op (ADDR_EXPR, base, 0);
-
-  if (TYPE_PTRMEM_P (TREE_TYPE (member)))
-    {
-      if (addr == error_mark_node)
+      else
        {
-         error ("object missing in `%E'", exp);
-         return error_mark_node;
+         /* If DECL is a static data member in a template
+            specialization, we must instantiate it here.  The
+            initializer for the static data member is not processed
+            until needed; we need it now.  */
+         mark_used (decl);
+         init = DECL_INITIAL (decl);
        }
+      if (init == error_mark_node)
+       return decl;
+      /* Initializers in templates are generally expanded during
+        instantiation, so before that for const int i(2)
+        INIT is a TREE_LIST with the actual initializer as
+        TREE_VALUE.  */
+      if (processing_template_decl
+         && init
+         && TREE_CODE (init) == TREE_LIST
+         && TREE_CHAIN (init) == NULL_TREE)
+       init = TREE_VALUE (init);
+      if (!init
+         || !TREE_TYPE (init)
+         || (integral_p
+             ? !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init))
+             : (!TREE_CONSTANT (init)
+                /* Do not return an aggregate constant (of which
+                   string literals are a special case), as we do not
+                   want to make inadvertent copies of such entities,
+                   and we must be sure that their addresses are the
+                   same everywhere.  */
+                || TREE_CODE (init) == CONSTRUCTOR
+                || TREE_CODE (init) == STRING_CST)))
+       break;
+      decl = unshare_expr (init);
+    }
+  return decl;
+}
 
-      basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
-      basetype = lookup_base (TREE_TYPE (TREE_TYPE (addr)),
-                             basetype, ba_check, NULL);
-      addr = build_base_path (PLUS_EXPR, addr, basetype, 1);
-      
-      member = cp_convert (ptrdiff_type_node, member);
+/* If DECL is a CONST_DECL, or a constant VAR_DECL initialized by
+   constant of integral or enumeration type, then return that value.
+   These are those variables permitted in constant expressions by
+   [5.19/1].  */
 
-      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);
-    }
-  abort ();
-  /* NOTREACHED */
-  return NULL_TREE;
+tree
+integral_constant_value (tree decl)
+{
+  return constant_value_1 (decl, /*integral_p=*/true);
 }
 
-/* If DECL is a `const' declaration, and its value is a known
-   constant, then return that value.  */
+/* A more relaxed version of integral_constant_value, used by the
+   common C/C++ code and by the C++ front end for optimization
+   purposes.  */
 
 tree
-decl_constant_value (decl)
-     tree decl;
+decl_constant_value (tree decl)
 {
-  if (TREE_READONLY_DECL_P (decl)
-      && ! TREE_THIS_VOLATILE (decl)
-      && DECL_INITIAL (decl)
-      && DECL_INITIAL (decl) != error_mark_node
-      /* This is invalid if initial value is not constant.
-        If it has either a function call, a memory reference,
-        or a variable, then re-evaluating it could give different results.  */
-      && TREE_CONSTANT (DECL_INITIAL (decl))
-      /* Check for cases where this is sub-optimal, even though valid.  */
-      && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR)
-    return DECL_INITIAL (decl);
-  return decl;
+  return constant_value_1 (decl,
+                          /*integral_p=*/processing_template_decl);
 }
 \f
 /* Common subroutines of build_new and build_vec_delete.  */
@@ -1919,443 +1697,324 @@ decl_constant_value (decl)
 /* Call the global __builtin_delete to delete ADDR.  */
 
 static tree
-build_builtin_delete_call (addr)
-     tree addr;
+build_builtin_delete_call (tree addr)
 {
   mark_used (global_delete_fndecl);
-  return build_call (global_delete_fndecl, build_tree_list (NULL_TREE, addr));
+  return build_call_n (global_delete_fndecl, 1, addr);
 }
 \f
-/* Generate a C++ "new" expression. DECL is either a TREE_LIST
-   (which needs to go through some sort of groktypename) or it
-   is the name of the class we are newing. INIT is an initialization value.
-   It is either an EXPRLIST, an EXPR_NO_COMMAS, or something in braces.
-   If INIT is void_type_node, it means do *not* call a constructor
-   for this instance.
-
-   For types with constructors, the data returned is initialized
-   by the appropriate constructor.
-
-   Whether the type has a constructor or not, if it has a pointer
-   to a virtual function table, then that pointer is set up
-   here.
-
-   Unless I am mistaken, a call to new () will return initialized
-   data regardless of whether the constructor itself is private or
-   not.  NOPE; new fails if the constructor is private (jcm).
+/* Build and return a NEW_EXPR.  If NELTS is non-NULL, TYPE[NELTS] is
+   the type of the object being allocated; otherwise, it's just TYPE.
+   INIT is the initializer, if any.  USE_GLOBAL_NEW is true if the
+   user explicitly wrote "::operator new".  PLACEMENT, if non-NULL, is
+   the TREE_LIST of arguments to be provided as arguments to a
+   placement new operator.  This routine performs no semantic checks;
+   it just creates and returns a NEW_EXPR.  */
 
-   Note that build_new does nothing to assure that any special
-   alignment requirements of the type are met.  Rather, it leaves
-   it up to malloc to do the right thing.  Otherwise, folding to
-   the right alignment cal cause problems if the user tries to later
-   free the memory returned by `new'.
-
-   PLACEMENT is the `placement' list for user-defined operator new ().  */
-
-tree
-build_new (placement, decl, init, use_global_new)
-     tree placement;
-     tree decl, init;
-     int use_global_new;
+static tree
+build_raw_new_expr (tree placement, tree type, tree nelts, tree init,
+                   int use_global_new)
 {
-  tree type, rval;
-  tree nelts = NULL_TREE, t;
-  int has_array = 0;
-
-  if (decl == error_mark_node)
-    return error_mark_node;
-
-  if (TREE_CODE (decl) == TREE_LIST)
-    {
-      tree absdcl = TREE_VALUE (decl);
-      tree last_absdcl = NULL_TREE;
-
-      if (current_function_decl
-         && DECL_CONSTRUCTOR_P (current_function_decl))
-       my_friendly_assert (immediate_size_expand == 0, 19990926);
-
-      nelts = integer_one_node;
-
-      if (absdcl && TREE_CODE (absdcl) == CALL_EXPR)
-       abort ();
-      while (absdcl && TREE_CODE (absdcl) == INDIRECT_REF)
-       {
-         last_absdcl = absdcl;
-         absdcl = TREE_OPERAND (absdcl, 0);
-       }
-
-      if (absdcl && TREE_CODE (absdcl) == ARRAY_REF)
-       {
-         /* probably meant to be a vec new */
-         tree this_nelts;
+  tree new_expr;
 
-         while (TREE_OPERAND (absdcl, 0)
-                && TREE_CODE (TREE_OPERAND (absdcl, 0)) == ARRAY_REF)
-           {
-             last_absdcl = absdcl;
-             absdcl = TREE_OPERAND (absdcl, 0);
-           }
+  new_expr = build4 (NEW_EXPR, build_pointer_type (type), placement, type,
+                    nelts, init);
+  NEW_EXPR_USE_GLOBAL (new_expr) = use_global_new;
+  TREE_SIDE_EFFECTS (new_expr) = 1;
 
-         has_array = 1;
-         this_nelts = TREE_OPERAND (absdcl, 1);
-         if (this_nelts != error_mark_node)
-           {
-             if (this_nelts == NULL_TREE)
-               error ("new of array type fails to specify size");
-             else if (processing_template_decl)
-               {
-                 nelts = this_nelts;
-                 absdcl = TREE_OPERAND (absdcl, 0);
-               }
-             else
-               {
-                 if (build_expr_type_conversion (WANT_INT | WANT_ENUM, 
-                                                 this_nelts, 0)
-                     == NULL_TREE)
-                   pedwarn ("size in array new must have integral type");
-
-                 this_nelts = save_expr (cp_convert (sizetype, this_nelts));
-                 absdcl = TREE_OPERAND (absdcl, 0);
-                 if (this_nelts == integer_zero_node)
-                   {
-                     warning ("zero size array reserves no space");
-                     nelts = integer_zero_node;
-                   }
-                 else
-                   nelts = cp_build_binary_op (MULT_EXPR, nelts, this_nelts);
-               }
-           }
-         else
-           nelts = integer_zero_node;
-       }
+  return new_expr;
+}
 
-      if (last_absdcl)
-       TREE_OPERAND (last_absdcl, 0) = absdcl;
-      else
-       TREE_VALUE (decl) = absdcl;
+/* Make sure that there are no aliasing issues with T, a placement new
+   expression applied to PLACEMENT, by recording the change in dynamic
+   type.  If placement new is inlined, as it is with libstdc++, and if
+   the type of the placement new differs from the type of the
+   placement location itself, then alias analysis may think it is OK
+   to interchange writes to the location from before the placement new
+   and from after the placement new.  We have to prevent type-based
+   alias analysis from applying.  PLACEMENT may be NULL, which means
+   that we couldn't capture it in a temporary variable, in which case
+   we use a memory clobber.  */
 
-      type = groktypename (decl);
-      if (! type || type == error_mark_node)
-       return error_mark_node;
-    }
-  else if (TREE_CODE (decl) == IDENTIFIER_NODE)
-    {
-      if (IDENTIFIER_HAS_TYPE_VALUE (decl))
-       {
-         /* An aggregate type.  */
-         type = IDENTIFIER_TYPE_VALUE (decl);
-         decl = TYPE_MAIN_DECL (type);
-       }
-      else
-       {
-         /* A builtin type.  */
-         decl = lookup_name (decl, 1);
-         my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 215);
-         type = TREE_TYPE (decl);
-       }
-    }
-  else if (TREE_CODE (decl) == TYPE_DECL)
-    {
-      type = TREE_TYPE (decl);
-    }
-  else
-    {
-      type = decl;
-      decl = TYPE_MAIN_DECL (type);
-    }
+static tree
+avoid_placement_new_aliasing (tree t, tree placement)
+{
+  tree type_change;
 
   if (processing_template_decl)
-    {
-      if (has_array)
-       t = tree_cons (tree_cons (NULL_TREE, type, NULL_TREE),
-                      build_min_nt (ARRAY_REF, NULL_TREE, nelts),
-                      NULL_TREE);
-      else
-       t = type;
-       
-      rval = build_min_nt (NEW_EXPR, placement, t, init);
-      NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
-      return rval;
-    }
-
-  /* ``A reference cannot be created by the new operator.  A reference
-     is not an object (8.2.2, 8.4.3), so a pointer to it could not be
-     returned by new.'' ARM 5.3.3 */
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    {
-      error ("new cannot be applied to a reference type");
-      type = TREE_TYPE (type);
-    }
-
-  if (TREE_CODE (type) == FUNCTION_TYPE)
-    {
-      error ("new cannot be applied to a function type");
-      return error_mark_node;
-    }
-
-  /* When the object being created is an array, the new-expression yields a
-     pointer to the initial element (if any) of the array.  For example,
-     both new int and new int[10] return an int*.  5.3.4.  */
-  if (TREE_CODE (type) == ARRAY_TYPE && has_array == 0)
-    {
-      nelts = array_type_nelts_top (type);
-      has_array = 1;
-      type = TREE_TYPE (type);
-    }
-
-  if (has_array)
-    t = build_nt (ARRAY_REF, type, nelts);
+    return t;
+
+  /* If we are not using type based aliasing, we don't have to do
+     anything.  */
+  if (!flag_strict_aliasing)
+    return t;
+
+  /* If we have a pointer and a location, record the change in dynamic
+     type.  Otherwise we need a general memory clobber.  */
+  if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+      && placement != NULL_TREE
+      && TREE_CODE (TREE_TYPE (placement)) == POINTER_TYPE)
+    type_change = build_stmt (CHANGE_DYNAMIC_TYPE_EXPR,
+                             TREE_TYPE (t),
+                             placement);
   else
-    t = type;
-
-  rval = build (NEW_EXPR, build_pointer_type (type), placement, t, init);
-  NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
-  TREE_SIDE_EFFECTS (rval) = 1;
-  rval = build_new_1 (rval);
-  if (rval == error_mark_node)
-    return error_mark_node;
-
-  /* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain.  */
-  rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval);
-  TREE_NO_UNUSED_WARNING (rval) = 1;
-
-  return rval;
-}
-
-/* Given a Java class, return a decl for the corresponding java.lang.Class. */
-
-tree
-build_java_class_ref (type)
-     tree type;
-{
-  tree name = NULL_TREE, class_decl;
-  static tree CL_suffix = NULL_TREE;
-  if (CL_suffix == NULL_TREE)
-    CL_suffix = get_identifier("class$");
-  if (jclass_node == NULL_TREE)
     {
-      jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jclass"));
-      if (jclass_node == NULL_TREE)
-       fatal_error ("call to Java constructor, while `jclass' undefined");
-
-      jclass_node = TREE_TYPE (jclass_node);
-    }
-
-  /* Mangle the class$ field */
-  {
-    tree field;
-    for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-      if (DECL_NAME (field) == CL_suffix)
-       {
-         mangle_decl (field);
-         name = DECL_ASSEMBLER_NAME (field);
-         break;
-       }
-    if (!field)
-      internal_error ("can't find class$");
-    }
+      /* Build a memory clobber.  */
+      type_change = build_stmt (ASM_EXPR,
+                               build_string (0, ""),
+                               NULL_TREE,
+                               NULL_TREE,
+                               tree_cons (NULL_TREE,
+                                          build_string (6, "memory"),
+                                          NULL_TREE));
 
-  class_decl = IDENTIFIER_GLOBAL_VALUE (name);
-  if (class_decl == NULL_TREE)
-    {
-      class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node));
-      TREE_STATIC (class_decl) = 1;
-      DECL_EXTERNAL (class_decl) = 1;
-      TREE_PUBLIC (class_decl) = 1;
-      DECL_ARTIFICIAL (class_decl) = 1;
-      DECL_IGNORED_P (class_decl) = 1;
-      pushdecl_top_level (class_decl);
-      make_decl_rtl (class_decl, NULL);
+      ASM_VOLATILE_P (type_change) = 1;
     }
-  return class_decl;
-}
-
-/* Returns the size of the cookie to use when allocating an array
-   whose elements have the indicated TYPE.  Assumes that it is already
-   known that a cookie is needed.  */
 
-static tree
-get_cookie_size (type)
-     tree type;
-{
-  tree cookie_size;
-
-  /* We need to allocate an additional max (sizeof (size_t), alignof
-     (true_type)) bytes.  */
-  tree sizetype_size;
-  tree type_align;
-  
-  sizetype_size = size_in_bytes (sizetype);
-  type_align = size_int (TYPE_ALIGN_UNIT (type));
-  if (INT_CST_LT_UNSIGNED (type_align, sizetype_size))
-    cookie_size = sizetype_size;
-  else
-    cookie_size = type_align;
-
-  return cookie_size;
+  return build2 (COMPOUND_EXPR, TREE_TYPE (t), type_change, t);
 }
 
-/* Called from cplus_expand_expr when expanding a NEW_EXPR.  The return
-   value is immediately handed to expand_expr.  */
+/* Generate code for a new-expression, including calling the "operator
+   new" function, initializing the object, and, if an exception occurs
+   during construction, cleaning up.  The arguments are as for
+   build_raw_new_expr.  */
 
 static tree
-build_new_1 (exp)
-     tree exp;
+build_new_1 (tree placement, tree type, tree nelts, tree init,
+            bool globally_qualified_p, tsubst_flags_t complain)
 {
-  tree placement, init;
-  tree type, true_type, size, rval, t;
-  tree full_type;
-  tree nelts = NULL_TREE;
-  tree alloc_call, alloc_expr, alloc_node;
+  tree size, rval;
+  /* True iff this is a call to "operator new[]" instead of just
+     "operator new".  */
+  bool array_p = false;
+  /* If ARRAY_P is true, the element type of the array.  This is never
+     an ARRAY_TYPE; for something like "new int[3][4]", the
+     ELT_TYPE is "int".  If ARRAY_P is false, this is the same type as
+     TYPE.  */
+  tree elt_type;
+  /* The type of the new-expression.  (This type is always a pointer
+     type.)  */
+  tree pointer_type;
+  tree outer_nelts = NULL_TREE;
+  tree alloc_call, alloc_expr;
+  /* The address returned by the call to "operator new".  This node is
+     a VAR_DECL and is therefore reusable.  */
+  tree alloc_node;
   tree alloc_fn;
   tree cookie_expr, init_expr;
-  int has_array = 0;
-  enum tree_code code;
-  int use_cookie, 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 nothrow, check_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
      order to store the number of elements.  */
   tree cookie_size = NULL_TREE;
+  tree placement_expr = NULL_TREE;
   /* True if the function we are calling is a placement allocation
      function.  */
   bool placement_allocation_fn_p;
-
-  placement = TREE_OPERAND (exp, 0);
-  type = TREE_OPERAND (exp, 1);
-  init = TREE_OPERAND (exp, 2);
-  globally_qualified_p = NEW_EXPR_USE_GLOBAL (exp);
-
-  if (TREE_CODE (type) == ARRAY_REF)
+  tree args = NULL_TREE;
+  /* True if the storage must be initialized, either by a constructor
+     or due to an explicit new-initializer.  */
+  bool is_initialized;
+  /* The address of the thing allocated, not including any cookie.  In
+     particular, if an array cookie is in use, DATA_ADDR is the
+     address of the first array element.  This node is a VAR_DECL, and
+     is therefore reusable.  */
+  tree data_addr;
+  tree init_preeval_expr = NULL_TREE;
+
+  if (nelts)
+    {
+      outer_nelts = nelts;
+      array_p = true;
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
     {
-      has_array = 1;
-      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);
+      array_p = true;
+      nelts = array_type_nelts_top (type);
+      outer_nelts = nelts;
+      type = TREE_TYPE (type);
     }
-  else
-    full_type = type;
-
-  true_type = type;
-
-  code = has_array ? VEC_NEW_EXPR : NEW_EXPR;
 
   /* If our base type is an array, then make sure we know how many elements
      it has.  */
-  while (TREE_CODE (true_type) == ARRAY_TYPE)
-    {
-      tree this_nelts = array_type_nelts_top (true_type);
-      nelts = cp_build_binary_op (MULT_EXPR, nelts, this_nelts);
-      true_type = TREE_TYPE (true_type);
+  for (elt_type = type;
+       TREE_CODE (elt_type) == ARRAY_TYPE;
+       elt_type = TREE_TYPE (elt_type))
+    nelts = cp_build_binary_op (input_location,
+                               MULT_EXPR, nelts,
+                               array_type_nelts_top (elt_type),
+                               complain);
+
+  if (TREE_CODE (elt_type) == VOID_TYPE)
+    {
+      if (complain & tf_error)
+        error ("invalid type %<void%> for new");
+      return error_mark_node;
     }
 
-  if (!complete_type_or_else (true_type, exp))
+  if (abstract_virtuals_error (NULL_TREE, elt_type))
     return error_mark_node;
 
-  size = size_in_bytes (true_type);
-  if (has_array)
-    size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
+  is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init);
 
-  if (TREE_CODE (true_type) == VOID_TYPE)
+  if (CP_TYPE_CONST_P (elt_type) && !init
+      && !type_has_user_provided_default_constructor (elt_type))
     {
-      error ("invalid type `void' for new");
+      if (complain & tf_error)
+        error ("uninitialized const in %<new%> of %q#T", elt_type);
       return error_mark_node;
     }
 
-  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 new[].  */
-  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;
+  size = size_in_bytes (elt_type);
+  if (array_p)
+    size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
 
-  /* 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);
-    }
+  alloc_fn = NULL_TREE;
 
   /* Allocate the object.  */
-  
-  if (! placement && TYPE_FOR_JAVA (true_type))
+  if (! placement && TYPE_FOR_JAVA (elt_type))
     {
-      tree class_addr, alloc_decl;
-      tree class_decl = build_java_class_ref (true_type);
-      tree class_size = size_in_bytes (true_type);
+      tree class_addr;
+      tree class_decl = build_java_class_ref (elt_type);
       static const char alloc_name[] = "_Jv_AllocObject";
-      use_java_new = 1;
-      alloc_decl = IDENTIFIER_GLOBAL_VALUE (get_identifier (alloc_name));
-      if (alloc_decl == NULL_TREE)
-       fatal_error ("call to Java constructor with `%s' undefined",
-                    alloc_name);
 
+      if (class_decl == error_mark_node)
+       return error_mark_node;
+
+      use_java_new = 1;
+      if (!get_global_value_if_present (get_identifier (alloc_name),
+                                       &alloc_fn))
+       {
+          if (complain & tf_error)
+            error ("call to Java constructor with %qs undefined", alloc_name);
+         return error_mark_node;
+       }
+      else if (really_overloaded_fn (alloc_fn))
+       {
+          if (complain & tf_error)
+            error ("%qD should never be overloaded", alloc_fn);
+         return error_mark_node;
+       }
+      alloc_fn = OVL_CURRENT (alloc_fn);
       class_addr = build1 (ADDR_EXPR, jclass_node, class_decl);
-      alloc_call = (build_function_call
-                   (alloc_decl,
-                    tree_cons (NULL_TREE, class_addr,
-                               build_tree_list (NULL_TREE, class_size))));
+      alloc_call = (cp_build_function_call
+                   (alloc_fn,
+                    build_tree_list (NULL_TREE, class_addr),
+                    complain));
+    }
+  else if (TYPE_FOR_JAVA (elt_type) && MAYBE_CLASS_TYPE_P (elt_type))
+    {
+      error ("Java class %q#T object allocated using placement new", elt_type);
+      return error_mark_node;
     }
   else
     {
       tree fnname;
-      tree args;
+      tree fns;
 
-      args = tree_cons (NULL_TREE, size, placement);
-      fnname = ansi_opname (code);
+      fnname = ansi_opname (array_p ? VEC_NEW_EXPR : NEW_EXPR);
 
-      if (use_global_new)
-       alloc_call = (build_new_function_call 
-                     (lookup_function_nonclass (fnname, args),
-                      args));
+      if (!globally_qualified_p
+         && CLASS_TYPE_P (elt_type)
+         && (array_p
+             ? TYPE_HAS_ARRAY_NEW_OPERATOR (elt_type)
+             : TYPE_HAS_NEW_OPERATOR (elt_type)))
+       {
+         /* Use a class-specific operator new.  */
+         /* If a cookie is required, add some extra space.  */
+         if (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type))
+           {
+             cookie_size = targetm.cxx.get_cookie_size (elt_type);
+             size = size_binop (PLUS_EXPR, size, cookie_size);
+           }
+         /* Create the argument list.  */
+         args = tree_cons (NULL_TREE, size, placement);
+         /* Do name-lookup to find the appropriate operator.  */
+         fns = lookup_fnfields (elt_type, fnname, /*protect=*/2);
+         if (fns == NULL_TREE)
+           {
+              if (complain & tf_error)
+                error ("no suitable %qD found in class %qT", fnname, elt_type);
+             return error_mark_node;
+           }
+         if (TREE_CODE (fns) == TREE_LIST)
+           {
+              if (complain & tf_error)
+                {
+                  error ("request for member %qD is ambiguous", fnname);
+                  print_candidates (fns);
+                }
+             return error_mark_node;
+           }
+         alloc_call = build_new_method_call (build_dummy_object (elt_type),
+                                             fns, args,
+                                             /*conversion_path=*/NULL_TREE,
+                                             LOOKUP_NORMAL,
+                                             &alloc_fn,
+                                             complain);
+       }
       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 (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type))
+           cookie_size = targetm.cxx.get_cookie_size (elt_type);
+         else
+           cookie_size = NULL_TREE;
+
+         alloc_call = build_operator_new_call (fnname, placement,
+                                               &size, &cookie_size,
+                                               &alloc_fn);
+       }
     }
 
   if (alloc_call == error_mark_node)
     return error_mark_node;
 
-  /* 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);
+  gcc_assert (alloc_fn != NULL_TREE);
+
+  /* If PLACEMENT is a simple pointer type and is not passed by reference,
+     then copy it into PLACEMENT_EXPR.  */
+  if (!processing_template_decl
+      && placement != NULL_TREE
+      && TREE_CHAIN (placement) == NULL_TREE
+      && TREE_CODE (TREE_TYPE (TREE_VALUE (placement))) == POINTER_TYPE
+      && TREE_CODE (alloc_call) == CALL_EXPR
+      && call_expr_nargs (alloc_call) == 2
+      && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 0))) == INTEGER_TYPE
+      && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 1))) == POINTER_TYPE)
+    {
+      tree placement_arg = CALL_EXPR_ARG (alloc_call, 1);
+
+      if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg)))
+         || VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg))))
+       {
+         placement_expr = get_target_expr (TREE_VALUE (placement));
+         CALL_EXPR_ARG (alloc_call, 1)
+           = convert (TREE_TYPE (placement_arg), placement_expr);
+       }
+    }
+
+  /* In the simple case, we can stop now.  */
+  pointer_type = build_pointer_type (type);
+  if (!cookie_size && !is_initialized)
+    {
+      rval = build_nop (pointer_type, alloc_call);
+      if (placement != NULL)
+       rval = avoid_placement_new_aliasing (rval, placement_expr);
+      return rval;
+    }
+
+  /* Store the result of the allocation call in a variable so that we can
+     use it more than once.  */
+  alloc_expr = get_target_expr (alloc_call);
+  alloc_node = TARGET_EXPR_SLOT (alloc_expr);
+
+  /* Strip any COMPOUND_EXPRs from ALLOC_CALL.  */
+  while (TREE_CODE (alloc_call) == COMPOUND_EXPR)
+    alloc_call = TREE_OPERAND (alloc_call, 1);
+
   /* 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:
@@ -2366,10 +2025,21 @@ build_new_1 (exp)
      there is no explicit placement argument.  If there is more than
      one argument, or there are variable arguments, then this is a
      placement allocation function.  */
-  placement_allocation_fn_p 
-    = (type_num_arguments (TREE_TYPE (alloc_fn)) > 1 
+  placement_allocation_fn_p
+    = (type_num_arguments (TREE_TYPE (alloc_fn)) > 1
        || varargs_function_p (alloc_fn));
 
+  /* Preevaluate the placement args so that we don't reevaluate them for a
+     placement delete.  */
+  if (placement_allocation_fn_p)
+    {
+      tree inits;
+      stabilize_call (alloc_call, &inits);
+      if (inits)
+       alloc_expr = build2 (COMPOUND_EXPR, TREE_TYPE (alloc_expr), inits,
+                            alloc_expr);
+    }
+
   /*        unless an allocation function is declared with an empty  excep-
      tion-specification  (_except.spec_),  throw(), it indicates failure to
      allocate storage by throwing a bad_alloc exception  (clause  _except_,
@@ -2383,77 +2053,149 @@ build_new_1 (exp)
   nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
   check_new = (flag_check_new || nothrow) && ! use_java_new;
 
-  alloc_expr = alloc_call;
-
-  if (use_cookie)
-    /* Adjust so we're pointing to the start of the object.  */
-    alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr),
-                       alloc_expr, cookie_size);
-
-  /* While we're working, use a pointer to the type we've actually
-     allocated.  */
-  alloc_expr = convert (build_pointer_type (full_type), alloc_expr);
-
-  /* Now save the allocation expression so we only evaluate it once.  */
-  alloc_expr = get_target_expr (alloc_expr);
-  alloc_node = TREE_OPERAND (alloc_expr, 0);
-
-  /* Now initialize the cookie.  */
-  if (use_cookie)
+  if (cookie_size)
     {
       tree cookie;
+      tree cookie_ptr;
+      tree size_ptr_type;
+
+      /* Adjust so we're pointing to the start of the object.  */
+      data_addr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (alloc_node),
+                         alloc_node, cookie_size);
 
       /* Store the number of bytes allocated so that we can know how
         many elements to destroy later.  We use the last sizeof
         (size_t) bytes to store the number of elements.  */
-      cookie = build (MINUS_EXPR, build_pointer_type (sizetype),
-                     alloc_node, size_in_bytes (sizetype));
-      cookie = build_indirect_ref (cookie, NULL);
+      cookie_ptr = size_binop (MINUS_EXPR, cookie_size, size_in_bytes (sizetype));
+      cookie_ptr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (alloc_node),
+                               alloc_node, cookie_ptr);
+      size_ptr_type = build_pointer_type (sizetype);
+      cookie_ptr = fold_convert (size_ptr_type, cookie_ptr);
+      cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain);
+
+      cookie_expr = build2 (MODIFY_EXPR, sizetype, cookie, nelts);
 
-      cookie_expr = build (MODIFY_EXPR, void_type_node, cookie, nelts);
-      TREE_SIDE_EFFECTS (cookie_expr) = 1;
+      if (targetm.cxx.cookie_has_size ())
+       {
+         /* Also store the element size.  */
+         cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type, cookie_ptr,
+                              fold_build1 (NEGATE_EXPR, sizetype,
+                                           size_in_bytes (sizetype)));
+
+         cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain);
+         cookie = build2 (MODIFY_EXPR, sizetype, cookie,
+                          size_in_bytes (elt_type));
+         cookie_expr = build2 (COMPOUND_EXPR, TREE_TYPE (cookie_expr),
+                               cookie, cookie_expr);
+       }
     }
   else
-    cookie_expr = NULL_TREE;
+    {
+      cookie_expr = NULL_TREE;
+      data_addr = alloc_node;
+    }
 
-  /* Now initialize the allocated object.  */
-  init_expr = NULL_TREE;
-  if (TYPE_NEEDS_CONSTRUCTING (type) || init)
+  /* Now use a pointer to the type we've actually allocated.  */
+  data_addr = fold_convert (pointer_type, data_addr);
+  /* Any further uses of alloc_node will want this type, too.  */
+  alloc_node = fold_convert (pointer_type, alloc_node);
+
+  /* Now initialize the allocated object.  Note that we preevaluate the
+     initialization expression, apart from the actual constructor call or
+     assignment--we do this because we want to delay the allocation as long
+     as possible in order to minimize the size of the exception region for
+     placement delete.  */
+  if (is_initialized)
     {
-      init_expr = build_indirect_ref (alloc_node, NULL);
+      bool stable;
+      bool explicit_value_init_p = false;
 
       if (init == void_zero_node)
-       init = build_default_init (full_type);
-      else if (init && pedantic && has_array)
-       pedwarn ("ISO C++ forbids initialization in array new");
+       {
+         init = NULL_TREE;
+         explicit_value_init_p = true;
+       }
 
-      if (has_array)
-       init_expr = build_vec_init (init_expr, init, 0);
-      else if (TYPE_NEEDS_CONSTRUCTING (type))
-       init_expr = build_method_call (init_expr, 
-                                      complete_ctor_identifier,
-                                      init, TYPE_BINFO (true_type),
-                                      LOOKUP_NORMAL);
+      if (array_p)
+       {
+         tree non_const_pointer_type = build_pointer_type
+           (cp_build_qualified_type (type, TYPE_QUALS (type) & ~TYPE_QUAL_CONST));
+
+         if (init && TREE_CHAIN (init) == NULL_TREE
+             && BRACE_ENCLOSED_INITIALIZER_P (TREE_VALUE (init))
+             && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
+           {
+             tree arraytype, domain;
+             init = TREE_VALUE (init);
+             if (TREE_CONSTANT (nelts))
+               domain = compute_array_index_type (NULL_TREE, nelts);
+             else
+               {
+                 domain = NULL_TREE;
+                 if (CONSTRUCTOR_NELTS (init) > 0)
+                   warning (0, "non-constant array size in new, unable to "
+                            "verify length of initializer-list");
+               }
+             arraytype = build_cplus_array_type (type, domain);
+             init = digest_init (arraytype, init);
+           }
+         else if (init)
+            {
+              if (complain & tf_error)
+                permerror (input_location, "ISO C++ forbids initialization in array new");
+              else
+                return error_mark_node;
+            }
+         init_expr
+           = build_vec_init (fold_convert (non_const_pointer_type, data_addr),
+                             cp_build_binary_op (input_location,
+                                                 MINUS_EXPR, outer_nelts,
+                                                 integer_one_node,
+                                                 complain),
+                             init,
+                             explicit_value_init_p,
+                             /*from_array=*/0,
+                              complain);
+
+         /* An array initialization is stable because the initialization
+            of each element is a full-expression, so the temporaries don't
+            leak out.  */
+         stable = true;
+       }
       else
        {
-         /* We are processing something like `new int (10)', which
-            means allocate an int, and initialize it with 10.  */
+         init_expr = cp_build_indirect_ref (data_addr, NULL, complain);
 
-         if (TREE_CODE (init) == TREE_LIST)
+         if (TYPE_NEEDS_CONSTRUCTING (type) && !explicit_value_init_p)
            {
-             if (TREE_CHAIN (init) != NULL_TREE)
-               pedwarn
-                 ("initializer list being treated as compound expression");
-             init = build_compound_expr (init);
+             init_expr = build_special_member_call (init_expr,
+                                                    complete_ctor_identifier,
+                                                    init, elt_type,
+                                                    LOOKUP_NORMAL,
+                                                     complain);
            }
-         else if (TREE_CODE (init) == CONSTRUCTOR
-                  && TREE_TYPE (init) == NULL_TREE)
+         else if (explicit_value_init_p)
            {
-             pedwarn ("ISO C++ forbids aggregate initializer to new");
-             init = digest_init (type, init, 0);
+             /* Something like `new int()'.  */
+             init_expr = build2 (INIT_EXPR, type,
+                                 init_expr, build_value_init (type));
            }
+         else
+           {
+             /* We are processing something like `new int (10)', which
+                means allocate an int, and initialize it with 10.  */
+
+             if (TREE_CODE (init) == TREE_LIST)
+               init = build_x_compound_expr_from_list (init,
+                                                       "new initializer");
+             else
+               gcc_assert (TREE_CODE (init) != CONSTRUCTOR
+                           || TREE_TYPE (init) != NULL_TREE);
 
-         init_expr = build_modify_expr (init_expr, INIT_EXPR, init);
+             init_expr = cp_build_modify_expr (init_expr, INIT_EXPR, init,
+                                               complain);
+           }
+         stable = stabilize_init (init_expr, &init_preeval_expr);
        }
 
       if (init_expr == error_mark_node)
@@ -2469,109 +2211,263 @@ build_new_1 (exp)
         freed.  */
       if (flag_exceptions && ! use_java_new)
        {
-         enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
+         enum tree_code dcode = array_p ? VEC_DELETE_EXPR : DELETE_EXPR;
          tree cleanup;
-         int flags = (LOOKUP_NORMAL 
-                      | (globally_qualified_p * LOOKUP_GLOBAL));
-         tree delete_node;
-
-         if (use_cookie)
-           /* 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, delete_node, size, flags,
-                                         (placement_allocation_fn_p 
-                                          ? alloc_call : NULL_TREE));
-
-         /* Ack!  First we allocate the memory.  Then we set our sentry
-            variable to true, and expand a cleanup that deletes the memory
-            if sentry is true.  Then we run the constructor, and finally
-            clear the sentry.
-
-            It would be nice to be able to handle this without the sentry
-            variable, perhaps with a TRY_CATCH_EXPR, but this doesn't
-            work.  We allocate the space first, so if there are any
-            temporaries with cleanups in the constructor args we need this
-            EH region to extend until end of full-expression to preserve
-            nesting.
-
-            If the backend had some mechanism so that we could force the
-            allocation to be expanded after all the other args to the
-            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 (cleanup)
+            is to use the same method for finding deallocation
+            functions that we use for finding allocation functions.  */
+         cleanup = (build_op_delete_call
+                    (dcode,
+                     alloc_node,
+                     size,
+                     globally_qualified_p,
+                     placement_allocation_fn_p ? alloc_call : NULL_TREE,
+                     alloc_fn));
+
+         if (!cleanup)
+           /* We're done.  */;
+         else if (stable)
+           /* This is much simpler if we were able to preevaluate all of
+              the arguments to the constructor call.  */
+           init_expr = build2 (TRY_CATCH_EXPR, void_type_node,
+                               init_expr, cleanup);
+         else
+           /* Ack!  First we allocate the memory.  Then we set our sentry
+              variable to true, and expand a cleanup that deletes the
+              memory if sentry is true.  Then we run the constructor, and
+              finally clear the sentry.
+
+              We need to do this because we allocate the space first, so
+              if there are any temporaries with cleanups in the
+              constructor args and we weren't able to preevaluate them, we
+              need this EH region to extend until end of full-expression
+              to preserve nesting.  */
            {
              tree end, sentry, begin;
 
              begin = get_target_expr (boolean_true_node);
-             sentry = TREE_OPERAND (begin, 0);
+             CLEANUP_EH_ONLY (begin) = 1;
 
-             TREE_OPERAND (begin, 2)
-               = build (COND_EXPR, void_type_node, sentry,
-                        cleanup, void_zero_node);
+             sentry = TARGET_EXPR_SLOT (begin);
 
-             end = build (MODIFY_EXPR, TREE_TYPE (sentry),
-                          sentry, boolean_false_node);
+             TARGET_EXPR_CLEANUP (begin)
+               = build3 (COND_EXPR, void_type_node, sentry,
+                         cleanup, void_zero_node);
+
+             end = build2 (MODIFY_EXPR, TREE_TYPE (sentry),
+                           sentry, boolean_false_node);
 
              init_expr
-               = build (COMPOUND_EXPR, void_type_node, begin,
-                        build (COMPOUND_EXPR, void_type_node, init_expr,
-                               end));
+               = build2 (COMPOUND_EXPR, void_type_node, begin,
+                         build2 (COMPOUND_EXPR, void_type_node, init_expr,
+                                 end));
            }
+
        }
     }
-  else if (CP_TYPE_CONST_P (true_type))
-    error ("uninitialized const in `new' of `%#T'", true_type);
+  else
+    init_expr = NULL_TREE;
 
   /* Now build up the return value in reverse order.  */
 
-  rval = alloc_node;
+  rval = data_addr;
 
   if (init_expr)
-    rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval);
+    rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval);
   if (cookie_expr)
-    rval = build (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
+    rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
 
-  if (rval == alloc_node)
-    /* If we didn't modify anything, strip the TARGET_EXPR and return the
-       (adjusted) call.  */
-    rval = TREE_OPERAND (alloc_expr, 1);
+  if (rval == data_addr)
+    /* If we don't have an initializer or a cookie, strip the TARGET_EXPR
+       and return the call (which doesn't need to be adjusted).  */
+    rval = TARGET_EXPR_INITIAL (alloc_expr);
   else
     {
       if (check_new)
        {
-         tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node,
-                                          integer_zero_node);
-         rval = build_conditional_expr (ifexp, rval, alloc_node);
+         tree ifexp = cp_build_binary_op (input_location,
+                                          NE_EXPR, alloc_node,
+                                          integer_zero_node,
+                                          complain);
+         rval = build_conditional_expr (ifexp, rval, alloc_node, 
+                                         complain);
        }
 
-      rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
+      /* Perform the allocation before anything else, so that ALLOC_NODE
+        has been initialized before we start using it.  */
+      rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
+    }
+
+  if (init_preeval_expr)
+    rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), init_preeval_expr, rval);
+
+  /* A new-expression is never an lvalue.  */
+  gcc_assert (!lvalue_p (rval));
+
+  if (placement != NULL)
+    rval = avoid_placement_new_aliasing (rval, placement_expr);
+
+  return rval;
+}
+
+/* Generate a representation for a C++ "new" expression.  PLACEMENT is
+   a TREE_LIST of placement-new arguments (or NULL_TREE if none).  If
+   NELTS is NULL, TYPE is the type of the storage to be allocated.  If
+   NELTS is not NULL, then this is an array-new allocation; TYPE is
+   the type of the elements in the array and NELTS is the number of
+   elements in the array.  INIT, if non-NULL, is the initializer for
+   the new object, or void_zero_node to indicate an initializer of
+   "()".  If USE_GLOBAL_NEW is true, then the user explicitly wrote
+   "::new" rather than just "new".  */
+
+tree
+build_new (tree placement, tree type, tree nelts, tree init,
+          int use_global_new, tsubst_flags_t complain)
+{
+  tree rval;
+  tree orig_placement;
+  tree orig_nelts;
+  tree orig_init;
+
+  if (placement == error_mark_node || type == error_mark_node
+      || init == error_mark_node)
+    return error_mark_node;
+
+  orig_placement = placement;
+  orig_nelts = nelts;
+  orig_init = init;
+
+  if (nelts == NULL_TREE && init != void_zero_node && list_length (init) == 1)
+    {
+      tree auto_node = type_uses_auto (type);
+      if (auto_node && describable_type (TREE_VALUE (init)))
+       type = do_auto_deduction (type, TREE_VALUE (init), auto_node);
+    }
+
+  if (processing_template_decl)
+    {
+      if (dependent_type_p (type)
+         || any_type_dependent_arguments_p (placement)
+         || (nelts && type_dependent_expression_p (nelts))
+         || (init != void_zero_node
+             && any_type_dependent_arguments_p (init)))
+       return build_raw_new_expr (placement, type, nelts, init,
+                                  use_global_new);
+      placement = build_non_dependent_args (placement);
+      if (nelts)
+       nelts = build_non_dependent_expr (nelts);
+      if (init != void_zero_node)
+       init = build_non_dependent_args (init);
+    }
+
+  if (nelts)
+    {
+      if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false))
+        {
+          if (complain & tf_error)
+            permerror (input_location, "size in array new must have integral type");
+          else
+            return error_mark_node;
+        }
+      nelts = cp_save_expr (cp_convert (sizetype, nelts));
+    }
+
+  /* ``A reference cannot be created by the new operator.  A reference
+     is not an object (8.2.2, 8.4.3), so a pointer to it could not be
+     returned by new.'' ARM 5.3.3 */
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      if (complain & tf_error)
+        error ("new cannot be applied to a reference type");
+      else
+        return error_mark_node;
+      type = TREE_TYPE (type);
+    }
+
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    {
+      if (complain & tf_error)
+        error ("new cannot be applied to a function type");
+      return error_mark_node;
     }
 
-  /* Now strip the outer ARRAY_TYPE, so we return a pointer to the first
-     element.  */
-  rval = convert (build_pointer_type (type), rval);
+  /* The type allocated must be complete.  If the new-type-id was
+     "T[N]" then we are just checking that "T" is complete here, but
+     that is equivalent, since the value of "N" doesn't matter.  */
+  if (!complete_type_or_else (type, NULL_TREE))
+    return error_mark_node;
+
+  rval = build_new_1 (placement, type, nelts, init, use_global_new, complain);
+  if (rval == error_mark_node)
+    return error_mark_node;
+
+  if (processing_template_decl)
+    return build_raw_new_expr (orig_placement, type, orig_nelts, orig_init,
+                              use_global_new);
+
+  /* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain.  */
+  rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval);
+  TREE_NO_WARNING (rval) = 1;
 
   return rval;
 }
+
+/* Given a Java class, return a decl for the corresponding java.lang.Class.  */
+
+tree
+build_java_class_ref (tree type)
+{
+  tree name = NULL_TREE, class_decl;
+  static tree CL_suffix = NULL_TREE;
+  if (CL_suffix == NULL_TREE)
+    CL_suffix = get_identifier("class$");
+  if (jclass_node == NULL_TREE)
+    {
+      jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jclass"));
+      if (jclass_node == NULL_TREE)
+       {
+         error ("call to Java constructor, while %<jclass%> undefined");
+         return error_mark_node;
+       }
+      jclass_node = TREE_TYPE (jclass_node);
+    }
+
+  /* Mangle the class$ field.  */
+  {
+    tree field;
+    for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+      if (DECL_NAME (field) == CL_suffix)
+       {
+         mangle_decl (field);
+         name = DECL_ASSEMBLER_NAME (field);
+         break;
+       }
+    if (!field)
+      {
+       error ("can't find %<class$%> in %qT", type);
+       return error_mark_node;
+      }
+  }
+
+  class_decl = IDENTIFIER_GLOBAL_VALUE (name);
+  if (class_decl == NULL_TREE)
+    {
+      class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node));
+      TREE_STATIC (class_decl) = 1;
+      DECL_EXTERNAL (class_decl) = 1;
+      TREE_PUBLIC (class_decl) = 1;
+      DECL_ARTIFICIAL (class_decl) = 1;
+      DECL_IGNORED_P (class_decl) = 1;
+      pushdecl_top_level (class_decl);
+      make_decl_rtl (class_decl);
+    }
+  return class_decl;
+}
 \f
 static tree
-build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
-     tree base, maxindex, type;
-     special_function_kind auto_delete_vec;
-     int use_global_delete;
+build_vec_delete_1 (tree base, tree maxindex, tree type,
+    special_function_kind auto_delete_vec, int use_global_delete)
 {
   tree virtual_size;
   tree ptype = build_pointer_type (type = complete_type (type));
@@ -2585,7 +2481,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
   tree body;
 
   /* This is the LOOP_EXPR that governs the deletion of the elements.  */
-  tree loop;
+  tree loop = 0;
 
   /* This is the thing that governs what to do after the loop has run.  */
   tree deallocate_expr = 0;
@@ -2595,56 +2491,47 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
      executing any other code in the loop.
      This is also the containing expression returned by this function.  */
   tree controller = NULL_TREE;
+  tree tmp;
 
   /* We should only have 1-D arrays here.  */
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    abort ();
+  gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
 
-  if (! IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
-    {
-      loop = integer_zero_node;
-      goto no_destructor;
-    }
+  if (! MAYBE_CLASS_TYPE_P (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
+    goto no_destructor;
 
   /* The below is short by the cookie size.  */
   virtual_size = size_binop (MULT_EXPR, size_exp,
                             convert (sizetype, maxindex));
 
   tbase = create_temporary_var (ptype);
-  tbase_init = build_modify_expr (tbase, NOP_EXPR,
-                                 fold (build (PLUS_EXPR, ptype,
-                                              base,
-                                              virtual_size)));
+  tbase_init = cp_build_modify_expr (tbase, NOP_EXPR,
+                                    fold_build2 (POINTER_PLUS_EXPR, ptype,
+                                                 fold_convert (ptype, base),
+                                                 virtual_size),
+                                    tf_warning_or_error);
   DECL_REGISTER (tbase) = 1;
-  controller = build (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE);
+  controller = build3 (BIND_EXPR, void_type_node, tbase,
+                      NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (controller) = 1;
 
-  body = NULL_TREE;
-
-  body = tree_cons (NULL_TREE,
-                   build_delete (ptype, tbase, sfk_complete_destructor,
-                                 LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1),
-                   body);
-
-  body = tree_cons (NULL_TREE,
-                   build_modify_expr (tbase, NOP_EXPR, build (MINUS_EXPR, ptype, tbase, size_exp)),
-                   body);
-
-  body = tree_cons (NULL_TREE,
-                   build (EXIT_EXPR, void_type_node,
-                          build (EQ_EXPR, boolean_type_node, base, tbase)),
-                   body);
-
-  loop = build (LOOP_EXPR, void_type_node, build_compound_expr (body));
-
-  loop = tree_cons (NULL_TREE, tbase_init,
-                   tree_cons (NULL_TREE, loop, NULL_TREE));
-  loop = build_compound_expr (loop);
+  body = build1 (EXIT_EXPR, void_type_node,
+                build2 (EQ_EXPR, boolean_type_node, tbase,
+                        fold_convert (ptype, base)));
+  tmp = fold_build1 (NEGATE_EXPR, sizetype, size_exp);
+  body = build_compound_expr
+    (body, cp_build_modify_expr (tbase, NOP_EXPR,
+                                build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp),
+                                tf_warning_or_error));
+  body = build_compound_expr
+    (body, build_delete (ptype, tbase, sfk_complete_destructor,
+                        LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
+
+  loop = build1 (LOOP_EXPR, void_type_node, body);
+  loop = build_compound_expr (tbase_init, loop);
 
  no_destructor:
   /* If the delete flag is one, or anything else with the low bit set,
      delete the storage.  */
-  deallocate_expr = integer_zero_node;
   if (auto_delete_vec != sfk_base_destructor)
     {
       tree base_tbd;
@@ -2660,62 +2547,71 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
        {
          tree cookie_size;
 
-         cookie_size = get_cookie_size (type);
-         base_tbd 
+         cookie_size = targetm.cxx.get_cookie_size (type);
+         base_tbd
            = cp_convert (ptype,
-                         cp_build_binary_op (MINUS_EXPR,
-                                             cp_convert (string_type_node, 
+                         cp_build_binary_op (input_location,
+                                             MINUS_EXPR,
+                                             cp_convert (string_type_node,
                                                          base),
-                                             cookie_size));
+                                             cookie_size,
+                                             tf_warning_or_error));
          /* True size with header.  */
          virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size);
        }
 
       if (auto_delete_vec == sfk_deleting_destructor)
-       deallocate_expr = build_x_delete (base_tbd,
-                                         2 | use_global_delete,
-                                         virtual_size);
-    }
-
-  if (loop && deallocate_expr != integer_zero_node)
-    {
-      body = tree_cons (NULL_TREE, loop,
-                       tree_cons (NULL_TREE, deallocate_expr, NULL_TREE));
-      body = build_compound_expr (body);
-    }
+       deallocate_expr = build_op_delete_call (VEC_DELETE_EXPR,
+                                               base_tbd, virtual_size,
+                                               use_global_delete & 1,
+                                               /*placement=*/NULL_TREE,
+                                               /*alloc_fn=*/NULL_TREE);
+    }
+
+  body = loop;
+  if (!deallocate_expr)
+    ;
+  else if (!body)
+    body = deallocate_expr;
   else
-    body = loop;
+    body = build_compound_expr (body, deallocate_expr);
+
+  if (!body)
+    body = integer_zero_node;
 
   /* Outermost wrapper: If pointer is null, punt.  */
-  body = fold (build (COND_EXPR, void_type_node,
-                     fold (build (NE_EXPR, boolean_type_node, base,
-                                  integer_zero_node)),
-                     body, integer_zero_node));
+  body = fold_build3 (COND_EXPR, void_type_node,
+                     fold_build2 (NE_EXPR, boolean_type_node, base,
+                                  convert (TREE_TYPE (base),
+                                           integer_zero_node)),
+                     body, integer_zero_node);
   body = build1 (NOP_EXPR, void_type_node, body);
 
   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 = build2 (COMPOUND_EXPR, void_type_node, base, body);
+
+  return convert_to_void (body, /*implicit=*/NULL, tf_warning_or_error);
 }
 
-/* Create an unnamed variable of the indicated TYPE.  */ 
+/* Create an unnamed variable of the indicated TYPE.  */
 
 tree
-create_temporary_var (type)
-     tree type;
+create_temporary_var (tree type)
 {
   tree decl;
+
   decl = build_decl (VAR_DECL, NULL_TREE, type);
   TREE_USED (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
-  DECL_SOURCE_FILE (decl) = input_filename;
-  DECL_SOURCE_LINE (decl) = lineno;
   DECL_IGNORED_P (decl) = 1;
+  DECL_SOURCE_LOCATION (decl) = input_location;
   DECL_CONTEXT (decl) = current_function_decl;
 
   return decl;
@@ -2729,17 +2625,15 @@ create_temporary_var (type)
    "outside" the binding contour of the function).  */
 
 static tree
-get_temp_regvar (type, init)
-     tree type, init;
+get_temp_regvar (tree type, tree init)
 {
   tree decl;
 
   decl = create_temporary_var (type);
-  if (building_stmt_tree ())
-    add_decl_stmt (decl);
-  if (!building_stmt_tree ())
-    SET_DECL_RTL (decl, assign_temp (type, 2, 0, 1));
-  finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
+  add_decl_expr (decl);
+
+  finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init, 
+                                         tf_warning_or_error));
 
   return decl;
 }
@@ -2747,9 +2641,17 @@ get_temp_regvar (type, init)
 /* `build_vec_init' returns tree structure that performs
    initialization of a vector of aggregate types.
 
-   BASE is a reference to the vector, of ARRAY_TYPE.
+   BASE is a reference to the vector, of ARRAY_TYPE, or a pointer
+     to the first element, of POINTER_TYPE.
+   MAXINDEX is the maximum index of the array (one less than the
+     number of elements).  It is only used if BASE is a pointer or
+     TYPE_DOMAIN (TREE_TYPE (BASE)) == NULL_TREE.
+
    INIT is the (possibly NULL) initializer.
 
+   If EXPLICIT_VALUE_INIT_P is true, then INIT must be NULL.  All
+   elements in the array are value-initialized.
+
    FROM_ARRAY is 0 if we should init everything with INIT
    (i.e., every element initialized from INIT).
    FROM_ARRAY is 1 if we should index into INIT in parallel
@@ -2758,95 +2660,127 @@ get_temp_regvar (type, init)
    but use assignment instead of initialization.  */
 
 tree
-build_vec_init (base, init, from_array)
-     tree base, init;
-     int from_array;
+build_vec_init (tree base, tree maxindex, tree init,
+               bool explicit_value_init_p,
+               int from_array, tsubst_flags_t complain)
 {
   tree rval;
   tree base2 = NULL_TREE;
   tree size;
   tree itype = NULL_TREE;
   tree iterator;
-  /* The type of the array.  */
+  /* The type of BASE.  */
   tree atype = TREE_TYPE (base);
   /* The type of an element in the array.  */
   tree type = TREE_TYPE (atype);
+  /* The element type reached after removing all outer array
+     types.  */
+  tree inner_elt_type;
   /* The type of a pointer to an element in the array.  */
   tree ptype;
   tree stmt_expr;
   tree compound_stmt;
   int destroy_temps;
   tree try_block = NULL_TREE;
-  tree try_body = NULL_TREE;
   int num_initialized_elts = 0;
-  tree maxindex = array_type_nelts (TREE_TYPE (base));
+  bool is_global;
 
-  if (maxindex == error_mark_node)
+  if (TREE_CODE (atype) == ARRAY_TYPE && 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 (explicit_value_init_p)
+    gcc_assert (!init);
+
+  inner_elt_type = strip_array_types (type);
+
+  /* Look through the TARGET_EXPR around a compound literal.  */
+  if (init && TREE_CODE (init) == TARGET_EXPR
+      && TREE_CODE (TARGET_EXPR_INITIAL (init)) == CONSTRUCTOR
+      && from_array != 2)
+    init = TARGET_EXPR_INITIAL (init);
+
+  if (init
+      && TREE_CODE (atype) == ARRAY_TYPE
+      && (from_array == 2
+         ? (!CLASS_TYPE_P (inner_elt_type)
+            || !TYPE_HAS_COMPLEX_ASSIGN_REF (inner_elt_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.  */
-          && (CONSTRUCTOR_ELTS (init) == NULL_TREE
-              || ! TYPE_HAS_NONTRIVIAL_DESTRUCTOR (target_type (type))))
+          && (VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (init))
+              || ! TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_elt_type)))
          || from_array))
     {
       /* Do non-default initialization of POD arrays resulting from
         brace-enclosed initializers.  In this case, digest_init and
         store_constructor will handle the semantics for us.  */
 
-      stmt_expr = build (INIT_EXPR, atype, base, init);
-      TREE_SIDE_EFFECTS (stmt_expr) = 1;
+      stmt_expr = build2 (INIT_EXPR, atype, base, init);
       return stmt_expr;
     }
 
   maxindex = cp_convert (ptrdiff_type_node, maxindex);
-  ptype = build_pointer_type (type);
   size = size_in_bytes (type);
-  if (TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE)
-    base = cp_convert (ptype, default_conversion (base));
+  if (TREE_CODE (atype) == ARRAY_TYPE)
+    {
+      ptype = build_pointer_type (type);
+      base = cp_convert (ptype, decay_conversion (base));
+    }
+  else
+    ptype = atype;
 
   /* The code we are generating looks like:
-
+     ({
        T* t1 = (T*) base;
        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 ...
+        ... destroy elements that were constructed ...
        }
-       return rval;
-       
+       rval;
+     })
+
      We can omit the try and catch blocks if we know that the
      initialization will never throw an exception, or if the array
      elements do not have destructors.  We can omit the loop completely if
-     the elements of the array do not have constructors.  
+     the elements of the array do not have constructors.
 
      We actually wrap the entire body of the above in a STMT_EXPR, for
-     tidiness.  
+     tidiness.
 
      When copying from array to another, when the array elements have
      only trivial copy constructors, we should use __builtin_memcpy
      rather than generating a loop.  That way, we could take advantage
-     of whatever cleverness the back-end has for dealing with copies
+     of whatever cleverness the back end has for dealing with copies
      of blocks of memory.  */
 
-  begin_init_stmts (&stmt_expr, &compound_stmt);
+  is_global = begin_init_stmts (&stmt_expr, &compound_stmt);
   destroy_temps = stmts_are_full_exprs_p ();
   current_stmt_tree ()->stmts_are_full_exprs_p = 0;
   rval = get_temp_regvar (ptype, base);
   base = get_temp_regvar (ptype, rval);
   iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
 
+  /* If initializing one array from another, initialize element by
+     element.  We rely upon the below calls to do the argument
+     checking.  Evaluate the initializer before entering the try block.  */
+  if (from_array && init && TREE_CODE (init) != CONSTRUCTOR)
+    {
+      base2 = decay_conversion (init);
+      itype = TREE_TYPE (base2);
+      base2 = get_temp_regvar (itype, base2);
+      itype = TREE_TYPE (itype);
+    }
+
   /* Protect the entire array initialization so that we can destroy
      the partially constructed array if an exception is thrown.
      But don't do this if we're assigning.  */
@@ -2854,32 +2788,34 @@ build_vec_init (base, init, from_array)
       && from_array != 2)
     {
       try_block = begin_try_block ();
-      try_body = begin_compound_stmt (/*has_no_scope=*/1);
     }
 
   if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
     {
       /* Do non-default initialization of non-POD arrays resulting from
         brace-enclosed initializers.  */
-
-      tree elts;
+      unsigned HOST_WIDE_INT idx;
+      tree elt;
       from_array = 0;
 
-      for (elts = CONSTRUCTOR_ELTS (init); elts; elts = TREE_CHAIN (elts))
+      FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt)
        {
-         tree elt = TREE_VALUE (elts);
          tree baseref = build1 (INDIRECT_REF, type, base);
 
          num_initialized_elts++;
 
-         if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE)
-           finish_expr_stmt (build_aggr_init (baseref, elt, 0));
+         current_stmt_tree ()->stmts_are_full_exprs_p = 1;
+         if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
+           finish_expr_stmt (build_aggr_init (baseref, elt, 0, complain));
          else
-           finish_expr_stmt (build_modify_expr (baseref, NOP_EXPR,
-                                                elt));
+           finish_expr_stmt (cp_build_modify_expr (baseref, NOP_EXPR,
+                                                    elt, complain));
+         current_stmt_tree ()->stmts_are_full_exprs_p = 0;
 
-         finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base, 0));
-         finish_expr_stmt (build_unary_op (PREDECREMENT_EXPR, iterator, 0));
+         finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
+                                               complain));
+         finish_expr_stmt (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+                                               complain));
        }
 
       /* Clear out INIT so that we don't get confused below.  */
@@ -2887,21 +2823,14 @@ build_vec_init (base, init, from_array)
     }
   else if (from_array)
     {
-      /* If initializing one array from another, initialize element by
-        element.  We rely upon the below calls the do argument
-        checking.  */ 
       if (init)
-       {
-         base2 = default_conversion (init);
-         itype = TREE_TYPE (base2);
-         base2 = get_temp_regvar (itype, base2);
-         itype = TREE_TYPE (itype);
-       }
+       /* OK, we set base2 above.  */;
       else if (TYPE_LANG_SPECIFIC (type)
               && TYPE_NEEDS_CONSTRUCTING (type)
               && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
        {
-         error ("initializer ends prematurely");
+          if (complain & tf_error)
+            error ("initializer ends prematurely");
          return error_mark_node;
        }
     }
@@ -2913,44 +2842,30 @@ build_vec_init (base, init, from_array)
      We do need to keep going if we're copying an array.  */
 
   if (from_array
-      || (TYPE_NEEDS_CONSTRUCTING (type)
+      || ((TYPE_NEEDS_CONSTRUCTING (type) || explicit_value_init_p)
          && ! (host_integerp (maxindex, 0)
                && (num_initialized_elts
                    == tree_low_cst (maxindex, 0) + 1))))
     {
       /* If the ITERATOR is equal to -1, then we don't have to loop;
         we've already initialized all the elements.  */
-      tree if_stmt;
-      tree do_stmt;
-      tree do_body;
+      tree for_stmt;
       tree elt_init;
+      tree to;
+
+      for_stmt = begin_for_stmt ();
+      finish_for_init_stmt (for_stmt);
+      finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator,
+                              build_int_cst (TREE_TYPE (iterator), -1)),
+                      for_stmt);
+      finish_for_expr (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+                                          complain),
+                      for_stmt);
 
-      if_stmt = begin_if_stmt ();
-      finish_if_stmt_cond (build (NE_EXPR, boolean_type_node,
-                                 iterator, integer_minus_one_node),
-                          if_stmt);
-
-      /* Otherwise, loop through the elements.  */
-      do_stmt = begin_do_stmt ();
-      do_body = begin_compound_stmt (/*has_no_scope=*/1);
-
-      /* When we're not building a statement-tree, things are a little
-        complicated.  If, when we recursively call build_aggr_init,
-        an expression containing a TARGET_EXPR is expanded, then it
-        may get a cleanup.  Then, the result of that expression is
-        passed to finish_expr_stmt, which will call
-        expand_start_target_temps/expand_end_target_temps.  However,
-        the latter call will not cause the cleanup to run because
-        that block will still be on the block stack.  So, we call
-        expand_start_target_temps here manually; the corresponding
-        call to expand_end_target_temps below will cause the cleanup
-        to be performed.  */
-      if (!building_stmt_tree ())
-       expand_start_target_temps ();
+      to = build1 (INDIRECT_REF, type, base);
 
       if (from_array)
        {
-         tree to = build1 (INDIRECT_REF, type, base);
          tree from;
 
          if (base2)
@@ -2959,13 +2874,15 @@ build_vec_init (base, init, from_array)
            from = NULL_TREE;
 
          if (from_array == 2)
-           elt_init = build_modify_expr (to, NOP_EXPR, from);
+           elt_init = cp_build_modify_expr (to, NOP_EXPR, from, 
+                                            complain);
          else if (TYPE_NEEDS_CONSTRUCTING (type))
-           elt_init = build_aggr_init (to, from, 0);
+           elt_init = build_aggr_init (to, from, 0, complain);
          else if (from)
-           elt_init = build_modify_expr (to, NOP_EXPR, from);
+           elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
+                                            complain);
          else
-           abort ();
+           gcc_unreachable ();
        }
       else if (TREE_CODE (type) == ARRAY_TYPE)
        {
@@ -2973,39 +2890,30 @@ 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,
+                                    explicit_value_init_p,
+                                    0, complain);
        }
+      else if (explicit_value_init_p)
+       elt_init = build2 (INIT_EXPR, type, to,
+                          build_value_init (type));
       else
-       elt_init = build_aggr_init (build1 (INDIRECT_REF, type, base), 
-                                   init, 0);
-      
-      /* The initialization of each array element is a
-        full-expression, as per core issue 124.  */
-      if (!building_stmt_tree ())
        {
-         genrtl_expr_stmt (elt_init);
-         expand_end_target_temps ();
-       }
-      else
-       {
-         current_stmt_tree ()->stmts_are_full_exprs_p = 1;
-         finish_expr_stmt (elt_init);
-         current_stmt_tree ()->stmts_are_full_exprs_p = 0;
+         gcc_assert (TYPE_NEEDS_CONSTRUCTING (type));
+         elt_init = build_aggr_init (to, init, 0, complain);
        }
 
-      finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base, 0));
-      if (base2)
-       finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base2, 0));
+      current_stmt_tree ()->stmts_are_full_exprs_p = 1;
+      finish_expr_stmt (elt_init);
+      current_stmt_tree ()->stmts_are_full_exprs_p = 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_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
+                                           complain));
+      if (base2)
+       finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base2, 0,
+                                             complain));
 
-      finish_then_clause (if_stmt);
-      finish_if_stmt ();
+      finish_for_stmt (for_stmt);
     }
 
   /* Make sure to cleanup any partially constructed elements.  */
@@ -3013,74 +2921,51 @@ build_vec_init (base, init, from_array)
       && from_array != 2)
     {
       tree e;
-      tree m = cp_build_binary_op (MINUS_EXPR, maxindex, iterator);
+      tree m = cp_build_binary_op (input_location,
+                                  MINUS_EXPR, maxindex, iterator,
+                                  complain);
 
       /* 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);
-       }
+       m = cp_build_binary_op (input_location,
+                               MULT_EXPR, m,
+                               array_type_nelts_total (type),
+                               complain);
 
-      finish_compound_stmt (/*has_no_scope=*/1, try_body);
       finish_cleanup_try_block (try_block);
       e = build_vec_delete_1 (rval, m,
-                             type,
-                             sfk_base_destructor,
+                             inner_elt_type, sfk_base_destructor,
                              /*use_global_delete=*/0);
       finish_cleanup (e, try_block);
     }
 
-  /* The value of the array initialization is the address of the
-     first element in the array.  */
-  finish_expr_stmt (rval);
-
-  stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
-  current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
-  return stmt_expr;
-}
-
-/* Free up storage of type TYPE, at address ADDR.
-
-   TYPE is a POINTER_TYPE and can be ptr_type_node for no special type
-   of pointer.
-
-   VIRTUAL_SIZE is the amount of storage that was allocated, and is
-   used as the second argument to operator delete.  It can include
-   things like padding and magic size cookies.  It has virtual in it,
-   because if you have a base pointer and you delete through a virtual
-   destructor, it should be the size of the dynamic object, not the
-   static object, see Free Store 12.5 ISO C++.
+  /* The value of the array initialization is the array itself, RVAL
+     is a pointer to the first element.  */
+  finish_stmt_expr_expr (rval, stmt_expr);
 
-   This does not call any destructors.  */
+  stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt);
 
-tree
-build_x_delete (addr, which_delete, virtual_size)
-     tree addr;
-     int which_delete;
-     tree virtual_size;
-{
-  int use_global_delete = which_delete & 1;
-  int use_vec_delete = !!(which_delete & 2);
-  enum tree_code code = use_vec_delete ? VEC_DELETE_EXPR : DELETE_EXPR;
-  int flags = LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL);
+  /* Now make the result have the correct type.  */
+  if (TREE_CODE (atype) == ARRAY_TYPE)
+    {
+      atype = build_pointer_type (atype);
+      stmt_expr = build1 (NOP_EXPR, atype, stmt_expr);
+      stmt_expr = cp_build_indirect_ref (stmt_expr, NULL, complain);
+    }
 
-  return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
+  current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
+  return stmt_expr;
 }
 
 /* Call the DTOR_KIND destructor for EXP.  FLAGS are as for
    build_delete.  */
 
 static tree
-build_dtor_call (exp, dtor_kind, flags)
-     tree exp;
-     special_function_kind dtor_kind;
-     int flags;
+build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
 {
   tree name;
-
+  tree fn;
   switch (dtor_kind)
     {
     case sfk_complete_destructor:
@@ -3096,9 +2981,15 @@ build_dtor_call (exp, dtor_kind, flags)
       break;
 
     default:
-      abort ();
-    }
-  return build_method_call (exp, name, NULL_TREE, NULL_TREE, flags);
+      gcc_unreachable ();
+    }
+  fn = lookup_fnfields (TREE_TYPE (exp), name, /*protect=*/2);
+  return build_new_method_call (exp, fn,
+                               /*args=*/NULL_TREE,
+                               /*conversion_path=*/NULL_TREE,
+                               flags,
+                               /*fn_p=*/NULL,
+                               tf_warning_or_error);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
@@ -3111,11 +3002,8 @@ build_dtor_call (exp, dtor_kind, flags)
    flags.  See cp-tree.h for more info.  */
 
 tree
-build_delete (type, addr, auto_delete, flags, use_global_delete)
-     tree type, addr;
-     special_function_kind auto_delete;
-     int flags;
-     int use_global_delete;
+build_delete (tree type, tree addr, special_function_kind auto_delete,
+    int flags, int use_global_delete)
 {
   tree expr;
 
@@ -3131,27 +3019,47 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
 
   if (TREE_CODE (type) == POINTER_TYPE)
     {
+      bool complete_p = true;
+
       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))
+
+      /* 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.  */
+      if (!VOID_TYPE_P (type))
        {
-         /* Call the builtin operator delete.  */
-         return build_builtin_delete_call (addr);
+         complete_type (type);
+         if (!COMPLETE_TYPE_P (type))
+           {
+             if (warning (0, "possible problem detected in invocation of "
+                          "delete operator:"))
+               {
+                 cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
+                 inform (input_location, "neither the destructor nor the class-specific "
+                         "operator delete will be called, even if they are "
+                         "declared when the class is defined.");
+               }
+             complete_p = false;
+           }
        }
+      if (VOID_TYPE_P (type) || !complete_p || !MAYBE_CLASS_TYPE_P (type))
+       /* Call the builtin operator delete.  */
+       return build_builtin_delete_call (addr);
       if (TREE_SIDE_EFFECTS (addr))
        addr = save_expr (addr);
 
-      /* throw away const and volatile on target type of addr */
+      /* Throw away const and volatile on target type of addr.  */
       addr = convert_force (build_pointer_type (type), addr, 0);
     }
   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");
@@ -3165,31 +3073,34 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
       /* Don't check PROTECT here; leave that decision to the
         destructor.  If the destructor is accessible, call it,
         else report error.  */
-      addr = build_unary_op (ADDR_EXPR, addr, 0);
+      addr = cp_build_unary_op (ADDR_EXPR, addr, 0, tf_warning_or_error);
       if (TREE_SIDE_EFFECTS (addr))
        addr = save_expr (addr);
 
       addr = convert_force (build_pointer_type (type), addr, 0);
     }
 
-  my_friendly_assert (IS_AGGR_TYPE (type), 220);
+  gcc_assert (MAYBE_CLASS_TYPE_P (type));
 
   if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     {
       if (auto_delete != sfk_deleting_destructor)
        return void_zero_node;
 
-      return build_op_delete_call
-       (DELETE_EXPR, addr, c_sizeof_nowarn (type),
-        LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
-        NULL_TREE);
+      return build_op_delete_call (DELETE_EXPR, addr,
+                                  cxx_sizeof_nowarn (type),
+                                  use_global_delete,
+                                  /*placement=*/NULL_TREE,
+                                  /*alloc_fn=*/NULL_TREE);
     }
   else
     {
+      tree head = NULL_TREE;
       tree do_delete = NULL_TREE;
       tree ifexp;
 
-      my_friendly_assert (TYPE_HAS_DESTRUCTOR (type), 20011213);
+      if (CLASSTYPE_LAZY_DESTRUCTOR (type))
+       lazily_declare_fn (sfk_destructor, type);
 
       /* For `::delete x', we must not use the deleting destructor
         since then we would not be sure to get the global `operator
@@ -3198,8 +3109,9 @@ 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. */
-         do_delete = build_builtin_delete_call (addr);
+         head = get_target_expr (build_headof (addr));
+         /* Delete the object.  */
+         do_delete = build_builtin_delete_call (head);
          /* Otherwise, treat this like a complete object destructor
             call.  */
          auto_delete = sfk_complete_destructor;
@@ -3215,9 +3127,10 @@ 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),
-                                           LOOKUP_NORMAL,
-                                           NULL_TREE);
+                                           cxx_sizeof_nowarn (type),
+                                           /*global_p=*/false,
+                                           /*placement=*/NULL_TREE,
+                                           /*alloc_fn=*/NULL_TREE);
          /* Call the complete object destructor.  */
          auto_delete = sfk_complete_destructor;
        }
@@ -3226,166 +3139,120 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
        {
          /* 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, c_sizeof_nowarn (type),
-                               LOOKUP_NORMAL, NULL_TREE);
+         build_op_delete_call (DELETE_EXPR, addr, cxx_sizeof_nowarn (type),
+                               /*global_p=*/false,
+                               /*placement=*/NULL_TREE,
+                               /*alloc_fn=*/NULL_TREE);
        }
 
-      expr = build_dtor_call (build_indirect_ref (addr, NULL),
+      expr = build_dtor_call (cp_build_indirect_ref (addr, NULL, 
+                                                     tf_warning_or_error),
                              auto_delete, flags);
       if (do_delete)
-       expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
+       expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete);
+
+      /* We need to calculate this before the dtor changes the vptr.  */
+      if (head)
+       expr = build2 (COMPOUND_EXPR, void_type_node, head, expr);
 
       if (flags & LOOKUP_DESTRUCTOR)
        /* Explicit destructor call; don't check for null pointer.  */
        ifexp = integer_one_node;
       else
        /* Handle deleting a null pointer.  */
-       ifexp = fold (cp_build_binary_op (NE_EXPR, addr, integer_zero_node));
+       ifexp = fold (cp_build_binary_op (input_location,
+                                         NE_EXPR, addr, integer_zero_node,
+                                         tf_warning_or_error));
 
       if (ifexp != integer_one_node)
-       expr = build (COND_EXPR, void_type_node,
-                     ifexp, expr, void_zero_node);
+       expr = build3 (COND_EXPR, void_type_node,
+                      ifexp, expr, void_zero_node);
 
       return expr;
     }
 }
 
-/* At the end of a destructor, call the destructors for our base classes
-   and members.
+/* At the beginning of a destructor, push cleanups that will call the
+   destructors for our base classes and members.
 
-   Called from finish_destructor_body.  */
+   Called from begin_destructor_body.  */
 
 void
-perform_base_cleanups ()
+push_base_cleanups (void)
 {
-  tree binfos;
-  int i, n_baseclasses;
+  tree binfo, base_binfo;
+  int i;
   tree member;
   tree expr;
-  tree member_destructions = NULL;
-  tree vbase_destructions = NULL;
+  VEC(tree,gc) *vbases;
 
-  for (member = TYPE_FIELDS (current_class_type); member;
-       member = TREE_CHAIN (member))
+  /* Run destructors for all virtual baseclasses.  */
+  if (CLASSTYPE_VBASECLASSES (current_class_type))
     {
-      if (TREE_CODE (member) != FIELD_DECL)
-       continue;
-      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
+      tree cond = (condition_conversion
+                  (build2 (BIT_AND_EXPR, integer_type_node,
+                           current_in_charge_parm,
+                           integer_two_node)));
+
+      /* The CLASSTYPE_VBASECLASSES vector is in initialization
+        order, which is also the right order for pushing cleanups.  */
+      for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
+          VEC_iterate (tree, vbases, i, base_binfo); i++)
        {
-         tree this_member = (build_component_ref
-                             (current_class_ref, member,
-                              NULL_TREE, 0));
-         tree this_type = TREE_TYPE (member);
-         expr = build_delete (this_type, this_member,
-                              sfk_complete_destructor,
-                              LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
-                              0);
-         if (!member_destructions)
-           member_destructions = expr;
-         else
-           member_destructions = build (COMPOUND_EXPR, 
-                                        TREE_TYPE (member_destructions),
-                                        expr,
-                                        member_destructions);
+         if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
+           {
+             expr = build_special_member_call (current_class_ref,
+                                               base_dtor_identifier,
+                                               NULL_TREE,
+                                               base_binfo,
+                                               (LOOKUP_NORMAL
+                                                | LOOKUP_NONVIRTUAL),
+                                                tf_warning_or_error);
+             expr = build3 (COND_EXPR, void_type_node, cond,
+                            expr, void_zero_node);
+             finish_decl_cleanup (NULL_TREE, expr);
+           }
        }
     }
-  if (member_destructions)
-    finish_expr_stmt (member_destructions);
-
-  binfos = BINFO_BASETYPES (TYPE_BINFO (current_class_type));
-  n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
 
   /* Take care of the remaining baseclasses.  */
-  for (i = n_baseclasses - 1; i >= 0; i--)
+  for (binfo = TYPE_BINFO (current_class_type), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
       if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
-         || TREE_VIA_VIRTUAL (base_binfo))
+         || BINFO_VIRTUAL_P (base_binfo))
        continue;
 
-      expr = build_scoped_method_call (current_class_ref, base_binfo,
-                                      base_dtor_identifier,
-                                      NULL_TREE);
-
-      finish_expr_stmt (expr);
+      expr = build_special_member_call (current_class_ref,
+                                       base_dtor_identifier,
+                                       NULL_TREE, base_binfo,
+                                       LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
+                                        tf_warning_or_error);
+      finish_decl_cleanup (NULL_TREE, expr);
     }
 
-  /* Run destructors for all virtual baseclasses.  */
-  if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+  for (member = TYPE_FIELDS (current_class_type); member;
+       member = TREE_CHAIN (member))
     {
-      tree vbases;
-      tree cond = (condition_conversion
-                  (build (BIT_AND_EXPR, integer_type_node,
-                          current_in_charge_parm,
-                          integer_two_node)));
-
-      vbases = CLASSTYPE_VBASECLASSES (current_class_type);
-      /* The CLASSTYPE_VBASECLASSES list is in initialization
-        order, which is also the right order for pushing cleanups.  */
-      for (; vbases;
-          vbases = TREE_CHAIN (vbases))
+      if (TREE_TYPE (member) == error_mark_node
+         || TREE_CODE (member) != FIELD_DECL
+         || DECL_ARTIFICIAL (member))
+       continue;
+      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
        {
-         tree vbase = TREE_VALUE (vbases);
-         tree base_type = BINFO_TYPE (vbase);
-
-         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 (COND_EXPR, void_type_node, cond,
-                           expr, void_zero_node);
-             if (!vbase_destructions)
-               vbase_destructions = expr;
-             else
-               vbase_destructions = build (COMPOUND_EXPR, 
-                                           TREE_TYPE (vbase_destructions),
-                                           expr,
-                                           vbase_destructions);
-           }
+         tree this_member = (build_class_member_access_expr
+                             (current_class_ref, member,
+                              /*access_path=*/NULL_TREE,
+                              /*preserve_reference=*/false,
+                              tf_warning_or_error));
+         tree this_type = TREE_TYPE (member);
+         expr = build_delete (this_type, this_member,
+                              sfk_complete_destructor,
+                              LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
+                              0);
+         finish_decl_cleanup (NULL_TREE, expr);
        }
     }
-  if (vbase_destructions)
-    finish_expr_stmt (vbase_destructions);
-}
-
-/* For type TYPE, delete the virtual baseclass objects of DECL.  */
-
-tree
-build_vbase_delete (type, decl)
-     tree type, decl;
-{
-  tree vbases = CLASSTYPE_VBASECLASSES (type);
-  tree result = NULL_TREE;
-  tree addr = build_unary_op (ADDR_EXPR, decl, 0);
-
-  my_friendly_assert (addr != error_mark_node, 222);
-
-  while (vbases)
-    {
-      tree this_addr 
-       = convert_force (build_pointer_type (BINFO_TYPE (TREE_VALUE (vbases))),
-                        addr, 0);
-      result = tree_cons (NULL_TREE,
-                         build_delete (TREE_TYPE (this_addr), this_addr,
-                                       sfk_base_destructor,
-                                       LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
-                         result);
-      vbases = TREE_CHAIN (vbases);
-    }
-  return build_compound_expr (nreverse (result));
 }
 
 /* Build a C++ vector delete expression.
@@ -3405,42 +3272,46 @@ build_vbase_delete (type, decl)
    be worth bothering.)  */
 
 tree
-build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete)
-     tree base, maxindex;
-     special_function_kind auto_delete_vec;
-     int use_global_delete;
+build_vec_delete (tree base, tree maxindex,
+    special_function_kind auto_delete_vec, int use_global_delete)
 {
   tree type;
-
-  if (TREE_CODE (base) == OFFSET_REF)
-    base = resolve_offset_ref (base);
+  tree rval;
+  tree base_init = NULL_TREE;
 
   type = TREE_TYPE (base);
 
-  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;
+      tree size_ptr_type = build_pointer_type (sizetype);
 
+      if (TREE_SIDE_EFFECTS (base))
+       {
+         base_init = get_target_expr (base);
+         base = TARGET_EXPR_SLOT (base_init);
+       }
       type = strip_array_types (TREE_TYPE (type));
-      cookie_addr = build (MINUS_EXPR,
-                          build_pointer_type (sizetype),
-                          base,
-                          TYPE_SIZE_UNIT (sizetype));
-      maxindex = build_indirect_ref (cookie_addr, NULL);
+      cookie_addr = fold_build1 (NEGATE_EXPR, sizetype, TYPE_SIZE_UNIT (sizetype));
+      cookie_addr = build2 (POINTER_PLUS_EXPR,
+                           size_ptr_type,
+                           fold_convert (size_ptr_type, base),
+                           cookie_addr);
+      maxindex = cp_build_indirect_ref (cookie_addr, NULL, tf_warning_or_error);
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
-      /* get the total number of things in the array, maxindex is a bad name */
+      /* Get the total number of things in the array, maxindex is a
+        bad name.  */
       maxindex = array_type_nelts_total (type);
       type = strip_array_types (type);
-      base = build_unary_op (ADDR_EXPR, base, 1);
+      base = cp_build_unary_op (ADDR_EXPR, base, 1, tf_warning_or_error);
+      if (TREE_SIDE_EFFECTS (base))
+       {
+         base_init = get_target_expr (base);
+         base = TARGET_EXPR_SLOT (base_init);
+       }
     }
   else
     {
@@ -3449,6 +3320,10 @@ build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete)
       return error_mark_node;
     }
 
-  return build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
+  rval = build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
                             use_global_delete);
+  if (base_init)
+    rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), base_init, rval);
+
+  return rval;
 }