OSDN Git Service

When a class template is explicitly instantiated, its member should be too.
[pf3gnuchains/gcc-fork.git] / gcc / cp / init.c
index c2b3711..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, 2003 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.
@@ -85,9 +85,7 @@ finish_init_stmts (bool is_global, tree stmt_expr, tree compound_stmt)
 {  
   finish_compound_stmt (compound_stmt);
   
-  stmt_expr = finish_stmt_expr (stmt_expr);
-  STMT_EXPR_NO_SCOPE (stmt_expr) = true;
-  TREE_USED (stmt_expr) = 1;
+  stmt_expr = finish_stmt_expr (stmt_expr, true);
 
   my_friendly_assert (!building_stmt_tree () == is_global, 20030726);
   
@@ -230,14 +228,17 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
       max_index = nelts ? nelts : array_type_nelts (type);
       my_friendly_assert (TREE_CODE (max_index) == INTEGER_CST, 20030618);
 
-      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);
+      /* 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)
@@ -247,7 +248,10 @@ build_zero_init (tree type, tree nelts, 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;
 }
@@ -294,7 +298,7 @@ build_default_init (tree type, tree nelts)
     return NULL_TREE;
       
   /* At this point, TYPE is either a POD class type, an array of POD
-     classes, or something even more inoccuous.  */
+     classes, or something even more innocuous.  */
   return build_zero_init (type, nelts, /*static_storage_p=*/false);
 }
 
@@ -339,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
@@ -370,6 +373,9 @@ 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
@@ -516,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.  */
@@ -724,12 +731,9 @@ build_vtbl_address (tree 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;
 }
@@ -763,7 +767,8 @@ expand_virtual_init (tree binfo, tree 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
@@ -1086,34 +1091,25 @@ build_aggr_init (tree exp, tree init, int 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);
+       itype = TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
       stmt_expr = build_vec_init (exp, NULL_TREE, init,
-                                 init && same_type_p (TREE_TYPE (init),
-                                                      TREE_TYPE (exp)));
+                                 itype && same_type_p (itype,
+                                                       TREE_TYPE (exp)));
       TREE_READONLY (exp) = was_const;
       TREE_THIS_VOLATILE (exp) = was_volatile;
       TREE_TYPE (exp) = type;
@@ -1123,7 +1119,7 @@ build_aggr_init (tree exp, tree init, int 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);
@@ -1148,9 +1144,13 @@ 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);
 
@@ -1185,8 +1185,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int 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);
@@ -1249,8 +1248,8 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int 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 (tree binfo, tree true_exp, tree exp, tree init, int flags)
@@ -1273,8 +1272,9 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int 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;
     }
 
@@ -1368,7 +1368,7 @@ build_offset_ref (tree type, tree name, bool address_p)
   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)
@@ -1450,6 +1450,14 @@ build_offset_ref (tree type, tree name, bool address_p)
       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;
@@ -1501,11 +1509,23 @@ build_offset_ref (tree type, tree name, bool address_p)
 
       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.  */
-         perform_or_defer_access_check (basebinfo, t);
+         /* Unique functions are handled easily.  */
+
+         /* For non-static member of base class, we need a special rule
+            for access checking [class.protected]:
+
+              If the access is to form a pointer to member, the
+              nested-name-specifier shall name the derived class
+              (or any class derived from that class).  */
+         if (address_p && DECL_P (t)
+             && DECL_NONSTATIC_MEMBER_P (t))
+           perform_or_defer_access_check (TYPE_BINFO (type), t);
+         else
+           perform_or_defer_access_check (basebinfo, t);
+
          mark_used (t);
          if (DECL_STATIC_FUNCTION_P (t))
            return t;
@@ -1517,6 +1537,11 @@ build_offset_ref (tree type, tree name, bool address_p)
          member = fnfields;
        }
     }
+  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);
 
   if (!address_p)
     {
@@ -1539,16 +1564,20 @@ build_offset_ref (tree type, tree name, bool address_p)
           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)
            {
-             member = build (OFFSET_REF, TREE_TYPE (member), decl, member);
              PTRMEM_OK_P (member) = 1;
              return build_unary_op (ADDR_EXPR, member, 0);
            }
-         error ("invalid use of non-static member function `%D'", member);
-         return error_mark_node;
+         error ("invalid use of non-static member function `%D'", 
+                TREE_OPERAND (member, 1));
+         return member;
        }
       else if (TREE_CODE (member) == FIELD_DECL)
        {
@@ -1572,8 +1601,31 @@ build_offset_ref (tree type, tree name, bool address_p)
 tree
 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.
@@ -1654,7 +1706,7 @@ build_new (tree placement, tree decl, tree init, int 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)
@@ -1744,6 +1796,7 @@ build_new (tree placement, tree decl, tree init, int use_global_new)
       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;
     }
 
@@ -1786,7 +1839,7 @@ build_new (tree placement, tree decl, tree init, int 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;
 }
@@ -1809,7 +1862,7 @@ build_java_class_ref (tree 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))
@@ -1869,7 +1922,7 @@ static tree
 build_new_1 (tree exp)
 {
   tree placement, init;
-  tree 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;
@@ -1910,6 +1963,7 @@ build_new_1 (tree exp)
      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);
@@ -1969,23 +2023,31 @@ build_new_1 (tree exp)
     {
       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 fns;
 
       fnname = ansi_opname (code);
 
@@ -2004,11 +2066,18 @@ build_new_1 (tree exp)
            }
          /* Create the argument list.  */
          args = tree_cons (NULL_TREE, size, placement);
-         /* Call the function.  */
-         alloc_call = build_method_call (build_dummy_object (true_type),
-                                         fnname, args, 
-                                         TYPE_BINFO (true_type),
-                                         LOOKUP_NORMAL);
+         /* 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
        {
@@ -2027,13 +2096,22 @@ build_new_1 (tree exp)
   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
@@ -2050,6 +2128,17 @@ build_new_1 (tree 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_,
@@ -2063,18 +2152,6 @@ build_new_1 (tree exp)
   nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
   check_new = (flag_check_new || nothrow) && ! use_java_new;
 
-  /* 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);
-
   if (cookie_size)
     {
       tree cookie;
@@ -2099,27 +2176,43 @@ build_new_1 (tree exp)
       data_addr = alloc_node;
     }
 
-  /* Now initialize the allocated object.  */
+  /* 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)
     {
+      bool stable;
+
       init_expr = build_indirect_ref (data_addr, NULL);
 
       if (init == void_zero_node)
        init = build_default_init (full_type, nelts);
-      else if (init && pedantic && has_array)
+      else if (init && has_array)
        pedwarn ("ISO C++ forbids initialization in array new");
 
       if (has_array)
-       init_expr
-         = build_vec_init (init_expr,
-                           cp_build_binary_op (MINUS_EXPR, outer_nelts,
-                                               integer_one_node),
-                           init, /*from_array=*/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
@@ -2127,15 +2220,13 @@ build_new_1 (tree exp)
 
          if (TREE_CODE (init) == TREE_LIST)
            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)
@@ -2153,43 +2244,33 @@ build_new_1 (tree exp)
        {
          enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
          tree cleanup;
-         int flags = (LOOKUP_NORMAL 
-                      | (globally_qualified_p * LOOKUP_GLOBAL));
 
          /* The Standard is unclear here, but the right thing to do
             is to use the same method for finding deallocation
             functions that we use for finding allocation functions.  */
-         flags |= LOOKUP_SPECULATIVELY;
-
-         cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
+         cleanup = build_op_delete_call (dcode, 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;
 
@@ -2210,6 +2291,7 @@ build_new_1 (tree exp)
                         build (COMPOUND_EXPR, void_type_node, init_expr,
                                end));
            }
+           
        }
     }
   else
@@ -2242,8 +2324,17 @@ build_new_1 (tree exp)
       rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
     }
 
+  if (init_preeval_expr)
+    rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_preeval_expr, rval);
+
   /* Convert to the final type.  */
-  return build_nop (pointer_type, rval);
+  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
@@ -2354,7 +2445,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
   /* 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);
 
@@ -2478,7 +2570,7 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
     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;
@@ -2490,7 +2582,8 @@ build_vec_init (tree base, tree maxindex, tree init, int 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
@@ -2538,11 +2631,13 @@ build_vec_init (tree base, tree maxindex, tree init, int 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));
@@ -2662,18 +2757,22 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
 
       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);
+
+  /* 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;
 }
@@ -2698,9 +2797,9 @@ 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
@@ -2764,27 +2863,39 @@ build_delete (tree type, tree addr, special_function_kind auto_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)
@@ -2819,8 +2930,7 @@ build_delete (tree type, tree addr, special_function_kind auto_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
@@ -2855,7 +2965,7 @@ build_delete (tree type, tree addr, special_function_kind auto_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;
@@ -2866,7 +2976,7 @@ build_delete (tree type, tree addr, special_function_kind auto_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),
@@ -2895,7 +3005,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
    Called from begin_destructor_body.  */
 
 void
-push_base_cleanups ()
+push_base_cleanups (void)
 {
   tree binfos;
   int i, n_baseclasses;
@@ -3044,7 +3154,8 @@ build_vec_delete (tree base, tree maxindex,
     }
   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);