OSDN Git Service

91th Cygnus<->FSF quick merge
[pf3gnuchains/gcc-fork.git] / gcc / cp / class.c
index e640010..8cddd98 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions related to building classes and their related objects.
-   Copyright (C) 1987, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -16,16 +16,19 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
-/* High-level class interface. */
+/* High-level class interface.  */
 
 #include "config.h"
 #include "tree.h"
 #include <stdio.h>
 #include "cp-tree.h"
 #include "flags.h"
+#include "rtl.h"
+#include "output.h"
 
 #include "obstack.h"
 #define obstack_chunk_alloc xmalloc
@@ -34,7 +37,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern struct obstack permanent_obstack;
 
 /* This is how we tell when two virtual member functions are really the
-   same. */
+   same.  */
 #define SAME_FN(FN1DECL, FN2DECL) (DECL_ASSEMBLER_NAME (FN1DECL) == DECL_ASSEMBLER_NAME (FN2DECL))
 
 extern void set_class_shadows PROTO ((tree));
@@ -69,8 +72,9 @@ struct class_level
   int unused;
 };
 
-tree current_class_decl, C_C_D;        /* PARM_DECL: the class instance variable */
-tree current_vtable_decl;
+/* The currect_class_ptr is the pointer to the current class.
+   current_class_ref is the actual current class.  */
+tree current_class_ptr, current_class_ref;
 
 /* The following two can be derived from the previous one */
 tree current_class_name;       /* IDENTIFIER_NODE: name of current class */
@@ -79,11 +83,10 @@ tree previous_class_type;   /* _TYPE: the previous type that was a class */
 tree previous_class_values;            /* TREE_LIST: copy of the class_shadowed list
                                   when leaving an outermost class scope.  */
 static tree get_vfield_name PROTO((tree));
-tree the_null_vtable_entry;
 
 /* Way of stacking language names.  */
 tree *current_lang_base, *current_lang_stack;
-static int current_lang_stacksize;
+int current_lang_stacksize;
 
 /* Names of languages we recognize.  */
 tree lang_name_c, lang_name_cplusplus;
@@ -94,8 +97,18 @@ tree current_lang_name;
    via this node.  */
 static tree base_layout_decl;
 
-/* Variables shared between cp-class.c and cp-call.c.  */
+/* Constants used for access control.  */
+tree access_default_node; /* 0 */
+tree access_public_node; /* 1 */
+tree access_protected_node; /* 2 */
+tree access_private_node; /* 3 */
+tree access_default_virtual_node; /* 4 */
+tree access_public_virtual_node; /* 5 */
+tree access_private_virtual_node; /* 6 */
 
+/* Variables shared between class.c and call.c.  */
+
+#ifdef GATHER_STATISTICS
 int n_vtables = 0;
 int n_vtable_entries = 0;
 int n_vtable_searches = 0;
@@ -104,9 +117,11 @@ int n_convert_harshness = 0;
 int n_compute_conversion_costs = 0;
 int n_build_method_call = 0;
 int n_inner_fields_searched = 0;
+#endif
 
 /* Virtual baseclass things.  */
-tree
+
+static tree
 build_vbase_pointer (exp, type)
      tree exp, type;
 {
@@ -114,12 +129,13 @@ build_vbase_pointer (exp, type)
 
   name = (char *) alloca (TYPE_NAME_LENGTH (type) + sizeof (VBASE_NAME) + 1);
   sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (type));
-  return build_component_ref (exp, get_identifier (name), 0, 0);
+  return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
 }
 
 /* Is the type of the EXPR, the complete type of the object?
-   If we are going to be wrong, we must be conservative, and return 0. */
-int
+   If we are going to be wrong, we must be conservative, and return 0.  */
+
+static int
 complete_type_p (expr)
      tree expr;
 {
@@ -139,20 +155,20 @@ complete_type_p (expr)
        case CALL_EXPR: 
          if (! TREE_HAS_CONSTRUCTOR (expr))
            break;
-         /* fall through... */
+         /* fall through...  */
        case VAR_DECL:
        case FIELD_DECL:
          if (TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
              && IS_AGGR_TYPE (TREE_TYPE (TREE_TYPE (expr)))
              && TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type)
            return 1;
-         /* fall through... */
+         /* fall through...  */
        case TARGET_EXPR:
        case PARM_DECL:
          if (IS_AGGR_TYPE (TREE_TYPE (expr))
              && TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type)
            return 1;
-         /* fall through... */
+         /* fall through...  */
        case PLUS_EXPR:
        default:
          break;
@@ -170,6 +186,7 @@ complete_type_p (expr)
    TYPE is the type we want this path to have on exit.
 
    ALIAS_THIS is non-zero if EXPR in an expression involving `this'.  */
+
 tree
 build_vbase_path (code, type, expr, path, alias_this)
      enum tree_code code;
@@ -184,12 +201,15 @@ build_vbase_path (code, type, expr, path, alias_this)
   tree basetype;
   tree offset = integer_zero_node;
 
+  if (nonnull == 0 && (alias_this && flag_this_is_variable <= 0))
+    nonnull = 1;
+
   /* We need additional logic to convert back to the unconverted type
      (the static type of the complete object), and then convert back
      to the type we want.  Until that is done, or until we can
      recognize when that is, we cannot do the short cut logic. (mrs) */
-  /* Do this, until we can undo any previous convertions.  See net35.C
-     for a testcase. */
+  /* Do this, until we can undo any previous conversions.  See net35.C
+     for a testcase.  */
   fixed_type_p = complete_type_p (expr);
 
   if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
@@ -223,11 +243,10 @@ build_vbase_path (code, type, expr, path, alias_this)
 
              if (changed)
                {
-                 extern int flag_assume_nonnull_objects;
                  tree ind;
 
                  /* We already check for ambiguous things in the caller, just
-                    find a path. */
+                    find a path.  */
                  if (last)
                    {
                      tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0);
@@ -235,12 +254,14 @@ build_vbase_path (code, type, expr, path, alias_this)
                    }
                  ind = build_indirect_ref (nonnull_expr, NULL_PTR);
                  nonnull_expr = build_vbase_pointer (ind, last_virtual);
-                 if (nonnull == 0 && !flag_assume_nonnull_objects
+                 if (nonnull == 0
+                     && (TREE_CODE (type) == POINTER_TYPE
+                         || !flag_assume_nonnull_objects)
                      && null_expr == NULL_TREE)
                    {
-                     null_expr = build1 (NOP_EXPR, TYPE_POINTER_TO (last_virtual), integer_zero_node);
-                     expr = build (COND_EXPR, TYPE_POINTER_TO (last_virtual),
-                                   build (EQ_EXPR, integer_type_node, expr,
+                     null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node);
+                     expr = build (COND_EXPR, build_pointer_type (last_virtual),
+                                   build (EQ_EXPR, boolean_type_node, expr,
                                           integer_zero_node),
                                    null_expr, nonnull_expr);
                    }
@@ -280,12 +301,9 @@ build_vbase_path (code, type, expr, path, alias_this)
   if (changed)
     {
       tree intype = TREE_TYPE (TREE_TYPE (expr));
-      if (TYPE_MAIN_VARIANT (intype) == BINFO_TYPE (last))
-       basetype = intype;
-      else
+      if (TYPE_MAIN_VARIANT (intype) != BINFO_TYPE (last))
        {
          tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (intype), 0);
-         basetype = last;
          offset = BINFO_OFFSET (binfo);
        }
     }
@@ -303,13 +321,17 @@ build_vbase_path (code, type, expr, path, alias_this)
 
   if (TREE_INT_CST_LOW (offset))
     {
+      /* Bash types to make the backend happy.  */
+      offset = convert (type, offset);
+      expr = build1 (NOP_EXPR, type, expr);
+
       /* For multiple inheritance: if `this' can be set by any
         function, then it could be 0 on entry to any function.
         Preserve such zeroness here.  Otherwise, only in the
         case of constructors need we worry, and in those cases,
-        it will be zero, or initialized to some legal value to
+        it will be zero, or initialized to some valid value to
         which we may add.  */
-      if (nonnull == 0 && (alias_this == 0 || flag_this_is_variable > 0))
+      if (nonnull == 0)
        {
          if (null_expr)
            TREE_TYPE (null_expr) = type;
@@ -319,7 +341,7 @@ build_vbase_path (code, type, expr, path, alias_this)
            expr = save_expr (expr);
 
          return build (COND_EXPR, type,
-                       build (EQ_EXPR, integer_type_node, expr, integer_zero_node),
+                       build (EQ_EXPR, boolean_type_node, expr, integer_zero_node),
                        null_expr,
                        build (code, type, expr, offset));
        }
@@ -339,94 +361,88 @@ build_vbase_path (code, type, expr, path, alias_this)
 
 /* Virtual function things.  */
 
-/* Virtual functions to be dealt with after laying out our
-   base classes.  Usually this is used only when classes have virtual
-   baseclasses, but it can happen also when classes have non-virtual
-   baseclasses if the derived class overrides baseclass functions
-   at different offsets.  */
-static tree pending_hard_virtuals;
-static int doing_hard_virtuals;
+/* Virtual functions to be dealt with after laying out our base
+   classes.  We do all overrides after we layout virtual base classes.  */
 
-/* XXX This is set but never used.  (bpk) */
-#if 0
-/* Temporary binfo list to memoize lookups of the left-most non-virtual
-   baseclass B in a lattice topped by T.  B can appear multiple times
-   in the lattice.
-   TREE_PURPOSE is B's TYPE_MAIN_VARIANT.
-   TREE_VALUE is the path by which B is reached from T.
-   TREE_TYPE is B's real type.
-
-   If TREE_TYPE is NULL_TREE, it means that B was reached via
-   a virtual baseclass.
-   N.B.: This list consists of nodes on the temporary obstack.  */
-static tree leftmost_baseclasses;
-#endif
+static tree pending_hard_virtuals;
 
 /* Build an entry in the virtual function table.
    DELTA is the offset for the `this' pointer.
    PFN is an ADDR_EXPR containing a pointer to the virtual function.
    Note that the index (DELTA2) in the virtual function table
    is always 0.  */
-tree
+
+static tree
 build_vtable_entry (delta, pfn)
      tree delta, pfn;
 {
-  extern int flag_huge_objects;
-  tree elems = tree_cons (NULL_TREE, delta,
-                         tree_cons (NULL_TREE, integer_zero_node,
-                                    build_tree_list (NULL_TREE, pfn)));
-  tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
-
-  /* DELTA is constructed by `size_int', which means it may be an
-     unsigned quantity on some platforms.  Therefore, we cannot use
-     `int_fits_type_p', because when DELTA is really negative,
-     `force_fit_type' will make it look like a very large number.  */
-
-  if ((TREE_INT_CST_LOW (TYPE_MAX_VALUE (delta_type_node))
-       < TREE_INT_CST_LOW (delta))
-      || (TREE_INT_CST_LOW (delta)
-         < TREE_INT_CST_LOW (TYPE_MIN_VALUE (delta_type_node))))
-    if (flag_huge_objects)
-      sorry ("object size exceeds built-in limit for virtual function table implementation");
-    else
-      sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
+  if (flag_vtable_thunks)
+    {
+      HOST_WIDE_INT idelta = TREE_INT_CST_LOW (delta);
+      if (idelta && ! DECL_ABSTRACT_VIRTUAL_P (TREE_OPERAND (pfn, 0)))
+       {
+         pfn = build1 (ADDR_EXPR, vtable_entry_type,
+                       make_thunk (pfn, idelta));
+         TREE_READONLY (pfn) = 1;
+         TREE_CONSTANT (pfn) = 1;
+       }
+#ifdef GATHER_STATISTICS
+      n_vtable_entries += 1;
+#endif
+      return pfn;
+    }
+  else
+    {
+      extern int flag_huge_objects;
+      tree elems = tree_cons (NULL_TREE, delta,
+                             tree_cons (NULL_TREE, integer_zero_node,
+                                        build_tree_list (NULL_TREE, pfn)));
+      tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
+
+      /* DELTA is constructed by `size_int', which means it may be an
+        unsigned quantity on some platforms.  Therefore, we cannot use
+        `int_fits_type_p', because when DELTA is really negative,
+        `force_fit_type' will make it look like a very large number.  */
+
+      if ((TREE_INT_CST_LOW (TYPE_MAX_VALUE (delta_type_node))
+          < TREE_INT_CST_LOW (delta))
+         || (TREE_INT_CST_LOW (delta)
+             < TREE_INT_CST_LOW (TYPE_MIN_VALUE (delta_type_node))))
+       if (flag_huge_objects)
+         sorry ("object size exceeds built-in limit for virtual function table implementation");
+       else
+         sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
 
-  TREE_CONSTANT (entry) = 1;
-  TREE_STATIC (entry) = 1;
-  TREE_READONLY (entry) = 1;
+      TREE_CONSTANT (entry) = 1;
+      TREE_STATIC (entry) = 1;
+      TREE_READONLY (entry) = 1;
 
 #ifdef GATHER_STATISTICS
-  n_vtable_entries += 1;
+      n_vtable_entries += 1;
 #endif
 
-  return entry;
+      return entry;
+    }
 }
 
 /* Given an object INSTANCE, return an expression which yields the
-   virtual function corresponding to INDEX.  There are many special
-   cases for INSTANCE which we take care of here, mainly to avoid
-   creating extra tree nodes when we don't have to.  */
+   virtual function vtable element corresponding to INDEX.  There are
+   many special cases for INSTANCE which we take care of here, mainly
+   to avoid creating extra tree nodes when we don't have to.  */
+
 tree
-build_vfn_ref (ptr_to_instptr, instance, idx)
-     tree *ptr_to_instptr, instance;
-     tree idx;
+build_vtbl_ref (instance, idx)
+     tree instance, idx;
 {
-  extern int building_cleanup;
   tree vtbl, aref;
   tree basetype = TREE_TYPE (instance);
 
   if (TREE_CODE (basetype) == REFERENCE_TYPE)
     basetype = TREE_TYPE (basetype);
 
-  if (instance == C_C_D)
-    {
-      if (current_vtable_decl == NULL_TREE
-         || current_vtable_decl == error_mark_node
-         || !UNIQUELY_DERIVED_FROM_P (DECL_FCONTEXT (CLASSTYPE_VFIELD (current_class_type)), basetype))
-       vtbl = build_indirect_ref (build_vfield_ref (instance, basetype), NULL_PTR);
-      else
-       vtbl = current_vtable_decl;
-    }
+  if (instance == current_class_ref)
+    vtbl = build_indirect_ref (build_vfield_ref (instance, basetype),
+                              NULL_PTR);
   else
     {
       if (optimize)
@@ -461,8 +477,6 @@ build_vfn_ref (ptr_to_instptr, instance, idx)
        }
 
       if (IS_AGGR_TYPE (TREE_TYPE (instance))
-         && !IS_SIGNATURE_POINTER (TREE_TYPE (instance))
-         && !IS_SIGNATURE_REFERENCE (TREE_TYPE (instance))
          && (TREE_CODE (instance) == RESULT_DECL
              || TREE_CODE (instance) == PARM_DECL
              || TREE_CODE (instance) == VAR_DECL))
@@ -474,53 +488,52 @@ build_vfn_ref (ptr_to_instptr, instance, idx)
   assemble_external (vtbl);
   aref = build_array_ref (vtbl, idx);
 
-  /* Save the intermediate result in a SAVE_EXPR so we don't have to
-     compute each component of the virtual function pointer twice.  */ 
-  if (!building_cleanup && TREE_CODE (aref) == INDIRECT_REF)
-    TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
-
-  *ptr_to_instptr
-    = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr),
-            *ptr_to_instptr,
-            convert (ptrdiff_type_node,
-                     build_component_ref (aref, delta_identifier, 0, 0)));
-  return build_component_ref (aref, pfn_identifier, 0, 0);
+  return aref;
 }
 
-/* Set TREE_PUBLIC and/or TREE_EXTERN on the vtable DECL,
-   based on TYPE and other static flags.
-
-   Note that anything public is tagged TREE_PUBLIC, whether
-   it's public in this file or in another one.  */
+/* Given an object INSTANCE, return an expression which yields the
+   virtual function corresponding to INDEX.  There are many special
+   cases for INSTANCE which we take care of here, mainly to avoid
+   creating extra tree nodes when we don't have to.  */
 
-static void
-import_export_vtable (decl, type)
-  tree decl, type;
+tree
+build_vfn_ref (ptr_to_instptr, instance, idx)
+     tree *ptr_to_instptr, instance;
+     tree idx;
 {
-  if (write_virtuals >= 2)
-    {
-      if (CLASSTYPE_INTERFACE_KNOWN (type))
-       {
-         TREE_PUBLIC (decl) = 1;
-         DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type);
-       }
-    }
-  else if (write_virtuals != 0)
+  tree aref = build_vtbl_ref (instance, idx);
+
+  /* When using thunks, there is no extra delta, and we get the pfn
+     directly.  */
+  if (flag_vtable_thunks)
+    return aref;
+
+  if (ptr_to_instptr)
     {
-      TREE_PUBLIC (decl) = 1;
-      if (write_virtuals < 0)
-       DECL_EXTERNAL (decl) = 1;
+      /* Save the intermediate result in a SAVE_EXPR so we don't have to
+        compute each component of the virtual function pointer twice.  */ 
+      if (TREE_CODE (aref) == INDIRECT_REF)
+       TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
+
+      *ptr_to_instptr
+       = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr),
+                *ptr_to_instptr,
+                convert (ptrdiff_type_node,
+                         build_component_ref (aref, delta_identifier, NULL_TREE, 0)));
     }
+
+  return build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
 }
 
 /* Return the name of the virtual function table (as an IDENTIFIER_NODE)
    for the given TYPE.  */
+
 static tree
 get_vtable_name (type)
      tree type;
 {
   tree type_id = build_typename_overload (type);
-  char *buf = (char *)alloca (sizeof (VTABLE_NAME_FORMAT)
+  char *buf = (char *)alloca (strlen (VTABLE_NAME_FORMAT)
                              + IDENTIFIER_LENGTH (type_id) + 2);
   char *ptr = IDENTIFIER_POINTER (type_id);
   int i;
@@ -537,10 +550,78 @@ get_vtable_name (type)
   return get_identifier (buf);
 }
 
+/* Return the offset to the main vtable for a given base BINFO.  */
+
+tree
+get_vfield_offset (binfo)
+     tree binfo;
+{
+  return size_binop (PLUS_EXPR,
+                    size_binop (FLOOR_DIV_EXPR,
+                                DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
+                                size_int (BITS_PER_UNIT)),
+                    BINFO_OFFSET (binfo));
+}
+
+/* Get the offset to the start of the original binfo that we derived
+   this binfo from.  If we find TYPE first, return the offset only
+   that far.  The shortened search is useful because the this pointer
+   on method calling is expected to point to a DECL_CONTEXT (fndecl)
+   object, and not a baseclass of it.  */
+
+static tree
+get_derived_offset (binfo, type)
+     tree binfo, type;
+{
+  tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
+  tree offset2;
+  int i;
+  while (BINFO_BASETYPES (binfo)
+        && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
+    {
+      tree binfos = BINFO_BASETYPES (binfo);
+      if (BINFO_TYPE (binfo) == type)
+       break;
+      binfo = TREE_VEC_ELT (binfos, i);
+    }
+  offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
+  return size_binop (MINUS_EXPR, offset1, offset2);
+}
+
+/* Update the rtti info for this class.  */
+
+static void
+set_rtti_entry (virtuals, offset, type)
+     tree virtuals, offset, type;
+{
+  tree vfn;
+
+  if (flag_rtti)
+    vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, get_tinfo_fn (type));
+  else
+    vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, size_zero_node);
+  TREE_CONSTANT (vfn) = 1;
+
+  if (! flag_vtable_thunks)
+    TREE_VALUE (virtuals) = build_vtable_entry (offset, vfn);
+  else
+    {
+      tree voff = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
+      TREE_CONSTANT (voff) = 1;
+
+      TREE_VALUE (virtuals) = build_vtable_entry (size_zero_node, voff);
+
+      /* The second slot is for the tdesc pointer when thunks are used.  */
+      TREE_VALUE (TREE_CHAIN (virtuals))
+       = build_vtable_entry (size_zero_node, vfn);
+    }
+}
+
 /* Build a virtual function for type TYPE.
    If BINFO is non-NULL, build the vtable starting with the initial
    approximation that it is the same as the one which is the head of
    the association list.  */
+
 static tree
 build_vtable (binfo, type)
      tree binfo, type;
@@ -550,8 +631,15 @@ build_vtable (binfo, type)
 
   if (binfo)
     {
+      tree offset;
+
       virtuals = copy_list (BINFO_VIRTUALS (binfo));
       decl = build_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo)));
+
+      /* Now do rtti stuff.  */
+      offset = get_derived_offset (TYPE_BINFO (type), NULL_TREE);
+      offset = size_binop (MINUS_EXPR, size_zero_node, offset);
+      set_rtti_entry (virtuals, offset, type);
     }
   else
     {
@@ -565,7 +653,7 @@ build_vtable (binfo, type)
 #endif
 
   /* Set TREE_PUBLIC and TREE_EXTERN as appropriate.  */
-  import_export_vtable (decl, type);
+  import_export_vtable (decl, type, 0);
 
   IDENTIFIER_GLOBAL_VALUE (name) = decl = pushdecl_top_level (decl);
   /* Initialize the association list for this type, based
@@ -586,17 +674,9 @@ build_vtable (binfo, type)
   /* Why is this conditional? (mrs) */
   if (binfo && write_virtuals >= 0)
     DECL_VIRTUAL_P (decl) = 1;
-#if 0
-  /* Remember which class this vtable is really for.  */
-  if (binfo)
-    DECL_VPARENT (decl) = BINFO_TYPE (binfo);
-  else
-    DECL_VPARENT (decl) = type;
-#endif
   DECL_CONTEXT (decl) = type;
 
   binfo = TYPE_BINFO (type);
-  SET_BINFO_VTABLE_PATH_MARKED (binfo);
   SET_BINFO_NEW_VTABLE_MARKED (binfo);
   return decl;
 }
@@ -621,8 +701,8 @@ build_vtable (binfo, type)
 
    Make sure to use the DECL_ASSEMBLER_NAME of the TYPE_NAME of the
    type, as template have DECL_NAMEs like: X<int>, whereas the
-   DECL_ASSEMBLER_NAME is set to be something the assembler can handle.
-  */
+   DECL_ASSEMBLER_NAME is set to be something the assembler can handle.  */
+
 static tree
 build_type_pathname (format, parent, type)
      char *format;
@@ -664,6 +744,8 @@ build_type_pathname (format, parent, type)
   return id;
 }
 
+extern tree signed_size_zero_node;
+
 /* Give TYPE a new virtual function table which is initialized
    with a skeleton-copy of its original initialization.  The only
    entry that changes is the `delta' entry, so we can really
@@ -672,25 +754,21 @@ build_type_pathname (format, parent, type)
    FOR_TYPE is the derived type which caused this table to
    be needed.
 
-   BINFO is the type association which provided TYPE for FOR_TYPE.
+   BINFO is the type association which provided TYPE for FOR_TYPE.  */
 
-   The way we update BASE_BINFO's vtable information is just to change the
-   association information in FOR_TYPE's association list.  */
 static void
-prepare_fresh_vtable (binfo, base_binfo, for_type)
-     tree binfo, base_binfo, for_type;
+prepare_fresh_vtable (binfo, for_type)
+     tree binfo, for_type;
 {
   tree basetype = BINFO_TYPE (binfo);
   tree orig_decl = BINFO_VTABLE (binfo);
+  /* This name is too simplistic.  We can have multiple basetypes for
+     for_type, and we really want different names.  (mrs) */
   tree name = build_type_pathname (VTABLE_NAME_FORMAT, basetype, for_type);
   tree new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl));
-  tree path;
-  int result;
+  tree offset;
 
   /* Remember which class this vtable is really for.  */
-#if 0
-  DECL_VPARENT (new_decl) = BINFO_TYPE (base_binfo);
-#endif
   DECL_CONTEXT (new_decl) = for_type;
 
   TREE_STATIC (new_decl) = 1;
@@ -704,11 +782,26 @@ prepare_fresh_vtable (binfo, base_binfo, for_type)
 
   /* Make fresh virtual list, so we can smash it later.  */
   BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo));
-  /* Install the value for `headof' if that's what we're doing.  */
-  if (flag_dossier)
-    TREE_VALUE (TREE_CHAIN (BINFO_VIRTUALS (binfo)))
-      = build_vtable_entry (size_binop (MINUS_EXPR, integer_zero_node, BINFO_OFFSET (binfo)),
-                           FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (TREE_CHAIN (BINFO_VIRTUALS (binfo)))));
+
+  if (TREE_VIA_VIRTUAL (binfo))
+    {
+      tree binfo1 = binfo_member (BINFO_TYPE (binfo), 
+                                 CLASSTYPE_VBASECLASSES (for_type));
+
+      /* XXX - This should never happen, if it does, the caller should
+        ensure that the binfo is from for_type's binfos, not from any
+        base type's.  We can remove all this code after a while.  */
+      if (binfo1 != binfo)
+       warning ("internal inconsistency: binfo offset error for rtti");
+
+      offset = BINFO_OFFSET (binfo1);
+    }
+  else
+    offset = BINFO_OFFSET (binfo);
+
+  set_rtti_entry (BINFO_VIRTUALS (binfo),
+                 size_binop (MINUS_EXPR, signed_size_zero_node, offset),
+                 for_type);
 
 #ifdef GATHER_STATISTICS
   n_vtables += 1;
@@ -716,91 +809,42 @@ prepare_fresh_vtable (binfo, base_binfo, for_type)
 #endif
 
   /* Set TREE_PUBLIC and TREE_EXTERN as appropriate.  */
-  import_export_vtable (new_decl, for_type);
+  import_export_vtable (new_decl, for_type, 0);
 
   if (TREE_VIA_VIRTUAL (binfo))
     my_friendly_assert (binfo == binfo_member (BINFO_TYPE (binfo),
                                   CLASSTYPE_VBASECLASSES (current_class_type)),
                        170);
   SET_BINFO_NEW_VTABLE_MARKED (binfo);
-  SET_BINFO_VTABLE_PATH_MARKED (binfo);
-
-  /* Mark all types between FOR_TYPE and TYPE as having been
-     touched, so that if we change virtual function table entries,
-     new vtables will be initialized.  We may reach the virtual
-     baseclass via ambiguous intervening baseclasses.  This
-     loop makes sure we get through to the actual baseclass we marked.
-
-     Also, update the vtable entries to reflect the overrides
-     of the top-most class (short of the top type).  */
-
-  do
-    {
-      result = get_base_distance (basetype, for_type, 0, &path);
-      for_type = path;
-      while (path)
-       {
-         tree path_binfo = path;
-         tree path_type = BINFO_TYPE (path);
-
-         if (TREE_VIA_VIRTUAL (path))
-           path_binfo = binfo_member (path_type,
-                                      CLASSTYPE_VBASECLASSES (current_class_type));
-
-         SET_BINFO_VTABLE_PATH_MARKED (path_binfo);
-         if (BINFO_INHERITANCE_CHAIN (path)
-             && CLASSTYPE_VFIELD (path_type) != NULL_TREE
-             && (DECL_NAME (CLASSTYPE_VFIELD (BINFO_TYPE (binfo)))
-                 == DECL_NAME (CLASSTYPE_VFIELD (path_type)))
-             /* This is the baseclass just before the original FOR_TYPE.  */
-             && BINFO_INHERITANCE_CHAIN (BINFO_INHERITANCE_CHAIN (path)) == NULL_TREE)
-           {
-             tree old_virtuals = TREE_CHAIN (BINFO_VIRTUALS (binfo));
-             tree new_virtuals = TREE_CHAIN (BINFO_VIRTUALS (path_binfo));
-             if (flag_dossier)
-               {
-                 old_virtuals = TREE_CHAIN (old_virtuals);
-                 new_virtuals = TREE_CHAIN (new_virtuals);
-               }
-             while (old_virtuals)
-               {
-                 TREE_VALUE (old_virtuals) = TREE_VALUE (new_virtuals);
-                 old_virtuals = TREE_CHAIN (old_virtuals);
-                 new_virtuals = TREE_CHAIN (new_virtuals);
-               }
-           }
-         path = BINFO_INHERITANCE_CHAIN (path);
-       }
-    }
-  while (result == -2);
 }
 
+#if 0
 /* Access the virtual function table entry that logically
    contains BASE_FNDECL.  VIRTUALS is the virtual function table's
-   initializer.  */
+   initializer.  We can run off the end, when dealing with virtual
+   destructors in MI situations, return NULL_TREE in that case.  */
+
 static tree
 get_vtable_entry (virtuals, base_fndecl)
      tree virtuals, base_fndecl;
 {
-  unsigned HOST_WIDE_INT i = (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
-#ifdef VTABLE_USES_MASK
-          && 0
-#endif
+  unsigned HOST_WIDE_INT n = (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
           ? (TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl))
              & (((unsigned HOST_WIDE_INT)1<<(BITS_PER_WORD-1))-1))
           : TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl)));
 
 #ifdef GATHER_STATISTICS
-  n_vtable_searches += i;
+  n_vtable_searches += n;
 #endif
 
-  while (i > 0)
+  while (n > 0 && virtuals)
     {
+      --n;
       virtuals = TREE_CHAIN (virtuals);
-      i -= 1;
     }
   return virtuals;
 }
+#endif
 
 /* Put new entry ENTRY into virtual function table initializer
    VIRTUALS.
@@ -811,691 +855,145 @@ static void
 modify_vtable_entry (old_entry_in_list, new_entry, fndecl)
      tree old_entry_in_list, new_entry, fndecl;
 {
-  tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (old_entry_in_list));
-  tree vindex;
+  tree base_fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (old_entry_in_list)), 0);
 
 #ifdef NOTQUITE
-  cp_warning ("replaced %D with %D", DECL_ASSEMBLER_NAME (TREE_OPERAND (base_pfn, 0)), DECL_ASSEMBLER_NAME (fndecl));
+  cp_warning ("replaced %D with %D", DECL_ASSEMBLER_NAME (base_fndecl),
+             DECL_ASSEMBLER_NAME (fndecl));
 #endif
-  /* We can't put in the really right offset information
-     here, since we have not yet laid out the class to
-     take into account virtual base classes.  */
   TREE_VALUE (old_entry_in_list) = new_entry;
-  vindex = DECL_VINDEX (TREE_OPERAND (base_pfn, 0));
-  if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
-    DECL_VINDEX (fndecl) = vindex;
-  else
-    {
-      if (! tree_int_cst_equal (DECL_VINDEX (fndecl), vindex))
-       {
-         tree elts = CONSTRUCTOR_ELTS (new_entry);
-
-         if (! doing_hard_virtuals)
-           {
-             pending_hard_virtuals
-               = tree_cons (fndecl, FNADDR_FROM_VTABLE_ENTRY (new_entry),
-                            pending_hard_virtuals);
-             TREE_TYPE (pending_hard_virtuals) = TREE_OPERAND (base_pfn, 0);
-             return;
-           }
-       }
-    }
-}
-
-/* Check to ensure that the virtual function table slot in VFIELD,
-   found by DECL_VINDEX of the BASE_FNDECL is in fact from a parent
-   virtual function table that is the same parent as for the
-   BASE_FNDECL given to us.  */
 
-static int
-related_vslot (base_fndecl, vfields, type)
-     tree base_fndecl, vfields, type;
-{
-  tree base_context = TYPE_MAIN_VARIANT (DECL_CONTEXT (base_fndecl));
-  tree base;
-  tree path;
-  int distance;
-
-  if (TREE_CODE (vfields) != TREE_LIST)
-    abort ();
-  base = VF_NORMAL_VALUE (vfields);
-  if (base == NULL_TREE)
-    base = VF_BASETYPE_VALUE (vfields);
-
-  /* The simple right way to do this is to ensure that the context of
-     the base virtual function is found along the leftmost path
-     between the most derived type associated with the vfield and the
-     current type.  */
-  distance = get_base_distance (base, type, 0, &path);
-  if (distance == -1)
-    abort ();
-  while (path)
-    {
-      if (BINFO_TYPE (path) == base_context)
-       return 1;
-      path = BINFO_INHERITANCE_CHAIN (path);
-    }
-
-  /* given:
-               Rr
-              / \
-             Mm  Hh
-              \ /
-               P
-
-     make sure we fill in P's vtable for H with overrides of r,
-     but be cautious of virtual base classes.  */
-  /* Combine the two below after debugging. */
-  if (get_base_distance (base_context, base, 0, &path) != -1)
+  /* Now assign virtual dispatch information, if unset.  */
+  /* We can dispatch this, through any overridden base function.  */
+  if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
     {
-      while (path)
-       {
-         if (TREE_VIA_VIRTUAL (path))
-           return 0;
-         path = BINFO_INHERITANCE_CHAIN (path);
-       }
-      /* Make sure that:
-
-                RRB
-                |
-           RL   RR
-             \ /
-          L   R
-           \ /
-            C
-
-        returns 0.   VF_BASETYPE_VALUE is RL, base_context is RRB, type is C,
-        and the vfield we are checking is R.  */
-      if (VF_BASETYPE_VALUE (vfields)
-         && get_base_distance (base_context, VF_BASETYPE_VALUE (vfields), 0, &path) == -1
-         && get_base_distance (VF_BASETYPE_VALUE (vfields), base_context, 0, &path) == -1)
-       return 0;
-      return 1;
+      DECL_VINDEX (fndecl) = DECL_VINDEX (base_fndecl);
+      DECL_CONTEXT (fndecl) = DECL_CONTEXT (base_fndecl);
     }
-  return 0;
 }
 
-static void modify_vtable_entries ();
-
-/* Access the virtual function table entry i.  VIRTUALS is the virtual
+/* Access the virtual function table entry N.  VIRTUALS is the virtual
    function table's initializer.  */
+
 static tree
-get_vtable_entry_n (virtuals, i)
+get_vtable_entry_n (virtuals, n)
      tree virtuals;
-     unsigned HOST_WIDE_INT i;
+     unsigned HOST_WIDE_INT n;
 {
-  while (i > 0)
+  while (n > 0)
     {
+      --n;
       virtuals = TREE_CHAIN (virtuals);
-      i -= 1;
     }
   return virtuals;
 }
 
-#if 0
-/* Find the vfield (in the CLASSTYPE_VFIELDS chain) of the given binfo. */
+/* Add a virtual function to all the appropriate vtables for the class
+   T.  DECL_VINDEX(X) should be error_mark_node, if we want to
+   allocate a new slot in our table.  If it is error_mark_node, we
+   know that no other function from another vtable is overridden by X.
+   HAS_VIRTUAL keeps track of how many virtuals there are in our main
+   vtable for the type, and we build upon the PENDING_VIRTUALS list
+   and return it.  */
+
 static tree
-find_associated_vfield (binfo, t)
-     tree t, binfo;
+add_virtual_function (pending_virtuals, has_virtual, fndecl, t)
+     tree pending_virtuals;
+     int *has_virtual;
+     tree fndecl;
+     tree t; /* Structure type.  */
 {
-  tree vfields;
-  tree save_vfields = 0;
-  for (vfields = CLASSTYPE_VFIELDS (t); vfields; vfields = TREE_CHAIN (vfields))
-    {
-      if (VF_BINFO_VALUE (vfields) == binfo)
-       return vfields;
-    }
-  for (vfields = CLASSTYPE_VFIELDS (t); vfields; vfields = TREE_CHAIN (vfields))
+  /* FUNCTION_TYPEs and OFFSET_TYPEs no longer freely
+     convert to void *.  Make such a conversion here.  */
+  tree vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
+  TREE_CONSTANT (vfn) = 1;
+
+#ifndef DUMB_USER
+  if (current_class_type == 0)
+    cp_warning ("internal problem, current_class_type is zero when adding `%D', please report",
+               fndecl);
+  if (current_class_type && t != current_class_type)
+    cp_warning ("internal problem, current_class_type differs when adding `%D', please report",
+               fndecl);
+#endif
+
+  /* If the virtual function is a redefinition of a prior one,
+     figure out in which base class the new definition goes,
+     and if necessary, make a fresh virtual function table
+     to hold that entry.  */
+  if (DECL_VINDEX (fndecl) == error_mark_node)
     {
-      tree path;
-      get_base_distance (VF_BASETYPE_VALUE (vfields), t, 0, &path);
-      while (path)
+      tree entry;
+
+      /* We remember that this was the base sub-object for rtti.  */
+      CLASSTYPE_RTTI (t) = t;
+
+      /* If we are using thunks, use two slots at the front, one
+        for the offset pointer, one for the tdesc pointer.  */
+      if (*has_virtual == 0 && flag_vtable_thunks)
        {
-         if (path == binfo)
-           return vfields;
-         path = BINFO_INHERITANCE_CHAIN (path);
+         *has_virtual = 1;
        }
-    }      
-  /* This is from a virtual base class's vtable, hopefully. */
-  return 0;
-}
-#endif
 
+      /* Build a new INT_CST for this DECL_VINDEX.  */
+      {
+       static tree index_table[256];
+       tree idx;
+       /* We skip a slot for the offset/tdesc entry.  */
+       int i = ++(*has_virtual);
 
-/* Returns != 0 is the BINFO is the normal one for the main vfield, 0
-   otherwise. We don't have to worry about the finding BINFO in
-   CLASSTYPE_VBASECLASSES, if it is virtual, as we never inherit
-   vtables from virtual base classes.  */
-static int
-is_normal (binfo, t)
-     tree t, binfo;
-{
-  tree binfo2;
-  int i = CLASSTYPE_VFIELD_PARENT (t);
-  if (i != -1)
+       if (i >= 256 || index_table[i] == 0)
+         {
+           idx = build_int_2 (i, 0);
+           if (i < 256)
+             index_table[i] = idx;
+         }
+       else
+         idx = index_table[i];
+
+       /* Now assign virtual dispatch information.  */
+       DECL_VINDEX (fndecl) = idx;
+       DECL_CONTEXT (fndecl) = t;
+      }
+      entry = build_vtable_entry (integer_zero_node, vfn);
+      pending_virtuals = tree_cons (DECL_VINDEX (fndecl), entry, pending_virtuals);
+    }
+  /* Might already be INTEGER_CST if declared twice in class.  We will
+     give error later or we've already given it.  */
+  else if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
     {
-      tree base_binfo = TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (t)), i);
-      if (base_binfo == binfo)
-       return 1;
+      /* Need an entry in some other virtual function table.
+         Deal with this after we have laid out our virtual base classes.  */
+      pending_hard_virtuals = temp_tree_cons (fndecl, vfn, pending_hard_virtuals);
     }
-  return 0;
+  return pending_virtuals;
 }
+\f
+/* Obstack on which to build the vector of class methods.  */
+struct obstack class_obstack;
+extern struct obstack *current_obstack;
 
-/* Modify virtual function tables in lattice topped by T to place
-   FNDECL in tables which previously held BASE_FNDECL.  This marches
-   through the vtables directly, looking for exact mactes to
-   modify. */
-static void
-modify_other_vtable_entries (t, binfo, fndecl, base_fndecl, pfn)
-     tree t, binfo;
-     tree fndecl, base_fndecl, pfn;
-{
-  tree vfields, virtuals;
-  tree binfos;
-  int i, n_baselinks;
-  unsigned HOST_WIDE_INT n;
-  
-  virtuals = BINFO_VIRTUALS (binfo);
-  n = 0;
-  while (virtuals)
-    {
-      tree current_fndecl = TREE_VALUE (virtuals);
-      tree *binfo2_ptr;
-      current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl);
-      current_fndecl = TREE_OPERAND (current_fndecl, 0);
-      if (current_fndecl && SAME_FN (current_fndecl, base_fndecl))
-       {
-         /* Most of the below was copied from
-            modify_vtable_entries (t, fndecl, base_fndecl, pfn); */
-         tree base_offset, offset;
-         tree context = DECL_CLASS_CONTEXT (fndecl);
-         tree vfield = CLASSTYPE_VFIELD (t);
-         int normal = 1;
-         tree binfo2, this_offset;
-         tree base, path;
-
-         offset = integer_zero_node;
-         if (context != t && TYPE_USES_COMPLEX_INHERITANCE (t))
-           {
-             offset = virtual_offset (context, CLASSTYPE_VBASECLASSES (t), offset);
-             if (offset == NULL_TREE)
-               {
-                 tree binfo = get_binfo (context, t, 0);
-                 offset = BINFO_OFFSET (binfo);
-               }
-           }
-
-         /* Get the path starting from the deepest base class CONTEXT
-            of T (i.e., first defn of BASE_FNDECL).  */
-         get_base_distance (binfo, t, 0, &path);
-         binfo2_ptr = 0;
-
-         /* Get our best approximation of what to use for constructing
-            the virtual function table for T.  */
-         do
-           {
-             /* Walk from base toward derived, stopping at the
-                most derived baseclass that matters.  That baseclass
-                is exactly the one which provides the vtable along
-                the VFIELD spine, but no more.  */
-             if (TREE_VIA_VIRTUAL (path))
-               {
-                 base = path;
-                 binfo2 = binfo_member (BINFO_TYPE (base), CLASSTYPE_VBASECLASSES (t));
-                 /* This should never have TREE_USED set. */
-                 binfo2_ptr = 0;
-                 break;
-               }
-             if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE
-                 || (BINFO_TYPE (BINFO_BASETYPE (BINFO_INHERITANCE_CHAIN (path), 0))
-                     != BINFO_TYPE (path))
-                 || BINFO_INHERITANCE_CHAIN (BINFO_INHERITANCE_CHAIN (path)) == NULL_TREE)
-               {
-                 base = path;
-                 binfo2 = base;
-                 binfo2_ptr = 0;
-                 break;
-               }
-             path = BINFO_INHERITANCE_CHAIN (path);
-             binfo2_ptr = &BINFO_INHERITANCE_CHAIN (path);
-           }
-         while (1);
+/* Add method METHOD to class TYPE.  This is used when a method
+   has been defined which did not initially appear in the class definition,
+   and helps cut down on spurious error messages.
 
-         /* Find the right offset for the this pointer based on the base
-            class we just found.  */
-         base_offset = BINFO_OFFSET (binfo2);
-         this_offset = size_binop (MINUS_EXPR, offset, base_offset);
+   FIELDS is the entry in the METHOD_VEC vector entry of the class type where
+   the method should be added.  */
 
-         /* Make sure we can modify the derived association with immunity.  */
-         if (TREE_USED (binfo2)) {
-           my_friendly_assert (*binfo2_ptr == binfo2, 999);
-           *binfo2_ptr = copy_binfo (binfo2);
-         }
-
-#if 0
-         vfields = find_associated_vfield (binfo2, t);
-
-         /* We call this case NORMAL iff this virtual function table
-            pointer field has its storage reserved in this class.
-            This is normally the case without virtual baseclasses
-            or off-center multiple baseclasses.  */
-         normal = (vfields && vfield != NULL_TREE
-                   && VF_BASETYPE_VALUE (vfields) == DECL_FCONTEXT (vfield)
-                   && (VF_BINFO_VALUE (vfields) == NULL_TREE
-                       || ! TREE_VIA_VIRTUAL (VF_BINFO_VALUE (vfields))));
-
-         if (normal && VF_BINFO_VALUE (vfields))
-           /* Everything looks normal so far...check that we are really
-              working from VFIELD's basetype, and not some other appearance
-              of that basetype in the lattice.  */
-           normal = (VF_BINFO_VALUE (vfields)
-                     == get_binfo (VF_BASETYPE_VALUE (vfields), t, 0));
-#else
-         normal = is_normal (binfo2, t);
-#endif
-
-         if (normal)
-           {
-             /* In this case, it is *type*'s vtable we are modifying.
-                We start with the approximation that it's vtable is that
-                of the immediate base class.  */
-             binfo2 = TYPE_BINFO (t);
-             if (! BINFO_NEW_VTABLE_MARKED (binfo2))
-               build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
-           }
-         else
-           {
-             /* This is our very own copy of `basetype' to play with.
-                Later, we will fill in all the virtual functions
-                that override the virtual functions in these base classes
-                which are not defined by the current type.  */
-             if (! BINFO_NEW_VTABLE_MARKED (binfo2))
-               prepare_fresh_vtable (binfo2, base, t);
-           }
-
-#ifdef NOTQUITE
-         cp_warning ("in %D", DECL_NAME (BINFO_VTABLE (binfo2)));
-#endif
-         modify_vtable_entry (get_vtable_entry_n (BINFO_VIRTUALS (binfo2), n),
-                              build_vtable_entry (this_offset, pfn),
-                              fndecl);
-       } else if (current_fndecl && DECL_NAME (current_fndecl) == DECL_NAME (base_fndecl))
-         {
-#ifdef NOTQUITE
-           cp_warning ("%D not replaced (looking for %D) in %D", DECL_ASSEMBLER_NAME (current_fndecl), DECL_ASSEMBLER_NAME (base_fndecl), DECL_NAME (BINFO_VTABLE (binfo)));
-#endif
-         }
-      ++n;
-      virtuals = TREE_CHAIN (virtuals);
-    }
-  binfos = BINFO_BASETYPES (binfo);
-  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  for (i = 0; i < n_baselinks; i++)
-    {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      /* Don't modify virtual bases, as we share them down this way. */
-      /* We hope that other places will get things down this direction. */
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       continue;
-      modify_other_vtable_entries (t, base_binfo, fndecl, base_fndecl, pfn);
-    }
-}
-
-/* Modify virtual function tables in lattice topped by T to
-   place FNDECL in tables which previously held BASE_FNDECL.
-   PFN is just FNDECL wrapped in an ADDR_EXPR, so that it
-   is suitable for placement directly into an initializer.
-
-   All distinct virtual function tables that this type uses
-   must be updated.  */
-static void
-modify_vtable_entries (t, fndecl, base_fndecl, pfn)
-     tree t;
-     tree fndecl, base_fndecl, pfn;
-{
-  tree base_offset, offset;
-  tree base_context = DECL_CONTEXT (base_fndecl);
-  tree context = DECL_CLASS_CONTEXT (fndecl);
-  tree vfield = CLASSTYPE_VFIELD (t);
-  tree vfields, vbases;
-  tree saved_pfn;
-
-#ifdef NOTQUITE
-  cp_warning ("modifing all %D into %D for %T", base_fndecl, fndecl, t);
-  if (DECL_CONTEXT (fndecl) != DECL_CONTEXT (base_fndecl))
-    {
-      cp_warning ("switching contexts from %T to %T for %x",
-                 DECL_CONTEXT (fndecl),
-                 DECL_CONTEXT (base_fndecl), fndecl);
-      cp_warning ("base was %D, new is %D", DECL_ASSEMBLER_NAME (base_fndecl),
-                 DECL_ASSEMBLER_NAME(fndecl));
-    }
-#endif
-  DECL_CONTEXT (fndecl) = DECL_CONTEXT (base_fndecl);
-
-  offset = integer_zero_node;
-  if (context != t && TYPE_USES_COMPLEX_INHERITANCE (t))
-    {
-      offset = virtual_offset (context, CLASSTYPE_VBASECLASSES (t), offset);
-      if (offset == NULL_TREE)
-       {
-         tree binfo = get_binfo (context, t, 0);
-         offset = BINFO_OFFSET (binfo);
-       }
-    }
-
-  /* For each layer of base class (i.e., the first base class, and each
-     virtual base class from that one), modify the virtual function table
-     of the derived class to contain the new virtual function.
-     A class has as many vfields as it has virtual base classes (total).  */
-  for (vfields = CLASSTYPE_VFIELDS (t); vfields; vfields = TREE_CHAIN (vfields))
-    {
-      int normal = 1;
-      tree binfo, this_offset;
-      tree base, path;
-
-      if (!related_vslot (base_fndecl, vfields, t))
-         continue;
-
-      /* Find the right base class for this derived class, call it BASE.  */
-      base = VF_BASETYPE_VALUE (vfields);
-
-      /* Get the path starting from the deepest base class CONTEXT
-        of T (i.e., first defn of BASE_FNDECL).  */
-      get_base_distance (DECL_CONTEXT (base_fndecl), t, 0, &path);
-
-      /* Get our best approximation of what to use for constructing
-        the virtual function table for T.  */
-      do
-       {
-         /* Walk from base toward derived, stopping at the
-            most derived baseclass that matters.  That baseclass
-            is exactly the one which provides the vtable along
-            the VFIELD spine, but no more.  */
-         if (TREE_VIA_VIRTUAL (path))
-           {
-             base = path;
-             binfo = binfo_member (BINFO_TYPE (base), CLASSTYPE_VBASECLASSES (t));
-             break;
-           }
-         if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE
-             || (BINFO_TYPE (BINFO_BASETYPE (BINFO_INHERITANCE_CHAIN (path), 0))
-                 != BINFO_TYPE (path))
-             || BINFO_INHERITANCE_CHAIN (BINFO_INHERITANCE_CHAIN (path)) == NULL_TREE)
-           {
-             base = path;
-             binfo = base;
-             break;
-           }
-         path = BINFO_INHERITANCE_CHAIN (path);
-       }
-      while (1);
-
-      /* Find the right offset for the this pointer based on the base
-        class we just found.  */
-      base_offset = BINFO_OFFSET (binfo);
-      this_offset = size_binop (MINUS_EXPR, offset, base_offset);
-
-      /* Make sure we can modify the derived association with immunity.  */
-      if (TREE_USED (TYPE_BINFO (t)))
-       TYPE_BINFO (t) = copy_binfo (TYPE_BINFO (t));
-
-      /* We call this case NORMAL iff this virtual function table
-        pointer field has its storage reserved in this class.
-        This is normally the case without virtual baseclasses
-        or off-center multiple baseclasses.  */
-      normal = (vfield != NULL_TREE
-               && VF_BASETYPE_VALUE (vfields) == DECL_FCONTEXT (vfield)
-               && (VF_BINFO_VALUE (vfields) == NULL_TREE
-                   || ! TREE_VIA_VIRTUAL (VF_BINFO_VALUE (vfields))));
-
-      if (normal && VF_BINFO_VALUE (vfields))
-       /* Everything looks normal so far...check that we are really
-          working from VFIELD's basetype, and not some other appearance
-          of that basetype in the lattice.  */
-       normal = (VF_BINFO_VALUE (vfields)
-                 == get_binfo (VF_BASETYPE_VALUE (vfields), t, 0));
-
-      if (normal)
-       {
-         /* In this case, it is *type*'s vtable we are modifying.
-            We start with the approximation that it's vtable is that
-            of the immediate base class.  */
-         base_context = t;
-         binfo = TYPE_BINFO (t);
-         if (! BINFO_NEW_VTABLE_MARKED (binfo))
-           build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
-       }
-      else
-       {
-         /* This is our very own copy of `basetype' to play with.
-            Later, we will fill in all the virtual functions
-            that override the virtual functions in these base classes
-            which are not defined by the current type.  */
-         if (! BINFO_NEW_VTABLE_MARKED (binfo))
-           prepare_fresh_vtable (binfo, base, t);
-       }
-
-      saved_pfn = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (get_vtable_entry (BINFO_VIRTUALS (binfo), base_fndecl))), 0);
-#ifdef NOTQUITE
-      cp_warning ("in %D", DECL_NAME (BINFO_VTABLE (binfo)));
-#endif
-      /* The this_offset can be wrong, if we try and modify an entry
-        that had been modified once before. */
-      if (! SAME_FN (saved_pfn, fndecl))
-        {
-         modify_vtable_entry (get_vtable_entry (BINFO_VIRTUALS (binfo), base_fndecl),
-                              build_vtable_entry (this_offset, pfn),
-                              fndecl);
-         modify_other_vtable_entries (t, TYPE_BINFO (t), fndecl, saved_pfn, pfn);
-       }
-    }
-  for (vbases = CLASSTYPE_VBASECLASSES (t); vbases; vbases = TREE_CHAIN (vbases))
-    {
-      tree this_offset;
-      tree base, path;
-
-      if (! BINFO_VTABLE (vbases))
-       /* There are only two ways that a type can fail to have
-          virtual functions: neither it nor any of its base
-          types define virtual functions (in which case
-          no updating need be done), or virtual functions
-          accessible to it come from virtual base classes
-          (in which case we have or will get them modified
-          in other passes of this loop).  */
-       continue;
-
-      base = BINFO_TYPE (vbases);
-      path = NULL_TREE;
-
-      if (base != base_context
-         && get_base_distance (base_context, base, 0, &path) == -1)
-       continue;
-
-      if (path)
-       this_offset = size_binop (MINUS_EXPR, offset, BINFO_OFFSET (path));
-      else
-       this_offset = offset;
-
-      /* Doesn't matter if not actually from this virtual base class,
-         but shouldn't come from deeper virtual baseclasses.  The enclosing
-        loop should take care of such baseclasses.  */
-      while (path)
-       {
-         if (TREE_VIA_VIRTUAL (path))
-           goto skip;
-         path = BINFO_INHERITANCE_CHAIN (path);
-       }
-
-      base_offset = BINFO_OFFSET (vbases);
-      this_offset = size_binop (MINUS_EXPR, this_offset, base_offset);
-
-      /* Make sure we can modify the derived association with immunity.  */
-      if (TREE_USED (TYPE_BINFO (t)))
-       TYPE_BINFO (t) = copy_binfo (TYPE_BINFO (t));
-
-      /* This is our very own copy of `basetype' to play with.  */
-      if (! BINFO_NEW_VTABLE_MARKED (vbases))
-       {
-         tree context_binfo = binfo_value (base_context, base);
-         prepare_fresh_vtable (vbases, context_binfo, t);
-       }
-      saved_pfn = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (get_vtable_entry (BINFO_VIRTUALS (vbases), base_fndecl))), 0);
-#ifdef NOTQUITE
-      cp_warning ("in %D", DECL_NAME (BINFO_VTABLE (vbases)));
-#endif
-      /* The this_offset can be wrong, if we try and modify an entry
-        that had been modified once before. */
-      if (! SAME_FN (saved_pfn, fndecl))
-       {
-         modify_vtable_entry (get_vtable_entry (BINFO_VIRTUALS (vbases),
-                                                base_fndecl),
-                              build_vtable_entry (this_offset, pfn),
-                              fndecl);
-         modify_other_vtable_entries (t, TYPE_BINFO (t), fndecl, saved_pfn, pfn);
-       }
-    skip: {}
-    }
-}
-
-static tree
-add_virtual_function (pending_virtuals, has_virtual, x, t)
-     tree pending_virtuals;
-     int *has_virtual;
-     tree x;
-     tree t; /* Structure type. */
-{
-  int debug_vbase = 1;
-
-  /* FUNCTION_TYPEs and OFFSET_TYPEs no longer freely
-     convert to void *.  Make such a conversion here.  */
-  tree vfn = build1 (ADDR_EXPR, ptr_type_node, x);
-  TREE_CONSTANT (vfn) = 1;
-
-  /* current_class_type may be NULL_TREE in case of error.  */
-  if (current_class_type)
-    TREE_ADDRESSABLE (x) = CLASSTYPE_VTABLE_NEEDS_WRITING (current_class_type);
-
-  /* If the virtual function is a redefinition of a prior one,
-     figure out in which base class the new definition goes,
-     and if necessary, make a fresh virtual function table
-     to hold that entry.  */
-  if (DECL_VINDEX (x) == error_mark_node)
-    {
-      tree entry = build_vtable_entry (integer_zero_node, vfn);
-
-      if (flag_dossier && *has_virtual == 0)
-       {
-         /* CLASSTYPE_DOSSIER is only used as a Boolean (NULL or not). */
-         CLASSTYPE_DOSSIER (t) = integer_one_node;
-         *has_virtual = 1;
-        }
-
-      /* Build a new INT_CST for this DECL_VINDEX.  */
-#ifdef VTABLE_USES_MASK
-      SET_DECL_VINDEX (x, build_int_2 (++(*has_virtual), 0));
-#else
-      {
-       static tree index_table[256];
-       tree index;
-       int i = ++(*has_virtual);
-
-       if (i >= 256 || index_table[i] == 0)
-         {
-           index = build_int_2 (i, 0);
-           if (i < 256)
-             index_table[i] = index;
-         }
-       else
-         index = index_table[i];
-
-       DECL_VINDEX (x) = index;
-      }
-#endif
-      pending_virtuals = tree_cons (DECL_VINDEX (x), entry, pending_virtuals);
-    }
-  /* Happens if declared twice in class or we're not in a class definition.
-     We will give error later or we've already given it.  */
-  else if (TREE_CODE (DECL_VINDEX (x)) == INTEGER_CST
-          || current_class_type == NULL_TREE)
-    return pending_virtuals;
-  else if (debug_vbase && TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
-    {
-      /* Need an entry in some other virtual function table.
-         Deal with this after we have laid out our virtual base classes.  */
-      pending_hard_virtuals = temp_tree_cons (x, vfn, pending_hard_virtuals);
-    }
-  else
-    {
-      /* Need an entry in some other virtual function table.
-         We can do this now.  */
-      tree base_fndecl_list = DECL_VINDEX (x), base_fndecls, prev = 0;
-      tree vtable_context = DECL_FCONTEXT (CLASSTYPE_VFIELD (current_class_type));
-      tree true_base_fndecl = 0;
-
-      /* First assign DECL_VINDEX from the base vfn with which
-        we share our vtable.  */
-      base_fndecls = base_fndecl_list;
-      while (base_fndecls)
-       {
-         if (TREE_CHAIN (base_fndecls) == NULL_TREE
-             || DECL_FCONTEXT (CLASSTYPE_VFIELD (DECL_CLASS_CONTEXT (TREE_VALUE (base_fndecls)))) == vtable_context)
-           {
-             true_base_fndecl = TREE_VALUE (base_fndecls);
-             modify_vtable_entries (current_class_type, x,
-                                    true_base_fndecl, vfn);
-             if (prev)
-               TREE_CHAIN (prev) = TREE_CHAIN (base_fndecls);
-             else
-               base_fndecl_list = prev;
-             break;
-           }
-         prev = base_fndecls;
-         base_fndecls = TREE_CHAIN (base_fndecls);
-       }
-
-      /* Now fill in the rest of the vtables.  */
-      base_fndecls = base_fndecl_list;
-      while (base_fndecls)
-       {
-         /* If we haven't found one we like, first one wins.  */
-         if (true_base_fndecl == 0)
-           true_base_fndecl = TREE_VALUE (base_fndecls);
-
-         modify_vtable_entries (current_class_type, x,
-                                TREE_VALUE (base_fndecls), vfn);
-         base_fndecls = TREE_CHAIN (base_fndecls);
-       }
-
-      DECL_CONTEXT (x) = DECL_CONTEXT (true_base_fndecl);
-    }
-  return pending_virtuals;
-}
-\f
-/* Obstack on which to build the vector of class methods.  */
-struct obstack class_obstack;
-extern struct obstack *current_obstack;
-
-/* Add method METHOD to class TYPE.  This is used when a method
-   has been defined which did not initially appear in the class definition,
-   and helps cut down on spurious error messages.
-
-   FIELDS is the entry in the METHOD_VEC vector entry of the class type where
-   the method should be added.  */
-void
-add_method (type, fields, method)
-     tree type, *fields, method;
-{
-  /* We must make a copy of METHOD here, since we must be sure that
-     we have exclusive title to this method's DECL_CHAIN.  */
-  tree decl;
+void
+add_method (type, fields, method)
+     tree type, *fields, method;
+{
+  /* We must make a copy of METHOD here, since we must be sure that
+     we have exclusive title to this method's DECL_CHAIN.  */
+  tree decl;
 
   push_obstacks (&permanent_obstack, &permanent_obstack);
   {
     decl = copy_node (method);
     if (DECL_RTL (decl) == 0
         && (!processing_template_decl
-            || !uses_template_parms (decl)))
+           || !uses_template_parms (decl)))
       {
        make_function_rtl (decl);
        DECL_RTL (method) = DECL_RTL (decl);
@@ -1513,8 +1011,16 @@ add_method (type, fields, method)
       tree method_vec = make_node (TREE_VEC);
       if (TYPE_IDENTIFIER (type) == DECL_NAME (decl))
        {
-         TREE_VEC_ELT (method_vec, 0) = decl;
-         TREE_VEC_LENGTH (method_vec) = 1;
+         /* ??? Is it possible for there to have been enough room in the
+            current chunk for the tree_vec structure but not a tree_vec
+            plus a tree*?  Will this work in that case?  */
+         obstack_free (current_obstack, method_vec);
+         obstack_blank (current_obstack, sizeof (struct tree_vec) + sizeof (tree *));
+         if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)))
+           TREE_VEC_ELT (method_vec, 1) = decl;
+         else
+           TREE_VEC_ELT (method_vec, 0) = decl;
+         TREE_VEC_LENGTH (method_vec) = 2;
        }
       else
        {
@@ -1522,9 +1028,9 @@ add_method (type, fields, method)
             current chunk for the tree_vec structure but not a tree_vec
             plus a tree*?  Will this work in that case?  */
          obstack_free (current_obstack, method_vec);
-         obstack_blank (current_obstack, sizeof (struct tree_vec) + sizeof (tree *));
-         TREE_VEC_ELT (method_vec, 1) = decl;
-         TREE_VEC_LENGTH (method_vec) = 2;
+         obstack_blank (current_obstack, sizeof (struct tree_vec) + 2*sizeof (tree *));
+         TREE_VEC_ELT (method_vec, 2) = decl;
+         TREE_VEC_LENGTH (method_vec) = 3;
          obstack_finish (current_obstack);
        }
       CLASSTYPE_METHOD_VEC (type) = method_vec;
@@ -1538,11 +1044,12 @@ add_method (type, fields, method)
          METHOD_VEC always has a slot for such entries.  */
       if (TYPE_IDENTIFIER (type) == DECL_NAME (decl))
        {
-         /* TREE_VEC_ELT (method_vec, 0) = decl; */
-         if (decl != TREE_VEC_ELT (method_vec, 0))
+         int idx = !!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl));
+         /* TREE_VEC_ELT (method_vec, idx) = decl; */
+         if (decl != TREE_VEC_ELT (method_vec, idx))
            {
-             DECL_CHAIN (decl) = TREE_VEC_ELT (method_vec, 0);
-             TREE_VEC_ELT (method_vec, 0) = decl;
+             DECL_CHAIN (decl) = TREE_VEC_ELT (method_vec, idx);
+             TREE_VEC_ELT (method_vec, idx) = decl;
            }
        }
       else
@@ -1571,7 +1078,7 @@ add_method (type, fields, method)
                                   * sizeof (char *)
                                 + len * sizeof (tree));
                  tmp_vec = (tree) obstack_base (ob);
-                 bcopy (method_vec, tmp_vec,
+                 bcopy ((char *) method_vec, (char *) tmp_vec,
                         (sizeof (struct tree_common)
                          + tree_code_length[(int) TREE_VEC] * sizeof (char *)
                          + (len-1) * sizeof (tree)));
@@ -1620,21 +1127,20 @@ add_method (type, fields, method)
    Note that anonymous fields which are not of UNION_TYPE are
    not duplicates, they are just anonymous fields.  This happens
    when we have unnamed bitfields, for example.  */
+
 static tree
-delete_duplicate_fields_1 (field, field_ptr, fields)
-     tree field, *field_ptr, fields;
+delete_duplicate_fields_1 (field, fields)
+     tree field, fields;
 {
   tree x;
-  tree prev = field_ptr ? *field_ptr : 0;
+  tree prev = 0;
   if (DECL_NAME (field) == 0)
     {
       if (TREE_CODE (TREE_TYPE (field)) != UNION_TYPE)
        return fields;
 
       for (x = TYPE_FIELDS (TREE_TYPE (field)); x; x = TREE_CHAIN (x))
-       fields = delete_duplicate_fields_1 (x, field_ptr, fields);
-      if (prev)
-       TREE_CHAIN (prev) = fields;
+       fields = delete_duplicate_fields_1 (x, fields);
       return fields;
     }
   else
@@ -1646,7 +1152,7 @@ delete_duplicate_fields_1 (field, field_ptr, fields)
              if (TREE_CODE (TREE_TYPE (x)) != UNION_TYPE)
                continue;
              TYPE_FIELDS (TREE_TYPE (x))
-               = delete_duplicate_fields_1 (field, (tree *)0, TYPE_FIELDS (TREE_TYPE (x)));
+               = delete_duplicate_fields_1 (field, TYPE_FIELDS (TREE_TYPE (x)));
              if (TYPE_FIELDS (TREE_TYPE (x)) == 0)
                {
                  if (prev == 0)
@@ -1668,11 +1174,23 @@ delete_duplicate_fields_1 (field, field_ptr, fields)
                                x);
                  else if (TREE_CODE (field) == TYPE_DECL
                           && TREE_CODE (x) == TYPE_DECL)
-                   cp_error_at ("duplicate class scope type `%D'", x);
+                   {
+                     if (TREE_TYPE (field) == TREE_TYPE (x))
+                       continue;
+                     cp_error_at ("duplicate nested type `%D'", x);
+                   }
                  else if (TREE_CODE (field) == TYPE_DECL
                           || TREE_CODE (x) == TYPE_DECL)
-                   cp_error_at ("duplicate field `%D' (as type and non-type)",
-                               x);
+                   {
+                     /* Hide tag decls.  */
+                     if ((TREE_CODE (field) == TYPE_DECL
+                          && DECL_ARTIFICIAL (field))
+                         || (TREE_CODE (x) == TYPE_DECL
+                             && DECL_ARTIFICIAL (x)))
+                       continue;
+                     cp_error_at ("duplicate field `%D' (as type and non-type)",
+                                  x);
+                   }
                  else
                    cp_error_at ("duplicate member `%D'", x);
                  if (prev == 0)
@@ -1692,19 +1210,20 @@ delete_duplicate_fields (fields)
 {
   tree x;
   for (x = fields; x && TREE_CHAIN (x); x = TREE_CHAIN (x))
-    TREE_CHAIN (x) = delete_duplicate_fields_1 (x, &x, TREE_CHAIN (x));
+    TREE_CHAIN (x) = delete_duplicate_fields_1 (x, TREE_CHAIN (x));
 }
 
 /* Change the access of FDECL to ACCESS in T.
    Return 1 if change was legit, otherwise return 0.  */
+
 static int
 alter_access (t, fdecl, access)
      tree t;
      tree fdecl;
-     enum access_type access;
+     tree access;
 {
   tree elem = purpose_member (t, DECL_ACCESS (fdecl));
-  if (elem && TREE_VALUE (elem) != (tree)access)
+  if (elem && TREE_VALUE (elem) != access)
     {
       if (TREE_CODE (TREE_TYPE (fdecl)) == FUNCTION_DECL)
        {
@@ -1714,39 +1233,31 @@ alter_access (t, fdecl, access)
        error ("conflicting access specifications for field `%s', ignored",
               IDENTIFIER_POINTER (DECL_NAME (fdecl)));
     }
-  else if (TREE_PRIVATE (fdecl) && access != access_private)
-    cp_error_at ("cannot make private `%D' non-private", fdecl);
+  else if (TREE_PRIVATE (fdecl))
+    {
+      if (access != access_private_node)
+       cp_error_at ("cannot make private `%D' non-private", fdecl);
+      goto alter;
+    }
   else if (TREE_PROTECTED (fdecl))
     {
-      if (access == access_public)
-       cp_error_at ("cannot make protected `%D' public", fdecl);
+      if (access != access_protected_node)
+       cp_error_at ("cannot make protected `%D' non-protected", fdecl);
       goto alter;
     }
   /* ARM 11.3: an access declaration may not be used to restrict access
      to a member that is accessible in the base class.  */
-  else if (TREE_PUBLIC (fdecl)
-          && (access == access_private
-              || access == access_protected))
+  else if (access != access_public_node)
     cp_error_at ("cannot reduce access of public member `%D'", fdecl);
   else if (elem == NULL_TREE)
     {
     alter:
-      DECL_ACCESS (fdecl) = tree_cons (t, (tree)access,
-                                          DECL_ACCESS (fdecl));
+      DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
       return 1;
     }
   return 0;
 }
 
-static tree
-get_vfield_offset (binfo)
-     tree binfo;
-{
-  return size_binop (PLUS_EXPR,
-                    DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
-                    BINFO_OFFSET (binfo));
-}
-
 /* If FOR_TYPE needs to reinitialize virtual function table pointers
    for TYPE's sub-objects, add such reinitializations to BASE_INIT_LIST.
    Returns BASE_INIT_LIST appropriately modified.  */
@@ -1765,7 +1276,7 @@ maybe_fixup_vptrs (for_type, binfo, base_init_list)
          : VF_BASETYPE_VALUE (vfields);
 
       tree base_binfo = get_binfo (basetype, for_type, 0);
-      /* Punt until this is implemented. */
+      /* Punt until this is implemented.  */
       if (1 /* BINFO_MODIFIED (base_binfo) */)
        {
          tree base_offset = get_vfield_offset (base_binfo);
@@ -1913,12 +1424,10 @@ struct base_info
   int n_ancestors;
   tree vfield;
   tree vfields;
+  tree rtti;
   char cant_have_default_ctor;
   char cant_have_const_ctor;
-  char cant_synth_copy_ctor;
-  char cant_synth_asn_ref;
   char no_const_asn_ref;
-  char needs_virtual_dtor;
 };
 
 /* Record information about type T derived from its base classes.
@@ -1948,7 +1457,7 @@ finish_base_struct (t, b, t_binfo)
   tree binfos = BINFO_BASETYPES (t_binfo);
   int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
   int first_vfn_base_index = -1;
-  bzero (b, sizeof (struct base_info));
+  bzero ((char *) b, sizeof (struct base_info));
 
   for (i = 0; i < n_baseclasses; i++)
     {
@@ -1972,13 +1481,8 @@ finish_base_struct (t, b, t_binfo)
            TREE_VEC_ELT (binfos, j) = TREE_VEC_ELT (binfos, j+1);
        }
 
-      if (TYPE_HAS_INIT_REF (basetype)
-         && !TYPE_HAS_CONST_INIT_REF (basetype))
+      if (! TYPE_HAS_CONST_INIT_REF (basetype))
        b->cant_have_const_ctor = 1;
-      if (! TYPE_HAS_INIT_REF (basetype)
-         || (TYPE_HAS_NONPUBLIC_CTOR (basetype) == 2
-             && ! is_friend_type (t, basetype)))
-       b->cant_synth_copy_ctor = 1;
 
       if (TYPE_HAS_CONSTRUCTOR (basetype)
          && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype))
@@ -1995,31 +1499,18 @@ finish_base_struct (t, b, t_binfo)
       if (TYPE_HAS_ASSIGN_REF (basetype)
          && !TYPE_HAS_CONST_ASSIGN_REF (basetype))
        b->no_const_asn_ref = 1;
-      if (! TYPE_HAS_ASSIGN_REF (basetype)
-         || (TYPE_HAS_NONPUBLIC_ASSIGN_REF (basetype) == 2
-             && ! is_friend_type (t, basetype)))
-       b->cant_synth_asn_ref = 1;
 
       b->n_ancestors += CLASSTYPE_N_SUPERCLASSES (basetype);
       TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype);
       TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (basetype);
       TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype);
-      TYPE_HAS_COMPLEX_INIT_REF (t) |= (TYPE_HAS_COMPLEX_INIT_REF (basetype)
-                                       || TYPE_NEEDS_CONSTRUCTING (basetype));
+      TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (basetype);
 
       TYPE_OVERLOADS_CALL_EXPR (t) |= TYPE_OVERLOADS_CALL_EXPR (basetype);
       TYPE_OVERLOADS_ARRAY_REF (t) |= TYPE_OVERLOADS_ARRAY_REF (basetype);
       TYPE_OVERLOADS_ARROW (t) |= TYPE_OVERLOADS_ARROW (basetype);
 
       if (! TREE_VIA_VIRTUAL (base_binfo)
-#if 0
-         /* This cannot be done, as prepare_fresh_vtable wants to modify
-            binfos associated with vfields anywhere in the hierarchy, not
-            just immediate base classes.  Due to unsharing, the compiler
-            might consume 3% more memory on a real program.
-            */
-         && ! BINFO_OFFSET_ZEROP (base_binfo)
-#endif
          && BINFO_BASETYPES (base_binfo))
        {
          tree base_binfos = BINFO_BASETYPES (base_binfo);
@@ -2034,13 +1525,14 @@ finish_base_struct (t, b, t_binfo)
              if (! TREE_VIA_VIRTUAL (base_base_binfo))
                TREE_VEC_ELT (base_binfos, j)
                  = make_binfo (BINFO_OFFSET (base_base_binfo),
-                               BINFO_TYPE (base_base_binfo),
+                               base_base_binfo,
                                BINFO_VTABLE (base_base_binfo),
                                BINFO_VIRTUALS (base_base_binfo),
                                chain);
              chain = TREE_VEC_ELT (base_binfos, j);
              TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
              TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
+             BINFO_INHERITANCE_CHAIN (chain) = base_binfo;
            }
 
          /* Completely unshare potentially shared data, and
@@ -2053,9 +1545,10 @@ finish_base_struct (t, b, t_binfo)
 
       if (TYPE_VIRTUAL_P (basetype))
        {
-         /* If there's going to be a destructor needed, make
-            sure it will be virtual.  */
-         b->needs_virtual_dtor = 1;
+         /* Ensure that this is set from at least a virtual base
+             class.  */
+         if (b->rtti == NULL_TREE)
+           b->rtti = CLASSTYPE_RTTI (basetype);
 
          /* Don't borrow virtuals from virtual baseclasses.  */
          if (TREE_VIA_VIRTUAL (base_binfo))
@@ -2066,6 +1559,11 @@ finish_base_struct (t, b, t_binfo)
              tree vfields;
              first_vfn_base_index = i;
 
+             /* Update these two, now that we know what vtable we are
+                going to extend.  This is so that we can add virtual
+                functions, and override them properly.  */
+             BINFO_VTABLE (t_binfo) = TYPE_BINFO_VTABLE (basetype);
+             BINFO_VIRTUALS (t_binfo) = TYPE_BINFO_VIRTUALS (basetype);
              b->has_virtual = CLASSTYPE_VSIZE (basetype);
              b->vfield = CLASSTYPE_VFIELD (basetype);
              b->vfields = copy_list (CLASSTYPE_VFIELDS (basetype));
@@ -2109,6 +1607,12 @@ finish_base_struct (t, b, t_binfo)
              if (b->has_virtual == 0)
                {
                  first_vfn_base_index = i;
+
+                 /* Update these two, now that we know what vtable we are
+                    going to extend.  This is so that we can add virtual
+                    functions, and override them properly.  */
+                 BINFO_VTABLE (t_binfo) = TYPE_BINFO_VTABLE (basetype);
+                 BINFO_VIRTUALS (t_binfo) = TYPE_BINFO_VIRTUALS (basetype);
                  b->has_virtual = CLASSTYPE_VSIZE (basetype);
                  b->vfield = CLASSTYPE_VFIELD (basetype);
                  CLASSTYPE_VFIELD (t) = b->vfield;
@@ -2144,10 +1648,22 @@ finish_base_struct (t, b, t_binfo)
        {
          cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
                      basetype, t);
-         b->cant_synth_asn_ref = 1;
-         b->cant_synth_copy_ctor = 1;
        }
     }
+  {
+    tree v = get_vbase_types (t_binfo);
+
+    for (; v; v = TREE_CHAIN (v))
+      {
+       tree basetype = BINFO_TYPE (v);
+       if (get_base_distance (basetype, t_binfo, 0, (tree*)0) == -2)
+         {
+           if (extra_warnings)
+             cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
+                         basetype, t);
+         }
+      }
+  }    
 
   {
     tree vfields;
@@ -2165,6 +1681,11 @@ finish_base_struct (t, b, t_binfo)
   if (b->vfield == 0)
     /* If all virtual functions come only from virtual baseclasses.  */
     return -1;
+
+  /* Update the rtti base if we have a non-virtual base class version
+     of it.  */
+  b->rtti = CLASSTYPE_RTTI (BINFO_TYPE (TREE_VEC_ELT (binfos, first_vfn_base_index)));
+
   return first_vfn_base_index;
 }
 
@@ -2180,13 +1701,13 @@ typecode_p (type, code)
 \f
 /* Set memoizing fields and bits of T (and its variants) for later use.
    MAX_HAS_VIRTUAL is the largest size of any T's virtual function tables.  */
+
 static void
 finish_struct_bits (t, max_has_virtual)
      tree t;
      int max_has_virtual;
 {
   int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
-  tree method_vec = CLASSTYPE_METHOD_VEC (t);
 
   /* Fix up variants (if any).  */
   tree variants = TYPE_NEXT_VARIANT (t);
@@ -2205,23 +1726,31 @@ finish_struct_bits (t, max_has_virtual)
       /* Copy whatever these are holding today.  */
       TYPE_MIN_VALUE (variants) = TYPE_MIN_VALUE (t);
       TYPE_MAX_VALUE (variants) = TYPE_MAX_VALUE (t);
+      TYPE_FIELDS (variants) = TYPE_FIELDS (t);
+      TYPE_SIZE (variants) = TYPE_SIZE (t);
       variants = TYPE_NEXT_VARIANT (variants);
     }
 
   if (n_baseclasses && max_has_virtual)
     {
       /* Done by `finish_struct' for classes without baseclasses.  */
-      int has_abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (t) != 0;
+      int might_have_abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (t) != 0;
       tree binfos = TYPE_BINFO_BASETYPES (t);
       for (i = n_baseclasses-1; i >= 0; i--)
        {
-         has_abstract_virtuals
+         might_have_abstract_virtuals
            |= (CLASSTYPE_ABSTRACT_VIRTUALS (BINFO_TYPE (TREE_VEC_ELT (binfos, i))) != 0);
-         if (has_abstract_virtuals)
+         if (might_have_abstract_virtuals)
            break;
        }
-      if (has_abstract_virtuals)
-       CLASSTYPE_ABSTRACT_VIRTUALS (t) = get_abstract_virtuals (t);
+      if (might_have_abstract_virtuals)
+       {
+         /* We use error_mark_node from override_one_vtable to signal
+            an artificial abstract.  */
+         if (CLASSTYPE_ABSTRACT_VIRTUALS (t) == error_mark_node)
+           CLASSTYPE_ABSTRACT_VIRTUALS (t) = NULL_TREE;
+         CLASSTYPE_ABSTRACT_VIRTUALS (t) = get_abstract_virtuals (t);
+       }
     }
 
   if (n_baseclasses)
@@ -2246,90 +1775,97 @@ finish_struct_bits (t, max_has_virtual)
        }
     }
 
-  /* Need to test METHOD_VEC here in case all methods
-     (conversions and otherwise) are inherited.  */
-  if (TYPE_HAS_CONVERSION (t) && method_vec != NULL_TREE)
-    {
-      tree first_conversions[last_conversion_type];
-      tree last_conversions[last_conversion_type];
-      enum conversion_type conv_index;
-      tree *tmp;
-      int i;
-
-      bzero (first_conversions, sizeof (first_conversions));
-      bzero (last_conversions, sizeof (last_conversions));
-      for (tmp = &TREE_VEC_ELT (method_vec, 1);
-          tmp != TREE_VEC_END (method_vec); tmp += 1)
-       {
-         /* ??? This should compare DECL_NAME (*tmp) == ansi_opname[TYPE_EXPR].  */
-         if (IDENTIFIER_TYPENAME_P (DECL_ASSEMBLER_NAME (*tmp)))
-           {
-             tree fntype = TREE_TYPE (*tmp);
-             tree return_type = TREE_TYPE (fntype);
-             my_friendly_assert (TREE_CODE (fntype) == METHOD_TYPE, 171);
-
-             if (typecode_p (return_type, POINTER_TYPE))
-               {
-                 if (TYPE_READONLY (TREE_TYPE (return_type)))
-                   conv_index = constptr_conv;
-                 else
-                   conv_index = ptr_conv;
-               }
-             else if (typecode_p (return_type, INTEGER_TYPE))
-               {
-                 TYPE_HAS_INT_CONVERSION (t) = 1;
-                 conv_index = int_conv;
-               }
-             else if (typecode_p (return_type, REAL_TYPE))
-               {
-                 TYPE_HAS_REAL_CONVERSION (t) = 1;
-                 conv_index = real_conv;
-               }
-             else
-               continue;
-
-             if (first_conversions[(int) conv_index] == NULL_TREE)
-               first_conversions[(int) conv_index] = *tmp;
-             last_conversions[(int) conv_index] = *tmp;
-           }
-       }
-
-      for (i = 0; i < (int) last_conversion_type; i++)
-       if (first_conversions[i] != last_conversions[i])
-         CLASSTYPE_CONVERSION (t, i) = error_mark_node;
-       else
-         CLASSTYPE_CONVERSION (t, i) = first_conversions[i];
-    }
-
-  /* If this type has constructors, force its mode to be BLKmode,
-     and force its TREE_ADDRESSABLE bit to be nonzero.  */
-  if (TYPE_NEEDS_CONSTRUCTING (t) || TYPE_NEEDS_DESTRUCTOR (t))
+  /* If this type has a copy constructor, force its mode to be BLKmode, and
+     force its TREE_ADDRESSABLE bit to be nonzero.  This will cause it to
+     be passed by invisible reference and prevent it from being returned in
+     a register.
+
+     Also do this if the class has BLKmode but can still be returned in
+     registers, since function_cannot_inline_p won't let us inline
+     functions returning such a type.  This affects the HP-PA.  */
+  if (! TYPE_HAS_TRIVIAL_INIT_REF (t)
+      || (TYPE_MODE (t) == BLKmode && ! aggregate_value_p (t)
+         && CLASSTYPE_NON_AGGREGATE (t)))
     {
-      tree variants = t;
-
-      if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
-       DECL_MODE (TYPE_NAME (t)) = BLKmode;
-      while (variants)
+      tree variants;
+      DECL_MODE (TYPE_MAIN_DECL (t)) = BLKmode;
+      for (variants = t; variants; variants = TYPE_NEXT_VARIANT (variants))
        {
          TYPE_MODE (variants) = BLKmode;
          TREE_ADDRESSABLE (variants) = 1;
-         variants = TYPE_NEXT_VARIANT (variants);
        }
     }
 }
 
-/* Warn about duplicate methods in fn_fields.  Also compact method
-   lists so that lookup can be made faster.
+/* Add FNDECL to the method_vec growing on the class_obstack.  Used by
+   finish_struct_methods.  Note, FNDECL cannot be a constructor or
+   destructor, those cases are handled by the caller.  */
 
-   Algorithm: Outer loop builds lists by method name.  Inner loop
-   checks for redundant method names within a list.
+static void
+grow_method (fndecl, method_vec_ptr)
+     tree fndecl;
+     tree *method_vec_ptr;
+{
+  tree method_vec = (tree)obstack_base (&class_obstack);
 
-   Data Structure: List of method lists.  The outer list is a
+  /* Start off past the constructors and destructor.  */
+  tree *testp = &TREE_VEC_ELT (method_vec, 2);
+
+  while (testp < (tree *) obstack_next_free (&class_obstack)
+        && (*testp == NULL_TREE || DECL_NAME (*testp) != DECL_NAME (fndecl)))
+    testp++;
+
+  if (testp < (tree *) obstack_next_free (&class_obstack))
+    {
+      tree x, prev_x;
+
+      for (x = *testp; x; x = DECL_CHAIN (x))
+       {
+         if (DECL_NAME (fndecl) == ansi_opname[(int) DELETE_EXPR]
+             || DECL_NAME (fndecl) == ansi_opname[(int) VEC_DELETE_EXPR])
+           {
+             /* ANSI C++ June 5 1992 WP 12.5.5.1 */
+             cp_error_at ("`%D' overloaded", fndecl);
+             cp_error_at ("previous declaration as `%D' here", x);
+           }
+         if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (x))
+           {
+             /* Friend-friend ambiguities are warned about outside
+                this loop.  */
+             cp_error_at ("ambiguous method `%#D' in structure", fndecl);
+             break;
+           }
+         prev_x = x;
+       }
+      if (x == 0)
+       {
+         if (*testp)
+           DECL_CHAIN (prev_x) = fndecl;
+         else
+           *testp = fndecl;
+       }
+    }
+  else
+    {
+      obstack_ptr_grow (&class_obstack, fndecl);
+      *method_vec_ptr = (tree)obstack_base (&class_obstack);
+    }
+}
+
+/* Warn about duplicate methods in fn_fields.  Also compact method
+   lists so that lookup can be made faster.
+
+   Algorithm: Outer loop builds lists by method name.  Inner loop
+   checks for redundant method names within a list.
+
+   Data Structure: List of method lists.  The outer list is a
    TREE_LIST, whose TREE_PURPOSE field is the field name and the
-   TREE_VALUE is the TREE_CHAIN of the FUNCTION_DECLs.  Friends are
-   chained in the same way as member functions, but they live in the
-   TREE_TYPE field of the outer list.  That allows them to be quickly
-   deleted, and requires no extra storage.
+   TREE_VALUE is the DECL_CHAIN of the FUNCTION_DECLs.  TREE_CHAIN
+   links the entire list of methods for TYPE_METHODS.  Friends are
+   chained in the same way as member functions (? TREE_CHAIN or
+   DECL_CHAIN), but they live in the TREE_TYPE field of the outer
+   list.  That allows them to be quickly deleted, and requires no
+   extra storage.
 
    If there are any constructors/destructors, they are moved to the
    front of the list.  This makes pushclass more efficient.
@@ -2339,36 +1875,35 @@ finish_struct_bits (t, max_has_virtual)
    us to reduce search time in places like `build_method_call' to
    consider only reasonably likely functions.  */
 
-static tree
+tree
 finish_struct_methods (t, fn_fields, nonprivate_method)
      tree t;
      tree fn_fields;
      int nonprivate_method;
 {
   tree method_vec;
-  tree name = constructor_name (t);
+  tree save_fn_fields = fn_fields;
+  tree ctor_name = constructor_name (t);
   int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
 
   /* Now prepare to gather fn_fields into vector.  */
   struct obstack *ambient_obstack = current_obstack;
   current_obstack = &class_obstack;
-  method_vec = make_node (TREE_VEC);
-  /* Room has been saved for constructors and destructors.  */
+  method_vec = make_tree_vec (2);
   current_obstack = ambient_obstack;
+
   /* Now make this a live vector.  */
   obstack_free (&class_obstack, method_vec);
-  obstack_blank (&class_obstack, sizeof (struct tree_vec));
 
-  while (fn_fields)
+  /* Save room for constructors and destructors.  */
+  obstack_blank (&class_obstack, sizeof (struct tree_vec) + sizeof (struct tree *));
+
+  /* First fill in entry 0 with the constructors, entry 1 with destructors,
+     and the next few with type conversion operators (if any).  */
+
+  for (; fn_fields; fn_fields = TREE_CHAIN (fn_fields))
     {
-      /* NEXT Pointer, TEST Pointer, and BASE Pointer.  */
-      tree nextp, *testp;
       tree fn_name = DECL_NAME (fn_fields);
-      if (fn_name == NULL_TREE)
-       fn_name = name;
-
-      nextp = TREE_CHAIN (fn_fields);
-      TREE_CHAIN (fn_fields) = NULL_TREE;
 
       /* Clear out this flag.
 
@@ -2379,7 +1914,7 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
       /* Note here that a copy ctor is private, so we don't dare generate
         a default copy constructor for a class that has a member
         of this type without making sure they have access to it.  */
-      if (fn_name == name)
+      if (fn_name == ctor_name)
        {
          tree parmtypes = FUNCTION_ARG_CHAIN (fn_fields);
          tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
@@ -2397,13 +1932,47 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
                    TYPE_HAS_NONPUBLIC_CTOR (t) = 2;
                }
            }
+         if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fn_fields)))
+           {       
+             /* Destructors go in slot 1.  */
+             DECL_CHAIN (fn_fields) = TREE_VEC_ELT (method_vec, 1);
+             TREE_VEC_ELT (method_vec, 1) = fn_fields;
+           }
+         else
+           {
+             /* Constructors go in slot 0.  */
+             DECL_CHAIN (fn_fields) = TREE_VEC_ELT (method_vec, 0);
+             TREE_VEC_ELT (method_vec, 0) = fn_fields;
+           }
        }
-      else if (fn_name == ansi_opname[(int) MODIFY_EXPR])
+      else if (IDENTIFIER_TYPENAME_P (fn_name))
+       {
+         tree return_type = TREE_TYPE (TREE_TYPE (fn_fields));
+
+         if (typecode_p (return_type, INTEGER_TYPE)
+             || typecode_p (return_type, BOOLEAN_TYPE)
+             || typecode_p (return_type, ENUMERAL_TYPE))
+           TYPE_HAS_INT_CONVERSION (t) = 1;
+         else if (typecode_p (return_type, REAL_TYPE))
+           TYPE_HAS_REAL_CONVERSION (t) = 1;
+
+         grow_method (fn_fields, &method_vec);
+       }
+    }
+
+  fn_fields = save_fn_fields;
+  for (; fn_fields; fn_fields = TREE_CHAIN (fn_fields))
+    {
+      tree fn_name = DECL_NAME (fn_fields);
+
+      if (fn_name == ctor_name || IDENTIFIER_TYPENAME_P (fn_name))
+       continue;
+
+      if (fn_name == ansi_opname[(int) MODIFY_EXPR])
        {
          tree parmtype = TREE_VALUE (FUNCTION_ARG_CHAIN (fn_fields));
 
-         if (TREE_CODE (parmtype) == REFERENCE_TYPE
-             && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == t)
+         if (copy_assignment_arg_p (parmtype, DECL_VIRTUAL_P (fn_fields)))
            {
              if (TREE_PROTECTED (fn_fields))
                TYPE_HAS_NONPUBLIC_ASSIGN_REF (t) = 1;
@@ -2412,246 +1981,976 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
            }
        }
 
-      /* Constructors are handled easily in search routines.
-        Besides, we know we won't find any, so do not bother looking.  */
-      if (fn_name == name && TREE_VEC_ELT (method_vec, 0) == 0)
-       TREE_VEC_ELT (method_vec, 0) = fn_fields;
+      grow_method (fn_fields, &method_vec);
+    }
+
+  TREE_VEC_LENGTH (method_vec) = (tree *)obstack_next_free (&class_obstack)
+    - (&TREE_VEC_ELT (method_vec, 0));
+  obstack_finish (&class_obstack);
+  CLASSTYPE_METHOD_VEC (t) = method_vec;
+
+  if (nonprivate_method == 0
+      && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
+      && DECL_FRIENDLIST (TYPE_MAIN_DECL (t)) == NULL_TREE)
+    {
+      tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
+      for (i = 0; i < n_baseclasses; i++)
+       if (TREE_VIA_PUBLIC (TREE_VEC_ELT (binfos, i))
+           || TREE_VIA_PROTECTED (TREE_VEC_ELT (binfos, i)))
+         {
+           nonprivate_method = 1;
+           break;
+         }
+      if (nonprivate_method == 0)
+       cp_warning ("all member functions in class `%T' are private", t);
+    }
+
+  /* Warn if all destructors are private (in which case this class is
+     effectively unusable.  */
+  if (TYPE_HAS_DESTRUCTOR (t))
+    {
+      tree dtor = TREE_VEC_ELT (method_vec, 1);
+
+      /* Wild parse errors can cause this to happen.  */
+      if (dtor == NULL_TREE)
+       TYPE_HAS_DESTRUCTOR (t) = 0;
+      else if (TREE_PRIVATE (dtor)
+              && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
+              && DECL_FRIENDLIST (TYPE_MAIN_DECL (t)) == NULL_TREE
+              && warn_ctor_dtor_privacy)
+       cp_warning ("`%#T' only defines a private destructor and has no friends",
+                   t);
+    }
+
+  /* Now for each member function (except for constructors and
+     destructors), compute where member functions of the same
+     name reside in base classes.  */
+  if (n_baseclasses != 0
+      && TREE_VEC_LENGTH (method_vec) > 2)
+    {
+      int len = TREE_VEC_LENGTH (method_vec);
+      tree baselink_vec = make_tree_vec (len);
+      int any_links = 0;
+      tree baselink_binfo = build_tree_list (NULL_TREE, TYPE_BINFO (t));
+
+      for (i = 2; i < len; i++)
+       {
+         TREE_VEC_ELT (baselink_vec, i)
+           = get_baselinks (baselink_binfo, t, DECL_NAME (TREE_VEC_ELT (method_vec, i)));
+         if (TREE_VEC_ELT (baselink_vec, i) != 0)
+           any_links = 1;
+       }
+      if (any_links != 0)
+       CLASSTYPE_BASELINK_VEC (t) = baselink_vec;
+      else
+       obstack_free (current_obstack, baselink_vec);
+    }
+
+  return method_vec;
+}
+
+/* Emit error when a duplicate definition of a type is seen.  Patch up.  */
+
+void
+duplicate_tag_error (t)
+     tree t;
+{
+  cp_error ("redefinition of `%#T'", t);
+  cp_error_at ("previous definition here", t);
+
+  /* Pretend we haven't defined this type.  */
+
+  /* All of the component_decl's were TREE_CHAINed together in the parser.
+     finish_struct_methods walks these chains and assembles all methods with
+     the same base name into DECL_CHAINs. Now we don't need the parser chains
+     anymore, so we unravel them.  */
+
+  /* This used to be in finish_struct, but it turns out that the
+     TREE_CHAIN is used by dbxout_type_methods and perhaps some other
+     things...  */
+  if (CLASSTYPE_METHOD_VEC (t)) 
+    {
+      tree method_vec = CLASSTYPE_METHOD_VEC (t);
+      int i, len  = TREE_VEC_LENGTH (method_vec);
+      for (i = 0; i < len; i++)
+       {
+         tree unchain = TREE_VEC_ELT (method_vec, i);
+         while (unchain != NULL_TREE) 
+           {
+             TREE_CHAIN (unchain) = NULL_TREE;
+             unchain = DECL_CHAIN (unchain);
+           }
+       }
+    }
+
+  if (TYPE_LANG_SPECIFIC (t))
+    {
+      tree as_list = CLASSTYPE_AS_LIST (t);
+      tree binfo = TYPE_BINFO (t);
+      tree binfo_as_list = CLASSTYPE_BINFO_AS_LIST (t);
+      int interface_only = CLASSTYPE_INTERFACE_ONLY (t);
+      int interface_unknown = CLASSTYPE_INTERFACE_UNKNOWN (t);
+
+      bzero ((char *) TYPE_LANG_SPECIFIC (t), sizeof (struct lang_type));
+      BINFO_BASETYPES(binfo) = NULL_TREE;
+
+      CLASSTYPE_AS_LIST (t) = as_list;
+      TYPE_BINFO (t) = binfo;
+      CLASSTYPE_BINFO_AS_LIST (t) = binfo_as_list;
+      CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+      SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
+      CLASSTYPE_VBASE_SIZE (t) = integer_zero_node;
+      TYPE_REDEFINED (t) = 1;
+    }
+  TYPE_SIZE (t) = NULL_TREE;
+  TYPE_MODE (t) = VOIDmode;
+  TYPE_FIELDS (t) = NULL_TREE;
+  TYPE_METHODS (t) = NULL_TREE;
+  TYPE_VFIELD (t) = NULL_TREE;
+  TYPE_CONTEXT (t) = NULL_TREE;
+}
+
+/* finish up all new vtables.  */
+
+static void
+finish_vtbls (binfo, do_self, t)
+     tree binfo;
+     int do_self;
+     tree t;
+{
+  tree binfos = BINFO_BASETYPES (binfo);
+  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+  /* Should we use something besides CLASSTYPE_VFIELDS? */
+  if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+    {
+      if (BINFO_NEW_VTABLE_MARKED (binfo))
+       {
+         tree decl, context;
+
+         decl = BINFO_VTABLE (binfo);
+         context = DECL_CONTEXT (decl);
+         DECL_CONTEXT (decl) = 0;
+         if (write_virtuals >= 0
+             && DECL_INITIAL (decl) != BINFO_VIRTUALS (binfo))
+           DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE,
+                                           BINFO_VIRTUALS (binfo));
+         cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0, 0);
+         DECL_CONTEXT (decl) = context;
+       }
+      CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
+    }
+
+  for (i = 0; i < n_baselinks; 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))
+       {
+         base_binfo = binfo_member (BINFO_TYPE (base_binfo), CLASSTYPE_VBASECLASSES (t));
+       }
+      finish_vtbls (base_binfo, is_not_base_vtable, t);
+    }
+}
+
+/* True if we should override the given BASE_FNDECL with the given
+   FNDECL.  */
+
+static int
+overrides (fndecl, base_fndecl)
+     tree fndecl, base_fndecl;
+{
+  /* Destructors have special names.  */
+  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl)) &&
+      DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+    return 1;
+  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl)) ||
+      DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+    return 0;
+  if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
+    {
+      tree types, base_types;
+#if 0
+      retypes = TREE_TYPE (TREE_TYPE (fndecl));
+      base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
+#endif
+      types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+      base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
+      if ((TYPE_READONLY (TREE_TYPE (TREE_VALUE (base_types)))
+          == TYPE_READONLY (TREE_TYPE (TREE_VALUE (types))))
+         && compparms (TREE_CHAIN (base_types), TREE_CHAIN (types), 3))
+       return 1;
+    }
+  return 0;
+}
+
+static tree
+get_class_offset_1 (parent, binfo, context, t, fndecl)
+     tree parent, binfo, context, t, fndecl;
+{
+  tree binfos = BINFO_BASETYPES (binfo);
+  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  tree rval = NULL_TREE;
+
+  if (binfo == parent)
+    return error_mark_node;
+
+  for (i = 0; i < n_baselinks; i++)
+    {
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+      tree nrval;
+
+      if (TREE_VIA_VIRTUAL (base_binfo))
+       base_binfo = binfo_member (BINFO_TYPE (base_binfo),
+                                  CLASSTYPE_VBASECLASSES (t));
+      nrval = get_class_offset_1 (parent, base_binfo, context, t, fndecl);
+      /* See if we have a new value */
+      if (nrval && (nrval != error_mark_node || rval==0))
+       {
+         /* Only compare if we have two offsets */
+         if (rval && rval != error_mark_node
+             && ! tree_int_cst_equal (nrval, rval))
+           {
+             /* Only give error if the two offsets are different */
+             error ("every virtual function must have a unique final overrider");
+             cp_error ("  found two (or more) `%T' class subobjects in `%T'", context, t);
+             cp_error ("  with virtual `%D' from virtual base class", fndecl);
+             return rval;
+           }
+         rval = nrval;
+       }
+       
+      if (rval && BINFO_TYPE (binfo) == context)
+       {
+         my_friendly_assert (rval == error_mark_node
+                             || tree_int_cst_equal (rval, BINFO_OFFSET (binfo)), 999);
+         rval = BINFO_OFFSET (binfo);
+       }
+    }
+  return rval;
+}
+
+/* Get the offset to the CONTEXT subobject that is related to the
+   given BINFO.  */
+
+static tree
+get_class_offset (context, t, binfo, fndecl)
+     tree context, t, binfo, fndecl;
+{
+  tree first_binfo = binfo;
+  tree offset;
+  int i;
+
+  if (context == t)
+    return integer_zero_node;
+
+  if (BINFO_TYPE (binfo) == context)
+    return BINFO_OFFSET (binfo);
+
+  /* Check less derived binfos first.  */
+  while (BINFO_BASETYPES (binfo)
+        && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
+    {
+      tree binfos = BINFO_BASETYPES (binfo);
+      binfo = TREE_VEC_ELT (binfos, i);
+      if (BINFO_TYPE (binfo) == context)
+       return BINFO_OFFSET (binfo);
+    }
+
+  /* Ok, not found in the less derived binfos, now check the more
+     derived binfos.  */
+  offset = get_class_offset_1 (first_binfo, TYPE_BINFO (t), context, t, fndecl);
+  if (offset==0 || TREE_CODE (offset) != INTEGER_CST)
+    my_friendly_abort (999);   /* we have to find it.  */
+  return offset;
+}
+
+/* Skip RTTI information at the front of the virtual list.  */
+
+unsigned HOST_WIDE_INT
+skip_rtti_stuff (virtuals)
+     tree *virtuals;
+{
+  int n;
+
+  n = 0;
+  if (*virtuals)
+    {
+      /* We always reserve a slot for the offset/tdesc entry.  */
+      ++n;
+      *virtuals = TREE_CHAIN (*virtuals);
+    }
+  if (flag_vtable_thunks && *virtuals)
+    {
+      /* The second slot is reserved for the tdesc pointer when thunks
+         are used.  */
+      ++n;
+      *virtuals = TREE_CHAIN (*virtuals);
+    }
+  return n;
+}
+
+static void
+modify_one_vtable (binfo, t, fndecl, pfn)
+     tree binfo, t, fndecl, pfn;
+{
+  tree virtuals = BINFO_VIRTUALS (binfo);
+  unsigned HOST_WIDE_INT n;
+  
+  /* update rtti entry */
+  if (flag_rtti)
+    {
+      if (binfo == TYPE_BINFO (t))
+       {
+         if (! BINFO_NEW_VTABLE_MARKED (binfo))
+           build_vtable (TYPE_BINFO (DECL_CONTEXT (CLASSTYPE_VFIELD (t))), t);
+       }
       else
        {
-         testp = &TREE_VEC_ELT (method_vec, 0);
-         if (*testp == NULL_TREE)
-           testp++;
-         while (((HOST_WIDE_INT) testp
-                 < (HOST_WIDE_INT) obstack_next_free (&class_obstack))
-                && DECL_NAME (*testp) != fn_name)
-           testp++;
-         if ((HOST_WIDE_INT) testp
-             < (HOST_WIDE_INT) obstack_next_free (&class_obstack))
+         if (! BINFO_NEW_VTABLE_MARKED (binfo))
+           prepare_fresh_vtable (binfo, t);
+       }
+    }
+  if (fndecl == NULL_TREE)
+    return;
+
+  n = skip_rtti_stuff (&virtuals);
+
+  while (virtuals)
+    {
+      tree current_fndecl = TREE_VALUE (virtuals);
+      current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl);
+      current_fndecl = TREE_OPERAND (current_fndecl, 0);
+      if (current_fndecl && overrides (fndecl, current_fndecl))
+       {
+         tree base_offset, offset;
+         tree context = DECL_CLASS_CONTEXT (fndecl);
+         tree vfield = CLASSTYPE_VFIELD (t);
+         tree this_offset;
+
+         offset = get_class_offset (context, t, binfo, fndecl);
+
+         /* Find the right offset for the this pointer based on the
+            base class we just found.  We have to take into
+            consideration the virtual base class pointers that we
+            stick in before the virtual function table pointer.
+
+            Also, we want just the delta between the most base class
+            that we derived this vfield from and us.  */
+         base_offset = size_binop (PLUS_EXPR,
+                                   get_derived_offset (binfo, DECL_CONTEXT (current_fndecl)),
+                                   BINFO_OFFSET (binfo));
+         this_offset = size_binop (MINUS_EXPR, offset, base_offset);
+
+         /* Make sure we can modify the derived association with immunity.  */
+         if (TREE_USED (binfo))
+           my_friendly_assert (0, 999);
+
+         if (binfo == TYPE_BINFO (t))
+           {
+             /* In this case, it is *type*'s vtable we are modifying.
+                We start with the approximation that it's vtable is that
+                of the immediate base class.  */
+             if (! BINFO_NEW_VTABLE_MARKED (binfo))
+               build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
+           }
+         else
+           {
+             /* This is our very own copy of `basetype' to play with.
+                Later, we will fill in all the virtual functions
+                that override the virtual functions in these base classes
+                which are not defined by the current type.  */
+             if (! BINFO_NEW_VTABLE_MARKED (binfo))
+               prepare_fresh_vtable (binfo, t);
+           }
+
+#ifdef NOTQUITE
+         cp_warning ("in %D", DECL_NAME (BINFO_VTABLE (binfo)));
+#endif
+         modify_vtable_entry (get_vtable_entry_n (BINFO_VIRTUALS (binfo), n),
+                              build_vtable_entry (this_offset, pfn),
+                              fndecl);
+       }
+      ++n;
+      virtuals = TREE_CHAIN (virtuals);
+    }
+}
+
+/* These are the ones that are not through virtual base classes.  */
+
+static void
+modify_all_direct_vtables (binfo, do_self, t, fndecl, pfn)
+     tree binfo;
+     int do_self;
+     tree t, fndecl, pfn;
+{
+  tree binfos = BINFO_BASETYPES (binfo);
+  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+  /* Should we use something besides CLASSTYPE_VFIELDS? */
+  if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+    {
+      modify_one_vtable (binfo, t, fndecl, pfn);
+    }
+
+  for (i = 0; i < n_baselinks; 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))
+       modify_all_direct_vtables (base_binfo, is_not_base_vtable, t, fndecl, pfn);
+    }
+}
+
+/* Fixup all the delta entries in this one vtable that need updating.  */
+
+static void
+fixup_vtable_deltas1 (binfo, t)
+     tree binfo, t;
+{
+  tree virtuals = BINFO_VIRTUALS (binfo);
+  unsigned HOST_WIDE_INT n;
+  
+  n = skip_rtti_stuff (&virtuals);
+
+  while (virtuals)
+    {
+      tree fndecl = TREE_VALUE (virtuals);
+      tree pfn = FNADDR_FROM_VTABLE_ENTRY (fndecl);
+      tree delta = DELTA_FROM_VTABLE_ENTRY (fndecl);
+      fndecl = TREE_OPERAND (pfn, 0);
+      if (fndecl)
+       {
+         tree base_offset, offset;
+         tree context = DECL_CLASS_CONTEXT (fndecl);
+         tree vfield = CLASSTYPE_VFIELD (t);
+         tree this_offset;
+
+         offset = get_class_offset (context, t, binfo, fndecl);
+
+         /* Find the right offset for the this pointer based on the
+            base class we just found.  We have to take into
+            consideration the virtual base class pointers that we
+            stick in before the virtual function table pointer.
+
+            Also, we want just the delta between the most base class
+            that we derived this vfield from and us.  */
+         base_offset = size_binop (PLUS_EXPR,
+                                   get_derived_offset (binfo, DECL_CONTEXT (fndecl)),
+                                   BINFO_OFFSET (binfo));
+         this_offset = size_binop (MINUS_EXPR, offset, base_offset);
+
+         if (! tree_int_cst_equal (this_offset, delta))
            {
-             tree x, prev_x;
+             /* Make sure we can modify the derived association with immunity.  */
+             if (TREE_USED (binfo))
+               my_friendly_assert (0, 999);
 
-             for (x = *testp; x; x = DECL_CHAIN (x))
+             if (binfo == TYPE_BINFO (t))
                {
-                 if (DECL_NAME (fn_fields) == ansi_opname[(int) DELETE_EXPR])
-                   {
-                     /* ANSI C++ June 5 1992 WP 12.5.5.1 */
-                     cp_error_at ("`%D' overloaded", fn_fields);
-                     cp_error_at ("previous declaration as `%D' here", x);
-                   }
-                 if (DECL_ASSEMBLER_NAME (fn_fields)==DECL_ASSEMBLER_NAME (x))
-                   {
-                     /* We complain about multiple destructors on sight,
-                        so we do not repeat the warning here.  Friend-friend
-                        ambiguities are warned about outside this loop.  */
-                     if (!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fn_fields)))
-                       cp_error_at ("ambiguous method `%#D' in structure",
-                                    fn_fields);
-                     break;
-                   }
-                 prev_x = x;
+                 /* In this case, it is *type*'s vtable we are modifying.
+                    We start with the approximation that it's vtable is that
+                    of the immediate base class.  */
+                 if (! BINFO_NEW_VTABLE_MARKED (binfo))
+                   build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
                }
-             if (x == 0)
+             else
                {
-                 if (*testp)
-                   DECL_CHAIN (prev_x) = fn_fields;
-                 else
-                   *testp = fn_fields;
+                 /* This is our very own copy of `basetype' to play with.
+                    Later, we will fill in all the virtual functions
+                    that override the virtual functions in these base classes
+                    which are not defined by the current type.  */
+                 if (! BINFO_NEW_VTABLE_MARKED (binfo))
+                   prepare_fresh_vtable (binfo, t);
                }
+
+             modify_vtable_entry (get_vtable_entry_n (BINFO_VIRTUALS (binfo), n),
+                                  build_vtable_entry (this_offset, pfn),
+                                  fndecl);
            }
-         else
+       }
+      ++n;
+      virtuals = TREE_CHAIN (virtuals);
+    }
+}
+
+/* Fixup all the delta entries in all the direct vtables that need updating.
+   This happens when we have non-overridden virtual functions from a
+   virtual base class, that are at a different offset, in the new
+   hierarchy, because the layout of the virtual bases has changed.  */
+
+static void
+fixup_vtable_deltas (binfo, init_self, t)
+     tree binfo;
+     int init_self;
+     tree t;
+{
+  tree binfos = BINFO_BASETYPES (binfo);
+  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+  for (i = 0; i < n_baselinks; 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))
+       fixup_vtable_deltas (base_binfo, is_not_base_vtable, t);
+    }
+  /* Should we use something besides CLASSTYPE_VFIELDS? */
+  if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+    {
+      fixup_vtable_deltas1 (binfo, t);
+    }
+}
+
+/* These are the ones that are through virtual base classes.  */
+
+static void
+modify_all_indirect_vtables (binfo, do_self, via_virtual, t, fndecl, pfn)
+     tree binfo;
+     int do_self, via_virtual;
+     tree t, fndecl, pfn;
+{
+  tree binfos = BINFO_BASETYPES (binfo);
+  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+  /* Should we use something besides CLASSTYPE_VFIELDS? */
+  if (do_self && via_virtual && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+    {
+      modify_one_vtable (binfo, t, fndecl, pfn);
+    }
+
+  for (i = 0; i < n_baselinks; 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))
+       {
+         via_virtual = 1;
+         base_binfo = binfo_member (BINFO_TYPE (base_binfo), CLASSTYPE_VBASECLASSES (t));
+       }
+      modify_all_indirect_vtables (base_binfo, is_not_base_vtable, via_virtual, t, fndecl, pfn);
+    }
+}
+
+static void
+modify_all_vtables (t, fndecl, vfn)
+     tree t, fndecl, vfn;
+{
+  /* Do these first, so that we will make use of any non-virtual class's
+     vtable, over a virtual classes vtable.  */
+  modify_all_direct_vtables (TYPE_BINFO (t), 1, t, fndecl, vfn);
+  if (TYPE_USES_VIRTUAL_BASECLASSES (t))
+    modify_all_indirect_vtables (TYPE_BINFO (t), 1, 0, t, fndecl, vfn);
+}
+
+/* Here, we already know that they match in every respect.
+   All we have to check is where they had their declarations.  */
+
+static int 
+strictly_overrides (fndecl1, fndecl2)
+     tree fndecl1, fndecl2;
+{
+  int distance = get_base_distance (DECL_CLASS_CONTEXT (fndecl2),
+                                   DECL_CLASS_CONTEXT (fndecl1),
+                                   0, (tree *)0);
+  if (distance == -2 || distance > 0)
+    return 1;
+  return 0;
+}
+
+/* Merge overrides for one vtable.
+   If we want to merge in same function, we are fine.
+   else
+     if one has a DECL_CLASS_CONTEXT that is a parent of the
+       other, than choose the more derived one
+     else
+       potentially ill-formed (see 10.3 [class.virtual])
+       we have to check later to see if there was an
+       override in this class.  If there was ok, if not
+       then it is ill-formed.  (mrs)
+
+   We take special care to reuse a vtable, if we can.  */
+
+static void
+override_one_vtable (binfo, old, t)
+     tree binfo, old, t;
+{
+  tree virtuals = BINFO_VIRTUALS (binfo);
+  tree old_virtuals = BINFO_VIRTUALS (old);
+  enum { REUSE_NEW, REUSE_OLD, UNDECIDED, NEITHER } choose = UNDECIDED;
+
+  /* If we have already committed to modifying it, then don't try and
+     reuse another vtable.  */
+  if (BINFO_NEW_VTABLE_MARKED (binfo))
+    choose = NEITHER;
+
+  skip_rtti_stuff (&virtuals);
+  skip_rtti_stuff (&old_virtuals);
+
+  while (virtuals)
+    {
+      tree fndecl = TREE_VALUE (virtuals);
+      tree old_fndecl = TREE_VALUE (old_virtuals);
+      fndecl = FNADDR_FROM_VTABLE_ENTRY (fndecl);
+      old_fndecl = FNADDR_FROM_VTABLE_ENTRY (old_fndecl);
+      fndecl = TREE_OPERAND (fndecl, 0);
+      old_fndecl = TREE_OPERAND (old_fndecl, 0);
+      /* First check to see if they are the same.  */
+      if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (old_fndecl))
+       {
+         /* No need to do anything.  */
+       }
+      else if (strictly_overrides (fndecl, old_fndecl))
+       {
+         if (choose == UNDECIDED)
+           choose = REUSE_NEW;
+         else if (choose == REUSE_OLD)
            {
-             obstack_ptr_grow (&class_obstack, fn_fields);
-             method_vec = (tree)obstack_base (&class_obstack);
+             choose = NEITHER;
+             if (! BINFO_NEW_VTABLE_MARKED (binfo))
+               {
+                 prepare_fresh_vtable (binfo, t);
+                 override_one_vtable (binfo, old, t);
+                 return;
+               }
            }
        }
-      fn_fields = nextp;
+      else if (strictly_overrides (old_fndecl, fndecl))
+       {
+         if (choose == UNDECIDED)
+           choose = REUSE_OLD;
+         else if (choose == REUSE_NEW)
+           {
+             choose = NEITHER;
+             if (! BINFO_NEW_VTABLE_MARKED (binfo))
+               {
+                 prepare_fresh_vtable (binfo, t);
+                 override_one_vtable (binfo, old, t);
+                 return;
+               }
+             TREE_VALUE (virtuals) = TREE_VALUE (old_virtuals);
+           }
+         else if (choose == NEITHER)
+           {
+             TREE_VALUE (virtuals) = TREE_VALUE (old_virtuals);
+           }  
+       }
+      else
+       {
+         choose = NEITHER;
+         if (! BINFO_NEW_VTABLE_MARKED (binfo))
+           {
+             prepare_fresh_vtable (binfo, t);
+             override_one_vtable (binfo, old, t);
+             return;
+           }
+         {
+           /* This MUST be overridden, or the class is ill-formed.  */
+           /* For now, we just make it abstract.  */
+           tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
+           tree vfn;
+
+           fndecl = copy_node (fndecl);
+           copy_lang_decl (fndecl);
+           DECL_ABSTRACT_VIRTUAL_P (fndecl) = 1;
+           /* Make sure we search for it later.  */
+           if (! CLASSTYPE_ABSTRACT_VIRTUALS (t))
+             CLASSTYPE_ABSTRACT_VIRTUALS (t) = error_mark_node;
+
+           vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
+           TREE_CONSTANT (vfn) = 1;
+           
+           /* We can use integer_zero_node, as we will will core dump
+              if this is used anyway.  */
+           TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, vfn);
+         }
+       }
+      virtuals = TREE_CHAIN (virtuals);
+      old_virtuals = TREE_CHAIN (old_virtuals);
     }
 
-  TREE_VEC_LENGTH (method_vec) = (tree *)obstack_next_free (&class_obstack)
-    - (&TREE_VEC_ELT (method_vec, 0));
-  obstack_finish (&class_obstack);
-  CLASSTYPE_METHOD_VEC (t) = method_vec;
+  /* Let's reuse the old vtable.  */
+  if (choose == REUSE_OLD)
+    {
+      BINFO_VTABLE (binfo) = BINFO_VTABLE (old);
+      BINFO_VIRTUALS (binfo) = BINFO_VIRTUALS (old);
+    }
+}
 
-  if (nonprivate_method == 0
-      && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
-      && DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE)
+/* Merge in overrides for virtual bases.
+   BINFO is the hierarchy we want to modify, and OLD has the potential
+   overrides.  */
+
+static void
+merge_overrides (binfo, old, do_self, t)
+     tree binfo, old;
+     int do_self;
+     tree t;
+{
+  tree binfos = BINFO_BASETYPES (binfo);
+  tree old_binfos = BINFO_BASETYPES (old);
+  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+  /* Should we use something besides CLASSTYPE_VFIELDS? */
+  if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
     {
-      tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
-      for (i = 0; i < n_baseclasses; i++)
-       if (TREE_VIA_PUBLIC (TREE_VEC_ELT (binfos, i))
-           || TREE_VIA_PROTECTED (TREE_VEC_ELT (binfos, i)))
-         {
-           nonprivate_method = 1;
-           break;
-         }
-      if (nonprivate_method == 0)
-       cp_warning ("all member functions in class `%T' are private", t);
+      override_one_vtable (binfo, old, t);
     }
 
-  /* If there are constructors (and destructors), they are at the
-     front.  Place destructors at very front.  Also warn if all
-     constructors and/or destructors are private (in which case this
-     class is effectively unusable.  */
-  if (TYPE_HAS_DESTRUCTOR (t))
+  for (i = 0; i < n_baselinks; i++)
     {
-      tree dtor, prev;
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+      tree old_base_binfo = TREE_VEC_ELT (old_binfos, i);
+      int is_not_base_vtable =
+       i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+      if (! TREE_VIA_VIRTUAL (base_binfo))
+       merge_overrides (base_binfo, old_base_binfo, is_not_base_vtable, t);
+    }
+}
 
-      for (dtor = TREE_VEC_ELT (method_vec, 0);
-          dtor;
-          prev = dtor, dtor = DECL_CHAIN (dtor))
-       {
-         if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (dtor)))
-           {
-             if (TREE_PRIVATE (dtor)
-                 && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
-                 && DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE
-                 && warn_ctor_dtor_privacy)
-               warning ("class `%s' only defines a private destructor and has no friends",
-                        TYPE_NAME_STRING (t));
-             break;
-           }
-       }
+/* Get the base virtual function declarations in T that are either
+   overridden or hidden by FNDECL as a list.  We set TREE_PURPOSE with
+   the overrider/hider.  */
 
-      /* Wild parse errors can cause this to happen.  */
-      if (dtor == NULL_TREE)
-       TYPE_HAS_DESTRUCTOR (t) = 0;
-      else if (dtor != TREE_VEC_ELT (method_vec, 0))
-       {
-         DECL_CHAIN (prev) = DECL_CHAIN (dtor);
-         DECL_CHAIN (dtor) = TREE_VEC_ELT (method_vec, 0);
-         TREE_VEC_ELT (method_vec, 0) = dtor;
-       }
+tree
+get_basefndecls (fndecl, t)
+     tree fndecl, t;
+{
+  tree methods = TYPE_METHODS (t);
+  tree base_fndecls = NULL_TREE;
+  tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
+  int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+  while (methods)
+    {
+      if (TREE_CODE (methods) == FUNCTION_DECL
+         && DECL_VINDEX (methods) != NULL_TREE
+         && DECL_NAME (fndecl) == DECL_NAME (methods))
+       base_fndecls = temp_tree_cons (fndecl, methods, base_fndecls);
+
+      methods = TREE_CHAIN (methods);
     }
 
-  /* Now for each member function (except for constructors and
-     destructors), compute where member functions of the same
-     name reside in base classes.  */
-  if (n_baseclasses != 0
-      && TREE_VEC_LENGTH (method_vec) > 1)
+  if (base_fndecls)
+    return base_fndecls;
+
+  for (i = 0; i < n_baseclasses; i++)
     {
-      int len = TREE_VEC_LENGTH (method_vec);
-      tree baselink_vec = make_tree_vec (len);
-      int any_links = 0;
-      tree baselink_binfo = build_tree_list (NULL_TREE, TYPE_BINFO (t));
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+      tree basetype = BINFO_TYPE (base_binfo);
 
-      for (i = 1; i < len; i++)
-       {
-         TREE_VEC_ELT (baselink_vec, i)
-           = get_baselinks (baselink_binfo, t, DECL_NAME (TREE_VEC_ELT (method_vec, i)));
-         if (TREE_VEC_ELT (baselink_vec, i) != 0)
-           any_links = 1;
-       }
-      if (any_links != 0)
-       CLASSTYPE_BASELINK_VEC (t) = baselink_vec;
-      else
-       obstack_free (current_obstack, baselink_vec);
+      base_fndecls = chainon (get_basefndecls (fndecl, basetype),
+                             base_fndecls);
     }
 
-  /* Now add the methods to the TYPE_METHODS of T, arranged in a chain.  */
-  {
-    tree x, last_x = NULL_TREE;
-    int limit = TREE_VEC_LENGTH (method_vec);
+  return base_fndecls;
+}
 
-    for (i = 1; i < limit; i++)
-      {
-       for (x = TREE_VEC_ELT (method_vec, i); x; x = DECL_CHAIN (x))
-         {
-           if (last_x != NULL_TREE)
-             TREE_CHAIN (last_x) = x;
-           last_x = x;
-         }
-      }
+/* Mark the functions that have been hidden with their overriders.
+   Since we start out with all functions already marked with a hider,
+   no need to mark functions that are just hidden.  */
 
-    /* Put ctors and dtors at the front of the list.  */
-    x = TREE_VEC_ELT (method_vec, 0);
-    if (x)
-      {
-       while (DECL_CHAIN (x))
-         {
-           /* Let's avoid being circular about this.  */
-           if (x == DECL_CHAIN (x))
-             break;
-           TREE_CHAIN (x) = DECL_CHAIN (x);
-           x = DECL_CHAIN (x);
-         }
-       if (TREE_VEC_LENGTH (method_vec) > 1)
-         TREE_CHAIN (x) = TREE_VEC_ELT (method_vec, 1);
-       else
-         TREE_CHAIN (x) = NULL_TREE;
-      }
-  }
+static void
+mark_overriders (fndecl, base_fndecls)
+     tree fndecl, base_fndecls;
+{
+  while (base_fndecls)
+    {
+      if (overrides (TREE_VALUE (base_fndecls), fndecl))
+       TREE_PURPOSE (base_fndecls) = fndecl;
 
-#if 0
-  TYPE_METHODS (t) = TREE_VEC_ELT (method_vec, 0)
-    ? TREE_VEC_ELT (method_vec, 0) : TREE_VEC_ELT (method_vec, 1);
-#else
-  TYPE_METHODS (t) = method_vec;
-#endif
+      base_fndecls = TREE_CHAIN (base_fndecls);
+    }
+}
 
-  return method_vec;
+/* If this declaration supersedes the declaration of
+   a method declared virtual in the base class, then
+   mark this field as being virtual as well.  */
+
+static void
+check_for_override (decl, ctype)
+     tree decl, ctype;
+{
+  tree binfos = BINFO_BASETYPES (TYPE_BINFO (ctype));
+  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  int virtualp = DECL_VIRTUAL_P (decl);
+
+  for (i = 0; i < n_baselinks; i++)
+    {
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+      if (TYPE_VIRTUAL_P (BINFO_TYPE (base_binfo))
+         || flag_all_virtual == 1)
+       {
+         tree tmp = get_matching_virtual
+           (base_binfo, decl,
+            DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)));
+         if (tmp)
+           {
+             /* If this function overrides some virtual in some base
+                class, then the function itself is also necessarily
+                virtual, even if the user didn't explicitly say so.  */
+             DECL_VIRTUAL_P (decl) = 1;
+
+             /* The TMP we really want is the one from the deepest
+                baseclass on this path, taking care not to
+                duplicate if we have already found it (via another
+                path to its virtual baseclass.  */
+             if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
+               {
+                 cp_error_at ("method `%D' may not be declared static",
+                              decl);
+                 cp_error_at ("(since `%D' declared virtual in base class.)",
+                              tmp);
+                 break;
+               }
+             virtualp = 1;
+
+#if 0 /* The signature of an overriding function is not changed.  */
+             {
+               /* The argument types may have changed...  */
+               tree type = TREE_TYPE (decl);
+               tree argtypes = TYPE_ARG_TYPES (type);
+               tree base_variant = TREE_TYPE (TREE_VALUE (argtypes));
+               tree raises = TYPE_RAISES_EXCEPTIONS (type);
+
+               argtypes = commonparms (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (tmp))),
+                                       TREE_CHAIN (argtypes));
+               /* But the return type has not.  */
+               type = build_cplus_method_type (base_variant, TREE_TYPE (type), argtypes);
+               if (raises)
+                 type = build_exception_variant (type, raises);
+               TREE_TYPE (decl) = type;
+             }
+#endif
+             DECL_VINDEX (decl)
+               = tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl));
+             break;
+           }
+       }
+    }
+  if (virtualp)
+    {
+      if (DECL_VINDEX (decl) == NULL_TREE)
+       DECL_VINDEX (decl) = error_mark_node;
+      IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
+    }
 }
 
-/* Emit error when a duplicate definition of a type is seen.  Patch up. */
+/* Warn about hidden virtual functions that are not overridden in t.
+   We know that constructors and destructors don't apply.  */
 
 void
-duplicate_tag_error (t)
+warn_hidden (t)
      tree t;
 {
-  cp_error ("redefinition of `%#T'", t);
-
-  /* Pretend we haven't defined this type.  */
+  tree method_vec = CLASSTYPE_METHOD_VEC (t);
+  int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
+  int i;
 
-  /* All of the component_decl's were TREE_CHAINed together in the parser.
-     finish_struct_methods walks these chains and assembles all methods with
-     the same base name into DECL_CHAINs. Now we don't need the parser chains
-     anymore, so we unravel them.
-   */
-  /*
-   * This used to be in finish_struct, but it turns out that the
-   * TREE_CHAIN is used by dbxout_type_methods and perhaps some other things...
-   */
-  if (CLASSTYPE_METHOD_VEC(t)) 
+  /* We go through each separately named virtual function.  */
+  for (i = 2; i < n_methods; ++i)
     {
-      tree tv = CLASSTYPE_METHOD_VEC(t);
-      int i, len  = TREE_VEC_LENGTH (tv);
-      for (i = 0; i < len; i++)
+      tree fndecl = TREE_VEC_ELT (method_vec, i);
+
+      tree base_fndecls = NULL_TREE;
+      tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
+      int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+      if (DECL_VINDEX (fndecl) == NULL_TREE)
+       continue;
+
+      /* First we get a list of all possible functions that might be
+        hidden from each base class.  */
+      for (i = 0; i < n_baseclasses; i++)
        {
-         tree unchain = TREE_VEC_ELT (tv, i);
-         while (unchain != NULL_TREE) 
+         tree base_binfo = TREE_VEC_ELT (binfos, i);
+         tree basetype = BINFO_TYPE (base_binfo);
+
+         base_fndecls = chainon (get_basefndecls (fndecl, basetype),
+                                 base_fndecls);
+       }
+
+      if (TREE_CHAIN (fndecl)
+         && DECL_NAME (TREE_CHAIN (fndecl)) == DECL_NAME (fndecl))
+         fndecl = TREE_CHAIN (fndecl);
+       else
+         fndecl = NULL_TREE;
+
+      /* ...then mark up all the base functions with overriders, preferring
+        overriders to hiders.  */
+      if (base_fndecls)
+       while (fndecl)
+         {
+           mark_overriders (fndecl, base_fndecls);
+           
+           if (TREE_CHAIN (fndecl)
+               && DECL_NAME (TREE_CHAIN (fndecl)) == DECL_NAME (fndecl))
+             fndecl = TREE_CHAIN (fndecl);
+           else
+             fndecl = NULL_TREE;
+         }
+
+      /* Now give a warning for all base functions without overriders,
+        as they are hidden.  */
+      while (base_fndecls)
+       {
+         if (! overrides (TREE_VALUE (base_fndecls),
+                          TREE_PURPOSE (base_fndecls)))
            {
-             TREE_CHAIN (unchain) = NULL_TREE;
-             unchain = DECL_CHAIN(unchain);
+             /* Here we know it is a hider, and no overrider exists.  */
+             cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
+             cp_warning_at ("  by `%D'", TREE_PURPOSE (base_fndecls));
            }
+
+         base_fndecls = TREE_CHAIN (base_fndecls);
        }
     }
+}
 
-  if (TYPE_LANG_SPECIFIC (t))
+/* Check for things that are invalid.  There are probably plenty of other
+   things we should check for also.  */
+
+static void
+finish_struct_anon (t)
+     tree t;
+{
+  tree field;
+  for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
     {
-      tree as_list = CLASSTYPE_AS_LIST (t);
-      tree binfo = TYPE_BINFO (t);
-      tree binfo_as_list = CLASSTYPE_BINFO_AS_LIST (t);
-      int interface_only = CLASSTYPE_INTERFACE_ONLY (t);
-      int interface_unknown = CLASSTYPE_INTERFACE_UNKNOWN (t);
+      if (TREE_STATIC (field))
+       continue;
+      if (TREE_CODE (field) != FIELD_DECL)
+       continue;
 
-      bzero (TYPE_LANG_SPECIFIC (t), sizeof (struct lang_type));
-      BINFO_BASETYPES(binfo) = NULL_TREE;
+      if (DECL_NAME (field) == NULL_TREE
+         && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+       {
+         tree* uelt = &TYPE_FIELDS (TREE_TYPE (field));
+         for (; *uelt; uelt = &TREE_CHAIN (*uelt))
+           {
+             if (TREE_CODE (*uelt) != FIELD_DECL)
+               continue;
 
-      CLASSTYPE_AS_LIST (t) = as_list;
-      TYPE_BINFO (t) = binfo;
-      CLASSTYPE_BINFO_AS_LIST (t) = binfo_as_list;
-      CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
-      SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
-      CLASSTYPE_VBASE_SIZE (t) = integer_zero_node;
-      TYPE_REDEFINED (t) = 1;
+             if (TREE_PRIVATE (*uelt))
+               cp_pedwarn_at ("private member `%#D' in anonymous union",
+                              *uelt);
+             else if (TREE_PROTECTED (*uelt))
+               cp_pedwarn_at ("protected member `%#D' in anonymous union",
+                              *uelt);
+
+             TREE_PRIVATE (*uelt) = TREE_PRIVATE (field);
+             TREE_PROTECTED (*uelt) = TREE_PROTECTED (field);
+           }
+       }
     }
-  TYPE_SIZE (t) = NULL_TREE;
-  TYPE_MODE (t) = VOIDmode;
-  TYPE_FIELDS (t) = NULL_TREE;
-  TYPE_METHODS (t) = NULL_TREE;
-  TYPE_VFIELD (t) = NULL_TREE;
-  TYPE_CONTEXT (t) = NULL_TREE;
 }
 
+extern int interface_only, interface_unknown;
+
 /* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration
    (or C++ class declaration).
 
@@ -2681,6 +2980,8 @@ duplicate_tag_error (t)
    TREE_LIST elements, whose TREE_PURPOSE field tells what access
    the list has, and the TREE_VALUE slot gives the actual fields.
 
+   ATTRIBUTES is the set of decl attributes to be applied, if any.
+
    If flag_all_virtual == 1, then we lay all functions into
    the virtual function table, as though they were declared
    virtual.  Constructors do not lay down in the virtual function table.
@@ -2712,22 +3013,16 @@ duplicate_tag_error (t)
    or otherwise in a type-consistent manner.  */
 
 tree
-finish_struct (t, list_of_fieldlists, warn_anon)
+finish_struct_1 (t, warn_anon)
      tree t;
-     tree list_of_fieldlists;
      int warn_anon;
 {
-  extern int interface_only, interface_unknown;
-  extern tree EHS_type;
-
   int old;
-  int round_up_size = 1;
-
+  tree name = TYPE_IDENTIFIER (t);
   enum tree_code code = TREE_CODE (t);
-  register tree x, last_x, method_vec;
-  int needs_virtual_dtor;
-  tree name = TYPE_NAME (t), fields, fn_fields, tail;
-  enum access_type access;
+  tree fields = TYPE_FIELDS (t);
+  tree fn_fields = TYPE_METHODS (t);
+  tree x, last_x, method_vec;
   int all_virtual;
   int has_virtual;
   int max_has_virtual;
@@ -2737,8 +3032,6 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   tree vfields;
   int cant_have_default_ctor;
   int cant_have_const_ctor;
-  int cant_synth_copy_ctor;
-  int cant_synth_asn_ref;
   int no_const_asn_ref;
 
   /* The index of the first base class which has virtual
@@ -2749,46 +3042,16 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   int any_default_members = 0;
   int const_sans_init = 0;
   int ref_sans_init = 0;
-  int do_mem_init = 0;
   int nonprivate_method = 0;
   tree t_binfo = TYPE_BINFO (t);
-  tree access_decls = 0;
-
-  if (TREE_CODE (name) == TYPE_DECL)
-    {
-#if 0                          /* Maybe later.  -jason  */
-      struct tinst_level *til = tinst_for_decl();
-
-      if (til)
-       {
-         DECL_SOURCE_FILE (name) = til->file;
-         if (DECL_SOURCE_LINE (name))
-           DECL_SOURCE_LINE (name) = til->line;
-       }
-      else
-#endif
-       {
-         extern int lineno;
-         
-         DECL_SOURCE_FILE (name) = input_filename;
-         /* For TYPE_DECL that are not typedefs (those marked with a line
-            number of zero, we don't want to mark them as real typedefs.
-            If this fails one needs to make sure real typedefs have a
-            previous line number, even if it is wrong, that way the below
-            will fill in the right line number.  (mrs) */
-         if (DECL_SOURCE_LINE (name))
-           DECL_SOURCE_LINE (name) = lineno;
-       }
-      name = DECL_NAME (name);
-    }
+  tree access_decls = NULL_TREE;
+  int aggregate = 1;
+  int empty = 1;
+  int has_pointers = 0;
 
-  if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (name))
-    warning ("anonymous class type not used to declare any objects");
+  if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
+    pedwarn ("anonymous class type not used to declare any objects");
 
-#if 0
-  /* This is set here, but it's never actually used anywhere.  (bpk) */
-  leftmost_baseclasses = NULL_TREE;
-#endif
   if (TYPE_SIZE (t))
     {
       if (IS_AGGR_TYPE (t))
@@ -2799,33 +3062,28 @@ finish_struct (t, list_of_fieldlists, warn_anon)
       return t;
     }
 
-  /* Append the fields we need for constructing signature tables.  */
-  if (IS_SIGNATURE (t))
-    append_signature_fields (list_of_fieldlists);
-
   GNU_xref_decl (current_function_decl, t);
 
   /* If this type was previously laid out as a forward reference,
      make sure we lay it out again.  */
 
-  TYPE_SIZE (t) = 0;
+  TYPE_SIZE (t) = NULL_TREE;
   CLASSTYPE_GOT_SEMICOLON (t) = 0;
 
-  /* A signature type will contain the fields of the signature table.
-     Therefore, it's not only an interface.  */
-  if (IS_SIGNATURE (t))
-    {
-      CLASSTYPE_INTERFACE_ONLY (t) = 0;
-      SET_CLASSTYPE_INTERFACE_KNOWN (t);
-    }
-  else
+#if 0
+  /* This is in general too late to do this.  I moved the main case up to
+     left_curly, what else needs to move?  */
+  if (! IS_SIGNATURE (t))
     {
-      CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
-      SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
+      my_friendly_assert (CLASSTYPE_INTERFACE_ONLY (t) == interface_only, 999);
+      my_friendly_assert (CLASSTYPE_INTERFACE_KNOWN (t) == ! interface_unknown, 999);
     }
+#endif
 
-  if (flag_dossier)
+#if 0
+  if (flag_rtti)
     build_t_desc (t, 0);
+#endif
 
   TYPE_BINFO (t) = NULL_TREE;
 
@@ -2849,24 +3107,24 @@ finish_struct (t, list_of_fieldlists, warn_anon)
 
       /* If using multiple inheritance, this may cause variants of our
         basetypes to be used (instead of their canonical forms).  */
-      fields = layout_basetypes (t, BINFO_BASETYPES (t_binfo));
-      last_x = tree_last (fields);
+      tree vf = layout_basetypes (t, BINFO_BASETYPES (t_binfo));
+      last_x = tree_last (vf);
+      fields = chainon (vf, fields);
 
       first_vfn_base_index = finish_base_struct (t, &base_info, t_binfo);
-      /* Remember where we got our vfield from */
+      /* Remember where we got our vfield from */
       CLASSTYPE_VFIELD_PARENT (t) = first_vfn_base_index;
       has_virtual = base_info.has_virtual;
       max_has_virtual = base_info.max_has_virtual;
       CLASSTYPE_N_SUPERCLASSES (t) += base_info.n_ancestors;
       vfield = base_info.vfield;
       vfields = base_info.vfields;
+      CLASSTYPE_RTTI (t) = base_info.rtti;
       cant_have_default_ctor = base_info.cant_have_default_ctor;
       cant_have_const_ctor = base_info.cant_have_const_ctor;
-      cant_synth_copy_ctor = base_info.cant_synth_copy_ctor;
-      cant_synth_asn_ref = base_info.cant_synth_asn_ref;
       no_const_asn_ref = base_info.no_const_asn_ref;
-      needs_virtual_dtor = base_info.needs_virtual_dtor;
       n_baseclasses = TREE_VEC_LENGTH (BINFO_BASETYPES (t_binfo));
+      aggregate = 0;
     }
   else
     {
@@ -2875,24 +3133,22 @@ finish_struct (t, list_of_fieldlists, warn_anon)
       max_has_virtual = has_virtual;
       vfield = NULL_TREE;
       vfields = NULL_TREE;
-      fields = NULL_TREE;
+      CLASSTYPE_RTTI (t) = NULL_TREE;
       last_x = NULL_TREE;
       cant_have_default_ctor = 0;
       cant_have_const_ctor = 0;
-      cant_synth_copy_ctor = 0;
-      cant_synth_asn_ref = 0;
       no_const_asn_ref = 0;
-      needs_virtual_dtor = 0;
     }
 
+#if 0
+  /* Both of these should be done before now.  */
   if (write_virtuals == 3 && CLASSTYPE_INTERFACE_KNOWN (t)
-      && current_lang_name == lang_name_cplusplus && ! IS_SIGNATURE (t))
+      && ! IS_SIGNATURE (t))
     {
-      CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
-      CLASSTYPE_VTABLE_NEEDS_WRITING (t) = ! interface_only;
+      my_friendly_assert (CLASSTYPE_INTERFACE_ONLY (t) == interface_only, 999);
+      my_friendly_assert (CLASSTYPE_VTABLE_NEEDS_WRITING (t) == ! interface_only, 999);
     }
-  else if (IS_SIGNATURE (t))
-    CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 0;
+#endif
 
   /* The three of these are approximations which may later be
      modified.  Needed at this point to make add_virtual_function
@@ -2902,11 +3158,6 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   CLASSTYPE_VFIELDS (t) = vfields;
   CLASSTYPE_VFIELD (t) = vfield;
 
-  fn_fields = NULL_TREE;
-  tail = NULL_TREE;
-  if (last_x && list_of_fieldlists)
-    TREE_CHAIN (last_x) = TREE_VALUE (list_of_fieldlists);
-
   if (IS_SIGNATURE (t))
     all_virtual = 0;
   else if (flag_all_virtual == 1 && TYPE_OVERLOADS_METHOD_CALL_EXPR (t))
@@ -2914,378 +3165,389 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   else
     all_virtual = 0;
 
-  /* For signatures, we made all methods `public' in the parser and
-     reported an error if a access specifier was used.  */
-  if (CLASSTYPE_DECLARED_CLASS (t) == 0)
+  for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))
     {
-      nonprivate_method = 1;
-      if (list_of_fieldlists
-         && TREE_PURPOSE (list_of_fieldlists) == (tree)access_default)
-       TREE_PURPOSE (list_of_fieldlists) = (tree)access_public;
+      GNU_xref_member (current_class_name, x);
+
+      nonprivate_method |= ! TREE_PRIVATE (x);
+
+      /* If this was an evil function, don't keep it in class.  */
+      if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (x)))
+       continue;
+
+      DECL_CLASS_CONTEXT (x) = t;
+
+      /* Do both of these, even though they're in the same union;
+        if the insn `r' member and the size `i' member are
+        different sizes, as on the alpha, the larger of the two
+        will end up with garbage in it.  */
+      DECL_SAVED_INSNS (x) = NULL_RTX;
+      DECL_FIELD_SIZE (x) = 0;
+
+      check_for_override (x, t);
+      if (DECL_ABSTRACT_VIRTUAL_P (x) && ! DECL_VINDEX (x))
+       cp_error_at ("initializer specified for non-virtual method `%D'", x);
+
+      /* The name of the field is the original field name
+        Save this in auxiliary field for later overloading.  */
+      if (DECL_VINDEX (x)
+         || (all_virtual == 1 && ! DECL_CONSTRUCTOR_P (x)))
+       {
+         pending_virtuals = add_virtual_function (pending_virtuals,
+                                                  &has_virtual, x, t);
+         if (DECL_ABSTRACT_VIRTUAL_P (x))
+           abstract_virtuals = tree_cons (NULL_TREE, x, abstract_virtuals);
+#if 0
+         /* XXX Why did I comment this out?  (jason) */
+         else
+           TREE_USED (x) = 1;
+#endif
+       }
     }
-  else if (list_of_fieldlists
-          && TREE_PURPOSE (list_of_fieldlists) == (tree)access_default)
-    TREE_PURPOSE (list_of_fieldlists) = (tree)access_private;
 
-  while (list_of_fieldlists)
+  for (x = TYPE_FIELDS (t); x; x = TREE_CHAIN (x))
     {
-      access = (enum access_type)TREE_PURPOSE (list_of_fieldlists);
+      GNU_xref_member (current_class_name, x);
 
-      for (x = TREE_VALUE (list_of_fieldlists); x; x = TREE_CHAIN (x))
+      if (TREE_CODE (x) == FIELD_DECL)
        {
-         TREE_PRIVATE (x) = access == access_private;
-         TREE_PROTECTED (x) = access == access_protected;
-         GNU_xref_member (current_class_name, x);
-
-          if (TREE_CODE (x) == TYPE_DECL)
-            {
-             /* Make sure we set this up.  In find_scoped_type, it explicitly
-                looks for a TYPE_DECL in the TYPE_FIELDS list.  If we don't
-                do this here, we'll miss including this TYPE_DECL in the
-                list.  */
-             if (! fields)
-               fields = x;
-             last_x = x;
-             DECL_CONTEXT (x) = t;
-             continue;
-           }
+         DECL_PACKED (x) |= TYPE_PACKED (t);
+         empty = 0;
+       }
 
+      /* Handle access declarations.  */
+      if (TREE_CODE (x) == USING_DECL)
+       {
+         tree ctype = DECL_INITIAL (x);
+         tree sname = DECL_NAME (x);
+         tree access
+           = TREE_PRIVATE (x) ? access_private_node :
+             TREE_PROTECTED (x) ? access_protected_node : access_public_node;
+         tree fdecl, binfo;
+
+         if (last_x)
+           TREE_CHAIN (last_x) = TREE_CHAIN (x);
+         else
+           fields = TREE_CHAIN (x);
 
-         if (TREE_CODE (x) == FUNCTION_DECL)
-           {
-             nonprivate_method |= ! TREE_PRIVATE (x);
+         binfo = binfo_or_else (ctype, t);
+         if (! binfo)
+           continue;
 
-             /* If this was an evil function, don't keep it in class.  */
-             if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (x)))
-               continue;
+         if (sname == constructor_name (ctype)
+             || sname == constructor_name_full (ctype))
+           cp_error_at ("using-declaration for constructor", x);
 
-             if (last_x)
-               TREE_CHAIN (last_x) = TREE_CHAIN (x);
-             if (! fn_fields)
-               fn_fields = x;
-             else
-               TREE_CHAIN (tail) = x;
-             tail = x;
+         fdecl = lookup_field (binfo, sname, 0, 0);
+         if (! fdecl)
+           fdecl = lookup_fnfields (binfo, sname, 0);
+
+         if (fdecl)
+           access_decls = tree_cons (access, fdecl, access_decls);
+         else
+           cp_error_at ("no members matching `%D' in `%#T'", x, ctype);
+         continue;
+       }
+
+      last_x = x;
+
+      if (TREE_CODE (x) == TYPE_DECL)
+       continue;
+
+      /* If we've gotten this far, it's a data member, possibly static,
+        or an enumerator.  */
+
+      DECL_FIELD_CONTEXT (x) = t;
+
+      /* ``A local class cannot have static data members.'' ARM 9.4 */
+      if (current_function_decl && TREE_STATIC (x))
+       cp_error_at ("field `%D' in local class cannot be static", x);
+
+      /* Perform error checking that did not get done in
+        grokdeclarator.  */
+      if (TREE_CODE (TREE_TYPE (x)) == FUNCTION_TYPE)
+       {
+         cp_error_at ("field `%D' invalidly declared function type",
+                      x);
+         TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
+       }
+      else if (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE)
+       {
+         cp_error_at ("field `%D' invalidly declared method type", x);
+         TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
+       }
+      else if (TREE_CODE (TREE_TYPE (x)) == OFFSET_TYPE)
+       {
+         cp_error_at ("field `%D' invalidly declared offset type", x);
+         TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
+       }
 
 #if 0
-             /* ??? What if we have duplicate declarations
-                in T's definition?  */
-             if (DECL_CLASS_CONTEXT (x))
-               continue;
+      if (DECL_NAME (x) == constructor_name (t))
+       cant_have_default_ctor = 1;
 #endif
-             DECL_CLASS_CONTEXT (x) = t;
 
-             DECL_FIELD_SIZE (x) = 0;
+      if (TREE_TYPE (x) == error_mark_node)
+       continue;
+         
+      DECL_SAVED_INSNS (x) = NULL_RTX;
+      DECL_FIELD_SIZE (x) = 0;
 
-             /* The name of the field is the original field name
-                Save this in auxiliary field for later overloading.  */
-             if (DECL_VINDEX (x)
-                 || (all_virtual == 1 && ! DECL_CONSTRUCTOR_P (x)))
-               {
-                 pending_virtuals = add_virtual_function (pending_virtuals,
-                                                          &has_virtual, x, t);
-                 if (DECL_ABSTRACT_VIRTUAL_P (x))
-                   abstract_virtuals = tree_cons (NULL_TREE, x, abstract_virtuals);
-               }
-             continue;
-           }
+      /* When this goes into scope, it will be a non-local reference.  */
+      DECL_NONLOCAL (x) = 1;
 
-         /* Handle access declarations.  */
-         if (DECL_NAME (x) && TREE_CODE (DECL_NAME (x)) == SCOPE_REF)
-           {
-             tree fdecl = TREE_OPERAND (DECL_NAME (x), 1);
+      if (TREE_CODE (x) == CONST_DECL)
+       continue;
 
-             if (last_x)
-               TREE_CHAIN (last_x) = TREE_CHAIN (x);
-             access_decls = tree_cons ((tree) access, fdecl, access_decls);
-             continue;
-           }
+      if (TREE_CODE (x) == VAR_DECL)
+       {
+         if (TREE_CODE (t) == UNION_TYPE)
+           /* Unions cannot have static members.  */
+           cp_error_at ("field `%D' declared static in union", x);
+             
+         continue;
+       }
+
+      /* Now it can only be a FIELD_DECL.  */
 
-         /* If we've gotten this far, it's a data member, possibly static,
-            or an enumerator. */
+      if (TREE_PRIVATE (x) || TREE_PROTECTED (x))
+       aggregate = 0;
 
-         DECL_FIELD_CONTEXT (x) = t;
+      /* If this is of reference type, check if it needs an init.
+        Also do a little ANSI jig if necessary.  */
+      if (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE)
+       {
+         if (DECL_INITIAL (x) == NULL_TREE)
+           ref_sans_init = 1;
 
-         /* ``A local class cannot have static data members.'' ARM 9.4 */
-         if (current_function_decl && TREE_STATIC (x))
-           cp_error_at ("field `%D' in local class cannot be static", x);
+         /* ARM $12.6.2: [A member initializer list] (or, for an
+            aggregate, initialization by a brace-enclosed list) is the
+            only way to initialize nonstatic const and reference
+            members.  */
+         cant_have_default_ctor = 1;
+         TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
 
-         /* Perform error checking that did not get done in
-             grokdeclarator.  */
-         if (TREE_CODE (TREE_TYPE (x)) == FUNCTION_TYPE)
+         if (! TYPE_HAS_CONSTRUCTOR (t) && extra_warnings)
            {
-             cp_error_at ("field `%D' invalidly declared function type",
-                       x);
-             TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
+             if (DECL_NAME (x))
+               cp_warning_at ("non-static reference `%#D' in class without a constructor", x);
+             else
+               cp_warning_at ("non-static reference in class without a constructor", x);
            }
-         else if (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE)
+       }
+
+      if (TREE_CODE (TREE_TYPE (x)) == POINTER_TYPE)
+       has_pointers = 1;
+
+      /* If any field is const, the structure type is pseudo-const.  */
+      if (TREE_READONLY (x))
+       {
+         C_TYPE_FIELDS_READONLY (t) = 1;
+         if (DECL_INITIAL (x) == NULL_TREE)
+           const_sans_init = 1;
+
+         /* ARM $12.6.2: [A member initializer list] (or, for an
+            aggregate, initialization by a brace-enclosed list) is the
+            only way to initialize nonstatic const and reference
+            members.  */
+         cant_have_default_ctor = 1;
+         TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
+
+         if (! TYPE_HAS_CONSTRUCTOR (t) && !IS_SIGNATURE (t)
+             && extra_warnings)
            {
-             cp_error_at ("field `%D' invalidly declared method type", x);
-                 TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
+             if (DECL_NAME (x))
+               cp_warning_at ("non-static const member `%#D' in class without a constructor", x);
+             else
+               cp_warning_at ("non-static const member in class without a constructor", x);
            }
-         else if (TREE_CODE (TREE_TYPE (x)) == OFFSET_TYPE)
+       }
+      else
+       {
+         /* A field that is pseudo-const makes the structure
+            likewise.  */
+         tree t1 = TREE_TYPE (x);
+         while (TREE_CODE (t1) == ARRAY_TYPE)
+           t1 = TREE_TYPE (t1);
+         if (IS_AGGR_TYPE (t1))
            {
-             cp_error_at ("field `%D' invalidly declared offset type", x);
-             TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
+             if (C_TYPE_FIELDS_READONLY (t1))
+               C_TYPE_FIELDS_READONLY (t) = 1;
+             if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (t1))
+               const_sans_init = 1;
            }
+       }
 
-         if (TREE_TYPE (x) == error_mark_node)
-           continue;
-         
-         if (! fields)
-           fields = x;
-         last_x = x;
-
-         DECL_FIELD_SIZE (x) = 0;
-
-         /* When this goes into scope, it will be a non-local reference.  */
-         DECL_NONLOCAL (x) = 1;
-
-         if (TREE_CODE (x) == CONST_DECL)
-           continue;
-
-         if (TREE_CODE (x) == VAR_DECL)
+      /* We set DECL_BIT_FIELD tentatively in grokbitfield.
+        If the type and width are valid, we'll keep it set.
+        Otherwise, the flag is cleared.  */
+      if (DECL_BIT_FIELD (x))
+       {
+         DECL_BIT_FIELD (x) = 0;
+         /* Invalid bit-field size done by grokfield.  */
+         /* Detect invalid bit-field type.  */
+         if (DECL_INITIAL (x)
+             && ! INTEGRAL_TYPE_P (TREE_TYPE (x)))
            {
-             if (TREE_CODE (t) == UNION_TYPE)
-               /* Unions cannot have static members.  */
-               cp_error_at ("field `%D' declared static in union", x);
-             
-             continue;
+             cp_error_at ("bit-field `%#D' with non-integral type", x);
+             DECL_INITIAL (x) = NULL;
            }
 
-         /* Now it can only be a FIELD_DECL.  */
-
-         /* If this is of reference type, check if it needs an init.
-            Also do a little ANSI jig if necessary.  */
-         if (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE)
+         /* Detect and ignore out of range field width.  */
+         if (DECL_INITIAL (x))
            {
-             if (DECL_INITIAL (x) == NULL_TREE)
-               ref_sans_init = 1;
+             tree w = DECL_INITIAL (x);
+             register int width;
+
+             /* Avoid the non_lvalue wrapper added by fold for PLUS_EXPRs.  */
+             STRIP_NOPS (w);
 
-             /* ARM $12.6.2: [A member initializer list] is the only
-                way to initialize a nonstatic const and reference
-                [member].  */
-             cant_synth_asn_ref = 1;
-             cant_have_default_ctor = 1;
-             TYPE_HAS_COMPLEX_INIT_REF (t) = 1;
+             /* detect invalid field size.  */
+             if (TREE_CODE (w) == CONST_DECL)
+               w = DECL_INITIAL (w);
+             else if (TREE_READONLY_DECL_P (w))
+               w = decl_constant_value (w);
 
-             if (! TYPE_HAS_CONSTRUCTOR (t))
+             if (TREE_CODE (w) != INTEGER_CST)
                {
-                 if (DECL_NAME (x))
-                   cp_pedwarn_at ("non-static reference `%#D' in class without a constructor", x);
-                 else
-                   cp_pedwarn_at ("non-static reference in class without a constructor", x);
+                 cp_error_at ("bit-field `%D' width not an integer constant",
+                              x);
+                 DECL_INITIAL (x) = NULL_TREE;
                }
-           }
-
-         /* If any field is const, the structure type is pseudo-const.  */
-         if (TREE_READONLY (x))
-           {
-             C_TYPE_FIELDS_READONLY (t) = 1;
-             if (DECL_INITIAL (x) == NULL_TREE)
-               const_sans_init = 1;
-
-             /* ARM $12.6.2: [A member initializer list] is the only
-                way to initialize a nonstatic const and reference
-                [member].  */
-             cant_synth_asn_ref = 1;
-             cant_have_default_ctor = 1;
-             TYPE_HAS_COMPLEX_INIT_REF (t) = 1;
-
-             if (! TYPE_HAS_CONSTRUCTOR (t) && !IS_SIGNATURE (t))
+             else if (width = TREE_INT_CST_LOW (w),
+                      width < 0)
                {
-                 if (DECL_NAME (x))
-                   cp_pedwarn_at ("non-static const member `%#D' in class without a constructor", x);
-                 else
-                   cp_pedwarn_at ("non-static const member in class without a constructor", x);
+                 DECL_INITIAL (x) = NULL;
+                 cp_error_at ("negative width in bit-field `%D'", x);
                }
-           }
-         else
-           {
-             /* A field that is pseudo-const makes the structure
-                likewise.  */
-             tree t1 = TREE_TYPE (x);
-             while (TREE_CODE (t1) == ARRAY_TYPE)
-               t1 = TREE_TYPE (t1);
-             if (IS_AGGR_TYPE (t1))
+             else if (width == 0 && DECL_NAME (x) != 0)
                {
-                 if (C_TYPE_FIELDS_READONLY (t1))
-                   C_TYPE_FIELDS_READONLY (t) = 1;
-                 if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (t1))
-                   const_sans_init = 1;
+                 DECL_INITIAL (x) = NULL;
+                 cp_error_at ("zero width for bit-field `%D'", x);
                }
-           }
-
-         /* We set DECL_BIT_FIELD tentatively in grokbitfield.
-            If the type and width are valid, we'll keep it set.
-            Otherwise, the flag is cleared.  */
-         if (DECL_BIT_FIELD (x))
-           {
-             DECL_BIT_FIELD (x) = 0;
-             /* Invalid bit-field size done by grokfield.  */
-             /* Detect invalid bit-field type.  */
-             if (DECL_INITIAL (x)
-                 && TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE
-                 && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE)
+             else if (width
+                      > TYPE_PRECISION (long_long_unsigned_type_node))
                {
-                 cp_error_at ("bit-field `%D' has invalid type", x);
+                 /* The backend will dump if you try to use something
+                    too big; avoid that.  */
                  DECL_INITIAL (x) = NULL;
+                 sorry ("bit-fields larger than %d bits",
+                        TYPE_PRECISION (long_long_unsigned_type_node));
+                 cp_error_at ("  in declaration of `%D'", x);
                }
-
-             /* Detect and ignore out of range field width.  */
-             if (DECL_INITIAL (x))
+             else if (width > TYPE_PRECISION (TREE_TYPE (x))
+                      && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE)
                {
-                 register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
-
-                 if (width < 0)
-                   {
-                     DECL_INITIAL (x) = NULL;
-                     cp_error_at ("negative width in bit-field `%D'", x);
-                   }
-                 else if (width == 0 && DECL_NAME (x) != 0)
-                   {
-                     DECL_INITIAL (x) = NULL;
-                     cp_error_at ("zero width for bit-field `%D'", x);
-                   }
-                 else if ((unsigned)width > TYPE_PRECISION (TREE_TYPE (x)))
-                   {
-                     DECL_INITIAL (x) = NULL;
-                     cp_error_at ("width of `%D' exceeds its type", x);
-                   }
+                 cp_warning_at ("width of `%D' exceeds its type", x);
                }
-
-             /* Process valid field width.  */
-             if (DECL_INITIAL (x))
+             else if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
+                      && ((min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
+                                          TREE_UNSIGNED (TREE_TYPE (x))) > width)
+                          || (min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
+                                             TREE_UNSIGNED (TREE_TYPE (x))) > width)))
                {
-                 register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
+                 cp_warning_at ("`%D' is too small to hold all values of `%#T'",
+                                x, TREE_TYPE (x));
+               }
 
-                 if (width == 0)
-                   {
+             if (DECL_INITIAL (x) == NULL_TREE)
+               ;
+             else if (width == 0)
+               {
 #ifdef EMPTY_FIELD_BOUNDARY
-                     /* field size 0 => mark following field as "aligned" */
-                     if (TREE_CHAIN (x))
-                       DECL_ALIGN (TREE_CHAIN (x))
-                         = MAX (DECL_ALIGN (TREE_CHAIN (x)), EMPTY_FIELD_BOUNDARY);
-                     /* field of size 0 at the end => round up the size.  */
-                     else
-                       round_up_size = EMPTY_FIELD_BOUNDARY;
+                 DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY);
 #endif
 #ifdef PCC_BITFIELD_TYPE_MATTERS
-                     DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
-                                           TYPE_ALIGN (TREE_TYPE (x)));
+                 DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
+                                       TYPE_ALIGN (TREE_TYPE (x)));
 #endif
-                   }
-                 else
-                   {
-                     DECL_INITIAL (x) = NULL_TREE;
-                     DECL_FIELD_SIZE (x) = width;
-                     DECL_BIT_FIELD (x) = 1;
-                     /* Traditionally a bit field is unsigned
-                        even if declared signed.  */
-                     if (flag_traditional
-                         && TREE_CODE (TREE_TYPE (x)) == INTEGER_TYPE)
-                       TREE_TYPE (x) = unsigned_type_node;
-                   }
                }
              else
-               /* Non-bit-fields are aligned for their type.  */
-               DECL_ALIGN (x) = MAX (DECL_ALIGN (x), TYPE_ALIGN (TREE_TYPE (x)));
+               {
+                 DECL_INITIAL (x) = NULL_TREE;
+                 DECL_FIELD_SIZE (x) = width;
+                 DECL_BIT_FIELD (x) = 1;
+               }
            }
          else
-           {
-             tree type = TREE_TYPE (x);
+           /* Non-bit-fields are aligned for their type.  */
+           DECL_ALIGN (x) = MAX (DECL_ALIGN (x), TYPE_ALIGN (TREE_TYPE (x)));
+       }
+      else
+       {
+         tree type = TREE_TYPE (x);
 
-             if (TREE_CODE (type) == ARRAY_TYPE)
-               type = TREE_TYPE (type);
+         while (TREE_CODE (type) == ARRAY_TYPE)
+           type = TREE_TYPE (type);
 
-             if (TYPE_LANG_SPECIFIC (type) && ! ANON_UNION_P (x))
-               {
-                 /* Never let anything with uninheritable virtuals
-                    make it through without complaint.  */
-                 if (CLASSTYPE_ABSTRACT_VIRTUALS (type))
-                   abstract_virtuals_error (x, type);
+         if (TYPE_LANG_SPECIFIC (type) && ! ANON_UNION_P (x)
+             && ! TYPE_PTRMEMFUNC_P (type))
+           {
+             /* Never let anything with uninheritable virtuals
+                make it through without complaint.  */
+             if (CLASSTYPE_ABSTRACT_VIRTUALS (type))
+               abstract_virtuals_error (x, type);
                      
-                 /* Don't let signatures make it through either.  */
-                 if (IS_SIGNATURE (type))
-                   signature_error (x, type);
+             /* Don't let signatures make it through either.  */
+             if (IS_SIGNATURE (type))
+               signature_error (x, type);
                      
-                 if (code == UNION_TYPE)
-                   {
-                     char * fie = 0;
-                     if (TYPE_NEEDS_CONSTRUCTING (type))
-                       fie = "constructor";
-                     else if (TYPE_NEEDS_DESTRUCTOR (type))
-                       fie = "destructor";
-                     else if (TYPE_HAS_REAL_ASSIGNMENT (type))
-                       fie = "assignment operator";
-                     if (fie)
-                       cp_error_at ("member `%#D' with %s not allowed in union", x,
-                                    fie);
-                   }
-                 else
-                   {
-                     TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type);
-                     TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (type);
-                     TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (type);
-                     TYPE_HAS_COMPLEX_INIT_REF (t)
-                       |= (TYPE_HAS_COMPLEX_INIT_REF (type)
-                           || TYPE_NEEDS_CONSTRUCTING (type));
-                   }
+             if (code == UNION_TYPE)
+               {
+                 char *fie = NULL;
+                 if (TYPE_NEEDS_CONSTRUCTING (type))
+                   fie = "constructor";
+                 else if (TYPE_NEEDS_DESTRUCTOR (type))
+                   fie = "destructor";
+                 else if (TYPE_HAS_REAL_ASSIGNMENT (type))
+                   fie = "assignment operator";
+                 if (fie)
+                   cp_error_at ("member `%#D' with %s not allowed in union", x,
+                                fie);
+               }
+             else
+               {
+                 TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type);
+                 TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (type);
+                 TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (type);
+                 TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type);
+               }
 
-                 if (! TYPE_HAS_INIT_REF (type)
-                     || (TYPE_HAS_NONPUBLIC_CTOR (type)
-                         && ! is_friend (t, type)))
-                   cant_synth_copy_ctor = 1;
-                 else if (!TYPE_HAS_CONST_INIT_REF (type))
-                   cant_have_const_ctor = 1;
-
-                 if (! TYPE_HAS_ASSIGN_REF (type)
-                     || (TYPE_HAS_NONPUBLIC_ASSIGN_REF (type)
-                         && ! is_friend (t, type)))
-                   cant_synth_asn_ref = 1;
-                 else if (!TYPE_HAS_CONST_ASSIGN_REF (type))
-                   no_const_asn_ref = 1;
-
-                 if (TYPE_HAS_CONSTRUCTOR (type)
-                     && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+             if (!TYPE_HAS_CONST_INIT_REF (type))
+               cant_have_const_ctor = 1;
+
+             if (!TYPE_HAS_CONST_ASSIGN_REF (type))
+               no_const_asn_ref = 1;
+
+             if (TYPE_HAS_CONSTRUCTOR (type)
+                 && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+               {
+                 cant_have_default_ctor = 1;
+#if 0
+                 /* This is wrong for aggregates.  */
+                 if (! TYPE_HAS_CONSTRUCTOR (t))
                    {
-                     cant_have_default_ctor = 1;
-                     if (! TYPE_HAS_CONSTRUCTOR (t))
-                       {
-                         if (DECL_NAME (x))
-                           cp_pedwarn_at ("member `%#D' with only non-default constructor", x);
-                         else
-                           cp_pedwarn_at ("member with only non-default constructor", x);
-                         cp_pedwarn_at ("in class without a constructor",
-                                        x);
-                       }
+                     if (DECL_NAME (x))
+                       cp_pedwarn_at ("member `%#D' with only non-default constructor", x);
+                     else
+                       cp_pedwarn_at ("member with only non-default constructor", x);
+                     cp_pedwarn_at ("in class without a constructor",
+                                    x);
                    }
-               }
-             if (DECL_INITIAL (x) != NULL_TREE)
-               {
-                 /* `build_class_init_list' does not recognize
-                     non-FIELD_DECLs.  */
-                 if (code == UNION_TYPE && any_default_members != 0)
-                   cp_error_at ("multiple fields in union `%T' initialized");
-                 any_default_members = 1;
+#endif
                }
            }
-       }
-      list_of_fieldlists = TREE_CHAIN (list_of_fieldlists);
-      /* link the tail while we have it! */
-      if (last_x)
-       {
-         TREE_CHAIN (last_x) = NULL_TREE;
-
-         if (list_of_fieldlists
-             && TREE_VALUE (list_of_fieldlists)
-             && TREE_CODE (TREE_VALUE (list_of_fieldlists)) != FUNCTION_DECL)
-           TREE_CHAIN (last_x) = TREE_VALUE (list_of_fieldlists);
+         if (DECL_INITIAL (x) != NULL_TREE)
+           {
+             /* `build_class_init_list' does not recognize
+                non-FIELD_DECLs.  */
+             if (code == UNION_TYPE && any_default_members != 0)
+               cp_error_at ("multiple fields in union `%T' initialized");
+             any_default_members = 1;
+           }
        }
     }
 
-  if (tail) TREE_CHAIN (tail) = NULL_TREE;
-
   /* If this type has any constant members which did not come
      with their own initialization, mark that fact here.  It is
      not an error here, since such types can be saved either by their
@@ -3294,72 +3556,83 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   CLASSTYPE_REF_FIELDS_NEED_INIT (t) = ref_sans_init;
   CLASSTYPE_ABSTRACT_VIRTUALS (t) = abstract_virtuals;
 
+  /* Synthesize any needed methods.  Note that methods will be synthesized
+     for anonymous unions; grok_x_components undoes that.  */
+
+  if (! fn_fields)
+    nonprivate_method = 1;
+
   if (TYPE_NEEDS_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t)
       && !IS_SIGNATURE (t))
     {
       /* Here we must cons up a destructor on the fly.  */
-      tree dtor = cons_up_default_function (t, name, fields,
-                                           needs_virtual_dtor != 0);
+      tree dtor = cons_up_default_function (t, name, 0);
+      check_for_override (dtor, t);
 
       /* If we couldn't make it work, then pretend we didn't need it.  */
       if (dtor == void_type_node)
        TYPE_NEEDS_DESTRUCTOR (t) = 0;
       else
        {
-         if (! fn_fields)
-           fn_fields = dtor;
-         else
-           TREE_CHAIN (tail) = dtor;
-         tail = dtor;
-
-         if (DECL_VINDEX (dtor) == NULL_TREE
-             && ! CLASSTYPE_DECLARED_EXCEPTION (t)
-             && (needs_virtual_dtor
-                 || pending_virtuals != NULL_TREE
-                 || pending_hard_virtuals != NULL_TREE))
-           DECL_VINDEX (dtor) = error_mark_node;
+         /* Link dtor onto end of fn_fields.  */
+
+         TREE_CHAIN (dtor) = fn_fields;
+         fn_fields = dtor;
+
          if (DECL_VINDEX (dtor))
            pending_virtuals = add_virtual_function (pending_virtuals,
-                                                    &has_virtual, dtor, NULL_TREE);
+                                                    &has_virtual, dtor, t);
          nonprivate_method = 1;
        }
     }
 
-  TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
-
-  /* Synthesize any needed methods.  Note that methods will be synthesized
-     for anonymous unions; grok_x_components undoes that.  */
+  /* Effective C++ rule 11.  */
+  if (has_pointers && warn_ecpp
+      && ! (TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
+    {
+      cp_warning ("`%#T' has pointer data members", t);
+      
+      if (! TYPE_HAS_INIT_REF (t))
+       {
+         cp_warning ("  but does not override `%T(const %T&)'", t, t);
+         if (! TYPE_HAS_ASSIGN_REF (t))
+           cp_warning ("  or `operator=(const %T&)'", t);
+       }
+      else if (! TYPE_HAS_ASSIGN_REF (t))
+       cp_warning ("  but does not override `operator=(const %T&)'", t);
+    }
 
-  if (! fn_fields)
-    nonprivate_method = 1;
+  TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
 
   TYPE_HAS_COMPLEX_INIT_REF (t)
     |= (TYPE_HAS_INIT_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t)
-       || has_virtual || any_default_members || first_vfn_base_index >= 0);
+       || has_virtual || any_default_members);
   TYPE_NEEDS_CONSTRUCTING (t)
     |= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_USES_VIRTUAL_BASECLASSES (t)
-       || has_virtual || any_default_members || first_vfn_base_index >= 0);
+       || has_virtual || any_default_members);
+  if (! IS_SIGNATURE (t))
+    CLASSTYPE_NON_AGGREGATE (t)
+      = ! aggregate || has_virtual || TYPE_HAS_CONSTRUCTOR (t);
 
   /* ARM $12.1: A default constructor will be generated for a class X
      only if no constructor has been declared for class X.  So we
      check TYPE_HAS_CONSTRUCTOR also, to make sure we don't generate
      one if they declared a constructor in this class.  */
-  if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor)
+  if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor
+      && ! IS_SIGNATURE (t))
     {
-      tree default_fn = cons_up_default_function (t, name, fields, 2);
+      tree default_fn = cons_up_default_function (t, name, 2);
       TREE_CHAIN (default_fn) = fn_fields;
       fn_fields = default_fn;
     }
 
-  /* Create default copy constructor, if needed.  Don't do it for
-     the exception handler.  */
-  if (! TYPE_HAS_INIT_REF (t) && ! cant_synth_copy_ctor && t != EHS_type)
+  /* Create default copy constructor, if needed.  */
+  if (! TYPE_HAS_INIT_REF (t) && ! IS_SIGNATURE (t))
     {
       /* ARM 12.18: You get either X(X&) or X(const X&), but
         not both.  --Chip  */
-      tree default_fn =
-       cons_up_default_function (t, name, fields,
-                                 cant_have_const_ctor ? 4 : 3);
+      tree default_fn = cons_up_default_function (t, name,
+                                                 3 + cant_have_const_ctor);
       TREE_CHAIN (default_fn) = fn_fields;
       fn_fields = default_fn;
     }
@@ -3367,26 +3640,24 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   TYPE_HAS_REAL_ASSIGNMENT (t) |= TYPE_HAS_ASSIGNMENT (t);
   TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);
   TYPE_HAS_COMPLEX_ASSIGN_REF (t)
-    |= (TYPE_HAS_ASSIGN_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t)
-       || has_virtual || first_vfn_base_index >= 0);
+    |= TYPE_HAS_ASSIGN_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t);
 
-  if (! TYPE_HAS_ASSIGN_REF (t) && ! cant_synth_asn_ref)
+  if (! TYPE_HAS_ASSIGN_REF (t) && ! IS_SIGNATURE (t))
     {
-      tree default_fn =
-       cons_up_default_function (t, name, fields,
-                                 no_const_asn_ref ? 6 : 5);
+      tree default_fn = cons_up_default_function (t, name,
+                                                 5 + no_const_asn_ref);
       TREE_CHAIN (default_fn) = fn_fields;
       fn_fields = default_fn;
     }
 
   if (fn_fields)
     {
+      TYPE_METHODS (t) = fn_fields;
       method_vec = finish_struct_methods (t, fn_fields, nonprivate_method);
 
       if (TYPE_HAS_CONSTRUCTOR (t)
-         && ! CLASSTYPE_DECLARED_EXCEPTION (t)
          && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
-         && DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE)
+         && DECL_FRIENDLIST (TYPE_MAIN_DECL (t)) == NULL_TREE)
        {
          int nonprivate_ctor = 0;
          tree ctor;
@@ -3416,7 +3687,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
     }
 
   {
-    int n_methods = TREE_VEC_LENGTH (method_vec);
+    int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
     
     for (access_decls = nreverse (access_decls); access_decls;
         access_decls = TREE_CHAIN (access_decls))
@@ -3424,8 +3695,8 @@ finish_struct (t, list_of_fieldlists, warn_anon)
        tree fdecl = TREE_VALUE (access_decls);
        tree flist = NULL_TREE;
        tree name;
-       enum access_type access = (enum access_type)TREE_PURPOSE(access_decls);
-       int i = 0;
+       tree access = TREE_PURPOSE (access_decls);
+       int i = 2;
        tree tmp;
 
        if (TREE_CODE (fdecl) == TREE_LIST)
@@ -3440,9 +3711,9 @@ finish_struct (t, list_of_fieldlists, warn_anon)
          if (DECL_NAME (TREE_VEC_ELT (method_vec, i)) == name)
            {
              cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
-             cp_error_at ("because of local method `%#D' with same name",
+             cp_error_at ("  because of local method `%#D' with same name",
                           TREE_VEC_ELT (method_vec, i));
-             fdecl = 0;
+             fdecl = NULL_TREE;
              break;
            }
 
@@ -3453,8 +3724,8 @@ finish_struct (t, list_of_fieldlists, warn_anon)
          if (DECL_NAME (tmp) == name)
            {
              cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
-             cp_error_at ("because of local field `%#D' with same name", tmp);
-             fdecl = 0;
+             cp_error_at ("  because of local field `%#D' with same name", tmp);
+             fdecl = NULL_TREE;
              break;
            }
 
@@ -3486,29 +3757,35 @@ finish_struct (t, list_of_fieldlists, warn_anon)
                                      ptr_type_node);
       /* If you change any of the below, take a look at all the
         other VFIELD_BASEs and VTABLE_BASEs in the code, and change
-        them too. */
+        them too.  */
       DECL_ASSEMBLER_NAME (vfield) = get_identifier (VFIELD_BASE);
       CLASSTYPE_VFIELD (t) = vfield;
       DECL_VIRTUAL_P (vfield) = 1;
+      DECL_ARTIFICIAL (vfield) = 1;
       DECL_FIELD_CONTEXT (vfield) = t;
       DECL_CLASS_CONTEXT (vfield) = t;
       DECL_FCONTEXT (vfield) = t;
+      DECL_SAVED_INSNS (vfield) = NULL_RTX;
       DECL_FIELD_SIZE (vfield) = 0;
       DECL_ALIGN (vfield) = TYPE_ALIGN (ptr_type_node);
-      if (CLASSTYPE_DOSSIER (t))
-       {
-         /* vfield is always first entry in structure.  */
-         TREE_CHAIN (vfield) = fields;
-         fields = vfield;
-       }
-      else if (last_x)
+#if 0
+      /* This is more efficient, but breaks binary compatibility, turn
+        it on sometime when we don't care.  If we turn it on, we also
+        have to enable the code in dfs_init_vbase_pointers.  */
+      /* vfield is always first entry in structure.  */
+      TREE_CHAIN (vfield) = fields;
+      fields = vfield;
+#else
+      if (last_x)
        {
-         my_friendly_assert (TREE_CHAIN (last_x) == 0, 175);
+         my_friendly_assert (TREE_CHAIN (last_x) == NULL_TREE, 175);
          TREE_CHAIN (last_x) = vfield;
          last_x = vfield;
        }
       else
        fields = vfield;
+#endif
+      empty = 0;
       vfields = chainon (vfields, CLASSTYPE_AS_LIST (t));
     }
 
@@ -3533,54 +3810,37 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   /* Delete all duplicate fields from the fields */
   delete_duplicate_fields (fields);
 
-  /* Now we have the final fieldlist for the data fields.  Record it,
-     then lay out the structure or union (including the fields).  */
-
-  TYPE_FIELDS (t) = fields;
-
-  /* If there's a :0 field at the end, round the size to the
-     EMPTY_FIELD_BOUNDARY.  */
-  TYPE_ALIGN (t) = round_up_size;
-
-  /* Pass layout information about base classes to layout_type, if any.  */
+  /* Catch function/field name conflict.  We don't need to do this for a
+     signature, since it can only contain the fields constructed in
+     append_signature_fields.  */
+  if (! IS_SIGNATURE (t))
+    {
+      int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
+      for (x = fields; x; x = TREE_CHAIN (x))
+       {
+         tree name = DECL_NAME (x);
+         int i = 2;
 
-  {
-    tree field;
-    for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
-      {
-       if (TREE_STATIC (field))
-         continue;
-       if (TREE_CODE (field) != FIELD_DECL)
-         continue;
+         if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))
+           continue;
 
-       /* If this field is an anonymous union,
-          give each union-member the same position as the union has.
-
-          ??? This is a real kludge because it makes the structure
-          of the types look strange.  This feature is only used by
-          C++, which should have build_component_ref build two
-          COMPONENT_REF operations, one for the union and one for
-          the inner field.  We set the offset of this field to zero
-          so that either the old or the correct method will work.
-          Setting DECL_FIELD_CONTEXT is wrong unless the inner fields are
-          moved into the type of this field, but nothing seems to break
-          by doing this.  */
-
-       if (DECL_NAME (field) == 0
-           && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
-         {
-           tree uelt = TYPE_FIELDS (TREE_TYPE (field));
-           for (; uelt; uelt = TREE_CHAIN (uelt))
+         for (; i < n_methods; ++i)
+           if (DECL_NAME (TREE_VEC_ELT (method_vec, i)) == name)
              {
-               DECL_FIELD_CONTEXT (uelt) = DECL_FIELD_CONTEXT (field);
-               DECL_FIELD_BITPOS (uelt) = DECL_FIELD_BITPOS (field);
+               cp_error_at ("data member `%#D' conflicts with", x);
+               cp_error_at ("function member `%#D'",
+                            TREE_VEC_ELT (method_vec, i));
+               break;
              }
+       }
+    }
 
-           DECL_FIELD_BITPOS (field) = integer_zero_node;
-         }
-      }
-  }
+  /* Now we have the final fieldlist for the data fields.  Record it,
+     then lay out the structure or union (including the fields).  */
+
+  TYPE_FIELDS (t) = fields;
 
+  /* Pass layout information about base classes to layout_type, if any.  */
   if (n_baseclasses)
     {
       tree pseudo_basetype = TREE_TYPE (base_layout_decl);
@@ -3592,67 +3852,34 @@ finish_struct (t, list_of_fieldlists, warn_anon)
       TYPE_MODE (pseudo_basetype) = TYPE_MODE (t);
       TYPE_ALIGN (pseudo_basetype) = CLASSTYPE_ALIGN (t);
       DECL_ALIGN (base_layout_decl) = TYPE_ALIGN (pseudo_basetype);
-      /* Don't re-use old size. */
-      DECL_SIZE (base_layout_decl) = 0;
+      /* Don't re-use old size.  */
+      DECL_SIZE (base_layout_decl) = NULL_TREE;
+    }
+  else if (empty)
+    {
+      /* C++: do not let empty structures exist.  */
+      tree decl = build_lang_field_decl
+       (FIELD_DECL, NULL_TREE, char_type_node);
+      TREE_CHAIN (decl) = TYPE_FIELDS (t);
+      TYPE_FIELDS (t) = decl;
     }
 
   layout_type (t);
 
-  {
-    tree field;
-    for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
-      {
-       if (TREE_STATIC (field))
-         continue;
-       if (TREE_CODE (field) != FIELD_DECL)
-         continue;
-
-       /* If this field is an anonymous union,
-          give each union-member the same position as the union has.
-
-          ??? This is a real kludge because it makes the structure
-          of the types look strange.  This feature is only used by
-          C++, which should have build_component_ref build two
-          COMPONENT_REF operations, one for the union and one for
-          the inner field.  We set the offset of this field to zero
-          so that either the old or the correct method will work.
-          Setting DECL_FIELD_CONTEXT is wrong unless the inner fields are
-          moved into the type of this field, but nothing seems to break
-          by doing this.  */
-
-       if (DECL_NAME (field) == 0
-           && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
-         {
-           tree uelt = TYPE_FIELDS (TREE_TYPE (field));
-           for (; uelt; uelt = TREE_CHAIN (uelt))
-             {
-               DECL_FIELD_CONTEXT (uelt) = DECL_FIELD_CONTEXT (field);
-               DECL_FIELD_BITPOS (uelt) = DECL_FIELD_BITPOS (field);
-             }
-
-           DECL_FIELD_BITPOS (field) = integer_zero_node;
-         }
-      }
-  }
+  finish_struct_anon (t);
 
-  if (n_baseclasses)
+  if (n_baseclasses || empty)
     TYPE_FIELDS (t) = TREE_CHAIN (TYPE_FIELDS (t));
 
-  /* C++: do not let empty structures exist.  */
-  if (integer_zerop (TYPE_SIZE (t)))
-    TYPE_SIZE (t) = TYPE_SIZE (char_type_node);
-
   /* Set the TYPE_DECL for this type to contain the right
      value for DECL_OFFSET, so that we can use it as part
      of a COMPONENT_REF for multiple inheritance.  */
 
-  if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
-    layout_decl (TYPE_NAME (t), 0);
+  layout_decl (TYPE_MAIN_DECL (t), 0);
 
-  /* Now fix up any virtual base class types that we
-     left lying around.  We must get these done
-     before we try to lay out the virtual function table.  */
-  doing_hard_virtuals = 1;
+  /* Now fix up any virtual base class types that we left lying
+     around.  We must get these done before we try to lay out the
+     virtual function table.  */
   pending_hard_virtuals = nreverse (pending_hard_virtuals);
 
   if (TYPE_USES_VIRTUAL_BASECLASSES (t))
@@ -3663,144 +3890,107 @@ finish_struct (t, list_of_fieldlists, warn_anon)
       vbases = CLASSTYPE_VBASECLASSES (t);
       CLASSTYPE_N_VBASECLASSES (t) = list_length (vbases);
 
-      while (vbases)
-       {
-         /* Update dossier info with offsets for virtual baseclasses.  */
-         if (flag_dossier && ! BINFO_NEW_VTABLE_MARKED (vbases))
-           prepare_fresh_vtable (vbases, vbases, t);
+      {
+       /* Now fixup overrides of all functions in vtables from all
+          direct or indirect virtual base classes.  */
+       tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
+       int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
 
-         vbases = TREE_CHAIN (vbases);
-       }
-    }
+       for (i = 0; i < n_baseclasses; i++)
+         {
+           tree base_binfo = TREE_VEC_ELT (binfos, i);
+           tree basetype = BINFO_TYPE (base_binfo);
+           tree vbases;
 
-#ifdef NOTQUITE
-  cp_warning ("Doing hard virtuals for %T...", t);
-#endif
-  while (pending_hard_virtuals)
-    {
-      /* Need an entry in some other virtual function table.  */
-      if (TREE_TYPE (pending_hard_virtuals))
-       {
-         /* This is how we modify entries when a vfn's index changes
-            between derived and base type.  */
-         modify_vtable_entries (t, TREE_PURPOSE (pending_hard_virtuals),
-                                TREE_TYPE (pending_hard_virtuals),
-                                TREE_VALUE (pending_hard_virtuals));
-       }
-      else
-       {
-         /* This is how we modify entries when a vfn comes from
-            a virtual baseclass.  */
-         tree base_fndecls = DECL_VINDEX (TREE_PURPOSE (pending_hard_virtuals));
-         /* Only do this, if it was missed before. */
-         if (TREE_CODE (base_fndecls) != INTEGER_CST)
-           {
-             my_friendly_assert (base_fndecls != error_mark_node, 176);
-             while (base_fndecls)
-               {
-                 modify_vtable_entries (t, TREE_PURPOSE (pending_hard_virtuals),
-                                        TREE_VALUE (base_fndecls),
-                                        TREE_VALUE (pending_hard_virtuals));
-                 modify_other_vtable_entries (t, TYPE_BINFO (t),
-                                              TREE_PURPOSE (pending_hard_virtuals),
-                                              TREE_VALUE (base_fndecls),
-                                              TREE_VALUE (pending_hard_virtuals));
-                 base_fndecls = TREE_CHAIN (base_fndecls);
-               }
-           } else {
-#ifdef NOTQUITE
-             cp_warning ("missed bases for `%D'", TREE_PURPOSE (pending_hard_virtuals));
-#endif
-           }
+           vbases = CLASSTYPE_VBASECLASSES (basetype);
+           while (vbases)
+             {
+               merge_overrides (binfo_member (BINFO_TYPE (vbases),
+                                              CLASSTYPE_VBASECLASSES (t)),
+                                vbases, 1, t);
+               vbases = TREE_CHAIN (vbases);
+             }
+         }
        }
-      pending_hard_virtuals = TREE_CHAIN (pending_hard_virtuals);
     }
 
-  if (TYPE_USES_VIRTUAL_BASECLASSES (t))
+  /* Set up the DECL_FIELD_BITPOS of the vfield if we need to, as we
+     might need to know it for setting up the offsets in the vtable
+     (or in thunks) below.  */
+  if (vfield != NULL_TREE
+      && DECL_FIELD_CONTEXT (vfield) != t)
     {
-      tree vbases;
-
-      vbases = CLASSTYPE_VBASECLASSES (t);
-      CLASSTYPE_N_VBASECLASSES (t) = list_length (vbases);
-
-      /* This loop makes all the entries in the virtual function tables
-        of interest contain the "latest" version of the functions
-        we have defined.  */
-
-      while (vbases)
-       {
-         tree virtuals = BINFO_VIRTUALS (vbases);
+      tree binfo = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
+      tree offset = BINFO_OFFSET (binfo);
 
-         if (virtuals)
-           {
-             /* Get past the `null' vtable entry...  */
-             virtuals = TREE_CHAIN (virtuals);
-             /* and the `dossier' vtable entry if we're doing dossiers.  */
-             if (flag_dossier)
-               virtuals = TREE_CHAIN (virtuals);
-           }
+      vfield = copy_node (vfield);
+      copy_lang_decl (vfield);
 
-         while (virtuals != NULL_TREE)
-           {
-             tree pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
-             tree base_fndecl = TREE_OPERAND (pfn, 0);
-             tree decl = get_first_matching_virtual (TYPE_BINFO (t), base_fndecl,
-                                                     DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl)));
-             tree context = DECL_CLASS_CONTEXT (decl);
-             if (! SAME_FN (decl, base_fndecl))
-               {
-                 tree base_context = DECL_CLASS_CONTEXT (base_fndecl);
-                 tree binfo = NULL_TREE, these_virtuals;
-#if 0
-                 unsigned HOST_WIDE_INT i
-                   = (TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl))
-                      & (((unsigned HOST_WIDE_INT)1<<(BITS_PER_WORD-1))-1));
+      if (! integer_zerop (offset))
+       offset = size_binop (MULT_EXPR, offset, size_int (BITS_PER_UNIT));
+      DECL_FIELD_CONTEXT (vfield) = t;
+      DECL_CLASS_CONTEXT (vfield) = t;
+      DECL_FIELD_BITPOS (vfield)
+       = size_binop (PLUS_EXPR, offset, DECL_FIELD_BITPOS (vfield));
+      CLASSTYPE_VFIELD (t) = vfield;
+    }
+    
+#ifdef NOTQUITE
+  cp_warning ("Doing hard virtuals for %T...", t);
 #endif
 
-                 if (TYPE_USES_VIRTUAL_BASECLASSES (context))
-                   binfo = virtual_member (base_context,
-                                           CLASSTYPE_VBASECLASSES (context));
-                 if (binfo == NULL_TREE)
-                   binfo = binfo_value (base_context, context);
-                 if (binfo != NULL_TREE)
-                   {
-#if 1
-                     pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (get_vtable_entry (BINFO_VIRTUALS (binfo), base_fndecl)));
-#else
-                     these_virtuals = BINFO_VIRTUALS (binfo);
+  if (has_virtual > max_has_virtual)
+    max_has_virtual = has_virtual;
+  if (max_has_virtual > 0)
+    TYPE_VIRTUAL_P (t) = 1;
 
-                     while (i-- > 0)
-                       these_virtuals = TREE_CHAIN (these_virtuals);
-                     pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (these_virtuals));
-#endif
-                     pfn = build1 (ADDR_EXPR, ptr_type_node, decl);
-                     TREE_CONSTANT (pfn) = 1;
-                     modify_vtable_entries (t, decl, base_fndecl, pfn);
-                   }
-               }
-             virtuals = TREE_CHAIN (virtuals);
-           }
+  if (flag_rtti && TYPE_VIRTUAL_P (t) && !pending_hard_virtuals)
+    modify_all_vtables (t, NULL_TREE, NULL_TREE);
 
+  while (pending_hard_virtuals)
+    {
+      modify_all_vtables (t,
+                         TREE_PURPOSE (pending_hard_virtuals),
+                         TREE_VALUE (pending_hard_virtuals));
+      pending_hard_virtuals = TREE_CHAIN (pending_hard_virtuals);
+    }
+  
+  if (TYPE_USES_VIRTUAL_BASECLASSES (t))
+    {
+      tree vbases;
+      /* Now fixup any virtual function entries from virtual bases
+        that have different deltas.  This has to come after we do the
+        pending hard virtuals, as we might have a function that comes
+        from multiple virtual base instances that is only overridden
+        by a hard virtual above.  */
+      vbases = CLASSTYPE_VBASECLASSES (t);
+      while (vbases)
+       {
+         /* We might be able to shorten the amount of work we do by
+            only doing this for vtables that come from virtual bases
+            that have differing offsets, but don't want to miss any
+            entries.  */
+         fixup_vtable_deltas (vbases, 1, t);
          vbases = TREE_CHAIN (vbases);
        }
     }
-  doing_hard_virtuals = 0;
 
   /* Under our model of GC, every C++ class gets its own virtual
      function table, at least virtually.  */
-  if (pending_virtuals || CLASSTYPE_DOSSIER (t))
+  if (pending_virtuals)
     {
       pending_virtuals = nreverse (pending_virtuals);
       /* We must enter these virtuals into the table.  */
       if (first_vfn_base_index < 0)
        {
-         if (flag_dossier)
-           pending_virtuals = tree_cons (NULL_TREE,
-                                         build_vtable_entry (integer_zero_node,
-                                                             build_t_desc (t, 0)),
-                                         pending_virtuals);
-         pending_virtuals = tree_cons (NULL_TREE, the_null_vtable_entry,
-                                       pending_virtuals);
+         /* The second slot is for the tdesc pointer when thunks are used.  */
+         if (flag_vtable_thunks)
+           pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
+
+         /* The first slot is for the rtti offset.  */
+         pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
+
+         set_rtti_entry (pending_virtuals, size_zero_node, t);
          build_vtable (NULL_TREE, t);
        }
       else
@@ -3810,11 +4000,6 @@ finish_struct (t, list_of_fieldlists, warn_anon)
 
          if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t)))
            build_vtable (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), first_vfn_base_index), t);
-
-         /* Update the dossier pointer for this class.  */
-         if (flag_dossier)
-           TREE_VALUE (TREE_CHAIN (TYPE_BINFO_VIRTUALS (t)))
-             = build_vtable_entry (integer_zero_node, build_t_desc (t, 0));
        }
 
       /* If this type has basetypes with constructors, then those
@@ -3827,13 +4012,6 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   else if (first_vfn_base_index >= 0)
     {
       tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), first_vfn_base_index);
-#if 0
-      /* For testing. */
-      tree binfo1 = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
-      if (binfo != binfo1)
-       warning ("binfos are different in vtable creation");
-#endif
-
       /* This class contributes nothing new to the virtual function
         table.  However, it may have declared functions which
         went into the virtual function table "inherited" from the
@@ -3849,18 +4027,8 @@ finish_struct (t, list_of_fieldlists, warn_anon)
        CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
     }
 
-  if (has_virtual > max_has_virtual)
-    max_has_virtual = has_virtual;
   if (max_has_virtual || first_vfn_base_index >= 0)
     {
-#ifdef VTABLE_USES_MASK
-      if (max_has_virtual >= VINDEX_MAX)
-       {
-         cp_error ("too many virtual functions for `%#T' (VINDEX_MAX < %d)",
-                   t, has_virtual);
-       }
-#endif
-      TYPE_VIRTUAL_P (t) = 1;
       CLASSTYPE_VSIZE (t) = has_virtual;
       if (first_vfn_base_index >= 0)
        {
@@ -3914,6 +4082,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
       if (TREE_TYPE (TYPE_BINFO_VTABLE (t)) != atype)
        {
          TREE_TYPE (TYPE_BINFO_VTABLE (t)) = atype;
+         DECL_SIZE (TYPE_BINFO_VTABLE (t)) = 0;
          layout_decl (TYPE_BINFO_VTABLE (t), 0);
          /* At one time the vtable info was grabbed 2 words at a time.  This
             fails on sparc unless you have 8-byte alignment.  (tiemann) */
@@ -3928,29 +4097,10 @@ finish_struct (t, list_of_fieldlists, warn_anon)
 
   finish_struct_bits (t, max_has_virtual);
 
-  /* Promote each bit-field's type to int if it is narrower than that.
-     There's more: complete the rtl for any static member objects which
-     is of the same type we're working on.  */
+  /* Complete the rtl for any static member objects of the type we're
+     working on.  */
   for (x = fields; x; x = TREE_CHAIN (x))
     {
-      if (DECL_BIT_FIELD (x)
-         && (C_PROMOTING_INTEGER_TYPE_P (TREE_TYPE (x))
-             || DECL_FIELD_SIZE (x) < TYPE_PRECISION (integer_type_node)))
-       {
-         tree type = TREE_TYPE (x);
-
-         /* Preserve unsignedness if traditional or if not really getting
-            any wider.  */
-         if (TREE_UNSIGNED (type)
-             && (flag_traditional
-                 ||
-                 (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)
-                  && DECL_FIELD_SIZE (x) == TYPE_PRECISION (integer_type_node))))
-           TREE_TYPE (x) = unsigned_type_node;
-         else
-           TREE_TYPE (x) = integer_type_node;
-       }
-
       if (TREE_CODE (x) == VAR_DECL && TREE_STATIC (x)
          && TREE_TYPE (x) == t)
        {
@@ -3959,33 +4109,6 @@ finish_struct (t, list_of_fieldlists, warn_anon)
        }
     }
 
-  /* Now add the tags, if any, to the list of TYPE_DECLs
-     defined for this type.  */
-  if (CLASSTYPE_TAGS (t))
-    {
-      x = CLASSTYPE_TAGS (t);
-      last_x = tree_last (TYPE_FIELDS (t));
-      while (x)
-       {
-         tree tag = build_lang_decl (TYPE_DECL, TREE_PURPOSE (x), TREE_VALUE (x));
-#ifdef DWARF_DEBUGGING_INFO
-         if (write_symbols == DWARF_DEBUG)
-           {
-             /* Notify dwarfout.c that this TYPE_DECL node represent a
-                gratuitous typedef.  */
-             DECL_IGNORED_P (tag) = 1;
-           }
-#endif /* DWARF_DEBUGGING_INFO */
-         DECL_CONTEXT (tag) = t;
-         DECL_CLASS_CONTEXT (tag) = t;
-         x = TREE_CHAIN (x);
-         last_x = chainon (last_x, tag);
-       }
-      if (TYPE_FIELDS (t) == 0)
-       TYPE_FIELDS (t) = last_x;
-      CLASSTYPE_LOCAL_TYPEDECLS (t) = 1;
-    }
-
   if (TYPE_HAS_CONSTRUCTOR (t))
     {
       tree vfields = CLASSTYPE_VFIELDS (t);
@@ -4005,26 +4128,14 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   else if (TYPE_NEEDS_CONSTRUCTING (t))
     build_class_init_list (t);
 
-  if (current_lang_name == lang_name_cplusplus)
-    {
-      if (! CLASSTYPE_DECLARED_EXCEPTION (t)
-         && ! IS_SIGNATURE (t))
-       embrace_waiting_friends (t);
-
-      /* Write out inline function definitions.  */
-      do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t));
-      CLASSTYPE_INLINE_FRIENDS (t) = 0;
-    }
+  /* Write out inline function definitions.  */
+  do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t));
+  CLASSTYPE_INLINE_FRIENDS (t) = 0;
 
   if (CLASSTYPE_VSIZE (t) != 0)
     {
-      if ((flag_this_is_variable & 1) == 0)
-       {
-         tree vtbl_ptr = build_decl (VAR_DECL, get_identifier (VPTR_NAME),
-                                     TREE_TYPE (vfield));
-         DECL_REGISTER (vtbl_ptr) = 1;
-         CLASSTYPE_VTBL_PTR (t) = vtbl_ptr;
-       }
+#if 0
+      /* This is now done above.  */
       if (DECL_FIELD_CONTEXT (vfield) != t)
        {
          tree binfo = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
@@ -4041,66 +4152,33 @@ finish_struct (t, list_of_fieldlists, warn_anon)
            = size_binop (PLUS_EXPR, offset, DECL_FIELD_BITPOS (vfield));
          CLASSTYPE_VFIELD (t) = vfield;
        }
+#endif
 
-      /* In addition to this one, all the other vfields should be listed. */
+      /* In addition to this one, all the other vfields should be listed.  */
       /* Before that can be done, we have to have FIELD_DECLs for them, and
         a place to find them.  */
       TYPE_NONCOPIED_PARTS (t) = build_tree_list (default_conversion (TYPE_BINFO_VTABLE (t)), vfield);
 
       if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (t)
-         && DECL_VINDEX (TREE_VEC_ELT (method_vec, 0)) == NULL_TREE)
+         && DECL_VINDEX (TREE_VEC_ELT (method_vec, 1)) == NULL_TREE)
        cp_warning ("`%#T' has virtual functions but non-virtual destructor",
                    t);
     }
 
   /* Make the rtl for any new vtables we have created, and unmark
      the base types we marked.  */
-  unmark_finished_struct (t);
-  TYPE_BEING_DEFINED (t) = 0;
-
-  if (flag_dossier && CLASSTYPE_VTABLE_NEEDS_WRITING (t))
-    {
-      tree variants;
-      tree tdecl;
+  finish_vtbls (TYPE_BINFO (t), 1, t);
+  hack_incomplete_structures (t);
 
-      /* Now instantiate its type descriptors.  */
-      tdecl = TREE_OPERAND (build_t_desc (t, 1), 0);
-      variants = TYPE_POINTER_TO (t);
-      build_type_variant (variants, 1, 0);
-      while (variants)
-       {
-         build_t_desc (variants, 1);
-         variants = TYPE_NEXT_VARIANT (variants);
-       }
-      variants = build_reference_type (t);
-      build_type_variant (variants, 1, 0);
-      while (variants)
-       {
-         build_t_desc (variants, 1);
-         variants = TYPE_NEXT_VARIANT (variants);
-       }
 #if 0
-      DECL_VPARENT (tdecl) = t;
-#endif
-      DECL_CONTEXT (tdecl) = t;
-    }
-  /* Still need to instantiate this C struct's type descriptor.  */
-  else if (flag_dossier && ! CLASSTYPE_DOSSIER (t))
-    build_t_desc (t, 1);
-
   if (TYPE_NAME (t) && TYPE_IDENTIFIER (t))
     undo_template_name_overload (TYPE_IDENTIFIER (t), 1);
-  if (current_class_type)
-    popclass (0);
-  else
-    error ("trying to finish struct, but kicked out due to previous parse errors.");
-
-  hack_incomplete_structures (t);
+#endif
 
   resume_momentary (old);
 
-  if (flag_cadillac)
-    cadillac_finish_struct (t);
+  if (warn_overloaded_virtual)
+    warn_hidden (t);
 
 #if 0
   /* This has to be done after we have sorted out what to do with
@@ -4109,13 +4187,13 @@ finish_struct (t, list_of_fieldlists, warn_anon)
     {
       /* Be smarter about nested classes here.  If a type is nested,
         only output it if we would output the enclosing type.  */
-      if (DECL_CONTEXT (TYPE_NAME (t))
-         && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (TYPE_NAME (t)))) == 't')
-       DECL_IGNORED_P (TYPE_NAME (t)) = TREE_ASM_WRITTEN (TYPE_NAME (t));
+      if (DECL_CONTEXT (TYPE_MAIN_DECL (t))
+         && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (TYPE_MAIN_DECL (t)))) == 't')
+       DECL_IGNORED_P (TYPE_MAIN_DECL (t)) = TREE_ASM_WRITTEN (TYPE_MAIN_DECL (t));
     }
 #endif
 
-  if (write_symbols != DWARF_DEBUG)
+  if (write_symbols != DWARF_DEBUG && write_symbols != DWARF2_DEBUG)
     {
       /* If the type has methods, we want to think about cutting down
         the amount of symbol table stuff we output.  The value stored in
@@ -4123,7 +4201,10 @@ finish_struct (t, list_of_fieldlists, warn_anon)
         For example, if a member function is seen and we decide to
         write out that member function, then we can change the value
         of the DECL_IGNORED_P slot, and the type will be output when
-        that member function's debug info is written out.  */
+        that member function's debug info is written out.
+
+        We can't do this with DWARF, which does not support name
+        references between translation units.  */
       if (CLASSTYPE_METHOD_VEC (t))
        {
          extern tree pending_vtables;
@@ -4131,20 +4212,212 @@ finish_struct (t, list_of_fieldlists, warn_anon)
          /* Don't output full info about any type
             which does not have its implementation defined here.  */
          if (TYPE_VIRTUAL_P (t) && write_virtuals == 2)
-           DECL_IGNORED_P (TYPE_NAME (t))
+           TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t))
              = (value_member (TYPE_IDENTIFIER (t), pending_vtables) == 0);
          else if (CLASSTYPE_INTERFACE_ONLY (t))
-           DECL_IGNORED_P (TYPE_NAME (t)) = 1;
+           TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+#if 0
+         /* XXX do something about this.  */
          else if (CLASSTYPE_INTERFACE_UNKNOWN (t))
            /* Only a first approximation!  */
-           DECL_IGNORED_P (TYPE_NAME (t)) = 1;
+           TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+#endif
        }
       else if (CLASSTYPE_INTERFACE_ONLY (t))
-       DECL_IGNORED_P (TYPE_NAME (t)) = 1;
+       TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
     }
 
   /* Finish debugging output for this type.  */
-  rest_of_type_compilation (t, global_bindings_p ());
+  rest_of_type_compilation (t, toplevel_bindings_p ());
+
+  return t;
+}
+
+tree
+finish_struct (t, list_of_fieldlists, attributes, warn_anon)
+     tree t, list_of_fieldlists, attributes;
+     int warn_anon;
+{
+  tree fields = NULL_TREE;
+  tree *tail = &TYPE_METHODS (t);
+  tree name = TYPE_NAME (t);
+  tree x, last_x = NULL_TREE;
+  tree access;
+  tree dummy = NULL_TREE;
+
+  if (TREE_CODE (name) == TYPE_DECL)
+    {
+      extern int lineno;
+         
+      DECL_SOURCE_FILE (name) = input_filename;
+      /* For TYPE_DECL that are not typedefs (those marked with a line
+        number of zero, we don't want to mark them as real typedefs.
+        If this fails one needs to make sure real typedefs have a
+        previous line number, even if it is wrong, that way the below
+        will fill in the right line number.  (mrs) */
+      if (DECL_SOURCE_LINE (name))
+       DECL_SOURCE_LINE (name) = lineno;
+      CLASSTYPE_SOURCE_LINE (t) = lineno;
+      name = DECL_NAME (name);
+    }
+
+  /* Append the fields we need for constructing signature tables.  */
+  if (IS_SIGNATURE (t))
+    append_signature_fields (list_of_fieldlists);
+
+  /* Move our self-reference declaration to the end of the field list so
+     any real field with the same name takes precedence.  */
+  if (list_of_fieldlists
+      && TREE_VALUE (list_of_fieldlists)
+      && DECL_ARTIFICIAL (TREE_VALUE (list_of_fieldlists)))
+    {
+      dummy = TREE_VALUE (list_of_fieldlists);
+      list_of_fieldlists = TREE_CHAIN (list_of_fieldlists);
+    }
+
+  if (last_x && list_of_fieldlists)
+    TREE_CHAIN (last_x) = TREE_VALUE (list_of_fieldlists);
+
+  while (list_of_fieldlists)
+    {
+      access = TREE_PURPOSE (list_of_fieldlists);
+
+      /* For signatures, we made all methods `public' in the parser and
+        reported an error if a access specifier was used.  */
+      if (access == access_default_node)
+       {
+         if (CLASSTYPE_DECLARED_CLASS (t) == 0)
+           access = access_public_node;
+         else
+           access = access_private_node;
+       }
+
+      for (x = TREE_VALUE (list_of_fieldlists); x; x = TREE_CHAIN (x))
+       {
+         TREE_PRIVATE (x) = access == access_private_node;
+         TREE_PROTECTED (x) = access == access_protected_node;
+
+         /* Check for inconsistent use of this name in the class body.
+             Enums, types and static vars have already been checked.  */
+         if (TREE_CODE (x) != TYPE_DECL && TREE_CODE (x) != USING_DECL
+             && TREE_CODE (x) != CONST_DECL && TREE_CODE (x) != VAR_DECL)
+           {
+             tree name = DECL_NAME (x);
+             tree icv;
+
+             /* Don't get confused by access decls.  */
+             if (name && TREE_CODE (name) == IDENTIFIER_NODE)
+               icv = IDENTIFIER_CLASS_VALUE (name);
+             else
+               icv = NULL_TREE;
+
+             if (icv
+                 /* Don't complain about constructors.  */
+                 && name != constructor_name (current_class_type)
+                 /* Or inherited names.  */
+                 && id_in_current_class (name)
+                 /* Or shadowed tags.  */
+                 && !(TREE_CODE (icv) == TYPE_DECL
+                      && DECL_CONTEXT (icv) == t))
+               {
+                 cp_error_at ("declaration of identifier `%D' as `%+#D'",
+                              name, x);
+                 cp_error_at ("conflicts with other use in class as `%#D'",
+                              icv);
+               }
+           }
+
+         if (TREE_CODE (x) == FUNCTION_DECL)
+           {
+             DECL_CLASS_CONTEXT (x) = t;
+             if (last_x)
+               TREE_CHAIN (last_x) = TREE_CHAIN (x);
+             /* Link x onto end of TYPE_METHODS.  */
+             *tail = x;
+             tail = &TREE_CHAIN (x);
+             continue;
+           }
+
+         if (TREE_CODE (x) != TYPE_DECL)
+           DECL_FIELD_CONTEXT (x) = t;
+
+         if (! fields)
+           fields = x;
+         last_x = x;
+       }
+      list_of_fieldlists = TREE_CHAIN (list_of_fieldlists);
+      /* link the tail while we have it! */
+      if (last_x)
+       {
+         TREE_CHAIN (last_x) = NULL_TREE;
+
+         if (list_of_fieldlists
+             && TREE_VALUE (list_of_fieldlists)
+             && TREE_CODE (TREE_VALUE (list_of_fieldlists)) != FUNCTION_DECL)
+           TREE_CHAIN (last_x) = TREE_VALUE (list_of_fieldlists);
+       }
+    }
+
+  /* Now add the tags, if any, to the list of TYPE_DECLs
+     defined for this type.  */
+  if (CLASSTYPE_TAGS (t) || dummy)
+    {
+      /* The list of tags was built up in pushtag in reverse order; we need
+        to fix that so that enumerators will be processed in forward order
+        in template instantiation.  */
+      CLASSTYPE_TAGS (t) = x = nreverse (CLASSTYPE_TAGS (t));
+      while (x)
+       {
+         tree tag = TYPE_MAIN_DECL (TREE_VALUE (x));
+
+         TREE_NONLOCAL_FLAG (TREE_VALUE (x)) = 0;
+         x = TREE_CHAIN (x);
+         last_x = chainon (last_x, tag);
+       }
+      if (dummy)
+       last_x = chainon (last_x, dummy);
+      if (fields == NULL_TREE)
+       fields = last_x;
+      CLASSTYPE_LOCAL_TYPEDECLS (t) = 1;
+    }
+
+  *tail = NULL_TREE;
+  TYPE_FIELDS (t) = fields;
+
+  cplus_decl_attributes (t, attributes, NULL_TREE);
+
+  if (processing_template_decl)
+    {
+      tree d = getdecls ();
+      for (; d; d = TREE_CHAIN (d))
+       {
+         /* If this is the decl for the class or one of the template
+             parms, we've seen all the injected decls.  */
+         if ((TREE_CODE (d) == TYPE_DECL
+              && (TREE_TYPE (d) == t
+                  || TREE_CODE (TREE_TYPE (d)) == TEMPLATE_TYPE_PARM))
+             || TREE_CODE (d) == CONST_DECL)
+           break;
+         /* Don't inject cache decls.  */
+         else if (IDENTIFIER_TEMPLATE (DECL_NAME (d)))
+           continue;
+         DECL_TEMPLATE_INJECT (CLASSTYPE_TI_TEMPLATE (t))
+           = tree_cons (NULL_TREE, d,
+                        DECL_TEMPLATE_INJECT (CLASSTYPE_TI_TEMPLATE (t)));
+       }
+      CLASSTYPE_METHOD_VEC (t)
+       = finish_struct_methods (t, TYPE_METHODS (t), 1);
+      TYPE_SIZE (t) = integer_zero_node;
+    }      
+  else
+    t = finish_struct_1 (t, warn_anon);
+
+  TYPE_BEING_DEFINED (t) = 0;
+
+  if (current_class_type)
+    popclass (0);
+  else
+    error ("trying to finish struct, but kicked out due to previous parse errors.");
 
   return t;
 }
@@ -4155,6 +4428,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
 
    *NONNULL is set iff INSTANCE can be known to be nonnull, regardless
    of our knowledge of its type.  */
+
 int
 resolves_to_fixed_type_p (instance, nonnull)
      tree instance;
@@ -4219,10 +4493,6 @@ resolves_to_fixed_type_p (instance, nonnull)
     case COMPONENT_REF:
       return resolves_to_fixed_type_p (TREE_OPERAND (instance, 1), nonnull);
 
-    case WITH_CLEANUP_EXPR:
-      if (TREE_CODE (TREE_OPERAND (instance, 0)) == ADDR_EXPR)
-       return resolves_to_fixed_type_p (TREE_OPERAND (instance, 0), nonnull);
-      /* fall through... */
     case VAR_DECL:
     case FIELD_DECL:
       if (TREE_CODE (TREE_TYPE (instance)) == ARRAY_TYPE
@@ -4232,7 +4502,7 @@ resolves_to_fixed_type_p (instance, nonnull)
            *nonnull = 1;
          return 1;
        }
-      /* fall through... */
+      /* fall through...  */
     case TARGET_EXPR:
     case PARM_DECL:
       if (IS_AGGR_TYPE (TREE_TYPE (instance)))
@@ -4243,7 +4513,7 @@ resolves_to_fixed_type_p (instance, nonnull)
        }
       else if (nonnull)
        {
-         if (instance == current_class_decl
+         if (instance == current_class_ptr
              && flag_this_is_variable <= 0)
            {
              /* Some people still use `this = 0' inside destructors.  */
@@ -4275,8 +4545,15 @@ init_class_processing ()
   current_lang_base = (tree *)xmalloc(current_lang_stacksize * sizeof (tree));
   current_lang_stack = current_lang_base;
 
+  access_default_node = build_int_2 (0, 0);
+  access_public_node = build_int_2 (1, 0);
+  access_protected_node = build_int_2 (2, 0);
+  access_private_node = build_int_2 (3, 0);
+  access_default_virtual_node = build_int_2 (4, 0);
+  access_public_virtual_node = build_int_2 (5, 0);
+  access_private_virtual_node = build_int_2 (6, 0);
+
   /* Keep these values lying around.  */
-  the_null_vtable_entry = build_vtable_entry (integer_zero_node, integer_zero_node);
   base_layout_decl = build_lang_field_decl (FIELD_DECL, NULL_TREE, error_mark_node);
   TREE_TYPE (base_layout_decl) = make_node (RECORD_TYPE);
 
@@ -4352,6 +4629,9 @@ pushclass (type, modify)
 
   pushlevel_class ();
 
+  if (CLASSTYPE_TEMPLATE_INFO (type))
+    overload_template_name (type);
+
   if (modify)
     {
       tree tags;
@@ -4364,24 +4644,17 @@ pushclass (type, modify)
       else
        current_function_decl = NULL_TREE;
 
-      if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
-        {
-          declare_uninstantiated_type_level ();
-         overload_template_name (current_class_name, 0);
-        }
-      else if (type != previous_class_type || current_class_depth > 1)
+      if (type != previous_class_type || current_class_depth > 1)
        {
          build_mi_matrix (type);
          push_class_decls (type);
          free_mi_matrix ();
-         if (current_class_depth == 1)
-           previous_class_type = type;
        }
       else
        {
          tree item;
 
-         /* Hooray, our cacheing was successful, let's just install the
+         /* Hooray, we successfully cached; let's just install the
             cached class_shadowed list, and walk through it to get the
             IDENTIFIER_TYPE_VALUEs correct.  */
          set_class_shadows (previous_class_values);
@@ -4406,22 +4679,17 @@ pushclass (type, modify)
 
       current_function_decl = this_fndecl;
     }
-
-  if (flag_cadillac)
-    cadillac_push_class (type);
 }
  
 /* Get out of the current class scope. If we were in a class scope
-   previously, that is the one popped to.  The flag MODIFY tells
-   whether the current scope declarations needs to be modified
-   as a result of popping to the previous scope.  */
+   previously, that is the one popped to.  The flag MODIFY tells whether
+   the current scope declarations needs to be modified as a result of
+   popping to the previous scope.  0 is used for class definitions.  */
+
 void
 popclass (modify)
      int modify;
 {
-  if (flag_cadillac)
-    cadillac_pop_class ();
-
   if (modify < 0)
     {
       /* Back this old class out completely.  */
@@ -4431,7 +4699,7 @@ popclass (modify)
       /* This code can be seen as a cache miss.  When we've cached a
         class' scope's bindings and we can't use them, we need to reset
         them.  This is it!  */
-      for (t = previous_class_values; t; t = TREE_CHAIN(t))
+      for (t = previous_class_values; t; t = TREE_CHAIN (t))
        IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (t)) = NULL_TREE;
       while (tags)
        {
@@ -4453,57 +4721,21 @@ popclass (modify)
          tags = TREE_CHAIN (tags);
        }
     }
-  if (TREE_CODE (current_class_type) == UNINSTANTIATED_P_TYPE)
-    undo_template_name_overload (current_class_name, 0);
 
-  poplevel_class ();
+  /* Force clearing of IDENTIFIER_CLASS_VALUEs after a class definition,
+     since not all class decls make it there currently.  */
+  poplevel_class (! modify);
 
   /* Since poplevel_class does the popping of class decls nowadays,
      this really only frees the obstack used for these decls.
      That's why it had to be moved down here.  */
   if (modify)
-    pop_class_decls (current_class_type);
+    pop_class_decls ();
 
   current_class_depth--;
   current_class_type = *--current_class_stack;
   current_class_name = *--current_class_stack;
 
-  if (current_class_type)
-    {
-      if (CLASSTYPE_VTBL_PTR (current_class_type))
-       {
-         current_vtable_decl = lookup_name (DECL_NAME (CLASSTYPE_VTBL_PTR (current_class_type)), 0);
-         if (current_vtable_decl)
-           current_vtable_decl = build_indirect_ref (current_vtable_decl,
-                                                     NULL_PTR);
-       }
-      current_class_decl = lookup_name (this_identifier, 0);
-      if (current_class_decl)
-       {
-         if (TREE_CODE (TREE_TYPE (current_class_decl)) == POINTER_TYPE)
-           {
-             tree temp;
-             /* Can't call build_indirect_ref here, because it has special
-                logic to return C_C_D given this argument.  */
-             C_C_D = build1 (INDIRECT_REF, current_class_type, current_class_decl);
-             temp = TREE_TYPE (TREE_TYPE (current_class_decl));
-             TREE_READONLY (C_C_D) = TYPE_READONLY (temp);
-             TREE_SIDE_EFFECTS (C_C_D) = TYPE_VOLATILE (temp);
-             TREE_THIS_VOLATILE (C_C_D) = TYPE_VOLATILE (temp);
-           }
-         else
-           C_C_D = current_class_decl;
-       }
-      else
-       C_C_D = NULL_TREE;
-    }
-  else
-    {
-      current_class_decl = NULL_TREE;
-      current_vtable_decl = NULL_TREE;
-      C_C_D = NULL_TREE;
-    }
-
   pop_memoized_context (modify);
 
  ret:
@@ -4522,7 +4754,13 @@ push_nested_class (type, modify)
      tree type;
      int modify;
 {
-  tree context = DECL_CONTEXT (TYPE_NAME (type));
+  tree context;
+
+  if (type == NULL_TREE || type == error_mark_node || ! IS_AGGR_TYPE (type)
+      || TREE_CODE (type) == TEMPLATE_TYPE_PARM)
+    return;
+  
+  context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
 
   if (context && TREE_CODE (context) == RECORD_TYPE)
     push_nested_class (context, 2);
@@ -4535,7 +4773,7 @@ void
 pop_nested_class (modify)
      int modify;
 {
-  tree context = DECL_CONTEXT (TYPE_NAME (current_class_type));
+  tree context = DECL_CONTEXT (TYPE_MAIN_DECL (current_class_type));
 
   popclass (modify);
   if (context && TREE_CODE (context) == RECORD_TYPE)
@@ -4571,39 +4809,32 @@ push_lang_context (name)
     }
   else
     error ("language string `\"%s\"' not recognized", IDENTIFIER_POINTER (name));
-
-  if (flag_cadillac)
-    cadillac_push_lang (name);
 }
   
 /* Get out of the current language scope.  */
+
 void
 pop_lang_context ()
 {
-  if (flag_cadillac)
-    cadillac_pop_lang ();
-
   current_lang_name = *--current_lang_stack;
   if (current_lang_name == lang_name_cplusplus)
     strict_prototype = strict_prototypes_lang_cplusplus;
   else if (current_lang_name == lang_name_c)
     strict_prototype = strict_prototypes_lang_c;
 }
-
-int
-root_lang_context_p ()
-{
-  return current_lang_stack == current_lang_base;
-}
 \f
 /* Type instantiation routines.  */
 
-/* This function will instantiate the type of the expression given
-   in RHS to match the type of LHSTYPE.  If LHSTYPE is NULL_TREE,
-   or other errors exist, the TREE_TYPE of RHS will be ERROR_MARK_NODE.
+/* This function will instantiate the type of the expression given in
+   RHS to match the type of LHSTYPE.  If errors exist, then return
+   error_mark_node.  If only complain is COMPLAIN is set.  If we are
+   not complaining, never modify rhs, as overload resolution wants to
+   try many possible instantiations, in hopes that at least one will
+   work.
 
    This function is used in build_modify_expr, convert_arguments,
    build_c_cast, and compute_conversion_costs.  */
+
 tree
 instantiate_type (lhstype, rhs, complain)
      tree lhstype, rhs;
@@ -4619,6 +4850,8 @@ instantiate_type (lhstype, rhs, complain)
   if (TREE_TYPE (rhs) != NULL_TREE && ! (type_unknown_p (rhs)))
     return rhs;
 
+  rhs = copy_node (rhs);
+
   /* This should really only be used when attempting to distinguish
      what sort of a pointer to function we have.  For now, any
      arithmetic operation which is not supported on pointers
@@ -4636,14 +4869,18 @@ instantiate_type (lhstype, rhs, complain)
 
     case INDIRECT_REF:
     case ARRAY_REF:
-      TREE_TYPE (rhs) = lhstype;
-      lhstype = build_pointer_type (lhstype);
-      TREE_OPERAND (rhs, 0)
-       = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
-      if (TREE_OPERAND (rhs, 0) == error_mark_node)
-       return error_mark_node;
+      {
+       tree new_rhs;
 
-      return rhs;
+       new_rhs = instantiate_type (build_pointer_type (lhstype),
+                                   TREE_OPERAND (rhs, 0), complain);
+       if (new_rhs == error_mark_node)
+         return error_mark_node;
+
+       TREE_TYPE (rhs) = lhstype;
+       TREE_OPERAND (rhs, 0) = new_rhs;
+       return rhs;
+      }
 
     case NOP_EXPR:
       rhs = copy_node (TREE_OPERAND (rhs, 0));
@@ -4670,6 +4907,7 @@ instantiate_type (lhstype, rhs, complain)
                  return error_mark_node;
                return build_vfn_ref (&base_ptr, base, DECL_VINDEX (function));
              }
+           mark_used (function);
            return function;
          }
 
@@ -4682,23 +4920,24 @@ instantiate_type (lhstype, rhs, complain)
        /* First look for an exact match  */
 
        while (field && TREE_TYPE (field) != lhstype)
-         field = TREE_CHAIN (field);
+         field = DECL_CHAIN (field);
        if (field)
          {
            TREE_OPERAND (rhs, 1) = field;
+           mark_used (field);
            return rhs;
          }
 
        /* No exact match found, look for a compatible function.  */
        field = TREE_OPERAND (rhs, 1);
        while (field && ! comptypes (lhstype, TREE_TYPE (field), 0))
-         field = TREE_CHAIN (field);
+         field = DECL_CHAIN (field);
        if (field)
          {
            TREE_OPERAND (rhs, 1) = field;
-           field = TREE_CHAIN (field);
+           field = DECL_CHAIN (field);
            while (field && ! comptypes (lhstype, TREE_TYPE (field), 0))
-             field = TREE_CHAIN (field);
+             field = DECL_CHAIN (field);
            if (field)
              {
                if (complain)
@@ -4720,16 +4959,13 @@ instantiate_type (lhstype, rhs, complain)
        tree elem, baselink, name;
        int globals = overloaded_globals_p (rhs);
 
-#if 0 /* obsolete */
-       /* If there's only one function we know about, return that.  */
-       if (globals > 0 && TREE_CHAIN (rhs) == NULL_TREE)
-         return TREE_VALUE (rhs);
-#endif
-
        /* First look for an exact match.  Search either overloaded
           functions or member functions.  May have to undo what
           `default_conversion' might do to lhstype.  */
 
+       if (TYPE_PTRMEMFUNC_P (lhstype))
+         lhstype = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
+
        if (TREE_CODE (lhstype) == POINTER_TYPE)
          if (TREE_CODE (TREE_TYPE (lhstype)) == FUNCTION_TYPE
              || TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE)
@@ -4753,50 +4989,78 @@ instantiate_type (lhstype, rhs, complain)
          {
            elem = get_first_fn (rhs);
            while (elem)
-             if (TREE_TYPE (elem) != lhstype)
+             if (! comptypes (lhstype, TREE_TYPE (elem), 1))
                elem = DECL_CHAIN (elem);
              else
-               return elem;
-           /* No exact match found, look for a compatible function.  */
+               {
+                 mark_used (elem);
+                 return elem;
+               }
+
+           /* No exact match found, look for a compatible template.  */
+           {
+             tree save_elem = 0;
+             for (elem = get_first_fn (rhs); elem; elem = DECL_CHAIN (elem))
+               if (TREE_CODE (elem) == TEMPLATE_DECL)
+                 {
+                   int n = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (elem));
+                   tree *t = (tree *) alloca (sizeof (tree) * n);
+                   int i, d = 0;
+                   i = type_unification (DECL_TEMPLATE_PARMS (elem), t,
+                                         TYPE_ARG_TYPES (TREE_TYPE (elem)),
+                                         TYPE_ARG_TYPES (lhstype), &d, 0, 1);
+                   if (i == 0)
+                     {
+                       if (save_elem)
+                         {
+                           cp_error ("ambiguous template instantiation converting to `%#T'", lhstype);
+                           return error_mark_node;
+                         }
+                       save_elem = instantiate_template (elem, t);
+                       /* Check the return type.  */
+                       if (! comptypes (TREE_TYPE (lhstype),
+                                        TREE_TYPE (TREE_TYPE (save_elem)), 1))
+                         save_elem = 0;
+                     }
+                 }
+             if (save_elem)
+               {
+                 mark_used (save_elem);
+                 return save_elem;
+               }
+           }
+
+           /* No match found, look for a compatible function.  */
            elem = get_first_fn (rhs);
-           while (elem && ! comp_target_types (lhstype, TREE_TYPE (elem), 1))
+           while (elem && comp_target_types (lhstype,
+                                             TREE_TYPE (elem), 1) <= 0)
              elem = DECL_CHAIN (elem);
            if (elem)
              {
                tree save_elem = elem;
                elem = DECL_CHAIN (elem);
-               while (elem && ! comp_target_types (lhstype, TREE_TYPE (elem),
-                                                   0))
+               while (elem && comp_target_types (lhstype,
+                                                 TREE_TYPE (elem), 0) <= 0)
                  elem = DECL_CHAIN (elem);
                if (elem)
                  {
                    if (complain)
                      {
-                       cp_error ("cannot resolve overload to target type `%#T';", lhstype);
-                       cp_error_at ("ambiguity between `%#D'", save_elem);
-                       cp_error_at ("and `%#D', at least", elem);
+                       cp_error ("cannot resolve overload to target type `%#T'",
+                                 lhstype);
+                       cp_error_at ("  ambiguity between `%#D'", save_elem);
+                       cp_error_at ("  and `%#D', at least", elem);
                      }
                    return error_mark_node;
                  }
-               if (TREE_CODE (save_elem) == TEMPLATE_DECL)
-                 {
-                   int ntparms = TREE_VEC_LENGTH
-                     (DECL_TEMPLATE_PARMS (save_elem));
-                   tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
-                   int i, dummy;
-                   i = type_unification
-                     (DECL_TEMPLATE_PARMS (save_elem), targs,
-                      TYPE_ARG_TYPES (TREE_TYPE (save_elem)),
-                      TYPE_ARG_TYPES (lhstype), &dummy, 0);
-                   save_elem = instantiate_template (save_elem, targs);
-                 }
+               mark_used (save_elem);
                return save_elem;
              }
            if (complain)
              {
-               cp_error ("cannot resolve overload to target type `%#T';",
+               cp_error ("cannot resolve overload to target type `%#T'",
                          lhstype);
-               cp_error ("no suitable overload of function `%D' exists",
+               cp_error ("  because no suitable overload of function `%D' exists",
                          TREE_PURPOSE (rhs));
              }
            return error_mark_node;
@@ -4822,10 +5086,13 @@ instantiate_type (lhstype, rhs, complain)
          {
            elem = TREE_VALUE (baselink);
            while (elem)
-             if (TREE_TYPE (elem) != lhstype)
-               elem = TREE_CHAIN (elem);
+             if (comptypes (lhstype, TREE_TYPE (elem), 1))
+               {
+                 mark_used (elem);
+                 return elem;
+               }
              else
-               return elem;
+               elem = DECL_CHAIN (elem);
          }
 
        /* No exact match found, look for a compatible method.  */
@@ -4833,27 +5100,31 @@ instantiate_type (lhstype, rhs, complain)
             baselink = next_baselink (baselink))
          {
            elem = TREE_VALUE (baselink);
-           while (elem && ! comp_target_types (lhstype, TREE_TYPE (elem), 1))
-             elem = TREE_CHAIN (elem);
+           while (elem && comp_target_types (lhstype,
+                                             TREE_TYPE (elem), 1) <= 0)
+             elem = DECL_CHAIN (elem);
            if (elem)
              {
                tree save_elem = elem;
-               elem = TREE_CHAIN (elem);
-               while (elem && ! comp_target_types (lhstype, TREE_TYPE (elem), 0))
-                 elem = TREE_CHAIN (elem);
+               elem = DECL_CHAIN (elem);
+               while (elem && comp_target_types (lhstype,
+                                                 TREE_TYPE (elem), 0) <= 0)
+                 elem = DECL_CHAIN (elem);
                if (elem)
                  {
                    if (complain)
                      error ("ambiguous overload for overloaded method requested");
                    return error_mark_node;
                  }
+               mark_used (save_elem);
                return save_elem;
              }
            name = DECL_NAME (TREE_VALUE (rhs));
+#if 0
            if (TREE_CODE (lhstype) == FUNCTION_TYPE && globals < 0)
              {
                /* Try to instantiate from non-member functions.  */
-               rhs = IDENTIFIER_GLOBAL_VALUE (name);
+               rhs = lookup_name_nonclass (name);
                if (rhs && TREE_CODE (rhs) == TREE_LIST)
                  {
                    /* This code seems to be missing a `return'.  */
@@ -4861,10 +5132,10 @@ instantiate_type (lhstype, rhs, complain)
                    instantiate_type (lhstype, rhs, complain);
                  }
              }
+#endif
          }
        if (complain)
-         error ("no static member functions named `%s'",
-                IDENTIFIER_POINTER (name));
+         cp_error ("no compatible member functions named `%D'", name);
        return error_mark_node;
       }
 
@@ -4876,10 +5147,12 @@ instantiate_type (lhstype, rhs, complain)
     case PLUS_EXPR:
     case MINUS_EXPR:
     case COMPOUND_EXPR:
-      TREE_OPERAND (rhs, 0) = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
+      TREE_OPERAND (rhs, 0)
+       = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
       if (TREE_OPERAND (rhs, 0) == error_mark_node)
        return error_mark_node;
-      TREE_OPERAND (rhs, 1) = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
+      TREE_OPERAND (rhs, 1)
+       = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
       if (TREE_OPERAND (rhs, 1) == error_mark_node)
        return error_mark_node;
 
@@ -4920,7 +5193,7 @@ instantiate_type (lhstype, rhs, complain)
     case POSTINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
       if (complain)
-       error ("illegal operation on uninstantiated type");
+       error ("invalid operation on uninstantiated type");
       return error_mark_node;
 
     case TRUTH_AND_EXPR:
@@ -4946,10 +5219,12 @@ instantiate_type (lhstype, rhs, complain)
            error ("not enough type information");
          return error_mark_node;
        }
-      TREE_OPERAND (rhs, 1) = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
+      TREE_OPERAND (rhs, 1)
+       = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
       if (TREE_OPERAND (rhs, 1) == error_mark_node)
        return error_mark_node;
-      TREE_OPERAND (rhs, 2) = instantiate_type (lhstype, TREE_OPERAND (rhs, 2), complain);
+      TREE_OPERAND (rhs, 2)
+       = instantiate_type (lhstype, TREE_OPERAND (rhs, 2), complain);
       if (TREE_OPERAND (rhs, 2) == error_mark_node)
        return error_mark_node;
 
@@ -4957,7 +5232,8 @@ instantiate_type (lhstype, rhs, complain)
       return rhs;
 
     case MODIFY_EXPR:
-      TREE_OPERAND (rhs, 1) = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
+      TREE_OPERAND (rhs, 1)
+       = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
       if (TREE_OPERAND (rhs, 1) == error_mark_node)
        return error_mark_node;
 
@@ -4965,19 +5241,29 @@ instantiate_type (lhstype, rhs, complain)
       return rhs;
       
     case ADDR_EXPR:
-      if (TREE_CODE (lhstype) != POINTER_TYPE)
+      if (TYPE_PTRMEMFUNC_P (lhstype))
+       lhstype = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
+      else if (TREE_CODE (lhstype) != POINTER_TYPE)
        {
          if (complain)
            error ("type for resolving address of overloaded function must be pointer type");
          return error_mark_node;
        }
-      TREE_TYPE (rhs) = lhstype;
-      lhstype = TREE_TYPE (lhstype);
-      TREE_OPERAND (rhs, 0) = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
-      if (TREE_OPERAND (rhs, 0) == error_mark_node)
-       return error_mark_node;
-
-      mark_addressable (TREE_OPERAND (rhs, 0));
+      {
+       tree fn = instantiate_type (TREE_TYPE (lhstype), TREE_OPERAND (rhs, 0), complain);
+       if (fn == error_mark_node)
+         return error_mark_node;
+       mark_addressable (fn);
+       TREE_TYPE (rhs) = lhstype;
+       TREE_OPERAND (rhs, 0) = fn;
+       TREE_CONSTANT (rhs) = staticp (fn);
+       if (TREE_CODE (lhstype) == POINTER_TYPE &&
+           TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE)
+         {
+           build_ptrmemfunc_type (lhstype);
+           rhs = build_ptrmemfunc (lhstype, rhs, 0);
+         }
+      }
       return rhs;
 
     case ENTRY_VALUE_EXPR:
@@ -4998,6 +5284,7 @@ instantiate_type (lhstype, rhs, complain)
    this may have to look back through base types to find the
    ultimate field name.  (For single inheritance, these could
    all be the same name.  Who knows for multiple inheritance).  */
+
 static tree
 get_vfield_name (type)
      tree type;
@@ -5039,6 +5326,7 @@ print_class_statistics ()
    decls that may be cached in the previous_class_values list.  For now, let's
    use the permanent obstack, later we may create a dedicated obstack just
    for this purpose.  The effect is undone by pop_obstacks.  */
+
 void
 maybe_push_cache_obstack ()
 {
@@ -5046,3 +5334,24 @@ maybe_push_cache_obstack ()
   if (current_class_depth == 1)
     current_obstack = &permanent_obstack;
 }
+
+/* Build a dummy reference to ourselves so Derived::Base (and A::A) works,
+   according to [class]:
+                                          The class-name is also inserted
+   into  the scope of the class itself.  For purposes of access checking,
+   the inserted class name is treated as if it were a public member name.  */
+
+tree
+build_self_reference ()
+{
+  tree name = constructor_name (current_class_type);
+  tree value = build_lang_decl (TYPE_DECL, name, current_class_type);
+  DECL_NONLOCAL (value) = 1;
+  DECL_CONTEXT (value) = current_class_type;
+  DECL_CLASS_CONTEXT (value) = current_class_type;
+  CLASSTYPE_LOCAL_TYPEDECLS (current_class_type) = 1;
+  DECL_ARTIFICIAL (value) = 1;
+
+  pushdecl_class_level (value);
+  return value;
+}