| /* Process declarations and variables for C compiler. |
| Copyright (C) 1988, 92, 93, 94, 95, 96, 1997 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, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, 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 "output.h" |
| #include "c-tree.h" |
| #include "c-lex.h" |
| #include <stdio.h> |
| |
| /* In grokdeclarator, distinguish syntactic contexts of declarators. */ |
| enum decl_context |
| { NORMAL, /* Ordinary declaration */ |
| FUNCDEF, /* Function definition */ |
| PARM, /* Declaration of parm before function body */ |
| FIELD, /* Declaration inside struct or union */ |
| BITFIELD, /* Likewise but with specified width */ |
| TYPENAME}; /* Typename (inside cast or sizeof) */ |
| |
| #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 boolean_type_node; |
| tree boolean_false_node; |
| tree boolean_true_node; |
| |
| tree ptrdiff_type_node; |
| |
| tree unsigned_char_type_node; |
| tree signed_char_type_node; |
| tree char_type_node; |
| tree wchar_type_node; |
| tree signed_wchar_type_node; |
| tree unsigned_wchar_type_node; |
| |
| tree float_type_node; |
| tree double_type_node; |
| tree long_double_type_node; |
| |
| tree complex_integer_type_node; |
| tree complex_float_type_node; |
| tree complex_double_type_node; |
| tree complex_long_double_type_node; |
| |
| tree intQI_type_node; |
| tree intHI_type_node; |
| tree intSI_type_node; |
| tree intDI_type_node; |
| |
| tree unsigned_intQI_type_node; |
| tree unsigned_intHI_type_node; |
| tree unsigned_intSI_type_node; |
| tree unsigned_intDI_type_node; |
| |
| /* a VOID_TYPE node. */ |
| |
| tree void_type_node; |
| |
| /* Nodes for types `void *' and `const void *'. */ |
| |
| tree ptr_type_node, const_ptr_type_node; |
| |
| /* Nodes for types `char *' and `const char *'. */ |
| |
| tree string_type_node, const_string_type_node; |
| |
| /* Type `char[SOMENUMBER]'. |
| Used when an array of char is needed and the size is irrelevant. */ |
| |
| tree char_array_type_node; |
| |
| /* Type `int[SOMENUMBER]' or something like it. |
| Used when an array of int needed and the size is irrelevant. */ |
| |
| tree int_array_type_node; |
| |
| /* Type `wchar_t[SOMENUMBER]' or something like it. |
| Used when a wide string literal is created. */ |
| |
| tree wchar_array_type_node; |
| |
| /* type `int ()' -- used for implicit declaration of functions. */ |
| |
| tree default_function_type; |
| |
| /* function types `double (double)' and `double (double, double)', etc. */ |
| |
| tree double_ftype_double, double_ftype_double_double; |
| tree int_ftype_int, long_ftype_long; |
| tree float_ftype_float; |
| tree ldouble_ftype_ldouble; |
| |
| /* Function type `void (void *, void *, int)' and similar ones */ |
| |
| tree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int; |
| |
| /* Function type `char *(char *, char *)' and similar ones */ |
| tree string_ftype_ptr_ptr, int_ftype_string_string; |
| |
| /* Function type `int (const void *, const void *, size_t)' */ |
| tree int_ftype_cptr_cptr_sizet; |
| |
| /* Two expressions that are constants with value zero. |
| The first is of type `int', the second of type `void *'. */ |
| |
| tree integer_zero_node; |
| tree null_pointer_node; |
| |
| /* A node for the integer constant 1. */ |
| |
| tree integer_one_node; |
| |
| /* 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. Note that will do not have to save this or `enum_overflow' |
| around nested function definition since such a definition could only |
| occur in an enum value expression and we don't use these variables in |
| that case. */ |
| |
| static tree enum_next_value; |
| |
| /* Nonzero means that there was overflow computing enum_next_value. */ |
| |
| static int enum_overflow; |
| |
| /* 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; |
| |
| /* Similar, for the file and line that the prototype came from if this is |
| an old-style definition. */ |
| static char *current_function_prototype_file; |
| static int current_function_prototype_line; |
| |
| /* 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. */ |
| |
| static 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 declared `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 BLOCK node for this level, if one has been preallocated. |
| If 0, the BLOCK is allocated (if needed) when the level is popped. */ |
| tree this_block; |
| |
| /* 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. */ |
| 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, NULL_BINDING_LEVEL, 0, 0, 0, 0, 0, 0, |
| NULL}; |
| |
| /* 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; |
| |
| /* Functions called automatically at the beginning and end of execution. */ |
| |
| tree static_ctors, static_dtors; |
| |
| /* Forward declarations. */ |
| |
| static struct binding_level * make_binding_level PROTO((void)); |
| static void clear_limbo_values PROTO((tree)); |
| static int duplicate_decls PROTO((tree, tree, int)); |
| static char *redeclaration_error_message PROTO((tree, tree)); |
| static void storedecls PROTO((tree)); |
| static void storetags PROTO((tree)); |
| static tree lookup_tag PROTO((enum tree_code, tree, |
| struct binding_level *, int)); |
| static tree lookup_tag_reverse PROTO((tree)); |
| static tree grokdeclarator PROTO((tree, tree, enum decl_context, |
| int)); |
| static tree grokparms PROTO((tree, int)); |
| static int field_decl_cmp PROTO((const GENERIC_PTR, const GENERIC_PTR)); |
| static void layout_array_type PROTO((tree)); |
| |
| /* 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 any builtin functions. */ |
| |
| int flag_no_builtin; |
| |
| /* Nonzero means don't recognize the non-ANSI builtin functions. |
| -ansi sets this. */ |
| |
| int flag_no_nonansi_builtin; |
| |
| /* Nonzero means do some things the same way PCC does. */ |
| |
| int flag_traditional; |
| |
| /* Nonzero means that we have builtin functions, and main is an int */ |
| |
| int flag_hosted = 1; |
| |
| /* Nonzero means to allow single precision math even if we're generally |
| being traditional. */ |
| int flag_allow_single_precision = 0; |
| |
| /* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ |
| |
| int flag_signed_bitfields = 1; |
| int explicit_flag_signed_bitfields = 0; |
| |
| /* Nonzero means handle `#ident' directives. 0 means ignore them. */ |
| |
| int flag_no_ident = 0; |
| |
| /* Nonzero means warn about 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; |
| |
| /* Nonzero means warn when casting a function call to a type that does |
| not match the return type (e.g. (float)sqrt() or (anything*)malloc() |
| when there is no previous declaration of sqrt or malloc. */ |
| |
| int warn_bad_function_cast; |
| |
| /* 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 for any global function def |
| without separate previous decl. */ |
| |
| int warn_missing_declarations; |
| |
| /* 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; |
| |
| /* Warn if initializer is not completely bracketed. */ |
| |
| int warn_missing_braces; |
| |
| /* Warn if main is suspicious. */ |
| |
| int warn_main; |
| |
| /* Warn about comparison of signed and unsigned values. |
| If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified. */ |
| |
| int warn_sign_compare = -1; |
| |
| /* Nonzero means `$' can be in an identifier. */ |
| |
| #ifndef DOLLARS_IN_IDENTIFIERS |
| #define DOLLARS_IN_IDENTIFIERS 1 |
| #endif |
| int dollars_in_ident = DOLLARS_IN_IDENTIFIERS; |
| |
| /* 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; |
| } |
| else if (!strcmp (p, "-fallow-single-precision")) |
| flag_allow_single_precision = 1; |
| else if (!strcmp (p, "-fhosted") || !strcmp (p, "-fno-freestanding")) |
| { |
| flag_hosted = 1; |
| flag_no_builtin = 0; |
| } |
| else if (!strcmp (p, "-ffreestanding") || !strcmp (p, "-fno-hosted")) |
| { |
| flag_hosted = 0; |
| flag_no_builtin = 1; |
| /* warn_main will be 2 if set by -Wall, 1 if set by -Wmain */ |
| if (warn_main == 2) |
| warn_main = 0; |
| } |
| else if (!strcmp (p, "-fnotraditional") || !strcmp (p, "-fno-traditional")) |
| { |
| flag_traditional = 0; |
| flag_writable_strings = 0; |
| } |
| else if (!strcmp (p, "-fdollars-in-identifiers")) |
| dollars_in_ident = 1; |
| else if (!strcmp (p, "-fno-dollars-in-identifiers")) |
| dollars_in_ident = 0; |
| 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") |
| || !strcmp (p, "-fno-unsigned-bitfields")) |
| { |
| flag_signed_bitfields = 1; |
| explicit_flag_signed_bitfields = 1; |
| } |
| else if (!strcmp (p, "-funsigned-bitfields") |
| || !strcmp (p, "-fno-signed-bitfields")) |
| { |
| flag_signed_bitfields = 0; |
| explicit_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_nonansi_builtin = 1; |
| 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, "-Wbad-function-cast")) |
| warn_bad_function_cast = 1; |
| else if (!strcmp (p, "-Wno-bad-function-cast")) |
| warn_bad_function_cast = 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, "-Wmissing-declarations")) |
| warn_missing_declarations = 1; |
| else if (!strcmp (p, "-Wno-missing-declarations")) |
| warn_missing_declarations = 0; |
| else if (!strcmp (p, "-Wredundant-decls")) |
| warn_redundant_decls = 1; |
| else if (!strcmp (p, "-Wno-redundant-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, "-Wreturn-type")) |
| warn_return_type = 1; |
| else if (!strcmp (p, "-Wno-return-type")) |
| warn_return_type = 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, "-Wundef")) |
| ; /* cpp handles this one. */ |
| else if (!strcmp (p, "-Wno-undef")) |
| ; /* cpp handles this one. */ |
| else if (!strcmp (p, "-Wimport")) |
| ; /* cpp handles this one. */ |
| else if (!strcmp (p, "-Wno-import")) |
| ; /* cpp handles this one. */ |
| else if (!strcmp (p, "-Wmissing-braces")) |
| warn_missing_braces = 1; |
| else if (!strcmp (p, "-Wno-missing-braces")) |
| warn_missing_braces = 0; |
| else if (!strcmp (p, "-Wmain")) |
| warn_main = 1; |
| else if (!strcmp (p, "-Wno-main")) |
| warn_main = 0; |
| else if (!strcmp (p, "-Wsign-compare")) |
| warn_sign_compare = 1; |
| else if (!strcmp (p, "-Wno-sign-compare")) |
| warn_sign_compare = 0; |
| else if (!strcmp (p, "-Wall")) |
| { |
| /* We save the value of warn_uninitialized, since if they put |
| -Wuninitialized on the command line, we need to generate a |
| warning about not using it without also specifying -O. */ |
| if (warn_uninitialized != 1) |
| warn_uninitialized = 2; |
| warn_implicit = 1; |
| warn_return_type = 1; |
| warn_unused = 1; |
| warn_switch = 1; |
| warn_format = 1; |
| warn_char_subscripts = 1; |
| warn_parentheses = 1; |
| warn_missing_braces = 1; |
| /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding can turn |
| it off only if it's not explicit. */ |
| warn_main = 2; |
| } |
| else |
| return 0; |
| |
| return 1; |
| } |
| |
| /* Hooks for print_node. */ |
| |
| void |
| print_lang_decl (file, node, indent) |
| FILE *file; |
| tree node; |
| int indent; |
| { |
| } |
| |
| void |
| print_lang_type (file, node, indent) |
| FILE *file; |
| tree node; |
| int indent; |
| { |
| } |
| |
| 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); |
| print_node (file, "limbo value", IDENTIFIER_LIMBO_VALUE (node), indent + 4); |
| } |
| |
| /* Hook called at end of compilation to assume 1 elt |
| for a top-level array decl that wasn't complete before. */ |
| |
| void |
| finish_incomplete_decl (decl) |
| tree decl; |
| { |
| if (TREE_CODE (decl) == VAR_DECL) |
| { |
| tree type = TREE_TYPE (decl); |
| if (type != error_mark_node |
| && TREE_CODE (type) == ARRAY_TYPE |
| && TYPE_DOMAIN (type) == 0) |
| { |
| if (! DECL_EXTERNAL (decl)) |
| warning_with_decl (decl, "array `%s' assumed to have one element"); |
| |
| complete_array_type (type, NULL_TREE, 1); |
| |
| layout_decl (decl, 0); |
| } |
| } |
| } |
| |
| /* 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. |
| But it turns out there is no way to pass the right value for |
| DEFINITION_FLAG, so we ignore it. */ |
| |
| void |
| declare_parm_level (definition_flag) |
| int definition_flag; |
| { |
| current_binding_level->parm_flag = 1; |
| } |
| |
| /* 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; |
| } |
| |
| /* Clear the limbo values of all identifiers defined in BLOCK or a subblock. */ |
| |
| static void |
| clear_limbo_values (block) |
| tree block; |
| { |
| tree tem; |
| |
| for (tem = BLOCK_VARS (block); tem; tem = TREE_CHAIN (tem)) |
| if (DECL_NAME (tem) != 0) |
| IDENTIFIER_LIMBO_VALUE (DECL_NAME (tem)) = 0; |
| |
| for (tem = BLOCK_SUBBLOCKS (block); tem; tem = TREE_CHAIN (tem)) |
| clear_limbo_values (tem); |
| } |
| |
| /* 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; |
| int block_previously_created; |
| |
| 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)) |
| { |
| /* If this decl was copied from a file-scope decl |
| on account of a block-scope extern decl, |
| propagate TREE_ADDRESSABLE to the file-scope decl. |
| |
| DECL_ABSTRACT_ORIGIN can be set to itself if warn_return_type is |
| true, since then the decl goes through save_for_inline_copying. */ |
| if (DECL_ABSTRACT_ORIGIN (decl) != 0 |
| && DECL_ABSTRACT_ORIGIN (decl) != decl) |
| TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; |
| else if (DECL_SAVED_INSNS (decl) != 0) |
| { |
| push_function_context (); |
| output_inline_function (decl); |
| pop_function_context (); |
| } |
| } |
| |
| /* 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. */ |
| |
| block = 0; |
| block_previously_created = (current_binding_level->this_block != 0); |
| if (block_previously_created) |
| block = current_binding_level->this_block; |
| else if (keep || functionbody |
| || (current_binding_level->keep_if_subblocks && subblocks != 0)) |
| block = make_node (BLOCK); |
| if (block != 0) |
| { |
| BLOCK_VARS (block) = decls; |
| BLOCK_TYPE_TAGS (block) = tags; |
| BLOCK_SUBBLOCKS (block) = subblocks; |
| remember_end_note (block); |
| } |
| |
| /* In each subblock, record that this is its superior. */ |
| |
| 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 (DECL_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) |
| { |
| clear_limbo_values (block); |
| |
| /* 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) |
| { |
| if (!block_previously_created) |
| 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; |
| } |
| |
| /* Delete the node BLOCK from the current binding level. |
| This is used for the block inside a stmt expr ({...}) |
| so that the block can be reinserted where appropriate. */ |
| |
| void |
| delete_block (block) |
| tree block; |
| { |
| tree t; |
| if (current_binding_level->blocks == block) |
| current_binding_level->blocks = TREE_CHAIN (block); |
| for (t = current_binding_level->blocks; t;) |
| { |
| if (TREE_CHAIN (t) == block) |
| TREE_CHAIN (t) = TREE_CHAIN (block); |
| else |
| t = TREE_CHAIN (t); |
| } |
| TREE_CHAIN (block) = NULL; |
| /* Clear TREE_USED which is always set by poplevel. |
| The flag is set again if insert_block is called. */ |
| TREE_USED (block) = 0; |
| } |
| |
| /* Insert BLOCK at the end of the list of subblocks of the |
| current binding level. This is used when a BIND_EXPR is expanded, |
| to handle the BLOCK node inside the BIND_EXPR. */ |
| |
| void |
| insert_block (block) |
| tree block; |
| { |
| TREE_USED (block) = 1; |
| current_binding_level->blocks |
| = chainon (current_binding_level->blocks, block); |
| } |
| |
| /* Set the BLOCK node for the innermost scope |
| (the one we are currently in). */ |
| |
| void |
| set_block (block) |
| register tree block; |
| { |
| current_binding_level->this_block = 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 (TREE_VALUE (link), |
| "label `%s' used but not defined"); |
| /* 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 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_TREE, type)); |
| |
| /* An approximation for now, so we can tell this is a function-scope tag. |
| This will be updated in poplevel. */ |
| TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (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. |
| |
| When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external declaration, |
| and OLDDECL is in an outer binding level and should thus not be changed. */ |
| |
| static int |
| duplicate_decls (newdecl, olddecl, different_binding_level) |
| register tree newdecl, olddecl; |
| int different_binding_level; |
| { |
| int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); |
| int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_INITIAL (newdecl) != 0); |
| tree oldtype = TREE_TYPE (olddecl); |
| tree newtype = TREE_TYPE (newdecl); |
| char *errmsg = 0; |
| |
| if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd') |
| DECL_MACHINE_ATTRIBUTES (newdecl) = DECL_MACHINE_ATTRIBUTES (olddecl); |
| |
| if (TREE_CODE (newtype) == ERROR_MARK |
| || TREE_CODE (oldtype) == 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) |
| || DECL_BUILT_IN_NONANSI (olddecl))) |
| { |
| /* If you declare a built-in or predefined function name as static, |
| the old definition is overridden, |
| but optionally warn this was a bad choice of name. */ |
| if (!TREE_PUBLIC (newdecl)) |
| { |
| if (!warn_shadow) |
| ; |
| else if (DECL_BUILT_IN (olddecl)) |
| warning_with_decl (newdecl, "shadowing built-in function `%s'"); |
| else |
| warning_with_decl (newdecl, "shadowing library function `%s'"); |
| } |
| /* Likewise, if the built-in is not ansi, then programs can |
| override it even globally without an error. */ |
| else if (! DECL_BUILT_IN (olddecl)) |
| warning_with_decl (newdecl, |
| "library function `%s' declared as non-function"); |
| |
| else if (DECL_BUILT_IN_NONANSI (olddecl)) |
| warning_with_decl (newdecl, |
| "built-in function `%s' declared as non-function"); |
| else |
| warning_with_decl (newdecl, |
| "built-in 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)) |
| { |
| /* A function declaration for a built-in function. */ |
| 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) |
| { |
| /* Accept the return type of the new declaration if same modes. */ |
| tree oldreturntype = TREE_TYPE (oldtype); |
| tree newreturntype = TREE_TYPE (newtype); |
| |
| /* Make sure we put the new type in the same obstack as the old ones. |
| If the old types are not both in the same obstack, use the |
| permanent one. */ |
| if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype)) |
| push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); |
| else |
| { |
| push_obstacks_nochange (); |
| end_temporary_allocation (); |
| } |
| |
| if (TYPE_MODE (oldreturntype) == TYPE_MODE (newreturntype)) |
| { |
| /* Function types may be shared, so we can't just modify |
| the return type of olddecl's function type. */ |
| tree trytype |
| = build_function_type (newreturntype, |
| TYPE_ARG_TYPES (oldtype)); |
| |
| types_match = comptypes (newtype, trytype); |
| if (types_match) |
| oldtype = trytype; |
| } |
| /* Accept harmless mismatch in first argument type also. |
| This is for ffs. */ |
| if (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0 |
| && TYPE_ARG_TYPES (oldtype) != 0 |
| && TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0 |
| && TREE_VALUE (TYPE_ARG_TYPES (oldtype)) != 0 |
| && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (newtype))) |
| == TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (oldtype))))) |
| { |
| /* Function types may be shared, so we can't just modify |
| the return type of olddecl's function type. */ |
| tree trytype |
| = build_function_type (TREE_TYPE (oldtype), |
| tree_cons (NULL_TREE, |
| TREE_VALUE (TYPE_ARG_TYPES (newtype)), |
| TREE_CHAIN (TYPE_ARG_TYPES (oldtype)))); |
| |
| types_match = comptypes (newtype, trytype); |
| if (types_match) |
| oldtype = trytype; |
| } |
| if (! different_binding_level) |
| TREE_TYPE (olddecl) = oldtype; |
| |
| pop_obstacks (); |
| } |
| if (!types_match) |
| { |
| /* If types don't match for a built-in, throw away the built-in. */ |
| warning_with_decl (newdecl, "conflicting types for built-in function `%s'"); |
| return 0; |
| } |
| } |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_SOURCE_LINE (olddecl) == 0) |
| { |
| /* A function declaration for a predeclared function |
| that isn't actually built in. */ |
| if (!TREE_PUBLIC (newdecl)) |
| { |
| /* If you declare it as static, the |
| default definition is overridden. */ |
| return 0; |
| } |
| else if (!types_match) |
| { |
| /* If the types don't match, preserve volatility indication. |
| Later on, we will discard everything else about the |
| default declaration. */ |
| TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); |
| } |
| } |
| /* Permit char *foo () to match void *foo (...) if not pedantic, |
| if one of them came from a system header file. */ |
| else if (!types_match |
| && TREE_CODE (olddecl) == FUNCTION_DECL |
| && TREE_CODE (newdecl) == FUNCTION_DECL |
| && TREE_CODE (TREE_TYPE (oldtype)) == POINTER_TYPE |
| && TREE_CODE (TREE_TYPE (newtype)) == POINTER_TYPE |
| && (DECL_IN_SYSTEM_HEADER (olddecl) |
| || DECL_IN_SYSTEM_HEADER (newdecl)) |
| && ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (newtype))) == void_type_node |
| && TYPE_ARG_TYPES (oldtype) == 0 |
| && self_promoting_args_p (TYPE_ARG_TYPES (newtype)) |
| && TREE_TYPE (TREE_TYPE (oldtype)) == char_type_node) |
| || |
| (TREE_TYPE (TREE_TYPE (newtype)) == char_type_node |
| && TYPE_ARG_TYPES (newtype) == 0 |
| && self_promoting_args_p (TYPE_ARG_TYPES (oldtype)) |
| && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node))) |
| { |
| if (pedantic) |
| pedwarn_with_decl (newdecl, "conflicting types for `%s'"); |
| /* Make sure we keep void * as ret type, not char *. */ |
| if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node) |
| TREE_TYPE (newdecl) = newtype = oldtype; |
| |
| /* Set DECL_IN_SYSTEM_HEADER, so that if we see another declaration |
| we will come back here again. */ |
| DECL_IN_SYSTEM_HEADER (newdecl) = 1; |
| } |
| 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 (oldtype), |
| TREE_TYPE (newtype)) |
| && TYPE_ARG_TYPES (newtype) == 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 (oldtype), |
| TREE_TYPE (newtype)) |
| && ((TYPE_ARG_TYPES (oldtype) == 0 |
| && DECL_INITIAL (olddecl) == 0) |
| || |
| (TYPE_ARG_TYPES (newtype) == 0 |
| && DECL_INITIAL (newdecl) == 0))) |
| { |
| /* Classify the problem further. */ |
| register tree t = TYPE_ARG_TYPES (oldtype); |
| if (t == 0) |
| t = TYPE_ARG_TYPES (newtype); |
| for (; t; t = TREE_CHAIN (t)) |
| { |
| register tree type = TREE_VALUE (t); |
| |
| if (TREE_CHAIN (t) == 0 |
| && TYPE_MAIN_VARIANT (type) != void_type_node) |
| { |
| error ("A parameter list with an ellipsis can't match"); |
| error ("an empty parameter name list declaration."); |
| break; |
| } |
| |
| if (TYPE_MAIN_VARIANT (type) == float_type_node |
| || C_PROMOTING_INTEGER_TYPE_P (type)) |
| { |
| 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 |
| { |
| errmsg = redeclaration_error_message (newdecl, olddecl); |
| if (errmsg) |
| { |
| error_with_decl (newdecl, errmsg); |
| error_with_decl (olddecl, |
| ((DECL_INITIAL (olddecl) |
| && current_binding_level == global_binding_level) |
| ? "`%s' previously defined here" |
| : "`%s' previously declared here")); |
| } |
| else if (TREE_CODE (newdecl) == TYPE_DECL |
| && (DECL_IN_SYSTEM_HEADER (olddecl) |
| || DECL_IN_SYSTEM_HEADER (newdecl))) |
| { |
| warning_with_decl (newdecl, "redefinition of `%s'"); |
| warning_with_decl |
| (olddecl, |
| ((DECL_INITIAL (olddecl) |
| && current_binding_level == global_binding_level) |
| ? "`%s' previously defined here" |
| : "`%s' previously declared here")); |
| } |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_INITIAL (olddecl) != 0 |
| && TYPE_ARG_TYPES (oldtype) == 0 |
| && TYPE_ARG_TYPES (newtype) != 0 |
| && TYPE_ACTUAL_ARG_TYPES (oldtype) != 0) |
| { |
| register tree type, parm; |
| register int nargs; |
| /* Prototype decl follows defn w/o prototype. */ |
| |
| for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype), |
| type = TYPE_ARG_TYPES (newtype), |
| nargs = 1; |
| (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) != void_type_node |
| || TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node); |
| parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++) |
| { |
| if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node |
| || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) |
| { |
| 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 |
| && TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == integer_type_node |
| && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == unsigned_type_node))) |
| { |
| errmsg = "prototype for `%s' follows and argument %d"; |
| break; |
| } |
| } |
| if (errmsg) |
| { |
| error_with_decl (newdecl, errmsg, nargs); |
| error_with_decl (olddecl, |
| "doesn't match non-prototype definition here"); |
| } |
| else |
| { |
| warning_with_decl (newdecl, "prototype for `%s' follows"); |
| warning_with_decl (olddecl, "non-prototype definition here"); |
| } |
| } |
| /* Warn about mismatches in various flags. */ |
| else |
| { |
| /* Warn if function is now inline |
| but was previously declared not inline and has been called. */ |
| if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && ! DECL_INLINE (olddecl) && DECL_INLINE (newdecl) |
| && TREE_USED (olddecl)) |
| warning_with_decl (newdecl, |
| "`%s' declared inline after being called"); |
| if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && ! DECL_INLINE (olddecl) && DECL_INLINE (newdecl) |
| && DECL_INITIAL (olddecl) != 0) |
| warning_with_decl (newdecl, |
| "`%s' declared inline after its definition"); |
| |
| /* If pedantic, warn when static declaration follows a non-static |
| declaration. Otherwise, do so only for functions. */ |
| if ((pedantic || TREE_CODE (olddecl) == FUNCTION_DECL) |
| && TREE_PUBLIC (olddecl) |
| && !TREE_PUBLIC (newdecl)) |
| warning_with_decl (newdecl, "static declaration for `%s' follows non-static"); |
| |
| /* Warn when const declaration follows a non-const |
| declaration, but not for functions. */ |
| if (TREE_CODE (olddecl) != FUNCTION_DECL |
| && !TREE_READONLY (olddecl) |
| && TREE_READONLY (newdecl)) |
| warning_with_decl (newdecl, "const declaration for `%s' follows non-const"); |
| /* These bits are logically part of the type, for variables. |
| But not for functions |
| (where qualifiers are not valid ANSI anyway). */ |
| else if (pedantic && TREE_CODE (olddecl) != FUNCTION_DECL |
| && (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"); |
| } |
| } |
| |
| /* Optionally warn about more than one declaration for the same name. */ |
| if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0 |
| /* Dont warn about a function declaration |
| followed by a definition. */ |
| && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0 |
| && DECL_INITIAL (olddecl) == 0) |
| /* Don't warn about extern decl followed by (tentative) definition. */ |
| && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))) |
| { |
| warning_with_decl (newdecl, "redundant redeclaration of `%s' in same scope"); |
| warning_with_decl (olddecl, "previous declaration of `%s'"); |
| } |
| |
| /* Copy all the DECL_... slots specified in the new decl |
| except for any that we copy here from the old type. |
| |
| Past this point, we don't change OLDTYPE and NEWTYPE |
| even if we change the types of NEWDECL and OLDDECL. */ |
| |
| if (types_match) |
| { |
| /* When copying info to olddecl, we store into write_olddecl |
| instead. This allows us to avoid modifying olddecl when |
| different_binding_level is true. */ |
| tree write_olddecl = different_binding_level ? newdecl : olddecl; |
| |
| /* Make sure we put the new type in the same obstack as the old ones. |
| If the old types are not both in the same obstack, use the permanent |
| one. */ |
| if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype)) |
| push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); |
| else |
| { |
| push_obstacks_nochange (); |
| end_temporary_allocation (); |
| } |
| |
| /* Merge the data types specified in the two decls. */ |
| if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl)) |
| { |
| if (different_binding_level) |
| TREE_TYPE (newdecl) |
| = build_type_attribute_variant |
| (newtype, |
| merge_attributes (TYPE_ATTRIBUTES (newtype), |
| TYPE_ATTRIBUTES (oldtype))); |
| else |
| TREE_TYPE (newdecl) |
| = TREE_TYPE (olddecl) |
| = common_type (newtype, oldtype); |
| } |
| |
| /* 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 (TREE_CODE (olddecl) != FUNCTION_DECL) |
| if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) |
| DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); |
| } |
| |
| /* Keep the old rtl since we can safely use it. */ |
| DECL_RTL (newdecl) = DECL_RTL (olddecl); |
| |
| /* Merge the type qualifiers. */ |
| if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl) |
| && !TREE_THIS_VOLATILE (newdecl)) |
| TREE_THIS_VOLATILE (write_olddecl) = 0; |
| if (TREE_READONLY (newdecl)) |
| TREE_READONLY (write_olddecl) = 1; |
| if (TREE_THIS_VOLATILE (newdecl)) |
| { |
| TREE_THIS_VOLATILE (write_olddecl) = 1; |
| if (TREE_CODE (newdecl) == VAR_DECL) |
| make_var_volatile (newdecl); |
| } |
| |
| /* Keep source location of definition rather than declaration. */ |
| /* When called with different_binding_level set, keep the old |
| information so that meaningful diagnostics can be given. */ |
| if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0 |
| && ! different_binding_level) |
| { |
| DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl); |
| DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl); |
| } |
| |
| /* Merge the unused-warning information. */ |
| if (DECL_IN_SYSTEM_HEADER (olddecl)) |
| DECL_IN_SYSTEM_HEADER (newdecl) = 1; |
| else if (DECL_IN_SYSTEM_HEADER (newdecl)) |
| DECL_IN_SYSTEM_HEADER (write_olddecl) = 1; |
| |
| /* Merge the initialization information. */ |
| /* When called with different_binding_level set, don't copy over |
| DECL_INITIAL, so that we don't accidentally change function |
| declarations into function definitions. */ |
| if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level) |
| DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); |
| |
| /* Merge the section attribute. |
| We want to issue an error if the sections conflict but that must be |
| done later in decl_attributes since we are called before attributes |
| are assigned. */ |
| if (DECL_SECTION_NAME (newdecl) == NULL_TREE) |
| DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); |
| DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); |
| } |
| |
| pop_obstacks (); |
| } |
| /* If cannot merge, then use the new type and qualifiers, |
| and don't preserve the old rtl. */ |
| else if (! different_binding_level) |
| { |
| 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. */ |
| DECL_WEAK (newdecl) |= DECL_WEAK (olddecl); |
| /* 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. */ |
| /* No need to worry about different_binding_level here because |
| then TREE_PUBLIC (newdecl) was true. */ |
| 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 (DECL_EXTERNAL (newdecl)) |
| { |
| TREE_STATIC (newdecl) = TREE_STATIC (olddecl); |
| DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl); |
| /* An extern decl does not override previous storage class. */ |
| TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); |
| if (! DECL_EXTERNAL (newdecl)) |
| DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); |
| } |
| else |
| { |
| TREE_STATIC (olddecl) = TREE_STATIC (newdecl); |
| TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); |
| } |
| |
| /* If either decl says `inline', this fn is inline, |
| unless its definition was passed already. */ |
| if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0) |
| DECL_INLINE (olddecl) = 1; |
| DECL_INLINE (newdecl) = DECL_INLINE (olddecl); |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (DECL_BUILT_IN (olddecl)) |
| { |
| /* Get rid of any built-in function if new arg types don't match it |
| or if we have a function definition. */ |
| if (! types_match || new_is_definition) |
| { |
| if (! different_binding_level) |
| { |
| TREE_TYPE (olddecl) = TREE_TYPE (newdecl); |
| DECL_BUILT_IN (olddecl) = 0; |
| } |
| } |
| else |
| { |
| /* If redeclaring a builtin function, and not a definition, |
| it stays built in. */ |
| DECL_BUILT_IN (newdecl) = 1; |
| DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); |
| } |
| } |
| /* Also preserve various other info from the definition. */ |
| else if (! new_is_definition) |
| DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl); |
| if (! new_is_definition) |
| { |
| DECL_RESULT (newdecl) = DECL_RESULT (olddecl); |
| /* When called with different_binding_level set, don't copy over |
| DECL_INITIAL, so that we don't accidentally change function |
| declarations into function definitions. */ |
| if (! different_binding_level) |
| DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); |
| DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl); |
| DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); |
| if (DECL_INLINE (newdecl)) |
| DECL_ABSTRACT_ORIGIN (newdecl) = olddecl; |
| } |
| } |
| if (different_binding_level) |
| { |
| /* Don't output a duplicate symbol for this declaration. */ |
| TREE_ASM_WRITTEN (newdecl) = 1; |
| return 0; |
| } |
| |
| /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. |
| But preserve OLDdECL's DECL_UID. */ |
| { |
| register unsigned olddecl_uid = DECL_UID (olddecl); |
| |
| bcopy ((char *) newdecl + sizeof (struct tree_common), |
| (char *) olddecl + sizeof (struct tree_common), |
| sizeof (struct tree_decl) - sizeof (struct tree_common)); |
| DECL_UID (olddecl) = olddecl_uid; |
| } |
| |
| 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 extern declaration for a function doesn't constitute nesting. |
| A local auto declaration does, since it's a forward decl |
| for a nested function coming later. */ |
| if (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0 |
| && DECL_EXTERNAL (x)) |
| DECL_CONTEXT (x) = 0; |
| |
| if (warn_nested_externs && DECL_EXTERNAL (x) && b != global_binding_level |
| && x != IDENTIFIER_IMPLICIT_DECL (name) |
| /* Don't print error messages for __FUNCTION__ and __PRETTY_FUNCTION__ */ |
| && !DECL_IN_SYSTEM_HEADER (x)) |
| warning ("nested extern declaration of `%s'", IDENTIFIER_POINTER (name)); |
| |
| if (name) |
| { |
| char *file; |
| int line; |
| int different_binding_level = 0; |
| |
| t = lookup_name_current_level (name); |
| /* Don't type check externs here when -traditional. This is so that |
| code with conflicting declarations inside blocks will get warnings |
| not errors. X11 for instance depends on this. */ |
| if (! t && DECL_EXTERNAL (x) && TREE_PUBLIC (x) && ! flag_traditional) |
| { |
| t = IDENTIFIER_GLOBAL_VALUE (name); |
| /* Type decls at global scope don't conflict with externs declared |
| inside lexical blocks. */ |
| if (t && TREE_CODE (t) == TYPE_DECL) |
| t = 0; |
| different_binding_level = 1; |
| } |
| 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 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) |
| /* Don't test for DECL_EXTERNAL, because grokdeclarator |
| sets this for all functions. */ |
| && ! TREE_PUBLIC (x) |
| && (TREE_CODE (x) == FUNCTION_DECL || b == global_binding_level) |
| /* 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 |
| (DECL_SOURCE_FILE (IDENTIFIER_IMPLICIT_DECL (name)), |
| DECL_SOURCE_LINE (IDENTIFIER_IMPLICIT_DECL (name)), |
| "previous declaration of `%s'", |
| IDENTIFIER_POINTER (name)); |
| } |
| |
| if (t != 0 && duplicate_decls (x, t, different_binding_level)) |
| { |
| 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; |
| } |
| return t; |
| } |
| |
| /* If we are processing a typedef statement, generate a whole new |
| ..._TYPE node (which will be just an variant of the existing |
| ..._TYPE node with identical properties) and then install the |
| TYPE_DECL node generated to represent the typedef name as the |
| TYPE_NAME of this brand new (duplicate) ..._TYPE node. |
| |
| The whole point here is to end up with a situation where each |
| and every ..._TYPE node the compiler creates will be uniquely |
| associated with AT MOST one node representing a typedef name. |
| This way, even though the compiler substitutes corresponding |
| ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very |
| early on, later parts of the compiler can always do the reverse |
| translation and get back the corresponding typedef name. For |
| example, given: |
| |
| typedef struct S MY_TYPE; |
| MY_TYPE object; |
| |
| Later parts of the compiler might only know that `object' was of |
| type `struct S' if if were not for code just below. With this |
| code however, later parts of the compiler see something like: |
| |
| struct S' == struct S |
| typedef struct S' MY_TYPE; |
| struct S' object; |
| |
| And they can then deduce (from the node for type struct S') that |
| the original object declaration was: |
| |
| MY_TYPE object; |
| |
| Being able to do this is important for proper support of protoize, |
| and also for generating precise symbolic debugging information |
| which takes full account of the programmer's (typedef) vocabulary. |
| |
| Obviously, we don't want to generate a duplicate ..._TYPE node if |
| the TYPE_DECL node that we are now processing really represents a |
| standard built-in type. |
| |
| 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) |
| { |
| if (TYPE_NAME (TREE_TYPE (x)) == 0) |
| TYPE_NAME (TREE_TYPE (x)) = x; |
| } |
| else if (TREE_TYPE (x) != error_mark_node) |
| { |
| tree tt = TREE_TYPE (x); |
| DECL_ORIGINAL_TYPE (x) = tt; |
| tt = build_type_copy (tt); |
| TYPE_NAME (tt) = x; |
| TREE_TYPE (x) = tt; |
| } |
| } |
| |
| /* Multiple external decls of the same identifier ought to match. |
| Check against both global declarations (when traditional) and out of |
| scope (limbo) block level declarations. |
| |
| We get warnings about inline functions where they are defined. |
| Avoid duplicate warnings where they are used. */ |
| if (TREE_PUBLIC (x) && ! DECL_INLINE (x)) |
| { |
| tree decl; |
| |
| if (flag_traditional && IDENTIFIER_GLOBAL_VALUE (name) != 0 |
| && (DECL_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name)) |
| || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name)))) |
| decl = IDENTIFIER_GLOBAL_VALUE (name); |
| else if (IDENTIFIER_LIMBO_VALUE (name) != 0) |
| /* Decls in limbo are always extern, so no need to check that. */ |
| decl = IDENTIFIER_LIMBO_VALUE (name); |
| else |
| decl = 0; |
| |
| if (decl && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl)) |
| /* If old decl is built-in, we already warned if we should. */ |
| && !DECL_BUILT_IN (decl)) |
| { |
| pedwarn_with_decl (x, |
| "type mismatch with previous external decl"); |
| pedwarn_with_decl (decl, "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 (IDENTIFIER_IMPLICIT_DECL (name), |
| "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 && DECL_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; |
| |
| /* We no longer care about any previous block level declarations. */ |
| IDENTIFIER_LIMBO_VALUE (name) = 0; |
| |
| /* 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 |
| && (TYPE_MAIN_VARIANT (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) && ! DECL_EXTERNAL (x)) |
| { |
| /* Okay to redeclare an ANSI built-in as static. */ |
| if (t != 0 && DECL_BUILT_IN (t)) |
| ; |
| /* Okay to declare a non-ANSI built-in as anything. */ |
| else if (t != 0 && DECL_BUILT_IN_NONANSI (t)) |
| ; |
| /* Okay to have global type decl after an earlier extern |
| declaration inside a lexical block. */ |
| else if (TREE_CODE (x) == TYPE_DECL) |
| ; |
| else 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 or declaration for the function. */ |
| if (oldlocal == 0 |
| && DECL_EXTERNAL (x) && !DECL_INLINE (x) |
| && oldglobal != 0 |
| && TREE_CODE (x) == FUNCTION_DECL |
| && TREE_CODE (oldglobal) == FUNCTION_DECL) |
| { |
| /* We have one. Their types must agree. */ |
| if (! comptypes (TREE_TYPE (x), |
| TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)))) |
| pedwarn_with_decl (x, "extern declaration of `%s' doesn't match global one"); |
| else |
| { |
| /* Inner extern decl is inline if global one is. |
| Copy enough to really inline it. */ |
| if (DECL_INLINE (oldglobal)) |
| { |
| DECL_INLINE (x) = DECL_INLINE (oldglobal); |
| DECL_INITIAL (x) = (current_function_decl == oldglobal |
| ? 0 : DECL_INITIAL (oldglobal)); |
| DECL_SAVED_INSNS (x) = DECL_SAVED_INSNS (oldglobal); |
| DECL_FRAME_SIZE (x) = DECL_FRAME_SIZE (oldglobal); |
| DECL_ARGUMENTS (x) = DECL_ARGUMENTS (oldglobal); |
| DECL_RESULT (x) = DECL_RESULT (oldglobal); |
| TREE_ASM_WRITTEN (x) = TREE_ASM_WRITTEN (oldglobal); |
| DECL_ABSTRACT_ORIGIN (x) = oldglobal; |
| } |
| /* Inner extern decl is built-in if global one is. */ |
| if (DECL_BUILT_IN (oldglobal)) |
| { |
| DECL_BUILT_IN (x) = DECL_BUILT_IN (oldglobal); |
| DECL_FUNCTION_CODE (x) = DECL_FUNCTION_CODE (oldglobal); |
| } |
| /* Keep the arg types from a file-scope fcn defn. */ |
| if (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != 0 |
| && DECL_INITIAL (oldglobal) |
| && TYPE_ARG_TYPES (TREE_TYPE (x)) == 0) |
| TREE_TYPE (x) = TREE_TYPE (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) |
| && DECL_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 |
| && DECL_EXTERNAL (x) |
| && TREE_PUBLIC (x)) |
| { |
| if (oldglobal == 0) |
| TREE_PUBLIC (name) = 1; |
| |
| /* Save this decl, so that we can do type checking against |
| other decls after it falls out of scope. |
| |
| Only save it once. This prevents temporary decls created in |
| expand_inline_function from being used here, since this |
| will have been set when the inline function was parsed. |
| It also helps give slightly better warnings. */ |
| if (IDENTIFIER_LIMBO_VALUE (name) == 0) |
| IDENTIFIER_LIMBO_VALUE (name) = x; |
| } |
| |
| /* Warn if shadowing an argument at the top level of the body. */ |
| if (oldlocal != 0 && !DECL_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 && !DECL_EXTERNAL (x) |
| /* No shadow warnings for internally generated vars. */ |
| && DECL_SOURCE_LINE (x) != 0 |
| /* No shadow warnings for vars made for inlining. */ |
| && ! DECL_FROM_INLINE (x)) |
| { |
| char *warnstring = 0; |
| |
| if (TREE_CODE (x) == PARM_DECL |
| && current_binding_level->level_chain->parm_flag) |
| /* Don't warn about the parm names in function declarator |
| within a function declarator. |
| It would be nice to avoid warning in any function |
| declarator in a declaration, as opposed to a definition, |
| but there is no way to tell it's not a definition. */ |
| ; |
| else if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL) |
| warnstring = "declaration of `%s' shadows a parameter"; |
| 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); |
| |
| DECL_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, NULL_PTR, 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; |
| /* pushdecl creates distinct types for TYPE_DECLs by calling |
| build_type_copy, so the above comparison generally fails. We do |
| another test against the TYPE_MAIN_VARIANT of the olddecl, which |
| is equivalent to what this code used to do before the build_type_copy |
| call. The variant type distinction should not matter for traditional |
| code, because it doesn't have type qualifiers. */ |
| if (flag_traditional |
| && TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)) == TREE_TYPE (newdecl)) |
| return 0; |
| if (DECL_IN_SYSTEM_HEADER (olddecl) || DECL_IN_SYSTEM_HEADER (newdecl)) |
| 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. */ |
| && !(DECL_INLINE (olddecl) && DECL_EXTERNAL (olddecl) |
| && !(DECL_INLINE (newdecl) && DECL_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 (DECL_EXTERNAL (newdecl) || DECL_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 |
| { |
| /* Newdecl has block scope. If olddecl has block scope also, then |
| reject two definitions, and reject a definition together with an |
| external reference. Otherwise, it is OK, because newdecl must |
| be an extern reference to olddecl. */ |
| if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl)) |
| && DECL_CONTEXT (newdecl) == DECL_CONTEXT (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); |
| |
| if (current_function_decl == 0) |
| { |
| error ("label %s referenced outside of any function", |
| IDENTIFIER_POINTER (id)); |
| return 0; |
| } |
| |
| /* 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); |
| |
| /* Make sure every label has an rtx. */ |
| label_rtx (decl); |
| |
| /* 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) |
| { |
| register tree dup; |
| |
| /* Check to make sure that the label hasn't already been declared |
| at this label scope */ |
| for (dup = named_labels; dup; dup = TREE_CHAIN (dup)) |
| if (TREE_VALUE (dup) == decl) |
| { |
| error ("duplicate label declaration `%s'", |
| IDENTIFIER_POINTER (name)); |
| error_with_decl (TREE_VALUE (dup), |
| "this is a previous declaration"); |
| /* Just use the previous declaration. */ |
| return lookup_label (name); |
| } |
| |
| 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 ("duplicate label `%s'", IDENTIFIER_POINTER (name)); |
| 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. */ |
| |
| 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 types of memcpy and strlen. */ |
| tree memcpy_ftype, memset_ftype, strlen_ftype; |
| tree void_ftype_any, ptr_ftype_void, ptr_ftype_ptr; |
| int wchar_type_size; |
| tree temp; |
| tree array_domain_type; |
| |
| 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)); |
| |
| long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("long long int"), |
| long_long_integer_type_node)); |
| |
| long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"), |
| long_long_unsigned_type_node)); |
| |
| short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"), |
| short_integer_type_node)); |
| |
| short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"), |
| short_unsigned_type_node)); |
| |
| /* `unsigned long' is the standard type for sizeof. |
| Traditionally, use a signed type. |
| Note that stddef.h uses `unsigned long', |
| and this must agree, even of long and int are the same size. */ |
| sizetype |
| = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))); |
| if (flag_traditional && TREE_UNSIGNED (sizetype)) |
| sizetype = signed_type (sizetype); |
| |
| 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; |
| TREE_TYPE (TYPE_SIZE (long_long_integer_type_node)) = sizetype; |
| TREE_TYPE (TYPE_SIZE (long_long_unsigned_type_node)) = sizetype; |
| TREE_TYPE (TYPE_SIZE (short_integer_type_node)) = sizetype; |
| TREE_TYPE (TYPE_SIZE (short_unsigned_type_node)) = sizetype; |
| |
| error_mark_node = make_node (ERROR_MARK); |
| TREE_TYPE (error_mark_node) = error_mark_node; |
| |
| /* Define both `signed char' and `unsigned char'. */ |
| signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"), |
| signed_char_type_node)); |
| |
| unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned char"), |
| unsigned_char_type_node)); |
| |
| intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node)); |
| |
| intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node)); |
| |
| intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node)); |
| |
| intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node)); |
| |
| unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node)); |
| |
| unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node)); |
| |
| unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node)); |
| |
| unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node)); |
| |
| float_type_node = make_node (REAL_TYPE); |
| TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE; |
| pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT], |
| float_type_node)); |
| layout_type (float_type_node); |
| |
| double_type_node = make_node (REAL_TYPE); |
| if (flag_short_double) |
| TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE; |
| else |
| TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE; |
| pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_DOUBLE], |
| double_type_node)); |
| layout_type (double_type_node); |
| |
| long_double_type_node = make_node (REAL_TYPE); |
| TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE; |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("long double"), |
| long_double_type_node)); |
| layout_type (long_double_type_node); |
| |
| complex_integer_type_node = make_node (COMPLEX_TYPE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"), |
| complex_integer_type_node)); |
| TREE_TYPE (complex_integer_type_node) = integer_type_node; |
| layout_type (complex_integer_type_node); |
| |
| complex_float_type_node = make_node (COMPLEX_TYPE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"), |
| complex_float_type_node)); |
| TREE_TYPE (complex_float_type_node) = float_type_node; |
| layout_type (complex_float_type_node); |
| |
| complex_double_type_node = make_node (COMPLEX_TYPE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"), |
| complex_double_type_node)); |
| TREE_TYPE (complex_double_type_node) = double_type_node; |
| layout_type (complex_double_type_node); |
| |
| complex_long_double_type_node = make_node (COMPLEX_TYPE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"), |
| complex_long_double_type_node)); |
| TREE_TYPE (complex_long_double_type_node) = long_double_type_node; |
| layout_type (complex_long_double_type_node); |
| |
| wchar_type_node |
| = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE))); |
| wchar_type_size = TYPE_PRECISION (wchar_type_node); |
| signed_wchar_type_node = signed_type (wchar_type_node); |
| unsigned_wchar_type_node = unsigned_type (wchar_type_node); |
| |
| integer_zero_node = build_int_2 (0, 0); |
| TREE_TYPE (integer_zero_node) = integer_type_node; |
| integer_one_node = build_int_2 (1, 0); |
| TREE_TYPE (integer_one_node) = integer_type_node; |
| |
| boolean_type_node = integer_type_node; |
| boolean_true_node = integer_one_node; |
| boolean_false_node = integer_zero_node; |
| |
| size_zero_node = build_int_2 (0, 0); |
| TREE_TYPE (size_zero_node) = sizetype; |
| size_one_node = build_int_2 (1, 0); |
| TREE_TYPE (size_one_node) = sizetype; |
| |
| void_type_node = make_node (VOID_TYPE); |
| pushdecl (build_decl (TYPE_DECL, |
| ridpointers[(int) RID_VOID], void_type_node)); |
| layout_type (void_type_node); /* Uses integer_zero_node */ |
| /* We are not going to have real types in C with less than byte alignment, |
| so we might as well not have any types that claim to have it. */ |
| TYPE_ALIGN (void_type_node) = BITS_PER_UNIT; |
| |
| null_pointer_node = build_int_2 (0, 0); |
| TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node); |
| layout_type (TREE_TYPE (null_pointer_node)); |
| |
| string_type_node = build_pointer_type (char_type_node); |
| const_string_type_node |
| = build_pointer_type (build_type_variant (char_type_node, 1, 0)); |
| |
| /* Make a type to be the domain of a few array types |
| whose domains don't really matter. |
| 200 is small enough that it always fits in size_t |
| and large enough that it can hold most function names for the |
| initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ |
| array_domain_type = build_index_type (build_int_2 (200, 0)); |
| |
| /* make a type for arrays of characters. |
| With luck nothing will ever really depend on the length of this |
| array type. */ |
| char_array_type_node |
| = build_array_type (char_type_node, array_domain_type); |
| /* Likewise for arrays of ints. */ |
| int_array_type_node |
| = build_array_type (integer_type_node, array_domain_type); |
| /* This is for wide string constants. */ |
| wchar_array_type_node |
| = build_array_type (wchar_type_node, array_domain_type); |
| |
| 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); |
| |
| void_ftype_any |
| = build_function_type (void_type_node, NULL_TREE); |
| |
| float_ftype_float |
| = build_function_type (float_type_node, |
| tree_cons (NULL_TREE, float_type_node, endlink)); |
| |
| double_ftype_double |
| = build_function_type (double_type_node, |
| tree_cons (NULL_TREE, double_type_node, endlink)); |
| |
| ldouble_ftype_ldouble |
| = build_function_type (long_double_type_node, |
| tree_cons (NULL_TREE, long_double_type_node, |
| endlink)); |
| |
| double_ftype_double_double |
| = build_function_type (double_type_node, |
| tree_cons (NULL_TREE, double_type_node, |
| tree_cons (NULL_TREE, |
| double_type_node, endlink))); |
| |
| int_ftype_int |
| = build_function_type (integer_type_node, |
| tree_cons (NULL_TREE, integer_type_node, endlink)); |
| |
| long_ftype_long |
| = build_function_type (long_integer_type_node, |
| tree_cons (NULL_TREE, |
| long_integer_type_node, endlink)); |
| |
| void_ftype_ptr_ptr_int |
| = build_function_type (void_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, |
| integer_type_node, |
| endlink)))); |
| |
| int_ftype_cptr_cptr_sizet |
| = build_function_type (integer_type_node, |
| tree_cons (NULL_TREE, const_ptr_type_node, |
| tree_cons (NULL_TREE, const_ptr_type_node, |
| tree_cons (NULL_TREE, |
| sizetype, |
| endlink)))); |
| |
| void_ftype_ptr_int_int |
| = build_function_type (void_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, integer_type_node, |
| tree_cons (NULL_TREE, |
| integer_type_node, |
| endlink)))); |
| |
| string_ftype_ptr_ptr /* strcpy prototype */ |
| = build_function_type (string_type_node, |
| tree_cons (NULL_TREE, string_type_node, |
| tree_cons (NULL_TREE, |
| const_string_type_node, |
| endlink))); |
| |
| int_ftype_string_string /* strcmp prototype */ |
| = build_function_type (integer_type_node, |
| tree_cons (NULL_TREE, const_string_type_node, |
| tree_cons (NULL_TREE, |
| const_string_type_node, |
| endlink))); |
| |
| strlen_ftype /* strlen prototype */ |
| = build_function_type (flag_traditional ? integer_type_node : sizetype, |
| tree_cons (NULL_TREE, const_string_type_node, |
| endlink)); |
| |
| traditional_ptr_type_node |
| = (flag_traditional ? string_type_node : ptr_type_node); |
| |
| memcpy_ftype /* memcpy prototype */ |
| = build_function_type (traditional_ptr_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, const_ptr_type_node, |
| tree_cons (NULL_TREE, |
| sizetype, |
| endlink)))); |
| |
| memset_ftype /* memset prototype */ |
| = build_function_type (traditional_ptr_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, integer_type_node, |
| tree_cons (NULL_TREE, |
| sizetype, |
| endlink)))); |
| |
| ptr_ftype_void = build_function_type (ptr_type_node, endlink); |
| ptr_ftype_ptr |
| = build_function_type (ptr_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, endlink)); |
| |
| builtin_function ("__builtin_constant_p", default_function_type, |
| BUILT_IN_CONSTANT_P, NULL_PTR); |
| |
| builtin_function ("__builtin_return_address", |
| build_function_type (ptr_type_node, |
| tree_cons (NULL_TREE, |
| unsigned_type_node, |
| endlink)), |
| BUILT_IN_RETURN_ADDRESS, NULL_PTR); |
| |
| builtin_function ("__builtin_frame_address", |
| build_function_type (ptr_type_node, |
| tree_cons (NULL_TREE, |
| unsigned_type_node, |
| endlink)), |
| BUILT_IN_FRAME_ADDRESS, NULL_PTR); |
| |
| builtin_function ("__builtin_aggregate_incoming_address", |
| build_function_type (ptr_type_node, NULL_TREE), |
| BUILT_IN_AGGREGATE_INCOMING_ADDRESS, NULL_PTR); |
| |
| /* Hooks for the DWARF 2 __throw routine. */ |
| builtin_function ("__builtin_unwind_init", |
| build_function_type (void_type_node, endlink), |
| BUILT_IN_UNWIND_INIT, NULL_PTR); |
| builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR); |
| builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR); |
| builtin_function ("__builtin_dwarf_fp_regnum", |
| build_function_type (unsigned_type_node, endlink), |
| BUILT_IN_DWARF_FP_REGNUM, NULL_PTR); |
| builtin_function ("__builtin_dwarf_reg_size", int_ftype_int, |
| BUILT_IN_DWARF_REG_SIZE, NULL_PTR); |
| builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr, |
| BUILT_IN_FROB_RETURN_ADDR, NULL_PTR); |
| builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr, |
| BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR); |
| builtin_function ("__builtin_set_return_addr_reg", |
| build_function_type (void_type_node, |
| tree_cons (NULL_TREE, |
| ptr_type_node, |
| endlink)), |
| BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR); |
| builtin_function ("__builtin_eh_stub", ptr_ftype_void, |
| BUILT_IN_EH_STUB, NULL_PTR); |
| builtin_function |
| ("__builtin_set_eh_regs", |
| build_function_type (void_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, |
| type_for_mode (ptr_mode, 0), |
| endlink))), |
| BUILT_IN_SET_EH_REGS, NULL_PTR); |
| |
| builtin_function ("__builtin_alloca", |
| build_function_type (ptr_type_node, |
| tree_cons (NULL_TREE, |
| sizetype, |
| endlink)), |
| BUILT_IN_ALLOCA, "alloca"); |
| builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); |
| /* Define alloca, ffs as builtins. |
| Declare _exit just to mark it as volatile. */ |
| if (! flag_no_builtin && !flag_no_nonansi_builtin) |
| { |
| temp = builtin_function ("alloca", |
| build_function_type (ptr_type_node, |
| tree_cons (NULL_TREE, |
| sizetype, |
| endlink)), |
| BUILT_IN_ALLOCA, NULL_PTR); |
| /* Suppress error if redefined as a non-function. */ |
| DECL_BUILT_IN_NONANSI (temp) = 1; |
| temp = builtin_function ("ffs", |