From 51e2940139d5e3e86590f6e6802ffc3f3010be5b Mon Sep 17 00:00:00 2001 From: Richard Stallman Date: Thu, 13 Feb 1992 22:21:26 +0000 Subject: [PATCH] Initial revision From-SVN: r319 --- gcc/c-decl.c | 5671 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 5671 insertions(+) create mode 100644 gcc/c-decl.c diff --git a/gcc/c-decl.c b/gcc/c-decl.c new file mode 100644 index 0000000..09038c1 --- /dev/null +++ b/gcc/c-decl.c @@ -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 + +/* 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 + +/* 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; + +/* 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 (); + +/* 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); +} + +/* 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; +} + +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; +} + +/* 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)); +} + +/* 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; +} + +/* 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; + } +} + +/* 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; + } +} + +/* 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; +} + +/* 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; +} + +/* 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; +} + +/* 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; +} + +/* 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"); + } +} + +/* 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; +} + +/* 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; +} + +/* 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< 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; + } +} + +/* 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); +} + +/* 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; + } + } +} + +/* 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; +} + +/* 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; +} + +/* 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); +} + +/* 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); +} + +/* 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; +} + +/* 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 (); +} + +/* 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)); +} + +/* 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; + } +} + +/* 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); +} -- 2.7.4