78th Cygnus<->FSF merge
[platform/upstream/gcc.git] / gcc / cp / decl.c
index 4dfff7e..49eb67e 100644 (file)
@@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA.  */
 #include <sys/types.h>
 #include <signal.h>
 #include "obstack.h"
+#include "defaults.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
@@ -98,7 +99,7 @@ static struct stack_level *decl_stack;
 
 #ifndef BOOL_TYPE_SIZE
 #ifdef SLOW_BYTE_ACCESS
-#define BOOL_TYPE_SIZE BITS_PER_WORD
+#define BOOL_TYPE_SIZE ((SLOW_BYTE_ACCESS) ? (BITS_PER_WORD) : (BITS_PER_UNIT))
 #else
 #define BOOL_TYPE_SIZE BITS_PER_UNIT
 #endif
@@ -126,6 +127,8 @@ static tree grokparms                               PROTO((tree, int));
 static tree lookup_nested_type                 PROTO((tree, tree));
 static char *redeclaration_error_message       PROTO((tree, tree));
 static void grok_op_properties                 PROTO((tree, int, int));
+extern void* push_eh_context                   PROTO(());
+extern void pop_eh_context                     PROTO((void *));
 
 tree define_function           
        PROTO((char *, tree, enum built_in_function, void (*)(), char *));
@@ -267,6 +270,11 @@ tree vtbl_type_node;
 
 tree dtor_label;
 
+/* In a destructor, the last insn emitted after the start of the
+   function and the parms.  */
+
+rtx last_dtor_insn;
+
 /* In a constructor, the point at which we are ready to return
    the pointer to the initialized object.  */
 
@@ -293,9 +301,10 @@ tree base_init_expr;
    Identifiers for `this' in member functions and the auto-delete
    parameter for destructors.  */
 tree this_identifier, in_charge_identifier;
-/* Used in pointer to member functions, and in vtables. */
+/* Used in pointer to member functions, in vtables, and in sigtables. */
 tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier;
-tree pfn_or_delta2_identifier;
+tree pfn_or_delta2_identifier, tag_identifier;
+tree vb_off_identifier, vt_off_identifier;
 
 /* A list (chain of TREE_LIST nodes) of named label uses.
    The TREE_PURPOSE field is the list of variables defined
@@ -547,9 +556,14 @@ struct binding_level
     /* The binding level which this one is contained in (inherits from).  */
     struct binding_level *level_chain;
 
-    /* Number of decls in `names' that have incomplete 
+    /* List of decls in `names' that have incomplete
        structure or union types.  */
-    unsigned int n_incomplete;
+    tree incomplete;
+
+    /* List of VAR_DECLS saved from a previous for statement.
+       These would be dead in ANSI-conforming code, but might
+       be referenced in traditional code. */
+    tree dead_vars_from_for;
 
     /* 1 for the level that holds the parameters of a function.
        2 for the level that holds a class declaration.
@@ -582,6 +596,9 @@ struct binding_level
     /* This is set for a namespace binding level.  */
     unsigned namespace_p : 1;
 
+    /* True if this level is that of a for-statement. */
+    unsigned is_for_scope : 1;
+
     /* One bit left for this word.  */
 
 #if defined(DEBUG_CP_BINDING_LEVELS)
@@ -938,6 +955,12 @@ pushlevel (tag_transparent)
   keep_next_level_flag = 0;
 }
 
+int
+note_level_for_for ()
+{
+  current_binding_level->is_for_scope = 1;
+}
+
 void
 pushlevel_temporary (tag_transparent)
      int tag_transparent;
@@ -1077,15 +1100,35 @@ poplevel (keep, reverse, functionbody)
     block = make_node (BLOCK);
   if (block != NULL_TREE)
     {
-      BLOCK_VARS (block) = decls;
-      BLOCK_TYPE_TAGS (block) = tags;
-      BLOCK_SUBBLOCKS (block) = subblocks;
-      /* If we created the block earlier on, and we are just diddling it now,
-        then it already should have a proper BLOCK_END_NOTE value associated
-        with it, so avoid trashing that.  Otherwise, for a new block, install
-        a new BLOCK_END_NOTE value.  */
-      if (! block_previously_created)
-       remember_end_note (block);
+      if (block_previously_created)
+       {
+         if (decls || tags || subblocks)
+           {
+             if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (block))
+               {
+                 warning ("internal compiler error: debugging info corrupted");
+               }
+             BLOCK_VARS (block) = decls;
+             BLOCK_TYPE_TAGS (block) = tags;
+
+             /* We can have previous subblocks and new subblocks when
+                doing fixup_gotos with complex cleanups.  We chain the new
+                subblocks onto the end of any pre-existing subblocks.  */
+             BLOCK_SUBBLOCKS (block) = chainon (BLOCK_SUBBLOCKS (block),
+                                                subblocks);
+           }
+         /* If we created the block earlier on, and we are just
+            diddling it now, then it already should have a proper
+            BLOCK_END_NOTE value associated with it.  */
+       }
+      else
+       {
+         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.  */
+         remember_end_note (block);
+       }
     }
 
   /* In each subblock, record that this is its superior.  */
@@ -1096,28 +1139,81 @@ poplevel (keep, reverse, functionbody)
 
   /* Clear out the meanings of the local variables of this level.  */
 
-  for (link = decls; link; link = TREE_CHAIN (link))
+  for (link = current_binding_level->dead_vars_from_for;
+       link != NULL_TREE; link = TREE_CHAIN (link))
     {
-      if (DECL_NAME (link) != NULL_TREE)
+      if (DECL_DEAD_FOR_LOCAL (link))
        {
-         /* If the ident. was used or addressed via a local extern decl,
-            don't forget that fact.  */
-         if (DECL_EXTERNAL (link))
+         tree id = DECL_NAME (link);
+         if (IDENTIFIER_LOCAL_VALUE (id) == link)
+           IDENTIFIER_LOCAL_VALUE (id) = DECL_SHADOWED_FOR_VAR (link);
+       }
+    }
+
+  if (current_binding_level->is_for_scope && flag_new_for_scope == 1)
+    {
+      for (link = decls; link; link = TREE_CHAIN (link))
+       {
+         if (TREE_CODE (link) == VAR_DECL)
+           DECL_DEAD_FOR_LOCAL (link) = 1;
+       }
+    }
+  else
+    {
+      for (link = decls; link; link = TREE_CHAIN (link))
+       {
+         if (DECL_NAME (link) != NULL_TREE)
            {
-             if (TREE_USED (link))
-               TREE_USED (DECL_ASSEMBLER_NAME (link)) = 1;
-             if (TREE_ADDRESSABLE (link))
-               TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
+             /* 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;
            }
-         IDENTIFIER_LOCAL_VALUE (DECL_NAME (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);
+  if (current_binding_level->is_for_scope && flag_new_for_scope == 1)
+    {
+      struct binding_level *outer = current_binding_level->level_chain;
+      for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
+       {
+         tree id = TREE_PURPOSE (link);
+         tree decl = IDENTIFIER_LOCAL_VALUE (id);
+         if (DECL_DEAD_FOR_LOCAL (decl))
+           DECL_SHADOWED_FOR_VAR (decl) = TREE_VALUE (link);
+         else
+           IDENTIFIER_LOCAL_VALUE (id) = TREE_VALUE (link);
+       }
+
+      /* Save declarations made in a 'for' statement so we can support pre-ANSI
+        'for' scoping semantics. */
+
+      /* We append the current names of for-variables to those from previous
+        declarations, so that when we get around to do an poplevel
+        on the OUTER level, we restore the any shadowed readl bindings.
+        Note that the new names are put first on the combined list,
+        so they get to be restored first.  This is important if there are
+        two for-loops using the same for-variable in the same block.
+        The binding we really want restored is whatever binding was shadowed
+        by the *first* for-variable, not the binding shadowed by the
+        second for-variable (which would be the first for-variable). */
+      outer->dead_vars_from_for
+       = chainon (current_binding_level->names, outer->dead_vars_from_for);
+    }
+  else
+    {
+      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);
@@ -1420,7 +1516,7 @@ print_binding_level (lvl)
   fprintf (stderr, " blocks=");
   fprintf (stderr, HOST_PTR_PRINTF, lvl->blocks);
   fprintf (stderr, " n_incomplete=%d parm_flag=%d keep=%d",
-          lvl->n_incomplete, lvl->parm_flag, lvl->keep);
+          list_length (lvl->incomplete), lvl->parm_flag, lvl->keep);
   if (lvl->tag_transparent)
     fprintf (stderr, " tag-transparent");
   if (lvl->more_cleanups_ok)
@@ -1575,7 +1671,56 @@ print_binding_stack ()
   print_binding_level (global_binding_level);
 }
 
-/* Push into the scope of the NAME namespace.  */
+extern char * first_global_object_name;
+
+/* Get a unique name for each call to this routine for unnamed namespaces.
+   Mostly copied from get_file_function_name.  */
+static tree
+get_unique_name ()
+{
+  static int temp_name_counter = 0;
+  char *buf;
+  register char *p;
+
+  if (first_global_object_name)
+    p = first_global_object_name;
+  else if (main_input_filename)
+    p = main_input_filename;
+  else
+    p = input_filename;
+
+#define UNNAMED_NAMESPACE_FORMAT "__%s_%d"
+
+  buf = (char *) alloca (sizeof (UNNAMED_NAMESPACE_FORMAT) + strlen (p));
+
+  sprintf (buf, UNNAMED_NAMESPACE_FORMAT, p, temp_name_counter++);
+
+  /* Don't need to pull weird characters out of global names.  */
+  if (p != first_global_object_name)
+    {
+      for (p = buf+11; *p; p++)
+       if (! ((*p >= '0' && *p <= '9')
+#if 0 /* we always want labels, which are valid C++ identifiers (+ `$') */
+#ifndef ASM_IDENTIFY_GCC       /* this is required if `.' is invalid -- k. raeburn */
+              || *p == '.'
+#endif
+#endif
+#ifndef NO_DOLLAR_IN_LABEL     /* this for `$'; unlikely, but... -- kr */
+              || *p == '$'
+#endif
+#ifndef NO_DOT_IN_LABEL                /* this for `.'; unlikely, but... */
+              || *p == '.'
+#endif
+              || (*p >= 'A' && *p <= 'Z')
+              || (*p >= 'a' && *p <= 'z')))
+         *p = '_';
+    }
+
+  return get_identifier (buf);
+}
+
+/* Push into the scope of the NAME namespace.  If NAME is NULL_TREE, then we
+   select a name that is unique to this compilation unit.  */
 void
 push_namespace (name)
      tree name;
@@ -1583,14 +1728,19 @@ push_namespace (name)
   extern tree current_namespace;
   tree old_id = get_namespace_id ();
   char *buf;
-  tree d = make_node (NAMESPACE_DECL);
+  tree d;
+
+  if (! name)
+    {
+      /* Create a truly ugly name! */
+      name = get_unique_name ();
+    }
+
+  d = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
 
-  DECL_NAME (d) = name;
-  DECL_ASSEMBLER_NAME (d) = name;
-  /* pushdecl wants to check the size of it to see if it is incomplete... */
-  TREE_TYPE (d) = void_type_node;
   /* Mark them as external, so redeclaration_error_message doesn't think
      they are duplicates. */
+
   DECL_EXTERNAL (d) = 1;
   d = pushdecl (d);
 
@@ -1599,12 +1749,10 @@ push_namespace (name)
       /* This is new for this compilation unit.  */
       pushlevel (0);
       declare_namespace_level ();
-      NAMESPACE_LEVEL (d) = (tree)current_binding_level;
+      NAMESPACE_LEVEL (d) = current_binding_level;
     }
   else
-    {
-      resume_level ((struct binding_level*)NAMESPACE_LEVEL (d));
-    }
+    resume_level (NAMESPACE_LEVEL (d));
 
   /* This code is just is bit old now... */ 
   current_namespace = tree_cons (NULL_TREE, name, current_namespace);
@@ -2015,6 +2163,7 @@ pushtag (name, type, globalize)
                  d = make_type_decl (name, type);
 #else
                  d = build_decl (TYPE_DECL, name, type);
+                 DECL_ASSEMBLER_NAME (d) = current_namespace_id (DECL_ASSEMBLER_NAME (d));
 #endif
                  SET_DECL_ARTIFICIAL (d);
 #ifdef DWARF_DEBUGGING_INFO
@@ -2276,8 +2425,20 @@ 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 = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 1);
+       types_match = 0;
     }
 
   return types_match;
@@ -2547,10 +2708,28 @@ duplicate_decls (newdecl, olddecl)
                  }
              }
 
-         if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl)
-             && TREE_ADDRESSABLE (olddecl))
-           cp_pedwarn ("`%#D' was used before it was declared inline",
-                       newdecl);
+         if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl))
+           {
+#if 0 /* I think this will be correct, but it's really annoying.  We should
+        fix the compiler to find vtables by indirection so it isn't
+        necessary.  (jason 8/25/95) */
+             if (DECL_VINDEX (olddecl) && ! DECL_ABSTRACT_VIRTUAL_P (olddecl))
+               {
+                 cp_pedwarn ("virtual function `%#D' redeclared inline",
+                             newdecl);
+                 cp_pedwarn_at ("previous non-inline declaration here",
+                                olddecl);
+               }
+             else
+#endif
+             if (TREE_ADDRESSABLE (olddecl))
+               {
+                 cp_pedwarn ("`%#D' was used before it was declared inline",
+                             newdecl);
+                 cp_pedwarn_at ("previous non-inline declaration here",
+                                olddecl);
+               }
+           }
        }
       /* These bits are logically part of the type for non-functions.  */
       else if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
@@ -2580,8 +2759,6 @@ duplicate_decls (newdecl, olddecl)
        DECL_CLASS_CONTEXT (newdecl) = DECL_CLASS_CONTEXT (olddecl);
       if (DECL_CHAIN (newdecl) == NULL_TREE)
        DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
-      if (DECL_NEXT_METHOD (newdecl) == NULL_TREE)
-       DECL_NEXT_METHOD (newdecl) = DECL_NEXT_METHOD (olddecl);
       if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0)
        DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl);
       DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl);
@@ -2665,9 +2842,9 @@ duplicate_decls (newdecl, olddecl)
        {
          tree ctype = NULL_TREE;
          ctype = DECL_CLASS_CONTEXT (newdecl);
-         TREE_TYPE (newdecl) = build_exception_variant (ctype, newtype,
+         TREE_TYPE (newdecl) = build_exception_variant (newtype,
                                                         TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)));
-         TREE_TYPE (olddecl) = build_exception_variant (ctype, newtype,
+         TREE_TYPE (olddecl) = build_exception_variant (newtype,
                                                         TYPE_RAISES_EXCEPTIONS (oldtype));
 
          if (! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0))
@@ -2746,7 +2923,7 @@ duplicate_decls (newdecl, olddecl)
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
-      DECL_C_STATIC (newdecl) = DECL_C_STATIC (olddecl);
+      DECL_C_STATIC (newdecl) |= DECL_C_STATIC (olddecl);
       DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl);
       DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
     }
@@ -2960,15 +3137,20 @@ pushdecl (x)
 
       else if (t != NULL_TREE)
        {
-         if (TREE_CODE (t) == PARM_DECL)
+         file = DECL_SOURCE_FILE (t);
+         line = DECL_SOURCE_LINE (t);
+         if (TREE_CODE (x) == VAR_DECL && DECL_DEAD_FOR_LOCAL (x))
+           ; /* This is OK. */
+         else if (TREE_CODE (t) == PARM_DECL)
            {
              if (DECL_CONTEXT (t) == NULL_TREE)
                fatal ("parse errors have confused me too much");
-           }
-         file = DECL_SOURCE_FILE (t);
-         line = DECL_SOURCE_LINE (t);
 
-         if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c)
+             /* Check for duplicate params. */
+             if (duplicate_decls (x, t))
+               return t;
+           }
+         else if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c)
               || (TREE_CODE (x) == TEMPLATE_DECL
                   && ! DECL_TEMPLATE_IS_CLASS (x)))
              && is_overloaded_fn (t))
@@ -3030,6 +3212,8 @@ pushdecl (x)
 #endif
              if (TREE_CODE (t) == TYPE_DECL)
                SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (t));
+             else if (TREE_CODE (t) == FUNCTION_DECL)
+               check_default_args (t);
 
              return t;
            }
@@ -3234,6 +3418,13 @@ 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
+                  && !DECL_DEAD_FOR_LOCAL (oldlocal))
+           {
+             warning ("variable `%s' shadows local",
+                      IDENTIFIER_POINTER (name));
+             cp_warning_at ("  this is the shadowed declaration", oldlocal);
+           }              
          /* Maybe warn if shadowing something else.  */
          else if (warn_shadow && !DECL_EXTERNAL (x)
                   /* No shadow warnings for internally generated vars.  */
@@ -3246,6 +3437,7 @@ pushdecl (x)
              if (oldlocal != NULL_TREE && TREE_CODE (oldlocal) == PARM_DECL)
                warnstring = "declaration of `%s' shadows a parameter";
              else if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE
+                      && current_class_decl
                       && !TREE_STATIC (name))
                warnstring = "declaration of `%s' shadows a member of `this'";
              else if (oldlocal != NULL_TREE)
@@ -3259,43 +3451,17 @@ pushdecl (x)
        }
 
       if (TREE_CODE (x) == FUNCTION_DECL)
-       {
-         /* This is probably the wrong place to check this, but it has to
-             come after the call to duplicate_decls.  */
-         tree arg = TYPE_ARG_TYPES (TREE_TYPE (x));
-         int saw_def = 0, i = 1;
-         for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i)
-           {
-             if (TREE_PURPOSE (arg))
-               saw_def = 1;
-             else if (saw_def)
-               {
-                 cp_error ("default argument missing for parameter %d of `%#D'",
-                           i, x);
-                 break;
-               }
-           }
-       }
+       check_default_args (x);
 
       /* Keep count of variables in this level with incomplete type.  */
-      if (TREE_CODE (x) != TEMPLATE_DECL
-         && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
-         && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE))
-       {
-         if (++b->n_incomplete == 0)
-           error ("too many incomplete variables at this point");
-       }
-
-      /* Keep count of variables in this level with incomplete type.  */
-      /* RTTI TD entries are created while defining the type_info.  */
       if (TREE_CODE (x) == VAR_DECL
          && TREE_TYPE (x) != error_mark_node
-         && TYPE_LANG_SPECIFIC (TREE_TYPE (x))
-         && TYPE_BEING_DEFINED (TREE_TYPE (x)))
-       {
-         if (++b->n_incomplete == 0)
-           error ("too many incomplete variables at this point");
-       }
+         && ((TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+              && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE))
+             /* 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);
     }
 
   /* Put decls on list in reverse order.
@@ -4046,6 +4212,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
                    /* Definition isn't the kind we were looking for.  */
                    cp_error ("`%#D' redeclared as %C", TREE_VALUE (tail),
                              form);
+                   return NULL_TREE;
                  }
                return TREE_VALUE (tail);
              }
@@ -4081,6 +4248,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
                                {
                                  cp_error ("`%#D' redeclared as %C in class scope",
                                            TREE_VALUE (tail), form);
+                                 return NULL_TREE;
                                }
                              return TREE_VALUE (tail);
                            }
@@ -4261,7 +4429,7 @@ lookup_name_real (name, prefer_type, nonclass)
 
       if (got_scope)
        type = got_scope;
-      else
+      else if (got_object != error_mark_node)
        type = got_object;
       
       if (type)
@@ -4563,9 +4731,6 @@ push_overloaded_decl_1 (x)
   push_overloaded_decl (x, 0);
 }
 
-#define builtin_function(NAME, TYPE, CODE, LIBNAME) \
-  define_function (NAME, TYPE, CODE, (void (*)())pushdecl, LIBNAME)
-
 #ifdef __GNUC__
 __inline
 #endif
@@ -4671,6 +4836,12 @@ init_decl_processing ()
   delta_identifier = get_identifier (VTABLE_DELTA_NAME);
   delta2_identifier = get_identifier (VTABLE_DELTA2_NAME);
   pfn_or_delta2_identifier = get_identifier ("__pfn_or_delta2");
+  if (flag_handle_signatures)
+    {
+      tag_identifier = get_identifier (SIGTABLE_TAG_NAME);
+      vb_off_identifier = get_identifier (SIGTABLE_VB_OFF_NAME);
+      vt_off_identifier = get_identifier (SIGTABLE_VT_OFF_NAME);
+    }
 
   /* Define `int' and `char' first so that dbx will output them first.  */
 
@@ -5097,21 +5268,21 @@ init_decl_processing ()
 #if 0
   /* Support for these has not been written in either expand_builtin
      or build_function_call.  */
-  builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, 0);
-  builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, 0);
+  builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, NULL_PTR);
+  builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR);
   builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR,
-                   0);
-  builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, 0);
+                   NULL_PTR);
+  builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, NULL_PTR);
   builtin_function ("__builtin_fmod", double_ftype_double_double,
-                   BUILT_IN_FMOD, 0);
+                   BUILT_IN_FMOD, NULL_PTR);
   builtin_function ("__builtin_frem", double_ftype_double_double,
-                   BUILT_IN_FREM, 0);
+                   BUILT_IN_FREM, NULL_PTR);
   builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, BUILT_IN_MEMSET,
-                   0);
+                   NULL_PTR);
   builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
-                   0);
+                   NULL_PTR);
   builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
-                   0);
+                   NULL_PTR);
 #endif
 
   /* C++ extensions */
@@ -5166,7 +5337,7 @@ init_decl_processing ()
      real gc code.  */
   if (flag_gc)
     {
-      builtin_function ("__gc_main", default_function_type, NOT_BUILT_IN, 0);
+      builtin_function ("__gc_main", default_function_type, NOT_BUILT_IN, NULL_PTR);
       pushdecl (lookup_name (get_identifier ("__gc_main"), 0));
     }
 
@@ -5217,17 +5388,33 @@ init_decl_processing ()
   if (flag_handle_signatures)
     {
       sigtable_entry_type = make_lang_type (RECORD_TYPE);
-      fields[0] = build_lang_field_decl (FIELD_DECL,
-                                        get_identifier (SIGTABLE_CODE_NAME),
-                                        short_integer_type_node);
-      fields[1] = build_lang_field_decl (FIELD_DECL,
-                                        get_identifier (SIGTABLE_OFFSET_NAME),
-                                        short_integer_type_node);
-      fields[2] = build_lang_field_decl (FIELD_DECL,
-                                        get_identifier (SIGTABLE_PFN_NAME),
+      fields[0] = build_lang_field_decl (FIELD_DECL, tag_identifier,
+                                        delta_type_node);
+      fields[1] = build_lang_field_decl (FIELD_DECL, vb_off_identifier,
+                                        delta_type_node);
+      fields[2] = build_lang_field_decl (FIELD_DECL, delta_identifier,
+                                        delta_type_node);
+      fields[3] = build_lang_field_decl (FIELD_DECL, index_identifier,
+                                        delta_type_node);
+      fields[4] = build_lang_field_decl (FIELD_DECL, pfn_identifier,
                                         ptr_type_node);
-      finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 2,
-                          double_type_node);
+
+      /* Set the alignment to the max of the alignment of ptr_type_node and
+        delta_type_node.  Double alignment wastes a word on the Sparc.  */
+      finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 4,
+                          (TYPE_ALIGN (ptr_type_node) > TYPE_ALIGN (delta_type_node))
+                          ? ptr_type_node
+                          : delta_type_node);
+
+      /* Make this part of an invisible union.  */
+      fields[5] = copy_node (fields[4]);
+      TREE_TYPE (fields[5]) = delta_type_node;
+      DECL_NAME (fields[5]) = vt_off_identifier;
+      DECL_MODE (fields[5]) = TYPE_MODE (delta_type_node);
+      DECL_SIZE (fields[5]) = TYPE_SIZE (delta_type_node);
+      TREE_UNSIGNED (fields[5]) = 0;
+      TREE_CHAIN (fields[4]) = fields[5];
+
       sigtable_entry_type = build_type_variant (sigtable_entry_type, 1, 0);
       record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type);
     }
@@ -5257,11 +5444,11 @@ init_decl_processing ()
       __i_desc_type_node = make_lang_type (RECORD_TYPE);
       __m_desc_type_node = make_lang_type (RECORD_TYPE);
       __t_desc_array_type =
-       build_array_type (TYPE_POINTER_TO (__t_desc_type_node), NULL_TREE);
+       build_array_type (build_pointer_type (__t_desc_type_node), NULL_TREE);
       __i_desc_array_type =
-       build_array_type (TYPE_POINTER_TO (__i_desc_type_node), NULL_TREE);
+       build_array_type (build_pointer_type (__i_desc_type_node), NULL_TREE);
       __m_desc_array_type =
-       build_array_type (TYPE_POINTER_TO (__m_desc_type_node), NULL_TREE);
+       build_array_type (build_pointer_type (__m_desc_type_node), NULL_TREE);
 
       fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
                                         string_type_node);
@@ -5271,7 +5458,7 @@ init_decl_processing ()
                                         unsigned_type_node);
       fields[3] = build_lang_field_decl (FIELD_DECL,
                                         get_identifier ("points_to"),
-                                        TYPE_POINTER_TO (__t_desc_type_node));
+                                        build_pointer_type (__t_desc_type_node));
       fields[4] = build_lang_field_decl (FIELD_DECL,
                                         get_identifier ("ivars_count"),
                                         integer_type_node);
@@ -5305,7 +5492,7 @@ init_decl_processing ()
       fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("offset"),
                                         integer_type_node);
       fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
-                                        TYPE_POINTER_TO (__t_desc_type_node));
+                                        build_pointer_type (__t_desc_type_node));
       finish_builtin_type (__i_desc_type_node, "__i_desc", fields, 2,
                           integer_type_node);
 
@@ -5329,9 +5516,9 @@ init_decl_processing ()
       fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("vindex"),
                                         integer_type_node);
       fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("vcontext"),
-                                        TYPE_POINTER_TO (__t_desc_type_node));
+                                        build_pointer_type (__t_desc_type_node));
       fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("return_type"),
-                                        TYPE_POINTER_TO (__t_desc_type_node));
+                                        build_pointer_type (__t_desc_type_node));
       fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("address"),
                                         build_pointer_type (default_function_type));
       fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("parm_count"),
@@ -5339,7 +5526,7 @@ init_decl_processing ()
       fields[6] = build_lang_field_decl (FIELD_DECL, get_identifier ("required_parms"),
                                         short_integer_type_node);
       fields[7] = build_lang_field_decl (FIELD_DECL, get_identifier ("parm_types"),
-                                        build_pointer_type (build_array_type (TYPE_POINTER_TO (__t_desc_type_node), NULL_TREE)));
+                                        build_pointer_type (build_array_type (build_pointer_type (__t_desc_type_node), NULL_TREE)));
       finish_builtin_type (__m_desc_type_node, "__m_desc", fields, 7,
                           integer_type_node);
     }
@@ -5404,6 +5591,8 @@ init_decl_processing ()
     }
   if (flag_cadillac)
     init_cadillac ();
+  if (! SUPPORTS_WEAK)
+    flag_weak = 0;
 
   /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__.  */
   declare_function_name ();
@@ -5580,7 +5769,7 @@ shadow_tag (declspecs)
       if (TYPE_FIELDS (t))
        {
          tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0,
-                                     NULL_TREE);
+                                     NULL_TREE, NULL_TREE);
          finish_anon_union (decl);
        }
       else
@@ -5621,7 +5810,7 @@ groktypename (typename)
     return typename;
   return grokdeclarator (TREE_VALUE (typename),
                         TREE_PURPOSE (typename),
-                        TYPENAME, 0, NULL_TREE);
+                        TYPENAME, 0, NULL_TREE, NULL_TREE);
 }
 
 /* Decode a declarator in an ordinary declaration or data definition.
@@ -5665,7 +5854,8 @@ start_decl (declarator, declspecs, initialized, raises)
       used_extern_spec = 1;
     }
 
-  decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, raises);
+  decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, raises,
+                        NULL_TREE);
   if (decl == NULL_TREE || decl == void_type_node)
     return NULL_TREE;
 
@@ -5840,13 +6030,25 @@ start_decl (declarator, declspecs, initialized, raises)
          else if (duplicate_decls (decl, field))
            decl = field;
        }
-      
-      /* If it was not explicitly declared `extern',
-        revoke any previous claims of DECL_EXTERNAL.  */
-      if (DECL_THIS_EXTERN (decl) == 0)
-       DECL_EXTERNAL (decl) = 0;
+      else
+       {
+         tree field = check_classfn (context, NULL_TREE, decl);
+         if (field && duplicate_decls (decl, field))
+           decl = field;
+       }
+
+      /* cp_finish_decl sets DECL_EXTERNAL if DECL_IN_AGGR_P is set.  */
       if (DECL_LANG_SPECIFIC (decl))
        DECL_IN_AGGR_P (decl) = 0;
+      if (DECL_USE_TEMPLATE (decl) || CLASSTYPE_USE_TEMPLATE (context))
+       SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+
+      /* Stupid stupid stupid stupid  (jason 7/21/95) */
+      if (pedantic && DECL_EXTERNAL (decl)
+         && ! DECL_TEMPLATE_SPECIALIZATION (decl))
+       cp_pedwarn ("declaration of `%#D' outside of class is not definition",
+                   decl);
+
       pushclass (context, 2);
     }
 
@@ -5993,7 +6195,7 @@ make_temporary_for_reference (decl, ctor_call, init, cleanupp)
     }
 
   TREE_TYPE (tmp_addr) = build_pointer_type (target_type);
-  DECL_INITIAL (decl) = convert (TYPE_POINTER_TO (target_type), tmp_addr);
+  DECL_INITIAL (decl) = convert (build_pointer_type (target_type), tmp_addr);
   TREE_TYPE (DECL_INITIAL (decl)) = type;
   if (TYPE_NEEDS_CONSTRUCTING (target_type))
     {
@@ -6101,7 +6303,7 @@ grok_reference_init (decl, type, init, cleanupp)
              if (TREE_CODE (tmp) == TARGET_EXPR)
                {
                  *cleanupp = build_delete
-                   (TYPE_POINTER_TO (subtype),
+                   (build_pointer_type (subtype),
                     build_unary_op (ADDR_EXPR, TREE_OPERAND (tmp, 0), 0),
                     integer_two_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
                  TREE_OPERAND (tmp, 2) = error_mark_node;
@@ -6344,7 +6546,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
            init = digest_init (type, init, (tree *) 0);
          else if (TREE_CODE (init) == CONSTRUCTOR)
            {
-             if (TYPE_NEEDS_CONSTRUCTING (type))
+             if (TYPE_NON_AGGREGATE_CLASS (type))
                {
                  cp_error ("`%D' must be initialized by constructor, not by `{...}'",
                            decl);
@@ -6353,47 +6555,6 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
              else
                goto dont_use_constructor;
            }
-#if 0
-         /* fix this in `build_functional_cast' instead.
-            Here's the trigger code:
-
-               struct ostream
-               {
-                 ostream ();
-                 ostream (int, char *);
-                 ostream (char *);
-                 operator char *();
-                 ostream (void *);
-                 operator void *();
-                 operator << (int);
-               };
-               int buf_size = 1024;
-               static char buf[buf_size];
-               const char *debug(int i) {
-                 char *b = &buf[0];
-                 ostream o = ostream(buf_size, b);
-                 o << i;
-                 return buf;
-               }
-               */
-
-         else if (TREE_CODE (init) == TARGET_EXPR
-                  && TREE_CODE (TREE_OPERAND (init, 1) == NEW_EXPR))
-           {
-             /* User wrote something like `foo x = foo (args)'  */
-             my_friendly_assert (TREE_CODE (TREE_OPERAND (init, 0)) == VAR_DECL, 150);
-             my_friendly_assert (DECL_NAME (TREE_OPERAND (init, 0)) == NULL_TREE, 151);
-
-             /* User wrote exactly `foo x = foo (args)'  */
-             if (TYPE_MAIN_VARIANT (type) == TREE_TYPE (init))
-               {
-                 init = build (CALL_EXPR, TREE_TYPE (init),
-                               TREE_OPERAND (TREE_OPERAND (init, 1), 0),
-                               TREE_OPERAND (TREE_OPERAND (init, 1), 1), 0);
-                 TREE_SIDE_EFFECTS (init) = 1;
-               }
-           }
-#endif
        }
       else
        {
@@ -6688,11 +6849,9 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
       else if (TREE_STATIC (decl) && type != error_mark_node)
        {
          /* Cleanups for static variables are handled by `finish_file'.  */
-         if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE)
+         if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
+             || TYPE_NEEDS_DESTRUCTOR (type))
            expand_static_init (decl, init);
-         else if (TYPE_NEEDS_DESTRUCTOR (type))
-           static_aggregates = perm_tree_cons (NULL_TREE, decl,
-                                               static_aggregates);
 
          /* Make entry in appropriate vector.  */
          if (flag_gc && type_needs_gc_entry (type))
@@ -6700,7 +6859,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
        }
       else if (! toplev)
        {
+         extern int temp_slot_level;
+         extern int target_temp_slot_level;
          tree old_cleanups = cleanups_this_call;
+         int old_temp_level = target_temp_slot_level;
+
          /* This is a declared decl which must live until the
             end of the binding contour.  It may need a cleanup.  */
 
@@ -6727,7 +6890,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
                {
                  /* XXX: Why don't we use decl here?  */
                  /* Ans: Because it was already expanded? */
-                 if (! expand_decl_cleanup (NULL_TREE, cleanup))
+                 if (! cp_expand_decl_cleanup (NULL_TREE, cleanup))
                    cp_error ("parser lost in parsing declaration of `%D'",
                              decl);
                  /* Cleanup used up here.  */
@@ -6735,6 +6898,10 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
                }
            }
 
+         push_temp_slots ();
+         push_temp_slots ();
+         target_temp_slot_level = temp_slot_level;
+
          if (DECL_SIZE (decl) && type != error_mark_node)
            {
              /* Compute and store the initial value.  */
@@ -6751,19 +6918,24 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
                 was initialized was ever used.  Don't do this if it has a
                 destructor, so we don't complain about the 'resource
                 allocation is initialization' idiom.  */
-             if (TYPE_NEEDS_CONSTRUCTING (type) && cleanup == NULL_TREE)
+             if (TYPE_NEEDS_CONSTRUCTING (type)
+                 && cleanup == NULL_TREE
+                 && DECL_NAME (decl))
                TREE_USED (decl) = 0;
 
              /* Store the cleanup, if there was one.  */
              if (cleanup)
                {
-                 if (! expand_decl_cleanup (decl, cleanup))
+                 if (! cp_expand_decl_cleanup (decl, cleanup))
                    cp_error ("parser lost in parsing declaration of `%D'",
                              decl);
                }
            }
          /* Cleanup any temporaries needed for the initial value.  */
          expand_cleanups_to (old_cleanups);
+         pop_temp_slots ();
+         pop_temp_slots ();
+         target_temp_slot_level = old_temp_level;
        }
     finish_end0:
 
@@ -6771,7 +6943,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
         due to initialization of qualified member variable.
         I.e., Foo::x = 10;  */
       {
-       tree context = DECL_CONTEXT (decl);
+       tree context = DECL_REAL_CONTEXT (decl);
        if (context
            && TREE_CODE_CLASS (TREE_CODE (context)) == 't'
            && (TREE_CODE (decl) == VAR_DECL
@@ -6842,7 +7014,6 @@ expand_static_init (decl, init)
      tree init;
 {
   tree oldstatic = value_member (decl, static_aggregates);
-  tree old_cleanups;
 
   if (oldstatic)
     {
@@ -6854,6 +7025,11 @@ expand_static_init (decl, init)
       /* Emit code to perform this initialization but once.  */
       tree temp;
 
+      extern int temp_slot_level;
+      extern int target_temp_slot_level;
+      tree old_cleanups;
+      int old_temp_level;
+
       /* Remember this information until end of file. */
       push_obstacks (&permanent_obstack, &permanent_obstack);
 
@@ -6863,17 +7039,62 @@ expand_static_init (decl, init)
       expand_start_cond (build_binary_op (EQ_EXPR, temp,
                                          integer_zero_node, 1), 0);
       old_cleanups = cleanups_this_call;
+      old_temp_level = target_temp_slot_level;
+      push_temp_slots ();
+      push_temp_slots ();
+      target_temp_slot_level = temp_slot_level;
+
       expand_assignment (temp, integer_one_node, 0, 0);
       if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
-         || TREE_CODE (init) == TREE_LIST)
+         || (init && TREE_CODE (init) == TREE_LIST))
        {
          expand_aggr_init (decl, init, 0, 0);
          do_pending_stack_adjust ();
        }
-      else
+      else if (init)
        expand_assignment (decl, init, 0, 0);
+
       /* Cleanup any temporaries needed for the initial value.  */
       expand_cleanups_to (old_cleanups);
+      pop_temp_slots ();
+      pop_temp_slots ();
+      target_temp_slot_level = old_temp_level;
+
+      if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
+       {
+         tree cleanup, fcall;
+         static tree Atexit = 0;
+         if (Atexit == 0)
+           {
+             tree atexit_fndecl, PFV, pfvlist;
+             /* Remember this information until end of file. */
+             push_obstacks (&permanent_obstack, &permanent_obstack);
+             PFV = build_pointer_type (build_function_type
+                                       (void_type_node, void_list_node));
+
+             pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
+
+             push_lang_context (lang_name_c);
+             atexit_fndecl = 
+               builtin_function ("atexit",
+                                 build_function_type (void_type_node,
+                                                      pfvlist),
+                                 NOT_BUILT_IN, NULL_PTR);
+             assemble_external (atexit_fndecl);
+             Atexit = default_conversion (atexit_fndecl);
+             pop_lang_context ();
+             pop_obstacks ();
+           }
+             
+         cleanup = start_anon_func ();
+         expand_expr_stmt (build_cleanup (decl));
+         end_anon_func ();
+         mark_addressable (cleanup);
+         cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
+         fcall = build_function_call (Atexit, tree_cons (NULL_TREE, cleanup, NULL_TREE));
+         expand_expr_stmt (fcall);
+       }
+
       expand_end_cond ();
       if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
        {
@@ -6955,7 +7176,7 @@ complete_array_type (type, initial_value, do_default)
       tree itype;
 
       TYPE_DOMAIN (type) = build_index_type (maxindex);
-      if (!TREE_TYPE (maxindex))
+      if (! TREE_TYPE (maxindex))
        TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
       if (initial_value)
         itype = TREE_TYPE (initial_value);
@@ -6963,6 +7184,11 @@ complete_array_type (type, initial_value, do_default)
        itype = NULL;
       if (itype && !TYPE_DOMAIN (itype))
        TYPE_DOMAIN (itype) = TYPE_DOMAIN (type);
+      /* The type of the main variant should never be used for arrays
+        of different sizes.  It should only ever be completed with the
+        size of the array.  */
+      if (! TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)))
+       TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = TYPE_DOMAIN (type);
     }
 
   /* Lay out the type now that we can get the real answer.  */
@@ -7024,12 +7250,12 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
    not look, and -1 if we should not call `grokclassfn' at all.  */
 static tree
 grokfndecl (ctype, type, declarator, virtualp, flags, quals,
-           raises, check, publicp, inlinep)
+           raises, attrlist, check, publicp, inlinep)
      tree ctype, type;
      tree declarator;
      int virtualp;
      enum overload_flags flags;
-     tree quals, raises;
+     tree quals, raises, attrlist;
      int check, publicp, inlinep;
 {
   tree cname, decl;
@@ -7043,7 +7269,7 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
 
   if (raises)
     {
-      type = build_exception_variant (ctype, type, raises);
+      type = build_exception_variant (type, raises);
       raises = TYPE_RAISES_EXCEPTIONS (type);
     }
   decl = build_lang_decl (FUNCTION_DECL, declarator, type);
@@ -7164,6 +7390,10 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
              /* avoid creating circularities.  */
              DECL_CHAIN (decl) = NULL_TREE;
            }
+
+         if (attrlist)
+           cplus_decl_attributes (decl, TREE_PURPOSE (attrlist),
+                                  TREE_VALUE (attrlist));
          make_decl_rtl (decl, NULL_PTR, 1);
        }
 
@@ -7214,7 +7444,7 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
                      type = build_cplus_method_type (base_variant, TREE_TYPE (type), argtypes);
                      if (raises)
                        {
-                         type = build_exception_variant (ctype, type, raises);
+                         type = build_exception_variant (type, raises);
                          raises = TYPE_RAISES_EXCEPTIONS (type);
                        }
                      TREE_TYPE (decl) = type;
@@ -7292,7 +7522,7 @@ grokvardecl (type, declarator, specbits, initialized, constp)
   else if (toplevel_bindings_p ())
     {
       TREE_PUBLIC (decl) = (RIDBIT_NOTSETP (RID_STATIC, specbits)
-                           && (DECL_EXTERNAL (decl) || ! constp));
+                           && (DECL_THIS_EXTERN (decl) || ! constp));
       TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
     }
   /* Not at top level, only `static' makes a static definition.  */
@@ -7324,6 +7554,7 @@ build_ptrmemfunc_type (type)
   push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
 
   u = make_lang_type (UNION_TYPE);
+  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);
@@ -7416,12 +7647,12 @@ build_ptrmemfunc_type (type)
 enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
 
 tree
-grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
+grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrlist)
      tree declspecs;
      tree declarator;
      enum decl_context decl_context;
      int initialized;
-     tree raises;
+     tree raises, attrlist;
 {
   RID_BIT_TYPE specbits;
   int nclasses = 0;
@@ -7471,222 +7702,211 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   /* Look inside a declarator for the name being declared
      and get it as a string, for an error message.  */
   {
-    tree last = NULL_TREE;
-    register tree decl = declarator;
+    tree *next = &declarator;
+    register tree decl;
     name = NULL;
 
-    while (decl)
-      switch (TREE_CODE (decl))
-        {
-       case COND_EXPR:
-         ctype = NULL_TREE;
-         decl = TREE_OPERAND (decl, 0);
-         break;
-
-       case BIT_NOT_EXPR:      /* for C++ destructors!  */
+    while (next && *next)
+      {
+       decl = *next;
+       switch (TREE_CODE (decl))
          {
-           tree name = TREE_OPERAND (decl, 0);
-           tree rename = NULL_TREE;
-
-           my_friendly_assert (flags == NO_SPECIAL, 152);
-           flags = DTOR_FLAG;
-           return_type = return_dtor;
-           my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
-           if (ctype == NULL_TREE)
-             {
-               if (current_class_type == NULL_TREE)
-                 {
-                   error ("destructors must be member functions");
-                   flags = NO_SPECIAL;
-                 }
-               else
-                 {
-                   tree t = constructor_name (current_class_name);
-                   if (t != name)
-                     rename = t;
-                 }
-             }
-           else
-             {
-               tree t = constructor_name (ctype);
-               if (t != name)
-                 rename = t;
-             }
-
-           if (rename)
-             {
-               error ("destructor `%s' must match class name `%s'",
-                      IDENTIFIER_POINTER (name),
-                      IDENTIFIER_POINTER (rename));
-               TREE_OPERAND (decl, 0) = rename;
-             }
-           decl = name;
-         }
-         break;
-
-       case ADDR_EXPR:         /* C++ reference declaration */
-         /* fall through */
-       case ARRAY_REF:
-       case INDIRECT_REF:
-         ctype = NULL_TREE;
-         innermost_code = TREE_CODE (decl);
-         last = decl;
-         decl = TREE_OPERAND (decl, 0);
-         break;
+         case COND_EXPR:
+           ctype = NULL_TREE;
+           next = &TREE_OPERAND (decl, 0);
+           break;
 
-       case CALL_EXPR:
-         if (parmlist_is_exprlist (TREE_OPERAND (decl, 1)))
+         case BIT_NOT_EXPR:    /* for C++ destructors!  */
            {
-             /* This is actually a variable declaration using constructor
-                syntax.  We need to call start_decl and cp_finish_decl so we
-                can get the variable initialized...  */
-
-             if (last)
-               /* We need to insinuate ourselves into the declarator in place
-                  of the CALL_EXPR.  */
-               TREE_OPERAND (last, 0) = TREE_OPERAND (decl, 0);
+             tree name = TREE_OPERAND (decl, 0);
+             tree rename = NULL_TREE;
+
+             my_friendly_assert (flags == NO_SPECIAL, 152);
+             flags = DTOR_FLAG;
+             return_type = return_dtor;
+             my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
+             if (ctype == NULL_TREE)
+               {
+                 if (current_class_type == NULL_TREE)
+                   {
+                     error ("destructors must be member functions");
+                     flags = NO_SPECIAL;
+                   }
+                 else
+                   {
+                     tree t = constructor_name (current_class_name);
+                     if (t != name)
+                       rename = t;
+                   }
+               }
              else
-               declarator = TREE_OPERAND (decl, 0);
-
-             init = TREE_OPERAND (decl, 1);
-
-             decl = start_decl (declarator, declspecs, 1, NULL_TREE);
-             finish_decl (decl, init, NULL_TREE);
-             return 0;
-           }
-         innermost_code = TREE_CODE (decl);
-         if (decl_context == FIELD && ctype == NULL_TREE)
-           ctype = current_class_type;
-         if (ctype
-             && TREE_OPERAND (decl, 0) == constructor_name_full (ctype))
-           TREE_OPERAND (decl, 0) = constructor_name (ctype);
-         decl = TREE_OPERAND (decl, 0);
-         if (ctype != NULL_TREE
-             && decl != NULL_TREE && flags != DTOR_FLAG
-             && decl == constructor_name (ctype))
-           {
-             return_type = return_ctor;
-             ctor_return_type = ctype;
-           }
-         ctype = NULL_TREE;
-         break;
-
-       case IDENTIFIER_NODE:
-         dname = decl;
-         decl = NULL_TREE;
+               {
+                 tree t = constructor_name (ctype);
+                 if (t != name)
+                   rename = t;
+               }
 
-         if (! IDENTIFIER_OPNAME_P (dname)
-             /* Linux headers use '__op'.  Arrgh.  */
-             || IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))
-           name = IDENTIFIER_POINTER (dname);
-         else
-           {
-             if (IDENTIFIER_TYPENAME_P (dname))
+             if (rename)
                {
-                 my_friendly_assert (flags == NO_SPECIAL, 154);
-                 flags = TYPENAME_FLAG;
-                 ctor_return_type = TREE_TYPE (dname);
-                 return_type = return_conversion;
+                 error ("destructor `%s' must match class name `%s'",
+                        IDENTIFIER_POINTER (name),
+                        IDENTIFIER_POINTER (rename));
+                 TREE_OPERAND (decl, 0) = rename;
                }
-             name = operator_name_string (dname);
+             next = &name;
            }
-         break;
+           break;
 
-       case RECORD_TYPE:
-       case UNION_TYPE:
-       case ENUMERAL_TYPE:
-         /* Parse error puts this typespec where
-            a declarator should go.  */
-         error ("declarator name missing");
-         dname = TYPE_NAME (decl);
-         if (dname && TREE_CODE (dname) == TYPE_DECL)
-           dname = DECL_NAME (dname);
-         name = dname ? IDENTIFIER_POINTER (dname) : "<nameless>";
-         declspecs = temp_tree_cons (NULL_TREE, decl, declspecs);
-         decl = NULL_TREE;
-         break;
+         case ADDR_EXPR:       /* C++ reference declaration */
+           /* fall through */
+         case ARRAY_REF:
+         case INDIRECT_REF:
+           ctype = NULL_TREE;
+           innermost_code = TREE_CODE (decl);
+           next = &TREE_OPERAND (decl, 0);
+           break;
 
-         /* C++ extension */
-       case SCOPE_REF:
-         {
-           /* Perform error checking, and convert class names to types.
-              We may call grokdeclarator multiple times for the same
-              tree structure, so only do the conversion once.  In this
-              case, we have exactly what we want for `ctype'.  */
-           tree cname = TREE_OPERAND (decl, 0);
-           if (cname == NULL_TREE)
-             ctype = NULL_TREE;
-           /* Can't use IS_AGGR_TYPE because CNAME might not be a type.  */
-           else if (IS_AGGR_TYPE_CODE (TREE_CODE (cname))
-                    || TREE_CODE (cname) == UNINSTANTIATED_P_TYPE)
-             ctype = cname;
-           else if (! is_aggr_typedef (cname, 1))
+         case CALL_EXPR:
+           if (parmlist_is_exprlist (TREE_OPERAND (decl, 1)))
              {
-               TREE_OPERAND (decl, 0) = NULL_TREE;
+               /* This is actually a variable declaration using constructor
+                  syntax.  We need to call start_decl and cp_finish_decl so we
+                  can get the variable initialized...  */
+
+               *next = TREE_OPERAND (decl, 0);
+               init = TREE_OPERAND (decl, 1);
+
+               decl = start_decl (declarator, declspecs, 1, NULL_TREE);
+               finish_decl (decl, init, NULL_TREE);
+               return 0;
              }
-           /* Must test TREE_OPERAND (decl, 1), in case user gives
-              us `typedef (class::memfunc)(int); memfunc *memfuncptr;'  */
-           else if (TREE_OPERAND (decl, 1)
-                    && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)
+           innermost_code = TREE_CODE (decl);
+           if (decl_context == FIELD && ctype == NULL_TREE)
+             ctype = current_class_type;
+           if (ctype && TREE_OPERAND (decl, 0) == ctype)
+             TREE_OPERAND (decl, 0) = constructor_name (ctype);
+           next = &TREE_OPERAND (decl, 0);
+           decl = *next;
+           if (ctype != NULL_TREE
+               && decl != NULL_TREE && flags != DTOR_FLAG
+               && decl == constructor_name (ctype))
              {
-               TREE_OPERAND (decl, 0) = IDENTIFIER_TYPE_VALUE (cname);
+               return_type = return_ctor;
+               ctor_return_type = ctype;
              }
-           else if (ctype == NULL_TREE)
+           ctype = NULL_TREE;
+           break;
+
+         case IDENTIFIER_NODE:
+           dname = decl;
+           next = 0;
+
+           if (is_rid (dname))
              {
-               ctype = IDENTIFIER_TYPE_VALUE (cname);
-               TREE_OPERAND (decl, 0) = ctype;
+               cp_error ("declarator-id missing; using reserved word `%D'",
+                         dname);
+               name = IDENTIFIER_POINTER (dname);
              }
-           else if (TREE_COMPLEXITY (decl) == current_class_depth)
-             TREE_OPERAND (decl, 0) = ctype;
+           if (! IDENTIFIER_OPNAME_P (dname)
+               /* Linux headers use '__op'.  Arrgh.  */
+               || IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))
+             name = IDENTIFIER_POINTER (dname);
            else
              {
-               if (! UNIQUELY_DERIVED_FROM_P (IDENTIFIER_TYPE_VALUE (cname),
-                                              ctype))
+               if (IDENTIFIER_TYPENAME_P (dname))
                  {
-                   cp_error ("type `%T' is not derived from type `%T'",
-                             IDENTIFIER_TYPE_VALUE (cname), ctype);
-                   TREE_OPERAND (decl, 0) = NULL_TREE;
-                 }
-               else
-                 {
-                   ctype = IDENTIFIER_TYPE_VALUE (cname);
-                   TREE_OPERAND (decl, 0) = ctype;
+                   my_friendly_assert (flags == NO_SPECIAL, 154);
+                   flags = TYPENAME_FLAG;
+                   ctor_return_type = TREE_TYPE (dname);
+                   return_type = return_conversion;
                  }
+               name = operator_name_string (dname);
              }
+           break;
 
-           if (ctype
-               && TREE_OPERAND (decl, 1) == constructor_name_full (ctype))
-             TREE_OPERAND (decl, 1) = constructor_name (ctype);
-           decl = TREE_OPERAND (decl, 1);
-           if (ctype)
+           /* C++ extension */
+         case SCOPE_REF:
+           {
+             /* Perform error checking, and decide on a ctype.  */
+             tree cname = TREE_OPERAND (decl, 0);
+             if (cname == NULL_TREE)
+               ctype = NULL_TREE;
+             else if (! is_aggr_type (cname, 1))
+               TREE_OPERAND (decl, 0) = NULL_TREE;
+             /* Must test TREE_OPERAND (decl, 1), in case user gives
+                us `typedef (class::memfunc)(int); memfunc *memfuncptr;'  */
+             else if (TREE_OPERAND (decl, 1)
+                      && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)
+               ctype = cname;
+             else if (ctype == NULL_TREE)
+               ctype = cname;
+             else if (TREE_COMPLEXITY (decl) == current_class_depth)
+               TREE_OPERAND (decl, 0) = ctype;
+             else
+               {
+                 if (! UNIQUELY_DERIVED_FROM_P (cname, ctype))
+                   {
+                     cp_error ("type `%T' is not derived from type `%T'",
+                               cname, ctype);
+                     TREE_OPERAND (decl, 0) = NULL_TREE;
+                   }
+                 else
+                   ctype = cname;
+               }
+
+             if (ctype
+                 && TREE_OPERAND (decl, 1) == constructor_name_full (ctype))
+               TREE_OPERAND (decl, 1) = constructor_name (ctype);
+             next = &TREE_OPERAND (decl, 1);
+             decl = *next;
+             if (ctype)
+               {
+                 if (TREE_CODE (decl) == IDENTIFIER_NODE
+                     && constructor_name (ctype) == decl)
+                   {
+                     return_type = return_ctor;
+                     ctor_return_type = ctype;
+                   }
+                 else if (TREE_CODE (decl) == BIT_NOT_EXPR
+                          && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
+                          && (constructor_name (ctype) == TREE_OPERAND (decl, 0)
+                              || constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
+                   {
+                     return_type = return_dtor;
+                     ctor_return_type = ctype;
+                     flags = DTOR_FLAG;
+                     TREE_OPERAND (decl, 0) = constructor_name (ctype);
+                     next = &TREE_OPERAND (decl, 0);
+                   }
+               }
+           }
+           break;
+
+         case ERROR_MARK:
+           next = 0;
+           break;
+
+         default:
+           if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't')
              {
-               if (TREE_CODE (decl) == IDENTIFIER_NODE
-                   && constructor_name (ctype) == decl)
-                 {
-                   return_type = return_ctor;
-                   ctor_return_type = ctype;
-                 }
-               else if (TREE_CODE (decl) == BIT_NOT_EXPR
-                        && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
-                        && (constructor_name (ctype) == TREE_OPERAND (decl, 0)
-                            || constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
-                 {
-                   return_type = return_dtor;
-                   ctor_return_type = ctype;
-                   flags = DTOR_FLAG;
-                   decl = TREE_OPERAND (decl, 0) = constructor_name (ctype);
-                 }
+               /* Parse error puts this typespec where
+                  a declarator should go.  */
+               error ("typename specified as declarator-id");
+               if (current_class_type)
+                 cp_error ("  perhaps you want `%T' for a constructor",
+                           current_class_name);
+               dname = TYPE_IDENTIFIER (decl);
+               name = dname ? IDENTIFIER_POINTER (dname) : "<nameless>";
+               declspecs = temp_tree_cons (NULL_TREE, integer_type_node,
+                                           declspecs);
+               *next = dname;
+               next = 0;
+               break;
              }
+           cp_compiler_error ("`%D' as declarator", decl);
+           return 0; /* We used to do a 155 abort here.  */
          }
-         break;
-
-       case ERROR_MARK:
-         decl = NULL_TREE;
-         break;
-
-       default:
-         return 0; /* We used to do a 155 abort here.  */
-       }
+      }
     if (name == NULL)
       name = "type name";
   }
@@ -7858,7 +8078,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
       if (return_type == return_dtor)
        type = void_type_node;
       else if (return_type == return_ctor)
-       type = TYPE_POINTER_TO (ctor_return_type);
+       type = build_pointer_type (ctor_return_type);
       else if (return_type == return_conversion)
        type = ctor_return_type;
       else if (current_class_type
@@ -7901,7 +8121,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
   else if (return_type == return_ctor)
     {
       error ("return type specification for constructor invalid");
-      type = TYPE_POINTER_TO (ctor_return_type);
+      type = build_pointer_type (ctor_return_type);
     }
   else if (return_type == return_conversion)
     {
@@ -8068,16 +8288,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          error ("non-object member `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
        }
-      else if (constp)
-       {
-         error ("const `%s' cannot be declared `mutable'", name);
-         RIDBIT_RESET (RID_MUTABLE, specbits);
-       }
-      else if (staticp)
-       {
-         error ("static `%s' cannot be declared `mutable'", name);
-         RIDBIT_RESET (RID_MUTABLE, specbits);
-       }
 #if 0
       if (RIDBIT_SETP (RID_TYPEDEF, specbits))
        {
@@ -8224,7 +8434,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
            SIGNATURE_GROKKING_TYPEDEF (current_class_type) = 1;
   
          loc_typedecl =
-           grokdeclarator (declarator, declspecs, FIELD, 0, NULL_TREE);
+           grokdeclarator (declarator, declspecs, FIELD, 0, NULL_TREE, NULL_TREE);
 
          if (previous_declspec)
            TREE_CHAIN (previous_declspec) = scanner;
@@ -8477,7 +8687,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                  cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", dname);
                if (TREE_CONSTANT (size))
                  {
+                   int old_flag_pedantic_errors = flag_pedantic_errors;
+                   int old_pedantic = pedantic;
+                   pedantic = flag_pedantic_errors = 1;
+                   /* Always give overflow errors on array subscripts.  */
                    constant_expression_warning (size);
+                   pedantic = old_pedantic;
+                   flag_pedantic_errors = old_flag_pedantic_errors;
                    if (INT_CST_LT (size, integer_zero_node))
                      {
                        cp_error ("size of array `%D' is negative", dname);
@@ -8637,7 +8853,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                      if (RIDBIT_ANY_SET (tmp_bits))
                        error ("return value type specifier for constructor ignored");
                    }
-                   type = TYPE_POINTER_TO (ctype);
+                   type = build_pointer_type (ctype);
                    if (decl_context == FIELD &&
                        IS_SIGNATURE (current_class_type))
                      {
@@ -9052,6 +9268,20 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
   /* If this is declaring a typedef name, return a TYPE_DECL.  */
 
+  if (RIDBIT_SETP (RID_MUTABLE, specbits))
+    {
+      if (constp)
+       {
+         error ("const `%s' cannot be declared `mutable'", name);
+         RIDBIT_RESET (RID_MUTABLE, specbits);
+       }
+      else if (staticp)
+       {
+         error ("static `%s' cannot be declared `mutable'", name);
+         RIDBIT_RESET (RID_MUTABLE, specbits);
+       }
+    }
+
   if (RIDBIT_SETP (RID_TYPEDEF, specbits))
     {
       tree decl;
@@ -9299,6 +9529,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
          {
            int publicp = 0;
 
+           /* We catch the others as conflicts with the builtin
+              typedefs.  */
+           if (friendp && declarator == ridpointers[(int) RID_SIGNED])
+             {
+               cp_error ("function `%D' cannot be declared friend",
+                         declarator);
+               friendp = 0;
+             }
+
            if (friendp == 0)
              {
                if (ctype == NULL_TREE)
@@ -9342,8 +9581,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                       || RIDBIT_SETP (RID_EXTERN, specbits)
                       || ! (funcdef_flag < 0 || inlinep));
            decl = grokfndecl (ctype, type, declarator,
-                              virtualp, flags, quals,
-                              raises, friendp ? -1 : 0, publicp, inlinep);
+                              virtualp, flags, quals, raises, attrlist,
+                              friendp ? -1 : 0, publicp, inlinep);
            if (decl == NULL_TREE)
              return NULL_TREE;
            decl = build_decl_attribute_variant (decl, decl_machine_attr);
@@ -9358,8 +9597,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
            /* All method decls are public, so tell grokfndecl to set
               TREE_PUBLIC, also.  */
            decl = grokfndecl (ctype, type, declarator,
-                              virtualp, flags, quals,
-                              raises, friendp ? -1 : 0, 1, 0);
+                              virtualp, flags, quals, raises, attrlist,
+                              friendp ? -1 : 0, 1, 0);
            if (decl == NULL_TREE)
              return NULL_TREE;
          }
@@ -9452,6 +9691,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
 
            if (staticp || (constp && initialized))
              {
+               /* ANSI C++ Apr '95 wp 9.2 */
+               if (staticp && 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_DECL is built by build_lang_field_decl.
@@ -9533,8 +9777,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                       && !RIDBIT_SETP (RID_INLINE, specbits)));
 
        decl = grokfndecl (ctype, type, original_name,
-                          virtualp, flags, quals,
-                          raises,
+                          virtualp, flags, quals, raises, attrlist,
                           processing_template_decl ? 0 : friendp ? 2 : 1,
                           publicp, inlinep);
        if (decl == NULL_TREE)
@@ -9607,8 +9850,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
            DECL_CONTEXT (decl) = ctype;
            if (staticp == 1)
              {
-               cp_error ("static member `%D' re-declared as static",
-                         decl);
+               cp_pedwarn ("static member `%D' re-declared as static", decl);
                staticp = 0;
                RIDBIT_RESET (RID_STATIC, specbits);
              }
@@ -9617,10 +9859,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                cp_error ("static member `%D' declared `register'", decl);
                RIDBIT_RESET (RID_REGISTER, specbits);
              }
-           if (RIDBIT_SETP (RID_EXTERN, specbits))
+           if (RIDBIT_SETP (RID_EXTERN, specbits) && pedantic)
              {
-               cp_error ("cannot explicitly declare member `%#D' to have extern linkage",
-                         decl);
+               cp_pedwarn ("cannot explicitly declare member `%#D' to have extern linkage",
+                           decl);
                RIDBIT_RESET (RID_EXTERN, specbits);
              }
          }
@@ -9823,7 +10065,8 @@ grokparms (first_parm, funcdef_flag)
                  /* @@ May need to fetch out a `raises' here.  */
                  decl = grokdeclarator (TREE_VALUE (decl),
                                         TREE_PURPOSE (decl),
-                                        PARM, init != NULL_TREE, NULL_TREE);
+                                        PARM, init != NULL_TREE,
+                                        NULL_TREE, NULL_TREE);
                  if (! decl)
                    continue;
                  type = TREE_TYPE (decl);
@@ -10345,7 +10588,13 @@ xref_tag (code_type_node, name, binfo, globalize)
 
   /* If a cross reference is requested, look up the type
      already defined for this tag and return it.  */
-  t = IDENTIFIER_TYPE_VALUE (name);
+  if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
+    {
+      t = name;
+      name = TYPE_NESTED_NAME (t);
+    }
+  else
+    t = IDENTIFIER_TYPE_VALUE (name);
   if (t && TREE_CODE (t) != code)
     t = NULL_TREE;
 
@@ -10528,17 +10777,17 @@ xref_basetypes (code_type_node, name, ref, binfo)
     {
       /* The base of a derived struct is public by default.  */
       int via_public
-       = (TREE_PURPOSE (binfo) == (tree)access_public
-          || TREE_PURPOSE (binfo) == (tree)access_public_virtual
+       = (TREE_PURPOSE (binfo) == access_public_node
+          || TREE_PURPOSE (binfo) == access_public_virtual_node
           || (tag_code != class_type
-              && (TREE_PURPOSE (binfo) == (tree)access_default
-                  || TREE_PURPOSE (binfo) == (tree)access_default_virtual)));
-      int via_protected = TREE_PURPOSE (binfo) == (tree)access_protected;
+              && (TREE_PURPOSE (binfo) == access_default_node
+                  || TREE_PURPOSE (binfo) == access_default_virtual_node)));
+      int via_protected = TREE_PURPOSE (binfo) == access_protected_node;
       int via_virtual
-       = (TREE_PURPOSE (binfo) == (tree)access_private_virtual
-          || TREE_PURPOSE (binfo) == (tree)access_public_virtual
-          || TREE_PURPOSE (binfo) == (tree)access_default_virtual);
-      tree basetype = TREE_TYPE (TREE_VALUE (binfo));
+       = (TREE_PURPOSE (binfo) == access_private_virtual_node
+          || TREE_PURPOSE (binfo) == access_public_virtual_node
+          || TREE_PURPOSE (binfo) == access_default_virtual_node);
+      tree basetype = TREE_VALUE (binfo);
       tree base_binfo;
 
       GNU_xref_hier (IDENTIFIER_POINTER (name),
@@ -10948,8 +11197,8 @@ grok_enum_decls (type, decl)
    @@ something we had previously.  */
 
 int
-start_function (declspecs, declarator, raises, pre_parsed_p)
-     tree declarator, declspecs, raises;
+start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
+     tree declspecs, declarator, raises, attrs;
      int pre_parsed_p;
 {
   tree decl1, olddecl;
@@ -10980,6 +11229,7 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
   protect_list = NULL_TREE;
   current_base_init_list = NULL_TREE;
   current_member_init_list = NULL_TREE;
+  ctor_label = dtor_label = NULL_TREE;
 
   clear_temp_name ();
 
@@ -11007,6 +11257,16 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
            cp_error_at ("previous declaration here", IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl1)));
        }
 
+      /* This can happen if a template class is instantiated as part of the
+        specialization of a member function which is defined in the class
+        template.  We should just use the specialization, but for now give an
+        error.  */
+      if (DECL_INITIAL (decl1) != NULL_TREE)
+       {
+         cp_error_at ("specialization of `%#D' not supported", decl1);
+         cp_error ("when defined in the class template body", decl1);
+       }
+
       last_function_parms = DECL_ARGUMENTS (decl1);
       last_function_parm_tags = NULL_TREE;
       fntype = TREE_TYPE (decl1);
@@ -11033,10 +11293,19 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
 
       /* In a fcn definition, arg types must be complete.  */
       require_complete_types_for_parms (last_function_parms);
+
+      /* In case some arg types were completed since the declaration was
+         parsed, fix up the decls.  */
+      {
+       tree t = last_function_parms;
+       for (; t; t = TREE_CHAIN (t))
+         layout_decl (t, 0);
+      }
     }
   else
     {
-      decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, raises);
+      decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, raises,
+                             NULL_TREE);
       /* If the declarator is not suitable for a function definition,
         cause a syntax error.  */
       if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) return 0;
@@ -11111,7 +11380,10 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
        TREE_TYPE (decl1)
          = build_function_type (void_type_node,
                                 TYPE_ARG_TYPES (TREE_TYPE (decl1)));
-      DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, TREE_TYPE (fntype));
+      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));
     }
 
   if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
@@ -11245,6 +11517,8 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
 
   GNU_xref_function (decl1, current_function_parms);
 
+  if (attrs)
+    cplus_decl_attributes (decl1, NULL_TREE, attrs);
   make_function_rtl (decl1);
 
   /* Allocate further tree nodes temporarily during compilation
@@ -11265,9 +11539,15 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
        restype = integer_type_node;
     }
   if (DECL_RESULT (decl1) == NULL_TREE)
-    DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, restype);
+    {
+      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);
+    }
 
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1)))
+  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
+      && DECL_LANGUAGE (decl1) == lang_cplusplus)
     {
       dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
       ctor_label = NULL_TREE;
@@ -11287,6 +11567,30 @@ start_function (declspecs, declarator, raises, pre_parsed_p)
   return 1;
 }
 \f
+void
+expand_start_early_try_stmts ()
+{
+  rtx insns;
+  start_sequence ();
+  expand_start_try_stmts ();
+  insns = get_insns ();
+  end_sequence ();
+  store_in_parms (insns);
+}
+
+void
+store_in_parms (insns)
+     rtx insns;
+{
+  rtx last_parm_insn;
+
+  last_parm_insn = get_first_nonparm_insn ();
+  if (last_parm_insn == NULL_RTX)
+    emit_insns (insns);
+  else
+    emit_insns_before (insns, previous_insn (last_parm_insn));
+}
+
 /* Store the parameter declarations into the current function declaration.
    This is called after parsing the parameter declarations, before
    digesting the body of the function.
@@ -11376,7 +11680,7 @@ store_parm_decls ()
              if (cleanup)
                {
                  expand_decl (parm);
-                 if (! expand_decl_cleanup (parm, cleanup))
+                 if (! cp_expand_decl_cleanup (parm, cleanup))
                    cp_error ("parser lost in parsing declaration of `%D'",
                              parm);
                  parms_have_cleanups = 1;
@@ -11426,7 +11730,7 @@ store_parm_decls ()
   if (flag_gc)
     {
       maybe_gc_cleanup = build_tree_list (NULL_TREE, error_mark_node);
-      if (! expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup))
+      if (! cp_expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup))
        cp_error ("parser lost in parsing declaration of `%D'", fndecl);
     }
 
@@ -11448,6 +11752,27 @@ store_parm_decls ()
        output_builtin_tdesc_entries ();
 #endif
     }
+
+  /* Take care of exception handling things. */
+  if (flag_handle_exceptions)
+    {
+      rtx insns;
+      start_sequence ();
+
+      /* Mark the start of a stack unwinder if we need one.  */
+      start_eh_unwinder ();
+
+      /* Do the starting of the exception specifications, if we have any.  */
+      if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
+       expand_start_eh_spec ();
+
+      insns = get_insns ();
+      end_sequence ();
+
+      if (insns)
+       store_in_parms (insns);
+    }
+  last_dtor_insn = get_last_insn ();
 }
 
 /* Bind a name and initialization to the return value of
@@ -11522,7 +11847,7 @@ finish_function (lineno, call_poplevel, nested)
 {
   register tree fndecl = current_function_decl;
   tree fntype, ctype = NULL_TREE;
-  rtx head, last_parm_insn, mark;
+  rtx last_parm_insn, insns;
   /* Label to use if this function is supposed to return a value.  */
   tree no_return_label = NULL_TREE;
   tree decls = NULL_TREE;
@@ -11574,6 +11899,7 @@ finish_function (lineno, call_poplevel, nested)
       tree in_charge_node = lookup_name (in_charge_identifier, 0);
       tree virtual_size;
       int ok_to_optimize_dtor = 0;
+      int empty_dtor = get_last_insn () == last_dtor_insn;
 
       if (current_function_assigns_this)
        cond = build (NE_EXPR, boolean_type_node,
@@ -11584,12 +11910,9 @@ finish_function (lineno, call_poplevel, nested)
 
          /* If this destructor is empty, then we don't need to check
             whether `this' is NULL in some cases.  */
-         mark = get_last_insn ();
-         last_parm_insn = get_first_nonparm_insn ();
-
          if ((flag_this_is_variable & 1) == 0)
            ok_to_optimize_dtor = 1;
-         else if (mark == last_parm_insn)
+         else if (empty_dtor)
            ok_to_optimize_dtor
              = (n_baseclasses == 0
                 || (n_baseclasses == 1
@@ -11654,8 +11977,8 @@ finish_function (lineno, call_poplevel, nested)
                {
                  if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
                    {
-                     tree ptr = convert_pointer_to_vbase (vbases, current_class_decl);
-                     expand_expr_stmt (build_delete (TYPE_POINTER_TO (BINFO_TYPE (vbases)),
+                     tree ptr = convert_pointer_to_vbase (BINFO_TYPE (vbases), current_class_decl);
+                     expand_expr_stmt (build_delete (build_pointer_type (BINFO_TYPE (vbases)),
                                                      ptr, integer_zero_node,
                                                      LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_HAS_IN_CHARGE, 0));
                    }
@@ -11679,7 +12002,7 @@ finish_function (lineno, call_poplevel, nested)
        exprstmt =
          build_method_call
            (build_indirect_ref
-            (build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type),
+            (build1 (NOP_EXPR, build_pointer_type (current_class_type),
                      error_mark_node),
              NULL_PTR),
             ansi_opname[(int) DELETE_EXPR],
@@ -11707,27 +12030,46 @@ finish_function (lineno, call_poplevel, nested)
 
       /* Back to the top of destructor.  */
       /* Dont execute destructor code if `this' is NULL.  */
-      mark = get_last_insn ();
-      last_parm_insn = get_first_nonparm_insn ();
-      if (last_parm_insn == NULL_RTX)
-       last_parm_insn = mark;
-      else
-       last_parm_insn = previous_insn (last_parm_insn);
 
-      /* Make all virtual function table pointers in non-virtual base
-        classes point to CURRENT_CLASS_TYPE's virtual function
-        tables.  */
-      expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_decl);
-      if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
-       expand_indirect_vtbls_init (binfo, C_C_D, current_class_decl, 0);
+      start_sequence ();
+
+      /* If the dtor is empty, and we know there is not possible way we could
+        use any vtable entries, before they are possibly set by a base class
+        dtor, we don't have to setup the vtables, as we know that any base
+        class dtoring will set up any vtables it needs.  We avoid MI,
+        because one base class dtor can do a virtual dispatch to an
+        overridden function that would need to have a non-related vtable set
+        up, we cannot avoid setting up vtables in that case.  We could
+        change this to see if there is just one vtable.  */
+      if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type))
+       {
+         /* Make all virtual function table pointers in non-virtual base
+            classes point to CURRENT_CLASS_TYPE's virtual function
+            tables.  */
+         expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_decl);
+
+         if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+           expand_indirect_vtbls_init (binfo, C_C_D, current_class_decl, 0);
+       }
+
       if (! ok_to_optimize_dtor)
        {
          cond = build_binary_op (NE_EXPR,
                                  current_class_decl, integer_zero_node, 1);
          expand_start_cond (cond, 0);
        }
-      if (mark != get_last_insn ())
-       reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
+
+      insns = get_insns ();
+      end_sequence ();
+
+      last_parm_insn = get_first_nonparm_insn ();
+      if (last_parm_insn == NULL_RTX)
+       last_parm_insn = get_last_insn ();
+      else
+       last_parm_insn = previous_insn (last_parm_insn);
+
+      emit_insns_after (insns, last_parm_insn);
+
       if (! ok_to_optimize_dtor)
        expand_end_cond ();
     }
@@ -11781,11 +12123,7 @@ finish_function (lineno, call_poplevel, nested)
 
       CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
 
-      /* must keep the first insn safe.  */
-      head = get_insns ();
-
-      /* this note will come up to the top with us.  */
-      mark = get_last_insn ();
+      start_sequence ();
 
       if (flag_this_is_variable > 0)
        {
@@ -11808,6 +12146,9 @@ finish_function (lineno, call_poplevel, nested)
          base_init_expr = NULL_TREE;
        }
 
+      insns = get_insns ();
+      end_sequence ();
+
       /* This is where the body of the constructor begins.
         If there were no insns in this function body, then the
         last_parm_insn is also the last insn.
@@ -11816,12 +12157,11 @@ finish_function (lineno, call_poplevel, nested)
         we don't hold on to it (across emit_base_init).  */
       last_parm_insn = get_first_nonparm_insn ();
       if (last_parm_insn == NULL_RTX)
-       last_parm_insn = mark;
+       last_parm_insn = get_last_insn ();
       else
        last_parm_insn = previous_insn (last_parm_insn);
 
-      if (mark != get_last_insn ())
-       reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
+      emit_insns_after (insns, last_parm_insn);
 
       end_protect_partials ();
 
@@ -11918,7 +12258,7 @@ finish_function (lineno, call_poplevel, nested)
   expand_function_end (input_filename, lineno, 1);
 
   if (flag_handle_exceptions)
-    expand_exception_blocks();
+    expand_exception_blocks ();
 
   /* This must come after expand_function_end because cleanups might
      have declarations (from inline functions) that need to go into
@@ -12030,6 +12370,7 @@ finish_function (lineno, call_poplevel, nested)
     }
 
   named_label_uses = NULL_TREE;
+  current_class_decl = NULL_TREE;
 }
 \f
 /* Create the FUNCTION_DECL for a function definition.
@@ -12058,7 +12399,8 @@ tree
 start_method (declspecs, declarator, raises)
      tree declarator, declspecs, raises;
 {
-  tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, raises);
+  tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, raises,
+                               NULL_TREE);
 
   /* Something too ugly to handle.  */
   if (fndecl == NULL_TREE)
@@ -12229,57 +12571,45 @@ void
 hack_incomplete_structures (type)
      tree type;
 {
-  tree decl;
+  tree *list;
 
-  if (current_binding_level->n_incomplete == 0)
+  if (current_binding_level->incomplete == NULL_TREE)
     return;
 
   if (!type) /* Don't do this for class templates.  */
     return;
 
-  for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl))
-    if (TREE_TYPE (decl) == type
-       || (TREE_TYPE (decl)
-           && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
-           && TREE_TYPE (TREE_TYPE (decl)) == type))
-      {
-       if (TREE_CODE (decl) == TYPE_DECL)
-         layout_type (TREE_TYPE (decl));
-       else
-         {
-           int toplevel = toplevel_bindings_p ();
-           if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
-               && TREE_TYPE (TREE_TYPE (decl)) == type)
-             layout_type (TREE_TYPE (decl));
-           layout_decl (decl, 0);
-           rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
-           if (! toplevel)
-             {
-               tree cleanup;
-               expand_decl (decl);
-               cleanup = maybe_build_cleanup (decl);
-               expand_decl_init (decl);
-               if (! expand_decl_cleanup (decl, cleanup))
-                 cp_error ("parser lost in parsing declaration of `%D'",
-                           decl);
-             }
-         }
-       /*
-       my_friendly_assert (current_binding_level->n_incomplete > 0, 164);
-       */
-       --current_binding_level->n_incomplete;
-      }
+  for (list = &current_binding_level->incomplete; *list; )
+    {
+      tree decl = TREE_VALUE (*list);
+      if (decl && TREE_TYPE (decl) == type
+         || (TREE_TYPE (decl)
+             && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+             && TREE_TYPE (TREE_TYPE (decl)) == type))
+       {
+         int toplevel = toplevel_bindings_p ();
+         if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+             && TREE_TYPE (TREE_TYPE (decl)) == type)
+           layout_type (TREE_TYPE (decl));
+         layout_decl (decl, 0);
+         rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
+         if (! toplevel)
+           {
+             tree cleanup;
+             expand_decl (decl);
+             cleanup = maybe_build_cleanup (decl);
+             expand_decl_init (decl);
+             if (! cp_expand_decl_cleanup (decl, cleanup))
+               cp_error ("parser lost in parsing declaration of `%D'",
+                         decl);
+           }
+         *list = TREE_CHAIN (*list);
+       }
+      else
+       list = &TREE_CHAIN (*list);
+    }
 }
 
-/* Nonzero if presently building a cleanup.  Needed because
-   SAVE_EXPRs are not the right things to use inside of cleanups.
-   They are only ever evaluated once, where the cleanup
-   might be evaluated several times.  In this case, a later evaluation
-   of the cleanup might fill in the SAVE_EXPR_RTL, and it will
-   not be valid for an earlier cleanup.  */
-
-int building_cleanup;
-
 /* If DECL is of a type which needs a cleanup, build that cleanup here.
    We don't build cleanups if just going for syntax checking, since
    fixup_cleanups does not know how to not handle them.
@@ -12295,8 +12625,6 @@ maybe_build_cleanup (decl)
     {
       int temp = 0, flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
       tree rval;
-      int old_building_cleanup = building_cleanup;
-      building_cleanup = 1;
 
       if (TREE_CODE (decl) != PARM_DECL)
        temp = suspend_momentary ();
@@ -12321,11 +12649,12 @@ maybe_build_cleanup (decl)
        rval = build_compound_expr (tree_cons (NULL_TREE, rval,
                                               build_tree_list (NULL_TREE, build_vbase_delete (type, decl))));
 
+      /* Since this is a cleanup, UNSAVE it now.  */
+      rval = unsave_expr (rval);
+
       if (TREE_CODE (decl) != PARM_DECL)
        resume_momentary (temp);
 
-      building_cleanup = old_building_cleanup;
-
       return rval;
     }
   return 0;
@@ -12344,6 +12673,14 @@ void
 cplus_expand_expr_stmt (exp)
      tree exp;
 {
+  extern int temp_slot_level;
+  extern int target_temp_slot_level; 
+  tree old_cleanups = cleanups_this_call;
+  int old_temp_level = target_temp_slot_level;
+  push_temp_slots ();
+  push_temp_slots ();
+  target_temp_slot_level = temp_slot_level;
+
   if (TREE_TYPE (exp) == unknown_type_node)
     {
       if (TREE_CODE (exp) == ADDR_EXPR || TREE_CODE (exp) == TREE_LIST)
@@ -12371,7 +12708,16 @@ cplus_expand_expr_stmt (exp)
 
   /* Clean up any pending cleanups.  This happens when a function call
      returns a cleanup-needing value that nobody uses.  */
-  expand_cleanups_to (NULL_TREE);
+  expand_cleanups_to (old_cleanups);
+  pop_temp_slots ();
+  pop_temp_slots ();
+  target_temp_slot_level = old_temp_level;
+  /* There might something left from building the trees.  */
+  if (cleanups_this_call)
+    {
+      expand_cleanups_to (NULL_TREE);
+    }
+  free_temp_slots ();
 }
 
 /* When a stmt has been parsed, this function is called.
@@ -12419,13 +12765,20 @@ 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);
+
   args = TREE_CHAIN (args);
   tmp = build_function_type (TREE_TYPE (function), args);
   tmp = build_type_variant (tmp, TYPE_READONLY (function),
                            TYPE_VOLATILE (function));
-  tmp = build_exception_variant (TYPE_METHOD_BASETYPE (function), tmp,
+  tmp = build_exception_variant (tmp,
                                 TYPE_RAISES_EXCEPTIONS (function));
   TREE_TYPE (*decl) = tmp;
+  if (DECL_ARGUMENTS (*decl))
+    DECL_ARGUMENTS (*decl) = TREE_CHAIN (DECL_ARGUMENTS (*decl));
   DECL_STATIC_FUNCTION_P (*decl) = 1;
   if (fn)
     *fn = tmp;
@@ -12453,6 +12806,7 @@ struct cp_function
   tree shadowed_labels;
   tree ctor_label;
   tree dtor_label;
+  rtx last_dtor_insn;
   tree protect_list;
   tree base_init_list;
   tree member_init_list;
@@ -12462,8 +12816,11 @@ struct cp_function
   rtx result_rtx;
   struct cp_function *next;
   struct binding_level *binding_level;
+  void* eh_context;
 };
 
+
+
 struct cp_function *cp_function_chain;
 
 extern int temp_name_counter;
@@ -12491,6 +12848,7 @@ push_cp_function_context (context)
   p->binding_level = current_binding_level;
   p->ctor_label = ctor_label;
   p->dtor_label = dtor_label;
+  p->last_dtor_insn = last_dtor_insn;
   p->assigns_this = current_function_assigns_this;
   p->just_assigned_this = current_function_just_assigned_this;
   p->parms_stored = current_function_parms_stored;
@@ -12502,6 +12860,8 @@ push_cp_function_context (context)
   p->member_init_list = current_member_init_list;
   p->class_decl = current_class_decl;
   p->C_C_D = C_C_D;
+
+  p->eh_context = push_eh_context ();
 }
 
 /* Restore the variables used during compilation of a C++ function.  */
@@ -12542,6 +12902,7 @@ pop_cp_function_context (context)
   current_binding_level = p->binding_level;
   ctor_label = p->ctor_label;
   dtor_label = p->dtor_label;
+  last_dtor_insn = p->last_dtor_insn;
   protect_list = p->protect_list;
   current_function_assigns_this = p->assigns_this;
   current_function_just_assigned_this = p->just_assigned_this;
@@ -12554,5 +12915,101 @@ pop_cp_function_context (context)
   current_class_decl = p->class_decl;
   C_C_D = p->C_C_D;
 
+  pop_eh_context (p->eh_context);
+
   free (p);
 }
+
+/* FSF LOCAL dje prefix attributes */
+/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
+   lists.  SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
+
+   The head of the declspec list is stored in DECLSPECS.
+   The head of the attribute list is stored in PREFIX_ATTRIBUTES.
+
+   Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
+   the list elements.  We drop the containing TREE_LIST nodes and link the
+   resulting attributes together the way decl_attributes expects them.  */
+
+void
+split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
+     tree specs_attrs;
+     tree *declspecs, *prefix_attributes;
+{
+  tree t, s, a, next, specs, attrs;
+
+  /* This can happen in c++ (eg: decl: typespec initdecls ';').  */
+  if (specs_attrs != NULL_TREE
+      && TREE_CODE (specs_attrs) != TREE_LIST)
+    {
+      *declspecs = specs_attrs;
+      *prefix_attributes = NULL_TREE;
+      return;
+    }
+
+  /* Remember to keep the lists in the same order, element-wise.  */
+
+  specs = s = NULL_TREE;
+  attrs = a = NULL_TREE;
+  for (t = specs_attrs; t; t = next)
+    {
+      next = TREE_CHAIN (t);
+      /* Declspecs have a non-NULL TREE_VALUE.  */
+      if (TREE_VALUE (t) != NULL_TREE)
+       {
+         if (specs == NULL_TREE)
+           specs = s = t;
+         else
+           {
+             TREE_CHAIN (s) = t;
+             s = t;
+           }
+       }
+      else
+       {
+         if (attrs == NULL_TREE)
+           attrs = a = TREE_PURPOSE (t);
+         else
+           {
+             TREE_CHAIN (a) = TREE_PURPOSE (t);
+             a = TREE_PURPOSE (t);
+           }
+       }
+    }
+
+  /* Terminate the lists.  */
+  if (s != NULL_TREE)
+    TREE_CHAIN (s) = NULL_TREE;
+  if (a != NULL_TREE)
+    TREE_CHAIN (a) = NULL_TREE;
+
+  /* All done.  */
+  *declspecs = specs;
+  *prefix_attributes = attrs;
+}
+
+/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
+   This function is used by the parser when a rule will accept attributes
+   in a particular position, but we don't want to support that just yet.
+
+   A warning is issued for every ignored attribute.  */
+
+tree
+strip_attrs (specs_attrs)
+     tree specs_attrs;
+{
+  tree specs, attrs;
+
+  split_specs_attrs (specs_attrs, &specs, &attrs);
+
+  while (attrs)
+    {
+      warning ("`%s' attribute ignored",
+              IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
+      attrs = TREE_CHAIN (attrs);
+    }
+
+  return specs;
+}
+/* END FSF LOCAL */
+