OSDN Git Service

Fix typos in comments.
[pf3gnuchains/gcc-fork.git] / gcc / cp / decl.c
index a3eadc4..e695ce2 100644 (file)
@@ -1,5 +1,5 @@
 /* Process declarations and variables for C compiler.
-   Copyright (C) 1988, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -41,10 +41,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
+extern tree builtin_return_address_fndecl;
+
 extern struct obstack permanent_obstack;
 
 extern int current_class_depth;
 
+extern tree cleanups_this_call;
+
+extern tree static_ctors, static_dtors;
+
 /* Stack of places to restore the search obstack back to.  */
    
 /* Obstack used for remembering local class declarations (like
@@ -89,6 +95,14 @@ static struct stack_level *decl_stack;
 #define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
 #endif
 
+#ifndef BOOL_TYPE_SIZE
+#ifdef SLOW_BYTE_ACCESS
+#define BOOL_TYPE_SIZE BITS_PER_WORD
+#else
+#define BOOL_TYPE_SIZE BITS_PER_UNIT
+#endif
+#endif
+
 /* We let tm.h override the types used here, to handle trivial differences
    such as the choice of unsigned int or long unsigned int for size_t.
    When machines start needing nontrivial differences in the size type,
@@ -107,22 +121,10 @@ static struct stack_level *decl_stack;
 #define WCHAR_TYPE "int"
 #endif
 
-#define builtin_function(NAME, TYPE, CODE, LIBNAME) \
-  define_function (NAME, TYPE, CODE, (void (*)())pushdecl, LIBNAME)
-#define auto_function(NAME, TYPE, CODE) \
-  do {                                 \
-    tree __name = NAME;                \
-    tree __type = TYPE;                        \
-    define_function (IDENTIFIER_POINTER (__name), __type, CODE,        \
-                    (void (*)())push_overloaded_decl_1,        \
-                    IDENTIFIER_POINTER (build_decl_overload (__name, TYPE_ARG_TYPES (__type), 0)));\
-  } while (0)
-
 static tree grokparms                          PROTO((tree, int));
 static tree lookup_nested_type                 PROTO((tree, tree));
 static char *redeclaration_error_message       PROTO((tree, tree));
 static void grok_op_properties                 PROTO((tree, int, int));
-static void deactivate_exception_cleanups      PROTO((void));
 
 tree define_function           
        PROTO((char *, tree, enum built_in_function, void (*)(), char *));
@@ -159,6 +161,8 @@ tree wchar_type_node;
 tree signed_wchar_type_node;
 tree unsigned_wchar_type_node;
 
+tree wchar_decl_node;
+
 tree float_type_node;
 tree double_type_node;
 tree long_double_type_node;
@@ -201,6 +205,9 @@ tree int_array_type_node;
 
 tree wchar_array_type_node;
 
+/* The bool data type, and constants */
+tree boolean_type_node, boolean_true_node, boolean_false_node;
+
 /* type `int ()' -- used for implicit declaration of functions.  */
 
 tree default_function_type;
@@ -226,30 +233,34 @@ tree int_ftype_cptr_cptr_sizet;
 /* C++ extensions */
 tree vtable_entry_type;
 tree delta_type_node;
-tree __t_desc_type_node, __i_desc_type_node, __m_desc_type_node;
+#if 0
+/* Old rtti stuff. */
+tree __baselist_desc_type_node;
+tree __i_desc_type_node, __m_desc_type_node;
 tree __t_desc_array_type, __i_desc_array_type, __m_desc_array_type;
+#endif
+tree __t_desc_type_node, __tp_desc_type_node;
+tree __access_mode_type_node;
+tree __bltn_desc_type_node, __user_desc_type_node, __class_desc_type_node;
+tree __ptr_desc_type_node, __attr_desc_type_node, __func_desc_type_node;
+tree __ptmf_desc_type_node, __ptmd_desc_type_node;
+#if 0
+/* Not needed yet?  May be needed one day?  */
+tree __bltn_desc_array_type, __user_desc_array_type, __class_desc_array_type;
+tree __ptr_desc_array_type, __attr_dec_array_type, __func_desc_array_type;
+tree __ptmf_desc_array_type, __ptmd_desc_array_type;
+#endif
+
 tree class_star_type_node;
 tree class_type_node, record_type_node, union_type_node, enum_type_node;
-tree exception_type_node, unknown_type_node;
+tree unknown_type_node;
 tree opaque_type_node, signature_type_node;
 tree sigtable_entry_type;
 tree maybe_gc_cleanup;
 
-/* Used for virtual function tables.  */
-tree vtbl_mask;
-
 /* Array type `vtable_entry_type[]' */
 tree vtbl_type_node;
 
-/* Static decls which do not have static initializers have no
-   initializers as far as GNU C is concerned.  EMPTY_INIT_NODE
-   is a static initializer which makes varasm code place the decl
-   in data rather than in bss space.  Such gymnastics are necessary
-   to avoid the problem that the linker will not include a library
-   file if all the library appears to contribute are bss variables.  */
-
-tree empty_init_node;
-
 /* In a destructor, the point at which all derived class destroying
    has been done, just before any base class destroying will be done.  */
 
@@ -260,12 +271,6 @@ tree dtor_label;
 
 tree ctor_label;
 
-/* A FUNCTION_DECL which can call `unhandled_exception'.
-   Not necessarily the one that the user will declare,
-   but sufficient to be called by routines that want to abort the program.  */
-
-tree unhandled_exception_fndecl;
-
 /* A FUNCTION_DECL which can call `abort'.  Not necessarily the
    one that the user will declare, but sufficient to be called
    by routines that want to abort the program.  */
@@ -310,16 +315,6 @@ static tree named_label_uses;
    in the TREE_PURPOSE slot.  */
 tree static_aggregates;
 
-/* A list of functions which were declared inline, but later had their
-   address taken.  Used only for non-virtual member functions, since we can
-   find other functions easily enough.  */
-tree pending_addressable_inlines;
-
-/* A list of overloaded functions which we should forget ever
-   existed, such as functions declared in a function's scope,
-   once we leave that function's scope.  */
-static tree overloads_to_forget;
-
 /* -- end of C++ */
 
 /* Two expressions that are constants with value zero.
@@ -345,6 +340,10 @@ int pending_invalid_xref_line;
 
 static tree enum_next_value;
 
+/* Nonzero means that there was overflow computing enum_next_value.  */
+
+static int enum_overflow;
+
 /* Parsing a function declarator leaves a list of parameter names
    or a chain or parameter decls here.  */
 
@@ -407,10 +406,6 @@ tree current_function_return_value;
 
 static int warn_about_return_type;
 
-/* Nonzero when starting a function declared `extern inline'.  */
-
-static int current_extern_inline;
-
 /* Nonzero means give `double' the same size as `float'.  */
 
 extern int flag_short_double;
@@ -419,14 +414,13 @@ extern int flag_short_double;
 
 extern int flag_no_builtin;
 
-/* Nonzero means do emit exported implementations of functions even if
-   they can be inlined.  */
+/* Nonzero means don't recognize the non-ANSI builtin functions.
+   -ansi sets this.  */
 
-extern int flag_implement_inlines;
+extern int flag_no_nonansi_builtin;
 
-/* Nonzero means handle things in ANSI, instead of GNU fashion.  This
-   flag should be tested for language behavior that's different between
-   ANSI and GNU, but not so horrible as to merit a PEDANTIC label.  */
+/* Nonzero means enable obscure ANSI features and disable GNU extensions
+   that might cause ANSI-compliant code to be miscompiled.  */
 
 extern int flag_ansi;
 
@@ -436,7 +430,7 @@ extern int flag_huge_objects;
 
 /* Nonzero if we want to conserve space in the .o files.  We do this
    by putting uninitialized data and runtime initialized data into
-   .common instead of .data at the expense of not flaging multiple
+   .common instead of .data at the expense of not flagging multiple
    definitions.  */
 extern int flag_conserve_space;
 
@@ -444,7 +438,7 @@ extern int flag_conserve_space;
 
 extern tree *current_lang_base, *current_lang_stack;
 \f
-/* C and C++ flags are in cp-decl2.c.  */
+/* C and C++ flags are in decl2.c.  */
 
 /* Set to 0 at beginning of a constructor, set to 1
    if that function does an allocation before referencing its
@@ -465,7 +459,7 @@ int current_function_obstack_index;
 
 int current_function_obstack_usage;
 
-/* Flag used when debugging cp-spew.c */
+/* Flag used when debugging spew.c */
 
 extern int spew_debug;
 
@@ -554,7 +548,7 @@ struct binding_level
 
     /* Number of decls in `names' that have incomplete 
        structure or union types.  */
-    unsigned short n_incomplete;
+    unsigned int n_incomplete;
 
     /* 1 for the level that holds the parameters of a function.
        2 for the level that holds a class declaration.
@@ -573,11 +567,6 @@ struct binding_level
     unsigned more_cleanups_ok : 1;
     unsigned have_cleanups : 1;
 
-    /* Nonzero if this level can safely have additional
-       exception-raising statements added to it.  */
-    unsigned more_exceptions_ok : 1;
-    unsigned have_exceptions : 1;
-
     /* Nonzero if we should accept any name as an identifier in
        this scope.  This happens in some template definitions.  */
     unsigned accept_any : 1;
@@ -666,7 +655,6 @@ push_binding_level (newlevel, tag_transparent, keep)
   current_binding_level = newlevel;
   newlevel->tag_transparent = tag_transparent;
   newlevel->more_cleanups_ok = 1;
-  newlevel->more_exceptions_ok = 1;
   newlevel->keep = keep;
 #if defined(DEBUG_CP_BINDING_LEVELS)
   newlevel->binding_depth = binding_depth;
@@ -760,23 +748,6 @@ declare_parm_level ()
   current_binding_level->parm_flag = 1;
 }
 
-/* Identify this binding level as a level of a default exception handler.  */
-
-void
-declare_implicit_exception ()
-{
-  current_binding_level->parm_flag = 3;
-}
-
-/* Nonzero if current binding contour contains expressions
-   that might raise exceptions.  */
-
-int
-have_exceptions_p ()
-{
-  return current_binding_level->have_exceptions;
-}
-
 void
 declare_uninstantiated_type_level ()
 {
@@ -957,7 +928,8 @@ poplevel (keep, reverse, functionbody)
     if (TREE_CODE (decl) == FUNCTION_DECL
        && ! TREE_ASM_WRITTEN (decl)
        && DECL_INITIAL (decl) != NULL_TREE
-       && TREE_ADDRESSABLE (decl))
+       && TREE_ADDRESSABLE (decl)
+       && decl_function_context (decl) == current_function_decl)
       {
        /* If this decl was copied from a file-scope decl
           on account of a block-scope extern decl,
@@ -1114,7 +1086,7 @@ poplevel (keep, reverse, functionbody)
     }
 
   /* Take care of compiler's internal binding structures.  */
-  if (tmp == 2 && !implicit_try_block)
+  if (tmp == 2)
     {
 #if 0
       /* We did not call push_momentary for this
@@ -1235,9 +1207,11 @@ pushlevel_class ()
   while (current_binding_level->parm_flag == 2);
 }
 
-/* ...and a poplevel for class declarations.  */
+/* ...and a poplevel for class declarations.  FORCE is used to force
+   clearing out of CLASS_VALUEs after a class definition.  */
 tree
-poplevel_class ()
+poplevel_class (force)
+     int force;
 {
   register struct binding_level *level = class_binding_level;
   tree block = NULL_TREE;
@@ -1249,11 +1223,11 @@ poplevel_class ()
   for (shadowed = level->shadowed; shadowed; shadowed = TREE_CHAIN (shadowed))
     IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed);
   /* If we're leaving a toplevel class, don't bother to do the setting
-     of IDENTIFER_CLASS_VALUE to NULL_TREE, since first of all this slot
+     of IDENTIFIER_CLASS_VALUE to NULL_TREE, since first of all this slot
      shouldn't even be used when current_class_type isn't set, and second,
-     if we don't touch it here, we're able to use the caching effect if the
+     if we don't touch it here, we're able to use the cache effect if the
      next time we're entering a class scope, it is the same class.  */
-  if (current_class_depth != 1)
+  if (current_class_depth != 1 || force)
     for (shadowed = level->class_shadowed;
         shadowed;
         shadowed = TREE_CHAIN (shadowed))
@@ -1307,10 +1281,6 @@ print_binding_level (lvl)
     fprintf (stderr, " more-cleanups-ok");
   if (lvl->have_cleanups)
     fprintf (stderr, " have-cleanups");
-  if (lvl->more_exceptions_ok)
-    fprintf (stderr, " more-exceptions-ok");
-  if (lvl->have_exceptions)
-    fprintf (stderr, " have-exceptions");
   fprintf (stderr, "\n");
   if (lvl->names)
     {
@@ -1469,8 +1439,12 @@ struct saved_scope {
   tree old_bindings;
   struct saved_scope *prev;
   tree class_name, class_type, class_decl, function_decl;
+  tree base_init_list, member_init_list;
   struct binding_level *class_bindings;
   tree previous_class_type;
+  tree *lang_base, *lang_stack, lang_name;
+  int lang_stacksize;
+  tree named_labels;
 };
 static struct saved_scope *current_saved_scope;
 extern tree prev_class_type;
@@ -1478,6 +1452,7 @@ extern tree prev_class_type;
 void
 push_to_top_level ()
 {
+  extern int current_lang_stacksize;
   struct saved_scope *s =
     (struct saved_scope *) xmalloc (sizeof (struct saved_scope));
   struct binding_level *b = current_binding_level;
@@ -1541,12 +1516,25 @@ push_to_top_level ()
   s->class_type = current_class_type;
   s->class_decl = current_class_decl;
   s->function_decl = current_function_decl;
+  s->base_init_list = current_base_init_list;
+  s->member_init_list = current_member_init_list;
   s->class_bindings = class_binding_level;
   s->previous_class_type = previous_class_type;
+  s->lang_stack = current_lang_stack;
+  s->lang_base = current_lang_base;
+  s->lang_stacksize = current_lang_stacksize;
+  s->lang_name = current_lang_name;
+  s->named_labels = named_labels;
   current_class_name = current_class_type = current_class_decl = NULL_TREE;
   current_function_decl = NULL_TREE;
   class_binding_level = (struct binding_level *)0;
   previous_class_type = NULL_TREE;
+  current_lang_stacksize = 10;
+  current_lang_stack = current_lang_base
+    = (tree *) xmalloc (current_lang_stacksize * sizeof (tree));
+  current_lang_name = lang_name_cplusplus;
+  strict_prototype = strict_prototypes_lang_cplusplus;
+  named_labels = NULL_TREE;
 
   s->prev = current_saved_scope;
   s->old_bindings = old_bindings;
@@ -1556,6 +1544,7 @@ push_to_top_level ()
 void
 pop_from_top_level ()
 {
+  extern int current_lang_stacksize;
   struct saved_scope *s = current_saved_scope;
   tree t;
 
@@ -1581,9 +1570,22 @@ pop_from_top_level ()
     C_C_D = CLASSTYPE_INST_VAR (current_class_type);
   else
     C_C_D = NULL_TREE;
+  current_base_init_list = s->base_init_list;
+  current_member_init_list = s->member_init_list;
   current_function_decl = s->function_decl;
   class_binding_level = s->class_bindings;
   previous_class_type = s->previous_class_type;
+  free (current_lang_base);
+  current_lang_base = s->lang_base;
+  current_lang_stack = s->lang_stack;
+  current_lang_name = s->lang_name;
+  current_lang_stacksize = s->lang_stacksize;
+  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;
+  named_labels = s->named_labels;
+
   free (s);
 }
 \f
@@ -1633,26 +1635,66 @@ static void
 set_nested_typename (decl, classname, name, type)
      tree decl, classname, name, type;
 {
+  char *buf;
   my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 136);
-  if (classname != NULL_TREE)
-    {
-      char *buf;
-      my_friendly_assert (TREE_CODE (classname) == IDENTIFIER_NODE, 137);
-      my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 138);
-      buf = (char *) alloca (4 + IDENTIFIER_LENGTH (classname)
-                            + IDENTIFIER_LENGTH (name));
-      sprintf (buf, "%s::%s", IDENTIFIER_POINTER (classname),
-              IDENTIFIER_POINTER (name));
-      DECL_NESTED_TYPENAME (decl) = get_identifier (buf);
-
-      /* This is a special usage of IDENTIFIER_TYPE_VALUE which have no
-        correspondence in any binding_level.  This is ok since the
-        DECL_NESTED_TYPENAME is just a convenience identifier whose
-        IDENTIFIER_TYPE_VALUE will remain constant from now on.  */
-      SET_IDENTIFIER_TYPE_VALUE (DECL_NESTED_TYPENAME (decl), type);
+
+  /* No need to do this for anonymous names, since they're unique.  */
+  if (ANON_AGGRNAME_P (name))
+    {
+      DECL_NESTED_TYPENAME (decl) = name;
+      return;
     }
-  else
-    DECL_NESTED_TYPENAME (decl) = name;
+
+  if (classname == NULL_TREE)
+    classname = get_identifier ("");
+
+  my_friendly_assert (TREE_CODE (classname) == IDENTIFIER_NODE, 137);
+  my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 138);
+  buf = (char *) alloca (4 + IDENTIFIER_LENGTH (classname)
+                        + IDENTIFIER_LENGTH (name));
+  sprintf (buf, "%s::%s", IDENTIFIER_POINTER (classname),
+          IDENTIFIER_POINTER (name));
+  DECL_NESTED_TYPENAME (decl) = get_identifier (buf);
+  TREE_MANGLED (DECL_NESTED_TYPENAME (decl)) = 1;
+
+  /* Create an extra decl so that the nested name will have a type value
+     where appropriate.  */
+  {
+    tree nested, type_decl;
+    nested = DECL_NESTED_TYPENAME (decl);
+    type_decl = build_decl (TYPE_DECL, nested, type);
+    DECL_NESTED_TYPENAME (type_decl) = nested;
+    SET_DECL_ARTIFICIAL (type_decl);
+    /* Mark the TYPE_DECL node created just above as a gratuitous one so that
+       dwarfout.c will know not to generate a TAG_typedef DIE for it, and
+       sdbout.c won't try to output a .def for "::foo".  */
+    DECL_IGNORED_P (type_decl) = 1;
+
+    /* Remove this when local classes are fixed.  */
+    SET_IDENTIFIER_TYPE_VALUE (nested, type);
+
+    pushdecl_nonclass_level (type_decl);
+  }
+}
+
+/* Pop off extraneous binding levels left over due to syntax errors.  */
+void
+pop_everything ()
+{
+#ifdef DEBUG_CP_BINDING_LEVELS
+  fprintf (stderr, "XXX entering pop_everything ()\n");
+#endif
+  while (current_binding_level != global_binding_level
+        && ! current_binding_level->pseudo_global)
+    {
+      if (class_binding_level)
+       pop_nested_class (1);
+      else
+       poplevel (0, 0, 0);
+    }
+#ifdef DEBUG_CP_BINDING_LEVELS
+  fprintf (stderr, "XXX leaving pop_everything ()\n");
+#endif
 }
 
 #if 0 /* not yet, should get fixed properly later */
@@ -1661,7 +1703,7 @@ set_nested_typename (decl, classname, name, type)
    incorrect results with `-g' unless they duplicate this code.
 
    This is currently needed mainly for dbxout.c, but we can make
-   use of it in cp-method.c later as well.  */
+   use of it in method.c later as well.  */
 tree
 make_type_decl (name, type)
      tree name, type;
@@ -1687,7 +1729,7 @@ make_type_decl (name, type)
 #endif
 
 /* Push a tag name NAME for struct/class/union/enum type TYPE.
-   Normally put into into the inner-most non-tag-tranparent scope,
+   Normally put into into the inner-most non-tag-transparent scope,
    but if GLOBALIZE is true, put it in the inner-most non-class scope.
    The latter is needed for implicit declarations. */
 
@@ -1697,7 +1739,8 @@ pushtag (name, type, globalize)
      int globalize;
 {
   register struct binding_level *b;
-  tree t_context = 0;
+  tree context = 0;
+  tree c_decl = 0;
 
   b = inner_binding_level;
   while (b->tag_transparent
@@ -1711,19 +1754,21 @@ pushtag (name, type, globalize)
 
   if (name)
     {
-      t_context = type ? TYPE_CONTEXT(type) : NULL_TREE;
-      if (!t_context && !globalize)
-        t_context = current_class_type;
+      context = type ? TYPE_CONTEXT (type) : NULL_TREE;
+      if (! context && ! globalize)
+        context = current_scope ();
+      if (context)
+       c_decl = TREE_CODE (context) == FUNCTION_DECL
+         ? context : TYPE_MAIN_DECL (context);
 
+#if 0
       /* Record the identifier as the type's name if it has none.  */
       if (TYPE_NAME (type) == NULL_TREE)
         TYPE_NAME (type) = name;
+#endif
       
       /* Do C++ gratuitous typedefing.  */
-      if (IDENTIFIER_TYPE_VALUE (name) != type
-         && (TREE_CODE (type) != RECORD_TYPE
-             || b->parm_flag != 2
-             || !CLASSTYPE_DECLARED_EXCEPTION (type)))
+      if (IDENTIFIER_TYPE_VALUE (name) != type)
         {
           register tree d;
          int newdecl = 0;
@@ -1731,11 +1776,7 @@ pushtag (name, type, globalize)
          if (b->parm_flag != 2
              || TYPE_SIZE (current_class_type) != NULL_TREE)
            {
-             if (current_lang_name == lang_name_cplusplus)
-               d = lookup_nested_type (type, 
-                       t_context ? TYPE_NAME (t_context) : NULL_TREE);
-             else
-               d = NULL_TREE;
+             d = lookup_nested_type (type, c_decl);
 
              if (d == NULL_TREE)
                {
@@ -1745,6 +1786,7 @@ pushtag (name, type, globalize)
 #else
                  d = build_decl (TYPE_DECL, name, type);
 #endif
+                 SET_DECL_ARTIFICIAL (d);
 #ifdef DWARF_DEBUGGING_INFO
                  if (write_symbols == DWARF_DEBUG)
                    {
@@ -1760,14 +1802,11 @@ pushtag (name, type, globalize)
              else
                d = TYPE_NAME (d);
 
+             TYPE_NAME (type) = d;
+
              /* If it is anonymous, then we are called from pushdecl,
-                and we don't want to infinitely recurse.  Also, if the
-                name is already in scope, we don't want to push it
-                again--pushdecl is only for pushing new decls.  */
-             if (! ANON_AGGRNAME_P (name)
-                 && TYPE_NAME (type)
-                 && (TREE_CODE (TYPE_NAME (type)) != TYPE_DECL
-                     || lookup_name (name, 1) != TYPE_NAME (type)))
+                and we don't want to infinitely recurse.  */
+             if (! ANON_AGGRNAME_P (name))
                {
                  if (b->parm_flag == 2)
                    d = pushdecl_class_level (d);
@@ -1779,7 +1818,8 @@ pushtag (name, type, globalize)
            {
              /* Make nested declarations go into class-level scope.  */
              newdecl = 1;
-             d = build_lang_field_decl (TYPE_DECL, name, type);
+             d = build_decl (TYPE_DECL, name, type);
+             SET_DECL_ARTIFICIAL (d);
 #ifdef DWARF_DEBUGGING_INFO
              if (write_symbols == DWARF_DEBUG)
                {
@@ -1790,6 +1830,9 @@ pushtag (name, type, globalize)
                  DECL_IGNORED_P (d) = 1;
                }
 #endif /* DWARF_DEBUGGING_INFO */
+
+             TYPE_MAIN_DECL (type) = d;
+
              /* Make sure we're in this type's scope when we push the
                 decl for a template, otherwise class_binding_level will
                 be NULL and we'll end up dying inside of
@@ -1800,41 +1843,31 @@ pushtag (name, type, globalize)
              if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
                popclass (0);
            }
-         if (write_symbols != DWARF_DEBUG)
-           {
-             if (ANON_AGGRNAME_P (name))
-               DECL_IGNORED_P (d) = 1;
-           }
-         TYPE_NAME (type) = d;
-
-         if ((t_context == NULL_TREE
-              && current_function_decl == NULL_TREE)
-             || current_lang_name != lang_name_cplusplus)
-           /* Non-nested class.  */
-           DECL_NESTED_TYPENAME (d) = name;
-         else if (current_function_decl != NULL_TREE)
-           {
-             /* Function-nested class.  */
-             set_nested_typename (d, 
-               DECL_ASSEMBLER_NAME (current_function_decl), name, type);
-             /* This builds the links for classes nested in fn scope.  */
-             DECL_CONTEXT (d) = current_function_decl;
-           }
-/*        else if (TYPE_SIZE (current_class_type) == NULL_TREE)
-*/
-         else if (t_context && TREE_CODE (t_context) == RECORD_TYPE)
+         if (newdecl)
            {
-             /* Class-nested class.  */
-             set_nested_typename (d, 
-               DECL_NESTED_TYPENAME (TYPE_NAME (t_context)), name, type);
-             /* This builds the links for classes nested in type scope.  */
-             DECL_CONTEXT (d) = t_context;
-             DECL_CLASS_CONTEXT (d) = t_context;
+             if (write_symbols != DWARF_DEBUG)
+               {
+                 if (ANON_AGGRNAME_P (name))
+                   DECL_IGNORED_P (d) = 1;
+               }
+
+             if (context == NULL_TREE)
+               /* Non-nested class.  */
+               set_nested_typename (d, NULL_TREE, name, type);
+             else if (context && TREE_CODE (context) == FUNCTION_DECL)
+               /* Function-nested class.  */
+               set_nested_typename (d, DECL_ASSEMBLER_NAME (c_decl),
+                                    name, type);
+             else /* if (context && IS_AGGR_TYPE (context)) */
+               /* Class-nested class.  */
+               set_nested_typename (d, DECL_NESTED_TYPENAME (c_decl),
+                                    name, type);
+
+             DECL_CONTEXT (d) = context;
+             TYPE_CONTEXT (type) = DECL_CONTEXT (d);
+             DECL_ASSEMBLER_NAME (d)
+               = get_identifier (build_overload_name (type, 1, 1));
            }
-         TYPE_CONTEXT (type) = DECL_CONTEXT (d);
-         if (newdecl)
-           DECL_ASSEMBLER_NAME (d)
-             = get_identifier (build_overload_name (type, 1, 1));
         }
       if (b->parm_flag == 2)
        {
@@ -1916,13 +1949,14 @@ clear_anon_tags ()
    For C++, we must compare the parameter list so that `int' can match
    `int&' in a parameter position, but `int&' is not confused with
    `const int&'.  */
-static int
+int
 decls_match (newdecl, olddecl)
      tree newdecl, olddecl;
 {
   int types_match;
 
-  if (TREE_CODE (newdecl) == FUNCTION_DECL && TREE_CODE (olddecl) == FUNCTION_DECL)
+  if (TREE_CODE (newdecl) == FUNCTION_DECL
+      && TREE_CODE (olddecl) == FUNCTION_DECL)
     {
       tree f1 = TREE_TYPE (newdecl);
       tree f2 = TREE_TYPE (olddecl);
@@ -1934,10 +1968,10 @@ decls_match (newdecl, olddecl)
         is METHOD_TYPE.  Change that to FUNCTION_TYPE, and
         proceed.  */
       if (TREE_CODE (f1) == METHOD_TYPE && DECL_STATIC_FUNCTION_P (olddecl))
-       revert_static_member_fn (&f1, &newdecl, &p1);
+       revert_static_member_fn (&newdecl, &f1, &p1);
       else if (TREE_CODE (f2) == METHOD_TYPE
               && DECL_STATIC_FUNCTION_P (newdecl))
-       revert_static_member_fn (&f2, &olddecl, &p2);
+       revert_static_member_fn (&olddecl, &f2, &p2);
 
       /* Here we must take care of the case where new default
         parameters are specified.  Also, warn if an old
@@ -1952,18 +1986,66 @@ decls_match (newdecl, olddecl)
          return 0;
        }
 
-      if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (f1)),
-                    TYPE_MAIN_VARIANT (TREE_TYPE (f2)), 2))
-       types_match = compparms (p1, p2, 2);
+      if (comptypes (TREE_TYPE (f1), TREE_TYPE (f2), 1))
+       {
+         if (! strict_prototypes_lang_c && DECL_LANGUAGE (olddecl) == lang_c
+             && p2 == NULL_TREE)
+           {
+             types_match = self_promoting_args_p (p1);
+             if (p1 == void_list_node)
+               TREE_TYPE (newdecl) = TREE_TYPE (olddecl);
+           }
+         else if (!strict_prototypes_lang_c && DECL_LANGUAGE (olddecl)==lang_c
+                  && DECL_LANGUAGE (newdecl) == lang_c && p1 == NULL_TREE)
+           {
+             types_match = self_promoting_args_p (p2);
+             TREE_TYPE (newdecl) = TREE_TYPE (olddecl);
+           }
+         else
+           types_match = compparms (p1, p2, 3);
+       }
       else
        types_match = 0;
     }
+  else if (TREE_CODE (newdecl) == TEMPLATE_DECL
+          && TREE_CODE (olddecl) == TEMPLATE_DECL)
+    {
+       tree newargs = DECL_TEMPLATE_PARMS (newdecl);
+       tree oldargs = DECL_TEMPLATE_PARMS (olddecl);
+       int i, len = TREE_VEC_LENGTH (newargs);
+
+       if (TREE_VEC_LENGTH (oldargs) != len)
+         return 0;
+       
+       for (i = 0; i < len; i++)
+         {
+           tree newarg = TREE_VALUE (TREE_VEC_ELT (newargs, i));
+           tree oldarg = TREE_VALUE (TREE_VEC_ELT (oldargs, i));
+           if (TREE_CODE (newarg) != TREE_CODE (oldarg))
+             return 0;
+           else if (TREE_CODE (newarg) == TYPE_DECL)
+             /* continue */;
+           else if (! comptypes (TREE_TYPE (newarg), TREE_TYPE (oldarg), 1))
+             return 0;
+         }
+
+       if (DECL_TEMPLATE_IS_CLASS (newdecl)
+           != DECL_TEMPLATE_IS_CLASS (olddecl))
+         types_match = 0;
+       else if (DECL_TEMPLATE_IS_CLASS (newdecl))
+         types_match = 1;
+       else
+         types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
+                                    DECL_TEMPLATE_RESULT (newdecl));
+    }
   else
     {
       if (TREE_TYPE (newdecl) == error_mark_node)
        types_match = TREE_TYPE (olddecl) == error_mark_node;
       else if (TREE_TYPE (olddecl) == NULL_TREE)
        types_match = TREE_TYPE (newdecl) == NULL_TREE;
+      else if (TREE_TYPE (newdecl) == NULL_TREE)
+       types_match = 0;
       else
        types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 1);
     }
@@ -1996,13 +2078,11 @@ warn_extern_redeclared_static (newdecl, olddecl)
     = "`%D' was declared implicitly `extern' and later `static'";
 
   if (flag_traditional
-      || TREE_CODE (newdecl) == TYPE_DECL
-      || (! warn_extern_inline
-         && DECL_INLINE (newdecl)))
+      || TREE_CODE (newdecl) == TYPE_DECL)
     return;
 
   name = DECL_ASSEMBLER_NAME (newdecl);
-  if (TREE_PUBLIC (name) && ! TREE_PUBLIC (newdecl))
+  if (TREE_PUBLIC (name) && DECL_THIS_STATIC (newdecl))
     {
       /* It's okay to redeclare an ANSI built-in function as static,
         or to declare a non-ANSI built-in function as anything.  */
@@ -2028,7 +2108,7 @@ warn_extern_redeclared_static (newdecl, olddecl)
    If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
    Otherwise, return 0.  */
 
-static int
+int
 duplicate_decls (newdecl, olddecl)
      register tree newdecl, olddecl;
 {
@@ -2038,43 +2118,10 @@ duplicate_decls (newdecl, olddecl)
   int new_defines_function;
   tree previous_c_decl = NULL_TREE;
 
-  if (TREE_CODE (newdecl) == FUNCTION_DECL
-      && is_overloaded_fn (olddecl))
-    {
-      olddecl = get_first_fn (olddecl);
-
-      while (olddecl)
-       {
-         if (DECL_LANGUAGE (olddecl) == lang_c)
-           previous_c_decl = olddecl;
-
-         /* Redeclaration.  */
-         if (decls_match (newdecl, olddecl))
-           {
-             types_match = 1;
-             break;
-           }
-         /* Ambiguous overload.  */
-         else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
-                             TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 2))
-           break;
+  if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd')
+    DECL_MACHINE_ATTRIBUTES (newdecl) = DECL_MACHINE_ATTRIBUTES (olddecl);
 
-         /* Attempt to define multiple C-binding fns.  */
-         if (previous_c_decl)
-           break;
-         
-         olddecl = DECL_CHAIN (olddecl);
-       }
-      if (!olddecl)
-       {
-         /* If we found no match, make this join the other
-            overloaded decls.  */
-         DECL_OVERLOADED (newdecl) = 1;
-         return 1;
-       }
-    }
-  else
-    types_match = decls_match (newdecl, olddecl);
+  types_match = decls_match (newdecl, olddecl);
 
   if (TREE_CODE (olddecl) != TREE_LIST)
     olddecl_friend = DECL_LANG_SPECIFIC (olddecl) && DECL_FRIEND_P (olddecl);
@@ -2090,147 +2137,113 @@ duplicate_decls (newdecl, olddecl)
          && TREE_CODE (TREE_TYPE (olddecl)) == ERROR_MARK))
     types_match = 1;
 
-  if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
-    {
-      cp_error ("`%#D' redeclared as different kind of symbol", newdecl);
-      if (TREE_CODE (olddecl) == TREE_LIST)
-       olddecl = TREE_VALUE (olddecl);
-      cp_error_at ("previous declaration of `%#D'", olddecl);
-
-      /* New decl is completely inconsistent with the old one =>
-        tell caller to replace the old one.  */
-
-      return 0;
-    }
-
   if (flag_traditional && TREE_CODE (newdecl) == FUNCTION_DECL
       && IDENTIFIER_IMPLICIT_DECL (DECL_ASSEMBLER_NAME (newdecl)) == olddecl)
     /* If -traditional, avoid error for redeclaring fcn
        after implicit decl.  */
     ;
   else if (TREE_CODE (olddecl) == FUNCTION_DECL
-          && (DECL_BUILT_IN (olddecl)
-              || DECL_BUILT_IN_NONANSI (olddecl)))
+          && DECL_ARTIFICIAL (olddecl)
+          && (DECL_BUILT_IN (olddecl) || DECL_BUILT_IN_NONANSI (olddecl)))
     {
       /* If you declare a built-in or predefined function name as static,
-        the old definition is overridden,
-        but optionally warn this was a bad choice of name.  */
-      if (! TREE_PUBLIC (newdecl))
+        the old definition is overridden, but optionally warn this was a
+        bad choice of name.  Ditto for overloads.  */
+      if (! DECL_PUBLIC (newdecl)
+         || (TREE_CODE (newdecl) == FUNCTION_DECL
+             && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)))
        {
          if (warn_shadow)
            cp_warning ("shadowing %s function `%#D'",
                        DECL_BUILT_IN (olddecl) ? "built-in" : "library",
-                       newdecl);
+                       olddecl);
          /* Discard the old built-in function.  */
          return 0;
        }
-      /* Likewise, if the built-in is not ansi, then programs can
-        override it even globally without an error.  */
-      else if (! DECL_BUILT_IN (olddecl))
-       cp_warning ("library function `%#D' declared as non-function",
-                   newdecl);
-
-      if (!types_match)
+      else if (! types_match)
        {
+         if (TREE_CODE (newdecl) != FUNCTION_DECL)
+           {
+             /* If the built-in is not ansi, then programs can override
+                it even globally without an error.  */
+             if (! DECL_BUILT_IN (olddecl))
+               cp_warning ("library function `%#D' redeclared as non-function `%#D'",
+                           olddecl, newdecl);
+             else
+               {
+                 cp_error ("declaration of `%#D'", newdecl);
+                 cp_error ("conflicts with built-in declaration `%#D'",
+                           olddecl);
+               }
+             return 0;
+           }
+
          cp_warning ("declaration of `%#D'", newdecl);
          cp_warning ("conflicts with built-in declaration `%#D'",
                      olddecl);
-         return 0;
        }
     }
-  else if (!types_match && previous_c_decl
-          && DECL_LANGUAGE (newdecl) == lang_c)
+  else if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
     {
-      cp_error ("declaration of C function `%#D' conflicts with", newdecl);
-      cp_error_at ("previous declaration `%#D' here", previous_c_decl);
+      if ((TREE_CODE (newdecl) == FUNCTION_DECL
+          && TREE_CODE (olddecl) == TEMPLATE_DECL
+          && ! DECL_TEMPLATE_IS_CLASS (olddecl))
+         || (TREE_CODE (olddecl) == FUNCTION_DECL
+             && TREE_CODE (newdecl) == TEMPLATE_DECL
+             && ! DECL_TEMPLATE_IS_CLASS (newdecl)))
+       return 0;
+      
+      cp_error ("`%#D' redeclared as different kind of symbol", newdecl);
+      if (TREE_CODE (olddecl) == TREE_LIST)
+       olddecl = TREE_VALUE (olddecl);
+      cp_error_at ("previous declaration of `%#D'", olddecl);
+
+      /* New decl is completely inconsistent with the old one =>
+        tell caller to replace the old one.  */
+
+      return 0;
     }
   else if (!types_match)
     {
-      tree oldtype = TREE_TYPE (olddecl);
-      tree newtype = TREE_TYPE (newdecl);
-      int give_error = 0;
-
-      /* Already complained about this, so don't do so again.  */
-      if (current_class_type == NULL_TREE
-         || IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl)) != current_class_type)
+      if (TREE_CODE (newdecl) == TEMPLATE_DECL)
        {
-         give_error = 1;
-
-         /* Since we're doing this before finish_struct can set the
-            line number on NEWDECL, we just do a regular error here.  */
-         if (DECL_SOURCE_LINE (newdecl) == 0)
-           cp_error ("conflicting types for `%#D'", newdecl);
-         else
-           cp_error_at ("conflicting types for `%#D'", newdecl);
+         /* The name of a class template may not be declared to refer to
+            any other template, class, function, object, namespace, value,
+            or type in the same scope. */
+         if (DECL_TEMPLATE_IS_CLASS (olddecl)
+             || DECL_TEMPLATE_IS_CLASS (newdecl))
+           {
+             cp_error ("declaration of template `%#D'", newdecl);
+             cp_error_at ("conflicts with previous declaration `%#D'",
+                          olddecl);
+           }
+         return 0;
        }
-
-      /* Check for function type mismatch
-        involving an empty arglist vs a nonempty one.  */
-      if (TREE_CODE (olddecl) == FUNCTION_DECL
-         && comptypes (TREE_TYPE (oldtype),
-                       TREE_TYPE (newtype), 1)
-         && ((TYPE_ARG_TYPES (oldtype) == NULL_TREE
-              && DECL_INITIAL (olddecl) == NULL_TREE)
-             || (TYPE_ARG_TYPES (newtype) == NULL_TREE
-                 && DECL_INITIAL (newdecl) == NULL_TREE)))
+      if (TREE_CODE (newdecl) == FUNCTION_DECL)
        {
-         /* Classify the problem further.  */
-         register tree t = TYPE_ARG_TYPES (oldtype);
-
-         if (t == NULL_TREE)
-           t = TYPE_ARG_TYPES (newtype);
-         for (; t; t = TREE_CHAIN (t))
+         if (DECL_LANGUAGE (newdecl) == lang_c
+             && DECL_LANGUAGE (olddecl) == lang_c)
            {
-             register tree type = TREE_VALUE (t);
-
-             if (TREE_CHAIN (t) == NULL_TREE && type != void_type_node)
-               {
-                 give_error = 1;
-                 error ("A parameter list with an ellipsis can't match");
-                 error ("an empty parameter name list declaration.");
-                 break;
-               }
-
-             if (TYPE_MAIN_VARIANT (type) == float_type_node
-                 || C_PROMOTING_INTEGER_TYPE_P (type))
-               {
-                 give_error = 1;
-                 error ("An argument type that has a default promotion");
-                 error ("can't match an empty parameter name list declaration.");
-                 break;
-               }
+             cp_error ("declaration of C function `%#D' conflicts with",
+                       newdecl);
+             cp_error_at ("previous declaration `%#D' here", olddecl);
            }
+         else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
+                             TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 3))
+           {
+             cp_error ("new declaration `%#D'", newdecl);
+             cp_error_at ("ambiguates old declaration `%#D'", olddecl);
+           }
+         else
+           return 0;
        }
-      if (give_error)
-       cp_error_at ("previous declaration as `%#D'", olddecl);
 
-      /* There is one thing GNU C++ cannot tolerate: a constructor
-        which takes the type of object being constructed.
-        Farm that case out here.  */
-      if (TREE_CODE (newdecl) == FUNCTION_DECL
-         && DECL_CONSTRUCTOR_P (newdecl))
+      /* Already complained about this, so don't do so again.  */
+      else if (current_class_type == NULL_TREE
+         || IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl)) != current_class_type)
        {
-         tree tmp = TREE_CHAIN (TYPE_ARG_TYPES (newtype));
-
-         if (tmp != NULL_TREE
-             && (TYPE_MAIN_VARIANT (TREE_VALUE (tmp))
-                 == TYPE_METHOD_BASETYPE (newtype)))
-           {
-             tree parm = TREE_CHAIN (DECL_ARGUMENTS (newdecl));
-             tree argtypes
-               = hash_tree_chain (build_reference_type (TREE_VALUE (tmp)),
-                                  TREE_CHAIN (tmp));
-
-             DECL_ARG_TYPE (parm)
-               = TREE_TYPE (parm)
-                 = TYPE_REFERENCE_TO (TREE_VALUE (tmp));
-
-             TREE_TYPE (newdecl) = newtype
-               = build_cplus_method_type (TYPE_METHOD_BASETYPE (newtype),
-                                          TREE_TYPE (newtype), argtypes);
-             error ("constructor cannot take as argument the type being constructed");
-             SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl), current_class_type);
-           }
+         cp_error ("conflicting types for `%#D'", newdecl);
+         cp_error_at ("previous declaration as `%#D'", olddecl);
        }
     }
   else
@@ -2238,7 +2251,7 @@ duplicate_decls (newdecl, olddecl)
       char *errmsg = redeclaration_error_message (newdecl, olddecl);
       if (errmsg)
        {
-         error_with_decl (newdecl, errmsg);
+         cp_error (errmsg, newdecl);
          if (DECL_NAME (olddecl) != NULL_TREE)
            cp_error_at ((DECL_INITIAL (olddecl)
                          && current_binding_level == global_binding_level)
@@ -2256,24 +2269,65 @@ duplicate_decls (newdecl, olddecl)
        }
       else if (TREE_CODE (olddecl) == FUNCTION_DECL
               && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl))
-       /* extern "C" int foo ();
-          int foo () { bar (); }
-          is OK.  */
-       if (current_lang_stack == current_lang_base)
-         DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl);
-       else
-         {
-           cp_error_at ("previous declaration of `%#D' with %L linkage",
-                        olddecl, DECL_LANGUAGE (olddecl));
-           cp_error ("conflicts with new declaration with %L linkage",
-                     DECL_LANGUAGE (newdecl));
-         }
+       {
+         /* extern "C" int foo ();
+            int foo () { bar (); }
+            is OK.  */
+         if (current_lang_stack == current_lang_base)
+           DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl);
+         else
+           {
+             cp_error_at ("previous declaration of `%#D' with %L linkage",
+                          olddecl, DECL_LANGUAGE (olddecl));
+             cp_error ("conflicts with new declaration with %L linkage",
+                       DECL_LANGUAGE (newdecl));
+           }
+       }
+
+      if (TREE_CODE (olddecl) == FUNCTION_DECL)
+       {
+         tree t1 = TYPE_ARG_TYPES (TREE_TYPE (olddecl));
+         tree t2 = TYPE_ARG_TYPES (TREE_TYPE (newdecl));
+         int i = 1;
+
+         if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE)
+           t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2);
+       
+         for (; t1 && t1 != void_list_node;
+              t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2), i++)
+           if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
+             {
+               if (simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+                 {
+                   if (pedantic)
+                     {
+                       cp_pedwarn ("default argument given for parameter %d of `%#D'",
+                                   i, newdecl);
+                       cp_pedwarn_at ("after previous specification in `%#D'",
+                                      olddecl);
+                     }
+                 }
+               else
+                 {
+                   cp_error ("default argument given for parameter %d of `%#D'",
+                             i, newdecl);
+                   cp_error_at ("conflicts with previous specification in `%#D'",
+                                olddecl);
+                 }
+             }
 
-      /* These bits are logically part of the type.  */
-      if (pedantic
-         && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
-             || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl)))
-       cp_error_at ("type qualifiers for `%D' conflict with previous decl", newdecl);
+         if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl)
+             && TREE_ADDRESSABLE (olddecl))
+           cp_pedwarn ("`%#D' was used before it was declared inline",
+                       newdecl);
+       }
+      /* These bits are logically part of the type for non-functions.  */
+      else if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
+              || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))
+       {
+         cp_pedwarn ("type qualifiers for `%#D'", newdecl);
+         cp_pedwarn_at ("conflict with previous decl `%#D'", olddecl);
+       }
     }
 
   /* If new decl is `static' and an `extern' was seen previously,
@@ -2295,8 +2349,13 @@ duplicate_decls (newdecl, olddecl)
        DECL_CLASS_CONTEXT (newdecl) = DECL_CLASS_CONTEXT (olddecl);
       if (DECL_CHAIN (newdecl) == NULL_TREE)
        DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
+      if (DECL_NEXT_METHOD (newdecl) == NULL_TREE)
+       DECL_NEXT_METHOD (newdecl) = DECL_NEXT_METHOD (olddecl);
       if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0)
        DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl);
+      DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl);
+      DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
+      DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl);
     }
 
   /* Deal with C++: must preserve virtual function table size.  */
@@ -2305,6 +2364,8 @@ duplicate_decls (newdecl, olddecl)
       register tree newtype = TREE_TYPE (newdecl);
       register tree oldtype = TREE_TYPE (olddecl);
 
+      DECL_NESTED_TYPENAME (newdecl) = DECL_NESTED_TYPENAME (olddecl);
+
       if (newtype != error_mark_node && oldtype != error_mark_node
          && TYPE_LANG_SPECIFIC (newtype) && TYPE_LANG_SPECIFIC (oldtype))
        {
@@ -2312,6 +2373,7 @@ duplicate_decls (newdecl, olddecl)
          CLASSTYPE_FRIEND_CLASSES (newtype)
            = CLASSTYPE_FRIEND_CLASSES (oldtype);
        }
+#if 0
       /* why assert here?  Just because debugging information is
         messed up? (mrs) */
       /* it happens on something like:
@@ -2320,8 +2382,8 @@ duplicate_decls (newdecl, olddecl)
                        int     x;
                } Thing;
       */
-#if 0
-      my_friendly_assert (DECL_IGNORED_P (olddecl) == DECL_IGNORED_P (newdecl), 139);
+      my_friendly_assert (DECL_IGNORED_P (olddecl) == DECL_IGNORED_P (newdecl),
+                         139);
 #endif
     }
 
@@ -2332,13 +2394,13 @@ duplicate_decls (newdecl, olddecl)
   /* Optionally warn about more than one declaration for the same name,
      but don't warn about a function declaration followed by a definition.  */
   if (warn_redundant_decls
-      && DECL_SOURCE_LINE (olddecl) != 0
+      && ! DECL_ARTIFICIAL (olddecl)
       && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE)
       /* Don't warn about extern decl followed by (tentative) definition.  */
       && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)))
     {
       cp_warning ("redundant redeclaration of `%D' in same scope", newdecl);
-      cp_warning ("previous declaration of `%D'", olddecl);
+      cp_warning_at ("previous declaration of `%D'", olddecl);
     }
 
   /* Copy all the DECL_... slots specified in the new decl
@@ -2348,8 +2410,19 @@ duplicate_decls (newdecl, olddecl)
     {
       /* Automatically handles default parameters.  */
       tree oldtype = TREE_TYPE (olddecl);
+      tree newtype;
+
+      /* Make sure we put the new type in the same obstack as the old one.  */
+      if (oldtype)
+       push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
+      else
+       {
+         push_obstacks_nochange ();
+         end_temporary_allocation ();
+       }
+
       /* Merge the data types specified in the two decls.  */
-      tree newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
+      newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
 
       if (TREE_CODE (newdecl) == VAR_DECL)
        DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl);
@@ -2366,29 +2439,26 @@ duplicate_decls (newdecl, olddecl)
          TREE_TYPE (olddecl) = build_exception_variant (ctype, newtype,
                                                         TYPE_RAISES_EXCEPTIONS (oldtype));
 
-         if (! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE(olddecl), 0))
+         if (! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0))
            {
-             cp_error ("declaration of `%D' raises different exceptions...", newdecl);
+             cp_error ("declaration of `%D' throws different exceptions...",
+                       newdecl);
              cp_error_at ("...from previous declaration here", olddecl);
            }
        }
       TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
 
       /* Lay the type out, unless already done.  */
-      if (oldtype != TREE_TYPE (newdecl))
-       {
-         if (TREE_TYPE (newdecl) != error_mark_node)
-           layout_type (TREE_TYPE (newdecl));
-         if (TREE_CODE (newdecl) != FUNCTION_DECL
-             && TREE_CODE (newdecl) != TYPE_DECL
-             && TREE_CODE (newdecl) != CONST_DECL)
-           layout_decl (newdecl, 0);
-       }
-      else
-       {
-         /* Since the type is OLDDECL's, make OLDDECL's size go with.  */
-         DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
-       }
+      if (oldtype != TREE_TYPE (newdecl)
+         && TREE_TYPE (newdecl) != error_mark_node)
+       layout_type (TREE_TYPE (newdecl));
+
+      if (TREE_CODE (newdecl) == VAR_DECL
+         || TREE_CODE (newdecl) == PARM_DECL
+         || TREE_CODE (newdecl) == RESULT_DECL
+         || TREE_CODE (newdecl) == FIELD_DECL
+         || TREE_CODE (newdecl) == TYPE_DECL)
+       layout_decl (newdecl, 0);
 
       /* Merge the type qualifiers.  */
       if (TREE_READONLY (newdecl))
@@ -2397,14 +2467,29 @@ duplicate_decls (newdecl, olddecl)
        TREE_THIS_VOLATILE (olddecl) = 1;
 
       /* Merge the initialization information.  */
-      if (DECL_INITIAL (newdecl) == NULL_TREE)
-       DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+      if (DECL_INITIAL (newdecl) == NULL_TREE
+         && DECL_INITIAL (olddecl) != NULL_TREE)
+       {
+         DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+         DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
+         DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
+       }
+
+      /* Merge the section attribute.
+         We want to issue an error if the sections conflict but that must be
+        done later in decl_attributes since we are called before attributes
+        are assigned.  */
+      if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
+       DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
+
       /* Keep the old rtl since we can safely use it, unless it's the
         call to abort() used for abstract virtuals.  */
       if ((DECL_LANG_SPECIFIC (olddecl)
           && !DECL_ABSTRACT_VIRTUAL_P (olddecl))
          || DECL_RTL (olddecl) != DECL_RTL (abort_fndecl))
        DECL_RTL (newdecl) = DECL_RTL (olddecl);
+
+      pop_obstacks ();
     }
   /* If cannot merge, then use the new type and qualifiers,
      and don't preserve the old rtl.  */
@@ -2422,45 +2507,55 @@ duplicate_decls (newdecl, olddecl)
     }
 
   /* Merge the storage class information.  */
-  if (DECL_EXTERNAL (newdecl))
+  if (DECL_EXTERNAL (newdecl) && ! DECL_INTERFACE_KNOWN (newdecl)
+      && ! (DECL_LANG_SPECIFIC (newdecl) && DECL_NOT_REALLY_EXTERN (newdecl)))
     {
       TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
       DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
+      TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
 
-      /* For functions, static overrides non-static.  */
       if (TREE_CODE (newdecl) == FUNCTION_DECL)
        {
-         TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
-         /* This is since we don't automatically
-            copy the attributes of NEWDECL into OLDDECL.  */
-         TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
-         /* If this clears `static', clear it in the identifier too.  */
-         if (! TREE_PUBLIC (olddecl))
-           TREE_PUBLIC (DECL_ASSEMBLER_NAME (olddecl)) = 0;
+         DECL_C_STATIC (newdecl) = DECL_C_STATIC (olddecl);
+         DECL_INTERFACE_KNOWN (newdecl) = DECL_INTERFACE_KNOWN (olddecl);
+         DECL_NOT_REALLY_EXTERN (newdecl) = DECL_NOT_REALLY_EXTERN (olddecl);
        }
-      else
-       TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
     }
   else
     {
       TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
-      /* A `const' which was not declared `extern' and is
-        in static storage is invisible.  */
+      /* A `const' which was not declared `extern' gets internal linkage.  */
       if (TREE_CODE (newdecl) == VAR_DECL
-         && TREE_READONLY (newdecl) && TREE_STATIC (newdecl)
-         && ! DECL_THIS_EXTERN (newdecl))
+         && TREE_READONLY (newdecl) && ! DECL_THIS_EXTERN (newdecl))
        TREE_PUBLIC (newdecl) = 0;
-      TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
-    }
+      else
+       {
+         TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
 
-  /* If either decl says `inline', this fn is inline,
-     unless its definition was passed already.  */
-  if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == NULL_TREE)
-    DECL_INLINE (olddecl) = 1;
-  DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
+         /* If this clears PUBLIC, clear it in the identifier too.  */
+         if (TREE_CODE (newdecl) == FUNCTION_DECL && ! TREE_PUBLIC (olddecl))
+           TREE_PUBLIC (DECL_ASSEMBLER_NAME (olddecl)) = 0;
+       }
+    }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
+      DECL_THIS_INLINE (newdecl) |= DECL_THIS_INLINE (olddecl);
+
+      /* If either decl says `inline', this fn is inline, unless its
+         definition was passed already.  */
+      if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == NULL_TREE)
+       DECL_INLINE (olddecl) = 1;
+      DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
+
+      if (! types_match)
+       {
+         DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl);
+         DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl);
+         DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl);
+         DECL_RESULT (olddecl) = DECL_RESULT (newdecl);
+         DECL_RTL (olddecl) = DECL_RTL (newdecl);
+       }
       if (new_defines_function)
        /* If defining a function declared with other language
           linkage, use the previously declared language linkage.  */
@@ -2472,7 +2567,7 @@ duplicate_decls (newdecl, olddecl)
          if (DECL_BUILT_IN (olddecl))
            {
              DECL_BUILT_IN (newdecl) = 1;
-             DECL_SET_FUNCTION_CODE (newdecl, DECL_FUNCTION_CODE (olddecl));
+             DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
              /* If we're keeping the built-in definition, keep the rtl,
                 regardless of declaration matches.  */
              DECL_RTL (newdecl) = DECL_RTL (olddecl);
@@ -2481,7 +2576,7 @@ duplicate_decls (newdecl, olddecl)
            DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl);
 
          DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
-         if (DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl))
+         if ((DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl)))
            /* Previously saved insns go together with
               the function's previous definition.  */
            DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
@@ -2489,12 +2584,26 @@ duplicate_decls (newdecl, olddecl)
          if (DECL_ARGUMENTS (olddecl))
            DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
        }
+      if (DECL_LANG_SPECIFIC (olddecl))
+       DECL_MAIN_VARIANT (newdecl) = DECL_MAIN_VARIANT (olddecl);
     }
 
+  if (TREE_CODE (newdecl) == TEMPLATE_DECL)
+    {
+      if (DECL_TEMPLATE_INFO (olddecl)->length)
+       DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
+      DECL_TEMPLATE_MEMBERS (newdecl) = DECL_TEMPLATE_MEMBERS (olddecl);
+      DECL_TEMPLATE_INSTANTIATIONS (newdecl)
+       = DECL_TEMPLATE_INSTANTIATIONS (olddecl);
+      if (DECL_CHAIN (newdecl) == NULL_TREE)
+       DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
+    }
+  
   /* Now preserve various other info from the definition.  */
   TREE_ADDRESSABLE (newdecl) = TREE_ADDRESSABLE (olddecl);
   TREE_ASM_WRITTEN (newdecl) = TREE_ASM_WRITTEN (olddecl);
   DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
+  DECL_ASSEMBLER_NAME (newdecl) = DECL_ASSEMBLER_NAME (olddecl);
 
   /* Don't really know how much of the language-specific
      values we should copy from old to new.  */
@@ -2502,6 +2611,7 @@ duplicate_decls (newdecl, olddecl)
     {
       DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
       DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
+      DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
     }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -2592,10 +2702,9 @@ pushdecl (x)
     nglobals = len;
 #endif
 
-  /* Don't change DECL_CONTEXT of virtual methods.  */
   if (x != current_function_decl
-      && (TREE_CODE (x) != FUNCTION_DECL
-         || !DECL_VIRTUAL_P (x))
+      /* Don't change DECL_CONTEXT of virtual methods.  */
+      && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
       && ! DECL_CONTEXT (x))
     DECL_CONTEXT (x) = current_function_decl;
   /* A local declaration for a function doesn't constitute nesting.  */
@@ -2613,7 +2722,7 @@ pushdecl (x)
 #else
   /* Type are looked up using the DECL_NAME, as that is what the rest of the
      compiler wants to use. */
-  if (TREE_CODE (x) == TYPE_DECL)
+  if (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL)
     name = DECL_NAME (x);
 #endif
 
@@ -2630,7 +2739,7 @@ pushdecl (x)
          cp_error_at ("`%#D' used prior to declaration", x);
        }
 
-      if (t != NULL_TREE)
+      else if (t != NULL_TREE)
        {
          if (TREE_CODE (t) == PARM_DECL)
            {
@@ -2639,57 +2748,82 @@ pushdecl (x)
            }
          file = DECL_SOURCE_FILE (t);
          line = DECL_SOURCE_LINE (t);
-       }
 
-      if (t != NULL_TREE
-         && (TREE_CODE (t) != TREE_CODE (x) || is_overloaded_fn (t)))
-       {
-         if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (x) == TYPE_DECL)
+         if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c)
+              || (TREE_CODE (x) == TEMPLATE_DECL
+                  && ! DECL_TEMPLATE_IS_CLASS (x)))
+             && is_overloaded_fn (t))
+           /* don't do anything just yet */;
+         else if (t == wchar_decl_node)
            {
-             /* We do nothing special here, because C++ does such nasty
-                things with TYPE_DECLs.  Instead, just let the TYPE_DECL
-                get shadowed, and know that if we need to find a TYPE_DECL
-                for a given name, we can look in the IDENTIFIER_TYPE_VALUE
-                slot of the identifier.  */
-             ;
+             if (pedantic && ! DECL_IN_SYSTEM_HEADER (x))
+               cp_pedwarn ("redeclaration of wchar_t as `%T'", TREE_TYPE (x));
+
+             /* Throw away the redeclaration.  */
+             return t;
            }
-         else if (duplicate_decls (x, t))
-           return t;
-       }
-      else if (t != NULL_TREE && duplicate_decls (x, t))
-       {
-#if 0
-         /* This is turned off until I have time to do it right (bpk).  */
-
-         /* Also warn if they did a prototype with `static' on it, but
-            then later left the `static' off.  */
-         else if (! TREE_PUBLIC (name) && TREE_PUBLIC (x))
+         else if (TREE_CODE (t) != TREE_CODE (x))
            {
-             if (DECL_LANG_SPECIFIC (t) && DECL_FRIEND_P (t))
+             if ((TREE_CODE (t) == TYPE_DECL && DECL_ARTIFICIAL (t))
+                 || (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)))
+               {
+                 /* We do nothing special here, because C++ does such nasty
+                    things with TYPE_DECLs.  Instead, just let the TYPE_DECL
+                    get shadowed, and know that if we need to find a TYPE_DECL
+                    for a given name, we can look in the IDENTIFIER_TYPE_VALUE
+                    slot of the identifier.  */
+                 ;
+               }
+             else if (duplicate_decls (x, t))
                return t;
+           }
+         else if (duplicate_decls (x, t))
+           {
+#if 0
+             /* This is turned off until I have time to do it right (bpk).  */
 
-             if (extra_warnings)
+             /* Also warn if they did a prototype with `static' on it, but
+                then later left the `static' off.  */
+             if (! TREE_PUBLIC (name) && TREE_PUBLIC (x))
                {
-                 cp_warning ("`static' missing from declaration of `%D'", t);
-                 warning_with_file_and_line (file, line,
-                                             "previous declaration of `%s'",
-                                             decl_as_string (t, 0));
-               }
+                 if (DECL_LANG_SPECIFIC (t) && DECL_FRIEND_P (t))
+                   return t;
 
-             /* Now fix things so it'll do what they expect.  */
-             if (current_function_decl)
-               TREE_PUBLIC (current_function_decl) = 0;
-           }
+                 if (extra_warnings)
+                   {
+                     cp_warning ("`static' missing from declaration of `%D'",
+                                 t);
+                     warning_with_file_and_line (file, line,
+                                                 "previous declaration of `%s'",
+                                                 decl_as_string (t, 0));
+                   }
+
+                 /* Now fix things so it'll do what they expect.  */
+                 if (current_function_decl)
+                   TREE_PUBLIC (current_function_decl) = 0;
+               }
+             /* Due to interference in memory reclamation (X may be
+                obstack-deallocated at this point), we must guard against
+                one really special case.  [jason: This should be handled
+                by start_function]  */
+             if (current_function_decl == x)
+               current_function_decl = t;
 #endif
+             if (TREE_CODE (t) == TYPE_DECL)
+               SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (t));
 
-         /* Due to interference in memory reclamation (X may be
-            obstack-deallocated at this point), we must guard against
-            one really special case.  */
-         if (current_function_decl == x)
-           current_function_decl = t;
+             return t;
+           }
+       }
 
-         return t;
+      if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
+       {
+         t = push_overloaded_decl (x, 1);
+         if (t != x || DECL_LANGUAGE (x) == lang_c)
+           return t;
        }
+      else if (TREE_CODE (x) == TEMPLATE_DECL && ! DECL_TEMPLATE_IS_CLASS (x))
+       return push_overloaded_decl (x, 0);
 
       /* If declaring a type as a typedef, and the type has no known
         typedef name, install this TYPE_DECL as its typedef name.  */
@@ -2710,6 +2844,7 @@ pushdecl (x)
            {
              tree tname = DECL_NAME (name);
 
+             /* This is a disgusting kludge for dealing with UPTs.  */
              if (global_bindings_p () && ANON_AGGRNAME_P (tname))
                {
                  /* do gratuitous C++ typedefing, and make sure that
@@ -2721,9 +2856,11 @@ pushdecl (x)
            }
          my_friendly_assert (TREE_CODE (name) == TYPE_DECL, 140);
 
-         if (DECL_NAME (name) && !DECL_NESTED_TYPENAME (name))
-           set_nested_typename (x, current_class_name,
-                                DECL_NAME (name), type);
+         /* Don't set nested_typename on template type parms, for instance.
+            Any artificial decls that need DECL_NESTED_TYPENAME will have it
+            set in pushtag.  */
+         if (! DECL_NESTED_TYPENAME (x) && ! DECL_ARTIFICIAL (x))
+           set_nested_typename (x, current_class_name, DECL_NAME (x), type);
 
          if (type != error_mark_node
              && TYPE_NAME (type)
@@ -2734,8 +2871,10 @@ pushdecl (x)
       /* Multiple external decls of the same identifier ought to match.
 
         We get warnings about inline functions where they are defined.
+        We get warnings about other functions from push_overloaded_decl.
+        
         Avoid duplicate warnings where they are used.  */
-      if (TREE_PUBLIC (x) && !DECL_INLINE (x))
+      if (TREE_PUBLIC (x) && TREE_CODE (x) != FUNCTION_DECL)
        {
          tree decl;
 
@@ -2746,14 +2885,13 @@ pushdecl (x)
          else
            decl = NULL_TREE;
 
-         if (decl && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl), 1)
+         if (decl
              /* If different sort of thing, we already gave an error.  */
              && TREE_CODE (decl) == TREE_CODE (x)
-             /* If old decl is built-in, we already warned if we should.  */
-             && !DECL_BUILT_IN (decl))
+             && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl), 1))
            {
              cp_pedwarn ("type mismatch with previous external decl", x);
-             cp_pedwarn_at ("previous external decl of `%D'", decl);
+             cp_pedwarn_at ("previous external decl of `%#D'", decl);
            }
        }
 
@@ -2777,14 +2915,14 @@ pushdecl (x)
 
          /* If the first global decl has external linkage,
             warn if we later see static one.  */
-         if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && TREE_PUBLIC (x))
+         if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && DECL_PUBLIC (x))
            TREE_PUBLIC (name) = 1;
 
-         /* Don't install a TYPE_DECL if we already have another
-            sort of _DECL with that name.  */
+         /* Don't install an artificial TYPE_DECL if we already have
+            another _DECL with that name.  */
          if (TREE_CODE (x) != TYPE_DECL
              || t == NULL_TREE
-             || TREE_CODE (t) == TYPE_DECL)
+             || ! DECL_ARTIFICIAL (x))
            IDENTIFIER_GLOBAL_VALUE (name) = x;
 
          /* Don't forget if the function was used via an implicit decl.  */
@@ -2807,7 +2945,8 @@ pushdecl (x)
 
          /* If new decl is `static' and an `extern' was seen previously,
             warn about it.  */
-         warn_extern_redeclared_static (x, t);
+         if (x != NULL_TREE && t != NULL_TREE && decls_match (x, t))
+           warn_extern_redeclared_static (x, t);
        }
       else
        {
@@ -2815,8 +2954,15 @@ pushdecl (x)
          tree oldlocal = IDENTIFIER_LOCAL_VALUE (name);
          tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name);
 
-         b->shadowed = tree_cons (name, oldlocal, b->shadowed);
-         IDENTIFIER_LOCAL_VALUE (name) = x;
+         /* Don't install an artificial TYPE_DECL if we already have
+            another _DECL with that name.  */
+         if (TREE_CODE (x) != TYPE_DECL
+             || t == NULL_TREE
+             || ! DECL_ARTIFICIAL (x))
+           {
+             b->shadowed = tree_cons (name, oldlocal, b->shadowed);
+             IDENTIFIER_LOCAL_VALUE (name) = x;
+           }
 
          /* If this is a TYPE_DECL, push it into the type value slot.  */
          if (TREE_CODE (x) == TYPE_DECL)
@@ -2825,45 +2971,19 @@ pushdecl (x)
          /* If this is an extern function declaration, see if we
             have a global definition or declaration for the function.  */
          if (oldlocal == NULL_TREE
-             && DECL_EXTERNAL (x) && !DECL_INLINE (x)
+             && DECL_EXTERNAL (x)
              && oldglobal != NULL_TREE
              && TREE_CODE (x) == FUNCTION_DECL
              && TREE_CODE (oldglobal) == FUNCTION_DECL)
            {
              /* We have one.  Their types must agree.  */
-             if (! comptypes (TREE_TYPE (x), TREE_TYPE (oldglobal), 1))
+             if (decls_match (x, oldglobal))
+               /* OK */;
+             else
                {
                  cp_warning ("extern declaration of `%#D' doesn't match", x);
                  cp_warning_at ("global declaration `%#D'", oldglobal);
                }
-             else
-               {
-                 /* Inner extern decl is inline if global one is.
-                    Copy enough to really inline it.  */
-                 if (DECL_INLINE (oldglobal))
-                   {
-                     DECL_INLINE (x) = DECL_INLINE (oldglobal);
-                     DECL_INITIAL (x) = (current_function_decl == oldglobal
-                                         ? NULL_TREE : DECL_INITIAL (oldglobal));
-                     DECL_SAVED_INSNS (x) = DECL_SAVED_INSNS (oldglobal);
-                     DECL_FRAME_SIZE (x) = DECL_FRAME_SIZE (oldglobal);
-                     DECL_ARGUMENTS (x) = DECL_ARGUMENTS (oldglobal);
-                     DECL_RESULT (x) = DECL_RESULT (oldglobal);
-                     TREE_ASM_WRITTEN (x) = TREE_ASM_WRITTEN (oldglobal);
-                     DECL_ABSTRACT_ORIGIN (x) = oldglobal;
-                   }
-                 /* Inner extern decl is built-in if global one is.  */
-                 if (DECL_BUILT_IN (oldglobal))
-                   {
-                     DECL_BUILT_IN (x) = DECL_BUILT_IN (oldglobal);
-                     DECL_SET_FUNCTION_CODE (x, DECL_FUNCTION_CODE (oldglobal));
-                   }
-                 /* Keep the arg types from a file-scope fcn defn.  */
-                 if (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != NULL_TREE
-                     && DECL_INITIAL (oldglobal)
-                     && TYPE_ARG_TYPES (TREE_TYPE (x)) == NULL_TREE)
-                   TREE_TYPE (x) = TREE_TYPE (oldglobal);
-               }
            }
          /* If we have a local external declaration,
             and no file-scope declaration has yet been seen,
@@ -2898,7 +3018,7 @@ pushdecl (x)
          /* Maybe warn if shadowing something else.  */
          else if (warn_shadow && !DECL_EXTERNAL (x)
                   /* No shadow warnings for internally generated vars.  */
-                  && DECL_SOURCE_LINE (x) != 0
+                  && ! DECL_ARTIFICIAL (x)
                   /* No shadow warnings for vars made for inlining.  */
                   && ! DECL_FROM_INLINE (x))
            {
@@ -2917,31 +3037,45 @@ pushdecl (x)
              if (warnstring)
                warning (warnstring, IDENTIFIER_POINTER (name));
            }
+       }
 
-         /* If storing a local value, there may already be one (inherited).
-            If so, record it for restoration when this binding level ends.  */
-         if (oldlocal != NULL_TREE)
-           b->shadowed = tree_cons (name, oldlocal, b->shadowed);
+      if (TREE_CODE (x) == FUNCTION_DECL)
+       {
+         /* This is probably the wrong place to check this, but it has to
+             come after the call to duplicate_decls.  */
+         tree arg = TYPE_ARG_TYPES (TREE_TYPE (x));
+         int saw_def = 0, i = 1;
+         for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i)
+           {
+             if (TREE_PURPOSE (arg))
+               saw_def = 1;
+             else if (saw_def)
+               {
+                 cp_error ("default argument missing for parameter %d of `%#D'",
+                           i, x);
+                 break;
+               }
+           }
        }
 
       /* Keep count of variables in this level with incomplete type.  */
       if (TREE_CODE (x) != TEMPLATE_DECL
-         && TREE_CODE (x) != CPLUS_CATCH_DECL
          && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
          && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE))
        {
          if (++b->n_incomplete == 0)
            error ("too many incomplete variables at this point");
        }
-    }
 
-  if (TREE_CODE (x) == TYPE_DECL && name != NULL_TREE)
-    {
-      if (current_class_name)
+      /* Keep count of variables in this level with incomplete type.  */
+      /* RTTI TD entries are created while defining the type_info.  */
+      if (TREE_CODE (x) == VAR_DECL
+         && TREE_TYPE (x) != error_mark_node
+         && TYPE_LANG_SPECIFIC (TREE_TYPE (x))
+         && TYPE_BEING_DEFINED (TREE_TYPE (x)))
        {
-         if (!DECL_NESTED_TYPENAME (x))
-           set_nested_typename (x, current_class_name, DECL_NAME (x),
-                                TREE_TYPE (x));
+         if (++b->n_incomplete == 0)
+           error ("too many incomplete variables at this point");
        }
     }
 
@@ -3045,17 +3179,66 @@ pushdecl_class_level (x)
 
   if (name)
     {
+      if (TYPE_BEING_DEFINED (current_class_type))
+       {
+         /* Check for inconsistent use of this name in the class body.
+            Types, enums, and static vars are checked here; other
+            members are checked in finish_struct.  */
+         tree icv = IDENTIFIER_CLASS_VALUE (name);
+
+         if (icv
+             /* Don't complain about inherited names.  */
+             && id_in_current_class (name)
+             /* Or shadowed tags.  */
+             && !(TREE_CODE (icv) == TYPE_DECL
+                  && DECL_CONTEXT (icv) == current_class_type))
+           {
+             cp_error ("declaration of identifier `%D' as `%#D'", name, x);
+             cp_error_at ("conflicts with previous use in class as `%#D'",
+                          icv);
+           }
+       }
+
       push_class_level_binding (name, x);
       if (TREE_CODE (x) == TYPE_DECL)
        {
          set_identifier_type_value (name, TREE_TYPE (x));
-         if (!DECL_NESTED_TYPENAME (x))
+
+         /* Don't set nested_typename on template type parms, for instance.
+            Any artificial decls that need DECL_NESTED_TYPENAME will have it
+            set in pushtag.  */
+         if (! DECL_NESTED_TYPENAME (x) && ! DECL_ARTIFICIAL (x))
            set_nested_typename (x, current_class_name, name, TREE_TYPE (x));
        }
     }
   return x;
 }
 
+/* This function is used to push the mangled decls for nested types into
+   the appropriate scope.  Previously pushdecl_top_level was used, but that
+   is incorrect for members of local classes.  */
+tree
+pushdecl_nonclass_level (x)
+     tree x;
+{
+  struct binding_level *b = current_binding_level;
+
+#if 0
+  /* Get out of class scope -- this isn't necessary, because class scope
+     doesn't make it into current_binding_level.  */
+  while (b->parm_flag == 2)
+    b = b->level_chain;
+#else
+  my_friendly_assert (b->parm_flag != 2, 180);
+#endif
+
+  /* Get out of template binding levels */
+  while (b->pseudo_global)
+    b = b->level_chain;
+
+  pushdecl_with_scope (x, b);
+}
+
 /* Make the declaration(s) of X appear in CLASS scope
    under the name NAME.  */
 void
@@ -3063,6 +3246,10 @@ push_class_level_binding (name, x)
      tree name;
      tree x;
 {
+  if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)
+      && purpose_member (name, class_binding_level->class_shadowed))
+    return;
+
   maybe_push_cache_obstack ();
   class_binding_level->class_shadowed
       = tree_cons (name, IDENTIFIER_CLASS_VALUE (name),
@@ -3090,10 +3277,10 @@ overloaded_globals_p (list)
   return 0;
 }
 
-/* DECL is a FUNCTION_DECL which may have other definitions already in place.
-   We get around this by making IDENTIFIER_GLOBAL_VALUE (DECL_NAME (DECL))
-   point to a list of all the things that want to be referenced by that name.
-   It is then up to the users of that name to decide what to do with that
+/* DECL is a FUNCTION_DECL which may have other definitions already in
+   place.  We get around this by making the value of the identifier point
+   to a list of all the things that want to be referenced by that name.  It
+   is then up to the users of that name to decide what to do with that
    list.
 
    DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its DECL_RESULT
@@ -3108,102 +3295,85 @@ push_overloaded_decl (decl, forgettable)
      int forgettable;
 {
   tree orig_name = DECL_NAME (decl);
-  tree glob = IDENTIFIER_GLOBAL_VALUE (orig_name);
+  tree old;
+  int doing_global = (global_bindings_p () || ! forgettable
+                     || flag_traditional || pseudo_global_level_p ());
 
-  DECL_OVERLOADED (decl) = 1;
-
-  if (forgettable
-      && ! flag_traditional
-      && (glob == NULL_TREE || TREE_PERMANENT (glob) == 1)
-      && !global_bindings_p ()
-      && !pseudo_global_level_p ())
-    overloads_to_forget = tree_cons (orig_name, glob, overloads_to_forget);
-
-  if (glob)
+  if (doing_global)
     {
-      if (DECL_LANGUAGE (decl) == lang_c)
+      old = IDENTIFIER_GLOBAL_VALUE (orig_name);
+      if (old && TREE_CODE (old) == FUNCTION_DECL
+         && DECL_ARTIFICIAL (old)
+         && (DECL_BUILT_IN (old) || DECL_BUILT_IN_NONANSI (old)))
        {
-         tree decls = get_first_fn (glob);
-         while (decls && DECL_LANGUAGE (decls) == lang_cplusplus)
-           decls = DECL_CHAIN (decls);
-         if (decls)
-           {
-             cp_error_at ("C-language function `%#D'", decls);
-             cp_error ("overloaded as `%#D'", decl);
-           }
+         if (duplicate_decls (decl, old))
+           return old;
+         old = NULL_TREE;
        }
+    }
+  else
+    {
+      old = IDENTIFIER_LOCAL_VALUE (orig_name);
+
+      if (! purpose_member (orig_name, current_binding_level->shadowed))
+       {
+         current_binding_level->shadowed
+           = tree_cons (orig_name, old, current_binding_level->shadowed);
+         old = NULL_TREE;
+       }
+    }
 
+  if (old)
+    {
+#if 0
       /* We cache the value of builtin functions as ADDR_EXPRs
         in the name space.  Convert it to some kind of _DECL after
         remembering what to forget.  */
-      if (TREE_CODE (glob) == ADDR_EXPR)
-       glob = TREE_OPERAND (glob, 0);
-
-      else if (TREE_CODE (decl) == TEMPLATE_DECL)
-       {
-         tree tmp;
-
-         for (tmp = get_first_fn (glob); tmp; tmp = DECL_CHAIN (tmp))
-           if (decl == tmp)
-             return decl;
-       }
-      else if (TREE_CODE (glob) == VAR_DECL)
+      if (TREE_CODE (old) == ADDR_EXPR)
+       old = TREE_OPERAND (old, 0);
+      else
+#endif
+      if (TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old))
        {
-         cp_error_at ("previous non-function declaration `%#D'", glob);
-         cp_error ("conflicts with function declaration `%#D'", decl);
-         return error_mark_node;
+         tree t = TREE_TYPE (old);
+         if (IS_AGGR_TYPE (t) && warn_shadow)
+           cp_warning ("`%#D' hides constructor for `%#T'", decl, t);
+         old = NULL_TREE;
        }
-      else if (is_overloaded_fn (glob))
+      else if (is_overloaded_fn (old))
         {
-          tree name = DECL_ASSEMBLER_NAME (decl);
           tree tmp;
          
-         for (tmp = get_first_fn (glob); tmp; tmp = DECL_CHAIN (tmp))
-           {
-             if (TREE_CODE (tmp) == FUNCTION_DECL
-                 && comptypes (TREE_TYPE (tmp), TREE_TYPE (decl), 2))
-               {
-                 if (DECL_LANGUAGE (tmp) != DECL_LANGUAGE (decl))
-                   {
-                     if (current_lang_stack == current_lang_base)
-                       {
-                         DECL_LANGUAGE (decl) = DECL_LANGUAGE (tmp);
-                         return tmp;
-                       }
-                     cp_error_at ("previous declaration of `%#D' with %L linkage",
-                                  tmp, DECL_LANGUAGE (tmp));
-                     cp_error ("conflicts with new %L-language declaration",
-                                  DECL_LANGUAGE (decl));
-                   }
-                 else if (TREE_CODE (tmp) != TEMPLATE_DECL
-                          && DECL_ASSEMBLER_NAME (tmp) != name)
-                   {
-                     cp_error ("new declaration `%#D'", decl);
-                     cp_error_at ("ambiguates old declaration `%#D'", tmp);
-                   }
-               }
-             /* If we really have seen this before, then if it ambiguates
-                something, we've already given an error before.  */
-             if (TREE_CODE (tmp) != TEMPLATE_DECL
-                 && DECL_ASSEMBLER_NAME (tmp) == name)
-               return decl;
-           }
+         for (tmp = get_first_fn (old); tmp; tmp = DECL_CHAIN (tmp))
+           if (decl == tmp || duplicate_decls (decl, tmp))
+             return tmp;
+       }
+      else
+       {
+         cp_error_at ("previous non-function declaration `%#D'", old);
+         cp_error ("conflicts with function declaration `%#D'", decl);
+         return error_mark_node;
        }
     }
-  if (glob || TREE_CODE (decl) == TEMPLATE_DECL)
+
+  if (old || TREE_CODE (decl) == TEMPLATE_DECL)
     {
-      if (glob && is_overloaded_fn (glob))
-       DECL_CHAIN (decl) = get_first_fn (glob);
+      if (old && is_overloaded_fn (old))
+       DECL_CHAIN (decl) = get_first_fn (old);
       else
        DECL_CHAIN (decl) = NULL_TREE;
-      glob = tree_cons (orig_name, decl, NULL_TREE);
-      TREE_TYPE (glob) = unknown_type_node;
+      old = tree_cons (orig_name, decl, NULL_TREE);
+      TREE_TYPE (old) = unknown_type_node;
     }
   else
     /* orig_name is not ambiguous.  */
-    glob = decl;
-  
-  IDENTIFIER_GLOBAL_VALUE (orig_name) = glob;
+    old = decl;
+
+  if (doing_global)
+    IDENTIFIER_GLOBAL_VALUE (orig_name) = old;
+  else
+    IDENTIFIER_LOCAL_VALUE (orig_name) = old;
+
   return decl;
 }
 \f
@@ -3269,10 +3439,10 @@ redeclaration_error_message (newdecl, olddecl)
       /* Because C++ can put things into name space for free,
         constructs like "typedef struct foo { ... } foo"
         would look like an erroneous redeclaration.  */
-      if (comptypes (newdecl, olddecl, 0))
+      if (comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0))
        return 0;
       else
-       return "redefinition of `%s'";
+       return "redefinition of `%#D'";
     }
   else if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
@@ -3282,39 +3452,37 @@ redeclaration_error_message (newdecl, olddecl)
       if (DECL_LANG_SPECIFIC (olddecl) && DECL_ABSTRACT_VIRTUAL_P (olddecl))
        return 0;
 
-      /* Declarations of functions can insist on internal linkage
-        but they can't be inconsistent with internal linkage,
-        so there can be no error on that account.
-        However defining the same name twice is no good.  */
+      /* We'll complain about linkage mismatches in
+         warn_extern_redeclared_static.  */
+
+      /* defining the same name twice is no good.  */
       if (DECL_INITIAL (olddecl) != NULL_TREE
-         && DECL_INITIAL (newdecl) != NULL_TREE
-         /* However, defining once as extern inline and a second
-            time in another way is ok.  */
-         && !(DECL_INLINE (olddecl) && DECL_EXTERNAL (olddecl)
-              && !(DECL_INLINE (newdecl) && DECL_EXTERNAL (newdecl))))
+         && DECL_INITIAL (newdecl) != NULL_TREE)
        {
          if (DECL_NAME (olddecl) == NULL_TREE)
-           return "`%s' not declared in class";
+           return "`%#D' not declared in class";
          else
-           return "redefinition of `%s'";
+           return "redefinition of `%#D'";
        }
       return 0;
     }
+  else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
+    {
+      if (DECL_INITIAL (olddecl) && DECL_INITIAL (newdecl))
+       return "redefinition of `%#D'";
+      return 0;
+    }
   else if (current_binding_level == global_binding_level)
     {
       /* Objects declared at top level:  */
+      /* Insist that the linkage match.  */
+      if (! TREE_PUBLIC (newdecl) && TREE_PUBLIC (olddecl))
+       return "conflicting declarations of `%#D'";
       /* If at least one is a reference, it's ok.  */
       if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl))
        return 0;
       /* Reject two definitions.  */
-      if (DECL_INITIAL (olddecl) != NULL_TREE
-         && DECL_INITIAL (newdecl) != NULL_TREE)
-       return "redefinition of `%s'";
-      /* Now we have two tentative defs, or one tentative and one real def.  */
-      /* Insist that the linkage match.  */
-      if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl))
-       return "conflicting declarations of `%s'";
-      return 0;
+      return "redefinition of `%#D'";
     }
   else
     {
@@ -3322,7 +3490,7 @@ redeclaration_error_message (newdecl, olddecl)
       /* Reject two definitions, and reject a definition
         together with an external reference.  */
       if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl)))
-       return "redeclaration of `%s'";
+       return "redeclaration of `%#D'";
       return 0;
     }
 }
@@ -3433,6 +3601,9 @@ define_label (filename, line, name)
       decl = lookup_label (name);
     }
 
+  if (name == get_identifier ("wchar_t"))
+    cp_pedwarn ("label named wchar_t");
+
   if (DECL_INITIAL (decl) != NULL_TREE)
     {
       cp_error ("duplicate label `%D'", decl);
@@ -3441,6 +3612,7 @@ define_label (filename, line, name)
   else
     {
       tree uses, prev;
+      int identified = 0;
 
       /* Mark label as having been defined.  */
       DECL_INITIAL (decl) = error_mark_node;
@@ -3466,15 +3638,16 @@ define_label (filename, line, name)
                           of internal entities.  They can't be accessed,
                           and they should be cleaned up
                           by the time we get to the label.  */
-                       && DECL_SOURCE_LINE (new_decls) != 0
+                       && ! DECL_ARTIFICIAL (new_decls)
                        && ((DECL_INITIAL (new_decls) != NULL_TREE
                             && DECL_INITIAL (new_decls) != error_mark_node)
                            || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
                      {
-                       if (IDENTIFIER_ERROR_LOCUS (decl) == NULL_TREE)
-                         cp_error ("invalid jump to label `%D'", decl);
-                       SET_IDENTIFIER_ERROR_LOCUS (decl, current_function_decl);
-                       cp_error ("crosses initialization of `%D'", new_decls);
+                       if (! identified)
+                         cp_error ("jump to label `%D'", decl);
+                       identified = 1;
+                       cp_error_at ("  crosses initialization of `%#D'",
+                                    new_decls);
                      }
                    new_decls = TREE_CHAIN (new_decls);
                  }
@@ -3493,6 +3666,30 @@ define_label (filename, line, name)
     }
 }
 
+struct cp_switch
+{
+  struct binding_level *level;
+  struct cp_switch *next;
+};
+
+static struct cp_switch *switch_stack;
+
+void
+push_switch ()
+{
+  struct cp_switch *p
+    = (struct cp_switch *) oballoc (sizeof (struct cp_switch));
+  p->level = current_binding_level;
+  p->next = switch_stack;
+  switch_stack = p;
+}
+
+void
+pop_switch ()
+{
+  switch_stack = switch_stack->next;
+}
+
 /* Same, but for CASE labels.  If DECL is NULL_TREE, it's the default.  */
 /* XXX Note decl is never actually used. (bpk) */
 void
@@ -3500,19 +3697,46 @@ define_case_label (decl)
      tree decl;
 {
   tree cleanup = last_cleanup_this_contour ();
+  struct binding_level *b = current_binding_level;
+  int identified = 0;
+
   if (cleanup)
     {
       static int explained = 0;
-      cp_error_at ("destructor needed for `%#D'", TREE_PURPOSE (cleanup));
-      error ("where case label appears here");
+      cp_warning_at ("destructor needed for `%#D'", TREE_PURPOSE (cleanup));
+      warning ("where case label appears here");
       if (!explained)
        {
-         error ("(enclose actions of previous case statements requiring");
-         error ("destructors in their own binding contours.)");
+         warning ("(enclose actions of previous case statements requiring");
+         warning ("destructors in their own binding contours.)");
          explained = 1;
        }
     }
 
+  for (; b && b != switch_stack->level; b = b->level_chain)
+    {
+      tree new_decls = b->names;
+      for (; new_decls; new_decls = TREE_CHAIN (new_decls))
+       {
+         if (TREE_CODE (new_decls) == VAR_DECL
+             /* Don't complain about crossing initialization
+                of internal entities.  They can't be accessed,
+                and they should be cleaned up
+                by the time we get to the label.  */
+             && ! DECL_ARTIFICIAL (new_decls)
+             && ((DECL_INITIAL (new_decls) != NULL_TREE
+                  && DECL_INITIAL (new_decls) != error_mark_node)
+                 || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
+           {
+             if (! identified)
+               error ("jump to case label");
+             identified = 1;
+             cp_error_at ("  crosses initialization of `%#D'",
+                          new_decls);
+           }
+       }
+    }
+
   /* After labels, make any new cleanups go into their
      own new (temporary) binding contour.  */
 
@@ -3764,8 +3988,9 @@ lookup_nested_type (type, context)
          }
          break;
        case FUNCTION_DECL:
-         return TYPE_IDENTIFIER (type) ? lookup_name (TYPE_IDENTIFIER (type), 1) : NULL_TREE;
-         break;
+         if (TYPE_NAME (type) && TYPE_IDENTIFIER (type))
+           return lookup_name (TYPE_IDENTIFIER (type), 1);
+         return NULL_TREE;
        default:
          my_friendly_abort (12);
        }
@@ -3780,43 +4005,107 @@ lookup_nested_type (type, context)
    definitions if there are many, or return 0 if it is undefined.
 
    If PREFER_TYPE is > 0, we prefer TYPE_DECLs.
-   If PREFER_TYPE is = 0, we prefer non-TYPE_DECLs.
-   If PREFER_TYPE is < 0, we arbitrate according to lexical context.  */
+   If PREFER_TYPE is -2, we're being called from yylex(). (UGLY)
+   Otherwise we prefer non-TYPE_DECLs.  */
 
 tree
-lookup_name (name, prefer_type)
+lookup_name_real (name, prefer_type, nonclass)
      tree name;
-     int prefer_type;
+     int prefer_type, nonclass;
 {
   register tree val;
+  int yylex = 0;
+  tree from_obj = NULL_TREE;
+
+  if (prefer_type == -2)
+    {
+      extern int looking_for_typename;
+      tree type;
+
+      yylex = 1;
+      prefer_type = looking_for_typename;
+
+      if (got_scope)
+       type = got_scope;
+      else
+       type = got_object;
+      
+      if (type)
+       {
+         if (type == error_mark_node)
+           return error_mark_node;
+         else if (type == void_type_node)
+           val = IDENTIFIER_GLOBAL_VALUE (name);
+         else if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+                  /* TFIXME -- don't do this for UPTs in new model.  */
+                  || TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
+           {
+             if (prefer_type > 0)
+               val = create_nested_upt (type, name);
+             else
+               val = NULL_TREE;
+           }
+         else if (! IS_AGGR_TYPE (type))
+           /* Someone else will give an error about this if needed. */
+           val = NULL_TREE;
+         else if (TYPE_BEING_DEFINED (type))
+           {
+             val = IDENTIFIER_CLASS_VALUE (name);
+             if (val && DECL_CONTEXT (val) != type)
+               {
+                 struct binding_level *b = class_binding_level;
+                 for (val = NULL_TREE; b; b = b->level_chain)
+                   {
+                     tree t = purpose_member (name, b->class_shadowed);
+                     if (t && TREE_VALUE (t)
+                         && DECL_CONTEXT (TREE_VALUE (t)) == type)
+                       {
+                         val = TREE_VALUE (t);
+                         break;
+                       }
+                   }
+               }
+             if (val == NULL_TREE
+                 && CLASSTYPE_LOCAL_TYPEDECLS (type))
+               val = lookup_field (type, name, 0, 1);
+           }
+         else if (type == current_class_type)
+           val = IDENTIFIER_CLASS_VALUE (name);
+         else
+           val = lookup_field (type, name, 0, prefer_type);
+       }
+      else
+       val = NULL_TREE;
 
+      if (got_scope)
+       goto done;
+
+      /* This special lookup only applies to types.  */
+      else if (got_object && val && TREE_CODE (val) == TYPE_DECL)
+       from_obj = val;
+    }
+    
   if (current_binding_level != global_binding_level
       && IDENTIFIER_LOCAL_VALUE (name))
     val = IDENTIFIER_LOCAL_VALUE (name);
   /* In C++ class fields are between local and global scope,
      just before the global scope.  */
-  else if (current_class_type)
+  else if (current_class_type && ! nonclass)
     {
       val = IDENTIFIER_CLASS_VALUE (name);
       if (val == NULL_TREE
-         && TYPE_SIZE (current_class_type) == NULL_TREE
+         && TYPE_BEING_DEFINED (current_class_type)
          && CLASSTYPE_LOCAL_TYPEDECLS (current_class_type))
-       {
-         /* Try to find values from base classes
-            if we are presently defining a type.
-            We are presently only interested in TYPE_DECLs.  */
-         val = lookup_field (current_class_type, name, 0, prefer_type < 0);
-         if (val == error_mark_node)
-           return val;
-         if (val && TREE_CODE (val) != TYPE_DECL)
-           val = NULL_TREE;
-       }
+       /* Try to find values from base classes if we are presently
+          defining a type.  We are presently only interested in
+          TYPE_DECLs.  */
+       val = lookup_field (current_class_type, name, 0, 1);
 
       /* yylex() calls this with -2, since we should never start digging for
         the nested name at the point where we haven't even, for example,
         created the COMPONENT_REF or anything like that.  */
       if (val == NULL_TREE)
-       val = lookup_nested_field (name, prefer_type != -2);
+       val = lookup_nested_field (name, ! yylex);
 
       if (val == NULL_TREE)
        val = IDENTIFIER_GLOBAL_VALUE (name);
@@ -3824,33 +4113,42 @@ lookup_name (name, prefer_type)
   else
     val = IDENTIFIER_GLOBAL_VALUE (name);
 
+ done:
   if (val)
     {
-      extern int looking_for_typename;
-
-      /* Arbitrate between finding a TYPE_DECL and finding
-        other kinds of _DECLs.  */
-      if (TREE_CODE (val) == TYPE_DECL || looking_for_typename < 0)
-       return val;
-
-      if (IDENTIFIER_HAS_TYPE_VALUE (name))
-       {
-         register tree val_as_type = TYPE_NAME (IDENTIFIER_TYPE_VALUE (name));
+      if (from_obj && from_obj != val)
+       cp_error ("lookup in the scope of `%#T' does not match lookup in the current scope",
+                 got_object);
 
-         if (val == val_as_type || prefer_type > 0
-             || looking_for_typename > 0)
-           return val_as_type;
-         if (prefer_type == 0)
-           return val;
-         return arbitrate_lookup (name, val, val_as_type);
-       }
-      if (TREE_TYPE (val) == error_mark_node)
-       return error_mark_node;
+      if ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template)
+         || TREE_CODE (val) == TYPE_DECL || prefer_type <= 0)
+       ;
+      else if (IDENTIFIER_HAS_TYPE_VALUE (name))
+       val = TYPE_NAME (IDENTIFIER_TYPE_VALUE (name));
+      else if (TREE_TYPE (val) == error_mark_node)
+       val = error_mark_node;
     }
+  else if (from_obj)
+    val = from_obj;
 
   return val;
 }
 
+tree
+lookup_name_nonclass (name)
+     tree name;
+{
+  return lookup_name_real (name, 0, 1);
+}
+
+tree
+lookup_name (name, prefer_type)
+     tree name;
+     int prefer_type;
+{
+  return lookup_name_real (name, prefer_type, 0);
+}
+
 /* Similar to `lookup_name' but look only at current binding level.  */
 
 tree
@@ -3869,9 +4167,19 @@ lookup_name_current_level (name)
     }
   else if (IDENTIFIER_LOCAL_VALUE (name) != NULL_TREE)
     {
-      for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
-       if (DECL_NAME (t) == name)
-         break;
+      struct binding_level *b = current_binding_level;
+      while (1)
+       {
+         for (t = b->names; t; t = TREE_CHAIN (t))
+           if (DECL_NAME (t) == name || DECL_ASSEMBLER_NAME (t) == name)
+             goto out;
+         if (b->keep == 2)
+           b = b->level_chain;
+         else
+           break;
+       }
+    out:
+      ;
     }
 
   return t;
@@ -3959,7 +4267,7 @@ record_builtin_type (rid_index, name, type)
        }
     }
 
-  if (flag_dossier)
+  if (flag_rtti)
     {
       if (builtin_type_tdescs_len+5 >= builtin_type_tdescs_max)
        {
@@ -3974,14 +4282,14 @@ record_builtin_type (rid_index, name, type)
          builtin_type_tdescs_arr[builtin_type_tdescs_len++]
            = build_pointer_type (type);
          builtin_type_tdescs_arr[builtin_type_tdescs_len++]
-           = build_type_variant (TYPE_POINTER_TO (type), 1, 0);
+           = build_pointer_type (build_type_variant (type, 1, 0));
        }
       if (TREE_CODE (type) != VOID_TYPE)
        {
          builtin_type_tdescs_arr[builtin_type_tdescs_len++]
            = build_reference_type (type);
          builtin_type_tdescs_arr[builtin_type_tdescs_len++]
-           = build_type_variant (TYPE_REFERENCE_TO (type), 1, 0);
+           = build_reference_type (build_type_variant (type, 1, 0));
        }
     }
 }
@@ -4017,6 +4325,22 @@ push_overloaded_decl_1 (x)
   push_overloaded_decl (x, 0);
 }
 
+#define builtin_function(NAME, TYPE, CODE, LIBNAME) \
+  define_function (NAME, TYPE, CODE, (void (*)())pushdecl, LIBNAME)
+
+#ifdef __GNUC__
+__inline
+#endif
+tree auto_function (name, type, code)
+     tree name, type;
+     enum built_in_function code;
+{
+  return define_function
+    (IDENTIFIER_POINTER (name), type, code, (void (*)())push_overloaded_decl_1,
+     IDENTIFIER_POINTER (build_decl_overload (name, TYPE_ARG_TYPES (type),
+                                             0)));
+}
+
 /* Create the predefined scalar types of C,
    and some nodes representing standard constants (0, 1, (void *)0).
    Initialize the global binding level.
@@ -4039,11 +4363,20 @@ init_decl_processing ()
   int wchar_type_size;
   tree temp;
   tree array_domain_type;
+  extern int flag_strict_prototype;
 
   /* Have to make these distinct before we try using them.  */
   lang_name_cplusplus = get_identifier ("C++");
   lang_name_c = get_identifier ("C");
 
+  if (flag_strict_prototype == 2)
+    {
+      if (pedantic)
+       strict_prototypes_lang_c = strict_prototypes_lang_cplusplus;
+    }
+  else
+    strict_prototypes_lang_c = flag_strict_prototype;
+
   /* Initially, C.  */
   current_lang_name = lang_name_c;
 
@@ -4076,7 +4409,7 @@ init_decl_processing ()
 #endif
 
   gcc_obstack_init (&decl_obstack);
-  if (flag_dossier)
+  if (flag_rtti)
     {
       builtin_type_tdescs_max = 100;
       builtin_type_tdescs_arr = (tree *)xmalloc (100 * sizeof (tree));
@@ -4089,7 +4422,8 @@ init_decl_processing ()
   error_mark_list = build_tree_list (error_mark_node, error_mark_node);
   TREE_TYPE (error_mark_list) = error_mark_node;
 
-  pushlevel (0);       /* make the binding_level structure for global names.  */
+  /* Make the binding_level structure for global names.  */
+  pushlevel (0);
   global_binding_level = current_binding_level;
 
   this_identifier = get_identifier (THIS_NAME);
@@ -4209,7 +4543,14 @@ init_decl_processing ()
   TREE_TYPE (integer_two_node) = integer_type_node;
   integer_three_node = build_int_2 (3, 0);
   TREE_TYPE (integer_three_node) = integer_type_node;
-  empty_init_node = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE);
+
+  boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE);
+  TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE);
+  record_builtin_type (RID_BOOL, "bool", boolean_type_node);
+  boolean_false_node = build_int_2 (0, 0);
+  TREE_TYPE (boolean_false_node) = boolean_type_node;
+  boolean_true_node = build_int_2 (1, 0);
+  TREE_TYPE (boolean_true_node) = boolean_type_node;
 
   /* These are needed by stor-layout.c.  */
   size_zero_node = size_int (0);
@@ -4230,7 +4571,8 @@ init_decl_processing ()
   TREE_TYPE (void_zero_node) = void_type_node;
 
   string_type_node = build_pointer_type (char_type_node);
-  const_string_type_node = build_pointer_type (build_type_variant (char_type_node, 1, 0));
+  const_string_type_node =
+    build_pointer_type (build_type_variant (char_type_node, 1, 0));
   record_builtin_type (RID_MAX, NULL_PTR, string_type_node);
 
   /* Make a type to be the domain of a few array types
@@ -4258,7 +4600,8 @@ init_decl_processing ()
   build_pointer_type (default_function_type);
 
   ptr_type_node = build_pointer_type (void_type_node);
-  const_ptr_type_node = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+  const_ptr_type_node =
+    build_pointer_type (build_type_variant (void_type_node, 1, 0));
   record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node);
   endlink = void_list_node;
   int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
@@ -4270,14 +4613,16 @@ init_decl_processing ()
 
   double_ftype_double_double
     = build_function_type (double_type_node,
-                          tree_cons (NULL_TREE, double_type_node, double_endlink));
+                          tree_cons (NULL_TREE, double_type_node,
+                                     double_endlink));
 
   int_ftype_int
     = build_function_type (integer_type_node, int_endlink);
 
   long_ftype_long
     = build_function_type (long_integer_type_node,
-                          tree_cons (NULL_TREE, long_integer_type_node, endlink));
+                          tree_cons (NULL_TREE, long_integer_type_node,
+                                     endlink));
 
   void_ftype_ptr_ptr_int
     = build_function_type (void_type_node,
@@ -4348,20 +4693,51 @@ init_decl_processing ()
   builtin_function ("__builtin_constant_p", int_ftype_int,
                    BUILT_IN_CONSTANT_P, NULL_PTR);
 
-  builtin_function ("__builtin_alloca",
-                   build_function_type (ptr_type_node,
+  builtin_return_address_fndecl =
+  builtin_function ("__builtin_return_address",
+                   build_function_type (ptr_type_node, 
                                         tree_cons (NULL_TREE,
-                                                   sizetype,
+                                                   unsigned_type_node,
                                                    endlink)),
-                   BUILT_IN_ALLOCA, "alloca");
-#if 0
-  builtin_function ("alloca",
+                   BUILT_IN_RETURN_ADDRESS, NULL_PTR);
+
+  builtin_function ("__builtin_frame_address",
+                   build_function_type (ptr_type_node, 
+                                        tree_cons (NULL_TREE,
+                                                   unsigned_type_node,
+                                                   endlink)),
+                   BUILT_IN_FRAME_ADDRESS, NULL_PTR);
+
+
+  builtin_function ("__builtin_alloca",
                    build_function_type (ptr_type_node,
                                         tree_cons (NULL_TREE,
                                                    sizetype,
                                                    endlink)),
-                   BUILT_IN_ALLOCA, NULL_PTR);
-#endif
+                   BUILT_IN_ALLOCA, "alloca");
+  /* Define alloca, ffs as builtins.
+     Declare _exit just to mark it as volatile.  */
+  if (! flag_no_builtin && !flag_no_nonansi_builtin)
+    {
+      temp = builtin_function ("alloca",
+                              build_function_type (ptr_type_node,
+                                                   tree_cons (NULL_TREE,
+                                                              sizetype,
+                                                              endlink)),
+                              BUILT_IN_ALLOCA, NULL_PTR);
+      /* Suppress error if redefined as a non-function.  */
+      DECL_BUILT_IN_NONANSI (temp) = 1;
+      temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
+      /* Suppress error if redefined as a non-function.  */
+      DECL_BUILT_IN_NONANSI (temp) = 1;
+      temp = builtin_function ("_exit", build_function_type (void_type_node,
+                                                            int_endlink),
+                              NOT_BUILT_IN, NULL_PTR);
+      TREE_THIS_VOLATILE (temp) = 1;
+      TREE_SIDE_EFFECTS (temp) = 1;
+      /* Suppress error if redefined as a non-function.  */
+      DECL_BUILT_IN_NONANSI (temp) = 1;
+    }
 
   builtin_function ("__builtin_abs", int_ftype_int,
                    BUILT_IN_ABS, NULL_PTR);
@@ -4392,7 +4768,7 @@ init_decl_processing ()
   builtin_function ("__builtin_classify_type", default_function_type,
                    BUILT_IN_CLASSIFY_TYPE, NULL_PTR);
   builtin_function ("__builtin_next_arg",
-                   build_function_type (ptr_type_node, endlink),
+                   build_function_type (ptr_type_node, NULL_TREE),
                    BUILT_IN_NEXT_ARG, NULL_PTR);
   builtin_function ("__builtin_args_info",
                    build_function_type (integer_type_node,
@@ -4452,7 +4828,8 @@ init_decl_processing ()
       builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP,
                        NULL_PTR);
       builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP, NULL_PTR);
-      builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY, NULL_PTR);
+      builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
+                       NULL_PTR);
 #if 0
       /* Not yet.  */
       builtin_function ("strncpy", strncpy_ftype, BUILT_IN_STRNCPY, NULL_PTR);
@@ -4460,6 +4837,23 @@ init_decl_processing ()
       builtin_function ("strlen", sizet_ftype_string, BUILT_IN_STRLEN, NULL_PTR);
       builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR);
       builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR);
+
+      /* Declare these functions volatile
+        to avoid spurious "control drops through" warnings.  */
+      temp = builtin_function ("abort",
+                              build_function_type (void_type_node, endlink),
+                              NOT_BUILT_IN, NULL_PTR);
+      TREE_THIS_VOLATILE (temp) = 1;
+      TREE_SIDE_EFFECTS (temp) = 1;
+      /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on
+         them...  */
+      DECL_BUILT_IN_NONANSI (temp) = 1;
+      temp = builtin_function ("exit", build_function_type (void_type_node,
+                                                           int_endlink),
+                              NOT_BUILT_IN, NULL_PTR);
+      TREE_THIS_VOLATILE (temp) = 1;
+      TREE_SIDE_EFFECTS (temp) = 1;
+      DECL_BUILT_IN_NONANSI (temp) = 1;
     }
 
 #if 0
@@ -4467,13 +4861,19 @@ init_decl_processing ()
      or build_function_call.  */
   builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, 0);
   builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, 0);
-  builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR, 0);
+  builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR,
+                   0);
   builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, 0);
-  builtin_function ("__builtin_fmod", double_ftype_double_double, BUILT_IN_FMOD, 0);
-  builtin_function ("__builtin_frem", double_ftype_double_double, BUILT_IN_FREM, 0);
-  builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, BUILT_IN_MEMSET, 0);
-  builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP, 0);
-  builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN, 0);
+  builtin_function ("__builtin_fmod", double_ftype_double_double,
+                   BUILT_IN_FMOD, 0);
+  builtin_function ("__builtin_frem", double_ftype_double_double,
+                   BUILT_IN_FREM, 0);
+  builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, BUILT_IN_MEMSET,
+                   0);
+  builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
+                   0);
+  builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
+                   0);
 #endif
 
   /* C++ extensions */
@@ -4487,13 +4887,14 @@ init_decl_processing ()
                        unknown_type_node));
   /* Make sure the "unknown type" typedecl gets ignored for debug info.  */
   DECL_IGNORED_P (decl) = 1;
+  TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
 #endif
   TYPE_SIZE (unknown_type_node) = TYPE_SIZE (void_type_node);
   TYPE_ALIGN (unknown_type_node) = 1;
   TYPE_MODE (unknown_type_node) = TYPE_MODE (void_type_node);
   /* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node.  */
   TREE_TYPE (unknown_type_node) = unknown_type_node;
-  /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same result.  */
+  /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same result. */
   TYPE_POINTER_TO (unknown_type_node) = unknown_type_node;
   TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node;
 
@@ -4514,6 +4915,11 @@ init_decl_processing ()
       : signed_wchar_type_node;
   record_builtin_type (RID_WCHAR, "__wchar_t", wchar_type_node);
 
+  /* Artificial declaration of wchar_t -- can be bashed */
+  wchar_decl_node = build_decl (TYPE_DECL, get_identifier ("wchar_t"),
+                               wchar_type_node);
+  pushdecl (wchar_decl_node);
+
   /* This is for wide string constants.  */
   wchar_array_type_node
     = build_array_type (wchar_type_node, array_domain_type);
@@ -4526,41 +4932,45 @@ init_decl_processing ()
       pushdecl (lookup_name (get_identifier ("__gc_main"), 0));
     }
 
-  /* Simplify life by making a "vtable_entry_type".  Give its
-     fields names so that the debugger can use them.  */
+  if (flag_vtable_thunks)
+    {
+      /* Make sure we get a unique function type, so we can give
+        its pointer type a name.  (This wins for gdb.) */
+      tree vfunc_type = make_node (FUNCTION_TYPE);
+      TREE_TYPE (vfunc_type) = integer_type_node;
+      TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
+      layout_type (vfunc_type);
 
-  vtable_entry_type = make_lang_type (RECORD_TYPE);
-  fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier, delta_type_node);
-  fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier, delta_type_node);
-  fields[2] = build_lang_field_decl (FIELD_DECL, pfn_identifier, ptr_type_node);
-  finish_builtin_type (vtable_entry_type, VTBL_PTR_TYPE, fields, 2,
-                      double_type_node);
-
-  /* Make this part of an invisible union.  */
-  fields[3] = copy_node (fields[2]);
-  TREE_TYPE (fields[3]) = delta_type_node;
-  DECL_NAME (fields[3]) = delta2_identifier;
-  DECL_MODE (fields[3]) = TYPE_MODE (delta_type_node);
-  DECL_SIZE (fields[3]) = TYPE_SIZE (delta_type_node);
-  TREE_UNSIGNED (fields[3]) = 0;
-  TREE_CHAIN (fields[2]) = fields[3];
-  vtable_entry_type = build_type_variant (vtable_entry_type, 1, 0);
-  record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type);
+      vtable_entry_type = build_pointer_type (vfunc_type);
+    }
+  else
+    {
+      vtable_entry_type = make_lang_type (RECORD_TYPE);
+      fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier,
+                                        delta_type_node);
+      fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier,
+                                        delta_type_node);
+      fields[2] = build_lang_field_decl (FIELD_DECL, pfn_identifier,
+                                        ptr_type_node);
+      finish_builtin_type (vtable_entry_type, VTBL_PTR_TYPE, fields, 2,
+                          double_type_node);
 
-#ifdef VTABLE_USES_MASK
-  /* This is primarily for virtual function definition.  We
-     declare an array of `void *', which can later be
-     converted to the appropriate function pointer type.
-     To do pointers to members, we need a mask which can
-     distinguish an index value into a virtual function table
-     from an address.  */
-  vtbl_mask = build_int_2 (~((HOST_WIDE_INT) VINDEX_MAX - 1), -1);
-#endif
+      /* Make this part of an invisible union.  */
+      fields[3] = copy_node (fields[2]);
+      TREE_TYPE (fields[3]) = delta_type_node;
+      DECL_NAME (fields[3]) = delta2_identifier;
+      DECL_MODE (fields[3]) = TYPE_MODE (delta_type_node);
+      DECL_SIZE (fields[3]) = TYPE_SIZE (delta_type_node);
+      TREE_UNSIGNED (fields[3]) = 0;
+      TREE_CHAIN (fields[2]) = fields[3];
+      vtable_entry_type = build_type_variant (vtable_entry_type, 1, 0);
+    }
+  record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type);
 
   vtbl_type_node
     = build_array_type (vtable_entry_type, NULL_TREE);
   layout_type (vtbl_type_node);
-  vtbl_type_node = build_type_variant (vtbl_type_node, 1, 0);
+  vtbl_type_node = cp_build_type_variant (vtbl_type_node, 1, 0);
   record_builtin_type (RID_MAX, NULL_PTR, vtbl_type_node);
 
   /* Simplify life by making a "sigtable_entry_type".  Give its
@@ -4569,16 +4979,23 @@ init_decl_processing ()
   if (flag_handle_signatures)
     {
       sigtable_entry_type = make_lang_type (RECORD_TYPE);
-      fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier (SIGTABLE_CODE_NAME), short_integer_type_node);
-      fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier (SIGTABLE_OFFSET_NAME), short_integer_type_node);
-      fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier (SIGTABLE_PFN_NAME), ptr_type_node);
+      fields[0] = build_lang_field_decl (FIELD_DECL,
+                                        get_identifier (SIGTABLE_CODE_NAME),
+                                        short_integer_type_node);
+      fields[1] = build_lang_field_decl (FIELD_DECL,
+                                        get_identifier (SIGTABLE_OFFSET_NAME),
+                                        short_integer_type_node);
+      fields[2] = build_lang_field_decl (FIELD_DECL,
+                                        get_identifier (SIGTABLE_PFN_NAME),
+                                        ptr_type_node);
       finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 2,
                           double_type_node);
       sigtable_entry_type = build_type_variant (sigtable_entry_type, 1, 0);
       record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type);
     }
 
-  if (flag_dossier)
+#if 0
+  if (flag_rtti)
     {
       /* Must build __t_desc type.  Currently, type descriptors look like this:
 
@@ -4601,9 +5018,12 @@ init_decl_processing ()
       __t_desc_type_node = make_lang_type (RECORD_TYPE);
       __i_desc_type_node = make_lang_type (RECORD_TYPE);
       __m_desc_type_node = make_lang_type (RECORD_TYPE);
-      __t_desc_array_type = build_array_type (TYPE_POINTER_TO (__t_desc_type_node), NULL_TREE);
-      __i_desc_array_type = build_array_type (TYPE_POINTER_TO (__i_desc_type_node), NULL_TREE);
-      __m_desc_array_type = build_array_type (TYPE_POINTER_TO (__m_desc_type_node), NULL_TREE);
+      __t_desc_array_type =
+       build_array_type (TYPE_POINTER_TO (__t_desc_type_node), NULL_TREE);
+      __i_desc_array_type =
+       build_array_type (TYPE_POINTER_TO (__i_desc_type_node), NULL_TREE);
+      __m_desc_array_type =
+       build_array_type (TYPE_POINTER_TO (__m_desc_type_node), NULL_TREE);
 
       fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
                                         string_type_node);
@@ -4611,7 +5031,8 @@ init_decl_processing ()
                                         unsigned_type_node);
       fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("bits"),
                                         unsigned_type_node);
-      fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("points_to"),
+      fields[3] = build_lang_field_decl (FIELD_DECL,
+                                        get_identifier ("points_to"),
                                         TYPE_POINTER_TO (__t_desc_type_node));
       fields[4] = build_lang_field_decl (FIELD_DECL,
                                         get_identifier ("ivars_count"),
@@ -4647,7 +5068,8 @@ init_decl_processing ()
                                         integer_type_node);
       fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
                                         TYPE_POINTER_TO (__t_desc_type_node));
-      finish_builtin_type (__i_desc_type_node, "__i_desc", fields, 2, integer_type_node);
+      finish_builtin_type (__i_desc_type_node, "__i_desc", fields, 2,
+                          integer_type_node);
 
       /* method descriptors look like this:
 
@@ -4680,12 +5102,11 @@ init_decl_processing ()
                                         short_integer_type_node);
       fields[7] = build_lang_field_decl (FIELD_DECL, get_identifier ("parm_types"),
                                         build_pointer_type (build_array_type (TYPE_POINTER_TO (__t_desc_type_node), NULL_TREE)));
-      finish_builtin_type (__m_desc_type_node, "__m_desc", fields, 7, integer_type_node);
+      finish_builtin_type (__m_desc_type_node, "__m_desc", fields, 7,
+                          integer_type_node);
     }
 
-  /* Now, C++.  */
-  current_lang_name = lang_name_cplusplus;
-  if (flag_dossier)
+  if (flag_rtti)
     {
       int i = builtin_type_tdescs_len;
       while (i > 0)
@@ -4695,26 +5116,35 @@ init_decl_processing ()
          TREE_PUBLIC (TREE_OPERAND (tdesc, 0)) = 1;
        }
     }
+#endif /*flag_rtti*/
+
+  /* Now, C++.  */
+  current_lang_name = lang_name_cplusplus;
 
   auto_function (ansi_opname[(int) NEW_EXPR],
                 build_function_type (ptr_type_node,
                                      tree_cons (NULL_TREE, sizetype,
                                                 void_list_node)),
                 NOT_BUILT_IN);
+  auto_function (ansi_opname[(int) VEC_NEW_EXPR],
+                build_function_type (ptr_type_node,
+                                     tree_cons (NULL_TREE, sizetype,
+                                                void_list_node)),
+                NOT_BUILT_IN);
   auto_function (ansi_opname[(int) DELETE_EXPR],
                 build_function_type (void_type_node,
                                      tree_cons (NULL_TREE, ptr_type_node,
                                                 void_list_node)),
                 NOT_BUILT_IN);
+  auto_function (ansi_opname[(int) VEC_DELETE_EXPR],
+                build_function_type (void_type_node,
+                                     tree_cons (NULL_TREE, ptr_type_node,
+                                                void_list_node)),
+                NOT_BUILT_IN);
 
-  abort_fndecl
-    = define_function ("abort",
-                      build_function_type (void_type_node, void_list_node),
-                      NOT_BUILT_IN, 0, 0);
-
-  unhandled_exception_fndecl
-    = define_function ("__unhandled_exception",
-                      build_function_type (void_type_node, NULL_TREE),
+  abort_fndecl
+    = define_function ("__pure_virtual",
+                      build_function_type (void_type_node, void_list_node),
                       NOT_BUILT_IN, 0, 0);
 
   /* Perform other language dependent initializations.  */
@@ -4723,19 +5153,14 @@ init_decl_processing ()
   init_search_processing ();
 
   if (flag_handle_exceptions)
-    {
-      if (flag_handle_exceptions == 2)
-       /* Too much trouble to inline all the trys needed for this.  */
-       flag_this_is_variable = 2;
-      init_exception_processing ();
-    }
+    init_exception_processing ();
   if (flag_gc)
     init_gc_processing ();
   if (flag_no_inline)
     {
       flag_inline_functions = 0;
 #if 0
-      /* This causes uneccessary emission of inline functions.  */
+      /* This causes unnecessary emission of inline functions.  */
       flag_default_inline = 0;
 #endif
     }
@@ -4749,6 +5174,74 @@ init_decl_processing ()
   init_function_format_info ();
 }
 
+/* initialize type descriptor type node of various rtti type. */
+
+int
+init_type_desc()
+{
+  tree tdecl;
+
+  tdecl = lookup_name (get_identifier ("type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __t_desc_type_node = TREE_TYPE(tdecl);
+  __tp_desc_type_node = build_pointer_type (__t_desc_type_node);
+
+#if 0
+  tdecl = lookup_name (get_identifier ("__baselist_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __baselist_desc_type_node = TREE_TYPE (tdecl);
+#endif
+
+  tdecl = lookup_name (get_identifier ("__builtin_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __bltn_desc_type_node = TREE_TYPE (tdecl);
+
+  tdecl = lookup_name (get_identifier ("__user_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __user_desc_type_node = TREE_TYPE (tdecl);
+
+  tdecl = lookup_name (get_identifier ("__class_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __class_desc_type_node = TREE_TYPE (tdecl);
+
+  tdecl = lookup_field (__class_desc_type_node, 
+       get_identifier ("access_mode"), 0, 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __access_mode_type_node = TREE_TYPE (tdecl);
+
+  tdecl = lookup_name (get_identifier ("__attr_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __attr_desc_type_node = TREE_TYPE (tdecl);
+
+  tdecl = lookup_name (get_identifier ("__pointer_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __ptr_desc_type_node = TREE_TYPE (tdecl);
+
+  tdecl = lookup_name (get_identifier ("__func_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __func_desc_type_node = TREE_TYPE (tdecl);
+
+  tdecl = lookup_name (get_identifier ("__ptmf_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __ptmf_desc_type_node = TREE_TYPE (tdecl);
+
+  tdecl = lookup_name (get_identifier ("__ptmd_type_info"), 0);
+  if (tdecl == NULL_TREE)
+    return 0;
+  __ptmd_desc_type_node = TREE_TYPE (tdecl);
+
+  return 1;
+}
 /* Make a definition for a builtin function named NAME and whose data type
    is TYPE.  TYPE should be a function type with argument types.
    FUNCTION_CODE tells later passes how to compile calls to this function.
@@ -4768,6 +5261,8 @@ define_function (name, type, function_code, pfn, library_name)
   tree decl = build_lang_decl (FUNCTION_DECL, get_identifier (name), type);
   DECL_EXTERNAL (decl) = 1;
   TREE_PUBLIC (decl) = 1;
+  DECL_INTERFACE_KNOWN (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
 
   /* Since `pushdecl' relies on DECL_ASSEMBLER_NAME instead of DECL_NAME,
      we cannot change DECL_ASSEMBLER_NAME until we have installed this
@@ -4779,7 +5274,7 @@ define_function (name, type, function_code, pfn, library_name)
   if (function_code != NOT_BUILT_IN)
     {
       DECL_BUILT_IN (decl) = 1;
-      DECL_SET_FUNCTION_CODE (decl, function_code);
+      DECL_FUNCTION_CODE (decl) = function_code;
     }
   return decl;
 }
@@ -4800,8 +5295,7 @@ shadow_tag (declspecs)
      tree declspecs;
 {
   int found_tag = 0;
-  int warned = 0;
-  int static_or_extern = 0;
+  tree ob_modifier = NULL_TREE;
   register tree link;
   register enum tree_code code, ok_code = ERROR_MARK;
   register tree t = NULL_TREE;
@@ -4812,46 +5306,24 @@ shadow_tag (declspecs)
 
       code = TREE_CODE (value);
       if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE)
-       /* Used to test also that TYPE_SIZE (value) != 0.
-          That caused warning for `struct foo;' at top level in the file.  */
        {
-         register tree name = TYPE_NAME (value);
-
-         if (name == NULL_TREE)
-           name = lookup_tag_reverse (value, NULL_TREE);
-
-         if (name && TREE_CODE (name) == TYPE_DECL)
-           name = DECL_NAME (name);
-
-         t = lookup_tag (code, name, inner_binding_level, 1);
+         my_friendly_assert (TYPE_NAME (value) != NULL_TREE, 261);
 
-         if (t == NULL_TREE)
-           {
-             push_obstacks (&permanent_obstack, &permanent_obstack);
-             if (IS_AGGR_TYPE_CODE (code))
-               t = make_lang_type (code);
-             else
-               t = make_node (code);
-             pushtag (name, t, 0);
-             pop_obstacks ();
-             ok_code = code;
-             break;
-           }
-         else if (name != NULL_TREE || code == ENUMERAL_TYPE)
-           ok_code = code;
+         if (code == ENUMERAL_TYPE && TYPE_SIZE (value) == 0)
+           cp_error ("forward declaration of `%#T'", value);
 
-         if (ok_code != ERROR_MARK)
-           found_tag++;
-         else
-           {
-             if (!warned)
-               pedwarn ("useless keyword or type name in declaration");
-             warned = 1;
-           }
+         t = value;
+         ok_code = code;
+         found_tag++;
        }
       else if (value == ridpointers[(int) RID_STATIC]
-              || value == ridpointers[(int) RID_EXTERN])
-       static_or_extern = 1;
+              || value == ridpointers[(int) RID_EXTERN]
+              || value == ridpointers[(int) RID_AUTO]
+              || value == ridpointers[(int) RID_REGISTER]
+              || value == ridpointers[(int) RID_INLINE]
+              || value == ridpointers[(int) RID_VIRTUAL]
+              || value == ridpointers[(int) RID_EXPLICIT])
+       ob_modifier = value;
     }
 
   /* This is where the variables in an anonymous union are
@@ -4870,7 +5342,8 @@ shadow_tag (declspecs)
         function members.  */
       if (TYPE_FIELDS (t))
        {
-         tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0, NULL_TREE);
+         tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0,
+                                     NULL_TREE);
          finish_anon_union (decl);
        }
       else
@@ -4879,38 +5352,25 @@ shadow_tag (declspecs)
   else
     {
       /* Anonymous unions are objects, that's why we only check for
-        static/extern specifiers in this branch.  */
-      if (static_or_extern)
-       error ("static/extern can only be specified for objects and functions");
+        inappropriate specifiers in this branch.  */
 
-      if (ok_code == RECORD_TYPE
-         && found_tag == 1
-         && TYPE_LANG_SPECIFIC (t)
-         && CLASSTYPE_DECLARED_EXCEPTION (t))
+      if (ob_modifier)
        {
-         if (TYPE_SIZE (t))
-           cp_error ("redeclaration of exception `%T'", t);
+         if (ob_modifier == ridpointers[(int) RID_INLINE]
+             || ob_modifier == ridpointers[(int) RID_VIRTUAL])
+           cp_error ("`%D' can only be specified for functions", ob_modifier);
+         else if (ob_modifier == ridpointers[(int) RID_EXPLICIT])
+           cp_error ("`%D' can only be specified for constructors",
+                     ob_modifier);
          else
-           {
-             tree ename, decl;
-
-             push_obstacks (&permanent_obstack, &permanent_obstack);
-
-             pushclass (t, 0);
-             finish_exception (t, NULL_TREE);
-
-             ename = TYPE_NAME (t);
-             if (TREE_CODE (ename) == TYPE_DECL)
-               ename = DECL_NAME (ename);
-             decl = build_lang_field_decl (VAR_DECL, ename, t);
-             finish_exception_decl (current_class_name, decl);
-             end_exception_decls ();
-
-             pop_obstacks ();
-           }
+           cp_error ("`%D' can only be specified for objects and functions",
+                     ob_modifier);
        }
-      else if (!warned && found_tag > 1)
-       warning ("multiple types in one declaration");
+
+      if (found_tag == 0)
+       pedwarn ("abstract declarator used as declaration");
+      else if (found_tag > 1)
+       pedwarn ("multiple types in one declaration");
     }
 }
 \f
@@ -4963,7 +5423,8 @@ start_decl (declarator, declspecs, initialized, raises)
   /* This should only be done once on the top most decl. */
   if (have_extern_spec && !used_extern_spec)
     {
-      declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), declspecs);
+      declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"),
+                                 declspecs);
       used_extern_spec = 1;
     }
 
@@ -4993,11 +5454,6 @@ start_decl (declarator, declspecs, initialized, raises)
       pop_obstacks ();
     }
 
-  /* Interesting work for this is done in `finish_exception_decl'.  */
-  if (TREE_CODE (type) == RECORD_TYPE
-      && CLASSTYPE_DECLARED_EXCEPTION (type))
-    return decl;
-
   /* Corresponding pop_obstacks is done in `finish_decl'.  */
   push_obstacks_nochange ();
 
@@ -5038,28 +5494,14 @@ start_decl (declarator, declspecs, initialized, raises)
           DECL_ARGUMENTS (decl) = args;
         }
       d = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), TREE_TYPE (decl));
-      if (interface_unknown && flag_external_templates && ! DECL_IN_SYSTEM_HEADER (decl))
-       warn_if_unknown_interface ();
-      TREE_PUBLIC (d) = TREE_PUBLIC (decl) = flag_external_templates && !interface_unknown;
+      TREE_PUBLIC (d) = TREE_PUBLIC (decl);
       TREE_STATIC (d) = TREE_STATIC (decl);
       DECL_EXTERNAL (d) = (DECL_EXTERNAL (decl)
                           && !(context && !DECL_THIS_EXTERN (decl)));
       DECL_TEMPLATE_RESULT (d) = decl;
-      DECL_OVERLOADED (d) = 1;
       decl = d;
     }
 
-  if (context && TYPE_SIZE (context) != NULL_TREE)
-    {
-      /* If it was not explicitly declared `extern',
-        revoke any previous claims of DECL_EXTERNAL.  */
-      if (DECL_THIS_EXTERN (decl) == 0)
-       DECL_EXTERNAL (decl) = 0;
-      if (DECL_LANG_SPECIFIC (decl))
-       DECL_IN_AGGR_P (decl) = 0;
-      pushclass (context, 2);
-    }
-
   /* If this type of object needs a cleanup, and control may
      jump past it, make a new binding level so that it is cleaned
      up only when it is initialized first.  */
@@ -5092,7 +5534,9 @@ start_decl (declarator, declspecs, initialized, raises)
       default:
        /* Don't allow initializations for incomplete types except for
           arrays which might be completed by the initialization.  */
-       if (TYPE_SIZE (type) != NULL_TREE)
+       if (type == error_mark_node)
+         ;                     /* Don't complain again.  */
+       else if (TYPE_SIZE (type) != NULL_TREE)
          ;                     /* A complete type is ok.  */
        else if (TREE_CODE (type) != ARRAY_TYPE)
          {
@@ -5149,36 +5593,45 @@ start_decl (declarator, declspecs, initialized, raises)
       DECL_INITIAL (decl) = error_mark_node;
     }
 
+  if (context && TYPE_SIZE (context) != NULL_TREE)
+    {
+      if (TREE_CODE (decl) == VAR_DECL)
+       {
+         tree field = lookup_field (context, DECL_NAME (decl), 0, 0);
+         if (field == NULL_TREE || TREE_CODE (field) != VAR_DECL)
+           cp_error ("`%#D' is not a static member of `%#T'", decl, context);
+         else if (duplicate_decls (decl, field))
+           decl = field;
+       }
+      
+      /* If it was not explicitly declared `extern',
+        revoke any previous claims of DECL_EXTERNAL.  */
+      if (DECL_THIS_EXTERN (decl) == 0)
+       DECL_EXTERNAL (decl) = 0;
+      if (DECL_LANG_SPECIFIC (decl))
+       DECL_IN_AGGR_P (decl) = 0;
+      pushclass (context, 2);
+    }
+
   /* Add this decl to the current binding level, but not if it
      comes from another scope, e.g. a static member variable.
      TEM may equal DECL or it may be a previous decl of the same name.  */
+  
   if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE)
       || (TREE_CODE (decl) == TEMPLATE_DECL && !global_bindings_p ())
       || TREE_CODE (type) == LANG_TYPE)
     tem = decl;
   else
-    {
-      tem = pushdecl (decl);
-      if (is_overloaded_fn (tem))
-       {
-         tree tem2;
-         tem = get_first_fn (tem);
-         tem2 = decl_value_member (decl, tem);
-         
-         if (tem2 != NULL_TREE)
-           tem = tem2;
-         else
-           {
-             while (tem && ! decls_match (decl, tem))
-               tem = DECL_CHAIN (tem);
-             if (tem == NULL_TREE)
-               tem = decl;
-           }
-       }
-    }
+    tem = pushdecl (decl);
             
-  /* Tell the back-end to use or not use .common as appropriate.  */
-  DECL_COMMON (tem) = flag_conserve_space;
+  /* Tell the back-end to use or not use .common as appropriate.  If we say
+     -fconserve-space, we want this to save space, at the expense of wrong
+     semantics.  If we say -fno-conserve-space, we want this to produce
+     errors about redefs; to do this we force variables into the data
+     segment.  Common storage is okay for non-public uninitialized data;
+     the linker can't match it with storage from other files, and we may
+     save some disk space.  */
+  DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (tem);
 
 #if 0
   /* We don't do this yet for GNU C++.  */
@@ -5197,10 +5650,7 @@ start_decl (declarator, declspecs, initialized, raises)
     }
 #endif
 
-  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_OVERLOADED (decl))
-    /* @@ Also done in start_function.  */
-    tem = push_overloaded_decl (tem, 1);
-  else if (TREE_CODE (decl) == TEMPLATE_DECL)
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
     {
       tree result = DECL_TEMPLATE_RESULT (decl);
       if (DECL_CONTEXT (result) != NULL_TREE)
@@ -5215,8 +5665,10 @@ start_decl (declarator, declspecs, initialized, raises)
              return NULL_TREE;
            }
 
-          if (/* TREE_CODE (result) == VAR_DECL */ 1)
-            {
+         if (TREE_CODE (result) == FUNCTION_DECL)
+           return tem;
+         else if (TREE_CODE (result) == VAR_DECL)
+           {
 #if 0
               tree tmpl = UPT_TEMPLATE (type);
              
@@ -5227,15 +5679,24 @@ start_decl (declarator, declspecs, initialized, raises)
               DECL_TEMPLATE_MEMBERS (tmpl)
                 = perm_tree_cons (DECL_NAME (tem), tem,
                                  DECL_TEMPLATE_MEMBERS (tmpl));
-#endif
              return tem;
+#else
+             sorry ("static data member templates");
+             return NULL_TREE;
+#endif
            }
-          my_friendly_abort (13);
+         else
+           my_friendly_abort (13);
         }
       else if (TREE_CODE (result) == FUNCTION_DECL)
-        tem = push_overloaded_decl (tem, 0);
-      else if (TREE_CODE (result) == VAR_DECL
-              || TREE_CODE (result) == TYPE_DECL)
+        /*tem = push_overloaded_decl (tem, 0)*/;
+      else if (TREE_CODE (result) == VAR_DECL)
+       {
+         cp_error ("data template `%#D' must be member of a class template",
+                   result);
+         return NULL_TREE;
+       }
+      else if (TREE_CODE (result) == TYPE_DECL)
        {
          cp_error ("invalid template `%#D'", result);
          return NULL_TREE;
@@ -5254,7 +5715,8 @@ start_decl (declarator, declspecs, initialized, raises)
         use temporary storage.  Do this even if we will ignore the value.  */
       if (current_binding_level == global_binding_level && debug_temp_inits)
        {
-         if (TYPE_NEEDS_CONSTRUCTING (type) || TREE_CODE (type) == REFERENCE_TYPE)
+         if (TYPE_NEEDS_CONSTRUCTING (type)
+             || TREE_CODE (type) == REFERENCE_TYPE)
            /* In this case, the initializer must lay down in permanent
               storage, since it will be saved until `finish_file' is run.   */
            ;
@@ -5269,6 +5731,7 @@ start_decl (declarator, declspecs, initialized, raises)
   return tem;
 }
 
+#if 0                          /* unused */
 static void
 make_temporary_for_reference (decl, ctor_call, init, cleanupp)
      tree decl, ctor_call, init;
@@ -5322,11 +5785,12 @@ make_temporary_for_reference (decl, ctor_call, init, cleanupp)
     {
       DECL_INITIAL (tmp) = init;
       TREE_STATIC (tmp) = current_binding_level == global_binding_level;
-      finish_decl (tmp, init, 0, 0);
+      finish_decl (tmp, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
     }
   if (TREE_STATIC (tmp))
     preserve_initializer ();
 }
+#endif
 
 /* Handle initialization of references.
    These three arguments from from `finish_decl', and have the
@@ -5337,15 +5801,13 @@ grok_reference_init (decl, type, init, cleanupp)
      tree decl, type, init;
      tree *cleanupp;
 {
-  char *errstr = NULL;
-  int is_reference;
   tree tmp;
-  tree this_ptr_type, actual_init = NULL_TREE;
 
   if (init == NULL_TREE)
     {
-      if (DECL_LANG_SPECIFIC (decl) == 0
-         || DECL_IN_AGGR_P (decl) == 0)
+      if ((DECL_LANG_SPECIFIC (decl) == 0
+          || DECL_IN_AGGR_P (decl) == 0)
+         && ! DECL_THIS_EXTERN (decl))
        {
          cp_error ("`%D' declared as reference but not initialized", decl);
          if (TREE_CODE (decl) == VAR_DECL)
@@ -5366,75 +5828,52 @@ grok_reference_init (decl, type, init, cleanupp)
 
   if (TREE_CODE (init) == TREE_LIST)
     init = build_compound_expr (init);
-  is_reference = TREE_CODE (TREE_TYPE (init)) == REFERENCE_TYPE;
-  tmp = is_reference ? convert_from_reference (init) : init;
+
+  if (TREE_CODE (TREE_TYPE (init)) == REFERENCE_TYPE)
+    init = convert_from_reference (init);
 
   if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE
       && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
     {
-      /* Note: default conversion is only called in very
-        special cases.  */
+      /* Note: default conversion is only called in very special cases.  */
       init = default_conversion (init);
     }
 
-  /* Can we just enreference this lvalue?  */
-  if ((is_reference || lvalue_p (init)
-       || (actual_init = unary_complex_lvalue (ADDR_EXPR, init)))
-      && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
-                   TYPE_MAIN_VARIANT (TREE_TYPE (tmp)), 0))
-    {
-      /* This section implements ANSI C++ June 5 1992 WP 8.4.3.5. */
-
-      /* A reference to a volatile T cannot be initialized with
-        a const T, and vice-versa.  */
-      if (TYPE_VOLATILE (TREE_TYPE (type)) && TREE_READONLY (init))
-       errstr = "cannot initialize a reference to a volatile `%T' with a const `%T'";
-      else if (TYPE_READONLY (TREE_TYPE (type)) && TREE_THIS_VOLATILE (init))
-       errstr = "cannot initialize a reference to a const `%T' with a volatile `%T'";
-      /* A reference to a plain T can be initialized only with a plain T. */
-      else if (!TYPE_VOLATILE (TREE_TYPE (type))
-              && !TYPE_READONLY (TREE_TYPE (type)))
-       {
-         if (TREE_READONLY (init))
-           errstr = "cannot initialize a reference to `%T' with a const `%T'";
-         else if (TREE_THIS_VOLATILE (init))
-           errstr = "cannot initialize a reference to `%T' with a volatile `%T'";
-       }
-      if (errstr)
-       {
-         cp_error (errstr, TREE_TYPE (type), TREE_TYPE (tmp));
-         goto fail;
-       }
-    }
-  /* OK, can we generate a reference then?  */
-  else if ((actual_init = convert_to_reference
-           (decl, type, init, 0, 0, "initialization", 0,
-            LOOKUP_SPECULATIVELY|LOOKUP_NORMAL)))
-    {
-      if (actual_init == error_mark_node)
-       goto fail;
+  tmp = convert_to_reference
+    (type, init, CONV_IMPLICIT, LOOKUP_SPECULATIVELY|LOOKUP_NORMAL, decl);
 
-      init = actual_init;
-      is_reference = 1;
-    }
-  /* OK, try going through a temporary.  */
-  else if ((actual_init = convert_to_reference
-           (error_mark_node, type, init, 0, 0, "initialization",
-            0, LOOKUP_NORMAL)))
+  if (tmp == error_mark_node)
+    goto fail;
+  else if (tmp != NULL_TREE)
     {
-      if (actual_init == error_mark_node)
-       goto fail;
-      
-      init = actual_init;
-      is_reference = 1;
+      tree subtype = TREE_TYPE (type);
+      init = tmp;
 
-      if (TREE_CODE (init) == WITH_CLEANUP_EXPR)
+      /* Associate the cleanup with the reference so that we
+        don't get burned by "aggressive" cleanup policy.  */
+      if (TYPE_NEEDS_DESTRUCTOR (subtype))
        {
-         /* Associate the cleanup with the reference so that we
-            don't get burned by "aggressive" cleanup policy.  */
-         *cleanupp = TREE_OPERAND (init, 2);
-         TREE_OPERAND (init, 2) = error_mark_node;
+         if (TREE_CODE (init) == WITH_CLEANUP_EXPR)
+           {
+             *cleanupp = TREE_OPERAND (init, 2);
+             TREE_OPERAND (init, 2) = error_mark_node;
+           }
+         else
+           {
+             if (TREE_CODE (tmp) == ADDR_EXPR)
+               tmp = TREE_OPERAND (tmp, 0);
+             if (TREE_CODE (tmp) == TARGET_EXPR)
+               {
+                 *cleanupp = build_delete
+                   (TYPE_POINTER_TO (subtype),
+                    build_unary_op (ADDR_EXPR, TREE_OPERAND (tmp, 0), 0),
+                    integer_two_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
+                 TREE_OPERAND (tmp, 2) = error_mark_node;
+               }
+           }
        }
+
+      DECL_INITIAL (decl) = save_expr (init);
     }
   else
     {
@@ -5442,54 +5881,6 @@ grok_reference_init (decl, type, init, cleanupp)
       goto fail;
     }
 
-  /* In the case of initialization, it is permissible
-     to assign one reference to another.  */
-  this_ptr_type = build_pointer_type (TREE_TYPE (type));
-
-  if (is_reference)
-    {
-      if (TREE_SIDE_EFFECTS (init))
-       DECL_INITIAL (decl) = save_expr (init);
-      else
-       DECL_INITIAL (decl) = init;
-    }
-  else if (lvalue_p (init))
-    {
-      tmp = build_unary_op (ADDR_EXPR, init, 0);
-      if (TREE_CODE (tmp) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (tmp, 0)) == WITH_CLEANUP_EXPR)
-       {
-         if (*cleanupp) my_friendly_abort (1);
-         *cleanupp = TREE_OPERAND (TREE_OPERAND (tmp, 0), 2);
-         TREE_OPERAND (TREE_OPERAND (tmp, 0), 2) = error_mark_node;
-       }
-      if (IS_AGGR_TYPE (TREE_TYPE (this_ptr_type)))
-       DECL_INITIAL (decl) = convert_pointer_to (TREE_TYPE (this_ptr_type), tmp);
-      else
-       DECL_INITIAL (decl) = convert (this_ptr_type, tmp);
-
-      DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
-      if (DECL_INITIAL (decl) == current_class_decl)
-       DECL_INITIAL (decl) = copy_node (current_class_decl);
-      TREE_TYPE (DECL_INITIAL (decl)) = type;
-    }
-  /* If actual_init is set here, it is set from the first check above.  */
-  else if (actual_init)
-    {
-      /* The initializer for this decl goes into its
-        DECL_REFERENCE_SLOT.  Make sure that we can handle
-        multiple evaluations without ill effect.  */
-      if (TREE_CODE (actual_init) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (actual_init, 0)) == TARGET_EXPR)
-       actual_init = save_expr (actual_init);
-      DECL_INITIAL (decl) = convert_pointer_to (TREE_TYPE (this_ptr_type), actual_init);
-      DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
-      TREE_TYPE (DECL_INITIAL (decl)) = type;
-    }
-  else
-    my_friendly_abort (1);
-
- done:
   /* ?? Can this be optimized in some cases to
      hand back the DECL_INITIAL slot??  */
   if (TYPE_SIZE (TREE_TYPE (type)))
@@ -5513,6 +5904,32 @@ grok_reference_init (decl, type, init, cleanupp)
   return;
 }
 
+/* Fill in DECL_INITIAL with some magical value to prevent expand_decl from
+   mucking with forces it does not comprehend (i.e. initialization with a
+   constructor).  If we are at global scope and won't go into COMMON, fill
+   it in with a dummy CONSTRUCTOR to force the variable into .data;
+   otherwise we can use error_mark_node.  */
+
+static tree
+obscure_complex_init (decl, init)
+     tree decl, init;
+{
+  if (! flag_no_inline && TREE_STATIC (decl))
+    {
+      if (extract_init (decl, init))
+       return NULL_TREE;
+    }
+
+  if (current_binding_level == global_binding_level
+      && ! DECL_COMMON (decl))
+    DECL_INITIAL (decl) = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE,
+                                NULL_TREE);
+  else
+    DECL_INITIAL (decl) = error_mark_node;
+
+  return init;
+}
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -5527,16 +5944,20 @@ grok_reference_init (decl, type, init, cleanupp)
    INIT0 holds the value of an initializer that should be allowed to escape
    the normal rules.
 
+   FLAGS is LOOKUP_ONLYCONVERTING is the = init syntax was used, else 0
+   if the (init) syntax was used.
+
    For functions that take default parameters, DECL points to its
    "maximal" instantiation.  `finish_decl' must then also declared its
    subsequently lower and lower forms of instantiation, checking for
    ambiguity as it goes.  This can be sped up later.  */
 
 void
-finish_decl (decl, init, asmspec_tree, need_pop)
+finish_decl (decl, init, asmspec_tree, need_pop, flags)
      tree decl, init;
      tree asmspec_tree;
      int need_pop;
+     int flags;
 {
   register tree type;
   tree cleanup = NULL_TREE, ttype;
@@ -5553,12 +5974,9 @@ finish_decl (decl, init, asmspec_tree, need_pop)
       return;
     }
 
+  /* If a name was specified, get the string.  */
   if (asmspec_tree)
-    {
       asmspec = TREE_STRING_POINTER (asmspec_tree);
-      /* Zero out old RTL, since we will rewrite it.  */
-      DECL_RTL (decl) = NULL_RTX;
-    }
 
   /* If the type of the thing we are declaring either has
      a constructor, or has a virtual function table pointer,
@@ -5568,6 +5986,14 @@ finish_decl (decl, init, asmspec_tree, need_pop)
 
   type = TREE_TYPE (decl);
 
+  if (type == error_mark_node)
+    {
+      if (current_binding_level == global_binding_level && temporary)
+       end_temporary_allocation ();
+
+      return;
+    }
+
   was_incomplete = (DECL_SIZE (decl) == NULL_TREE);
 
   /* Take care of TYPE_DECLs up front.  */
@@ -5579,7 +6005,8 @@ finish_decl (decl, init, asmspec_tree, need_pop)
          TREE_TYPE (decl) = type = TREE_TYPE (init);
          DECL_INITIAL (decl) = init = NULL_TREE;
        }
-      if (IS_AGGR_TYPE (type) && DECL_NAME (decl))
+      if (type != error_mark_node
+         && IS_AGGR_TYPE (type) && DECL_NAME (decl))
        {
          if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type)
            cp_warning ("shadowing previous type declaration of `%#D'", decl);
@@ -5591,13 +6018,6 @@ finish_decl (decl, init, asmspec_tree, need_pop)
                                DECL_CONTEXT (decl) == NULL_TREE, 0);
       goto finish_end;
     }
-  if (type != error_mark_node && IS_AGGR_TYPE (type)
-      && CLASSTYPE_DECLARED_EXCEPTION (type))
-    {
-      finish_exception_decl (NULL_TREE, decl);
-      CLASSTYPE_GOT_SEMICOLON (type) = 1;
-      goto finish_end;
-    }
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
       ttype = target_type (type);
@@ -5645,10 +6065,7 @@ finish_decl (decl, init, asmspec_tree, need_pop)
       if (asmspec)
        {
          /* This must override the asm specifier which was placed
-            by grokclassfn.  Lay this out fresh.
-            
-            @@ Should emit an error if this redefines an asm-specified
-            @@ name, or if we have already used the function's name.  */
+            by grokclassfn.  Lay this out fresh.  */
          DECL_RTL (TREE_TYPE (decl)) = NULL_RTX;
          DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
          make_decl_rtl (decl, asmspec, 0);
@@ -5662,13 +6079,17 @@ finish_decl (decl, init, asmspec_tree, need_pop)
   else if (TREE_CODE (type) == REFERENCE_TYPE
           || (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE_REFERENCE (type)))
     {
+      if (TREE_STATIC (decl))
+       make_decl_rtl (decl, NULL_PTR,
+                      current_binding_level == global_binding_level
+                      || pseudo_global_level_p ());
       grok_reference_init (decl, type, init, &cleanup);
       init = NULL_TREE;
     }
 
   GNU_xref_decl (current_function_decl, decl);
 
-  if (TREE_CODE (decl) == FIELD_DECL || DECL_EXTERNAL (decl))
+  if (TREE_CODE (decl) == FIELD_DECL)
     ;
   else if (TREE_CODE (decl) == CONST_DECL)
     {
@@ -5686,12 +6107,12 @@ finish_decl (decl, init, asmspec_tree, need_pop)
        {
          if (TREE_CODE (type) == ARRAY_TYPE)
            init = digest_init (type, init, (tree *) 0);
-         else if (TREE_CODE (init) == CONSTRUCTOR
-                  && CONSTRUCTOR_ELTS (init) != NULL_TREE)
+         else if (TREE_CODE (init) == CONSTRUCTOR)
            {
              if (TYPE_NEEDS_CONSTRUCTING (type))
                {
-                 cp_error ("`%D' must be initialized by constructor, not by `{...}'", decl);
+                 cp_error ("`%D' must be initialized by constructor, not by `{...}'",
+                           decl);
                  init = error_mark_node;
                }
              else
@@ -5738,39 +6159,21 @@ finish_decl (decl, init, asmspec_tree, need_pop)
                }
            }
 #endif
-
-         /* We must hide the initializer so that expand_decl
-            won't try to do something it does not understand.  */
-         if (current_binding_level == global_binding_level)
-           {
-             tree value;
-             if (flag_conserve_space)
-               /* If we say -fconserve-space, we want this to save
-                  space, at the expense of wrong semantics. */
-               /* Should this be a NULL_TREE? */
-               value = error_mark_node;
-             else
-               /* If we say -fno-conserve-space, we want this to
-                  produce errors about redefs, to do this we make it
-                  go in the data space */
-               value = digest_init (type, empty_init_node, (tree *) 0);
-             DECL_INITIAL (decl) = value;
-           }
-         else
-           DECL_INITIAL (decl) = error_mark_node;
        }
       else
        {
        dont_use_constructor:
          if (TREE_CODE (init) != TREE_VEC)
            init = store_init_value (decl, init);
-
-         if (init)
-           /* Don't let anyone try to initialize this variable
-              until we are ready to do so.  */
-           DECL_INITIAL (decl) = error_mark_node;
        }
+
+      if (init)
+       /* We must hide the initializer so that expand_decl
+          won't try to do something it does not understand.  */
+       init = obscure_complex_init (decl, init);
     }
+  else if (DECL_EXTERNAL (decl))
+    ;
   else if (TREE_CODE_CLASS (TREE_CODE (type)) == 't'
           && (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type)))
     {
@@ -5782,7 +6185,8 @@ finish_decl (decl, init, asmspec_tree, need_pop)
          if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (ctype))
            cp_error ("structure `%D' with uninitialized const members", decl);
          if (CLASSTYPE_REF_FIELDS_NEED_INIT (ctype))
-           cp_error ("structure `%D' with uninitialized reference members", decl);
+           cp_error ("structure `%D' with uninitialized reference members",
+                     decl);
        }
 
       if (TREE_CODE (decl) == VAR_DECL
@@ -5791,26 +6195,9 @@ finish_decl (decl, init, asmspec_tree, need_pop)
          && (TYPE_READONLY (type) || TREE_READONLY (decl)))
        cp_error ("uninitialized const `%D'", decl);
 
-      /* Initialize variables in need of static initialization
-        with `empty_init_node' to keep assemble_variable from putting them
-        in the wrong program space.  (Common storage is okay for non-public
-        uninitialized data; the linker can't match it with storage from other
-        files, and we may save some disk space.)  */
-      if (flag_pic == 0
-         && TREE_STATIC (decl)
-         && TREE_PUBLIC (decl)
-         && ! DECL_EXTERNAL (decl)
-         && TREE_CODE (decl) == VAR_DECL
-         && TYPE_NEEDS_CONSTRUCTING (type)
-         && (DECL_INITIAL (decl) == NULL_TREE
-             || DECL_INITIAL (decl) == error_mark_node)
-         /* If we say -fconserve-space, we want this to save space,
-            at the expense of wrong semantics. */
-         && ! flag_conserve_space)
-       {
-         tree value = digest_init (type, empty_init_node, (tree *) 0);
-         DECL_INITIAL (decl) = value;
-       }
+      if (TYPE_SIZE (type) != NULL_TREE
+         && TYPE_NEEDS_CONSTRUCTING (type))
+       init = obscure_complex_init (decl, NULL_TREE);
     }
   else if (TREE_CODE (decl) == VAR_DECL
           && TREE_CODE (type) != REFERENCE_TYPE
@@ -5902,6 +6289,10 @@ finish_decl (decl, init, asmspec_tree, need_pop)
        /* Let debugger know it should output info for this type.  */
        note_debug_info_needed (ttype);
 
+      if (TREE_STATIC (decl) && DECL_CONTEXT (decl)
+         && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
+       note_debug_info_needed (DECL_CONTEXT (decl));
+
       if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
          && DECL_SIZE (decl) != NULL_TREE
          && ! TREE_CONSTANT (DECL_SIZE (decl)))
@@ -5924,7 +6315,6 @@ finish_decl (decl, init, asmspec_tree, need_pop)
              cleanup = TREE_OPERAND (init, 2);
              init = TREE_OPERAND (init, 0);
              current_binding_level->have_cleanups = 1;
-             current_binding_level->more_exceptions_ok = 0;
            }
          else
            cleanup = maybe_build_cleanup (decl);
@@ -5959,14 +6349,6 @@ finish_decl (decl, init, asmspec_tree, need_pop)
       if (was_temp)
        end_temporary_allocation ();
 
-      /* If we are in need of a cleanup, get out of any implicit
-        handlers that have been established so far.  */
-      if (cleanup && current_binding_level->parm_flag == 3)
-       {
-         pop_implicit_try_blocks (decl);
-         current_binding_level->more_exceptions_ok = 0;
-       }
-
       if (TREE_CODE (decl) == VAR_DECL
          && current_binding_level != global_binding_level
          && ! TREE_STATIC (decl)
@@ -5979,7 +6361,7 @@ finish_decl (decl, init, asmspec_tree, need_pop)
               && TREE_READONLY (decl)
               && DECL_INITIAL (decl) != NULL_TREE
               && DECL_INITIAL (decl) != error_mark_node
-              && DECL_INITIAL (decl) != empty_init_node)
+              && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
        {
          DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
 
@@ -6002,14 +6384,11 @@ finish_decl (decl, init, asmspec_tree, need_pop)
              store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
              TREE_ASM_WRITTEN (decl) = 1;
            }
-         else if (toplev)
+         else if (toplev && ! TREE_PUBLIC (decl))
            {
-             /* Keep GCC from complaining that this variable
-                is defined but never used.  */
-             TREE_USED (decl) = 1;
              /* If this is a static const, change its apparent linkage
-                if it belongs to a #pragma interface.  */
-             if (TREE_STATIC (decl) && !interface_unknown)
+                if it belongs to a #pragma interface.  */
+             if (!interface_unknown)
                {
                  TREE_PUBLIC (decl) = 1;
                  DECL_EXTERNAL (decl) = interface_only;
@@ -6069,52 +6448,7 @@ finish_decl (decl, init, asmspec_tree, need_pop)
        signature_error (decl, TREE_TYPE (type));
 
       if (TREE_CODE (decl) == FUNCTION_DECL)
-       {
-         /* C++: Handle overloaded functions with default parameters.  */
-         if (DECL_OVERLOADED (decl))
-           {
-             tree parmtypes = TYPE_ARG_TYPES (type);
-             tree prev = NULL_TREE;
-             tree original_name = DECL_NAME (decl);
-             struct lang_decl *tmp_lang_decl = DECL_LANG_SPECIFIC (decl);
-             /* All variants will share an uncollectible lang_decl.  */
-             copy_decl_lang_specific (decl);
-
-             while (parmtypes && parmtypes != void_list_node)
-               {
-                 /* The default value for the parameter in parmtypes is
-                    stored in the TREE_PURPOSE of the TREE_LIST.  */ 
-                 if (TREE_PURPOSE (parmtypes))
-                   {
-                     tree fnname, fndecl;
-                     tree *argp;
-
-                     argp = prev ? & TREE_CHAIN (prev)
-                       : & TYPE_ARG_TYPES (type);
-
-                     *argp = NULL_TREE;
-                     fnname = build_decl_overload (original_name, TYPE_ARG_TYPES (type), 0);
-                     *argp = parmtypes;
-                     fndecl = build_decl (FUNCTION_DECL, fnname, type);
-                     DECL_EXTERNAL (fndecl) = DECL_EXTERNAL (decl);
-                     TREE_PUBLIC (fndecl) = TREE_PUBLIC (decl);
-                     DECL_INLINE (fndecl) = DECL_INLINE (decl);
-                     /* Keep G++ from thinking this function is unused.
-                        It is only used to speed up search in name space.  */
-                     TREE_USED (fndecl) = 1;
-                     TREE_ASM_WRITTEN (fndecl) = 1;
-                     DECL_INITIAL (fndecl) = NULL_TREE;
-                     DECL_LANG_SPECIFIC (fndecl) = DECL_LANG_SPECIFIC (decl);
-                     fndecl = pushdecl (fndecl);
-                     DECL_INITIAL (fndecl) = error_mark_node;
-                     DECL_RTL (fndecl) = DECL_RTL (decl);
-                   }
-                 prev = parmtypes;
-                 parmtypes = TREE_CHAIN (parmtypes);
-               }
-             DECL_LANG_SPECIFIC (decl) = tmp_lang_decl;
-           }
-       }
+       ;
       else if (DECL_EXTERNAL (decl))
        ;
       else if (TREE_STATIC (decl) && type != error_mark_node)
@@ -6132,6 +6466,7 @@ finish_decl (decl, init, asmspec_tree, need_pop)
        }
       else if (! toplev)
        {
+         tree old_cleanups = cleanups_this_call;
          /* This is a declared decl which must live until the
             end of the binding contour.  It may need a cleanup.  */
 
@@ -6156,7 +6491,11 @@ finish_decl (decl, init, asmspec_tree, need_pop)
                expand_decl (decl);
              else if (cleanup)
                {
-                 expand_decl_cleanup (NULL_TREE, cleanup);
+                 /* XXX: Why don't we use decl here?  */
+                 /* Ans: Because it was already expanded? */
+                 if (! expand_decl_cleanup (NULL_TREE, cleanup))
+                   cp_error ("parser lost in parsing declaration of `%D'",
+                             decl);
                  /* Cleanup used up here.  */
                  cleanup = NULL_TREE;
                }
@@ -6169,22 +6508,28 @@ finish_decl (decl, init, asmspec_tree, need_pop)
 
              if (init || TYPE_NEEDS_CONSTRUCTING (type))
                {
-                 emit_line_note (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
-                 expand_aggr_init (decl, init, 0);
+                 emit_line_note (DECL_SOURCE_FILE (decl),
+                                 DECL_SOURCE_LINE (decl));
+                 expand_aggr_init (decl, init, 0, flags);
                }
 
-             /* Set this to 0 so we can tell whether an aggregate
-                which was initialized was ever used.  */
-             if (TYPE_NEEDS_CONSTRUCTING (type))
+             /* Set this to 0 so we can tell whether an aggregate which
+                was initialized was ever used.  Don't do this if it has a
+                destructor, so we don't complain about the 'resource
+                allocation is initialization' idiom.  */
+             if (TYPE_NEEDS_CONSTRUCTING (type) && cleanup == NULL_TREE)
                TREE_USED (decl) = 0;
 
              /* Store the cleanup, if there was one.  */
              if (cleanup)
                {
                  if (! expand_decl_cleanup (decl, cleanup))
-                   cp_error ("parser lost in parsing declaration of `%D'", decl);
+                   cp_error ("parser lost in parsing declaration of `%D'",
+                             decl);
                }
            }
+         /* Cleanup any temporaries needed for the initial value.  */
+         expand_cleanups_to (old_cleanups);
        }
     finish_end0:
 
@@ -6216,6 +6561,23 @@ finish_decl (decl, init, asmspec_tree, need_pop)
 
  finish_end:
 
+  /* If requested, warn about definitions of large data objects.  */
+
+  if (warn_larger_than
+      && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
+      && !DECL_EXTERNAL (decl))
+    {
+      register tree decl_size = DECL_SIZE (decl);
+
+      if (decl_size && TREE_CODE (decl_size) == INTEGER_CST)
+       {
+         unsigned units = TREE_INT_CST_LOW (decl_size) / BITS_PER_UNIT;
+
+         if (units > larger_than_size)
+           warning_with_decl (decl, "size of `%s' is %u bytes", units);
+       }
+    }
+
   if (need_pop)
     {
       /* Resume permanent allocation, if not within a function.  */
@@ -6237,12 +6599,15 @@ expand_static_init (decl, init)
      tree init;
 {
   tree oldstatic = value_member (decl, static_aggregates);
+  tree old_cleanups;
+
   if (oldstatic)
     {
       if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
        cp_error ("multiple initializations given for `%D'", decl);
     }
-  else if (current_binding_level != global_binding_level)
+  else if (current_binding_level != global_binding_level
+          && current_binding_level->pseudo_global == 0)
     {
       /* Emit code to perform this initialization but once.  */
       tree temp;
@@ -6255,14 +6620,18 @@ expand_static_init (decl, init)
       rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
       expand_start_cond (build_binary_op (EQ_EXPR, temp,
                                          integer_zero_node, 1), 0);
+      old_cleanups = cleanups_this_call;
       expand_assignment (temp, integer_one_node, 0, 0);
-      if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+      if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
+         || TREE_CODE (init) == TREE_LIST)
        {
-         expand_aggr_init (decl, init, 0);
+         expand_aggr_init (decl, init, 0, 0);
          do_pending_stack_adjust ();
        }
       else
        expand_assignment (decl, init, 0, 0);
+      /* Cleanup any temporaries needed for the initial value.  */
+      expand_cleanups_to (old_cleanups);
       expand_end_cond ();
       if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
        {
@@ -6302,12 +6671,24 @@ complete_array_type (type, initial_value, do_default)
       /* Note MAXINDEX  is really the maximum index,
         one less than the size.  */
       if (TREE_CODE (initial_value) == STRING_CST)
-       maxindex = build_int_2 (TREE_STRING_LENGTH (initial_value) - 1, 0);
+       {
+         int eltsize
+           = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
+         maxindex = build_int_2 ((TREE_STRING_LENGTH (initial_value)
+                                  / eltsize) - 1, 0);
+       }
       else if (TREE_CODE (initial_value) == CONSTRUCTOR)
        {
-         register int nelts
-           = list_length (CONSTRUCTOR_ELTS (initial_value));
-         maxindex = build_int_2 (nelts - 1, - (nelts == 0));
+         tree elts = CONSTRUCTOR_ELTS (initial_value);
+         maxindex = size_binop (MINUS_EXPR, integer_zero_node, size_one_node);
+         for (; elts; elts = TREE_CHAIN (elts))
+           {
+             if (TREE_PURPOSE (elts))
+               maxindex = TREE_PURPOSE (elts);
+             else
+               maxindex = size_binop (PLUS_EXPR, maxindex, size_one_node);
+           }
+         maxindex = copy_node (maxindex);
        }
       else
        {
@@ -6329,9 +6710,17 @@ complete_array_type (type, initial_value, do_default)
 
   if (maxindex)
     {
+      tree itype;
+
       TYPE_DOMAIN (type) = build_index_type (maxindex);
       if (!TREE_TYPE (maxindex))
        TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
+      if (initial_value)
+        itype = TREE_TYPE (initial_value);
+      else
+       itype = NULL;
+      if (itype && !TYPE_DOMAIN (itype))
+       TYPE_DOMAIN (itype) = TYPE_DOMAIN (type);
     }
 
   /* Lay out the type now that we can get the real answer.  */
@@ -6372,11 +6761,12 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
   if (inlinep)
     cp_error ("`%D' declared as an `inline' %s", object, type);
   if (quals)
-    cp_error ("`const' and `volatile' function specifiers on `%D' invalid in %s declaration", object, type);
+    cp_error ("`const' and `volatile' function specifiers on `%D' invalid in %s declaration",
+             object, type);
   if (friendp)
     cp_error_at ("invalid friend declaration", object);
   if (raises)
-    cp_error_at ("invalid raises declaration", object);
+    cp_error_at ("invalid exception specifications", object);
 }
 
 /* CTYPE is class type, or null if non-class.
@@ -6391,13 +6781,14 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
    CHECK is 1 if we must find this method in CTYPE, 0 if we should
    not look, and -1 if we should not call `grokclassfn' at all.  */
 static tree
-grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, check, publicp)
+grokfndecl (ctype, type, declarator, virtualp, flags, quals,
+           raises, check, publicp, inlinep)
      tree ctype, type;
      tree declarator;
      int virtualp;
      enum overload_flags flags;
      tree quals, raises;
-     int check, publicp;
+     int check, publicp, inlinep;
 {
   tree cname, decl;
   int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
@@ -6426,8 +6817,25 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, check, publ
       DECL_CLASS_CONTEXT (decl) = ctype;
     }
 
-  if (publicp)
-    TREE_PUBLIC (decl) = 1;
+  /* All function decls start out public; we'll fix their linkage later (at
+     definition or EOF) if appropriate.  */
+  TREE_PUBLIC (decl) = 1;
+
+  if (ctype == NULL_TREE && ! strcmp (IDENTIFIER_POINTER (declarator), "main"))
+    {
+      if (inlinep)
+       error ("cannot declare `main' to be inline");
+      else if (! publicp)
+       error ("cannot declare `main' to be static");
+      inlinep = 0;
+      publicp = 1;
+    }
+         
+  if (! publicp)
+    DECL_C_STATIC (decl) = 1;
+
+  if (inlinep)
+    DECL_THIS_INLINE (decl) = DECL_INLINE (decl) = 1;
 
   DECL_EXTERNAL (decl) = 1;
   if (quals != NULL_TREE && TREE_CODE (type) == FUNCTION_TYPE)
@@ -6457,10 +6865,13 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, check, publ
       grokclassfn (ctype, declarator, decl, flags, quals);
       if (check)
        check_classfn (ctype, declarator, decl);
-      grok_ctor_properties (ctype, decl);
-      if (check == 0)
+      if (! grok_ctor_properties (ctype, decl))
+       return NULL_TREE;
+
+      if (check == 0 && ! current_function_decl)
        {
-         /* FIXME: this should only need to look at IDENTIFIER_GLOBAL_VALUE.  */
+         /* FIXME: this should only need to look at
+             IDENTIFIER_GLOBAL_VALUE.  */
          tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
          if (tmp == NULL_TREE)
            IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
@@ -6492,25 +6903,27 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, check, publ
       if (ctype == NULL_TREE || check)
        return decl;
 
-      /* Now install the declaration of this function so that
-        others may find it (esp. its DECL_FRIENDLIST).
-        Pretend we are at top level, we will get true
-        reference later, perhaps.
-
-        FIXME: This should only need to look at IDENTIFIER_GLOBAL_VALUE.  */
-      tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
-      if (tmp == NULL_TREE)
-       IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
-      else if (TREE_CODE (tmp) != TREE_CODE (decl))
-       cp_error ("inconsistent declarations for `%D'", decl);
-      else
+      /* Now install the declaration of this function so that others may
+        find it (esp. its DECL_FRIENDLIST).  Don't do this for local class
+        methods, though.  */
+      if (! current_function_decl)
        {
-         duplicate_decls (decl, tmp);
-         decl = tmp;
-         /* avoid creating circularities.  */
-         DECL_CHAIN (decl) = NULL_TREE;
+         /* FIXME: this should only need to look at
+             IDENTIFIER_GLOBAL_VALUE.  */
+         tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
+         if (tmp == NULL_TREE)
+           IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
+         else if (TREE_CODE (tmp) != TREE_CODE (decl))
+           cp_error ("inconsistent declarations for `%D'", decl);
+         else
+           {
+             duplicate_decls (decl, tmp);
+             decl = tmp;
+             /* avoid creating circularities.  */
+             DECL_CHAIN (decl) = NULL_TREE;
+           }
+         make_decl_rtl (decl, NULL_PTR, 1);
        }
-      make_decl_rtl (decl, NULL_PTR, 1);
 
       /* If this declaration supersedes the declaration of
         a method declared virtual in the base class, then
@@ -6522,10 +6935,11 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, check, publ
        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)
+           if (TYPE_VIRTUAL_P (BINFO_TYPE (base_binfo))
+               || flag_all_virtual == 1)
              {
-               tmp = get_first_matching_virtual (base_binfo, decl,
-                                                 flags == DTOR_FLAG);
+               tmp = get_matching_virtual (base_binfo, decl,
+                                           flags == DTOR_FLAG);
                if (tmp)
                  {
                    /* If this function overrides some virtual in some base
@@ -6539,40 +6953,33 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, check, publ
                       path to its virtual baseclass.  */
                    if (staticp)
                      {
-                       cp_error ("method `%D' may not be declared static", decl);
-                       cp_error_at ("(since `%D' declared virtual in base class.)", tmp);
+                       cp_error ("method `%D' may not be declared static",
+                                 decl);
+                       cp_error_at ("(since `%D' declared virtual in base class.)",
+                                    tmp);
                        break;
                      }
                    virtualp = 1;
 
-#if 0
-                   /* Disable this as we want the most recent fndecl, not the most
-                      base fndecl. */
-                   if ((TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (base_binfo))
-                        || TYPE_USES_MULTIPLE_INHERITANCE (ctype))
-                       && BINFO_TYPE (base_binfo) != DECL_CONTEXT (tmp))
-                     tmp = get_first_matching_virtual (TYPE_BINFO (DECL_CONTEXT (tmp)),
-                                                       decl, flags == DTOR_FLAG);
-#endif
-                   if (value_member (tmp, DECL_VINDEX (decl)) == NULL_TREE)
-                     {
-                       /* The argument types may have changed... */
-                       tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
-                       tree base_variant = TREE_TYPE (TREE_VALUE (argtypes));
-
-                       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 (ctype, type, raises);
-                           raises = TYPE_RAISES_EXCEPTIONS (type);
-                         }
-                       TREE_TYPE (decl) = type;
-                       DECL_VINDEX (decl)
-                         = tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl));
-                     }
+                   {
+                     /* The argument types may have changed... */
+                     tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+                     tree base_variant = TREE_TYPE (TREE_VALUE (argtypes));
+
+                     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 (ctype, type, raises);
+                         raises = TYPE_RAISES_EXCEPTIONS (type);
+                       }
+                     TREE_TYPE (decl) = type;
+                     DECL_VINDEX (decl)
+                       = tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl));
+                   }
+                   break;
                  }
              }
          }
@@ -6610,52 +7017,18 @@ grokvardecl (type, declarator, specbits, initialized)
     {
       /* If you declare a static member so that it
         can be initialized, the code will reach here.  */
-      tree field = lookup_field (TYPE_OFFSET_BASETYPE (type),
-                                declarator, 0, 0);
-      if (field == NULL_TREE || TREE_CODE (field) != VAR_DECL)
-       {
-         tree basetype = TYPE_OFFSET_BASETYPE (type);
-         error ("`%s' is not a static member of class `%s'",
-                IDENTIFIER_POINTER (declarator),
-                TYPE_NAME_STRING (basetype));
-         type = TREE_TYPE (type);
-         decl = build_lang_field_decl (VAR_DECL, declarator, type);
-         DECL_CONTEXT (decl) = basetype;
-         DECL_CLASS_CONTEXT (decl) = basetype;
-       }
-      else
-       {
-         tree f_type = TREE_TYPE (field);
-         tree o_type = TREE_TYPE (type);
-
-         if (TYPE_SIZE (f_type) == NULL_TREE)
-           {
-             if (TREE_CODE (f_type) != TREE_CODE (o_type)
-                 || (TREE_CODE (f_type) == ARRAY_TYPE
-                     && TREE_TYPE (f_type) != TREE_TYPE (o_type)))
-               error ("redeclaration of type for `%s'",
-                      IDENTIFIER_POINTER (declarator));
-             else if (TYPE_SIZE (o_type) != NULL_TREE)
-               TREE_TYPE (field) = type;
-           }
-         else if (f_type != o_type)
-           error ("redeclaration of type for `%s'",
-                  IDENTIFIER_POINTER (declarator));
-         decl = field;
-         if (initialized && DECL_INITIAL (decl)
-             /* Complain about multiply-initialized
-                member variables, but don't be faked
-                out if initializer is faked up from `empty_init_node'.  */
-             && (TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR
-                 || CONSTRUCTOR_ELTS (DECL_INITIAL (decl)) != NULL_TREE))
-           error_with_aggr_type (DECL_CONTEXT (decl),
-                                 "multiple initializations of static member `%s::%s'",
-                                 IDENTIFIER_POINTER (DECL_NAME (decl)));
-       }
+      tree basetype = TYPE_OFFSET_BASETYPE (type);
+      type = TREE_TYPE (type);
+      decl = build_lang_field_decl (VAR_DECL, declarator, type);
+      DECL_CONTEXT (decl) = basetype;
+      DECL_CLASS_CONTEXT (decl) = basetype;
+      DECL_ASSEMBLER_NAME (decl) = build_static_name (basetype, declarator);
     }
   else
     decl = build_decl (VAR_DECL, declarator, type);
 
+  DECL_ASSEMBLER_NAME (decl) = current_namespace_id (DECL_ASSEMBLER_NAME (decl));
+
   if (RIDBIT_SETP (RID_EXTERN, specbits))
     {
       DECL_THIS_EXTERN (decl) = 1;
@@ -6669,7 +7042,7 @@ grokvardecl (type, declarator, specbits, initialized)
     {
       TREE_PUBLIC (decl) = 1;
       TREE_STATIC (decl) = 1;
-      DECL_EXTERNAL (decl) = !initialized;
+      DECL_EXTERNAL (decl) = 0;
     }
   /* At top level, either `static' or no s.c. makes a definition
      (perhaps tentative), and absence of `static' makes it public.  */
@@ -6708,17 +7081,22 @@ build_ptrmemfunc_type (type)
 
   u = make_lang_type (UNION_TYPE);
   fields[0] = build_lang_field_decl (FIELD_DECL, pfn_identifier, type);
-  fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier, delta_type_node);
+  fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier,
+                                    delta_type_node);
   finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node);
   TYPE_NAME (u) = NULL_TREE;
 
   t = make_lang_type (RECORD_TYPE);
 
   /* Let the front-end know this is a pointer to member function. */
-  TYPE_PTRMEMFUNC_FLAG(t) = 1;
-
-  fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier, delta_type_node);
-  fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier, delta_type_node);
+  TYPE_PTRMEMFUNC_FLAG (t) = 1;
+  /* and not really an aggregate.  */
+  IS_AGGR_TYPE (t) = 0;
+
+  fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier,
+                                    delta_type_node);
+  fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier,
+                                    delta_type_node);
   fields[2] = build_lang_field_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
   finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
 
@@ -6755,6 +7133,7 @@ build_ptrmemfunc_type (type)
       try to parse.
      PARM for a parameter declaration (either within a function prototype
       or before a function body).  Make a PARM_DECL, or return void_type_node.
+     CATCHPARM for a parameter declaration before a catch clause.
      TYPENAME if for a typename (in a cast or sizeof).
       Don't make a DECL node; just return the ..._TYPE node.
      FIELD for a struct or union field; make a FIELD_DECL.
@@ -6807,7 +7186,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   int longlong = 0;
   int constp;
   int volatilep;
-  int virtualp, friendp, inlinep, staticp;
+  int virtualp, explicitp, friendp, inlinep, staticp;
   int explicit_int = 0;
   int explicit_char = 0;
   int opaque_typedef = 0;
@@ -6818,6 +7197,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   enum tree_code innermost_code = ERROR_MARK;
   int bitfield = 0;
   int size_varies = 0;
+  tree decl_machine_attr = NULL_TREE;
   /* Set this to error_mark_node for FIELD_DECLs we could not handle properly.
      All FIELD_DECLs we build here have `init' put into their DECL_INITIAL.  */
   tree init = NULL_TREE;
@@ -6831,7 +7211,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   tree ctype = current_class_type;
   tree ctor_return_type = NULL_TREE;
   enum overload_flags flags = NO_SPECIAL;
-  int seen_scope_ref = 0;
   tree quals = NULL_TREE;
 
   RIDBIT_RESET_ALL (specbits);
@@ -6848,7 +7227,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   /* Look inside a declarator for the name being declared
      and get it as a string, for an error message.  */
   {
-    tree type, last = NULL_TREE;
+    tree last = NULL_TREE;
     register tree decl = declarator;
     name = NULL;
 
@@ -6928,13 +7307,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
              init = TREE_OPERAND (decl, 1);
 
              decl = start_decl (declarator, declspecs, 1, NULL_TREE);
-             finish_decl (decl, init, NULL_TREE, 1);
+             finish_decl (decl, init, NULL_TREE, 1, 0);
              return 0;
            }
          innermost_code = TREE_CODE (decl);
-         decl = TREE_OPERAND (decl, 0);
          if (decl_context == FIELD && ctype == NULL_TREE)
            ctype = current_class_type;
+         if (ctype
+             && TREE_OPERAND (decl, 0) == constructor_name_full (ctype))
+           TREE_OPERAND (decl, 0) = constructor_name (ctype);
+         decl = TREE_OPERAND (decl, 0);
          if (ctype != NULL_TREE
              && decl != NULL_TREE && flags != DTOR_FLAG
              && decl == constructor_name (ctype))
@@ -6947,8 +7329,23 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
        case IDENTIFIER_NODE:
          dname = decl;
-         name = IDENTIFIER_POINTER (decl);
          decl = NULL_TREE;
+
+         if (! IDENTIFIER_OPNAME_P (dname)
+             /* Linux headers use '__op'.  Arrgh.  */
+             || IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))
+           name = IDENTIFIER_POINTER (dname);
+         else
+           {
+             if (IDENTIFIER_TYPENAME_P (dname))
+               {
+                 my_friendly_assert (flags == NO_SPECIAL, 154);
+                 flags = TYPENAME_FLAG;
+                 ctor_return_type = TREE_TYPE (dname);
+                 return_type = return_conversion;
+               }
+             name = operator_name_string (dname);
+           }
          break;
 
        case RECORD_TYPE:
@@ -6965,22 +7362,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          decl = NULL_TREE;
          break;
 
-       case TYPE_EXPR:
-         my_friendly_assert (flags == NO_SPECIAL, 154);
-         flags = TYPENAME_FLAG;
-         name = "operator <typename>"; /* We don't know the type yet.  */
-         /* Go to the absdcl.  */
-         decl = TREE_OPERAND (decl, 0);
-         return_type = return_conversion;
-         break;
-
          /* C++ extension */
        case SCOPE_REF:
-/*
-         if (seen_scope_ref == 1)
-           error ("multiple `::' terms in declarator invalid");
-*/
-         seen_scope_ref += 1;
          {
            /* Perform error checking, and convert class names to types.
               We may call grokdeclarator multiple times for the same
@@ -7027,6 +7410,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                  }
              }
 
+           if (ctype
+               && TREE_OPERAND (decl, 1) == constructor_name_full (ctype))
+             TREE_OPERAND (decl, 1) = constructor_name (ctype);
            decl = TREE_OPERAND (decl, 1);
            if (ctype)
              {
@@ -7038,12 +7424,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                  }
                else if (TREE_CODE (decl) == BIT_NOT_EXPR
                         && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
-                        && constructor_name (ctype) == TREE_OPERAND (decl, 0))
+                        && (constructor_name (ctype) == TREE_OPERAND (decl, 0)
+                            || constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
                  {
                    return_type = return_dtor;
                    ctor_return_type = ctype;
                    flags = DTOR_FLAG;
-                   decl = TREE_OPERAND (decl, 0);
+                   decl = TREE_OPERAND (decl, 0) = constructor_name (ctype);
                  }
              }
          }
@@ -7066,6 +7453,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   if (funcdef_flag && innermost_code != CALL_EXPR)
     return 0;
 
+  if (((dname && IDENTIFIER_OPNAME_P (dname)) || flags == TYPENAME_FLAG)
+      && innermost_code != CALL_EXPR
+      && ! (ctype && declspecs == NULL_TREE))
+    {
+      cp_error ("declaration of `%D' as non-function", dname);
+      return void_type_node;
+    }
+
   /* Anything declared one level down from the top level
      must be one of the parameters of a function
      (because the body is at least two levels down).  */
@@ -7113,34 +7508,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
       if (TREE_CODE (id) == IDENTIFIER_NODE)
        {
-         if (id == ridpointers[(int) RID_INT])
-           {
-             if (type)
-               error ("extraneous `int' ignored");
-             else
-               {
-                 explicit_int = 1;
-                 type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id));
-               }
-             goto found;
-           }
-         if (id == ridpointers[(int) RID_CHAR])
+         if (id == ridpointers[(int) RID_INT]
+             || id == ridpointers[(int) RID_CHAR]
+             || id == ridpointers[(int) RID_BOOL]
+             || id == ridpointers[(int) RID_WCHAR])
            {
              if (type)
-               error ("extraneous `char' ignored");
-             else
                {
-                 explicit_char = 1;
-                 type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id));
+                 if (id == ridpointers[(int) RID_BOOL])
+                   error ("`bool' is now a keyword");
+                 else
+                   cp_error ("extraneous `%T' ignored", id);
                }
-             goto found;
-           }
-         if (id == ridpointers[(int) RID_WCHAR])
-           {
-             if (type)
-               error ("extraneous `__wchar_t' ignored");
              else
                {
+                 if (id == ridpointers[(int) RID_INT])
+                   explicit_int = 1;
+                 else if (id == ridpointers[(int) RID_CHAR])
+                   explicit_char = 1;
                  type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id));
                }
              goto found;
@@ -7155,24 +7540,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
              goto found;
            }
 
-         for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++)
+         for (i = (int) RID_FIRST_MODIFIER; i <= (int) RID_LAST_MODIFIER; i++)
            {
              if (ridpointers[i] == id)
                {
                  if (i == (int) RID_LONG && RIDBIT_SETP (i, specbits))
                    {
-#if 0
-                     if (pedantic)
-                       pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
-                     else
-#endif
-                       if (longlong)
-                       error ("`long long long' is too long for GCC");
+                     if (pedantic && ! in_system_header)
+                       pedwarn ("ANSI C++ does not support `long long'");
+                     else if (longlong)
+                       error ("`long long long' is too long for GCC");
                      else
                        longlong = 1;
                    }
                  else if (RIDBIT_SETP (i, specbits))
-                   warning ("duplicate `%s'", IDENTIFIER_POINTER (id));
+                   pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
                  RIDBIT_SET (i, specbits);
                  goto found;
                }
@@ -7189,6 +7571,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          else
            {
              type = TREE_TYPE (t);
+             decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id);
              typedef_decl = t;
            }
        }
@@ -7207,6 +7590,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
      which case the type defaults to `unknown type' and is
      instantiated when assigning to a signature pointer or ref.  */
 
+  if (type == NULL_TREE
+      && (RIDBIT_SETP (RID_SIGNED, specbits)
+         || RIDBIT_SETP (RID_UNSIGNED, specbits)
+         || RIDBIT_SETP (RID_LONG, specbits)
+         || RIDBIT_SETP (RID_SHORT, specbits)))
+    {
+      /* These imply 'int'.  */
+      type = integer_type_node;
+      explicit_int = 1;
+    }
+
   if (type == NULL_TREE)
     {
       explicit_int = -1;
@@ -7214,6 +7608,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
        type = void_type_node;
       else if (return_type == return_ctor)
        type = TYPE_POINTER_TO (ctor_return_type);
+      else if (return_type == return_conversion)
+       type = ctor_return_type;
       else if (current_class_type
               && IS_SIGNATURE (current_class_type)
               && (RIDBIT_SETP (RID_TYPEDEF, specbits)
@@ -7224,16 +7620,25 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          opaque_typedef = 1;
          type = copy_node (opaque_type_node);
        }
+      /* access declaration */
+      else if (decl_context == FIELD && declarator
+              && TREE_CODE (declarator) == SCOPE_REF)
+       type = void_type_node;
       else
        {
-         if (funcdef_flag && warn_return_type
-             && return_type == return_normal
-             && ! (RIDBIT_SETP (RID_SIGNED, specbits)
-                   || RIDBIT_SETP (RID_UNSIGNED, specbits)
-                   || RIDBIT_SETP (RID_LONG, specbits)
-                   || RIDBIT_SETP (RID_SHORT, specbits)))
-           warn_about_return_type = 1;
-         /* Save warning until we know what is really going on.  */
+         if (funcdef_flag)
+           {
+             if (warn_return_type
+                 && return_type == return_normal)
+               /* Save warning until we know what is really going on.  */
+               warn_about_return_type = 1;
+           }
+         else if (RIDBIT_SETP (RID_TYPEDEF, specbits))
+           pedwarn ("ANSI C++ forbids typedef which does not specify a type");
+         else if (declspecs == NULL_TREE &&
+                  (innermost_code != CALL_EXPR || pedantic))
+           cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type or storage class",
+                       dname);
          type = integer_type_node;
        }
     }
@@ -7247,6 +7652,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
       error ("return type specification for constructor invalid");
       type = TYPE_POINTER_TO (ctor_return_type);
     }
+  else if (return_type == return_conversion)
+    {
+      if (comptypes (type, ctor_return_type, 1) == 0)
+       cp_error ("operator `%T' declared to return `%T'",
+                 ctor_return_type, type);
+      else
+       cp_pedwarn ("return type specified for `operator %T'",
+                   ctor_return_type);
+
+      type = ctor_return_type;
+    }
+  /* Catch typedefs that only specify a type, like 'typedef int;'.  */
+  else if (RIDBIT_SETP (RID_TYPEDEF, specbits) && declarator == NULL_TREE)
+    {
+      /* Template "this is a type" syntax; just ignore for now.  */
+      if (processing_template_defn)
+       return void_type_node;
+    }
 
   ctype = NULL_TREE;
 
@@ -7274,7 +7697,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
       if (TREE_CODE (type) == REAL_TYPE)
        error ("short, signed or unsigned invalid for `%s'", name);
-      else if (TREE_CODE (type) != INTEGER_TYPE || type == wchar_type_node)
+      else if (TREE_CODE (type) != INTEGER_TYPE)
        error ("long, short, signed or unsigned invalid for `%s'", name);
       else if (RIDBIT_SETP (RID_LONG, specbits)
               && RIDBIT_SETP (RID_SHORT, specbits))
@@ -7358,13 +7781,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type);
   staticp = 0;
   inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
+#if 0
+  /* This sort of redundancy is blessed in a footnote to the Sep 94 WP.  */
   if (constp > 1)
     warning ("duplicate `const'");
   if (volatilep > 1)
     warning ("duplicate `volatile'");
+#endif
   virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
+  RIDBIT_RESET (RID_VIRTUAL, specbits);
+  explicitp = RIDBIT_SETP (RID_EXPLICIT, specbits) != 0;
+  RIDBIT_RESET (RID_EXPLICIT, specbits);
 
-  /* operators new and delete are implicitly static.  */
   if (RIDBIT_SETP (RID_STATIC, specbits))
     staticp = 1 + (decl_context == FIELD);
 
@@ -7375,37 +7803,41 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
       staticp = 0;
     }
   friendp = RIDBIT_SETP (RID_FRIEND, specbits);
-  RIDBIT_RESET (RID_VIRTUAL, specbits);
   RIDBIT_RESET (RID_FRIEND, specbits);
 
   if (RIDBIT_SETP (RID_MUTABLE, specbits))
     {
       if (decl_context == PARM)
        {
-         error ("non-member `%s' cannot be declared mutable", name);
+         error ("non-member `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
        }
       else if (friendp || decl_context == TYPENAME)
        {
-         error ("non-object member `%s' cannot be declared mutable", name);
+         error ("non-object member `%s' cannot be declared `mutable'", name);
+         RIDBIT_RESET (RID_MUTABLE, specbits);
+       }
+      else if (constp)
+       {
+         error ("const `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
        }
       else if (staticp)
        {
-         error ("static `%s' cannot be declared mutable", name);
+         error ("static `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
        }
 #if 0
       if (RIDBIT_SETP (RID_TYPEDEF, specbits))
        {
-         error ("non-object member `%s' cannot be declared mutable", name);
+         error ("non-object member `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
        }
       /* Because local typedefs are parsed twice, we don't want this
         message here. */
       else if (decl_context != FIELD)
        {
-         error ("non-member `%s' cannot be declared mutable", name);
+         error ("non-member `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
        }
 #endif
@@ -7430,7 +7862,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
     }
 
   /* Give error if `virtual' is used outside of class declaration.  */
-  if (virtualp && current_class_name == NULL_TREE)
+  if (virtualp
+      && (current_class_name == NULL_TREE || decl_context != FIELD))
     {
       error ("virtual outside class declaration");
       virtualp = 0;
@@ -7462,7 +7895,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
        }
       if (volatilep)
        {
-         error ("`volatile' specified for signature member function `%s'", name);
+         error ("`volatile' specified for signature member function `%s'",
+                name);
          volatilep = 0;
        }
       if (inlinep)
@@ -7478,7 +7912,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
        }
       if (virtualp)
        {
-         error ("`virtual' specified for signature member function `%s'", name);
+         error ("`virtual' specified for signature member function `%s'",
+                name);
          /* Later, we'll make signature member functions virtual.  */
          virtualp = 0;
        }
@@ -7491,7 +7926,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
     error ("multiple storage classes in declaration of `%s'", name);
   else if (decl_context != NORMAL && nclasses > 0)
     {
-      if (decl_context == PARM
+      if ((decl_context == PARM || decl_context == CATCHPARM)
          && (RIDBIT_SETP (RID_REGISTER, specbits)
              || RIDBIT_SETP (RID_AUTO, specbits)))
        ;
@@ -7508,11 +7943,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
            error ("typedef declaration includes an initializer");
   
          /* To process a class-local typedef declaration, we descend down
-            the chain of declspecs looking for the `typedef' spec.  When we
-            find it, we splice it out of the chain of declspecs, and then
-            recursively call `grokdeclarator' with the original declarator
-            and with the newly adjusted declspecs.  This call should return
-            FIELD_DECL node with the TREE_TYPE (and other parts) set
+            the chain of declspecs looking for the `typedef' spec.  When
+            we find it, we replace it with `static', and then recursively
+            call `grokdeclarator' with the original declarator and with
+            the newly adjusted declspecs.  This call should return a
+            FIELD_DECL node with the TREE_TYPE (and other parts) set
             appropriately.  We can then just change the TREE_CODE on that
             from FIELD_DECL to TYPE_DECL and we're done.  */
 
@@ -7523,11 +7958,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
              if (TREE_VALUE (scanner) == ridpointers[(int) RID_TYPEDEF])
                break;
            }
+
          if (previous_declspec)
            TREE_CHAIN (previous_declspec) = TREE_CHAIN (scanner);
          else
            declspecs = TREE_CHAIN (scanner);
-  
+
+         declspecs = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC],
+                                declspecs);
+
          /* In the recursive call to grokdeclarator we need to know
             whether we are working on a signature-local typedef.  */
          if (IS_SIGNATURE (current_class_type))
@@ -7535,6 +7974,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   
          loc_typedecl =
            grokdeclarator (declarator, declspecs, FIELD, 0, NULL_TREE);
+
+         if (previous_declspec)
+           TREE_CHAIN (previous_declspec) = scanner;
   
          if (loc_typedecl != error_mark_node)
            {
@@ -7542,6 +7984,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
              register int *pi;
   
              TREE_SET_CODE (loc_typedecl, TYPE_DECL);
+             /* This is the same field as DECL_ARGUMENTS, which is set for
+                function typedefs by the above grokdeclarator.  */
+             DECL_NESTED_TYPENAME (loc_typedecl) = 0;
   
              pi = (int *) permalloc (sizeof (struct lang_decl_flags));
              while (i > 0)
@@ -7559,7 +8004,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          return loc_typedecl;
        }
       else if (decl_context == FIELD
-              && (! IS_SIGNATURE (current_class_type))
+              && (! IS_SIGNATURE (current_class_type)
+                  || SIGNATURE_GROKKING_TYPEDEF (current_class_type))
               /* C++ allows static class elements  */
               && RIDBIT_SETP (RID_STATIC, specbits))
        /* C++ also allows inlines and signed and unsigned elements,
@@ -7569,18 +8015,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
        {
          if (decl_context == FIELD)
            {
-             tree tmp = TREE_OPERAND (declarator, 0);
-             register int op = IDENTIFIER_OPNAME_P (tmp);
+             tree tmp = NULL_TREE;
+             register int op = 0;
+
+             if (declarator)
+               {
+                 tmp = TREE_OPERAND (declarator, 0);
+                 op = IDENTIFIER_OPNAME_P (tmp);
+               }
              error ("storage class specified for %s `%s'",
                     IS_SIGNATURE (current_class_type)
                     ? (op
                        ? "signature member operator"
                        : "signature member function")
-                    : (op ? "member operator" : "structure field"),
+                    : (op ? "member operator" : "field"),
                     op ? operator_name_string (tmp) : name);
            }
          else
-           error ((decl_context == PARM
+           error (((decl_context == PARM || decl_context == CATCHPARM)
                    ? "storage class specified for parameter `%s'"
                    : "storage class specified for typename"), name);
          RIDBIT_RESET (RID_REGISTER, specbits);
@@ -7598,7 +8050,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
     {
       if (current_binding_level == global_binding_level)
        {
-         /* It's common practice (and completely legal) to have a const
+         /* It's common practice (and completely valid) to have a const
             be initialized and declared extern.  */
          if (! constp)
            warning ("`%s' initialized and declared `extern'", name);
@@ -7650,7 +8102,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
         qualify the member name.
         an ADDR_EXPR (for &...),
         a BIT_NOT_EXPR (for destructors)
-        a TYPE_EXPR (for operator typenames)
 
         At this point, TYPE is the type of elements of an array,
         or for a function to return, or for a pointer to point to.
@@ -7690,6 +8141,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          {
            register tree itype = NULL_TREE;
            register tree size = TREE_OPERAND (declarator, 1);
+           /* The index is a signed object `sizetype' bits wide.  */
+           tree index_type = signed_type (sizetype);
 
            declarator = TREE_OPERAND (declarator, 0);
 
@@ -7709,7 +8162,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
            /* ARM $8.4.3: Since you can't have a pointer to a reference,
               you can't have arrays of references.  If we allowed them,
-              then we'd be saying x[i] is legal for an array x, but
+              then we'd be saying x[i] is valid for an array x, but
               then you'd have to ask: what does `*(x + i)' mean?  */
            if (TREE_CODE (type) == REFERENCE_TYPE)
              {
@@ -7779,22 +8232,31 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                        cp_error ("size of array `%D' is negative", dname);
                        size = integer_one_node;
                      }
-                   itype = build_index_type (size_binop (MINUS_EXPR, size,
-                                                         integer_one_node));
                  }
                else
                  {
                    if (pedantic)
-                     cp_pedwarn ("ANSI C++ forbids variable-size array `%D'", dname);
-                 dont_grok_size:
-                   itype =
-                     build_binary_op (MINUS_EXPR, size, integer_one_node, 1);
+                     {
+                       if (dname)
+                         cp_pedwarn ("ANSI C++ forbids variable-size array `%D'",
+                                     dname);
+                       else
+                         cp_pedwarn ("ANSI C++ forbids variable-size array");
+                     }
                    /* Make sure the array size remains visibly nonconstant
-                      even if it is (eg) a const variable with known value.  */
+                      even if it is (eg) a const variable with known value. */
                    size_varies = 1;
-                   itype = variable_size (itype);
-                   itype = build_index_type (itype);
                  }
+
+             dont_grok_size:
+               itype =
+                 fold (build_binary_op (MINUS_EXPR,
+                                        convert (index_type, size),
+                                        convert (index_type,
+                                                 integer_one_node), 1));
+               if (! TREE_CONSTANT (itype))
+                 itype = variable_size (itype);
+               itype = build_index_type (itype);
                resume_momentary (yes);
              }
 
@@ -7805,8 +8267,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
            type = build_cplus_array_type (type, itype);
            if (constp || volatilep)
-             /* Should this be c_build_type_variant? -jason */
-             type = build_type_variant (type, constp, volatilep);
+             type = cp_build_type_variant (type, constp, volatilep);
 
            ctype = NULL_TREE;
          }
@@ -7815,6 +8276,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
        case CALL_EXPR:
          {
            tree arg_types;
+           int funcdecl_p;
+           tree inner_parms = TREE_OPERAND (declarator, 1);
+           tree inner_decl = TREE_OPERAND (declarator, 0);
 
            /* Declaring a function type.
               Make sure we have a valid type for the function to return.  */
@@ -7823,12 +8287,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
            if (pedantic && (constp || volatilep))
              pedwarn ("function declared to return const or volatile result");
 #else
-           /* Merge any constancy or volatility into the target type
-              for the pointer.  */
+           /* Merge any constancy or volatility into the function return
+               type.  */
 
            if (constp || volatilep)
              {
-               type = build_type_variant (type, constp, volatilep);
+               type = cp_build_type_variant (type, constp, volatilep);
                if (IS_AGGR_TYPE (type))
                  build_pointer_type (type);
                constp = 0;
@@ -7849,12 +8313,25 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                type = integer_type_node;
              }
 
+           if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF)
+             inner_decl = TREE_OPERAND (inner_decl, 1);
+
+           /* Pick up type qualifiers which should be applied to `this'.  */
+           quals = TREE_OPERAND (declarator, 2);
+
+           /* Say it's a definition only for the CALL_EXPR
+              closest to the identifier.  */
+           funcdecl_p =
+             inner_decl && (TREE_CODE (inner_decl) == IDENTIFIER_NODE
+                            || TREE_CODE (inner_decl) == BIT_NOT_EXPR);
+
            if (ctype == NULL_TREE
                && decl_context == FIELD
+               && funcdecl_p
                && (friendp == 0 || dname == current_class_name))
              ctype = current_class_type;
 
-           if (ctype && flags == TYPENAME_FLAG)
+           if (ctype && return_type == return_conversion)
              TYPE_HAS_CONVERSION (ctype) = 1;
            if (ctype && constructor_name (ctype) == dname)
              {
@@ -7870,14 +8347,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                       may not be static.  */
                    if (staticp == 2)
                      error ("destructor cannot be static member function");
-                   if (TYPE_READONLY (type))
-                     {
-                       error ("destructors cannot be declared `const'");
-                       return void_type_node;
-                     }
-                   if (TYPE_VOLATILE (type))
+                   if (quals)
                      {
-                       error ("destructors cannot be declared `volatile'");
+                       error ("destructors cannot be declared `const' or `volatile'");
                        return void_type_node;
                      }
                    if (decl_context == FIELD)
@@ -7889,6 +8361,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                  }
                else            /* it's a constructor. */
                  {
+                   if (explicitp == 1)
+                     explicitp = 2;
                    /* ANSI C++ June 5 1992 WP 12.1.2.  A constructor may
                       not be declared const or volatile.  A constructor may
                       not be virtual.  A constructor may not be static.  */
@@ -7899,28 +8373,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                        pedwarn ("constructors cannot be declared virtual");
                        virtualp = 0;
                      }
-                   if (TYPE_READONLY (type))
+                   if (quals)
                      {
-                       error ("constructors cannot be declared `const'");
+                       error ("constructors cannot be declared `const' or `volatile'");
                        return void_type_node;
                      }
-                   if (TYPE_VOLATILE (type))
-                     {
-                       error ("constructors cannot be declared `volatile'");
-                       return void_type_node;
-                     }
                    {
-                     int inlinep, staticp;
-                     inlinep = RIDBIT_SETP (RID_INLINE, specbits);
-                     staticp = RIDBIT_SETP (RID_STATIC, specbits);
-                     RIDBIT_RESET (RID_INLINE, specbits);
-                     RIDBIT_RESET (RID_STATIC, specbits);
-                     if (RIDBIT_ANY_SET (specbits))
+                     RID_BIT_TYPE tmp_bits;
+                     bcopy ((void*)&specbits, (void*)&tmp_bits, sizeof(RID_BIT_TYPE));
+                     RIDBIT_RESET (RID_INLINE, tmp_bits);
+                     RIDBIT_RESET (RID_STATIC, tmp_bits);
+                     if (RIDBIT_ANY_SET (tmp_bits))
                        error ("return value type specifier for constructor ignored");
-                     if (inlinep)
-                       RIDBIT_SET (RID_INLINE, specbits);
-                     if (staticp)
-                       RIDBIT_SET (RID_STATIC, specbits);
                    }
                    type = TYPE_POINTER_TO (ctype);
                    if (decl_context == FIELD &&
@@ -7942,20 +8406,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                if (decl_context == FIELD)
                  staticp = 0;
              }
-           else if (friendp && virtualp)
+           else if (friendp)
              {
-               /* Cannot be both friend and virtual.  */
-               error ("virtual functions cannot be friends");
-               RIDBIT_RESET (RID_FRIEND, specbits);
-               friendp = 0;
+               if (initialized)
+                 error ("can't initialize friend function `%s'", name);
+               if (virtualp)
+                 {
+                   /* Cannot be both friend and virtual.  */
+                   error ("virtual functions cannot be friends");
+                   RIDBIT_RESET (RID_FRIEND, specbits);
+                   friendp = 0;
+                 }
+               if (decl_context == NORMAL)
+                 error ("friend declaration not in class definition");
+               if (current_function_decl && funcdef_flag)
+                 cp_error ("can't define friend function `%s' in a local class definition",
+                           name);
              }
 
-           if (decl_context == NORMAL && friendp)
-             error ("friend declaration not in class definition");
-
-           /* Pick up type qualifiers which should be applied to `this'.  */
-           quals = TREE_OPERAND (declarator, 2);
-
            /* Traditionally, declaring return type float means double.  */
 
            if (flag_traditional
@@ -7969,28 +8437,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
            /* Construct the function type and go to the next
               inner layer of declarator.  */
 
-           {
-             int funcdef_p;
-             tree inner_parms = TREE_OPERAND (declarator, 1);
-             tree inner_decl = TREE_OPERAND (declarator, 0);
-
-             declarator = TREE_OPERAND (declarator, 0);
-
-             if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF)
-               inner_decl = TREE_OPERAND (inner_decl, 1);
-
-             /* Say it's a definition only for the CALL_EXPR
-                closest to the identifier.  */
-             funcdef_p =
-               (inner_decl &&
-                (TREE_CODE (inner_decl) == IDENTIFIER_NODE
-                 || TREE_CODE (inner_decl) == TYPE_EXPR)) ? funcdef_flag : 0;
+           declarator = TREE_OPERAND (declarator, 0);
 
-             /* FIXME: This is where default args should be fully
-                processed.  */
+           /* FIXME: This is where default args should be fully
+              processed.  */
 
-             arg_types = grokparms (inner_parms, funcdef_p);
-           }
+           arg_types = grokparms (inner_parms, funcdecl_p ? funcdef_flag : 0);
 
            if (declarator)
              {
@@ -8034,6 +8486,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
              continue;
            }
 
+         if (TREE_CODE (type) == OFFSET_TYPE
+             && (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE
+                 || TREE_CODE (TREE_TYPE (type)) == REFERENCE_TYPE))
+           {
+             cp_error ("cannot declare pointer to `%#T' member",
+                       TREE_TYPE (type));
+             type = TREE_TYPE (type);
+           }
+
          /* Merge any constancy or volatility into the target type
             for the pointer.  */
 
@@ -8045,7 +8506,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                 signature pointer/reference itself.  */
              if (! IS_SIGNATURE (type))
                {
-                 type = build_type_variant (type, constp, volatilep);
+                 type = cp_build_type_variant (type, constp, volatilep);
                  if (IS_AGGR_TYPE (type))
                    build_pointer_type (type);
                  constp = 0;
@@ -8057,9 +8518,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
            {
              if (TREE_CODE (declarator) == ADDR_EXPR)
                {
-                 if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE)
-                   warning ("empty signature `%s' used in signature reference declaration",
-                            TYPE_NAME_STRING(type));
+                 if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE
+                     && TYPE_SIZE (type))
+                   cp_warning ("empty signature `%T' used in signature reference declaration",
+                               type);
 #if 0
                  type = build_signature_reference_type (type,
                                                         constp, volatilep);
@@ -8070,9 +8532,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                }
              else
                {
-                 if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE)
-                   warning ("empty signature `%s' used in signature pointer declaration",
-                            TYPE_NAME_STRING(type));
+                 if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE
+                     && TYPE_SIZE (type))
+                   cp_warning ("empty signature `%T' used in signature pointer declaration",
+                               type);
                  type = build_signature_pointer_type (type,
                                                       constp, volatilep);
                }
@@ -8124,9 +8587,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                    }
                }
              if (constp > 1)
-               warning ("duplicate `const'");
+               pedwarn ("duplicate `const'");
              if (volatilep > 1)
-               warning ("duplicate `volatile'");
+               pedwarn ("duplicate `volatile'");
+             if (TREE_CODE (declarator) == ADDR_EXPR
+                 && (constp || volatilep))
+               {
+                 if (constp)
+                   pedwarn ("discarding `const' applied to a reference");
+                 if (volatilep)
+                   pedwarn ("discarding `volatile' applied to a reference");
+                 constp = volatilep = 0;
+               }
            }
          declarator = TREE_OPERAND (declarator, 0);
          ctype = NULL_TREE;
@@ -8152,11 +8624,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
              /* don't fall out into global scope. Hides real bug? --eichin */ ;
            else if (TREE_COMPLEXITY (declarator) == current_class_depth)
              {
-               /* I'm not really sure what pushclass calls this popclass
-                  corresponds to.  One is in build_push_scope and that has
-                  been changed to a push_nested_class call, that's why I
-                  try to use pop_nested_class here instead.
-                  -niklas@appli.se */
+               /* This pop_nested_class corresponds to the
+                   push_nested_class used to push into class scope for
+                   parsing the argument list of a function decl, in
+                   qualified_id.  */
                pop_nested_class (1);
                TREE_COMPLEXITY (declarator) = current_class_depth;
              }
@@ -8182,33 +8653,39 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                /* This is the `standard' use of the scoping operator:
                   basetype :: member .  */
 
-               if (TREE_CODE (type) == FUNCTION_TYPE)
+               if (ctype == current_class_type)
+                 {
+                   /* class A {
+                        void A::f ();
+                      };
+
+                      Is this ill-formed?  */
+
+                   if (pedantic)
+                     cp_pedwarn ("extra qualification `%T::' on member `%s' ignored",
+                                 ctype, name);
+                 }
+               else if (TREE_CODE (type) == FUNCTION_TYPE)
                  {
                    if (current_class_type == NULL_TREE
-                       || TYPE_MAIN_VARIANT (ctype) == current_class_type
                        || friendp)
                      type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
                                                      TREE_TYPE (type), TYPE_ARG_TYPES (type));
                    else
                      {
-                       error ("cannot declare member function `%s::%s' within this class",
-                              TYPE_NAME_STRING (ctype), name);
+                       cp_error ("cannot declare member function `%T::%s' within `%T'",
+                                 ctype, name, current_class_type);
                        return void_type_node;
                      }
                  }
-               else if (TYPE_MAIN_VARIANT (ctype) == current_class_type)
-                 {
-                   if (extra_warnings)
-                     warning ("extra qualification `%s' on member `%s' ignored",
-                              TYPE_NAME_STRING (ctype), name);
-                   type = build_offset_type (ctype, type);
-                 }
                else if (TYPE_SIZE (ctype) != NULL_TREE
                         || (RIDBIT_SETP (RID_TYPEDEF, specbits)))
                  {
                    tree t;
                    /* have to move this code elsewhere in this function.
-                      this code is used for i.e., typedef int A::M; M *pm; */
+                      this code is used for i.e., typedef int A::M; M *pm;
+
+                      It is?  How? jason 10/2/94 */
 
                    if (explicit_int == -1 && decl_context == FIELD
                        && funcdef_flag == 0)
@@ -8234,7 +8711,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                                /* Don't include destructor with constructors.  */
                                t = DECL_CHAIN (TREE_VALUE (t));
                                if (t == NULL_TREE)
-                                 error ("class `%s' does not have any constructors", IDENTIFIER_POINTER (sname));
+                                 cp_error ("`%T' does not have any constructors",
+                                           ctype);
                                t = build_tree_list (NULL_TREE, t);
                              }
                            t = build_lang_field_decl (FIELD_DECL, build_nt (SCOPE_REF, ctype, t), type);
@@ -8242,25 +8720,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                            return t;
                          }
 
-                       if (flags == TYPENAME_FLAG)
-                         cp_error ("type conversion is not a member of structure `%T'", ctype);
-                       else
-                         cp_error
-                           ("field `%D' is not a member of structure `%T'",
-                            sname, ctype);
+                       cp_error
+                         ("field `%D' is not a member of structure `%T'",
+                          sname, ctype);
                      }
 
                    if (current_class_type)
                      {
-                       if (TYPE_MAIN_VARIANT (ctype) != current_class_type)
-                         {
-                           cp_error ("cannot declare member `%T::%s' within `%T'",
-                                  ctype, name, current_class_type);
-                           return void_type_node;
-                         }
-                       else if (extra_warnings)
-                         cp_warning ("extra qualification `%T' on member `%s' ignored",
-                                  ctype, name);
+                       cp_error ("cannot declare member `%T::%s' within `%T'",
+                                 ctype, name, current_class_type);
+                       return void_type_node;
                      }
                    type = build_offset_type (ctype, type);
                  }
@@ -8283,28 +8752,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
                declarator = sname;
              }
-           else if (TREE_CODE (sname) == TYPE_EXPR)
-             {
-               /* A TYPE_EXPR will change types out from under us.
-                  So do the TYPE_EXPR now, and make this SCOPE_REF
-                  inner to the TYPE_EXPR's CALL_EXPR.
-
-                  This does not work if we don't get a CALL_EXPR back.
-                  I did not think about error recovery, hence the
-                  my_friendly_abort.  */
-
-               /* Get the CALL_EXPR.  */
-               sname = grokoptypename (sname, 0);
-               my_friendly_assert (TREE_CODE (sname) == CALL_EXPR, 157);
-               type = TREE_TYPE (TREE_OPERAND (sname, 0));
-               /* Scope the CALL_EXPR's name.  */
-               TREE_OPERAND (declarator, 1) = TREE_OPERAND (sname, 0);
-               /* Put the SCOPE_EXPR in the CALL_EXPR's innermost position.  */
-               TREE_OPERAND (sname, 0) = declarator;
-               /* Now work from the CALL_EXPR.  */
-               declarator = sname;
-               continue;
-             }
            else if (TREE_CODE (sname) == SCOPE_REF)
              my_friendly_abort (17);
            else
@@ -8329,21 +8776,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          declarator = TREE_OPERAND (declarator, 0);
          break;
 
-       case TYPE_EXPR:
-         declarator = grokoptypename (declarator, 0);
-         if (explicit_int != -1)
-           {
-             tree stype = TREE_TYPE (TREE_OPERAND (declarator, 0));
-             if (comp_target_types (type, stype, 1) == 0)
-               cp_error ("`operator %T' declared to return `%T'", stype,
-                         type);
-             else
-               cp_pedwarn ("return type specified for `operator %T'", type);
-           }
-         dname = declarator;
-         type = TREE_TYPE (TREE_OPERAND (declarator, 0));
-         break;
-
        case RECORD_TYPE:
        case UNION_TYPE:
        case ENUMERAL_TYPE:
@@ -8359,6 +8791,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
        }
     }
 
+  if (explicitp == 1)
+    {
+      error ("only constructors can be declared `explicit'");
+      explicitp = 0;
+    }
+
   /* Now TYPE has the actual type.  */
 
   /* If this is declaring a typedef name, return a TYPE_DECL.  */
@@ -8370,7 +8808,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
       /* Note that the grammar rejects storage classes
         in typenames, fields or parameters.  */
       if (constp || volatilep)
-       type = build_type_variant (type, constp, volatilep);
+       type = cp_build_type_variant (type, constp, volatilep);
 
       /* If the user declares "struct {...} foo" then `foo' will have
         an anonymous name.  Fill that name in now.  Nothing can
@@ -8398,6 +8836,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                                   declarator, type);
            else
              set_nested_typename (d, TYPE_NESTED_NAME (c), declarator, type);
+
+           DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
+           DECL_ASSEMBLER_NAME (d)
+             = get_identifier (build_overload_name (type, 1, 1));
          }
        }
 
@@ -8409,7 +8851,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
       if (TREE_CODE (type) == OFFSET_TYPE || TREE_CODE (type) == METHOD_TYPE)
        {
          cp_error_at ("typedef name may not be class-qualified", decl);
-         TREE_TYPE (decl) = error_mark_node;
+         return NULL_TREE;
        }
       else if (quals)
        {
@@ -8459,18 +8901,33 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
        if (IS_SIGNATURE (type))
          error ("`const' or `volatile' specified with signature type");
        else  
-         type = build_type_variant (type, constp, volatilep);
+         type = cp_build_type_variant (type, constp, volatilep);
 
       /* Special case: "friend class foo" looks like a TYPENAME context.  */
       if (friendp)
        {
-         /* A friendly class?  */
-         if (current_class_type)
-           make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type));
-         else
-           error("trying to make class `%s' a friend of global scope",
-                 TYPE_NAME_STRING (type));
-         type = void_type_node;
+         if (volatilep)
+           {
+             cp_error ("`volatile' specified for friend class declaration");
+             volatilep = 0;
+           }
+         if (inlinep)
+           {
+             cp_error ("`inline' specified for friend class declaration");
+             inlinep = 0;
+           }
+
+         /* Only try to do this stuff if we didn't already give up.  */
+         if (type != integer_type_node)
+           {
+             /* A friendly class?  */
+             if (current_class_type)
+               make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type));
+             else
+               error ("trying to make class `%s' a friend of global scope",
+                      TYPE_NAME_STRING (type));
+             type = void_type_node;
+           }
        }
       else if (quals)
        {
@@ -8491,6 +8948,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
       return type;
     }
   else if (declarator == NULL_TREE && decl_context != PARM
+          && decl_context != CATCHPARM
           && TREE_CODE (type) != UNION_TYPE
           && ! bitfield)
     {
@@ -8505,7 +8963,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
   if (TYPE_MAIN_VARIANT (type) == void_type_node && decl_context != PARM)
     {
-      if (TREE_CODE (declarator) == IDENTIFIER_NODE)
+      if (! declarator)
+       error ("unnamed variable or field declared void");
+      else if (TREE_CODE (declarator) == IDENTIFIER_NODE)
        {
          if (IDENTIFIER_OPNAME_P (declarator))
 #if 0                          /* How could this happen? */
@@ -8530,43 +8990,28 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
     if (decl_context == PARM)
       {
-       tree parmtype = type;
-
        if (ctype)
          error ("cannot use `::' in parameter declaration");
 
        /* A parameter declared as an array of T is really a pointer to T.
           One declared as a function is really a pointer to a function.
-          One declared as a member is really a pointer to member.
-
-          Don't be misled by references.  */
-
-       if (TREE_CODE (type) == REFERENCE_TYPE)
-         type = TREE_TYPE (type);
+          One declared as a member is really a pointer to member.  */
 
        if (TREE_CODE (type) == ARRAY_TYPE)
          {
-           if (parmtype == type)
-             {
-               /* Transfer const-ness of array into that of type
-                  pointed to.  */
-               type = build_pointer_type
-                 (build_type_variant (TREE_TYPE (type), constp, volatilep));
-               volatilep = constp = 0;
-             }
-           else
-             type = build_pointer_type (TREE_TYPE (type));
+           /* Transfer const-ness of array into that of type pointed to. */
+           type = build_pointer_type
+             (cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
+           volatilep = constp = 0;
          }
        else if (TREE_CODE (type) == FUNCTION_TYPE)
          type = build_pointer_type (type);
        else if (TREE_CODE (type) == OFFSET_TYPE)
          type = build_pointer_type (type);
-
-       if (TREE_CODE (parmtype) == REFERENCE_TYPE)
+       else if (type == void_type_node && declarator)
          {
-           /* Transfer const-ness of reference into that of type pointed to.  */
-           type = build_type_variant (build_reference_type (type), constp, volatilep);
-           constp = volatilep = 0;
+           error ("declaration of `%s' as void", name);
+           return NULL_TREE;
          }
 
        decl = build_decl (PARM_DECL, declarator, type);
@@ -8589,28 +9034,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
           (For example, shorts and chars are passed as ints.)
           When there is a prototype, this is overridden later.  */
 
-       DECL_ARG_TYPE (decl) = type;
-       if (TYPE_MAIN_VARIANT (type) == float_type_node)
-         DECL_ARG_TYPE (decl) = build_type_variant (double_type_node,
-                                                    TYPE_READONLY (type),
-                                                    TYPE_VOLATILE (type));
-       else if (C_PROMOTING_INTEGER_TYPE_P (type))
-         {
-           tree argtype;
-
-           /* Retain unsignedness if traditional or if not really
-              getting wider.  */
-           if (TREE_UNSIGNED (type)
-               && (flag_traditional
-                   || TYPE_PRECISION (type)
-                       == TYPE_PRECISION (integer_type_node)))
-             argtype = unsigned_type_node;
-           else
-             argtype = integer_type_node;
-           DECL_ARG_TYPE (decl) = build_type_variant (argtype,
-                                                      TYPE_READONLY (type),
-                                                      TYPE_VOLATILE (type));
-         }
+       DECL_ARG_TYPE (decl) = type_promotes_to (type);
       }
     else if (decl_context == FIELD)
       {
@@ -8646,7 +9070,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                  }
 
                if (declarator == ansi_opname[(int) NEW_EXPR]
-                   || declarator == ansi_opname[(int) DELETE_EXPR])
+                   || declarator == ansi_opname[(int) VEC_NEW_EXPR]
+                   || declarator == ansi_opname[(int) DELETE_EXPR]
+                   || declarator == ansi_opname[(int) VEC_DELETE_EXPR])
                  {
                    if (virtualp)
                      {
@@ -8661,42 +9087,38 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
              }
 
            /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node.  */
-           publicp = (RIDBIT_SETP (RID_EXTERN, specbits)
-                      || (ctype != NULL_TREE && funcdef_flag >= 0)
-                      || (friendp
-                          && ! funcdef_flag
-                          && RIDBIT_NOTSETP (RID_STATIC, specbits)
-                          && RIDBIT_NOTSETP (RID_INLINE, specbits)));
+           publicp = (! friendp
+                      || RIDBIT_SETP (RID_EXTERN, specbits)
+                      || ! (funcdef_flag < 0 || inlinep));
            decl = grokfndecl (ctype, type, declarator,
                               virtualp, flags, quals,
-                              raises, friendp ? -1 : 0, publicp);
-           DECL_INLINE (decl) = inlinep;
+                              raises, friendp ? -1 : 0, publicp, inlinep);
+           if (decl == NULL_TREE)
+             return NULL_TREE;
+           decl = build_decl_attribute_variant (decl, decl_machine_attr);
+
+           if (explicitp == 2)
+             DECL_NONCONVERTING_P (decl) = 1;
          }
        else if (TREE_CODE (type) == METHOD_TYPE)
          {
+           /* We only get here for friend declarations of
+              members of other classes.  */
            /* All method decls are public, so tell grokfndecl to set
               TREE_PUBLIC, also.  */
            decl = grokfndecl (ctype, type, declarator,
                               virtualp, flags, quals,
-                              raises, friendp ? -1 : 0, 1);
-           DECL_INLINE (decl) = inlinep;
-         }
-       else if (TREE_CODE (type) == RECORD_TYPE
-                && CLASSTYPE_DECLARED_EXCEPTION (type))
-         {
-           /* Handle a class-local exception declaration.  */
-           decl = build_lang_field_decl (VAR_DECL, declarator, type);
-           if (ctype == NULL_TREE)
-             ctype = current_class_type;
-           finish_exception_decl (TREE_CODE (TYPE_NAME (ctype)) == TYPE_DECL
-                                  ? TYPE_IDENTIFIER (ctype) : TYPE_NAME (ctype), decl);
-           return void_type_node;
+                              raises, friendp ? -1 : 0, 1, 0);
+           if (decl == NULL_TREE)
+             return NULL_TREE;
          }
        else if (TYPE_SIZE (type) == NULL_TREE && !staticp
                 && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0))
          {
-           error ("field `%s' has incomplete type",
-                  IDENTIFIER_POINTER (declarator));
+           if (declarator)
+             cp_error ("field `%D' has incomplete type", declarator);
+           else
+             cp_error ("name `%T' has incomplete type", type);
 
            /* If we're instantiating a template, tell them which
               instantiation made the field's type be incomplete.  */
@@ -8705,9 +9127,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                && IDENTIFIER_TEMPLATE (DECL_NAME (TYPE_NAME (current_class_type)))
                && declspecs && TREE_VALUE (declspecs)
                && TREE_TYPE (TREE_VALUE (declspecs)) == type)
-             error ("  in instantiation of template `%s'",
-                    TYPE_NAME_STRING (current_class_type));
-               
+             cp_error ("  in instantiation of template `%T'",
+                       current_class_type);
+
            type = error_mark_node;
            decl = NULL_TREE;
          }
@@ -8744,24 +9166,37 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
        if (decl == NULL_TREE)
          {
-           /* ANSI C++ June 5 1992 WP 9.2.2 and 9.4.2.  A member-declarator
-              cannot have an initializer, and a static member declaration must
-              be defined elsewhere.  */
            if (initialized)
              {
+               /* Motion 10 at San Diego: If a static const integral data
+                  member is initialized with an integral constant
+                  expression, the initializer may appear either in the
+                  declaration (within the class), or in the definition,
+                  but not both.  If it appears in the class, the member is
+                  a member constant.  The file-scope definition is always
+                  required.  */
                if (staticp)
-                 error ("static member `%s' must be defined separately from its declaration",
-                         IDENTIFIER_POINTER (declarator));
+                 {
+                   if (pedantic)
+                     {
+                       if (! constp)
+                         cp_pedwarn ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
+                                     declarator);
+
+                       else if (! INTEGRAL_TYPE_P (type))
+                         cp_pedwarn ("ANSI C++ forbids member constant `%D' of non-integral type `%T'", declarator, type);
+                     }
+                 }
+
                /* Note that initialization of const members is prohibited
                   by the draft ANSI standard, though it appears to be in
                   common practice.  12.6.2: The argument list is used to
                   initialize the named nonstatic member....  This (or an
-                  aggregate) is the only way to initialize nonstatic const
-                  and reference members.  */
-               else
-                 pedwarn ("ANSI C++ forbids initialization of %s `%s'",
-                          constp ? "const member" : "member",
-                          IDENTIFIER_POINTER (declarator));
+                  initializer list) is the only way to initialize
+                  nonstatic const and reference members.  */
+               else if (pedantic || ! constp)
+                 cp_pedwarn ("ANSI C++ forbids initialization of %s `%D'",
+                             constp ? "const member" : "member", declarator);
              }
 
            if (staticp || (constp && initialized))
@@ -8771,11 +9206,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                   This VAR_DECL is built by build_lang_field_decl.
                   All other VAR_DECLs are built by build_decl.  */
                decl = build_lang_field_decl (VAR_DECL, declarator, type);
-               if (staticp || TREE_CODE (type) == ARRAY_TYPE)
-                 TREE_STATIC (decl) = 1;
-               /* In class context, static means public access.  */
-               TREE_PUBLIC (decl) = 1;
-               DECL_EXTERNAL (decl) = !initialized;
+               TREE_STATIC (decl) = 1;
+               /* In class context, 'static' means public access.  */
+               TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = !!staticp;
              }
            else
              {
@@ -8793,25 +9226,32 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
       }
     else if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
       {
-       int was_overloaded = 0;
        tree original_name = declarator;
        int publicp = 0;
 
        if (! declarator)
          return NULL_TREE;
 
-       if (RIDBIT_SETP (RID_AUTO, specbits)
-           || RIDBIT_SETP (RID_REGISTER, specbits))
-         error ("invalid storage class for function `%s'", name);
+       if (RIDBIT_SETP (RID_AUTO, specbits))
+         error ("storage class `auto' invalid for function `%s'", name);
+       else if (RIDBIT_SETP (RID_REGISTER, specbits))
+         error ("storage class `register' invalid for function `%s'", name);
 
        /* Function declaration not at top level.
           Storage classes other than `extern' are not allowed
           and `extern' makes no difference.  */
        if (current_binding_level != global_binding_level
-           && (RIDBIT_SETP (RID_STATIC, specbits) || RIDBIT_SETP (RID_INLINE, specbits))
+           && ! processing_template_decl
+           && (RIDBIT_SETP (RID_STATIC, specbits)
+               || RIDBIT_SETP (RID_INLINE, specbits))
            && pedantic)
-         pedwarn ("invalid storage class for function `%s'", name);
-
+         {
+           if (RIDBIT_SETP (RID_STATIC, specbits))
+             pedwarn ("storage class `static' invalid for function `%s' declared out of global scope", name);
+           else
+             pedwarn ("storage class `inline' invalid for function `%s' declared out of global scope", name);
+         }
+       
        if (ctype == NULL_TREE)
          {
            if (virtualp)
@@ -8828,34 +9268,28 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                      && IDENTIFIER_POINTER (original_name)[0] == '_'
                      && IDENTIFIER_POINTER (original_name)[1] == '_'
                      && strncmp (IDENTIFIER_POINTER (original_name)+2, "builtin_", 8) == 0))
-             {
-               /* Plain overloading: will not be grok'd by grokclassfn.  */
-               declarator = build_decl_overload (dname, TYPE_ARG_TYPES (type), 0);
-               was_overloaded = 1;
-             }
+             /* Plain overloading: will not be grok'd by grokclassfn.  */
+             declarator = build_decl_overload (dname, TYPE_ARG_TYPES (type), 0);
          }
        else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2)
          type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
                                          TREE_TYPE (type), TYPE_ARG_TYPES (type));
 
-       /* Record presence of `static'.  In C++, `inline' is like `static'.
-          Methods of classes should be public, unless we're dropping them
-          into some other file, so we don't clear TREE_PUBLIC for them.  */
-       publicp
-         = ((ctype
-             && CLASSTYPE_INTERFACE_KNOWN (ctype)
-             && ! CLASSTYPE_INTERFACE_ONLY (ctype))
-            || !(RIDBIT_SETP (RID_STATIC, specbits)
-                 || RIDBIT_SETP (RID_INLINE, specbits)));
+       /* Record presence of `static'.  In C++, `inline' implies `static'.  */
+       publicp = (ctype != NULL_TREE
+                  || (!RIDBIT_SETP (RID_STATIC, specbits)
+                      && !RIDBIT_SETP (RID_INLINE, specbits)));
 
        decl = grokfndecl (ctype, type, original_name,
                           virtualp, flags, quals,
                           raises,
                           processing_template_decl ? 0 : friendp ? 2 : 1,
-                          publicp);
+                          publicp, inlinep);
+       if (decl == NULL_TREE)
+         return NULL_TREE;
 
        if (ctype == NULL_TREE && DECL_LANGUAGE (decl) != lang_c)
-         DECL_ASSEMBLER_NAME (decl) = declarator;
+         DECL_ASSEMBLER_NAME (decl) = current_namespace_id (declarator);
 
        if (staticp == 1)
          {
@@ -8865,16 +9299,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
               declaring main to be static.  */
            if (TREE_CODE (type) == METHOD_TYPE)
              {
-               cp_error_at ("cannot declare member function `%D' to have static linkage", decl);
-               illegal_static = 1;
-             }
-           else if (! was_overloaded
-                    && ! ctype
-                    && IDENTIFIER_LENGTH (original_name) == 4
-                    && IDENTIFIER_POINTER (original_name)[0] == 'm'
-                    && ! strcmp (IDENTIFIER_POINTER (original_name), "main"))
-             {
-               error ("cannot declare function `main' to have static linkage");
+               cp_pedwarn ("cannot declare member function `%D' to have static linkage", decl);
                illegal_static = 1;
              }
            else if (current_function_decl)
@@ -8890,35 +9315,35 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                RIDBIT_RESET (RID_STATIC, specbits);
              }
          }
+      }
+    else
+      {
+       /* It's a variable.  */
 
-       /* Record presence of `inline', if it is reasonable.  */
-       if (inlinep)
+       if (decl_context == CATCHPARM)
          {
-           tree last = tree_last (TYPE_ARG_TYPES (type));
-
-           if (! was_overloaded
-               && ! ctype
-               && ! strcmp (IDENTIFIER_POINTER (original_name), "main"))
-             error ("cannot inline function `main'");
-           else if (last && last != void_list_node)
-             cp_warning ("cannot inline function `%D' which takes `...'", original_name);
-           else
-             /* Assume that otherwise the function can be inlined.  */
-             DECL_INLINE (decl) = 1;
+           if (ctype)
+             {
+               ctype = NULL_TREE;
+               error ("cannot use `::' in parameter declaration");
+             }
 
-           if (RIDBIT_SETP (RID_EXTERN, specbits))
+           /* A parameter declared as an array of T is really a pointer to T.
+              One declared as a function is really a pointer to a function.
+              One declared as a member is really a pointer to member.  */
+
+           if (TREE_CODE (type) == ARRAY_TYPE)
              {
-               current_extern_inline = 1;
-               if (flag_ansi || pedantic || flag_pedantic_errors)
-                 pedwarn ("ANSI C++ does not permit `extern inline'");
+               /* Transfer const-ness of array into that of type pointed to. */
+               type = build_pointer_type
+                 (cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
+               volatilep = constp = 0;
              }
+           else if (TREE_CODE (type) == FUNCTION_TYPE)
+             type = build_pointer_type (type);
+           else if (TREE_CODE (type) == OFFSET_TYPE)
+             type = build_pointer_type (type);
          }
-       if (was_overloaded)
-         DECL_OVERLOADED (decl) = 1;
-      }
-    else
-      {
-       /* It's a variable.  */
 
        /* An uninitialized decl with `extern' is a reference.  */
        decl = grokvardecl (type, declarator, specbits, initialized);
@@ -8927,6 +9352,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
        if (ctype)
          {
+           DECL_CONTEXT (decl) = ctype;
            if (staticp == 1)
              {
                cp_error ("static member `%D' re-declared as static",
@@ -8934,6 +9360,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                staticp = 0;
                RIDBIT_RESET (RID_STATIC, specbits);
              }
+           if (RIDBIT_SETP (RID_REGISTER, specbits) && TREE_STATIC (decl))
+             {
+               cp_error ("static member `%D' declared `register'", decl);
+               RIDBIT_RESET (RID_REGISTER, specbits);
+             }
            if (RIDBIT_SETP (RID_EXTERN, specbits))
              {
                cp_error ("cannot explicitly declare member `%#D' to have extern linkage",
@@ -8954,6 +9385,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
     if (RIDBIT_SETP (RID_REGISTER, specbits))
       DECL_REGISTER (decl) = 1;
 
+    if (RIDBIT_SETP (RID_EXTERN, specbits))
+      DECL_THIS_EXTERN (decl) = 1;
+
+    if (RIDBIT_SETP (RID_STATIC, specbits))
+      DECL_THIS_STATIC (decl) = 1;
+
     /* Record constancy and volatility.  */
 
     if (constp)
@@ -9212,7 +9649,8 @@ grokparms (first_parm, funcdef_flag)
                      any_init++;
                      if (TREE_CODE (init) == SAVE_EXPR)
                        PARM_DECL_EXPR (init) = 1;
-                     else if (TREE_CODE (init) == VAR_DECL)
+                     else if (TREE_CODE (init) == VAR_DECL
+                              || TREE_CODE (init) == PARM_DECL)
                        {
                          if (IDENTIFIER_LOCAL_VALUE (DECL_NAME (init)))
                            {
@@ -9229,12 +9667,15 @@ grokparms (first_parm, funcdef_flag)
                        }
                      else
                        init = require_instantiated_type (type, init, integer_zero_node);
-                   }
+           }
+#if 0 /* This is too early to check; trailing parms might be merged in by
+        duplicate_decls.  */
                  else if (any_init)
                    {
                      error ("all trailing parameters must have default arguments");
                      any_error = 1;
                    }
+#endif
                }
              else
                init = NULL_TREE;
@@ -9293,7 +9734,7 @@ grokparms (first_parm, funcdef_flag)
    `grok_op_properties' takes notice of the various forms of
    operator= which are defined, as well as what sorts of type conversion
    may apply.  Both functions take a FUNCTION_DECL as an argument.  */
-void
+int
 grok_ctor_properties (ctype, decl)
      tree ctype, decl;
 {
@@ -9330,18 +9771,26 @@ grok_ctor_properties (ctype, decl)
     {
       if (TREE_CHAIN (parmtypes) != NULL_TREE
          && TREE_CHAIN (parmtypes) == void_list_node)
-       cp_error ("invalid constructor; you probably meant `%T (%T&)'",
-                 ctype, ctype);
-      SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
-      TYPE_GETS_INIT_AGGR (ctype) = 1;
+       {
+         cp_error ("invalid constructor; you probably meant `%T (%T&)'",
+                   ctype, ctype);
+         SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
+
+         return 0;
+       }
+      else
+       TYPE_GETS_INIT_AGGR (ctype) = 1;
     }
   else if (TREE_CODE (parmtype) == VOID_TYPE
           || TREE_PURPOSE (parmtypes) != NULL_TREE)
     TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1;
+
+  return 1;
 }
 
 /* An operator with this name can be either unary or binary.  */
-int ambi_op_p (name)
+static int
+ambi_op_p (name)
      tree name;
 {
   return (name == ansi_opname [(int) INDIRECT_REF]
@@ -9353,7 +9802,8 @@ int ambi_op_p (name)
 }
 
 /* An operator with this name can only be unary.  */
-int unary_op_p (name)
+static int
+unary_op_p (name)
      tree name;
 {
   return (name == ansi_opname [(int) TRUTH_NOT_EXPR]
@@ -9371,44 +9821,38 @@ grok_op_properties (decl, virtualp, friendp)
   tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
   int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
   tree name = DECL_NAME (decl);
-  tree t;
 
-  if (! friendp)
-    for (t = current_class_type; t; t = TYPE_NEXT_VARIANT (t))
-      {
-       if (name == ansi_opname[(int) MODIFY_EXPR])
-         TYPE_HAS_ASSIGNMENT (t) = 1;
-       else if (name == ansi_opname[(int) CALL_EXPR])
-         TYPE_OVERLOADS_CALL_EXPR (t) = 1;
-       else if (name == ansi_opname[(int) ARRAY_REF])
-         TYPE_OVERLOADS_ARRAY_REF (t) = 1;
-       else if (name == ansi_opname[(int) COMPONENT_REF]
-                || name == ansi_opname[(int) MEMBER_REF])
-         TYPE_OVERLOADS_ARROW (t) = 1;
-       else if (name == ansi_opname[(int) NEW_EXPR])
-         {
-           if (TREE_CHAIN (argtypes) == void_list_node)
-             TREE_GETS_NEW (t) = 1;
-           else
-             TREE_GETS_PLACED_NEW (t) = 1;
-         }
-       else if (name == ansi_opname[(int) DELETE_EXPR])
-         TREE_GETS_DELETE (t) = 1;
-#if 0
-       else if (name == ansi_opname[(int) VEC_NEW_EXPR])
-         TREE_GETS_NEW (t) = 1;
-       else if (name == ansi_opname[(int) VEC_DELETE_EXPR])
-         TREE_GETS_DELETE (t) = 1;
-#endif
-      }
+  if (current_class_type == NULL_TREE)
+    friendp = 1;
 
-  if (name == ansi_opname[(int) NEW_EXPR])
+  if (! friendp)
+    {
+      if (name == ansi_opname[(int) MODIFY_EXPR])
+       TYPE_HAS_ASSIGNMENT (current_class_type) = 1;
+      else if (name == ansi_opname[(int) CALL_EXPR])
+       TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1;
+      else if (name == ansi_opname[(int) ARRAY_REF])
+       TYPE_OVERLOADS_ARRAY_REF (current_class_type) = 1;
+      else if (name == ansi_opname[(int) COMPONENT_REF]
+              || name == ansi_opname[(int) MEMBER_REF])
+       TYPE_OVERLOADS_ARROW (current_class_type) = 1;
+      else if (name == ansi_opname[(int) NEW_EXPR])
+       TYPE_GETS_NEW (current_class_type) |= 1;
+      else if (name == ansi_opname[(int) DELETE_EXPR])
+       TYPE_GETS_DELETE (current_class_type) |= 1;
+      else if (name == ansi_opname[(int) VEC_NEW_EXPR])
+       TYPE_GETS_NEW (current_class_type) |= 2;
+      else if (name == ansi_opname[(int) VEC_DELETE_EXPR])
+       TYPE_GETS_DELETE (current_class_type) |= 2;
+    }
+
+  if (name == ansi_opname[(int) NEW_EXPR]
+      || name == ansi_opname[(int) VEC_NEW_EXPR])
     {
-#if 0
       /* When the compiler encounters the definition of A::operator new, it
         doesn't look at the class declaration to find out if it's static.  */
-      my_friendly_assert (!methodp, 355);
-#endif
+      if (methodp)
+       revert_static_member_fn (&decl, NULL, NULL);
      
       /* Take care of function decl if we had syntax errors.  */
       if (argtypes == NULL_TREE)
@@ -9417,18 +9861,13 @@ grok_op_properties (decl, virtualp, friendp)
                               hash_tree_chain (integer_type_node,
                                                void_list_node));
       else
-       decl = coerce_new_type (TREE_TYPE (decl));
-    }
-#if 0
-  else if (name == ansi_opname[(int) VEC_NEW_EXPR])
-    {
+       TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
     }
-#endif
-  else if (name == ansi_opname[(int) DELETE_EXPR])
+  else if (name == ansi_opname[(int) DELETE_EXPR]
+          || name == ansi_opname[(int) VEC_DELETE_EXPR])
     {
-#if 0
-      my_friendly_assert (!methodp, 355);
-#endif
+      if (methodp)
+       revert_static_member_fn (&decl, NULL, NULL);
      
       if (argtypes == NULL_TREE)
        TREE_TYPE (decl) =
@@ -9436,19 +9875,21 @@ grok_op_properties (decl, virtualp, friendp)
                               hash_tree_chain (ptr_type_node,
                                                void_list_node));
       else
-       decl = coerce_delete_type (TREE_TYPE (decl));
-    }
-#if 0
-  else if (name == ansi_opname[(int) VEC_DELETE_EXPR])
-    {
+       {
+         TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
+
+         if (! friendp && name == ansi_opname[(int) VEC_DELETE_EXPR]
+             && (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl)))
+                 != void_list_node))
+           TYPE_VEC_DELETE_TAKES_SIZE (current_class_type) = 1;
+       }
     }
-#endif
   else
     {
       /* An operator function must either be a non-static member function
         or have at least one parameter of a class, a reference to a class,
         an enumeration, or a reference to an enumeration.  13.4.0.6 */
-      if (! methodp)
+      if (! methodp || DECL_STATIC_FUNCTION_P (decl))
        {
          if (OPERATOR_TYPENAME_P (name)
              || name == ansi_opname[(int) CALL_EXPR]
@@ -9460,6 +9901,9 @@ grok_op_properties (decl, virtualp, friendp)
            {
              tree p = argtypes;
 
+             if (DECL_STATIC_FUNCTION_P (decl))
+               cp_error ("`%D' must be either a non-static member function or a non-member function", decl);
+
              if (p)
                for (; TREE_VALUE (p) != void_type_node ; p = TREE_CHAIN (p))
                  {
@@ -9485,6 +9929,30 @@ grok_op_properties (decl, virtualp, friendp)
          || name == ansi_opname[(int) METHOD_CALL_EXPR])
        return;                 /* no restrictions on args */
 
+      if (IDENTIFIER_TYPENAME_P (name))
+       {
+         tree t = TREE_TYPE (name);
+         if (TREE_CODE (t) == VOID_TYPE)
+           pedwarn ("void is not a valid type conversion operator");
+         else if (! friendp)
+           {
+             int ref = (TREE_CODE (t) == REFERENCE_TYPE);
+             char *what = 0;
+             if (ref)
+               t = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+
+             if (t == current_class_type)
+               what = "the same type";
+             else if (IS_AGGR_TYPE (t)
+                      && DERIVED_FROM_P (t, current_class_type))
+               what = "a base class";
+
+             if (what)
+               warning ("conversion to %s%s will never use a type conversion operator",
+                        ref ? "a reference to " : "", what);
+           }
+       }
+
       if (name == ansi_opname[(int) MODIFY_EXPR])
        {
          tree parmtype;
@@ -9496,13 +9964,17 @@ grok_op_properties (decl, virtualp, friendp)
            }
          parmtype = TREE_VALUE (TREE_CHAIN (argtypes));
 
-         if (TREE_CODE (parmtype) == REFERENCE_TYPE
-             && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype))
-             == current_class_type)
+         if (copy_assignment_arg_p (parmtype, virtualp)
+             && ! friendp)
            {
              TYPE_HAS_ASSIGN_REF (current_class_type) = 1;
-             if (TYPE_READONLY (TREE_TYPE (parmtype)))
+             if (TREE_CODE (parmtype) != REFERENCE_TYPE
+                 || TYPE_READONLY (TREE_TYPE (parmtype)))
                TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1;
+#if 0 /* Too soon; done in grok_function_init */
+             if (DECL_ABSTRACT_VIRTUAL_P (decl))
+               TYPE_HAS_ABSTRACT_ASSIGN_REF (current_class_type) = 1;
+#endif
            }
        }
       else if (name == ansi_opname[(int) COND_EXPR])
@@ -9588,72 +10060,6 @@ grok_op_properties (decl, virtualp, friendp)
    the current frame for the name (since C++ allows new names in any
    scope.)  */
 
-/* avoid rewriting all callers of xref_tag */
-static int xref_next_defn = 0;
-
-tree
-xref_defn_tag (code_type_node, name, binfo)
-     tree code_type_node;
-     tree name, binfo;
-{
-  tree rv, ncp;
-  xref_next_defn = 1;
-
-  if (class_binding_level)
-    {
-      tree n1;
-      char *buf;
-      /* we need to build a new IDENTIFIER_NODE for name which nukes
-       * the pieces... */
-/*
-      n1 = IDENTIFIER_LOCAL_VALUE (current_class_name);
-      if (n1)
-       n1 = DECL_NAME (n1);
-      else
-       n1 = current_class_name;
-*/
-      n1 = TYPE_NAME(current_class_type);
-      if (n1)
-       n1 = DECL_NESTED_TYPENAME(n1);
-      else
-       n1 = current_class_name;
-      
-      buf = (char *) alloca (4 + IDENTIFIER_LENGTH (n1)
-                            + IDENTIFIER_LENGTH (name));
-      
-      sprintf (buf, "%s::%s", IDENTIFIER_POINTER (n1),
-              IDENTIFIER_POINTER (name));
-      ncp = get_identifier (buf);
-#ifdef SPEW_DEBUG
-      if (spew_debug)
-       printf("*** %s ***\n", IDENTIFIER_POINTER (ncp));
-#endif
-#if 0
-      IDENTIFIER_LOCAL_VALUE (name) =
-       build_lang_decl (TYPE_DECL, ncp, NULL_TREE);
-#endif
-      rv = xref_tag (code_type_node, name, binfo, 0);
-      if (! ANON_AGGRNAME_P (name))
-      {
-       register tree type_decl = build_lang_decl (TYPE_DECL, ncp, rv);
-#ifdef DWARF_DEBUGGING_INFO
-       /* Mark the TYPE_DECL node created just above as a gratuitous one
-          so that dwarfout.c will know not to generate a TAG_typedef DIE
-          for it.  */
-       if (write_symbols == DWARF_DEBUG)
-         DECL_IGNORED_P (type_decl) = 1;
-#endif /* DWARF_DEBUGGING_INFO */
-       pushdecl_top_level (type_decl);
-      }
-    }
-  else
-    {
-      rv = xref_tag (code_type_node, name, binfo, 0);
-    }
-  xref_next_defn = 0;
-  return rv;
-}
-
 tree
 xref_tag (code_type_node, name, binfo, globalize)
      tree code_type_node;
@@ -9663,7 +10069,7 @@ xref_tag (code_type_node, name, binfo, globalize)
   enum tag_types tag_code;
   enum tree_code code;
   int temp = 0;
-  int i, len;
+  int i;
   register tree ref, t;
   struct binding_level *b = inner_binding_level;
 
@@ -9672,19 +10078,11 @@ xref_tag (code_type_node, name, binfo, globalize)
     {
     case record_type:
     case class_type:
-    case exception_type:
     case signature_type:
       code = RECORD_TYPE;
-      len = list_length (binfo);
       break;
     case union_type:
       code = UNION_TYPE;
-      if (binfo)
-       {
-         cp_error ("derived union `%T' invalid", name);
-         binfo = NULL_TREE;
-       }
-      len = 0;
       break;
     case enum_type:
       code = ENUMERAL_TYPE;
@@ -9695,16 +10093,15 @@ xref_tag (code_type_node, name, binfo, globalize)
 
   /* If a cross reference is requested, look up the type
      already defined for this tag and return it.  */
-  if (t = IDENTIFIER_TYPE_VALUE(name))
-    {
-       if (TREE_CODE(t) != code) t = NULL_TREE;
-    }
-  if (xref_next_defn)
+  t = IDENTIFIER_TYPE_VALUE (name);
+  if (t && TREE_CODE (t) != code)
+    t = NULL_TREE;
+
+  if (! globalize)
     {
       /* If we know we are defining this tag, only look it up in this scope
        * and don't try to find it as a type. */
-      xref_next_defn = 0;
-      if (t && TYPE_CONTEXT(t) && strstr(IDENTIFIER_POINTER(name), "::"))
+      if (t && TYPE_CONTEXT(t) && TREE_MANGLED (name))
        ref = t;
       else
        ref = lookup_tag (code, name, b, 1);
@@ -9766,61 +10163,23 @@ xref_tag (code_type_node, name, binfo, globalize)
          if (flag_cadillac)
            cadillac_start_enum (ref);
        }
-      else if (tag_code == exception_type)
-       {
-         ref = make_lang_type (code);
-         /* Enable us to recognize when an exception type is created in
-            class context.  To do nested classes correctly, this should
-            probably be cleared out when we leave this class's scope.  */
-         CLASSTYPE_DECLARED_EXCEPTION (ref) = 1;
-         pushtag (name, ref, globalize);
-         if (flag_cadillac)
-           cadillac_start_struct (ref);
-       }
       else
        {
-         extern tree pending_vtables;
          struct binding_level *old_b = class_binding_level;
-         int needs_writing;
 
          ref = make_lang_type (code);
 
-         /* A signature type will contain the fields of the signature
-            table.  Therefore, it's not only an interface.  */
          if (tag_code == signature_type)
            {
              SET_SIGNATURE (ref);
+             /* Since a signature type will be turned into the type
+                of signature tables, it's not only an interface.  */
              CLASSTYPE_INTERFACE_ONLY (ref) = 0;
-             CLASSTYPE_INTERFACE_UNKNOWN (ref) = 0;
-           }
-
-         /* Record how to set the access of this class's
-            virtual functions.  If write_virtuals == 2 or 3, then
-            inline virtuals are ``extern inline''.  */
-         switch (write_virtuals)
-           {
-           case 0:
-           case 1:
-             needs_writing = 1;
-             break;
-           case 2:
-             needs_writing = !! value_member (name, pending_vtables);
-             break;
-           case 3:
-             needs_writing = ! CLASSTYPE_INTERFACE_ONLY (ref)
-               && CLASSTYPE_INTERFACE_KNOWN (ref);
-             break;
-           default:
-             needs_writing = 0;
+             SET_CLASSTYPE_INTERFACE_KNOWN (ref);
+             /* A signature doesn't have a vtable.  */
+             CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = 0;
            }
 
-         /* Signatures don't have a vtable.  As long as we don't have default
-            implementations, they behave as if `write_virtuals' were 3.  */
-         if (tag_code == signature_type)
-           CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = 0;
-         else
-           CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = needs_writing;
-
 #ifdef NONNESTED_CLASSES
          /* Class types don't nest the way enums do.  */
          class_binding_level = (struct binding_level *)0;
@@ -9834,23 +10193,13 @@ xref_tag (code_type_node, name, binfo, globalize)
     }
   else
     {
-      if (IS_AGGR_TYPE_CODE (code))
-       {
-         if (IS_AGGR_TYPE (ref)
-             && ((tag_code == exception_type)
-                 != (CLASSTYPE_DECLARED_EXCEPTION (ref) == 1)))
-           {
-             cp_error ("type `%T' is both exception and aggregate type", ref);
-             CLASSTYPE_DECLARED_EXCEPTION (ref) = (tag_code == exception_type);
-           }
-       }
-
       /* If it no longer looks like a nested type, make sure it's
         in global scope.  */
       if (b == global_binding_level && !class_binding_level
          && IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE)
        IDENTIFIER_GLOBAL_VALUE (name) = TYPE_NAME (ref);
 
+#if 0
       if (binfo)
        {
          tree tt1 = binfo;
@@ -9873,148 +10222,170 @@ xref_tag (code_type_node, name, binfo, globalize)
             build them on the permanent obstack.  */
          end_temporary_allocation ();
        }
+#endif
     }
 
   if (binfo)
+    xref_basetypes (code_type_node, name, ref, binfo);
+
+ just_return:
+
+  /* Until the type is defined, tentatively accept whatever
+     structure tag the user hands us.  */
+  if (TYPE_SIZE (ref) == NULL_TREE
+      && ref != current_class_type
+      /* Have to check this, in case we have contradictory tag info.  */
+      && IS_AGGR_TYPE_CODE (TREE_CODE (ref)))
     {
-      /* In the declaration `A : X, Y, ... Z' we mark all the types
-        (A, X, Y, ..., Z) so we can check for duplicates.  */
-      tree binfos;
-
-      SET_CLASSTYPE_MARKED (ref);
-      BINFO_BASETYPES (TYPE_BINFO (ref)) = binfos = make_tree_vec (len);
-
-      for (i = 0; binfo; binfo = TREE_CHAIN (binfo))
-       {
-         /* The base of a derived struct is public by default.  */
-         int via_public
-           = (TREE_PURPOSE (binfo) == (tree)access_public
-              || TREE_PURPOSE (binfo) == (tree)access_public_virtual
-              || (tag_code != class_type
-                  && (TREE_PURPOSE (binfo) == (tree)access_default
-                      || TREE_PURPOSE (binfo) == (tree)access_default_virtual)));
-         int via_protected = TREE_PURPOSE (binfo) == (tree)access_protected;
-         int via_virtual
-           = (TREE_PURPOSE (binfo) == (tree)access_private_virtual
-              || TREE_PURPOSE (binfo) == (tree)access_public_virtual
-              || TREE_PURPOSE (binfo) == (tree)access_default_virtual);
-         tree basetype = TREE_TYPE (TREE_VALUE (binfo));
-         tree base_binfo;
-
-         GNU_xref_hier (IDENTIFIER_POINTER (name),
-                        IDENTIFIER_POINTER (TREE_VALUE (binfo)),
-                        via_public, via_virtual, 0);
-
-         if (basetype && TREE_CODE (basetype) == TYPE_DECL)
-           basetype = TREE_TYPE (basetype);
-         if (!basetype || TREE_CODE (basetype) != RECORD_TYPE)
-           {
-             error ("base type `%s' fails to be a struct or class type",
-                    IDENTIFIER_POINTER (TREE_VALUE (binfo)));
-             continue;
-           }
+      if (tag_code == class_type)
+       CLASSTYPE_DECLARED_CLASS (ref) = 1;
+      else if (tag_code == record_type || tag_code == signature_type)
+       CLASSTYPE_DECLARED_CLASS (ref) = 0;
+    }
+
+  pop_obstacks ();
+
+  return ref;
+}
+
+void
+xref_basetypes (code_type_node, name, ref, binfo)
+     tree code_type_node;
+     tree name, ref;
+     tree binfo;
+{
+  /* In the declaration `A : X, Y, ... Z' we mark all the types
+     (A, X, Y, ..., Z) so we can check for duplicates.  */
+  tree binfos;
+  int i, len;
+  enum tag_types tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node);
+
+  if (tag_code == union_type)
+    {
+      cp_error ("derived union `%T' invalid", ref);
+      return;
+    }
+
+  len = list_length (binfo);
+  push_obstacks (TYPE_OBSTACK (ref), TYPE_OBSTACK (ref));
+
+  SET_CLASSTYPE_MARKED (ref);
+  BINFO_BASETYPES (TYPE_BINFO (ref)) = binfos = make_tree_vec (len);
+
+  for (i = 0; binfo; binfo = TREE_CHAIN (binfo))
+    {
+      /* The base of a derived struct is public by default.  */
+      int via_public
+       = (TREE_PURPOSE (binfo) == (tree)access_public
+          || TREE_PURPOSE (binfo) == (tree)access_public_virtual
+          || (tag_code != class_type
+              && (TREE_PURPOSE (binfo) == (tree)access_default
+                  || TREE_PURPOSE (binfo) == (tree)access_default_virtual)));
+      int via_protected = TREE_PURPOSE (binfo) == (tree)access_protected;
+      int via_virtual
+       = (TREE_PURPOSE (binfo) == (tree)access_private_virtual
+          || TREE_PURPOSE (binfo) == (tree)access_public_virtual
+          || TREE_PURPOSE (binfo) == (tree)access_default_virtual);
+      tree basetype = TREE_TYPE (TREE_VALUE (binfo));
+      tree base_binfo;
+
+      GNU_xref_hier (IDENTIFIER_POINTER (name),
+                    IDENTIFIER_POINTER (TREE_VALUE (binfo)),
+                    via_public, via_virtual, 0);
+
+      if (basetype && TREE_CODE (basetype) == TYPE_DECL)
+       basetype = TREE_TYPE (basetype);
+      if (!basetype || TREE_CODE (basetype) != RECORD_TYPE)
+       {
+         cp_error ("base type `%T' fails to be a struct or class type",
+                   TREE_VALUE (binfo));
+         continue;
+       }
 #if 1
-         /* This code replaces similar code in layout_basetypes.  */
-         else if (TYPE_SIZE (basetype) == NULL_TREE)
+      /* This code replaces similar code in layout_basetypes.  */
+      else if (TYPE_INCOMPLETE (basetype))
+       {
+         cp_error ("base class `%T' has incomplete type", basetype);
+         continue;
+       }
+#endif
+      else
+       {
+         if (CLASSTYPE_MARKED (basetype))
            {
-             cp_error ("base class `%T' has incomplete type", basetype);
+             if (basetype == ref)
+               cp_error ("recursive type `%T' undefined", basetype);
+             else
+               cp_error ("duplicate base type `%T' invalid", basetype);
              continue;
            }
-#endif
-         else
-           {
-             if (CLASSTYPE_MARKED (basetype))
-               {
-                 if (basetype == ref)
-                   cp_error ("recursive type `%T' undefined", basetype);
-                 else
-                   cp_error ("duplicate base type `%T' invalid", basetype);
-                 continue;
-               }
 
-             /* Note that the BINFO records which describe individual
-                inheritances are *not* shared in the lattice!  They
-                cannot be shared because a given baseclass may be
-                inherited with different `accessibility' by different
-                derived classes.  (Each BINFO record describing an
-                individual inheritance contains flags which say what
-                the `accessibility' of that particular inheritance is.)  */
+         /* Note that the BINFO records which describe individual
+            inheritances are *not* shared in the lattice!  They
+            cannot be shared because a given baseclass may be
+            inherited with different `accessibility' by different
+            derived classes.  (Each BINFO record describing an
+            individual inheritance contains flags which say what
+            the `accessibility' of that particular inheritance is.)  */
   
-             base_binfo = make_binfo (integer_zero_node, basetype,
-                                 TYPE_BINFO_VTABLE (basetype),
-                                 TYPE_BINFO_VIRTUALS (basetype), 0);
+         base_binfo = make_binfo (integer_zero_node, basetype,
+                                  TYPE_BINFO_VTABLE (basetype),
+                                  TYPE_BINFO_VIRTUALS (basetype), NULL_TREE);
  
-             TREE_VEC_ELT (binfos, i) = base_binfo;
-             TREE_VIA_PUBLIC (base_binfo) = via_public;
-             TREE_VIA_PROTECTED (base_binfo) = via_protected;
-             TREE_VIA_VIRTUAL (base_binfo) = via_virtual;
+         TREE_VEC_ELT (binfos, i) = base_binfo;
+         TREE_VIA_PUBLIC (base_binfo) = via_public;
+         TREE_VIA_PROTECTED (base_binfo) = via_protected;
+         TREE_VIA_VIRTUAL (base_binfo) = via_virtual;
+         BINFO_INHERITANCE_CHAIN (base_binfo) = TYPE_BINFO (ref);
 
-             SET_CLASSTYPE_MARKED (basetype);
+         SET_CLASSTYPE_MARKED (basetype);
 #if 0
-/* XYZZY TEST VIRTUAL BASECLASSES */
-if (CLASSTYPE_N_BASECLASSES (basetype) == NULL_TREE
-    && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
-    && via_virtual == 0)
-  {
-    warning ("making type `%s' a virtual baseclass",
-            TYPE_NAME_STRING (basetype));
-    via_virtual = 1;
-  }
+         /* XYZZY TEST VIRTUAL BASECLASSES */
+         if (CLASSTYPE_N_BASECLASSES (basetype) == NULL_TREE
+             && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
+             && via_virtual == 0)
+           {
+             warning ("making type `%s' a virtual baseclass",
+                      TYPE_NAME_STRING (basetype));
+             via_virtual = 1;
+           }
 #endif
-             /* We are free to modify these bits because they are meaningless
-                at top level, and BASETYPE is a top-level type.  */
-             if (via_virtual || TYPE_USES_VIRTUAL_BASECLASSES (basetype))
-               {
-                 TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1;
-                 TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
-               }
-
-             TYPE_OVERLOADS_METHOD_CALL_EXPR (ref) |= TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype);
-             TREE_GETS_NEW (ref) |= TREE_GETS_NEW (basetype);
-             TREE_GETS_PLACED_NEW (ref) |= TREE_GETS_PLACED_NEW (basetype);
-             TREE_GETS_DELETE (ref) |= TREE_GETS_DELETE (basetype);
-             CLASSTYPE_LOCAL_TYPEDECLS (ref) |= CLASSTYPE_LOCAL_TYPEDECLS (basetype);
-             i += 1;
+         /* We are free to modify these bits because they are meaningless
+            at top level, and BASETYPE is a top-level type.  */
+         if (via_virtual || TYPE_USES_VIRTUAL_BASECLASSES (basetype))
+           {
+             TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1;
+             TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
            }
-       }
-      if (i)
-       TREE_VEC_LENGTH (binfos) = i;
-      else
-       BINFO_BASETYPES (TYPE_BINFO (ref)) = NULL_TREE;
-
-      if (i > 1)
-       TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1;
-      else if (i == 1)
-       TYPE_USES_MULTIPLE_INHERITANCE (ref)
-         = TYPE_USES_MULTIPLE_INHERITANCE (BINFO_TYPE (TREE_VEC_ELT (binfos, 0)));
-      if (TYPE_USES_MULTIPLE_INHERITANCE (ref))
-       TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
 
-      /* Unmark all the types.  */
-      while (--i >= 0)
-       CLEAR_CLASSTYPE_MARKED (BINFO_TYPE (TREE_VEC_ELT (binfos, i)));
-      CLEAR_CLASSTYPE_MARKED (ref);
+         TYPE_OVERLOADS_METHOD_CALL_EXPR (ref) |= TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype);
+         TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype);
+         TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
+         CLASSTYPE_LOCAL_TYPEDECLS (ref) |= CLASSTYPE_LOCAL_TYPEDECLS (basetype);
+         i += 1;
+       }
     }
+  if (i)
+    TREE_VEC_LENGTH (binfos) = i;
+  else
+    BINFO_BASETYPES (TYPE_BINFO (ref)) = NULL_TREE;
 
- just_return:
+  if (i > 1)
+    TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1;
+  else if (i == 1)
+    TYPE_USES_MULTIPLE_INHERITANCE (ref)
+      = TYPE_USES_MULTIPLE_INHERITANCE (BINFO_TYPE (TREE_VEC_ELT (binfos, 0)));
+  if (TYPE_USES_MULTIPLE_INHERITANCE (ref))
+    TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
 
-  /* Until the type is defined, tentatively accept whatever
-     structure tag the user hands us.  */
-  if (TYPE_SIZE (ref) == NULL_TREE
-      && ref != current_class_type
-      /* Have to check this, in case we have contradictory tag info.  */
-      && IS_AGGR_TYPE_CODE (TREE_CODE (ref)))
-    {
-      if (tag_code == class_type)
-       CLASSTYPE_DECLARED_CLASS (ref) = 1;
-      else if (tag_code == record_type || tag_code == signature_type)
-       CLASSTYPE_DECLARED_CLASS (ref) = 0;
-    }
+  /* Unmark all the types.  */
+  while (--i >= 0)
+    CLEAR_CLASSTYPE_MARKED (BINFO_TYPE (TREE_VEC_ELT (binfos, i)));
+  CLEAR_CLASSTYPE_MARKED (ref);
 
   pop_obstacks ();
-
-  return ref;
 }
+  
 \f
 static tree current_local_enum = NULL_TREE;
 
@@ -10050,6 +10421,7 @@ start_enum (name)
     TREE_ADDRESSABLE (b->tags) = 1;
   current_local_enum = NULL_TREE;
 
+#if 0 /* This stuff gets cleared in finish_enum anyway.  */
   if (TYPE_VALUES (enumtype) != NULL_TREE)
     /* Completely replace its old definition.
        The old enumerators remain defined, however.  */
@@ -10062,11 +10434,13 @@ start_enum (name)
 
   TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
   TYPE_SIZE (enumtype) = NULL_TREE;
-  fixup_unsigned_type (enumtype);
+  fixup_signed_type (enumtype);
+#endif
 
   /* We copy this value because enumerated type constants
      are really of the type of the enumerator, not integer_type_node.  */
   enum_next_value = copy_node (integer_zero_node);
+  enum_overflow = 0;
 
   GNU_xref_decl (current_function_decl, enumtype);
   return enumtype;
@@ -10081,75 +10455,84 @@ tree
 finish_enum (enumtype, values)
      register tree enumtype, values;
 {
-  register tree pair, tem;
-  register HOST_WIDE_INT maxvalue = 0;
-  register HOST_WIDE_INT minvalue = 0;
-  register HOST_WIDE_INT i;
-
-  TYPE_VALUES (enumtype) = values;
-
+  register tree minnode, maxnode;
   /* Calculate the maximum value of any enumerator in this type.  */
 
   if (values)
     {
+      register tree pair;
+      register tree value = DECL_INITIAL (TREE_VALUE (values));
+      
       /* Speed up the main loop by performing some precalculations */
-
-      HOST_WIDE_INT value = TREE_INT_CST_LOW (TREE_VALUE (values));
       TREE_TYPE (TREE_VALUE (values)) = enumtype;
-      minvalue = maxvalue = value;
+      TREE_TYPE (value) = enumtype;
+      TREE_VALUE (values) = value;
+      minnode = maxnode = value;
       
       for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair))
        {
-         value = TREE_INT_CST_LOW (TREE_VALUE (pair));
-         if (value > maxvalue)
-           maxvalue = value;
-         else if (value < minvalue)
-           minvalue = value;
+         value = DECL_INITIAL (TREE_VALUE (pair));
          TREE_TYPE (TREE_VALUE (pair)) = enumtype;
+         TREE_TYPE (value) = enumtype;
+         TREE_VALUE (pair) = value;
+         if (tree_int_cst_lt (maxnode, value))
+           maxnode = value;
+         else if (tree_int_cst_lt (value, minnode))
+           minnode = value;
        }
     }
+  else
+    maxnode = minnode = integer_zero_node;
 
-  if (flag_short_enums)
-    {
-      /* Determine the precision this type needs, lay it out, and define it.  */
+  TYPE_VALUES (enumtype) = values;
 
-      for (i = maxvalue; i; i >>= 1)
-       TYPE_PRECISION (enumtype)++;
+  {
+    int unsignedp = tree_int_cst_sgn (minnode) >= 0;
+    int lowprec = min_precision (minnode, unsignedp);
+    int highprec = min_precision (maxnode, unsignedp);
+    int precision = MAX (lowprec, highprec);
 
-      if (!TYPE_PRECISION (enumtype))
-       TYPE_PRECISION (enumtype) = 1;
+    TYPE_SIZE (enumtype) = NULL_TREE;
 
-      /* Cancel the laying out previously done for the enum type,
-        so that fixup_unsigned_type will do it over.  */
-      TYPE_SIZE (enumtype) = NULL_TREE;
+    /* Set TYPE_MIN_VALUE and TYPE_MAX_VALUE according to `precision'.  */
 
+    TYPE_PRECISION (enumtype) = precision;
+    if (unsignedp)
       fixup_unsigned_type (enumtype);
-    }
+    else
+      fixup_signed_type (enumtype);
+
+    if (flag_short_enums || precision > TYPE_PRECISION (integer_type_node))
+      /* Use the width of the narrowest normal C type which is wide enough.  */
+      TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size
+                                                 (precision, 1));
+    else
+      TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
 
-  TREE_INT_CST_LOW (TYPE_MAX_VALUE (enumtype)) = maxvalue;
+    TYPE_SIZE (enumtype) = 0;
+    layout_type (enumtype);
+  }
 
-  /* An enum can have some negative values; then it is signed.  */
-  if (minvalue < 0)
-    {
-      TREE_INT_CST_LOW (TYPE_MIN_VALUE (enumtype)) = minvalue;
-      TREE_INT_CST_HIGH (TYPE_MIN_VALUE (enumtype)) = -1;
-      TREE_UNSIGNED (enumtype) = 0;
-    }
   if (flag_cadillac)
     cadillac_finish_enum (enumtype);
 
-  /* Fix up all variant types of this enum type.  */
-  for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem))
-    {
-      TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
-      TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
-      TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
-      TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
-      TYPE_MODE (tem) = TYPE_MODE (enumtype);
-      TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
-      TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
-      TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
-    }
+  {
+    register tree tem;
+    
+    /* Fix up all variant types of this enum type.  */
+    for (tem = TYPE_MAIN_VARIANT (enumtype); tem;
+        tem = TYPE_NEXT_VARIANT (tem))
+      {
+       TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
+       TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
+       TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
+       TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
+       TYPE_MODE (tem) = TYPE_MODE (enumtype);
+       TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
+       TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
+       TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
+      }
+  }
 
   /* Finish debugging output for this type.  */
 #if 0
@@ -10195,8 +10578,7 @@ build_enumerator (name, value)
        }
       else
        {
-         error ("enumerator value for `%s' not integer constant",
-                IDENTIFIER_POINTER (name));
+         cp_error ("enumerator value for `%D' not integer constant", name);
          value = NULL_TREE;
        }
     }
@@ -10206,13 +10588,17 @@ build_enumerator (name, value)
      to keep that from happening.  */
   /* Default based on previous value.  */
   if (value == NULL_TREE)
-    value = enum_next_value;
+    {
+      value = enum_next_value;
+      if (enum_overflow)
+       cp_error ("overflow in enumeration values at `%D'", name);
+    }
 
   /* Remove no-op casts from the value.  */
   if (value)
     STRIP_TYPE_NOPS (value);
 
-  /* Make up for hacks in cp-lex.c.  */
+  /* Make up for hacks in lex.c.  */
   if (value == integer_zero_node)
     value = build_int_2 (0, 0);
   else if (value == integer_one_node)
@@ -10225,30 +10611,10 @@ build_enumerator (name, value)
       TREE_TYPE (value) = integer_type_node;
     }
 
-  result = saveable_tree_cons (name, value, NULL_TREE);
-
   /* C++ associates enums with global, function, or class declarations.  */
 
-  /* There are a number of cases we need to be aware of here:
-                               current_class_type      current_function_decl
-     * global enums            NULL                    NULL
-     * fn-local enum           NULL                    SET
-     * class-local enum                SET                     NULL
-     * class->fn->enum         SET                     SET
-     * fn->class->enum         SET                     SET
-
-     Those last two make life interesting.  If it's a fn-local enum which is
-     itself inside a class, we need the enum to go into the fn's decls (our
-     second case below).  But if it's a class-local enum and the class itself
-     is inside a function, we need that enum to go into the decls for the
-     class.  To achieve this last goal, we must see if, when both
-     current_class_decl and current_function_decl are set, the class was
-     declared inside that function.  If so, we know to put the enum into
-     the class's scope.  */
-     
-  if ((current_class_type && ! current_function_decl)
-      || (current_class_type && current_function_decl
-         && TYPE_CONTEXT (current_class_type) == current_function_decl))
+  decl = current_scope ();
+  if (decl && decl == current_class_type)
     {
       /* This enum declaration is local to the class, so we must put
         it in that class's list of decls.  */
@@ -10273,9 +10639,12 @@ build_enumerator (name, value)
   /* Set basis for default for next value.  */
   enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value,
                                               integer_one_node, PLUS_EXPR);
+  enum_overflow = tree_int_cst_lt (enum_next_value, value);
+  
   if (enum_next_value == integer_one_node)
     enum_next_value = copy_node (enum_next_value);
 
+  result = saveable_tree_cons (name, decl, NULL_TREE);
   return result;
 }
 
@@ -10331,7 +10700,6 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
      tree declarator, declspecs, raises;
      int pre_parsed_p;
 {
-  extern tree EHS_decl;
   tree decl1, olddecl;
   tree ctype = NULL_TREE;
   tree fntype;
@@ -10340,9 +10708,6 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
   extern int used_extern_spec;
   int doing_friend = 0;
 
-  if (flag_handle_exceptions && EHS_decl == NULL_TREE)
-    init_exception_processing_1 ();
-
   /* Sanity check.  */
   my_friendly_assert (TREE_VALUE (void_list_node) == void_type_node, 160);
   my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161);
@@ -10351,13 +10716,18 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
   current_function_returns_value = 0;
   current_function_returns_null = 0;
   warn_about_return_type = 0;
-  current_extern_inline = 0;
+  named_labels = 0;
+  shadowed_labels = 0;
   current_function_assigns_this = 0;
   current_function_just_assigned_this = 0;
   current_function_parms_stored = 0;
   original_result_rtx = NULL_RTX;
   current_function_obstack_index = 0;
   current_function_obstack_usage = 0;
+  base_init_insns = NULL_RTX;
+  protect_list = NULL_TREE;
+  current_base_init_list = NULL_TREE;
+  current_member_init_list = NULL_TREE;
 
   clear_temp_name ();
 
@@ -10407,11 +10777,6 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
            doing_friend = 1;
        }
 
-      if ( !(DECL_VINDEX (decl1)
-            && write_virtuals >= 2
-            && CLASSTYPE_VTABLE_NEEDS_WRITING (ctype)))
-       current_extern_inline = TREE_PUBLIC (decl1) && DECL_INLINE (decl1);
-
       raises = TYPE_RAISES_EXCEPTIONS (fntype);
 
       /* In a fcn definition, arg types must be complete.  */
@@ -10452,7 +10817,8 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
          /* If this doesn't return integer_type, complain.  */
          if (TREE_TYPE (TREE_TYPE (decl1)) != integer_type_node)
            {
-             warning ("return type for `main' changed to integer type");
+             if (pedantic || warn_return_type)
+               pedwarn ("return type for `main' changed to integer type");
              TREE_TYPE (decl1) = fntype = default_function_type;
            }
          warn_about_return_type = 0;
@@ -10496,6 +10862,10 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
       DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, TREE_TYPE (fntype));
     }
 
+  if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
+      && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (fntype)))
+    abstract_virtuals_error (decl1, TREE_TYPE (fntype));
+
   if (warn_about_return_type)
     warning ("return-type defaults to `int'");
 
@@ -10510,57 +10880,38 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
      (This does not mean `static' in the C sense!)  */
   TREE_STATIC (decl1) = 1;
 
+  if (DECL_INTERFACE_KNOWN (decl1))
+    {
+      if (DECL_NOT_REALLY_EXTERN (decl1))
+       DECL_EXTERNAL (decl1) = 0;
+    }
   /* If this function belongs to an interface, it is public.
      If it belongs to someone else's interface, it is also external.
      It doesn't matter whether it's inline or not.  */
-  if (interface_unknown == 0)
+  else if (interface_unknown == 0)
     {
-      TREE_PUBLIC (decl1) = 1;
-      DECL_EXTERNAL (decl1) = (interface_only
-                              || (DECL_INLINE (decl1)
-                                  && ! flag_implement_inlines));
+      if (DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1))
+       DECL_EXTERNAL (decl1)
+         = (interface_only
+            || (DECL_THIS_INLINE (decl1) && ! flag_implement_inlines));
+      else
+       DECL_EXTERNAL (decl1) = 0;
+      DECL_NOT_REALLY_EXTERN (decl1) = 0;
+      DECL_INTERFACE_KNOWN (decl1) = 1;
     }
   else
-    /* This is a definition, not a reference.
-       So normally clear DECL_EXTERNAL.
-       However, `extern inline' acts like a declaration except for
-       defining how to inline.  So set DECL_EXTERNAL in that case.  */
-    DECL_EXTERNAL (decl1) = current_extern_inline;
-
-  /* Now see if this is the implementation of a declared function.  */
-  if (ctype == NULL_TREE && current_lang_name == lang_name_cplusplus
-      && !DECL_CONTEXT (decl1))
-    {
-      olddecl = lookup_name_current_level (DECL_NAME (decl1));
-      if (olddecl && TREE_CODE (olddecl) != FUNCTION_DECL)
-       olddecl = NULL_TREE;
-      if (olddecl && DECL_NAME (decl1) != DECL_NAME (olddecl))
-       {
-         /* Collision between user and internal naming scheme.  */
-         olddecl = lookup_name_current_level (DECL_ASSEMBLER_NAME (decl1));
-         if (olddecl == NULL_TREE)
-           olddecl = decl1;
-       }
-      if (olddecl && olddecl != decl1
-         && DECL_NAME (decl1) == DECL_NAME (olddecl))
-       {
-         if (TREE_CODE (olddecl) == FUNCTION_DECL
-             && decls_match (decl1, olddecl))
-           {
-             olddecl = DECL_MAIN_VARIANT (olddecl);
-             /* The following copy is needed to handle forcing a function's
-                linkage to obey the linkage of the original decl.  */
-             DECL_ASSEMBLER_NAME (decl1) = DECL_ASSEMBLER_NAME (olddecl);
-             DECL_OVERLOADED (decl1) = DECL_OVERLOADED (olddecl);
-             if (! DECL_BUILT_IN (olddecl) && DECL_INITIAL (olddecl))
-               redeclaration_error_message (decl1, olddecl);
-             if (duplicate_decls (decl1, olddecl))
-               decl1 = olddecl;
-             else
-               olddecl = NULL_TREE;
-           }
-         else
-           olddecl = NULL_TREE;
+    {
+      /* This is a definition, not a reference.
+        So clear DECL_EXTERNAL.  */
+      DECL_EXTERNAL (decl1) = 0;
+
+      if (DECL_THIS_INLINE (decl1) && ! DECL_C_STATIC (decl1))
+       DECL_DEFER_OUTPUT (decl1) = 1;
+      else
+       {
+         DECL_INTERFACE_KNOWN (decl1) = 1;
+         if (DECL_C_STATIC (decl1))
+           TREE_PUBLIC (decl1) = 0;
        }
     }
 
@@ -10568,30 +10919,15 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
      If we already have a decl for this name, and it is a FUNCTION_DECL,
      use the old decl.  */
 
-  if (olddecl)
-    current_function_decl = olddecl;
-  else if (pre_parsed_p == 0)
+  if (pre_parsed_p == 0)
     {
-      current_function_decl = pushdecl (decl1);
-      if (TREE_CODE (current_function_decl) == TREE_LIST)
-       {
-         /* @@ revert to modified original declaration.  */
-         decl1 = DECL_MAIN_VARIANT (decl1);
-         current_function_decl = decl1;
-       }
-      else
-       {
-         decl1 = current_function_decl;
-         DECL_MAIN_VARIANT (decl1) = decl1;
-       }
+      current_function_decl = decl1 = pushdecl (decl1);
+      DECL_MAIN_VARIANT (decl1) = decl1;
       fntype = TREE_TYPE (decl1);
     }
   else
     current_function_decl = decl1;
 
-  if (DECL_OVERLOADED (decl1))
-    decl1 = push_overloaded_decl (decl1, 1);
-
   if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1))
     {
       if (TREE_CODE (fntype) == METHOD_TYPE)
@@ -10604,18 +10940,6 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
     }
   restype = TREE_TYPE (fntype);
 
-  pushlevel (0);
-  current_binding_level->parm_flag = 1;
-
-  /* Save the parm names or decls from this function's declarator
-     where store_parm_decls will find them.  */
-  current_function_parms = last_function_parms;
-  current_function_parm_tags = last_function_parm_tags;
-
-  GNU_xref_function (decl1, current_function_parms);
-
-  make_function_rtl (decl1);
-
   if (ctype)
     {
       push_nested_class (ctype, 1);
@@ -10665,6 +10989,18 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
        push_memoized_context (0, 1);
     }
 
+  pushlevel (0);
+  current_binding_level->parm_flag = 1;
+
+  /* Save the parm names or decls from this function's declarator
+     where store_parm_decls will find them.  */
+  current_function_parms = last_function_parms;
+  current_function_parm_tags = last_function_parm_tags;
+
+  GNU_xref_function (decl1, current_function_parms);
+
+  make_function_rtl (decl1);
+
   /* Allocate further tree nodes temporarily during compilation
      of this function only.  Tiemann moved up here from bottom of fn.  */
   temporary_allocation ();
@@ -10717,7 +11053,6 @@ store_parm_decls ()
   register tree fndecl = current_function_decl;
   register tree parm;
   int parms_have_cleanups = 0;
-  tree eh_decl;
 
   /* This is either a chain of PARM_DECLs (when a prototype is used).  */
   tree specparms = current_function_parms;
@@ -10742,18 +11077,6 @@ store_parm_decls ()
   /* Create a binding level for the parms.  */
   expand_start_bindings (0);
 
-  /* Prepare to catch raises, if appropriate.  */
-  if (flag_handle_exceptions)
-    {
-      /* Get this cleanup to be run last, since it
-        is a call to `longjmp'.  */
-      setup_exception_throw_decl ();
-      eh_decl = current_binding_level->names;
-      current_binding_level->names = TREE_CHAIN (current_binding_level->names);
-    }
-  if (flag_handle_exceptions)
-    expand_start_try (integer_one_node, 0, 1);
-
   if (specparms != NULL_TREE)
     {
       /* This case is when the function was defined with an ANSI prototype.
@@ -10807,7 +11130,9 @@ store_parm_decls ()
              if (cleanup)
                {
                  expand_decl (parm);
-                 expand_decl_cleanup (parm, cleanup);
+                 if (! expand_decl_cleanup (parm, cleanup))
+                   cp_error ("parser lost in parsing declaration of `%D'",
+                             parm);
                  parms_have_cleanups = 1;
                }
            }
@@ -10841,14 +11166,6 @@ store_parm_decls ()
   DECL_SAVED_INSNS (fndecl) = NULL_RTX;
   expand_function_start (fndecl, parms_have_cleanups);
 
-  if (flag_handle_exceptions)
-    {
-      /* Make the throw decl visible at this level, just
-        not in the way of the parameters.  */
-      pushdecl (eh_decl);
-      expand_decl_init (eh_decl);
-    }
-
   /* Create a binding contour which can be used to catch
      cleanup-generated temporaries.  Also, if the return value needs or
      has initialization, deal with that now.  */
@@ -10863,7 +11180,8 @@ store_parm_decls ()
   if (flag_gc)
     {
       maybe_gc_cleanup = build_tree_list (NULL_TREE, error_mark_node);
-      expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup);
+      if (! expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup))
+       cp_error ("parser lost in parsing declaration of `%D'", fndecl);
     }
 
   /* If this function is `main', emit a call to `__main'
@@ -10878,9 +11196,11 @@ store_parm_decls ()
       if (flag_gc)
        expand_expr (build_function_call (lookup_name (get_identifier ("__gc_main"), 0), NULL_TREE),
                     0, VOIDmode, 0);
-
-      if (flag_dossier)
+#if 0
+      /* done at a different time */
+      if (flag_rtti)
        output_builtin_tdesc_entries ();
+#endif
     }
 }
 
@@ -10896,7 +11216,7 @@ store_return_init (return_id, init)
     /* Give this error as many times as there are occurrences,
        so that users can use Emacs compilation buffers to find
        and fix all such places.  */
-    error ("ANSI C++ does not permit named return values");
+    pedwarn ("ANSI C++ does not permit named return values");
 
   if (return_id != NULL_TREE)
     {
@@ -10931,63 +11251,10 @@ store_return_init (return_id, init)
       /* Let `finish_decl' know that this initializer is ok.  */
       DECL_INITIAL (decl) = init;
       pushdecl (decl);
-      finish_decl (decl, init, 0, 0);
+      finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
     }
 }
 
-#if 0
-/* Generate code for default X() constructor.  */
-static void
-build_default_constructor (fndecl)
-     tree fndecl;
-{
-  int i = CLASSTYPE_N_BASECLASSES (current_class_type);
-  tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
-  tree fields = TYPE_FIELDS (current_class_type);
-  tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
-
-  if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
-    parm = TREE_CHAIN (parm);
-  parm = DECL_REFERENCE_SLOT (parm);
-
-  while (--i >= 0)
-    {
-      tree basetype = TREE_VEC_ELT (binfos, i);
-      if (TYPE_HAS_INIT_REF (basetype))
-       {
-         tree name = TYPE_NAME (basetype);
-         if (TREE_CODE (name) == TYPE_DECL)
-           name = DECL_NAME (name);
-         current_base_init_list = tree_cons (name, parm, current_base_init_list);
-       }
-    }
-  for (; fields; fields = TREE_CHAIN (fields))
-    {
-      tree name, init;
-      if (TREE_STATIC (fields))
-       continue;
-      if (TREE_CODE (fields) != FIELD_DECL)
-       continue;
-      if (DECL_NAME (fields))
-       {
-         if (VFIELD_NAME_P (DECL_NAME (fields)))
-           continue;
-         if (VBASE_NAME_P (DECL_NAME (fields)))
-           continue;
-
-         /* True for duplicate members.  */
-         if (IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) != fields)
-           continue;
-       }
-
-      init = build (COMPONENT_REF, TREE_TYPE (fields), parm, fields);
-      init = build_tree_list (NULL_TREE, init);
-
-      current_member_init_list
-       = tree_cons (DECL_NAME (fields), init, current_member_init_list);
-    }
-}
-#endif
 \f
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
@@ -11002,14 +11269,14 @@ build_default_constructor (fndecl)
    constructors.  */
 
 void
-finish_function (lineno, call_poplevel)
+finish_function (lineno, call_poplevel, nested)
      int lineno;
      int call_poplevel;
+     int nested;
 {
   register tree fndecl = current_function_decl;
   tree fntype, ctype = NULL_TREE;
   rtx head, last_parm_insn, mark;
-  extern int sets_exception_throw_decl;
   /* Label to use if this function is supposed to return a value.  */
   tree no_return_label = NULL_TREE;
   tree decls = NULL_TREE;
@@ -11032,7 +11299,7 @@ finish_function (lineno, call_poplevel)
       store_parm_decls ();
     }
 
-  if (write_symbols != NO_DEBUG && TREE_CODE (fntype) != METHOD_TYPE)
+  if (write_symbols != NO_DEBUG /*&& TREE_CODE (fntype) != METHOD_TYPE*/)
     {
       tree ttype = target_type (fntype);
       tree parmdecl;
@@ -11063,7 +11330,7 @@ finish_function (lineno, call_poplevel)
       int ok_to_optimize_dtor = 0;
 
       if (current_function_assigns_this)
-       cond = build (NE_EXPR, integer_type_node,
+       cond = build (NE_EXPR, boolean_type_node,
                      current_class_decl, integer_zero_node);
       else
        {
@@ -11105,7 +11372,7 @@ finish_function (lineno, call_poplevel)
 
       /* These are two cases where we cannot delegate deletion.  */
       if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
-         || TREE_GETS_DELETE (current_class_type))
+         || TYPE_GETS_REG_DELETE (current_class_type))
        exprstmt = build_delete (current_class_type, C_C_D, integer_zero_node,
                                 LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
       else
@@ -11161,7 +11428,7 @@ finish_function (lineno, call_poplevel)
       virtual_size = c_sizeof (current_class_type);
 
       /* At the end, call delete if that's what's requested.  */
-      if (TREE_GETS_DELETE (current_class_type))
+      if (TYPE_GETS_REG_DELETE (current_class_type))
        /* This NOP_EXPR means we are in a static call context.  */
        exprstmt =
          build_method_call
@@ -11204,10 +11471,9 @@ finish_function (lineno, call_poplevel)
       /* Make all virtual function table pointers in non-virtual base
         classes point to CURRENT_CLASS_TYPE's virtual function
         tables.  */
-      init_vtbl_ptrs (binfo, 1, 0);
+      expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_decl);
       if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
-       expand_expr_stmt (build_vbase_vtables_init (binfo, binfo,
-                                                   C_C_D, current_class_decl, 0));
+       expand_indirect_vtbls_init (binfo, C_C_D, current_class_decl, 0);
       if (! ok_to_optimize_dtor)
        {
          cond = build_binary_op (NE_EXPR,
@@ -11227,14 +11493,13 @@ finish_function (lineno, call_poplevel)
 
       if (DECL_CONSTRUCTOR_P (current_function_decl))
        {
+         end_protect_partials ();
          expand_label (ctor_label);
          ctor_label = NULL_TREE;
 
          if (call_poplevel)
            {
              decls = getdecls ();
-             if (flag_handle_exceptions == 2)
-               deactivate_exception_cleanups ();
              expand_end_bindings (decls, decls != NULL_TREE, 0);
              poplevel (decls != NULL_TREE, 0, 0);
            }
@@ -11266,41 +11531,6 @@ finish_function (lineno, call_poplevel)
                                  current_class_decl, integer_zero_node, 1);
          thenclause = build_modify_expr (current_class_decl, NOP_EXPR,
                                          build_new (NULL_TREE, current_class_type, void_type_node, 0));
-         if (flag_handle_exceptions == 2)
-           {
-             tree cleanup, cleanup_deallocate;
-             tree virtual_size;
-
-             /* This is the size of the virtual object pointed to by
-                allocated_this.  In this case, it is simple.  */
-             virtual_size = c_sizeof (current_class_type);
-
-             allocated_this = build_decl (VAR_DECL, NULL_TREE, ptr_type_node);
-             DECL_REGISTER (allocated_this) = 1;
-             DECL_INITIAL (allocated_this) = error_mark_node;
-             expand_decl (allocated_this);
-             expand_decl_init (allocated_this);
-             /* How we cleanup `this' if an exception was raised before
-                we are ready to bail out.  */
-             cleanup = TREE_GETS_DELETE (current_class_type)
-               ? build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, allocated_this, virtual_size, NULL_TREE)
-                 /* The size of allocated_this is wrong, and hence the
-                    second argument to operator delete will be wrong. */
-                 : build_delete (TREE_TYPE (allocated_this), allocated_this,
-                                 integer_three_node,
-                                 LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE, 1);
-             cleanup_deallocate
-               = build_modify_expr (current_class_decl, NOP_EXPR, integer_zero_node);
-             cleanup = tree_cons (NULL_TREE, cleanup,
-                                  build_tree_list (NULL_TREE, cleanup_deallocate));
-
-             expand_decl_cleanup (allocated_this,
-                                  build (COND_EXPR, integer_type_node,
-                                         build (NE_EXPR, integer_type_node,
-                                                allocated_this, integer_zero_node),
-                                         build_compound_expr (cleanup),
-                                         integer_zero_node));
-           }
        }
 
       CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
@@ -11315,8 +11545,6 @@ finish_function (lineno, call_poplevel)
        {
          expand_start_cond (cond, 0);
          expand_expr_stmt (thenclause);
-         if (flag_handle_exceptions == 2)
-           expand_assignment (allocated_this, current_class_decl, 0, 0);
          expand_end_cond ();
        }
 
@@ -11346,21 +11574,16 @@ finish_function (lineno, call_poplevel)
       if (mark != get_last_insn ())
        reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
 
+      end_protect_partials ();
+
       /* This is where the body of the constructor ends.  */
       expand_label (ctor_label);
       ctor_label = NULL_TREE;
-      if (flag_handle_exceptions == 2)
-       {
-         expand_assignment (allocated_this, integer_zero_node, 0, 0);
-         if (call_poplevel)
-           deactivate_exception_cleanups ();
-       }
-
-      pop_implicit_try_blocks (NULL_TREE);
 
       if (call_poplevel)
        {
-         expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0);
+         decls = getdecls ();
+         expand_end_bindings (decls, decls != NULL_TREE, 0);
          poplevel (decls != NULL_TREE, 1, 0);
        }
 
@@ -11434,19 +11657,6 @@ finish_function (lineno, call_poplevel)
     /* Emit label at beginning of cleanup code for parameters.  */
     emit_label (cleanup_label);
 
-#if 1
-  /* Cheap hack to get better code from GNU C++.  Remove when cse is fixed.  */
-  if (exception_throw_decl && sets_exception_throw_decl == 0)
-    expand_assignment (exception_throw_decl, integer_zero_node, 0, 0);
-#endif
-
-  if (flag_handle_exceptions)
-    {
-      expand_end_try ();
-      expand_start_except (0, 0);
-      expand_end_except ();
-    }
-
   /* Get return value into register if that's where it's supposed to be.  */
   if (original_result_rtx)
     fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx);
@@ -11463,6 +11673,19 @@ finish_function (lineno, call_poplevel)
       expand_label (no_return_label);
     }
 
+  /* Generate rtl for function exit.  */
+  expand_function_end (input_filename, lineno, 1);
+
+  if (flag_handle_exceptions)
+    expand_exception_blocks();
+
+  /* This must come after expand_function_end because cleanups might
+     have declarations (from inline functions) that need to go into
+     this function's blocks.  */
+  if (current_binding_level->parm_flag != 1)
+    my_friendly_abort (122);
+  poplevel (1, 0, 1);
+
   /* reset scope for C++: if we were in the scope of a class,
      then when we finish this function, we are not longer so.
      This cannot be done until we know for sure that no more
@@ -11476,25 +11699,6 @@ finish_function (lineno, call_poplevel)
   else
     pop_memoized_context (1);
 
-  /* Forget about all overloaded functions defined in
-     this scope which go away.  */
-  while (overloads_to_forget)
-    {
-      IDENTIFIER_GLOBAL_VALUE (TREE_PURPOSE (overloads_to_forget))
-       = TREE_VALUE (overloads_to_forget);
-      overloads_to_forget = TREE_CHAIN (overloads_to_forget);
-    }
-
-  /* Generate rtl for function exit.  */
-  expand_function_end (input_filename, lineno, 1);
-
-  /* This must come after expand_function_end because cleanups might
-     have declarations (from inline functions) that need to go into
-     this function's blocks.  */
-  if (current_binding_level->parm_flag != 1)
-    my_friendly_abort (122);
-  poplevel (1, 0, 1);
-
   /* Must mark the RESULT_DECL as being in this function.  */
   DECL_CONTEXT (DECL_RESULT (fndecl)) = DECL_INITIAL (fndecl);
 
@@ -11509,39 +11713,17 @@ finish_function (lineno, call_poplevel)
   /* So we can tell if jump_optimize sets it to 1.  */
   can_reach_end = 0;
 
-  /* ??? Compensate for Sun brain damage in dealing with data segments
-     of PIC code.  */
-  if (flag_pic
-      && (DECL_CONSTRUCTOR_P (fndecl)
-         || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
-      && CLASSTYPE_NEEDS_VIRTUAL_REINIT (TYPE_METHOD_BASETYPE (fntype)))
-    DECL_INLINE (fndecl) = 0;
-
-  if (DECL_EXTERNAL (fndecl)
-      /* This function is just along for the ride.  If we can make
-        it inline, that's great.  Otherwise, just punt it.  */
-      && (DECL_INLINE (fndecl) == 0
-         || flag_no_inline
-         || function_cannot_inline_p (fndecl)))
-    {
-      extern int rtl_dump_and_exit;
-      int old_rtl_dump_and_exit = rtl_dump_and_exit;
-      int inline_spec = DECL_INLINE (fndecl);
-
-      /* This throws away the code for FNDECL.  */
-      rtl_dump_and_exit = 1;
-      /* This throws away the memory of the code for FNDECL.  */
-      if (flag_no_inline)
-       DECL_INLINE (fndecl) = 0;
-      rest_of_compilation (fndecl);
-      rtl_dump_and_exit = old_rtl_dump_and_exit;
-      DECL_INLINE (fndecl) = inline_spec;
-    }
-  else
+  /* Run the optimizers and output the assembler code for this function.  */
+  rest_of_compilation (fndecl);
+
+  if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl))
     {
-      /* Run the optimizers and output the assembler code for this
-         function.  */
-      rest_of_compilation (fndecl);
+      /* Set DECL_EXTERNAL so that assemble_external will be called as
+         necessary.  We'll clear it again in finish_file.  */
+      if (! DECL_EXTERNAL (fndecl))
+       DECL_NOT_REALLY_EXTERN (fndecl) = 1;
+      DECL_EXTERNAL (fndecl) = 1;
+      mark_inline_for_output (fndecl);
     }
 
   if (ctype && TREE_ASM_WRITTEN (fndecl))
@@ -11576,7 +11758,8 @@ finish_function (lineno, call_poplevel)
   /* Free all the tree nodes making up this function.  */
   /* Switch back to allocating nodes permanently
      until we start another function.  */
-  permanent_allocation (1);
+  if (! nested)
+    permanent_allocation (1);
 
   if (flag_cadillac)
     cadillac_finish_function (fndecl);
@@ -11592,8 +11775,19 @@ finish_function (lineno, call_poplevel)
        DECL_ARGUMENTS (fndecl) = NULL_TREE;
     }
 
-  /* Let the error reporting routines know that we're outside a function.  */
-  current_function_decl = NULL_TREE;
+  if (DECL_STATIC_CONSTRUCTOR (fndecl))
+    static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors);
+  if (DECL_STATIC_DESTRUCTOR (fndecl))
+    static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors);
+
+  if (! nested)
+    {
+      /* Let the error reporting routines know that we're outside a
+         function.  For a nested function, this value is used in
+         pop_cp_function_context and then reset via pop_function_context.  */
+      current_function_decl = NULL_TREE;
+    }
+
   named_label_uses = NULL_TREE;
 }
 \f
@@ -11655,12 +11849,17 @@ start_method (declspecs, declarator, raises)
       return void_type_node;
     }
 
-  /* If we're expanding a template, a function must be explicitly declared
-     inline if we're to compile it now.  If it isn't, we have to wait to see
-     whether it's needed, and whether an override exists.  */
-  if (flag_default_inline && !processing_template_defn)
+  DECL_THIS_INLINE (fndecl) = 1;
+
+  if (flag_default_inline)
     DECL_INLINE (fndecl) = 1;
 
+  if (processing_template_defn)
+    {
+      SET_DECL_IMPLICIT_INSTANTIATION (fndecl);
+      repo_template_used (fndecl);
+    }
+
   /* We read in the parameters on the maybepermanent_obstack,
      but we won't be getting back to them until after we
      may have clobbered them.  So the call to preserve_data
@@ -11684,12 +11883,15 @@ start_method (declspecs, declarator, raises)
        }
 
       if (DECL_CONSTRUCTOR_P (fndecl))
-       grok_ctor_properties (current_class_type, fndecl);
+       {
+         if (! grok_ctor_properties (current_class_type, fndecl))
+           return void_type_node;
+       }
       else if (IDENTIFIER_OPNAME_P (DECL_NAME (fndecl)))
        grok_op_properties (fndecl, DECL_VIRTUAL_P (fndecl), 0);
     }
 
-  finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
+  finish_decl (fndecl, NULL_TREE, NULL_TREE, 0, 0);
 
   /* Make a place for the parms */
   pushlevel (0);
@@ -11717,7 +11919,6 @@ finish_method (decl)
 {
   register tree fndecl = decl;
   tree old_initial;
-  tree context = DECL_CONTEXT (fndecl);
 
   register tree link;
 
@@ -11813,12 +12014,18 @@ hack_incomplete_structures (type)
            rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
            if (! toplevel)
              {
+               tree cleanup;
                expand_decl (decl);
-               expand_decl_cleanup (decl, maybe_build_cleanup (decl));
+               cleanup = maybe_build_cleanup (decl);
                expand_decl_init (decl);
+               if (! expand_decl_cleanup (decl, cleanup))
+                 cp_error ("parser lost in parsing declaration of `%D'",
+                           decl);
              }
          }
+       /*
        my_friendly_assert (current_binding_level->n_incomplete > 0, 164);
+       */
        --current_binding_level->n_incomplete;
       }
 }
@@ -11866,11 +12073,6 @@ maybe_build_cleanup (decl)
          || flag_expensive_optimizations)
        flags |= LOOKUP_NONVIRTUAL;
 
-      /* Use TYPE_MAIN_VARIANT so we don't get a warning about
-        calling delete on a `const' variable.  */
-      if (TYPE_READONLY (TREE_TYPE (TREE_TYPE (rval))))
-       rval = build1 (NOP_EXPR, TYPE_POINTER_TO (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (rval)))), rval);
-
       rval = build_delete (TREE_TYPE (rval), rval, integer_two_node, flags, 0);
 
       if (TYPE_USES_VIRTUAL_BASECLASSES (type)
@@ -11878,9 +12080,6 @@ maybe_build_cleanup (decl)
        rval = build_compound_expr (tree_cons (NULL_TREE, rval,
                                               build_tree_list (NULL_TREE, build_vbase_delete (type, decl))));
 
-      current_binding_level->have_cleanups = 1;
-      current_binding_level->more_exceptions_ok = 0;
-
       if (TREE_CODE (decl) != PARM_DECL)
        resume_momentary (temp);
 
@@ -11920,27 +12119,13 @@ cplus_expand_expr_stmt (exp)
          cp_warning ("reference, not call, to function `%D'", exp);
          warning ("at this point in file");
        }
-      if (TREE_RAISES (exp))
-       {
-         my_friendly_assert (flag_handle_exceptions, 165);
-         if (flag_handle_exceptions == 2)
-           {
-             if (! current_binding_level->more_exceptions_ok)
-               {
-                 extern struct nesting *nesting_stack, *block_stack;
-
-                 remove_implicit_immediately
-                   = (nesting_stack != block_stack);
-                 cplus_expand_start_try (1);
-               }
-             current_binding_level->have_exceptions = 1;
-           }
-       }
 
+#if 0
+      /* We should do this eventually, but right now this causes regex.o from
+        libg++ to miscompile, and tString to core dump.  */
+      exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
+#endif
       expand_expr_stmt (break_out_cleanups (exp));
-
-      if (remove_implicit_immediately)
-       pop_implicit_try_blocks (NULL_TREE);
     }
 
   /* Clean up any pending cleanups.  This happens when a function call
@@ -11978,110 +12163,149 @@ finish_stmt ()
     cadillac_finish_stmt ();
 }
 
+/* Change a static member function definition into a FUNCTION_TYPE, instead
+   of the METHOD_TYPE that we create when it's originally parsed.
+
+   WARNING: DO NOT pass &TREE_TYPE (decl) to FN or &TYPE_ARG_TYPES
+   (TREE_TYPE (decl)) to ARGTYPES, as doing so will corrupt the types of
+   other decls.  Either pass the addresses of local variables or NULL.  */
+
 void
-pop_implicit_try_blocks (decl)
-     tree decl;
+revert_static_member_fn (decl, fn, argtypes)
+     tree *decl, *fn, *argtypes;
 {
-  if (decl)
-    {
-      my_friendly_assert (current_binding_level->parm_flag == 3, 166);
-      current_binding_level->names = TREE_CHAIN (decl);
-    }
-
-  while (current_binding_level->parm_flag == 3)
-    {
-      tree name = get_identifier ("(compiler error)");
-      tree orig_ex_type = current_exception_type;
-      tree orig_ex_decl = current_exception_decl;
-      tree orig_ex_obj = current_exception_object;
-      tree decl = cplus_expand_end_try (2);
+  tree tmp;
+  tree function = fn ? *fn : TREE_TYPE (*decl);
+  tree args = argtypes ? *argtypes : TYPE_ARG_TYPES (function);
 
-      /* @@ It would be nice to make all these point
-        to exactly the same handler.  */
-      /* Start hidden EXCEPT.  */
-      cplus_expand_start_except (name, decl);
-      /* reraise ALL.  */
-      cplus_expand_reraise (NULL_TREE);
-      current_exception_type = orig_ex_type;
-      current_exception_decl = orig_ex_decl;
-      current_exception_object = orig_ex_obj;
-      /* This will reraise for us.  */
-      cplus_expand_end_except (error_mark_node);
-    }
+  args = TREE_CHAIN (args);
+  tmp = build_function_type (TREE_TYPE (function), args);
+  tmp = build_type_variant (tmp, TYPE_READONLY (function),
+                           TYPE_VOLATILE (function));
+  tmp = build_exception_variant (TYPE_METHOD_BASETYPE (function), tmp,
+                                TYPE_RAISES_EXCEPTIONS (function));
+  TREE_TYPE (*decl) = tmp;
+  DECL_STATIC_FUNCTION_P (*decl) = 1;
+  if (fn)
+    *fn = tmp;
+  if (argtypes)
+    *argtypes = args;
+}
 
-  if (decl)
-    {
-      TREE_CHAIN (decl) = current_binding_level->names;
-      current_binding_level->names = decl;
-    }
+int
+id_in_current_class (id)
+     tree id;
+{
+  return !!purpose_member (id, class_binding_level->class_shadowed);
 }
 
-/* Push a cleanup onto the current binding contour that will cause
-   ADDR to be cleaned up, in the case that an exception propagates
-   through its binding contour.  */
+struct cp_function
+{
+  int returns_value;
+  int returns_null;
+  int warn_about_return_type;
+  int assigns_this;
+  int just_assigned_this;
+  int parms_stored;
+  int temp_name_counter;
+  tree named_labels;
+  tree shadowed_labels;
+  tree ctor_label;
+  tree dtor_label;
+  tree protect_list;
+  tree base_init_list;
+  tree member_init_list;
+  rtx result_rtx;
+  rtx base_init_insns;
+  struct cp_function *next;
+  struct binding_level *binding_level;
+};
+
+struct cp_function *cp_function_chain;
+
+extern int temp_name_counter;
+
+/* Save and reinitialize the variables
+   used during compilation of a C++ function.  */
 
 void
-push_exception_cleanup (addr)
-     tree addr;
+push_cp_function_context (context)
+     tree context;
 {
-  tree decl = build_decl (VAR_DECL, get_identifier (EXCEPTION_CLEANUP_NAME), ptr_type_node);
-  tree cleanup;
-
-  decl = pushdecl (decl);
-  DECL_REGISTER (decl) = 1;
-  store_init_value (decl, addr);
-  expand_decl (decl);
-  expand_decl_init (decl);
-
-  cleanup = build (COND_EXPR, integer_type_node,
-                  build (NE_EXPR, integer_type_node,
-                         decl, integer_zero_node),
-                  build_delete (TREE_TYPE (addr), decl,
-                                lookup_name (in_charge_identifier, 0),
-                                LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
-                  integer_zero_node);
-  expand_decl_cleanup (decl, cleanup);
+  struct cp_function *p
+    = (struct cp_function *) xmalloc (sizeof (struct cp_function));
+
+  push_function_context_to (context);
+
+  p->next = cp_function_chain;
+  cp_function_chain = p;
+
+  p->named_labels = named_labels;
+  p->shadowed_labels = shadowed_labels;
+  p->returns_value = current_function_returns_value;
+  p->returns_null = current_function_returns_null;
+  p->warn_about_return_type = warn_about_return_type;
+  p->binding_level = current_binding_level;
+  p->ctor_label = ctor_label;
+  p->dtor_label = dtor_label;
+  p->assigns_this = current_function_assigns_this;
+  p->just_assigned_this = current_function_just_assigned_this;
+  p->parms_stored = current_function_parms_stored;
+  p->result_rtx = original_result_rtx;
+  p->base_init_insns = base_init_insns;
+  p->protect_list = protect_list;
+  p->temp_name_counter = temp_name_counter;
+  p->base_init_list = current_base_init_list;
+  p->member_init_list = current_member_init_list;
 }
 
-/* For each binding contour, emit code that deactivates the
-   exception cleanups.  All other cleanups are left as they were.  */
+/* Restore the variables used during compilation of a C++ function.  */
 
-static void
-deactivate_exception_cleanups ()
+void
+pop_cp_function_context (context)
+     tree context;
 {
-  struct binding_level *b = current_binding_level;
-  tree xyzzy = get_identifier (EXCEPTION_CLEANUP_NAME);
-  while (b != class_binding_level)
+  struct cp_function *p = cp_function_chain;
+  tree link;
+
+  /* Bring back all the labels that were shadowed.  */
+  for (link = shadowed_labels; link; link = TREE_CHAIN (link))
+    if (DECL_NAME (TREE_VALUE (link)) != 0)
+      SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)),
+                                 TREE_VALUE (link));
+
+#if 0
+  if (DECL_SAVED_INSNS (current_function_decl) == 0)
     {
-      if (b->parm_flag == 3)
-       {
-         tree decls = b->names;
-         while (decls)
-           {
-             if (DECL_NAME (decls) == xyzzy)
-               expand_assignment (decls, integer_zero_node, 0, 0);
-             decls = TREE_CHAIN (decls);
-           }
-       }
-      b = b->level_chain;
+      /* Stop pointing to the local nodes about to be freed.  */
+      /* But DECL_INITIAL must remain nonzero so we know this
+        was an actual function definition.  */
+      DECL_INITIAL (current_function_decl) = error_mark_node;
+      DECL_ARGUMENTS (current_function_decl) = 0;
     }
-}
-
-/* Change a static member function definition into a FUNCTION_TYPE, instead
-   of the METHOD_TYPE that we create when it's originally parsed.  */
-void
-revert_static_member_fn (fn, decl, argtypes)
-     tree *fn, *decl, *argtypes;
-{
-  tree tmp, function = *fn;
+#endif
 
-  *argtypes = TREE_CHAIN (*argtypes);
-  tmp = build_function_type (TREE_TYPE (function), *argtypes);
-  tmp = build_type_variant (tmp, TYPE_READONLY (function),
-                           TYPE_VOLATILE (function));
-  tmp = build_exception_variant (TYPE_METHOD_BASETYPE (function), tmp,
-                                TYPE_RAISES_EXCEPTIONS (function));
-  TREE_TYPE (*decl) = tmp;
-  *fn = tmp;
-  DECL_STATIC_FUNCTION_P (*decl) = 1;
+  pop_function_context_from (context);
+
+  cp_function_chain = p->next;
+
+  named_labels = p->named_labels;
+  shadowed_labels = p->shadowed_labels;
+  current_function_returns_value = p->returns_value;
+  current_function_returns_null = p->returns_null;
+  warn_about_return_type = p->warn_about_return_type;
+  current_binding_level = p->binding_level;
+  ctor_label = p->ctor_label;
+  dtor_label = p->dtor_label;
+  protect_list = p->protect_list;
+  current_function_assigns_this = p->assigns_this;
+  current_function_just_assigned_this = p->just_assigned_this;
+  current_function_parms_stored = p->parms_stored;
+  original_result_rtx = p->result_rtx;
+  base_init_insns = p->base_init_insns;
+  temp_name_counter = p->temp_name_counter;
+  current_base_init_list = p->base_init_list;
+  current_member_init_list = p->member_init_list;
+
+  free (p);
 }