OSDN Git Service

When a class template is explicitly instantiated, its member should be too.
[pf3gnuchains/gcc-fork.git] / gcc / cp / init.c
index 964ee1e..5f0872e 100644 (file)
@@ -1,6 +1,6 @@
 /* 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 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
@@ -35,25 +35,27 @@ Boston, MA 02111-1307, USA.  */
 #include "except.h"
 #include "toplev.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 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 expand_aggr_init_1 (tree, tree, tree, tree, int);
+static void expand_default_init (tree, tree, tree, tree, int);
+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 PARAMS ((tree));
-static int member_init_ok_or_else PARAMS ((tree, tree, tree));
-static void expand_virtual_init PARAMS ((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 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));
+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_default_init (tree, tree);
+static tree build_new_1        (tree);
+static tree get_cookie_size (tree);
+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
@@ -64,45 +66,29 @@ static tree build_vtbl_address PARAMS ((tree));
    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 ();
+  bool is_global = !building_stmt_tree ();
   
-  if (building_stmt_tree ())
-    *compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
+  *stmt_expr_p = begin_stmt_expr ();
+  *compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/true);
+
+  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)
 {  
-  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);
+  finish_compound_stmt (compound_stmt);
   
-  /* 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);
 
+  my_friendly_assert (!building_stmt_tree () == is_global, 20030726);
+  
   return stmt_expr;
 }
 
@@ -113,9 +99,7 @@ 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)))
@@ -127,7 +111,7 @@ dfs_initialize_vtbl_ptrs (binfo, data)
       expand_virtual_init (binfo, base_ptr);
     }
 
-  SET_BINFO_MARKED (binfo);
+  BINFO_MARKED (binfo) = 1;
 
   return NULL_TREE;
 }
@@ -136,8 +120,7 @@ dfs_initialize_vtbl_ptrs (binfo, data)
    ADDR.  */
 
 void
-initialize_vtbl_ptrs (addr)
-     tree addr;
+initialize_vtbl_ptrs (tree addr)
 {
   tree list;
   tree type;
@@ -146,13 +129,12 @@ 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_real (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs,
+                NULL, unmarkedp, list);
+  dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, type);
 }
 
 /* Return an expression for the zero-initialization of an object with
@@ -160,12 +142,14 @@ initialize_vtbl_ptrs (addr)
    that T is a scalar), or a CONSTRUCTOR (in the case that T is an
    aggregate).  In either case, the value can be used as DECL_INITIAL
    for a decl of the indicated TYPE; it is a valid static initializer.
-   If 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.  */
+   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_zero_init (tree type, bool static_storage_p)
+build_zero_init (tree type, tree nelts, bool static_storage_p)
 {
   tree init = NULL_TREE;
 
@@ -187,6 +171,9 @@ build_zero_init (tree type, bool static_storage_p)
 
      -- if T is a reference type, no initialization is performed.  */
 
+  my_friendly_assert (nelts == NULL_TREE || TREE_CODE (nelts) == INTEGER_CST,
+                     20030618);
+
   if (type == error_mark_node)
     ;
   else if (static_storage_p && zero_init_p (type))
@@ -203,7 +190,7 @@ build_zero_init (tree type, bool static_storage_p)
       tree inits;
 
       /* Build a constructor to contain the initializations.  */
-      init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+      init = build_constructor (type, NULL_TREE);
       /* Iterate over the fields, building initializations.  */
       inits = NULL_TREE;
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
@@ -218,6 +205,7 @@ build_zero_init (tree type, bool static_storage_p)
          if (static_storage_p && !zero_init_p (TREE_TYPE (field)))
            inits = tree_cons (field, 
                               build_zero_init (TREE_TYPE (field),
+                                               /*nelts=*/NULL_TREE,
                                                static_storage_p),
                               inits);
 
@@ -234,16 +222,23 @@ build_zero_init (tree type, bool static_storage_p)
       tree inits;
 
       /* Build a constructor to contain the initializations.  */
-      init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+      init = build_constructor (type, NULL_TREE);
       /* Iterate over the array elements, building initializations.  */
       inits = NULL_TREE;
-      for (index = size_zero_node, max_index = array_type_nelts (type);
-          !tree_int_cst_lt (max_index, index);
-          index = size_binop (PLUS_EXPR, index, size_one_node))
-       inits = tree_cons (index,
-                          build_zero_init (TREE_TYPE (type), 
-                                           static_storage_p),
-                          inits);
+      max_index = nelts ? nelts : array_type_nelts (type);
+      my_friendly_assert (TREE_CODE (max_index) == INTEGER_CST, 20030618);
+
+      /* 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))
+       for (index = size_zero_node;
+            !tree_int_cst_lt (max_index, index);
+            index = size_binop (PLUS_EXPR, index, size_one_node))
+         inits = tree_cons (index,
+                            build_zero_init (TREE_TYPE (type),
+                                             /*nelts=*/NULL_TREE,
+                                             static_storage_p),
+                            inits);
       CONSTRUCTOR_ELTS (init) = nreverse (inits);
     }
   else if (TREE_CODE (type) == REFERENCE_TYPE)
@@ -253,19 +248,23 @@ build_zero_init (tree type, bool static_storage_p)
 
   /* In all cases, the initializer is a constant.  */
   if (init)
-    TREE_CONSTANT (init) = 1;
+    {
+      TREE_CONSTANT (init) = 1;
+      TREE_INVARIANT (init) = 1;
+    }
 
   return init;
 }
 
-/* Build an expression for the default-initialization of an object
-   with type T.  If initialization T requires calling constructors,
-   this function returns NULL_TREE; the caller is responsible for
-   arranging for the constructors to be called.  */
+/* Build an expression for the default-initialization of an object of
+   the indicated TYPE.  If NELTS is non-NULL, and TYPE is an
+   ARRAY_TYPE, NELTS is the number of elements in the array.  If
+   initialization of TYPE requires calling constructors, this function
+   returns NULL_TREE; the caller is responsible for arranging for the
+   constructors to be called.  */
 
 static tree
-build_default_init (type)
-     tree type;
+build_default_init (tree type, tree nelts)
 {
   /* [dcl.init]:
 
@@ -294,12 +293,13 @@ build_default_init (type)
      standard says we should have generated would be precisely the
      same as that obtained by calling build_zero_init below, so things
      work out OK.  */
-  if (TYPE_NEEDS_CONSTRUCTING (type))
+  if (TYPE_NEEDS_CONSTRUCTING (type)
+      || (nelts && TREE_CODE (nelts) != INTEGER_CST))
     return NULL_TREE;
       
   /* At this point, TYPE is either a POD class type, an array of POD
-     classes, or something even more inoccuous.  */
-  return build_zero_init (type, /*static_storage_p=*/false);
+     classes, or something even more innocuous.  */
+  return build_zero_init (type, nelts, /*static_storage_p=*/false);
 }
 
 /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
@@ -343,8 +343,7 @@ perform_member_init (tree member, tree init)
          finish_expr_stmt (init);
        }
     }
-  else if (TYPE_NEEDS_CONSTRUCTING (type)
-          || (init && TYPE_HAS_CONSTRUCTOR (type)))
+  else if (TYPE_NEEDS_CONSTRUCTING (type))
     {
       if (explicit
          && TREE_CODE (type) == ARRAY_TYPE
@@ -353,7 +352,8 @@ perform_member_init (tree member, tree init)
          && TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE)
        {
          /* Initialization of one array from another.  */
-         finish_expr_stmt (build_vec_init (decl, TREE_VALUE (init), 1));
+         finish_expr_stmt (build_vec_init (decl, NULL_TREE, TREE_VALUE (init),
+                                           /* from_array=*/1));
        }
       else
        finish_expr_stmt (build_aggr_init (decl, init, 0));
@@ -364,7 +364,7 @@ perform_member_init (tree member, tree init)
        {
          if (explicit)
            {
-             init = build_default_init (type);
+             init = build_default_init (type, /*nelts=*/NULL_TREE);
              if (TREE_CODE (type) == REFERENCE_TYPE)
                warning
                  ("default-initialization of `%#D', which has reference type",
@@ -373,19 +373,14 @@ perform_member_init (tree member, tree init)
          /* member traversal: note it leaves init NULL */
          else if (TREE_CODE (type) == REFERENCE_TYPE)
            pedwarn ("uninitialized reference member `%D'", member);
+         else if (CP_TYPE_CONST_P (type))
+           pedwarn ("uninitialized member `%D' with `const' type `%T'",
+                    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));
@@ -410,10 +405,7 @@ perform_member_init (tree member, tree init)
    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;
+build_field_list (tree t, tree list, int *uses_unions_p)
 {
   tree fields;
 
@@ -530,6 +522,7 @@ sort_mem_initializers (tree t, tree mem_inits)
            cp_warning_at ("  `%#D'", subobject);
          else
            warning ("  base `%T'", subobject);
+         warning ("  when initialized here");
        }
 
       /* Look again, from the beginning of the list.  */
@@ -656,6 +649,8 @@ emit_mem_initializers (tree mem_inits)
      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)
@@ -696,10 +691,11 @@ emit_mem_initializers (tree mem_inits)
 
       mem_inits = TREE_CHAIN (mem_inits);
     }
+  in_base_initializer = 0;
 
   /* Initialize the vptrs.  */
   initialize_vtbl_ptrs (current_class_ptr);
-
+  
   /* Initialize the data members.  */
   while (mem_inits)
     {
@@ -713,8 +709,7 @@ emit_mem_initializers (tree mem_inits)
    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;
@@ -736,12 +731,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;
 }
@@ -753,8 +745,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;
@@ -776,7 +767,8 @@ expand_virtual_init (binfo, decl)
                     TREE_TYPE (vtt_parm), 
                     vtt_parm,
                     vtt_index);
-      vtbl2 = build1 (INDIRECT_REF, TREE_TYPE (vtbl), vtbl2);
+      vtbl2 = build_indirect_ref (vtbl2, NULL);
+      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
@@ -806,9 +798,7 @@ expand_virtual_init (binfo, decl)
    destroyed.  */
 
 static void
-expand_cleanup_for_base (binfo, flag)
-     tree binfo;
-     tree flag;
+expand_cleanup_for_base (tree binfo, tree flag)
 {
   tree expr;
 
@@ -857,25 +847,17 @@ construct_virtual_base (tree vbase, tree arguments)
   flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
   inner_if_stmt = begin_if_stmt ();
   finish_if_stmt_cond (flag, inner_if_stmt);
-  compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/true);
 
   /* Compute the location of the virtual base.  If we're
      constructing virtual bases, then we must be the most derived
      class.  Therefore, we don't have to look up the virtual base;
      we already know where it is.  */
-  exp = build (PLUS_EXPR,
-              TREE_TYPE (current_class_ptr),
-              current_class_ptr,
-              fold (build1 (NOP_EXPR, TREE_TYPE (current_class_ptr),
-                            BINFO_OFFSET (vbase))));
-  exp = build1 (NOP_EXPR, 
-               build_pointer_type (BINFO_TYPE (vbase)), 
-               exp);
-  exp = build1 (INDIRECT_REF, BINFO_TYPE (vbase), exp);
-
-  expand_aggr_init_1 (vbase, current_class_ref, exp,
-                     arguments, LOOKUP_COMPLAIN);
-  finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+  exp = convert_to_base_statically (current_class_ref, vbase);
+
+  expand_aggr_init_1 (vbase, current_class_ref, exp, arguments, 
+                     LOOKUP_COMPLAIN);
+  finish_compound_stmt (compound_stmt);
   finish_then_clause (inner_if_stmt);
   finish_if_stmt ();
 
@@ -885,8 +867,7 @@ construct_virtual_base (tree vbase, tree arguments)
 /* 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);
 
@@ -905,10 +886,7 @@ initializing_context (field)
    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;
@@ -943,16 +921,15 @@ member_init_ok_or_else (field, type, member_name)
 
 /* NAME is a FIELD_DECL, an IDENTIFIER_NODE which names a field, or it
    is a _TYPE node or TYPE_DECL which names a base for that type.
-   INIT is a parameter list for that field's or base's constructor.
-   Check the validity of NAME, and return a TREE_LIST of the base
-   _TYPE or FIELD_DECL and the INIT.  If NAME is invalid, return
+   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 (tree name, tree init)
+expand_member_init (tree name)
 {
   tree basetype;
   tree field;
@@ -989,26 +966,52 @@ expand_member_init (tree name, tree init)
   else
     basetype = NULL_TREE;
 
-  my_friendly_assert (init != NULL_TREE, 0);
-
   if (basetype)
     {
-      tree binfo;
+      tree class_binfo;
+      tree direct_binfo;
+      tree virtual_binfo;
+      int i;
 
       if (current_template_parms)
-       return build_tree_list (basetype, init);
+       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; i < BINFO_N_BASETYPES (class_binfo); ++i)
+       if (same_type_p (basetype, 
+                        TYPE_BINFO_BASETYPE (current_class_type, i)))
+         {
+           direct_binfo = BINFO_BASETYPE (class_binfo, i);
+           break;
+         }
+      /* Look for a virtual base -- unless the direct base is itself
+        virtual.  */
+      if (!direct_binfo || !TREE_VIA_VIRTUAL (direct_binfo))
+       {
+         virtual_binfo 
+           = purpose_member (basetype,
+                             CLASSTYPE_VBASECLASSES (current_class_type));
+         if (virtual_binfo)
+           virtual_binfo = TREE_VALUE (virtual_binfo);
+       }
 
-      binfo = lookup_base (current_class_type, basetype, 
-                          ba_ignore, NULL);
-      if (binfo)
+      /* [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)
        {
-         if (TREE_VIA_VIRTUAL (binfo))
-           binfo = binfo_for_vbase (basetype, current_class_type);
-         else if (BINFO_INHERITANCE_CHAIN (binfo) 
-                  != TYPE_BINFO (current_class_type))
-           binfo = NULL_TREE;
+         error ("'%D' is both a direct base and an indirect virtual base",
+                basetype);
+         return NULL_TREE;
        }
-      if (!binfo)
+
+      if (!direct_binfo && !virtual_binfo)
        {
          if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
            error ("type `%D' is not a direct or virtual base of `%T'",
@@ -1019,18 +1022,17 @@ expand_member_init (tree name, tree init)
          return NULL_TREE;
        }
 
-      if (binfo)
-       return build_tree_list (binfo, init);
+      return direct_binfo ? direct_binfo : virtual_binfo;
     }
   else
     {
       if (TREE_CODE (name) == IDENTIFIER_NODE)
-       field = lookup_field (current_class_type, name, 1, 0);
+       field = lookup_field (current_class_type, name, 1, false);
       else
        field = name;
 
       if (member_init_ok_or_else (field, current_class_type, name))
-       return build_tree_list (field, init);
+       return field;
     }
 
   return NULL_TREE;
@@ -1068,9 +1070,7 @@ expand_member_init (tree name, tree 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)
 {
   tree stmt_expr;
   tree compound_stmt;
@@ -1078,6 +1078,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;
@@ -1090,34 +1091,25 @@ 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");
          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,
+                                 itype && same_type_p (itype,
+                                                       TREE_TYPE (exp)));
       TREE_READONLY (exp) = was_const;
       TREE_THIS_VOLATILE (exp) = was_volatile;
       TREE_TYPE (exp) = type;
@@ -1127,16 +1119,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);
+  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;
@@ -1148,15 +1140,17 @@ build_aggr_init (exp, init, flags)
 /* Like build_aggr_init, but not just for aggregates.  */
 
 tree
-build_init (decl, init, flags)
-     tree decl, init;
-     int flags;
+build_init (tree decl, tree init, int flags)
 {
   tree expr;
 
-  if (IS_AGGR_TYPE (TREE_TYPE (decl))
-      || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+  if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
     expr = build_aggr_init (decl, init, flags);
+  else if (CLASS_TYPE_P (TREE_TYPE (decl)))
+    expr = build_special_member_call (decl, complete_ctor_identifier,
+                                     build_tree_list (NULL_TREE, init),
+                                     TYPE_BINFO (TREE_TYPE (decl)),
+                                     LOOKUP_NORMAL|flags);
   else
     expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
 
@@ -1164,11 +1158,7 @@ build_init (decl, 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)
 {
   tree type = TREE_TYPE (exp);
   tree ctor_name;
@@ -1195,8 +1185,7 @@ 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 
-              && TREE_HAS_CONSTRUCTOR (init))
+      else if (BRACE_ENCLOSED_INITIALIZER_P (init))
        {
          /* A brace-enclosed initializer for an aggregate.  */
          my_friendly_assert (CP_AGGREGATE_TYPE_P (type), 20021016);
@@ -1239,12 +1228,7 @@ expand_default_init (binfo, true_exp, exp, init, flags)
 
   rval = build_special_member_call (exp, ctor_name, parms, binfo, flags);
   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));
 }
 
 /* This function is responsible for initializing EXP with INIT
@@ -1264,15 +1248,11 @@ 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)
 {
   tree type = TREE_TYPE (exp);
 
@@ -1292,8 +1272,9 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
       /* If store_init_value returns NULL_TREE, the INIT has been
         record in the DECL_INITIAL for EXP.  That means there's
         nothing more we have to do.  */
-      if (store_init_value (exp, init))
-       finish_expr_stmt (build (INIT_EXPR, type, exp, init));
+      init = store_init_value (exp, init);
+      if (init)
+       finish_expr_stmt (init);
       return;
     }
 
@@ -1306,9 +1287,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
    OR_ELSE is nonzero, give an error message.  */
 
 int
-is_aggr_type (type, or_else)
-     tree type;
-     int or_else;
+is_aggr_type (tree type, int or_else)
 {
   if (type == error_mark_node)
     return 0;
@@ -1327,9 +1306,7 @@ is_aggr_type (type, or_else)
 /* Like is_aggr_typedef, but returns typedef if successful.  */
 
 tree
-get_aggr_from_typedef (name, or_else)
-     tree name;
-     int or_else;
+get_aggr_from_typedef (tree name, int or_else)
 {
   tree type;
 
@@ -1357,8 +1334,7 @@ get_aggr_from_typedef (name, or_else)
 }
 
 tree
-get_type_value (name)
-     tree name;
+get_type_value (tree name)
 {
   if (name == error_mark_node)
     return NULL_TREE;
@@ -1369,162 +1345,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;
-  tree fns;
-  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 finish_call_expr (name, parmlist, /*disallow_virtual=*/true);
-    }
-
-  if (DECL_P (name))
-    name = DECL_NAME (name);
-
-  if (TREE_CODE (type) == NAMESPACE_DECL)
-    return finish_call_expr (lookup_namespace_name (type, name),
-                            parmlist,
-                            /*disallow_virtual=*/true);
-
-  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 finish_call_expr (lookup_namespace_name (ns, name),
-                                parmlist,
-                                /*disallow_virtual=*/true);
-    }
-
-  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);
-
-  fns = lookup_fnfields (basetype_path, method_name, 0);
-  if (fns)
-    {
-      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-       BASELINK_FUNCTIONS (fns) = build_nt (TEMPLATE_ID_EXPR,
-                                            BASELINK_FUNCTIONS (fns),
-                                            TREE_OPERAND (name, 1));
-      return build_new_method_call (decl, fns, parmlist,
-                                   /*conversion_path=*/NULL_TREE,
-                                   LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
-    }
-
-  /* Convert 'this' to the specified type to disambiguate conversion
-     to the function's context.  */
-  if (decl == current_class_ref
-      /* ??? this is wrong, but if this conversion is invalid we need to
-        defer it until we know whether we are calling a static or
-        non-static member function.  Be conservative for now.  */
-      && ACCESSIBLY_UNIQUELY_DERIVED_P (type, current_class_type))
-    {
-      basetype_path = NULL_TREE;
-      decl = build_scoped_ref (decl, type, &basetype_path);
-      if (decl == error_mark_node)
-       return error_mark_node;
-    }
-
-  if (constructor_name_p (method_name, type))
-    return build_functional_cast (type, parmlist);
-  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.
@@ -1532,10 +1357,9 @@ 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 name, bool address_p)
 {
-  tree decl, t = error_mark_node;
+  tree decl;
   tree member;
   tree basebinfo = NULL_TREE;
   tree orig_name = name;
@@ -1544,7 +1368,7 @@ build_offset_ref (type, name)
   if (TREE_CODE (name) == TEMPLATE_DECL)
     return name;
 
-  if (processing_template_decl || uses_template_parms (type))
+  if (dependent_type_p (type) || type_dependent_expression_p (name))
     return build_min_nt (SCOPE_REF, type, name);
 
   if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
@@ -1559,16 +1383,10 @@ build_offset_ref (type, 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));
-           }
+         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);
@@ -1580,7 +1398,7 @@ build_offset_ref (type, name)
   /* Handle namespace names fully here.  */
   if (TREE_CODE (type) == NAMESPACE_DECL)
     {
-      t = lookup_namespace_name (type, name);
+      tree t = lookup_namespace_name (type, name);
       if (t == error_mark_node)
         return t;
       if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
@@ -1626,12 +1444,45 @@ build_offset_ref (type, name)
        return error_mark_node;
     }
 
+  if (!member)
+    {
+      error ("`%D' is not a member of type `%T'", name, type);
+      return error_mark_node;
+    }
+
+  if (processing_template_decl)
+    {
+      if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
+       return build_min (SCOPE_REF, TREE_TYPE (member), type, orig_name);
+      else
+       return build_min (SCOPE_REF, TREE_TYPE (member), type, name);
+    }
+
+  if (TREE_CODE (member) == TYPE_DECL)
+    {
+      TREE_USED (member) = 1;
+      return member;
+    }
+  /* static class members and class-specific enum
+     values can be returned without further ado.  */
+  if (TREE_CODE (member) == VAR_DECL || TREE_CODE (member) == CONST_DECL)
+    {
+      mark_used (member);
+      return convert_from_reference (member);
+    }
+
+  if (TREE_CODE (member) == FIELD_DECL && DECL_C_BIT_FIELD (member))
+    {
+      error ("invalid pointer to bit-field `%D'", member);
+      return error_mark_node;
+    }
+
   /* 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 = BASELINK_FUNCTIONS (fnfields);
+      tree t = BASELINK_FUNCTIONS (fnfields);
 
       if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
        {
@@ -1658,200 +1509,123 @@ build_offset_ref (type, name)
 
       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;
+         /* 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);
+         else
+           perform_or_defer_access_check (basebinfo, t);
+
          mark_used (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;
-    }
-
-  t = member;
-
-  if (t == NULL_TREE)
-    {
-      error ("`%D' is not a member of type `%T'", name, type);
-      return error_mark_node;
-    }
-
-  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);
-    }
-
-  if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t))
-    {
-      error ("invalid pointer to bit-field `%D'", t);
-      return error_mark_node;
-    }
-
-  /* static class functions too.  */
-  if (TREE_CODE (t) == FUNCTION_DECL
-      && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
-    abort ();
-
-  /* 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;
-}
-
-/* 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)
+      else
        {
-         error ("object missing in use of pointer-to-member construct");
-         return error_mark_node;
+         TREE_TYPE (fnfields) = unknown_type_node;
+         member = fnfields;
        }
-      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 (!cxx_mark_addressable (member))
-       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;
-
-  /* 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;
     }
+  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);
 
-  /* 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)))
+  if (!address_p)
     {
-      tree binfo = NULL_TREE;
+      /* If MEMBER is non-static, then the program has fallen afoul of
+        [expr.prim]:
 
-      /* Try to get to basetype from 'this'; if that doesn't work,
-         nothing will.  */
-      base = current_class_ref;
+          An id-expression that denotes a nonstatic data member or
+          nonstatic member function of a class can only be used:
 
-      /* First convert to the intermediate base specified, if appropriate.  */
-      if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
-       base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type), &binfo);
+          -- 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
 
-      return build_class_member_access_expr (base, member,
-                                            /*access_path=*/NULL_TREE,
-                                            /*preserve_reference=*/false);
-    }
+          -- to form a pointer to member (_expr.unary.op_), or
 
-  /* 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);
+          -- in the body of a nonstatic member function of that class or
+          of a class derived from that class (_class.mfct.nonstatic_), or
 
-  if (TYPE_PTRMEM_P (TREE_TYPE (member)))
-    {
-      if (addr == error_mark_node)
+          -- 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 a the qualified name suitable
+            for use as the operand to "&" -- even though the "&" is
+            not actually present.  */
+         member = build (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 build_unary_op (ADDR_EXPR, member, 0);
+           }
+         error ("invalid use of non-static member function `%D'", 
+                TREE_OPERAND (member, 1));
+         return member;
+       }
+      else if (TREE_CODE (member) == FIELD_DECL)
        {
-         error ("object missing in `%E'", exp);
+         error ("invalid use of non-static data member `%D'", member);
          return error_mark_node;
        }
-
-      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);
-
-      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);
+      return member;
     }
-  abort ();
-  /* NOTREACHED */
-  return NULL_TREE;
+
+  /* In member functions, the form `type::name' is no longer
+     equivalent to `this->type::name', at least not until
+     resolve_offset_ref.  */
+  member = build (OFFSET_REF, TREE_TYPE (member), decl, member);
+  PTRMEM_OK_P (member) = 1;
+  return member;
 }
 
 /* If DECL is a `const' declaration, and its value is a known
    constant, then return that value.  */
 
 tree
-decl_constant_value (decl)
-     tree decl;
+decl_constant_value (tree decl)
 {
-  if (TREE_READONLY_DECL_P (decl)
-      && ! TREE_THIS_VOLATILE (decl)
+  /* When we build a COND_EXPR, we don't know whether it will be used
+     as an lvalue or as an rvalue.  If it is an lvalue, it's not safe
+     to replace the second and third operands with their
+     initializers.  So, we do that here.  */
+  if (TREE_CODE (decl) == COND_EXPR)
+    {
+      tree d1;
+      tree d2;
+
+      d1 = decl_constant_value (TREE_OPERAND (decl, 1));
+      d2 = decl_constant_value (TREE_OPERAND (decl, 2));
+
+      if (d1 != TREE_OPERAND (decl, 1) || d2 != TREE_OPERAND (decl, 2))
+       return build (COND_EXPR,
+                     TREE_TYPE (decl),
+                     TREE_OPERAND (decl, 0), d1, d2);
+    }
+
+  if (DECL_P (decl)
+      && (/* Enumeration constants are constant.  */
+         TREE_CODE (decl) == CONST_DECL
+         /* And so are variables with a 'const' type -- unless they
+            are also 'volatile'.  */
+         || CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))
+      && TREE_CODE (decl) != PARM_DECL
       && DECL_INITIAL (decl)
       && DECL_INITIAL (decl) != error_mark_node
       /* This is invalid if initial value is not constant.
@@ -1869,8 +1643,7 @@ 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));
@@ -1903,10 +1676,7 @@ build_builtin_delete_call (addr)
    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;
+build_new (tree placement, tree decl, tree init, int use_global_new)
 {
   tree type, rval;
   tree nelts = NULL_TREE, t;
@@ -1936,7 +1706,7 @@ build_new (placement, decl, init, use_global_new)
 
       if (absdcl && TREE_CODE (absdcl) == ARRAY_REF)
        {
-         /* probably meant to be a vec new */
+         /* Probably meant to be a vec new.  */
          tree this_nelts;
 
          while (TREE_OPERAND (absdcl, 0)
@@ -2023,8 +1793,10 @@ build_new (placement, decl, init, use_global_new)
       else
        t = type;
        
-      rval = build_min_nt (NEW_EXPR, placement, t, init);
+      rval = build_min (NEW_EXPR, build_pointer_type (type), 
+                       placement, t, init);
       NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
+      TREE_SIDE_EFFECTS (rval) = 1;
       return rval;
     }
 
@@ -2067,7 +1839,7 @@ build_new (placement, decl, 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_UNUSED_WARNING (rval) = 1;
+  TREE_NO_WARNING (rval) = 1;
 
   return rval;
 }
@@ -2075,8 +1847,7 @@ build_new (placement, decl, init, use_global_new)
 /* Given a Java class, return a decl for the corresponding java.lang.Class.  */
 
 tree
-build_java_class_ref (type)
-     tree type;
+build_java_class_ref (tree type)
 {
   tree name = NULL_TREE, class_decl;
   static tree CL_suffix = NULL_TREE;
@@ -2091,7 +1862,7 @@ build_java_class_ref (type)
       jclass_node = TREE_TYPE (jclass_node);
     }
 
-  /* Mangle the class$ field */
+  /* Mangle the class$ field */
   {
     tree field;
     for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
@@ -2125,8 +1896,7 @@ build_java_class_ref (type)
    known that a cookie is needed.  */
 
 static tree
-get_cookie_size (type)
-     tree type;
+get_cookie_size (tree type)
 {
   tree cookie_size;
 
@@ -2149,24 +1919,33 @@ get_cookie_size (type)
    value is immediately handed to expand_expr.  */
 
 static tree
-build_new_1 (exp)
-     tree exp;
+build_new_1 (tree exp)
 {
   tree placement, init;
-  tree type, true_type, size, rval, t;
+  tree true_type, size, rval;
+  /* The type of the new-expression.  (This type is always a pointer
+     type.)  */
+  tree pointer_type;
+  /* The type pointed to by POINTER_TYPE.  */
+  tree type;
+  /* The type being allocated.  For "new T[...]" this will be an
+     ARRAY_TYPE.  */
   tree full_type;
+  /* A pointer type pointing to to the FULL_TYPE.  */
+  tree full_pointer_type;
+  tree outer_nelts = NULL_TREE;
   tree nelts = NULL_TREE;
-  tree alloc_call, alloc_expr, alloc_node;
+  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;
+  int nothrow, check_new;
   /* Nonzero if the user wrote `::new' rather than just `new'.  */
   int globally_qualified_p;
-  /* Nonzero if we're going to call a global operator new, rather than
-     a class-specific version.  */
-  int use_global_new;
   int use_java_new = 0;
   /* If non-NULL, the number of extra bytes to allocate at the
      beginning of the storage allocated for an array-new expression in
@@ -2175,6 +1954,16 @@ build_new_1 (exp)
   /* True if the function we are calling is a placement allocation
      function.  */
   bool placement_allocation_fn_p;
+  tree args = NULL_TREE;
+  /* 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;
 
   placement = TREE_OPERAND (exp, 0);
   type = TREE_OPERAND (exp, 1);
@@ -2184,12 +1973,11 @@ build_new_1 (exp)
   if (TREE_CODE (type) == ARRAY_REF)
     {
       has_array = 1;
-      nelts = TREE_OPERAND (type, 1);
+      nelts = outer_nelts = TREE_OPERAND (type, 1);
       type = TREE_OPERAND (type, 0);
 
-      full_type = cp_build_binary_op (MINUS_EXPR, nelts, integer_one_node);
-      full_type = build_index_type (full_type);
-      full_type = build_cplus_array_type (type, full_type);
+      /* Use an incomplete array type to avoid VLA headaches.  */
+      full_type = build_cplus_array_type (type, NULL_TREE);
     }
   else
     full_type = type;
@@ -2210,10 +1998,6 @@ build_new_1 (exp)
   if (!complete_type_or_else (true_type, exp))
     return error_mark_node;
 
-  size = size_in_bytes (true_type);
-  if (has_array)
-    size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
-
   if (TREE_CODE (true_type) == VOID_TYPE)
     {
       error ("invalid type `void' for new");
@@ -2223,90 +2007,113 @@ build_new_1 (exp)
   if (abstract_virtuals_error (NULL_TREE, true_type))
     return error_mark_node;
 
-  /* Figure out whether or not we're going to use the global operator
-     new.  */
-  if (!globally_qualified_p
-      && IS_AGGR_TYPE (true_type)
-      && (has_array
-         ? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
-         : TYPE_HAS_NEW_OPERATOR (true_type)))
-    use_global_new = 0;
-  else
-    use_global_new = 1;
-
-  /* We only need cookies for arrays containing types for which we
-     need cookies.  */
-  if (!has_array || !TYPE_VEC_NEW_USES_COOKIE (true_type))
-    use_cookie = 0;
-  /* When using placement new, users may not realize that they need
-     the extra storage.  We require that the operator called be
-     the global placement operator 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;
-
-  /* Compute the number of extra bytes to allocate, now that we know
-     whether or not we need the cookie.  */
-  if (use_cookie)
+  is_initialized = (TYPE_NEEDS_CONSTRUCTING (type) || init);
+  if (CP_TYPE_CONST_P (true_type) && !is_initialized)
     {
-      cookie_size = get_cookie_size (true_type);
-      size = size_binop (PLUS_EXPR, size, cookie_size);
+      error ("uninitialized const in `new' of `%#T'", true_type);
+      return error_mark_node;
     }
 
+  size = size_in_bytes (true_type);
+  if (has_array)
+    size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
+
   /* Allocate the object.  */
-  
   if (! placement && TYPE_FOR_JAVA (true_type))
     {
       tree class_addr, alloc_decl;
       tree class_decl = build_java_class_ref (true_type);
-      tree class_size = size_in_bytes (true_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);
 
+      use_java_new = 1;
+      alloc_decl = NULL;
+      if (!get_global_value_if_present (get_identifier (alloc_name), 
+                                       &alloc_decl))
+       {
+         error ("call to Java constructor with `%s' undefined", alloc_name);
+         return error_mark_node;
+       }
+      else if (really_overloaded_fn (alloc_decl))
+       {
+         error ("`%D' should never be overloaded", alloc_decl);
+         return error_mark_node;
+       }
+      alloc_decl = OVL_CURRENT (alloc_decl);
       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))));
+                    build_tree_list (NULL_TREE, class_addr)));
     }
   else
     {
       tree fnname;
-      tree args;
+      tree fns;
 
-      args = tree_cons (NULL_TREE, size, placement);
       fnname = ansi_opname (code);
 
-      if (use_global_new)
-       alloc_call = (build_new_function_call 
-                     (lookup_function_nonclass (fnname, args),
-                      args));
+      if (!globally_qualified_p 
+         && CLASS_TYPE_P (true_type)
+         && (has_array
+             ? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
+             : TYPE_HAS_NEW_OPERATOR (true_type)))
+       {
+         /* Use a class-specific operator new.  */
+         /* If a cookie is required, add some extra space.  */
+         if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
+           {
+             cookie_size = get_cookie_size (true_type);
+             size = size_binop (PLUS_EXPR, size, cookie_size);
+           }
+         /* Create the argument list.  */
+         args = tree_cons (NULL_TREE, size, placement);
+         /* Do name-lookup to find the appropriate operator.  */
+         fns = lookup_fnfields (true_type, fnname, /*protect=*/2);
+         if (TREE_CODE (fns) == TREE_LIST)
+           {
+             error ("request for member `%D' is ambiguous", fnname);
+             print_candidates (fns);
+             return error_mark_node;
+           }
+         alloc_call = build_new_method_call (build_dummy_object (true_type),
+                                             fns, args,
+                                             /*conversion_path=*/NULL_TREE,
+                                             LOOKUP_NORMAL);
+       }
       else
-       alloc_call = build_method_call (build_dummy_object (true_type),
-                                       fnname, args, 
-                                       TYPE_BINFO (true_type),
-                                       LOOKUP_NORMAL);
+       {
+         /* Use a global operator new.  */
+         /* See if a cookie might be required.  */
+         if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
+           cookie_size = get_cookie_size (true_type);
+         else
+           cookie_size = NULL_TREE;
+
+         alloc_call = build_operator_new_call (fnname, placement, 
+                                               &size, &cookie_size);
+       }
     }
 
   if (alloc_call == error_mark_node)
     return error_mark_node;
 
-  /* The ALLOC_CALL should be a CALL_EXPR -- 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);
+  /* In the simple case, we can stop now.  */
+  pointer_type = build_pointer_type (type);
+  if (!cookie_size && !is_initialized)
+    return build_nop (pointer_type, alloc_call);
+
+  /* While we're working, use a pointer to the type we've actually
+     allocated. Store the result of the call in a variable so that we
+     can use it more than once.  */
+  full_pointer_type = build_pointer_type (full_type);
+  alloc_expr = get_target_expr (build_nop (full_pointer_type, 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);
+  alloc_fn = get_callee_fndecl (alloc_call);
   my_friendly_assert (alloc_fn != NULL_TREE, 20020325);
+
   /* Now, check to see if this function is actually a placement
      allocation function.  This can happen even when PLACEMENT is NULL
      because we might have something like:
@@ -2321,6 +2128,17 @@ build_new_1 (exp)
     = (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 = build (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_,
@@ -2334,77 +2152,81 @@ 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;
 
+      /* Adjust so we're pointing to the start of the object.  */
+      data_addr = get_target_expr (build (PLUS_EXPR, full_pointer_type,
+                                         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));
+                     data_addr, size_in_bytes (sizetype));
       cookie = build_indirect_ref (cookie, NULL);
 
-      cookie_expr = build (MODIFY_EXPR, void_type_node, cookie, nelts);
-      TREE_SIDE_EFFECTS (cookie_expr) = 1;
+      cookie_expr = build (MODIFY_EXPR, sizetype, cookie, nelts);
+      data_addr = TARGET_EXPR_SLOT (data_addr);
     }
   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 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;
+
+      init_expr = build_indirect_ref (data_addr, NULL);
 
       if (init == void_zero_node)
-       init = build_default_init (full_type);
-      else if (init && pedantic && has_array)
+       init = build_default_init (full_type, nelts);
+      else if (init && has_array)
        pedwarn ("ISO C++ forbids initialization in array new");
 
       if (has_array)
-       init_expr = build_vec_init (init_expr, init, 0);
+       {
+         init_expr
+           = build_vec_init (init_expr,
+                             cp_build_binary_op (MINUS_EXPR, outer_nelts,
+                                                 integer_one_node),
+                             init, /*from_array=*/0);
+
+         /* 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 if (TYPE_NEEDS_CONSTRUCTING (type))
-       init_expr = build_special_member_call (init_expr, 
-                                              complete_ctor_identifier,
-                                              init, TYPE_BINFO (true_type),
-                                              LOOKUP_NORMAL);
+       {
+         init_expr = build_special_member_call (init_expr, 
+                                                complete_ctor_identifier,
+                                                init, TYPE_BINFO (true_type),
+                                                LOOKUP_NORMAL);
+         stable = stabilize_init (init_expr, &init_preeval_expr);
+       }
       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)
-           {
-             if (TREE_CHAIN (init) != NULL_TREE)
-               pedwarn
-                 ("initializer list being treated as compound expression");
-             init = build_compound_expr (init);
-           }
+           init = build_x_compound_expr_from_list (init, "new initializer");
+
          else if (TREE_CODE (init) == CONSTRUCTOR
                   && TREE_TYPE (init) == NULL_TREE)
-           {
-             pedwarn ("ISO C++ forbids aggregate initializer to new");
-             init = digest_init (type, init, 0);
-           }
+           abort ();
 
          init_expr = build_modify_expr (init_expr, INIT_EXPR, init);
+         stable = stabilize_init (init_expr, &init_preeval_expr);
        }
 
       if (init_expr == error_mark_node)
@@ -2422,52 +2244,33 @@ build_new_1 (exp)
        {
          enum tree_code dcode = has_array ? 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,
+            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));
 
-         /* 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.  Er, no, it wouldn't;
-            we just don't run the constructor.  The standard says it's
-            unspecified whether or not the args are evaluated.
-
-            FIXME FIXME FIXME inline invisible refs as refs.  That way we
-            can preevaluate value parameters.  */
-
-         if (cleanup)
+         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 = build (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;
 
@@ -2488,14 +2291,15 @@ build_new_1 (exp)
                         build (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);
@@ -2503,9 +2307,9 @@ build_new_1 (exp)
     rval = build (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 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)
@@ -2515,21 +2319,27 @@ build_new_1 (exp)
          rval = build_conditional_expr (ifexp, rval, alloc_node);
        }
 
+      /* Perform the allocation before anything else, so that ALLOC_NODE
+        has been initialized before we start using it.  */
       rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
     }
 
-  /* Now strip the outer ARRAY_TYPE, so we return a pointer to the first
-     element.  */
-  rval = convert (build_pointer_type (type), rval);
+  if (init_preeval_expr)
+    rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_preeval_expr, rval);
+
+  /* Convert to the final type.  */
+  rval = build_nop (pointer_type, rval);
+
+  /* A new-expression is never an lvalue.  */
+  if (real_lvalue_p (rval))
+    rval = build1 (NON_LVALUE_EXPR, TREE_TYPE (rval), rval);
 
   return rval;
 }
 \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));
@@ -2543,7 +2353,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;
@@ -2559,10 +2369,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
     abort ();
 
   if (! IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
-    {
-      loop = integer_zero_node;
-      goto no_destructor;
-    }
+    goto no_destructor;
 
   /* The below is short by the cookie size.  */
   virtual_size = size_binop (MULT_EXPR, size_exp,
@@ -2577,32 +2384,21 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
   controller = build (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 = build (EXIT_EXPR, void_type_node,
+               build (EQ_EXPR, boolean_type_node, base, tbase));
+  body = build_compound_expr
+    (body, build_modify_expr (tbase, NOP_EXPR,
+                             build (MINUS_EXPR, ptype, tbase, size_exp)));
+  body = build_compound_expr
+    (body, build_delete (ptype, tbase, sfk_complete_destructor,
+                        LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
 
-  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);
+  loop = build (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;
@@ -2635,19 +2431,22 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, 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);
-    }
+  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)),
+                                  convert (TREE_TYPE (base),
+                                           integer_zero_node))),
                      body, integer_zero_node));
   body = build1 (NOP_EXPR, void_type_node, body);
 
@@ -2661,22 +2460,20 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
     /* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR.  */
     body = build (COMPOUND_EXPR, void_type_node, base, body);
 
-  return cp_convert (void_type_node, body);
+  return convert_to_void (body, /*implicit=*/NULL);
 }
 
 /* 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_SOURCE_LOCATION (decl) = input_location;
   DECL_IGNORED_P (decl) = 1;
   DECL_CONTEXT (decl) = current_function_decl;
 
@@ -2691,16 +2488,13 @@ 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);
-  else
-    SET_DECL_RTL (decl, assign_temp (type, 2, 0, 1));
+  add_decl_stmt (decl);
+  
   finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
 
   return decl;
@@ -2710,6 +2504,9 @@ get_temp_regvar (type, init)
    initialization of a vector of aggregate types.
 
    BASE is a reference to the vector, of ARRAY_TYPE.
+   MAXINDEX is the maximum index of the array (one less than the
+     number of elements).  It is only used if
+     TYPE_DOMAIN (TREE_TYPE (BASE)) == NULL_TREE.
    INIT is the (possibly NULL) initializer.
 
    FROM_ARRAY is 0 if we should init everything with INIT
@@ -2720,9 +2517,7 @@ 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, int from_array)
 {
   tree rval;
   tree base2 = NULL_TREE;
@@ -2741,9 +2536,12 @@ build_vec_init (base, init, from_array)
   tree try_block = NULL_TREE;
   tree try_body = NULL_TREE;
   int num_initialized_elts = 0;
-  tree maxindex = array_type_nelts (TREE_TYPE (base));
+  bool is_global;
+  
+  if (TYPE_DOMAIN (atype))
+    maxindex = array_type_nelts (atype);
 
-  if (maxindex == error_mark_node)
+  if (maxindex == NULL_TREE || maxindex == error_mark_node)
     return error_mark_node;
 
   if (init
@@ -2769,10 +2567,10 @@ build_vec_init (base, init, from_array)
   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));
+    base = cp_convert (ptype, decay_conversion (base));
 
   /* The code we are generating looks like:
-
+     ({
        T* t1 = (T*) base;
        T* rval = t1;
        ptrdiff_t iterator = maxindex;
@@ -2784,7 +2582,8 @@ build_vec_init (base, init, from_array)
        } catch (...) {
          ... 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
@@ -2800,7 +2599,7 @@ build_vec_init (base, init, from_array)
      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);
@@ -2814,7 +2613,7 @@ build_vec_init (base, init, from_array)
       && from_array != 2)
     {
       try_block = begin_try_block ();
-      try_body = begin_compound_stmt (/*has_no_scope=*/1);
+      try_body = begin_compound_stmt (/*has_no_scope=*/true);
     }
 
   if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
@@ -2832,11 +2631,13 @@ build_vec_init (base, init, from_array)
 
          num_initialized_elts++;
 
+         current_stmt_tree ()->stmts_are_full_exprs_p = 1;
          if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE)
            finish_expr_stmt (build_aggr_init (baseref, elt, 0));
          else
            finish_expr_stmt (build_modify_expr (baseref, NOP_EXPR,
                                                 elt));
+         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));
@@ -2852,7 +2653,7 @@ build_vec_init (base, init, from_array)
         checking.  */ 
       if (init)
        {
-         base2 = default_conversion (init);
+         base2 = decay_conversion (init);
          itype = TREE_TYPE (base2);
          base2 = get_temp_regvar (itype, base2);
          itype = TREE_TYPE (itype);
@@ -2893,21 +2694,7 @@ build_vec_init (base, init, from_array)
                       for_stmt);
 
       /* Otherwise, loop through the elements.  */
-      for_body = begin_compound_stmt (/*has_no_scope=*/1);
-
-      /* When we're not building a statement-tree, things are a little
-        complicated.  If, when we recursively call build_aggr_init,
-        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 ();
+      for_body = begin_compound_stmt (/*has_no_scope=*/true);
 
       if (from_array)
        {
@@ -2934,31 +2721,21 @@ build_vec_init (base, init, from_array)
            sorry
              ("cannot initialize multi-dimensional array with initializer");
          elt_init = build_vec_init (build1 (INDIRECT_REF, type, base),
-                                    0, 0);
+                                    0, 0, 0);
        }
       else
        elt_init = build_aggr_init (build1 (INDIRECT_REF, type, base), 
                                    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;
-       }
+      current_stmt_tree ()->stmts_are_full_exprs_p = 1;
+      finish_expr_stmt (elt_init);
+      current_stmt_tree ()->stmts_are_full_exprs_p = 0;
 
       finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base, 0));
       if (base2)
        finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base2, 0));
 
-      finish_compound_stmt (/*has_no_scope=*/1, for_body);
+      finish_compound_stmt (for_body);
       finish_for_stmt (for_stmt);
     }
 
@@ -2978,20 +2755,24 @@ build_vec_init (base, init, from_array)
          type = strip_array_types (type);
        }
 
-      finish_compound_stmt (/*has_no_scope=*/1, try_body);
+      finish_compound_stmt (try_body);
       finish_cleanup_try_block (try_block);
-      e = build_vec_delete_1 (rval, m,
-                             type,
-                             sfk_base_destructor,
+      e = build_vec_delete_1 (rval, m, 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);
+  /* 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 = finish_init_stmts (is_global, stmt_expr, compound_stmt);
 
-  stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
+  /* Now convert make the result have the correct type.  */
+  atype = build_pointer_type (atype);
+  stmt_expr = build1 (NOP_EXPR, atype, stmt_expr);
+  stmt_expr = build_indirect_ref (stmt_expr, NULL);
+  
   current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
   return stmt_expr;
 }
@@ -3011,30 +2792,24 @@ build_vec_init (base, init, from_array)
    This does not call any destructors.  */
 
 tree
-build_x_delete (addr, which_delete, virtual_size)
-     tree addr;
-     int which_delete;
-     tree virtual_size;
+build_x_delete (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);
 
-  return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
+  return build_op_delete_call (code, addr, virtual_size, use_global_delete, 
+                              NULL_TREE);
 }
 
 /* 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:
@@ -3052,8 +2827,13 @@ build_dtor_call (exp, dtor_kind, flags)
     default:
       abort ();
     }
-  return build_method_call (exp, name, NULL_TREE, 
-                           TYPE_BINFO (TREE_TYPE (exp)), flags);
+
+  exp = convert_from_reference (exp);
+  fn = lookup_fnfields (TREE_TYPE (exp), name, /*protect=*/2);
+  return build_new_method_call (exp, fn, 
+                               /*args=*/NULL_TREE,
+                               /*conversion_path=*/NULL_TREE,
+                               flags);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
@@ -3066,11 +2846,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;
 
@@ -3086,27 +2863,39 @@ 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 (TREE_CODE (type) == ARRAY_TYPE)
        goto handle_array;
 
-      if (VOID_TYPE_P (type)
-         /* We don't want to warn about delete of void*, only other
-            incomplete types.  Deleting other incomplete types
-            invokes undefined behavior, but it is not ill-formed, so
-            compile to something that would even do The Right Thing
-            (TM) should the type have a trivial dtor and no delete
-            operator.  */
-         || !complete_type_or_diagnostic (type, addr, 1)
-         || !IS_AGGR_TYPE (type))
+      /* 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))
+           {
+             warning ("possible problem detected in invocation of "
+                      "delete operator:");
+             cxx_incomplete_type_diagnostic (addr, type, 1);
+             inform ("neither the destructor nor the class-specific "\r
+                     "operator delete will be called, even if they are "\r
+                     "declared when the class is defined.");
+             complete_p = false;
+           }
        }
+      if (VOID_TYPE_P (type) || !complete_p || !IS_AGGR_TYPE (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)
@@ -3141,8 +2930,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
        return void_zero_node;
 
       return build_op_delete_call
-       (DELETE_EXPR, addr, cxx_sizeof_nowarn (type),
-        LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
+       (DELETE_EXPR, addr, cxx_sizeof_nowarn (type), use_global_delete,
         NULL_TREE);
     }
   else
@@ -3177,7 +2965,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
          do_delete = build_op_delete_call (DELETE_EXPR,
                                            addr,
                                            cxx_sizeof_nowarn (type),
-                                           LOOKUP_NORMAL,
+                                           /*global_p=*/false,
                                            NULL_TREE);
          /* Call the complete object destructor.  */
          auto_delete = sfk_complete_destructor;
@@ -3188,7 +2976,7 @@ 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, cxx_sizeof_nowarn (type),
-                               LOOKUP_NORMAL, NULL_TREE);
+                               /*global_p=*/false, NULL_TREE);
        }
 
       expr = build_dtor_call (build_indirect_ref (addr, NULL),
@@ -3217,7 +3005,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
    Called from begin_destructor_body.  */
 
 void
-push_base_cleanups ()
+push_base_cleanups (void)
 {
   tree binfos;
   int i, n_baseclasses;
@@ -3299,28 +3087,26 @@ push_base_cleanups ()
 /* For type TYPE, delete the virtual baseclass objects of DECL.  */
 
 tree
-build_vbase_delete (type, decl)
-     tree type, decl;
+build_vbase_delete (tree type, tree decl)
 {
   tree vbases = CLASSTYPE_VBASECLASSES (type);
-  tree result = NULL_TREE;
+  tree result;
   tree addr = build_unary_op (ADDR_EXPR, decl, 0);
 
   my_friendly_assert (addr != error_mark_node, 222);
 
-  while (vbases)
+  for (result = convert_to_void (integer_zero_node, NULL);
+       vbases; vbases = TREE_CHAIN (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);
+      tree base_addr = convert_force
+       (build_pointer_type (BINFO_TYPE (TREE_VALUE (vbases))), addr, 0);
+      tree base_delete = build_delete
+       (TREE_TYPE (base_addr), base_addr, sfk_base_destructor,
+        LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
+      
+      result = build_compound_expr (result, base_delete);
     }
-  return build_compound_expr (nreverse (result));
+  return result;
 }
 
 /* Build a C++ vector delete expression.
@@ -3340,27 +3126,25 @@ 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);
-
   if (TREE_CODE (type) == POINTER_TYPE)
     {
       /* Step back one from start of vector, and read dimension.  */
       tree cookie_addr;
 
       if (TREE_SIDE_EFFECTS (base))
-       base = save_expr (base);
+       {
+         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),
@@ -3370,12 +3154,16 @@ build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete)
     }
   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);
       if (TREE_SIDE_EFFECTS (base))
-       base = save_expr (base);
+       {
+         base_init = get_target_expr (base);
+         base = TARGET_EXPR_SLOT (base_init);
+       }
     }
   else
     {
@@ -3384,6 +3172,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 = build (COMPOUND_EXPR, TREE_TYPE (rval), base_init, rval);
+
+  return rval;
 }