cp-tree.def (CPLUS_BINDING): Update documentation.
[gcc.git] / gcc / cp / decl.c
index 488cd0bc6b49138b75dc8c13233b86af69e912d4..7c9a518e1617eb5fd04236fb865fbfcad1e510dd 100644 (file)
@@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "except.h"
 #include "toplev.h"
+#include "../hash.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
@@ -146,7 +147,7 @@ static void resume_binding_level PROTO((struct binding_level *));
 static struct binding_level *make_binding_level PROTO((void));
 static int namespace_bindings_p PROTO((void));
 static void declare_namespace_level PROTO((void));
-static void signal_catch PROTO((int));
+static void signal_catch PROTO((int)) ATTRIBUTE_NORETURN;
 static void storedecls PROTO((tree));
 static void storetags PROTO((tree));
 static void require_complete_types_for_parms PROTO((tree));
@@ -168,8 +169,6 @@ static tree lookup_tag PROTO((enum tree_code, tree,
                              struct binding_level *, int));
 static void set_identifier_type_value_with_scope
        PROTO((tree, tree, struct binding_level *));
-static void set_identifier_local_value_with_scope
-       PROTO((tree, tree, struct binding_level *));
 static void record_builtin_type PROTO((enum rid, char *, tree));
 static void record_unknown_type PROTO((tree, char *));
 static int member_function_or_else PROTO((tree, tree, char *));
@@ -177,6 +176,11 @@ static void bad_specifiers PROTO((tree, char *, int, int, int, int,
                                  int));
 static void lang_print_error_function PROTO((char *));
 static tree maybe_process_template_type_declaration PROTO((tree, int, struct binding_level*));
+static void check_for_uninitialized_const_var PROTO((tree));
+static unsigned long typename_hash PROTO((hash_table_key));
+static boolean typename_compare PROTO((hash_table_key, hash_table_key));
+static void push_binding PROTO((tree, tree, struct binding_level*));
+static void pop_binding PROTO((tree));
 
 #if defined (DEBUG_CP_BINDING_LEVELS)
 static void indent PROTO((void));
@@ -229,13 +233,17 @@ tree intQI_type_node;
 tree intHI_type_node;
 tree intSI_type_node;
 tree intDI_type_node;
+#if HOST_BITS_PER_WIDE_INT >= 64
 tree intTI_type_node;
+#endif
 
 tree unsigned_intQI_type_node;
 tree unsigned_intHI_type_node;
 tree unsigned_intSI_type_node;
 tree unsigned_intDI_type_node;
+#if HOST_BITS_PER_WIDE_INT >= 64
 tree unsigned_intTI_type_node;
+#endif
 
 tree java_byte_type_node;
 tree java_short_type_node;
@@ -329,6 +337,7 @@ tree sigtable_entry_type;
 
 /* Array type `vtable_entry_type[]' */
 tree vtbl_type_node;
+tree vtbl_ptr_type_node;
 
 /* namespace std */
 tree std_node;
@@ -365,6 +374,10 @@ tree ctor_label;
 
 tree abort_fndecl;
 
+/* A FUNCTION_DECL for the default `::operator delete'.  */
+
+tree global_delete_fndecl;
+
 extern rtx cleanup_label, return_label;
 
 /* If original DECL_RESULT of current function was a register,
@@ -496,11 +509,6 @@ int current_function_returns_null;
 
 tree current_function_return_value;
 
-/* Set to nonzero by `grokdeclarator' for a function
-   whose return type is defaulted, if warnings for this are desired.  */
-
-static int warn_about_return_type;
-
 /* Nonzero means give `double' the same size as `float'.  */
 
 extern int flag_short_double;
@@ -603,7 +611,8 @@ struct binding_level
   {
     /* A chain of _DECL nodes for all variables, constants, functions,
        and typedef types.  These are in the reverse of the order
-       supplied.  */
+       supplied.  There may be OVERLOADs on this list, too, but they
+       are wrapped in TREE_LISTs; the TREE_VALUE is the OVERLOAD.  */
     tree names;
 
     /* A list of structure, union and enum definitions, for looking up
@@ -623,16 +632,16 @@ struct binding_level
        VALUE the common ancestor with this binding_level's namespace. */
     tree using_directives;
 
-    /* For each level, a list of shadowed outer-level local definitions
-       to be restored when this level is popped.
-       Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and
-       whose TREE_VALUE is its old definition (a kind of ..._DECL node).  */
-    tree shadowed;
-
-    /* Same, for IDENTIFIER_CLASS_VALUE.  */
+    /* If this binding level is the binding level for a class, then
+       class_shadowed is a TREE_LIST.  The TREE_PURPOSE of each node
+       is the name of an entity bound in the class; the TREE_VALUE is
+       the IDENTIFIER_CLASS_VALUE before we entered the class.  Thus,
+       when leaving class scope, we can restore the
+       IDENTIFIER_CLASS_VALUE by walking this list.  */
     tree class_shadowed;
 
-    /* Same, for IDENTIFIER_TYPE_VALUE.  */
+    /* Similar to class_shadowed, but for IDENTIFIER_TYPE_VALUE, and
+       is used for all binding levels.  */
     tree type_shadowed;
 
     /* For each level (except not the global one),
@@ -653,7 +662,8 @@ struct binding_level
 
     /* List of VAR_DECLS saved from a previous for statement.
        These would be dead in ANSI-conforming code, but might
-       be referenced in ARM-era code.  */
+       be referenced in ARM-era code.  These are stored in a
+       TREE_LIST; the TREE_VALUE is the actual declaration.  */
     tree dead_vars_from_for;
 
     /* 1 for the level that holds the parameters of a function.
@@ -1022,6 +1032,112 @@ pushlevel_temporary (tag_transparent)
   expand_start_bindings (0);
 }
 
+/* For a binding between a name and an entity at a block scope,
+   this is the `struct binding_level' for the block.  */
+#define BINDING_LEVEL(NODE) \
+   ((struct binding_level*) ((struct tree_binding*)NODE)->scope)
+
+/* These are currently unused, but permanent, CPLUS_BINDING nodes.
+   They are kept here because they are allocated from the permanent
+   obstack and cannot be easily freed.  */
+static tree free_binding_nodes;
+
+/* Make DECL the innermost binding for ID.  The LEVEL is the binding
+   level at which this declaration is being bound.  */
+
+static void
+push_binding (id, decl, level)
+     tree id;
+     tree decl;
+     struct binding_level* level;
+{
+  tree binding;
+
+  if (!free_binding_nodes)
+    {
+      /* There are no free nodes, so we must build one here.  */
+      push_obstacks_nochange ();
+      end_temporary_allocation ();
+      binding = make_node (CPLUS_BINDING);
+      pop_obstacks ();
+    }
+  else
+    {
+      /* There are nodes on the free list.  Grab the first one.  */
+      binding = free_binding_nodes;
+      
+      /* And update the free list.  */
+      free_binding_nodes = TREE_CHAIN (free_binding_nodes);
+    }
+
+  /* Now, fill in the binding information.  */
+  BINDING_VALUE (binding) = decl;
+  BINDING_LEVEL (binding) = level;
+  LOCAL_BINDING_P (binding) = (level != class_binding_level);
+
+  /* And put it on the front of the ilst of bindings for ID.  */
+  TREE_CHAIN (binding) = IDENTIFIER_BINDING (id);
+  IDENTIFIER_BINDING (id) = binding;
+}
+
+/* Bind DECL to ID in the current_binding_level.  */
+
+void
+push_local_binding (id, decl)
+     tree id;
+     tree decl;
+{
+  tree d = decl;;
+
+  if (TREE_CODE (decl) == OVERLOAD)
+    /* We must put the OVERLOAD into a TREE_LIST since the
+       TREE_CHAIN of an OVERLOAD is already used.  */
+    decl = build_tree_list (NULL_TREE, decl);
+
+  /* Create a binding, hanging off of ID.  */
+  push_binding (id, d, current_binding_level);
+
+  /* And put DECL on the list of things declared by the current
+     binding level.  */
+  TREE_CHAIN (decl) = current_binding_level->names;
+  current_binding_level->names = decl;
+}
+
+/* Bind DECL to ID in the class_binding_level.  */
+
+void
+push_class_binding (id, decl)
+     tree id;
+     tree decl;
+{
+  push_binding (id, decl, class_binding_level);
+}
+
+/* Remove the innermost binding for ID; it has gone out of scope.  */
+
+static void 
+pop_binding (id) 
+     tree id;
+{
+  tree binding;
+
+  if (id == NULL_TREE)
+    /* It's easiest to write the loops that call this function without
+       checking whether or not the entities involved have names.  We
+       get here for such an entity.  */
+    return;
+
+  my_friendly_assert (IDENTIFIER_BINDING (id) != NULL_TREE, 0);
+
+  /* Unhook the innermost binding from the list of bindings.  */
+  binding = IDENTIFIER_BINDING (id);
+  IDENTIFIER_BINDING (id) = TREE_CHAIN (binding);
+
+  /* And place this list node on the free list.  */
+  TREE_CHAIN (binding) = free_binding_nodes;
+  free_binding_nodes = binding;
+}
+
 /* Exit a binding level.
    Pop the level off, and restore the state of the identifier-decl mappings
    that were in effect when this level was entered.
@@ -1030,12 +1146,6 @@ pushlevel_temporary (tag_transparent)
    and create a "block" (a BLOCK node) for the level
    to record its declarations and subblocks for symbol table output.
 
-   If KEEP == 2, this level's subblocks go to the front,
-   not the back of the current binding level.  This happens,
-   for instance, when code for constructors and destructors
-   need to generate code at the end of a function which must
-   be moved up to the front of the function.
-
    If FUNCTIONBODY is nonzero, this level is the body of a function,
    so create a block as if KEEP were set and also clear out all
    label names.
@@ -1061,6 +1171,18 @@ poplevel (keep, reverse, functionbody)
   tree block = NULL_TREE;
   tree decl;
   int block_previously_created;
+  int leaving_for_scope;
+
+  if (current_binding_level->parm_flag == 2
+      || current_binding_level->class_shadowed)
+    /* We should not be using poplevel to pop a class binding level.
+       Use poplevel_class instead.  */
+    my_friendly_abort (0);
+
+  /* We used to use KEEP == 2 to indicate that the new block should go
+     at the beginning of the list of blocks at this binding level,
+     rather than the end.  This hack is no longer used.  */
+  my_friendly_assert (keep == 0 || keep == 1, 0);
 
   GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level,
                      (HOST_WIDE_INT) current_binding_level->level_chain,
@@ -1120,9 +1242,8 @@ poplevel (keep, reverse, functionbody)
          if (decls || tags || subblocks)
            {
              if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (block))
-               {
-                 warning ("internal compiler error: debugging info corrupted");
-               }
+               warning ("internal compiler error: debugging info corrupted");
+
              BLOCK_VARS (block) = decls;
              BLOCK_TYPE_TAGS (block) = tags;
 
@@ -1141,7 +1262,8 @@ poplevel (keep, reverse, functionbody)
          BLOCK_VARS (block) = decls;
          BLOCK_TYPE_TAGS (block) = tags;
          BLOCK_SUBBLOCKS (block) = subblocks;
-         /* Otherwise, for a new block, install a new BLOCK_END_NOTE value.  */
+         /* Otherwise, for a new block, install a new BLOCK_END_NOTE
+            value.  */ 
          remember_end_note (block);
        }
     }
@@ -1152,92 +1274,116 @@ poplevel (keep, reverse, functionbody)
     for (link = subblocks; link; link = TREE_CHAIN (link))
       BLOCK_SUPERCONTEXT (link) = block;
 
-  /* Clear out the meanings of the local variables of this level.  */
-
-  if (current_binding_level->is_for_scope && flag_new_for_scope == 1)
-    {
-      struct binding_level *outer = current_binding_level->level_chain;
-      for (link = decls; link; link = TREE_CHAIN (link))
-       {
-         if (TREE_CODE (link) == VAR_DECL)
-           DECL_DEAD_FOR_LOCAL (link) = 1;
+  /* We still support the old for-scope rules, whereby the variables
+     in a for-init statement were in scope after the for-statement
+     ended.  We only use the new rules in flag_new_for_scope is
+     nonzero.  */
+  leaving_for_scope 
+    = current_binding_level->is_for_scope && flag_new_for_scope == 1;
+
+  /* Remove declarations for all the DECLs in this level.  */
+  for (link = decls; link; link = TREE_CHAIN (link))
+    {
+      if (leaving_for_scope && TREE_CODE (link) == VAR_DECL)
+       {
+         tree outer_binding 
+           = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (link)));
+         tree ns_binding;
+
+         if (!outer_binding)
+           ns_binding = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (link));
+                                                  
+         if (outer_binding 
+             && (BINDING_LEVEL (outer_binding) 
+                 == current_binding_level->level_chain))
+           /* We have something like:
+              
+                int i;
+                for (int i; ;);
+                
+              and we are leaving the `for' scope.  There's no reason to
+              keep the binding of the inner `i' in this case.  */
+           pop_binding (DECL_NAME (link));
+         else if ((outer_binding 
+                   && (TREE_CODE (BINDING_VALUE (outer_binding)) 
+                       == TYPE_DECL))
+                  || (ns_binding 
+                      && TREE_CODE (ns_binding) == TYPE_DECL))
+           /* Here, we have something like:
+
+                typedef int I;
+
+                void f () {
+                  for (int I; ;);
+                }
+
+              We must pop the for-scope binding so we know what's a
+              type and what isn't.  */
+           pop_binding (DECL_NAME (link));
          else
-           IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
-       }
-
-      /* Save declarations made in a 'for' statement so we can support pre-ANSI
-        'for' scoping semantics.  */
-
-      for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
-       {
-         tree id = TREE_PURPOSE (link);
-         tree decl = IDENTIFIER_LOCAL_VALUE (id);
-
-         if (decl && DECL_DEAD_FOR_LOCAL (decl))
            {
-             /* In this case keep the dead for-decl visible,
-                but remember what (if anything) it shadowed.  */
-             DECL_SHADOWED_FOR_VAR (decl) = TREE_VALUE (link);
-             TREE_CHAIN (decl) = outer->dead_vars_from_for;
-             outer->dead_vars_from_for = decl;
+             /* Mark this VAR_DECL as dead so that we can tell we left it
+                there only for backward compatibility.  */
+             DECL_DEAD_FOR_LOCAL (link) = 1;
+             
+             /* Keep track of what should of have happenned when we
+                popped the binding.  */
+             if (outer_binding && BINDING_VALUE (outer_binding))
+               DECL_SHADOWED_FOR_VAR (link) 
+                 = BINDING_VALUE (outer_binding);
+
+             /* Add it to the list of dead variables in the next
+                outermost binding to that we can remove these when we
+                leave that binding.  */
+             current_binding_level->level_chain->dead_vars_from_for
+               = tree_cons (NULL_TREE, link,
+                            current_binding_level->level_chain->
+                            dead_vars_from_for);
+
+             /* Although we don't pop the CPLUS_BINDING, we do clear
+                its BINDING_LEVEL since the level is going away now.  */
+             BINDING_LEVEL (IDENTIFIER_BINDING (DECL_NAME (link)))
+               = 0;
            }
-         else
-           IDENTIFIER_LOCAL_VALUE (id) = TREE_VALUE (link);
        }
-    }
-  else /* Not special for scope.  */
-    {
-      for (link = decls; link; link = TREE_CHAIN (link))
+      else 
        {
-         if (DECL_NAME (link) != NULL_TREE)
-           {
-             /* If the ident. was used or addressed via a local extern decl,
-                don't forget that fact.  */
-             if (DECL_EXTERNAL (link))
-               {
-                 if (TREE_USED (link))
-                   TREE_USED (DECL_ASSEMBLER_NAME (link)) = 1;
-                 if (TREE_ADDRESSABLE (link))
-                   TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
-               }
-             IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
-           }
+         /* Remove the binding.  */
+         if (TREE_CODE_CLASS (TREE_CODE (link)) == 'd')
+           pop_binding (DECL_NAME (link));
+         else if (TREE_CODE (link) == TREE_LIST)
+           pop_binding (DECL_NAME (OVL_FUNCTION (TREE_VALUE (link))));
+         else
+           my_friendly_abort (0);
        }
+    }
 
-      /* Restore all name-meanings of the outer levels
-        that were shadowed by this level.  */
-
-      for (link = current_binding_level->shadowed;
-          link; link = TREE_CHAIN (link))
-       IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
-
-      /* We first restore the regular decls and *then* the dead_vars_from_for
-        to handle this case:
-
-        int i; // i#1
-        {
-          for (int i; ; ) { ...} // i#2
-           int i; // i#3
-        } // we are here
-
-        In this case, we want remove the binding for i#3, restoring
-        that of i#2.  Then we want to remove the binding for i#2,
-        and restore that of i#1.  */
+  /* Remove declarations for any `for' variables from inner scopes
+     that we kept around.  */
+  for (link = current_binding_level->dead_vars_from_for;
+       link; link = TREE_CHAIN (link))
+    pop_binding (DECL_NAME (TREE_VALUE (link)));
 
-      link = current_binding_level->dead_vars_from_for;
-      for (; link != NULL_TREE; link = TREE_CHAIN (link))
-       {
-         tree id = DECL_NAME (link);
-         if (IDENTIFIER_LOCAL_VALUE (id) == link)
-           IDENTIFIER_LOCAL_VALUE (id) = DECL_SHADOWED_FOR_VAR (link);
-       }
+  /* Restore the IDENTIFIER_TYPE_VALUEs.  */
+  for (link = current_binding_level->type_shadowed;
+       link; link = TREE_CHAIN (link))
+    SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
+  
+  /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
+     list if a `using' declaration put them there.  The debugging
+     back-ends won't understand OVERLOAD, so we remove them here.
+     Because the BLOCK_VARS are (temporarily) shared with
+     CURRENT_BINDING_LEVEL->NAMES we must do this fixup after we have
+     popped all the bindings.  */
+  if (block)
+    {
+      tree* d;
 
-      for (link = current_binding_level->class_shadowed;
-          link; link = TREE_CHAIN (link))
-       IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
-      for (link = current_binding_level->type_shadowed;
-          link; link = TREE_CHAIN (link))
-       SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
+      for (d = &BLOCK_VARS (block); 
+          *d; 
+          d = *d ? &TREE_CHAIN (*d) : d)
+       if (TREE_CODE (*d) == TREE_LIST)
+         *d = TREE_CHAIN (*d);
     }
 
   /* If the level being exited is the top level of a function,
@@ -1312,14 +1458,8 @@ poplevel (keep, reverse, functionbody)
      must be carried forward so they will later become subblocks
      of something else.  */
   else if (subblocks)
-    {
-      if (keep == 2)
-       current_binding_level->blocks
-         = chainon (subblocks, current_binding_level->blocks);
-      else
-       current_binding_level->blocks
-         = chainon (current_binding_level->blocks, subblocks);
-    }
+    current_binding_level->blocks
+      = chainon (current_binding_level->blocks, subblocks);
 
   /* Take care of compiler's internal binding structures.  */
   if (tmp == 2)
@@ -1406,9 +1546,7 @@ pushlevel_class ()
       free_binding_level = free_binding_level->level_chain;
     }
   else
-    {
-      newlevel = make_binding_level ();
-    }
+    newlevel = make_binding_level ();
 
 #if defined(DEBUG_CP_BINDING_LEVELS)
   is_class_level = 1;
@@ -1443,8 +1581,6 @@ poplevel_class (force)
   my_friendly_assert (level != 0, 354);
   
   decl_stack = pop_stack_level (decl_stack);
-  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 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,
@@ -1467,6 +1603,12 @@ poplevel_class (force)
        shadowed = TREE_CHAIN (shadowed))
     SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed));
 
+  /* Remove the bindings for all of the class-level declarations.  */
+  for (shadowed = level->class_shadowed; 
+       shadowed; 
+       shadowed = TREE_CHAIN (shadowed))
+    pop_binding (TREE_PURPOSE (shadowed));
+
   GNU_xref_end_scope ((HOST_WIDE_INT) class_binding_level,
                      (HOST_WIDE_INT) class_binding_level->level_chain,
                      class_binding_level->parm_flag,
@@ -1573,15 +1715,6 @@ print_binding_level (lvl)
       if (i)
        fprintf (stderr, "\n");
     }
-  if (lvl->shadowed)
-    {
-      fprintf (stderr, " shadowed:");
-      for (t = lvl->shadowed; t; t = TREE_CHAIN (t))
-       {
-         fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t)));
-       }
-      fprintf (stderr, "\n");
-    }
   if (lvl->class_shadowed)
     {
       fprintf (stderr, " class-shadowed:");
@@ -1773,7 +1906,7 @@ void
 push_namespace (name)
      tree name;
 {
-  tree d;
+  tree d = NULL_TREE;
   int need_new = 1;
   int implicit_use = 0;
   int global = 0;
@@ -1896,7 +2029,9 @@ struct saved_scope {
   tree old_bindings;
   tree old_namespace;
   struct saved_scope *prev;
-  tree class_name, class_type, function_decl;
+  tree class_name, class_type;
+  tree access_specifier;
+  tree function_decl;
   struct binding_level *class_bindings;
   tree *lang_base, *lang_stack, lang_name;
   int lang_stacksize;
@@ -1929,9 +2064,11 @@ store_bindings (names, old_bindings)
       else
        id = DECL_NAME (t);
 
-      if (!id
-         || (!IDENTIFIER_LOCAL_VALUE (id)
-             && !IDENTIFIER_CLASS_VALUE (id)))
+      if (!id 
+         /* Note that we may have an IDENTIFIER_CLASS_VALUE even when
+            we have no IDENTIFIER_BINDING if we have left the class
+            scope, but cached the class-level declarations.  */
+         || !(IDENTIFIER_BINDING (id) || IDENTIFIER_CLASS_VALUE (id)))
        continue;
 
       for (t1 = old_bindings; t1; t1 = TREE_CHAIN (t1))
@@ -1951,9 +2088,9 @@ store_bindings (names, old_bindings)
          my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 135);
          TREE_VEC_ELT (binding, 0) = id;
          TREE_VEC_ELT (binding, 1) = REAL_IDENTIFIER_TYPE_VALUE (id);
-         TREE_VEC_ELT (binding, 2) = IDENTIFIER_LOCAL_VALUE (id);
+         TREE_VEC_ELT (binding, 2) = IDENTIFIER_BINDING (id);
          TREE_VEC_ELT (binding, 3) = IDENTIFIER_CLASS_VALUE (id);
-         IDENTIFIER_LOCAL_VALUE (id) = NULL_TREE;
+         IDENTIFIER_BINDING (id) = NULL_TREE;
          IDENTIFIER_CLASS_VALUE (id) = NULL_TREE;
        }
       TREE_CHAIN (binding) = old_bindings;
@@ -2010,6 +2147,7 @@ maybe_push_to_top_level (pseudo)
   s->old_namespace = current_namespace;
   s->class_name = current_class_name;
   s->class_type = current_class_type;
+  s->access_specifier = current_access_specifier;
   s->function_decl = current_function_decl;
   s->class_bindings = class_binding_level;
   s->lang_stack = current_lang_stack;
@@ -2081,7 +2219,7 @@ pop_from_top_level ()
       if (id)
        {
          SET_IDENTIFIER_TYPE_VALUE (id, TREE_VEC_ELT (t, 1));
-         IDENTIFIER_LOCAL_VALUE (id) = TREE_VEC_ELT (t, 2);
+         IDENTIFIER_BINDING (id) = TREE_VEC_ELT (t, 2);
          IDENTIFIER_CLASS_VALUE (id) = TREE_VEC_ELT (t, 3);
        }
       t = TREE_CHAIN (t);
@@ -2091,6 +2229,7 @@ pop_from_top_level ()
   current_namespace = s->old_namespace;
   current_class_name = s->class_name;
   current_class_type = s->class_type;
+  current_access_specifier = s->access_specifier;
   current_function_decl = s->function_decl;
   class_binding_level = s->class_bindings;
   free (current_lang_base);
@@ -2164,26 +2303,6 @@ set_identifier_type_value (id, type)
   set_identifier_type_value_with_scope (id, type, inner_binding_level);
 }
 
-static void
-set_identifier_local_value_with_scope (id, val, b)
-     tree id, val;
-     struct binding_level *b;
-{
-  tree oldlocal;
-  my_friendly_assert (! b->namespace_p, 980716);
-
-  oldlocal = IDENTIFIER_LOCAL_VALUE (id);
-  b->shadowed = tree_cons (id, oldlocal, b->shadowed);
-  IDENTIFIER_LOCAL_VALUE (id) = val;
-}
-
-void
-set_identifier_local_value (id, val)
-     tree id, val;
-{
-  set_identifier_local_value_with_scope (id, val, current_binding_level);
-}
-
 /* Return the type associated with id. */
 
 tree
@@ -2297,6 +2416,7 @@ maybe_process_template_type_declaration (type, globalize, b)
            {
              pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
                                   b->level_chain);
+             finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
              /* Put this tag on the list of tags for the class, since
                 that won't happen below because B is not the class
                 binding level, but is instead the pseudo-global level.  */
@@ -2391,7 +2511,15 @@ pushtag (name, type, globalize)
                                                       globalize, b);
 
          if (b->parm_flag == 2)
-           d = pushdecl_class_level (d);
+           {
+             pushdecl_class_level (d);
+             if (newdecl && !PROCESSING_REAL_TEMPLATE_DECL_P ())
+               /* Put this TYPE_DECL on the TYPE_FIELDS list for the
+                  class.  But if it's a member template class, we
+                  want the TEMPLATE_DECL, not the TYPE_DECL, so this
+                  is done later.  */
+               finish_member_declaration (d);
+           }
          else
            d = pushdecl_with_scope (d, b);
 
@@ -2493,8 +2621,12 @@ decls_match (newdecl, olddecl)
 {
   int types_match;
 
-  if (TREE_CODE (newdecl) == FUNCTION_DECL
-      && TREE_CODE (olddecl) == FUNCTION_DECL)
+  if (TREE_CODE (newdecl) != TREE_CODE (olddecl))
+    /* If the two DECLs are not even the same kind of thing, we're not
+       interested in their types.  */
+    return 0;
+
+  if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
       tree f1 = TREE_TYPE (newdecl);
       tree f2 = TREE_TYPE (olddecl);
@@ -2529,7 +2661,7 @@ decls_match (newdecl, olddecl)
          return 0;
        }
 
-      if (comptypes (TREE_TYPE (f1), TREE_TYPE (f2), 1))
+      if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2)))
        {
          if (! strict_prototypes_lang_c && DECL_LANGUAGE (olddecl) == lang_c
              && p2 == NULL_TREE)
@@ -2545,13 +2677,12 @@ decls_match (newdecl, olddecl)
              TREE_TYPE (newdecl) = TREE_TYPE (olddecl);
            }
          else
-           types_match = compparms (p1, p2, 3);
+           types_match = compparms (p1, p2);
        }
       else
        types_match = 0;
     }
-  else if (TREE_CODE (newdecl) == TEMPLATE_DECL
-          && TREE_CODE (olddecl) == TEMPLATE_DECL)
+  else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
     {
       if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
                                DECL_TEMPLATE_PARMS (olddecl)))
@@ -2571,20 +2702,10 @@ decls_match (newdecl, olddecl)
        types_match = TREE_TYPE (newdecl) == NULL_TREE;
       else if (TREE_TYPE (newdecl) == NULL_TREE)
        types_match = 0;
-      /* Qualifiers must match, and they may be present on either, the type
-        or the decl.  */
-      else if ((TREE_READONLY (newdecl)
-               || TYPE_READONLY (TREE_TYPE (newdecl)))
-              == (TREE_READONLY (olddecl)
-                  || TYPE_READONLY (TREE_TYPE (olddecl)))
-              && (TREE_THIS_VOLATILE (newdecl)
-                   || TYPE_VOLATILE (TREE_TYPE (newdecl)))
-                  == (TREE_THIS_VOLATILE (olddecl)
-                      || TYPE_VOLATILE (TREE_TYPE (olddecl))))
-       types_match = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (newdecl)),
-                                TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)), 1);
       else
-       types_match = 0;
+       types_match = comptypes (TREE_TYPE (newdecl),
+                                TREE_TYPE (olddecl),
+                                COMPARE_REDECLARATION);
     }
 
   return types_match;
@@ -2759,7 +2880,7 @@ duplicate_decls (newdecl, olddecl)
          else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
                   && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
                   && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))),
-                                TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))), 3)
+                                TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))))
                   && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
                                           DECL_TEMPLATE_PARMS (olddecl)))
            {
@@ -2778,7 +2899,7 @@ duplicate_decls (newdecl, olddecl)
              cp_error_at ("previous declaration `%#D' here", olddecl);
            }
          else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
-                             TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 3))
+                             TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
            {
              cp_error ("new declaration `%#D'", newdecl);
              cp_error_at ("ambiguates old declaration `%#D'", olddecl);
@@ -2908,13 +3029,6 @@ duplicate_decls (newdecl, olddecl)
                             olddecl);
            }
        }
-      /* 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,
@@ -2984,9 +3098,6 @@ duplicate_decls (newdecl, olddecl)
                             DECL_TEMPLATE_RESULT (olddecl)))
        cp_error ("invalid redeclaration of %D", newdecl);
       TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl));
-      DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl);
-      if (DECL_TEMPLATE_INFO (newdecl))
-       DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
       DECL_TEMPLATE_SPECIALIZATIONS (olddecl) 
        = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
                   DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
@@ -3118,11 +3229,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 (DECL_TEMPLATE_INFO (newdecl) == NULL_TREE)
-       {
-         DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
-         DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl);
-       }
+      DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
       olddecl_friend = DECL_FRIEND_P (olddecl);
     }
 
@@ -3329,14 +3436,14 @@ pushdecl (x)
 {
   register tree t;
   register tree name = DECL_ASSEMBLER_NAME (x);
-  register struct binding_level *b = current_binding_level;
+  int need_new_binding = 1;
 
   if (current_function_decl && x != current_function_decl
       /* A local declaration for a function doesn't constitute nesting.  */
       && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
       /* Don't change DECL_CONTEXT of virtual methods.  */
       && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
-      && ! DECL_CONTEXT (x))
+      && !DECL_CONTEXT (x))
     DECL_CONTEXT (x) = current_function_decl;
   if (!DECL_CONTEXT (x))
     DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
@@ -3459,11 +3566,18 @@ pushdecl (x)
            }
        }
 
+      check_template_shadow (x);
+
       if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
        {
          t = push_overloaded_decl (x, 1);
          if (t != x || DECL_LANGUAGE (x) == lang_c)
            return t;
+         if (!namespace_bindings_p ())
+           /* We do not need to create a binding for this name;
+              push_overloaded_decl will have already done so if
+              necessary.  */
+           need_new_binding = 0;
        }
       else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
        return push_overloaded_decl (x, 0);
@@ -3479,7 +3593,12 @@ pushdecl (x)
              if (TYPE_NAME (type) == 0)
                TYPE_NAME (type) = x;
             }
-          else if (type != error_mark_node && TYPE_NAME (type) != x)
+          else if (type != error_mark_node && TYPE_NAME (type) != x
+                  /* We don't want to copy the type when all we're
+                     doing is making a TYPE_DECL for the purposes of
+                     inlining.  */
+                  && (!TYPE_NAME (type) 
+                      || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
             {
              push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
 
@@ -3495,7 +3614,15 @@ pushdecl (x)
          if (type != error_mark_node
              && TYPE_NAME (type)
              && TYPE_IDENTIFIER (type))
-            set_identifier_type_value_with_scope (DECL_NAME (x), type, b);
+            set_identifier_type_value_with_scope (DECL_NAME (x), type, 
+                                                 current_binding_level);
+
+         if (TREE_CODE (x) == TYPE_DECL
+             && DECL_ARTIFICIAL (x)
+             && t != NULL_TREE)
+           /* We don't want an artificial TYPE_DECL is we already
+              have another DECL with the same name.  */
+           need_new_binding = 0;
        }
 
       /* Multiple external decls of the same identifier ought to match.
@@ -3518,7 +3645,7 @@ pushdecl (x)
          if (decl
              /* If different sort of thing, we already gave an error.  */
              && TREE_CODE (decl) == TREE_CODE (x)
-             && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl), 1))
+             && !same_type_p (TREE_TYPE (x), TREE_TYPE (decl)))
            {
              cp_pedwarn ("type mismatch with previous external decl", x);
              cp_pedwarn_at ("previous external decl of `%#D'", decl);
@@ -3536,11 +3663,7 @@ pushdecl (x)
          if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && TREE_PUBLIC (x))
            TREE_PUBLIC (name) = 1;
 
-         /* 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))
+         if (need_new_binding)
            {
              if (TREE_CODE (x) == FUNCTION_DECL)
                my_friendly_assert 
@@ -3575,25 +3698,29 @@ pushdecl (x)
       else
        {
          /* Here to install a non-global value.  */
-         tree oldlocal = IDENTIFIER_LOCAL_VALUE (name);
+         tree oldlocal = IDENTIFIER_VALUE (name);
          tree oldglobal = IDENTIFIER_NAMESPACE_VALUE (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
-             || ! DECL_ARTIFICIAL (x))
-           set_identifier_local_value_with_scope (name, x, b);
+         if (need_new_binding)
+           {
+             push_local_binding (name, x);
+             /* Because push_local_binding will hook X on to the
+                current_binding_level's name list, we don't want to
+                do that again below.  */
+             need_new_binding = 0;
+           }
 
          /* If this is a TYPE_DECL, push it into the type value slot.  */
          if (TREE_CODE (x) == TYPE_DECL)
-           set_identifier_type_value_with_scope (name, TREE_TYPE (x), b);
+           set_identifier_type_value_with_scope (name, TREE_TYPE (x), 
+                                                 current_binding_level);
 
          /* Clear out any TYPE_DECL shadowed by a namespace so that
             we won't think this is a type.  The C struct hack doesn't
             go through namespaces.  */
          if (TREE_CODE (x) == NAMESPACE_DECL)
-           set_identifier_type_value_with_scope (name, NULL_TREE, b);
+           set_identifier_type_value_with_scope (name, NULL_TREE, 
+                                                 current_binding_level);
 
          /* If this is an extern function declaration, see if we
             have a global definition or declaration for the function.  */
@@ -3619,9 +3746,7 @@ pushdecl (x)
              && oldglobal == NULL_TREE
              && DECL_EXTERNAL (x)
              && TREE_PUBLIC (x))
-           {
-             TREE_PUBLIC (name) = 1;
-           }
+           TREE_PUBLIC (name) = 1;
 
          if (DECL_FROM_INLINE (x))
            /* Inline decls shadow nothing.  */;
@@ -3642,7 +3767,8 @@ pushdecl (x)
              if (b->parm_flag == 1)
                cp_error ("declaration of `%#D' shadows a parameter", name);
            }
-         else if (warn_shadow && oldlocal != NULL_TREE && b->is_for_scope
+         else if (warn_shadow && oldlocal != NULL_TREE
+                  && current_binding_level->is_for_scope
                   && !DECL_DEAD_FOR_LOCAL (oldlocal))
            {
              warning ("variable `%s' shadows local",
@@ -3673,16 +3799,6 @@ pushdecl (x)
              if (warnstring)
                warning (warnstring, IDENTIFIER_POINTER (name));
            }
-         /* Check to see if decl redeclares a template parameter. */
-         if (oldlocal && (current_class_type || current_function_decl) 
-             && current_template_parms)
-           {
-             if (decl_template_parm_p (oldlocal))
-               {
-                 cp_error ("re-using name of template parameter `%T' in this scope", name);
-                 cp_error_at (" previously declared here `%#D'", oldlocal);
-               }
-           }
        }
 
       if (TREE_CODE (x) == FUNCTION_DECL)
@@ -3696,15 +3812,20 @@ pushdecl (x)
              /* RTTI TD entries are created while defining the type_info.  */
              || (TYPE_LANG_SPECIFIC (TREE_TYPE (x))
                  && TYPE_BEING_DEFINED (TREE_TYPE (x)))))
-       b->incomplete = tree_cons (NULL_TREE, x, b->incomplete);
+       current_binding_level->incomplete 
+         = tree_cons (NULL_TREE, x, current_binding_level->incomplete);
     }
 
-  /* Put decls on list in reverse order.
-     We will reverse them later if necessary.  */
-  TREE_CHAIN (x) = b->names;
-  b->names = x;
-  if (! (b != global_binding_level || TREE_PERMANENT (x)))
-    my_friendly_abort (124);
+  if (need_new_binding)
+    {
+      /* Put decls on list in reverse order.
+        We will reverse them later if necessary.  */
+      TREE_CHAIN (x) = current_binding_level->names;
+      current_binding_level->names = x;
+      if (! (current_binding_level != global_binding_level 
+            || TREE_PERMANENT (x)))
+       my_friendly_abort (124);
+    }
 
   return x;
 }
@@ -3801,7 +3922,7 @@ pushdecl_top_level (x)
 
 /* Make the declaration of X appear in CLASS scope.  */
 
-tree
+void
 pushdecl_class_level (x)
      tree x;
 {
@@ -3818,8 +3939,8 @@ pushdecl_class_level (x)
             Types, enums, and static vars are checked here; other
             members are checked in finish_struct.  */
          tree icv = IDENTIFIER_CLASS_VALUE (name);
-         tree ilv = IDENTIFIER_LOCAL_VALUE (name);
 
+         /* This should match check_member_decl_is_same_in_complete_scope.  */
          if (icv && icv != x
              && flag_optional_diags
              /* Don't complain about inherited names.  */
@@ -3833,26 +3954,13 @@ pushdecl_class_level (x)
                             icv);
            }
 
-         /* Check to see if decl redeclares a template parameter. */
-         if (ilv && ! decls_match (ilv, x)
-             && (current_class_type || current_function_decl) 
-             && current_template_parms)
-           {
-             if (decl_template_parm_p (ilv))
-               {
-                 cp_error ("re-using name of template parameter `%T' in this scope", name);
-                 cp_error_at (" previously declared here `%#D'", ilv);
-               }
-           }
+         check_template_shadow (x);
        }
 
       push_class_level_binding (name, x);
       if (TREE_CODE (x) == TYPE_DECL)
-       {
-         set_identifier_type_value (name, TREE_TYPE (x));
-       }
+       set_identifier_type_value (name, TREE_TYPE (x));
     }
-  return x;
 }
 
 #if 0
@@ -3895,12 +4003,20 @@ push_class_level_binding (name, x)
       && purpose_member (name, class_binding_level->class_shadowed))
     return;
 
+  /* If this declaration shadows a declaration from an enclosing
+     class, then we will need to restore IDENTIFIER_CLASS_VALUE when
+     we leave this class.  Record the shadowed declaration here.  */
   maybe_push_cache_obstack ();
   class_binding_level->class_shadowed
       = tree_cons (name, IDENTIFIER_CLASS_VALUE (name),
                   class_binding_level->class_shadowed);
   pop_obstacks ();
+
+  /* Put the binding on the stack of bindings for the identifier, and
+     update IDENTIFIER_CLASS_VALUE.  */
+  push_class_binding (name, x);
   IDENTIFIER_CLASS_VALUE (name) = x;
+
   obstack_ptr_grow (&decl_obstack, x);
 }
 
@@ -3955,11 +4071,11 @@ push_using_directive (used)
   return ud;
 }
 
-/* DECL is a FUNCTION_DECL which may have other definitions already in
-   place.  We get around this by making the value of the identifier point
-   to a list of all the things that want to be referenced by that name.  It
-   is then up to the users of that name to decide what to do with that
-   list.
+/* DECL is a FUNCTION_DECL for a non-member function, which may have
+   other definitions already in place.  We get around this by making
+   the value of the identifier point to a list of all the things that
+   want to be referenced by that name.  It is then up to the users of
+   that name to decide what to do with that list.
 
    DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its DECL_RESULT
    slot.  It is dealt with the same way.
@@ -3973,13 +4089,14 @@ push_overloaded_decl (decl, forgettable)
      tree decl;
      int forgettable;
 {
-  tree orig_name = DECL_NAME (decl);
+  tree name = DECL_NAME (decl);
   tree old;
+  tree new_binding;
   int doing_global = (namespace_bindings_p () || ! forgettable);
 
   if (doing_global)
     {
-      old = namespace_binding (orig_name, DECL_CONTEXT (decl));
+      old = namespace_binding (name, DECL_CONTEXT (decl));
       if (old && TREE_CODE (old) == FUNCTION_DECL
          && DECL_ARTIFICIAL (old)
          && (DECL_BUILT_IN (old) || DECL_BUILT_IN_NONANSI (old)))
@@ -3990,16 +4107,7 @@ push_overloaded_decl (decl, forgettable)
        }
     }
   else
-    {
-      old = IDENTIFIER_LOCAL_VALUE (orig_name);
-
-      if (! purpose_member (orig_name, current_binding_level->shadowed))
-       {
-         current_binding_level->shadowed
-           = tree_cons (orig_name, old, current_binding_level->shadowed);
-         old = NULL_TREE;
-       }
-    }
+    old = lookup_name_current_level (name);
 
   if (old)
     {
@@ -4032,17 +4140,44 @@ push_overloaded_decl (decl, forgettable)
   if (old || TREE_CODE (decl) == TEMPLATE_DECL)
     {
       if (old && TREE_CODE (old) != OVERLOAD)
-       old = ovl_cons (old, NULL_TREE);
-      old = ovl_cons (decl, old);
+       new_binding = ovl_cons (decl, ovl_cons (old, NULL_TREE));
+      else
+       new_binding = ovl_cons (decl, old);
     }
   else
-    /* orig_name is not ambiguous.  */
-    old = decl;
+    /* NAME is not ambiguous.  */
+    new_binding = decl;
 
   if (doing_global)
-    set_namespace_binding (orig_name, current_namespace, old);
+    set_namespace_binding (name, current_namespace, new_binding);
   else
-    IDENTIFIER_LOCAL_VALUE (orig_name) = old;
+    {
+      /* We only create an OVERLOAD if there was a previous binding at
+        this level.  In that case, we need to remove the old binding
+        and replace it with the new binding.  We must also run
+        through the NAMES on the current binding level to update the
+        chain.  */
+      if (TREE_CODE (new_binding) == OVERLOAD)
+       {
+         tree *d;
+         
+         for (d = &BINDING_LEVEL (IDENTIFIER_BINDING (name))->names;
+              *d;
+              d = &TREE_CHAIN (*d))
+           if (*d == old
+               || (TREE_CODE (*d) == TREE_LIST
+                   && TREE_VALUE (*d) == old))
+             {
+               *d = TREE_CHAIN (*d);
+               break;
+             }
+
+         pop_binding (name);
+       }
+
+      /* Install the new binding.  */
+      push_local_binding (name, new_binding);
+    }
 
   return decl;
 }
@@ -4107,7 +4242,7 @@ redeclaration_error_message (newdecl, olddecl)
       /* Because C++ can put things into name space for free,
         constructs like "typedef struct foo { ... } foo"
         would look like an erroneous redeclaration.  */
-      if (comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0))
+      if (same_type_p (TREE_TYPE (newdecl), TREE_TYPE (olddecl)))
        return 0;
       else
        return "redefinition of `%#D'";
@@ -4337,9 +4472,8 @@ define_label (filename, line, name)
                           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))))
+                       && !(DECL_INITIAL (new_decls) == NULL_TREE
+                            && pod_type_p (TREE_TYPE (new_decls))))
                      {
                        if (! identified) 
                          {
@@ -4349,8 +4483,13 @@ define_label (filename, line, name)
                                                      "  from here");
                            identified = 1;
                        }
-                       cp_error_at ("  crosses initialization of `%#D'",
-                                    new_decls);
+                       if (DECL_INITIAL (new_decls)
+                           || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls)))
+                         cp_error_at ("  crosses initialization of `%#D'",
+                                      new_decls);
+                       else
+                         cp_error_at ("  enters scope of non-POD `%#D'",
+                                        new_decls);
                      }
                    new_decls = TREE_CHAIN (new_decls);
                  }
@@ -4404,8 +4543,7 @@ pop_switch ()
 /* XXX Note decl is never actually used. (bpk) */
 
 void
-define_case_label (decl)
-     tree decl;
+define_case_label ()
 {
   tree cleanup = last_cleanup_this_contour ();
   struct binding_level *b = current_binding_level;
@@ -4748,6 +4886,11 @@ lookup_namespace_name (namespace, name)
   tree val;
 
   my_friendly_assert (TREE_CODE (namespace) == NAMESPACE_DECL, 370);
+
+  /* This happens for A::B<int> when B is a namespace. */
+  if (TREE_CODE (name) == NAMESPACE_DECL)
+    return name;
+
   my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 373);
   
   val = binding_init (&_b);
@@ -4768,11 +4911,111 @@ lookup_namespace_name (namespace, name)
   return error_mark_node;
 }
 
+/* Hash a TYPENAME_TYPE.  K is really of type `tree'.  */
+
+static unsigned long
+typename_hash (k)
+     hash_table_key k;
+{
+  unsigned long hash;
+  tree t;
+
+  t = (tree) k;
+  hash = (((unsigned long) TYPE_CONTEXT (t))
+         ^ ((unsigned long) DECL_NAME (TYPE_NAME (t))));
+
+  return hash;
+}
+
+/* Compare two TYPENAME_TYPEs.  K1 and K2 are really of type `tree'.  */
+
+static boolean
+typename_compare (k1, k2)
+     hash_table_key k1;
+     hash_table_key k2;
+{
+  tree t1;
+  tree t2;
+  tree d1;
+  tree d2;
+
+  t1 = (tree) k1;
+  t2 = (tree) k2;
+  d1 = TYPE_NAME (t1);
+  d2 = TYPE_NAME (t2);
+  
+  return (DECL_NAME (d1) == DECL_NAME (d2)
+         && same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2))
+         && ((TREE_TYPE (t1) != NULL_TREE) 
+             == (TREE_TYPE (t2) != NULL_TREE))
+         && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+         && TYPENAME_TYPE_FULLNAME (t1) == TYPENAME_TYPE_FULLNAME (t2));
+}
+
+/* Build a TYPENAME_TYPE.  If the type is `typename T::t', CONTEXT is
+   the type of `T', NAME is the IDENTIFIER_NODE for `t'.  If BASE_TYPE
+   is non-NULL, this type is being created by the implicit typename
+   extension, and BASE_TYPE is a type named `t' in some base class of
+   `T' which depends on template parameters.  
+
+   Returns the new TYPENAME_TYPE.  */
+
+tree
+build_typename_type (context, name, fullname, base_type)
+     tree context;
+     tree name;
+     tree fullname;
+     tree base_type;
+{
+  tree t;
+  tree d;
+  struct hash_entry* e;
+
+  static struct hash_table ht;
+
+  push_obstacks (&permanent_obstack, &permanent_obstack);
+
+  if (!ht.table
+      && !hash_table_init (&ht, &hash_newfunc, &typename_hash, 
+                          &typename_compare))
+    fatal ("virtual memory exhausted");
+
+  /* Build the TYPENAME_TYPE.  */
+  t = make_lang_type (TYPENAME_TYPE);
+  TYPE_CONTEXT (t) = FROB_CONTEXT (context);
+  TYPENAME_TYPE_FULLNAME (t) = fullname;
+  TREE_TYPE (t) = base_type;
+
+  /* Build the corresponding TYPE_DECL.  */
+  d = build_decl (TYPE_DECL, name, t);
+  TYPE_NAME (TREE_TYPE (d)) = d;
+  TYPE_STUB_DECL (TREE_TYPE (d)) = d;
+  DECL_CONTEXT (d) = FROB_CONTEXT (context);
+  DECL_ARTIFICIAL (d) = 1;
+
+  /* See if we already have this type.  */
+  e = hash_lookup (&ht, t, /*create=*/false, /*copy=*/0);
+  if (e)
+    {
+      /* This will free not only TREE_TYPE, but the lang-specific data
+        and the TYPE_DECL as well.  */
+      obstack_free (&permanent_obstack, t);
+      t = (tree) e->key;
+    }
+  else
+    /* Insert the type into the table.  */
+    hash_lookup (&ht, t, /*create=*/true, /*copy=*/0);
+
+  pop_obstacks ();
+
+  return t;
+}
+
 tree
 make_typename_type (context, name)
      tree context, name;
 {
-  tree t, d;
+  tree t;
   tree fullname;
 
   if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
@@ -4791,6 +5034,15 @@ make_typename_type (context, name)
   if (TREE_CODE (name) != IDENTIFIER_NODE)
     my_friendly_abort (2000);
 
+  if (TREE_CODE (context) == NAMESPACE_DECL)
+    {
+      /* We can get here from typename_sub0 in the explicit_template_type
+        expansion.  Just fail.  */
+      cp_error ("no class template named `%#T' in `%#T'",
+               name, context);
+      return error_mark_node;
+    }
+
   if (! uses_template_parms (context)
       || currently_open_class (context))
     {
@@ -4829,22 +5081,8 @@ make_typename_type (context, name)
          return TREE_TYPE (t);
        }
     }
-
-  if (processing_template_decl)
-    push_obstacks (&permanent_obstack, &permanent_obstack);
-  t = make_lang_type (TYPENAME_TYPE);
-  TYPENAME_TYPE_FULLNAME (t) = fullname;
-  d = build_decl (TYPE_DECL, name, t);
-  if (processing_template_decl)
-    pop_obstacks ();
-
-  TYPE_CONTEXT (t) = FROB_CONTEXT (context);
-  TYPE_NAME (TREE_TYPE (d)) = d;
-  TYPE_STUB_DECL (TREE_TYPE (d)) = d;
-  DECL_CONTEXT (d) = FROB_CONTEXT (context);
-  CLASSTYPE_GOT_SEMICOLON (t) = 1;
-
-  return t;
+  
+  return build_typename_type (context, name, fullname,  NULL_TREE);
 }
 
 /* Select the right _DECL from multiple choices. */
@@ -4991,7 +5229,6 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
   register tree val;
   int yylex = 0;
   tree from_obj = NULL_TREE;
-  tree locval, classval;
   int flags;
 
   /* Hack: copy flag set by parser, if set. */
@@ -5084,98 +5321,92 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
   else
     flags = lookup_flags (prefer_type, namespaces_only);
 
-  locval = classval = NULL_TREE;
-
-  if (! namespace_bindings_p ())
-    locval = qualify_lookup (IDENTIFIER_LOCAL_VALUE (name), flags);
-
-  /* In C++ class fields are between local and global scope,
-     just before the global scope.  */
-  if (current_class_type && ! nonclass)
-    {
-      classval = IDENTIFIER_CLASS_VALUE (name);
-      if (classval == NULL_TREE && TYPE_BEING_DEFINED (current_class_type))
-       /* Try to find values from base classes if we are presently
-          defining a type.  We are presently only interested in
-          TYPE_DECLs.  */
-       classval = lookup_field (current_class_type, name, 0, 1);
-
-      /* Add implicit 'typename' to types from template bases.  lookup_field
-         will do this for us.  If classval is actually from an enclosing
-         scope, lookup_nested_field will get it for us.  */
-      else if (processing_template_decl
-              && classval && TREE_CODE (classval) == TYPE_DECL
-              && ! currently_open_class (DECL_CONTEXT (classval))
-              && uses_template_parms (current_class_type))
-       classval = lookup_field (current_class_type, name, 0, 1);
+  /* First, look in a non-global scope, carefully avoiding any
+     class-scope bindings if required.  */
+  val = IDENTIFIER_BINDING (name); 
+  while (val && nonclass && !LOCAL_BINDING_P (val))
+    val = TREE_CHAIN (val);
 
-      /* yylex() calls this with -2, since we should never start digging for
-        the nested name at the point where we haven't even, for example,
-        created the COMPONENT_REF or anything like that.  */
-      if (classval == NULL_TREE)
-       classval = lookup_nested_field (name, ! yylex);
-
-      classval = qualify_lookup (classval, flags);
+  /* Get the DECL actually bound.  */
+  if (val)
+    val = BINDING_VALUE (val);
+
+  /* If VAL is a type from a dependent base, we're not really supposed
+     to be able to see it; the fact that we can is the "implicit
+     typename" extension.  We call lookup_field here to turn VAL into
+     a TYPE_DECL for a TYPENAME_TYPE.  */
+  if (processing_template_decl && val
+      && val == IDENTIFIER_CLASS_VALUE (name)
+      && TREE_CODE (val) == TYPE_DECL
+      && !currently_open_class (DECL_CONTEXT (val))
+      && uses_template_parms (current_class_type))
+    val = lookup_field (current_class_type, name, 0, 1);
+
+  /* Make sure that this binding is the sort of thing we're looking
+     for.  */
+  val = qualify_lookup (val, flags);
+
+  /* We don't put names from baseclasses onto the IDENTIFIER_BINDING
+     list when we're defining a type.  It would probably be simpler to
+     do this, but we don't.  So, we must lookup names from base
+     classes explicitly.  */
+  if (!val && !nonclass 
+      && current_class_type && TYPE_BEING_DEFINED (current_class_type))
+    {
+      val = qualify_lookup (lookup_field (current_class_type, name, 0, 0),
+                           flags);
+      if (!val)
+       val = qualify_lookup (lookup_nested_field (name, !yylex),
+                             flags);
     }
+  
+  /* If we found a type from a dependent base class (using the
+     implicit typename extension), turn it into the TYPE_DECL for a
+     TYPENAME_TYPE here.  */
+  if (val && TREE_CODE (val) == TYPE_DECL
+      && IMPLICIT_TYPENAME_P (TREE_TYPE (val)))
+    {
+      tree global_val;
+
+      /* Any other name takes precedence over an implicit typename.  Warn the
+        user about this potentially confusing lookup.  */
+      global_val = unqualified_namespace_lookup (name, flags);
+
+      if (global_val)
+       {
+         tree subtype;
+
+         /* Only warn when not lexing; we don't want to warn if they
+            use this name as a declarator.  */
+         subtype = TREE_TYPE (TREE_TYPE (val));
+         if (! yylex
+             && ! (TREE_CODE (global_val) == TEMPLATE_DECL
+                   && CLASSTYPE_TEMPLATE_INFO (subtype)
+                   && CLASSTYPE_TI_TEMPLATE (subtype) == global_val)
+             && ! (TREE_CODE (global_val) == TYPE_DECL
+                   && same_type_p (TREE_TYPE (global_val), subtype)))
+           {
+             cp_warning ("lookup of `%D' finds `%#D'", name, global_val);
+             cp_warning ("  instead of `%D' from dependent base class",
+                         val);
+             cp_warning ("  (use `typename %T::%D' if that's what you meant)",
+                         constructor_name (current_class_type), name);
+           }
 
-  if (locval && classval)
-    {
-      if (current_scope () == current_function_decl
-         && ! hack_decl_function_context (current_function_decl))
-       /* Not in a nested function.  */
-       val = locval;
-      else
-       {
-         /* This is incredibly horrible.  The whole concept of
-            IDENTIFIER_LOCAL_VALUE / IDENTIFIER_CLASS_VALUE /
-            IDENTIFIER_GLOBAL_VALUE needs to be scrapped for local
-            classes.  */
-         tree lctx = hack_decl_function_context (locval);
-         tree cctx = hack_decl_function_context (classval);
-
-         if (lctx == current_scope ())
-           val = locval;
-         else if (lctx == cctx)
-           val = classval;
-         else
-           /* I don't know which is right; let's just guess for now.  */
-           val = locval;
+         /* Use the global value instead of the implicit typename.  */
+         val = global_val;
        }
     }
-  else if (locval)
-    val = locval;
-  else if (classval)
-    val = classval;
-  else
+  else if (!val)
+    /* No local, or class-scoped binding.  Look for a namespace-scope
+       declaration.  */
     val = unqualified_namespace_lookup (name, flags);
 
-  if (classval && TREE_CODE (val) == TYPE_DECL
-      && TREE_CODE (TREE_TYPE (val)) == TYPENAME_TYPE
-      && TREE_TYPE (TREE_TYPE (val)))
+ done:
+  if (val)
     {
-      tree nsval = unqualified_namespace_lookup (name, flags);
-
-      if (val && nsval && TREE_CODE (nsval) == TYPE_DECL)
-       {
-         static int explained;
-         cp_warning ("namespace-scope type `%#D'", nsval);
-         cp_warning
-           ("  is used instead of `%D' from dependent base class", val);
-         if (! explained)
-           {
-             explained = 1;
-             cp_warning ("  (use `typename %D' if that's what you meant)",
-                         val);
-           }
-         val = nsval;
-       }
-    }
-
- done:
-  if (val)
-    {
-      /* This should only warn about types used in qualified-ids.  */
-      if (from_obj && from_obj != val)
+      /* This should only warn about types used in qualified-ids.  */
+      if (from_obj && from_obj != val)
        {
          if (looking_for_typename && TREE_CODE (from_obj) == TYPE_DECL
              && TREE_CODE (val) == TYPE_DECL
@@ -5194,17 +5425,6 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
            val = from_obj;
        }
 
-      if ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template)
-         || TREE_CODE (val) == TYPE_DECL || prefer_type <= 0)
-       ;
-      /* Caller wants a class-or-namespace-name. */
-      else if (prefer_type == 1 && TREE_CODE (val) == NAMESPACE_DECL)
-       ;
-      else if (IDENTIFIER_HAS_TYPE_VALUE (name))
-       val = TYPE_MAIN_DECL (IDENTIFIER_TYPE_VALUE (name));
-      else if (TREE_TYPE (val) == error_mark_node)
-       val = error_mark_node;
-
       /* If we have a single function from a using decl, pull it out.  */
       if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val))
        val = OVL_FUNCTION (val);
@@ -5262,13 +5482,16 @@ lookup_name_current_level (name)
       if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST)
        t = TREE_VALUE (t);
     }
-  else if (IDENTIFIER_LOCAL_VALUE (name) != NULL_TREE)
+  else if (IDENTIFIER_BINDING (name) 
+          && LOCAL_BINDING_P (IDENTIFIER_BINDING (name)))
     {
       struct binding_level *b = current_binding_level;
+
       while (1)
        {
-         if (purpose_member (name, b->shadowed))
-           return IDENTIFIER_LOCAL_VALUE (name);
+         if (BINDING_LEVEL (IDENTIFIER_BINDING (name)) == b)
+           return IDENTIFIER_VALUE (name);
+         
          if (b->keep == 2)
            b = b->level_chain;
          else
@@ -5489,7 +5712,7 @@ init_decl_processing ()
   tree string_ftype_ptr_ptr, int_ftype_string_string;
   tree sizetype_endlink;
   tree ptr_ftype, ptr_ftype_unsigned, ptr_ftype_sizetype;
-  tree void_ftype, void_ftype_int, void_ftype_ptr, ptr_ftype_void;
+  tree void_ftype, void_ftype_int, void_ftype_ptr;
 
   /* Have to make these distinct before we try using them.  */
   lang_name_cplusplus = get_identifier ("C++");
@@ -5506,6 +5729,8 @@ init_decl_processing ()
 
   if (flag_strict_prototype == 2)
     flag_strict_prototype = pedantic;
+  if (! flag_permissive && ! pedantic)
+    flag_pedantic_errors = 1;
 
   strict_prototypes_lang_c = flag_strict_prototype;
 
@@ -5518,7 +5743,6 @@ init_decl_processing ()
   current_binding_level = NULL_BINDING_LEVEL;
   free_binding_level = NULL_BINDING_LEVEL;
 
-#ifndef __CYGWIN32__
   /* Because most segmentation signals can be traced back into user
      code, catch them and at least give the user a chance of working
      around compiler bugs.  */
@@ -5540,13 +5764,6 @@ init_decl_processing ()
 #ifdef SIGBUS
   signal (SIGBUS, signal_catch);
 #endif
-#else /* ndef __CYGWIN32__ */
-  /* Cygwin32 cannot handle catching signals other than
-     SIGABRT yet.  We hope this will cease to be the case soon. */
-#ifdef SIGABRT
-  signal (SIGABRT, signal_catch);
-#endif
-#endif /* ndef __CYGWIN32__ */
 
   gcc_obstack_init (&decl_obstack);
 
@@ -5643,8 +5860,10 @@ init_decl_processing ()
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
   intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
+#if HOST_BITS_PER_WIDE_INT >= 64
   intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intTI_type_node));
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("__int128_t"), intTI_type_node));
+#endif
   unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
   unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
@@ -5653,8 +5872,10 @@ init_decl_processing ()
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
   unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
+#if HOST_BITS_PER_WIDE_INT >= 64
   unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node));
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("__uint128_t"), unsigned_intTI_type_node));
+#endif
 
   float_type_node = make_node (REAL_TYPE);
   TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
@@ -5750,7 +5971,8 @@ init_decl_processing ()
 
   string_type_node = build_pointer_type (char_type_node);
   const_string_type_node
-    = build_pointer_type (build_type_variant (char_type_node, 1, 0));
+    = build_pointer_type (build_qualified_type (char_type_node, 
+                                               TYPE_QUAL_CONST));
 #if 0
   record_builtin_type (RID_MAX, NULL_PTR, string_type_node);
 #endif
@@ -5780,7 +6002,8 @@ init_decl_processing ()
 
   ptr_type_node = build_pointer_type (void_type_node);
   const_ptr_type_node
-    = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+    = build_pointer_type (build_qualified_type (void_type_node,
+                                               TYPE_QUAL_CONST)); 
 #if 0
   record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node);
 #endif
@@ -5877,10 +6100,6 @@ init_decl_processing ()
   builtin_function ("__builtin_frame_address", ptr_ftype_unsigned,
                    BUILT_IN_FRAME_ADDRESS, NULL_PTR);
 
-  ptr_ftype_void = build_function_type (ptr_type_node, endlink);
-  builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
-  builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
-
   builtin_function ("__builtin_alloca", ptr_ftype_sizetype,
                    BUILT_IN_ALLOCA, "alloca");
   builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
@@ -6113,15 +6332,19 @@ init_decl_processing ()
       DECL_SIZE (fields[3]) = TYPE_SIZE (delta_type_node);
       TREE_UNSIGNED (fields[3]) = 0;
       TREE_CHAIN (fields[2]) = fields[3];
-      vtable_entry_type = build_type_variant (vtable_entry_type, 1, 0);
+      vtable_entry_type = build_qualified_type (vtable_entry_type,
+                                               TYPE_QUAL_CONST);
     }
   record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type);
 
   vtbl_type_node
-    = build_array_type (vtable_entry_type, NULL_TREE);
+    = build_cplus_array_type (vtable_entry_type, NULL_TREE);
   layout_type (vtbl_type_node);
-  vtbl_type_node = cp_build_type_variant (vtbl_type_node, 1, 0);
+  vtbl_type_node = build_qualified_type (vtbl_type_node, TYPE_QUAL_CONST);
   record_builtin_type (RID_MAX, NULL_PTR, vtbl_type_node);
+  vtbl_ptr_type_node = build_pointer_type (vtable_entry_type);
+  layout_type (vtbl_ptr_type_node);
+  record_builtin_type (RID_MAX, NULL_PTR, vtbl_ptr_type_node);
 
   /* Simplify life by making a "sigtable_entry_type".  Give its
      fields names so that the debugger can use them.  */
@@ -6156,7 +6379,8 @@ init_decl_processing ()
       TREE_UNSIGNED (fields[5]) = 0;
       TREE_CHAIN (fields[4]) = fields[5];
 
-      sigtable_entry_type = build_type_variant (sigtable_entry_type, 1, 0);
+      sigtable_entry_type = build_qualified_type (sigtable_entry_type, 
+                                                 TYPE_QUAL_CONST);
       record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type);
     }
 
@@ -6185,7 +6409,8 @@ init_decl_processing ()
       (void_ftype_ptr, build_tree_list (NULL_TREE, NULL_TREE));
     auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN);
     auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN);
-    auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN);
+    global_delete_fndecl
+      = auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN);
     auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype, NOT_BUILT_IN);
   }
 
@@ -6277,41 +6502,81 @@ define_function (name, type, function_code, pfn, library_name)
   return decl;
 }
 \f
-/* Called when a declaration is seen that contains no names to declare.
-   If its type is a reference to a structure, union or enum inherited
-   from a containing scope, shadow that tag name for the current scope
-   with a forward reference.
-   If its type defines a new named structure or union
-   or defines an enum, it is valid but we need not do anything here.
-   Otherwise, it is an error.
+/* When we call finish_struct for an anonymous union, we create
+   default copy constructors and such.  But, an anonymous union
+   shouldn't have such things; this function undoes the damage to the
+   anonymous union type T.
 
-   C++: may have to grok the declspecs to learn about static,
-   complain for anonymous unions.  */
+   (The reason that we create the synthesized methods is that we don't
+   distinguish `union { int i; }' from `typedef union { int i; } U'.
+   The first is an anonymous union; the second is just an ordinary
+   union type.)  */
 
 void
-shadow_tag (declspecs)
+fixup_anonymous_union (t)
+     tree t;
+{
+  tree *q;
+
+  /* Wipe out memory of synthesized methods */
+  TYPE_HAS_CONSTRUCTOR (t) = 0;
+  TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0;
+  TYPE_HAS_INIT_REF (t) = 0;
+  TYPE_HAS_CONST_INIT_REF (t) = 0;
+  TYPE_HAS_ASSIGN_REF (t) = 0;
+  TYPE_HAS_ASSIGNMENT (t) = 0;
+  TYPE_HAS_CONST_ASSIGN_REF (t) = 0;
+
+  /* Splice the implicitly generated functions out of the TYPE_METHODS
+     list.  */
+  q = &TYPE_METHODS (t);
+  while (*q)
+    {
+      if (DECL_ARTIFICIAL (*q))
+       *q = TREE_CHAIN (*q);
+      else
+       q = &TREE_CHAIN (*q);
+    }
+
+  /* ANSI C++ June 5 1992 WP 9.5.3.  Anonymous unions may not have
+     function members.  */
+  if (TYPE_METHODS (t))
+    error ("an anonymous union cannot have function members");
+}
+
+/* Make sure that a declaration with no declarator is well-formed, i.e.
+   just defines a tagged type or anonymous union.
+
+   Returns the type defined, if any.  */
+
+tree
+check_tag_decl (declspecs)
      tree declspecs;
 {
-  int found_tag = 0;
+  int found_type = 0;
   tree ob_modifier = NULL_TREE;
   register tree link;
-  register enum tree_code code, ok_code = ERROR_MARK;
   register tree t = NULL_TREE;
 
   for (link = declspecs; link; link = TREE_CHAIN (link))
     {
       register tree value = TREE_VALUE (link);
 
-      code = TREE_CODE (value);
-      if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE)
+      if (TYPE_P (value))
        {
-         my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
-
-         maybe_process_partial_specialization (value);
+         ++found_type;
 
-         t = value;
-         ok_code = code;
-         found_tag++;
+         if (IS_AGGR_TYPE (value) || TREE_CODE (value) == ENUMERAL_TYPE)
+           {
+             my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
+             t = value;
+           }
+       }
+      else if (value == ridpointers[(int) RID_FRIEND])
+       {
+         if (current_class_type == NULL_TREE
+             || current_scope () != current_class_type)
+           ob_modifier = value;
        }
       else if (value == ridpointers[(int) RID_STATIC]
               || value == ridpointers[(int) RID_EXTERN]
@@ -6319,47 +6584,67 @@ shadow_tag (declspecs)
               || value == ridpointers[(int) RID_REGISTER]
               || value == ridpointers[(int) RID_INLINE]
               || value == ridpointers[(int) RID_VIRTUAL]
+              || value == ridpointers[(int) RID_CONST]
+              || value == ridpointers[(int) RID_VOLATILE]
               || value == ridpointers[(int) RID_EXPLICIT])
        ob_modifier = value;
     }
 
+  if (found_type > 1)
+    error ("multiple types in one declaration");
+
+  /* Inside a class, we might be in a friend or access declaration.
+     Until we have a good way of detecting the latter, don't warn.  */
+  if (t == NULL_TREE && ! current_class_type)
+    pedwarn ("declaration does not declare anything");
+  else if (t && ANON_UNION_TYPE_P (t))
+    /* Anonymous unions are objects, so they can have specifiers.  */;
+  else if (ob_modifier)
+    {
+      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_FRIEND])
+       cp_error ("`%D' can only be specified inside a class", ob_modifier);
+      else if (ob_modifier == ridpointers[(int) RID_EXPLICIT])
+       cp_error ("`%D' can only be specified for constructors",
+                 ob_modifier);
+      else
+       cp_error ("`%D' can only be specified for objects and functions",
+                 ob_modifier);
+    }
+
+  return t;
+}
+
+/* Called when a declaration is seen that contains no names to declare.
+   If its type is a reference to a structure, union or enum inherited
+   from a containing scope, shadow that tag name for the current scope
+   with a forward reference.
+   If its type defines a new named structure or union
+   or defines an enum, it is valid but we need not do anything here.
+   Otherwise, it is an error.
+
+   C++: may have to grok the declspecs to learn about static,
+   complain for anonymous unions.  */
+
+void
+shadow_tag (declspecs)
+     tree declspecs;
+{
+  tree t = check_tag_decl (declspecs);
+
+  if (t)
+    maybe_process_partial_specialization (t);
+
   /* This is where the variables in an anonymous union are
      declared.  An anonymous union declaration looks like:
      union { ... } ;
      because there is no declarator after the union, the parser
      sends that declaration here.  */
-  if (ok_code == UNION_TYPE
-      && t != NULL_TREE
-      && ((TREE_CODE (TYPE_NAME (t)) == IDENTIFIER_NODE
-          && ANON_AGGRNAME_P (TYPE_NAME (t)))
-         || (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
-             && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))))
-    {
-      /* See also grok_x_components.  */
-      tree *q;
-
-      /* Wipe out memory of synthesized methods */
-      TYPE_HAS_CONSTRUCTOR (t) = 0;
-      TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0;
-      TYPE_HAS_INIT_REF (t) = 0;
-      TYPE_HAS_CONST_INIT_REF (t) = 0;
-      TYPE_HAS_ASSIGN_REF (t) = 0;
-      TYPE_HAS_ASSIGNMENT (t) = 0;
-      TYPE_HAS_CONST_ASSIGN_REF (t) = 0;
-
-      q = &TYPE_METHODS (t);
-      while (*q)
-       {
-         if (DECL_ARTIFICIAL (*q))
-           *q = TREE_CHAIN (*q);
-         else
-           q = &TREE_CHAIN (*q);
-       }
-
-      /* ANSI C++ June 5 1992 WP 9.5.3.  Anonymous unions may not have
-        function members.  */
-      if (TYPE_METHODS (t))
-       error ("an anonymous union cannot have function members");
+  if (t && ANON_UNION_TYPE_P (t))
+    {
+      fixup_anonymous_union (t);
 
       if (TYPE_FIELDS (t))
        {
@@ -6368,29 +6653,6 @@ shadow_tag (declspecs)
          finish_anon_union (decl);
        }
     }
-  else
-    {
-      /* Anonymous unions are objects, that's why we only check for
-        inappropriate specifiers in this branch.  */
-
-      if (ob_modifier)
-       {
-         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
-           cp_error ("`%D' can only be specified for objects and functions",
-                     ob_modifier);
-       }
-
-      if (found_tag == 0)
-       cp_error ("abstract declarator used as declaration");
-      else if (found_tag > 1)
-       pedwarn ("multiple types in one declaration");
-    }
 }
 \f
 /* Decode a "typename", such as "int **", returning a ..._TYPE node.  */
@@ -6559,6 +6821,8 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
 
   if (context && TYPE_SIZE (complete_type (context)) != NULL_TREE)
     {
+      pushclass (context, 2);
+
       if (TREE_CODE (decl) == VAR_DECL)
        {
          tree field = lookup_field (context, DECL_NAME (decl), 0, 0);
@@ -6595,15 +6859,27 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
       DECL_IN_AGGR_P (decl) = 0;
       if ((DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) 
          || CLASSTYPE_USE_TEMPLATE (context))
-       SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+       {
+         SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+         /* [temp.expl.spec] An explicit specialization of a static data
+            member of a template is a definition if the declaration
+            includes an initializer; otherwise, it is a declaration.
+
+            We check for processing_specialization so this only applies
+            to the new specialization syntax.  */
+         if (DECL_INITIAL (decl) == NULL_TREE && processing_specialization)
+           DECL_EXTERNAL (decl) = 1;
+       }
 
       if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl))
        cp_pedwarn ("declaration of `%#D' outside of class is not definition",
                    decl);
-
-      pushclass (context, 2);
     }
 
+#ifdef SET_DEFAULT_DECL_ATTRIBUTES
+  SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes);
+#endif
+  
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   cplus_decl_attributes (decl, attributes, prefix_attributes);
 
@@ -6646,7 +6922,7 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
      data segment.  */
   DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (tem);
 #endif
-
+  
   if (! processing_template_decl)
     start_decl_1 (tem);
 
@@ -6805,10 +7081,6 @@ grok_reference_init (decl, type, init)
       return;
     }
 
-  if (TREE_TYPE (init) && TREE_CODE (TREE_TYPE (init)) == UNKNOWN_TYPE)
-    /* decay_conversion is probably wrong for references to functions.  */
-    init = decay_conversion (instantiate_type (TREE_TYPE (type), init, 1));
-
   if (TREE_CODE (init) == TREE_LIST)
     init = build_compound_expr (init);
 
@@ -6889,6 +7161,25 @@ obscure_complex_init (decl, init)
   return init;
 }
 
+/* Issue an error message if DECL is an uninitialized const variable.  */
+
+static void
+check_for_uninitialized_const_var (decl)
+     tree decl;
+{
+  tree type = TREE_TYPE (decl);
+
+  /* ``Unless explicitly declared extern, a const object does not have
+     external linkage and must be initialized. ($8.4; $12.1)'' ARM
+     7.1.6 */
+  if (TREE_CODE (decl) == VAR_DECL
+      && TREE_CODE (type) != REFERENCE_TYPE
+      && CP_TYPE_CONST_P (type)
+      && !TYPE_NEEDS_CONSTRUCTING (type)
+      && !DECL_INITIAL (decl))
+    cp_error ("uninitialized const `%D'", decl);
+}
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -6945,6 +7236,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
       init = NULL_TREE;
     }
 
+  if (current_class_type
+      && DECL_REAL_CONTEXT (decl) == current_class_type
+      && TYPE_BEING_DEFINED (current_class_type)
+      && (DECL_INITIAL (decl) || init))
+    DECL_DEFINED_IN_CLASS_P (decl) = 1;
+
   if (TREE_CODE (decl) == VAR_DECL 
       && DECL_CONTEXT (decl)
       && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
@@ -7089,7 +7386,8 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
        {
          if (TREE_CODE (type) == ARRAY_TYPE)
            init = digest_init (type, init, (tree *) 0);
-         else if (TREE_CODE (init) == CONSTRUCTOR)
+         else if (TREE_CODE (init) == CONSTRUCTOR
+                  && TREE_HAS_CONSTRUCTOR (init))
            {
              if (TYPE_NON_AGGREGATE_CLASS (type))
                {
@@ -7130,32 +7428,16 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
                      decl);
        }
 
-      if (TREE_CODE (decl) == VAR_DECL
-         && !DECL_INITIAL (decl)
-         && !TYPE_NEEDS_CONSTRUCTING (type)
-         && (TYPE_READONLY (type) || TREE_READONLY (decl)))
-       cp_error ("uninitialized const `%D'", decl);
+      check_for_uninitialized_const_var (decl);
 
       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
-          && (TYPE_READONLY (type) || TREE_READONLY (decl)))
-    {
-      /* ``Unless explicitly declared extern, a const object does not have
-        external linkage and must be initialized. ($8.4; $12.1)'' ARM 7.1.6
-        However, if it's `const int foo = 1; const int foo;', don't complain
-        about the second decl, since it does have an initializer before.
-        We deliberately don't complain about arrays, because they're
-        supposed to be initialized by a constructor.  */
-      if (! DECL_INITIAL (decl)
-         && TREE_CODE (type) != ARRAY_TYPE
-         && (!pedantic || !current_class_type))
-       cp_error ("uninitialized const `%#D'", decl);
-    }
 
+    }
+  else
+    check_for_uninitialized_const_var (decl);
+  
   /* For top-level declaration, the initial value was read in
      the temporary obstack.  MAXINDEX, rtl, etc. to be made below
      must go in the permanent obstack; but don't discard the
@@ -7280,20 +7562,52 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
       if (was_temp)
        end_temporary_allocation ();
 
-      /* Extern inline function static data has external linkage.
-         Instead of trying to deal with that, we disable inlining of
-         such functions.  The ASM_WRITTEN check is to avoid hitting this
-         for __FUNCTION__.  */
+      /* Static data in a function with comdat linkage also has comdat
+         linkage.  */
       if (TREE_CODE (decl) == VAR_DECL
          && TREE_STATIC (decl)
+         /* Don't mess with __FUNCTION__.  */
          && ! TREE_ASM_WRITTEN (decl)
          && current_function_decl
          && DECL_CONTEXT (decl) == current_function_decl
-         && DECL_THIS_INLINE (current_function_decl)
+         && (DECL_THIS_INLINE (current_function_decl)
+             || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
          && TREE_PUBLIC (current_function_decl))
        {
+         /* Rather than try to get this right with inlining, we suppress
+            inlining of such functions.  */
          current_function_cannot_inline
            = "function with static variable cannot be inline";
+
+         /* If flag_weak, we don't need to mess with this, as we can just
+            make the function weak, and let it refer to its unique local
+            copy.  This works because we don't allow the function to be
+            inlined.  */
+         if (! flag_weak)
+           {
+             if (DECL_INTERFACE_KNOWN (current_function_decl))
+               {
+                 TREE_PUBLIC (decl) = 1;
+                 DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl);
+               }
+             else if (DECL_INITIAL (decl) == NULL_TREE
+                      || DECL_INITIAL (decl) == error_mark_node)
+               {
+                 TREE_PUBLIC (decl) = 1;
+                 DECL_COMMON (decl) = 1;
+               }
+             /* else we lose. We can only do this if we can use common,
+                 which we can't if it has been initialized.  */
+
+             if (TREE_PUBLIC (decl))
+               DECL_ASSEMBLER_NAME (decl)
+                 = build_static_name (current_function_decl, DECL_NAME (decl));
+             else if (! DECL_ARTIFICIAL (decl))
+               {
+                 cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
+                 cp_warning_at ("  you can work around this by removing the initializer"), decl;
+               }
+           }
        }
 
       else if (TREE_CODE (decl) == VAR_DECL
@@ -7471,7 +7785,8 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
 
          if (current_binding_level->is_for_scope)
            {
-             struct binding_level *outer = current_binding_level->level_chain;
+             struct binding_level *outer 
+               = current_binding_level->level_chain;
 
              /* Check to see if the same name is already bound at
                 the outer level, either because it was directly declared,
@@ -7483,36 +7798,20 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
                 Otherwise, we need to preserve the temp slot for decl
                 to last into the outer binding level.  */
 
-             int handling_dead_for_vars = 0;
-             tree link = outer->names;
-             for (; ; link = TREE_CHAIN (link))
+             tree outer_binding 
+               = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (decl)));
+             
+             if (outer_binding && BINDING_LEVEL (outer_binding) == outer
+                 && (TREE_CODE (BINDING_VALUE (outer_binding)) 
+                     == VAR_DECL)
+                 && DECL_DEAD_FOR_LOCAL (BINDING_VALUE (outer_binding)))
                {
-                 if (link == NULL && handling_dead_for_vars == 0)
-                   {
-                     link = outer->dead_vars_from_for;
-                     handling_dead_for_vars = 1;
-                   }
-                 if (link == NULL)
-                   {
-                     if (DECL_IN_MEMORY_P (decl))
-                       preserve_temp_slots (DECL_RTL (decl));
-                     break;
-                   }
-                 if (DECL_NAME (link) == DECL_NAME (decl))
-                   {
-                     if (handling_dead_for_vars)
-                       {
-                         tree shadowing
-                           = purpose_member (DECL_NAME (decl),
-                                             current_binding_level->shadowed);
-                         if (shadowing && TREE_VALUE (shadowing) == link)
-                           TREE_VALUE (shadowing)
-                             = DECL_SHADOWED_FOR_VAR (link);
-                       }
-                     current_binding_level->is_for_scope = 0;
-                     break;
-                   }
+                 BINDING_VALUE (outer_binding)
+                   = DECL_SHADOWED_FOR_VAR (BINDING_VALUE (outer_binding));
+                 current_binding_level->is_for_scope = 0;
                }
+             else if (DECL_IN_MEMORY_P (decl))
+               preserve_temp_slots (DECL_RTL (decl));
            }
 
          expand_start_target_temps ();
@@ -7527,7 +7826,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
                {
                  emit_line_note (DECL_SOURCE_FILE (decl),
                                  DECL_SOURCE_LINE (decl));
-                 expand_aggr_init (decl, init, 0, flags);
+                 expand_aggr_init (decl, init, flags);
                }
 
              /* Set this to 0 so we can tell whether an aggregate which
@@ -7647,26 +7946,59 @@ expand_static_init (decl, init)
       /* Remember this information until end of file.  */
       push_obstacks (&permanent_obstack, &permanent_obstack);
 
-      /* Emit code to perform this initialization but once.  */
+      /* Emit code to perform this initialization but once.  This code
+        looks like:
+
+           static int temp = 0;
+           if (!temp) {
+             // Do initialization.
+            temp = 1;
+            // Register variable for destruction at end of program.
+          }
+
+        Note that the `temp' variable is only set to 1 *after* the
+        initialization is complete.  This ensures that an exception,
+        thrown during the construction, will cause the variable to
+        reinitialized when we pass through this code again, as per:
+        
+          [stmt.dcl]
+
+          If the initialization exits by throwing an exception, the
+          initialization is not complete, so it will be tried again
+          the next time control enters the declaration.
+
+         In theory, this process should be thread-safe, too; multiple
+        threads should not be able to initialize the variable more
+        than once.  We don't yet attempt to ensure thread-safety.  */
       temp = get_temp_name (integer_type_node, 1);
       rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
+
+      /* Begin the conditional initialization.  */
       expand_start_cond (build_binary_op (EQ_EXPR, temp,
                                          integer_zero_node, 1), 0);
       expand_start_target_temps ();
 
-      expand_assignment (temp, integer_one_node, 0, 0);
+      /* Do the initialization itself.  */
       if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
          || (init && TREE_CODE (init) == TREE_LIST))
        {
-         expand_aggr_init (decl, init, 0, 0);
+         expand_aggr_init (decl, init, 0);
          do_pending_stack_adjust ();
        }
       else if (init)
        expand_assignment (decl, init, 0, 0);
 
-      /* Cleanup any temporaries needed for the initial value.  */
+      /* Set TEMP to 1.  */
+      expand_assignment (temp, integer_one_node, 0, 0);
+
+      /* Cleanup any temporaries needed for the initial value.  If
+        destroying one of the temporaries causes an exception to be
+        thrown, then the object itself has still been fully
+        constructed.  */
       expand_end_target_temps ();
 
+      /* Use atexit to register a function for destroying this static
+        variable.  */
       if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
        {
          tree cleanup, fcall;
@@ -7693,8 +8025,13 @@ expand_static_init (decl, init)
              pop_obstacks ();
            }
              
+         /* Call build_cleanup before we enter the anonymous function
+            so that any access checks will be done relative to the
+            current scope, rather than the scope of the anonymous
+            function.  */
+         fcall = build_cleanup (decl);
          cleanup = start_anon_func ();
-         expand_expr_stmt (build_cleanup (decl));
+         expand_expr_stmt (fcall);
          end_anon_func ();
          mark_addressable (cleanup);
          cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
@@ -7856,7 +8193,10 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
    or `volatile'.
    RAISES is a list of exceptions that this function can raise.
    CHECK is 1 if we must find this method in CTYPE, 0 if we should
-   not look, and -1 if we should not call `grokclassfn' at all.  */
+   not look, and -1 if we should not call `grokclassfn' at all.  
+
+   Returns `error_mark_node' if something goes wrong, after issuing
+   applicable error messages.  */
 
 static tree
 grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
@@ -7891,9 +8231,23 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
   if (TYPE_VOLATILE (type))
     TREE_THIS_VOLATILE (decl) = 1;
 
-  /* This decl is not from the current namespace. */
+  /* If this decl has namespace scope, set that up.  */
   if (in_namespace)
     set_decl_namespace (decl, in_namespace);
+  else if (publicp && ! ctype)
+    DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
+
+  /* `main' and builtins have implicit 'C' linkage.  */
+  if ((MAIN_NAME_P (declarator)
+       || (IDENTIFIER_LENGTH (declarator) > 10
+          && IDENTIFIER_POINTER (declarator)[0] == '_'
+          && IDENTIFIER_POINTER (declarator)[1] == '_'
+          && strncmp (IDENTIFIER_POINTER (declarator)+2, "builtin_", 8) == 0))
+      && current_lang_name == lang_name_cplusplus
+      && ctype == NULL_TREE
+      /* NULL_TREE means global namespace.  */
+      && DECL_CONTEXT (decl) == NULL_TREE)
+    DECL_LANGUAGE (decl) = lang_c;
 
   /* Should probably propagate const out from type to decl I bet (mrs).  */
   if (staticp)
@@ -7905,8 +8259,10 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
   if (ctype)
     DECL_CLASS_CONTEXT (decl) = ctype;
 
-  if (ctype == NULL_TREE && MAIN_NAME_P (declarator))
+  if (ctype == NULL_TREE && DECL_MAIN_P (decl))
     {
+      if (processing_template_decl)
+       error ("cannot declare `main' to be a template");
       if (inlinep)
        error ("cannot declare `main' to be inline");
       else if (! publicp)
@@ -7915,8 +8271,10 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
       publicp = 1;
     }
 
-  /* Members of anonymous types have no linkage; make them internal.  */
-  if (ctype && ANON_AGGRNAME_P (TYPE_IDENTIFIER (ctype)))
+  /* Members of anonymous types and local classes have no linkage; make
+     them internal.  */
+  if (ctype && (ANON_AGGRNAME_P (TYPE_IDENTIFIER (ctype))
+               || hack_decl_function_context (TYPE_MAIN_DECL (ctype))))
     publicp = 0;
 
   if (publicp)
@@ -7930,7 +8288,13 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
       if (t)
        {
          if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
-           cp_pedwarn ("non-local function `%#D' uses anonymous type", decl);
+           {
+             if (DECL_LANGUAGE (decl) == lang_c)
+               /* Allow this; it's pretty common in C.  */;
+             else
+               cp_pedwarn ("non-local function `%#D' uses anonymous type",
+                           decl);
+           }
          else
            cp_pedwarn ("non-local function `%#D' uses local type `%T'",
                        decl, t);
@@ -7996,6 +8360,17 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
        }
     }
 
+  /* Plain overloading: will not be grok'd by grokclassfn.  */
+  if (! ctype && ! processing_template_decl
+      && DECL_LANGUAGE (decl) != lang_c
+      && (! DECL_USE_TEMPLATE (decl) || name_mangling_version < 1))
+    set_mangled_name_for_decl (decl);
+
+  if (funcdef_flag)
+    /* Make the init_value nonzero so pushdecl knows this is not
+       tentative.  error_mark_node is replaced later with the BLOCK.  */
+    DECL_INITIAL (decl) = error_mark_node;
+
   /* Caller will do the rest of this.  */
   if (check < 0)
     return decl;
@@ -8013,7 +8388,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
         the following calls is supposed to do.  */
       DECL_CONSTRUCTOR_P (decl) = 1;
 
-      grokclassfn (ctype, declarator, decl, flags, quals);
+      grokclassfn (ctype, decl, flags, quals);
 
       decl = check_explicit_specialization (orig_declarator, decl,
                                            template_count, 
@@ -8022,7 +8397,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
       if (decl == error_mark_node)
        return error_mark_node;
 
-      if ((! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
+      if ((! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
          && check)
        {
          tmp = check_classfn (ctype, decl);
@@ -8036,23 +8411,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
            return tmp;
        }
       if (! grok_ctor_properties (ctype, decl))
-       return NULL_TREE;
-
-      if (check == 0 && ! current_function_decl)
-       {
-         /* Assembler names live in the global namespace. */
-         tmp = IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl));
-         if (tmp == NULL_TREE)
-           SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl);
-         else if (TREE_CODE (tmp) != TREE_CODE (decl))
-           cp_error ("inconsistent declarations for `%D'", decl);
-         else
-           {
-             duplicate_decls (decl, tmp);
-             decl = tmp;
-           }
-         make_decl_rtl (decl, NULL_PTR, 1);
-       }
+       return error_mark_node;
     }
   else
     {
@@ -8062,7 +8421,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
         This call may change the type of the function (because
         of default parameters)!  */
       if (ctype != NULL_TREE)
-       grokclassfn (ctype, cname, decl, flags, quals);
+       grokclassfn (ctype, decl, flags, quals);
 
       decl = check_explicit_specialization (orig_declarator, decl,
                                            template_count, 
@@ -8072,7 +8431,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
        return error_mark_node;
 
       if (ctype != NULL_TREE
-         && (! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
+         && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
          && check)
        {
          tmp = check_classfn (ctype, decl);
@@ -8101,37 +8460,11 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
       if (ctype == NULL_TREE || check)
        return decl;
 
-      /* Now install the declaration of this function so that others may
-        find it (esp. its DECL_FRIENDLIST).  Don't do this for local class
-        methods, though.  */
-      if (! current_function_decl)
-       {
-         if (!DECL_TEMPLATE_SPECIALIZATION (decl))
-           {
-             /* We don't do this for specializations since the
-                equivalent checks will be done later.  Also, at this
-                point the DECL_ASSEMBLER_NAME is not yet fully
-                accurate.  */
-
-             /* FIXME: this should only need to look at
-                IDENTIFIER_GLOBAL_VALUE.  */
-             tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
-             if (tmp == NULL_TREE)
-               SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl);
-             else if (TREE_CODE (tmp) != TREE_CODE (decl))
-               cp_error ("inconsistent declarations for `%D'", decl);
-             else
-               {
-                 duplicate_decls (decl, tmp);
-                 decl = tmp;
-               }
-           }
+      if (attrlist)
+       cplus_decl_attributes (decl, TREE_PURPOSE (attrlist), 
+                              TREE_VALUE (attrlist));
+      make_decl_rtl (decl, NULL_PTR, 1);
 
-         if (attrlist)
-           cplus_decl_attributes (decl, TREE_PURPOSE (attrlist),
-                                  TREE_VALUE (attrlist));
-         make_decl_rtl (decl, NULL_PTR, 1);
-       }
       if (virtualp)
        {
          DECL_VIRTUAL_P (decl) = 1;
@@ -8170,12 +8503,23 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
     }
   else
     {
-      tree context = in_namespace ? in_namespace : current_namespace;
+      tree context;
+
+      if (in_namespace)
+       context = in_namespace;
+      else if (namespace_bindings_p () || RIDBIT_SETP (RID_EXTERN, specbits))
+       context = current_namespace;
+      else
+       context = NULL_TREE;
+
       decl = build_decl (VAR_DECL, declarator, complete_type (type));
-      if (context != global_namespace && namespace_bindings_p ()
-         && current_lang_name != lang_name_c)
-       DECL_ASSEMBLER_NAME (decl) =  build_static_name (context,
-                                                        declarator);
+
+      if (context)
+       set_decl_namespace (decl, context);
+
+      context = DECL_CONTEXT (decl);
+      if (declarator && context && current_lang_name != lang_name_c)
+       DECL_ASSEMBLER_NAME (decl) = build_static_name (context, declarator);
     }
 
   if (in_namespace)
@@ -8251,7 +8595,7 @@ build_ptrmemfunc_type (type)
   push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
 
   u = make_lang_type (UNION_TYPE);
-  IS_AGGR_TYPE (u) = 0;
+  SET_IS_AGGR_TYPE (u, 0);
   fields[0] = build_lang_field_decl (FIELD_DECL, pfn_identifier, type);
   fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier,
                                     delta_type_node);
@@ -8263,7 +8607,7 @@ build_ptrmemfunc_type (type)
   /* Let the front-end know this is a pointer to member function...  */
   TYPE_PTRMEMFUNC_FLAG (t) = 1;
   /* ... and not really an aggregate.  */
-  IS_AGGR_TYPE (t) = 0;
+  SET_IS_AGGR_TYPE (t, 0);
 
   fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier,
                                     delta_type_node);
@@ -8343,6 +8687,41 @@ build_ptrmemfunc_type (type)
 
 enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
 
+/* DECL is a VAR_DECL defined in-class, whose TYPE is also given.
+   Check to see that the definition is valid.  Issue appropriate error
+   messages.  Return 1 if the definition is particularly bad, or 0
+   otherwise.  */
+
+int
+check_static_variable_definition (decl, type)
+     tree decl;
+     tree type;
+{
+  /* Motion 10 at San Diego: If a static const integral data member is
+     initialized with an integral constant expression, the initializer
+     may appear either in the declaration (within the class), or in
+     the definition, but not both.  If it appears in the class, the
+     member is a member constant.  The file-scope definition is always
+     required.  */
+  if (CLASS_TYPE_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      cp_error ("in-class initialization of static data member of non-integral type `%T'", 
+               type);
+      /* If we just return the declaration, crashes will sometimes
+        occur.  We therefore return void_type_node, as if this was a
+        friend declaration, to cause callers to completely ignore
+        this declaration.  */
+      return 1;
+    }
+  else if (!CP_TYPE_CONST_P (type))
+    cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
+             decl);
+  else if (pedantic && !INTEGRAL_TYPE_P (type))
+    cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type);
+
+  return 0;
+}
+
 tree
 grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
      tree declspecs;
@@ -8357,7 +8736,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   tree type = NULL_TREE;
   int longlong = 0;
   int constp;
+  int restrictp;
   int volatilep;
+  int type_quals;
   int virtualp, explicitp, friendp, inlinep, staticp;
   int explicit_int = 0;
   int explicit_char = 0;
@@ -8390,6 +8771,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   tree raises = NULL_TREE;
   int template_count = 0;
   tree in_namespace = NULL_TREE;
+  tree inner_attrs;
+  int ignore_attrs;
 
   RIDBIT_RESET_ALL (specbits);
   if (decl_context == FUNCDEF)
@@ -8411,6 +8794,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        decl = *next;
        switch (TREE_CODE (decl))
          {
+         case TREE_LIST:
+           /* For attributes.  */
+           next = &TREE_VALUE (decl);
+           break;
+
          case COND_EXPR:
            ctype = NULL_TREE;
            next = &TREE_OPERAND (decl, 0);
@@ -8478,10 +8866,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                init = TREE_OPERAND (decl, 1);
 
                decl = start_decl (declarator, declspecs, 1, NULL_TREE, NULL_TREE);
-               /* Look for __unused__ attribute */
-               if (TREE_USED (TREE_TYPE (decl)))
-                 TREE_USED (decl) = 1;
-               finish_decl (decl, init, NULL_TREE);
+               if (decl)
+                 {
+                   /* Look for __unused__ attribute */
+                   if (TREE_USED (TREE_TYPE (decl)))
+                     TREE_USED (decl) = 1;
+                   finish_decl (decl, init, NULL_TREE);
+                 }
+               else
+                 cp_error ("invalid declarator");
                return 0;
              }
            innermost_code = TREE_CODE (decl);
@@ -8858,24 +9251,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        }
       else
        {
-         if (funcdef_flag)
-           {
-             if (warn_return_type
-                 && return_type == return_normal)
-               /* Save warning until we know what is really going on.  */
-               warn_about_return_type = 1;
-           }
-         else if (RIDBIT_SETP (RID_TYPEDEF, specbits))
-           pedwarn ("ANSI C++ forbids typedef which does not specify a type");
-         else if (innermost_code != CALL_EXPR || pedantic
-                  || (warn_return_type && return_type == return_normal))
-           {
-             if (innermost_code == CALL_EXPR)
-               cp_pedwarn ("return-type of `%D' defaults to `int'", dname);
-             else
-               cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type",
-                           dname);
-           }
+         if (! pedantic && ! warn_return_type
+             && funcdef_flag
+             && MAIN_NAME_P (dname)
+             && ctype == NULL_TREE
+             && in_namespace == NULL_TREE
+             && current_namespace == global_namespace)
+           /* Let `main () { }' slide, since it's so common.  */;
+         else
+           cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type",
+                       dname);
          type = integer_type_node;
        }
     }
@@ -8891,7 +9276,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
     }
   else if (return_type == return_conversion)
     {
-      if (comptypes (type, ctor_return_type, 1) == 0)
+      if (!same_type_p (type, ctor_return_type))
        cp_error ("operator `%T' declared to return `%T'",
                  ctor_return_type, type);
       else
@@ -8912,8 +9297,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       && TYPE_MAIN_VARIANT (type) == double_type_node)
     {
       RIDBIT_RESET (RID_LONG, specbits);
-      type = build_type_variant (long_double_type_node, TYPE_READONLY (type),
-                                TYPE_VOLATILE (type));
+      type = build_qualified_type (long_double_type_node, 
+                                  CP_TYPE_QUALS (type));
     }
 
   /* Check all other uses of type modifiers.  */
@@ -9035,17 +9420,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
   if (return_type == return_conversion 
       && (RIDBIT_SETP (RID_CONST, specbits)
-         || RIDBIT_SETP (RID_VOLATILE, specbits)))
-    cp_error ("`operator %T' cannot be cv-qualified",
+         || RIDBIT_SETP (RID_VOLATILE, specbits)
+         || RIDBIT_SETP (RID_RESTRICT, specbits)))
+    cp_error ("qualifiers are not allowed on declaration of `operator %T'",
              ctor_return_type);
 
   /* Set CONSTP if this declaration is `const', whether by
      explicit specification or via a typedef.
      Likewise for VOLATILEP.  */
 
-  constp = !! RIDBIT_SETP (RID_CONST, specbits) + TYPE_READONLY (type);
-  volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type);
-  type = build_type_variant (type, 0, 0);
+  constp = !! RIDBIT_SETP (RID_CONST, specbits) + CP_TYPE_CONST_P (type);
+  restrictp = 
+    !! RIDBIT_SETP (RID_RESTRICT, specbits) + CP_TYPE_RESTRICT_P (type);
+  volatilep = 
+    !! RIDBIT_SETP (RID_VOLATILE, specbits) + CP_TYPE_VOLATILE_P (type);
+  type_quals = ((constp ? TYPE_QUAL_CONST : 0)
+               | (restrictp ? TYPE_QUAL_RESTRICT : 0)
+               | (volatilep ? TYPE_QUAL_VOLATILE : 0));
+  type = cp_build_qualified_type (type, type_quals);
   staticp = 0;
   inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
   virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
@@ -9065,6 +9457,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   friendp = RIDBIT_SETP (RID_FRIEND, specbits);
   RIDBIT_RESET (RID_FRIEND, specbits);
 
+  /* $7.1.2, Function specifiers */
+  if (friendp && explicitp)
+    error ("only declarations of constructors can be `explicit'");
+
   if (RIDBIT_SETP (RID_MUTABLE, specbits))
     {
       if (decl_context == PARM)
@@ -9122,16 +9518,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       && IS_SIGNATURE (current_class_type)
       && RIDBIT_NOTSETP (RID_TYPEDEF, specbits))
     {
-      if (constp)
-       {
-         error ("`const' specified for signature member function `%s'", name);
-         constp = 0;
-       }
-      if (volatilep)
+      if (type_quals != TYPE_UNQUALIFIED)
        {
-         error ("`volatile' specified for signature member function `%s'",
-                name);
-         volatilep = 0;
+         error ("type qualifiers specified for signature member function `%s'", name);
+         type_quals = TYPE_UNQUALIFIED;
        }
       if (inlinep)
        {
@@ -9218,7 +9608,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        {
          /* It's common practice (and completely valid) to have a const
             be initialized and declared extern.  */
-         if (! constp)
+         if (!(type_quals & TYPE_QUAL_CONST))
            warning ("`%s' initialized and declared `extern'", name);
        }
       else
@@ -9240,6 +9630,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
      Descend through it, creating more complex types, until we reach
      the declared identifier (or NULL_TREE, in an absolute declarator).  */
 
+  inner_attrs = NULL_TREE;
+  ignore_attrs = 0;  
+
   while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE
         && TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
     {
@@ -9286,8 +9679,32 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              quals = NULL_TREE;
            }
        }
+
+      /* See the comment for the TREE_LIST case, below.  */
+      if (ignore_attrs)
+       ignore_attrs = 0;
+      else if (inner_attrs)
+       {
+         decl_attributes (type, inner_attrs, NULL_TREE);
+         inner_attrs = NULL_TREE;
+       }
+
       switch (TREE_CODE (declarator))
        {
+       case TREE_LIST:
+         {
+           /* We encode a declarator with embedded attributes using
+              a TREE_LIST.  The attributes apply to the declarator
+              directly inside them, so we have to skip an iteration
+              before applying them to the type.  If the declarator just
+              inside is the declarator-id, we apply the attrs to the
+              decl itself.  */
+           inner_attrs = TREE_PURPOSE (declarator);
+           ignore_attrs = 1;
+           declarator = TREE_VALUE (declarator);
+         }
+         break;
+
        case ARRAY_REF:
          {
            register tree itype = NULL_TREE;
@@ -9341,6 +9758,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
            if (size == error_mark_node)
              type = error_mark_node;
+           else if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
+             {
+               /* [dcl.array]
+
+                  the constant expressions that specify the bounds of
+                  the arrays can be omitted only for the first member
+                  of the sequence.  */
+               cp_error ("declaration of `%D' as multidimensional array",
+                         dname);
+               cp_error ("must have bounds for all dimensions except the first");
+               type = error_mark_node;
+             }
 
            if (type == error_mark_node)
              continue;
@@ -9363,6 +9792,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                   constant, but we don't know what the value is yet.  */
                if (processing_template_decl)
                  {
+                   /* Resolve a qualified reference to an enumerator or
+                      static const data member of ours.  */
+                   if (TREE_CODE (size) == SCOPE_REF
+                       && TREE_OPERAND (size, 0) == current_class_type)
+                     {
+                       tree t = lookup_field (current_class_type,
+                                              TREE_OPERAND (size, 1), 0, 0);
+                       if (t)
+                         size = t;
+                     }
+
                    itype = make_node (INTEGER_TYPE);
                    TYPE_MIN_VALUE (itype) = size_zero_node;
                    TYPE_MAX_VALUE (itype) = build_min
@@ -9371,7 +9811,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  }
 
                if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE
-                   && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE)
+                   && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE
+                   && TREE_CODE (TREE_TYPE (size)) != BOOLEAN_TYPE)
                  {
                    cp_error ("size of array `%D' has non-integer type",
                              dname);
@@ -9439,15 +9880,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                resume_momentary (yes);
              }
 
-         /* Build the array type itself, then merge any constancy or
-            volatility into the target type.  We must do it in this order
-            to ensure that the TYPE_MAIN_VARIANT field of the array type
-            is set correctly.  */
-
            type = build_cplus_array_type (type, itype);
-           if (constp || volatilep)
-             type = cp_build_type_variant (type, constp, volatilep);
-
            ctype = NULL_TREE;
          }
          break;
@@ -9461,23 +9894,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
            /* Declaring a function type.
               Make sure we have a valid type for the function to return.  */
-#if 0
-           /* Is this an error?  Should they be merged into TYPE here?  */
-           if (pedantic && (constp || volatilep))
-             pedwarn ("function declared to return const or volatile result");
-#else
-           /* Merge any constancy or volatility into the function return
-               type.  */
 
-           if (constp || volatilep)
-             {
-               type = cp_build_type_variant (type, constp, volatilep);
-               if (IS_AGGR_TYPE (type))
-                 build_pointer_type (type);
-               constp = 0;
-               volatilep = 0;
-             }
-#endif
+           /* We now know that the TYPE_QUALS don't apply to the
+               decl, but to its return type.  */
+           type_quals = TYPE_UNQUALIFIED;
 
            /* Warn about some types functions can't return.  */
 
@@ -9536,8 +9956,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                      error ("destructor cannot be static member function");
                    if (quals)
                      {
-                       error ("destructors cannot be declared `const' or `volatile'");
-                       return void_type_node;
+                       cp_error ("destructors may not be `%s'",
+                                 IDENTIFIER_POINTER (TREE_VALUE (quals)));
+                       quals = NULL_TREE;
                      }
                    if (decl_context == FIELD)
                      {
@@ -9562,8 +9983,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                      }
                    if (quals)
                      {
-                       error ("constructors cannot be declared `const' or `volatile'");
-                       return void_type_node;
+                       cp_error ("constructors may not be `%s'",
+                                 IDENTIFIER_POINTER (TREE_VALUE (quals)));
+                       quals = NULL_TREE;
                      }
                    {
                      RID_BIT_TYPE tmp_bits;
@@ -9621,24 +10043,22 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
            arg_types = grokparms (inner_parms, funcdecl_p ? funcdef_flag : 0);
 
-           if (declarator)
+           if (declarator && flags == DTOR_FLAG)
              {
-               /* Get past destructors, etc.
-                  We know we have one because FLAGS will be non-zero.
-
-                  Complain about improper parameter lists here.  */
+               /* A destructor declared in the body of a class will
+                  be represented as a BIT_NOT_EXPR.  But, we just
+                  want the underlying IDENTIFIER.  */
                if (TREE_CODE (declarator) == BIT_NOT_EXPR)
+                 declarator = TREE_OPERAND (declarator, 0);
+               
+               if (strict_prototype == 0 && arg_types == NULL_TREE)
+                 arg_types = void_list_node;
+               else if (arg_types == NULL_TREE
+                        || arg_types != void_list_node)
                  {
-                   declarator = TREE_OPERAND (declarator, 0);
-
-                   if (strict_prototype == 0 && arg_types == NULL_TREE)
-                     arg_types = void_list_node;
-                   else if (arg_types == NULL_TREE
-                            || arg_types != void_list_node)
-                     {
-                       error ("destructors cannot be specified with parameters");
-                       arg_types = void_list_node;
-                     }
+                   cp_error ("destructors may not have parameters");
+                   arg_types = void_list_node;
+                   last_function_parms = NULL_TREE;
                  }
              }
 
@@ -9685,21 +10105,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          /* Merge any constancy or volatility into the target type
             for the pointer.  */
 
-         if (constp || volatilep)
-           {
-             /* A const or volatile signature pointer/reference is
-                pointing to a const or volatile object, i.e., the
-                `optr' is const or volatile, respectively, not the
-                signature pointer/reference itself.  */
-             if (! IS_SIGNATURE (type))
-               {
-                 type = cp_build_type_variant (type, constp, volatilep);
-                 if (IS_AGGR_TYPE (type))
-                   build_pointer_type (type);
-                 constp = 0;
-                 volatilep = 0;
-               }
-           }
+         /* We now know that the TYPE_QUALS don't apply to the decl,
+            but to the target of the pointer.  */
+         type_quals = TYPE_UNQUALIFIED;
 
          if (IS_SIGNATURE (type))
            {
@@ -9710,8 +10118,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                    cp_warning ("empty signature `%T' used in signature reference declaration",
                                type);
 #if 0
-                 type = build_signature_reference_type (type,
-                                                        constp, volatilep);
+                 type = build_signature_reference_type (type);
 #else
                  sorry ("signature reference");
                  return NULL_TREE;
@@ -9723,26 +10130,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                      && TYPE_SIZE (type))
                    cp_warning ("empty signature `%T' used in signature pointer declaration",
                                type);
-                 type = build_signature_pointer_type (type,
-                                                      constp, volatilep);
+                 type = build_signature_pointer_type (type);
                }
-             constp = 0;
-             volatilep = 0;
            }
          else if (TREE_CODE (declarator) == ADDR_EXPR)
            {
-             if (TREE_CODE (type) == FUNCTION_TYPE)
-               {
-                 error ("cannot declare references to functions; use pointer to function instead");
-                 type = build_pointer_type (type);
-               }
+             if (TREE_CODE (type) == VOID_TYPE)
+               error ("invalid type: `void &'");
              else
-               {
-                 if (TREE_CODE (type) == VOID_TYPE)
-                   error ("invalid type: `void &'");
-                 else
-                   type = build_reference_type (type);
-               }
+               type = build_reference_type (type);
            }
          else if (TREE_CODE (type) == METHOD_TYPE)
            {
@@ -9758,25 +10154,37 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            {
              register tree typemodlist;
              int erred = 0;
+
+             constp = 0;
+             volatilep = 0;
+             restrictp = 0;
              for (typemodlist = TREE_TYPE (declarator); typemodlist;
                   typemodlist = TREE_CHAIN (typemodlist))
                {
-                 if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST])
+                 tree qualifier = TREE_VALUE (typemodlist);
+
+                 if (qualifier == ridpointers[(int) RID_CONST])
                    constp++;
-                 else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE])
+                 else if (qualifier == ridpointers[(int) RID_VOLATILE])
                    volatilep++;
+                 else if (qualifier == ridpointers[(int) RID_RESTRICT])
+                   restrictp++;
                  else if (!erred)
                    {
                      erred = 1;
-                     error ("invalid type modifier within %s declarator",
-                            TREE_CODE (declarator) == ADDR_EXPR
-                            ? "reference" : "pointer");
+                     error ("invalid type modifier within pointer declarator");
                    }
                }
              if (constp > 1)
                pedwarn ("duplicate `const'");
              if (volatilep > 1)
                pedwarn ("duplicate `volatile'");
+             if (restrictp > 1)
+               pedwarn ("duplicate `restrict'");
+
+             type_quals = ((constp ? TYPE_QUAL_CONST : 0)
+                           | (restrictp ? TYPE_QUAL_RESTRICT : 0)
+                           | (volatilep ? TYPE_QUAL_VOLATILE : 0));
              if (TREE_CODE (declarator) == ADDR_EXPR
                  && (constp || volatilep))
                {
@@ -9784,8 +10192,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                    pedwarn ("discarding `const' applied to a reference");
                  if (volatilep)
                    pedwarn ("discarding `volatile' applied to a reference");
-                 constp = volatilep = 0;
+                 type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
                }
+             type = cp_build_qualified_type (type, type_quals);
            }
          declarator = TREE_OPERAND (declarator, 0);
          ctype = NULL_TREE;
@@ -9854,7 +10263,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            ctype = TREE_OPERAND (declarator, 0);
 
            t = ctype;
-           while (t != NULL_TREE) 
+           while (t != NULL_TREE && CLASS_TYPE_P (t)
              {
                if (CLASSTYPE_TEMPLATE_INFO (t) &&
                    !CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
@@ -9890,8 +10299,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  {
                    if (current_class_type == NULL_TREE
                        || friendp)
-                     type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
-                                                     TREE_TYPE (type), TYPE_ARG_TYPES (type));
+                     type = build_cplus_method_type (ctype, TREE_TYPE (type),
+                                                     TYPE_ARG_TYPES (type));
                    else
                      {
                        cp_error ("cannot declare member function `%T::%s' within `%T'",
@@ -9919,10 +10328,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  {
                     if (TREE_CODE (type) == FUNCTION_TYPE)
                      type
-                       = build_cplus_method_type (build_type_variant (ctype,
-                                                                      constp,
-                                                                      volatilep),
-                                                  TREE_TYPE (type),
+                       = build_cplus_method_type (ctype, TREE_TYPE (type),
                                                   TYPE_ARG_TYPES (type));
                  }
                else
@@ -9945,7 +10351,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                else
                  {
                    if (TREE_CODE (type) == FUNCTION_TYPE)
-                     type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), TREE_TYPE (type), TYPE_ARG_TYPES (type));
+                     type = build_cplus_method_type (ctype, TREE_TYPE (type),
+                                                     TYPE_ARG_TYPES (type));
                    else
                      type = build_offset_type (ctype, type);
                  }
@@ -9972,6 +10379,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        }
     }
 
+  /* See the comment for the TREE_LIST case, above.  */
+  if (inner_attrs)
+    {
+      if (! ignore_attrs)
+       decl_attributes (type, inner_attrs, NULL_TREE);
+      else if (attrlist)
+       TREE_VALUE (attrlist) = chainon (inner_attrs, TREE_VALUE (attrlist));
+      else
+       attrlist = build_decl_list (NULL_TREE, inner_attrs);
+    }
+
   if (explicitp == 1)
     {
       error ("only constructors can be declared `explicit'");
@@ -9984,7 +10402,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
   if (RIDBIT_SETP (RID_MUTABLE, specbits))
     {
-      if (constp)
+      if (type_quals & TYPE_QUAL_CONST)
        {
          error ("const `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
@@ -10002,14 +10420,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
       /* Note that the grammar rejects storage classes
         in typenames, fields or parameters.  */
-      if (constp || volatilep)
-       type = cp_build_type_variant (type, constp, volatilep);
       if (current_lang_name == lang_name_java)
        TYPE_FOR_JAVA (type) = 1;
 
       if (decl_context == FIELD)
        {
-         if (declarator == current_class_name)
+         if (declarator == constructor_name (current_class_type))
            cp_pedwarn ("ANSI C++ forbids nested type `%D' with same name as enclosing class",
                        declarator);
          decl = build_lang_decl (TYPE_DECL, declarator, type);
@@ -10036,6 +10452,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
          && ANON_AGGRNAME_P (TYPE_IDENTIFIER (type)))
        {
+         /* FIXME: This is bogus; we should not be doing this for
+                   cv-qualified types.  */
+
          /* For anonymous structs that are cv-qualified, need to use
              TYPE_MAIN_VARIANT so that name will mangle correctly. As
              type not referenced after this block, don't bother
@@ -10049,6 +10468,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          if (TYPE_LANG_SPECIFIC (type))
            TYPE_WAS_ANONYMOUS (type) = 1;
 
+         /* If this is a typedef within a template class, the nested
+            type is a (non-primary) template.  The name for the
+            template needs updating as well.  */
+         if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_TEMPLATE_INFO (type))
+           DECL_NAME (CLASSTYPE_TI_TEMPLATE (type)) 
+             = TYPE_IDENTIFIER (type);
+
          /* XXX Temporarily set the scope. 
             When returning, start_decl expects it as NULL_TREE,
             and will then then set it using pushdecl. */
@@ -10090,9 +10516,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
 
       if (RIDBIT_SETP (RID_MUTABLE, specbits))
-       {
-         error ("non-object member `%s' cannot be declared mutable", name);
-       }
+       error ("non-object member `%s' cannot be declared mutable", name);
 
       bad_specifiers (decl, "type", virtualp, quals != NULL_TREE,
                      inlinep, friendp, raises != NULL_TREE);
@@ -10122,21 +10546,20 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
     {
       /* Note that the grammar rejects storage classes
         in typenames, fields or parameters.  */
-      if (constp || volatilep)
+      if (type_quals != TYPE_UNQUALIFIED)
        {
          if (IS_SIGNATURE (type))
-           error ("`const' or `volatile' specified with signature type");
-         else  
-           type = cp_build_type_variant (type, constp, volatilep);
+           error ("type qualifiers specified for signature type");
+         type_quals = TYPE_UNQUALIFIED;
        }
 
       /* Special case: "friend class foo" looks like a TYPENAME context.  */
       if (friendp)
        {
-         if (volatilep)
+         if (type_quals != TYPE_UNQUALIFIED)
            {
-             cp_error ("`volatile' specified for friend class declaration");
-             volatilep = 0;
+             cp_error ("type qualifiers specified for friend class declaration");
+             type_quals = TYPE_UNQUALIFIED;
            }
          if (inlinep)
            {
@@ -10203,36 +10626,38 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   /* Now create the decl, which may be a VAR_DECL, a PARM_DECL
      or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE.  */
 
+  if (decl_context == PARM || decl_context == CATCHPARM)
+    {
+      if (ctype || in_namespace)
+       error ("cannot use `::' in parameter declaration");
+
+      /* A parameter declared as an array of T is really a pointer to T.
+        One declared as a function is really a pointer to a function.
+        One declared as a member is really a pointer to member.  */
+
+      if (TREE_CODE (type) == ARRAY_TYPE)
+       {
+         /* Transfer const-ness of array into that of type pointed to.  */
+         type = build_pointer_type (TREE_TYPE (type));
+         type_quals = TYPE_UNQUALIFIED;
+       }
+      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 (TREE_CODE (type) == VOID_TYPE && declarator)
+       {
+         error ("declaration of `%s' as void", name);
+         return NULL_TREE;
+       }
+    }
+  
   {
     register tree decl;
 
     if (decl_context == PARM)
       {
-       if (ctype || in_namespace)
-         error ("cannot use `::' in parameter declaration");
-
-       /* A parameter declared as an array of T is really a pointer to T.
-          One declared as a function is really a pointer to a function.
-          One declared as a member is really a pointer to member.  */
-
-       if (TREE_CODE (type) == ARRAY_TYPE)
-         {
-           /* Transfer const-ness of array into that of type pointed to.  */
-           type = build_pointer_type
-             (cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
-           volatilep = constp = 0;
-         }
-       else if (TREE_CODE (type) == FUNCTION_TYPE)
-         type = build_pointer_type (type);
-       else if (TREE_CODE (type) == OFFSET_TYPE)
-         type = build_pointer_type (type);
-       else if (TREE_CODE (type) == VOID_TYPE && declarator)
-         {
-           error ("declaration of `%s' as void", name);
-           return NULL_TREE;
-         }
-
-       decl = build_decl (PARM_DECL, declarator, complete_type (type));
+       decl = build_decl (PARM_DECL, declarator, type);
 
        bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE,
                        inlinep, friendp, raises != NULL_TREE);
@@ -10262,7 +10687,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
               are error_mark_node, for example.  */
            decl = NULL_TREE;
          }
-       else if (in_namespace)
+       else if (in_namespace && !friendp)
          {
            /* Something like struct S { int N::j; };  */
            cp_error ("invalid use of `::'");
@@ -10316,8 +10741,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                      }
                  }
                else if (staticp < 2)
-                 type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
-                                                 TREE_TYPE (type), TYPE_ARG_TYPES (type));
+                 type = build_cplus_method_type (ctype, TREE_TYPE (type),
+                                                 TYPE_ARG_TYPES (type));
              }
 
            /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node.  */
@@ -10332,16 +10757,45 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                               virtualp, flags, quals, raises, attrlist,
                               friendp ? -1 : 0, friendp, publicp, inlinep,
                               funcdef_flag, template_count, in_namespace);
-           if (decl == NULL_TREE)
-             return NULL_TREE;
+           if (decl == NULL_TREE || decl == error_mark_node)
+             return decl;
 #if 0
            /* This clobbers the attrs stored in `decl' from `attrlist'.  */
            /* The decl and setting of decl_machine_attr is also turned off.  */
            decl = build_decl_attribute_variant (decl, decl_machine_attr);
 #endif
 
+           /* [class.conv.ctor]
+
+              A constructor declared without the function-specifier
+              explicit that can be called with a single parameter
+              specifies a conversion from the type of its first
+              parameter to the type of its class.  Such a constructor
+              is called a converting constructor.  */
            if (explicitp == 2)
              DECL_NONCONVERTING_P (decl) = 1;
+           else if (DECL_CONSTRUCTOR_P (decl))
+             {
+               /* The constructor can be called with exactly one
+                  parameter if there is at least one parameter, and
+                  any subsequent parameters have default arguments.
+                  We don't look at the first parameter, which is
+                  really just the `this' parameter for the new
+                  object.  */
+               tree arg_types = 
+                 TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl)));
+
+               /* Skip the `in_chrg' argument too, if present.  */
+               if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (decl)))
+                 arg_types = TREE_CHAIN (arg_types);
+
+               if (arg_types == void_list_node
+                   || (arg_types 
+                       && TREE_CHAIN (arg_types) 
+                       && TREE_CHAIN (arg_types) != void_list_node
+                       && !TREE_PURPOSE (TREE_CHAIN (arg_types))))
+                 DECL_NONCONVERTING_P (decl) = 1;
+             }
          }
        else if (TREE_CODE (type) == METHOD_TYPE)
          {
@@ -10440,47 +10894,36 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                       the rest of the compiler does not correctly
                       handle the initialization unless the member is
                       static so we make it static below.  */
-                   cp_pedwarn ("ANSI C++ forbids initialization of %s `%D'",
-                               constp ? "const member" : "member", 
+                   cp_pedwarn ("ANSI C++ forbids initialization of member `%D'",
                                declarator);
                    cp_pedwarn ("making `%D' static", declarator);
                    staticp = 1;
                  }
 
-               /* Motion 10 at San Diego: If a static const integral data
-                  member is initialized with an integral constant
-                  expression, the initializer may appear either in the
-                  declaration (within the class), or in the definition,
-                  but not both.  If it appears in the class, the member is
-                  a member constant.  The file-scope definition is always
-                  required.  */
-               if (CLASS_TYPE_P (type)
-                   || TREE_CODE (type) == REFERENCE_TYPE)
-                 {
-                   cp_error ("in-class initialization of static data member of non-integral type `%T'", 
-                             type);
-                   /* If we just return the declaration, crashes will
-                      sometimes occur.  We therefore return
-                      void_type_node, as if this was a friend
-                      declaration, to cause callers to completely
-                      ignore this declaration.  */
-                   return void_type_node;
-                 }
-               else if (!constp)
-                 cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
-                           declarator);
-               else if (pedantic && ! INTEGRAL_TYPE_P (type) 
-                        && !uses_template_parms (type))
-                 cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", declarator, type);
+               if (uses_template_parms (type))
+                 /* We'll check at instantiation time.  */
+                 ;
+               else if (check_static_variable_definition (declarator,
+                                                          type))
+                 /* If we just return the declaration, crashes
+                    will sometimes occur.  We therefore return
+                    void_type_node, as if this was a friend
+                    declaration, to cause callers to completely
+                    ignore this declaration.  */
+                 return void_type_node;
              }
 
+           /* 9.2p13 [class.mem] */
+           if (declarator == constructor_name (current_class_type)
+               /* Divergence from the standard:  In extern "C", we
+                  allow non-static data members here, because C does
+                  and /usr/include/netinet/in.h uses that.  */
+               && (staticp || current_lang_name != lang_c))
+             cp_pedwarn ("ANSI C++ forbids data member `%D' with same name as enclosing class",
+                         declarator);
+
            if (staticp)
              {
-               /* ANSI C++ Apr '95 wp 9.2 */
-               if (declarator == current_class_name)
-                 cp_pedwarn ("ANSI C++ forbids static member `%D' with same name as enclosing class",
-                             declarator);
-
                /* C++ allows static class members.
                   All other work for this is done by grokfield.
                   This VAR_DCL is built by build_lang_field_decl.
@@ -10543,22 +10986,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                error ("virtual non-class function `%s'", name);
                virtualp = 0;
              }
-
-           if (current_lang_name == lang_name_cplusplus
-               && ! processing_template_decl
-               && ! MAIN_NAME_P (original_name)
-               && ! (IDENTIFIER_LENGTH (original_name) > 10
-                     && IDENTIFIER_POINTER (original_name)[0] == '_'
-                     && IDENTIFIER_POINTER (original_name)[1] == '_'
-                     && strncmp (IDENTIFIER_POINTER (original_name)+2, "builtin_", 8) == 0))
-             /* Plain overloading: will not be grok'd by grokclassfn.  */
-             if (name_mangling_version < 1 
-                 || TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
-               declarator = build_decl_overload (dname, TYPE_ARG_TYPES (type), 0);
          }
        else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2)
-         type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
-                                         TREE_TYPE (type), TYPE_ARG_TYPES (type));
+         type = build_cplus_method_type (ctype, TREE_TYPE (type),
+                                         TYPE_ARG_TYPES (type));
 
        /* Record presence of `static'.  */
        publicp = (ctype != NULL_TREE
@@ -10578,11 +11009,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        if (decl == error_mark_node)
          return error_mark_node;
 
-       if (ctype == NULL_TREE && DECL_LANGUAGE (decl) != lang_c
-           && (! DECL_USE_TEMPLATE (decl) ||
-               name_mangling_version < 1)) 
-         DECL_ASSEMBLER_NAME (decl) = declarator;
-       
        if (staticp == 1)
          {
            int illegal_static = 0;
@@ -10612,35 +11038,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       {
        /* It's a variable.  */
 
-       if (decl_context == CATCHPARM)
-         {
-           if (ctype)
-             {
-               ctype = NULL_TREE;
-               error ("cannot use `::' in parameter declaration");
-             }
-
-           /* A parameter declared as an array of T is really a pointer to T.
-              One declared as a function is really a pointer to a function.
-              One declared as a member is really a pointer to member.  */
-
-           if (TREE_CODE (type) == ARRAY_TYPE)
-             {
-               /* Transfer const-ness of array into that of type
-                   pointed to.  */
-               type = build_pointer_type
-                 (cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
-               volatilep = constp = 0;
-             }
-           else if (TREE_CODE (type) == FUNCTION_TYPE)
-             type = build_pointer_type (type);
-           else if (TREE_CODE (type) == OFFSET_TYPE)
-             type = build_pointer_type (type);
-         }
-
        /* An uninitialized decl with `extern' is a reference.  */
        decl = grokvardecl (type, declarator, &specbits, 
-                           initialized, constp, in_namespace);
+                           initialized, 
+                           (type_quals & TYPE_QUAL_CONST) != 0, 
+                           in_namespace);
        bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE,
                        inlinep, friendp, raises != NULL_TREE);
 
@@ -10685,14 +11087,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       DECL_THIS_STATIC (decl) = 1;
 
     /* Record constancy and volatility.  */
-
-    if (constp)
-      TREE_READONLY (decl) = TREE_CODE (type) != REFERENCE_TYPE;
-    if (volatilep)
-      {
-       TREE_SIDE_EFFECTS (decl) = 1;
-       TREE_THIS_VOLATILE (decl) = 1;
-      }
+    /* FIXME: Disallow `restrict' pointer-to-member declarations.  */
+    c_apply_type_quals_to_decl (type_quals, decl);
 
     return decl;
   }
@@ -10725,18 +11121,14 @@ parmlist_is_exprlist (exprs)
   return 1;
 }
 
-/* Subroutine of `grokparms'.  In a fcn definition, arg types must
-   be complete.
-
-   C++: also subroutine of `start_function'.  */
+/* Subroutine of start_function.  Ensure that each of the parameter
+   types (as listed in PARMS) is complete, as is required for a
+   function definition.  */
 
 static void
 require_complete_types_for_parms (parms)
      tree parms;
 {
-  if (processing_template_decl)
-    return;
-
   while (parms)
     {
       tree type = TREE_TYPE (parms);
@@ -10749,31 +11141,9 @@ require_complete_types_for_parms (parms)
            error ("parameter has incomplete type");
          TREE_TYPE (parms) = error_mark_node;
        }
-#if 0
-      /* If the arg types are incomplete in a declaration,
-        they must include undefined tags.
-        These tags can never be defined in the scope of the declaration,
-        so the types can never be completed,
-        and no call can be compiled successfully.  */
-      /* This is not the right behavior for C++, but not having
-        it is also probably wrong.  */
       else
-       {
-         /* Now warn if is a pointer to an incomplete type.  */
-         while (TREE_CODE (type) == POINTER_TYPE
-                || TREE_CODE (type) == REFERENCE_TYPE)
-           type = TREE_TYPE (type);
-         type = TYPE_MAIN_VARIANT (type);
-         if (TYPE_SIZE (type) == NULL_TREE)
-           {
-             if (DECL_NAME (parm) != NULL_TREE)
-               warning ("parameter `%s' points to incomplete type",
-                        IDENTIFIER_POINTER (DECL_NAME (parm)));
-             else
-               warning ("parameter points to incomplete type");
-           }
-       }
-#endif
+       layout_decl (parms, 0);
+
       parms = TREE_CHAIN (parms);
     }
 }
@@ -10870,9 +11240,13 @@ grokparms (first_parm, funcdef_flag)
                                         TREE_PURPOSE (decl),
                                         PARM, init != NULL_TREE,
                                         NULL_TREE);
-                 if (! decl)
+                 if (! decl || TREE_TYPE (decl) == error_mark_node)
                    continue;
-                 type = TREE_TYPE (decl);
+
+                 /* Top-level qualifiers on the parameters are
+                    ignored for function types.  */
+                 type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
+
                  if (TREE_CODE (type) == VOID_TYPE)
                    decl = void_type_node;
                  else if (TREE_CODE (type) == METHOD_TYPE)
@@ -10963,24 +11337,32 @@ grokparms (first_parm, funcdef_flag)
                      /* Unparsed default arg from in-class decl.  */
                      else if (TREE_CODE (init) == DEFAULT_ARG)
                        ;
-                     else if (TREE_CODE (init) == VAR_DECL
-                              || TREE_CODE (init) == PARM_DECL)
+                     else if (TREE_CODE (init) == PARM_DECL
+                              || TREE_CODE (init) == VAR_DECL)
                        {
-                         if (IDENTIFIER_LOCAL_VALUE (DECL_NAME (init)))
+                         if (TREE_CODE (init) == VAR_DECL
+                             && (IDENTIFIER_VALUE (DECL_NAME (init))
+                                 == init)
+                             && LOCAL_BINDING_P
+                             (IDENTIFIER_BINDING (DECL_NAME
+                                                  (init))))
                            {
-                             /* ``Local variables may not be used in default
-                                argument expressions.'' dpANSI C++ 8.2.6 */
-                             /* If extern int i; within a function is not
-                                considered a local variable, then this code is
-                                wrong.  */
+                             /* ``Local variables may not be used in
+                                default argument expressions.''
+                                dpANSI C++ 8.2.6 */
+
                              cp_error ("local variable `%D' may not be used as a default argument", init);
                              any_error = 1;
                            }
                          else if (TREE_READONLY_DECL_P (init))
                            init = decl_constant_value (init);
                        }
-                     else
-                       init = require_instantiated_type (type, init, integer_zero_node);
+                     else if (TREE_TYPE (init) == NULL_TREE)
+                       {
+                         error ("argument list may not have an initializer list");
+                         init = error_mark_node;
+                       }
+
                      if (! processing_template_decl
                          && init != error_mark_node
                          && TREE_CODE (init) != DEFAULT_ARG
@@ -11032,10 +11414,6 @@ grokparms (first_parm, funcdef_flag)
 
   last_function_parms = decls;
 
-  /* In a fcn definition, arg types must be complete.  */
-  if (funcdef_flag > 0)
-    require_complete_types_for_parms (last_function_parms);
-
   return result;
 }
 
@@ -11100,19 +11478,45 @@ grok_ctor_properties (ctype, decl)
       parmtype = TREE_VALUE (parmtypes);
     }
 
+  /* [class.copy]
+
+     A non-template constructor for class X is a copy constructor if
+     its first parameter is of type X&, const X&, volatile X& or const
+     volatile X&, and either there are no other parameters or else all
+     other parameters have default arguments.  */
   if (TREE_CODE (parmtype) == REFERENCE_TYPE
       && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype
       && (TREE_CHAIN (parmtypes) == NULL_TREE
          || TREE_CHAIN (parmtypes) == void_list_node
-         || TREE_PURPOSE (TREE_CHAIN (parmtypes))))
+         || TREE_PURPOSE (TREE_CHAIN (parmtypes)))
+      && !(DECL_TEMPLATE_INSTANTIATION (decl)
+          && is_member_template (DECL_TI_TEMPLATE (decl))))
     {
       TYPE_HAS_INIT_REF (ctype) = 1;
-      if (TYPE_READONLY (TREE_TYPE (parmtype)))
+      if (CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
        TYPE_HAS_CONST_INIT_REF (ctype) = 1;
     }
+  /* [class.copy]
+
+     A declaration of a constructor for a class X is ill-formed if its
+     first parameter is of type (optionally cv-qualified) X and either
+     there are no other parameters or else all other parameters have
+     default arguments.  
+
+     We *don't* complain about member template instantiations that
+     have this form, though; they can occur as we try to decide what
+     constructor to use during overload resolution.  Since overload
+     resolution will never prefer such a constructor to the
+     non-template copy constructor (which is either explicitly or
+     implicitly defined), there's no need to worry about their
+     existence.  Theoretically, they should never even be
+     instantiated, but that's hard to forestall.  */
   else if (TYPE_MAIN_VARIANT (parmtype) == ctype
-          && TREE_CHAIN (parmtypes) != NULL_TREE
-          && TREE_CHAIN (parmtypes) == void_list_node)
+          && (TREE_CHAIN (parmtypes) == NULL_TREE
+              || TREE_CHAIN (parmtypes) == void_list_node
+              || TREE_PURPOSE (TREE_CHAIN (parmtypes)))
+          && !(DECL_TEMPLATE_INSTANTIATION (decl)
+               && is_member_template (DECL_TI_TEMPLATE (decl))))
     {
       cp_error ("invalid constructor; you probably meant `%T (const %T&)'",
                ctype, ctype);
@@ -11168,7 +11572,15 @@ grok_op_properties (decl, virtualp, friendp)
 
   if (! friendp)
     {
-      if (name == ansi_opname[(int) MODIFY_EXPR])
+      /* [class.copy]
+
+        A user-declared copy assignment operator X::operator= is a
+        non-static non-template member function of class X with
+        exactly one parameter of type X, X&, const X&, volatile X& or
+        const volatile X&.  */
+      if (name == ansi_opname[(int) MODIFY_EXPR]
+         && !(DECL_TEMPLATE_INSTANTIATION (decl)
+              && is_member_template (DECL_TI_TEMPLATE (decl))))
        TYPE_HAS_ASSIGNMENT (current_class_type) = 1;
       else if (name == ansi_opname[(int) CALL_EXPR])
        TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1;
@@ -11312,7 +11724,7 @@ grok_op_properties (decl, virtualp, friendp)
            {
              TYPE_HAS_ASSIGN_REF (current_class_type) = 1;
              if (TREE_CODE (parmtype) != REFERENCE_TYPE
-                 || TYPE_READONLY (TREE_TYPE (parmtype)))
+                 || CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
                TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1;
            }
        }
@@ -11364,14 +11776,14 @@ grok_op_properties (decl, virtualp, friendp)
              if (list_length (argtypes) == 2)
                {
                  if (TREE_CODE (ret) != REFERENCE_TYPE
-                     || !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ret)),
-                                    arg, 1))
+                     || !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ret)),
+                                      arg))
                    cp_warning ("prefix `%D' should return `%T'", decl,
                                build_reference_type (arg));
                }
              else
                {
-                 if (!comptypes (TYPE_MAIN_VARIANT (ret), arg, 1))
+                 if (!same_type_p (TYPE_MAIN_VARIANT (ret), arg))
                    cp_warning ("postfix `%D' should return `%T'", decl, arg);
                }
            }
@@ -11433,6 +11845,27 @@ grok_op_properties (decl, virtualp, friendp)
     }
 }
 \f
+static char *
+tag_name (code)
+     enum tag_types code;
+{
+  switch (code)
+    {
+    case record_type:
+      return "struct";
+    case class_type:
+      return "class";
+    case union_type:
+      return "union ";
+    case enum_type:
+      return "enum";
+    case signature_type:
+      return "signature";
+    default:
+      my_friendly_abort (981122);
+    }
+}
+
 /* Get the struct, enum or union (CODE says which) with tag NAME.
    Define the tag as a forward-reference if it is not defined.
 
@@ -11495,25 +11928,16 @@ xref_tag (code_type_node, name, globalize)
     }
   else
     t = IDENTIFIER_TYPE_VALUE (name);
+
   if (t && TREE_CODE (t) != code && TREE_CODE (t) != TEMPLATE_TYPE_PARM
       && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM)
     t = NULL_TREE;
 
   if (! globalize)
     {
-      if (t && (TREE_CODE (t) == TEMPLATE_TYPE_PARM 
-                           || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM))
-       {
-         cp_error ("redeclaration of template type-parameter `%T'", name);
-         cp_error_at ("  previously declared here `%#D'", 
-                      TEMPLATE_TYPE_DECL (t));
-       }
-      if (t && TYPE_CONTEXT (t) && got_type)
-       ref = t;
-      else
-       /* 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.  */
-       ref = lookup_tag (code, name, b, 1);
+      /* 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.  */
+      ref = lookup_tag (code, name, b, 1);
     }
   else
     {
@@ -11546,7 +11970,12 @@ xref_tag (code_type_node, name, globalize)
       else 
        {
          if (t)
-           ref = t;
+           {
+             if (t != TYPE_MAIN_VARIANT (t))
+               cp_pedwarn ("using typedef-name `%D' after `%s'",
+                           TYPE_NAME (t), tag_name (tag_code));
+             ref = t;
+           }
          else
            ref = lookup_tag (code, name, b, 0);
          
@@ -11669,6 +12098,19 @@ xref_tag (code_type_node, name, globalize)
 
   TREE_TYPE (ref) = attributes;
 
+  if (ref && TYPE_P (ref))
+    {
+      /* [dcl.type.elab]
+            
+        If the identifier resolves to a typedef-name or a template
+        type-parameter, the elaborated-type-specifier is
+        ill-formed.  */
+      if (TYPE_LANG_SPECIFIC (ref) && TYPE_WAS_ANONYMOUS (ref))
+       cp_error ("`%T' is a typedef name", ref);
+      else if (TREE_CODE (ref) == TEMPLATE_TYPE_PARM)
+       cp_error ("`%T' is a template type paramter", ref);
+    }
+
   return ref;
 }
 
@@ -11783,9 +12225,12 @@ xref_basetypes (code_type_node, name, ref, binfo)
             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));
+         base_binfo 
+           = make_binfo (integer_zero_node, basetype,
+                         CLASS_TYPE_P (basetype)
+                         ? TYPE_BINFO_VTABLE (basetype) : NULL_TREE,
+                         CLASS_TYPE_P (basetype)
+                         ? TYPE_BINFO_VIRTUALS (basetype) : NULL_TREE);
  
          TREE_VEC_ELT (binfos, i) = base_binfo;
          TREE_VIA_PUBLIC (base_binfo) = via_public;
@@ -11807,9 +12252,12 @@ xref_basetypes (code_type_node, name, ref, binfo)
              TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
            }
 
-         TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype);
-         TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
-         CLASSTYPE_LOCAL_TYPEDECLS (ref) |= CLASSTYPE_LOCAL_TYPEDECLS (basetype);
+         if (CLASS_TYPE_P (basetype))
+           {
+             TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype);
+             TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
+           }
+
          i += 1;
        }
     }
@@ -11821,8 +12269,14 @@ xref_basetypes (code_type_node, name, ref, binfo)
   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)));
+    {
+      tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, 0));
+      
+      if (CLASS_TYPE_P (basetype))
+       TYPE_USES_MULTIPLE_INHERITANCE (ref)
+         = TYPE_USES_MULTIPLE_INHERITANCE (basetype);
+    }
+
   if (TYPE_USES_MULTIPLE_INHERITANCE (ref))
     TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
 
@@ -11835,8 +12289,6 @@ xref_basetypes (code_type_node, name, ref, binfo)
 }
   
 \f
-tree current_local_enum = NULL_TREE;
-
 /* Begin compiling the definition of an enumeration type.
    NAME is its name (or null if anonymous).
    Returns the type object, as yet incomplete.
@@ -11852,11 +12304,7 @@ start_enum (name)
 
   /* We are wasting space here and putting these on the permanent_obstack so
      that typeid(local enum) will work correctly. */
-#if 0
-  if (processing_template_decl && current_function_decl)
-#endif
-   
-  end_temporary_allocation ();
+  push_obstacks (&permanent_obstack, &permanent_obstack);
 
   /* If this is the real definition for a previous forward reference,
      fill in the contents in the same object that used to be the
@@ -11876,8 +12324,6 @@ start_enum (name)
   if (current_class_type)
     TREE_ADDRESSABLE (b->tags) = 1;
 
-  current_local_enum = NULL_TREE;
-
   /* We don't copy this value because build_enumerator needs to do it.  */
   enum_next_value = integer_zero_node;
   enum_overflow = 0;
@@ -11960,61 +12406,58 @@ finish_enum (enumtype)
     {
       tree scope = current_scope ();
       if (scope && TREE_CODE (scope) == FUNCTION_DECL)
-       {
-         add_tree (build_min (TAG_DEFN, enumtype));
-         resume_temporary_allocation ();
-       }
-      return enumtype;
+       add_tree (build_min (TAG_DEFN, enumtype));
     }
+  else
+    {
+      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);
+      tree tem;
 
-  {
-    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);
-
-    TYPE_SIZE (enumtype) = NULL_TREE;
-
-    /* Set TYPE_MIN_VALUE and TYPE_MAX_VALUE according to `precision'.  */
+      TYPE_SIZE (enumtype) = NULL_TREE;
 
-    TYPE_PRECISION (enumtype) = precision;
-    if (unsignedp)
-      fixup_unsigned_type (enumtype);
-    else
-      fixup_signed_type (enumtype);
+      /* Set TYPE_MIN_VALUE and TYPE_MAX_VALUE according to `precision'.  */
 
-    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_PRECISION (enumtype) = precision;
+      if (unsignedp)
+       fixup_unsigned_type (enumtype);
+      else
+       fixup_signed_type (enumtype);
 
-    TYPE_SIZE (enumtype) = 0;
-    layout_type (enumtype);
-  }
+      if (flag_short_enums || (precision > TYPE_PRECISION (integer_type_node)))
+       /* Use the width of the narrowest normal C type which is wide
+          enough.  */ 
+       TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size
+                                                   (precision, 1));
+      else
+       TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
 
-  {
-    register tree tem;
+      TYPE_SIZE (enumtype) = 0;
+      layout_type (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_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (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);
-      }
-  }
+      /* 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_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (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.  */
+      rest_of_type_compilation (enumtype, namespace_bindings_p ());
+    }
 
-  /* Finish debugging output for this type.  */
-  rest_of_type_compilation (enumtype, namespace_bindings_p ());
+  /* In start_enum we pushed obstacks.  Here, we must pop them.  */
+  pop_obstacks ();
 
   return enumtype;
 }
@@ -12097,8 +12540,10 @@ build_enumerator (name, value, type)
  if (context && context == current_class_type)
    {
      pushdecl_class_level (decl);
-     TREE_CHAIN (decl) = current_local_enum;
-     current_local_enum = decl;
+     /* In something like `struct S { enum E { i = 7 }; };' we put `i'
+       on the TYPE_FIELDS list for `S'.  (That's so that you can say
+       things like `S::i' later.)  */
+     finish_member_declaration (decl);
    }
  else
    {
@@ -12118,47 +12563,6 @@ build_enumerator (name, value, type)
   return result;
 }
 
-/* Called after we have finished the declaration of an enumeration
-   type, and, perhaps, some objects whose type involves the
-   enumeration type.  DECL, if non-NULL, is the declaration of the
-   first such object.  
-
-   If CURRENT_LOCAL_ENUM is NULL, the DECL is returned. 
-
-   If CURRENT_LOCAL_ENUM is non-NULL, it should be the CONST_DECL for
-   the last enumeration constant of an enumeration type that is a
-   member of a class.  The enumeration constants are already chained
-   together through their TREE_CHAIN fields.  This function sets the
-   TREE_CHAIN of the last enumeration constant to DECL.  The
-   CONST_DECL for the last enumeration constant is returned.  
-
-   CURRENT_LOCAL_ENUM will always be NULL when this function 
-   returns.  */
-
-tree
-grok_enum_decls (decl)
-     tree decl;
-{
-  tree d = current_local_enum;
-  
-  if (d == NULL_TREE)
-    return decl;
-  
-  while (1)
-    {
-      if (TREE_CHAIN (d) == NULL_TREE)
-       {
-         TREE_CHAIN (d) = decl;
-         break;
-       }
-      d = TREE_CHAIN (d);
-    }
-
-  decl = current_local_enum;
-  current_local_enum = NULL_TREE;
-  
-  return decl;
-}
 \f
 static int function_depth;
 
@@ -12167,6 +12571,15 @@ static int function_depth;
    they describe the function's name and the type it returns,
    but twisted together in a fashion that parallels the syntax of C.
 
+   If PRE_PARSED_P is non-zero then DECLARATOR is really the DECL for
+   the function we are about to process; DECLSPECS are ignored.  For
+   example, we set PRE_PARSED_P when processing the definition of
+   inline function that was defined in-class; the definition is
+   actually processed when the class is complete.  In this case,
+   PRE_PARSED_P is 2.  We also set PRE_PARSED_P when instanting the
+   body of a template function, and when constructing thunk functions
+   and such; in these cases PRE_PARSED_P is 1.
+   
    This function creates a binding context for the function body
    as well as setting up the FUNCTION_DECL in current_function_decl.
 
@@ -12203,7 +12616,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
   /* Assume, until we see it does.  */
   current_function_returns_value = 0;
   current_function_returns_null = 0;
-  warn_about_return_type = 0;
   named_labels = 0;
   shadowed_labels = 0;
   current_function_assigns_this = 0;
@@ -12268,17 +12680,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
            doing_friend = 1;
        }
 
-      /* In a fcn definition, arg types must be complete.  */
-      require_complete_types_for_parms (DECL_ARGUMENTS (decl1));
-
-      /* In case some arg types were completed since the declaration was
-         parsed, fix up the decls.  */
-      {
-       tree t = DECL_ARGUMENTS (decl1);
-       for (; t; t = TREE_CHAIN (t))
-         layout_decl (t, 0);
-      }
-
       last_function_parms = DECL_ARGUMENTS (decl1);
       last_function_parm_tags = NULL_TREE;
     }
@@ -12292,8 +12693,7 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
       fntype = TREE_TYPE (decl1);
 
       restype = TREE_TYPE (fntype);
-      if (IS_AGGR_TYPE (restype) && ! TYPE_PTRMEMFUNC_P (restype)
-         && ! CLASSTYPE_GOT_SEMICOLON (restype))
+      if (CLASS_TYPE_P (restype) && !CLASSTYPE_GOT_SEMICOLON (restype))
        {
          cp_error ("semicolon missing after declaration of `%#T'", restype);
          shadow_tag (build_expr_list (NULL_TREE, restype));
@@ -12319,7 +12719,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
                pedwarn ("return type for `main' changed to `int'");
              TREE_TYPE (decl1) = fntype = default_function_type;
            }
-         warn_about_return_type = 0;
        }
     }
 
@@ -12329,16 +12728,37 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
       && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != NULL_TREE)
     cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)));
 
+  announce_function (decl1);
+
+  /* Set up current_class_type, and enter the scope of the class, if
+     appropriate.  */
+  if (ctype)
+    push_nested_class (ctype, 1);
+  else if (DECL_STATIC_FUNCTION_P (decl1))
+    push_nested_class (DECL_CONTEXT (decl1), 2);
+
+  /* Now that we have entered the scope of the class, we must restore
+     the bindings for any template parameters surrounding DECL1, if it
+     is an inline member template.  (Order is important; consider the
+     case where a template parameter has the same name as a field of
+     the class.)  It is not until after this point that
+     PROCESSING_TEMPLATE_DECL is guaranteed to be set up correctly.  */
+  if (pre_parsed_p == 2)
+    maybe_begin_member_template_processing (decl1);
+
+  /* We are now in the scope of the function being defined.  */
   current_function_decl = decl1;
+
   /* 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;
 
-  announce_function (decl1);
-
   if (! processing_template_decl)
     {
+      /* In a fcn definition, arg types must be complete.  */
+      require_complete_types_for_parms (DECL_ARGUMENTS (decl1));
+
       if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE)
        {
          cp_error ("return-type `%#T' is an incomplete type",
@@ -12359,8 +12779,10 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
                                     TYPE_ARG_TYPES (TREE_TYPE (decl1)));
          DECL_RESULT (decl1)
            = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype)));
-         TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (TREE_TYPE (fntype));
-         TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (TREE_TYPE (fntype));
+         TREE_READONLY (DECL_RESULT (decl1))
+           = CP_TYPE_CONST_P (TREE_TYPE (fntype));
+         TREE_THIS_VOLATILE (DECL_RESULT (decl1))
+           = CP_TYPE_VOLATILE_P (TREE_TYPE (fntype));
        }
 
       if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
@@ -12368,9 +12790,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
        abstract_virtuals_error (decl1, TREE_TYPE (fntype));
     }
 
-  if (warn_about_return_type)
-    pedwarn ("return-type defaults to `int'");
-
   /* Effective C++ rule 15.  See also c_expand_return.  */
   if (warn_ecpp
       && DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR]
@@ -12381,17 +12800,14 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
      error_mark_node is replaced below (in poplevel) with the BLOCK.  */
   DECL_INITIAL (decl1) = error_mark_node;
 
+#ifdef SET_DEFAULT_DECL_ATTRIBUTES
+  SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs);
+#endif
+  
   /* This function exists in static storage.
      (This does not mean `static' in the C sense!)  */
   TREE_STATIC (decl1) = 1;
 
-  /* Set up current_class_type, and enter the scope of the class, if
-     appropriate.  */
-  if (ctype)
-    push_nested_class (ctype, 1);
-  else if (DECL_STATIC_FUNCTION_P (decl1))
-    push_nested_class (DECL_CONTEXT (decl1), 2);
-
   /* We must call push_template_decl after current_class_type is set
      up.  (If we are processing inline definitions after exiting a
      class scope, current_class_type will be NULL_TREE until set above
@@ -12498,13 +12914,24 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
 
          if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
            {
-             int i = suspend_momentary ();
+             int i;
 
-             /* Fool build_indirect_ref.  */
+             if (! hack_decl_function_context (decl1))
+               temporary_allocation ();
+             i = suspend_momentary ();
+
+             /* Normally, build_indirect_ref returns
+                current_class_ref whenever current_class_ptr is
+                dereferenced.  This time, however, we want it to
+                *create* current_class_ref, so we temporarily clear
+                current_class_ptr to fool it.  */
              current_class_ptr = NULL_TREE;
              current_class_ref = build_indirect_ref (t, NULL_PTR);
              current_class_ptr = t;
+
              resume_momentary (i);
+             if (! hack_decl_function_context (decl1))
+               end_temporary_allocation ();
            }
          else
            /* We're having a signature pointer here.  */
@@ -12513,9 +12940,7 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
        }
     }
   else
-    {
-      current_class_ptr = current_class_ref = NULL_TREE;
-    }
+    current_class_ptr = current_class_ref = NULL_TREE;
 
   pushlevel (0);
   current_binding_level->parm_flag = 1;
@@ -12524,6 +12949,7 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
 
   if (attrs)
     cplus_decl_attributes (decl1, NULL_TREE, attrs);
+  
   make_function_rtl (decl1);
 
   /* Promote the value to int before returning it.  */
@@ -12539,8 +12965,8 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
     {
       DECL_RESULT (decl1)
        = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype));
-      TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (restype);
-      TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (restype);
+      TREE_READONLY (DECL_RESULT (decl1)) = CP_TYPE_CONST_P (restype);
+      TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = CP_TYPE_VOLATILE_P (restype);
     }
 
   /* Allocate further tree nodes temporarily during compilation
@@ -12617,9 +13043,6 @@ store_parm_decls ()
   /* Initialize RTL machinery.  */
   init_function_start (fndecl, input_filename, lineno);
 
-  /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function.  */
-  declare_function_name ();
-
   /* Create a binding level for the parms.  */
   expand_start_bindings (0);
 
@@ -12705,6 +13128,9 @@ store_parm_decls ()
 
   storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
 
+  /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function.  */
+  declare_function_name ();
+
   /* Initialize the RTL code for the function.  */
   DECL_SAVED_INSNS (fndecl) = NULL_RTX;
   if (! processing_template_decl)
@@ -12815,18 +13241,23 @@ store_return_init (return_id, init)
    This is called after parsing the body of the function definition.
    LINENO is the current line number.
 
-   C++: CALL_POPLEVEL is non-zero if an extra call to poplevel
-   (and expand_end_bindings) must be made to take care of the binding
-   contour for the base initializers.  This is only relevant for
-   constructors.
+   FLAGS is a bitwise or of the following values: 
+     1 - CALL_POPLEVEL 
+       An extra call to poplevel (and expand_end_bindings) must be
+       made to take care of the binding contour for the base
+       initializers.  This is only relevant for constructors.
+     2 - INCLASS_INLINE
+       We just finished processing the body of an in-class inline
+       function definition.  (This processing will have taken place
+       after the class definition is complete.)
 
    NESTED is nonzero if we were in the middle of compiling another function
    when we started on this one.  */
 
 void
-finish_function (lineno, call_poplevel, nested)
+finish_function (lineno, flags, nested)
      int lineno;
-     int call_poplevel;
+     int flags;
      int nested;
 {
   register tree fndecl = current_function_decl;
@@ -12835,6 +13266,9 @@ finish_function (lineno, call_poplevel, nested)
   /* Label to use if this function is supposed to return a value.  */
   tree no_return_label = NULL_TREE;
   tree decls = NULL_TREE;
+  int call_poplevel = (flags & 1) != 0;
+  int inclass_inline = (flags & 2) != 0;
+  int in_template;
 
   /* When we get some parse errors, we can end up without a
      current_function_decl, so cope.  */
@@ -12934,7 +13368,8 @@ finish_function (lineno, call_poplevel, nested)
             pointer to represent the type of our base class.  */
 
          /* This side-effect makes call to `build_delete' generate the
-            code we have to have at the end of this destructor.  */
+            code we have to have at the end of this destructor.
+            `build_delete' will set the flag again.  */
          TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
 
          /* These are two cases where we cannot delegate deletion.  */
@@ -12993,8 +13428,6 @@ finish_function (lineno, call_poplevel, nested)
                expand_end_cond ();
            }
 
-         TYPE_HAS_DESTRUCTOR (current_class_type) = 1;
-
          virtual_size = c_sizeof (current_class_type);
 
          /* At the end, call delete if that's what's requested.  */
@@ -13028,7 +13461,7 @@ finish_function (lineno, call_poplevel, nested)
 
          /* End of destructor.  */
          expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0);
-         poplevel (2, 0, 0);   /* XXX change to 1 */
+         poplevel (getdecls () != NULL_TREE, 0, 0);
 
          /* Back to the top of destructor.  */
          /* Don't execute destructor code if `this' is NULL.  */
@@ -13241,6 +13674,27 @@ finish_function (lineno, call_poplevel, nested)
       /* Generate rtl for function exit.  */
       expand_function_end (input_filename, lineno, 1);
     }
+  
+  /* Must mark the RESULT_DECL as being in this function.  */
+  DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
+
+  /* Set the BLOCK_SUPERCONTEXT of the outermost function scope to point
+     to the FUNCTION_DECL node itself.  */
+  BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+
+  /* If we're processing a template, squirrel away the definition
+     until we do an instantiation.  */
+  if (processing_template_decl)
+    {
+      --minimal_parse_mode;
+      DECL_SAVED_TREE (fndecl) = TREE_CHAIN (DECL_SAVED_TREE (fndecl));
+      /* We have to save this value here in case
+        maybe_end_member_template_processing decides to pop all the
+        template parameters.  */
+      in_template = 1;
+    }
+  else
+    in_template = 0;
 
   /* This must come after expand_function_end because cleanups might
      have declarations (from inline functions) that need to go into
@@ -13249,6 +13703,13 @@ finish_function (lineno, call_poplevel, nested)
     my_friendly_abort (122);
   poplevel (1, 0, 1);
 
+  /* If this is a in-class inline definition, we may have to pop the
+     bindings for the template parameters that we added in
+     maybe_begin_member_template_processing when start_function was
+     called.  */
+  if (inclass_inline)
+    maybe_end_member_template_processing ();
+
   /* 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
@@ -13260,14 +13721,7 @@ finish_function (lineno, call_poplevel, nested)
       pop_nested_class (1);
     }
 
-  /* Must mark the RESULT_DECL as being in this function.  */
-  DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
-
-  /* Set the BLOCK_SUPERCONTEXT of the outermost function scope to point
-     to the FUNCTION_DECL node itself.  */
-  BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
-
-  if (! processing_template_decl)
+  if (!in_template)
     {
       int saved_flag_keep_inline_functions =
        flag_keep_inline_functions;
@@ -13351,12 +13805,6 @@ finish_function (lineno, call_poplevel, nested)
   /* Free all the tree nodes making up this function.  */
   /* Switch back to allocating nodes permanently
      until we start another function.  */
-  if (processing_template_decl)
-    {
-      --minimal_parse_mode;
-      DECL_SAVED_TREE (fndecl) = TREE_CHAIN (DECL_SAVED_TREE (fndecl));
-    }
-
   if (! nested)
     permanent_allocation (1);
 
@@ -13391,8 +13839,6 @@ finish_function (lineno, call_poplevel, nested)
 }
 \f
 /* Create the FUNCTION_DECL for a function definition.
-   LINE1 is the line number that the definition absolutely begins on.
-   LINE2 is the line number that the name of the function appears on.
    DECLSPECS and DECLARATOR are the parts of the declaration;
    they describe the return type and the name of the function,
    but twisted together in a fashion that parallels the syntax of C.
@@ -13414,11 +13860,11 @@ finish_function (lineno, call_poplevel, nested)
    CHANGES TO CODE IN `grokfield'.  */
 
 tree
-start_method (declspecs, declarator)
-     tree declarator, declspecs;
+start_method (declspecs, declarator, attrlist)
+     tree declarator, declspecs, attrlist;
 {
   tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0,
-                               NULL_TREE);
+                               attrlist);
 
   /* Something too ugly to handle.  */
   if (fndecl == NULL_TREE)
@@ -13447,6 +13893,8 @@ start_method (declspecs, declarator)
       return void_type_node;
     }
 
+  check_template_shadow (fndecl);
+
   DECL_THIS_INLINE (fndecl) = 1;
 
   if (flag_default_inline)
@@ -13528,23 +13976,11 @@ finish_method (decl)
   for (link = current_binding_level->names; link; link = TREE_CHAIN (link))
     {
       if (DECL_NAME (link) != NULL_TREE)
-       IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0;
+       pop_binding (DECL_NAME (link));
       my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163);
       DECL_CONTEXT (link) = NULL_TREE;
     }
 
-  /* Restore all name-meanings of the outer levels
-     that were shadowed by this level.  */
-
-  for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
-      IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
-  for (link = current_binding_level->class_shadowed;
-       link; link = TREE_CHAIN (link))
-    IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
-  for (link = current_binding_level->type_shadowed;
-       link; link = TREE_CHAIN (link))
-    SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
-
   GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level,
                      (HOST_WIDE_INT) current_binding_level->level_chain,
                      current_binding_level->parm_flag,
@@ -13704,10 +14140,10 @@ cplus_expand_expr_stmt (exp)
 
   if (TREE_TYPE (exp) == unknown_type_node)
     {
-      if (TREE_CODE (exp) == ADDR_EXPR || TREE_CODE (exp) == TREE_LIST)
+      if (TREE_CODE (exp) == COMPONENT_REF)
+       error ("invalid reference to a member function name, did you forget the ()?");
+      else
        error ("address of overloaded function with no contextual type information");
-      else if (TREE_CODE (exp) == COMPONENT_REF)
-       warning ("useless reference to a member function name, did you forget the ()?");
     }
   else
     {
@@ -13782,15 +14218,14 @@ revert_static_member_fn (decl, fn, argtypes)
   tree function = fn ? *fn : TREE_TYPE (*decl);
   tree args = argtypes ? *argtypes : TYPE_ARG_TYPES (function);
 
-  if (TYPE_READONLY (TREE_TYPE (TREE_VALUE (args))))
-    cp_error ("static member function `%#D' declared const", *decl);
-  if (TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (args))))
-    cp_error ("static member function `%#D' declared volatile", *decl);
+  if (CP_TYPE_QUALS (TREE_TYPE (TREE_VALUE (args))) 
+      != TYPE_UNQUALIFIED)
+    cp_error ("static member function `%#D' declared with type qualifiers", 
+             *decl);
 
   args = TREE_CHAIN (args);
   tmp = build_function_type (TREE_TYPE (function), args);
-  tmp = build_type_variant (tmp, TYPE_READONLY (function),
-                           TYPE_VOLATILE (function));
+  tmp = build_qualified_type (tmp, CP_TYPE_QUALS (function));
   tmp = build_exception_variant (tmp,
                                 TYPE_RAISES_EXCEPTIONS (function));
   TREE_TYPE (*decl) = tmp;
@@ -13814,12 +14249,12 @@ 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;
+  struct named_label_list *named_label_uses;
   tree shadowed_labels;
   tree ctor_label;
   tree dtor_label;
@@ -13856,10 +14291,10 @@ push_cp_function_context (context)
   cp_function_chain = p;
 
   p->named_labels = named_labels;
+  p->named_label_uses = named_label_uses;
   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;
@@ -13898,10 +14333,10 @@ pop_cp_function_context (context)
   cp_function_chain = p->next;
 
   named_labels = p->named_labels;
+  named_label_uses = p->named_label_uses;
   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;