41st Cygnus<->FSF merge
[platform/upstream/gcc.git] / gcc / cp / init.c
index eeb5de6..5e5d580 100644 (file)
@@ -50,17 +50,19 @@ void expand_aggr_init ();
 static void expand_aggr_init_1 ();
 static void expand_recursive_init_1 ();
 static void expand_recursive_init ();
+static void expand_virtual_init PROTO((tree, tree));
 tree expand_vec_init ();
-tree build_vec_delete ();
 
 static void add_friend (), add_friends ();
 
 /* Cache _builtin_new and _builtin_delete exprs.  */
-static tree BIN, BID;
+static tree BIN, BID, BIVN, BIVD;
 
 /* Cache the identifier nodes for the two magic field of a new cookie.  */
 static tree nc_nelts_field_id;
+#if 0
 static tree nc_ptr_2comp_field_id;
+#endif
 
 static tree minus_one;
 
@@ -78,6 +80,10 @@ void init_init_processing ()
   TREE_USED (TREE_OPERAND (BIN, 0)) = 0;
   BID = default_conversion (get_first_fn (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) DELETE_EXPR])));
   TREE_USED (TREE_OPERAND (BID, 0)) = 0;
+  BIVN = default_conversion (get_first_fn (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) VEC_NEW_EXPR])));
+  TREE_USED (TREE_OPERAND (BIVN, 0)) = 0;
+  BIVD = default_conversion (get_first_fn (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) VEC_DELETE_EXPR])));
+  TREE_USED (TREE_OPERAND (BIVD, 0)) = 0;
   minus_one = build_int_2 (-1, -1);
 
   /* Define the structure that holds header information for
@@ -95,23 +101,40 @@ void init_init_processing ()
    virtual base classes.  Initialize binfo's vtable pointer, if
    INIT_SELF is true.  CAN_ELIDE is true when we know that all virtual
    function table pointers in all bases have been initialized already,
-   probably because their constructors have just be run.  */
+   probably because their constructors have just be run.  ADDR is the
+   pointer to the object whos vtables we are going to initialize.
+
+   REAL_BINFO is usually the same as BINFO, except when addr is not of
+   pointer to the type of the real derived type that we want to
+   initialize for.  This is the case when addr is a pointer to a sub
+   object of a complete object, and we only want to do part of the
+   complete object's initiailzation of vtable pointers.  This is done
+   for all virtual table pointers in virtual base classes.  REAL_BINFO
+   is used to find the BINFO_VTABLE that we initialize with.  BINFO is
+   used for conversions of addr to subobjects.
+
+   BINFO_TYPE (real_binfo) must be BINFO_TYPE (binfo).
+
+   Relies upon binfo being inside TYPE_BINFO (TREE_TYPE (TREE_TYPE
+   (addr))).  */
 void
-init_vtbl_ptrs (binfo, init_self, can_elide)
-     tree binfo;
+expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
+     tree real_binfo, binfo, addr;
      int init_self, can_elide;
 {
-  tree vfields;
+  tree real_binfos = BINFO_BASETYPES (real_binfo);
   tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  int i, n_baselinks = real_binfos ? TREE_VEC_LENGTH (real_binfos) : 0;
 
   for (i = 0; i < n_baselinks; i++)
     {
+      tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
       tree base_binfo = TREE_VEC_ELT (binfos, i);
       int is_not_base_vtable =
-       i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
-      if (! TREE_VIA_VIRTUAL (base_binfo))
-       init_vtbl_ptrs (base_binfo, is_not_base_vtable, can_elide);
+       i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+      if (! TREE_VIA_VIRTUAL (real_base_binfo))
+       expand_direct_vtbls_init (real_base_binfo, base_binfo,
+                                 is_not_base_vtable, can_elide, addr);
     }
 #if 0
   /* Before turning this on, make sure it is correct.  */
@@ -119,10 +142,10 @@ init_vtbl_ptrs (binfo, init_self, can_elide)
     return;
 #endif
   /* Should we use something besides CLASSTYPE_VFIELDS? */
-  if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+  if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (real_binfo)))
     {
-      tree base_ptr = convert_pointer_to_real (binfo, current_class_decl);
-      expand_expr_stmt (build_virtual_init (binfo, binfo, base_ptr));
+      tree base_ptr = convert_pointer_to_real (binfo, addr);
+      expand_virtual_init (real_binfo, base_ptr);
     }
 }
 \f
@@ -194,12 +217,8 @@ perform_member_init (member, name, init, explicit)
          expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
        }
     }
-
-  if (flag_handle_exceptions == 2 && TYPE_NEEDS_DESTRUCTOR (type))
-    {
-      cplus_expand_start_try (1);
-      push_exception_cleanup (build_unary_op (ADDR_EXPR, decl, 0));
-    }
+  if (flag_handle_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
+    cp_warning ("caution, member `%D' may not be destroyed in the presense of an exception during construction", member);
 }
 
 /* Subroutine of emit_member_init.  */
@@ -345,13 +364,12 @@ emit_base_init (t, immediately)
 {
   extern tree in_charge_identifier;
 
-  tree member, decl, vbases;
-  tree init_list, member_init;
+  tree member, vbases;
+  tree init_list;
   int pass, start;
   tree t_binfo = TYPE_BINFO (t);
   tree binfos = BINFO_BASETYPES (t_binfo);
   int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  tree fields_to_unmark = NULL_TREE;
   int have_init_list = 0, from_init_list;
 
   if (! immediately)
@@ -368,20 +386,6 @@ emit_base_init (t, immediately)
     emit_line_note_force (DECL_SOURCE_FILE (current_function_decl),
                          DECL_SOURCE_LINE (current_function_decl));
 
-  /* In this case, we always need IN_CHARGE_NODE, because we have
-     to know whether to deallocate or not before exiting.  */
-  if (flag_handle_exceptions == 2
-      && lookup_name (in_charge_identifier, 0) == NULL_TREE)
-    {
-      tree in_charge_node = pushdecl (build_decl (VAR_DECL, in_charge_identifier,
-                                                 integer_type_node));
-      store_init_value (in_charge_node, build (EQ_EXPR, integer_type_node,
-                                              current_class_decl,
-                                              integer_zero_node));
-      expand_decl (in_charge_node);
-      expand_decl_init (in_charge_node);
-    }
-
   start = ! TYPE_USES_VIRTUAL_BASECLASSES (t);
   for (pass = start; pass < 2; pass++)
     {
@@ -499,11 +503,6 @@ emit_base_init (t, immediately)
          expand_aggr_init_1 (t_binfo, 0,
                              build_indirect_ref (member, NULL_PTR), init,
                              BINFO_OFFSET_ZEROP (binfo), LOOKUP_COMPLAIN);
-         if (flag_handle_exceptions == 2 && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
-           {
-             cplus_expand_start_try (1);
-             push_exception_cleanup (member);
-           }
        }
 
       if (pass == 0)
@@ -572,12 +571,6 @@ emit_base_init (t, immediately)
              expand_aggr_init_1 (t_binfo, 0, ref, NULL_TREE,
                                  BINFO_OFFSET_ZEROP (base_binfo),
                                  LOOKUP_COMPLAIN);
-             if (flag_handle_exceptions == 2
-                 && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
-               {
-                 cplus_expand_start_try (1);
-                 push_exception_cleanup (base);
-               }
            }
        }
       CLEAR_BINFO_BASEINIT_MARKED (base_binfo);
@@ -600,18 +593,13 @@ emit_base_init (t, immediately)
   /* Initialize all the virtual function table fields that
      do come from virtual base classes. */
   if (TYPE_USES_VIRTUAL_BASECLASSES (t))
-    expand_expr_stmt (build_vbase_vtables_init (t_binfo, t_binfo,
-                                               C_C_D, current_class_decl, 0));
+    expand_indirect_vtbls_init (t_binfo, C_C_D, current_class_decl, 0);
   for (vbases = CLASSTYPE_VBASECLASSES (t); vbases; vbases = TREE_CHAIN (vbases))
     CLEAR_BINFO_BASEINIT_MARKED (vbases);
 
   /* Initialize all the virtual function table fields that
      do not come from virtual base classes.  */
-  init_vtbl_ptrs (t_binfo, 0, 1);
-
-  if (CLASSTYPE_NEEDS_VIRTUAL_REINIT (t))
-    expand_expr_stmt (build_virtual_init (TYPE_BINFO (t), t,
-                                         current_class_decl));
+  expand_direct_vtbls_init (t_binfo, t_binfo, 1, 1, current_class_decl);
 
   if (current_member_init_list)
     {
@@ -655,7 +643,7 @@ emit_base_init (t, immediately)
          /* member could be, for example, a CONST_DECL for an enumerated
             tag; we don't want to try to initialize that, since it already
             has a value.  */
-         if (TREE_CODE (member) != FIELD_DECL)
+         if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member))
            continue;
 
          name = DECL_NAME (member);
@@ -704,86 +692,32 @@ check_base_init (t)
 
    BINFO is the exact type that DECL is supposed to be.  In
    multiple inheritance, this might mean "C's A" if C : A, B.  */
-tree
-build_virtual_init (main_binfo, binfo, decl)
-     tree main_binfo, binfo;
-     tree decl;
+static void
+expand_virtual_init (binfo, decl)
+     tree binfo, decl;
 {
-  tree type;
+  tree type = BINFO_TYPE (binfo);
   tree vtbl, vtbl_ptr;
   tree vtype, vtype_binfo;
 
-  if (TREE_CODE (binfo) == TREE_VEC)
-    type = BINFO_TYPE (binfo);
-  else if (TREE_CODE (binfo) == RECORD_TYPE)
-    {
-      type = binfo;
-      binfo = TYPE_BINFO (type);
-    }
-  else
-    my_friendly_abort (46);
-
+  /* This code is crusty.  Should be simple, like:
+     vtbl = BINFO_VTABLE (binfo);
+     */
   vtype = DECL_CONTEXT (CLASSTYPE_VFIELD (type));
   vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
-#if 0
-  /* This code suggests that it's time to rewrite how we handle
-     replicated baseclasses in G++.  */
-  if (get_base_distance (vtype, TREE_TYPE (TREE_TYPE (decl)),
-                        0, (tree *) 0) == -2)
-    {
-      tree binfos = TYPE_BINFO_BASETYPES (TREE_TYPE (TREE_TYPE (decl)));
-      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-      tree result = NULL_TREE;
-
-      for (i = n_baselinks-1; i >= 0; i--)
-       {
-         tree base_binfo = TREE_VEC_ELT (binfos, i);
-         tree this_decl;
-
-         if (get_base_distance (vtype, BINFO_TYPE (base_binfo), 0, 0) == -1)
-           continue;
-
-         if (TREE_VIA_VIRTUAL (base_binfo))
-           this_decl = build_vbase_pointer (build_indirect_ref (decl, NULL_PTR), BINFO_TYPE (base_binfo));
-         else if (BINFO_OFFSET_ZEROP (base_binfo))
-           this_decl = build1 (NOP_EXPR, TYPE_POINTER_TO (BINFO_TYPE (base_binfo)),
-                               decl);
-         else
-           this_decl = build (PLUS_EXPR, TYPE_POINTER_TO (BINFO_TYPE (base_binfo)),
-                              decl, BINFO_OFFSET (base_binfo));
-         result = tree_cons (NULL_TREE, build_virtual_init (main_binfo, base_binfo, this_decl), result);
-       }
-      return build_compound_expr (result);
-    }
-#endif
-
-    {
-#if 1
-#if 1
-      vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)), binfo));
-#else
-      /* The below does not work when we have to step through the
-        vfield, on our way down to the most base class for the
-        vfield. */
-      vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)),
-                                       BINFO_TYPE (main_binfo)));
-#endif
-#else
-      my_friendly_assert (BINFO_TYPE (main_binfo) == BINFO_TYPE (binfo), 208);
-      vtbl = BINFO_VTABLE (main_binfo);
-#endif /* 1 */
-      assemble_external (vtbl);
-      TREE_USED (vtbl) = 1;
-      vtbl = build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (vtbl)), vtbl);
-    }
+  vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)), binfo));
+  if (!flag_vtable_thunks)
+    assemble_external (vtbl);
+  TREE_USED (vtbl) = 1;
+  vtbl = build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (vtbl)), vtbl);
   decl = convert_pointer_to_real (vtype_binfo, decl);
   vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL_PTR), vtype);
   if (vtbl_ptr == error_mark_node)
-    return error_mark_node;
+    return;
 
   /* Have to convert VTBL since array sizes may be different.  */
-  return build_modify_expr (vtbl_ptr, NOP_EXPR,
-                           convert (TREE_TYPE (vtbl_ptr), vtbl));
+  vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl);
+  expand_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
 }
 
 /* Subroutine of `expand_aggr_vbase_init'.
@@ -1183,13 +1117,7 @@ expand_aggr_init (exp, init, alias_this)
       int was_const_elts = TYPE_READONLY (TREE_TYPE (type));
       tree itype = init ? TREE_TYPE (init) : NULL_TREE;
       if (was_const_elts)
-       {
-         tree atype = build_cplus_array_type (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
-                                              TYPE_DOMAIN (type));
-         if (init && (TREE_TYPE (exp) == TREE_TYPE (init)))
-           TREE_TYPE (init) = atype;
-         TREE_TYPE (exp) = atype;
-       }
+       TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
       if (init && TREE_TYPE (init) == NULL_TREE)
        {
          /* Handle bad initializers like:
@@ -1304,8 +1232,7 @@ expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags)
              tree addr = build_unary_op (ADDR_EXPR, exp, 0);
              expand_aggr_vbase_init (binfo, exp, addr, NULL_TREE);
 
-             expand_expr_stmt (build_vbase_vtables_init (binfo, binfo,
-                                                         exp, addr, 1));
+             expand_indirect_vtbls_init (binfo, exp, addr, 1);
            }
          expand_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
          return;
@@ -1427,7 +1354,6 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
 {
   tree type = TREE_TYPE (exp);
   tree init_type = NULL_TREE;
-  tree rval;
 
   my_friendly_assert (init != error_mark_node && type != error_mark_node, 211);
 
@@ -1715,14 +1641,16 @@ expand_recursive_init_1 (binfo, true_exp, addr, init_list, alias_this)
                 are initializing the ultimate users of those vtables.  */
              if (TREE_VALUE (init_list))
                {
-                 /* We have to ensure that the second argment to
-                    build_virtual_init is in binfo's hierarchy.  */
-                 expand_expr_stmt (build_virtual_init (binfo,
-                                                       get_binfo (TREE_VALUE (init_list), binfo, 0),
-                                                       addr));
+                 /* We have to ensure that the first argment to
+                    expand_virtual_init is in binfo's hierarchy.  */
+                 /* Is it the case that this is exactly the right binfo? */
+                 /* If it is ok, then fixup expand_virtual_init, to make
+                    it much simpler. */
+                 expand_virtual_init (get_binfo (TREE_VALUE (init_list), binfo, 0),
+                                     addr);
                  if (TREE_VALUE (init_list) == binfo
                      && TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
-                   expand_expr_stmt (build_vbase_vtables_init (binfo, binfo, true_exp, addr, 1));
+                   expand_indirect_vtbls_init (binfo, true_exp, addr, 1);
                }
            }
          else
@@ -1771,7 +1699,7 @@ expand_recursive_init (binfo, true_exp, exp, init, init_list, alias_this)
   if (true_exp == exp && TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
     {
       expand_aggr_vbase_init (binfo, exp, addr, init_list);
-      expand_expr_stmt (build_vbase_vtables_init (binfo, binfo, true_exp, addr, 1));
+      expand_indirect_vtbls_init (binfo, true_exp, addr, 1);
     }
   expand_recursive_init_1 (binfo, true_exp, addr, init_list, alias_this);
 
@@ -1803,12 +1731,10 @@ is_aggr_typedef (name, or_else)
 
   if (IDENTIFIER_HAS_TYPE_VALUE (name))
     type = IDENTIFIER_TYPE_VALUE (name);
-  else if (IDENTIFIER_HAS_CLASS_TYPE_VALUE (name))
-    type = IDENTIFIER_CLASS_TYPE_VALUE (name);
   else
     {
       if (or_else)
-       cp_error ("`%T' fails to be an aggregate typedef", name);
+       cp_error ("`%T' is not an aggregate typedef", name);
       return 0;
     }
 
@@ -1816,7 +1742,7 @@ is_aggr_typedef (name, or_else)
       && TREE_CODE (type) != TEMPLATE_TYPE_PARM)
     {
       if (or_else)
-       cp_error ("type `%T' is of non-aggregate type", type);
+       cp_error ("`%T' is not an aggregate type", type);
       return 0;
     }
   return 1;
@@ -1835,8 +1761,6 @@ get_aggr_from_typedef (name, or_else)
 
   if (IDENTIFIER_HAS_TYPE_VALUE (name))
     type = IDENTIFIER_TYPE_VALUE (name);
-  else if (IDENTIFIER_HAS_CLASS_TYPE_VALUE (name))
-    type = IDENTIFIER_CLASS_TYPE_VALUE (name);
   else
     {
       if (or_else)
@@ -1858,15 +1782,11 @@ tree
 get_type_value (name)
      tree name;
 {
-  tree type;
-
   if (name == error_mark_node)
     return NULL_TREE;
 
   if (IDENTIFIER_HAS_TYPE_VALUE (name))
     return IDENTIFIER_TYPE_VALUE (name);
-  else if (IDENTIFIER_CLASS_VALUE (name))
-    return IDENTIFIER_CLASS_TYPE_VALUE (name);
   else
     return NULL_TREE;
 }
@@ -1924,7 +1844,7 @@ build_member_call (cname, name, parmlist)
 
   if (dont_use_this)
     {
-      basetype_path = NULL_TREE;
+      basetype_path = TYPE_BINFO (type);
       decl = build1 (NOP_EXPR, TYPE_POINTER_TO (type), error_mark_node);
     }
   else if (current_class_decl == 0)
@@ -1940,7 +1860,7 @@ build_member_call (cname, name, parmlist)
        {
          tree newtype = build_type_variant (type, TYPE_READONLY (oldtype),
                                             TYPE_VOLATILE (oldtype));
-         decl = convert_force (TYPE_POINTER_TO (newtype), olddecl);
+         decl = convert_force (build_pointer_type (newtype), olddecl);
        }
       else
        decl = olddecl;
@@ -1948,11 +1868,11 @@ build_member_call (cname, name, parmlist)
 
   decl = build_indirect_ref (decl, NULL_PTR);
 
-  if (t = lookup_fnfields (TYPE_BINFO (type), method_name, 0))
+  if (t = lookup_fnfields (basetype_path, method_name, 0))
     return build_method_call (decl, method_name, parmlist, basetype_path,
                              LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
   if (TREE_CODE (name) == IDENTIFIER_NODE
-      && (t = lookup_field (TYPE_BINFO (type), name, 1, 0)))
+      && ((t = lookup_field (TYPE_BINFO (type), name, 1, 0))))
     {
       if (t == error_mark_node)
        return error_mark_node;
@@ -2039,10 +1959,12 @@ build_offset_ref (cname, name)
       return error_mark_node;
     }
 
+#if 0
   if (TREE_CODE (name) == TYPE_EXPR)
     /* Pass a TYPE_DECL to build_component_type_expr.  */
     return build_component_type_expr (TYPE_NAME (TREE_TYPE (cname)),
                                      name, NULL_TREE, 1);
+#endif
 
   fnfields = lookup_fnfields (TYPE_BINFO (type), name, 1);
   fields = lookup_field (type, name, 0, 0);
@@ -2159,8 +2081,7 @@ build_offset_ref (cname, name)
 
   if (t == NULL_TREE)
     {
-      cp_error ("`%D' is not a member of type `%T'", name,
-                 IDENTIFIER_TYPE_VALUE (cname));
+      cp_error ("`%D' is not a member of type `%T'", name, type);
       return error_mark_node;
     }
 
@@ -2209,14 +2130,6 @@ get_member_function (exp_addr_ptr, exp, member)
       /* Cast function to signed integer.  */
       e0 = build1 (NOP_EXPR, integer_type_node, function);
 
-#ifdef VTABLE_USES_MASK
-      /* If we are willing to limit the number of
-        virtual functions a class may have to some
-        *small* number, then if, for a function address,
-        we are passed some small number, we know that
-        it is a virtual function index, and work from there.  */
-      e1 = build (BIT_AND_EXPR, integer_type_node, e0, vtbl_mask);
-#else
       /* There is a hack here that takes advantage of
         twos complement arithmetic, and the fact that
         there are more than one UNITS to the WORD.
@@ -2231,7 +2144,6 @@ get_member_function (exp_addr_ptr, exp, member)
       e1 = build_compound_expr (tree_cons (NULL_TREE, exp_addr,
                                           build_tree_list (NULL_TREE, e1)));
       e1 = save_expr (e1);
-#endif
 
       if (TREE_SIDE_EFFECTS (*exp_addr_ptr))
        {
@@ -2328,13 +2240,11 @@ resolve_offset_ref (exp)
       enum access_type access;
 
       if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
-       {
-         basetype = TYPE_OFFSET_BASETYPE (type);
-         base = convert_pointer_to (basetype, current_class_decl);
-       }
+       basetype = TYPE_OFFSET_BASETYPE (type);
       else
-       base = current_class_decl;
-      basetype = DECL_CONTEXT (member);
+       basetype = DECL_CONTEXT (member);
+
+      base = current_class_decl;
       
       if (get_base_distance (basetype, TREE_TYPE (TREE_TYPE (base)), 0, &basetype_path) < 0)
        {
@@ -2525,8 +2435,10 @@ add_friend (type, decl)
            {
              if (decl == TREE_VALUE (friends))
                {
-                 cp_pedwarn_at ("`%D' is already a friend of class `%T'",
-                                decl, type);
+                 cp_pedwarn ("`%D' is already a friend of class `%T'",
+                             decl, type);
+                 cp_pedwarn_at ("previous friend declaration of `%D'",
+                                TREE_VALUE (friends));
                  return;
                }
            }
@@ -2606,9 +2518,9 @@ static void
 xref_friend (type, decl, ctype)
      tree type, decl, ctype;
 {
-  tree typedecl = TYPE_NAME (type);
   tree friend_decl = TYPE_NAME (ctype);
 #if 0
+  tree typedecl = TYPE_NAME (type);
   tree t = tree_cons (NULL_TREE, ctype, DECL_UNDEFINED_FRIENDS (typedecl));
 
   DECL_UNDEFINED_FRIENDS (typedecl) = t;
@@ -2695,40 +2607,9 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals)
      enum overload_flags flags;
      tree quals;
 {
-  /* first, lets find out if what we are making a friend needs overloading */
-  tree previous_decl;
-  int was_c_linkage = 0;
-
   /* Every decl that gets here is a friend of something.  */
   DECL_FRIEND_P (decl) = 1;
 
-  /* If we find something in scope, let see if it has extern "C" linkage.  */
-  /* This code is pretty general and should be ripped out and reused
-     as a separate function. */
-  if (DECL_NAME (decl))
-    {
-      previous_decl = lookup_name (DECL_NAME (decl), 0);
-      if (previous_decl && TREE_CODE (previous_decl) == TREE_LIST)
-       {
-         do
-           {
-             if (TREE_TYPE (TREE_VALUE (previous_decl)) == TREE_TYPE (decl))
-               {
-                 previous_decl = TREE_VALUE (previous_decl);
-                 break;
-               }
-             previous_decl = TREE_CHAIN (previous_decl);
-           }
-         while (previous_decl);
-       }
-
-      /* It had extern "C" linkage, so don't overload this.  */
-      if (previous_decl && TREE_CODE (previous_decl) == FUNCTION_DECL
-         && TREE_TYPE (decl) == TREE_TYPE (previous_decl)
-         && DECL_LANGUAGE (previous_decl) == lang_c)
-       was_c_linkage = 1;
-    }
-         
   if (ctype)
     {
       tree cname = TYPE_NAME (ctype);
@@ -2793,7 +2674,6 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals)
          decl = void_type_node;
        }
     }
-  /* never overload C functions */
   else if (TREE_CODE (decl) == FUNCTION_DECL
           && ((IDENTIFIER_LENGTH (declarator) == 4
                && IDENTIFIER_POINTER (declarator)[0] == 'm'
@@ -2802,21 +2682,13 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals)
                   && IDENTIFIER_POINTER (declarator)[0] == '_'
                   && IDENTIFIER_POINTER (declarator)[1] == '_'
                   && strncmp (IDENTIFIER_POINTER (declarator)+2,
-                              "builtin_", 8) == 0)
-              || was_c_linkage))
+                              "builtin_", 8) == 0)))
     {
       /* raw "main", and builtin functions never gets overloaded,
         but they can become friends.  */
       TREE_PUBLIC (decl) = 1;
       add_friend (current_class_type, decl);
       DECL_FRIEND_P (decl) = 1;
-      if (IDENTIFIER_POINTER (declarator)[0] == '_')
-       {
-         if (! strcmp (IDENTIFIER_POINTER (declarator)+10, "new"))
-           TREE_GETS_NEW (current_class_type) = 0;
-         else if (! strcmp (IDENTIFIER_POINTER (declarator)+10, "delete"))
-           TREE_GETS_DELETE (current_class_type) = 0;
-       }
       decl = void_type_node;
     }
   /* A global friend.
@@ -2836,29 +2708,21 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals)
 
       /* We can call pushdecl here, because the TREE_CHAIN of this
         FUNCTION_DECL is not needed for other purposes.  */
-      decl = pushdecl_top_level (decl);
+      decl = pushdecl (decl);
 
       make_decl_rtl (decl, NULL_PTR, 1);
       add_friend (current_class_type, decl);
 
-      if (! TREE_OVERLOADED (declarator)
-         && IDENTIFIER_GLOBAL_VALUE (declarator)
-         && TREE_CODE (IDENTIFIER_GLOBAL_VALUE (declarator)) == FUNCTION_DECL)
-       {
-         error ("friend `%s' implicitly overloaded",
-                IDENTIFIER_POINTER (declarator));
-         cp_error_at ("after declaration of non-overloaded `%D'", IDENTIFIER_GLOBAL_VALUE (declarator));
-       }
       DECL_FRIEND_P (decl) = 1;
-      DECL_OVERLOADED (decl) = 1;
+#if 0
       TREE_OVERLOADED (declarator) = 1;
-      decl = push_overloaded_decl (decl, 1);
+#endif
     }
   else
     {
       /* @@ Should be able to ingest later definitions of this function
         before use.  */
-      tree decl = IDENTIFIER_GLOBAL_VALUE (declarator);
+      tree decl = lookup_name_nonclass (declarator);
       if (decl == NULL_TREE)
        {
          warning ("implicitly declaring `%s' as struct",
@@ -2973,7 +2837,7 @@ build_builtin_call (type, node, arglist)
 
    Unless I am mistaken, a call to new () will return initialized
    data regardless of whether the constructor itself is private or
-   not.
+   not.  NOPE; new fails if the constructor is private (jcm).
 
    Note that build_new does nothing to assure that any special
    alignment requirements of the type are met.  Rather, it leaves
@@ -2990,8 +2854,9 @@ build_new (placement, decl, init, use_global_new)
      int use_global_new;
 {
   tree type, true_type, size, rval;
-  tree init1 = NULL_TREE, nelts;
-  int has_call = 0, has_array = 0;
+  tree nelts;
+  int has_array = 0;
+  enum tree_code code = NEW_EXPR;
 
   tree pending_sizes = NULL_TREE;
 
@@ -3014,13 +2879,7 @@ build_new (placement, decl, init, use_global_new)
       nelts = integer_one_node;
 
       if (absdcl && TREE_CODE (absdcl) == CALL_EXPR)
-       {
-         /* probably meant to be a call */
-         has_call = 1;
-         init1 = TREE_OPERAND (absdcl, 1);
-         absdcl = TREE_OPERAND (absdcl, 0);
-         TREE_VALUE (decl) = absdcl;
-       }
+       my_friendly_abort (215);
       while (absdcl && TREE_CODE (absdcl) == INDIRECT_REF)
        {
          last_absdcl = absdcl;
@@ -3047,7 +2906,7 @@ build_new (placement, decl, init, use_global_new)
                error ("new of array type fails to specify size");
              else
                {
-                 this_nelts = save_expr (this_nelts);
+                 this_nelts = save_expr (convert (sizetype, this_nelts));
                  absdcl = TREE_OPERAND (absdcl, 0);
                  if (this_nelts == integer_zero_node)
                    {
@@ -3068,25 +2927,12 @@ build_new (placement, decl, init, use_global_new)
        TREE_VALUE (decl) = absdcl;
 
       type = true_type = groktypename (decl);
-      if (! type || type == error_mark_node
-         || true_type == error_mark_node)
+      if (! type || type == error_mark_node)
        {
          immediate_size_expand = old_immediate_size_expand;
          return error_mark_node;
        }
 
-      /* ``A reference cannot be created by the new operator.  A reference
-        is not an object (8.2.2, 8.4.3), so a pointer to it could not be
-        returned by new.'' ARM 5.3.3 */
-      if (TREE_CODE (type) == REFERENCE_TYPE)
-       error ("new cannot be applied to a reference type");
-
-      type = TYPE_MAIN_VARIANT (type);
-      if (type == void_type_node)
-       {
-         error ("invalid type: `void []'");
-         return error_mark_node;
-       }
       if (current_function_decl
          && DECL_CONSTRUCTOR_P (current_function_decl))
        {
@@ -3123,42 +2969,37 @@ build_new (placement, decl, init, use_global_new)
       decl = TYPE_NAME (type);
     }
 
-  if (TYPE_SIZE (type) == 0)
+  /* ``A reference cannot be created by the new operator.  A reference
+     is not an object (8.2.2, 8.4.3), so a pointer to it could not be
+     returned by new.'' ARM 5.3.3 */
+  if (TREE_CODE (type) == REFERENCE_TYPE)
     {
-      if (type == void_type_node)
-       error ("invalid type for new: `void'");
-      else
-       incomplete_type_error (0, type);
-      return error_mark_node;
+      error ("new cannot be applied to a reference type");
+      type = true_type = TREE_TYPE (type);
     }
 
-  if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_ABSTRACT_VIRTUALS (type))
+  /* When the object being created is an array, the new-expression yields a
+     pointer to the initial element (if any) of the array.  For example,
+     both new int and new int[10] return an int*.  5.3.4.  */
+  if (TREE_CODE (type) == ARRAY_TYPE && has_array == 0)
     {
-      abstract_virtuals_error (NULL_TREE, type);
-      return error_mark_node;
+      nelts = array_type_nelts_top (type);
+      has_array = 1;
+      type = true_type = TREE_TYPE (type);
     }
 
-  if (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE (type))
+  if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
     {
-      signature_error (NULL_TREE, type);
-      return error_mark_node;
+      pedwarn ("const and volatile types cannot be created with operator new");
+      type = true_type = TYPE_MAIN_VARIANT (type);
     }
-
+  
   /* If our base type is an array, then make sure we know how many elements
      it has.  */
   while (TREE_CODE (true_type) == ARRAY_TYPE)
     {
       tree this_nelts = array_type_nelts_top (true_type);
-      if (nelts == integer_one_node)
-       {
-         has_array = 1;
-         nelts = this_nelts;
-       }
-      else
-       {
-         my_friendly_assert (has_array != 0, 216);
-         nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
-       }
+      nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
       true_type = TREE_TYPE (true_type);
     }
   if (has_array)
@@ -3167,31 +3008,52 @@ build_new (placement, decl, init, use_global_new)
   else
     size = size_in_bytes (type);
 
-  if (has_call)
-    init = init1;
+  if (TYPE_SIZE (true_type) == 0)
+    {
+      if (true_type == void_type_node)
+       error ("invalid type for new: `void'");
+      else
+       incomplete_type_error (0, true_type);
+      return error_mark_node;
+    }
+
+  if (TYPE_LANG_SPECIFIC (true_type)
+      && CLASSTYPE_ABSTRACT_VIRTUALS (true_type))
+    {
+      abstract_virtuals_error (NULL_TREE, true_type);
+      return error_mark_node;
+    }
+
+  if (TYPE_LANG_SPECIFIC (true_type) && IS_SIGNATURE (true_type))
+    {
+      signature_error (NULL_TREE, true_type);
+      return error_mark_node;
+    }
 
   /* Get a little extra space to store a couple of things before the new'ed
      array. */
-  if (has_array && TYPE_NEEDS_DESTRUCTOR (true_type))
+  if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
     {
       tree extra = BI_header_size;
 
       size = size_binop (PLUS_EXPR, size, extra);
     }
 
+  if (has_array)
+    code = VEC_NEW_EXPR;
+
   /* Allocate the object. */
-  if (TYPE_LANG_SPECIFIC (true_type)
-      && (TREE_GETS_NEW (true_type) || TREE_GETS_PLACED_NEW (true_type))
-      && !use_global_new)
-    rval = build_opfncall (NEW_EXPR, LOOKUP_NORMAL,
+  if (! use_global_new && TYPE_LANG_SPECIFIC (true_type)
+      && (TYPE_GETS_NEW (true_type) & (1 << has_array)))
+    rval = build_opfncall (code, LOOKUP_NORMAL,
                           TYPE_POINTER_TO (true_type), size, placement);
   else if (placement)
     {
-      rval = build_opfncall (NEW_EXPR, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
+      rval = build_opfncall (code, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
                             ptr_type_node, size, placement);
       rval = convert (TYPE_POINTER_TO (true_type), rval);
     }
-  else if (flag_this_is_variable > 0
+  else if (! has_array && flag_this_is_variable > 0
           && TYPE_HAS_CONSTRUCTOR (true_type) && init != void_type_node)
     {
       if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST)
@@ -3205,7 +3067,8 @@ build_new (placement, decl, init, use_global_new)
   else
     {
       rval = build_builtin_call (build_pointer_type (true_type),
-                                BIN, build_tree_list (NULL_TREE, size));
+                                has_array ? BIVN : BIN,
+                                build_tree_list (NULL_TREE, size));
 #if 0
       /* See comment above as to why this is disabled.  */
       if (alignment)
@@ -3218,14 +3081,13 @@ build_new (placement, decl, init, use_global_new)
        }
 #endif
       TREE_CALLS_NEW (rval) = 1;
-      TREE_SIDE_EFFECTS (rval) = 1;
     }
 
   /* if rval is NULL_TREE I don't have to allocate it, but are we totally
      sure we have some extra bytes in that case for the BI_header_size
      cookies? And how does that interact with the code below? (mrs) */
   /* Finish up some magic for new'ed arrays */
-  if (has_array && TYPE_NEEDS_DESTRUCTOR (true_type) && rval != NULL_TREE)
+  if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type) && rval != NULL_TREE)
     {
       tree extra = BI_header_size;
       tree cookie, exp1;
@@ -3302,8 +3164,7 @@ build_new (placement, decl, init, use_global_new)
   if (init == void_type_node)
     goto done;
 
-  if (TYPE_NEEDS_CONSTRUCTING (type)
-      || (has_call || init))
+  if (TYPE_NEEDS_CONSTRUCTING (type) || init)
     {
       if (! TYPE_NEEDS_CONSTRUCTING (type) && ! IS_AGGR_TYPE (type))
        {
@@ -3611,20 +3472,21 @@ expand_vec_init (decl, base, maxindex, init, from_array)
 
    This does not call any destructors.  */
 tree
-build_x_delete (type, addr, use_global_delete, virtual_size)
+build_x_delete (type, addr, which_delete, virtual_size)
      tree type, addr;
-     int use_global_delete;
+     int which_delete;
      tree virtual_size;
 {
+  int use_global_delete = which_delete & 1;
+  int use_vec_delete = !!(which_delete & 2);
   tree rval;
+  enum tree_code code = use_vec_delete ? VEC_DELETE_EXPR : DELETE_EXPR;
 
-  if (!use_global_delete
-      && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
-      && TREE_GETS_DELETE (TREE_TYPE (type)))
-    rval = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
-                          virtual_size, NULL_TREE);
+  if (! use_global_delete && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
+      && (TYPE_GETS_DELETE (TREE_TYPE (type)) & (1 << use_vec_delete)))
+    rval = build_opfncall (code, LOOKUP_NORMAL, addr, virtual_size, NULL_TREE);
   else
-    rval = build_builtin_call (void_type_node, BID,
+    rval = build_builtin_call (void_type_node, use_vec_delete ? BIVD : BID,
                               build_tree_list (NULL_TREE, addr));
   return rval;
 }
@@ -3665,7 +3527,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
 
   if (TREE_CODE (type) == POINTER_TYPE)
     {
-      type = TREE_TYPE (type);
+      type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
       if (TYPE_SIZE (type) == 0)
        {
          incomplete_type_error (0, type);
@@ -3681,6 +3543,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
        }
       if (TREE_SIDE_EFFECTS (addr))
        addr = save_expr (addr);
+
+      /* throw away const and volatile on target type of addr */
+      addr = convert_force (build_pointer_type (type), addr);
       ref = build_indirect_ref (addr, NULL_PTR);
       ptr = 1;
     }
@@ -3691,7 +3556,8 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
        addr = save_expr (addr);
       return build_vec_delete (addr, array_type_nelts (type),
                               c_sizeof_nowarn (TREE_TYPE (type)),
-                              NULL_TREE, auto_delete, integer_two_node);
+                              auto_delete, integer_two_node,
+                              use_global_delete);
     }
   else
     {
@@ -3719,17 +3585,13 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
 
   if (! TYPE_NEEDS_DESTRUCTOR (type))
     {
-      tree virtual_size;
-
       if (auto_delete == integer_zero_node)
        return void_zero_node;
 
       /* Pass the size of the object down to the operator delete() in
         addition to the ADDR.  */
-      if (TREE_GETS_DELETE (type) && !use_global_delete)
+      if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
        {
-         /* This is probably wrong. It should be the size of the virtual
-            object being deleted.  */
          tree virtual_size = c_sizeof_nowarn (type);
          return build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
                                 virtual_size, NULL_TREE);
@@ -3748,6 +3610,26 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
     {
       tree dtor = DECL_MAIN_VARIANT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0));
       tree basetypes = TYPE_BINFO (type);
+      tree passed_auto_delete;
+      tree do_delete = NULL_TREE;
+
+      if (use_global_delete)
+       {
+         tree cond = fold (build (BIT_AND_EXPR, integer_type_node,
+                                  auto_delete, integer_one_node));
+         tree call = build_builtin_call
+           (void_type_node, BID, build_tree_list (NULL_TREE, addr));
+
+         cond = fold (build (COND_EXPR, void_type_node, cond,
+                             call, void_zero_node));
+         if (cond != void_zero_node)
+           do_delete = cond;
+
+         passed_auto_delete = fold (build (BIT_AND_EXPR, integer_type_node,
+                                           auto_delete, integer_two_node));
+       }
+      else
+       passed_auto_delete = auto_delete;
 
       if (flags & LOOKUP_PROTECT)
        {
@@ -3795,8 +3677,10 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
          if (function == error_mark_node)
            return error_mark_node;
          TREE_TYPE (function) = build_pointer_type (TREE_TYPE (dtor));
-         TREE_CHAIN (parms) = build_tree_list (NULL_TREE, auto_delete);
+         TREE_CHAIN (parms) = build_tree_list (NULL_TREE, passed_auto_delete);
          expr = build_function_call (function, parms);
+         if (do_delete)
+           expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
          if (ptr && (flags & LOOKUP_DESTRUCTOR) == 0)
            {
              /* Handle the case where a virtual destructor is
@@ -3833,8 +3717,10 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
             but that's now obsolete.  */
          my_friendly_assert (DECL_INITIAL (dtor) != void_type_node, 221);
 
-         TREE_CHAIN (parms) = build_tree_list (NULL_TREE, auto_delete);
+         TREE_CHAIN (parms) = build_tree_list (NULL_TREE, passed_auto_delete);
          expr = build_function_call (dtor, parms);
+         if (do_delete)
+           expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
 
          if (ifexp != integer_one_node)
            expr = build (COND_EXPR, void_type_node,
@@ -3856,7 +3742,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
         operator delete, call the parent parent destructor (if any),
         but let this node do the deleting.  Otherwise, it is ok
         to let the parent destructor do the deleting.  */
-      if (TREE_GETS_DELETE (type) && !use_global_delete)
+      if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
        {
          parent_auto_delete = integer_zero_node;
          if (auto_delete == integer_zero_node)
@@ -3989,8 +3875,6 @@ build_vbase_delete (type, decl)
    MAXINDEX is the number of elements to be deleted.
    ELT_SIZE is the nominal size of each element in the vector.
    BASE is the expression that should yield the store to be deleted.
-   DTOR_DUMMY is a placeholder for a destructor.  The library function
-   __builtin_vec_delete has a pointer to function in this position.
    This function expands (or synthesizes) these calls itself.
    AUTO_DELETE_VEC says whether the container (vector) should be deallocated.
    AUTO_DELETE say whether each item in the container should be deallocated.
@@ -4004,10 +3888,11 @@ build_vbase_delete (type, decl)
    confirm the size, and trap if the numbers differ; not clear that it'd
    be worth bothering.)  */
 tree
-build_vec_delete (base, maxindex, elt_size, dtor_dummy, auto_delete_vec, auto_delete)
+build_vec_delete (base, maxindex, elt_size, auto_delete_vec, auto_delete,
+                 use_global_delete)
      tree base, maxindex, elt_size;
-     tree dtor_dummy;
      tree auto_delete_vec, auto_delete;
+     int use_global_delete;
 {
   tree ptype = TREE_TYPE (base);
   tree type;
@@ -4100,7 +3985,8 @@ build_vec_delete (base, maxindex, elt_size, dtor_dummy, auto_delete_vec, auto_de
       /* This is the real size */
       virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
       body = build_tree_list (NULL_TREE,
-                             build_x_delete (ptr_type_node, base_tbd, 0,
+                             build_x_delete (ptype, base_tbd,
+                                             2 | use_global_delete,
                                              virtual_size));
       body = build (COND_EXPR, void_type_node,
                    build (BIT_AND_EXPR, integer_type_node,
@@ -4112,7 +3998,7 @@ build_vec_delete (base, maxindex, elt_size, dtor_dummy, auto_delete_vec, auto_de
 
   body = tree_cons (NULL_TREE,
                    build_delete (ptype, tbase, auto_delete,
-                                 LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
+                                 LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1),
                    body);
 
   body = tree_cons (NULL_TREE,
@@ -4143,7 +4029,7 @@ build_vec_delete (base, maxindex, elt_size, dtor_dummy, auto_delete_vec, auto_de
       /* The below is short by BI_header_size */
       virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
 
-      if (loop == integer_zero_node)
+      if (! TYPE_VEC_NEW_USES_COOKIE (type))
        /* no header */
        base_tbd = base;
       else
@@ -4156,7 +4042,8 @@ build_vec_delete (base, maxindex, elt_size, dtor_dummy, auto_delete_vec, auto_de
          /* True size with header. */
          virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
        }
-      deallocate_expr = build_x_delete (ptr_type_node, base_tbd, 1,
+      deallocate_expr = build_x_delete (ptype, base_tbd,
+                                       2 | use_global_delete,
                                        virtual_size);
       if (auto_delete_vec != integer_one_node)
        deallocate_expr = build (COND_EXPR, void_type_node,