OSDN Git Service

Fix typos in comments.
[pf3gnuchains/gcc-fork.git] / gcc / cp / decl.c
index 4bbfec9..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.
@@ -49,6 +49,8 @@ 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
@@ -93,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,
@@ -111,17 +121,6 @@ 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));
@@ -162,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;
@@ -205,7 +206,7 @@ tree int_array_type_node;
 tree wchar_array_type_node;
 
 /* The bool data type, and constants */
-tree bool_type_node, true_node, false_node;
+tree boolean_type_node, boolean_true_node, boolean_false_node;
 
 /* type `int ()' -- used for implicit declaration of functions.  */
 
@@ -232,11 +233,27 @@ 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;
@@ -244,15 +261,6 @@ tree maybe_gc_cleanup;
 /* 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.  */
 
@@ -398,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;
@@ -410,7 +414,13 @@ extern int flag_short_double;
 
 extern int flag_no_builtin;
 
-/* Nonzero means disable GNU extensions.  */
+/* Nonzero means don't recognize the non-ANSI builtin functions.
+   -ansi sets this.  */
+
+extern int flag_no_nonansi_builtin;
+
+/* Nonzero means enable obscure ANSI features and disable GNU extensions
+   that might cause ANSI-compliant code to be miscompiled.  */
 
 extern int flag_ansi;
 
@@ -420,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;
 
@@ -538,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.
@@ -918,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,
@@ -1212,9 +1223,9 @@ poplevel_class (force)
   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 || force)
     for (shadowed = level->class_shadowed;
@@ -1428,6 +1439,7 @@ 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;
@@ -1504,6 +1516,8 @@ 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;
@@ -1556,6 +1570,8 @@ 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;
@@ -1619,27 +1635,46 @@ 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);
-      TREE_MANGLED (DECL_NESTED_TYPENAME (decl)) = 1;
-
-      /* 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.  */
@@ -1694,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. */
 
@@ -1724,17 +1759,16 @@ pushtag (name, type, globalize)
         context = current_scope ();
       if (context)
        c_decl = TREE_CODE (context) == FUNCTION_DECL
-         ? context : TYPE_NAME (context);
+         ? 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;
@@ -1752,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)
                    {
@@ -1767,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);
@@ -1787,6 +1819,7 @@ pushtag (name, type, globalize)
              /* Make nested declarations go into class-level scope.  */
              newdecl = 1;
              d = build_decl (TYPE_DECL, name, type);
+             SET_DECL_ARTIFICIAL (d);
 #ifdef DWARF_DEBUGGING_INFO
              if (write_symbols == DWARF_DEBUG)
                {
@@ -1797,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
@@ -1807,38 +1843,31 @@ pushtag (name, type, globalize)
              if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
                popclass (0);
            }
-         if (write_symbols != DWARF_DEBUG)
+         if (newdecl)
            {
-             if (ANON_AGGRNAME_P (name))
-               DECL_IGNORED_P (d) = 1;
-           }
-         TYPE_NAME (type) = d;
+             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);
 
-         if (context == NULL_TREE)
-           /* Non-nested class.  */
-           DECL_NESTED_TYPENAME (d) = name;
-         else if (context && TREE_CODE (context) == FUNCTION_DECL)
-           {
-             /* Function-nested class.  */
-             set_nested_typename (d, DECL_ASSEMBLER_NAME (c_decl),
-                                  name, type);
-             /* This builds the links for classes nested in fn scope.  */
-             DECL_CONTEXT (d) = context;
-           }
-/*        else if (TYPE_SIZE (current_class_type) == NULL_TREE)
-*/
-         else if (context && IS_AGGR_TYPE (context))
-           {
-             /* Class-nested class.  */
-             set_nested_typename (d, DECL_NESTED_TYPENAME (c_decl),
-                                  name, type);
-             /* This builds the links for classes nested in type scope.  */
              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)
        {
@@ -1920,7 +1949,7 @@ 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;
 {
@@ -1990,11 +2019,11 @@ decls_match (newdecl, olddecl)
        
        for (i = 0; i < len; i++)
          {
-           tree newarg = TREE_VEC_ELT (newargs, i);
-           tree oldarg = TREE_VEC_ELT (oldargs, 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) == IDENTIFIER_NODE)
+           else if (TREE_CODE (newarg) == TYPE_DECL)
              /* continue */;
            else if (! comptypes (TREE_TYPE (newarg), TREE_TYPE (oldarg), 1))
              return 0;
@@ -2049,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.  */
@@ -2091,6 +2118,9 @@ duplicate_decls (newdecl, olddecl)
   int new_defines_function;
   tree previous_c_decl = NULL_TREE;
 
+  if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd')
+    DECL_MACHINE_ATTRIBUTES (newdecl) = DECL_MACHINE_ATTRIBUTES (olddecl);
+
   types_match = decls_match (newdecl, olddecl);
 
   if (TREE_CODE (olddecl) != TREE_LIST)
@@ -2113,12 +2143,13 @@ duplicate_decls (newdecl, olddecl)
        after implicit decl.  */
     ;
   else if (TREE_CODE (olddecl) == FUNCTION_DECL
+          && 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.  Ditto for overloads.  */
-      if (! TREE_PUBLIC (newdecl)
+      if (! DECL_PUBLIC (newdecl)
          || (TREE_CODE (newdecl) == FUNCTION_DECL
              && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)))
        {
@@ -2197,9 +2228,8 @@ duplicate_decls (newdecl, olddecl)
                        newdecl);
              cp_error_at ("previous declaration `%#D' here", olddecl);
            }
-
-         if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
-                        TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 2))
+         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);
@@ -2212,12 +2242,7 @@ duplicate_decls (newdecl, olddecl)
       else if (current_class_type == NULL_TREE
          || IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl)) != current_class_type)
        {
-         /* 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);
+         cp_error ("conflicting types for `%#D'", newdecl);
          cp_error_at ("previous declaration as `%#D'", olddecl);
        }
     }
@@ -2259,12 +2284,50 @@ duplicate_decls (newdecl, 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 (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);
+                 }
+             }
+
+         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,
@@ -2290,6 +2353,9 @@ duplicate_decls (newdecl, olddecl)
        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.  */
@@ -2298,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))
        {
@@ -2332,7 +2400,7 @@ duplicate_decls (newdecl, olddecl)
       && !(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
@@ -2342,13 +2410,10 @@ duplicate_decls (newdecl, olddecl)
     {
       /* Automatically handles default parameters.  */
       tree oldtype = TREE_TYPE (olddecl);
-      /* Merge the data types specified in the two decls.  */
-      tree newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
+      tree newtype;
 
-      /* Make sure we put the new type in the same obstack as the old ones.
-        If the old types are not both in the same obstack, use the permanent
-        one.  */
-      if (oldtype && TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (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
        {
@@ -2356,6 +2421,9 @@ duplicate_decls (newdecl, olddecl)
          end_temporary_allocation ();
        }
 
+      /* Merge the data types specified in the two decls.  */
+      newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
+
       if (TREE_CODE (newdecl) == VAR_DECL)
        DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl);
       /* Do this after calling `common_type' so that default
@@ -2373,7 +2441,7 @@ duplicate_decls (newdecl, olddecl)
 
          if (! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0))
            {
-             cp_error ("declaration of `%D' raises different exceptions...",
+             cp_error ("declaration of `%D' throws different exceptions...",
                        newdecl);
              cp_error_at ("...from previous declaration here", olddecl);
            }
@@ -2381,21 +2449,16 @@ duplicate_decls (newdecl, 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
-             && TREE_CODE (newdecl) != TEMPLATE_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))
@@ -2444,47 +2507,47 @@ 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);
 
-      if (TREE_CODE (newdecl) != FUNCTION_DECL)
-       TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
+      if (TREE_CODE (newdecl) == FUNCTION_DECL)
+       {
+         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_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;
-      else if (TREE_CODE (newdecl) != FUNCTION_DECL)
-       TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+      else
+       {
+         TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+
+         /* 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;
+       }
     }
 
-  /* 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_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 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 (TREE_CODE (newdecl) == FUNCTION_DECL)
-    {
       if (! types_match)
        {
          DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl);
@@ -2521,6 +2584,8 @@ 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)
@@ -2530,12 +2595,15 @@ duplicate_decls (newdecl, 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.  */
@@ -2543,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)
@@ -2653,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
 
@@ -2685,9 +2754,18 @@ pushdecl (x)
                   && ! DECL_TEMPLATE_IS_CLASS (x)))
              && is_overloaded_fn (t))
            /* don't do anything just yet */;
+         else if (t == wchar_decl_node)
+           {
+             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 (TREE_CODE (t) != TREE_CODE (x))
            {
-             if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (x) == TYPE_DECL)
+             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
@@ -2766,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
@@ -2777,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)
@@ -2834,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.  */
@@ -2873,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)
@@ -2883,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_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,
@@ -2975,11 +3037,25 @@ 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.  */
@@ -2990,15 +3066,16 @@ pushdecl (x)
          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 (! TREE_MANGLED (name))
-           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");
        }
     }
 
@@ -3126,7 +3203,11 @@ pushdecl_class_level (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));
        }
     }
@@ -3165,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),
@@ -3248,17 +3333,12 @@ push_overloaded_decl (decl, forgettable)
        old = TREE_OPERAND (old, 0);
       else
 #endif
-      if (TREE_CODE (old) == VAR_DECL)
-       {
-         cp_error_at ("previous non-function declaration `%#D'", old);
-         cp_error ("conflicts with function declaration `%#D'", decl);
-         return error_mark_node;
-       }
-      else if (TREE_CODE (old) == TYPE_DECL)
+      if (TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old))
        {
          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 (old))
         {
@@ -3268,6 +3348,12 @@ push_overloaded_decl (decl, forgettable)
            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 (old || TREE_CODE (decl) == TEMPLATE_DECL)
@@ -3366,34 +3452,18 @@ 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 "`%#D' not declared in class";
          else
            return "redefinition of `%#D'";
        }
-
-      {
-       tree t1 = TYPE_ARG_TYPES (TREE_TYPE (olddecl));
-       tree t2 = TYPE_ARG_TYPES (TREE_TYPE (newdecl));
-
-       if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE)
-         t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2);
-       
-       for (; t1; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
-         if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
-           return "duplicate default arguments given for `%#D'";
-      }
       return 0;
     }
   else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
@@ -3405,13 +3475,12 @@ redeclaration_error_message (newdecl, olddecl)
   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;
-      /* 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 `%#D'";
       /* Reject two definitions.  */
       return "redefinition of `%#D'";
     }
@@ -3532,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);
@@ -3540,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;
@@ -3570,10 +3643,11 @@ define_label (filename, line, name)
                             && 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);
                  }
@@ -3592,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
@@ -3599,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.  */
 
@@ -3863,9 +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);
        }
@@ -3890,41 +4015,50 @@ lookup_name_real (name, 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 (got_scope != NULL_TREE)
+      if (type)
        {
-         if (got_scope == void_type_node)
+         if (type == error_mark_node)
+           return error_mark_node;
+         else if (type == void_type_node)
            val = IDENTIFIER_GLOBAL_VALUE (name);
-         else if (TREE_CODE (got_scope) == TEMPLATE_TYPE_PARM
+         else if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
                   /* TFIXME -- don't do this for UPTs in new model.  */
-                  || TREE_CODE (got_scope) == UNINSTANTIATED_P_TYPE)
+                  || TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
            {
              if (prefer_type > 0)
-               val = create_nested_upt (got_scope, name);
+               val = create_nested_upt (type, name);
              else
                val = NULL_TREE;
            }
-         else if (! IS_AGGR_TYPE (got_scope))
+         else if (! IS_AGGR_TYPE (type))
            /* Someone else will give an error about this if needed. */
            val = NULL_TREE;
-         else if (TYPE_BEING_DEFINED (got_scope))
+         else if (TYPE_BEING_DEFINED (type))
            {
              val = IDENTIFIER_CLASS_VALUE (name);
-             if (val && DECL_CONTEXT (val) != got_scope)
+             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)) == got_scope)
+                         && DECL_CONTEXT (TREE_VALUE (t)) == type)
                        {
                          val = TREE_VALUE (t);
                          break;
@@ -3932,16 +4066,23 @@ lookup_name_real (name, prefer_type, nonclass)
                    }
                }
              if (val == NULL_TREE
-                 && CLASSTYPE_LOCAL_TYPEDECLS (got_scope))
-               val = lookup_field (got_scope, name, 0, 1);
+                 && CLASSTYPE_LOCAL_TYPEDECLS (type))
+               val = lookup_field (type, name, 0, 1);
            }
-         else if (got_scope == current_class_type)
+         else if (type == current_class_type)
            val = IDENTIFIER_CLASS_VALUE (name);
          else
-           val = lookup_field (got_scope, name, 0, 0);
-
-         goto done;
+           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
@@ -3975,16 +4116,20 @@ lookup_name_real (name, prefer_type, nonclass)
  done:
   if (val)
     {
+      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 ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template)
          || TREE_CODE (val) == TYPE_DECL || prefer_type <= 0)
-       return val;
-
-      if (IDENTIFIER_HAS_TYPE_VALUE (name))
-       return TYPE_NAME (IDENTIFIER_TYPE_VALUE (name));
-
-      if (TREE_TYPE (val) == error_mark_node)
-       return error_mark_node;
+       ;
+      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;
 }
@@ -4026,7 +4171,7 @@ lookup_name_current_level (name)
       while (1)
        {
          for (t = b->names; t; t = TREE_CHAIN (t))
-           if (DECL_NAME (t) == name)
+           if (DECL_NAME (t) == name || DECL_ASSEMBLER_NAME (t) == name)
              goto out;
          if (b->keep == 2)
            b = b->level_chain;
@@ -4122,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)
        {
@@ -4137,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));
        }
     }
 }
@@ -4180,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.
@@ -4202,13 +4363,19 @@ 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_ansi || pedantic)
-    strict_prototypes_lang_c = strict_prototypes_lang_cplusplus;
+  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;
@@ -4242,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));
@@ -4376,15 +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);
 
-  bool_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
-  TREE_SET_CODE (bool_type_node, BOOLEAN_TYPE);
-  record_builtin_type (RID_BOOL, "bool", bool_type_node);
-  false_node = build_int_2 (0, 0);
-  TREE_TYPE (false_node) = bool_type_node;
-  true_node = build_int_2 (1, 0);
-  TREE_TYPE (true_node) = bool_type_node;
+  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);
@@ -4549,14 +4715,29 @@ init_decl_processing ()
                                                    sizetype,
                                                    endlink)),
                    BUILT_IN_ALLOCA, "alloca");
-#if 0
-  builtin_function ("alloca",
-                   build_function_type (ptr_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   sizetype,
-                                                   endlink)),
-                   BUILT_IN_ALLOCA, NULL_PTR);
-#endif
+  /* 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);
@@ -4656,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
@@ -4717,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);
@@ -4767,7 +4970,7 @@ init_decl_processing ()
   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
@@ -4791,7 +4994,8 @@ init_decl_processing ()
       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:
 
@@ -4902,9 +5106,7 @@ init_decl_processing ()
                           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)
@@ -4914,6 +5116,10 @@ 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,
@@ -4937,7 +5143,7 @@ init_decl_processing ()
                 NOT_BUILT_IN);
 
   abort_fndecl
-    = define_function ("abort",
+    = define_function ("__pure_virtual",
                       build_function_type (void_type_node, void_list_node),
                       NOT_BUILT_IN, 0, 0);
 
@@ -4954,7 +5160,7 @@ init_decl_processing ()
     {
       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
     }
@@ -4968,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.
@@ -4987,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
@@ -5019,7 +5295,6 @@ shadow_tag (declspecs)
      tree declspecs;
 {
   int found_tag = 0;
-  int warned = 0;
   tree ob_modifier = NULL_TREE;
   register tree link;
   register enum tree_code code, ok_code = ERROR_MARK;
@@ -5032,46 +5307,22 @@ shadow_tag (declspecs)
       code = TREE_CODE (value);
       if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE)
        {
-         register tree name = TYPE_NAME (value);
+         my_friendly_assert (TYPE_NAME (value) != NULL_TREE, 261);
 
          if (code == ENUMERAL_TYPE && TYPE_SIZE (value) == 0)
            cp_error ("forward declaration of `%#T'", 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);
-
-         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;
-           }
-         else if (name != NULL_TREE || code == ENUMERAL_TYPE)
-           ok_code = code;
-
-         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]
               || value == ridpointers[(int) RID_AUTO]
-              || value == ridpointers[(int) RID_REGISTER])
+              || value == ridpointers[(int) RID_REGISTER]
+              || value == ridpointers[(int) RID_INLINE]
+              || value == ridpointers[(int) RID_VIRTUAL]
+              || value == ridpointers[(int) RID_EXPLICIT])
        ob_modifier = value;
     }
 
@@ -5102,36 +5353,23 @@ shadow_tag (declspecs)
     {
       /* Anonymous unions are objects, that's why we only check for
         inappropriate specifiers in this branch.  */
-      if (ob_modifier)
-       cp_error ("`%D' can only be specified for objects and functions",
-                 ob_modifier);
 
-      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);
+           cp_error ("`%D' can only be specified for objects and functions",
+                     ob_modifier);
+       }
 
-             ename = TYPE_NAME (t);
-             if (TREE_CODE (ename) == TYPE_DECL)
-               ename = DECL_NAME (ename);
-             decl = build_lang_field_decl (VAR_DECL, ename, t);
-
-             pop_obstacks ();
-           }
-       }
-      else if (found_tag == 0)
+      if (found_tag == 0)
        pedwarn ("abstract declarator used as declaration");
-      else if (!warned && found_tag > 1)
+      else if (found_tag > 1)
        pedwarn ("multiple types in one declaration");
     }
 }
@@ -5216,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 ();
 
@@ -5261,11 +5494,7 @@ 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)));
@@ -5273,17 +5502,6 @@ start_decl (declarator, declspecs, initialized, raises)
       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.  */
@@ -5375,9 +5593,30 @@ 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)
@@ -5385,8 +5624,14 @@ start_decl (declarator, declspecs, initialized, raises)
   else
     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++.  */
@@ -5540,7 +5785,7 @@ 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 ();
@@ -5556,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)
@@ -5585,64 +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. */
+  tmp = convert_to_reference
+    (type, init, CONV_IMPLICIT, LOOKUP_SPECULATIVELY|LOOKUP_NORMAL, decl);
 
-      /* 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
-           (type, init, CONV_IMPLICIT,
-            LOOKUP_SPECULATIVELY|LOOKUP_NORMAL, decl)))
+  if (tmp == error_mark_node)
+    goto fail;
+  else if (tmp != NULL_TREE)
     {
-      if (actual_init == error_mark_node)
-       goto fail;
+      tree subtype = TREE_TYPE (type);
+      init = tmp;
 
-      init = actual_init;
-      is_reference = 1;
-
-      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
     {
@@ -5650,55 +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);
-
   /* ?? Can this be optimized in some cases to
      hand back the DECL_INITIAL slot??  */
   if (TYPE_SIZE (TREE_TYPE (type)))
@@ -5722,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,
@@ -5736,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;
@@ -5774,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.  */
@@ -5798,12 +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))
-    {
-      CLASSTYPE_GOT_SEMICOLON (type) = 1;
-      goto finish_end;
-    }
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
       ttype = target_type (type);
@@ -5851,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);
@@ -5868,6 +6079,10 @@ 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;
     }
@@ -5892,8 +6107,7 @@ 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))
                {
@@ -5945,38 +6159,18 @@ 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))
     ;
@@ -6001,28 +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.  Consts have to go
-        into data, though, since the backend would put them in text
-        otherwise.  */
-      if (flag_pic == 0
-         && TREE_STATIC (decl)
-         && (TREE_PUBLIC (decl) || was_readonly)
-         && ! 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
@@ -6114,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)))
@@ -6182,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));
 
@@ -6208,7 +6387,7 @@ finish_decl (decl, init, asmspec_tree, need_pop)
          else if (toplev && ! TREE_PUBLIC (decl))
            {
              /* If this is a static const, change its apparent linkage
-                if it belongs to a #pragma interface.  */
+                if it belongs to a #pragma interface.  */
              if (!interface_unknown)
                {
                  TREE_PUBLIC (decl) = 1;
@@ -6269,55 +6448,7 @@ finish_decl (decl, init, asmspec_tree, need_pop)
        signature_error (decl, TREE_TYPE (type));
 
       if (TREE_CODE (decl) == FUNCTION_DECL)
-       {
-#if 0
-         /* 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;
-           }
-#endif
-       }
+       ;
       else if (DECL_EXTERNAL (decl))
        ;
       else if (TREE_STATIC (decl) && type != error_mark_node)
@@ -6379,12 +6510,14 @@ finish_decl (decl, init, asmspec_tree, need_pop)
                {
                  emit_line_note (DECL_SOURCE_FILE (decl),
                                  DECL_SOURCE_LINE (decl));
-                 expand_aggr_init (decl, init, 0);
+                 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.  */
@@ -6489,9 +6622,10 @@ expand_static_init (decl, init)
                                          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
@@ -6537,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
        {
@@ -6620,7 +6766,7 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
   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.
@@ -6636,13 +6782,13 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
    not look, and -1 if we should not call `grokclassfn' at all.  */
 static tree
 grokfndecl (ctype, type, declarator, virtualp, flags, quals,
-           raises, check, publicp)
+           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;
@@ -6671,8 +6817,25 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
       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)
@@ -6854,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;
@@ -6913,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.  */
@@ -6960,7 +7089,9 @@ build_ptrmemfunc_type (type)
   t = make_lang_type (RECORD_TYPE);
 
   /* Let the front-end know this is a pointer to member function. */
-  TYPE_PTRMEMFUNC_FLAG(t) = 1;
+  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);
@@ -7002,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.
@@ -7054,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;
@@ -7065,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;
@@ -7174,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))
@@ -7195,7 +7331,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          dname = decl;
          decl = NULL_TREE;
 
-         if (IDENTIFIER_OPNAME_P (dname))
+         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))
                {
@@ -7206,8 +7346,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                }
              name = operator_name_string (dname);
            }
-         else
-           name = IDENTIFIER_POINTER (dname);
          break;
 
        case RECORD_TYPE:
@@ -7272,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)
              {
@@ -7283,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);
                  }
              }
          }
@@ -7311,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).  */
@@ -7358,44 +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 (type)
-               error ("extraneous `char' ignored");
-             else
-               {
-                 explicit_char = 1;
-                 type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id));
-               }
-             goto found;
-           }
-         if (id == ridpointers[(int) RID_BOOL])
+         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 `bool' ignored");
-             else
                {
-                 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;
@@ -7410,14 +7540,14 @@ 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 (pedantic && flag_ansi)
-                       pedwarn ("duplicate `long'");
+                     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
@@ -7441,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;
            }
        }
@@ -7459,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;
@@ -7478,22 +7620,21 @@ 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)
            {
              if (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)))
+                 && return_type == return_normal)
                /* Save warning until we know what is really going on.  */
                warn_about_return_type = 1;
            }
-         else if (decl_context == FIELD && declarator
-                  && TREE_CODE (declarator) == SCOPE_REF)
-           /* OK -- access declaration */;
+         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",
@@ -7513,7 +7654,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
     }
   else if (return_type == return_conversion)
     {
-      if (comp_target_types (type, ctor_return_type, 1) == 0)
+      if (comptypes (type, ctor_return_type, 1) == 0)
        cp_error ("operator `%T' declared to return `%T'",
                  ctor_return_type, type);
       else
@@ -7522,6 +7663,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
       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;
 
@@ -7549,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))
@@ -7633,11 +7781,17 @@ 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);
 
   if (RIDBIT_SETP (RID_STATIC, specbits))
     staticp = 1 + (decl_context == FIELD);
@@ -7649,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
@@ -7704,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;
@@ -7767,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)))
        ;
@@ -7800,17 +7959,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                break;
            }
 
-         if (scanner == IDENTIFIER_AS_LIST (ridpointers [(int) RID_TYPEDEF]))
-           {
-             if (previous_declspec)
-               TREE_CHAIN (previous_declspec)
-                 = IDENTIFIER_AS_LIST (ridpointers [(int) RID_STATIC]);
-             else
-               declspecs
-                 = IDENTIFIER_AS_LIST (ridpointers [(int) RID_STATIC]);
-           }
+         if (previous_declspec)
+           TREE_CHAIN (previous_declspec) = TREE_CHAIN (scanner);
          else
-           TREE_VALUE (scanner) = ridpointers[(int) RID_STATIC];
+           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.  */
@@ -7819,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)
            {
@@ -7826,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)
@@ -7843,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,
@@ -7853,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);
@@ -7882,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);
@@ -7973,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);
 
@@ -7992,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)
              {
@@ -8052,7 +8222,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                  }
                if (TREE_READONLY_DECL_P (size))
                  size = decl_constant_value (size);
-               if (flag_ansi && integer_zerop (size))
+               if (pedantic && integer_zerop (size))
                  cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", dname);
                if (TREE_CONSTANT (size))
                  {
@@ -8062,12 +8232,10 @@ 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 (flag_ansi)
+                   if (pedantic)
                      {
                        if (dname)
                          cp_pedwarn ("ANSI C++ forbids variable-size array `%D'",
@@ -8075,15 +8243,20 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                        else
                          cp_pedwarn ("ANSI C++ forbids variable-size array");
                      }
-                 dont_grok_size:
-                   itype =
-                     build_binary_op (MINUS_EXPR, size, integer_one_node, 1);
                    /* 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);
              }
 
@@ -8094,7 +8267,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
            type = build_cplus_array_type (type, itype);
            if (constp || volatilep)
-             type = c_build_type_variant (type, constp, volatilep);
+             type = cp_build_type_variant (type, constp, volatilep);
 
            ctype = NULL_TREE;
          }
@@ -8103,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.  */
@@ -8111,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;
@@ -8137,8 +8313,21 @@ 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;
 
@@ -8158,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)
@@ -8177,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.  */
@@ -8187,16 +8373,11 @@ 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;
-                     }
                    {
                      RID_BIT_TYPE tmp_bits;
                      bcopy ((void*)&specbits, (void*)&tmp_bits, sizeof(RID_BIT_TYPE));
@@ -8225,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
@@ -8252,27 +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)
-                 ? 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)
              {
@@ -8316,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.  */
 
@@ -8327,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;
@@ -8339,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);
@@ -8352,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);
                }
@@ -8413,9 +8594,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                  && (constp || volatilep))
                {
                  if (constp)
-                   warning ("discarding `const' applied to a reference");
+                   pedwarn ("discarding `const' applied to a reference");
                  if (volatilep)
-                   warning ("discarding `volatile' applied to a reference");
+                   pedwarn ("discarding `volatile' applied to a reference");
                  constp = volatilep = 0;
                }
            }
@@ -8472,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)
@@ -8524,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);
@@ -8539,15 +8727,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
                    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);
                  }
@@ -8609,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.  */
@@ -8620,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
@@ -8648,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));
          }
        }
 
@@ -8659,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)
        {
@@ -8709,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)
        {
@@ -8741,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)
     {
@@ -8755,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? */
@@ -8791,13 +9001,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          {
            /* Transfer const-ness of array into that of type pointed to. */
            type = build_pointer_type
-             (build_type_variant (TREE_TYPE (type), constp, volatilep));
+             (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);
+       else if (type == void_type_node && declarator)
+         {
+           error ("declaration of `%s' as void", name);
+           return NULL_TREE;
+         }
 
        decl = build_decl (PARM_DECL, declarator, type);
 
@@ -8872,48 +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
-                          && RIDBIT_NOTSETP (RID_INLINE, specbits))
-                      || (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);
+                              raises, friendp ? -1 : 0, publicp, inlinep);
            if (decl == NULL_TREE)
              return NULL_TREE;
+           decl = build_decl_attribute_variant (decl, decl_machine_attr);
 
-           DECL_INLINE (decl) = inlinep;
+           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);
+                              raises, friendp ? -1 : 0, 1, 0);
            if (decl == NULL_TREE)
              return NULL_TREE;
-
-           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;
-           return void_type_node;
          }
        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.  */
@@ -8922,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;
          }
@@ -8989,7 +9194,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                   initialize the named nonstatic member....  This (or an
                   initializer list) is the only way to initialize
                   nonstatic const and reference members.  */
-               else if (flag_ansi || ! constp)
+               else if (pedantic || ! constp)
                  cp_pedwarn ("ANSI C++ forbids initialization of %s `%D'",
                              constp ? "const member" : "member", declarator);
              }
@@ -9001,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) = !!staticp;
+               TREE_STATIC (decl) = 1;
+               /* In class context, 'static' means public access.  */
+               TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = !!staticp;
              }
            else
              {
@@ -9072,25 +9275,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          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))
-            || !(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)
          {
@@ -9100,15 +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 (! 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)
@@ -9124,32 +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 (ctype)
+             {
+               ctype = NULL_TREE;
+               error ("cannot use `::' in parameter declaration");
+             }
 
-           if (! 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;
+           /* 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 (RIDBIT_SETP (RID_EXTERN, specbits))
+           if (TREE_CODE (type) == ARRAY_TYPE)
              {
-               current_extern_inline = 1;
-               if (flag_ansi)
-                 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);
          }
-      }
-    else
-      {
-       /* It's a variable.  */
 
        /* An uninitialized decl with `extern' is a reference.  */
        decl = grokvardecl (type, declarator, specbits, initialized);
@@ -9166,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",
@@ -9189,6 +9388,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
     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)
@@ -9447,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)))
                            {
@@ -9464,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;
@@ -9854,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_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_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_nonclass_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;
@@ -9929,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;
 
@@ -9938,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;
@@ -9965,18 +10097,12 @@ xref_tag (code_type_node, name, binfo, globalize)
   if (t && TREE_CODE (t) != code)
     t = NULL_TREE;
 
-  if (xref_next_defn)
+  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))
-       {
-         if (TREE_MANGLED (name))
-           ref = t;
-         else
-           ref = lookup_tag (code, name, b, 1);
-       }
+      if (t && TYPE_CONTEXT(t) && TREE_MANGLED (name))
+       ref = t;
       else
        ref = lookup_tag (code, name, b, 1);
     }
@@ -10037,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;
@@ -10105,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;
@@ -10144,127 +10222,11 @@ xref_tag (code_type_node, name, binfo, globalize)
             build them on the permanent obstack.  */
          end_temporary_allocation ();
        }
+#endif
     }
 
   if (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;
-
-      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 1
-         /* This code replaces similar code in layout_basetypes.  */
-         else if (TYPE_SIZE (basetype) == NULL_TREE)
-           {
-             cp_error ("base class `%T' has incomplete type", 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.)  */
-  
-             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;
-
-             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;
-  }
-#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);
-             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;
-
-      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);
-    }
+    xref_basetypes (code_type_node, name, ref, binfo);
 
  just_return:
 
@@ -10285,6 +10247,145 @@ if (CLASSTYPE_N_BASECLASSES (basetype) == NULL_TREE
 
   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_INCOMPLETE (basetype))
+       {
+         cp_error ("base class `%T' has incomplete type", 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.)  */
+  
+         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;
+         BINFO_INHERITANCE_CHAIN (base_binfo) = TYPE_BINFO (ref);
+
+         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;
+           }
+#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);
+         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;
+
+  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);
+
+  pop_obstacks ();
+}
+  
 \f
 static tree current_local_enum = NULL_TREE;
 
@@ -10320,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.  */
@@ -10332,7 +10434,8 @@ 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.  */
@@ -10352,84 +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;
-
+  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_TYPE (TREE_VALUE (values)) = enumtype;
-      TREE_TYPE (DECL_INITIAL (TREE_VALUE (values))) = enumtype;
-      TREE_VALUE (values) = DECL_INITIAL (TREE_VALUE (values));
-      value = TREE_INT_CST_LOW (TREE_VALUE (values));
-      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 = DECL_INITIAL (TREE_VALUE (pair));
          TREE_TYPE (TREE_VALUE (pair)) = enumtype;
-         TREE_TYPE (DECL_INITIAL (TREE_VALUE (pair))) = enumtype;
-         TREE_VALUE (pair) = DECL_INITIAL (TREE_VALUE (pair));
-         value = TREE_INT_CST_LOW (TREE_VALUE (pair));
-         if (value > maxvalue)
-           maxvalue = value;
-         else if (value < minvalue)
-           minvalue = value;
+         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;
 
   TYPE_VALUES (enumtype) = values;
 
-  if (flag_short_enums)
-    {
-      /* Determine the precision this type needs, lay it out, and define
-         it.  */
-
-      /* First reset precision */
-      TYPE_PRECISION (enumtype) = 0;
-
-      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);
 
-  TREE_INT_CST_LOW (TYPE_MAX_VALUE (enumtype)) = maxvalue;
+    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);
+
+    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
@@ -10613,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 ();
 
@@ -10669,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 = DECL_THIS_EXTERN (decl1) && DECL_INLINE (decl1);
-
       raises = TYPE_RAISES_EXCEPTIONS (fntype);
 
       /* In a fcn definition, arg types must be complete.  */
@@ -10715,7 +10818,7 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
          if (TREE_TYPE (TREE_TYPE (decl1)) != integer_type_node)
            {
              if (pedantic || warn_return_type)
-               warning ("return type for `main' changed to integer type");
+               pedwarn ("return type for `main' changed to integer type");
              TREE_TYPE (decl1) = fntype = default_function_type;
            }
          warn_about_return_type = 0;
@@ -10759,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'");
 
@@ -10773,31 +10880,39 @@ 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 if (DECL_EXPLICIT_INSTANTIATION (decl1))
-    /* PUBLIC and EXTERNAL set by do_*_instantiation */;
   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;
+        So clear DECL_EXTERNAL.  */
+      DECL_EXTERNAL (decl1) = 0;
 
-#if 0
-      DECL_DEFER_OUTPUT (decl1)
-       = (DECL_INLINE (decl1) && (DECL_IMPLICIT_INSTANTIATION (decl1)
-                                  || DECL_FUNCTION_MEMBER_P (decl1)));
-#endif
+      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;
+       }
     }
 
   /* Record the decl so that the function name is defined.
@@ -10825,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);
@@ -10886,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 ();
@@ -11081,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
     }
 }
 
@@ -11095,7 +11212,7 @@ store_return_init (return_id, init)
 {
   tree decl = DECL_RESULT (current_function_decl);
 
-  if (flag_ansi)
+  if (pedantic)
     /* 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.  */
@@ -11134,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
@@ -11205,9 +11269,10 @@ 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;
@@ -11234,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;
@@ -11265,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
        {
@@ -11428,6 +11493,7 @@ finish_function (lineno, call_poplevel)
 
       if (DECL_CONSTRUCTOR_P (current_function_decl))
        {
+         end_protect_partials ();
          expand_label (ctor_label);
          ctor_label = NULL_TREE;
 
@@ -11508,13 +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 (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);
        }
 
@@ -11604,19 +11673,6 @@ finish_function (lineno, call_poplevel)
       expand_label (no_return_label);
     }
 
-  /* 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
-     class members will ever be referenced in this function
-     (i.e., calls to destructors).  */
-  if (current_class_name)
-    {
-      ctype = current_class_type;
-      pop_nested_class (1);
-    }
-  else
-    pop_memoized_context (1);
-
   /* Generate rtl for function exit.  */
   expand_function_end (input_filename, lineno, 1);
 
@@ -11630,6 +11686,19 @@ finish_function (lineno, call_poplevel)
     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
+     class members will ever be referenced in this function
+     (i.e., calls to destructors).  */
+  if (current_class_name)
+    {
+      ctype = current_class_type;
+      pop_nested_class (1);
+    }
+  else
+    pop_memoized_context (1);
+
   /* Must mark the RESULT_DECL as being in this function.  */
   DECL_CONTEXT (DECL_RESULT (fndecl)) = DECL_INITIAL (fndecl);
 
@@ -11644,44 +11713,16 @@ 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);
-    }
+  /* Run the optimizers and output the assembler code for this function.  */
+  rest_of_compilation (fndecl);
 
-  if (DECL_INLINE (fndecl)
-      && !TREE_ASM_WRITTEN (fndecl) && DECL_FUNCTION_MEMBER_P (fndecl))
+  if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (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);
     }
 
@@ -11717,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);
@@ -11733,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
@@ -11796,11 +11849,16 @@ start_method (declspecs, declarator, raises)
       return void_type_node;
     }
 
+  DECL_THIS_INLINE (fndecl) = 1;
+
   if (flag_default_inline)
     DECL_INLINE (fndecl) = 1;
 
   if (processing_template_defn)
-    SET_DECL_IMPLICIT_INSTANTIATION (fndecl);
+    {
+      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
@@ -11833,7 +11891,7 @@ start_method (declspecs, declarator, raises)
        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);
@@ -11965,7 +12023,9 @@ hack_incomplete_structures (type)
                            decl);
              }
          }
+       /*
        my_friendly_assert (current_binding_level->n_incomplete > 0, 164);
+       */
        --current_binding_level->n_incomplete;
       }
 }
@@ -12013,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)
@@ -12065,6 +12120,11 @@ cplus_expand_expr_stmt (exp)
          warning ("at this point in file");
        }
 
+#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));
     }
 
@@ -12138,3 +12198,114 @@ id_in_current_class (id)
 {
   return !!purpose_member (id, class_binding_level->class_shadowed);
 }
+
+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_cp_function_context (context)
+     tree context;
+{
+  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;
+}
+
+/* Restore the variables used during compilation of a C++ function.  */
+
+void
+pop_cp_function_context (context)
+     tree context;
+{
+  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)
+    {
+      /* 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;
+    }
+#endif
+
+  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);
+}