Initial revision
authorRichard Stallman <rms@gnu.org>
Thu, 13 Feb 1992 22:21:26 +0000 (22:21 +0000)
committerRichard Stallman <rms@gnu.org>
Thu, 13 Feb 1992 22:21:26 +0000 (22:21 +0000)
From-SVN: r319

gcc/c-decl.c [new file with mode: 0644]

diff --git a/gcc/c-decl.c b/gcc/c-decl.c
new file mode 100644 (file)
index 0000000..09038c1
--- /dev/null
@@ -0,0 +1,5671 @@
+/* Process declarations and variables for C compiler.
+   Copyright (C) 1988, 1992 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+/* Process declarations and symbol lookup for C front end.
+   Also constructs types; the standard scalar types at initialization,
+   and structure, union, array and enum types when they are declared.  */
+
+/* ??? not all decl nodes are given the most useful possible
+   line numbers.  For example, the CONST_DECLs for enum values.  */
+
+#include "config.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-tree.h"
+#include "c-lex.h"
+#include <stdio.h>
+
+/* In grokdeclarator, distinguish syntactic contexts of declarators.  */
+enum decl_context
+{ NORMAL,                      /* Ordinary declaration */
+  FUNCDEF,                     /* Function definition */
+  PARM,                                /* Declaration of parm before function body */
+  FIELD,                       /* Declaration inside struct or union */
+  BITFIELD,                    /* Likewise but with specified width */
+  TYPENAME};                   /* Typename (inside cast or sizeof)  */
+
+#undef NULL
+#define NULL 0
+
+#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,
+   it would be best to do something here to figure out automatically
+   from other information what type to use.  */
+
+#ifndef SIZE_TYPE
+#define SIZE_TYPE "long unsigned int"
+#endif
+
+#ifndef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "long int"
+#endif
+
+#ifndef WCHAR_TYPE
+#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 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;
+
+/* 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[256]' or something like it.
+   Used when an array of char is needed and the size is irrelevant.  */
+
+tree char_array_type_node;
+
+/* Type `int[256]' or something like it.
+   Used when an array of int needed and the size is irrelevant.  */
+
+tree int_array_type_node;
+
+/* Type `wchar_t[256]' 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;
+
+/* 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 `size_t (const char *)' */
+tree sizet_ftype_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;
+
+/* Nonzero if we have seen an invalid cross reference
+   to a struct, union, or enum, but not yet printed the message.  */
+
+tree pending_invalid_xref;
+/* File and line to appear in the eventual error message.  */
+char *pending_invalid_xref_file;
+int pending_invalid_xref_line;
+
+/* While defining an enum type, this is 1 plus the last enumerator
+   constant value.  */
+
+static tree enum_next_value;
+
+/* Parsing a function declarator leaves a list of parameter names
+   or a chain or parameter decls here.  */
+
+static tree last_function_parms;
+
+/* Parsing a function declarator leaves here a chain of structure
+   and enum types declared in the parmlist.  */
+
+static tree last_function_parm_tags;
+
+/* After parsing the declarator that starts a function definition,
+   `start_function' puts here the list of parameter names or chain of decls.
+   `store_parm_decls' finds it here.  */
+
+static tree current_function_parms;
+
+/* Similar, for last_function_parm_tags.  */
+static tree current_function_parm_tags;
+
+/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
+   that have names.  Here so we can clear out their names' definitions
+   at the end of the function.  */
+
+tree named_labels;
+
+/* A list of LABEL_DECLs from outer contexts that are currently shadowed.  */
+
+static tree shadowed_labels;
+
+/* Nonzero when store_parm_decls is called indicates a varargs function.
+   Value not meaningful after store_parm_decls.  */
+
+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.  */
+
+int current_function_returns_value;
+
+/* Set to 0 at beginning of a function definition, set to 1 if
+   a return statement with no argument is seen.  */
+
+int current_function_returns_null;
+
+/* Set to nonzero by `grokdeclarator' for a function
+   whose return type is defaulted, if warnings for this are desired.  */
+
+static int warn_about_return_type;
+
+/* Nonzero when starting a function delcared `extern inline'.  */
+
+static int current_extern_inline;
+\f
+/* For each binding contour we allocate a binding_level structure
+ * which records the names defined in that contour.
+ * Contours include:
+ *  0) the global one
+ *  1) one for each function definition,
+ *     where internal declarations of the parameters appear.
+ *  2) one for each compound statement,
+ *     to record its declarations.
+ *
+ * The current meaning of a name can be found by searching the levels from
+ * the current one out to the global one.
+ */
+
+/* Note that the information in the `names' component of the global contour
+   is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers.  */
+
+struct binding_level
+  {
+    /* A chain of _DECL nodes for all variables, constants, functions,
+       and typedef types.  These are in the reverse of the order supplied.
+     */
+    tree names;
+
+    /* A list of structure, union and enum definitions,
+     * for looking up tag names.
+     * It is a chain of TREE_LIST nodes, each of whose TREE_PURPOSE is a name,
+     * or NULL_TREE; and whose TREE_VALUE is a RECORD_TYPE, UNION_TYPE,
+     * or ENUMERAL_TYPE node.
+     */
+    tree tags;
+
+    /* For each level, a list of shadowed outer-level local definitions
+       to be restored when this level is popped.
+       Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and
+       whose TREE_VALUE is its old definition (a kind of ..._DECL node).  */
+    tree shadowed;
+
+    /* For each level (except not the global one),
+       a chain of BLOCK nodes for all the levels
+       that were entered and exited one level down.  */
+    tree blocks;
+
+    /* The binding level which this one is contained in (inherits from).  */
+    struct binding_level *level_chain;
+
+    /* Nonzero for the level that holds the parameters of a function.  */
+    /* 2 for a definition, 1 for a declaration.  */
+    char parm_flag;
+
+    /* Nonzero if this level "doesn't exist" for tags.  */
+    char tag_transparent;
+
+    /* Nonzero if sublevels of this level "don't exist" for tags.
+       This is set in the parm level of a function definition
+       while reading the function body, so that the outermost block
+       of the function body will be tag-transparent.  */
+    char subblocks_tag_transparent;
+
+    /* Nonzero means make a BLOCK for this level regardless of all else.  */
+    char keep;
+
+    /* Nonzero means make a BLOCK if this level has any subblocks.  */
+    char keep_if_subblocks;
+
+    /* Number of decls in `names' that have incomplete 
+       structure or union types.  */
+    int n_incomplete;
+
+    /* A list of decls giving the (reversed) specified order of parms,
+       not including any forward-decls in the parmlist.
+       This is so we can put the parms in proper order for assign_parms.  */
+    tree parm_order;
+  };
+
+#define NULL_BINDING_LEVEL (struct binding_level *) NULL
+  
+/* The binding level currently in effect.  */
+
+static struct binding_level *current_binding_level;
+
+/* A chain of binding_level structures awaiting reuse.  */
+
+static struct binding_level *free_binding_level;
+
+/* The outermost binding level, for names of file scope.
+   This is created when the compiler is started and exists
+   through the entire run.  */
+
+static struct binding_level *global_binding_level;
+
+/* Binding level structures are initialized by copying this one.  */
+
+static struct binding_level clear_binding_level
+  = {NULL, NULL, NULL, NULL, NULL, 0, 0, 0};
+
+/* Nonzero means unconditionally make a BLOCK for the next level pushed.  */
+
+static int keep_next_level_flag;
+
+/* Nonzero means make a BLOCK for the next level pushed
+   if it has subblocks.  */
+
+static int keep_next_if_subblocks;
+  
+/* The chain of outer levels of label scopes.
+   This uses the same data structure used for binding levels,
+   but it works differently: each link in the chain records
+   saved values of named_labels and shadowed_labels for
+   a label binding level outside the current one.  */
+
+static struct binding_level *label_level_chain;
+
+/* Forward declarations.  */
+
+static tree grokparms (), grokdeclarator ();
+tree pushdecl ();
+static tree builtin_function ();
+
+static tree lookup_tag ();
+static tree lookup_tag_reverse ();
+static tree lookup_name_current_level ();
+static char *redeclaration_error_message ();
+static void layout_array_type ();
+\f
+/* C-specific option variables.  */
+
+/* Nonzero means allow type mismatches in conditional expressions;
+   just make their values `void'.   */
+
+int flag_cond_mismatch;
+
+/* Nonzero means give `double' the same size as `float'.  */
+
+int flag_short_double;
+
+/* Nonzero means don't recognize the keyword `asm'.  */
+
+int flag_no_asm;
+
+/* Nonzero means don't recognize the non-ANSI builtin functions.  */
+
+int flag_no_builtin;
+
+/* Nonzero means do some things the same way PCC does.  */
+
+int flag_traditional;
+
+/* Nonzero means to treat bitfields as signed unless they say `unsigned'.  */
+
+int flag_signed_bitfields = 1;
+
+/* Nonzero means handle `#ident' directives.  0 means ignore them.  */
+
+int flag_no_ident = 0;
+
+/* Nonzero means warn about implicit declarations.  */
+
+int warn_implicit;
+
+/* Nonzero means give string constants the type `const char *'
+   to get extra warnings from them.  These warnings will be too numerous
+   to be useful, except in thoroughly ANSIfied programs.  */
+
+int warn_write_strings;
+
+/* Nonzero means warn about pointer casts that can drop a type qualifier
+   from the pointer target type.  */
+
+int warn_cast_qual;
+
+/* Warn about traditional constructs whose meanings changed in ANSI C.  */
+
+int warn_traditional;
+
+/* Nonzero means warn about sizeof(function) or addition/subtraction
+   of function pointers.  */
+
+int warn_pointer_arith;
+
+/* Nonzero means warn for non-prototype function decls
+   or non-prototyped defs without previous prototype.  */
+
+int warn_strict_prototypes;
+
+/* Nonzero means warn for any global function def
+   without separate previous prototype decl.  */
+
+int warn_missing_prototypes;
+
+/* Nonzero means warn about multiple (redundant) decls for the same single
+   variable or function.  */
+
+int warn_redundant_decls = 0;
+
+/* Nonzero means warn about extern declarations of objects not at
+   file-scope level and about *all* declarations of functions (whether
+   extern or static) not at file-scope level.  Note that we exclude
+   implicit function declarations.  To get warnings about those, use
+   -Wimplicit.  */
+
+int warn_nested_externs = 0;
+
+/* Warn about *printf or *scanf format/argument anomalies. */
+
+int warn_format;
+
+/* Warn about a subscript that has type char.  */
+
+int warn_char_subscripts = 0;
+
+/* Warn if a type conversion is done that might have confusing results.  */
+
+int warn_conversion;
+
+/* Warn if adding () is suggested.  */
+
+int warn_parentheses = 1;
+
+/* Nonzero means `$' can be in an identifier.
+   See cccp.c for reasons why this breaks some obscure ANSI C programs.  */
+
+#ifndef DOLLARS_IN_IDENTIFIERS
+#define DOLLARS_IN_IDENTIFIERS 1
+#endif
+int dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 1;
+
+char *language_string = "GNU C";
+
+/* Decode the string P as a language-specific option for C.
+   Return 1 if it is recognized (and handle it);
+   return 0 if not recognized.  */
+   
+int
+c_decode_option (p)
+     char *p;
+{
+  if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional"))
+    {
+      flag_traditional = 1;
+      flag_writable_strings = 1;
+#if DOLLARS_IN_IDENTIFIERS > 0
+      dollars_in_ident = 1;
+#endif
+    }
+  else if (!strcmp (p, "-fnotraditional"))
+    ;
+  else if (!strcmp (p, "-fsigned-char"))
+    flag_signed_char = 1;
+  else if (!strcmp (p, "-funsigned-char"))
+    flag_signed_char = 0;
+  else if (!strcmp (p, "-fno-signed-char"))
+    flag_signed_char = 0;
+  else if (!strcmp (p, "-fno-unsigned-char"))
+    flag_signed_char = 1;
+  else if (!strcmp (p, "-fsigned-bitfields"))
+    flag_signed_bitfields = 1;
+  else if (!strcmp (p, "-funsigned-bitfields"))
+    flag_signed_bitfields = 0;
+  else if (!strcmp (p, "-fno-signed-bitfields"))
+    flag_signed_bitfields = 0;
+  else if (!strcmp (p, "-fno-unsigned-bitfields"))
+    flag_signed_bitfields = 1;
+  else if (!strcmp (p, "-fshort-enums"))
+    flag_short_enums = 1;
+  else if (!strcmp (p, "-fno-short-enums"))
+    flag_short_enums = 0;
+  else if (!strcmp (p, "-fcond-mismatch"))
+    flag_cond_mismatch = 1;
+  else if (!strcmp (p, "-fno-cond-mismatch"))
+    flag_cond_mismatch = 0;
+  else if (!strcmp (p, "-fshort-double"))
+    flag_short_double = 1;
+  else if (!strcmp (p, "-fno-short-double"))
+    flag_short_double = 0;
+  else if (!strcmp (p, "-fasm"))
+    flag_no_asm = 0;
+  else if (!strcmp (p, "-fno-asm"))
+    flag_no_asm = 1;
+  else if (!strcmp (p, "-fbuiltin"))
+    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_builtin = 1, dollars_in_ident = 0;
+  else if (!strcmp (p, "-Wimplicit"))
+    warn_implicit = 1;
+  else if (!strcmp (p, "-Wno-implicit"))
+    warn_implicit = 0;
+  else if (!strcmp (p, "-Wwrite-strings"))
+    warn_write_strings = 1;
+  else if (!strcmp (p, "-Wno-write-strings"))
+    warn_write_strings = 0;
+  else if (!strcmp (p, "-Wcast-qual"))
+    warn_cast_qual = 1;
+  else if (!strcmp (p, "-Wno-cast-qual"))
+    warn_cast_qual = 0;
+  else if (!strcmp (p, "-Wpointer-arith"))
+    warn_pointer_arith = 1;
+  else if (!strcmp (p, "-Wno-pointer-arith"))
+    warn_pointer_arith = 0;
+  else if (!strcmp (p, "-Wstrict-prototypes"))
+    warn_strict_prototypes = 1;
+  else if (!strcmp (p, "-Wno-strict-prototypes"))
+    warn_strict_prototypes = 0;
+  else if (!strcmp (p, "-Wmissing-prototypes"))
+    warn_missing_prototypes = 1;
+  else if (!strcmp (p, "-Wno-missing-prototypes"))
+    warn_missing_prototypes = 0;
+  else if (!strcmp (p, "-Wredundant-decls"))
+    warn_redundant_decls = 1;
+  else if (!strcmp (p, "-Wnoredundant-decls"))
+    warn_redundant_decls = 0;
+  else if (!strcmp (p, "-Wnested-externs"))
+    warn_nested_externs = 1;
+  else if (!strcmp (p, "-Wno-nested-externs"))
+    warn_nested_externs = 0;
+  else if (!strcmp (p, "-Wtraditional"))
+    warn_traditional = 1;
+  else if (!strcmp (p, "-Wno-traditional"))
+    warn_traditional = 0;
+  else if (!strcmp (p, "-Wformat"))
+    warn_format = 1;
+  else if (!strcmp (p, "-Wno-format"))
+    warn_format = 0;
+  else if (!strcmp (p, "-Wchar-subscripts"))
+    warn_char_subscripts = 1;
+  else if (!strcmp (p, "-Wno-char-subscripts"))
+    warn_char_subscripts = 0;
+  else if (!strcmp (p, "-Wconversion"))
+    warn_conversion = 1;
+  else if (!strcmp (p, "-Wno-conversion"))
+    warn_conversion = 0;
+  else if (!strcmp (p, "-Wparentheses"))
+    warn_parentheses = 1;
+  else if (!strcmp (p, "-Wno-parentheses"))
+    warn_parentheses = 0;
+  else if (!strcmp (p, "-Wcomment"))
+    ; /* cpp handles this one.  */
+  else if (!strcmp (p, "-Wno-comment"))
+    ; /* cpp handles this one.  */
+  else if (!strcmp (p, "-Wcomments"))
+    ; /* cpp handles this one.  */
+  else if (!strcmp (p, "-Wno-comments"))
+    ; /* cpp handles this one.  */
+  else if (!strcmp (p, "-Wtrigraphs"))
+    ; /* cpp handles this one.  */
+  else if (!strcmp (p, "-Wno-trigraphs"))
+    ; /* cpp handles this one.  */
+  else if (!strcmp (p, "-Wall"))
+    {
+      extra_warnings = 1;
+      warn_uninitialized = 1;
+      warn_implicit = 1;
+      warn_return_type = 1;
+      warn_unused = 1;
+      warn_switch = 1;
+      warn_format = 1;
+      warn_char_subscripts = 1;
+    }
+  else
+    return 0;
+
+  return 1;
+}
+
+/* Hooks for print_node.  */
+
+void
+print_lang_decl ()
+{
+}
+
+void
+print_lang_type ()
+{
+}
+
+void
+print_lang_identifier (file, node, indent)
+     FILE *file;
+     tree node;
+     int indent;
+{
+  print_node (file, "global", IDENTIFIER_GLOBAL_VALUE (node), indent + 4);
+  print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4);
+  print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4);
+  print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4);
+  print_node (file, "error locus", IDENTIFIER_ERROR_LOCUS (node), indent + 4);
+}
+\f
+/* Create a new `struct binding_level'.  */
+
+static
+struct binding_level *
+make_binding_level ()
+{
+  /* NOSTRICT */
+  return (struct binding_level *) xmalloc (sizeof (struct binding_level));
+}
+
+/* Nonzero if we are currently in the global binding level.  */
+
+int
+global_bindings_p ()
+{
+  return current_binding_level == global_binding_level;
+}
+
+void
+keep_next_level ()
+{
+  keep_next_level_flag = 1;
+}
+
+/* Nonzero if the current level needs to have a BLOCK made.  */
+
+int
+kept_level_p ()
+{
+  return ((current_binding_level->keep_if_subblocks
+          && current_binding_level->blocks != 0)
+         || current_binding_level->keep
+         || current_binding_level->names != 0
+         || (current_binding_level->tags != 0
+             && !current_binding_level->tag_transparent));
+}
+
+/* Identify this binding level as a level of parameters.
+   DEFINITION_FLAG is 1 for a definition, 0 for a declaration.  */
+
+void
+declare_parm_level (definition_flag)
+     int definition_flag;
+{
+  current_binding_level->parm_flag = 1 + definition_flag;
+}
+
+/* Nonzero if currently making parm declarations.  */
+
+int
+in_parm_level_p ()
+{
+  return current_binding_level->parm_flag;
+}
+
+/* Enter a new binding level.
+   If TAG_TRANSPARENT is nonzero, do so only for the name space of variables,
+   not for that of tags.  */
+
+void
+pushlevel (tag_transparent)
+     int tag_transparent;
+{
+  register struct binding_level *newlevel = NULL_BINDING_LEVEL;
+
+  /* If this is the top level of a function,
+     just make sure that NAMED_LABELS is 0.  */
+
+  if (current_binding_level == global_binding_level)
+    {
+      named_labels = 0;
+    }
+
+  /* Reuse or create a struct for this binding level.  */
+
+  if (free_binding_level)
+    {
+      newlevel = free_binding_level;
+      free_binding_level = free_binding_level->level_chain;
+    }
+  else
+    {
+      newlevel = make_binding_level ();
+    }
+
+  /* Add this level to the front of the chain (stack) of levels that
+     are active.  */
+
+  *newlevel = clear_binding_level;
+  newlevel->tag_transparent
+    = (tag_transparent
+       || (current_binding_level
+          ? current_binding_level->subblocks_tag_transparent
+          : 0));
+  newlevel->level_chain = current_binding_level;
+  current_binding_level = newlevel;
+  newlevel->keep = keep_next_level_flag;
+  keep_next_level_flag = 0;
+  newlevel->keep_if_subblocks = keep_next_if_subblocks;
+  keep_next_if_subblocks = 0;
+}
+
+/* Exit a binding level.
+   Pop the level off, and restore the state of the identifier-decl mappings
+   that were in effect when this level was entered.
+
+   If KEEP is nonzero, this level had explicit declarations, so
+   and create a "block" (a BLOCK node) for the level
+   to record its declarations and subblocks for symbol table output.
+
+   If FUNCTIONBODY is nonzero, this level is the body of a function,
+   so create a block as if KEEP were set and also clear out all
+   label names.
+
+   If REVERSE is nonzero, reverse the order of decls before putting
+   them into the BLOCK.  */
+
+tree
+poplevel (keep, reverse, functionbody)
+     int keep;
+     int reverse;
+     int functionbody;
+{
+  register tree link;
+  /* The chain of decls was accumulated in reverse order.
+     Put it into forward order, just for cleanliness.  */
+  tree decls;
+  tree tags = current_binding_level->tags;
+  tree subblocks = current_binding_level->blocks;
+  tree block = 0;
+  tree decl;
+
+  keep |= current_binding_level->keep;
+
+  /* This warning is turned off because it causes warnings for
+     declarations like `extern struct foo *x'.  */
+#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)
+      {
+       tree type = TREE_VALUE (link);
+       char *errmsg;
+       switch (TREE_CODE (type))
+         {
+         case RECORD_TYPE:
+           errmsg = "`struct %s' incomplete in scope ending here";
+           break;
+         case UNION_TYPE:
+           errmsg = "`union %s' incomplete in scope ending here";
+           break;
+         case ENUMERAL_TYPE:
+           errmsg = "`enum %s' incomplete in scope ending here";
+           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 */
+
+  /* Get the decls in the order they were written.
+     Usually current_binding_level->names is in reverse order.
+     But parameter decls were previously put in forward order.  */
+
+  if (reverse)
+    current_binding_level->names
+      = decls = nreverse (current_binding_level->names);
+  else
+    decls = current_binding_level->names;
+
+  /* Output any nested inline functions within this block
+     if they weren't already output.  */
+
+  for (decl = decls; decl; decl = TREE_CHAIN (decl))
+    if (TREE_CODE (decl) == FUNCTION_DECL
+       && ! TREE_ASM_WRITTEN (decl)
+       && DECL_INITIAL (decl) != 0
+       && TREE_ADDRESSABLE (decl))
+      output_inline_function (decl);
+
+  /* If there were any declarations or structure tags in that level,
+     or if this level is a function body,
+     create a BLOCK to record them for the life of this function.  */
+
+  if (keep || functionbody
+      || (current_binding_level->keep_if_subblocks && subblocks != 0))
+    block = build_block (keep ? decls : 0, keep ? tags : 0,
+                        subblocks, 0, 0);
+
+  /* In each subblock, record that this is its superior.  */
+
+  for (link = subblocks; link; link = TREE_CHAIN (link))
+    BLOCK_SUPERCONTEXT (link) = block;
+
+  /* Clear out the meanings of the local variables of this level.  */
+
+  for (link = decls; link; link = TREE_CHAIN (link))
+    {
+      if (DECL_NAME (link) != 0)
+       {
+         /* If the ident. was used or addressed via a local extern decl,
+            don't forget that fact.  */
+         if (TREE_EXTERNAL (link))
+           {
+             if (TREE_USED (link))
+               TREE_USED (DECL_NAME (link)) = 1;
+             if (TREE_ADDRESSABLE (link))
+               TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
+           }
+         IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0;
+       }
+    }
+
+  /* Restore all name-meanings of the outer levels
+     that were shadowed by this level.  */
+
+  for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
+    IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+
+  /* If the level being exited is the top level of a function,
+     check over all the labels, and clear out the current
+     (function local) meanings of their names.  */
+
+  if (functionbody)
+    {
+      /* If this is the top level block of a function,
+        the vars are the function's parameters.
+        Don't leave them in the BLOCK because they are
+        found in the FUNCTION_DECL instead.  */
+
+      BLOCK_VARS (block) = 0;
+
+      /* Clear out the definitions of all label names,
+        since their scopes end here,
+        and add them to BLOCK_VARS.  */
+
+      for (link = named_labels; link; link = TREE_CHAIN (link))
+       {
+         register tree label = TREE_VALUE (link);
+
+         if (DECL_INITIAL (label) == 0)
+           {
+             error_with_decl (label, "label `%s' used but not defined");
+             /* Avoid crashing later.  */
+             define_label (input_filename, lineno,
+                           DECL_NAME (label));
+           }
+         else if (warn_unused && !TREE_USED (label))
+           warning_with_decl (label, "label `%s' defined but not used");
+         IDENTIFIER_LABEL_VALUE (DECL_NAME (label)) = 0;
+
+         /* Put the labels into the "variables" of the
+            top-level block, so debugger can see them.  */
+         TREE_CHAIN (label) = BLOCK_VARS (block);
+         BLOCK_VARS (block) = label;
+       }
+    }
+
+  /* Pop the current level, and free the structure for reuse.  */
+
+  {
+    register struct binding_level *level = current_binding_level;
+    current_binding_level = current_binding_level->level_chain;
+
+    level->level_chain = free_binding_level;
+    free_binding_level = level;
+  }
+
+  /* Dispose of the block that we just made inside some higher level.  */
+  if (functionbody)
+    DECL_INITIAL (current_function_decl) = block;
+  else if (block)
+    current_binding_level->blocks
+      = chainon (current_binding_level->blocks, block);
+  /* If we did not make a block for the level just exited,
+     any blocks made for inner levels
+     (since they cannot be recorded as subblocks in that level)
+     must be carried forward so they will later become subblocks
+     of something else.  */
+  else if (subblocks)
+    current_binding_level->blocks
+      = chainon (current_binding_level->blocks, subblocks);
+
+  /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this
+     binding contour so that they point to the appropriate construct, i.e.
+     either to the current FUNCTION_DECL node, or else to the BLOCK node
+     we just constructed.
+
+     Note that for tagged types whose scope is just the formal parameter
+     list for some function type specification, we can't properly set
+     their TYPE_CONTEXTs here, because we don't have a pointer to the
+     appropriate FUNCTION_TYPE node readily available to us.  For those
+     cases, the TYPE_CONTEXTs of the relevant tagged type nodes get set
+     in `grokdeclarator' as soon as we have created the FUNCTION_TYPE
+     node which will represent the "scope" for these "parameter list local"
+     tagged types.
+  */
+
+  if (functionbody)
+    for (link = tags; link; link = TREE_CHAIN (link))
+      TYPE_CONTEXT (TREE_VALUE (link)) = current_function_decl;
+  else if (block)
+    for (link = tags; link; link = TREE_CHAIN (link))
+      TYPE_CONTEXT (TREE_VALUE (link)) = block;
+
+  if (block)
+    TREE_USED (block) = 1;
+  return block;
+}
+\f
+void
+push_label_level ()
+{
+  register struct binding_level *newlevel;
+
+  /* Reuse or create a struct for this binding level.  */
+
+  if (free_binding_level)
+    {
+      newlevel = free_binding_level;
+      free_binding_level = free_binding_level->level_chain;
+    }
+  else
+    {
+      newlevel = make_binding_level ();
+    }
+
+  /* Add this level to the front of the chain (stack) of label levels.  */
+
+  newlevel->level_chain = label_level_chain;
+  label_level_chain = newlevel;
+
+  newlevel->names = named_labels;
+  newlevel->shadowed = shadowed_labels;
+  named_labels = 0;
+  shadowed_labels = 0;
+}
+
+void
+pop_label_level ()
+{
+  register struct binding_level *level = label_level_chain;
+  tree link, prev;
+
+  /* Clear out the definitions of the declared labels in this level.
+     Leave in the list any ordinary, non-declared labels.  */
+  for (link = named_labels, prev = 0; link;)
+    {
+      if (C_DECLARED_LABEL_FLAG (TREE_VALUE (link)))
+       {
+         if (DECL_SOURCE_LINE (TREE_VALUE (link)) == 0)
+           {
+             error_with_decl ("label `%s' used but not defined",
+                              TREE_VALUE (link));
+             /* Avoid crashing later.  */
+             define_label (input_filename, lineno,
+                           DECL_NAME (TREE_VALUE (link)));
+           }
+         else if (warn_unused && !TREE_USED (TREE_VALUE (link)))
+           warning_with_decl (TREE_VALUE (link), 
+                              "label `%s' defined but not used");
+         IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) = 0;
+
+         /* Delete this element from the list.  */
+         link = TREE_CHAIN (link);
+         if (prev)
+           TREE_CHAIN (prev) = link;
+         else
+           named_labels = link;
+       }
+      else
+       {
+         prev = link;
+         link = TREE_CHAIN (link);
+       }
+    }
+
+  /* Bring back all the labels that were shadowed.  */
+  for (link = shadowed_labels; link; link = TREE_CHAIN (link))
+    if (DECL_NAME (TREE_VALUE (link)) != 0)
+      IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)))
+       = TREE_VALUE (link);
+
+  named_labels = chainon (named_labels, level->names);
+  shadowed_labels = level->shadowed;
+
+  /* Pop the current level, and free the structure for reuse.  */
+  label_level_chain = label_level_chain->level_chain;
+  level->level_chain = free_binding_level;
+  free_binding_level = level;
+}
+\f
+/* Push a definition or a declaration of struct, union or enum tag "name".
+   "type" should be the type node.
+   We assume that the tag "name" is not already defined.
+
+   Note that the definition may really be just a forward reference.
+   In that case, the TYPE_SIZE will be zero.  */
+
+void
+pushtag (name, type)
+     tree name, type;
+{
+  register struct binding_level *b;
+
+  /* Find the proper binding level for this type tag.  */
+
+  for (b = current_binding_level; b->tag_transparent; b = b->level_chain)
+    continue;
+
+  if (name)
+    {
+      /* Record the identifier as the type's name if it has none.  */
+
+      if (TYPE_NAME (type) == 0)
+       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);
+    }
+
+  /* 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
+     NULL-named TYPE_DECL node helps dwarfout.c to know when it needs
+     to output a a representation of a tagged type, and it also gives
+     us a convenient place to record the "scope start" address for the
+     tagged type.  */
+
+  TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL, type));
+}
+\f
+/* Handle when a new declaration NEWDECL
+   has the same name as an old one OLDDECL
+   in the same binding contour.
+   Prints an error message if appropriate.
+
+   If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
+   Otherwise, return 0.  */
+
+static int
+duplicate_decls (newdecl, olddecl)
+     register tree newdecl, olddecl;
+{
+  int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
+  int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
+                          && DECL_INITIAL (newdecl) != 0);
+
+  if (TREE_CODE (TREE_TYPE (newdecl)) == ERROR_MARK
+      || TREE_CODE (TREE_TYPE (olddecl)) == ERROR_MARK)
+    types_match = 0;
+
+  /* New decl is completely inconsistent with the old one =>
+     tell caller to replace the old one.
+     This is always an error except in the case of shadowing a builtin.  */
+  if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
+    {
+      if (TREE_CODE (olddecl) == FUNCTION_DECL
+         && DECL_BUILT_IN (olddecl))
+       {
+         /* If you declare a built-in function name as static, the
+            built-in definition is overridden,
+            but optionally warn this was a bad choice of name.  */
+         if (!TREE_PUBLIC (newdecl))
+           {
+             if (warn_shadow)
+               warning_with_decl (newdecl, "shadowing built-in function `%s'");
+           }
+         /* Likewise, if the built-in is not ansi, then programs can
+            overide it even globally without an error.  */
+         else if (DECL_BUILT_IN_NONANSI (olddecl))
+           warning_with_decl (newdecl,
+                              "built-in function `%s' declared as non-function");
+         else
+           error_with_decl (newdecl,
+                            "built-in function `%s' declared as non-function");
+       }
+      else if (TREE_CODE (olddecl) == FUNCTION_DECL
+              && DECL_BUILT_IN_NONANSI (olddecl))
+       {
+         /* If overriding decl is static,
+            optionally warn this was a bad choice of name.  */
+         if (!TREE_PUBLIC (newdecl))
+           {
+             if (warn_shadow)
+               warning_with_decl (newdecl, "shadowing library function `%s'");
+           }
+         /* Otherwise, always warn.  */
+         else
+           warning_with_decl (newdecl,
+                              "library function `%s' declared as non-function");
+       }
+      else
+       {
+         error_with_decl (newdecl, "`%s' redeclared as different kind of symbol");
+         error_with_decl (olddecl, "previous declaration of `%s'");
+       }
+
+      return 0;
+    }
+
+  /* For real parm decl following a forward decl,
+     return 1 so old decl will be reused.  */
+  if (types_match && TREE_CODE (newdecl) == PARM_DECL
+      && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl))
+    return 1;
+
+  /* The new declaration is the same kind of object as the old one.
+     The declarations may partially match.  Print warnings if they don't
+     match enough.  Ultimately, copy most of the information from the new
+     decl to the old one, and keep using the old one.  */
+
+  if (flag_traditional && TREE_CODE (newdecl) == FUNCTION_DECL
+      && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (newdecl)) == olddecl
+      && DECL_INITIAL (olddecl) == 0)
+    /* If -traditional, avoid error for redeclaring fcn
+       after implicit decl.  */
+    ;
+  else if (TREE_CODE (olddecl) == FUNCTION_DECL
+          && DECL_BUILT_IN (olddecl))
+    {
+      if (!TREE_PUBLIC (newdecl))
+       {
+         /* If you declare a built-in function name as static, the
+            built-in definition is overridden,
+            but optionally warn this was a bad choice of name.  */
+         if (warn_shadow)
+           warning_with_decl (newdecl, "shadowing built-in function `%s'");
+         /* Discard the old built-in function.  */
+         return 0;
+       }
+      else if (!types_match)
+       warning_with_decl (newdecl, "conflicting types for built-in function `%s'");
+    }
+  else if (TREE_CODE (olddecl) == FUNCTION_DECL
+          && DECL_BUILT_IN_NONANSI (olddecl))
+    {
+      if (!TREE_PUBLIC (newdecl))
+       {
+         /* If you declare a built-in function name as static, the
+            built-in definition is overridden,
+            but optionally warn this was a bad choice of name.  */
+         if (warn_shadow)
+           warning_with_decl (newdecl, "shadowing library function `%s'");
+         /* Discard the old built-in function.  */
+         return 0;
+       }
+      else if (!types_match)
+       warning_with_decl (newdecl, "conflicting types for library function `%s'");
+    }
+  else if (!types_match
+          /* Permit char *foo (int, ...); followed by char *foo ();
+             if not pedantic.  */
+          && ! (TREE_CODE (olddecl) == FUNCTION_DECL
+                && ! pedantic
+                /* Return types must still match.  */
+                && comptypes (TREE_TYPE (TREE_TYPE (olddecl)),
+                              TREE_TYPE (TREE_TYPE (newdecl)))
+                && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) == 0))
+    {
+      error_with_decl (newdecl, "conflicting types for `%s'");
+      /* Check for function type mismatch
+        involving an empty arglist vs a nonempty one.  */
+      if (TREE_CODE (olddecl) == FUNCTION_DECL
+         && comptypes (TREE_TYPE (TREE_TYPE (olddecl)),
+                       TREE_TYPE (TREE_TYPE (newdecl)))
+         && ((TYPE_ARG_TYPES (TREE_TYPE (olddecl)) == 0
+              && DECL_INITIAL (olddecl) == 0)
+             ||
+             (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) == 0
+              && DECL_INITIAL (newdecl) == 0)))
+       {
+         /* Classify the problem further.  */
+         register tree t = TYPE_ARG_TYPES (TREE_TYPE (olddecl));
+         if (t == 0)
+           t = TYPE_ARG_TYPES (TREE_TYPE (newdecl));
+         for (; t; t = TREE_CHAIN (t))
+           {
+             register tree type = TREE_VALUE (t);
+
+             if (TREE_CHAIN (t) == 0 && type != void_type_node)
+               {
+                 error ("A parameter list with an ellipsis can't match");
+                 error ("an empty parameter name list declaration.");
+                 break;
+               }
+
+             if (type == float_type_node
+                 || (TREE_CODE (type) == INTEGER_TYPE
+                     && (TYPE_PRECISION (type)
+                         < TYPE_PRECISION (integer_type_node))))
+               {
+                 error ("An argument type that has a default promotion");
+                 error ("can't match an empty parameter name list declaration.");
+                 break;
+               }
+           }
+       }
+      error_with_decl (olddecl, "previous declaration of `%s'");
+    }
+  else
+    {
+      char *errmsg = redeclaration_error_message (newdecl, olddecl);
+      if (errmsg)
+       {
+         error_with_decl (newdecl, errmsg);
+         error_with_decl (olddecl,
+                          "`%s' previously declared here");
+       }
+      else if (TREE_CODE (olddecl) == FUNCTION_DECL
+              && DECL_INITIAL (olddecl) != 0
+              && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) == 0
+              && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0)
+       {
+         register tree type, parm;
+         register int nargs;
+         /* Prototype decl follows defn w/o prototype.  */
+
+         for (parm = TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (olddecl)),
+              type = TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
+              nargs = 1;
+              (TREE_VALUE (parm) != void_type_node
+               || TREE_VALUE (type) != void_type_node);
+              parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++)
+           {
+             if (TREE_VALUE (parm) == void_type_node
+                 || TREE_VALUE (type) == void_type_node)
+               {
+                 errmsg = "prototype for `%s' follows and number of arguments";
+                 break;
+               }
+             /* Type for passing arg must be consistent
+                with that declared for the arg.  */
+             if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type))
+                 /* If -traditional, allow `unsigned int' instead of `int'
+                    in the prototype.  */
+                 && (! (flag_traditional
+                        && TREE_VALUE (parm) == integer_type_node
+                        && TREE_VALUE (type) == unsigned_type_node)))
+               {
+                 errmsg = "prototype for `%s' follows and argument %d";
+                 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 if function is now inline
+        but was previously declared not inline and has been called.  */
+      else
+       {
+         if (TREE_CODE (olddecl) == FUNCTION_DECL
+             && ! TREE_INLINE (olddecl) && TREE_INLINE (newdecl)
+             && TREE_USED (olddecl))
+           warning_with_decl (newdecl,
+                              "`%s' declared inline after being called");
+         if (TREE_CODE (olddecl) == FUNCTION_DECL
+             && TREE_INLINE (olddecl) != TREE_INLINE (newdecl))
+           warning_with_decl (newdecl,
+                              "`%s' declarations disagree about `inline'");
+         /* It is nice to warn when a function is declared
+            global first and then static.  */
+         if (TREE_CODE (olddecl) == FUNCTION_DECL
+             && TREE_PUBLIC (olddecl)
+             && !TREE_PUBLIC (newdecl))
+           warning_with_decl (newdecl, "static declaration for `%s' follows non-static");
+
+         /* These bits are logically part of the type.  */
+         if (pedantic
+             && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
+                 || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl)))
+           pedwarn_with_decl (newdecl, "type qualifiers for `%s' conflict with previous decl");
+       }
+    }
+
+  /* Copy all the DECL_... slots specified in the new decl
+     except for any that we copy here from the old type.  */
+
+  if (types_match)
+    {
+      tree oldtype = TREE_TYPE (olddecl);
+      /* Merge the data types specified in the two decls.  */
+      if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
+       TREE_TYPE (newdecl)
+         = TREE_TYPE (olddecl)
+           = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
+
+      /* Lay the type out, unless already done.  */
+      if (oldtype != TREE_TYPE (newdecl))
+       {
+         if (TREE_TYPE (newdecl) != error_mark_node)
+           layout_type (TREE_TYPE (newdecl));
+         if (TREE_CODE (newdecl) != FUNCTION_DECL
+             && TREE_CODE (newdecl) != TYPE_DECL
+             && TREE_CODE (newdecl) != CONST_DECL)
+           layout_decl (newdecl, 0);
+       }
+      else
+       {
+         /* Since the type is OLDDECL's, make OLDDECL's size go with.  */
+         DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
+         if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
+           DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
+       }
+
+      /* Merge the type qualifiers.  */
+      if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl)
+         && !TREE_THIS_VOLATILE (newdecl))
+       TREE_THIS_VOLATILE (olddecl) = 0;
+      if (TREE_READONLY (newdecl))
+       TREE_READONLY (olddecl) = 1;
+      if (TREE_THIS_VOLATILE (newdecl))
+       TREE_THIS_VOLATILE (olddecl) = 1;
+
+      /* Keep source location of definition rather than declaration.  */
+      if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+       {
+         DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
+         DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
+       }
+
+      /* Merge the initialization information.  */
+      if (DECL_INITIAL (newdecl) == 0)
+       DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+      /* Keep the old rtl since we can safely use it.  */
+      DECL_RTL (newdecl) = DECL_RTL (olddecl);
+    }
+  /* If cannot merge, then use the new type and qualifiers,
+     and don't preserve the old rtl.  */
+  else
+    {
+      TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
+      TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
+      TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl);
+      TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl);
+    }
+
+  /* Merge the storage class information.  */
+  /* For functions, static overrides non-static.  */
+  if (TREE_CODE (newdecl) == FUNCTION_DECL)
+    {
+      TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
+      /* This is since we don't automatically
+        copy the attributes of NEWDECL into OLDDECL.  */
+      TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+      /* If this clears `static', clear it in the identifier too.  */
+      if (! TREE_PUBLIC (olddecl))
+       TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
+    }
+  if (TREE_EXTERNAL (newdecl))
+    {
+      TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
+      TREE_EXTERNAL (newdecl) = TREE_EXTERNAL (olddecl);
+      /* An extern decl does not override previous storage class.  */
+      TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
+    }
+  else
+    {
+      TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
+      TREE_EXTERNAL (olddecl) = 0;
+      TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+    }
+  /* If either decl says `inline', this fn is inline,
+     unless its definition was passed already.  */
+  if (TREE_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0)
+    TREE_INLINE (olddecl) = 1;
+
+  /* Get rid of any built-in function if new arg types don't match it
+     or if we have a function definition.  */
+  if (TREE_CODE (newdecl) == FUNCTION_DECL
+      && DECL_BUILT_IN (olddecl)
+      && (!types_match || new_is_definition))
+    {
+      TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
+      DECL_BUILT_IN (olddecl) = 0;
+    }
+
+  /* If redeclaring a builtin function, and not a definition,
+     it stays built in.
+     Also preserve various other info from the definition.  */
+  if (TREE_CODE (newdecl) == FUNCTION_DECL && !new_is_definition)
+    {
+      if (DECL_BUILT_IN (olddecl))
+       {
+         DECL_BUILT_IN (newdecl) = 1;
+         DECL_SET_FUNCTION_CODE (newdecl, DECL_FUNCTION_CODE (olddecl));
+       }
+      else
+       DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl);
+
+      DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
+      DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+      DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
+      DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+    }
+
+  bcopy ((char *) newdecl + sizeof (struct tree_common),
+        (char *) olddecl + sizeof (struct tree_common),
+        sizeof (struct tree_decl) - sizeof (struct tree_common));
+
+  return 1;
+}
+
+/* Record a decl-node X as belonging to the current lexical scope.
+   Check for errors (such as an incompatible declaration for the same
+   name already seen in the same scope).
+
+   Returns either X or an old decl for the same name.
+   If an old decl is returned, it may have been smashed
+   to agree with what X says.  */
+
+tree
+pushdecl (x)
+     tree x;
+{
+  register tree t;
+  register tree name = DECL_NAME (x);
+  register struct binding_level *b = current_binding_level;
+
+  DECL_CONTEXT (x) = current_function_decl;
+  /* A local declaration for a function doesn't constitute nesting.  */
+  if (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0)
+    DECL_CONTEXT (x) = 0;
+
+  if (warn_nested_externs && TREE_EXTERNAL (x) && b != global_binding_level
+      && x != IDENTIFIER_IMPLICIT_DECL (name))
+    warning ("nested extern declaration of `%s'", IDENTIFIER_POINTER (name));
+
+  if (name)
+    {
+      char *file;
+      int line;
+
+      t = lookup_name_current_level (name);
+      if (t != 0 && t == error_mark_node)
+       /* error_mark_node is 0 for a while during initialization!  */
+       {
+         t = 0;
+         error_with_decl (x, "`%s' used prior to declaration");
+       }
+
+      if (t != 0)
+       {
+         file = DECL_SOURCE_FILE (t);
+         line = DECL_SOURCE_LINE (t);
+       }
+
+      if (t != 0 && duplicate_decls (x, t))
+       {
+         if (TREE_CODE (t) == PARM_DECL)
+           {
+             /* Don't allow more than one "real" duplicate
+                of a forward parm decl.  */
+             TREE_ASM_WRITTEN (t) = TREE_ASM_WRITTEN (x);
+             return t;
+           }
+         /* If this decl is `static' and an implicit decl was seen previously,
+            warn.  But don't complain if -traditional,
+            since traditional compilers don't complain.  */
+         if (!flag_traditional && TREE_PUBLIC (name)
+             && ! TREE_PUBLIC (x) && ! TREE_EXTERNAL (x)
+             /* We used to warn also for explicit extern followed by static,
+                but sometimes you need to do it that way.  */
+             && IDENTIFIER_IMPLICIT_DECL (name) != 0)
+           {
+             pedwarn ("`%s' was declared implicitly `extern' and later `static'",
+                      IDENTIFIER_POINTER (name));
+             pedwarn_with_file_and_line (file, line,
+                                         "previous declaration of `%s'",
+                                         IDENTIFIER_POINTER (name));
+           }
+         if (warn_redundant_decls && line != 0)
+           {
+             warning ("redundant redeclaration of `%s' in same scope",
+                      IDENTIFIER_POINTER (name));
+             warning_with_file_and_line (file, line,
+                                         "previous declaration of `%s'",
+                                         IDENTIFIER_POINTER (name));
+           }
+         return t;
+       }
+
+      /* If declaring a type as a typedef, and the type has no known
+        typedef name, install this TYPE_DECL as its typedef name.  If
+         generating prototypes, *don't* assign the current name to the
+         existing type node, but rather give the name its own associated
+         type node.  This new type node is created as a type variant of
+         the existing type node, but it is essentially identical to the
+         existing one.  Obviously, we don't generate these type variants
+         if the node that we are working on is a standard type and it has
+         not yet been assigned a name.  In that case we must allow the
+         standard type to given its standard name (by the compiler).
+         Since all standard types are effectively declared at line zero
+         in the source file, we can easily check to see if we are working
+         on a standard type by checking the current value of lineno.  */
+
+      if (TREE_CODE (x) == TYPE_DECL)
+        {
+          if (DECL_SOURCE_LINE (x) == 0 || !flag_gen_aux_info)
+            {
+             if (TYPE_NAME (TREE_TYPE (x)) == 0)
+               TYPE_NAME (TREE_TYPE (x)) = x;
+            }
+          else
+            {
+              tree tt = TREE_TYPE (x);
+
+              tt = c_build_type_variant (tt,
+                                        TYPE_READONLY (tt), TYPE_VOLATILE (tt));
+              TYPE_NAME (tt) = x;
+              TREE_TYPE (x) = tt;
+            }
+        }
+
+      /* Multiple external decls of the same identifier ought to match.  */
+
+      if (TREE_EXTERNAL (x) && IDENTIFIER_GLOBAL_VALUE (name) != 0
+         && (TREE_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name))
+             || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name)))
+         /* We get warnings about inline functions where they are defined.
+            Avoid duplicate warnings where they are used.  */
+         && !TREE_INLINE (x))
+       {
+         if (! comptypes (TREE_TYPE (x),
+                          TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name))))
+           {
+             pedwarn_with_decl (x,
+                                "type mismatch with previous external decl");
+             pedwarn_with_decl (IDENTIFIER_GLOBAL_VALUE (name),
+                                "previous external decl of `%s'");
+           }
+       }
+
+      /* If a function has had an implicit declaration, and then is defined,
+        make sure they are compatible.  */
+
+      if (IDENTIFIER_IMPLICIT_DECL (name) != 0
+         && IDENTIFIER_GLOBAL_VALUE (name) == 0
+         && TREE_CODE (x) == FUNCTION_DECL
+         && ! comptypes (TREE_TYPE (x),
+                         TREE_TYPE (IDENTIFIER_IMPLICIT_DECL (name))))
+       {
+         warning_with_decl (x, "type mismatch with previous implicit declaration");
+         warning_with_decl (x, "previous implicit declaration of `%s'");
+       }
+
+      /* In PCC-compatibility mode, extern decls of vars with no current decl
+        take effect at top level no matter where they are.  */
+      if (flag_traditional && TREE_EXTERNAL (x)
+         && lookup_name (name) == 0)
+       {
+         tree type = TREE_TYPE (x);
+
+         /* But don't do this if the type contains temporary nodes.  */
+         while (type)
+           {
+             if (type == error_mark_node)
+               break;
+             if (! TREE_PERMANENT (type))
+               {
+                 warning_with_decl (x, "type of external `%s' is not global");
+                 /* By exiting the loop early, we leave TYPE nonzero,
+                    and thus prevent globalization of the decl.  */
+                 break;
+               }
+             else if (TREE_CODE (type) == FUNCTION_TYPE
+                      && TYPE_ARG_TYPES (type) != 0)
+               /* The types might not be truly local,
+                  but the list of arg types certainly is temporary.
+                  Since prototypes are nontraditional,
+                  ok not to do the traditional thing.  */
+               break;
+             type = TREE_TYPE (type);
+           }
+
+         if (type == 0)
+           b = global_binding_level;
+       }
+
+      /* This name is new in its binding level.
+        Install the new declaration and return it.  */
+      if (b == global_binding_level)
+       {
+         /* Install a global value.  */
+         
+         /* If the first global decl has external linkage,
+            warn if we later see static one.  */
+         if (IDENTIFIER_GLOBAL_VALUE (name) == 0 && TREE_PUBLIC (x))
+           TREE_PUBLIC (name) = 1;
+
+         IDENTIFIER_GLOBAL_VALUE (name) = x;
+
+         /* Don't forget if the function was used via an implicit decl.  */
+         if (IDENTIFIER_IMPLICIT_DECL (name)
+             && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name)))
+           TREE_USED (x) = 1, TREE_USED (name) = 1;
+
+         /* Don't forget if its address was taken in that way.  */
+         if (IDENTIFIER_IMPLICIT_DECL (name)
+             && TREE_ADDRESSABLE (IDENTIFIER_IMPLICIT_DECL (name)))
+           TREE_ADDRESSABLE (x) = 1;
+
+         /* Warn about mismatches against previous implicit decl.  */
+         if (IDENTIFIER_IMPLICIT_DECL (name) != 0
+             /* If this real decl matches the implicit, don't complain.  */
+             && ! (TREE_CODE (x) == FUNCTION_DECL
+                   && TREE_TYPE (TREE_TYPE (x)) == integer_type_node))
+           pedwarn ("`%s' was previously implicitly declared to return `int'",
+                    IDENTIFIER_POINTER (name));
+
+         /* If this decl is `static' and an `extern' was seen previously,
+            that is erroneous.  */
+         if (TREE_PUBLIC (name)
+             && ! TREE_PUBLIC (x) && ! TREE_EXTERNAL (x))
+           {
+             if (IDENTIFIER_IMPLICIT_DECL (name))
+               pedwarn ("`%s' was declared implicitly `extern' and later `static'",
+                        IDENTIFIER_POINTER (name));
+             else
+               pedwarn ("`%s' was declared `extern' and later `static'",
+                        IDENTIFIER_POINTER (name));
+           }
+       }
+      else
+       {
+         /* 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 for the function.  */
+         if (oldlocal == 0
+             && TREE_EXTERNAL (x) && !TREE_INLINE (x)
+             && oldglobal != 0
+             && TREE_CODE (x) == FUNCTION_DECL
+             && TREE_CODE (oldglobal) == FUNCTION_DECL)
+           {
+             /* We have one.  Their types must agree.  */
+             if (! comptypes (TREE_TYPE (x),
+                              TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name))))
+               pedwarn_with_decl (x, "local declaration of `%s' doesn't match global one");
+             /* If the global one is inline, make the local one inline.  */
+             else if (TREE_INLINE (oldglobal)
+                      || DECL_BUILT_IN (oldglobal)
+                      || (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != 0
+                          && TYPE_ARG_TYPES (TREE_TYPE (x)) == 0))
+               IDENTIFIER_LOCAL_VALUE (name) = oldglobal;
+           }
+
+#if 0 /* This case is probably sometimes the right thing to do.  */
+         /* If we have a local external declaration,
+            then any file-scope declaration should not
+            have been static.  */
+         if (oldlocal == 0 && oldglobal != 0
+             && !TREE_PUBLIC (oldglobal)
+             && TREE_EXTERNAL (x) && TREE_PUBLIC (x))
+           warning ("`%s' locally external but globally static",
+                    IDENTIFIER_POINTER (name));
+#endif
+
+         /* If we have a local external declaration,
+            and no file-scope declaration has yet been seen,
+            then if we later have a file-scope decl it must not be static.  */
+         if (oldlocal == 0
+             && oldglobal == 0
+             && TREE_EXTERNAL (x)
+             && TREE_PUBLIC (x))
+           {
+             TREE_PUBLIC (name) = 1;
+           }
+
+         /* Warn if shadowing an argument at the top level of the body.  */
+         if (oldlocal != 0 && !TREE_EXTERNAL (x)
+             /* This warning doesn't apply to the parms of a nested fcn.  */
+             && ! current_binding_level->parm_flag
+             /* Check that this is one level down from the parms.  */
+             && current_binding_level->level_chain->parm_flag
+             /* Check that the decl being shadowed
+                comes from the parm level, one level up.  */
+             && chain_member (oldlocal, current_binding_level->level_chain->names))
+           {
+             if (TREE_CODE (oldlocal) == PARM_DECL)
+               pedwarn ("declaration of `%s' shadows a parameter",
+                        IDENTIFIER_POINTER (name));
+             else
+               pedwarn ("declaration of `%s' shadows a symbol from the parameter list",
+                        IDENTIFIER_POINTER (name));
+           }
+
+         /* Maybe warn if shadowing something else.  */
+         else if (warn_shadow && !TREE_EXTERNAL (x)
+                  /* No shadow warnings for vars made for inlining.  */
+                  && ! DECL_FROM_INLINE (x))
+           {
+             char *warnstring = 0;
+
+             if (TREE_CODE (x) == PARM_DECL
+                 && current_binding_level->parm_flag == 1)
+               /* Don't warn about the parm names in a declaration.  */
+               ;
+             else if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL)
+               warnstring = "declaration of `%s' shadows a parameter";
+             else if (oldlocal != 0)
+               warnstring = "declaration of `%s' shadows previous local";
+             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));
+           }
+
+         /* If storing a local value, there may already be one (inherited).
+            If so, record it for restoration when this binding level ends.  */
+         if (oldlocal != 0)
+           b->shadowed = tree_cons (name, oldlocal, b->shadowed);
+       }
+
+      /* Keep count of variables in this level with incomplete type.  */
+      if (TYPE_SIZE (TREE_TYPE (x)) == 0)
+       ++b->n_incomplete;
+    }
+
+  /* Put decls on list in reverse order.
+     We will reverse them later if necessary.  */
+  TREE_CHAIN (x) = b->names;
+  b->names = x;
+
+  return x;
+}
+
+/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate.  */
+
+tree
+pushdecl_top_level (x)
+     tree x;
+{
+  register tree t;
+  register struct binding_level *b = current_binding_level;
+
+  current_binding_level = global_binding_level;
+  t = pushdecl (x);
+  current_binding_level = b;
+  return t;
+}
+\f
+/* Generate an implicit declaration for identifier FUNCTIONID
+   as a function of type int ().  Print a warning if appropriate.  */
+
+tree
+implicitly_declare (functionid)
+     tree functionid;
+{
+  register tree decl;
+  int traditional_warning = 0;
+  /* 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.  */
+/*  if (IDENTIFIER_IMPLICIT_DECL (functionid) != 0)
+    decl = IDENTIFIER_IMPLICIT_DECL (functionid);
+  else  */
+    decl = build_decl (FUNCTION_DECL, functionid, default_function_type);
+
+  /* Warn of implicit decl following explicit local extern decl.
+     This is probably a program designed for traditional C.  */
+  if (TREE_PUBLIC (functionid) && IDENTIFIER_GLOBAL_VALUE (functionid) == 0)
+    traditional_warning = 1;
+
+  /* Warn once of an implicit declaration.  */
+  implicit_warning = (IDENTIFIER_IMPLICIT_DECL (functionid) == 0);
+
+  TREE_EXTERNAL (decl) = 1;
+  TREE_PUBLIC (decl) = 1;
+
+  /* Record that we have an implicit decl and this is it.  */
+  IDENTIFIER_IMPLICIT_DECL (functionid) = decl;
+
+  /* ANSI standard says implicit declarations are in the innermost block.
+     So we record the decl in the standard fashion.
+     If flag_traditional is set, pushdecl does it top-level.  */
+  pushdecl (decl);
+
+  /* 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, 0, 0, 0);
+
+  if (warn_implicit && implicit_warning)
+    warning ("implicit declaration of function `%s'",
+            IDENTIFIER_POINTER (functionid));
+  else if (warn_traditional && traditional_warning)
+    warning ("function `%s' was previously declared within a block",
+            IDENTIFIER_POINTER (functionid));
+
+  /* Write a record describing this implicit function declaration to the
+     prototypes file (if requested).  */
+
+  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.  */
+
+static char *
+redeclaration_error_message (newdecl, olddecl)
+     tree newdecl, olddecl;
+{
+  if (TREE_CODE (newdecl) == TYPE_DECL)
+    {
+      if (flag_traditional && TREE_TYPE (newdecl) == TREE_TYPE (olddecl))
+       return 0;
+      return "redefinition of `%s'";
+    }
+  else if (TREE_CODE (newdecl) == FUNCTION_DECL)
+    {
+      /* Declarations of functions can insist on internal linkage
+        but they can't be inconsistent with internal linkage,
+        so there can be no error on that account.
+        However defining the same name twice is no good.  */
+      if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0
+         /* However, defining once as extern inline and a second
+            time in another way is ok.  */
+         && !(TREE_INLINE (olddecl) && TREE_EXTERNAL (olddecl)
+              && !(TREE_INLINE (newdecl) && TREE_EXTERNAL (newdecl))))
+       return "redefinition of `%s'";
+      return 0;
+    }
+  else if (current_binding_level == global_binding_level)
+    {
+      /* Objects declared at top level:  */
+      /* If at least one is a reference, it's ok.  */
+      if (TREE_EXTERNAL (newdecl) || TREE_EXTERNAL (olddecl))
+       return 0;
+      /* Reject two definitions.  */
+      if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0)
+       return "redefinition of `%s'";
+      /* Now we have two tentative defs, or one tentative and one real def.  */
+      /* Insist that the linkage match.  */
+      if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl))
+       return "conflicting declarations of `%s'";
+      return 0;
+    }
+  else if (current_binding_level->parm_flag
+          && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl))
+    return 0;
+  else
+    {
+      /* Objects declared with block scope:  */
+      /* Reject two definitions, and reject a definition
+        together with an external reference.  */
+      if (!(TREE_EXTERNAL (newdecl) && TREE_EXTERNAL (olddecl)))
+       return "redeclaration of `%s'";
+      return 0;
+    }
+}
+\f
+/* Get the LABEL_DECL corresponding to identifier ID as a label.
+   Create one if none exists so far for the current function.
+   This function is called for both label definitions and label references.  */
+
+tree
+lookup_label (id)
+     tree id;
+{
+  register tree decl = IDENTIFIER_LABEL_VALUE (id);
+
+  /* Use a label already defined or ref'd with this name.  */
+  if (decl != 0)
+    {
+      /* But not if it is inherited and wasn't declared to be inheritable.  */
+      if (DECL_CONTEXT (decl) != current_function_decl
+         && ! C_DECLARED_LABEL_FLAG (decl))
+       return shadow_label (id);
+      return decl;
+    }
+
+  decl = build_decl (LABEL_DECL, id, void_type_node);
+
+  /* A label not explicitly declared must be local to where it's ref'd.  */
+  DECL_CONTEXT (decl) = current_function_decl;
+
+  DECL_MODE (decl) = VOIDmode;
+
+  /* Say where one reference is to the label,
+     for the sake of the error if it is not defined.  */
+  DECL_SOURCE_LINE (decl) = lineno;
+  DECL_SOURCE_FILE (decl) = input_filename;
+
+  IDENTIFIER_LABEL_VALUE (id) = decl;
+
+  named_labels = tree_cons (NULL_TREE, decl, named_labels);
+
+  return decl;
+}
+
+/* Make a label named NAME in the current function,
+   shadowing silently any that may be inherited from containing functions
+   or containing scopes.
+
+   Note that valid use, if the label being shadowed
+   comes from another scope in the same function,
+   requires calling declare_nonlocal_label right away.  */
+
+tree
+shadow_label (name)
+     tree name;
+{
+  register tree decl = IDENTIFIER_LABEL_VALUE (name);
+
+  if (decl != 0)
+    {
+      shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels);
+      IDENTIFIER_LABEL_VALUE (name) = decl = 0;
+    }
+
+  return lookup_label (name);
+}
+
+/* Define a label, specifying the location in the source file.
+   Return the LABEL_DECL node for the label, if the definition is valid.
+   Otherwise return 0.  */
+
+tree
+define_label (filename, line, name)
+     char *filename;
+     int line;
+     tree name;
+{
+  tree decl = lookup_label (name);
+
+  /* If label with this name is known from an outer context, shadow it.  */
+  if (decl != 0 && DECL_CONTEXT (decl) != current_function_decl)
+    {
+      shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels);
+      IDENTIFIER_LABEL_VALUE (name) = 0;
+      decl = lookup_label (name);
+    }
+
+  if (DECL_INITIAL (decl) != 0)
+    {
+      error_with_decl (decl, "duplicate label `%s'");
+      return 0;
+    }
+  else
+    {
+      /* Mark label as having been defined.  */
+      DECL_INITIAL (decl) = error_mark_node;
+      /* Say where in the source.  */
+      DECL_SOURCE_FILE (decl) = filename;
+      DECL_SOURCE_LINE (decl) = line;
+      return decl;
+    }
+}
+\f
+/* Return the list of declarations of the current level.
+   Note that this list is in reverse order unless/until
+   you nreverse it; and when you do nreverse it, you must
+   store the result back using `storedecls' or you will lose.  */
+
+tree
+getdecls ()
+{
+  return current_binding_level->names;
+}
+
+/* Return the list of type-tags (for structs, etc) of the current level.  */
+
+tree
+gettags ()
+{
+  return current_binding_level->tags;
+}
+
+/* Store the list of declarations of the current level.
+   This is done for the parameter declarations of a function being defined,
+   after they are modified in the light of any missing parameters.  */
+
+static void
+storedecls (decls)
+     tree decls;
+{
+  current_binding_level->names = decls;
+}
+
+/* Similarly, store the list of tags of the current level.  */
+
+static void
+storetags (tags)
+     tree tags;
+{
+  current_binding_level->tags = tags;
+}
+\f
+/* Given NAME, an IDENTIFIER_NODE,
+   return the structure (or union or enum) definition for that name.
+   Searches binding levels from BINDING_LEVEL up to the global level.
+   If THISLEVEL_ONLY is nonzero, searches only the specified context
+   (but skips any tag-transparent contexts to find one that is
+   meaningful for tags).
+   CODE says which kind of type the caller wants;
+   it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE.
+   If the wrong kind of type is found, an error is reported.  */
+
+static tree
+lookup_tag (code, name, binding_level, thislevel_only)
+     enum tree_code code;
+     struct binding_level *binding_level;
+     tree name;
+     int thislevel_only;
+{
+  register struct binding_level *level;
+
+  for (level = binding_level; level; level = level->level_chain)
+    {
+      register tree tail;
+      for (tail = level->tags; tail; tail = TREE_CHAIN (tail))
+       {
+         if (TREE_PURPOSE (tail) == name)
+           {
+             if (TREE_CODE (TREE_VALUE (tail)) != code)
+               {
+                 /* Definition isn't the kind we were looking for.  */
+                 pending_invalid_xref = name;
+                 pending_invalid_xref_file = input_filename;
+                 pending_invalid_xref_line = lineno;
+               }
+             return TREE_VALUE (tail);
+           }
+       }
+      if (thislevel_only && ! level->tag_transparent)
+       return NULL_TREE;
+    }
+  return NULL_TREE;
+}
+
+/* Print an error message now
+   for a recent invalid struct, union or enum cross reference.
+   We don't print them immediately because they are not invalid
+   when used in the `struct foo;' construct for shadowing.  */
+
+void
+pending_xref_error ()
+{
+  if (pending_invalid_xref != 0)
+    error_with_file_and_line (pending_invalid_xref_file,
+                             pending_invalid_xref_line,
+                             "`%s' defined as wrong kind of tag",
+                             IDENTIFIER_POINTER (pending_invalid_xref));
+  pending_invalid_xref = 0;
+}
+
+/* Given a type, find the tag that was defined for it and return the tag name.
+   Otherwise return 0.  */
+
+static tree
+lookup_tag_reverse (type)
+     tree type;
+{
+  register struct binding_level *level;
+
+  for (level = current_binding_level; level; level = level->level_chain)
+    {
+      register tree tail;
+      for (tail = level->tags; tail; tail = TREE_CHAIN (tail))
+       {
+         if (TREE_VALUE (tail) == type)
+           return TREE_PURPOSE (tail);
+       }
+    }
+  return NULL_TREE;
+}
+\f
+/* Look up NAME in the current binding level and its superiors
+   in the namespace of variables, functions and typedefs.
+   Return a ..._DECL node of some kind representing its definition,
+   or return 0 if it is undefined.  */
+
+tree
+lookup_name (name)
+     tree name;
+{
+  register tree val;
+  if (current_binding_level != global_binding_level
+      && IDENTIFIER_LOCAL_VALUE (name))
+    val = IDENTIFIER_LOCAL_VALUE (name);
+  else
+    val = IDENTIFIER_GLOBAL_VALUE (name);
+  return val;
+}
+
+/* Similar to `lookup_name' but look only at current binding level.  */
+
+static tree
+lookup_name_current_level (name)
+     tree name;
+{
+  register tree t;
+
+  if (current_binding_level == global_binding_level)
+    return IDENTIFIER_GLOBAL_VALUE (name);
+
+  if (IDENTIFIER_LOCAL_VALUE (name) == 0)
+    return 0;
+
+  for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
+    if (DECL_NAME (t) == name)
+      break;
+
+  return t;
+}
+\f
+/* Create the predefined scalar types of C,
+   and some nodes representing standard constants (0, 1, (void *)0).
+   Initialize the global binding level.
+   Make definitions for built-in primitive functions.  */
+
+void
+init_decl_processing ()
+{
+  register tree endlink;
+  /* Either char* or void*.  */
+  tree traditional_ptr_type_node;
+  /* Data type of memcpy.  */
+  tree memcpy_ftype;
+  int wchar_type_size;
+  tree temp;
+
+  current_function_decl = NULL;
+  named_labels = NULL;
+  current_binding_level = NULL_BINDING_LEVEL;
+  free_binding_level = NULL_BINDING_LEVEL;
+  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.  */
+
+  integer_type_node = make_signed_type (INT_TYPE_SIZE);
+  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));
+
+  /* `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 of long and int are the same size.  */
+  if (flag_traditional)
+    sizetype = long_integer_type_node;
+  else
+    sizetype
+      = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)));
+
+  ptrdiff_type_node
+    = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
+
+  TREE_TYPE (TYPE_SIZE (integer_type_node)) = sizetype;
+  TREE_TYPE (TYPE_SIZE (char_type_node)) = sizetype;
+  TREE_TYPE (TYPE_SIZE (unsigned_type_node)) = sizetype;
+  TREE_TYPE (TYPE_SIZE (long_unsigned_type_node)) = sizetype;
+  TREE_TYPE (TYPE_SIZE (long_integer_type_node)) = sizetype;
+
+  error_mark_node = make_node (ERROR_MARK);
+  TREE_TYPE (error_mark_node) = error_mark_node;
+
+  short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"),
+                       short_integer_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));
+
+  short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"),
+                       short_unsigned_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));
+
+  /* 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));
+
+  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);
+
+  wchar_type_node
+    = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE)));
+  wchar_type_size = TYPE_PRECISION (wchar_type_node);
+  signed_wchar_type_node = type_for_size (wchar_type_size, 0);
+  unsigned_wchar_type_node = type_for_size (wchar_type_size, 1);
+
+  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;
+
+  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));
+
+  /* make a type for arrays of 256 characters.
+     256 is picked randomly because we have a type for integers from 0 to 255.
+     With luck nothing will ever really depend on the length of this
+     array type.  */
+  char_array_type_node
+    = build_array_type (char_type_node, unsigned_char_type_node);
+  /* Likewise for arrays of ints.  */
+  int_array_type_node
+    = build_array_type (integer_type_node, unsigned_char_type_node);
+  /* This is for wide string constants.  */
+  wchar_array_type_node
+    = build_array_type (wchar_type_node, unsigned_char_type_node);
+
+  default_function_type
+    = build_function_type (integer_type_node, NULL_TREE);
+
+  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);
+
+  double_ftype_double
+    = build_function_type (double_type_node,
+                          tree_cons (NULL_TREE, 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)));
+
+  sizet_ftype_string           /* strlen prototype */
+    = build_function_type (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))));
+
+  /* ``integer_tpe_node'' mispelling corrected: North-Keys 30 Mar 91 */
+  builtin_function ("__builtin_constant_p",
+                   build_function_type (integer_type_node, endlink),
+                   BUILT_IN_CONSTANT_P, 0);
+
+  builtin_function ("__builtin_return_address",
+                   build_function_type (integer_type_node, 
+                                        tree_cons (NULL_TREE,
+                                                   unsigned_type_node,
+                                                   endlink)),
+                   BUILT_IN_RETURN_ADDRESS, 0);
+
+  builtin_function ("__builtin_frame_address",
+                   build_function_type (integer_type_node, 
+                                        tree_cons (NULL_TREE,
+                                                   unsigned_type_node,
+                                                   endlink)),
+                   BUILT_IN_FRAME_ADDRESS, 0);
+
+  builtin_function ("__builtin_alloca",
+                   build_function_type (ptr_type_node,
+                                        tree_cons (NULL_TREE,
+                                                   sizetype,
+                                                   endlink)),
+                   BUILT_IN_ALLOCA, "alloca");
+  if (! flag_no_builtin)
+    {
+      tree exit_type;
+      temp = builtin_function ("alloca",
+                              build_function_type (ptr_type_node,
+                                                   tree_cons (NULL_TREE,
+                                                              sizetype,
+                                                              endlink)),
+                              BUILT_IN_ALLOCA, 0);
+      /* Suppress error if redefined as a non-function.  */
+      DECL_BUILT_IN_NONANSI (temp) = 1;
+      /* 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",
+                              build_function_type (void_type_node, 0),
+                              NOT_BUILT_IN, 0);
+      TREE_THIS_VOLATILE (temp) = 1;
+      TREE_SIDE_EFFECTS (temp) = 1;
+      /* Suppress error if redefined as a non-function.  */
+      DECL_BUILT_IN_NONANSI (temp) = 1;
+      exit_type = build_function_type (void_type_node, 0);
+      temp = builtin_function ("exit", exit_type, NOT_BUILT_IN, 0);
+      TREE_THIS_VOLATILE (temp) = 1;
+      TREE_SIDE_EFFECTS (temp) = 1;
+      /* Suppress error if redefined as a non-function.  */
+      DECL_BUILT_IN_NONANSI (temp) = 1;
+      temp = builtin_function ("_exit", exit_type, NOT_BUILT_IN, 0);
+      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, 0);
+  builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS, 0);
+  builtin_function ("__builtin_labs", long_ftype_long, BUILT_IN_LABS, 0);
+  builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, 0);
+  builtin_function ("__builtin_saveregs", default_function_type,
+                   BUILT_IN_SAVEREGS, 0);
+/* 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, 0);
+#endif
+  builtin_function ("__builtin_classify_type", default_function_type,
+                   BUILT_IN_CLASSIFY_TYPE, 0);
+  builtin_function ("__builtin_next_arg",
+                   build_function_type (ptr_type_node, endlink),
+                   BUILT_IN_NEXT_ARG, 0);
+  builtin_function ("__builtin_args_info",
+                   build_function_type (integer_type_node,
+                                        tree_cons (NULL_TREE,
+                                                   integer_type_node,
+                                                   endlink)),
+                   BUILT_IN_ARGS_INFO, 0);
+
+  /* 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_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", sizet_ftype_string,
+                   BUILT_IN_STRLEN, "strlen");
+  /* 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, a traditional C program can do so.  */
+  if (!flag_traditional)
+    {
+      builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, 0);
+      builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, 0);
+      builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, 0);
+      builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, 0);
+      builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP, 0);
+      builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP, 0);
+      builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY, 0);
+      builtin_function ("strlen", sizet_ftype_string, BUILT_IN_STRLEN, 0);
+    }
+
+#if 0
+  /* Support for these has not been written in either expand_builtin
+     or build_function_call.  */
+  builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, 0);
+  builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, 0);
+  builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR, 0);
+  builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, 0);
+  builtin_function ("__builtin_fmod", double_ftype_double_double, BUILT_IN_FMOD, 0);
+  builtin_function ("__builtin_frem", double_ftype_double_double, BUILT_IN_FREM, 0);
+  builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, BUILT_IN_MEMSET, 0);
+  builtin_function ("__builtin_fsqrt", double_ftype_double, BUILT_IN_FSQRT, 0);
+  builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP, 0);
+  builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN, 0);
+#endif
+
+  start_identifier_warnings ();
+
+  init_format_info_table ();
+}
+
+/* Return a definition for a builtin function named NAME and whose data type
+   is TYPE.  TYPE should be a function type with argument types.
+   FUNCTION_CODE tells later passes how to compile calls to this function.
+   See tree.h for its possible values.
+
+   If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
+   the name to be called if we can't opencode the function.  */
+
+static tree
+builtin_function (name, type, function_code, library_name)
+     char *name;
+     tree type;
+     enum built_in_function function_code;
+     char *library_name;
+{
+  tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type);
+  TREE_EXTERNAL (decl) = 1;
+  TREE_PUBLIC (decl) = 1;
+  if (library_name)
+    DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name);
+  make_decl_rtl (decl, 0, 1);
+  pushdecl (decl);
+  if (function_code != NOT_BUILT_IN)
+    {
+      DECL_BUILT_IN (decl) = 1;
+      DECL_SET_FUNCTION_CODE (decl, function_code);
+    }
+
+  return decl;
+}
+\f
+/* Called when a declaration is seen that contains no names to declare.
+   If its type is a reference to a structure, union or enum inherited
+   from a containing scope, shadow that tag name for the current scope
+   with a forward reference.
+   If its type defines a new named structure or union
+   or defines an enum, it is valid but we need not do anything here.
+   Otherwise, it is an error.  */
+
+void
+shadow_tag (declspecs)
+     tree declspecs;
+{
+  int found_tag = 0;
+  int warned = 0;
+  register tree link;
+
+  pending_invalid_xref = 0;
+
+  for (link = declspecs; link; link = TREE_CHAIN (link))
+    {
+      register tree value = TREE_VALUE (link);
+      register enum tree_code code = TREE_CODE (value);
+
+      if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
+       /* Used to test also that TYPE_SIZE (value) != 0.
+          That caused warning for `struct foo;' at top level in the file.  */
+       {
+         register tree name = lookup_tag_reverse (value);
+         register tree t;
+
+         found_tag++;
+
+         if (name == 0)
+           {
+             if (code != ENUMERAL_TYPE)        /* Empty unnamed enum OK */
+               {
+                 pedwarn ("unnamed struct/union that defines no instances");
+                 warned = 1;
+               }
+           }
+         else
+           {
+             t = lookup_tag (code, name, current_binding_level, 1);
+
+             if (t == 0)
+               {
+                 t = make_node (code);
+                 pushtag (name, t);
+               }
+           }
+       }
+      else
+       {
+         if (!warned)
+           warning ("useless keyword or type name in empty declaration");
+         warned = 1;
+       }
+    }
+
+  if (!warned)
+    {
+      if (found_tag > 1)
+       error ("two types specified in one empty declaration");
+      if (found_tag == 0)
+       pedwarn ("empty declaration");
+    }
+}
+\f
+/* Decode a "typename", such as "int **", returning a ..._TYPE node.  */
+
+tree
+groktypename (typename)
+     tree typename;
+{
+  if (TREE_CODE (typename) != TREE_LIST)
+    return typename;
+  return grokdeclarator (TREE_VALUE (typename),
+                        TREE_PURPOSE (typename),
+                        TYPENAME, 0);
+}
+
+/* Return a PARM_DECL node for a given pair of specs and declarator.  */
+
+tree
+groktypename_in_parm_context (typename)
+     tree typename;
+{
+  if (TREE_CODE (typename) != TREE_LIST)
+    return typename;
+  return grokdeclarator (TREE_VALUE (typename),
+                        TREE_PURPOSE (typename),
+                        PARM, 0);
+}
+
+/* Decode a declarator in an ordinary declaration or data definition.
+   This is called as soon as the type information and variable name
+   have been parsed, before parsing the initializer if any.
+   Here we create the ..._DECL node, fill in its type,
+   and put it on the list of decls for the current context.
+   The ..._DECL node is returned as the value.
+
+   Exception: for arrays where the length is not specified,
+   the type is left null, to be filled in by `finish_decl'.
+
+   Function definitions do not come here; they go to start_function
+   instead.  However, external and forward declarations of functions
+   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)
+     tree declspecs, declarator;
+     int initialized;
+{
+  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 (initialized)
+    /* Is it valid for this decl to have an initializer at all?
+       If not, set INITIALIZED to zero, which will indirectly
+       tell `finish_decl' to ignore the initializer once it is parsed.  */
+    switch (TREE_CODE (decl))
+      {
+      case TYPE_DECL:
+       /* typedef foo = bar  means give foo the same type as bar.
+          We haven't parsed bar yet, so `finish_decl' will fix that up.
+          Any other case of an initialization in a TYPE_DECL is an error.  */
+       if (pedantic || list_length (declspecs) > 1)
+         {
+           error ("typedef `%s' is initialized",
+                  IDENTIFIER_POINTER (DECL_NAME (decl)));
+           initialized = 0;
+         }
+       break;
+
+      case FUNCTION_DECL:
+       error ("function `%s' is initialized like a variable",
+              IDENTIFIER_POINTER (DECL_NAME (decl)));
+       initialized = 0;
+       break;
+
+      case PARM_DECL:
+       /* DECL_INITIAL in a PARM_DECL is really DECL_ARG_TYPE.  */
+       error ("parameter `%s' is initialized",
+              IDENTIFIER_POINTER (DECL_NAME (decl)));
+       initialized = 0;
+       break;
+
+      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)
+         {
+           /* A complete type is ok if size is fixed.  */
+
+           if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST
+               || C_DECL_VARIABLE_SIZE (decl))
+             {
+               error ("variable-sized object may not be initialized");
+               initialized = 0;
+             }
+         }
+       else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
+         {
+           error ("variable `%s' has initializer but incomplete type",
+                  IDENTIFIER_POINTER (DECL_NAME (decl)));
+           initialized = 0;
+         }
+       else if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl))) == 0)
+         {
+           error ("elements of array `%s' have incomplete type",
+                  IDENTIFIER_POINTER (DECL_NAME (decl)));
+           initialized = 0;
+         }
+      }
+
+  if (initialized)
+    {
+#if 0  /* Seems redundant with grokdeclarator.  */
+      if (current_binding_level != global_binding_level
+         && TREE_EXTERNAL (decl)
+         && TREE_CODE (decl) != FUNCTION_DECL)
+       warning ("declaration of `%s' has `extern' and is initialized",
+                IDENTIFIER_POINTER (DECL_NAME (decl)));
+#endif
+      TREE_EXTERNAL (decl) = 0;
+      if (current_binding_level == global_binding_level)
+       TREE_STATIC (decl) = 1;
+
+      /* Tell `pushdecl' this is an initialized decl
+        even though we don't yet have the initializer expression.
+        Also tell `finish_decl' it may store the real initializer.  */
+      DECL_INITIAL (decl) = error_mark_node;
+    }
+
+  /* If this is a function declaration, write a record describing it to the
+     prototypes file (if requested).  */
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    gen_aux_info_record (decl, 0, 0, TYPE_ARG_TYPES (TREE_TYPE (decl)) != 0);
+
+  /* Add this decl to the current binding level.
+     TEM may equal DECL or it may be a previous decl of the same name.  */
+  tem = pushdecl (decl);
+
+  /* For a local variable, define the RTL now.  */
+  if (current_binding_level != global_binding_level
+      /* But not if this is a duplicate decl
+        and we preserved the rtl from the previous one
+        (which may or may not happen).  */
+      && DECL_RTL (tem) == 0)
+    {
+      if (TYPE_SIZE (TREE_TYPE (tem)) != 0)
+       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;
+}
+
+/* Finish processing of a declaration;
+   install its initial value.
+   If the length of an array type is not known before,
+   it must be determined now, from the initial value, or it is an error.  */
+
+void
+finish_decl (decl, init, asmspec_tree)
+     tree decl, init;
+     tree asmspec_tree;
+{
+  register tree type = TREE_TYPE (decl);
+  int was_incomplete = (DECL_SIZE (decl) == 0);
+  int temporary = allocation_temporary_p ();
+  char *asmspec = 0;
+
+  if (asmspec_tree)
+    asmspec = TREE_STRING_POINTER (asmspec_tree);
+
+  /* If `start_decl' didn't like having an initialization, ignore it now.  */
+
+  if (init != 0 && DECL_INITIAL (decl) == 0)
+    init = 0;
+  /* Don't crash if parm is initialized.  */
+  if (TREE_CODE (decl) == PARM_DECL)
+    init = 0;
+
+  if (init)
+    {
+      if (TREE_CODE (decl) != TYPE_DECL)
+       store_init_value (decl, init);
+      else
+       {
+         /* typedef foo = bar; store the type of bar as the type of foo.  */
+         TREE_TYPE (decl) = TREE_TYPE (init);
+         DECL_INITIAL (decl) = init = 0;
+       }
+    }
+
+  /* For top-level declaration, the initial value was read in
+     the temporary obstack.  MAXINDEX, rtl, etc. to be made below
+     must go in the permanent obstack; but don't discard the
+     temporary data yet.  */
+
+  if (current_binding_level == global_binding_level && temporary)
+    end_temporary_allocation ();
+
+  /* Deduce size of array from initialization, if not already known */
+
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_DOMAIN (type) == 0
+      && TREE_CODE (decl) != TYPE_DECL)
+    {
+      int do_default
+       = (TREE_STATIC (decl)
+          /* Even if pedantic, an external linkage array
+             may have incomplete type at first.  */
+          ? pedantic && !TREE_PUBLIC (decl)
+          : !TREE_EXTERNAL (decl));
+      int failure
+       = complete_array_type (type, DECL_INITIAL (decl), do_default);
+
+      /* Get the completed type made by complete_array_type.  */
+      type = TREE_TYPE (decl);
+
+      if (failure == 1)
+       error_with_decl (decl, "initializer fails to determine size of `%s'");
+
+      if (failure == 2)
+       {
+         if (do_default)
+           error_with_decl (decl, "array size missing in `%s'");
+         else if (!pedantic && TREE_STATIC (decl))
+           TREE_EXTERNAL (decl) = 1;
+       }
+
+      if (pedantic && TYPE_DOMAIN (type) != 0
+         && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+                             integer_zero_node))
+       error_with_decl (decl, "zero-size array `%s'");
+
+      layout_decl (decl, 0);
+    }
+
+  if (TREE_CODE (decl) == VAR_DECL)
+    {
+      if (TREE_STATIC (decl) && DECL_SIZE (decl) == 0)
+       {
+         /* A static variable with an incomplete type:
+            that is an error if it is initialized or `static'.
+            Otherwise, let it through, but if it is not `extern'
+            then it may cause an error message later.  */
+         if (! (TREE_PUBLIC (decl) && DECL_INITIAL (decl) == 0))
+           error_with_decl (decl, "storage size of `%s' isn't known");
+       }
+      else if (!TREE_EXTERNAL (decl) && DECL_SIZE (decl) == 0)
+       {
+         /* An automatic variable with an incomplete type:
+            that is an error.  */
+         error_with_decl (decl, "storage size of `%s' isn't known");
+         TREE_TYPE (decl) = error_mark_node;
+       }
+
+      if ((TREE_EXTERNAL (decl) || TREE_STATIC (decl))
+         && DECL_SIZE (decl) != 0
+         && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+       error_with_decl (decl, "storage size of `%s' isn't constant");
+    }
+
+  /* Output the assembler code and/or RTL code for variables and functions,
+     unless the type is an undefined structure or union.
+     If not, it will get done when the type is completed.  */
+
+  if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      if (flag_traditional && 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,
+                                   current_binding_level == global_binding_level,
+                                   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,
+                                   current_binding_level == global_binding_level,
+                                   0);
+       }
+      if (current_binding_level != global_binding_level)
+       {
+         /* Recompute the RTL of a local array now
+            if it used to be an incomplete type.  */
+         if (was_incomplete
+             && ! TREE_STATIC (decl) && ! TREE_EXTERNAL (decl))
+           {
+             /* If we used it already as memory, it must stay in memory.  */
+             TREE_ADDRESSABLE (decl) = TREE_USED (decl);
+             /* If it's still incomplete now, no init will save it.  */
+             if (DECL_SIZE (decl) == 0)
+               DECL_INITIAL (decl) = 0;
+             expand_decl (decl);
+           }
+         /* Compute and store the initial value.  */
+         expand_decl_init (decl);
+       }
+    }
+
+  if (TREE_CODE (decl) == TYPE_DECL)
+    {
+      /* 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, 0,
+                               current_binding_level == global_binding_level,
+                               0);
+    }
+
+  if (temporary && TREE_PERMANENT (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.  */
+      if (DECL_INITIAL (decl) != 0)
+       DECL_INITIAL (decl) = error_mark_node;
+    }
+
+  /* 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 ();
+  if (current_binding_level == global_binding_level && temporary)
+    /* Actually free the temporary space that we no longer need.  */
+    permanent_allocation ();
+
+  /* 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.  */
+  if (current_binding_level == global_binding_level)
+    get_pending_sizes ();
+}
+
+/* If DECL has a cleanup, build and return that cleanup here.
+   This is a callback called by expand_expr.  */
+
+tree
+maybe_build_cleanup (decl)
+     tree decl;
+{
+  /* There are no cleanups in C.  */
+  return NULL_TREE;
+}
+
+/* Given a parsed parameter declaration,
+   decode it into a PARM_DECL and push that on the current binding level.
+   Also, for the sake of forward parm decls,
+   record the given order of parms in `parm_order'.  */
+
+void
+push_parm_decl (parm)
+     tree parm;
+{
+  tree decl;
+
+  /* The corresponding pop_obstacks is in finish_decl.  */
+  push_obstacks_nochange ();
+
+  decl = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm), PARM, 0);
+  decl = pushdecl (decl);
+
+  current_binding_level->parm_order
+    = tree_cons (NULL_TREE, decl, current_binding_level->parm_order);
+
+  /* Add this decl to the current binding level.  */
+  finish_decl (decl, NULL_TREE, NULL_TREE);
+}
+
+/* Clear the given order of parms in `parm_order'.
+   Used at start of parm list,
+   and also at semicolon terminating forward decls.  */
+
+void
+clear_parm_order ()
+{
+  current_binding_level->parm_order = NULL_TREE;
+}
+\f
+/* Make TYPE a complete type based on INITIAL_VALUE.
+   Return 0 if successful, 1 if INITIAL_VALUE can't be decyphered,
+   2 if there was no information (in which case assume 1 if DO_DEFAULT).  */
+
+int
+complete_array_type (type, initial_value, do_default)
+     tree type;
+     tree initial_value;
+     int do_default;
+{
+  register tree maxindex = NULL_TREE;
+  int value = 0;
+
+  if (initial_value)
+    {
+      /* Note MAXINDEX  is really the maximum index,
+        one less than the size.  */
+      if (TREE_CODE (initial_value) == STRING_CST)
+       {
+         int eltsize
+           = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
+         maxindex = build_int_2 (TREE_STRING_LENGTH (initial_value) / eltsize - 1, 0);
+       }
+      else if (TREE_CODE (initial_value) == CONSTRUCTOR)
+       {
+         register int nelts
+           = list_length (CONSTRUCTOR_ELTS (initial_value));
+         maxindex = build_int_2 (nelts - 1, 0);
+       }
+      else
+       {
+         /* Make an error message unless that happened already.  */
+         if (initial_value != error_mark_node)
+           value = 1;
+
+         /* Prevent further error messages.  */
+         maxindex = build_int_2 (1, 0);
+       }
+    }
+
+  if (!maxindex)
+    {
+      if (do_default)
+       maxindex = build_int_2 (1, 0);
+      value = 2;
+    }
+
+  if (maxindex)
+    {
+      TYPE_DOMAIN (type) = build_index_type (maxindex);
+      if (!TREE_TYPE (maxindex))
+       TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
+    }
+
+  /* Lay out the type now that we can get the real answer.  */
+
+  layout_type (type);
+
+  return value;
+}
+\f
+/* Given declspecs and a declarator,
+   determine the name and type of the object declared
+   and construct a ..._DECL node for it.
+   (In one case we can return a ..._TYPE node instead.
+    For invalid input we sometimes return 0.)
+
+   DECLSPECS is a chain of tree_list nodes whose value fields
+    are the storage classes and type specifiers.
+
+   DECL_CONTEXT says which syntactic context this declaration is in:
+     NORMAL for most contexts.  Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL.
+     FUNCDEF for a function definition.  Like NORMAL but a few different
+      error messages in each case.  Return value may be zero meaning
+      this definition is too screwy to try to parse.
+     PARM for a parameter declaration (either within a function prototype
+      or before a function body).  Make a PARM_DECL, or return void_type_node.
+     TYPENAME if for a typename (in a cast or sizeof).
+      Don't make a DECL node; just return the ..._TYPE node.
+     FIELD for a struct or union field; make a FIELD_DECL.
+     BITFIELD for a field with specified width.
+   INITIALIZED is 1 if the decl has an initializer.
+
+   In the TYPENAME case, DECLARATOR is really an absolute declarator.
+   It may also be so in the PARM case, for a prototype where the
+   argument type is specified but not the name.
+
+   This function is where the complicated C meanings of `static'
+   and `extern' are intrepreted.  */
+
+static tree
+grokdeclarator (declarator, declspecs, decl_context, initialized)
+     tree declspecs;
+     tree declarator;
+     enum decl_context decl_context;
+     int initialized;
+{
+  int specbits = 0;
+  tree spec;
+  tree type = NULL_TREE;
+  int longlong = 0;
+  int constp;
+  int volatilep;
+  int inlinep;
+  int explicit_int = 0;
+  int explicit_char = 0;
+  tree typedef_decl = 0;
+  char *name;
+  tree typedef_type = 0;
+  int funcdef_flag = 0;
+  enum tree_code innermost_code = ERROR_MARK;
+  int bitfield = 0;
+  int variable_size = 0;
+
+  if (decl_context == BITFIELD)
+    bitfield = 1, decl_context = FIELD;
+
+  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.  */
+  {
+    register tree decl = declarator;
+    name = 0;
+
+    while (decl)
+      switch (TREE_CODE (decl))
+       {
+       case ARRAY_REF:
+       case INDIRECT_REF:
+       case CALL_EXPR:
+         innermost_code = TREE_CODE (decl);
+         decl = TREE_OPERAND (decl, 0);
+         break;
+
+       case IDENTIFIER_NODE:
+         name = IDENTIFIER_POINTER (decl);
+         decl = 0;
+         break;
+
+       default:
+         abort ();
+       }
+    if (name == 0)
+      name = "type name";
+  }
+
+  /* A function definition's declarator must have the form of
+     a function declarator.  */
+
+  if (funcdef_flag && innermost_code != CALL_EXPR)
+    return 0;
+
+  /* Anything declared one level down from the top level
+     must be one of the parameters of a function
+     (because the body is at least two levels down).  */
+
+  /* If this looks like a function definition, make it one,
+     even if it occurs where parms are expected.
+     Then store_parm_decls will reject it and not use it as a parm.  */
+  if (decl_context == NORMAL && !funcdef_flag
+      && current_binding_level->level_chain == global_binding_level)
+    decl_context = PARM;
+
+  /* Look through the decl specs and record which ones appear.
+     Some typespecs are defined as built-in typenames.
+     Others, the ones that are modifiers of other types,
+     are represented by bits in SPECBITS: set the bits for
+     the modifiers that appear.  Storage class keywords are also in SPECBITS.
+
+     If there is a typedef name or a type, store the type in TYPE.
+     This includes builtin typedefs such as `int'.
+
+     Set EXPLICIT_INT or EXPLICIT_CHAR if the type is `int' or `char'
+     and did not come from a user typedef.
+
+     Set LONGLONG if `long' is mentioned twice.  */
+
+  for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
+    {
+      register int i;
+      register tree id = TREE_VALUE (spec);
+
+      if (id == ridpointers[(int) RID_INT])
+       explicit_int = 1;
+      if (id == ridpointers[(int) RID_CHAR])
+       explicit_char = 1;
+
+      if (TREE_CODE (id) == IDENTIFIER_NODE)
+       for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++)
+         {
+           if (ridpointers[i] == id)
+             {
+               if (i == (int) RID_LONG && specbits & (1<<i))
+                 {
+                   if (pedantic)
+                     pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
+                   else if (longlong)
+                     warning ("`long long long' is too long for GCC");
+                   else
+                     longlong = 1;
+                 }
+               else if (specbits & (1 << i))
+                 warning ("duplicate `%s'", IDENTIFIER_POINTER (id));
+               specbits |= 1 << i;
+               goto found;
+             }
+         }
+      if (type)
+       error ("two or more data types in declaration of `%s'", name);
+      /* Actual typedefs come to us as TYPE_DECL nodes.  */
+      else if (TREE_CODE (id) == TYPE_DECL)
+       {
+         type = TREE_TYPE (id);
+         typedef_decl = id;
+       }
+      /* Built-in types come as identifiers.  */
+      else if (TREE_CODE (id) == IDENTIFIER_NODE)
+       {
+         register tree t = lookup_name (id);
+         if (TREE_TYPE (t) == error_mark_node)
+           ;
+         else if (!t || TREE_CODE (t) != TYPE_DECL)
+           error ("`%s' fails to be a typedef or built in type",
+                  IDENTIFIER_POINTER (id));
+         else
+           {
+             type = TREE_TYPE (t);
+             typedef_decl = t;
+           }
+       }
+      else if (TREE_CODE (id) != ERROR_MARK)
+       type = id;
+
+    found: {}
+    }
+
+  typedef_type = type;
+  if (type)
+    variable_size = C_TYPE_VARIABLE_SIZE (type);
+
+  /* No type at all: default to `int', and set EXPLICIT_INT
+     because it was not a user-defined typedef.  */
+
+  if (type == 0)
+    {
+      if (funcdef_flag && warn_return_type
+         && ! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
+                           | (1 << (int) RID_SIGNED) | (1 << (int) RID_UNSIGNED))))
+       warn_about_return_type = 1;
+      explicit_int = 1;
+      type = integer_type_node;
+    }
+
+  /* Now process the modifiers that were specified
+     and check for invalid combinations.  */
+
+  /* Long double is a special combination.  */
+
+  if ((specbits & 1 << (int) RID_LONG) && type == double_type_node)
+    {
+      specbits &= ~ (1 << (int) RID_LONG);
+      type = long_double_type_node;
+    }
+
+  /* Check all other uses of type modifiers.  */
+
+  if (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
+                 | (1 << (int) RID_UNSIGNED) | (1 << (int) RID_SIGNED)))
+    {
+      int ok = 0;
+
+      if (TREE_CODE (type) != INTEGER_TYPE)
+       error ("long, short, signed or unsigned invalid for `%s'", name);
+      else if ((specbits & 1 << (int) RID_LONG)
+              && (specbits & 1 << (int) RID_SHORT))
+       error ("long and short specified together for `%s'", name);
+      else if (((specbits & 1 << (int) RID_LONG)
+               || (specbits & 1 << (int) RID_SHORT))
+              && explicit_char)
+       error ("long or short specified with char for `%s'", name);
+      else if (((specbits & 1 << (int) RID_LONG)
+               || (specbits & 1 << (int) RID_SHORT))
+              && TREE_CODE (type) == REAL_TYPE)
+       error ("long or short specified with floating type for `%s'", name);
+      else if ((specbits & 1 << (int) RID_SIGNED)
+              && (specbits & 1 << (int) RID_UNSIGNED))
+       error ("signed and unsigned given together for `%s'", name);
+      else
+       {
+         ok = 1;
+         if (!explicit_int && !explicit_char && pedantic)
+           {
+             pedwarn ("long, short, signed or unsigned used invalidly for `%s'",
+                      name);
+             if (flag_pedantic_errors)
+               ok = 0;
+           }
+       }
+
+      /* Discard the type modifiers if they are invalid.  */
+      if (! ok)
+       {
+         specbits &= ~((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
+                       | (1 << (int) RID_UNSIGNED) | (1 << (int) RID_SIGNED));
+         longlong = 0;
+       }
+    }
+
+  /* Decide whether an integer type is signed or not.
+     Optionally treat bitfields as signed by default.  */
+  if (specbits & 1 << (int) RID_UNSIGNED
+      /* Traditionally, all bitfields are unsigned.  */
+      || (bitfield && flag_traditional)
+      || (bitfield && ! flag_signed_bitfields
+         && (explicit_int || explicit_char
+             /* A typedef for plain `int' without `signed'
+                can be controlled just like plain `int'.  */
+             || ! (typedef_decl != 0
+                   && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
+         && TREE_CODE (type) != ENUMERAL_TYPE
+         && !(specbits & 1 << (int) RID_SIGNED)))
+    {
+      if (longlong)
+       type = long_long_unsigned_type_node;
+      else if (specbits & 1 << (int) RID_LONG)
+       type = long_unsigned_type_node;
+      else if (specbits & 1 << (int) RID_SHORT)
+       type = short_unsigned_type_node;
+      else if (type == char_type_node)
+       type = unsigned_char_type_node;
+      else if (typedef_decl)
+       type = unsigned_type (type);
+      else
+       type = unsigned_type_node;
+    }
+  else if ((specbits & 1 << (int) RID_SIGNED)
+          && type == char_type_node)
+    type = signed_char_type_node;
+  else if (longlong)
+    type = long_long_integer_type_node;
+  else if (specbits & 1 << (int) RID_LONG)
+    type = long_integer_type_node;
+  else if (specbits & 1 << (int) RID_SHORT)
+    type = short_integer_type_node;
+
+  /* Set CONSTP if this declaration is `const', whether by
+     explicit specification or via a typedef.
+     Likewise for VOLATILEP.  */
+
+  constp = !! (specbits & 1 << (int) RID_CONST) + TYPE_READONLY (type);
+  volatilep = !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (type);
+  inlinep = !! (specbits & (1 << (int) RID_INLINE));
+  if (constp > 1)
+    warning ("duplicate `const'");
+  if (volatilep > 1)
+    warning ("duplicate `volatile'");
+  if (! flag_gen_aux_info && (TYPE_READONLY (type) || TYPE_VOLATILE (type)))
+    type = TYPE_MAIN_VARIANT (type);
+
+  /* Warn if two storage classes are given. Default to `auto'.  */
+
+  {
+    int nclasses = 0;
+
+    if (specbits & 1 << (int) RID_AUTO) nclasses++;
+    if (specbits & 1 << (int) RID_STATIC) nclasses++;
+    if (specbits & 1 << (int) RID_EXTERN) nclasses++;
+    if (specbits & 1 << (int) RID_REGISTER) nclasses++;
+    if (specbits & 1 << (int) RID_TYPEDEF) nclasses++;
+
+    /* Warn about storage classes that are invalid for certain
+       kinds of declarations (parameters, typenames, etc.).  */
+
+    if (nclasses > 1)
+      error ("multiple storage classes in declaration of `%s'", name);
+    else if (funcdef_flag
+            && (specbits
+                & ((1 << (int) RID_REGISTER)
+                   | (1 << (int) RID_AUTO)
+                   | (1 << (int) RID_TYPEDEF))))
+      {
+       if (specbits & 1 << (int) RID_AUTO
+           && (pedantic || current_binding_level == global_binding_level))
+         pedwarn ("function definition declared `auto'");
+       if (specbits & 1 << (int) RID_REGISTER)
+         error ("function definition declared `register'");
+       if (specbits & 1 << (int) RID_TYPEDEF)
+         error ("function definition declared `typedef'");
+       specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
+                      | (1 << (int) RID_AUTO));
+      }
+    else if (decl_context != NORMAL && nclasses > 0)
+      {
+       if (decl_context == PARM && specbits & 1 << (int) RID_REGISTER)
+         ;
+       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);
+           specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
+                          | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
+                          | (1 << (int) RID_EXTERN));
+         }
+      }
+    else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
+      {
+       /* `extern' with initialization is invalid if not at top level.  */
+       if (current_binding_level == global_binding_level)
+         warning ("`%s' initialized and declared `extern'", name);
+       else
+         error ("`%s' has both `extern' and initializer", name);
+      }
+    else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag
+            && current_binding_level != global_binding_level)
+      error ("nested function `%s' declared `extern'", name);
+    else if (current_binding_level == global_binding_level
+            && specbits & (1 << (int) RID_AUTO))
+      error ("top-level declaration of `%s' specifies `auto'", name);
+  }
+
+  /* Now figure out the structure of the declarator proper.
+     Descend through it, creating more complex types, until we reach
+     the declared identifier (or NULL_TREE, in an absolute declarator).  */
+
+  while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE)
+    {
+      if (type == error_mark_node)
+       {
+         declarator = TREE_OPERAND (declarator, 0);
+         continue;
+       }
+
+      /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]),
+        an INDIRECT_REF (for *...),
+        a CALL_EXPR (for ...(...)),
+        an identifier (for the name being declared)
+        or a null pointer (for the place in an absolute declarator
+        where the name was omitted).
+        For the last two cases, we have just exited the loop.
+
+        At this point, TYPE is the type of elements of an array,
+        or for a function to return, or for a pointer to point to.
+        After this sequence of ifs, TYPE is the type of the
+        array or function or pointer, and DECLARATOR has had its
+        outermost layer removed.  */
+
+      if (TREE_CODE (declarator) == ARRAY_REF)
+       {
+         register tree itype = NULL_TREE;
+         register tree size = TREE_OPERAND (declarator, 1);
+
+         declarator = TREE_OPERAND (declarator, 0);
+
+         /* Check for some types that there cannot be arrays of.  */
+
+         if (type == void_type_node)
+           {
+             error ("declaration of `%s' as array of voids", name);
+             type = error_mark_node;
+           }
+
+         if (TREE_CODE (type) == FUNCTION_TYPE)
+           {
+             error ("declaration of `%s' as array of functions", name);
+             type = error_mark_node;
+           }
+
+         if (size == error_mark_node)
+           type = error_mark_node;
+
+         if (type == error_mark_node)
+           continue;
+
+         /* 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.  */
+
+         if (size)
+           {
+             /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
+             while (TREE_CODE (size) == NON_LVALUE_EXPR)
+               size = TREE_OPERAND (size, 0);
+
+             if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE
+                 && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE)
+               {
+                 error ("size of array `%s' has non-integer type", name);
+                 size = integer_one_node;
+               }
+             if (pedantic && integer_zerop (size))
+               pedwarn ("ANSI C forbids zero-size array `%s'", name);
+             if (TREE_CODE (size) == INTEGER_CST)
+               {
+                 if (INT_CST_LT (size, integer_zero_node))
+                   {
+                     error ("size of array `%s' is negative", name);
+                     size = integer_one_node;
+                   }
+                 itype = build_index_type (build_int_2 (TREE_INT_CST_LOW (size) - 1, 0));
+               }
+             else
+               {
+                 if (pedantic)
+                   pedwarn ("ANSI C forbids variable-size array `%s'", name);
+                 itype = build_binary_op (MINUS_EXPR, size, integer_one_node,
+                                          1);
+                 /* Make sure the array size remains visibly nonconstant
+                    even if it is (eg) a const variable with known value.  */
+                 variable_size = 1;
+                 itype = build_index_type (save_expr (itype));
+               }
+           }
+
+#if 0 /* This had bad results for pointers to arrays, as in
+        union incomplete (*foo)[4];  */
+         /* Complain about arrays of incomplete types, except in typedefs.  */
+
+         if (TYPE_SIZE (type) == 0
+             /* Avoid multiple warnings for nested array types.  */
+             && TREE_CODE (type) != ARRAY_TYPE
+             && !(specbits & (1 << (int) RID_TYPEDEF))
+             && !C_TYPE_BEING_DEFINED (type))
+           warning ("array type has incomplete element type");
+#endif
+
+         /* Build the array type itself.
+            Merge any constancy or volatility into the target type.  */
+
+#if 0  /* We shouldn't have a function type here at all!
+         Functions aren't allowed as array elements.  */
+         if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
+             && (constp || volatilep))
+           pedwarn ("ANSI C forbids const or volatile function types");
+#endif
+         if (constp || volatilep)
+           type = c_build_type_variant (type, constp, volatilep);
+
+#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;
+#endif
+
+         type = build_array_type (type, itype);
+         if (variable_size)
+           C_TYPE_VARIABLE_SIZE (type) = 1;
+       }
+      else if (TREE_CODE (declarator) == CALL_EXPR)
+       {
+         tree arg_types;
+
+         /* Declaring a function type.
+            Make sure we have a valid type for the function to return.  */
+         if (type == error_mark_node)
+           continue;
+
+         variable_size = 0;
+
+         /* Warn about some types functions can't return.  */
+
+         if (TREE_CODE (type) == FUNCTION_TYPE)
+           {
+             error ("`%s' declared as function returning a function", name);
+             type = integer_type_node;
+           }
+         if (TREE_CODE (type) == ARRAY_TYPE)
+           {
+             error ("`%s' declared as function returning an array", name);
+             type = integer_type_node;
+           }
+
+#ifndef TRADITIONAL_RETURN_FLOAT
+         /* Traditionally, declaring return type float means double.  */
+
+         if (flag_traditional && type == float_type_node)
+           type = double_type_node;
+#endif /* TRADITIONAL_RETURN_FLOAT */
+
+         /* Construct the function type and go to the next
+            inner layer of declarator.  */
+
+         arg_types = grokparms (TREE_OPERAND (declarator, 1),
+                                funcdef_flag
+                                /* Say it's a definition
+                                   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 ? 0 : arg_types);
+#endif
+         type = build_function_type (type, arg_types);
+         declarator = TREE_OPERAND (declarator, 0);
+
+         /* Set the TYPE_CONTEXTs for each tagged type which is local to
+            the formal parameter list of this FUNCTION_TYPE to point to
+            the FUNCTION_TYPE node itself.  */
+
+         {
+           register tree link;
+
+           for (link = current_function_parm_tags;
+                link;
+                link = TREE_CHAIN (link))
+             TYPE_CONTEXT (TREE_VALUE (link)) = type;
+         }
+       }
+      else if (TREE_CODE (declarator) == INDIRECT_REF)
+       {
+         /* Merge any constancy or volatility into the target type
+            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;
+         variable_size = 0;
+
+         type = build_pointer_type (type);
+
+         /* Process a list of type modifier keywords
+            (such as const or volatile) that were given inside the `*'.  */
+
+         if (TREE_TYPE (declarator))
+           {
+             register tree typemodlist;
+             int erred = 0;
+             for (typemodlist = TREE_TYPE (declarator); typemodlist;
+                  typemodlist = TREE_CHAIN (typemodlist))
+               {
+                 if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST])
+                   constp++;
+                 else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE])
+                   volatilep++;
+                 else if (!erred)
+                   {
+                     erred = 1;
+                     error ("invalid type modifier within pointer declarator");
+                   }
+               }
+             if (constp > 1)
+               warning ("duplicate `const'");
+             if (volatilep > 1)
+               warning ("duplicate `volatile'");
+           }
+
+         declarator = TREE_OPERAND (declarator, 0);
+       }
+      else
+       abort ();
+
+    }
+
+  /* Now TYPE has the actual type.  */
+
+  /* If this is declaring a typedef name, return a TYPE_DECL.  */
+
+  if (specbits & (1 << (int) RID_TYPEDEF))
+    {
+      tree decl;
+      /* 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);
+      pop_obstacks ();
+      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;
+      return decl;
+    }
+
+  /* Detect the case of an array type of unspecified size
+     which came, as such, direct from a typedef name.
+     We must copy the type, so that each identifier gets
+     a distinct type, so that each identifier's size can be
+     controlled separately by its own initializer.  */
+
+  if (type != 0 && typedef_type != 0
+      && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type)
+      && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0)
+    {
+      type = build_array_type (TREE_TYPE (type), 0);
+      if (variable_size)
+       C_TYPE_VARIABLE_SIZE (type) = 1;
+    }
+
+  /* If this is a type name (such as, in a cast or sizeof),
+     compute the type and return it now.  */
+
+  if (decl_context == TYPENAME)
+    {
+      /* 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);
+      pop_obstacks ();
+      return type;
+    }
+
+  /* `void' at top level (not within pointer)
+     is allowed only in typedefs or type names.
+     We don't complain about parms either, but that is because
+     a better error message can be made later.  */
+
+  if (type == void_type_node && decl_context != PARM)
+    {
+      error ("variable or field `%s' declared void",
+            IDENTIFIER_POINTER (declarator));
+      type = integer_type_node;
+    }
+
+  /* Now create the decl, which may be a VAR_DECL, a PARM_DECL
+     or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE.  */
+
+  {
+    register tree decl;
+
+    if (decl_context == PARM)
+      {
+       tree type_as_written = 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.  */
+
+       if (TREE_CODE (type) == ARRAY_TYPE)
+         {
+           /* Transfer const-ness of array into that of type pointed to.  */
+           type = build_pointer_type
+                   (c_build_type_variant (TREE_TYPE (type), constp, volatilep));
+           volatilep = constp = 0;
+           variable_size = 0;
+         }
+       else if (TREE_CODE (type) == FUNCTION_TYPE)
+         {
+           if (pedantic && (constp || volatilep))
+             pedwarn ("ANSI C forbids const or volatile function types");
+           type = build_pointer_type (c_build_type_variant (type, constp, volatilep));
+           volatilep = constp = 0;
+         }
+
+       if (initialized)
+         error ("parameter `%s' is initialized", name);
+
+       decl = build_decl (PARM_DECL, declarator, type);
+       if (variable_size)
+         C_DECL_VARIABLE_SIZE (decl) = 1;
+
+       /* Compute the type actually passed in the parmlist,
+          for the case where there is no prototype.
+          (For example, shorts and chars are passed as ints.)
+          When there is a prototype, this is overridden later.  */
+
+       DECL_ARG_TYPE (decl) = type;
+       if (type == float_type_node)
+         DECL_ARG_TYPE (decl) = double_type_node;
+       else if (TREE_CODE (type) == INTEGER_TYPE
+                && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
+         DECL_ARG_TYPE (decl) = integer_type_node;
+
+       DECL_ARG_TYPE_AS_WRITTEN (decl) = type_as_written;
+      }
+    else if (decl_context == FIELD)
+      {
+       /* Structure field.  It may not be a function.  */
+
+       if (TREE_CODE (type) == FUNCTION_TYPE)
+         {
+           error ("field `%s' declared as a function",
+                  IDENTIFIER_POINTER (declarator));
+           type = build_pointer_type (type);
+         }
+       else if (TREE_CODE (type) != ERROR_MARK && TYPE_SIZE (type) == 0)
+         {
+           error ("field `%s' has incomplete type",
+                  IDENTIFIER_POINTER (declarator));
+           type = error_mark_node;
+         }
+       /* Move type qualifiers down to element of an array.  */
+       if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep))
+         {
+           type = build_array_type (c_build_type_variant (TREE_TYPE (type),
+                                                          constp, volatilep),
+                                    TYPE_DOMAIN (type));
+#if 0 /* Leave the field const or volatile as well.  */
+           constp = volatilep = 0;
+#endif
+         }
+       decl = build_decl (FIELD_DECL, declarator, type);
+       if (variable_size)
+         C_DECL_VARIABLE_SIZE (decl) = 1;
+      }
+    else if (TREE_CODE (type) == FUNCTION_TYPE)
+      {
+       if (specbits & (1 << (int) RID_AUTO)
+           && (pedantic || current_binding_level == global_binding_level))
+         pedwarn ("invalid storage class for function `%s'",
+                IDENTIFIER_POINTER (declarator));
+       if (specbits & (1 << (int) RID_REGISTER))
+         error ("invalid storage class for function `%s'",
+                IDENTIFIER_POINTER (declarator));
+       /* Function declaration not at top level.
+          Storage classes other than `extern' are not allowed
+          and `extern' makes no difference.  */
+       if (current_binding_level != global_binding_level
+           && (specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE)))
+           && pedantic)
+         pedwarn ("invalid storage class for function `%s'",
+                  IDENTIFIER_POINTER (declarator));
+       decl = build_decl (FUNCTION_DECL, declarator, type);
+
+       if (pedantic && (constp || volatilep))
+         pedwarn ("ANSI C forbids const or volatile functions");
+
+       /* Every function declaration is "external"
+          except for those which are inside a function body
+          in which `auto' is used.
+          That is a case not specified by ANSI C,
+          and we use it for forward declarations for nested functions.  */
+       if (!(specbits & (1 << (int) RID_AUTO))
+           || current_binding_level == global_binding_level)
+         TREE_EXTERNAL (decl) = 1;
+       /* Record absence of global scope for `static' or `auto'.  */
+       TREE_PUBLIC (decl)
+         = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO)));
+       /* Record presence of `inline', if it is reasonable.  */
+       if (inlinep)
+         {
+           tree last = tree_last (TYPE_ARG_TYPES (type));
+
+           if (! strcmp (IDENTIFIER_POINTER (declarator), "main"))
+             warning ("cannot inline function `main'");
+           else if (last && TREE_VALUE (last) != void_type_node)
+             warning ("inline declaration ignored for function with `...'");
+           else
+             /* Assume that otherwise the function can be inlined.  */
+             TREE_INLINE (decl) = 1;
+
+           if (specbits & (1 << (int) RID_EXTERN))
+             current_extern_inline = 1;
+         }
+      }
+    else
+      {
+       /* It's a variable.  */
+
+       /* Move type qualifiers down to element of an array.  */
+       if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep))
+         {
+           type = build_array_type (c_build_type_variant (TREE_TYPE (type),
+                                                          constp, volatilep),
+                                    TYPE_DOMAIN (type));
+#if 0 /* Leave the variable const or volatile as well.  */
+           constp = volatilep = 0;
+#endif
+         }
+
+       decl = build_decl (VAR_DECL, declarator, type);
+       if (variable_size)
+         C_DECL_VARIABLE_SIZE (decl) = 1;
+
+       if (inlinep)
+         pedwarn_with_decl (decl, "variable `%s' declared `inline'");
+
+       /* An uninitialized decl with `extern' is a reference.  */
+       TREE_EXTERNAL (decl)
+         = !initialized && (specbits & (1 << (int) RID_EXTERN));
+       /* At top level, either `static' or no s.c. makes a definition
+          (perhaps tentative), and absence of `static' makes it public.  */
+       if (current_binding_level == global_binding_level)
+         {
+           TREE_PUBLIC (decl) = !(specbits & (1 << (int) RID_STATIC));
+           TREE_STATIC (decl) = ! TREE_EXTERNAL (decl);
+         }
+       /* Not at top level, only `static' makes a static definition.  */
+       else
+         {
+           TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0;
+           TREE_PUBLIC (decl) = TREE_EXTERNAL (decl);
+         }
+      }
+
+    /* Record `register' declaration for warnings on &
+       and in case doing stupid register allocation.  */
+
+    if (specbits & (1 << (int) RID_REGISTER))
+      TREE_REGDECL (decl) = 1;
+
+    /* Record constancy and volatility.  */
+
+    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;
+  }
+}
+\f
+/* Make a variant type in the proper way for C, propagating qualifiers
+   down to the element type of an array.  */
+
+tree
+c_build_type_variant (type, constp, volatilep)
+     tree type;
+     int constp, volatilep;
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    type = build_array_type (c_build_type_variant (TREE_TYPE (type),
+                                                  constp, volatilep),
+                            TYPE_DOMAIN (type));
+  return build_type_variant (type, constp, volatilep);
+}
+\f
+/* Decode the parameter-list info for a function type or function definition.
+   The argument is the value returned by `get_parm_info' (or made in parse.y
+   if there is an identifier list instead of a parameter decl list).
+   These two functions are separate because when a function returns
+   or receives functions then each is called multiple times but the order
+   of calls is different.  The last call to `grokparms' is always the one
+   that contains the formal parameter names of a function definition.
+
+   Store in `last_function_parms' a chain of the decls of parms.
+   Also store in `last_function_parm_tags' a chain of the struct, union,
+   and enum tags declared among the parms.
+
+   Return a list of arg types to use in the FUNCTION_TYPE for this function.
+
+   FUNCDEF_FLAG is nonzero for a function definition, 0 for
+   a mere declaration.  A nonempty identifier-list gets an error message
+   when FUNCDEF_FLAG is zero.  */
+
+static tree
+grokparms (parms_info, funcdef_flag)
+     tree parms_info;
+     int funcdef_flag;
+{
+  tree first_parm = TREE_CHAIN (parms_info);
+
+  last_function_parms = TREE_PURPOSE (parms_info);
+  last_function_parm_tags = TREE_VALUE (parms_info);
+
+  if (warn_strict_prototypes && first_parm == 0 && !funcdef_flag)
+    warning ("function declaration isn't a prototype");
+
+  if (first_parm != 0
+      && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE)
+    {
+      if (! funcdef_flag)
+       pedwarn ("parameter names (without types) in function declaration");
+
+      last_function_parms = first_parm;
+      return 0;
+    }
+  else
+    {
+      tree parm;
+      tree typelt;
+      /* We no longer test FUNCDEF_FLAG.
+        If the arg types are incomplete in a declaration,
+        they must include undefined tags.
+        These tags can never be defined in the scope of the declaration,
+        so the types can never be completed,
+        and no call can be compiled successfully.  */
+#if 0
+      /* In a fcn definition, arg types must be complete.  */
+      if (funcdef_flag)
+#endif
+       for (parm = last_function_parms, typelt = first_parm;
+            parm;
+            parm = TREE_CHAIN (parm))
+         /* Skip over any enumeration constants declared here.  */
+         if (TREE_CODE (parm) == PARM_DECL)
+           {
+             /* Barf if the parameter itself has an incomplete type.  */
+             tree type = TREE_VALUE (typelt);
+             if (TYPE_SIZE (type) == 0)
+               {
+                 if (funcdef_flag && DECL_NAME (parm) != 0)
+                   error ("parameter `%s' has incomplete type",
+                          IDENTIFIER_POINTER (DECL_NAME (parm)));
+                 else
+                   warning ("parameter has incomplete type");
+                 if (funcdef_flag)
+                   {
+                     TREE_VALUE (typelt) = error_mark_node;
+                     TREE_TYPE (parm) = error_mark_node;
+                   }
+               }
+#if 0  /* This has been replaced by parm_tags_warning
+         which uses a more accurate criterion for what to warn about.  */
+             else
+               {
+                 /* Now warn if is a pointer to an incomplete type.  */
+                 while (TREE_CODE (type) == POINTER_TYPE
+                        || TREE_CODE (type) == REFERENCE_TYPE)
+                   type = TREE_TYPE (type);
+                 type = TYPE_MAIN_VARIANT (type);
+                 if (TYPE_SIZE (type) == 0)
+                   {
+                     if (DECL_NAME (parm) != 0)
+                       warning ("parameter `%s' points to incomplete type",
+                                IDENTIFIER_POINTER (DECL_NAME (parm)));
+                     else
+                       warning ("parameter points to incomplete type");
+                   }
+               }
+#endif
+             typelt = TREE_CHAIN (typelt);
+           }
+
+      return first_parm;
+    }
+}
+
+
+/* Return a tree_list node with info on a parameter list just parsed.
+   The TREE_PURPOSE is a chain of decls of those parms.
+   The TREE_VALUE is a list of structure, union and enum tags defined.
+   The TREE_CHAIN is a list of argument types to go in the FUNCTION_TYPE.
+   This tree_list node is later fed to `grokparms'.
+
+   VOID_AT_END nonzero means append `void' to the end of the type-list.
+   Zero means the parmlist ended with an ellipsis so don't append `void'.  */
+
+tree
+get_parm_info (void_at_end)
+     int void_at_end;
+{
+  register tree decl, t;
+  register tree types = 0;
+  int erred = 0;
+  tree tags = gettags ();
+  tree parms = getdecls ();
+  tree new_parms = 0;
+  tree order = current_binding_level->parm_order;
+
+  /* Just `void' (and no ellipsis) is special.  There are really no parms.  */
+  if (void_at_end && parms != 0
+      && TREE_CHAIN (parms) == 0
+      && TREE_TYPE (parms) == void_type_node
+      && DECL_NAME (parms) == 0)
+    {
+      parms = NULL_TREE;
+      storedecls (NULL_TREE);
+      return saveable_tree_cons (NULL_TREE, NULL_TREE,
+                                saveable_tree_cons (NULL_TREE, void_type_node, NULL_TREE));
+    }
+
+  /* Extract enumerator values and other non-parms declared with the parms.  */
+  for (decl = parms; decl; )
+    {
+      tree next = TREE_CHAIN (decl);
+
+      if (TREE_CODE (decl) != PARM_DECL)
+       {
+         TREE_CHAIN (decl) = new_parms;
+         new_parms = decl;
+       }
+      decl = next;
+    }
+
+  /* Put the parm decls back in the order they were in in the parm list.  */
+  for (t = order; t; t = TREE_CHAIN (t))
+    {
+      if (TREE_CHAIN (t))
+       TREE_CHAIN (TREE_VALUE (t)) = TREE_VALUE (TREE_CHAIN (t));
+      else
+       TREE_CHAIN (TREE_VALUE (t)) = 0;
+    }
+
+  new_parms = chainon (order ? nreverse (TREE_VALUE (order)) : 0,
+                      new_parms);
+
+  /* Store the parmlist in the binding level since the old one
+     is no longer a valid list.  (We have changed the chain pointers.)  */
+  storedecls (new_parms);
+
+  for (decl = new_parms; decl; decl = TREE_CHAIN (decl))
+    /* There may also be declarations for enumerators if an enumeration
+       type is declared among the parms.  Ignore them here.  */
+    if (TREE_CODE (decl) == PARM_DECL)
+      {
+       /* Since there is a prototype,
+          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
+           && 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);
+       if (TREE_VALUE (types) == void_type_node && ! erred
+           && DECL_NAME (decl) == 0)
+         {
+           error ("`void' in parameter list must be the entire list");
+           erred = 1;
+         }
+      }
+
+  if (void_at_end)
+    return saveable_tree_cons (new_parms, tags,
+                              nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types)));
+
+  return saveable_tree_cons (new_parms, tags, nreverse (types));
+}
+
+/* At end of parameter list, warn about any struct, union or enum tags
+   defined within.  Do so because these types cannot ever become complete.  */
+
+void
+parmlist_tags_warning ()
+{
+  tree elt;
+  static int already;
+
+  for (elt = current_binding_level->tags; elt; elt = TREE_CHAIN (elt))
+    {
+      enum tree_code code = TREE_CODE (TREE_VALUE (elt));
+      warning ("`%s %s' declared inside parameter list",
+              (code == RECORD_TYPE ? "struct"
+               : code == UNION_TYPE ? "union"
+               : "enum"),
+              IDENTIFIER_POINTER (TREE_PURPOSE (elt)));
+      if (! already)
+       {
+         warning ("its scope is only this definition or declaration,");
+         warning ("which is probably not what you want.");
+         already = 1;
+       }
+    }
+}
+\f
+/* Get the struct, enum or union (CODE says which) with tag NAME.
+   Define the tag as a forward-reference if it is not defined.  */
+
+tree
+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.  */
+
+  register tree ref = lookup_tag (code, name, current_binding_level, 0);
+  /* Even if this is the wrong type of tag, return what we found.
+     There will be an error message anyway, from pending_xref_error.
+     If we create an empty xref just for an invalid use of the type,
+     the main result is to create lots of superflous error messages.  */
+  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,
+     the forward-reference will be altered into a real type.  */
+
+  ref = make_node (code);
+  if (code == ENUMERAL_TYPE)
+    {
+      /* (In ANSI, Enums can be referred to only if already defined.)  */
+      if (pedantic)
+       pedwarn ("ANSI C forbids forward references to `enum' types");
+      /* Give the type a default layout like unsigned int
+        to avoid crashing if it does not get defined.  */
+      TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node);
+      TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node);
+      TREE_UNSIGNED (ref) = 1;
+      TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node);
+      TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node);
+      TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node);
+    }
+
+  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.  */
+
+tree
+start_struct (code, name)
+     enum tree_code code;
+     tree name;
+{
+  /* If there is already a tag defined at this binding level
+     (as a forward reference), just return it.  */
+
+  register tree ref = 0;
+
+  if (name != 0)
+    ref = lookup_tag (code, name, current_binding_level, 1);
+  if (ref && TREE_CODE (ref) == code)
+    {
+      C_TYPE_BEING_DEFINED (ref) = 1;
+      if (TYPE_FIELDS (ref))
+       error ((code == UNION_TYPE ? "redefinition of `union %s'"
+               : "redefinition of `struct %s'"),
+              IDENTIFIER_POINTER (name));
+
+      return ref;
+    }
+
+  /* Otherwise create a forward-reference just so the tag is in scope.  */
+
+  ref = make_node (code);
+  pushtag (name, ref);
+  C_TYPE_BEING_DEFINED (ref) = 1;
+  return ref;
+}
+
+/* Process the specs, declarator (NULL if omitted) and width (NULL if omitted)
+   of a structure component, returning a FIELD_DECL node.
+   WIDTH is non-NULL for bit fields only, and is an INTEGER_CST node.
+
+   This is done during the parsing of the struct declaration.
+   The FIELD_DECL nodes are chained together and the lot of them
+   are ultimately passed to `build_struct' to make the RECORD_TYPE node.  */
+
+tree
+grokfield (filename, line, declarator, declspecs, width)
+     char *filename;
+     int line;
+     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, NULL);
+  DECL_INITIAL (value) = width;
+
+  return value;
+}
+\f
+/* Function to help qsort sort FIELD_DECLs by name order.  */
+
+static int
+field_decl_cmp (x, y)
+     tree *x, *y;
+{
+  return (long)DECL_NAME (*x) - (long)DECL_NAME (*y);
+}
+
+/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
+   FIELDLIST is a chain of FIELD_DECL nodes for the fields.  */
+
+tree
+finish_struct (t, fieldlist)
+     register tree t, fieldlist;
+{
+  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,
+     make sure we lay it out again.  */
+
+  TYPE_SIZE (t) = 0;
+
+  /* Nameless union parm types are useful as GCC extension.  */
+  if (! (TREE_CODE (t) == UNION_TYPE && TYPE_NAME (t) == 0) && !pedantic)
+    /* Otherwise, warn about any struct or union def. in parmlist.  */
+    if (in_parm_level_p ())
+      {
+       if (pedantic)
+         pedwarn ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms"
+                   : "structure defined inside parms"));
+       else
+         warning ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms"
+                   : "structure defined inside parms"));
+      }
+
+  old_momentary = suspend_momentary ();
+
+  if (fieldlist == 0 && pedantic)
+    pedwarn ((TREE_CODE (t) == UNION_TYPE ? "union has no members"
+             : "structure has no members"));
+
+  /* Install struct as DECL_CONTEXT of each field decl.
+     Also process specified field sizes.
+     Set DECL_FRAME_SIZE to the specified size, or 0 if none specified.
+     The specified size is found in the DECL_INITIAL.
+     Store 0 there, except for ": 0" fields (so we can find them
+     and delete them, below).  */
+
+  for (x = fieldlist; x; x = TREE_CHAIN (x))
+    {
+      DECL_CONTEXT (x) = t;
+      DECL_FRAME_SIZE (x) = 0;
+
+      /* If any field is const, the structure type is pseudo-const.  */
+      if (TREE_READONLY (x))
+       C_TYPE_FIELDS_READONLY (t) = 1;
+      else
+       {
+         /* A field that is pseudo-const makes the structure likewise.  */
+         tree t1 = TREE_TYPE (x);
+         while (TREE_CODE (t1) == ARRAY_TYPE)
+           t1 = TREE_TYPE (t1);
+         if ((TREE_CODE (t1) == RECORD_TYPE || TREE_CODE (t1) == UNION_TYPE)
+             && C_TYPE_FIELDS_READONLY (t1))
+           C_TYPE_FIELDS_READONLY (t) = 1;
+       }
+
+      /* Any field that is volatile means variables of this type must be
+        treated in some ways as volatile.  */
+      if (TREE_THIS_VOLATILE (x))
+       C_TYPE_FIELDS_VOLATILE (t) = 1;
+
+      /* Any field of nominal variable size implies structure is too.  */
+      if (C_DECL_VARIABLE_SIZE (x))
+       C_TYPE_VARIABLE_SIZE (t) = 1;
+
+      /* Detect invalid bit-field size.  */
+      while (DECL_INITIAL (x)
+            && TREE_CODE (DECL_INITIAL (x)) == NON_LVALUE_EXPR)
+       DECL_INITIAL (x) = TREE_OPERAND (DECL_INITIAL (x), 0);
+      if (DECL_INITIAL (x) && TREE_CODE (DECL_INITIAL (x)) != INTEGER_CST)
+       {
+         error_with_decl (x, "bit-field `%s' width not an integer constant");
+         DECL_INITIAL (x) = NULL;
+       }
+
+      /* Detect invalid bit-field type.  */
+      if (DECL_INITIAL (x)
+         && TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE
+         && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE)
+       {
+         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)
+       pedwarn_with_decl (x, "bit-field `%s' type invalid in ANSI C");
+
+      /* Detect and ignore out of range field width.  */
+      if (DECL_INITIAL (x))
+       {
+         register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
+
+         if (width < 0)
+           {
+             DECL_INITIAL (x) = NULL;
+             error_with_decl (x, "negative width in bit-field `%s'");
+           }
+         else if (width == 0 && DECL_NAME (x) != 0)
+           {
+             error_with_decl (x, "zero width for bit-field `%s'");
+             DECL_INITIAL (x) = NULL;
+           }
+         else if (width > TYPE_PRECISION (TREE_TYPE (x)))
+           {
+             DECL_INITIAL (x) = NULL;
+             pedwarn_with_decl (x, "width of `%s' exceeds its type");
+           }
+       }
+
+      /* Process valid field width.  */
+      if (DECL_INITIAL (x))
+       {
+         register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
+
+         DECL_FRAME_SIZE (x) = width;
+         DECL_BIT_FIELD (x) = 1;
+         DECL_INITIAL (x) = NULL;
+
+         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);
+#endif
+#ifdef PCC_BITFIELD_TYPE_MATTERS
+             DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
+                                   TYPE_ALIGN (TREE_TYPE (x)));
+#endif
+           }
+       }
+      else
+       /* Non-bit-fields are aligned for their type.  */
+       DECL_ALIGN (x) = MAX (DECL_ALIGN (x), TYPE_ALIGN (TREE_TYPE (x)));
+    }
+
+  /* Now DECL_INITIAL is null on all members.  */
+
+  /* Delete all duplicate fields from the fieldlist */
+  for (x = fieldlist; x && TREE_CHAIN (x);)
+    /* Anonymous fields aren't duplicates.  */
+    if (DECL_NAME (TREE_CHAIN (x)) == 0)
+      x = TREE_CHAIN (x);
+    else
+      {
+       register tree y = fieldlist;
+         
+       while (1)
+         {
+           if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x)))
+             break;
+           if (y == x)
+             break;
+           y = TREE_CHAIN (y);
+         }
+       if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x)))
+         {
+           error_with_decl (TREE_CHAIN (x), "duplicate member `%s'");
+           TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x));
+         }
+       else x = TREE_CHAIN (x);
+      }
+
+  /* Now we have the nearly final fieldlist.  Record it,
+     then lay out the structure or union (including the fields).  */
+
+  TYPE_FIELDS (t) = fieldlist;
+
+  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);
+    }
+
+  /*  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);
+      TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
+      TYPE_ALIGN (x) = TYPE_ALIGN (t);
+    }
+
+  /* Promote each bit-field's type to int if it is narrower than that.  */
+  for (x = fieldlist; x; x = TREE_CHAIN (x))
+    if (DECL_BIT_FIELD (x)
+       && TREE_CODE (TREE_TYPE (x)) == INTEGER_TYPE
+       && (TREE_INT_CST_LOW (DECL_SIZE (x))
+           < TYPE_PRECISION (integer_type_node)))
+      TREE_TYPE (x) = integer_type_node;
+
+  /* If this structure or union completes the type of any previous
+     variable declaration, lay it out and output its rtl.  */
+
+  if (current_binding_level->n_incomplete != 0)
+    {
+      tree decl;
+      for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl))
+       {
+         if (TREE_TYPE (decl) == t
+             && TREE_CODE (decl) != TYPE_DECL)
+           {
+             layout_decl (decl, 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, 0, toplevel, 0);
+             if (! toplevel)
+               expand_decl (decl);
+             --current_binding_level->n_incomplete;
+           }
+         else if (TYPE_SIZE (TREE_TYPE (decl)) == 0
+                  && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+           {
+             tree element = TREE_TYPE (decl);
+             while (TREE_CODE (element) == ARRAY_TYPE)
+               element = TREE_TYPE (element);
+             if (element == t)
+               layout_array_type (TREE_TYPE (decl));
+           }
+       }
+    }
+
+  resume_momentary (old_momentary);
+
+  /* Finish debugging output for this type.  */
+  rest_of_type_compilation (t, toplevel);
+
+  return t;
+}
+
+/* Lay out the type T, and its element type, and so on.  */
+
+static void
+layout_array_type (t)
+     tree t;
+{
+  if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+    layout_array_type (TREE_TYPE (t));
+  layout_type (t);
+}
+\f
+/* Begin compiling the definition of an enumeration type.
+   NAME is its name (or null if anonymous).
+   Returns the type object, as yet incomplete.
+   Also records info about it so that build_enumerator
+   may be used to declare the individual values as they are read.  */
+
+tree
+start_enum (name)
+     tree name;
+{
+  register tree enumtype = 0;
+
+  /* If this is the real definition for a previous forward reference,
+     fill in the contents in the same object that used to be the
+     forward reference.  */
+
+  if (name != 0)
+    enumtype = lookup_tag (ENUMERAL_TYPE, name, current_binding_level, 1);
+
+  if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE)
+    {
+      enumtype = make_node (ENUMERAL_TYPE);
+      pushtag (name, enumtype);
+    }
+
+  C_TYPE_BEING_DEFINED (enumtype) = 1;
+
+  if (TYPE_VALUES (enumtype) != 0)
+    {
+      /* This enum is a named one that has been declared already.  */
+      error ("redeclaration of `enum %s'", IDENTIFIER_POINTER (name));
+
+      /* Completely replace its old definition.
+        The old enumerators remain defined, however.  */
+      TYPE_VALUES (enumtype) = 0;
+    }
+
+  enum_next_value = integer_zero_node;
+
+  return enumtype;
+}
+
+/* After processing and defining all the values of an enumeration type,
+   install their decls in the enumeration type and finish it off.
+   ENUMTYPE is the type object and VALUES a list of decl-value pairs.
+   Returns ENUMTYPE.  */
+
+tree
+finish_enum (enumtype, values)
+     register tree enumtype, values;
+{
+  register tree pair;
+  tree minnode = 0, maxnode = 0;
+  register long maxvalue = 0;
+  register long minvalue = 0;
+  register int i;
+  unsigned precision = 0;
+  int toplevel = global_binding_level == current_binding_level;
+
+  if (in_parm_level_p ())
+    warning ("enum defined inside parms");
+
+  /* Calculate the maximum value of any enumerator in this type.  */
+
+  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;
+
+  /* Determine the precision this type needs.  */
+
+  if (TREE_INT_CST_HIGH (minnode) >= 0
+      ? tree_int_cst_lt (TYPE_MAX_VALUE (unsigned_type_node), maxnode)
+      : (tree_int_cst_lt (minnode, TYPE_MIN_VALUE (integer_type_node))
+        || tree_int_cst_lt (TYPE_MAX_VALUE (integer_type_node), maxnode)))
+    precision = TYPE_PRECISION (long_long_integer_type_node);
+  else
+    {
+      int maxvalue = TREE_INT_CST_LOW (maxnode);
+      int minvalue = TREE_INT_CST_LOW (minnode);
+
+      if (maxvalue > 0)
+       precision = floor_log2 (maxvalue) + 1;
+      if (minvalue < 0)
+       {
+         /* Compute number of bits to represent magnitude of a negative value.
+            Add one to MINVALUE since range of negative numbers
+            includes the power of two.  */
+         unsigned negprecision = floor_log2 (-minvalue - 1) + 1;
+         if (negprecision > precision)
+           precision = negprecision;
+         precision += 1;       /* room for sign bit */
+       }
+
+      if (!precision)
+       precision = 1;
+    }
+
+  if (flag_short_enums || precision > TYPE_PRECISION (integer_type_node))
+    /* Use the width of the narrowest normal C type which is wide enough.  */
+    TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size (precision, 1));
+  else
+    TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
+
+  TYPE_SIZE (enumtype) = 0;
+  layout_type (enumtype);
+
+  /* An enum can have some negative values; then it is signed.  */
+  TREE_UNSIGNED (enumtype) = ! tree_int_cst_lt (minnode, integer_zero_node);
+
+  /* If the enumerators might not fit in an int, change their type now.  */
+  /* It seems more useful in the debugger to leave these as int
+     unless the enumerator is wider than int.  */
+  if (TYPE_PRECISION (enumtype) <= TYPE_PRECISION (integer_type_node))
+    for (pair = values; pair; pair = TREE_CHAIN (pair))
+      {
+       TREE_TYPE (TREE_PURPOSE (pair)) = enumtype;
+       DECL_SIZE (TREE_PURPOSE (pair)) = TYPE_SIZE (enumtype);
+       DECL_ALIGN (TREE_PURPOSE (pair)) = TYPE_ALIGN (enumtype);
+      }
+
+  /* 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));
+
+  TYPE_VALUES (enumtype) = values;
+
+  /* Finish debugging output for this type.  */
+  rest_of_type_compilation (enumtype, toplevel);
+
+  return enumtype;
+}
+
+/* Build and install a CONST_DECL for one value of the
+   current enumeration type (one that was begun with start_enum).
+   Return a tree-list containing the CONST_DECL and its value.
+   Assignment of sequential values by default is handled here.  */
+
+tree
+build_enumerator (name, value)
+     tree name, value;
+{
+  register tree decl;
+
+  /* Validate and default VALUE.  */
+
+  /* Remove no-op casts from the value.  */
+  while (value != 0
+        && (TREE_CODE (value) == NOP_EXPR
+            || TREE_CODE (value) == NON_LVALUE_EXPR))
+    value = TREE_OPERAND (value, 0);
+
+  if (value != 0 && TREE_CODE (value) != INTEGER_CST)
+    {
+      error ("enumerator value for `%s' not integer constant",
+            IDENTIFIER_POINTER (name));
+      value = 0;
+    }
+
+  /* Default based on previous value.  */
+  /* It should no longer be possible to have NON_LVALUE_EXPR
+     in the default.  */
+  if (value == 0)
+    value = enum_next_value;
+
+  if (pedantic && ! int_fits_type_p (value, integer_type_node))
+    {
+      pedwarn ("ANSI C restricts enumerator values to range of `int'");
+      value = integer_zero_node;
+    }
+
+  /* Set basis for default for next value.  */
+  enum_next_value = build_binary_op (PLUS_EXPR, value, integer_one_node, 0);
+
+  /* Now create a declaration for the enum value name.  */
+
+  decl = build_decl (CONST_DECL, name, integer_type_node);
+  DECL_INITIAL (decl) = value;
+  TREE_TYPE (value) = integer_type_node;
+  pushdecl (decl);
+
+  return saveable_tree_cons (decl, value, NULL);
+}
+\f
+/* Create the FUNCTION_DECL for a function definition.
+   DECLSPECS and DECLARATOR are the parts of the declaration;
+   they describe the function's name and the type it returns,
+   but twisted together in a fashion that parallels the syntax of C.
+
+   This function creates a binding context for the function body
+   as well as setting up the FUNCTION_DECL in current_function_decl.
+
+   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.  */
+
+int
+start_function (declspecs, declarator, nested)
+     tree declarator, declspecs;
+     int nested;
+{
+  tree decl1, old_decl;
+  tree restype;
+
+  current_function_returns_value = 0;  /* Assume, until we see it does. */
+  current_function_returns_null = 0;
+  warn_about_return_type = 0;
+  current_extern_inline = 0;
+  c_function_varargs = 0;
+  named_labels = 0;
+  shadowed_labels = 0;
+
+  decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1);
+
+  /* If the declarator is not suitable for a function definition,
+     cause a syntax error.  */
+  if (decl1 == 0)
+    return 0;
+
+  announce_function (decl1);
+
+  if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl1))) == 0)
+    {
+      error ("return-type is an incomplete type");
+      /* Make it return void instead.  */
+      TREE_TYPE (decl1)
+       = build_function_type (void_type_node,
+                              TYPE_ARG_TYPES (TREE_TYPE (decl1)));
+    }
+
+  if (warn_about_return_type)
+    warning ("return-type defaults to `int'");
+
+  /* Save the parm names or decls from this function's declarator
+     where store_parm_decls will find them.  */
+  current_function_parms = last_function_parms;
+  current_function_parm_tags = last_function_parm_tags;
+
+  /* Make the init_value nonzero so pushdecl knows this is not tentative.
+     error_mark_node is replaced below (in poplevel) with the BLOCK.  */
+  DECL_INITIAL (decl1) = error_mark_node;
+
+  /* If this definition isn't a prototype and we had a prototype declaration
+     before, copy the arg type info from that prototype.
+     But not if what we had before was a builtin function.  */
+  old_decl = lookup_name_current_level (DECL_NAME (decl1));
+  if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
+      && !DECL_BUILT_IN (old_decl)
+      && TREE_TYPE (TREE_TYPE (decl1)) == TREE_TYPE (TREE_TYPE (old_decl))
+      && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0)
+    TREE_TYPE (decl1) = TREE_TYPE (old_decl);
+
+  /* Optionally warn of old-fashioned def with no previous prototype.  */
+  if (warn_strict_prototypes
+      && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0
+      && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0))
+    warning ("function declaration isn't a prototype");
+  /* Optionally warn of any global def with no previous prototype.  */
+  else if (warn_missing_prototypes
+          && TREE_PUBLIC (decl1)
+          && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0))
+    warning_with_decl (decl1, "no previous prototype for `%s'");
+  /* Optionally warn of any def with no previous prototype
+     if the function has already been used.  */
+  else if (warn_missing_prototypes
+          && old_decl != 0 && TREE_USED (old_decl)
+          && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0))
+    warning_with_decl (decl1, "`%s' was used with no prototype before its definition");
+
+  /* This is a definition, not a reference.
+     So normally clear TREE_EXTERNAL.
+     However, `extern inline' acts like a declaration
+     except for defining how to inline.  So set TREE_EXTERNAL in that case.  */
+  TREE_EXTERNAL (decl1) = current_extern_inline;
+
+  /* This function exists in static storage.
+     (This does not mean `static' in the C sense!)  */
+  TREE_STATIC (decl1) = 1;
+
+  /* A nested function is not global.  */
+  if (current_function_decl != 0)
+    TREE_PUBLIC (decl1) = 0;
+
+  /* Record the decl so that the function name is defined.
+     If we already have a decl for this name, and it is a FUNCTION_DECL,
+     use the old decl.  */
+
+  current_function_decl = pushdecl (decl1);
+
+  pushlevel (0);
+  declare_parm_level (1);
+  current_binding_level->subblocks_tag_transparent = 1;
+
+  make_function_rtl (current_function_decl);
+
+  restype = TREE_TYPE (TREE_TYPE (current_function_decl));
+  /* Promote the value to int before returning it.  */
+  if (TREE_CODE (restype) == INTEGER_TYPE
+      && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node))
+    restype = integer_type_node;
+  DECL_RESULT (current_function_decl) = build_decl (RESULT_DECL, 0, 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)))
+    TREE_ADDRESSABLE (current_function_decl) = 1;
+
+  return 1;
+}
+
+/* Record that this function is going to be a varargs function.
+   This is called before store_parm_decls, which is too early
+   to call mark_varargs directly.  */
+
+void
+c_mark_varargs ()
+{
+  c_function_varargs = 1;
+}
+\f
+/* Store the parameter declarations into the current function declaration.
+   This is called after parsing the parameter declarations, before
+   digesting the body of the function.
+
+   For an old-style definition, modify the function's type
+   to specify at least the number of arguments.  */
+
+void
+store_parm_decls ()
+{
+  register tree fndecl = current_function_decl;
+  register tree parm;
+
+  /* This is either a chain of PARM_DECLs (if a prototype was used)
+     or a list of IDENTIFIER_NODEs (for an old-fashioned C definition).  */
+  tree specparms = current_function_parms;
+
+  /* This is a list of types declared among parms in a prototype.  */
+  tree parmtags = current_function_parm_tags;
+
+  /* This is a chain of PARM_DECLs from old-style parm declarations.  */
+  register tree parmdecls = getdecls ();
+
+  /* This is a chain of any other decls that came in among the parm
+     declarations.  If a parm is declared with  enum {foo, bar} x;
+     then CONST_DECLs for foo and bar are put here.  */
+  tree nonparms = 0;
+
+  /* Nonzero if this definition is written with a prototype.  */
+  int prototype = 0;
+
+  if (specparms != 0 && TREE_CODE (specparms) != TREE_LIST)
+    {
+      /* This case is when the function was defined with an ANSI prototype.
+        The parms already have decls, so we need not do anything here
+        except record them as in effect
+        and complain if any redundant old-style parm decls were written.  */
+
+      register tree next;
+      tree others = 0;
+
+      prototype = 1;
+
+      if (parmdecls != 0)
+       error_with_decl (fndecl,
+                        "parm types given both in parmlist and separately");
+
+      specparms = nreverse (specparms);
+      for (parm = specparms; parm; parm = next)
+       {
+         next = TREE_CHAIN (parm);
+         if (TREE_CODE (parm) == PARM_DECL)
+           {
+             if (DECL_NAME (parm) == 0)
+               error_with_decl (parm, "parameter name omitted");
+             else if (TREE_TYPE (parm) == void_type_node)
+               error_with_decl (parm, "parameter `%s' declared void");
+             pushdecl (parm);
+           }
+         else
+           {
+             /* If we find an enum constant or a type tag,
+                put it aside for the moment.  */
+             TREE_CHAIN (parm) = 0;
+             others = chainon (others, parm);
+           }
+       }
+
+      /* Get the decls in their original chain order
+        and record in the function.  */
+      DECL_ARGUMENTS (fndecl) = getdecls ();
+
+#if 0
+      /* If this function takes a variable number of arguments,
+        add a phony parameter to the end of the parm list,
+        to represent the position of the first unnamed argument.  */
+      if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl))))
+         != void_type_node)
+       {
+         tree dummy = build_decl (PARM_DECL, NULL_TREE, void_type_node);
+         /* Let's hope the address of the unnamed parm
+            won't depend on its type.  */
+         TREE_TYPE (dummy) = integer_type_node;
+         DECL_ARG_TYPE (dummy) = integer_type_node;
+         DECL_ARGUMENTS (fndecl)
+           = chainon (DECL_ARGUMENTS (fndecl), dummy);
+       }
+#endif
+
+      /* Now pushdecl the enum constants.  */
+      for (parm = others; parm; parm = next)
+       {
+         next = TREE_CHAIN (parm);
+         if (DECL_NAME (parm) == 0)
+           ;
+         else if (TREE_TYPE (parm) == void_type_node)
+           ;
+         else if (TREE_CODE (parm) != PARM_DECL)
+           pushdecl (parm);
+       }
+
+      storetags (chainon (parmtags, gettags ()));
+    }
+  else
+    {
+      /* SPECPARMS is an identifier list--a chain of TREE_LIST nodes
+        each with a parm name as the TREE_VALUE.
+
+        PARMDECLS is a chain of declarations for parameters.
+        Warning! It can also contain CONST_DECLs which are not parameters
+        but are names of enumerators of any enum types
+        declared among the parameters.
+
+        First match each formal parameter name with its declaration.
+        Associate decls with the names and store the decls
+        into the TREE_PURPOSE slots.  */
+
+      for (parm = parmdecls; parm; parm = TREE_CHAIN (parm))
+       DECL_RESULT (parm) = 0;
+
+      for (parm = specparms; parm; parm = TREE_CHAIN (parm))
+       {
+         register tree tail, found = NULL;
+
+         if (TREE_VALUE (parm) == 0)
+           {
+             error_with_decl (fndecl, "parameter name missing from parameter list");
+             TREE_PURPOSE (parm) = 0;
+             continue;
+           }
+
+         /* See if any of the parmdecls specifies this parm by name.
+            Ignore any enumerator decls.  */
+         for (tail = parmdecls; tail; tail = TREE_CHAIN (tail))
+           if (DECL_NAME (tail) == TREE_VALUE (parm)
+               && TREE_CODE (tail) == PARM_DECL)
+             {
+               found = tail;
+               break;
+             }
+
+         /* If declaration already marked, we have a duplicate name.
+            Complain, and don't use this decl twice.   */
+         if (found && DECL_RESULT (found) != 0)
+           {
+             error_with_decl (found, "multiple parameters named `%s'");
+             found = 0;
+           }
+
+         /* If the declaration says "void", complain and ignore it.  */
+         if (found && TREE_TYPE (found) == void_type_node)
+           {
+             error_with_decl (found, "parameter `%s' declared void");
+             TREE_TYPE (found) = integer_type_node;
+             DECL_ARG_TYPE (found) = integer_type_node;
+             layout_decl (found, 0);
+           }
+
+         /* Traditionally, a parm declared float is actually a double.  */
+         if (found && flag_traditional
+             && TREE_TYPE (found) == float_type_node)
+           TREE_TYPE (found) = double_type_node;
+
+         /* If no declaration found, default to int.  */
+         if (!found)
+           {
+             found = build_decl (PARM_DECL, TREE_VALUE (parm),
+                                 integer_type_node);
+             DECL_ARG_TYPE (found) = TREE_TYPE (found);
+             DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl);
+             DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl);
+             if (extra_warnings)
+               warning_with_decl (found, "type of `%s' defaults to `int'");
+             pushdecl (found);
+           }
+
+         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;
+       }
+
+      /* Put anything which is on the parmdecls chain and which is
+        not a PARM_DECL onto the list NONPARMS.  (The types of
+        non-parm things which might appear on the list include
+        enumerators and NULL-named TYPE_DECL nodes.) Complain about
+        any actual PARM_DECLs not matched with any names.  */
+
+      nonparms = 0;
+      for (parm = parmdecls; parm; )
+       {
+         tree next = TREE_CHAIN (parm);
+         TREE_CHAIN (parm) = 0;
+
+         if (TREE_CODE (parm) != PARM_DECL)
+           nonparms = chainon (nonparms, parm);
+         else
+           {
+             /* Complain about args with incomplete types.  */
+             if (TYPE_SIZE (TREE_TYPE (parm)) == 0)
+               {
+                 error_with_decl (parm, "parameter `%s' has incomplete type");
+                 TREE_TYPE (parm) = error_mark_node;
+               }
+
+             if (DECL_RESULT (parm) == 0)
+               {
+                 error_with_decl (parm,
+                                  "declaration for parameter `%s' but no such parameter");
+                 /* Pretend the parameter was not missing.
+                    This gets us to a standard state and minimizes
+                    further error messages.  */
+                 specparms
+                   = chainon (specparms,
+                              tree_cons (parm, NULL_TREE, NULL_TREE));
+               }
+           }
+
+         parm = next;
+       }
+
+      /* Chain the declarations together in the order of the list of names.  */
+      /* Store that chain in the function decl, replacing the list of names.  */
+      parm = specparms;
+      DECL_ARGUMENTS (fndecl) = 0;
+      {
+       register tree last;
+       for (last = 0; parm; parm = TREE_CHAIN (parm))
+         if (TREE_PURPOSE (parm))
+           {
+             if (last == 0)
+               DECL_ARGUMENTS (fndecl) = TREE_PURPOSE (parm);
+             else
+               TREE_CHAIN (last) = TREE_PURPOSE (parm);
+             last = TREE_PURPOSE (parm);
+             TREE_CHAIN (last) = 0;
+           }
+      }
+
+      /* If there was a previous prototype,
+        set the DECL_ARG_TYPE of each argument according to
+        the type previously specified, and report any mismatches.  */
+
+      if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
+       {
+         register tree type;
+         for (parm = DECL_ARGUMENTS (fndecl),
+              type = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+              parm || (type && TREE_VALUE (type) != void_type_node);
+              parm = TREE_CHAIN (parm), type = TREE_CHAIN (type))
+           {
+             if (parm == 0 || type == 0
+                 || TREE_VALUE (type) == void_type_node)
+               {
+                 error ("number of arguments doesn't match prototype");
+                 break;
+               }
+             /* Type for passing arg must be consistent
+                with that declared for the arg.  */
+             if (! comptypes (DECL_ARG_TYPE (parm), TREE_VALUE (type))
+                 /* If -traditional, allow `unsigned int' instead of `int'
+                    in the prototype.  */
+                 && (! (flag_traditional
+                        && DECL_ARG_TYPE (parm) == integer_type_node
+                        && TREE_VALUE (type) == unsigned_type_node)))
+               {
+                 error ("argument `%s' doesn't match function prototype",
+                        IDENTIFIER_POINTER (DECL_NAME (parm)));
+                 if (DECL_ARG_TYPE (parm) == integer_type_node
+                     && TREE_VALUE (type) == TREE_TYPE (parm))
+                   {
+                     error ("a formal parameter type that promotes to `int'");
+                     error ("can match only `int' in the prototype");
+                   }
+                 if (DECL_ARG_TYPE (parm) == double_type_node
+                     && TREE_VALUE (type) == TREE_TYPE (parm))
+                   {
+                     error ("a formal parameter type that promotes to `double'");
+                     error ("can match only `double' in the prototype");
+                   }
+               }
+           }
+         TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = 0;
+       }
+
+      /* Otherwise, create a prototype that would match.  */
+
+      else
+       {
+         register tree actual, type;
+         register tree last = 0;
+
+         for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm))
+           {
+             type = perm_tree_cons (NULL, DECL_ARG_TYPE (parm), NULL);
+             if (last)
+               TREE_CHAIN (last) = type;
+             else
+               actual = type;
+             last = type;
+           }
+         type = perm_tree_cons (NULL, void_type_node, NULL);
+         if (last)
+           TREE_CHAIN (last) = type;
+         else
+           actual = type;
+
+         TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual;
+       }
+
+      /* Now store the final chain of decls for the arguments
+        as the decl-chain of the current lexical scope.
+        Put the enumerators in as well, at the front so that
+        DECL_ARGUMENTS is not modified.  */
+
+      storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
+    }
+
+  /* Make sure the binding level for the top of the function body
+     gets a BLOCK if there are any in the function.
+     Otherwise, the dbx output is wrong.  */
+
+  keep_next_if_subblocks = 1;
+
+  /* ??? This might be an improvement,
+     but needs to be thought about some more.  */
+#if 0
+  keep_next_level_flag = 1;
+#endif
+
+  /* Write a record describing this function definition to the prototypes
+     file (if requested).  */
+
+  gen_aux_info_record (fndecl, 1, 0, prototype);
+
+  /* Initialize the RTL code for the function.  */
+
+  init_function_start (fndecl, input_filename, lineno);
+
+  /* If this is a varargs function, inform function.c.  */
+
+  if (c_function_varargs)
+    mark_varargs ();
+
+  /* Set up parameters and prepare for return, for the function.  */
+
+  expand_function_start (fndecl, 0);
+
+  /* If this function is `main', emit a call to `__main'
+     to run global initializers, etc.  */
+  if (DECL_NAME (fndecl)
+      && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0
+      && DECL_CONTEXT (fndecl) == NULL_TREE)
+    expand_main_function ();
+}
+\f
+/* SPECPARMS is an identifier list--a chain of TREE_LIST nodes
+   each with a parm name as the TREE_VALUE.  A null pointer as TREE_VALUE
+   stands for an ellipsis in the identifier list.
+
+   PARMLIST is the data returned by get_parm_info for the
+   parmlist that follows the semicolon.
+
+   We return a value of the same sort that get_parm_info returns,
+   except that it describes the combination of identifiers and parmlist.  */
+
+tree
+combine_parm_decls (specparms, parmlist, void_at_end)
+     tree specparms, parmlist;
+     int void_at_end;
+{
+  register tree fndecl = current_function_decl;
+  register tree parm;
+
+  tree parmdecls = TREE_PURPOSE (parmlist);
+
+  /* This is a chain of any other decls that came in among the parm
+     declarations.  They were separated already by get_parm_info,
+     so we just need to keep them separate.  */
+  tree nonparms = TREE_VALUE (parmlist);
+
+  tree types = 0;
+
+  for (parm = parmdecls; parm; parm = TREE_CHAIN (parm))
+    DECL_RESULT (parm) = 0;
+
+  for (parm = specparms; parm; parm = TREE_CHAIN (parm))
+    {
+      register tree tail, found = NULL;
+
+      /* See if any of the parmdecls specifies this parm by name.  */
+      for (tail = parmdecls; tail; tail = TREE_CHAIN (tail))
+       if (DECL_NAME (tail) == TREE_VALUE (parm))
+         {
+           found = tail;
+           break;
+         }
+
+      /* If declaration already marked, we have a duplicate name.
+        Complain, and don't use this decl twice.   */
+      if (found && DECL_RESULT (found) != 0)
+       {
+         error_with_decl (found, "multiple parameters named `%s'");
+         found = 0;
+       }
+
+      /* If the declaration says "void", complain and ignore it.  */
+      if (found && TREE_TYPE (found) == void_type_node)
+       {
+         error_with_decl (found, "parameter `%s' declared void");
+         TREE_TYPE (found) = integer_type_node;
+         DECL_ARG_TYPE (found) = integer_type_node;
+         layout_decl (found, 0);
+       }
+
+      /* Traditionally, a parm declared float is actually a double.  */
+      if (found && flag_traditional
+         && TREE_TYPE (found) == float_type_node)
+       TREE_TYPE (found) = double_type_node;
+
+      /* If no declaration found, default to int.  */
+      if (!found)
+       {
+         found = build_decl (PARM_DECL, TREE_VALUE (parm),
+                             integer_type_node);
+         DECL_ARG_TYPE (found) = TREE_TYPE (found);
+         DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl);
+         DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl);
+         error (found, "type of parameter `%s' is not declared");
+         pushdecl (found);
+       }
+
+      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;
+    }
+
+  /* Complain about any actual PARM_DECLs not matched with any names.  */
+
+  for (parm = parmdecls; parm; )
+    {
+      tree next = TREE_CHAIN (parm);
+      TREE_CHAIN (parm) = 0;
+
+      /* Complain about args with incomplete types.  */
+      if (TYPE_SIZE (TREE_TYPE (parm)) == 0)
+       {
+         error_with_decl (parm, "parameter `%s' has incomplete type");
+         TREE_TYPE (parm) = error_mark_node;
+       }
+
+      if (DECL_RESULT (parm) == 0)
+       {
+         error_with_decl (parm,
+                          "declaration for parameter `%s' but no such parameter");
+         /* Pretend the parameter was not missing.
+            This gets us to a standard state and minimizes
+            further error messages.  */
+         specparms
+           = chainon (specparms,
+                      tree_cons (parm, NULL_TREE, NULL_TREE));
+       }
+
+      parm = next;
+    }
+
+  /* Chain the declarations together in the order of the list of names.
+     At the same time, build up a list of their types, in reverse order.  */
+
+  parm = specparms;
+  parmdecls = 0;
+  {
+    register tree last;
+    for (last = 0; parm; parm = TREE_CHAIN (parm))
+      if (TREE_PURPOSE (parm))
+       {
+         if (last == 0)
+           parmdecls = TREE_PURPOSE (parm);
+         else
+           TREE_CHAIN (last) = TREE_PURPOSE (parm);
+         last = TREE_PURPOSE (parm);
+         TREE_CHAIN (last) = 0;
+
+         types = saveable_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 saveable_tree_cons (parmdecls, nonparms, nreverse (types));
+}
+\f
+/* Finish up a function declaration and compile that function
+   all the way to assembler language output.  The free the storage
+   for the function definition.
+
+   This is called after parsing the body of the function definition.
+
+   NESTED is nonzero if the function being finished is nested in another.  */
+
+void
+finish_function (nested)
+     int nested;
+{
+  register tree fndecl = current_function_decl;
+
+/*  TREE_READONLY (fndecl) = 1;
+    This caused &foo to be of type ptr-to-const-function
+    which then got a warning when stored in a ptr-to-function variable.  */
+
+  poplevel (1, 0, 1);
+
+  /* Must mark the RESULT_DECL as being in this function.  */
+
+  DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
+
+  /* Obey `register' declarations if `setjmp' is called in this fn.  */
+  if (flag_traditional && current_function_calls_setjmp)
+    {
+      setjmp_protect (DECL_INITIAL (fndecl));
+      setjmp_protect_args ();
+    }
+
+#ifdef DEFAULT_MAIN_RETURN
+  if (! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main"))
+    {
+      /* Make it so that `main' always returns success by default.  */
+      DEFAULT_MAIN_RETURN;
+    }
+#endif
+
+  /* Generate rtl for function exit.  */
+  expand_function_end (input_filename, lineno);
+
+  /* So we can tell if jump_optimize sets it to 1.  */
+  can_reach_end = 0;
+
+  /* Run the optimizers and output the assembler code for this function.  */
+  rest_of_compilation (fndecl);
+
+  current_function_returns_null |= can_reach_end;
+
+  if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
+    warning ("`volatile' function does return");
+  else if (warn_return_type && current_function_returns_null
+          && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) != void_type_node)
+    /* If this function returns non-void and control can drop through,
+       complain.  */
+    warning ("control reaches end of non-void function");
+  /* With just -W, complain only if function returns both with
+     and without a value.  */
+  else if (extra_warnings
+          && current_function_returns_value && current_function_returns_null)
+    warning ("this function may return with or without a value");
+
+  /* Free all the tree nodes making up this function.  */
+  /* Switch back to allocating nodes permanently
+     until we start another function.  */
+  if (! nested)
+    permanent_allocation ();
+
+  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.  */
+      DECL_INITIAL (fndecl) = error_mark_node;
+      DECL_ARGUMENTS (fndecl) = 0;
+    }
+
+  if (! nested)
+    {
+      /* Let the error reporting routines know that we're outside a
+        function.  For a nested function, this value is used in
+        pop_c_function_context and then reset via pop_function_context.  */
+      current_function_decl = NULL;
+    }
+}
+\f
+/* Save and restore the variables in this file and elsewhere
+   that keep track of the progress of compilation of the current function.
+   Used for nested functions.  */
+
+struct c_function
+{
+  struct c_function *next;
+  tree enum_next_value;
+  tree named_labels;
+  tree shadowed_labels;
+  int returns_value;
+  int returns_null;
+  int warn_about_return_type;
+  int extern_inline;
+  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 ()
+{
+  struct c_function *p
+    = (struct c_function *) xmalloc (sizeof (struct c_function));
+
+  push_function_context ();
+
+  p->next = c_function_chain;
+  c_function_chain = p;
+
+  p->enum_next_value = enum_next_value;
+  p->named_labels = named_labels;
+  p->shadowed_labels = shadowed_labels;
+  p->returns_value = current_function_returns_value;
+  p->returns_null = current_function_returns_null;
+  p->warn_about_return_type = warn_about_return_type;
+  p->extern_inline = current_extern_inline;
+  p->binding_level = current_binding_level;
+}
+
+/* Restore the variables used during compilation of a C function.  */
+
+void
+pop_c_function_context ()
+{
+  struct c_function *p = c_function_chain;
+  tree link;
+
+  /* Bring back all the labels that were shadowed.  */
+  for (link = shadowed_labels; link; link = TREE_CHAIN (link))
+    if (DECL_NAME (TREE_VALUE (link)) != 0)
+      IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)))
+       = TREE_VALUE (link);
+
+  if (DECL_SAVED_INSNS (current_function_decl) == 0)
+    {
+      /* Stop pointing to the local nodes about to be freed.  */
+      /* But DECL_INITIAL must remain nonzero so we know this
+        was an actual function definition.  */
+      DECL_INITIAL (current_function_decl) = error_mark_node;
+      DECL_ARGUMENTS (current_function_decl) = 0;
+    }
+
+  pop_function_context ();
+
+  c_function_chain = p->next;
+
+  enum_next_value = p->enum_next_value;
+  named_labels = p->named_labels;
+  shadowed_labels = p->shadowed_labels;
+  current_function_returns_value = p->returns_value;
+  current_function_returns_null = p->returns_null;
+  warn_about_return_type = p->warn_about_return_type;
+  current_extern_inline = p->extern_inline;
+  current_binding_level = p->binding_level;
+
+  free (p);
+}