OSDN Git Service

91th Cygnus<->FSF quick merge
[pf3gnuchains/gcc-fork.git] / gcc / cp / init.c
index 154ab80..378629c 100644 (file)
@@ -19,7 +19,6 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-
 /* High-level class interface.  */
 
 #include "config.h"
@@ -28,6 +27,7 @@ Boston, MA 02111-1307, USA.  */
 #include "cp-tree.h"
 #include "flags.h"
 #include "output.h"
+#include "except.h"
 
 /* In C++, structures with well-defined constructors are initialized by
    those constructors, unasked.  CURRENT_BASE_INIT_LIST
@@ -40,8 +40,6 @@ Boston, MA 02111-1307, USA.  */
    line.  Perhaps this was not intended.  */
 tree current_base_init_list, current_member_init_list;
 
-extern tree cleanups_this_call;
-
 void emit_base_init ();
 void check_base_init ();
 static void expand_aggr_vbase_init ();
@@ -52,8 +50,6 @@ static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int, int));
 static void expand_virtual_init PROTO((tree, tree));
 tree expand_vec_init ();
 
-static void add_friend (), add_friends ();
-
 /* Cache _builtin_new and _builtin_delete exprs.  */
 static tree BIN, BID, BIVN, BIVD;
 
@@ -127,8 +123,8 @@ expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
     {
       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 (real_binfo));
+      int is_not_base_vtable
+       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);
@@ -156,13 +152,8 @@ perform_member_init (member, name, init, explicit)
 {
   tree decl;
   tree type = TREE_TYPE (member);
-  extern int temp_slot_level;
-  extern int target_temp_slot_level; 
-  tree old_cleanups = cleanups_this_call;
-  int old_temp_level = target_temp_slot_level;
-  push_temp_slots ();
-  push_temp_slots ();
-  target_temp_slot_level = temp_slot_level;
+
+  expand_start_target_temps ();
 
   if (TYPE_NEEDS_CONSTRUCTING (type)
       || (init && TYPE_HAS_CONSTRUCTOR (type)))
@@ -222,25 +213,26 @@ perform_member_init (member, name, init, explicit)
          expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
        }
     }
-  expand_cleanups_to (old_cleanups);
-  pop_temp_slots ();
-  pop_temp_slots ();
-  target_temp_slot_level = old_temp_level;
-  /* There might something left from building the trees.  */
-  if (cleanups_this_call)
-    {
-      expand_cleanups_to (NULL_TREE);
-    }
+
+  expand_end_target_temps ();
   free_temp_slots ();
 
   if (TYPE_NEEDS_DESTRUCTOR (type))
     {
-      tree expr = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
+      tree expr;
+
+      /* All cleanups must be on the function_obstack.  */
+      push_obstacks_nochange ();
+      resume_temporary_allocation ();
+
+      expr = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
       expr = build_delete (type, expr, integer_zero_node,
                           LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
 
       if (expr != error_mark_node)
        add_partial_entry (expr);
+
+      pop_obstacks ();
     }
 }
 
@@ -483,13 +475,9 @@ static tree
 build_partial_cleanup_for (binfo)
      tree binfo;
 {
-  tree expr = convert_pointer_to_real (binfo,
-                                      build_unary_op (ADDR_EXPR, current_class_ref, 0));
-
-  return build_delete (TREE_TYPE (expr),
-                      expr,
-                      integer_zero_node,
-                      LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+  return build_scoped_method_call
+    (current_class_ref, binfo, dtor_identifier,
+     build_tree_list (NULL_TREE, integer_zero_node));
 }
 
 /* Perform whatever initializations have yet to be done on the base
@@ -579,31 +567,23 @@ emit_base_init (t, immediately)
       if (TREE_PURPOSE (rbase_init_list))
        init = TREE_VALUE (rbase_init_list);
       else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo)))
-       init = NULL_TREE;
+       {
+         init = NULL_TREE;
+         if (extra_warnings && copy_args_p (current_function_decl))
+           cp_warning ("base class `%#T' should be explicitly initialized in the copy constructor",
+                       BINFO_TYPE (base_binfo));
+       }
 
       if (init != void_list_node)
        {
-         extern int temp_slot_level;
-         extern int target_temp_slot_level; 
-         tree old_cleanups = cleanups_this_call;
-         int old_temp_level = target_temp_slot_level;
-         push_temp_slots ();
-         push_temp_slots ();
-         target_temp_slot_level = temp_slot_level;
+         expand_start_target_temps ();
 
          member = convert_pointer_to_real (base_binfo, current_class_ptr);
          expand_aggr_init_1 (base_binfo, NULL_TREE,
                              build_indirect_ref (member, NULL_PTR), init,
                              BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_NORMAL);
-         expand_cleanups_to (old_cleanups);
-         pop_temp_slots ();
-         pop_temp_slots ();
-         target_temp_slot_level = old_temp_level;
-         /* There might something left from building the trees.  */
-         if (cleanups_this_call)
-           {
-             expand_cleanups_to (NULL_TREE);
-           }
+
+         expand_end_target_temps ();
          free_temp_slots ();
        }
 
@@ -665,6 +645,12 @@ emit_base_init (t, immediately)
          init = DECL_INITIAL (member);
 
          from_init_list = 0;
+
+         /* Effective C++ rule 12.  */
+         if (warn_ecpp && init == NULL_TREE
+             && !DECL_ARTIFICIAL (member)
+             && TREE_CODE (TREE_TYPE (member)) != ARRAY_TYPE)
+           cp_warning ("`%D' should be initialized in the member initialization list", member);            
        }
 
       perform_member_init (member, name, init, from_init_list);
@@ -785,28 +771,14 @@ expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
   tree init = purpose_member (binfo, init_list);
   tree ref = build_indirect_ref (addr, NULL_PTR);
 
-  extern int temp_slot_level;
-  extern int target_temp_slot_level; 
-  tree old_cleanups = cleanups_this_call;
-  int old_temp_level = target_temp_slot_level;
-  push_temp_slots ();
-  push_temp_slots ();
-  target_temp_slot_level = temp_slot_level;
+  expand_start_target_temps ();
 
   if (init)
     init = TREE_VALUE (init);
   /* Call constructors, but don't set up vtables.  */
   expand_aggr_init_1 (binfo, exp, ref, init, 0, LOOKUP_COMPLAIN);
 
-  expand_cleanups_to (old_cleanups);
-  pop_temp_slots ();
-  pop_temp_slots ();
-  target_temp_slot_level = old_temp_level;
-  /* There might something left from building the trees.  */
-  if (cleanups_this_call)
-    {
-      expand_cleanups_to (NULL_TREE);
-    }
+  expand_end_target_temps ();
   free_temp_slots ();
 }
 
@@ -997,22 +969,21 @@ expand_member_init (exp, name, init)
                }
 #endif
            }
-         else
+         else if (basetype != type
+                  && ! current_template_parms
+                  && ! vec_binfo_member (basetype,
+                                         TYPE_BINFO_BASETYPES (type))
+                  && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
            {
-             if (basetype != type
-                 && ! vec_binfo_member (basetype, TYPE_BINFO_BASETYPES (type))
-                 && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
-               {
-                 if (IDENTIFIER_CLASS_VALUE (name))
-                   goto try_member;
-                 if (TYPE_USES_VIRTUAL_BASECLASSES (type))
-                   cp_error ("type `%T' is not an immediate or virtual basetype for `%T'",
-                             basetype, type);
-                 else
-                   cp_error ("type `%T' is not an immediate basetype for `%T'",
-                             basetype, type);
-                 return;
-               }
+             if (IDENTIFIER_CLASS_VALUE (name))
+               goto try_member;
+             if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+               cp_error ("type `%T' is not an immediate or virtual basetype for `%T'",
+                         basetype, type);
+             else
+               cp_error ("type `%T' is not an immediate basetype for `%T'",
+                         basetype, type);
+             return;
            }
 
          if (purpose_member (basetype, current_base_init_list))
@@ -1281,7 +1252,7 @@ expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
         via the copy constructor, even if the call is elided.  */
       if (! (TREE_CODE (exp) == VAR_DECL && DECL_ARTIFICIAL (exp)
             && TREE_CODE (init) == TARGET_EXPR && TREE_TYPE (init) == type))
-       init = cp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+       init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
 
       expand_assignment (exp, init, 0, 0);
       return;
@@ -1435,7 +1406,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
 
       if (TREE_CODE (init) != TREE_LIST)
        {
-         if (TREE_CODE (init_type) == ERROR_MARK)
+         if (init_type == error_mark_node)
            return;
 
          /* This happens when we use C++'s functional cast notation.
@@ -1541,7 +1512,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
          if (init_list && TREE_CHAIN (init_list))
            {
              warning ("initializer list being treated as compound expression");
-             init = convert (type, build_compound_expr (init_list));
+             init = cp_convert (type, build_compound_expr (init_list));
              if (init == error_mark_node)
                return;
            }
@@ -1925,7 +1896,6 @@ build_offset_ref (type, name)
          tree access;
 
          /* unique functions are handled easily.  */
-       unique:
          access = compute_access (basebinfo, t);
          if (access == access_protected_node)
            {
@@ -2131,14 +2101,14 @@ resolve_offset_ref (exp)
 
       basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (member));
       addr = convert_pointer_to (basetype, addr);
-      member = convert (ptrdiff_type_node,
-                       build_unary_op (ADDR_EXPR, member, 0));
+      member = cp_convert (ptrdiff_type_node,
+                          build_unary_op (ADDR_EXPR, member, 0));
       
       /* Pointer to data mebers are offset by one, so that a null
         pointer with a real value of 0 is distinguishable from an
         offset of the first member of a structure.  */
       member = build_binary_op (MINUS_EXPR, member,
-                               convert (ptrdiff_type_node, integer_one_node),
+                               cp_convert (ptrdiff_type_node, integer_one_node),
                                0);
 
       return build1 (INDIRECT_REF, type,
@@ -2169,7 +2139,7 @@ decl_constant_value (decl)
       && ! pedantic
 #endif /* 0 */
       && DECL_INITIAL (decl) != 0
-      && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK
+      && DECL_INITIAL (decl) != error_mark_node
       /* This is invalid if initial value is not constant.
         If it has either a function call, a memory reference,
         or a variable, then re-evaluating it could give different results.  */
@@ -2187,408 +2157,12 @@ decl_constant_value (decl)
   return decl;
 }
 \f
-/* Friend handling routines.  */
-/* Friend data structures:
-
-   Lists of friend functions come from TYPE_DECL nodes.  Since all
-   aggregate types are automatically typedef'd, these nodes are guaranteed
-   to exist.
-
-   The TREE_PURPOSE of a friend list is the name of the friend,
-   and its TREE_VALUE is another list.
-
-   For each element of that list, either the TREE_VALUE or the TREE_PURPOSE
-   will be filled in, but not both.  The TREE_VALUE of that list is an
-   individual function which is a friend.  The TREE_PURPOSE of that list
-   indicates a type in which all functions by that name are friends.
-
-   Lists of friend classes come from _TYPE nodes.  Love that consistency
-   thang.  */
-
-int
-is_friend_type (type1, type2)
-     tree type1, type2;
-{
-  return is_friend (type1, type2);
-}
-
-int
-is_friend (type, supplicant)
-     tree type, supplicant;
-{
-  int declp;
-  register tree list;
-
-  if (supplicant == NULL_TREE || type == NULL_TREE)
-    return 0;
-
-  declp = (TREE_CODE_CLASS (TREE_CODE (supplicant)) == 'd');
-
-  if (declp)
-    /* It's a function decl.  */
-    {
-      tree list = DECL_FRIENDLIST (TYPE_NAME (type));
-      tree name = DECL_NAME (supplicant);
-      tree ctype;
-
-      if (DECL_FUNCTION_MEMBER_P (supplicant))
-       ctype = DECL_CLASS_CONTEXT (supplicant);
-      else
-       ctype = NULL_TREE;
-
-      for (; list ; list = TREE_CHAIN (list))
-       {
-         if (name == TREE_PURPOSE (list))
-           {
-             tree friends = TREE_VALUE (list);
-             for (; friends ; friends = TREE_CHAIN (friends))
-               {
-                 if (ctype == TREE_PURPOSE (friends))
-                   return 1;
-                 if (comptypes (TREE_TYPE (supplicant),
-                                TREE_TYPE (TREE_VALUE (friends)), 1))
-                   return 1;
-               }
-             break;
-           }
-       }
-    }
-  else
-    /* It's a type.  */
-    {
-      if (type == supplicant)
-       return 1;
-      
-      list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_NAME (type)));
-      for (; list ; list = TREE_CHAIN (list))
-       if (supplicant == TREE_VALUE (list))
-         return 1;
-    }      
-
-  {
-    tree context;
-
-    if (! declp)
-      {
-       /* Are we a nested or local class?  If so, we aren't friends
-           with the CONTEXT.  */
-       if (IS_AGGR_TYPE (supplicant))
-         context = NULL_TREE;
-       else
-         context = DECL_CONTEXT (TYPE_NAME (supplicant));
-      }
-    else if (DECL_FUNCTION_MEMBER_P (supplicant))
-      context = DECL_CLASS_CONTEXT (supplicant);
-    else
-      context = NULL_TREE;
-
-    if (context)
-      return is_friend (type, context);
-  }
-
-  return 0;
-}
-
-/* Add a new friend to the friends of the aggregate type TYPE.
-   DECL is the FUNCTION_DECL of the friend being added.  */
-
-static void
-add_friend (type, decl)
-     tree type, decl;
-{
-  tree typedecl = TYPE_NAME (type);
-  tree list = DECL_FRIENDLIST (typedecl);
-  tree name = DECL_NAME (decl);
-
-  while (list)
-    {
-      if (name == TREE_PURPOSE (list))
-       {
-         tree friends = TREE_VALUE (list);
-         for (; friends ; friends = TREE_CHAIN (friends))
-           {
-             if (decl == TREE_VALUE (friends))
-               {
-                 cp_warning ("`%D' is already a friend of class `%T'",
-                             decl, type);
-                 cp_warning_at ("previous friend declaration of `%D'",
-                                TREE_VALUE (friends));
-                 return;
-               }
-           }
-         TREE_VALUE (list) = tree_cons (error_mark_node, decl,
-                                        TREE_VALUE (list));
-         return;
-       }
-      list = TREE_CHAIN (list);
-    }
-  DECL_FRIENDLIST (typedecl)
-    = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
-                DECL_FRIENDLIST (typedecl));
-  if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR])
-    {
-      tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
-      TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
-      if (parmtypes && TREE_CHAIN (parmtypes))
-       {
-         tree parmtype = TREE_VALUE (TREE_CHAIN (parmtypes));
-         if (TREE_CODE (parmtype) == REFERENCE_TYPE
-             && TREE_TYPE (parmtypes) == TREE_TYPE (typedecl))
-           TYPE_HAS_ASSIGN_REF (TREE_TYPE (typedecl)) = 1;
-       }
-    }
-}
-
-/* Declare that every member function NAME in FRIEND_TYPE
-   (which may be NULL_TREE) is a friend of type TYPE.  */
-
-static void
-add_friends (type, name, friend_type)
-     tree type, name, friend_type;
-{
-  tree typedecl = TYPE_NAME (type);
-  tree list = DECL_FRIENDLIST (typedecl);
-
-  while (list)
-    {
-      if (name == TREE_PURPOSE (list))
-       {
-         tree friends = TREE_VALUE (list);
-         while (friends && TREE_PURPOSE (friends) != friend_type)
-           friends = TREE_CHAIN (friends);
-         if (friends)
-           if (friend_type)
-             warning ("method `%s::%s' is already a friend of class",
-                      TYPE_NAME_STRING (friend_type),
-                      IDENTIFIER_POINTER (name));
-           else
-             warning ("function `%s' is already a friend of class `%s'",
-                      IDENTIFIER_POINTER (name),
-                      IDENTIFIER_POINTER (DECL_NAME (typedecl)));
-         else
-           TREE_VALUE (list) = tree_cons (friend_type, NULL_TREE,
-                                          TREE_VALUE (list));
-         return;
-       }
-      list = TREE_CHAIN (list);
-    }
-  DECL_FRIENDLIST (typedecl) =
-    tree_cons (name,
-              build_tree_list (friend_type, NULL_TREE),
-              DECL_FRIENDLIST (typedecl));
-  if (! strncmp (IDENTIFIER_POINTER (name),
-                IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]),
-                strlen (IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]))))
-    {
-      TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
-      sorry ("declaring \"friend operator =\" will not find \"operator = (X&)\" if it exists");
-    }
-}
-
-/* Make FRIEND_TYPE a friend class to TYPE.  If FRIEND_TYPE has already
-   been defined, we make all of its member functions friends of
-   TYPE.  If not, we make it a pending friend, which can later be added
-   when its definition is seen.  If a type is defined, then its TYPE_DECL's
-   DECL_UNDEFINED_FRIENDS contains a (possibly empty) list of friend
-   classes that are not defined.  If a type has not yet been defined,
-   then the DECL_WAITING_FRIENDS contains a list of types
-   waiting to make it their friend.  Note that these two can both
-   be in use at the same time!  */
-
-void
-make_friend_class (type, friend_type)
-     tree type, friend_type;
-{
-  tree classes;
-
-  if (IS_SIGNATURE (type))
-    {
-      error ("`friend' declaration in signature definition");
-      return;
-    }
-  if (IS_SIGNATURE (friend_type))
-    {
-      error ("signature type `%s' declared `friend'",
-            IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (friend_type))));
-      return;
-    }
-  if (type == friend_type)
-    {
-      pedwarn ("class `%s' is implicitly friends with itself",
-              TYPE_NAME_STRING (type));
-      return;
-    }
-
-  GNU_xref_hier (TYPE_NAME_STRING (type),
-                TYPE_NAME_STRING (friend_type), 0, 0, 1);
-
-  classes = CLASSTYPE_FRIEND_CLASSES (type);
-  while (classes && TREE_VALUE (classes) != friend_type)
-    classes = TREE_CHAIN (classes);
-  if (classes)
-    warning ("class `%s' is already friends with class `%s'",
-            TYPE_NAME_STRING (TREE_VALUE (classes)), TYPE_NAME_STRING (type));
-  else
-    {
-      CLASSTYPE_FRIEND_CLASSES (type)
-       = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
-    }
-}
-
-/* Main friend processor.  This is large, and for modularity purposes,
-   has been removed from grokdeclarator.  It returns `void_type_node'
-   to indicate that something happened, though a FIELD_DECL is
-   not returned.
-
-   CTYPE is the class this friend belongs to.
-
-   DECLARATOR is the name of the friend.
-
-   DECL is the FUNCTION_DECL that the friend is.
-
-   In case we are parsing a friend which is part of an inline
-   definition, we will need to store PARM_DECL chain that comes
-   with it into the DECL_ARGUMENTS slot of the FUNCTION_DECL.
-
-   FLAGS is just used for `grokclassfn'.
-
-   QUALS say what special qualifies should apply to the object
-   pointed to by `this'.  */
-
-tree
-do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
-     tree ctype, declarator, decl, parmdecls;
-     enum overload_flags flags;
-     tree quals;
-     int funcdef_flag;
-{
-  /* Every decl that gets here is a friend of something.  */
-  DECL_FRIEND_P (decl) = 1;
-
-  if (ctype)
-    {
-      tree cname = TYPE_NAME (ctype);
-      if (TREE_CODE (cname) == TYPE_DECL)
-       cname = DECL_NAME (cname);
-
-      /* A method friend.  */
-      if (TREE_CODE (decl) == FUNCTION_DECL)
-       {
-         if (flags == NO_SPECIAL && ctype && declarator == cname)
-           DECL_CONSTRUCTOR_P (decl) = 1;
-
-         /* This will set up DECL_ARGUMENTS for us.  */
-         grokclassfn (ctype, cname, decl, flags, quals);
-         if (TYPE_SIZE (ctype) != 0)
-           decl = check_classfn (ctype, decl);
-
-         if (TREE_TYPE (decl) != error_mark_node)
-           {
-             if (TYPE_SIZE (ctype))
-               add_friend (current_class_type, decl);
-             else
-               {
-                 cp_error ("member `%D' declared as friend before type `%T' defined",
-                           decl, ctype);
-               }
-           }
-       }
-      else
-       {
-         /* Possibly a bunch of method friends.  */
-
-         /* Get the class they belong to.  */
-         tree ctype = IDENTIFIER_TYPE_VALUE (cname);
-         tree fields = lookup_fnfields (TYPE_BINFO (ctype), declarator, 0);
-
-         if (fields)
-           add_friends (current_class_type, declarator, ctype);
-         else
-           error ("method `%s' is not a member of class `%s'",
-                  IDENTIFIER_POINTER (declarator),
-                  IDENTIFIER_POINTER (cname));
-         decl = void_type_node;
-       }
-    }
-  else if (TREE_CODE (decl) == FUNCTION_DECL
-          && ((IDENTIFIER_LENGTH (declarator) == 4
-               && IDENTIFIER_POINTER (declarator)[0] == 'm'
-               && ! strcmp (IDENTIFIER_POINTER (declarator), "main"))
-              || (IDENTIFIER_LENGTH (declarator) > 10
-                  && IDENTIFIER_POINTER (declarator)[0] == '_'
-                  && IDENTIFIER_POINTER (declarator)[1] == '_'
-                  && strncmp (IDENTIFIER_POINTER (declarator)+2,
-                              "builtin_", 8) == 0)))
-    {
-      /* raw "main", and builtin functions never gets overloaded,
-        but they can become friends.  */
-      add_friend (current_class_type, decl);
-      DECL_FRIEND_P (decl) = 1;
-      decl = void_type_node;
-    }
-  /* A global friend.
-     @@ or possibly a friend from a base class ?!?  */
-  else if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      /* Friends must all go through the overload machinery,
-        even though they may not technically be overloaded.
-
-        Note that because classes all wind up being top-level
-        in their scope, their friend wind up in top-level scope as well.  */
-      DECL_ASSEMBLER_NAME (decl)
-       = build_decl_overload (declarator, TYPE_ARG_TYPES (TREE_TYPE (decl)),
-                              TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
-      DECL_ARGUMENTS (decl) = parmdecls;
-      if (funcdef_flag)
-       DECL_CLASS_CONTEXT (decl) = current_class_type;
-
-      /* We can call pushdecl here, because the TREE_CHAIN of this
-        FUNCTION_DECL is not needed for other purposes.  */
-      decl = pushdecl (decl);
-
-      make_decl_rtl (decl, NULL_PTR, 1);
-      add_friend (current_class_type, decl);
-
-      DECL_FRIEND_P (decl) = 1;
-    }
-  else
-    {
-      /* @@ Should be able to ingest later definitions of this function
-        before use.  */
-      tree decl = lookup_name_nonclass (declarator);
-      if (decl == NULL_TREE)
-       {
-         warning ("implicitly declaring `%s' as struct",
-                  IDENTIFIER_POINTER (declarator));
-         decl = xref_tag (record_type_node, declarator, NULL_TREE, 1);
-         decl = TYPE_NAME (decl);
-       }
-
-      /* Allow abbreviated declarations of overloaded functions,
-        but not if those functions are really class names.  */
-      if (TREE_CODE (decl) == TREE_LIST && TREE_TYPE (TREE_PURPOSE (decl)))
-       {
-         warning ("`friend %s' archaic, use `friend class %s' instead",
-                  IDENTIFIER_POINTER (declarator),
-                  IDENTIFIER_POINTER (declarator));
-         decl = TREE_TYPE (TREE_PURPOSE (decl));
-       }
-
-      if (TREE_CODE (decl) == TREE_LIST)
-       add_friends (current_class_type, TREE_PURPOSE (decl), NULL_TREE);
-      else
-       make_friend_class (current_class_type, TREE_TYPE (decl));
-      decl = void_type_node;
-    }
-  return decl;
-}
-\f
 /* Common subroutines of build_new and build_vec_delete.  */
 
 /* Common interface for calling "builtin" functions that are not
    really builtin.  */
 
-tree
+static tree
 build_builtin_call (type, node, arglist)
      tree type;
      tree node;
@@ -2637,10 +2211,10 @@ build_new (placement, decl, init, use_global_new)
 {
   tree type, true_type, size, rval;
   tree nelts;
-  tree alloc_expr, alloc_temp;
+  tree alloc_expr;
   int has_array = 0;
   enum tree_code code = NEW_EXPR;
-  int use_cookie;
+  int use_cookie, nothrow, check_new;
 
   tree pending_sizes = NULL_TREE;
 
@@ -2695,7 +2269,7 @@ build_new (placement, decl, init, use_global_new)
                }
              else
                {
-                 this_nelts = save_expr (convert (sizetype, this_nelts));
+                 this_nelts = save_expr (cp_convert (sizetype, this_nelts));
                  absdcl = TREE_OPERAND (absdcl, 0);
                  if (this_nelts == integer_zero_node)
                    {
@@ -2735,7 +2309,7 @@ build_new (placement, decl, init, use_global_new)
        {
          /* An aggregate type.  */
          type = IDENTIFIER_TYPE_VALUE (decl);
-         decl = TYPE_NAME (type);
+         decl = TYPE_MAIN_DECL (type);
        }
       else
        {
@@ -2755,7 +2329,7 @@ build_new (placement, decl, init, use_global_new)
     {
       type = decl;
       true_type = type;
-      decl = TYPE_NAME (type);
+      decl = TYPE_MAIN_DECL (type);
     }
 
   if (processing_template_decl)
@@ -2841,6 +2415,16 @@ build_new (placement, decl, init, use_global_new)
       return error_mark_node;
     }
 
+  /* If the first placement arg is of type nothrow_t, it's allowed to
+     return 0 on allocation failure.  */
+  nothrow = (placement && TREE_VALUE (placement)
+            && TREE_TYPE (TREE_VALUE (placement))
+            && IS_AGGR_TYPE (TREE_TYPE (TREE_VALUE (placement)))
+            && (TYPE_IDENTIFIER (TREE_TYPE (TREE_VALUE (placement)))
+                == get_identifier ("nothrow_t")));
+
+  check_new = flag_check_new || nothrow;
+
 #if 1
   /* Get a little extra space to store a couple of things before the new'ed
      array, if this isn't the default placement new.  */
@@ -2853,10 +2437,7 @@ build_new (placement, decl, init, use_global_new)
      array, if this is either non-placement new or new (nothrow).  */
   
   use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type)
-               && (! placement
-                   || (IS_AGGR_TYPE (TREE_TYPE (placement))
-                       && (TYPE_IDENTIFIER (TREE_TYPE (placement))
-                           == get_identifier ("nothrow_t")))));
+               && (! placement || nothrow));
 #endif
 
   if (use_cookie)
@@ -2883,7 +2464,7 @@ build_new (placement, decl, init, use_global_new)
     {
       rval = build_opfncall (code, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
                             ptr_type_node, size, placement);
-      rval = convert (build_pointer_type (true_type), rval);
+      rval = cp_convert (build_pointer_type (true_type), rval);
     }
   else if (! has_array && flag_this_is_variable > 0
           && TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
@@ -2904,7 +2485,7 @@ build_new (placement, decl, init, use_global_new)
       TREE_CALLS_NEW (rval) = 1;
     }
 
-  if (flag_check_new && rval)
+  if (check_new && rval)
     alloc_expr = rval = save_expr (rval);
   else
     alloc_expr = NULL_TREE;
@@ -2917,8 +2498,8 @@ build_new (placement, decl, init, use_global_new)
     {
       tree extra = BI_header_size;
       tree cookie, exp1;
-      rval = convert (ptr_type_node, rval);    /* convert to void * first */
-      rval = convert (string_type_node, rval); /* lets not add void* and ints */
+      rval = cp_convert (ptr_type_node, rval);    /* convert to void * first */
+      rval = cp_convert (string_type_node, rval); /* lets not add void* and ints */
       rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra, 1));
       /* Store header info.  */
       cookie = build_indirect_ref (build (MINUS_EXPR, build_pointer_type (BI_header_type),
@@ -2927,7 +2508,7 @@ build_new (placement, decl, init, use_global_new)
                    build_component_ref (cookie, nc_nelts_field_id, NULL_TREE, 0),
                    nelts);
       TREE_SIDE_EFFECTS (exp1) = 1;
-      rval = convert (build_pointer_type (true_type), rval);
+      rval = cp_convert (build_pointer_type (true_type), rval);
       TREE_CALLS_NEW (rval) = 1;
       TREE_SIDE_EFFECTS (rval) = 1;
       rval = build_compound_expr (tree_cons (NULL_TREE, exp1,
@@ -3170,11 +2751,11 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
   if (auto_delete != integer_zero_node
       && auto_delete != integer_two_node)
     {
-      tree base_tbd = convert (ptype,
-                              build_binary_op (MINUS_EXPR,
-                                               convert (ptr_type_node, base),
-                                               BI_header_size,
-                                               1));
+      tree base_tbd = cp_convert (ptype,
+                                 build_binary_op (MINUS_EXPR,
+                                                  cp_convert (ptr_type_node, base),
+                                                  BI_header_size,
+                                                  1));
       /* This is the real size */
       virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
       body = build_tree_list (NULL_TREE,
@@ -3227,11 +2808,11 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
        base_tbd = base;
       else
        {
-         base_tbd = convert (ptype,
-                             build_binary_op (MINUS_EXPR,
-                                              convert (string_type_node, base),
-                                              BI_header_size,
-                                              1));
+         base_tbd = cp_convert (ptype,
+                                build_binary_op (MINUS_EXPR,
+                                                 cp_convert (string_type_node, base),
+                                                 BI_header_size,
+                                                 1));
          /* True size with header.  */
          virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
        }
@@ -3266,7 +2847,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
       return controller;
     }
   else
-    return convert (void_type_node, body);
+    return cp_convert (void_type_node, body);
 }
 
 /* Build a tree to cleanup partially built arrays.
@@ -3310,7 +2891,7 @@ expand_vec_init (decl, base, maxindex, init, from_array)
   tree type = TREE_TYPE (TREE_TYPE (base));
   tree size;
 
-  maxindex = convert (ptrdiff_type_node, maxindex);
+  maxindex = cp_convert (ptrdiff_type_node, maxindex);
   if (maxindex == error_mark_node)
     return error_mark_node;
 
@@ -3328,9 +2909,9 @@ expand_vec_init (decl, base, maxindex, init, from_array)
   /* Set to zero in case size is <= 0.  Optimizer will delete this if
      it is not needed.  */
   rval = get_temp_regvar (build_pointer_type (type),
-                         convert (build_pointer_type (type), null_pointer_node));
+                         cp_convert (build_pointer_type (type), null_pointer_node));
   base = default_conversion (base);
-  base = convert (build_pointer_type (type), base);
+  base = cp_convert (build_pointer_type (type), base);
   expand_assignment (rval, base, 0, 0);
   base = get_temp_regvar (build_pointer_type (type), base);
 
@@ -3490,20 +3071,22 @@ expand_vec_init (decl, base, maxindex, init, from_array)
          push_obstacks_nochange ();
          resume_temporary_allocation ();
          {
-           tree e1, e2 = make_node (RTL_EXPR);
-           TREE_TYPE (e2) = void_type_node;
-           RTL_EXPR_RTL (e2) = const0_rtx;
-           TREE_SIDE_EFFECTS (e2) = 1;
-           start_sequence_for_rtl_expr (e2);
+           tree e1, cleanup = make_node (RTL_EXPR);
+           TREE_TYPE (cleanup) = void_type_node;
+           RTL_EXPR_RTL (cleanup) = const0_rtx;
+           TREE_SIDE_EFFECTS (cleanup) = 1;
+           start_sequence_for_rtl_expr (cleanup);
 
            e1 = build_array_eh_cleanup
              (rval,
               build_binary_op (MINUS_EXPR, maxindex, iterator, 1),
               type);
            expand_expr (e1, const0_rtx, VOIDmode, 0);
-           RTL_EXPR_SEQUENCE (e2) = get_insns ();
+           RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
            end_sequence ();
-           expand_eh_region_end (e2);
+
+           cleanup = protect_with_terminate (cleanup);
+           expand_eh_region_end (cleanup);
          }
          pop_obstacks ();
        }
@@ -3571,11 +3154,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
      int flags;
      int use_global_delete;
 {
-  tree function;
   tree member;
   tree expr;
   tree ref;
-  int ptr;
 
   if (addr == error_mark_node)
     return error_mark_node;
@@ -3609,7 +3190,6 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
       /* throw away const and volatile on target type of addr */
       addr = convert_force (build_pointer_type (type), addr, 0);
       ref = build_indirect_ref (addr, NULL_PTR);
-      ptr = 1;
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
@@ -3639,12 +3219,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
       else
        addr = convert_force (build_pointer_type (type), addr, 0);
 
-      if (TREE_CODE (addr) == NOP_EXPR
-         && TREE_OPERAND (addr, 0) == current_class_ptr)
-       ref = current_class_ref;
-      else
-       ref = build_indirect_ref (addr, NULL_PTR);
-      ptr = 0;
+      ref = build_indirect_ref (addr, NULL_PTR);
     }
 
   my_friendly_assert (IS_AGGR_TYPE (type), 220);
@@ -3673,10 +3248,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
      of the base classes; otherwise, we must do that here.  */
   if (TYPE_HAS_DESTRUCTOR (type))
     {
-      tree parms = build_tree_list (NULL_TREE, addr);
-      tree dtor = DECL_MAIN_VARIANT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1));
       tree passed_auto_delete;
       tree do_delete = NULL_TREE;
+      tree ifexp;
 
       if (use_global_delete)
        {
@@ -3696,108 +3270,29 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
       else
        passed_auto_delete = auto_delete;
 
-      if (flags & LOOKUP_PROTECT)
-       {
-         tree access;
-         tree basetypes = NULL_TREE;
-         if (current_class_type != NULL_TREE)
-           basetypes = get_binfo (type, current_class_type, 0);
-         if (basetypes == NULL_TREE)
-           basetypes = TYPE_BINFO (type);
-         access = compute_access (basetypes, dtor);
+      expr = build_method_call
+       (ref, dtor_identifier, build_tree_list (NULL_TREE, passed_auto_delete),
+        NULL_TREE, flags);
 
-         if (access == access_private_node)
-           {
-             if (flags & LOOKUP_COMPLAIN)
-               cp_error ("destructor for type `%T' is private in this scope", type);
-             return error_mark_node;
-           }
-         else if (access == access_protected_node)
-           {
-             if (flags & LOOKUP_COMPLAIN)
-               cp_error ("destructor for type `%T' is protected in this scope", type);
-             return error_mark_node;
-           }
-       }
-
-      /* Once we are in a destructor, try not going through
-        the virtual function table to find the next destructor.  */
-      if (DECL_VINDEX (dtor)
-         && ! (flags & LOOKUP_NONVIRTUAL)
-         && TREE_CODE (auto_delete) != PARM_DECL
-         && (ptr == 1 || ! resolves_to_fixed_type_p (ref, 0)))
-       {
-         tree binfo, basetype;
-         /* The code below is probably all broken.  See call.c for the
-            complete right way to do this. this offsets may not be right
-            in the below.  (mrs) */
-         /* This destructor must be called via virtual function table.  */
-         dtor = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (DECL_CONTEXT (dtor)), 1);
-         basetype = DECL_CLASS_CONTEXT (dtor);
-         binfo = get_binfo (basetype,
-                            TREE_TYPE (TREE_TYPE (TREE_VALUE (parms))),
-                            0);
-         expr = convert_pointer_to_real (binfo, TREE_VALUE (parms));
-         if (expr != TREE_VALUE (parms))
-           {
-             expr = fold (expr);
-             ref = build_indirect_ref (expr, NULL_PTR);
-             TREE_VALUE (parms) = expr;
-           }
-         function = build_vfn_ref (&TREE_VALUE (parms), ref, DECL_VINDEX (dtor));
-         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, 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
-                being called on an item that is 0.
+      if (do_delete)
+       expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
 
-                @@ Does this really need to be done?  */
-             tree ifexp = build_binary_op(NE_EXPR, addr, integer_zero_node,1);
-
-             expr = build (COND_EXPR, void_type_node,
-                           ifexp, expr, void_zero_node);
-           }
-       }
+      if (flags & LOOKUP_DESTRUCTOR)
+       /* Explicit destructor call; don't check for null pointer.  */
+       ifexp = integer_one_node;
       else
-       {
-         tree ifexp;
-
-         if ((flags & LOOKUP_DESTRUCTOR)
-             || TREE_CODE (ref) == VAR_DECL
-             || TREE_CODE (ref) == PARM_DECL
-             || TREE_CODE (ref) == COMPONENT_REF
-             || TREE_CODE (ref) == ARRAY_REF)
-           /* These can't be 0.  */
-           ifexp = integer_one_node;
-         else
-           /* Handle the case where a non-virtual destructor is
-              being called on an item that is 0.  */
-           ifexp = build_binary_op (NE_EXPR, addr, integer_zero_node, 1);
+       /* Handle deleting a null pointer.  */
+       ifexp = fold (build_binary_op (NE_EXPR, addr, integer_zero_node, 1));
 
-         /* Used to mean that this destructor was known to be empty,
-            but that's now obsolete.  */
-         my_friendly_assert (DECL_INITIAL (dtor) != void_type_node, 221);
+      if (ifexp != integer_one_node)
+       expr = build (COND_EXPR, void_type_node,
+                     ifexp, expr, void_zero_node);
 
-         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,
-                         ifexp, expr, void_zero_node);
-       }
       return expr;
     }
   else
     {
-      /* This can get visibilities wrong.  */
+      /* We only get here from finish_function for a destructor.  */
       tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
       int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
       tree base_binfo = n_baseclasses > 0 ? TREE_VEC_ELT (binfos, 0) : NULL_TREE;
@@ -3805,39 +3300,12 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
       tree parent_auto_delete = auto_delete;
       tree cond;
 
-      /* If this type does not have a destructor, but does have
-        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 (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
-       {
-         parent_auto_delete = integer_zero_node;
-         if (auto_delete == integer_zero_node)
-           cond = NULL_TREE;
-         else
-           {
-             tree virtual_size;
-
-               /* This is probably wrong. It should be the size of the
-                  virtual object being deleted.  */
-             virtual_size = c_sizeof_nowarn (type);
-
-             expr = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
-                                    virtual_size, NULL_TREE);
-             if (expr == error_mark_node)
-               return error_mark_node;
-             if (auto_delete != integer_one_node)
-               cond = build (COND_EXPR, void_type_node,
-                             build (BIT_AND_EXPR, integer_type_node,
-                                    auto_delete, integer_one_node),
-                             expr, void_zero_node);
-             else
-               cond = expr;
-           }
-       }
+      /* If we have member delete or vbases, we call delete in
+        finish_function.  */
+      if (auto_delete == integer_zero_node)
+       cond = NULL_TREE;
       else if (base_binfo == NULL_TREE
-              || (TREE_VIA_VIRTUAL (base_binfo) == 0
-                  && ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))))
+              || ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
        {
          cond = build (COND_EXPR, void_type_node,
                        build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node),
@@ -3862,8 +3330,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
          else
            this_auto_delete = integer_zero_node;
 
-         expr = build_delete (build_pointer_type (BINFO_TYPE (base_binfo)), addr,
-                              this_auto_delete, flags, 0);
+         expr = build_scoped_method_call
+           (ref, base_binfo, dtor_identifier,
+            build_tree_list (NULL_TREE, this_auto_delete));
          exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
        }
 
@@ -3875,13 +3344,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
              || TREE_VIA_VIRTUAL (base_binfo))
            continue;
 
-         /* May be zero offset if other baseclasses are virtual.  */
-         expr = fold (build (PLUS_EXPR, build_pointer_type (BINFO_TYPE (base_binfo)),
-                             addr, BINFO_OFFSET (base_binfo)));
-
-         expr = build_delete (build_pointer_type (BINFO_TYPE (base_binfo)), expr,
-                              integer_zero_node,
-                              flags, 0);
+         expr = build_scoped_method_call
+           (ref, base_binfo, dtor_identifier,
+            build_tree_list (NULL_TREE, integer_zero_node));
 
          exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
        }