OSDN Git Service

Fix date on last entry.
[pf3gnuchains/gcc-fork.git] / gcc / c-decl.c
index 168400b..df1d707 100644 (file)
@@ -1,5 +1,6 @@
 /* Process declarations and variables for C compiler.
-   Copyright (C) 1988, 92-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+   Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -30,16 +31,17 @@ Boston, MA 02111-1307, USA.  */
 #include "system.h"
 #include "tree.h"
 #include "flags.h"
+#include "function.h"
 #include "output.h"
 #include "c-tree.h"
 #include "c-lex.h"
 #include "toplev.h"
+#include "defaults.h"
+#include "ggc.h"
 
 #if USE_CPPLIB
 #include "cpplib.h"
-extern cpp_reader  parse_in;
-extern cpp_options parse_options;
-static int cpp_initialized;
+extern cpp_reader parse_in;
 #endif
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
@@ -51,42 +53,6 @@ enum decl_context
   BITFIELD,                    /* Likewise but with specified width */
   TYPENAME};                   /* Typename (inside cast or sizeof)  */
 
-#ifndef CHAR_TYPE_SIZE
-#define CHAR_TYPE_SIZE BITS_PER_UNIT
-#endif
-
-#ifndef SHORT_TYPE_SIZE
-#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
-#endif
-
-#ifndef INT_TYPE_SIZE
-#define INT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef LONG_TYPE_SIZE
-#define LONG_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef LONG_LONG_TYPE_SIZE
-#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-
-#ifndef WCHAR_UNSIGNED
-#define WCHAR_UNSIGNED 0
-#endif
-
-#ifndef FLOAT_TYPE_SIZE
-#define FLOAT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef DOUBLE_TYPE_SIZE
-#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-
-#ifndef LONG_DOUBLE_TYPE_SIZE
-#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-
 /* We let tm.h override the types used here, to handle trivial differences
    such as the choice of unsigned int or long unsigned int for size_t.
    When machines start needing nontrivial differences in the size type,
@@ -105,117 +71,8 @@ enum decl_context
 #define WCHAR_TYPE "int"
 #endif
 \f
-/* a node which has tree code ERROR_MARK, and whose type is itself.
-   All erroneous expressions are replaced with this node.  All functions
-   that accept nodes as arguments should avoid generating error messages
-   if this node is one of the arguments, since it is undesirable to get
-   multiple error messages from one error in the input.  */
-
-tree error_mark_node;
-
-/* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */
-
-tree short_integer_type_node;
-tree integer_type_node;
-tree long_integer_type_node;
-tree long_long_integer_type_node;
-
-tree short_unsigned_type_node;
-tree unsigned_type_node;
-tree long_unsigned_type_node;
-tree long_long_unsigned_type_node;
-
-tree boolean_type_node;
-tree boolean_false_node;
-tree boolean_true_node;
-
-tree ptrdiff_type_node;
-
-tree unsigned_char_type_node;
-tree signed_char_type_node;
-tree char_type_node;
-tree wchar_type_node;
-tree signed_wchar_type_node;
-tree unsigned_wchar_type_node;
-
-tree float_type_node;
-tree double_type_node;
-tree long_double_type_node;
-
-tree complex_integer_type_node;
-tree complex_float_type_node;
-tree complex_double_type_node;
-tree complex_long_double_type_node;
-
-tree intQI_type_node;
-tree intHI_type_node;
-tree intSI_type_node;
-tree intDI_type_node;
-tree intTI_type_node;
-
-tree unsigned_intQI_type_node;
-tree unsigned_intHI_type_node;
-tree unsigned_intSI_type_node;
-tree unsigned_intDI_type_node;
-tree unsigned_intTI_type_node;
-
-/* a VOID_TYPE node.  */
-
-tree void_type_node;
-
-/* Nodes for types `void *' and `const void *'.  */
-
-tree ptr_type_node, const_ptr_type_node;
-
-/* Nodes for types `char *' and `const char *'.  */
-
-tree string_type_node, const_string_type_node;
-
-/* Type `char[SOMENUMBER]'.
-   Used when an array of char is needed and the size is irrelevant.  */
-
-tree char_array_type_node;
-
-/* Type `int[SOMENUMBER]' or something like it.
-   Used when an array of int needed and the size is irrelevant.  */
-
-tree int_array_type_node;
-
-/* Type `wchar_t[SOMENUMBER]' or something like it.
-   Used when a wide string literal is created.  */
-
-tree wchar_array_type_node;
-
-/* type `int ()' -- used for implicit declaration of functions.  */
-
-tree default_function_type;
-
-/* function types `double (double)' and `double (double, double)', etc.  */
-
-tree double_ftype_double, double_ftype_double_double;
-tree int_ftype_int, long_ftype_long;
-tree float_ftype_float;
-tree ldouble_ftype_ldouble;
-
-/* Function type `void (void *, void *, int)' and similar ones */
-
-tree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int;
-
-/* Function type `char *(char *, char *)' and similar ones */
-tree string_ftype_ptr_ptr, int_ftype_string_string;
-
-/* Function type `int (const void *, const void *, size_t)' */
-tree int_ftype_cptr_cptr_sizet;
-
-/* Two expressions that are constants with value zero.
-   The first is of type `int', the second of type `void *'.  */
-
-tree integer_zero_node;
-tree null_pointer_node;
-
-/* A node for the integer constant 1.  */
-
-tree integer_one_node;
+/* Do GC.  */
+int ggc_p = 1;
 
 /* Nonzero if we have seen an invalid cross reference
    to a struct, union, or enum, but not yet printed the message.  */
@@ -276,10 +133,6 @@ static tree shadowed_labels;
 
 static int c_function_varargs;
 
-/* The FUNCTION_DECL for the function currently being compiled,
-   or 0 if between functions.  */
-tree current_function_decl;
-
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
 
@@ -421,20 +274,21 @@ tree static_ctors, static_dtors;
 
 /* Forward declarations.  */
 
-static struct binding_level * make_binding_level       PROTO((void));
-static void clear_limbo_values         PROTO((tree));
-static int duplicate_decls             PROTO((tree, tree, int));
-static char *redeclaration_error_message PROTO((tree, tree));
-static void storedecls                 PROTO((tree));
-static void storetags                  PROTO((tree));
-static tree lookup_tag                 PROTO((enum tree_code, tree,
-                                              struct binding_level *, int));
-static tree lookup_tag_reverse         PROTO((tree));
-static tree grokdeclarator             PROTO((tree, tree, enum decl_context,
-                                              int));
-static tree grokparms                  PROTO((tree, int));
-static int field_decl_cmp              PROTO((const GENERIC_PTR, const GENERIC_PTR));
-static void layout_array_type          PROTO((tree));
+static struct binding_level * make_binding_level       PARAMS ((void));
+static void mark_binding_level         PARAMS ((void *));
+static void clear_limbo_values         PARAMS ((tree));
+static int duplicate_decls             PARAMS ((tree, tree, int));
+static int redeclaration_error_message PARAMS ((tree, tree));
+static void storedecls                 PARAMS ((tree));
+static void storetags                  PARAMS ((tree));
+static tree lookup_tag                 PARAMS ((enum tree_code, tree,
+                                                struct binding_level *, int));
+static tree lookup_tag_reverse         PARAMS ((tree));
+static tree grokdeclarator             PARAMS ((tree, tree, enum decl_context,
+                                                int));
+static tree grokparms                  PARAMS ((tree, int));
+static void layout_array_type          PARAMS ((tree));
+static tree c_make_fname_decl           PARAMS ((tree, const char *, int));
 \f
 /* C-specific option variables.  */
 
@@ -447,6 +301,10 @@ int flag_cond_mismatch;
 
 int flag_short_double;
 
+/* Nonzero means give `wchar_t' the same size as `short'.  */
+
+int flag_short_wchar;
+
 /* Nonzero means don't recognize the keyword `asm'.  */
 
 int flag_no_asm;
@@ -464,6 +322,10 @@ int flag_no_nonansi_builtin;
 
 int flag_traditional;
 
+/* Nonzero means use the ISO C99 dialect of C.  */
+
+int flag_isoc99 = 0;
+
 /* Nonzero means that we have builtin functions, and main is an int */
 
 int flag_hosted = 1;
@@ -477,10 +339,6 @@ int flag_allow_single_precision = 0;
 int flag_signed_bitfields = 1;
 int explicit_flag_signed_bitfields = 0;
 
-/* Nonzero means handle `#ident' directives.  0 means ignore them.  */
-
-int flag_no_ident = 0;
-
 /* Nonzero means warn about use of implicit int. */
 
 int warn_implicit_int;
@@ -511,6 +369,10 @@ int warn_cast_qual;
 
 int warn_bad_function_cast;
 
+/* Warn about functions which might be candidates for attribute noreturn. */
+
+int warn_missing_noreturn;
+
 /* Warn about traditional constructs whose meanings changed in ANSI C.  */
 
 int warn_traditional;
@@ -581,6 +443,10 @@ int warn_unknown_pragmas = 0; /* Tri state variable.  */
 
 int warn_sign_compare = -1;
 
+/* Warn about testing equality of floating point numbers. */
+
+int warn_float_equal = 0;
+
 /* Nonzero means warn about use of multicharacter literals.  */
 
 int warn_multichar = 1;
@@ -593,23 +459,17 @@ int warn_multichar = 1;
 int dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
 
 /* Decode the string P as a language-specific option for C.
-   Return the number of strings consumed.  */
+   Return the number of strings consumed.  Should not complain
+   if it does not recognise the option.  */
    
 int
 c_decode_option (argc, argv)
-     int argc;
+     int argc ATTRIBUTE_UNUSED;
      char **argv;
 {
   int strings_processed;
   char *p = argv[0];
 #if USE_CPPLIB
-  if (! cpp_initialized)
-    {
-      cpp_reader_init (&parse_in);
-      parse_in.data = &parse_options;
-      cpp_options_init (&parse_options);
-      cpp_initialized = 1;
-    }
   strings_processed = cpp_handle_option (&parse_in, argc, argv);
 #else
   strings_processed = 0;
@@ -640,6 +500,65 @@ c_decode_option (argc, argv)
       flag_traditional = 0;
       flag_writable_strings = 0;
     }
+  else if (!strncmp (p, "-std=", 5))
+    {
+      /* Select the appropriate language standard.  We currently
+        recognize:
+        -std=iso9899:1990      same as -ansi
+        -std=iso9899:199409    ISO C as modified in amend. 1
+        -std=iso9899:1999      ISO C 99
+        -std=c89               same as -std=iso9899:1990
+        -std=c99               same as -std=iso9899:1999
+        -std=gnu89             default, iso9899:1990 + gnu extensions
+        -std=gnu99             iso9899:1999 + gnu extensions
+      */
+      const char *argstart = &p[5];
+
+      if (!strcmp (argstart, "iso9899:1990")
+         || !strcmp (argstart, "c89"))
+       {
+       iso_1990:
+         flag_traditional = 0;
+         flag_writable_strings = 0;
+         flag_no_asm = 1;
+         flag_no_nonansi_builtin = 1;
+         flag_isoc99 = 0;
+       }
+      else if (!strcmp (argstart, "iso9899:199409"))
+       {
+         /* ??? The changes since ISO C 1990 are not supported.  */
+         goto iso_1990;
+       }
+      else if (!strcmp (argstart, "iso9899:199x")
+              || !strcmp (argstart, "iso9899:1999")
+              || !strcmp (argstart, "c9x")
+              || !strcmp (argstart, "c99"))
+       {
+         flag_traditional = 0;
+         flag_writable_strings = 0;
+         flag_no_asm = 1;
+         flag_no_nonansi_builtin = 1;
+         flag_isoc99 = 1;
+       }
+      else if (!strcmp (argstart, "gnu89"))
+       {
+         flag_traditional = 0;
+         flag_writable_strings = 0;
+         flag_no_asm = 0;
+         flag_no_nonansi_builtin = 0;
+         flag_isoc99 = 0;
+       }
+      else if (!strcmp (argstart, "gnu9x") || !strcmp (argstart, "gnu99"))
+       {
+         flag_traditional = 0;
+         flag_writable_strings = 0;
+         flag_no_asm = 0;
+         flag_no_nonansi_builtin = 0;
+         flag_isoc99 = 1;
+       }
+      else
+       error ("unknown C standard `%s'", argstart);
+    }
   else if (!strcmp (p, "-fdollars-in-identifiers"))
     dollars_in_ident = 1;
   else if (!strcmp (p, "-fno-dollars-in-identifiers"))
@@ -668,6 +587,10 @@ c_decode_option (argc, argv)
     flag_short_enums = 1;
   else if (!strcmp (p, "-fno-short-enums"))
     flag_short_enums = 0;
+  else if (!strcmp (p, "-fshort-wchar"))
+    flag_short_wchar = 1;
+  else if (!strcmp (p, "-fno-short-wchar"))
+    flag_short_wchar = 0;
   else if (!strcmp (p, "-fcond-mismatch"))
     flag_cond_mismatch = 1;
   else if (!strcmp (p, "-fno-cond-mismatch"))
@@ -684,12 +607,8 @@ c_decode_option (argc, argv)
     flag_no_builtin = 0;
   else if (!strcmp (p, "-fno-builtin"))
     flag_no_builtin = 1;
-  else if (!strcmp (p, "-fno-ident"))
-    flag_no_ident = 1;
-  else if (!strcmp (p, "-fident"))
-    flag_no_ident = 0;
   else if (!strcmp (p, "-ansi"))
-    flag_no_asm = 1, flag_no_nonansi_builtin = 1;
+    goto iso_1990;
   else if (!strcmp (p, "-Werror-implicit-function-declaration"))
     mesg_implicit_function_declaration = 2;
   else if (!strcmp (p, "-Wimplicit-function-declaration"))
@@ -724,6 +643,10 @@ c_decode_option (argc, argv)
     warn_bad_function_cast = 1;
   else if (!strcmp (p, "-Wno-bad-function-cast"))
     warn_bad_function_cast = 0;
+  else if (!strcmp (p, "-Wmissing-noreturn"))
+    warn_missing_noreturn = 1;
+  else if (!strcmp (p, "-Wno-missing-noreturn"))
+    warn_missing_noreturn = 0;
   else if (!strcmp (p, "-Wpointer-arith"))
     warn_pointer_arith = 1;
   else if (!strcmp (p, "-Wno-pointer-arith"))
@@ -752,6 +675,8 @@ c_decode_option (argc, argv)
     warn_traditional = 1;
   else if (!strcmp (p, "-Wno-traditional"))
     warn_traditional = 0;
+  else if (!strncmp (p, "-Wformat=", 9))
+    warn_format = atol (p + 9);
   else if (!strcmp (p, "-Wformat"))
     warn_format = 1;
   else if (!strcmp (p, "-Wno-format"))
@@ -799,11 +724,15 @@ c_decode_option (argc, argv)
   else if (!strcmp (p, "-Wmain"))
     warn_main = 1;
   else if (!strcmp (p, "-Wno-main"))
-    warn_main = 0;
+    warn_main = -1;
   else if (!strcmp (p, "-Wsign-compare"))
     warn_sign_compare = 1;
   else if (!strcmp (p, "-Wno-sign-compare"))
     warn_sign_compare = 0;
+  else if (!strcmp (p, "-Wfloat-equal"))
+    warn_float_equal = 1;
+  else if (!strcmp (p, "-Wno-float-equal"))
+    warn_float_equal = 0;
   else if (!strcmp (p, "-Wmultichar"))
     warn_multichar = 1;
   else if (!strcmp (p, "-Wno-multichar"))
@@ -942,7 +871,7 @@ kept_level_p ()
 
 void
 declare_parm_level (definition_flag)
-     int definition_flag;
+     int definition_flag ATTRIBUTE_UNUSED;
 {
   current_binding_level->parm_flag = 1;
 }
@@ -1056,27 +985,25 @@ poplevel (keep, reverse, functionbody)
 #if 0
   /* Warn about incomplete structure types in this level.  */
   for (link = tags; link; link = TREE_CHAIN (link))
-    if (TYPE_SIZE (TREE_VALUE (link)) == 0)
+    if (!COMPLETE_TYPE_P (TREE_VALUE (link)))
       {
        tree type = TREE_VALUE (link);
-       char *errmsg;
+       tree type_name = TYPE_NAME (type);
+       char *id = IDENTIFIER_POINTER (TREE_CODE (type_name) == IDENTIFIER_NODE
+                                      ? type_name
+                                      : DECL_NAME (type_name));
        switch (TREE_CODE (type))
          {
          case RECORD_TYPE:
-           errmsg = "`struct %s' incomplete in scope ending here";
+           error ("`struct %s' incomplete in scope ending here", id);
            break;
          case UNION_TYPE:
-           errmsg = "`union %s' incomplete in scope ending here";
+           error ("`union %s' incomplete in scope ending here", id);
            break;
          case ENUMERAL_TYPE:
-           errmsg = "`enum %s' incomplete in scope ending here";
+           error ("`enum %s' incomplete in scope ending here", id);
            break;
          }
-       if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
-         error (errmsg, IDENTIFIER_POINTER (TYPE_NAME (type)));
-       else
-         /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL.  */
-         error (errmsg, IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
       }
 #endif /* 0 */
 
@@ -1130,9 +1057,7 @@ poplevel (keep, reverse, functionbody)
   if (block != 0)
     {
       BLOCK_VARS (block) = decls;
-      BLOCK_TYPE_TAGS (block) = tags;
       BLOCK_SUBBLOCKS (block) = subblocks;
-      remember_end_note (block);
     }
 
   /* In each subblock, record that this is its superior.  */
@@ -1416,10 +1341,7 @@ pushtag (name, type)
        TYPE_NAME (type) = name;
     }
 
-  if (b == global_binding_level)
-    b->tags = perm_tree_cons (name, type, b->tags);
-  else
-    b->tags = saveable_tree_cons (name, type, b->tags);
+  b->tags = tree_cons (name, type, b->tags);
 
   /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the
      tagged type we just added to the current binding level.  This fake
@@ -1456,9 +1378,9 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
                           && DECL_INITIAL (newdecl) != 0);
   tree oldtype = TREE_TYPE (olddecl);
   tree newtype = TREE_TYPE (newdecl);
-  char *errmsg = 0;
+  int errmsg = 0;
 
-  if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd')
+  if (DECL_P (olddecl))
     DECL_MACHINE_ATTRIBUTES (newdecl)
       =  merge_machine_decl_attributes (olddecl, newdecl);
 
@@ -1546,17 +1468,6 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
          tree oldreturntype = TREE_TYPE (oldtype);
          tree newreturntype = TREE_TYPE (newtype);
 
-         /* Make sure we put the new type in the same obstack as the old ones.
-            If the old types are not both in the same obstack, use the
-            permanent one.  */
-         if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype))
-           push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
-         else
-           {
-             push_obstacks_nochange ();
-             end_temporary_allocation ();
-           }
-
           if (TYPE_MODE (oldreturntype) == TYPE_MODE (newreturntype))
             {
              /* Function types may be shared, so we can't just modify
@@ -1592,8 +1503,6 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
            }
          if (! different_binding_level)
            TREE_TYPE (olddecl) = oldtype;
-
-         pop_obstacks ();
        }
       if (!types_match)
        {
@@ -1683,16 +1592,13 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
              if (TREE_CHAIN (t) == 0
                  && TYPE_MAIN_VARIANT (type) != void_type_node)
                {
-                 error ("A parameter list with an ellipsis can't match");
-                 error ("an empty parameter name list declaration.");
+                 error ("A parameter list with an ellipsis can't match an empty parameter name list declaration.");
                  break;
                }
 
-             if (TYPE_MAIN_VARIANT (type) == float_type_node
-                 || C_PROMOTING_INTEGER_TYPE_P (type))
+             if (simple_type_promotes_to (type) != NULL_TREE)
                {
-                 error ("An argument type that has a default promotion");
-                 error ("can't match an empty parameter name list declaration.");
+                 error ("An argument type that has a default promotion can't match an empty parameter name list declaration.");
                  break;
                }
            }
@@ -1704,7 +1610,21 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
       errmsg = redeclaration_error_message (newdecl, olddecl);
       if (errmsg)
        {
-         error_with_decl (newdecl, errmsg);
+         switch (errmsg)
+           {
+           case 1:
+             error_with_decl (newdecl, "redefinition of `%s'");
+             break;
+           case 2:
+             error_with_decl (newdecl, "redeclaration of `%s'");
+             break;
+           case 3:
+             error_with_decl (newdecl, "conflicting declarations of `%s'");
+             break;
+           default:
+             abort ();
+           }
+
          error_with_decl (olddecl,
                           ((DECL_INITIAL (olddecl)
                             && current_binding_level == global_binding_level)
@@ -1736,14 +1656,22 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
          for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype),
               type = TYPE_ARG_TYPES (newtype),
               nargs = 1;
-              (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) != void_type_node
-               || TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node);
+              ;
               parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++)
            {
              if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node
+                 && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
+               {
+                 warning_with_decl (newdecl, "prototype for `%s' follows");
+                 warning_with_decl (olddecl, "non-prototype definition here");
+                 break;
+               }
+             if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node
                  || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
                {
-                 errmsg = "prototype for `%s' follows and number of arguments";
+                 error_with_decl (newdecl, "prototype for `%s' follows and number of arguments doesn't match");
+                 error_with_decl (olddecl, "non-prototype definition here");
+                 errmsg = 1;
                  break;
                }
              /* Type for passing arg must be consistent
@@ -1755,21 +1683,14 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
                         && TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == integer_type_node
                         && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == unsigned_type_node)))
                {
-                 errmsg = "prototype for `%s' follows and argument %d";
+                 error_with_decl (newdecl,
+                                  "prototype for `%s' follows and argument %d doesn't match",
+                                  nargs);
+                 error_with_decl (olddecl, "non-prototype definition here");
+                 errmsg = 1;
                  break;
                }
            }
-         if (errmsg)
-           {
-             error_with_decl (newdecl, errmsg, nargs);
-             error_with_decl (olddecl,
-                              "doesn't match non-prototype definition here");
-           }
-         else
-           {
-             warning_with_decl (newdecl, "prototype for `%s' follows");
-             warning_with_decl (olddecl, "non-prototype definition here");
-           }
        }
       /* Warn about mismatches in various flags.  */
       else
@@ -1794,6 +1715,14 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
              && !TREE_PUBLIC (newdecl))
            warning_with_decl (newdecl, "static declaration for `%s' follows non-static");
 
+         /* If warn_traditional, warn when a non-static function
+            declaration follows a static one. */
+         if (warn_traditional
+             && TREE_CODE (olddecl) == FUNCTION_DECL
+             && !TREE_PUBLIC (olddecl)
+             && TREE_PUBLIC (newdecl))
+           warning_with_decl (newdecl, "non-static declaration for `%s' follows static");
+
          /* Warn when const declaration follows a non-const
             declaration, but not for functions.  */
          if (TREE_CODE (olddecl) != FUNCTION_DECL
@@ -1836,17 +1765,6 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
         different_binding_level is true.  */
       tree write_olddecl = different_binding_level ? newdecl : olddecl;
 
-      /* Make sure we put the new type in the same obstack as the old ones.
-        If the old types are not both in the same obstack, use the permanent
-        one.  */
-      if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype))
-       push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
-      else
-       {
-         push_obstacks_nochange ();
-         end_temporary_allocation ();
-       }
-                      
       /* Merge the data types specified in the two decls.  */
       if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
        {
@@ -1876,6 +1794,8 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
        {
          /* Since the type is OLDDECL's, make OLDDECL's size go with.  */
          DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
+         DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
+         DECL_MODE (newdecl) = DECL_MODE (olddecl);
          if (TREE_CODE (olddecl) != FUNCTION_DECL)
            if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
              DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
@@ -1885,11 +1805,14 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
       DECL_RTL (newdecl) = DECL_RTL (olddecl);
 
       /* Merge the type qualifiers.  */
-      if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl)
-         && !TREE_THIS_VOLATILE (newdecl))
+      if (TREE_CODE (olddecl) == FUNCTION_DECL
+         && DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl)
+         && ! TREE_THIS_VOLATILE (newdecl))
        TREE_THIS_VOLATILE (write_olddecl) = 0;
+
       if (TREE_READONLY (newdecl))
        TREE_READONLY (write_olddecl) = 1;
+
       if (TREE_THIS_VOLATILE (newdecl))
        {
          TREE_THIS_VOLATILE (write_olddecl) = 1;
@@ -1927,6 +1850,10 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
       if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
        DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
 
+      /* Copy the assembler name.
+        Currently, it can only be defined in the prototype.  */
+      DECL_ASSEMBLER_NAME (newdecl) = DECL_ASSEMBLER_NAME (olddecl);
+
       if (TREE_CODE (newdecl) == FUNCTION_DECL)
        {
          DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
@@ -1934,9 +1861,11 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
 
          DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
            |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+         DECL_NO_CHECK_MEMORY_USAGE (newdecl)
+           |= DECL_NO_CHECK_MEMORY_USAGE (olddecl);
+         DECL_NO_LIMIT_STACK (newdecl)
+           |= DECL_NO_LIMIT_STACK (olddecl);
        }
-
-      pop_obstacks ();
     }
   /* If cannot merge, then use the new type and qualifiers,
      and don't preserve the old rtl.  */
@@ -1978,14 +1907,15 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
       TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
     }
 
-  /* If either decl says `inline', this fn is inline,
-     unless its definition was passed already.  */
-  if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0)
-    DECL_INLINE (olddecl) = 1;
-  DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
-
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
+      /* If either decl says `inline', this fn is inline,
+        unless its definition was passed already.  */
+      if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0)
+       DECL_INLINE (olddecl) = 1;
+
+      DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
+
       if (DECL_BUILT_IN (olddecl))
        {
          /* Get rid of any built-in function if new arg types don't match it
@@ -1995,14 +1925,14 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
              if (! different_binding_level)
                {
                  TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
-                 DECL_BUILT_IN (olddecl) = 0;
+                 DECL_BUILT_IN_CLASS (olddecl) = NOT_BUILT_IN;
                }
            }
          else
            {
              /* If redeclaring a builtin function, and not a definition,
                 it stays built in.  */
-             DECL_BUILT_IN (newdecl) = 1;
+             DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
              DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
            }
        }
@@ -2219,7 +2149,8 @@ pushdecl (x)
 
         We get warnings about inline functions where they are defined.
         Avoid duplicate warnings where they are used.  */
-      if (TREE_PUBLIC (x) && ! DECL_INLINE (x))
+      if (TREE_PUBLIC (x)
+         && ! (TREE_CODE (x) == FUNCTION_DECL && DECL_INLINE (x)))
        {
          tree decl;
 
@@ -2269,7 +2200,7 @@ pushdecl (x)
            {
              if (type == error_mark_node)
                break;
-             if (! TREE_PERMANENT (type))
+             if (! TYPE_CONTEXT (type))
                {
                  warning_with_decl (x, "type of external `%s' is not global");
                  /* By exiting the loop early, we leave TYPE nonzero,
@@ -2356,15 +2287,16 @@ pushdecl (x)
          /* Here to install a non-global value.  */
          tree oldlocal = IDENTIFIER_LOCAL_VALUE (name);
          tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name);
+
          IDENTIFIER_LOCAL_VALUE (name) = x;
 
          /* If this is an extern function declaration, see if we
             have a global definition or declaration for the function.  */
          if (oldlocal == 0
-             && DECL_EXTERNAL (x) && !DECL_INLINE (x)
              && oldglobal != 0
              && TREE_CODE (x) == FUNCTION_DECL
-             && TREE_CODE (oldglobal) == FUNCTION_DECL)
+             && TREE_CODE (oldglobal) == FUNCTION_DECL
+             && DECL_EXTERNAL (x) && ! DECL_INLINE (x))
            {
              /* We have one.  Their types must agree.  */
              if (! comptypes (TREE_TYPE (x),
@@ -2389,7 +2321,7 @@ pushdecl (x)
                  /* Inner extern decl is built-in if global one is.  */
                  if (DECL_BUILT_IN (oldglobal))
                    {
-                     DECL_BUILT_IN (x) = DECL_BUILT_IN (oldglobal);
+                     DECL_BUILT_IN_CLASS (x) = DECL_BUILT_IN_CLASS (oldglobal);
                      DECL_FUNCTION_CODE (x) = DECL_FUNCTION_CODE (oldglobal);
                    }
                  /* Keep the arg types from a file-scope fcn defn.  */
@@ -2457,7 +2389,7 @@ pushdecl (x)
                   /* No shadow warnings for vars made for inlining.  */
                   && ! DECL_FROM_INLINE (x))
            {
-             char *warnstring = 0;
+             char *id = IDENTIFIER_POINTER (name);
 
              if (TREE_CODE (x) == PARM_DECL
                  && current_binding_level->level_chain->parm_flag)
@@ -2468,15 +2400,12 @@ pushdecl (x)
                   but there is no way to tell it's not a definition.  */
                ;
              else if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL)
-               warnstring = "declaration of `%s' shadows a parameter";
+               warning ("declaration of `%s' shadows a parameter", id);
              else if (oldlocal != 0)
-               warnstring = "declaration of `%s' shadows previous local";
+               warning ("declaration of `%s' shadows previous local", id);
              else if (IDENTIFIER_GLOBAL_VALUE (name) != 0
                       && IDENTIFIER_GLOBAL_VALUE (name) != error_mark_node)
-               warnstring = "declaration of `%s' shadows global declaration";
-
-             if (warnstring)
-               warning (warnstring, IDENTIFIER_POINTER (name));
+               warning ("declaration of `%s' shadows global declaration", id);
            }
 
          /* If storing a local value, there may already be one (inherited).
@@ -2486,7 +2415,7 @@ pushdecl (x)
        }
 
       /* Keep count of variables in this level with incomplete type.  */
-      if (TYPE_SIZE (TREE_TYPE (x)) == 0)
+      if (!COMPLETE_TYPE_P (TREE_TYPE (x)))
        ++b->n_incomplete;
     }
 
@@ -2525,10 +2454,6 @@ implicitly_declare (functionid)
   /* Only one "implicit declaration" warning per identifier.  */
   int implicit_warning;
 
-  /* Save the decl permanently so we can warn if definition follows.  */
-  push_obstacks_nochange ();
-  end_temporary_allocation ();
-
   /* We used to reuse an old implicit decl here,
      but this loses with inline functions because it can clobber
      the saved decl chains.  */
@@ -2579,18 +2504,16 @@ implicitly_declare (functionid)
 
   gen_aux_info_record (decl, 0, 1, 0);
 
-  pop_obstacks ();
-
   return decl;
 }
 
 /* Return zero if the declaration NEWDECL is valid
    when the declaration OLDDECL (assumed to be for the same name)
    has already been seen.
-   Otherwise return an error message format string with a %s
-   where the identifier should go.  */
+   Otherwise return 1 if NEWDECL is a redefinition, 2 if it is a redeclaration,
+   and 3 if it is a conflicting declaration.  */
 
-static char *
+static int
 redeclaration_error_message (newdecl, olddecl)
      tree newdecl, olddecl;
 {
@@ -2609,7 +2532,7 @@ redeclaration_error_message (newdecl, olddecl)
        return 0;
       if (DECL_IN_SYSTEM_HEADER (olddecl) || DECL_IN_SYSTEM_HEADER (newdecl))
        return 0;
-      return "redefinition of `%s'";
+      return 1;
     }
   else if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
@@ -2620,9 +2543,9 @@ redeclaration_error_message (newdecl, olddecl)
       if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0
          /* However, defining once as extern inline and a second
             time in another way is ok.  */
-         && !(DECL_INLINE (olddecl) && DECL_EXTERNAL (olddecl)
-              && !(DECL_INLINE (newdecl) && DECL_EXTERNAL (newdecl))))
-       return "redefinition of `%s'";
+         && ! (DECL_INLINE (olddecl) && DECL_EXTERNAL (olddecl)
+              && ! (DECL_INLINE (newdecl) && DECL_EXTERNAL (newdecl))))
+       return 1;
       return 0;
     }
   else if (current_binding_level == global_binding_level)
@@ -2633,11 +2556,11 @@ redeclaration_error_message (newdecl, olddecl)
        return 0;
       /* Reject two definitions.  */
       if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0)
-       return "redefinition of `%s'";
+       return 1;
       /* Now we have two tentative defs, or one tentative and one real def.  */
       /* Insist that the linkage match.  */
       if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl))
-       return "conflicting declarations of `%s'";
+       return 3;
       return 0;
     }
   else if (current_binding_level->parm_flag
@@ -2651,7 +2574,7 @@ redeclaration_error_message (newdecl, olddecl)
         be an extern reference to olddecl.  */
       if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl))
          && DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl))
-       return "redeclaration of `%s'";
+       return 2;
       return 0;
     }
 }
@@ -2936,6 +2859,25 @@ lookup_name_current_level (name)
   return t;
 }
 \f
+/* Mark ARG for GC.  */
+static void 
+mark_binding_level (arg)
+     void *arg;
+{
+  struct binding_level *level = *(struct binding_level **) arg;
+
+  while (level)
+    {
+      ggc_mark_tree (level->names);
+      ggc_mark_tree (level->tags);
+      ggc_mark_tree (level->shadowed);
+      ggc_mark_tree (level->blocks);
+      ggc_mark_tree (level->this_block);
+      ggc_mark_tree (level->parm_order);
+      level = level->level_chain;
+    }
+}
+
 /* Create the predefined scalar types of C,
    and some nodes representing standard constants (0, 1, (void *) 0).
    Initialize the global binding level.
@@ -2945,14 +2887,10 @@ void
 init_decl_processing ()
 {
   register tree endlink;
-  /* Either char* or void*.  */
-  tree traditional_ptr_type_node;
-  /* Data types of memcpy and strlen.  */
-  tree memcpy_ftype, memset_ftype, strlen_ftype;
-  tree void_ftype_any, ptr_ftype_void, ptr_ftype_ptr;
+  tree ptr_ftype_void, ptr_ftype_ptr;
   int wchar_type_size;
-  tree temp;
   tree array_domain_type;
+  tree t;
 
   current_function_decl = NULL;
   named_labels = NULL;
@@ -2961,181 +2899,101 @@ init_decl_processing ()
   pushlevel (0);       /* make the binding_level structure for global names */
   global_binding_level = current_binding_level;
 
-  /* Define `int' and `char' first so that dbx will output them first.  */
+  build_common_tree_nodes (flag_signed_char);
 
-  integer_type_node = make_signed_type (INT_TYPE_SIZE);
+  /* Define `int' and `char' first so that dbx will output them first.  */
   pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_INT],
                        integer_type_node));
-
-  /* Define `char', which is like either `signed char' or `unsigned char'
-     but not the same as either.  */
-
-  char_type_node
-    = (flag_signed_char
-       ? make_signed_type (CHAR_TYPE_SIZE)
-       : make_unsigned_type (CHAR_TYPE_SIZE));
   pushdecl (build_decl (TYPE_DECL, get_identifier ("char"),
                        char_type_node));
-
-  long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("long int"),
                        long_integer_type_node));
-
-  unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"),
                        unsigned_type_node));
-
-  long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("long unsigned int"),
                        long_unsigned_type_node));
-
-  long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("long long int"),
                        long_long_integer_type_node));
-
-  long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"),
                        long_long_unsigned_type_node));
-
-  short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"),
                        short_integer_type_node));
-
-  short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"),
                        short_unsigned_type_node));
-
-  /* `unsigned long' is the standard type for sizeof.
-     Traditionally, use a signed type.
-     Note that stddef.h uses `unsigned long',
-     and this must agree, even if long and int are the same size.  */
-  set_sizetype
-    (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))));
-  if (flag_traditional && TREE_UNSIGNED (sizetype))
-    set_sizetype (signed_type (sizetype));
-
-  ptrdiff_type_node
-    = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
-
-  error_mark_node = make_node (ERROR_MARK);
-  TREE_TYPE (error_mark_node) = error_mark_node;
-
-  /* Define both `signed char' and `unsigned char'.  */
-  signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"),
                        signed_char_type_node));
-
-  unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned char"),
                        unsigned_char_type_node));
-
-  intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node));
-
-  intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node));
-
-  intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
-
-  intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
-
-  intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+#if HOST_BITS_PER_WIDE_INT >= 64
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intTI_type_node));
-
-  unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
+#endif
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
-
-  unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node));
-
-  unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
-
-  unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
-
-  unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+#if HOST_BITS_PER_WIDE_INT >= 64
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node));
+#endif
+
+  /* `unsigned long' is the standard type for sizeof.
+     Traditionally, use a signed type.
+     Note that stddef.h uses `unsigned long',
+     and this must agree, even if long and int are the same size.  */
+  t = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)));
+  if (flag_traditional && TREE_UNSIGNED (t))
+    t = signed_type (t);
+    
+  set_sizetype (t);
+
+  /* Create the widest literal types. */
+  widest_integer_literal_type_node
+    = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
+  widest_unsigned_literal_type_node
+    = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, 
+                       widest_integer_literal_type_node));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, 
+                       widest_unsigned_literal_type_node));
+
+  build_common_tree_nodes_2 (flag_short_double);
 
-  float_type_node = make_node (REAL_TYPE);
-  TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
   pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT],
                        float_type_node));
-  layout_type (float_type_node);
-
-  double_type_node = make_node (REAL_TYPE);
-  if (flag_short_double)
-    TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
-  else
-    TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
   pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_DOUBLE],
                        double_type_node));
-  layout_type (double_type_node);
-
-  long_double_type_node = make_node (REAL_TYPE);
-  TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
   pushdecl (build_decl (TYPE_DECL, get_identifier ("long double"),
                        long_double_type_node));
-  layout_type (long_double_type_node);
-
-  complex_integer_type_node = make_node (COMPLEX_TYPE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
                        complex_integer_type_node));
-  TREE_TYPE (complex_integer_type_node) = integer_type_node;
-  layout_type (complex_integer_type_node);
-
-  complex_float_type_node = make_node (COMPLEX_TYPE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
                        complex_float_type_node));
-  TREE_TYPE (complex_float_type_node) = float_type_node;
-  layout_type (complex_float_type_node);
-
-  complex_double_type_node = make_node (COMPLEX_TYPE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
                        complex_double_type_node));
-  TREE_TYPE (complex_double_type_node) = double_type_node;
-  layout_type (complex_double_type_node);
-
-  complex_long_double_type_node = make_node (COMPLEX_TYPE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
                        complex_long_double_type_node));
-  TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
-  layout_type (complex_long_double_type_node);
+  pushdecl (build_decl (TYPE_DECL,
+                       ridpointers[(int) RID_VOID], void_type_node));
 
-  wchar_type_node
-    = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE)));
+#ifdef MD_INIT_BUILTINS
+  MD_INIT_BUILTINS;
+#endif
+
+  wchar_type_node = get_identifier (flag_short_wchar
+                                   ? "short unsigned int"
+                                   : WCHAR_TYPE);
+  wchar_type_node = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (wchar_type_node));
   wchar_type_size = TYPE_PRECISION (wchar_type_node);
   signed_wchar_type_node = signed_type (wchar_type_node);
   unsigned_wchar_type_node = unsigned_type (wchar_type_node);
 
-  integer_zero_node = build_int_2 (0, 0);
-  TREE_TYPE (integer_zero_node) = integer_type_node;
-  integer_one_node = build_int_2 (1, 0);
-  TREE_TYPE (integer_one_node) = integer_type_node;
-
   boolean_type_node = integer_type_node;
   boolean_true_node = integer_one_node;
   boolean_false_node = integer_zero_node;
 
-  size_zero_node = build_int_2 (0, 0);
-  TREE_TYPE (size_zero_node) = sizetype;
-  size_one_node = build_int_2 (1, 0);
-  TREE_TYPE (size_one_node) = sizetype;
-
-  void_type_node = make_node (VOID_TYPE);
-  pushdecl (build_decl (TYPE_DECL,
-                       ridpointers[(int) RID_VOID], void_type_node));
-  layout_type (void_type_node);        /* Uses integer_zero_node */
-  /* We are not going to have real types in C with less than byte alignment,
-     so we might as well not have any types that claim to have it.  */
-  TYPE_ALIGN (void_type_node) = BITS_PER_UNIT;
-
-  null_pointer_node = build_int_2 (0, 0);
-  TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
-  layout_type (TREE_TYPE (null_pointer_node));
-
   string_type_node = build_pointer_type (char_type_node);
   const_string_type_node
     = build_pointer_type (build_type_variant (char_type_node, 1, 0));
@@ -3159,369 +3017,56 @@ init_decl_processing ()
   wchar_array_type_node
     = build_array_type (wchar_type_node, array_domain_type);
 
+  void_list_node = tree_cons (NULL_TREE, void_type_node, NULL_TREE);
+
   default_function_type
     = build_function_type (integer_type_node, NULL_TREE);
+  ptrdiff_type_node
+    = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
 
-  ptr_type_node = build_pointer_type (void_type_node);
-  const_ptr_type_node
-    = build_pointer_type (build_type_variant (void_type_node, 1, 0));
-
-  endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE);
-
-  void_ftype_any
-    = build_function_type (void_type_node, NULL_TREE);
-
-  float_ftype_float
-    = build_function_type (float_type_node,
-                          tree_cons (NULL_TREE, float_type_node, endlink));
-
-  double_ftype_double
-    = build_function_type (double_type_node,
-                          tree_cons (NULL_TREE, double_type_node, endlink));
-
-  ldouble_ftype_ldouble
-    = build_function_type (long_double_type_node,
-                          tree_cons (NULL_TREE, long_double_type_node,
-                                     endlink));
-
-  double_ftype_double_double
-    = build_function_type (double_type_node,
-                          tree_cons (NULL_TREE, double_type_node,
-                                     tree_cons (NULL_TREE,
-                                                double_type_node, endlink)));
-
-  int_ftype_int
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, integer_type_node, endlink));
-
-  long_ftype_long
-    = build_function_type (long_integer_type_node,
-                          tree_cons (NULL_TREE,
-                                     long_integer_type_node, endlink));
-
-  void_ftype_ptr_ptr_int
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node,
-                                     tree_cons (NULL_TREE, ptr_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           integer_type_node,
-                                                           endlink))));
-
-  int_ftype_cptr_cptr_sizet
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_ptr_type_node,
-                                     tree_cons (NULL_TREE, const_ptr_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           sizetype,
-                                                           endlink))));
-
-  void_ftype_ptr_int_int
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           integer_type_node,
-                                                           endlink))));
-
-  string_ftype_ptr_ptr         /* strcpy prototype */
-    = build_function_type (string_type_node,
-                          tree_cons (NULL_TREE, string_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                endlink)));
-
-  int_ftype_string_string      /* strcmp prototype */
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                endlink)));
-
-  strlen_ftype         /* strlen prototype */
-    = build_function_type (flag_traditional ? integer_type_node : sizetype,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     endlink));
-
-  traditional_ptr_type_node
-    = (flag_traditional ? string_type_node : ptr_type_node);
-
-  memcpy_ftype /* memcpy prototype */
-    = build_function_type (traditional_ptr_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node,
-                                     tree_cons (NULL_TREE, const_ptr_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           sizetype,
-                                                           endlink))));
-
-  memset_ftype /* memset prototype */
-    = build_function_type (traditional_ptr_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           sizetype,
-                                                           endlink))));
+  c_common_nodes_and_builtins (0, flag_no_builtin, flag_no_nonansi_builtin);
 
+  endlink = void_list_node;
   ptr_ftype_void = build_function_type (ptr_type_node, endlink);
   ptr_ftype_ptr
     = build_function_type (ptr_type_node,
                           tree_cons (NULL_TREE, ptr_type_node, endlink));
 
-  builtin_function ("__builtin_constant_p", default_function_type,
-                   BUILT_IN_CONSTANT_P, NULL_PTR);
-
-  builtin_function ("__builtin_return_address",
-                   build_function_type (ptr_type_node, 
-                                        tree_cons (NULL_TREE,
-                                                   unsigned_type_node,
-                                                   endlink)),
-                   BUILT_IN_RETURN_ADDRESS, NULL_PTR);
-
-  builtin_function ("__builtin_frame_address",
-                   build_function_type (ptr_type_node, 
-                                        tree_cons (NULL_TREE,
-                                                   unsigned_type_node,
-                                                   endlink)),
-                   BUILT_IN_FRAME_ADDRESS, NULL_PTR);
-
   builtin_function ("__builtin_aggregate_incoming_address",
                    build_function_type (ptr_type_node, NULL_TREE),
-                   BUILT_IN_AGGREGATE_INCOMING_ADDRESS, NULL_PTR);
+                   BUILT_IN_AGGREGATE_INCOMING_ADDRESS,
+                   BUILT_IN_NORMAL, NULL_PTR);
 
   /* Hooks for the DWARF 2 __throw routine.  */
   builtin_function ("__builtin_unwind_init",
                    build_function_type (void_type_node, endlink),
-                   BUILT_IN_UNWIND_INIT, NULL_PTR);
-  builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
-  builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
+                   BUILT_IN_UNWIND_INIT, BUILT_IN_NORMAL, NULL_PTR);
+  builtin_function ("__builtin_dwarf_cfa", ptr_ftype_void,
+                   BUILT_IN_DWARF_CFA, BUILT_IN_NORMAL, NULL_PTR);
   builtin_function ("__builtin_dwarf_fp_regnum",
                    build_function_type (unsigned_type_node, endlink),
-                   BUILT_IN_DWARF_FP_REGNUM, NULL_PTR);
-  builtin_function ("__builtin_dwarf_reg_size", int_ftype_int,
-                   BUILT_IN_DWARF_REG_SIZE, NULL_PTR);             
+                   BUILT_IN_DWARF_FP_REGNUM, BUILT_IN_NORMAL, NULL_PTR);
+  builtin_function ("__builtin_init_dwarf_reg_size_table", void_ftype_ptr,
+                   BUILT_IN_INIT_DWARF_REG_SIZES, BUILT_IN_NORMAL, NULL_PTR);
   builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr,
-                   BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
+                   BUILT_IN_FROB_RETURN_ADDR, BUILT_IN_NORMAL, NULL_PTR);
   builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
-                   BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
-  builtin_function ("__builtin_set_return_addr_reg",
-                   build_function_type (void_type_node, 
-                                        tree_cons (NULL_TREE,
-                                                   ptr_type_node,
-                                                   endlink)),
-                   BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR);
-  builtin_function ("__builtin_eh_stub_old", ptr_ftype_void,
-                   BUILT_IN_EH_STUB_OLD, NULL_PTR);
-  builtin_function ("__builtin_eh_stub", ptr_ftype_void,
-                   BUILT_IN_EH_STUB, NULL_PTR);
+                   BUILT_IN_EXTRACT_RETURN_ADDR, BUILT_IN_NORMAL, NULL_PTR);
   builtin_function
-    ("__builtin_set_eh_regs",
+    ("__builtin_eh_return",
      build_function_type (void_type_node,
                          tree_cons (NULL_TREE, ptr_type_node,
                                     tree_cons (NULL_TREE,
                                                type_for_mode (ptr_mode, 0),
-                                               endlink))),
-     BUILT_IN_SET_EH_REGS, NULL_PTR);
-
-  builtin_function ("__builtin_alloca",
-                   build_function_type (ptr_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   sizetype,
-                                                   endlink)),
-                   BUILT_IN_ALLOCA, "alloca");
-  builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
-  /* Define alloca, ffs as builtins.
-     Declare _exit just to mark it as volatile.  */
-  if (! flag_no_builtin && !flag_no_nonansi_builtin)
-    {
-      temp = builtin_function ("alloca",
-                              build_function_type (ptr_type_node,
-                                                   tree_cons (NULL_TREE,
-                                                              sizetype,
-                                                              endlink)),
-                              BUILT_IN_ALLOCA, NULL_PTR);
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-      temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-      temp = builtin_function ("_exit", void_ftype_any, NOT_BUILT_IN,
-                              NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-    }
-
-  builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR);
-  builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS,
-                   NULL_PTR);
-  builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS,
-                   NULL_PTR);
-  builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
-                   NULL_PTR);
-  builtin_function ("__builtin_labs", long_ftype_long, BUILT_IN_LABS,
-                   NULL_PTR);
-  builtin_function ("__builtin_saveregs",
-                   build_function_type (ptr_type_node, NULL_TREE),
-                   BUILT_IN_SAVEREGS, NULL_PTR);
-/* EXPAND_BUILTIN_VARARGS is obsolete.  */
-#if 0
-  builtin_function ("__builtin_varargs",
-                   build_function_type (ptr_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   integer_type_node,
-                                                   endlink)),
-                   BUILT_IN_VARARGS, NULL_PTR);
-#endif
-  builtin_function ("__builtin_classify_type", default_function_type,
-                   BUILT_IN_CLASSIFY_TYPE, NULL_PTR);
-  builtin_function ("__builtin_next_arg",
-                   build_function_type (ptr_type_node, NULL_TREE),
-                   BUILT_IN_NEXT_ARG, NULL_PTR);
-  builtin_function ("__builtin_args_info",
-                   build_function_type (integer_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   integer_type_node,
-                                                   endlink)),
-                   BUILT_IN_ARGS_INFO, NULL_PTR);
-
-  /* Untyped call and return.  */
-  builtin_function ("__builtin_apply_args",
-                   build_function_type (ptr_type_node, NULL_TREE),
-                   BUILT_IN_APPLY_ARGS, NULL_PTR);
-
-  temp = tree_cons (NULL_TREE,
-                   build_pointer_type (build_function_type (void_type_node,
-                                                            NULL_TREE)),
-                   tree_cons (NULL_TREE,
-                              ptr_type_node,
-                              tree_cons (NULL_TREE,
-                                         sizetype,
-                                         endlink)));
-  builtin_function ("__builtin_apply",
-                   build_function_type (ptr_type_node, temp),
-                   BUILT_IN_APPLY, NULL_PTR);
-  builtin_function ("__builtin_return",
-                   build_function_type (void_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   ptr_type_node,
-                                                   endlink)),
-                   BUILT_IN_RETURN, NULL_PTR);
-
-  /* Currently under experimentation.  */
-  builtin_function ("__builtin_memcpy", memcpy_ftype,
-                   BUILT_IN_MEMCPY, "memcpy");
-  builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet,
-                   BUILT_IN_MEMCMP, "memcmp");
-  builtin_function ("__builtin_memset", memset_ftype,
-                   BUILT_IN_MEMSET, "memset");
-  builtin_function ("__builtin_strcmp", int_ftype_string_string,
-                   BUILT_IN_STRCMP, "strcmp");
-  builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
-                   BUILT_IN_STRCPY, "strcpy");
-  builtin_function ("__builtin_strlen", strlen_ftype,
-                   BUILT_IN_STRLEN, "strlen");
-  builtin_function ("__builtin_sqrtf", float_ftype_float, 
-                   BUILT_IN_FSQRT, "sqrtf");
-  builtin_function ("__builtin_fsqrt", double_ftype_double, 
-                   BUILT_IN_FSQRT, "sqrt");
-  builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble, 
-                   BUILT_IN_FSQRT, "sqrtl");
-  builtin_function ("__builtin_sinf", float_ftype_float, 
-                   BUILT_IN_SIN, "sinf");
-  builtin_function ("__builtin_sin", double_ftype_double, 
-                   BUILT_IN_SIN, "sin");
-  builtin_function ("__builtin_sinl", ldouble_ftype_ldouble, 
-                   BUILT_IN_SIN, "sinl");
-  builtin_function ("__builtin_cosf", float_ftype_float, 
-                   BUILT_IN_COS, "cosf");
-  builtin_function ("__builtin_cos", double_ftype_double, 
-                   BUILT_IN_COS, "cos");
-  builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, 
-                   BUILT_IN_COS, "cosl");
-  builtin_function ("__builtin_setjmp",
-                   build_function_type (integer_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   ptr_type_node, endlink)),
-                   BUILT_IN_SETJMP, NULL_PTR);
-  builtin_function ("__builtin_longjmp",
-                   build_function_type
-                   (void_type_node,
-                    tree_cons (NULL, ptr_type_node,
-                               tree_cons (NULL_TREE,
-                                          integer_type_node,
-                                          endlink))),
-                   BUILT_IN_LONGJMP, NULL_PTR);
-  builtin_function ("__builtin_trap",
-                   build_function_type (void_type_node, endlink),
-                   BUILT_IN_TRAP, NULL_PTR);
-
-  /* In an ANSI C program, it is okay to supply built-in meanings
-     for these functions, since applications cannot validly use them
-     with any other meaning.
-     However, honor the -fno-builtin option.  */
-  if (!flag_no_builtin)
-    {
-      builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR);
-      builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS, NULL_PTR);
-      builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, NULL_PTR);
-      builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
-                       NULL_PTR);
-      builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, NULL_PTR);
-      builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR);
-      builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP,
-                       NULL_PTR);
-      builtin_function ("memset", memset_ftype, BUILT_IN_MEMSET, NULL_PTR);
-      builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
-                       NULL_PTR);
-      builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
-                       NULL_PTR);
-      builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN, NULL_PTR);
-      builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT, NULL_PTR);
-      builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT, NULL_PTR);
-      builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT,
-                       NULL_PTR);
-      builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN, NULL_PTR);
-      builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR);
-      builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN, NULL_PTR);
-      builtin_function ("cosf", float_ftype_float, BUILT_IN_COS, NULL_PTR);
-      builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR);
-      builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, NULL_PTR);
-
-      /* Declare these functions volatile
-        to avoid spurious "control drops through" warnings.  */
-      /* Don't specify the argument types, to avoid errors
-        from certain code which isn't valid in ANSI but which exists.  */
-      temp = builtin_function ("abort", void_ftype_any, NOT_BUILT_IN,
-                              NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-      temp = builtin_function ("exit", void_ftype_any, NOT_BUILT_IN, NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-    }
-
-#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, NULL_PTR);
-  builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR);
-  builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR,
-                   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, NULL_PTR);
-  builtin_function ("__builtin_frem", double_ftype_double_double,
-                   BUILT_IN_FREM, NULL_PTR);
-  builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
-                   NULL_PTR);
-  builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
-                   NULL_PTR);
-#endif
+                                               tree_cons (NULL_TREE,
+                                                          ptr_type_node,
+                                                          endlink)))),
+     BUILT_IN_EH_RETURN, BUILT_IN_NORMAL, NULL_PTR);
 
   pedantic_lvalues = pedantic;
 
   /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__.  */
+  make_fname_decl = c_make_fname_decl;
   declare_function_name ();
 
   start_identifier_warnings ();
@@ -3534,6 +3079,55 @@ init_decl_processing ()
   incomplete_decl_finalize_hook = finish_incomplete_decl;
 
   lang_get_alias_set = c_get_alias_set;
+
+  /* Record our roots.  */
+
+  ggc_add_tree_root (c_global_trees, CTI_MAX);
+  ggc_add_tree_root (&named_labels, 1);
+  ggc_add_tree_root (&shadowed_labels, 1);
+  ggc_add_root (&current_binding_level, 1, sizeof current_binding_level,
+               mark_binding_level);
+  ggc_add_root (&label_level_chain, 1, sizeof label_level_chain,
+               mark_binding_level);
+  ggc_add_tree_root (&static_ctors, 1);
+  ggc_add_tree_root (&static_dtors, 1);
+}
+
+/* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
+   decl, NAME is the initialization string and TYPE_DEP indicates whether
+   NAME depended on the type of the function.  As we don't yet implement
+   delayed emission of static data, we mark the decl as emitted
+   so it is not placed in the output.  Anything using it must therefore pull
+   out the STRING_CST initializer directly.  This does mean that these names
+   are string merging candidates, which C99 does not permit.  */
+
+static tree
+c_make_fname_decl (id, name, type_dep)
+     tree id;
+     const char *name;
+     int type_dep ATTRIBUTE_UNUSED;
+{
+  tree decl, type, init;
+  size_t length = strlen (name);
+
+  type =  build_array_type
+          (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
+          build_index_type (build_int_2 (length, 0)));
+
+  decl = build_decl (VAR_DECL, id, type);
+  TREE_STATIC (decl) = 1;
+  TREE_READONLY (decl) = 1;
+  TREE_ASM_WRITTEN (decl) = 1;
+  DECL_SOURCE_LINE (decl) = 0;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IN_SYSTEM_HEADER (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  init = build_string (length + 1, name);
+  TREE_TYPE (init) = type;
+  DECL_INITIAL (decl) = init;
+  finish_decl (pushdecl (decl), init, NULL_TREE);
+  
+  return decl;
 }
 
 /* Return a definition for a builtin function named NAME and whose data type
@@ -3545,11 +3139,12 @@ init_decl_processing ()
    the name to be called if we can't opencode the function.  */
 
 tree
-builtin_function (name, type, function_code, library_name)
-     char *name;
+builtin_function (name, type, function_code, class, library_name)
+     const char *name;
      tree type;
-     enum built_in_function function_code;
-     char *library_name;
+     int function_code;
+     enum built_in_class class;
+     const char *library_name;
 {
   tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type);
   DECL_EXTERNAL (decl) = 1;
@@ -3563,11 +3158,9 @@ builtin_function (name, type, function_code, library_name)
     DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name);
   make_decl_rtl (decl, NULL_PTR, 1);
   pushdecl (decl);
-  if (function_code != NOT_BUILT_IN)
-    {
-      DECL_BUILT_IN (decl) = 1;
-      DECL_FUNCTION_CODE (decl) = function_code;
-    }
+  DECL_BUILT_IN_CLASS (decl) = class;
+  DECL_FUNCTION_CODE (decl) = function_code;
+
   /* Warn if a function in the namespace for users
      is used without an occasion to consider it declared.  */
   if (name[0] != '_' || name[1] != '_')
@@ -3703,10 +3296,6 @@ groktypename_in_parm_context (typename)
    do go through here.  Structure field declarations are done by
    grokfield and not through here.  */
 
-/* Set this to zero to debug not using the temporary obstack
-   to parse initializers.  */
-int debug_temp_inits = 1;
-
 tree
 start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
      tree declarator, declspecs;
@@ -3716,12 +3305,8 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
   register tree decl = grokdeclarator (declarator, declspecs,
                                       NORMAL, initialized);
   register tree tem;
-  int init_written = initialized;
 
-  /* The corresponding pop_obstacks is in finish_decl.  */
-  push_obstacks_nochange ();
-
-  if (warn_main && TREE_CODE (decl) != FUNCTION_DECL 
+  if (warn_main > 0 && TREE_CODE (decl) != FUNCTION_DECL 
       && !strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)), "main"))
     warning_with_decl (decl, "`%s' is usually a function");
 
@@ -3759,7 +3344,7 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
       default:
        /* Don't allow initializations for incomplete types
           except for arrays which might be completed by the initialization.  */
-       if (TYPE_SIZE (TREE_TYPE (decl)) != 0)
+       if (COMPLETE_TYPE_P (TREE_TYPE (decl)))
          {
            /* A complete type is ok if size is fixed.  */
 
@@ -3776,7 +3361,7 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
                   IDENTIFIER_POINTER (DECL_NAME (decl)));
            initialized = 0;
          }
-       else if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl))) == 0)
+       else if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
          {
            error ("elements of array `%s' have incomplete type",
                   IDENTIFIER_POINTER (DECL_NAME (decl)));
@@ -3835,21 +3420,13 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
         (which may or may not happen).  */
       && DECL_RTL (tem) == 0)
     {
-      if (TYPE_SIZE (TREE_TYPE (tem)) != 0)
+      if (COMPLETE_TYPE_P (TREE_TYPE (tem)))
        expand_decl (tem);
       else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
               && DECL_INITIAL (tem) != 0)
        expand_decl (tem);
     }
 
-  if (init_written)
-    {
-      /* When parsing and digesting the initializer,
-        use temporary storage.  Do this even if we will ignore the value.  */
-      if (current_binding_level == global_binding_level && debug_temp_inits)
-       temporary_allocation ();
-    }
-
   return tem;
 }
 
@@ -3865,7 +3442,6 @@ finish_decl (decl, init, asmspec_tree)
 {
   register tree type = TREE_TYPE (decl);
   int was_incomplete = (DECL_SIZE (decl) == 0);
-  int temporary = allocation_temporary_p ();
   char *asmspec = 0;
 
   /* If a name was specified, get the string.   */
@@ -3900,16 +3476,6 @@ finish_decl (decl, init, asmspec_tree)
        }
     }
 
-  /* Pop back to the obstack that is current for this binding level.
-     This is because MAXINDEX, rtl, etc. to be made below
-     must go in the permanent obstack.  But don't discard the
-     temporary data yet.  */
-  pop_obstacks ();
-#if 0 /* pop_obstacks was near the end; this is what was here.  */
-  if (current_binding_level == global_binding_level && temporary)
-    end_temporary_allocation ();
-#endif
-
   /* Deduce size of array from initialization, if not already known */
 
   if (TREE_CODE (type) == ARRAY_TYPE
@@ -3957,8 +3523,7 @@ finish_decl (decl, init, asmspec_tree)
 
   if (TREE_CODE (decl) == VAR_DECL)
     {
-      if (DECL_SIZE (decl) == 0
-         && TYPE_SIZE (TREE_TYPE (decl)) != 0)
+      if (DECL_SIZE (decl) == 0 && COMPLETE_TYPE_P (TREE_TYPE (decl)))
        layout_decl (decl, 0);
 
       if (DECL_SIZE (decl) == 0
@@ -4001,8 +3566,9 @@ finish_decl (decl, init, asmspec_tree)
      name.  */
   if (TREE_CODE (decl) == FUNCTION_DECL && asmspec)
       {
-       DECL_BUILT_IN (decl) = 0;
+       DECL_BUILT_IN_CLASS (decl) = NOT_BUILT_IN;
        DECL_RTL (decl) = 0;
+       DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
       }
 
   /* Output the assembler code and/or RTL code for variables and functions,
@@ -4011,26 +3577,12 @@ finish_decl (decl, init, asmspec_tree)
 
   if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
     {
-      if ((flag_traditional || TREE_PERMANENT (decl))
-         && allocation_temporary_p ())
-       {
-         push_obstacks_nochange ();
-         end_temporary_allocation ();
-         /* This is a no-op in c-lang.c or something real in objc-actions.c.  */
-         maybe_objc_check_decl (decl);
-         rest_of_decl_compilation (decl, asmspec,
-                                   (DECL_CONTEXT (decl) == 0
-                                    || TREE_ASM_WRITTEN (decl)),
-                                   0);
-         pop_obstacks ();
-       }
-      else
-       {
-         /* This is a no-op in c-lang.c or something real in objc-actions.c.  */
-         maybe_objc_check_decl (decl);
-         rest_of_decl_compilation (decl, asmspec, DECL_CONTEXT (decl) == 0,
-                                   0);
-       }
+      /* This is a no-op in c-lang.c or something real in objc-actions.c.  */
+      maybe_objc_check_decl (decl);
+      rest_of_decl_compilation (decl, asmspec,
+                               (DECL_CONTEXT (decl) == 0
+                                || TREE_ASM_WRITTEN (decl)), 0);
+
       if (DECL_CONTEXT (decl) != 0)
        {
          /* Recompute the RTL of a local array now
@@ -4055,82 +3607,9 @@ finish_decl (decl, init, asmspec_tree)
     {
       /* This is a no-op in c-lang.c or something real in objc-actions.c.  */
       maybe_objc_check_decl (decl);
-      rest_of_decl_compilation (decl, NULL_PTR, DECL_CONTEXT (decl) == 0,
-                               0);
-    }
-
-  /* ??? After 2.3, test (init != 0) instead of TREE_CODE.  */
-  /* This test used to include TREE_PERMANENT, however, we have the same
-     problem with initializers at the function level.  Such initializers get
-     saved until the end of the function on the momentary_obstack.  */
-  if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
-      && temporary
-      /* DECL_INITIAL is not defined in PARM_DECLs, since it shares
-        space with DECL_ARG_TYPE.  */
-      && TREE_CODE (decl) != PARM_DECL)
-    {
-      /* We need to remember that this array HAD an initialization,
-        but discard the actual temporary nodes,
-        since we can't have a permanent node keep pointing to them.  */
-      /* We make an exception for inline functions, since it's
-        normal for a local extern redeclaration of an inline function
-        to have a copy of the top-level decl's DECL_INLINE.  */
-      if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
-       {
-         /* If this is a const variable, then preserve the
-            initializer instead of discarding it so that we can optimize
-            references to it.  */
-         /* This test used to include TREE_STATIC, but this won't be set
-            for function level initializers.  */
-         if (TREE_READONLY (decl) || ITERATOR_P (decl))
-           {
-             preserve_initializer ();
-             /* Hack?  Set the permanent bit for something that is permanent,
-                but not on the permanent obstack, so as to convince
-                output_constant_def to make its rtl on the permanent
-                obstack.  */
-             TREE_PERMANENT (DECL_INITIAL (decl)) = 1;
-
-             /* The initializer and DECL must have the same (or equivalent
-                types), but if the initializer is a STRING_CST, its type
-                might not be on the right obstack, so copy the type
-                of DECL.  */
-             TREE_TYPE (DECL_INITIAL (decl)) = type;
-           }
-         else
-           DECL_INITIAL (decl) = error_mark_node;
-       }
-    }
-
-  /* If requested, warn about definitions of large data objects.  */
-
-  if (warn_larger_than
-      && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
-      && !DECL_EXTERNAL (decl))
-    {
-      register tree decl_size = DECL_SIZE (decl);
-
-      if (decl_size && TREE_CODE (decl_size) == INTEGER_CST)
-       {
-          unsigned units = TREE_INT_CST_LOW(decl_size) / BITS_PER_UNIT;
-
-         if (units > larger_than_size)
-           warning_with_decl (decl, "size of `%s' is %u bytes", units);
-       }
+      rest_of_decl_compilation (decl, NULL_PTR, DECL_CONTEXT (decl) == 0, 0);
     }
 
-#if 0
-  /* Resume permanent allocation, if not within a function.  */
-  /* The corresponding push_obstacks_nochange is in start_decl,
-     and in push_parm_decl and in grokfield.  */
-  pop_obstacks ();
-#endif
-
-  /* If we have gone back from temporary to permanent allocation,
-     actually free the temporary space that we no longer need.  */
-  if (temporary && !allocation_temporary_p ())
-    permanent_allocation (0);
-
   /* At the end of a declaration, throw away any variable type sizes
      of types defined inside that declaration.  There is no use
      computing them in the following function definition.  */
@@ -4163,9 +3642,6 @@ push_parm_decl (parm)
   /* Don't try computing parm sizes now -- wait till fn is called.  */
   immediate_size_expand = 0;
 
-  /* The corresponding pop_obstacks is in finish_decl.  */
-  push_obstacks_nochange ();
-
   decl = grokdeclarator (TREE_VALUE (TREE_PURPOSE (parm)),
                         TREE_PURPOSE (TREE_PURPOSE (parm)), PARM, 0);
   decl_attributes (decl, TREE_VALUE (TREE_VALUE (parm)),
@@ -4229,13 +3705,14 @@ complete_array_type (type, initial_value, do_default)
       else if (TREE_CODE (initial_value) == CONSTRUCTOR)
        {
          tree elts = CONSTRUCTOR_ELTS (initial_value);
-         maxindex = size_binop (MINUS_EXPR, integer_zero_node, size_one_node);
+         maxindex = build_int_2 (-1, -1);
          for (; elts; elts = TREE_CHAIN (elts))
            {
              if (TREE_PURPOSE (elts))
                maxindex = TREE_PURPOSE (elts);
              else
-               maxindex = size_binop (PLUS_EXPR, maxindex, size_one_node);
+               maxindex = fold (build (PLUS_EXPR, integer_type_node,
+                                       maxindex, integer_one_node));
            }
          maxindex = copy_node (maxindex);
        }
@@ -4312,13 +3789,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
   tree type = NULL_TREE;
   int longlong = 0;
   int constp;
+  int restrictp;
   int volatilep;
+  int type_quals = TYPE_UNQUALIFIED;
   int inlinep;
   int explicit_int = 0;
   int explicit_char = 0;
   int defaulted_int = 0;
   tree typedef_decl = 0;
-  char *name;
+  const char *name;
   tree typedef_type = 0;
   int funcdef_flag = 0;
   enum tree_code innermost_code = ERROR_MARK;
@@ -4332,11 +3811,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
   if (decl_context == FUNCDEF)
     funcdef_flag = 1, decl_context = NORMAL;
 
-  push_obstacks_nochange ();
-
-  if (flag_traditional && allocation_temporary_p ())
-    end_temporary_allocation ();
-
   /* Look inside a declarator for the name being declared
      and get it as a string, for an error message.  */
   {
@@ -4472,15 +3946,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
                          | (1 << (int) RID_UNSIGNED))))
          /* Don't warn about typedef foo = bar.  */
          && ! (specbits & (1 << (int) RID_TYPEDEF) && initialized)
-         && ! (in_system_header && ! allocation_temporary_p ()))
+         && ! in_system_header)
        {
-         /* C9x will probably require a diagnostic here.
-            For now, issue a warning if -Wreturn-type and this is a function,
-            or if -Wimplicit; prefer the former warning since it is more
-            explicit.  */
+         /* Issue a warning if this is an ISO C 99 program or if -Wreturn-type
+            and this is a function, or if -Wimplicit; prefer the former
+            warning since it is more explicit.  */
          if ((warn_implicit_int || warn_return_type) && funcdef_flag)
            warn_about_return_type = 1;
-         else if (warn_implicit_int)
+         else if (warn_implicit_int || flag_isoc99)
            warning ("type defaults to `int' in declaration of `%s'", name);
        }
 
@@ -4622,19 +4095,26 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
        type = build_complex_type (type);
     }
 
-  /* Set CONSTP if this declaration is `const', whether by
-     explicit specification or via a typedef.
-     Likewise for VOLATILEP.  */
-
+  /* Figure out the type qualifiers for the declaration.  There are
+     two ways a declaration can become qualified.  One is something
+     like `const int i' where the `const' is explicit.  Another is
+     something like `typedef const int CI; CI i' where the type of the
+     declaration contains the `const'.  */
   constp = !! (specbits & 1 << (int) RID_CONST) + TYPE_READONLY (type);
+  restrictp = !! (specbits & 1 << (int) RID_RESTRICT) + TYPE_RESTRICT (type);
   volatilep = !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (type);
   inlinep = !! (specbits & (1 << (int) RID_INLINE));
   if (constp > 1)
     pedwarn ("duplicate `const'");
+  if (restrictp > 1)
+    pedwarn ("duplicate `restrict'");
   if (volatilep > 1)
     pedwarn ("duplicate `volatile'");
-  if (! flag_gen_aux_info && (TYPE_READONLY (type) || TYPE_VOLATILE (type)))
+  if (! flag_gen_aux_info && (TYPE_QUALS (type)))
     type = TYPE_MAIN_VARIANT (type);
+  type_quals = ((constp ? TYPE_QUAL_CONST : 0)
+               | (restrictp ? TYPE_QUAL_RESTRICT : 0)
+               | (volatilep ? TYPE_QUAL_VOLATILE : 0));
 
   /* Warn if two storage classes are given. Default to `auto'.  */
 
@@ -4675,12 +4155,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          ;
        else
          {
-           error ((decl_context == FIELD
-                   ? "storage class specified for structure field `%s'"
-                   : (decl_context == PARM
-                      ? "storage class specified for parameter `%s'"
-                      : "storage class specified for typename")),
-                  name);
+           switch (decl_context)
+             {
+             case FIELD:
+               error ("storage class specified for structure field `%s'", name);
+               break;
+             case PARM:
+               error ("storage class specified for parameter `%s'", name);
+               break;
+             default:
+               error ("storage class specified for typename");
+               break;
+             }
            specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
                           | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
                           | (1 << (int) RID_EXTERN));
@@ -4744,8 +4230,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
        {
          register tree itype = NULL_TREE;
          register tree size = TREE_OPERAND (declarator, 1);
-         /* An uninitialized decl with `extern' is a reference.  */
-         int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN));
          /* The index is a signed object `sizetype' bits wide.  */
          tree index_type = signed_type (sizetype);
 
@@ -4771,12 +4255,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          if (type == error_mark_node)
            continue;
 
-         /* If this is a block level extern, it must live past the end
-            of the function so that we can check it against other extern
-            declarations (IDENTIFIER_LIMBO_VALUE).  */
-         if (extern_ref && allocation_temporary_p ())
-           end_temporary_allocation ();
-
          /* If size was specified, set ITYPE to a range-type for that size.
             Otherwise, ITYPE remains null.  finish_decl may figure it out
             from an initial value.  */
@@ -4847,7 +4325,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
         union incomplete (*foo)[4];  */
          /* Complain about arrays of incomplete types, except in typedefs.  */
 
-         if (TYPE_SIZE (type) == 0
+         if (!COMPLETE_TYPE_P (type)
              /* Avoid multiple warnings for nested array types.  */
              && TREE_CODE (type) != ARRAY_TYPE
              && !(specbits & (1 << (int) RID_TYPEDEF))
@@ -4868,13 +4346,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
             is set correctly.  */
 
          type = build_array_type (type, itype);
-         if (constp || volatilep)
-           type = c_build_type_variant (type, constp, volatilep);
+         if (type_quals)
+           type = c_build_qualified_type (type, type_quals);
 
 #if 0  /* don't clear these; leave them set so that the array type
           or the variable is itself const or volatile.  */
-         constp = 0;
-         volatilep = 0;
+         type_quals = TYPE_UNQUALIFIED;
 #endif
 
          if (size_varies)
@@ -4882,8 +4359,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
        }
       else if (TREE_CODE (declarator) == CALL_EXPR)
        {
-         int extern_ref = (!(specbits & (1 << (int) RID_AUTO))
-                           || current_binding_level == global_binding_level);
          tree arg_types;
 
          /* Declaring a function type.
@@ -4913,12 +4388,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
            type = double_type_node;
 #endif /* TRADITIONAL_RETURN_FLOAT */
 
-         /* If this is a block level extern, it must live past the end
-            of the function so that we can check it against other extern
-            declarations (IDENTIFIER_LIMBO_VALUE).  */
-         if (extern_ref && allocation_temporary_p ())
-           end_temporary_allocation ();
-
          /* Construct the function type and go to the next
             inner layer of declarator.  */
 
@@ -4928,23 +4397,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
                                    only for the CALL_EXPR
                                    closest to the identifier.  */
                                 && TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE);
-#if 0 /* This seems to be false.  We turn off temporary allocation
-        above in this function if -traditional.
-        And this code caused inconsistent results with prototypes:
-        callers would ignore them, and pass arguments wrong.  */
-
-         /* Omit the arg types if -traditional, since the arg types
-            and the list links might not be permanent.  */
-         type = build_function_type (type,
-                                     flag_traditional 
-                                     ? NULL_TREE : arg_types);
-#endif
-         /* ANSI seems to say that `const int foo ();'
-            does not make the function foo const.  */
-         if (constp || volatilep)
-           type = c_build_type_variant (type, constp, volatilep);
-         constp = 0;
-         volatilep = 0;
+         /* Type qualifiers before the return type of the function
+            qualify the return type, not the function type.  */
+         if (type_quals)
+           type = c_build_qualified_type (type, type_quals);
+         type_quals = TYPE_UNQUALIFIED;
 
          type = build_function_type (type, arg_types);
          declarator = TREE_OPERAND (declarator, 0);
@@ -4968,12 +4425,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
             for the pointer.  */
 
          if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-             && (constp || volatilep))
-           pedwarn ("ANSI C forbids const or volatile function types");
-         if (constp || volatilep)
-           type = c_build_type_variant (type, constp, volatilep);
-         constp = 0;
-         volatilep = 0;
+             && type_quals)
+           pedwarn ("ANSI C forbids qualified function types");
+         if (type_quals)
+           type = c_build_qualified_type (type, type_quals);
+         type_quals = TYPE_UNQUALIFIED;
          size_varies = 0;
 
          type = build_pointer_type (type);
@@ -4985,13 +4441,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
            {
              register tree typemodlist;
              int erred = 0;
+
+             constp = 0;
+             volatilep = 0;
+             restrictp = 0;
              for (typemodlist = TREE_TYPE (declarator); typemodlist;
                   typemodlist = TREE_CHAIN (typemodlist))
                {
-                 if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST])
+                 tree qualifier = TREE_VALUE (typemodlist);
+
+                 if (qualifier == ridpointers[(int) RID_CONST])
                    constp++;
-                 else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE])
+                 else if (qualifier == ridpointers[(int) RID_VOLATILE])
                    volatilep++;
+                 else if (qualifier == ridpointers[(int) RID_RESTRICT])
+                   restrictp++;
                  else if (!erred)
                    {
                      erred = 1;
@@ -5002,6 +4466,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
                pedwarn ("duplicate `const'");
              if (volatilep > 1)
                pedwarn ("duplicate `volatile'");
+             if (restrictp > 1)
+               pedwarn ("duplicate `restrict'");
+
+             type_quals = ((constp ? TYPE_QUAL_CONST : 0)
+                           | (restrictp ? TYPE_QUAL_RESTRICT : 0)
+                           | (volatilep ? TYPE_QUAL_VOLATILE : 0));
            }
 
          declarator = TREE_OPERAND (declarator, 0);
@@ -5016,7 +4486,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
   /* Did array size calculations overflow?  */
 
   if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_SIZE (type)
+      && COMPLETE_TYPE_P (type)
       && TREE_OVERFLOW (TYPE_SIZE (type)))
     error ("size of array `%s' is too large", name);
 
@@ -5028,15 +4498,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
       /* Note that the grammar rejects storage classes
         in typenames, fields or parameters */
       if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-         && (constp || volatilep))
-       pedwarn ("ANSI C forbids const or volatile function types");
-      if (constp || volatilep)
-       type = c_build_type_variant (type, constp, volatilep);
+         && type_quals)
+       pedwarn ("ANSI C forbids qualified function types");
+      if (type_quals)
+       type = c_build_qualified_type (type, type_quals);
       decl = build_decl (TYPE_DECL, declarator, type);
       if ((specbits & (1 << (int) RID_SIGNED))
          || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
        C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
-      pop_obstacks ();
       return decl;
     }
 
@@ -5063,11 +4532,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
       /* Note that the grammar rejects storage classes
         in typenames, fields or parameters */
       if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-         && (constp || volatilep))
+         && type_quals)
        pedwarn ("ANSI C forbids const or volatile function types");
-      if (constp || volatilep)
-       type = c_build_type_variant (type, constp, volatilep);
-      pop_obstacks ();
+      if (type_quals)
+       type = c_build_qualified_type (type, type_quals);
       return type;
     }
 
@@ -5097,7 +4565,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
     if (decl_context == PARM)
       {
        tree type_as_written = type;
-       tree main_type;
+       tree promoted_type;
 
        /* A parameter declared as an array of T is really a pointer to T.
           One declared as a function is really a pointer to a function.  */
@@ -5106,20 +4574,20 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          {
            /* Transfer const-ness of array into that of type pointed to.  */
            type = TREE_TYPE (type);
-           if (constp || volatilep)
-             type = c_build_type_variant (type, constp, volatilep);
+           if (type_quals)
+             type = c_build_qualified_type (type, type_quals);
            type = build_pointer_type (type);
-           volatilep = constp = 0;
+           type_quals = TYPE_UNQUALIFIED;
            size_varies = 0;
          }
        else if (TREE_CODE (type) == FUNCTION_TYPE)
          {
-           if (pedantic && (constp || volatilep))
-             pedwarn ("ANSI C forbids const or volatile function types");
-           if (constp || volatilep)
-             type = c_build_type_variant (type, constp, volatilep);
+           if (pedantic && type_quals)
+             pedwarn ("ANSI C forbids qualified function types");
+           if (type_quals)
+             type = c_build_qualified_type (type, type_quals);
            type = build_pointer_type (type);
-           volatilep = constp = 0;
+           type_quals = TYPE_UNQUALIFIED;
          }
 
        decl = build_decl (PARM_DECL, declarator, type);
@@ -5131,25 +4599,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
           (For example, shorts and chars are passed as ints.)
           When there is a prototype, this is overridden later.  */
 
-       DECL_ARG_TYPE (decl) = type;
-       main_type = (type == error_mark_node
-                    ? error_mark_node
-                    : TYPE_MAIN_VARIANT (type));
-       if (main_type == float_type_node)
-         DECL_ARG_TYPE (decl) = double_type_node;
-       /* Don't use TYPE_PRECISION to decide whether to promote,
-          because we should convert short if it's the same size as int,
-          but we should not convert long if it's the same size as int.  */
-       else if (TREE_CODE (main_type) != ERROR_MARK
-                && C_PROMOTING_INTEGER_TYPE_P (main_type))
+       if (type == error_mark_node)
+         promoted_type = type;
+       else
          {
-           if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)
-               && TREE_UNSIGNED (type))
-             DECL_ARG_TYPE (decl) = unsigned_type_node;
-           else
-             DECL_ARG_TYPE (decl) = integer_type_node;
+           promoted_type = simple_type_promotes_to (type);
+           if (! promoted_type)
+             promoted_type = type;
          }
 
+       DECL_ARG_TYPE (decl) = promoted_type;
        DECL_ARG_TYPE_AS_WRITTEN (decl) = type_as_written;
       }
     else if (decl_context == FIELD)
@@ -5161,19 +4620,20 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
            error ("field `%s' declared as a function", name);
            type = build_pointer_type (type);
          }
-       else if (TREE_CODE (type) != ERROR_MARK && TYPE_SIZE (type) == 0)
+       else if (TREE_CODE (type) != ERROR_MARK
+                && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type))
          {
            error ("field `%s' has incomplete type", name);
            type = error_mark_node;
          }
        /* Move type qualifiers down to element of an array.  */
-       if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep))
+       if (TREE_CODE (type) == ARRAY_TYPE && type_quals)
          {
-           type = build_array_type (c_build_type_variant (TREE_TYPE (type),
-                                                          constp, volatilep),
+           type = build_array_type (c_build_qualified_type (TREE_TYPE (type),
+                                                            type_quals),
                                     TYPE_DOMAIN (type));
 #if 0 /* Leave the field const or volatile as well.  */
-           constp = volatilep = 0;
+           type_quals = TYPE_UNQUALIFIED;
 #endif
          }
        decl = build_decl (FIELD_DECL, declarator, type);
@@ -5203,27 +4663,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
            && pedantic)
          pedwarn ("invalid storage class for function `%s'", name);
 
-       /* If this is a block level extern, it must live past the end
-          of the function so that we can check it against other
-          extern declarations (IDENTIFIER_LIMBO_VALUE).  */
-       if (extern_ref && allocation_temporary_p ())
-         end_temporary_allocation ();
-
        decl = build_decl (FUNCTION_DECL, declarator, type);
        decl = build_decl_attribute_variant (decl, decl_machine_attr);
 
-       if (pedantic && (constp || volatilep)
-           && ! DECL_IN_SYSTEM_HEADER (decl))
-         pedwarn ("ANSI C forbids const or volatile functions");
+       if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl))
+         pedwarn ("ANSI C forbids qualified function types");
 
        if (pedantic
            && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl))) == void_type_node
-           && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (decl)))
-               || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (decl))))
+           && TYPE_QUALS (TREE_TYPE (TREE_TYPE (decl)))
            && ! DECL_IN_SYSTEM_HEADER (decl))
-         pedwarn ("ANSI C forbids const or volatile void function return type");
+         pedwarn ("ANSI C forbids qualified void function return type");
 
-       if (volatilep
+       /* GNU C interprets a `volatile void' return type to indicate
+          that the function does not return.  */
+       if ((type_quals & TYPE_QUAL_VOLATILE)
            && TREE_TYPE (TREE_TYPE (decl)) != void_type_node)
          warning ("`noreturn' function returns non-void value");
 
@@ -5253,22 +4707,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
        int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN));
 
        /* Move type qualifiers down to element of an array.  */
-       if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep))
+       if (TREE_CODE (type) == ARRAY_TYPE && type_quals)
          {
-           type = build_array_type (c_build_type_variant (TREE_TYPE (type),
-                                                          constp, volatilep),
+           type = build_array_type (c_build_qualified_type (TREE_TYPE (type),
+                                                            type_quals),
                                     TYPE_DOMAIN (type));
 #if 0 /* Leave the variable const or volatile as well.  */
-           constp = volatilep = 0;
+           type_quals = TYPE_UNQUALIFIED;
 #endif
          }
 
-       /* If this is a block level extern, it must live past the end
-          of the function so that we can check it against other
-          extern declarations (IDENTIFIER_LIMBO_VALUE).  */
-       if (extern_ref && allocation_temporary_p ())
-         end_temporary_allocation ();
-
        decl = build_decl (VAR_DECL, declarator, type);
        if (size_varies)
          C_DECL_VARIABLE_SIZE (decl) = 1;
@@ -5306,22 +4754,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
       DECL_REGISTER (decl) = 1;
 
     /* Record constancy and volatility.  */
+    c_apply_type_quals_to_decl (type_quals, decl);
 
-    if (constp)
-      TREE_READONLY (decl) = 1;
-    if (volatilep)
-      {
-       TREE_SIDE_EFFECTS (decl) = 1;
-       TREE_THIS_VOLATILE (decl) = 1;
-      }
     /* If a type has volatile components, it should be stored in memory.
        Otherwise, the fact that those components are volatile
        will be ignored, and would even crash the compiler.  */
     if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)))
       mark_addressable (decl);
 
-    pop_obstacks ();
-
     return decl;
   }
 }
@@ -5389,7 +4829,7 @@ grokparms (parms_info, funcdef_flag)
            {
              /* Barf if the parameter itself has an incomplete type.  */
              tree type = TREE_VALUE (typelt);
-             if (TYPE_SIZE (type) == 0)
+             if (!COMPLETE_TYPE_P (type))
                {
                  if (funcdef_flag && DECL_NAME (parm) != 0)
                    error ("parameter `%s' has incomplete type",
@@ -5411,7 +4851,7 @@ grokparms (parms_info, funcdef_flag)
                         || TREE_CODE (type) == REFERENCE_TYPE)
                    type = TREE_TYPE (type);
                  type = TYPE_MAIN_VARIANT (type);
-                 if (TYPE_SIZE (type) == 0)
+                 if (!COMPLETE_TYPE_P (type))
                    {
                      if (DECL_NAME (parm) != 0)
                        warning ("parameter `%s' points to incomplete type",
@@ -5424,19 +4864,6 @@ grokparms (parms_info, funcdef_flag)
              typelt = TREE_CHAIN (typelt);
            }
 
-      /* Allocate the list of types the way we allocate a type.  */
-      if (first_parm && ! TREE_PERMANENT (first_parm))
-       {
-         /* Construct a copy of the list of types
-            on the saveable obstack.  */
-         tree result = NULL;
-         for (typelt = first_parm; typelt; typelt = TREE_CHAIN (typelt))
-           result = saveable_tree_cons (NULL_TREE, TREE_VALUE (typelt),
-                                        result);
-         return nreverse (result);
-       }
-      else
-       /* The list we have is permanent already.  */
        return first_parm;
     }
 }
@@ -5471,8 +4898,8 @@ get_parm_info (void_at_end)
     {
       parms = NULL_TREE;
       storedecls (NULL_TREE);
-      return saveable_tree_cons (NULL_TREE, NULL_TREE,
-                                saveable_tree_cons (NULL_TREE, void_type_node, NULL_TREE));
+      return tree_cons (NULL_TREE, NULL_TREE,
+                       tree_cons (NULL_TREE, void_type_node, NULL_TREE));
     }
 
   /* Extract enumerator values and other non-parms declared with the parms.
@@ -5520,14 +4947,13 @@ get_parm_info (void_at_end)
           args are passed in their declared types.  */
        tree type = TREE_TYPE (decl);
        DECL_ARG_TYPE (decl) = type;
-#ifdef PROMOTE_PROTOTYPES
-       if ((TREE_CODE (type) == INTEGER_TYPE
-            || TREE_CODE (type) == ENUMERAL_TYPE)
+       if (PROMOTE_PROTOTYPES
+           && (TREE_CODE (type) == INTEGER_TYPE
+               || TREE_CODE (type) == ENUMERAL_TYPE)
            && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
          DECL_ARG_TYPE (decl) = integer_type_node;
-#endif
 
-       types = saveable_tree_cons (NULL_TREE, TREE_TYPE (decl), types);
+       types = tree_cons (NULL_TREE, TREE_TYPE (decl), types);
        if (TYPE_MAIN_VARIANT (TREE_VALUE (types)) == void_type_node && ! erred
            && DECL_NAME (decl) == 0)
          {
@@ -5537,10 +4963,10 @@ get_parm_info (void_at_end)
       }
 
   if (void_at_end)
-    return saveable_tree_cons (new_parms, tags,
-                              nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types)));
+    return tree_cons (new_parms, tags,
+                     nreverse (tree_cons (NULL_TREE, void_type_node, types)));
 
-  return saveable_tree_cons (new_parms, tags, nreverse (types));
+  return tree_cons (new_parms, tags, nreverse (types));
 }
 
 /* At end of parameter list, warn about any struct, union or enum tags
@@ -5573,8 +4999,7 @@ parmlist_tags_warning ()
 
       if (! already)
        {
-         warning ("its scope is only this definition or declaration,");
-         warning ("which is probably not what you want.");
+         warning ("its scope is only this definition or declaration, which is probably not what you want.");
          already = 1;
        }
     }
@@ -5588,8 +5013,6 @@ xref_tag (code, name)
      enum tree_code code;
      tree name;
 {
-  int temporary = allocation_temporary_p ();
-
   /* If a cross reference is requested, look up the type
      already defined for this tag and return it.  */
 
@@ -5601,11 +5024,6 @@ xref_tag (code, name)
   if (ref)
     return ref;
 
-  push_obstacks_nochange ();
-
-  if (current_binding_level == global_binding_level && temporary)
-    end_temporary_allocation ();
-
   /* If no such tag is yet defined, create a forward-reference node
      and record it as the "definition".
      When a real declaration of this type is found,
@@ -5629,17 +5047,12 @@ xref_tag (code, name)
 
   pushtag (name, ref);
 
-  pop_obstacks ();
-
   return ref;
 }
 \f
 /* Make sure that the tag NAME is defined *in the current binding level*
    at least as a forward reference.
-   CODE says which kind of tag NAME ought to be.
-
-   We also do a push_obstacks_nochange
-   whose matching pop is in finish_struct.  */
+   CODE says which kind of tag NAME ought to be.  */
 
 tree
 start_struct (code, name)
@@ -5651,10 +5064,6 @@ start_struct (code, name)
 
   register tree ref = 0;
 
-  push_obstacks_nochange ();
-  if (current_binding_level == global_binding_level)
-    end_temporary_allocation ();
-
   if (name != 0)
     ref = lookup_tag (code, name, current_binding_level, 1);
   if (ref && TREE_CODE (ref) == code)
@@ -5662,8 +5071,8 @@ start_struct (code, name)
       C_TYPE_BEING_DEFINED (ref) = 1;
       TYPE_PACKED (ref) = flag_pack_struct;
       if (TYPE_FIELDS (ref))
-       error ((code == UNION_TYPE ? "redefinition of `union %s'"
-               : "redefinition of `struct %s'"),
+       error ("redefinition of `%s %s'",
+              code == UNION_TYPE ? "union" : "struct",
               IDENTIFIER_POINTER (name));
 
       return ref;
@@ -5688,15 +5097,12 @@ start_struct (code, name)
 
 tree
 grokfield (filename, line, declarator, declspecs, width)
-     char *filename;
-     int line;
+     const char *filename ATTRIBUTE_UNUSED;
+     int line ATTRIBUTE_UNUSED;
      tree declarator, declspecs, width;
 {
   tree value;
 
-  /* The corresponding pop_obstacks is in finish_decl.  */
-  push_obstacks_nochange ();
-
   value = grokdeclarator (declarator, declspecs, width ? BITFIELD : FIELD, 0);
 
   finish_decl (value, NULL_TREE, NULL_TREE);
@@ -5706,31 +5112,9 @@ grokfield (filename, line, declarator, declspecs, width)
   return value;
 }
 \f
-/* Function to help qsort sort FIELD_DECLs by name order.  */
-
-static int
-field_decl_cmp (xp, yp)
-     const GENERIC_PTR xp;
-     const GENERIC_PTR yp;
-{
-  tree *x = (tree *)xp, *y = (tree *)yp;
-
-  if (DECL_NAME (*x) == DECL_NAME (*y))
-    return 0;
-  if (DECL_NAME (*x) == NULL)
-    return -1;
-  if (DECL_NAME (*y) == NULL)
-    return 1;
-  if (DECL_NAME (*x) < DECL_NAME (*y))
-    return -1;
-  return 1;
-}
-
 /* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
    FIELDLIST is a chain of FIELD_DECL nodes for the fields.
-   ATTRIBUTES are attributes to be applied to the structure.
-
-   We also do a pop_obstacks to match the push in start_struct.  */
+   ATTRIBUTES are attributes to be applied to the structure.  */
 
 tree
 finish_struct (t, fieldlist, attributes)
@@ -5739,7 +5123,6 @@ finish_struct (t, fieldlist, attributes)
      tree attributes;
 {
   register tree x;
-  int old_momentary;
   int toplevel = global_binding_level == current_binding_level;
 
   /* If this type was previously laid out as a forward reference,
@@ -5755,15 +5138,13 @@ finish_struct (t, fieldlist, attributes)
     if (in_parm_level_p ())
       {
        if (pedantic)
-         pedwarn ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms"
-                   : "structure defined inside parms"));
+         pedwarn ("%s defined inside parms",
+                  TREE_CODE (t) == UNION_TYPE ? "union" : "structure");
        else if (! flag_traditional)
-         warning ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms"
-                   : "structure defined inside parms"));
+         warning ("%s defined inside parms",
+                  TREE_CODE (t) == UNION_TYPE ? "union" : "structure");
       }
 
-  old_momentary = suspend_momentary ();
-
   if (pedantic)
     {
       for (x = fieldlist; x; x = TREE_CHAIN (x))
@@ -5772,14 +5153,12 @@ finish_struct (t, fieldlist, attributes)
 
       if (x == 0)
        pedwarn ("%s has no %smembers",
-                (TREE_CODE (t) == UNION_TYPE ? "union" : "structure"),
-                (fieldlist ? "named " : ""));
+                TREE_CODE (t) == UNION_TYPE ? "union" : "struct",
+                fieldlist ? "named " : "");
     }
 
   /* Install struct as DECL_CONTEXT of each field decl.
-     Also process specified field sizes.
-     Set DECL_FIELD_SIZE to the specified size, or 0 if none specified.
-     The specified size is found in the DECL_INITIAL.
+     Also process specified field sizes,m which is found in the DECL_INITIAL.
      Store 0 there, except for ": 0" fields (so we can find them
      and delete them, below).  */
 
@@ -5787,7 +5166,6 @@ finish_struct (t, fieldlist, attributes)
     {
       DECL_CONTEXT (x) = t;
       DECL_PACKED (x) |= TYPE_PACKED (t);
-      DECL_FIELD_SIZE (x) = 0;
 
       /* If any field is const, the structure type is pseudo-const.  */
       if (TREE_READONLY (x))
@@ -5826,7 +5204,8 @@ finish_struct (t, fieldlist, attributes)
            constant_expression_warning (DECL_INITIAL (x));
          else
            {
-             error_with_decl (x, "bit-field `%s' width not an integer constant");
+             error_with_decl (x,
+                              "bit-field `%s' width not an integer constant");
              DECL_INITIAL (x) = NULL;
            }
        }
@@ -5839,6 +5218,7 @@ finish_struct (t, fieldlist, attributes)
          error_with_decl (x, "bit-field `%s' has invalid type");
          DECL_INITIAL (x) = NULL;
        }
+
       if (DECL_INITIAL (x) && pedantic
          && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != integer_type_node
          && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != unsigned_type_node
@@ -5848,69 +5228,62 @@ finish_struct (t, fieldlist, attributes)
                   == TYPE_PRECISION (integer_type_node))))
        pedwarn_with_decl (x, "bit-field `%s' type invalid in ANSI C");
 
-      /* Detect and ignore out of range field width.  */
+      /* Detect and ignore out of range field width and process valid
+        field widths.  */
       if (DECL_INITIAL (x))
        {
-         unsigned HOST_WIDE_INT width = TREE_INT_CST_LOW (DECL_INITIAL (x));
-
          if (tree_int_cst_sgn (DECL_INITIAL (x)) < 0)
+           error_with_decl (x, "negative width in bit-field `%s'");
+         else if (0 < compare_tree_int (DECL_INITIAL (x), 
+                                        TYPE_PRECISION (TREE_TYPE (x))))
+           pedwarn_with_decl (x, "width of `%s' exceeds its type");
+         else if (integer_zerop (DECL_INITIAL (x)) && DECL_NAME (x) != 0)
+           error_with_decl (x, "zero width for bit-field `%s'");
+         else
            {
-             DECL_INITIAL (x) = NULL;
-             error_with_decl (x, "negative width in bit-field `%s'");
-           }
-         else if (TREE_INT_CST_HIGH (DECL_INITIAL (x)) != 0
-                  || width > TYPE_PRECISION (TREE_TYPE (x)))
-           {
-             DECL_INITIAL (x) = NULL;
-             pedwarn_with_decl (x, "width of `%s' exceeds its type");
-           }
-         else if (width == 0 && DECL_NAME (x) != 0)
-           {
-             error_with_decl (x, "zero width for bit-field `%s'");
-             DECL_INITIAL (x) = NULL;
-           }
-       }
-
-      /* Process valid field width.  */
-      if (DECL_INITIAL (x))
-       {
-         register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
-
-         if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
-             && (width < min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
-                                        TREE_UNSIGNED (TREE_TYPE (x)))
-                 || width < min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
-                                           TREE_UNSIGNED (TREE_TYPE (x)))))
-           warning_with_decl (x, "`%s' is narrower than values of its type");
-
-         DECL_FIELD_SIZE (x) = width;
-         DECL_BIT_FIELD (x) = DECL_C_BIT_FIELD (x) = 1;
-         DECL_INITIAL (x) = NULL;
-
-         if (width == 0)
-           {
-             /* field size 0 => force desired amount of alignment.  */
+             /* The test above has assured us that TREE_INT_CST_HIGH is 0.  */
+             unsigned HOST_WIDE_INT width
+               = TREE_INT_CST_LOW (DECL_INITIAL (x));
+
+             if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
+                 && (width < min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
+                                            TREE_UNSIGNED (TREE_TYPE (x)))
+                     || (width
+                         < min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
+                                          TREE_UNSIGNED (TREE_TYPE (x))))))
+               warning_with_decl (x,
+                                  "`%s' is narrower than values of its type");
+
+             DECL_SIZE (x) = bitsize_int (width);
+             DECL_BIT_FIELD (x) = DECL_C_BIT_FIELD (x) = 1;
+
+             if (width == 0)
+               {
+                 /* field size 0 => force desired amount of alignment.  */
 #ifdef EMPTY_FIELD_BOUNDARY
-             DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY);
+                 DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY);
 #endif
 #ifdef PCC_BITFIELD_TYPE_MATTERS
-             if (PCC_BITFIELD_TYPE_MATTERS)
-               DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
-                                     TYPE_ALIGN (TREE_TYPE (x)));
+                 if (PCC_BITFIELD_TYPE_MATTERS)
+                   DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
+                                         TYPE_ALIGN (TREE_TYPE (x)));
 #endif
+               }
            }
        }
+
       else if (TREE_TYPE (x) != error_mark_node)
        {
          unsigned int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT
-                          : TYPE_ALIGN (TREE_TYPE (x)));
+                                   : TYPE_ALIGN (TREE_TYPE (x)));
+
          /* Non-bit-fields are aligned for their type, except packed
             fields which require only BITS_PER_UNIT alignment.  */
          DECL_ALIGN (x) = MAX (DECL_ALIGN (x), min_align);
        }
-    }
 
-  /* Now DECL_INITIAL is null on all members.  */
+      DECL_INITIAL (x) = 0;
+    }
 
   /* Delete all duplicate fields from the fieldlist */
   for (x = fieldlist; x && TREE_CHAIN (x);)
@@ -5944,60 +5317,21 @@ finish_struct (t, fieldlist, attributes)
 
   layout_type (t);
 
-  /* Delete all zero-width bit-fields from the front of the fieldlist */
-  while (fieldlist
-        && DECL_INITIAL (fieldlist))
-    fieldlist = TREE_CHAIN (fieldlist);
-  /* Delete all such members from the rest of the fieldlist */
-  for (x = fieldlist; x;)
-    {
-      if (TREE_CHAIN (x) && DECL_INITIAL (TREE_CHAIN (x)))
-       TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x));
-      else x = TREE_CHAIN (x);
-    }
+  /* Delete all zero-width bit-fields from the fieldlist */
+  {
+    tree *fieldlistp = &fieldlist;
+    while (*fieldlistp)
+      if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp))
+       *fieldlistp = TREE_CHAIN (*fieldlistp);
+      else
+       fieldlistp = &TREE_CHAIN (*fieldlistp);
+  }
 
   /*  Now we have the truly final field list.
       Store it in this type and in the variants.  */
 
   TYPE_FIELDS (t) = fieldlist;
 
-  /* If there are lots of fields, sort so we can look through them fast.
-     We arbitrarily consider 16 or more elts to be "a lot".  */
-  {
-    int len = 0;
-
-    for (x = fieldlist; x; x = TREE_CHAIN (x))
-      {
-       if (len > 15)
-         break;
-       len += 1;
-      }
-    if (len > 15)
-      {
-       tree *field_array;
-       char *space;
-
-       len += list_length (x);
-       /* Use the same allocation policy here that make_node uses, to
-          ensure that this lives as long as the rest of the struct decl.
-          All decls in an inline function need to be saved.  */
-       if (allocation_temporary_p ())
-         space = savealloc (sizeof (struct lang_type) + len * sizeof (tree));
-       else
-         space = oballoc (sizeof (struct lang_type) + len * sizeof (tree));
-
-       TYPE_LANG_SPECIFIC (t) = (struct lang_type *) space;
-       TYPE_LANG_SPECIFIC (t)->len = len;
-
-       field_array = &TYPE_LANG_SPECIFIC (t)->elts[0];
-       len = 0;
-       for (x = fieldlist; x; x = TREE_CHAIN (x))
-         field_array[len++] = x;
-
-       qsort (field_array, len, sizeof (tree), field_decl_cmp);
-      }
-  }
-
   for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
     {
       TYPE_FIELDS (x) = TYPE_FIELDS (t);
@@ -6034,7 +5368,7 @@ finish_struct (t, fieldlist, attributes)
                expand_decl (decl);
              --current_binding_level->n_incomplete;
            }
-         else if (TYPE_SIZE (TREE_TYPE (decl)) == 0
+         else if (!COMPLETE_TYPE_P (TREE_TYPE (decl))
                   && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
            {
              tree element = TREE_TYPE (decl);
@@ -6046,14 +5380,9 @@ finish_struct (t, fieldlist, attributes)
        }
     }
 
-  resume_momentary (old_momentary);
-
   /* Finish debugging output for this type.  */
   rest_of_type_compilation (t, toplevel);
 
-  /* The matching push is in start_struct.  */
-  pop_obstacks ();
-
   return t;
 }
 
@@ -6087,12 +5416,6 @@ start_enum (name)
   if (name != 0)
     enumtype = lookup_tag (ENUMERAL_TYPE, name, current_binding_level, 1);
 
-  /* The corresponding pop_obstacks is in finish_enum.  */
-  push_obstacks_nochange ();
-  /* If these symbols and types are global, make them permanent.  */
-  if (current_binding_level == global_binding_level)
-    end_temporary_allocation ();
-
   if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE)
     {
       enumtype = make_node (ENUMERAL_TYPE);
@@ -6134,8 +5457,8 @@ finish_enum (enumtype, values, attributes)
 {
   register tree pair, tem;
   tree minnode = 0, maxnode = 0;
-  int lowprec, highprec, precision;
-  int toplevel = global_binding_level == current_binding_level;
+  int precision, unsign;
+  int toplevel = (global_binding_level == current_binding_level);
 
   if (in_parm_level_p ())
     warning ("enum defined inside parms");
@@ -6147,67 +5470,63 @@ finish_enum (enumtype, values, attributes)
   if (values == error_mark_node)
     minnode = maxnode = integer_zero_node;
   else
-    for (pair = values; pair; pair = TREE_CHAIN (pair))
-      {
-       tree value = TREE_VALUE (pair);
-       if (pair == values)
-         minnode = maxnode = TREE_VALUE (pair);
-       else
-         {
-           if (tree_int_cst_lt (maxnode, value))
-             maxnode = value;
-           if (tree_int_cst_lt (value, minnode))
-             minnode = value;
-         }
-      }
-
-  TYPE_MIN_VALUE (enumtype) = minnode;
-  TYPE_MAX_VALUE (enumtype) = maxnode;
-
-  /* An enum can have some negative values; then it is signed.  */
-  TREE_UNSIGNED (enumtype) = tree_int_cst_sgn (minnode) >= 0;
-
-  /* Determine the precision this type needs.  */
-
-  lowprec = min_precision (minnode, TREE_UNSIGNED (enumtype));
-  highprec = min_precision (maxnode, TREE_UNSIGNED (enumtype));
-  precision = MAX (lowprec, highprec);
-
-  if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
     {
-      tree narrowest = type_for_size (precision, 1);
-      if (narrowest == 0)
+      minnode = maxnode = TREE_VALUE (values);
+      for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair))
        {
-         warning ("enumeration values exceed range of largest integer");
-         narrowest = long_long_integer_type_node;
+         tree value = TREE_VALUE (pair);
+         if (tree_int_cst_lt (maxnode, value))
+           maxnode = value;
+         if (tree_int_cst_lt (value, minnode))
+           minnode = value;
        }
+    }
 
-      TYPE_PRECISION (enumtype) = TYPE_PRECISION (narrowest);
+  /* Construct the final type of this enumeration.  It is the same
+     as one of the integral types - the narrowest one that fits, except
+     that normally we only go as narrow as int - and signed iff any of
+     the values are negative.  */
+  unsign = (tree_int_cst_sgn (minnode) >= 0);
+  precision = MAX (min_precision (minnode, unsign),
+                  min_precision (maxnode, unsign));
+  if (!TYPE_PACKED (enumtype))
+    precision = MAX (precision, TYPE_PRECISION (integer_type_node));
+  if (type_for_size (precision, unsign) == 0)
+    {
+      warning ("enumeration values exceed range of largest integer");
+      precision = TYPE_PRECISION (long_long_integer_type_node);
     }
-  else
-    TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
 
+  TYPE_MIN_VALUE (enumtype) = minnode;
+  TYPE_MAX_VALUE (enumtype) = maxnode;
+  TYPE_PRECISION (enumtype) = precision;
+  TREE_UNSIGNED (enumtype) = unsign;
   TYPE_SIZE (enumtype) = 0;
   layout_type (enumtype);
 
   if (values != error_mark_node)
     {
-      /* Change the type of the enumerators to be the enum type.
-        Formerly this was done only for enums that fit in an int,
-        but the comment said it was done only for enums wider than int.
-        It seems necessary to do this for wide enums,
-        and best not to change what's done for ordinary narrower ones.  */
+      /* Change the type of the enumerators to be the enum type.  We
+        need to do this irrespective of the size of the enum, for
+        proper type checking.  Replace the DECL_INITIALs of the
+        enumerators, and the value slots of the list, with copies
+        that have the enum type; they cannot be modified in place
+        because they may be shared (e.g.  integer_zero_node) Finally,
+        change the purpose slots to point to the names of the decls.  */
       for (pair = values; pair; pair = TREE_CHAIN (pair))
        {
-         TREE_TYPE (TREE_PURPOSE (pair)) = enumtype;
-         DECL_SIZE (TREE_PURPOSE (pair)) = TYPE_SIZE (enumtype);
-         if (TREE_CODE (TREE_PURPOSE (pair)) != FUNCTION_DECL)
-           DECL_ALIGN (TREE_PURPOSE (pair)) = TYPE_ALIGN (enumtype);
-       }
+         tree enu = TREE_PURPOSE (pair);
 
-      /* Replace the decl nodes in VALUES with their names.  */
-      for (pair = values; pair; pair = TREE_CHAIN (pair))
-       TREE_PURPOSE (pair) = DECL_NAME (TREE_PURPOSE (pair));
+         TREE_TYPE (enu) = enumtype;
+         DECL_SIZE (enu) = TYPE_SIZE (enumtype);
+         DECL_SIZE_UNIT (enu) = TYPE_SIZE_UNIT (enumtype);
+         DECL_ALIGN (enu) = TYPE_ALIGN (enumtype);
+         DECL_MODE (enu) = TYPE_MODE (enumtype);
+         DECL_INITIAL (enu) = convert (enumtype, DECL_INITIAL (enu));
+
+         TREE_PURPOSE (pair) = DECL_NAME (enu);
+         TREE_VALUE (pair) = DECL_INITIAL (enu);
+       }
 
       TYPE_VALUES (enumtype) = values;
     }
@@ -6215,6 +5534,8 @@ finish_enum (enumtype, values, attributes)
   /* Fix up all variant types of this enum type.  */
   for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem))
     {
+      if (tem == enumtype)
+       continue;
       TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
       TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
       TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
@@ -6229,9 +5550,6 @@ finish_enum (enumtype, values, attributes)
   /* Finish debugging output for this type.  */
   rest_of_type_compilation (enumtype, toplevel);
 
-  /* This matches a push in start_enum.  */
-  pop_obstacks ();
-
   return enumtype;
 }
 
@@ -6301,7 +5619,7 @@ build_enumerator (name, value)
   TREE_TYPE (value) = type;
   pushdecl (decl);
 
-  return saveable_tree_cons (decl, value, NULL_TREE);
+  return tree_cons (decl, value, NULL_TREE);
 }
 \f
 /* Create the FUNCTION_DECL for a function definition.
@@ -6314,14 +5632,11 @@ build_enumerator (name, value)
 
    Returns 1 on success.  If the DECLARATOR is not suitable for a function
    (it defines a datum instead), we return 0, which tells
-   yyparse to report a parse error.
-
-   NESTED is nonzero for a function nested within another function.  */
+   yyparse to report a parse error.  */
 
 int
-start_function (declspecs, declarator, prefix_attributes, attributes, nested)
+start_function (declspecs, declarator, prefix_attributes, attributes)
      tree declarator, declspecs, prefix_attributes, attributes;
-     int nested;
 {
   tree decl1, old_decl;
   tree restype;
@@ -6352,7 +5667,7 @@ start_function (declspecs, declarator, prefix_attributes, attributes, nested)
 
   announce_function (decl1);
 
-  if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl1))) == 0)
+  if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1))))
     {
       error ("return-type is an incomplete type");
       /* Make it return void instead.  */
@@ -6431,6 +5746,10 @@ start_function (declspecs, declarator, prefix_attributes, attributes, nested)
      except for defining how to inline.  So set DECL_EXTERNAL in that case.  */
   DECL_EXTERNAL (decl1) = current_extern_inline;
 
+#ifdef SET_DEFAULT_DECL_ATTRIBUTES
+  SET_DEFAULT_DECL_ATTRIBUTES (decl1, attributes);
+#endif
+  
   /* This function exists in static storage.
      (This does not mean `static' in the C sense!)  */
   TREE_STATIC (decl1) = 1;
@@ -6440,7 +5759,7 @@ start_function (declspecs, declarator, prefix_attributes, attributes, nested)
     TREE_PUBLIC (decl1) = 0;
 
   /* Warn for unlikely, improbable, or stupid declarations of `main'. */
-  if (warn_main
+  if (warn_main > 0
       && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))) == 0)
     {
       tree args;
@@ -6529,11 +5848,6 @@ start_function (declspecs, declarator, prefix_attributes, attributes, nested)
   DECL_RESULT (current_function_decl)
     = build_decl (RESULT_DECL, NULL_TREE, restype);
 
-  if (!nested)
-    /* Allocate further tree nodes temporarily during compilation
-       of this function only.  */
-    temporary_allocation ();
-
   /* If this fcn was already referenced via a block-scope `extern' decl
      (or an implicit decl), propagate certain information about the usage.  */
   if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl)))
@@ -6624,7 +5938,9 @@ store_parm_decls ()
            {
              if (DECL_NAME (parm) == 0)
                error_with_decl (parm, "parameter name omitted");
-             else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node)
+             else if (TREE_CODE (TREE_TYPE (parm)) != ERROR_MARK
+                      && (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
+                          == void_type_node))
                {
                  error_with_decl (parm, "parameter `%s' declared void");
                  /* Change the type to error_mark_node so this parameter
@@ -6691,8 +6007,10 @@ store_parm_decls ()
         Associate decls with the names and store the decls
         into the TREE_PURPOSE slots.  */
 
+      /* We use DECL_WEAK as a flag to show which parameters have been
+        seen already since it is not used on PARM_DECL or CONST_DECL.  */
       for (parm = parmdecls; parm; parm = TREE_CHAIN (parm))
-       DECL_RESULT (parm) = 0;
+       DECL_WEAK (parm) = 0;
 
       for (parm = specparms; parm; parm = TREE_CHAIN (parm))
        {
@@ -6700,7 +6018,8 @@ store_parm_decls ()
 
          if (TREE_VALUE (parm) == 0)
            {
-             error_with_decl (fndecl, "parameter name missing from parameter list");
+             error_with_decl (fndecl,
+                              "parameter name missing from parameter list");
              TREE_PURPOSE (parm) = 0;
              continue;
            }
@@ -6717,7 +6036,7 @@ store_parm_decls ()
 
          /* If declaration already marked, we have a duplicate name.
             Complain, and don't use this decl twice.   */
-         if (found && DECL_RESULT (found) != 0)
+         if (found && DECL_WEAK (found))
            {
              error_with_decl (found, "multiple parameters named `%s'");
              found = 0;
@@ -6756,10 +6075,8 @@ store_parm_decls ()
 
          TREE_PURPOSE (parm) = found;
 
-         /* Mark this decl as "already found" -- see test, above.
-            It is safe to use DECL_RESULT for this
-            since it is not used in PARM_DECLs or CONST_DECLs.  */
-         DECL_RESULT (found) = error_mark_node;
+         /* Mark this decl as "already found" */
+         DECL_WEAK (found) = 1;
        }
 
       /* Put anything which is on the parmdecls chain and which is
@@ -6779,13 +6096,13 @@ store_parm_decls ()
          else
            {
              /* Complain about args with incomplete types.  */
-             if (TYPE_SIZE (TREE_TYPE (parm)) == 0)
+             if (!COMPLETE_TYPE_P (TREE_TYPE (parm)))
                {
                  error_with_decl (parm, "parameter `%s' has incomplete type");
                  TREE_TYPE (parm) = error_mark_node;
                }
 
-             if (DECL_RESULT (parm) == 0)
+             if (! DECL_WEAK (parm))
                {
                  error_with_decl (parm,
                                   "declaration for parameter `%s' but no such parameter");
@@ -6854,13 +6171,14 @@ store_parm_decls ()
                         `int foo(float x) {...}'.  This is particularly
                         useful for argument types like uid_t.  */
                      DECL_ARG_TYPE (parm) = TREE_TYPE (parm);
-#ifdef PROMOTE_PROTOTYPES
-                     if ((TREE_CODE (TREE_TYPE (parm)) == INTEGER_TYPE
-                          || TREE_CODE (TREE_TYPE (parm)) == ENUMERAL_TYPE)
+
+                     if (PROMOTE_PROTOTYPES
+                         && (TREE_CODE (TREE_TYPE (parm)) == INTEGER_TYPE
+                             || TREE_CODE (TREE_TYPE (parm)) == ENUMERAL_TYPE)
                          && TYPE_PRECISION (TREE_TYPE (parm))
                          < TYPE_PRECISION (integer_type_node))
                        DECL_ARG_TYPE (parm) = integer_type_node;
-#endif
+
                      if (pedantic)
                        {
                          pedwarn ("promoted argument `%s' doesn't match prototype",
@@ -6896,15 +6214,14 @@ store_parm_decls ()
 
          for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm))
            {
-             type = perm_tree_cons (NULL_TREE, DECL_ARG_TYPE (parm),
-                                    NULL_TREE);
+             type = tree_cons (NULL_TREE, DECL_ARG_TYPE (parm), NULL_TREE);
              if (last)
                TREE_CHAIN (last) = type;
              else
                actual = type;
              last = type;
            }
-         type = perm_tree_cons (NULL_TREE, void_type_node, NULL_TREE);
+         type = tree_cons (NULL_TREE, void_type_node, NULL_TREE);
          if (last)
            TREE_CHAIN (last) = type;
          else
@@ -7001,7 +6318,7 @@ combine_parm_decls (specparms, parmlist, void_at_end)
   tree types = 0;
 
   for (parm = parmdecls; parm; parm = TREE_CHAIN (parm))
-    DECL_RESULT (parm) = 0;
+    DECL_WEAK (parm) = 0;
 
   for (parm = specparms; parm; parm = TREE_CHAIN (parm))
     {
@@ -7017,7 +6334,7 @@ combine_parm_decls (specparms, parmlist, void_at_end)
 
       /* If declaration already marked, we have a duplicate name.
         Complain, and don't use this decl twice.   */
-      if (found && DECL_RESULT (found) != 0)
+      if (found && DECL_WEAK (found))
        {
          error_with_decl (found, "multiple parameters named `%s'");
          found = 0;
@@ -7055,10 +6372,8 @@ combine_parm_decls (specparms, parmlist, void_at_end)
 
       TREE_PURPOSE (parm) = found;
 
-      /* Mark this decl as "already found" -- see test, above.
-        It is safe to use DECL_RESULT for this
-        since it is not used in PARM_DECLs or CONST_DECLs.  */
-      DECL_RESULT (found) = error_mark_node;
+      /* Mark this decl as "already found".  */
+      DECL_WEAK (found) = 1;
     }
 
   /* Complain about any actual PARM_DECLs not matched with any names.  */
@@ -7069,13 +6384,13 @@ combine_parm_decls (specparms, parmlist, void_at_end)
       TREE_CHAIN (parm) = 0;
 
       /* Complain about args with incomplete types.  */
-      if (TYPE_SIZE (TREE_TYPE (parm)) == 0)
+      if (!COMPLETE_TYPE_P (TREE_TYPE (parm)))
        {
          error_with_decl (parm, "parameter `%s' has incomplete type");
          TREE_TYPE (parm) = error_mark_node;
        }
 
-      if (DECL_RESULT (parm) == 0)
+      if (! DECL_WEAK (parm))
        {
          error_with_decl (parm,
                           "declaration for parameter `%s' but no such parameter");
@@ -7107,17 +6422,15 @@ combine_parm_decls (specparms, parmlist, void_at_end)
          last = TREE_PURPOSE (parm);
          TREE_CHAIN (last) = 0;
 
-         types = saveable_tree_cons (NULL_TREE, TREE_TYPE (parm), types);
+         types = tree_cons (NULL_TREE, TREE_TYPE (parm), types);
        }
   }
   
   if (void_at_end)
-    return saveable_tree_cons (parmdecls, nonparms,
-                              nreverse (saveable_tree_cons (NULL_TREE,
-                                                            void_type_node,
-                                                            types)));
+    return tree_cons (parmdecls, nonparms,
+                     nreverse (tree_cons (NULL_TREE, void_type_node, types)));
 
-  return saveable_tree_cons (parmdecls, nonparms, nreverse (types));
+  return tree_cons (parmdecls, nonparms, nreverse (types));
 }
 \f
 /* Finish up a function declaration and compile that function
@@ -7157,12 +6470,8 @@ finish_function (nested)
       if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
          != integer_type_node)
        {
-         /* You would expect the sense of this test to be the other way
-            around, but if warn_main is set, we will already have warned,
-            so this would be a duplicate.  This is the warning you get
-            in some environments even if you *don't* ask for it, because
-            these are environments where it may be more of a problem than
-            usual.  */
+         /* If warn_main is 1 (-Wmain) or 2 (-Wall), we have already warned.
+            If warn_main is -1 (-Wno-main) we don't want to be warned. */
          if (! warn_main)
            pedwarn_with_decl (fndecl, "return type of `%s' is not `int'");
        }
@@ -7181,11 +6490,26 @@ finish_function (nested)
   /* So we can tell if jump_optimize sets it to 1.  */
   can_reach_end = 0;
 
+  /* If this is a nested function, protect the local variables in the stack
+     above us from being collected while we're compiling this function.  */
+  if (nested)
+    ggc_push_context ();
+
   /* Run the optimizers and output the assembler code for this function.  */
   rest_of_compilation (fndecl);
 
+  /* Undo the GC context switch.  */
+  if (nested)
+    ggc_pop_context ();
+
   current_function_returns_null |= can_reach_end;
 
+  if (warn_missing_noreturn
+      && !TREE_THIS_VOLATILE (fndecl)
+      && !current_function_returns_null
+      && !current_function_returns_value)
+    warning ("function might be possible candidate for attribute `noreturn'");
+
   if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
     warning ("`noreturn' function does return");
   else if (warn_return_type && can_reach_end
@@ -7205,40 +6529,36 @@ finish_function (nested)
 
   if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl))
     {
-      register tree ret_type = TREE_TYPE (TREE_TYPE (fndecl));
+      tree ret_type = TREE_TYPE (TREE_TYPE (fndecl));
 
-      if (ret_type)
+      if (ret_type && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST
+         && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type),
+                                  larger_than_size))
        {
-         register tree ret_type_size = TYPE_SIZE (ret_type);
+         unsigned int size_as_int
+           = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type));
 
-         if (TREE_CODE (ret_type_size) == INTEGER_CST)
-           {
-             unsigned units
-               = TREE_INT_CST_LOW (ret_type_size) / BITS_PER_UNIT;
-
-             if (units > larger_than_size)
-               warning_with_decl (fndecl,
-                                  "size of return value of `%s' is %u bytes",
-                                  units);
-           }
+         if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0)
+           warning_with_decl (fndecl,
+                              "size of return value of `%s' is %u bytes",
+                              size_as_int);
+         else
+           warning_with_decl (fndecl,
+                      "size of return value of `%s' is larger than %d bytes",
+                              larger_than_size);
        }
     }
 
-  /* Free all the tree nodes making up this function.  */
-  /* Switch back to allocating nodes permanently
-     until we start another function.  */
-  if (! nested)
-    permanent_allocation (1);
-
   if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested)
     {
-      /* Stop pointing to the local nodes about to be freed.  */
-      /* But DECL_INITIAL must remain nonzero so we know this
-        was an actual function definition.  */
-      /* For a nested function, this is done in pop_c_function_context.  */
-      /* If rest_of_compilation set this to 0, leave it 0.  */
+      /* Stop pointing to the local nodes about to be freed. 
+        But DECL_INITIAL must remain nonzero so we know this
+        was an actual function definition. 
+        For a nested function, this is done in pop_c_function_context.
+        If rest_of_compilation set this to 0, leave it 0.  */
       if (DECL_INITIAL (fndecl) != 0)
        DECL_INITIAL (fndecl) = error_mark_node;
+
       DECL_ARGUMENTS (fndecl) = 0;
     }
 
@@ -7246,19 +6566,20 @@ finish_function (nested)
     {
 #ifndef ASM_OUTPUT_CONSTRUCTOR
       if (! flag_gnu_linker)
-       static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors);
+       static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
       else
 #endif
-      assemble_constructor (IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+       assemble_constructor (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))); 
+
     }
   if (DECL_STATIC_DESTRUCTOR (fndecl))
     {
 #ifndef ASM_OUTPUT_DESTRUCTOR
       if (! flag_gnu_linker)
-       static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors);
+       static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
       else
 #endif
-      assemble_destructor (IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+       assemble_destructor (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)));
     }
 
   if (! nested)
@@ -7274,9 +6595,8 @@ finish_function (nested)
    that keep track of the progress of compilation of the current function.
    Used for nested functions.  */
 
-struct c_function
+struct language_function
 {
-  struct c_function *next;
   tree named_labels;
   tree shadowed_labels;
   int returns_value;
@@ -7286,24 +6606,16 @@ struct c_function
   struct binding_level *binding_level;
 };
 
-struct c_function *c_function_chain;
-
 /* Save and reinitialize the variables
    used during compilation of a C function.  */
 
 void
-push_c_function_context ()
+push_c_function_context (f)
+     struct function *f;
 {
-  struct c_function *p
-    = (struct c_function *) xmalloc (sizeof (struct c_function));
-
-  if (pedantic)
-    pedwarn ("ANSI C forbids nested functions");
-
-  push_function_context ();
-
-  p->next = c_function_chain;
-  c_function_chain = p;
+  struct language_function *p;
+  p = (struct language_function *) xmalloc (sizeof (struct language_function));
+  f->language = p;
 
   p->named_labels = named_labels;
   p->shadowed_labels = shadowed_labels;
@@ -7317,9 +6629,10 @@ push_c_function_context ()
 /* Restore the variables used during compilation of a C function.  */
 
 void
-pop_c_function_context ()
+pop_c_function_context (f)
+     struct function *f;
 {
-  struct c_function *p = c_function_chain;
+  struct language_function *p = f->language;
   tree link;
 
   /* Bring back all the labels that were shadowed.  */
@@ -7337,10 +6650,6 @@ pop_c_function_context ()
       DECL_ARGUMENTS (current_function_decl) = 0;
     }
 
-  pop_function_context ();
-
-  c_function_chain = p->next;
-
   named_labels = p->named_labels;
   shadowed_labels = p->shadowed_labels;
   current_function_returns_value = p->returns_value;
@@ -7350,6 +6659,22 @@ pop_c_function_context ()
   current_binding_level = p->binding_level;
 
   free (p);
+  f->language = 0;
+}
+
+/* Mark the language specific parts of F for GC.  */
+void
+mark_c_function_context (f)
+     struct function *f;
+{
+  struct language_function *p = f->language;
+
+  if (p == 0)
+    return;
+
+  ggc_mark_tree (p->shadowed_labels);
+  ggc_mark_tree (p->named_labels);
+  mark_binding_level (&p->binding_level);
 }
 
 /* integrate_decl_tree calls this function, but since we don't use the
@@ -7360,3 +6685,32 @@ copy_lang_decl (node)
      tree node ATTRIBUTE_UNUSED;
 {
 }
+
+/* Mark ARG for GC.  */
+void
+lang_mark_false_label_stack (arg)
+     struct label_node *arg;
+{
+  /* C doesn't use false_label_stack.  It better be NULL.  */
+  if (arg != NULL)
+    abort();
+}
+
+/* Mark the language specific bits in T for GC.  */
+void
+lang_mark_tree (t)
+     tree t;
+{
+  if (TREE_CODE (t) == IDENTIFIER_NODE)
+    {
+      struct lang_identifier *i = (struct lang_identifier *) t;
+      ggc_mark_tree (i->global_value);
+      ggc_mark_tree (i->local_value);
+      ggc_mark_tree (i->label_value);
+      ggc_mark_tree (i->implicit_decl);
+      ggc_mark_tree (i->error_locus);
+      ggc_mark_tree (i->limbo_value);
+    }
+  else if (TYPE_P (t) && TYPE_LANG_SPECIFIC (t))
+    ggc_mark (TYPE_LANG_SPECIFIC (t));
+}