mirror of
https://github.com/pmret/gcc-papermario.git
synced 2024-11-09 12:22:38 +01:00
7278 lines
232 KiB
C
7278 lines
232 KiB
C
|
/* Process declarations and variables for C compiler.
|
|||
|
Copyright (C) 1988, 92-97, 1998 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 <stdio.h>
|
|||
|
#include "tree.h"
|
|||
|
#include "flags.h"
|
|||
|
#include "output.h"
|
|||
|
#include "c-tree.h"
|
|||
|
#include "c-lex.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 use of implicit int. */
|
|||
|
|
|||
|
int warn_implicit_int;
|
|||
|
|
|||
|
/* Nonzero means message about use of implicit function declarations;
|
|||
|
1 means warning; 2 means error. */
|
|||
|
|
|||
|
int mesg_implicit_function_declaration;
|
|||
|
|
|||
|
/* 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, "-Werror-implicit-function-declaration"))
|
|||
|
mesg_implicit_function_declaration = 2;
|
|||
|
else if (!strcmp (p, "-Wimplicit-function-declaration"))
|
|||
|
mesg_implicit_function_declaration = 1;
|
|||
|
else if (!strcmp (p, "-Wno-implicit-function-declaration"))
|
|||
|
mesg_implicit_function_declaration = 0;
|
|||
|
else if (!strcmp (p, "-Wimplicit-int"))
|
|||
|
warn_implicit_int = 1;
|
|||
|
else if (!strcmp (p, "-Wno-implicit-int"))
|
|||
|
warn_implicit_int = 0;
|
|||
|
else if (!strcmp (p, "-Wimplicit"))
|
|||
|
{
|
|||
|
warn_implicit_int = 1;
|
|||
|
if (mesg_implicit_function_declaration != 2)
|
|||
|
mesg_implicit_function_declaration = 1;
|
|||
|
}
|
|||
|
else if (!strcmp (p, "-Wno-implicit"))
|
|||
|
warn_implicit_int = 0, mesg_implicit_function_declaration = 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_int = 1;
|
|||
|
mesg_implicit_function_declaration = 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
|
|||
|
/* Don't 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 or debugging information for this
|
|||
|
declaration. */
|
|||
|
TREE_ASM_WRITTEN (newdecl) = DECL_IGNORED_P (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
|
|||
|
&& DECL_ORIGINAL_TYPE (x) == NULL_TREE)
|
|||
|
{
|
|||
|
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 (mesg_implicit_function_declaration && implicit_warning)
|
|||
|
{
|
|||
|
if (mesg_implicit_function_declaration == 2)
|
|||
|
error ("implicit declaration of function `%s'",
|
|||
|
IDENTIFIER_POINTER (functionid));
|
|||
|
else
|
|||
|
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", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
|
|||
|
/* Suppress error if redefined as a non-function. */
|
|||
|
DECL_BUILT_IN_NONANSI (temp) = 1;
|
|||
|
temp = builtin_function ("_exit", void_ftype_any, NOT_BUILT_IN,
|
|||
|
NULL_PTR);
|
|||
|
TREE_THIS_VOLATILE (temp) = 1;
|
|||
|
TREE_SIDE_EFFECTS (temp) = 1;
|
|||
|
/* Suppress error if redefined as a non-function. */
|
|||
|
DECL_BUILT_IN_NONANSI (temp) = 1;
|
|||
|
}
|
|||
|
|
|||
|
builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR);
|
|||
|
builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("__builtin_labs", long_ftype_long, BUILT_IN_LABS,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("__builtin_saveregs",
|
|||
|
build_function_type (ptr_type_node, NULL_TREE),
|
|||
|
BUILT_IN_SAVEREGS, NULL_PTR);
|
|||
|
/* EXPAND_BUILTIN_VARARGS is obsolete. */
|
|||
|
#if 0
|
|||
|
builtin_function ("__builtin_varargs",
|
|||
|
build_function_type (ptr_type_node,
|
|||
|
tree_cons (NULL_TREE,
|
|||
|
integer_type_node,
|
|||
|
endlink)),
|
|||
|
BUILT_IN_VARARGS, NULL_PTR);
|
|||
|
#endif
|
|||
|
builtin_function ("__builtin_classify_type", default_function_type,
|
|||
|
BUILT_IN_CLASSIFY_TYPE, NULL_PTR);
|
|||
|
builtin_function ("__builtin_next_arg",
|
|||
|
build_function_type (ptr_type_node, NULL_TREE),
|
|||
|
BUILT_IN_NEXT_ARG, NULL_PTR);
|
|||
|
builtin_function ("__builtin_args_info",
|
|||
|
build_function_type (integer_type_node,
|
|||
|
tree_cons (NULL_TREE,
|
|||
|
integer_type_node,
|
|||
|
endlink)),
|
|||
|
BUILT_IN_ARGS_INFO, NULL_PTR);
|
|||
|
|
|||
|
/* Untyped call and return. */
|
|||
|
builtin_function ("__builtin_apply_args",
|
|||
|
build_function_type (ptr_type_node, NULL_TREE),
|
|||
|
BUILT_IN_APPLY_ARGS, NULL_PTR);
|
|||
|
|
|||
|
temp = tree_cons (NULL_TREE,
|
|||
|
build_pointer_type (build_function_type (void_type_node,
|
|||
|
NULL_TREE)),
|
|||
|
tree_cons (NULL_TREE,
|
|||
|
ptr_type_node,
|
|||
|
tree_cons (NULL_TREE,
|
|||
|
sizetype,
|
|||
|
endlink)));
|
|||
|
builtin_function ("__builtin_apply",
|
|||
|
build_function_type (ptr_type_node, temp),
|
|||
|
BUILT_IN_APPLY, NULL_PTR);
|
|||
|
builtin_function ("__builtin_return",
|
|||
|
build_function_type (void_type_node,
|
|||
|
tree_cons (NULL_TREE,
|
|||
|
ptr_type_node,
|
|||
|
endlink)),
|
|||
|
BUILT_IN_RETURN, NULL_PTR);
|
|||
|
|
|||
|
/* Currently under experimentation. */
|
|||
|
builtin_function ("__builtin_memcpy", memcpy_ftype,
|
|||
|
BUILT_IN_MEMCPY, "memcpy");
|
|||
|
builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet,
|
|||
|
BUILT_IN_MEMCMP, "memcmp");
|
|||
|
builtin_function ("__builtin_memset", memset_ftype,
|
|||
|
BUILT_IN_MEMSET, NULL_PTR);
|
|||
|
builtin_function ("__builtin_strcmp", int_ftype_string_string,
|
|||
|
BUILT_IN_STRCMP, "strcmp");
|
|||
|
builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
|
|||
|
BUILT_IN_STRCPY, "strcpy");
|
|||
|
builtin_function ("__builtin_strlen", strlen_ftype,
|
|||
|
BUILT_IN_STRLEN, "strlen");
|
|||
|
builtin_function ("__builtin_sqrtf", float_ftype_float,
|
|||
|
BUILT_IN_FSQRT, "sqrtf");
|
|||
|
builtin_function ("__builtin_fsqrt", double_ftype_double,
|
|||
|
BUILT_IN_FSQRT, "sqrt");
|
|||
|
builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble,
|
|||
|
BUILT_IN_FSQRT, "sqrtl");
|
|||
|
builtin_function ("__builtin_sinf", float_ftype_float,
|
|||
|
BUILT_IN_SIN, "sinf");
|
|||
|
builtin_function ("__builtin_sin", double_ftype_double,
|
|||
|
BUILT_IN_SIN, "sin");
|
|||
|
builtin_function ("__builtin_sinl", ldouble_ftype_ldouble,
|
|||
|
BUILT_IN_SIN, "sinl");
|
|||
|
builtin_function ("__builtin_cosf", float_ftype_float,
|
|||
|
BUILT_IN_COS, "cosf");
|
|||
|
builtin_function ("__builtin_cos", double_ftype_double,
|
|||
|
BUILT_IN_COS, "cos");
|
|||
|
builtin_function ("__builtin_cosl", ldouble_ftype_ldouble,
|
|||
|
BUILT_IN_COS, "cosl");
|
|||
|
builtin_function ("__builtin_setjmp",
|
|||
|
build_function_type (integer_type_node,
|
|||
|
tree_cons (NULL_TREE,
|
|||
|
ptr_type_node, endlink)),
|
|||
|
BUILT_IN_SETJMP, NULL_PTR);
|
|||
|
builtin_function ("__builtin_longjmp",
|
|||
|
build_function_type
|
|||
|
(void_type_node,
|
|||
|
tree_cons (NULL, ptr_type_node,
|
|||
|
tree_cons (NULL_TREE,
|
|||
|
integer_type_node,
|
|||
|
endlink))),
|
|||
|
BUILT_IN_LONGJMP, NULL_PTR);
|
|||
|
|
|||
|
/* In an ANSI C program, it is okay to supply built-in meanings
|
|||
|
for these functions, since applications cannot validly use them
|
|||
|
with any other meaning.
|
|||
|
However, honor the -fno-builtin option. */
|
|||
|
if (!flag_no_builtin)
|
|||
|
{
|
|||
|
builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR);
|
|||
|
builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS, NULL_PTR);
|
|||
|
builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, NULL_PTR);
|
|||
|
builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, NULL_PTR);
|
|||
|
builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR);
|
|||
|
builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("memset", memset_ftype, BUILT_IN_MEMSET, NULL_PTR);
|
|||
|
builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN, NULL_PTR);
|
|||
|
builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT, NULL_PTR);
|
|||
|
builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT, NULL_PTR);
|
|||
|
builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN, NULL_PTR);
|
|||
|
builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR);
|
|||
|
builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN, NULL_PTR);
|
|||
|
builtin_function ("cosf", float_ftype_float, BUILT_IN_COS, NULL_PTR);
|
|||
|
builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR);
|
|||
|
builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, NULL_PTR);
|
|||
|
|
|||
|
/* Declare these functions volatile
|
|||
|
to avoid spurious "control drops through" warnings. */
|
|||
|
/* Don't specify the argument types, to avoid errors
|
|||
|
from certain code which isn't valid in ANSI but which exists. */
|
|||
|
temp = builtin_function ("abort", void_ftype_any, NOT_BUILT_IN,
|
|||
|
NULL_PTR);
|
|||
|
TREE_THIS_VOLATILE (temp) = 1;
|
|||
|
TREE_SIDE_EFFECTS (temp) = 1;
|
|||
|
temp = builtin_function ("exit", void_ftype_any, NOT_BUILT_IN, NULL_PTR);
|
|||
|
TREE_THIS_VOLATILE (temp) = 1;
|
|||
|
TREE_SIDE_EFFECTS (temp) = 1;
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
/* Support for these has not been written in either expand_builtin
|
|||
|
or build_function_call. */
|
|||
|
builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, NULL_PTR);
|
|||
|
builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR);
|
|||
|
builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("__builtin_fmod", double_ftype_double_double,
|
|||
|
BUILT_IN_FMOD, NULL_PTR);
|
|||
|
builtin_function ("__builtin_frem", double_ftype_double_double,
|
|||
|
BUILT_IN_FREM, NULL_PTR);
|
|||
|
builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int,
|
|||
|
BUILT_IN_MEMSET, NULL_PTR);
|
|||
|
builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
|
|||
|
NULL_PTR);
|
|||
|
builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
|
|||
|
NULL_PTR);
|
|||
|
#endif
|
|||
|
|
|||
|
pedantic_lvalues = pedantic;
|
|||
|
|
|||
|
/* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
|
|||
|
declare_function_name ();
|
|||
|
|
|||
|
start_identifier_warnings ();
|
|||
|
|
|||
|
/* Prepare to check format strings against argument lists. */
|
|||
|
init_function_format_info ();
|
|||
|
|
|||
|
init_iterators ();
|
|||
|
|
|||
|
incomplete_decl_finalize_hook = finish_incomplete_decl;
|
|||
|
}
|
|||
|
|
|||
|
/* Return a definition for a builtin function named NAME and whose data type
|
|||
|
is TYPE. TYPE should be a function type with argument types.
|
|||
|
FUNCTION_CODE tells later passes how to compile calls to this function.
|
|||
|
See tree.h for its possible values.
|
|||
|
|
|||
|
If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
|
|||
|
the name to be called if we can't opencode the function. */
|
|||
|
|
|||
|
tree
|
|||
|
builtin_function (name, type, function_code, library_name)
|
|||
|
char *name;
|
|||
|
tree type;
|
|||
|
enum built_in_function function_code;
|
|||
|
char *library_name;
|
|||
|
{
|
|||
|
tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type);
|
|||
|
DECL_EXTERNAL (decl) = 1;
|
|||
|
TREE_PUBLIC (decl) = 1;
|
|||
|
/* If -traditional, permit redefining a builtin function any way you like.
|
|||
|
(Though really, if the program redefines these functions,
|
|||
|
it probably won't work right unless compiled with -fno-builtin.) */
|
|||
|
if (flag_traditional && name[0] != '_')
|
|||
|
DECL_BUILT_IN_NONANSI (decl) = 1;
|
|||
|
if (library_name)
|
|||
|
DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name);
|
|||
|
make_decl_rtl (decl, NULL_PTR, 1);
|
|||
|
pushdecl (decl);
|
|||
|
if (function_code != NOT_BUILT_IN)
|
|||
|
{
|
|||
|
DECL_BUILT_IN (decl) = 1;
|
|||
|
DECL_FUNCTION_CODE (decl) = function_code;
|
|||
|
}
|
|||
|
/* Warn if a function in the namespace for users
|
|||
|
is used without an occasion to consider it declared. */
|
|||
|
if (name[0] != '_' || name[1] != '_')
|
|||
|
C_DECL_ANTICIPATED (decl) = 1;
|
|||
|
|
|||
|
return decl;
|
|||
|
}
|
|||
|
|
|||
|
/* Called when a declaration is seen that contains no names to declare.
|
|||
|
If its type is a reference to a structure, union or enum inherited
|
|||
|
from a containing scope, shadow that tag name for the current scope
|
|||
|
with a forward reference.
|
|||
|
If its type defines a new named structure or union
|
|||
|
or defines an enum, it is valid but we need not do anything here.
|
|||
|
Otherwise, it is an error. */
|
|||
|
|
|||
|
void
|
|||
|
shadow_tag (declspecs)
|
|||
|
tree declspecs;
|
|||
|
{
|
|||
|
shadow_tag_warned (declspecs, 0);
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
shadow_tag_warned (declspecs, warned)
|
|||
|
tree declspecs;
|
|||
|
int warned;
|
|||
|
/* 1 => we have done a pedwarn. 2 => we have done a warning, but
|
|||
|
no pedwarn. */
|
|||
|
{
|
|||
|
int found_tag = 0;
|
|||
|
register tree link;
|
|||
|
|
|||
|
pending_invalid_xref = 0;
|
|||
|
|
|||
|
for (link = declspecs; link; link = TREE_CHAIN (link))
|
|||
|
{
|
|||
|
register tree value = TREE_VALUE (link);
|
|||
|
register enum tree_code code = TREE_CODE (value);
|
|||
|
|
|||
|
if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
|
|||
|
/* Used to test also that TYPE_SIZE (value) != 0.
|
|||
|
That caused warning for `struct foo;' at top level in the file. */
|
|||
|
{
|
|||
|
register tree name = lookup_tag_reverse (value);
|
|||
|
register tree t;
|
|||
|
|
|||
|
found_tag++;
|
|||
|
|
|||
|
if (name == 0)
|
|||
|
{
|
|||
|
if (warned != 1 && code != ENUMERAL_TYPE)
|
|||
|
/* Empty unnamed enum OK */
|
|||
|
{
|
|||
|
pedwarn ("unnamed struct/union that defines no instances");
|
|||
|
warned = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
t = lookup_tag (code, name, current_binding_level, 1);
|
|||
|
|
|||
|
if (t == 0)
|
|||
|
{
|
|||
|
t = make_node (code);
|
|||
|
pushtag (name, t);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!warned && ! in_system_header)
|
|||
|
{
|
|||
|
warning ("useless keyword or type name in empty declaration");
|
|||
|
warned = 2;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (found_tag > 1)
|
|||
|
error ("two types specified in one empty declaration");
|
|||
|
|
|||
|
if (warned != 1)
|
|||
|
{
|
|||
|
if (found_tag == 0)
|
|||
|
pedwarn ("empty declaration");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
|
|||
|
|
|||
|
tree
|
|||
|
groktypename (typename)
|
|||
|
tree typename;
|
|||
|
{
|
|||
|
if (TREE_CODE (typename) != TREE_LIST)
|
|||
|
return typename;
|
|||
|
return grokdeclarator (TREE_VALUE (typename),
|
|||
|
TREE_PURPOSE (typename),
|
|||
|
TYPENAME, 0);
|
|||
|
}
|
|||
|
|
|||
|
/* Return a PARM_DECL node for a given pair of specs and declarator. */
|
|||
|
|
|||
|
tree
|
|||
|
groktypename_in_parm_context (typename)
|
|||
|
tree typename;
|
|||
|
{
|
|||
|
if (TREE_CODE (typename) != TREE_LIST)
|
|||
|
return typename;
|
|||
|
return grokdeclarator (TREE_VALUE (typename),
|
|||
|
TREE_PURPOSE (typename),
|
|||
|
PARM, 0);
|
|||
|
}
|
|||
|
|
|||
|
/* Decode a declarator in an ordinary declaration or data definition.
|
|||
|
This is called as soon as the type information and variable name
|
|||
|
have been parsed, before parsing the initializer if any.
|
|||
|
Here we create the ..._DECL node, fill in its type,
|
|||
|
and put it on the list of decls for the current context.
|
|||
|
The ..._DECL node is returned as the value.
|
|||
|
|
|||
|
Exception: for arrays where the length is not specified,
|
|||
|
the type is left null, to be filled in by `finish_decl'.
|
|||
|
|
|||
|
Function definitions do not come here; they go to start_function
|
|||
|
instead. However, external and forward declarations of functions
|
|||
|
do go through here. Structure field declarations are done by
|
|||
|
grokfield and not through here. */
|
|||
|
|
|||
|
/* Set this to zero to debug not using the temporary obstack
|
|||
|
to parse initializers. */
|
|||
|
int debug_temp_inits = 1;
|
|||
|
|
|||
|
tree
|
|||
|
start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
|
|||
|
tree declarator, declspecs;
|
|||
|
int initialized;
|
|||
|
tree attributes, prefix_attributes;
|
|||
|
{
|
|||
|
register tree decl = grokdeclarator (declarator, declspecs,
|
|||
|
NORMAL, initialized);
|
|||
|
register tree tem;
|
|||
|
int init_written = initialized;
|
|||
|
|
|||
|
/* The corresponding pop_obstacks is in finish_decl. */
|
|||
|
push_obstacks_nochange ();
|
|||
|
|
|||
|
if (warn_main && !strcmp (IDENTIFIER_POINTER (declarator), "main"))
|
|||
|
warning_with_decl (decl, "`%s' is usually a function");
|
|||
|
|
|||
|
if (initialized)
|
|||
|
/* Is it valid for this decl to have an initializer at all?
|
|||
|
If not, set INITIALIZED to zero, which will indirectly
|
|||
|
tell `finish_decl' to ignore the initializer once it is parsed. */
|
|||
|
switch (TREE_CODE (decl))
|
|||
|
{
|
|||
|
case TYPE_DECL:
|
|||
|
/* typedef foo = bar means give foo the same type as bar.
|
|||
|
We haven't parsed bar yet, so `finish_decl' will fix that up.
|
|||
|
Any other case of an initialization in a TYPE_DECL is an error. */
|
|||
|
if (pedantic || list_length (declspecs) > 1)
|
|||
|
{
|
|||
|
error ("typedef `%s' is initialized",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (decl)));
|
|||
|
initialized = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case FUNCTION_DECL:
|
|||
|
error ("function `%s' is initialized like a variable",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (decl)));
|
|||
|
initialized = 0;
|
|||
|
break;
|
|||
|
|
|||
|
case PARM_DECL:
|
|||
|
/* DECL_INITIAL in a PARM_DECL is really DECL_ARG_TYPE. */
|
|||
|
error ("parameter `%s' is initialized",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (decl)));
|
|||
|
initialized = 0;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
/* Don't allow initializations for incomplete types
|
|||
|
except for arrays which might be completed by the initialization. */
|
|||
|
if (TYPE_SIZE (TREE_TYPE (decl)) != 0)
|
|||
|
{
|
|||
|
/* A complete type is ok if size is fixed. */
|
|||
|
|
|||
|
if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST
|
|||
|
|| C_DECL_VARIABLE_SIZE (decl))
|
|||
|
{
|
|||
|
error ("variable-sized object may not be initialized");
|
|||
|
initialized = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
|
|||
|
{
|
|||
|
error ("variable `%s' has initializer but incomplete type",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (decl)));
|
|||
|
initialized = 0;
|
|||
|
}
|
|||
|
else if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl))) == 0)
|
|||
|
{
|
|||
|
error ("elements of array `%s' have incomplete type",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (decl)));
|
|||
|
initialized = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (initialized)
|
|||
|
{
|
|||
|
#if 0 /* Seems redundant with grokdeclarator. */
|
|||
|
if (current_binding_level != global_binding_level
|
|||
|
&& DECL_EXTERNAL (decl)
|
|||
|
&& TREE_CODE (decl) != FUNCTION_DECL)
|
|||
|
warning ("declaration of `%s' has `extern' and is initialized",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (decl)));
|
|||
|
#endif
|
|||
|
DECL_EXTERNAL (decl) = 0;
|
|||
|
if (current_binding_level == global_binding_level)
|
|||
|
TREE_STATIC (decl) = 1;
|
|||
|
|
|||
|
/* Tell `pushdecl' this is an initialized decl
|
|||
|
even though we don't yet have the initializer expression.
|
|||
|
Also tell `finish_decl' it may store the real initializer. */
|
|||
|
DECL_INITIAL (decl) = error_mark_node;
|
|||
|
}
|
|||
|
|
|||
|
/* If this is a function declaration, write a record describing it to the
|
|||
|
prototypes file (if requested). */
|
|||
|
|
|||
|
if (TREE_CODE (decl) == FUNCTION_DECL)
|
|||
|
gen_aux_info_record (decl, 0, 0, TYPE_ARG_TYPES (TREE_TYPE (decl)) != 0);
|
|||
|
|
|||
|
/* ANSI specifies that a tentative definition which is not merged with
|
|||
|
a non-tentative definition behaves exactly like a definition with an
|
|||
|
initializer equal to zero. (Section 3.7.2)
|
|||
|
-fno-common gives strict ANSI behavior. Usually you don't want it.
|
|||
|
This matters only for variables with external linkage. */
|
|||
|
if (! flag_no_common || ! TREE_PUBLIC (decl))
|
|||
|
DECL_COMMON (decl) = 1;
|
|||
|
|
|||
|
/* Set attributes here so if duplicate decl, will have proper attributes. */
|
|||
|
decl_attributes (decl, attributes, prefix_attributes);
|
|||
|
|
|||
|
/* Add this decl to the current binding level.
|
|||
|
TEM may equal DECL or it may be a previous decl of the same name. */
|
|||
|
tem = pushdecl (decl);
|
|||
|
|
|||
|
/* For a local variable, define the RTL now. */
|
|||
|
if (current_binding_level != global_binding_level
|
|||
|
/* But not if this is a duplicate decl
|
|||
|
and we preserved the rtl from the previous one
|
|||
|
(which may or may not happen). */
|
|||
|
&& DECL_RTL (tem) == 0)
|
|||
|
{
|
|||
|
if (TYPE_SIZE (TREE_TYPE (tem)) != 0)
|
|||
|
expand_decl (tem);
|
|||
|
else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
|
|||
|
&& DECL_INITIAL (tem) != 0)
|
|||
|
expand_decl (tem);
|
|||
|
}
|
|||
|
|
|||
|
if (init_written)
|
|||
|
{
|
|||
|
/* When parsing and digesting the initializer,
|
|||
|
use temporary storage. Do this even if we will ignore the value. */
|
|||
|
if (current_binding_level == global_binding_level && debug_temp_inits)
|
|||
|
temporary_allocation ();
|
|||
|
}
|
|||
|
|
|||
|
return tem;
|
|||
|
}
|
|||
|
|
|||
|
/* Finish processing of a declaration;
|
|||
|
install its initial value.
|
|||
|
If the length of an array type is not known before,
|
|||
|
it must be determined now, from the initial value, or it is an error. */
|
|||
|
|
|||
|
void
|
|||
|
finish_decl (decl, init, asmspec_tree)
|
|||
|
tree decl, init;
|
|||
|
tree asmspec_tree;
|
|||
|
{
|
|||
|
register tree type = TREE_TYPE (decl);
|
|||
|
int was_incomplete = (DECL_SIZE (decl) == 0);
|
|||
|
int temporary = allocation_temporary_p ();
|
|||
|
char *asmspec = 0;
|
|||
|
|
|||
|
/* If a name was specified, get the string. */
|
|||
|
if (asmspec_tree)
|
|||
|
asmspec = TREE_STRING_POINTER (asmspec_tree);
|
|||
|
|
|||
|
/* If `start_decl' didn't like having an initialization, ignore it now. */
|
|||
|
|
|||
|
if (init != 0 && DECL_INITIAL (decl) == 0)
|
|||
|
init = 0;
|
|||
|
/* Don't crash if parm is initialized. */
|
|||
|
if (TREE_CODE (decl) == PARM_DECL)
|
|||
|
init = 0;
|
|||
|
|
|||
|
if (ITERATOR_P (decl))
|
|||
|
{
|
|||
|
if (init == 0)
|
|||
|
error_with_decl (decl, "iterator has no initial value");
|
|||
|
else
|
|||
|
init = save_expr (init);
|
|||
|
}
|
|||
|
|
|||
|
if (init)
|
|||
|
{
|
|||
|
if (TREE_CODE (decl) != TYPE_DECL)
|
|||
|
store_init_value (decl, init);
|
|||
|
else
|
|||
|
{
|
|||
|
/* typedef foo = bar; store the type of bar as the type of foo. */
|
|||
|
TREE_TYPE (decl) = TREE_TYPE (init);
|
|||
|
DECL_INITIAL (decl) = init = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Pop back to the obstack that is current for this binding level.
|
|||
|
This is because MAXINDEX, rtl, etc. to be made below
|
|||
|
must go in the permanent obstack. But don't discard the
|
|||
|
temporary data yet. */
|
|||
|
pop_obstacks ();
|
|||
|
#if 0 /* pop_obstacks was near the end; this is what was here. */
|
|||
|
if (current_binding_level == global_binding_level && temporary)
|
|||
|
end_temporary_allocation ();
|
|||
|
#endif
|
|||
|
|
|||
|
/* Deduce size of array from initialization, if not already known */
|
|||
|
|
|||
|
if (TREE_CODE (type) == ARRAY_TYPE
|
|||
|
&& TYPE_DOMAIN (type) == 0
|
|||
|
&& TREE_CODE (decl) != TYPE_DECL)
|
|||
|
{
|
|||
|
int do_default
|
|||
|
= (TREE_STATIC (decl)
|
|||
|
/* Even if pedantic, an external linkage array
|
|||
|
may have incomplete type at first. */
|
|||
|
? pedantic && !TREE_PUBLIC (decl)
|
|||
|
: !DECL_EXTERNAL (decl));
|
|||
|
int failure
|
|||
|
= complete_array_type (type, DECL_INITIAL (decl), do_default);
|
|||
|
|
|||
|
/* Get the completed type made by complete_array_type. */
|
|||
|
type = TREE_TYPE (decl);
|
|||
|
|
|||
|
if (failure == 1)
|
|||
|
error_with_decl (decl, "initializer fails to determine size of `%s'");
|
|||
|
|
|||
|
if (failure == 2)
|
|||
|
{
|
|||
|
if (do_default)
|
|||
|
error_with_decl (decl, "array size missing in `%s'");
|
|||
|
/* If a `static' var's size isn't known,
|
|||
|
make it extern as well as static, so it does not get
|
|||
|
allocated.
|
|||
|
If it is not `static', then do not mark extern;
|
|||
|
finish_incomplete_decl will give it a default size
|
|||
|
and it will get allocated. */
|
|||
|
else if (!pedantic && TREE_STATIC (decl) && ! TREE_PUBLIC (decl))
|
|||
|
DECL_EXTERNAL (decl) = 1;
|
|||
|
}
|
|||
|
|
|||
|
/* TYPE_MAX_VALUE is always one less than the number of elements
|
|||
|
in the array, because we start counting at zero. Therefore,
|
|||
|
warn only if the value is less than zero. */
|
|||
|
if (pedantic && TYPE_DOMAIN (type) != 0
|
|||
|
&& tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0)
|
|||
|
error_with_decl (decl, "zero or negative size array `%s'");
|
|||
|
|
|||
|
layout_decl (decl, 0);
|
|||
|
}
|
|||
|
|
|||
|
if (TREE_CODE (decl) == VAR_DECL)
|
|||
|
{
|
|||
|
if (DECL_SIZE (decl) == 0
|
|||
|
&& TYPE_SIZE (TREE_TYPE (decl)) != 0)
|
|||
|
layout_decl (decl, 0);
|
|||
|
|
|||
|
if (DECL_SIZE (decl) == 0
|
|||
|
&& (TREE_STATIC (decl)
|
|||
|
?
|
|||
|
/* A static variable with an incomplete type
|
|||
|
is an error if it is initialized.
|
|||
|
Also if it is not file scope.
|
|||
|
Otherwise, let it through, but if it is not `extern'
|
|||
|
then it may cause an error message later. */
|
|||
|
/* A duplicate_decls call could have changed an extern
|
|||
|
declaration into a file scope one. This can be detected
|
|||
|
by TREE_ASM_WRITTEN being set. */
|
|||
|
(DECL_INITIAL (decl) != 0
|
|||
|
|| DECL_CONTEXT (decl) != 0 && ! TREE_ASM_WRITTEN (decl))
|
|||
|
:
|
|||
|
/* An automatic variable with an incomplete type
|
|||
|
is an error. */
|
|||
|
!DECL_EXTERNAL (decl)))
|
|||
|
{
|
|||
|
error_with_decl (decl, "storage size of `%s' isn't known");
|
|||
|
TREE_TYPE (decl) = error_mark_node;
|
|||
|
}
|
|||
|
|
|||
|
if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
|
|||
|
&& DECL_SIZE (decl) != 0)
|
|||
|
{
|
|||
|
if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
|
|||
|
constant_expression_warning (DECL_SIZE (decl));
|
|||
|
else
|
|||
|
error_with_decl (decl, "storage size of `%s' isn't constant");
|
|||
|
}
|
|||
|
|
|||
|
if (TREE_USED (type))
|
|||
|
TREE_USED (decl) = 1;
|
|||
|
}
|
|||
|
|
|||
|
/* If this is a function and an assembler name is specified, it isn't
|
|||
|
builtin any more. Also reset DECL_RTL so we can give it its new
|
|||
|
name. */
|
|||
|
if (TREE_CODE (decl) == FUNCTION_DECL && asmspec)
|
|||
|
{
|
|||
|
DECL_BUILT_IN (decl) = 0;
|
|||
|
DECL_RTL (decl) = 0;
|
|||
|
}
|
|||
|
|
|||
|
/* Output the assembler code and/or RTL code for variables and functions,
|
|||
|
unless the type is an undefined structure or union.
|
|||
|
If not, it will get done when the type is completed. */
|
|||
|
|
|||
|
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
|
|||
|
{
|
|||
|
if ((flag_traditional || TREE_PERMANENT (decl))
|
|||
|
&& allocation_temporary_p ())
|
|||
|
{
|
|||
|
push_obstacks_nochange ();
|
|||
|
end_temporary_allocation ();
|
|||
|
/* This is a no-op in c-lang.c or something real in objc-actions.c. */
|
|||
|
maybe_objc_check_decl (decl);
|
|||
|
rest_of_decl_compilation (decl, asmspec,
|
|||
|
(DECL_CONTEXT (decl) == 0
|
|||
|
|| TREE_ASM_WRITTEN (decl)),
|
|||
|
0);
|
|||
|
pop_obstacks ();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* This is a no-op in c-lang.c or something real in objc-actions.c. */
|
|||
|
maybe_objc_check_decl (decl);
|
|||
|
rest_of_decl_compilation (decl, asmspec, DECL_CONTEXT (decl) == 0,
|
|||
|
0);
|
|||
|
}
|
|||
|
if (DECL_CONTEXT (decl) != 0)
|
|||
|
{
|
|||
|
/* Recompute the RTL of a local array now
|
|||
|
if it used to be an incomplete type. */
|
|||
|
if (was_incomplete
|
|||
|
&& ! TREE_STATIC (decl) && ! DECL_EXTERNAL (decl))
|
|||
|
{
|
|||
|
/* If we used it already as memory, it must stay in memory. */
|
|||
|
TREE_ADDRESSABLE (decl) = TREE_USED (decl);
|
|||
|
/* If it's still incomplete now, no init will save it. */
|
|||
|
if (DECL_SIZE (decl) == 0)
|
|||
|
DECL_INITIAL (decl) = 0;
|
|||
|
expand_decl (decl);
|
|||
|
}
|
|||
|
/* Compute and store the initial value. */
|
|||
|
if (TREE_CODE (decl) != FUNCTION_DECL)
|
|||
|
expand_decl_init (decl);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (TREE_CODE (decl) == TYPE_DECL)
|
|||
|
{
|
|||
|
/* This is a no-op in c-lang.c or something real in objc-actions.c. */
|
|||
|
maybe_objc_check_decl (decl);
|
|||
|
rest_of_decl_compilation (decl, NULL_PTR, DECL_CONTEXT (decl) == 0,
|
|||
|
0);
|
|||
|
}
|
|||
|
|
|||
|
/* ??? After 2.3, test (init != 0) instead of TREE_CODE. */
|
|||
|
/* This test used to include TREE_PERMANENT, however, we have the same
|
|||
|
problem with initializers at the function level. Such initializers get
|
|||
|
saved until the end of the function on the momentary_obstack. */
|
|||
|
if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
|
|||
|
&& temporary
|
|||
|
/* DECL_INITIAL is not defined in PARM_DECLs, since it shares
|
|||
|
space with DECL_ARG_TYPE. */
|
|||
|
&& TREE_CODE (decl) != PARM_DECL)
|
|||
|
{
|
|||
|
/* We need to remember that this array HAD an initialization,
|
|||
|
but discard the actual temporary nodes,
|
|||
|
since we can't have a permanent node keep pointing to them. */
|
|||
|
/* We make an exception for inline functions, since it's
|
|||
|
normal for a local extern redeclaration of an inline function
|
|||
|
to have a copy of the top-level decl's DECL_INLINE. */
|
|||
|
if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
|
|||
|
{
|
|||
|
/* If this is a const variable, then preserve the
|
|||
|
initializer instead of discarding it so that we can optimize
|
|||
|
references to it. */
|
|||
|
/* This test used to include TREE_STATIC, but this won't be set
|
|||
|
for function level initializers. */
|
|||
|
if (TREE_READONLY (decl) || ITERATOR_P (decl))
|
|||
|
{
|
|||
|
preserve_initializer ();
|
|||
|
/* Hack? Set the permanent bit for something that is permanent,
|
|||
|
but not on the permanent obstack, so as to convince
|
|||
|
output_constant_def to make its rtl on the permanent
|
|||
|
obstack. */
|
|||
|
TREE_PERMANENT (DECL_INITIAL (decl)) = 1;
|
|||
|
|
|||
|
/* The initializer and DECL must have the same (or equivalent
|
|||
|
types), but if the initializer is a STRING_CST, its type
|
|||
|
might not be on the right obstack, so copy the type
|
|||
|
of DECL. */
|
|||
|
TREE_TYPE (DECL_INITIAL (decl)) = type;
|
|||
|
}
|
|||
|
else
|
|||
|
DECL_INITIAL (decl) = error_mark_node;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* If requested, warn about definitions of large data objects. */
|
|||
|
|
|||
|
if (warn_larger_than
|
|||
|
&& (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
|
|||
|
&& !DECL_EXTERNAL (decl))
|
|||
|
{
|
|||
|
register tree decl_size = DECL_SIZE (decl);
|
|||
|
|
|||
|
if (decl_size && TREE_CODE (decl_size) == INTEGER_CST)
|
|||
|
{
|
|||
|
unsigned units = TREE_INT_CST_LOW(decl_size) / BITS_PER_UNIT;
|
|||
|
|
|||
|
if (units > larger_than_size)
|
|||
|
warning_with_decl (decl, "size of `%s' is %u bytes", units);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
/* Resume permanent allocation, if not within a function. */
|
|||
|
/* The corresponding push_obstacks_nochange is in start_decl,
|
|||
|
and in push_parm_decl and in grokfield. */
|
|||
|
pop_obstacks ();
|
|||
|
#endif
|
|||
|
|
|||
|
/* If we have gone back from temporary to permanent allocation,
|
|||
|
actually free the temporary space that we no longer need. */
|
|||
|
if (temporary && !allocation_temporary_p ())
|
|||
|
permanent_allocation (0);
|
|||
|
|
|||
|
/* At the end of a declaration, throw away any variable type sizes
|
|||
|
of types defined inside that declaration. There is no use
|
|||
|
computing them in the following function definition. */
|
|||
|
if (current_binding_level == global_binding_level)
|
|||
|
get_pending_sizes ();
|
|||
|
}
|
|||
|
|
|||
|
/* If DECL has a cleanup, build and return that cleanup here.
|
|||
|
This is a callback called by expand_expr. */
|
|||
|
|
|||
|
tree
|
|||
|
maybe_build_cleanup (decl)
|
|||
|
tree decl;
|
|||
|
{
|
|||
|
/* There are no cleanups in C. */
|
|||
|
return NULL_TREE;
|
|||
|
}
|
|||
|
|
|||
|
/* Given a parsed parameter declaration,
|
|||
|
decode it into a PARM_DECL and push that on the current binding level.
|
|||
|
Also, for the sake of forward parm decls,
|
|||
|
record the given order of parms in `parm_order'. */
|
|||
|
|
|||
|
void
|
|||
|
push_parm_decl (parm)
|
|||
|
tree parm;
|
|||
|
{
|
|||
|
tree decl;
|
|||
|
int old_immediate_size_expand = immediate_size_expand;
|
|||
|
/* Don't try computing parm sizes now -- wait till fn is called. */
|
|||
|
immediate_size_expand = 0;
|
|||
|
|
|||
|
/* The corresponding pop_obstacks is in finish_decl. */
|
|||
|
push_obstacks_nochange ();
|
|||
|
|
|||
|
decl = grokdeclarator (TREE_VALUE (TREE_PURPOSE (parm)),
|
|||
|
TREE_PURPOSE (TREE_PURPOSE (parm)), PARM, 0);
|
|||
|
decl_attributes (decl, TREE_VALUE (TREE_VALUE (parm)),
|
|||
|
TREE_PURPOSE (TREE_VALUE (parm)));
|
|||
|
|
|||
|
#if 0
|
|||
|
if (DECL_NAME (decl))
|
|||
|
{
|
|||
|
tree olddecl;
|
|||
|
olddecl = lookup_name (DECL_NAME (decl));
|
|||
|
if (pedantic && olddecl != 0 && TREE_CODE (olddecl) == TYPE_DECL)
|
|||
|
pedwarn_with_decl (decl, "ANSI C forbids parameter `%s' shadowing typedef");
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
decl = pushdecl (decl);
|
|||
|
|
|||
|
immediate_size_expand = old_immediate_size_expand;
|
|||
|
|
|||
|
current_binding_level->parm_order
|
|||
|
= tree_cons (NULL_TREE, decl, current_binding_level->parm_order);
|
|||
|
|
|||
|
/* Add this decl to the current binding level. */
|
|||
|
finish_decl (decl, NULL_TREE, NULL_TREE);
|
|||
|
}
|
|||
|
|
|||
|
/* Clear the given order of parms in `parm_order'.
|
|||
|
Used at start of parm list,
|
|||
|
and also at semicolon terminating forward decls. */
|
|||
|
|
|||
|
void
|
|||
|
clear_parm_order ()
|
|||
|
{
|
|||
|
current_binding_level->parm_order = NULL_TREE;
|
|||
|
}
|
|||
|
|
|||
|
/* Make TYPE a complete type based on INITIAL_VALUE.
|
|||
|
Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
|
|||
|
2 if there was no information (in which case assume 1 if DO_DEFAULT). */
|
|||
|
|
|||
|
int
|
|||
|
complete_array_type (type, initial_value, do_default)
|
|||
|
tree type;
|
|||
|
tree initial_value;
|
|||
|
int do_default;
|
|||
|
{
|
|||
|
register tree maxindex = NULL_TREE;
|
|||
|
int value = 0;
|
|||
|
|
|||
|
if (initial_value)
|
|||
|
{
|
|||
|
/* Note MAXINDEX is really the maximum index,
|
|||
|
one less than the size. */
|
|||
|
if (TREE_CODE (initial_value) == STRING_CST)
|
|||
|
{
|
|||
|
int eltsize
|
|||
|
= int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
|
|||
|
maxindex = build_int_2 ((TREE_STRING_LENGTH (initial_value)
|
|||
|
/ eltsize) - 1, 0);
|
|||
|
}
|
|||
|
else if (TREE_CODE (initial_value) == CONSTRUCTOR)
|
|||
|
{
|
|||
|
tree elts = CONSTRUCTOR_ELTS (initial_value);
|
|||
|
maxindex = size_binop (MINUS_EXPR, integer_zero_node, size_one_node);
|
|||
|
for (; elts; elts = TREE_CHAIN (elts))
|
|||
|
{
|
|||
|
if (TREE_PURPOSE (elts))
|
|||
|
maxindex = TREE_PURPOSE (elts);
|
|||
|
else
|
|||
|
maxindex = size_binop (PLUS_EXPR, maxindex, size_one_node);
|
|||
|
}
|
|||
|
maxindex = copy_node (maxindex);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Make an error message unless that happened already. */
|
|||
|
if (initial_value != error_mark_node)
|
|||
|
value = 1;
|
|||
|
|
|||
|
/* Prevent further error messages. */
|
|||
|
maxindex = build_int_2 (0, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!maxindex)
|
|||
|
{
|
|||
|
if (do_default)
|
|||
|
maxindex = build_int_2 (0, 0);
|
|||
|
value = 2;
|
|||
|
}
|
|||
|
|
|||
|
if (maxindex)
|
|||
|
{
|
|||
|
TYPE_DOMAIN (type) = build_index_type (maxindex);
|
|||
|
if (!TREE_TYPE (maxindex))
|
|||
|
TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
|
|||
|
}
|
|||
|
|
|||
|
/* Lay out the type now that we can get the real answer. */
|
|||
|
|
|||
|
layout_type (type);
|
|||
|
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
/* Given declspecs and a declarator,
|
|||
|
determine the name and type of the object declared
|
|||
|
and construct a ..._DECL node for it.
|
|||
|
(In one case we can return a ..._TYPE node instead.
|
|||
|
For invalid input we sometimes return 0.)
|
|||
|
|
|||
|
DECLSPECS is a chain of tree_list nodes whose value fields
|
|||
|
are the storage classes and type specifiers.
|
|||
|
|
|||
|
DECL_CONTEXT says which syntactic context this declaration is in:
|
|||
|
NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL.
|
|||
|
FUNCDEF for a function definition. Like NORMAL but a few different
|
|||
|
error messages in each case. Return value may be zero meaning
|
|||
|
this definition is too screwy to try to parse.
|
|||
|
PARM for a parameter declaration (either within a function prototype
|
|||
|
or before a function body). Make a PARM_DECL, or return void_type_node.
|
|||
|
TYPENAME if for a typename (in a cast or sizeof).
|
|||
|
Don't make a DECL node; just return the ..._TYPE node.
|
|||
|
FIELD for a struct or union field; make a FIELD_DECL.
|
|||
|
BITFIELD for a field with specified width.
|
|||
|
INITIALIZED is 1 if the decl has an initializer.
|
|||
|
|
|||
|
In the TYPENAME case, DECLARATOR is really an absolute declarator.
|
|||
|
It may also be so in the PARM case, for a prototype where the
|
|||
|
argument type is specified but not the name.
|
|||
|
|
|||
|
This function is where the complicated C meanings of `static'
|
|||
|
and `extern' are interpreted. */
|
|||
|
|
|||
|
static tree
|
|||
|
grokdeclarator (declarator, declspecs, decl_context, initialized)
|
|||
|
tree declspecs;
|
|||
|
tree declarator;
|
|||
|
enum decl_context decl_context;
|
|||
|
int initialized;
|
|||
|
{
|
|||
|
int specbits = 0;
|
|||
|
tree spec;
|
|||
|
tree type = NULL_TREE;
|
|||
|
int longlong = 0;
|
|||
|
int constp;
|
|||
|
int volatilep;
|
|||
|
int inlinep;
|
|||
|
int explicit_int = 0;
|
|||
|
int explicit_char = 0;
|
|||
|
int defaulted_int = 0;
|
|||
|
tree typedef_decl = 0;
|
|||
|
char *name;
|
|||
|
tree typedef_type = 0;
|
|||
|
int funcdef_flag = 0;
|
|||
|
enum tree_code innermost_code = ERROR_MARK;
|
|||
|
int bitfield = 0;
|
|||
|
int size_varies = 0;
|
|||
|
tree decl_machine_attr = NULL_TREE;
|
|||
|
|
|||
|
if (decl_context == BITFIELD)
|
|||
|
bitfield = 1, decl_context = FIELD;
|
|||
|
|
|||
|
if (decl_context == FUNCDEF)
|
|||
|
funcdef_flag = 1, decl_context = NORMAL;
|
|||
|
|
|||
|
push_obstacks_nochange ();
|
|||
|
|
|||
|
if (flag_traditional && allocation_temporary_p ())
|
|||
|
end_temporary_allocation ();
|
|||
|
|
|||
|
/* Look inside a declarator for the name being declared
|
|||
|
and get it as a string, for an error message. */
|
|||
|
{
|
|||
|
register tree decl = declarator;
|
|||
|
name = 0;
|
|||
|
|
|||
|
while (decl)
|
|||
|
switch (TREE_CODE (decl))
|
|||
|
{
|
|||
|
case ARRAY_REF:
|
|||
|
case INDIRECT_REF:
|
|||
|
case CALL_EXPR:
|
|||
|
innermost_code = TREE_CODE (decl);
|
|||
|
decl = TREE_OPERAND (decl, 0);
|
|||
|
break;
|
|||
|
|
|||
|
case IDENTIFIER_NODE:
|
|||
|
name = IDENTIFIER_POINTER (decl);
|
|||
|
decl = 0;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
abort ();
|
|||
|
}
|
|||
|
if (name == 0)
|
|||
|
name = "type name";
|
|||
|
}
|
|||
|
|
|||
|
/* A function definition's declarator must have the form of
|
|||
|
a function declarator. */
|
|||
|
|
|||
|
if (funcdef_flag && innermost_code != CALL_EXPR)
|
|||
|
return 0;
|
|||
|
|
|||
|
/* Anything declared one level down from the top level
|
|||
|
must be one of the parameters of a function
|
|||
|
(because the body is at least two levels down). */
|
|||
|
|
|||
|
/* If this looks like a function definition, make it one,
|
|||
|
even if it occurs where parms are expected.
|
|||
|
Then store_parm_decls will reject it and not use it as a parm. */
|
|||
|
if (decl_context == NORMAL && !funcdef_flag
|
|||
|
&& current_binding_level->parm_flag)
|
|||
|
decl_context = PARM;
|
|||
|
|
|||
|
/* Look through the decl specs and record which ones appear.
|
|||
|
Some typespecs are defined as built-in typenames.
|
|||
|
Others, the ones that are modifiers of other types,
|
|||
|
are represented by bits in SPECBITS: set the bits for
|
|||
|
the modifiers that appear. Storage class keywords are also in SPECBITS.
|
|||
|
|
|||
|
If there is a typedef name or a type, store the type in TYPE.
|
|||
|
This includes builtin typedefs such as `int'.
|
|||
|
|
|||
|
Set EXPLICIT_INT or EXPLICIT_CHAR if the type is `int' or `char'
|
|||
|
and did not come from a user typedef.
|
|||
|
|
|||
|
Set LONGLONG if `long' is mentioned twice. */
|
|||
|
|
|||
|
for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
|
|||
|
{
|
|||
|
register int i;
|
|||
|
register tree id = TREE_VALUE (spec);
|
|||
|
|
|||
|
if (id == ridpointers[(int) RID_INT])
|
|||
|
explicit_int = 1;
|
|||
|
if (id == ridpointers[(int) RID_CHAR])
|
|||
|
explicit_char = 1;
|
|||
|
|
|||
|
if (TREE_CODE (id) == IDENTIFIER_NODE)
|
|||
|
for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++)
|
|||
|
{
|
|||
|
if (ridpointers[i] == id)
|
|||
|
{
|
|||
|
if (i == (int) RID_LONG && specbits & (1<<i))
|
|||
|
{
|
|||
|
if (longlong)
|
|||
|
error ("`long long long' is too long for GCC");
|
|||
|
else
|
|||
|
{
|
|||
|
if (pedantic && ! in_system_header)
|
|||
|
pedwarn ("ANSI C does not support `long long'");
|
|||
|
longlong = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (specbits & (1 << i))
|
|||
|
pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
|
|||
|
specbits |= 1 << i;
|
|||
|
goto found;
|
|||
|
}
|
|||
|
}
|
|||
|
if (type)
|
|||
|
error ("two or more data types in declaration of `%s'", name);
|
|||
|
/* Actual typedefs come to us as TYPE_DECL nodes. */
|
|||
|
else if (TREE_CODE (id) == TYPE_DECL)
|
|||
|
{
|
|||
|
type = TREE_TYPE (id);
|
|||
|
decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id);
|
|||
|
typedef_decl = id;
|
|||
|
}
|
|||
|
/* Built-in types come as identifiers. */
|
|||
|
else if (TREE_CODE (id) == IDENTIFIER_NODE)
|
|||
|
{
|
|||
|
register tree t = lookup_name (id);
|
|||
|
if (TREE_TYPE (t) == error_mark_node)
|
|||
|
;
|
|||
|
else if (!t || TREE_CODE (t) != TYPE_DECL)
|
|||
|
error ("`%s' fails to be a typedef or built in type",
|
|||
|
IDENTIFIER_POINTER (id));
|
|||
|
else
|
|||
|
{
|
|||
|
type = TREE_TYPE (t);
|
|||
|
typedef_decl = t;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (TREE_CODE (id) != ERROR_MARK)
|
|||
|
type = id;
|
|||
|
|
|||
|
found: {}
|
|||
|
}
|
|||
|
|
|||
|
typedef_type = type;
|
|||
|
if (type)
|
|||
|
size_varies = C_TYPE_VARIABLE_SIZE (type);
|
|||
|
|
|||
|
/* No type at all: default to `int', and set DEFAULTED_INT
|
|||
|
because it was not a user-defined typedef. */
|
|||
|
|
|||
|
if (type == 0)
|
|||
|
{
|
|||
|
if (! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
|
|||
|
| (1 << (int) RID_SIGNED)
|
|||
|
| (1 << (int) RID_UNSIGNED))))
|
|||
|
{
|
|||
|
/* C9x will probably require a diagnostic here.
|
|||
|
For now, issue a warning if -Wreturn-type and this is a function,
|
|||
|
or if -Wimplicit; prefer the former warning since it is more
|
|||
|
explicit. */
|
|||
|
if ((warn_implicit_int || warn_return_type) && funcdef_flag)
|
|||
|
warn_about_return_type = 1;
|
|||
|
else if (warn_implicit_int)
|
|||
|
warning ("type defaults to `int' in declaration of `%s'", name);
|
|||
|
}
|
|||
|
|
|||
|
defaulted_int = 1;
|
|||
|
type = integer_type_node;
|
|||
|
}
|
|||
|
|
|||
|
/* Now process the modifiers that were specified
|
|||
|
and check for invalid combinations. */
|
|||
|
|
|||
|
/* Long double is a special combination. */
|
|||
|
|
|||
|
if ((specbits & 1 << (int) RID_LONG) && ! longlong
|
|||
|
&& TYPE_MAIN_VARIANT (type) == double_type_node)
|
|||
|
{
|
|||
|
specbits &= ~ (1 << (int) RID_LONG);
|
|||
|
type = long_double_type_node;
|
|||
|
}
|
|||
|
|
|||
|
/* Check all other uses of type modifiers. */
|
|||
|
|
|||
|
if (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
|
|||
|
| (1 << (int) RID_UNSIGNED) | (1 << (int) RID_SIGNED)))
|
|||
|
{
|
|||
|
int ok = 0;
|
|||
|
|
|||
|
if ((specbits & 1 << (int) RID_LONG)
|
|||
|
&& (specbits & 1 << (int) RID_SHORT))
|
|||
|
error ("both long and short specified for `%s'", name);
|
|||
|
else if (((specbits & 1 << (int) RID_LONG)
|
|||
|
|| (specbits & 1 << (int) RID_SHORT))
|
|||
|
&& explicit_char)
|
|||
|
error ("long or short specified with char for `%s'", name);
|
|||
|
else if (((specbits & 1 << (int) RID_LONG)
|
|||
|
|| (specbits & 1 << (int) RID_SHORT))
|
|||
|
&& TREE_CODE (type) == REAL_TYPE)
|
|||
|
{
|
|||
|
static int already = 0;
|
|||
|
|
|||
|
error ("long or short specified with floating type for `%s'", name);
|
|||
|
if (! already && ! pedantic)
|
|||
|
{
|
|||
|
error ("the only valid combination is `long double'");
|
|||
|
already = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
else if ((specbits & 1 << (int) RID_SIGNED)
|
|||
|
&& (specbits & 1 << (int) RID_UNSIGNED))
|
|||
|
error ("both signed and unsigned specified for `%s'", name);
|
|||
|
else if (TREE_CODE (type) != INTEGER_TYPE)
|
|||
|
error ("long, short, signed or unsigned invalid for `%s'", name);
|
|||
|
else
|
|||
|
{
|
|||
|
ok = 1;
|
|||
|
if (!explicit_int && !defaulted_int && !explicit_char && pedantic)
|
|||
|
{
|
|||
|
pedwarn ("long, short, signed or unsigned used invalidly for `%s'",
|
|||
|
name);
|
|||
|
if (flag_pedantic_errors)
|
|||
|
ok = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Discard the type modifiers if they are invalid. */
|
|||
|
if (! ok)
|
|||
|
{
|
|||
|
specbits &= ~((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
|
|||
|
| (1 << (int) RID_UNSIGNED) | (1 << (int) RID_SIGNED));
|
|||
|
longlong = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((specbits & (1 << (int) RID_COMPLEX))
|
|||
|
&& TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE)
|
|||
|
{
|
|||
|
error ("complex invalid for `%s'", name);
|
|||
|
specbits &= ~ (1 << (int) RID_COMPLEX);
|
|||
|
}
|
|||
|
|
|||
|
/* Decide whether an integer type is signed or not.
|
|||
|
Optionally treat bitfields as signed by default. */
|
|||
|
if (specbits & 1 << (int) RID_UNSIGNED
|
|||
|
/* Traditionally, all bitfields are unsigned. */
|
|||
|
|| (bitfield && flag_traditional
|
|||
|
&& (! explicit_flag_signed_bitfields || !flag_signed_bitfields))
|
|||
|
|| (bitfield && ! flag_signed_bitfields
|
|||
|
&& (explicit_int || defaulted_int || explicit_char
|
|||
|
/* A typedef for plain `int' without `signed'
|
|||
|
can be controlled just like plain `int'. */
|
|||
|
|| ! (typedef_decl != 0
|
|||
|
&& C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
|
|||
|
&& TREE_CODE (type) != ENUMERAL_TYPE
|
|||
|
&& !(specbits & 1 << (int) RID_SIGNED)))
|
|||
|
{
|
|||
|
if (longlong)
|
|||
|
type = long_long_unsigned_type_node;
|
|||
|
else if (specbits & 1 << (int) RID_LONG)
|
|||
|
type = long_unsigned_type_node;
|
|||
|
else if (specbits & 1 << (int) RID_SHORT)
|
|||
|
type = short_unsigned_type_node;
|
|||
|
else if (type == char_type_node)
|
|||
|
type = unsigned_char_type_node;
|
|||
|
else if (typedef_decl)
|
|||
|
type = unsigned_type (type);
|
|||
|
else
|
|||
|
type = unsigned_type_node;
|
|||
|
}
|
|||
|
else if ((specbits & 1 << (int) RID_SIGNED)
|
|||
|
&& type == char_type_node)
|
|||
|
type = signed_char_type_node;
|
|||
|
else if (longlong)
|
|||
|
type = long_long_integer_type_node;
|
|||
|
else if (specbits & 1 << (int) RID_LONG)
|
|||
|
type = long_integer_type_node;
|
|||
|
else if (specbits & 1 << (int) RID_SHORT)
|
|||
|
type = short_integer_type_node;
|
|||
|
|
|||
|
if (specbits & 1 << (int) RID_COMPLEX)
|
|||
|
{
|
|||
|
/* If we just have "complex", it is equivalent to
|
|||
|
"complex double", but if any modifiers at all are specified it is
|
|||
|
the complex form of TYPE. E.g, "complex short" is
|
|||
|
"complex short int". */
|
|||
|
|
|||
|
if (defaulted_int && ! longlong
|
|||
|
&& ! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
|
|||
|
| (1 << (int) RID_SIGNED)
|
|||
|
| (1 << (int) RID_UNSIGNED))))
|
|||
|
type = complex_double_type_node;
|
|||
|
else if (type == integer_type_node)
|
|||
|
type = complex_integer_type_node;
|
|||
|
else if (type == float_type_node)
|
|||
|
type = complex_float_type_node;
|
|||
|
else if (type == double_type_node)
|
|||
|
type = complex_double_type_node;
|
|||
|
else if (type == long_double_type_node)
|
|||
|
type = complex_long_double_type_node;
|
|||
|
else
|
|||
|
type = build_complex_type (type);
|
|||
|
}
|
|||
|
|
|||
|
/* Set CONSTP if this declaration is `const', whether by
|
|||
|
explicit specification or via a typedef.
|
|||
|
Likewise for VOLATILEP. */
|
|||
|
|
|||
|
constp = !! (specbits & 1 << (int) RID_CONST) + TYPE_READONLY (type);
|
|||
|
volatilep = !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (type);
|
|||
|
inlinep = !! (specbits & (1 << (int) RID_INLINE));
|
|||
|
if (constp > 1)
|
|||
|
pedwarn ("duplicate `const'");
|
|||
|
if (volatilep > 1)
|
|||
|
pedwarn ("duplicate `volatile'");
|
|||
|
if (! flag_gen_aux_info && (TYPE_READONLY (type) || TYPE_VOLATILE (type)))
|
|||
|
type = TYPE_MAIN_VARIANT (type);
|
|||
|
|
|||
|
/* Warn if two storage classes are given. Default to `auto'. */
|
|||
|
|
|||
|
{
|
|||
|
int nclasses = 0;
|
|||
|
|
|||
|
if (specbits & 1 << (int) RID_AUTO) nclasses++;
|
|||
|
if (specbits & 1 << (int) RID_STATIC) nclasses++;
|
|||
|
if (specbits & 1 << (int) RID_EXTERN) nclasses++;
|
|||
|
if (specbits & 1 << (int) RID_REGISTER) nclasses++;
|
|||
|
if (specbits & 1 << (int) RID_TYPEDEF) nclasses++;
|
|||
|
if (specbits & 1 << (int) RID_ITERATOR) nclasses++;
|
|||
|
|
|||
|
/* Warn about storage classes that are invalid for certain
|
|||
|
kinds of declarations (parameters, typenames, etc.). */
|
|||
|
|
|||
|
if (nclasses > 1)
|
|||
|
error ("multiple storage classes in declaration of `%s'", name);
|
|||
|
else if (funcdef_flag
|
|||
|
&& (specbits
|
|||
|
& ((1 << (int) RID_REGISTER)
|
|||
|
| (1 << (int) RID_AUTO)
|
|||
|
| (1 << (int) RID_TYPEDEF))))
|
|||
|
{
|
|||
|
if (specbits & 1 << (int) RID_AUTO
|
|||
|
&& (pedantic || current_binding_level == global_binding_level))
|
|||
|
pedwarn ("function definition declared `auto'");
|
|||
|
if (specbits & 1 << (int) RID_REGISTER)
|
|||
|
error ("function definition declared `register'");
|
|||
|
if (specbits & 1 << (int) RID_TYPEDEF)
|
|||
|
error ("function definition declared `typedef'");
|
|||
|
specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
|
|||
|
| (1 << (int) RID_AUTO));
|
|||
|
}
|
|||
|
else if (decl_context != NORMAL && nclasses > 0)
|
|||
|
{
|
|||
|
if (decl_context == PARM && specbits & 1 << (int) RID_REGISTER)
|
|||
|
;
|
|||
|
else
|
|||
|
{
|
|||
|
error ((decl_context == FIELD
|
|||
|
? "storage class specified for structure field `%s'"
|
|||
|
: (decl_context == PARM
|
|||
|
? "storage class specified for parameter `%s'"
|
|||
|
: "storage class specified for typename")),
|
|||
|
name);
|
|||
|
specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
|
|||
|
| (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
|
|||
|
| (1 << (int) RID_EXTERN));
|
|||
|
}
|
|||
|
}
|
|||
|
else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
|
|||
|
{
|
|||
|
/* `extern' with initialization is invalid if not at top level. */
|
|||
|
if (current_binding_level == global_binding_level)
|
|||
|
warning ("`%s' initialized and declared `extern'", name);
|
|||
|
else
|
|||
|
error ("`%s' has both `extern' and initializer", name);
|
|||
|
}
|
|||
|
else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag
|
|||
|
&& current_binding_level != global_binding_level)
|
|||
|
error ("nested function `%s' declared `extern'", name);
|
|||
|
else if (current_binding_level == global_binding_level
|
|||
|
&& specbits & (1 << (int) RID_AUTO))
|
|||
|
error ("top-level declaration of `%s' specifies `auto'", name);
|
|||
|
else if ((specbits & 1 << (int) RID_ITERATOR)
|
|||
|
&& TREE_CODE (declarator) != IDENTIFIER_NODE)
|
|||
|
{
|
|||
|
error ("iterator `%s' has derived type", name);
|
|||
|
type = error_mark_node;
|
|||
|
}
|
|||
|
else if ((specbits & 1 << (int) RID_ITERATOR)
|
|||
|
&& TREE_CODE (type) != INTEGER_TYPE)
|
|||
|
{
|
|||
|
error ("iterator `%s' has noninteger type", name);
|
|||
|
type = error_mark_node;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now figure out the structure of the declarator proper.
|
|||
|
Descend through it, creating more complex types, until we reach
|
|||
|
the declared identifier (or NULL_TREE, in an absolute declarator). */
|
|||
|
|
|||
|
while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE)
|
|||
|
{
|
|||
|
if (type == error_mark_node)
|
|||
|
{
|
|||
|
declarator = TREE_OPERAND (declarator, 0);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
/* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]),
|
|||
|
an INDIRECT_REF (for *...),
|
|||
|
a CALL_EXPR (for ...(...)),
|
|||
|
an identifier (for the name being declared)
|
|||
|
or a null pointer (for the place in an absolute declarator
|
|||
|
where the name was omitted).
|
|||
|
For the last two cases, we have just exited the loop.
|
|||
|
|
|||
|
At this point, TYPE is the type of elements of an array,
|
|||
|
or for a function to return, or for a pointer to point to.
|
|||
|
After this sequence of ifs, TYPE is the type of the
|
|||
|
array or function or pointer, and DECLARATOR has had its
|
|||
|
outermost layer removed. */
|
|||
|
|
|||
|
if (TREE_CODE (declarator) == ARRAY_REF)
|
|||
|
{
|
|||
|
register tree itype = NULL_TREE;
|
|||
|
register tree size = TREE_OPERAND (declarator, 1);
|
|||
|
/* An uninitialized decl with `extern' is a reference. */
|
|||
|
int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN));
|
|||
|
/* The index is a signed object `sizetype' bits wide. */
|
|||
|
tree index_type = signed_type (sizetype);
|
|||
|
|
|||
|
declarator = TREE_OPERAND (declarator, 0);
|
|||
|
|
|||
|
/* Check for some types that there cannot be arrays of. */
|
|||
|
|
|||
|
if (TYPE_MAIN_VARIANT (type) == void_type_node)
|
|||
|
{
|
|||
|
error ("declaration of `%s' as array of voids", name);
|
|||
|
type = error_mark_node;
|
|||
|
}
|
|||
|
|
|||
|
if (TREE_CODE (type) == FUNCTION_TYPE)
|
|||
|
{
|
|||
|
error ("declaration of `%s' as array of functions", name);
|
|||
|
type = error_mark_node;
|
|||
|
}
|
|||
|
|
|||
|
if (size == error_mark_node)
|
|||
|
type = error_mark_node;
|
|||
|
|
|||
|
if (type == error_mark_node)
|
|||
|
continue;
|
|||
|
|
|||
|
/* If this is a block level extern, it must live past the end
|
|||
|
of the function so that we can check it against other extern
|
|||
|
declarations (IDENTIFIER_LIMBO_VALUE). */
|
|||
|
if (extern_ref && allocation_temporary_p ())
|
|||
|
end_temporary_allocation ();
|
|||
|
|
|||
|
/* If size was specified, set ITYPE to a range-type for that size.
|
|||
|
Otherwise, ITYPE remains null. finish_decl may figure it out
|
|||
|
from an initial value. */
|
|||
|
|
|||
|
if (size)
|
|||
|
{
|
|||
|
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
|
|||
|
STRIP_TYPE_NOPS (size);
|
|||
|
|
|||
|
if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE
|
|||
|
&& TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE)
|
|||
|
{
|
|||
|
error ("size of array `%s' has non-integer type", name);
|
|||
|
size = integer_one_node;
|
|||
|
}
|
|||
|
|
|||
|
if (pedantic && integer_zerop (size))
|
|||
|
pedwarn ("ANSI C forbids zero-size array `%s'", name);
|
|||
|
|
|||
|
if (TREE_CODE (size) == INTEGER_CST)
|
|||
|
{
|
|||
|
constant_expression_warning (size);
|
|||
|
if (tree_int_cst_sgn (size) < 0)
|
|||
|
{
|
|||
|
error ("size of array `%s' is negative", name);
|
|||
|
size = integer_one_node;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Make sure the array size remains visibly nonconstant
|
|||
|
even if it is (eg) a const variable with known value. */
|
|||
|
size_varies = 1;
|
|||
|
|
|||
|
if (pedantic)
|
|||
|
{
|
|||
|
if (TREE_CONSTANT (size))
|
|||
|
pedwarn ("ANSI C forbids array `%s' whose size can't be evaluated", name);
|
|||
|
else
|
|||
|
pedwarn ("ANSI C forbids variable-size array `%s'", name);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Convert size to index_type, so that if it is a variable
|
|||
|
the computations will be done in the proper mode. */
|
|||
|
itype = fold (build (MINUS_EXPR, index_type,
|
|||
|
convert (index_type, size),
|
|||
|
convert (index_type, size_one_node)));
|
|||
|
|
|||
|
/* If that overflowed, the array is too big.
|
|||
|
??? While a size of INT_MAX+1 technically shouldn't cause
|
|||
|
an overflow (because we subtract 1), the overflow is recorded
|
|||
|
during the conversion to index_type, before the subtraction.
|
|||
|
Handling this case seems like an unnecessary complication. */
|
|||
|
if (TREE_OVERFLOW (itype))
|
|||
|
{
|
|||
|
error ("size of array `%s' is too large", name);
|
|||
|
type = error_mark_node;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (size_varies)
|
|||
|
itype = variable_size (itype);
|
|||
|
itype = build_index_type (itype);
|
|||
|
}
|
|||
|
|
|||
|
#if 0 /* This had bad results for pointers to arrays, as in
|
|||
|
union incomplete (*foo)[4]; */
|
|||
|
/* Complain about arrays of incomplete types, except in typedefs. */
|
|||
|
|
|||
|
if (TYPE_SIZE (type) == 0
|
|||
|
/* Avoid multiple warnings for nested array types. */
|
|||
|
&& TREE_CODE (type) != ARRAY_TYPE
|
|||
|
&& !(specbits & (1 << (int) RID_TYPEDEF))
|
|||
|
&& !C_TYPE_BEING_DEFINED (type))
|
|||
|
warning ("array type has incomplete element type");
|
|||
|
#endif
|
|||
|
|
|||
|
#if 0 /* We shouldn't have a function type here at all!
|
|||
|
Functions aren't allowed as array elements. */
|
|||
|
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
|
|||
|
&& (constp || volatilep))
|
|||
|
pedwarn ("ANSI C forbids const or volatile function types");
|
|||
|
#endif
|
|||
|
|
|||
|
/* Build the array type itself, then merge any constancy or
|
|||
|
volatility into the target type. We must do it in this order
|
|||
|
to ensure that the TYPE_MAIN_VARIANT field of the array type
|
|||
|
is set correctly. */
|
|||
|
|
|||
|
type = build_array_type (type, itype);
|
|||
|
if (constp || volatilep)
|
|||
|
type = c_build_type_variant (type, constp, volatilep);
|
|||
|
|
|||
|
#if 0 /* don't clear these; leave them set so that the array type
|
|||
|
or the variable is itself const or volatile. */
|
|||
|
constp = 0;
|
|||
|
volatilep = 0;
|
|||
|
#endif
|
|||
|
|
|||
|
if (size_varies)
|
|||
|
C_TYPE_VARIABLE_SIZE (type) = 1;
|
|||
|
}
|
|||
|
else if (TREE_CODE (declarator) == CALL_EXPR)
|
|||
|
{
|
|||
|
int extern_ref = (!(specbits & (1 << (int) RID_AUTO))
|
|||
|
|| current_binding_level == global_binding_level);
|
|||
|
tree arg_types;
|
|||
|
|
|||
|
/* Declaring a function type.
|
|||
|
Make sure we have a valid type for the function to return. */
|
|||
|
if (type == error_mark_node)
|
|||
|
continue;
|
|||
|
|
|||
|
size_varies = 0;
|
|||
|
|
|||
|
/* Warn about some types functions can't return. */
|
|||
|
|
|||
|
if (TREE_CODE (type) == FUNCTION_TYPE)
|
|||
|
{
|
|||
|
error ("`%s' declared as function returning a function", name);
|
|||
|
type = integer_type_node;
|
|||
|
}
|
|||
|
if (TREE_CODE (type) == ARRAY_TYPE)
|
|||
|
{
|
|||
|
error ("`%s' declared as function returning an array", name);
|
|||
|
type = integer_type_node;
|
|||
|
}
|
|||
|
|
|||
|
#ifndef TRADITIONAL_RETURN_FLOAT
|
|||
|
/* Traditionally, declaring return type float means double. */
|
|||
|
|
|||
|
if (flag_traditional && TYPE_MAIN_VARIANT (type) == float_type_node)
|
|||
|
type = double_type_node;
|
|||
|
#endif /* TRADITIONAL_RETURN_FLOAT */
|
|||
|
|
|||
|
/* If this is a block level extern, it must live past the end
|
|||
|
of the function so that we can check it against other extern
|
|||
|
declarations (IDENTIFIER_LIMBO_VALUE). */
|
|||
|
if (extern_ref && allocation_temporary_p ())
|
|||
|
end_temporary_allocation ();
|
|||
|
|
|||
|
/* Construct the function type and go to the next
|
|||
|
inner layer of declarator. */
|
|||
|
|
|||
|
arg_types = grokparms (TREE_OPERAND (declarator, 1),
|
|||
|
funcdef_flag
|
|||
|
/* Say it's a definition
|
|||
|
only for the CALL_EXPR
|
|||
|
closest to the identifier. */
|
|||
|
&& TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE);
|
|||
|
#if 0 /* This seems to be false. We turn off temporary allocation
|
|||
|
above in this function if -traditional.
|
|||
|
And this code caused inconsistent results with prototypes:
|
|||
|
callers would ignore them, and pass arguments wrong. */
|
|||
|
|
|||
|
/* Omit the arg types if -traditional, since the arg types
|
|||
|
and the list links might not be permanent. */
|
|||
|
type = build_function_type (type,
|
|||
|
flag_traditional
|
|||
|
? NULL_TREE : arg_types);
|
|||
|
#endif
|
|||
|
/* ANSI seems to say that `const int foo ();'
|
|||
|
does not make the function foo const. */
|
|||
|
if (constp || volatilep)
|
|||
|
type = c_build_type_variant (type, constp, volatilep);
|
|||
|
constp = 0;
|
|||
|
volatilep = 0;
|
|||
|
|
|||
|
type = build_function_type (type, arg_types);
|
|||
|
declarator = TREE_OPERAND (declarator, 0);
|
|||
|
|
|||
|
/* Set the TYPE_CONTEXTs for each tagged type which is local to
|
|||
|
the formal parameter list of this FUNCTION_TYPE to point to
|
|||
|
the FUNCTION_TYPE node itself. */
|
|||
|
|
|||
|
{
|
|||
|
register tree link;
|
|||
|
|
|||
|
for (link = current_function_parm_tags;
|
|||
|
link;
|
|||
|
link = TREE_CHAIN (link))
|
|||
|
TYPE_CONTEXT (TREE_VALUE (link)) = type;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (TREE_CODE (declarator) == INDIRECT_REF)
|
|||
|
{
|
|||
|
/* Merge any constancy or volatility into the target type
|
|||
|
for the pointer. */
|
|||
|
|
|||
|
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
|
|||
|
&& (constp || volatilep))
|
|||
|
pedwarn ("ANSI C forbids const or volatile function types");
|
|||
|
if (constp || volatilep)
|
|||
|
type = c_build_type_variant (type, constp, volatilep);
|
|||
|
constp = 0;
|
|||
|
volatilep = 0;
|
|||
|
size_varies = 0;
|
|||
|
|
|||
|
type = build_pointer_type (type);
|
|||
|
|
|||
|
/* Process a list of type modifier keywords
|
|||
|
(such as const or volatile) that were given inside the `*'. */
|
|||
|
|
|||
|
if (TREE_TYPE (declarator))
|
|||
|
{
|
|||
|
register tree typemodlist;
|
|||
|
int erred = 0;
|
|||
|
for (typemodlist = TREE_TYPE (declarator); typemodlist;
|
|||
|
typemodlist = TREE_CHAIN (typemodlist))
|
|||
|
{
|
|||
|
if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST])
|
|||
|
constp++;
|
|||
|
else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE])
|
|||
|
volatilep++;
|
|||
|
else if (!erred)
|
|||
|
{
|
|||
|
erred = 1;
|
|||
|
error ("invalid type modifier within pointer declarator");
|
|||
|
}
|
|||
|
}
|
|||
|
if (constp > 1)
|
|||
|
pedwarn ("duplicate `const'");
|
|||
|
if (volatilep > 1)
|
|||
|
pedwarn ("duplicate `volatile'");
|
|||
|
}
|
|||
|
|
|||
|
declarator = TREE_OPERAND (declarator, 0);
|
|||
|
}
|
|||
|
else
|
|||
|
abort ();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/* Now TYPE has the actual type. */
|
|||
|
|
|||
|
/* Did array size calculations overflow? */
|
|||
|
|
|||
|
if (TREE_CODE (type) == ARRAY_TYPE
|
|||
|
&& TYPE_SIZE (type)
|
|||
|
&& TREE_OVERFLOW (TYPE_SIZE (type)))
|
|||
|
error ("size of array `%s' is too large", name);
|
|||
|
|
|||
|
/* If this is declaring a typedef name, return a TYPE_DECL. */
|
|||
|
|
|||
|
if (specbits & (1 << (int) RID_TYPEDEF))
|
|||
|
{
|
|||
|
tree decl;
|
|||
|
/* Note that the grammar rejects storage classes
|
|||
|
in typenames, fields or parameters */
|
|||
|
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
|
|||
|
&& (constp || volatilep))
|
|||
|
pedwarn ("ANSI C forbids const or volatile function types");
|
|||
|
if (constp || volatilep)
|
|||
|
type = c_build_type_variant (type, constp, volatilep);
|
|||
|
decl = build_decl (TYPE_DECL, declarator, type);
|
|||
|
if ((specbits & (1 << (int) RID_SIGNED))
|
|||
|
|| (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
|
|||
|
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
|
|||
|
pop_obstacks ();
|
|||
|
return decl;
|
|||
|
}
|
|||
|
|
|||
|
/* Detect the case of an array type of unspecified size
|
|||
|
which came, as such, direct from a typedef name.
|
|||
|
We must copy the type, so that each identifier gets
|
|||
|
a distinct type, so that each identifier's size can be
|
|||
|
controlled separately by its own initializer. */
|
|||
|
|
|||
|
if (type != 0 && typedef_type != 0
|
|||
|
&& TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type)
|
|||
|
&& TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0)
|
|||
|
{
|
|||
|
type = build_array_type (TREE_TYPE (type), 0);
|
|||
|
if (size_varies)
|
|||
|
C_TYPE_VARIABLE_SIZE (type) = 1;
|
|||
|
}
|
|||
|
|
|||
|
/* If this is a type name (such as, in a cast or sizeof),
|
|||
|
compute the type and return it now. */
|
|||
|
|
|||
|
if (decl_context == TYPENAME)
|
|||
|
{
|
|||
|
/* Note that the grammar rejects storage classes
|
|||
|
in typenames, fields or parameters */
|
|||
|
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
|
|||
|
&& (constp || volatilep))
|
|||
|
pedwarn ("ANSI C forbids const or volatile function types");
|
|||
|
if (constp || volatilep)
|
|||
|
type = c_build_type_variant (type, constp, volatilep);
|
|||
|
pop_obstacks ();
|
|||
|
return type;
|
|||
|
}
|
|||
|
|
|||
|
/* Aside from typedefs and type names (handle above),
|
|||
|
`void' at top level (not within pointer)
|
|||
|
is allowed only in public variables.
|
|||
|
We don't complain about parms either, but that is because
|
|||
|
a better error message can be made later. */
|
|||
|
|
|||
|
if (TYPE_MAIN_VARIANT (type) == void_type_node && decl_context != PARM
|
|||
|
&& ! ((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE)
|
|||
|
&& ((specbits & (1 << (int) RID_EXTERN))
|
|||
|
|| (current_binding_level == global_binding_level
|
|||
|
&& !(specbits
|
|||
|
& ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER)))))))
|
|||
|
{
|
|||
|
error ("variable or field `%s' declared void", name);
|
|||
|
type = integer_type_node;
|
|||
|
}
|
|||
|
|
|||
|
/* Now create the decl, which may be a VAR_DECL, a PARM_DECL
|
|||
|
or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */
|
|||
|
|
|||
|
{
|
|||
|
register tree decl;
|
|||
|
|
|||
|
if (decl_context == PARM)
|
|||
|
{
|
|||
|
tree type_as_written = type;
|
|||
|
tree main_type;
|
|||
|
|
|||
|
/* A parameter declared as an array of T is really a pointer to T.
|
|||
|
One declared as a function is really a pointer to a function. */
|
|||
|
|
|||
|
if (TREE_CODE (type) == ARRAY_TYPE)
|
|||
|
{
|
|||
|
/* Transfer const-ness of array into that of type pointed to. */
|
|||
|
type = TREE_TYPE (type);
|
|||
|
if (constp || volatilep)
|
|||
|
type = c_build_type_variant (type, constp, volatilep);
|
|||
|
type = build_pointer_type (type);
|
|||
|
volatilep = constp = 0;
|
|||
|
size_varies = 0;
|
|||
|
}
|
|||
|
else if (TREE_CODE (type) == FUNCTION_TYPE)
|
|||
|
{
|
|||
|
if (pedantic && (constp || volatilep))
|
|||
|
pedwarn ("ANSI C forbids const or volatile function types");
|
|||
|
if (constp || volatilep)
|
|||
|
type = c_build_type_variant (type, constp, volatilep);
|
|||
|
type = build_pointer_type (type);
|
|||
|
volatilep = constp = 0;
|
|||
|
}
|
|||
|
|
|||
|
decl = build_decl (PARM_DECL, declarator, type);
|
|||
|
if (size_varies)
|
|||
|
C_DECL_VARIABLE_SIZE (decl) = 1;
|
|||
|
|
|||
|
/* Compute the type actually passed in the parmlist,
|
|||
|
for the case where there is no prototype.
|
|||
|
(For example, shorts and chars are passed as ints.)
|
|||
|
When there is a prototype, this is overridden later. */
|
|||
|
|
|||
|
DECL_ARG_TYPE (decl) = type;
|
|||
|
main_type = (type == error_mark_node
|
|||
|
? error_mark_node
|
|||
|
: TYPE_MAIN_VARIANT (type));
|
|||
|
if (main_type == float_type_node)
|
|||
|
DECL_ARG_TYPE (decl) = double_type_node;
|
|||
|
/* Don't use TYPE_PRECISION to decide whether to promote,
|
|||
|
because we should convert short if it's the same size as int,
|
|||
|
but we should not convert long if it's the same size as int. */
|
|||
|
else if (TREE_CODE (main_type) != ERROR_MARK
|
|||
|
&& C_PROMOTING_INTEGER_TYPE_P (main_type))
|
|||
|
{
|
|||
|
if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)
|
|||
|
&& TREE_UNSIGNED (type))
|
|||
|
DECL_ARG_TYPE (decl) = unsigned_type_node;
|
|||
|
else
|
|||
|
DECL_ARG_TYPE (decl) = integer_type_node;
|
|||
|
}
|
|||
|
|
|||
|
DECL_ARG_TYPE_AS_WRITTEN (decl) = type_as_written;
|
|||
|
}
|
|||
|
else if (decl_context == FIELD)
|
|||
|
{
|
|||
|
/* Structure field. It may not be a function. */
|
|||
|
|
|||
|
if (TREE_CODE (type) == FUNCTION_TYPE)
|
|||
|
{
|
|||
|
error ("field `%s' declared as a function", name);
|
|||
|
type = build_pointer_type (type);
|
|||
|
}
|
|||
|
else if (TREE_CODE (type) != ERROR_MARK && TYPE_SIZE (type) == 0)
|
|||
|
{
|
|||
|
error ("field `%s' has incomplete type", name);
|
|||
|
type = error_mark_node;
|
|||
|
}
|
|||
|
/* Move type qualifiers down to element of an array. */
|
|||
|
if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep))
|
|||
|
{
|
|||
|
type = build_array_type (c_build_type_variant (TREE_TYPE (type),
|
|||
|
constp, volatilep),
|
|||
|
TYPE_DOMAIN (type));
|
|||
|
#if 0 /* Leave the field const or volatile as well. */
|
|||
|
constp = volatilep = 0;
|
|||
|
#endif
|
|||
|
}
|
|||
|
decl = build_decl (FIELD_DECL, declarator, type);
|
|||
|
if (size_varies)
|
|||
|
C_DECL_VARIABLE_SIZE (decl) = 1;
|
|||
|
}
|
|||
|
else if (TREE_CODE (type) == FUNCTION_TYPE)
|
|||
|
{
|
|||
|
/* Every function declaration is "external"
|
|||
|
except for those which are inside a function body
|
|||
|
in which `auto' is used.
|
|||
|
That is a case not specified by ANSI C,
|
|||
|
and we use it for forward declarations for nested functions. */
|
|||
|
int extern_ref = (!(specbits & (1 << (int) RID_AUTO))
|
|||
|
|| current_binding_level == global_binding_level);
|
|||
|
|
|||
|
if (specbits & (1 << (int) RID_AUTO)
|
|||
|
&& (pedantic || current_binding_level == global_binding_level))
|
|||
|
pedwarn ("invalid storage class for function `%s'", name);
|
|||
|
if (specbits & (1 << (int) RID_REGISTER))
|
|||
|
error ("invalid storage class for function `%s'", name);
|
|||
|
/* Function declaration not at top level.
|
|||
|
Storage classes other than `extern' are not allowed
|
|||
|
and `extern' makes no difference. */
|
|||
|
if (current_binding_level != global_binding_level
|
|||
|
&& (specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE)))
|
|||
|
&& pedantic)
|
|||
|
pedwarn ("invalid storage class for function `%s'", name);
|
|||
|
|
|||
|
/* If this is a block level extern, it must live past the end
|
|||
|
of the function so that we can check it against other
|
|||
|
extern declarations (IDENTIFIER_LIMBO_VALUE). */
|
|||
|
if (extern_ref && allocation_temporary_p ())
|
|||
|
end_temporary_allocation ();
|
|||
|
|
|||
|
decl = build_decl (FUNCTION_DECL, declarator, type);
|
|||
|
decl = build_decl_attribute_variant (decl, decl_machine_attr);
|
|||
|
|
|||
|
if (pedantic && (constp || volatilep)
|
|||
|
&& ! DECL_IN_SYSTEM_HEADER (decl))
|
|||
|
pedwarn ("ANSI C forbids const or volatile functions");
|
|||
|
|
|||
|
if (pedantic
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl))) == void_type_node
|
|||
|
&& (TYPE_READONLY (TREE_TYPE (TREE_TYPE (decl)))
|
|||
|
|| TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (decl))))
|
|||
|
&& ! DECL_IN_SYSTEM_HEADER (decl))
|
|||
|
pedwarn ("ANSI C forbids const or volatile void function return type");
|
|||
|
|
|||
|
if (volatilep
|
|||
|
&& TREE_TYPE (TREE_TYPE (decl)) != void_type_node)
|
|||
|
warning ("`noreturn' function returns non-void value");
|
|||
|
|
|||
|
if (extern_ref)
|
|||
|
DECL_EXTERNAL (decl) = 1;
|
|||
|
/* Record absence of global scope for `static' or `auto'. */
|
|||
|
TREE_PUBLIC (decl)
|
|||
|
= !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO)));
|
|||
|
|
|||
|
/* Record presence of `inline', if it is reasonable. */
|
|||
|
if (inlinep)
|
|||
|
{
|
|||
|
tree last = tree_last (TYPE_ARG_TYPES (type));
|
|||
|
|
|||
|
if (! strcmp (IDENTIFIER_POINTER (declarator), "main"))
|
|||
|
warning ("cannot inline function `main'");
|
|||
|
else
|
|||
|
/* Assume that otherwise the function can be inlined. */
|
|||
|
DECL_INLINE (decl) = 1;
|
|||
|
|
|||
|
if (specbits & (1 << (int) RID_EXTERN))
|
|||
|
current_extern_inline = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* It's a variable. */
|
|||
|
/* An uninitialized decl with `extern' is a reference. */
|
|||
|
int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN));
|
|||
|
|
|||
|
/* Move type qualifiers down to element of an array. */
|
|||
|
if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep))
|
|||
|
{
|
|||
|
type = build_array_type (c_build_type_variant (TREE_TYPE (type),
|
|||
|
constp, volatilep),
|
|||
|
TYPE_DOMAIN (type));
|
|||
|
#if 0 /* Leave the variable const or volatile as well. */
|
|||
|
constp = volatilep = 0;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
/* If this is a block level extern, it must live past the end
|
|||
|
of the function so that we can check it against other
|
|||
|
extern declarations (IDENTIFIER_LIMBO_VALUE). */
|
|||
|
if (extern_ref && allocation_temporary_p ())
|
|||
|
end_temporary_allocation ();
|
|||
|
|
|||
|
decl = build_decl (VAR_DECL, declarator, type);
|
|||
|
if (size_varies)
|
|||
|
C_DECL_VARIABLE_SIZE (decl) = 1;
|
|||
|
|
|||
|
if (inlinep)
|
|||
|
pedwarn_with_decl (decl, "variable `%s' declared `inline'");
|
|||
|
|
|||
|
DECL_EXTERNAL (decl) = extern_ref;
|
|||
|
/* At top level, the presence of a `static' or `register' storage
|
|||
|
class specifier, or the absence of all storage class specifiers
|
|||
|
makes this declaration a definition (perhaps tentative). Also,
|
|||
|
the absence of both `static' and `register' makes it public. */
|
|||
|
if (current_binding_level == global_binding_level)
|
|||
|
{
|
|||
|
TREE_PUBLIC (decl)
|
|||
|
= !(specbits
|
|||
|
& ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER)));
|
|||
|
TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
|
|||
|
}
|
|||
|
/* Not at top level, only `static' makes a static definition. */
|
|||
|
else
|
|||
|
{
|
|||
|
TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0;
|
|||
|
TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
|
|||
|
}
|
|||
|
|
|||
|
if (specbits & 1 << (int) RID_ITERATOR)
|
|||
|
ITERATOR_P (decl) = 1;
|
|||
|
}
|
|||
|
|
|||
|
/* Record `register' declaration for warnings on &
|
|||
|
and in case doing stupid register allocation. */
|
|||
|
|
|||
|
if (specbits & (1 << (int) RID_REGISTER))
|
|||
|
DECL_REGISTER (decl) = 1;
|
|||
|
|
|||
|
/* Record constancy and volatility. */
|
|||
|
|
|||
|
if (constp)
|
|||
|
TREE_READONLY (decl) = 1;
|
|||
|
if (volatilep)
|
|||
|
{
|
|||
|
TREE_SIDE_EFFECTS (decl) = 1;
|
|||
|
TREE_THIS_VOLATILE (decl) = 1;
|
|||
|
}
|
|||
|
/* If a type has volatile components, it should be stored in memory.
|
|||
|
Otherwise, the fact that those components are volatile
|
|||
|
will be ignored, and would even crash the compiler. */
|
|||
|
if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)))
|
|||
|
mark_addressable (decl);
|
|||
|
|
|||
|
pop_obstacks ();
|
|||
|
|
|||
|
return decl;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Decode the parameter-list info for a function type or function definition.
|
|||
|
The argument is the value returned by `get_parm_info' (or made in parse.y
|
|||
|
if there is an identifier list instead of a parameter decl list).
|
|||
|
These two functions are separate because when a function returns
|
|||
|
or receives functions then each is called multiple times but the order
|
|||
|
of calls is different. The last call to `grokparms' is always the one
|
|||
|
that contains the formal parameter names of a function definition.
|
|||
|
|
|||
|
Store in `last_function_parms' a chain of the decls of parms.
|
|||
|
Also store in `last_function_parm_tags' a chain of the struct, union,
|
|||
|
and enum tags declared among the parms.
|
|||
|
|
|||
|
Return a list of arg types to use in the FUNCTION_TYPE for this function.
|
|||
|
|
|||
|
FUNCDEF_FLAG is nonzero for a function definition, 0 for
|
|||
|
a mere declaration. A nonempty identifier-list gets an error message
|
|||
|
when FUNCDEF_FLAG is zero. */
|
|||
|
|
|||
|
static tree
|
|||
|
grokparms (parms_info, funcdef_flag)
|
|||
|
tree parms_info;
|
|||
|
int funcdef_flag;
|
|||
|
{
|
|||
|
tree first_parm = TREE_CHAIN (parms_info);
|
|||
|
|
|||
|
last_function_parms = TREE_PURPOSE (parms_info);
|
|||
|
last_function_parm_tags = TREE_VALUE (parms_info);
|
|||
|
|
|||
|
if (warn_strict_prototypes && first_parm == 0 && !funcdef_flag
|
|||
|
&& !in_system_header)
|
|||
|
warning ("function declaration isn't a prototype");
|
|||
|
|
|||
|
if (first_parm != 0
|
|||
|
&& TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE)
|
|||
|
{
|
|||
|
if (! funcdef_flag)
|
|||
|
pedwarn ("parameter names (without types) in function declaration");
|
|||
|
|
|||
|
last_function_parms = first_parm;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
tree parm;
|
|||
|
tree typelt;
|
|||
|
/* We no longer test FUNCDEF_FLAG.
|
|||
|
If the arg types are incomplete in a declaration,
|
|||
|
they must include undefined tags.
|
|||
|
These tags can never be defined in the scope of the declaration,
|
|||
|
so the types can never be completed,
|
|||
|
and no call can be compiled successfully. */
|
|||
|
#if 0
|
|||
|
/* In a fcn definition, arg types must be complete. */
|
|||
|
if (funcdef_flag)
|
|||
|
#endif
|
|||
|
for (parm = last_function_parms, typelt = first_parm;
|
|||
|
parm;
|
|||
|
parm = TREE_CHAIN (parm))
|
|||
|
/* Skip over any enumeration constants declared here. */
|
|||
|
if (TREE_CODE (parm) == PARM_DECL)
|
|||
|
{
|
|||
|
/* Barf if the parameter itself has an incomplete type. */
|
|||
|
tree type = TREE_VALUE (typelt);
|
|||
|
if (TYPE_SIZE (type) == 0)
|
|||
|
{
|
|||
|
if (funcdef_flag && DECL_NAME (parm) != 0)
|
|||
|
error ("parameter `%s' has incomplete type",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parm)));
|
|||
|
else
|
|||
|
warning ("parameter has incomplete type");
|
|||
|
if (funcdef_flag)
|
|||
|
{
|
|||
|
TREE_VALUE (typelt) = error_mark_node;
|
|||
|
TREE_TYPE (parm) = error_mark_node;
|
|||
|
}
|
|||
|
}
|
|||
|
#if 0 /* This has been replaced by parm_tags_warning
|
|||
|
which uses a more accurate criterion for what to warn about. */
|
|||
|
else
|
|||
|
{
|
|||
|
/* Now warn if is a pointer to an incomplete type. */
|
|||
|
while (TREE_CODE (type) == POINTER_TYPE
|
|||
|
|| TREE_CODE (type) == REFERENCE_TYPE)
|
|||
|
type = TREE_TYPE (type);
|
|||
|
type = TYPE_MAIN_VARIANT (type);
|
|||
|
if (TYPE_SIZE (type) == 0)
|
|||
|
{
|
|||
|
if (DECL_NAME (parm) != 0)
|
|||
|
warning ("parameter `%s' points to incomplete type",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parm)));
|
|||
|
else
|
|||
|
warning ("parameter points to incomplete type");
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
typelt = TREE_CHAIN (typelt);
|
|||
|
}
|
|||
|
|
|||
|
/* Allocate the list of types the way we allocate a type. */
|
|||
|
if (first_parm && ! TREE_PERMANENT (first_parm))
|
|||
|
{
|
|||
|
/* Construct a copy of the list of types
|
|||
|
on the saveable obstack. */
|
|||
|
tree result = NULL;
|
|||
|
for (typelt = first_parm; typelt; typelt = TREE_CHAIN (typelt))
|
|||
|
result = saveable_tree_cons (NULL_TREE, TREE_VALUE (typelt),
|
|||
|
result);
|
|||
|
return nreverse (result);
|
|||
|
}
|
|||
|
else
|
|||
|
/* The list we have is permanent already. */
|
|||
|
return first_parm;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Return a tree_list node with info on a parameter list just parsed.
|
|||
|
The TREE_PURPOSE is a chain of decls of those parms.
|
|||
|
The TREE_VALUE is a list of structure, union and enum tags defined.
|
|||
|
The TREE_CHAIN is a list of argument types to go in the FUNCTION_TYPE.
|
|||
|
This tree_list node is later fed to `grokparms'.
|
|||
|
|
|||
|
VOID_AT_END nonzero means append `void' to the end of the type-list.
|
|||
|
Zero means the parmlist ended with an ellipsis so don't append `void'. */
|
|||
|
|
|||
|
tree
|
|||
|
get_parm_info (void_at_end)
|
|||
|
int void_at_end;
|
|||
|
{
|
|||
|
register tree decl, t;
|
|||
|
register tree types = 0;
|
|||
|
int erred = 0;
|
|||
|
tree tags = gettags ();
|
|||
|
tree parms = getdecls ();
|
|||
|
tree new_parms = 0;
|
|||
|
tree order = current_binding_level->parm_order;
|
|||
|
|
|||
|
/* Just `void' (and no ellipsis) is special. There are really no parms. */
|
|||
|
if (void_at_end && parms != 0
|
|||
|
&& TREE_CHAIN (parms) == 0
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_TYPE (parms)) == void_type_node
|
|||
|
&& DECL_NAME (parms) == 0)
|
|||
|
{
|
|||
|
parms = NULL_TREE;
|
|||
|
storedecls (NULL_TREE);
|
|||
|
return saveable_tree_cons (NULL_TREE, NULL_TREE,
|
|||
|
saveable_tree_cons (NULL_TREE, void_type_node, NULL_TREE));
|
|||
|
}
|
|||
|
|
|||
|
/* Extract enumerator values and other non-parms declared with the parms.
|
|||
|
Likewise any forward parm decls that didn't have real parm decls. */
|
|||
|
for (decl = parms; decl; )
|
|||
|
{
|
|||
|
tree next = TREE_CHAIN (decl);
|
|||
|
|
|||
|
if (TREE_CODE (decl) != PARM_DECL)
|
|||
|
{
|
|||
|
TREE_CHAIN (decl) = new_parms;
|
|||
|
new_parms = decl;
|
|||
|
}
|
|||
|
else if (TREE_ASM_WRITTEN (decl))
|
|||
|
{
|
|||
|
error_with_decl (decl, "parameter `%s' has just a forward declaration");
|
|||
|
TREE_CHAIN (decl) = new_parms;
|
|||
|
new_parms = decl;
|
|||
|
}
|
|||
|
decl = next;
|
|||
|
}
|
|||
|
|
|||
|
/* Put the parm decls back in the order they were in in the parm list. */
|
|||
|
for (t = order; t; t = TREE_CHAIN (t))
|
|||
|
{
|
|||
|
if (TREE_CHAIN (t))
|
|||
|
TREE_CHAIN (TREE_VALUE (t)) = TREE_VALUE (TREE_CHAIN (t));
|
|||
|
else
|
|||
|
TREE_CHAIN (TREE_VALUE (t)) = 0;
|
|||
|
}
|
|||
|
|
|||
|
new_parms = chainon (order ? nreverse (TREE_VALUE (order)) : 0,
|
|||
|
new_parms);
|
|||
|
|
|||
|
/* Store the parmlist in the binding level since the old one
|
|||
|
is no longer a valid list. (We have changed the chain pointers.) */
|
|||
|
storedecls (new_parms);
|
|||
|
|
|||
|
for (decl = new_parms; decl; decl = TREE_CHAIN (decl))
|
|||
|
/* There may also be declarations for enumerators if an enumeration
|
|||
|
type is declared among the parms. Ignore them here. */
|
|||
|
if (TREE_CODE (decl) == PARM_DECL)
|
|||
|
{
|
|||
|
/* Since there is a prototype,
|
|||
|
args are passed in their declared types. */
|
|||
|
tree type = TREE_TYPE (decl);
|
|||
|
DECL_ARG_TYPE (decl) = type;
|
|||
|
#ifdef PROMOTE_PROTOTYPES
|
|||
|
if ((TREE_CODE (type) == INTEGER_TYPE
|
|||
|
|| TREE_CODE (type) == ENUMERAL_TYPE)
|
|||
|
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
|
|||
|
DECL_ARG_TYPE (decl) = integer_type_node;
|
|||
|
#endif
|
|||
|
|
|||
|
types = saveable_tree_cons (NULL_TREE, TREE_TYPE (decl), types);
|
|||
|
if (TYPE_MAIN_VARIANT (TREE_VALUE (types)) == void_type_node && ! erred
|
|||
|
&& DECL_NAME (decl) == 0)
|
|||
|
{
|
|||
|
error ("`void' in parameter list must be the entire list");
|
|||
|
erred = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (void_at_end)
|
|||
|
return saveable_tree_cons (new_parms, tags,
|
|||
|
nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types)));
|
|||
|
|
|||
|
return saveable_tree_cons (new_parms, tags, nreverse (types));
|
|||
|
}
|
|||
|
|
|||
|
/* At end of parameter list, warn about any struct, union or enum tags
|
|||
|
defined within. Do so because these types cannot ever become complete. */
|
|||
|
|
|||
|
void
|
|||
|
parmlist_tags_warning ()
|
|||
|
{
|
|||
|
tree elt;
|
|||
|
static int already;
|
|||
|
|
|||
|
for (elt = current_binding_level->tags; elt; elt = TREE_CHAIN (elt))
|
|||
|
{
|
|||
|
enum tree_code code = TREE_CODE (TREE_VALUE (elt));
|
|||
|
/* An anonymous union parm type is meaningful as a GNU extension.
|
|||
|
So don't warn for that. */
|
|||
|
if (code == UNION_TYPE && TREE_PURPOSE (elt) == 0 && !pedantic)
|
|||
|
continue;
|
|||
|
if (TREE_PURPOSE (elt) != 0)
|
|||
|
warning ("`%s %s' declared inside parameter list",
|
|||
|
(code == RECORD_TYPE ? "struct"
|
|||
|
: code == UNION_TYPE ? "union"
|
|||
|
: "enum"),
|
|||
|
IDENTIFIER_POINTER (TREE_PURPOSE (elt)));
|
|||
|
else
|
|||
|
warning ("anonymous %s declared inside parameter list",
|
|||
|
(code == RECORD_TYPE ? "struct"
|
|||
|
: code == UNION_TYPE ? "union"
|
|||
|
: "enum"));
|
|||
|
|
|||
|
if (! already)
|
|||
|
{
|
|||
|
warning ("its scope is only this definition or declaration,");
|
|||
|
warning ("which is probably not what you want.");
|
|||
|
already = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Get the struct, enum or union (CODE says which) with tag NAME.
|
|||
|
Define the tag as a forward-reference if it is not defined. */
|
|||
|
|
|||
|
tree
|
|||
|
xref_tag (code, name)
|
|||
|
enum tree_code code;
|
|||
|
tree name;
|
|||
|
{
|
|||
|
int temporary = allocation_temporary_p ();
|
|||
|
|
|||
|
/* If a cross reference is requested, look up the type
|
|||
|
already defined for this tag and return it. */
|
|||
|
|
|||
|
register tree ref = lookup_tag (code, name, current_binding_level, 0);
|
|||
|
/* Even if this is the wrong type of tag, return what we found.
|
|||
|
There will be an error message anyway, from pending_xref_error.
|
|||
|
If we create an empty xref just for an invalid use of the type,
|
|||
|
the main result is to create lots of superfluous error messages. */
|
|||
|
if (ref)
|
|||
|
return ref;
|
|||
|
|
|||
|
push_obstacks_nochange ();
|
|||
|
|
|||
|
if (current_binding_level == global_binding_level && temporary)
|
|||
|
end_temporary_allocation ();
|
|||
|
|
|||
|
/* If no such tag is yet defined, create a forward-reference node
|
|||
|
and record it as the "definition".
|
|||
|
When a real declaration of this type is found,
|
|||
|
the forward-reference will be altered into a real type. */
|
|||
|
|
|||
|
ref = make_node (code);
|
|||
|
if (code == ENUMERAL_TYPE)
|
|||
|
{
|
|||
|
/* (In ANSI, Enums can be referred to only if already defined.) */
|
|||
|
if (pedantic)
|
|||
|
pedwarn ("ANSI C forbids forward references to `enum' types");
|
|||
|
/* Give the type a default layout like unsigned int
|
|||
|
to avoid crashing if it does not get defined. */
|
|||
|
TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node);
|
|||
|
TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node);
|
|||
|
TREE_UNSIGNED (ref) = 1;
|
|||
|
TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node);
|
|||
|
TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node);
|
|||
|
TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node);
|
|||
|
}
|
|||
|
|
|||
|
pushtag (name, ref);
|
|||
|
|
|||
|
pop_obstacks ();
|
|||
|
|
|||
|
return ref;
|
|||
|
}
|
|||
|
|
|||
|
/* Make sure that the tag NAME is defined *in the current binding level*
|
|||
|
at least as a forward reference.
|
|||
|
CODE says which kind of tag NAME ought to be.
|
|||
|
|
|||
|
We also do a push_obstacks_nochange
|
|||
|
whose matching pop is in finish_struct. */
|
|||
|
|
|||
|
tree
|
|||
|
start_struct (code, name)
|
|||
|
enum tree_code code;
|
|||
|
tree name;
|
|||
|
{
|
|||
|
/* If there is already a tag defined at this binding level
|
|||
|
(as a forward reference), just return it. */
|
|||
|
|
|||
|
register tree ref = 0;
|
|||
|
|
|||
|
push_obstacks_nochange ();
|
|||
|
if (current_binding_level == global_binding_level)
|
|||
|
end_temporary_allocation ();
|
|||
|
|
|||
|
if (name != 0)
|
|||
|
ref = lookup_tag (code, name, current_binding_level, 1);
|
|||
|
if (ref && TREE_CODE (ref) == code)
|
|||
|
{
|
|||
|
C_TYPE_BEING_DEFINED (ref) = 1;
|
|||
|
TYPE_PACKED (ref) = flag_pack_struct;
|
|||
|
if (TYPE_FIELDS (ref))
|
|||
|
error ((code == UNION_TYPE ? "redefinition of `union %s'"
|
|||
|
: "redefinition of `struct %s'"),
|
|||
|
IDENTIFIER_POINTER (name));
|
|||
|
|
|||
|
return ref;
|
|||
|
}
|
|||
|
|
|||
|
/* Otherwise create a forward-reference just so the tag is in scope. */
|
|||
|
|
|||
|
ref = make_node (code);
|
|||
|
pushtag (name, ref);
|
|||
|
C_TYPE_BEING_DEFINED (ref) = 1;
|
|||
|
TYPE_PACKED (ref) = flag_pack_struct;
|
|||
|
return ref;
|
|||
|
}
|
|||
|
|
|||
|
/* Process the specs, declarator (NULL if omitted) and width (NULL if omitted)
|
|||
|
of a structure component, returning a FIELD_DECL node.
|
|||
|
WIDTH is non-NULL for bit fields only, and is an INTEGER_CST node.
|
|||
|
|
|||
|
This is done during the parsing of the struct declaration.
|
|||
|
The FIELD_DECL nodes are chained together and the lot of them
|
|||
|
are ultimately passed to `build_struct' to make the RECORD_TYPE node. */
|
|||
|
|
|||
|
tree
|
|||
|
grokfield (filename, line, declarator, declspecs, width)
|
|||
|
char *filename;
|
|||
|
int line;
|
|||
|
tree declarator, declspecs, width;
|
|||
|
{
|
|||
|
tree value;
|
|||
|
|
|||
|
/* The corresponding pop_obstacks is in finish_decl. */
|
|||
|
push_obstacks_nochange ();
|
|||
|
|
|||
|
value = grokdeclarator (declarator, declspecs, width ? BITFIELD : FIELD, 0);
|
|||
|
|
|||
|
finish_decl (value, NULL_TREE, NULL_TREE);
|
|||
|
DECL_INITIAL (value) = width;
|
|||
|
|
|||
|
maybe_objc_check_decl (value);
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
/* Function to help qsort sort FIELD_DECLs by name order. */
|
|||
|
|
|||
|
static int
|
|||
|
field_decl_cmp (xp, yp)
|
|||
|
const GENERIC_PTR xp;
|
|||
|
const GENERIC_PTR yp;
|
|||
|
{
|
|||
|
tree *x = (tree *)xp, *y = (tree *)yp;
|
|||
|
|
|||
|
if (DECL_NAME (*x) == DECL_NAME (*y))
|
|||
|
return 0;
|
|||
|
if (DECL_NAME (*x) == NULL)
|
|||
|
return -1;
|
|||
|
if (DECL_NAME (*y) == NULL)
|
|||
|
return 1;
|
|||
|
if (DECL_NAME (*x) < DECL_NAME (*y))
|
|||
|
return -1;
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
|
|||
|
FIELDLIST is a chain of FIELD_DECL nodes for the fields.
|
|||
|
ATTRIBUTES are attributes to be applied to the structure.
|
|||
|
|
|||
|
We also do a pop_obstacks to match the push in start_struct. */
|
|||
|
|
|||
|
tree
|
|||
|
finish_struct (t, fieldlist, attributes)
|
|||
|
tree t;
|
|||
|
tree fieldlist;
|
|||
|
tree attributes;
|
|||
|
{
|
|||
|
register tree x;
|
|||
|
int old_momentary;
|
|||
|
int toplevel = global_binding_level == current_binding_level;
|
|||
|
|
|||
|
/* If this type was previously laid out as a forward reference,
|
|||
|
make sure we lay it out again. */
|
|||
|
|
|||
|
TYPE_SIZE (t) = 0;
|
|||
|
|
|||
|
decl_attributes (t, attributes, NULL_TREE);
|
|||
|
|
|||
|
/* Nameless union parm types are useful as GCC extension. */
|
|||
|
if (! (TREE_CODE (t) == UNION_TYPE && TYPE_NAME (t) == 0) && !pedantic)
|
|||
|
/* Otherwise, warn about any struct or union def. in parmlist. */
|
|||
|
if (in_parm_level_p ())
|
|||
|
{
|
|||
|
if (pedantic)
|
|||
|
pedwarn ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms"
|
|||
|
: "structure defined inside parms"));
|
|||
|
else if (! flag_traditional)
|
|||
|
warning ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms"
|
|||
|
: "structure defined inside parms"));
|
|||
|
}
|
|||
|
|
|||
|
old_momentary = suspend_momentary ();
|
|||
|
|
|||
|
if (pedantic)
|
|||
|
{
|
|||
|
for (x = fieldlist; x; x = TREE_CHAIN (x))
|
|||
|
if (DECL_NAME (x) != 0)
|
|||
|
break;
|
|||
|
|
|||
|
if (x == 0)
|
|||
|
pedwarn ("%s has no %smembers",
|
|||
|
(TREE_CODE (t) == UNION_TYPE ? "union" : "structure"),
|
|||
|
(fieldlist ? "named " : ""));
|
|||
|
}
|
|||
|
|
|||
|
/* Install struct as DECL_CONTEXT of each field decl.
|
|||
|
Also process specified field sizes.
|
|||
|
Set DECL_FIELD_SIZE to the specified size, or 0 if none specified.
|
|||
|
The specified size is found in the DECL_INITIAL.
|
|||
|
Store 0 there, except for ": 0" fields (so we can find them
|
|||
|
and delete them, below). */
|
|||
|
|
|||
|
for (x = fieldlist; x; x = TREE_CHAIN (x))
|
|||
|
{
|
|||
|
DECL_CONTEXT (x) = t;
|
|||
|
DECL_PACKED (x) |= TYPE_PACKED (t);
|
|||
|
DECL_FIELD_SIZE (x) = 0;
|
|||
|
|
|||
|
/* If any field is const, the structure type is pseudo-const. */
|
|||
|
if (TREE_READONLY (x))
|
|||
|
C_TYPE_FIELDS_READONLY (t) = 1;
|
|||
|
else
|
|||
|
{
|
|||
|
/* A field that is pseudo-const makes the structure likewise. */
|
|||
|
tree t1 = TREE_TYPE (x);
|
|||
|
while (TREE_CODE (t1) == ARRAY_TYPE)
|
|||
|
t1 = TREE_TYPE (t1);
|
|||
|
if ((TREE_CODE (t1) == RECORD_TYPE || TREE_CODE (t1) == UNION_TYPE)
|
|||
|
&& C_TYPE_FIELDS_READONLY (t1))
|
|||
|
C_TYPE_FIELDS_READONLY (t) = 1;
|
|||
|
}
|
|||
|
|
|||
|
/* Any field that is volatile means variables of this type must be
|
|||
|
treated in some ways as volatile. */
|
|||
|
if (TREE_THIS_VOLATILE (x))
|
|||
|
C_TYPE_FIELDS_VOLATILE (t) = 1;
|
|||
|
|
|||
|
/* Any field of nominal variable size implies structure is too. */
|
|||
|
if (C_DECL_VARIABLE_SIZE (x))
|
|||
|
C_TYPE_VARIABLE_SIZE (t) = 1;
|
|||
|
|
|||
|
/* Detect invalid nested redefinition. */
|
|||
|
if (TREE_TYPE (x) == t)
|
|||
|
error ("nested redefinition of `%s'",
|
|||
|
IDENTIFIER_POINTER (TYPE_NAME (t)));
|
|||
|
|
|||
|
/* Detect invalid bit-field size. */
|
|||
|
if (DECL_INITIAL (x))
|
|||
|
STRIP_NOPS (DECL_INITIAL (x));
|
|||
|
if (DECL_INITIAL (x))
|
|||
|
{
|
|||
|
if (TREE_CODE (DECL_INITIAL (x)) == INTEGER_CST)
|
|||
|
constant_expression_warning (DECL_INITIAL (x));
|
|||
|
else
|
|||
|
{
|
|||
|
error_with_decl (x, "bit-field `%s' width not an integer constant");
|
|||
|
DECL_INITIAL (x) = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Detect invalid bit-field type. */
|
|||
|
if (DECL_INITIAL (x)
|
|||
|
&& TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE
|
|||
|
&& TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE)
|
|||
|
{
|
|||
|
error_with_decl (x, "bit-field `%s' has invalid type");
|
|||
|
DECL_INITIAL (x) = NULL;
|
|||
|
}
|
|||
|
if (DECL_INITIAL (x) && pedantic
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_TYPE (x)) != integer_type_node
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_TYPE (x)) != unsigned_type_node
|
|||
|
/* Accept an enum that's equivalent to int or unsigned int. */
|
|||
|
&& !(TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
|
|||
|
&& (TYPE_PRECISION (TREE_TYPE (x))
|
|||
|
== TYPE_PRECISION (integer_type_node))))
|
|||
|
pedwarn_with_decl (x, "bit-field `%s' type invalid in ANSI C");
|
|||
|
|
|||
|
/* Detect and ignore out of range field width. */
|
|||
|
if (DECL_INITIAL (x))
|
|||
|
{
|
|||
|
unsigned HOST_WIDE_INT width = TREE_INT_CST_LOW (DECL_INITIAL (x));
|
|||
|
|
|||
|
if (tree_int_cst_sgn (DECL_INITIAL (x)) < 0)
|
|||
|
{
|
|||
|
DECL_INITIAL (x) = NULL;
|
|||
|
error_with_decl (x, "negative width in bit-field `%s'");
|
|||
|
}
|
|||
|
else if (TREE_INT_CST_HIGH (DECL_INITIAL (x)) != 0
|
|||
|
|| width > TYPE_PRECISION (TREE_TYPE (x)))
|
|||
|
{
|
|||
|
DECL_INITIAL (x) = NULL;
|
|||
|
pedwarn_with_decl (x, "width of `%s' exceeds its type");
|
|||
|
}
|
|||
|
else if (width == 0 && DECL_NAME (x) != 0)
|
|||
|
{
|
|||
|
error_with_decl (x, "zero width for bit-field `%s'");
|
|||
|
DECL_INITIAL (x) = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Process valid field width. */
|
|||
|
if (DECL_INITIAL (x))
|
|||
|
{
|
|||
|
register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
|
|||
|
|
|||
|
if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
|
|||
|
&& (width < min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
|
|||
|
TREE_UNSIGNED (TREE_TYPE (x)))
|
|||
|
|| width < min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
|
|||
|
TREE_UNSIGNED (TREE_TYPE (x)))))
|
|||
|
warning_with_decl (x, "`%s' is narrower than values of its type");
|
|||
|
|
|||
|
DECL_FIELD_SIZE (x) = width;
|
|||
|
DECL_BIT_FIELD (x) = DECL_C_BIT_FIELD (x) = 1;
|
|||
|
DECL_INITIAL (x) = NULL;
|
|||
|
|
|||
|
if (width == 0)
|
|||
|
{
|
|||
|
/* field size 0 => force desired amount of alignment. */
|
|||
|
#ifdef EMPTY_FIELD_BOUNDARY
|
|||
|
DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY);
|
|||
|
#endif
|
|||
|
#ifdef PCC_BITFIELD_TYPE_MATTERS
|
|||
|
if (PCC_BITFIELD_TYPE_MATTERS)
|
|||
|
DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
|
|||
|
TYPE_ALIGN (TREE_TYPE (x)));
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
else if (TREE_TYPE (x) != error_mark_node)
|
|||
|
{
|
|||
|
int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT
|
|||
|
: TYPE_ALIGN (TREE_TYPE (x)));
|
|||
|
/* Non-bit-fields are aligned for their type, except packed
|
|||
|
fields which require only BITS_PER_UNIT alignment. */
|
|||
|
DECL_ALIGN (x) = MAX (DECL_ALIGN (x), min_align);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now DECL_INITIAL is null on all members. */
|
|||
|
|
|||
|
/* Delete all duplicate fields from the fieldlist */
|
|||
|
for (x = fieldlist; x && TREE_CHAIN (x);)
|
|||
|
/* Anonymous fields aren't duplicates. */
|
|||
|
if (DECL_NAME (TREE_CHAIN (x)) == 0)
|
|||
|
x = TREE_CHAIN (x);
|
|||
|
else
|
|||
|
{
|
|||
|
register tree y = fieldlist;
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x)))
|
|||
|
break;
|
|||
|
if (y == x)
|
|||
|
break;
|
|||
|
y = TREE_CHAIN (y);
|
|||
|
}
|
|||
|
if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x)))
|
|||
|
{
|
|||
|
error_with_decl (TREE_CHAIN (x), "duplicate member `%s'");
|
|||
|
TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x));
|
|||
|
}
|
|||
|
else x = TREE_CHAIN (x);
|
|||
|
}
|
|||
|
|
|||
|
/* Now we have the nearly final fieldlist. Record it,
|
|||
|
then lay out the structure or union (including the fields). */
|
|||
|
|
|||
|
TYPE_FIELDS (t) = fieldlist;
|
|||
|
|
|||
|
layout_type (t);
|
|||
|
|
|||
|
/* Delete all zero-width bit-fields from the front of the fieldlist */
|
|||
|
while (fieldlist
|
|||
|
&& DECL_INITIAL (fieldlist))
|
|||
|
fieldlist = TREE_CHAIN (fieldlist);
|
|||
|
/* Delete all such members from the rest of the fieldlist */
|
|||
|
for (x = fieldlist; x;)
|
|||
|
{
|
|||
|
if (TREE_CHAIN (x) && DECL_INITIAL (TREE_CHAIN (x)))
|
|||
|
TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x));
|
|||
|
else x = TREE_CHAIN (x);
|
|||
|
}
|
|||
|
|
|||
|
/* Now we have the truly final field list.
|
|||
|
Store it in this type and in the variants. */
|
|||
|
|
|||
|
TYPE_FIELDS (t) = fieldlist;
|
|||
|
|
|||
|
/* If there are lots of fields, sort so we can look through them fast.
|
|||
|
We arbitrarily consider 16 or more elts to be "a lot". */
|
|||
|
{
|
|||
|
int len = 0;
|
|||
|
|
|||
|
for (x = fieldlist; x; x = TREE_CHAIN (x))
|
|||
|
{
|
|||
|
if (len > 15)
|
|||
|
break;
|
|||
|
len += 1;
|
|||
|
}
|
|||
|
if (len > 15)
|
|||
|
{
|
|||
|
tree *field_array;
|
|||
|
char *space;
|
|||
|
|
|||
|
len += list_length (x);
|
|||
|
/* Use the same allocation policy here that make_node uses, to
|
|||
|
ensure that this lives as long as the rest of the struct decl.
|
|||
|
All decls in an inline function need to be saved. */
|
|||
|
if (allocation_temporary_p ())
|
|||
|
space = savealloc (sizeof (struct lang_type) + len * sizeof (tree));
|
|||
|
else
|
|||
|
space = oballoc (sizeof (struct lang_type) + len * sizeof (tree));
|
|||
|
|
|||
|
TYPE_LANG_SPECIFIC (t) = (struct lang_type *) space;
|
|||
|
TYPE_LANG_SPECIFIC (t)->len = len;
|
|||
|
|
|||
|
field_array = &TYPE_LANG_SPECIFIC (t)->elts[0];
|
|||
|
len = 0;
|
|||
|
for (x = fieldlist; x; x = TREE_CHAIN (x))
|
|||
|
field_array[len++] = x;
|
|||
|
|
|||
|
qsort (field_array, len, sizeof (tree), field_decl_cmp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
|
|||
|
{
|
|||
|
TYPE_FIELDS (x) = TYPE_FIELDS (t);
|
|||
|
TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
|
|||
|
TYPE_ALIGN (x) = TYPE_ALIGN (t);
|
|||
|
}
|
|||
|
|
|||
|
/* If this was supposed to be a transparent union, but we can't
|
|||
|
make it one, warn and turn off the flag. */
|
|||
|
if (TREE_CODE (t) == UNION_TYPE
|
|||
|
&& TYPE_TRANSPARENT_UNION (t)
|
|||
|
&& TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t)))
|
|||
|
{
|
|||
|
TYPE_TRANSPARENT_UNION (t) = 0;
|
|||
|
warning ("union cannot be made transparent");
|
|||
|
}
|
|||
|
|
|||
|
/* If this structure or union completes the type of any previous
|
|||
|
variable declaration, lay it out and output its rtl. */
|
|||
|
|
|||
|
if (current_binding_level->n_incomplete != 0)
|
|||
|
{
|
|||
|
tree decl;
|
|||
|
for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl))
|
|||
|
{
|
|||
|
if (TREE_TYPE (decl) == t
|
|||
|
&& TREE_CODE (decl) != TYPE_DECL)
|
|||
|
{
|
|||
|
layout_decl (decl, 0);
|
|||
|
/* This is a no-op in c-lang.c or something real in objc-actions.c. */
|
|||
|
maybe_objc_check_decl (decl);
|
|||
|
rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
|
|||
|
if (! toplevel)
|
|||
|
expand_decl (decl);
|
|||
|
--current_binding_level->n_incomplete;
|
|||
|
}
|
|||
|
else if (TYPE_SIZE (TREE_TYPE (decl)) == 0
|
|||
|
&& TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
|
|||
|
{
|
|||
|
tree element = TREE_TYPE (decl);
|
|||
|
while (TREE_CODE (element) == ARRAY_TYPE)
|
|||
|
element = TREE_TYPE (element);
|
|||
|
if (element == t)
|
|||
|
layout_array_type (TREE_TYPE (decl));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
resume_momentary (old_momentary);
|
|||
|
|
|||
|
/* Finish debugging output for this type. */
|
|||
|
rest_of_type_compilation (t, toplevel);
|
|||
|
|
|||
|
/* The matching push is in start_struct. */
|
|||
|
pop_obstacks ();
|
|||
|
|
|||
|
return t;
|
|||
|
}
|
|||
|
|
|||
|
/* Lay out the type T, and its element type, and so on. */
|
|||
|
|
|||
|
static void
|
|||
|
layout_array_type (t)
|
|||
|
tree t;
|
|||
|
{
|
|||
|
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
|
|||
|
layout_array_type (TREE_TYPE (t));
|
|||
|
layout_type (t);
|
|||
|
}
|
|||
|
|
|||
|
/* Begin compiling the definition of an enumeration type.
|
|||
|
NAME is its name (or null if anonymous).
|
|||
|
Returns the type object, as yet incomplete.
|
|||
|
Also records info about it so that build_enumerator
|
|||
|
may be used to declare the individual values as they are read. */
|
|||
|
|
|||
|
tree
|
|||
|
start_enum (name)
|
|||
|
tree name;
|
|||
|
{
|
|||
|
register tree enumtype = 0;
|
|||
|
|
|||
|
/* If this is the real definition for a previous forward reference,
|
|||
|
fill in the contents in the same object that used to be the
|
|||
|
forward reference. */
|
|||
|
|
|||
|
if (name != 0)
|
|||
|
enumtype = lookup_tag (ENUMERAL_TYPE, name, current_binding_level, 1);
|
|||
|
|
|||
|
/* The corresponding pop_obstacks is in finish_enum. */
|
|||
|
push_obstacks_nochange ();
|
|||
|
/* If these symbols and types are global, make them permanent. */
|
|||
|
if (current_binding_level == global_binding_level)
|
|||
|
end_temporary_allocation ();
|
|||
|
|
|||
|
if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE)
|
|||
|
{
|
|||
|
enumtype = make_node (ENUMERAL_TYPE);
|
|||
|
pushtag (name, enumtype);
|
|||
|
}
|
|||
|
|
|||
|
C_TYPE_BEING_DEFINED (enumtype) = 1;
|
|||
|
|
|||
|
if (TYPE_VALUES (enumtype) != 0)
|
|||
|
{
|
|||
|
/* This enum is a named one that has been declared already. */
|
|||
|
error ("redeclaration of `enum %s'", IDENTIFIER_POINTER (name));
|
|||
|
|
|||
|
/* Completely replace its old definition.
|
|||
|
The old enumerators remain defined, however. */
|
|||
|
TYPE_VALUES (enumtype) = 0;
|
|||
|
}
|
|||
|
|
|||
|
enum_next_value = integer_zero_node;
|
|||
|
enum_overflow = 0;
|
|||
|
|
|||
|
if (flag_short_enums)
|
|||
|
TYPE_PACKED (enumtype) = 1;
|
|||
|
|
|||
|
return enumtype;
|
|||
|
}
|
|||
|
|
|||
|
/* After processing and defining all the values of an enumeration type,
|
|||
|
install their decls in the enumeration type and finish it off.
|
|||
|
ENUMTYPE is the type object, VALUES a list of decl-value pairs,
|
|||
|
and ATTRIBUTES are the specified attributes.
|
|||
|
Returns ENUMTYPE. */
|
|||
|
|
|||
|
tree
|
|||
|
finish_enum (enumtype, values, attributes)
|
|||
|
tree enumtype;
|
|||
|
tree values;
|
|||
|
tree attributes;
|
|||
|
{
|
|||
|
register tree pair, tem;
|
|||
|
tree minnode = 0, maxnode = 0;
|
|||
|
int lowprec, highprec, precision;
|
|||
|
int toplevel = global_binding_level == current_binding_level;
|
|||
|
|
|||
|
if (in_parm_level_p ())
|
|||
|
warning ("enum defined inside parms");
|
|||
|
|
|||
|
decl_attributes (enumtype, attributes, NULL_TREE);
|
|||
|
|
|||
|
/* Calculate the maximum value of any enumerator in this type. */
|
|||
|
|
|||
|
if (values == error_mark_node)
|
|||
|
minnode = maxnode = integer_zero_node;
|
|||
|
else
|
|||
|
for (pair = values; pair; pair = TREE_CHAIN (pair))
|
|||
|
{
|
|||
|
tree value = TREE_VALUE (pair);
|
|||
|
if (pair == values)
|
|||
|
minnode = maxnode = TREE_VALUE (pair);
|
|||
|
else
|
|||
|
{
|
|||
|
if (tree_int_cst_lt (maxnode, value))
|
|||
|
maxnode = value;
|
|||
|
if (tree_int_cst_lt (value, minnode))
|
|||
|
minnode = value;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
TYPE_MIN_VALUE (enumtype) = minnode;
|
|||
|
TYPE_MAX_VALUE (enumtype) = maxnode;
|
|||
|
|
|||
|
/* An enum can have some negative values; then it is signed. */
|
|||
|
TREE_UNSIGNED (enumtype) = tree_int_cst_sgn (minnode) >= 0;
|
|||
|
|
|||
|
/* Determine the precision this type needs. */
|
|||
|
|
|||
|
lowprec = min_precision (minnode, TREE_UNSIGNED (enumtype));
|
|||
|
highprec = min_precision (maxnode, TREE_UNSIGNED (enumtype));
|
|||
|
precision = MAX (lowprec, highprec);
|
|||
|
|
|||
|
if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
|
|||
|
{
|
|||
|
tree narrowest = type_for_size (precision, 1);
|
|||
|
if (narrowest == 0)
|
|||
|
{
|
|||
|
warning ("enumeration values exceed range of largest integer");
|
|||
|
narrowest = long_long_integer_type_node;
|
|||
|
}
|
|||
|
|
|||
|
TYPE_PRECISION (enumtype) = TYPE_PRECISION (narrowest);
|
|||
|
}
|
|||
|
else
|
|||
|
TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
|
|||
|
|
|||
|
TYPE_SIZE (enumtype) = 0;
|
|||
|
layout_type (enumtype);
|
|||
|
|
|||
|
if (values != error_mark_node)
|
|||
|
{
|
|||
|
/* Change the type of the enumerators to be the enum type.
|
|||
|
Formerly this was done only for enums that fit in an int,
|
|||
|
but the comment said it was done only for enums wider than int.
|
|||
|
It seems necessary to do this for wide enums,
|
|||
|
and best not to change what's done for ordinary narrower ones. */
|
|||
|
for (pair = values; pair; pair = TREE_CHAIN (pair))
|
|||
|
{
|
|||
|
TREE_TYPE (TREE_PURPOSE (pair)) = enumtype;
|
|||
|
DECL_SIZE (TREE_PURPOSE (pair)) = TYPE_SIZE (enumtype);
|
|||
|
if (TREE_CODE (TREE_PURPOSE (pair)) != FUNCTION_DECL)
|
|||
|
DECL_ALIGN (TREE_PURPOSE (pair)) = TYPE_ALIGN (enumtype);
|
|||
|
}
|
|||
|
|
|||
|
/* Replace the decl nodes in VALUES with their names. */
|
|||
|
for (pair = values; pair; pair = TREE_CHAIN (pair))
|
|||
|
TREE_PURPOSE (pair) = DECL_NAME (TREE_PURPOSE (pair));
|
|||
|
|
|||
|
TYPE_VALUES (enumtype) = values;
|
|||
|
}
|
|||
|
|
|||
|
/* Fix up all variant types of this enum type. */
|
|||
|
for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem))
|
|||
|
{
|
|||
|
TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
|
|||
|
TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
|
|||
|
TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
|
|||
|
TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
|
|||
|
TYPE_MODE (tem) = TYPE_MODE (enumtype);
|
|||
|
TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
|
|||
|
TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
|
|||
|
TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
|
|||
|
}
|
|||
|
|
|||
|
/* Finish debugging output for this type. */
|
|||
|
rest_of_type_compilation (enumtype, toplevel);
|
|||
|
|
|||
|
/* This matches a push in start_enum. */
|
|||
|
pop_obstacks ();
|
|||
|
|
|||
|
return enumtype;
|
|||
|
}
|
|||
|
|
|||
|
/* Build and install a CONST_DECL for one value of the
|
|||
|
current enumeration type (one that was begun with start_enum).
|
|||
|
Return a tree-list containing the CONST_DECL and its value.
|
|||
|
Assignment of sequential values by default is handled here. */
|
|||
|
|
|||
|
tree
|
|||
|
build_enumerator (name, value)
|
|||
|
tree name, value;
|
|||
|
{
|
|||
|
register tree decl, type;
|
|||
|
|
|||
|
/* Validate and default VALUE. */
|
|||
|
|
|||
|
/* Remove no-op casts from the value. */
|
|||
|
if (value)
|
|||
|
STRIP_TYPE_NOPS (value);
|
|||
|
|
|||
|
if (value != 0)
|
|||
|
{
|
|||
|
if (TREE_CODE (value) == INTEGER_CST)
|
|||
|
{
|
|||
|
value = default_conversion (value);
|
|||
|
constant_expression_warning (value);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
error ("enumerator value for `%s' not integer constant",
|
|||
|
IDENTIFIER_POINTER (name));
|
|||
|
value = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Default based on previous value. */
|
|||
|
/* It should no longer be possible to have NON_LVALUE_EXPR
|
|||
|
in the default. */
|
|||
|
if (value == 0)
|
|||
|
{
|
|||
|
value = enum_next_value;
|
|||
|
if (enum_overflow)
|
|||
|
error ("overflow in enumeration values");
|
|||
|
}
|
|||
|
|
|||
|
if (pedantic && ! int_fits_type_p (value, integer_type_node))
|
|||
|
{
|
|||
|
pedwarn ("ANSI C restricts enumerator values to range of `int'");
|
|||
|
value = integer_zero_node;
|
|||
|
}
|
|||
|
|
|||
|
/* Set basis for default for next value. */
|
|||
|
enum_next_value = build_binary_op (PLUS_EXPR, value, integer_one_node, 0);
|
|||
|
enum_overflow = tree_int_cst_lt (enum_next_value, value);
|
|||
|
|
|||
|
/* Now create a declaration for the enum value name. */
|
|||
|
|
|||
|
type = TREE_TYPE (value);
|
|||
|
type = type_for_size (MAX (TYPE_PRECISION (type),
|
|||
|
TYPE_PRECISION (integer_type_node)),
|
|||
|
((flag_traditional
|
|||
|
|| TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node))
|
|||
|
&& TREE_UNSIGNED (type)));
|
|||
|
|
|||
|
decl = build_decl (CONST_DECL, name, type);
|
|||
|
DECL_INITIAL (decl) = value;
|
|||
|
TREE_TYPE (value) = type;
|
|||
|
pushdecl (decl);
|
|||
|
|
|||
|
return saveable_tree_cons (decl, value, NULL_TREE);
|
|||
|
}
|
|||
|
|
|||
|
/* Create the FUNCTION_DECL for a function definition.
|
|||
|
DECLSPECS, DECLARATOR, PREFIX_ATTRIBUTES and ATTRIBUTES are the parts of
|
|||
|
the declaration; they describe the function's name and the type it returns,
|
|||
|
but twisted together in a fashion that parallels the syntax of C.
|
|||
|
|
|||
|
This function creates a binding context for the function body
|
|||
|
as well as setting up the FUNCTION_DECL in current_function_decl.
|
|||
|
|
|||
|
Returns 1 on success. If the DECLARATOR is not suitable for a function
|
|||
|
(it defines a datum instead), we return 0, which tells
|
|||
|
yyparse to report a parse error.
|
|||
|
|
|||
|
NESTED is nonzero for a function nested within another function. */
|
|||
|
|
|||
|
int
|
|||
|
start_function (declspecs, declarator, prefix_attributes, attributes, nested)
|
|||
|
tree declarator, declspecs, prefix_attributes, attributes;
|
|||
|
int nested;
|
|||
|
{
|
|||
|
tree decl1, old_decl;
|
|||
|
tree restype;
|
|||
|
int old_immediate_size_expand = immediate_size_expand;
|
|||
|
|
|||
|
current_function_returns_value = 0; /* Assume, until we see it does. */
|
|||
|
current_function_returns_null = 0;
|
|||
|
warn_about_return_type = 0;
|
|||
|
current_extern_inline = 0;
|
|||
|
c_function_varargs = 0;
|
|||
|
named_labels = 0;
|
|||
|
shadowed_labels = 0;
|
|||
|
|
|||
|
/* Don't expand any sizes in the return type of the function. */
|
|||
|
immediate_size_expand = 0;
|
|||
|
|
|||
|
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1);
|
|||
|
|
|||
|
/* If the declarator is not suitable for a function definition,
|
|||
|
cause a syntax error. */
|
|||
|
if (decl1 == 0)
|
|||
|
{
|
|||
|
immediate_size_expand = old_immediate_size_expand;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
decl_attributes (decl1, prefix_attributes, attributes);
|
|||
|
|
|||
|
announce_function (decl1);
|
|||
|
|
|||
|
if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl1))) == 0)
|
|||
|
{
|
|||
|
error ("return-type is an incomplete type");
|
|||
|
/* Make it return void instead. */
|
|||
|
TREE_TYPE (decl1)
|
|||
|
= build_function_type (void_type_node,
|
|||
|
TYPE_ARG_TYPES (TREE_TYPE (decl1)));
|
|||
|
}
|
|||
|
|
|||
|
if (warn_about_return_type)
|
|||
|
warning ("return-type defaults to `int'");
|
|||
|
|
|||
|
/* Save the parm names or decls from this function's declarator
|
|||
|
where store_parm_decls will find them. */
|
|||
|
current_function_parms = last_function_parms;
|
|||
|
current_function_parm_tags = last_function_parm_tags;
|
|||
|
|
|||
|
/* Make the init_value nonzero so pushdecl knows this is not tentative.
|
|||
|
error_mark_node is replaced below (in poplevel) with the BLOCK. */
|
|||
|
DECL_INITIAL (decl1) = error_mark_node;
|
|||
|
|
|||
|
/* If this definition isn't a prototype and we had a prototype declaration
|
|||
|
before, copy the arg type info from that prototype.
|
|||
|
But not if what we had before was a builtin function. */
|
|||
|
old_decl = lookup_name_current_level (DECL_NAME (decl1));
|
|||
|
if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
|
|||
|
&& !DECL_BUILT_IN (old_decl)
|
|||
|
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
|
|||
|
== TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (old_decl))))
|
|||
|
&& TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0)
|
|||
|
{
|
|||
|
TREE_TYPE (decl1) = TREE_TYPE (old_decl);
|
|||
|
current_function_prototype_file = DECL_SOURCE_FILE (old_decl);
|
|||
|
current_function_prototype_line = DECL_SOURCE_LINE (old_decl);
|
|||
|
}
|
|||
|
|
|||
|
/* If there is no explicit declaration, look for any out-of-scope implicit
|
|||
|
declarations. */
|
|||
|
if (old_decl == 0)
|
|||
|
old_decl = IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1));
|
|||
|
|
|||
|
/* Optionally warn of old-fashioned def with no previous prototype. */
|
|||
|
if (warn_strict_prototypes
|
|||
|
&& TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0
|
|||
|
&& !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0))
|
|||
|
warning ("function declaration isn't a prototype");
|
|||
|
/* Optionally warn of any global def with no previous prototype. */
|
|||
|
else if (warn_missing_prototypes
|
|||
|
&& TREE_PUBLIC (decl1)
|
|||
|
&& !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0)
|
|||
|
&& strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))))
|
|||
|
warning_with_decl (decl1, "no previous prototype for `%s'");
|
|||
|
/* Optionally warn of any def with no previous prototype
|
|||
|
if the function has already been used. */
|
|||
|
else if (warn_missing_prototypes
|
|||
|
&& old_decl != 0 && TREE_USED (old_decl)
|
|||
|
&& TYPE_ARG_TYPES (TREE_TYPE (old_decl)) == 0)
|
|||
|
warning_with_decl (decl1,
|
|||
|
"`%s' was used with no prototype before its definition");
|
|||
|
/* Optionally warn of any global def with no previous declaration. */
|
|||
|
else if (warn_missing_declarations
|
|||
|
&& TREE_PUBLIC (decl1)
|
|||
|
&& old_decl == 0
|
|||
|
&& strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))))
|
|||
|
warning_with_decl (decl1, "no previous declaration for `%s'");
|
|||
|
/* Optionally warn of any def with no previous declaration
|
|||
|
if the function has already been used. */
|
|||
|
else if (warn_missing_declarations
|
|||
|
&& old_decl != 0 && TREE_USED (old_decl)
|
|||
|
&& old_decl == IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)))
|
|||
|
warning_with_decl (decl1,
|
|||
|
"`%s' was used with no declaration before its definition");
|
|||
|
|
|||
|
/* This is a definition, not a reference.
|
|||
|
So normally clear DECL_EXTERNAL.
|
|||
|
However, `extern inline' acts like a declaration
|
|||
|
except for defining how to inline. So set DECL_EXTERNAL in that case. */
|
|||
|
DECL_EXTERNAL (decl1) = current_extern_inline;
|
|||
|
|
|||
|
/* This function exists in static storage.
|
|||
|
(This does not mean `static' in the C sense!) */
|
|||
|
TREE_STATIC (decl1) = 1;
|
|||
|
|
|||
|
/* A nested function is not global. */
|
|||
|
if (current_function_decl != 0)
|
|||
|
TREE_PUBLIC (decl1) = 0;
|
|||
|
|
|||
|
/* Warn for unlikely, improbable, or stupid declarations of `main'. */
|
|||
|
if (warn_main
|
|||
|
&& strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))) == 0)
|
|||
|
{
|
|||
|
tree args;
|
|||
|
int argct = 0;
|
|||
|
|
|||
|
if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
|
|||
|
!= integer_type_node)
|
|||
|
pedwarn_with_decl (decl1, "return type of `%s' is not `int'");
|
|||
|
|
|||
|
for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args;
|
|||
|
args = TREE_CHAIN (args))
|
|||
|
{
|
|||
|
tree type = args ? TREE_VALUE (args) : 0;
|
|||
|
|
|||
|
if (type == void_type_node)
|
|||
|
break;
|
|||
|
|
|||
|
++argct;
|
|||
|
switch (argct)
|
|||
|
{
|
|||
|
case 1:
|
|||
|
if (TYPE_MAIN_VARIANT (type) != integer_type_node)
|
|||
|
pedwarn_with_decl (decl1,
|
|||
|
"first argument of `%s' should be `int'");
|
|||
|
break;
|
|||
|
|
|||
|
case 2:
|
|||
|
if (TREE_CODE (type) != POINTER_TYPE
|
|||
|
|| TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
|
|||
|
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
|
|||
|
!= char_type_node))
|
|||
|
pedwarn_with_decl (decl1,
|
|||
|
"second argument of `%s' should be `char **'");
|
|||
|
break;
|
|||
|
|
|||
|
case 3:
|
|||
|
if (TREE_CODE (type) != POINTER_TYPE
|
|||
|
|| TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
|
|||
|
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
|
|||
|
!= char_type_node))
|
|||
|
pedwarn_with_decl (decl1,
|
|||
|
"third argument of `%s' should probably be `char **'");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* It is intentional that this message does not mention the third
|
|||
|
argument, which is warned for only pedantically, because it's
|
|||
|
blessed by mention in an appendix of the standard. */
|
|||
|
if (argct > 0 && (argct < 2 || argct > 3))
|
|||
|
pedwarn_with_decl (decl1, "`%s' takes only zero or two arguments");
|
|||
|
|
|||
|
if (argct == 3 && pedantic)
|
|||
|
pedwarn_with_decl (decl1, "third argument of `%s' is deprecated");
|
|||
|
|
|||
|
if (! TREE_PUBLIC (decl1))
|
|||
|
pedwarn_with_decl (decl1, "`%s' is normally a non-static function");
|
|||
|
}
|
|||
|
|
|||
|
/* Record the decl so that the function name is defined.
|
|||
|
If we already have a decl for this name, and it is a FUNCTION_DECL,
|
|||
|
use the old decl. */
|
|||
|
|
|||
|
current_function_decl = pushdecl (decl1);
|
|||
|
|
|||
|
pushlevel (0);
|
|||
|
declare_parm_level (1);
|
|||
|
current_binding_level->subblocks_tag_transparent = 1;
|
|||
|
|
|||
|
make_function_rtl (current_function_decl);
|
|||
|
|
|||
|
restype = TREE_TYPE (TREE_TYPE (current_function_decl));
|
|||
|
/* Promote the value to int before returning it. */
|
|||
|
if (C_PROMOTING_INTEGER_TYPE_P (restype))
|
|||
|
{
|
|||
|
/* It retains unsignedness if traditional
|
|||
|
or if not really getting wider. */
|
|||
|
if (TREE_UNSIGNED (restype)
|
|||
|
&& (flag_traditional
|
|||
|
|| (TYPE_PRECISION (restype)
|
|||
|
== TYPE_PRECISION (integer_type_node))))
|
|||
|
restype = unsigned_type_node;
|
|||
|
else
|
|||
|
restype = integer_type_node;
|
|||
|
}
|
|||
|
DECL_RESULT (current_function_decl)
|
|||
|
= build_decl (RESULT_DECL, NULL_TREE, restype);
|
|||
|
|
|||
|
if (!nested)
|
|||
|
/* Allocate further tree nodes temporarily during compilation
|
|||
|
of this function only. */
|
|||
|
temporary_allocation ();
|
|||
|
|
|||
|
/* If this fcn was already referenced via a block-scope `extern' decl
|
|||
|
(or an implicit decl), propagate certain information about the usage. */
|
|||
|
if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl)))
|
|||
|
TREE_ADDRESSABLE (current_function_decl) = 1;
|
|||
|
|
|||
|
immediate_size_expand = old_immediate_size_expand;
|
|||
|
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
/* Record that this function is going to be a varargs function.
|
|||
|
This is called before store_parm_decls, which is too early
|
|||
|
to call mark_varargs directly. */
|
|||
|
|
|||
|
void
|
|||
|
c_mark_varargs ()
|
|||
|
{
|
|||
|
c_function_varargs = 1;
|
|||
|
}
|
|||
|
|
|||
|
/* Store the parameter declarations into the current function declaration.
|
|||
|
This is called after parsing the parameter declarations, before
|
|||
|
digesting the body of the function.
|
|||
|
|
|||
|
For an old-style definition, modify the function's type
|
|||
|
to specify at least the number of arguments. */
|
|||
|
|
|||
|
void
|
|||
|
store_parm_decls ()
|
|||
|
{
|
|||
|
register tree fndecl = current_function_decl;
|
|||
|
register tree parm;
|
|||
|
|
|||
|
/* This is either a chain of PARM_DECLs (if a prototype was used)
|
|||
|
or a list of IDENTIFIER_NODEs (for an old-fashioned C definition). */
|
|||
|
tree specparms = current_function_parms;
|
|||
|
|
|||
|
/* This is a list of types declared among parms in a prototype. */
|
|||
|
tree parmtags = current_function_parm_tags;
|
|||
|
|
|||
|
/* This is a chain of PARM_DECLs from old-style parm declarations. */
|
|||
|
register tree parmdecls = getdecls ();
|
|||
|
|
|||
|
/* This is a chain of any other decls that came in among the parm
|
|||
|
declarations. If a parm is declared with enum {foo, bar} x;
|
|||
|
then CONST_DECLs for foo and bar are put here. */
|
|||
|
tree nonparms = 0;
|
|||
|
|
|||
|
/* Nonzero if this definition is written with a prototype. */
|
|||
|
int prototype = 0;
|
|||
|
|
|||
|
if (specparms != 0 && TREE_CODE (specparms) != TREE_LIST)
|
|||
|
{
|
|||
|
/* This case is when the function was defined with an ANSI prototype.
|
|||
|
The parms already have decls, so we need not do anything here
|
|||
|
except record them as in effect
|
|||
|
and complain if any redundant old-style parm decls were written. */
|
|||
|
|
|||
|
register tree next;
|
|||
|
tree others = 0;
|
|||
|
|
|||
|
prototype = 1;
|
|||
|
|
|||
|
if (parmdecls != 0)
|
|||
|
{
|
|||
|
tree decl, link;
|
|||
|
|
|||
|
error_with_decl (fndecl,
|
|||
|
"parm types given both in parmlist and separately");
|
|||
|
/* Get rid of the erroneous decls; don't keep them on
|
|||
|
the list of parms, since they might not be PARM_DECLs. */
|
|||
|
for (decl = current_binding_level->names;
|
|||
|
decl; decl = TREE_CHAIN (decl))
|
|||
|
if (DECL_NAME (decl))
|
|||
|
IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) = 0;
|
|||
|
for (link = current_binding_level->shadowed;
|
|||
|
link; link = TREE_CHAIN (link))
|
|||
|
IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
|
|||
|
current_binding_level->names = 0;
|
|||
|
current_binding_level->shadowed = 0;
|
|||
|
}
|
|||
|
|
|||
|
specparms = nreverse (specparms);
|
|||
|
for (parm = specparms; parm; parm = next)
|
|||
|
{
|
|||
|
next = TREE_CHAIN (parm);
|
|||
|
if (TREE_CODE (parm) == PARM_DECL)
|
|||
|
{
|
|||
|
if (DECL_NAME (parm) == 0)
|
|||
|
error_with_decl (parm, "parameter name omitted");
|
|||
|
else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node)
|
|||
|
{
|
|||
|
error_with_decl (parm, "parameter `%s' declared void");
|
|||
|
/* Change the type to error_mark_node so this parameter
|
|||
|
will be ignored by assign_parms. */
|
|||
|
TREE_TYPE (parm) = error_mark_node;
|
|||
|
}
|
|||
|
pushdecl (parm);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* If we find an enum constant or a type tag,
|
|||
|
put it aside for the moment. */
|
|||
|
TREE_CHAIN (parm) = 0;
|
|||
|
others = chainon (others, parm);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Get the decls in their original chain order
|
|||
|
and record in the function. */
|
|||
|
DECL_ARGUMENTS (fndecl) = getdecls ();
|
|||
|
|
|||
|
#if 0
|
|||
|
/* If this function takes a variable number of arguments,
|
|||
|
add a phony parameter to the end of the parm list,
|
|||
|
to represent the position of the first unnamed argument. */
|
|||
|
if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl))))
|
|||
|
!= void_type_node)
|
|||
|
{
|
|||
|
tree dummy = build_decl (PARM_DECL, NULL_TREE, void_type_node);
|
|||
|
/* Let's hope the address of the unnamed parm
|
|||
|
won't depend on its type. */
|
|||
|
TREE_TYPE (dummy) = integer_type_node;
|
|||
|
DECL_ARG_TYPE (dummy) = integer_type_node;
|
|||
|
DECL_ARGUMENTS (fndecl)
|
|||
|
= chainon (DECL_ARGUMENTS (fndecl), dummy);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
/* Now pushdecl the enum constants. */
|
|||
|
for (parm = others; parm; parm = next)
|
|||
|
{
|
|||
|
next = TREE_CHAIN (parm);
|
|||
|
if (DECL_NAME (parm) == 0)
|
|||
|
;
|
|||
|
else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node)
|
|||
|
;
|
|||
|
else if (TREE_CODE (parm) != PARM_DECL)
|
|||
|
pushdecl (parm);
|
|||
|
}
|
|||
|
|
|||
|
storetags (chainon (parmtags, gettags ()));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* SPECPARMS is an identifier list--a chain of TREE_LIST nodes
|
|||
|
each with a parm name as the TREE_VALUE.
|
|||
|
|
|||
|
PARMDECLS is a chain of declarations for parameters.
|
|||
|
Warning! It can also contain CONST_DECLs which are not parameters
|
|||
|
but are names of enumerators of any enum types
|
|||
|
declared among the parameters.
|
|||
|
|
|||
|
First match each formal parameter name with its declaration.
|
|||
|
Associate decls with the names and store the decls
|
|||
|
into the TREE_PURPOSE slots. */
|
|||
|
|
|||
|
for (parm = parmdecls; parm; parm = TREE_CHAIN (parm))
|
|||
|
DECL_RESULT (parm) = 0;
|
|||
|
|
|||
|
for (parm = specparms; parm; parm = TREE_CHAIN (parm))
|
|||
|
{
|
|||
|
register tree tail, found = NULL;
|
|||
|
|
|||
|
if (TREE_VALUE (parm) == 0)
|
|||
|
{
|
|||
|
error_with_decl (fndecl, "parameter name missing from parameter list");
|
|||
|
TREE_PURPOSE (parm) = 0;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
/* See if any of the parmdecls specifies this parm by name.
|
|||
|
Ignore any enumerator decls. */
|
|||
|
for (tail = parmdecls; tail; tail = TREE_CHAIN (tail))
|
|||
|
if (DECL_NAME (tail) == TREE_VALUE (parm)
|
|||
|
&& TREE_CODE (tail) == PARM_DECL)
|
|||
|
{
|
|||
|
found = tail;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
/* If declaration already marked, we have a duplicate name.
|
|||
|
Complain, and don't use this decl twice. */
|
|||
|
if (found && DECL_RESULT (found) != 0)
|
|||
|
{
|
|||
|
error_with_decl (found, "multiple parameters named `%s'");
|
|||
|
found = 0;
|
|||
|
}
|
|||
|
|
|||
|
/* If the declaration says "void", complain and ignore it. */
|
|||
|
if (found && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == void_type_node)
|
|||
|
{
|
|||
|
error_with_decl (found, "parameter `%s' declared void");
|
|||
|
TREE_TYPE (found) = integer_type_node;
|
|||
|
DECL_ARG_TYPE (found) = integer_type_node;
|
|||
|
layout_decl (found, 0);
|
|||
|
}
|
|||
|
|
|||
|
/* Traditionally, a parm declared float is actually a double. */
|
|||
|
if (found && flag_traditional
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_TYPE (found)) == float_type_node)
|
|||
|
{
|
|||
|
TREE_TYPE (found) = double_type_node;
|
|||
|
DECL_ARG_TYPE (found) = double_type_node;
|
|||
|
layout_decl (found, 0);
|
|||
|
}
|
|||
|
|
|||
|
/* If no declaration found, default to int. */
|
|||
|
if (!found)
|
|||
|
{
|
|||
|
found = build_decl (PARM_DECL, TREE_VALUE (parm),
|
|||
|
integer_type_node);
|
|||
|
DECL_ARG_TYPE (found) = TREE_TYPE (found);
|
|||
|
DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl);
|
|||
|
DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl);
|
|||
|
if (extra_warnings)
|
|||
|
warning_with_decl (found, "type of `%s' defaults to `int'");
|
|||
|
pushdecl (found);
|
|||
|
}
|
|||
|
|
|||
|
TREE_PURPOSE (parm) = found;
|
|||
|
|
|||
|
/* Mark this decl as "already found" -- see test, above.
|
|||
|
It is safe to use DECL_RESULT for this
|
|||
|
since it is not used in PARM_DECLs or CONST_DECLs. */
|
|||
|
DECL_RESULT (found) = error_mark_node;
|
|||
|
}
|
|||
|
|
|||
|
/* Put anything which is on the parmdecls chain and which is
|
|||
|
not a PARM_DECL onto the list NONPARMS. (The types of
|
|||
|
non-parm things which might appear on the list include
|
|||
|
enumerators and NULL-named TYPE_DECL nodes.) Complain about
|
|||
|
any actual PARM_DECLs not matched with any names. */
|
|||
|
|
|||
|
nonparms = 0;
|
|||
|
for (parm = parmdecls; parm; )
|
|||
|
{
|
|||
|
tree next = TREE_CHAIN (parm);
|
|||
|
TREE_CHAIN (parm) = 0;
|
|||
|
|
|||
|
if (TREE_CODE (parm) != PARM_DECL)
|
|||
|
nonparms = chainon (nonparms, parm);
|
|||
|
else
|
|||
|
{
|
|||
|
/* Complain about args with incomplete types. */
|
|||
|
if (TYPE_SIZE (TREE_TYPE (parm)) == 0)
|
|||
|
{
|
|||
|
error_with_decl (parm, "parameter `%s' has incomplete type");
|
|||
|
TREE_TYPE (parm) = error_mark_node;
|
|||
|
}
|
|||
|
|
|||
|
if (DECL_RESULT (parm) == 0)
|
|||
|
{
|
|||
|
error_with_decl (parm,
|
|||
|
"declaration for parameter `%s' but no such parameter");
|
|||
|
/* Pretend the parameter was not missing.
|
|||
|
This gets us to a standard state and minimizes
|
|||
|
further error messages. */
|
|||
|
specparms
|
|||
|
= chainon (specparms,
|
|||
|
tree_cons (parm, NULL_TREE, NULL_TREE));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
parm = next;
|
|||
|
}
|
|||
|
|
|||
|
/* Chain the declarations together in the order of the list of names. */
|
|||
|
/* Store that chain in the function decl, replacing the list of names. */
|
|||
|
parm = specparms;
|
|||
|
DECL_ARGUMENTS (fndecl) = 0;
|
|||
|
{
|
|||
|
register tree last;
|
|||
|
for (last = 0; parm; parm = TREE_CHAIN (parm))
|
|||
|
if (TREE_PURPOSE (parm))
|
|||
|
{
|
|||
|
if (last == 0)
|
|||
|
DECL_ARGUMENTS (fndecl) = TREE_PURPOSE (parm);
|
|||
|
else
|
|||
|
TREE_CHAIN (last) = TREE_PURPOSE (parm);
|
|||
|
last = TREE_PURPOSE (parm);
|
|||
|
TREE_CHAIN (last) = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* If there was a previous prototype,
|
|||
|
set the DECL_ARG_TYPE of each argument according to
|
|||
|
the type previously specified, and report any mismatches. */
|
|||
|
|
|||
|
if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
|
|||
|
{
|
|||
|
register tree type;
|
|||
|
for (parm = DECL_ARGUMENTS (fndecl),
|
|||
|
type = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
|
|||
|
parm || (type && (TYPE_MAIN_VARIANT (TREE_VALUE (type))
|
|||
|
!= void_type_node));
|
|||
|
parm = TREE_CHAIN (parm), type = TREE_CHAIN (type))
|
|||
|
{
|
|||
|
if (parm == 0 || type == 0
|
|||
|
|| TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
|
|||
|
{
|
|||
|
error ("number of arguments doesn't match prototype");
|
|||
|
error_with_file_and_line (current_function_prototype_file,
|
|||
|
current_function_prototype_line,
|
|||
|
"prototype declaration");
|
|||
|
break;
|
|||
|
}
|
|||
|
/* Type for passing arg must be consistent
|
|||
|
with that declared for the arg. */
|
|||
|
if (! comptypes (DECL_ARG_TYPE (parm), TREE_VALUE (type)))
|
|||
|
{
|
|||
|
if (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
|
|||
|
== TYPE_MAIN_VARIANT (TREE_VALUE (type)))
|
|||
|
{
|
|||
|
/* Adjust argument to match prototype. E.g. a previous
|
|||
|
`int foo(float);' prototype causes
|
|||
|
`int foo(x) float x; {...}' to be treated like
|
|||
|
`int foo(float x) {...}'. This is particularly
|
|||
|
useful for argument types like uid_t. */
|
|||
|
DECL_ARG_TYPE (parm) = TREE_TYPE (parm);
|
|||
|
#ifdef PROMOTE_PROTOTYPES
|
|||
|
if ((TREE_CODE (TREE_TYPE (parm)) == INTEGER_TYPE
|
|||
|
|| TREE_CODE (TREE_TYPE (parm)) == ENUMERAL_TYPE)
|
|||
|
&& TYPE_PRECISION (TREE_TYPE (parm))
|
|||
|
< TYPE_PRECISION (integer_type_node))
|
|||
|
DECL_ARG_TYPE (parm) = integer_type_node;
|
|||
|
#endif
|
|||
|
if (pedantic)
|
|||
|
{
|
|||
|
pedwarn ("promoted argument `%s' doesn't match prototype",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parm)));
|
|||
|
warning_with_file_and_line
|
|||
|
(current_function_prototype_file,
|
|||
|
current_function_prototype_line,
|
|||
|
"prototype declaration");
|
|||
|
}
|
|||
|
}
|
|||
|
/* If -traditional, allow `int' argument to match
|
|||
|
`unsigned' prototype. */
|
|||
|
else if (! (flag_traditional
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == integer_type_node
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_VALUE (type)) == unsigned_type_node))
|
|||
|
{
|
|||
|
error ("argument `%s' doesn't match prototype",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parm)));
|
|||
|
error_with_file_and_line (current_function_prototype_file,
|
|||
|
current_function_prototype_line,
|
|||
|
"prototype declaration");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = 0;
|
|||
|
}
|
|||
|
|
|||
|
/* Otherwise, create a prototype that would match. */
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
tree actual = 0, last = 0, type;
|
|||
|
|
|||
|
for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm))
|
|||
|
{
|
|||
|
type = perm_tree_cons (NULL_TREE, DECL_ARG_TYPE (parm),
|
|||
|
NULL_TREE);
|
|||
|
if (last)
|
|||
|
TREE_CHAIN (last) = type;
|
|||
|
else
|
|||
|
actual = type;
|
|||
|
last = type;
|
|||
|
}
|
|||
|
type = perm_tree_cons (NULL_TREE, void_type_node, NULL_TREE);
|
|||
|
if (last)
|
|||
|
TREE_CHAIN (last) = type;
|
|||
|
else
|
|||
|
actual = type;
|
|||
|
|
|||
|
/* We are going to assign a new value for the TYPE_ACTUAL_ARG_TYPES
|
|||
|
of the type of this function, but we need to avoid having this
|
|||
|
affect the types of other similarly-typed functions, so we must
|
|||
|
first force the generation of an identical (but separate) type
|
|||
|
node for the relevant function type. The new node we create
|
|||
|
will be a variant of the main variant of the original function
|
|||
|
type. */
|
|||
|
|
|||
|
TREE_TYPE (fndecl) = build_type_copy (TREE_TYPE (fndecl));
|
|||
|
|
|||
|
TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual;
|
|||
|
}
|
|||
|
|
|||
|
/* Now store the final chain of decls for the arguments
|
|||
|
as the decl-chain of the current lexical scope.
|
|||
|
Put the enumerators in as well, at the front so that
|
|||
|
DECL_ARGUMENTS is not modified. */
|
|||
|
|
|||
|
storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
|
|||
|
}
|
|||
|
|
|||
|
/* Make sure the binding level for the top of the function body
|
|||
|
gets a BLOCK if there are any in the function.
|
|||
|
Otherwise, the dbx output is wrong. */
|
|||
|
|
|||
|
keep_next_if_subblocks = 1;
|
|||
|
|
|||
|
/* ??? This might be an improvement,
|
|||
|
but needs to be thought about some more. */
|
|||
|
#if 0
|
|||
|
keep_next_level_flag = 1;
|
|||
|
#endif
|
|||
|
|
|||
|
/* Write a record describing this function definition to the prototypes
|
|||
|
file (if requested). */
|
|||
|
|
|||
|
gen_aux_info_record (fndecl, 1, 0, prototype);
|
|||
|
|
|||
|
/* Initialize the RTL code for the function. */
|
|||
|
|
|||
|
init_function_start (fndecl, input_filename, lineno);
|
|||
|
|
|||
|
/* If this is a varargs function, inform function.c. */
|
|||
|
|
|||
|
if (c_function_varargs)
|
|||
|
mark_varargs ();
|
|||
|
|
|||
|
/* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */
|
|||
|
|
|||
|
declare_function_name ();
|
|||
|
|
|||
|
/* Set up parameters and prepare for return, for the function. */
|
|||
|
|
|||
|
expand_function_start (fndecl, 0);
|
|||
|
|
|||
|
/* If this function is `main', emit a call to `__main'
|
|||
|
to run global initializers, etc. */
|
|||
|
if (DECL_NAME (fndecl)
|
|||
|
&& strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0
|
|||
|
&& DECL_CONTEXT (fndecl) == NULL_TREE)
|
|||
|
expand_main_function ();
|
|||
|
}
|
|||
|
|
|||
|
/* SPECPARMS is an identifier list--a chain of TREE_LIST nodes
|
|||
|
each with a parm name as the TREE_VALUE. A null pointer as TREE_VALUE
|
|||
|
stands for an ellipsis in the identifier list.
|
|||
|
|
|||
|
PARMLIST is the data returned by get_parm_info for the
|
|||
|
parmlist that follows the semicolon.
|
|||
|
|
|||
|
We return a value of the same sort that get_parm_info returns,
|
|||
|
except that it describes the combination of identifiers and parmlist. */
|
|||
|
|
|||
|
tree
|
|||
|
combine_parm_decls (specparms, parmlist, void_at_end)
|
|||
|
tree specparms, parmlist;
|
|||
|
int void_at_end;
|
|||
|
{
|
|||
|
register tree fndecl = current_function_decl;
|
|||
|
register tree parm;
|
|||
|
|
|||
|
tree parmdecls = TREE_PURPOSE (parmlist);
|
|||
|
|
|||
|
/* This is a chain of any other decls that came in among the parm
|
|||
|
declarations. They were separated already by get_parm_info,
|
|||
|
so we just need to keep them separate. */
|
|||
|
tree nonparms = TREE_VALUE (parmlist);
|
|||
|
|
|||
|
tree types = 0;
|
|||
|
|
|||
|
for (parm = parmdecls; parm; parm = TREE_CHAIN (parm))
|
|||
|
DECL_RESULT (parm) = 0;
|
|||
|
|
|||
|
for (parm = specparms; parm; parm = TREE_CHAIN (parm))
|
|||
|
{
|
|||
|
register tree tail, found = NULL;
|
|||
|
|
|||
|
/* See if any of the parmdecls specifies this parm by name. */
|
|||
|
for (tail = parmdecls; tail; tail = TREE_CHAIN (tail))
|
|||
|
if (DECL_NAME (tail) == TREE_VALUE (parm))
|
|||
|
{
|
|||
|
found = tail;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
/* If declaration already marked, we have a duplicate name.
|
|||
|
Complain, and don't use this decl twice. */
|
|||
|
if (found && DECL_RESULT (found) != 0)
|
|||
|
{
|
|||
|
error_with_decl (found, "multiple parameters named `%s'");
|
|||
|
found = 0;
|
|||
|
}
|
|||
|
|
|||
|
/* If the declaration says "void", complain and ignore it. */
|
|||
|
if (found && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == void_type_node)
|
|||
|
{
|
|||
|
error_with_decl (found, "parameter `%s' declared void");
|
|||
|
TREE_TYPE (found) = integer_type_node;
|
|||
|
DECL_ARG_TYPE (found) = integer_type_node;
|
|||
|
layout_decl (found, 0);
|
|||
|
}
|
|||
|
|
|||
|
/* Traditionally, a parm declared float is actually a double. */
|
|||
|
if (found && flag_traditional
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_TYPE (found)) == float_type_node)
|
|||
|
{
|
|||
|
TREE_TYPE (found) = double_type_node;
|
|||
|
DECL_ARG_TYPE (found) = double_type_node;
|
|||
|
layout_decl (found, 0);
|
|||
|
}
|
|||
|
|
|||
|
/* If no declaration found, default to int. */
|
|||
|
if (!found)
|
|||
|
{
|
|||
|
found = build_decl (PARM_DECL, TREE_VALUE (parm),
|
|||
|
integer_type_node);
|
|||
|
DECL_ARG_TYPE (found) = TREE_TYPE (found);
|
|||
|
DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl);
|
|||
|
DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl);
|
|||
|
error_with_decl (found, "type of parameter `%s' is not declared");
|
|||
|
pushdecl (found);
|
|||
|
}
|
|||
|
|
|||
|
TREE_PURPOSE (parm) = found;
|
|||
|
|
|||
|
/* Mark this decl as "already found" -- see test, above.
|
|||
|
It is safe to use DECL_RESULT for this
|
|||
|
since it is not used in PARM_DECLs or CONST_DECLs. */
|
|||
|
DECL_RESULT (found) = error_mark_node;
|
|||
|
}
|
|||
|
|
|||
|
/* Complain about any actual PARM_DECLs not matched with any names. */
|
|||
|
|
|||
|
for (parm = parmdecls; parm; )
|
|||
|
{
|
|||
|
tree next = TREE_CHAIN (parm);
|
|||
|
TREE_CHAIN (parm) = 0;
|
|||
|
|
|||
|
/* Complain about args with incomplete types. */
|
|||
|
if (TYPE_SIZE (TREE_TYPE (parm)) == 0)
|
|||
|
{
|
|||
|
error_with_decl (parm, "parameter `%s' has incomplete type");
|
|||
|
TREE_TYPE (parm) = error_mark_node;
|
|||
|
}
|
|||
|
|
|||
|
if (DECL_RESULT (parm) == 0)
|
|||
|
{
|
|||
|
error_with_decl (parm,
|
|||
|
"declaration for parameter `%s' but no such parameter");
|
|||
|
/* Pretend the parameter was not missing.
|
|||
|
This gets us to a standard state and minimizes
|
|||
|
further error messages. */
|
|||
|
specparms
|
|||
|
= chainon (specparms,
|
|||
|
tree_cons (parm, NULL_TREE, NULL_TREE));
|
|||
|
}
|
|||
|
|
|||
|
parm = next;
|
|||
|
}
|
|||
|
|
|||
|
/* Chain the declarations together in the order of the list of names.
|
|||
|
At the same time, build up a list of their types, in reverse order. */
|
|||
|
|
|||
|
parm = specparms;
|
|||
|
parmdecls = 0;
|
|||
|
{
|
|||
|
register tree last;
|
|||
|
for (last = 0; parm; parm = TREE_CHAIN (parm))
|
|||
|
if (TREE_PURPOSE (parm))
|
|||
|
{
|
|||
|
if (last == 0)
|
|||
|
parmdecls = TREE_PURPOSE (parm);
|
|||
|
else
|
|||
|
TREE_CHAIN (last) = TREE_PURPOSE (parm);
|
|||
|
last = TREE_PURPOSE (parm);
|
|||
|
TREE_CHAIN (last) = 0;
|
|||
|
|
|||
|
types = saveable_tree_cons (NULL_TREE, TREE_TYPE (parm), types);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (void_at_end)
|
|||
|
return saveable_tree_cons (parmdecls, nonparms,
|
|||
|
nreverse (saveable_tree_cons (NULL_TREE,
|
|||
|
void_type_node,
|
|||
|
types)));
|
|||
|
|
|||
|
return saveable_tree_cons (parmdecls, nonparms, nreverse (types));
|
|||
|
}
|
|||
|
|
|||
|
/* Finish up a function declaration and compile that function
|
|||
|
all the way to assembler language output. The free the storage
|
|||
|
for the function definition.
|
|||
|
|
|||
|
This is called after parsing the body of the function definition.
|
|||
|
|
|||
|
NESTED is nonzero if the function being finished is nested in another. */
|
|||
|
|
|||
|
void
|
|||
|
finish_function (nested)
|
|||
|
int nested;
|
|||
|
{
|
|||
|
register tree fndecl = current_function_decl;
|
|||
|
|
|||
|
/* TREE_READONLY (fndecl) = 1;
|
|||
|
This caused &foo to be of type ptr-to-const-function
|
|||
|
which then got a warning when stored in a ptr-to-function variable. */
|
|||
|
|
|||
|
poplevel (1, 0, 1);
|
|||
|
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
|
|||
|
|
|||
|
/* Must mark the RESULT_DECL as being in this function. */
|
|||
|
|
|||
|
DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
|
|||
|
|
|||
|
/* Obey `register' declarations if `setjmp' is called in this fn. */
|
|||
|
if (flag_traditional && current_function_calls_setjmp)
|
|||
|
{
|
|||
|
setjmp_protect (DECL_INITIAL (fndecl));
|
|||
|
setjmp_protect_args ();
|
|||
|
}
|
|||
|
|
|||
|
if (! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main"))
|
|||
|
{
|
|||
|
if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
|
|||
|
!= integer_type_node)
|
|||
|
{
|
|||
|
/* You would expect the sense of this test to be the other way
|
|||
|
around, but if warn_main is set, we will already have warned,
|
|||
|
so this would be a duplicate. This is the warning you get
|
|||
|
in some environments even if you *don't* ask for it, because
|
|||
|
these are environments where it may be more of a problem than
|
|||
|
usual. */
|
|||
|
if (! warn_main)
|
|||
|
pedwarn_with_decl (fndecl, "return type of `%s' is not `int'");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#ifdef DEFAULT_MAIN_RETURN
|
|||
|
/* Make it so that `main' always returns success by default. */
|
|||
|
DEFAULT_MAIN_RETURN;
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Generate rtl for function exit. */
|
|||
|
expand_function_end (input_filename, lineno, 0);
|
|||
|
|
|||
|
/* So we can tell if jump_optimize sets it to 1. */
|
|||
|
can_reach_end = 0;
|
|||
|
|
|||
|
/* Run the optimizers and output the assembler code for this function. */
|
|||
|
rest_of_compilation (fndecl);
|
|||
|
|
|||
|
current_function_returns_null |= can_reach_end;
|
|||
|
|
|||
|
if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
|
|||
|
warning ("`noreturn' function does return");
|
|||
|
else if (warn_return_type && can_reach_end
|
|||
|
&& TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) != void_type_node)
|
|||
|
/* If this function returns non-void and control can drop through,
|
|||
|
complain. */
|
|||
|
warning ("control reaches end of non-void function");
|
|||
|
/* With just -W, complain only if function returns both with
|
|||
|
and without a value. */
|
|||
|
else if (extra_warnings
|
|||
|
&& current_function_returns_value && current_function_returns_null)
|
|||
|
warning ("this function may return with or without a value");
|
|||
|
|
|||
|
/* If requested, warn about function definitions where the function will
|
|||
|
return a value (usually of some struct or union type) which itself will
|
|||
|
take up a lot of stack space. */
|
|||
|
|
|||
|
if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl))
|
|||
|
{
|
|||
|
register tree ret_type = TREE_TYPE (TREE_TYPE (fndecl));
|
|||
|
|
|||
|
if (ret_type)
|
|||
|
{
|
|||
|
register tree ret_type_size = TYPE_SIZE (ret_type);
|
|||
|
|
|||
|
if (TREE_CODE (ret_type_size) == INTEGER_CST)
|
|||
|
{
|
|||
|
unsigned units
|
|||
|
= TREE_INT_CST_LOW (ret_type_size) / BITS_PER_UNIT;
|
|||
|
|
|||
|
if (units > larger_than_size)
|
|||
|
warning_with_decl (fndecl,
|
|||
|
"size of return value of `%s' is %u bytes",
|
|||
|
units);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Free all the tree nodes making up this function. */
|
|||
|
/* Switch back to allocating nodes permanently
|
|||
|
until we start another function. */
|
|||
|
if (! nested)
|
|||
|
permanent_allocation (1);
|
|||
|
|
|||
|
if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested)
|
|||
|
{
|
|||
|
/* Stop pointing to the local nodes about to be freed. */
|
|||
|
/* But DECL_INITIAL must remain nonzero so we know this
|
|||
|
was an actual function definition. */
|
|||
|
/* For a nested function, this is done in pop_c_function_context. */
|
|||
|
/* If rest_of_compilation set this to 0, leave it 0. */
|
|||
|
if (DECL_INITIAL (fndecl) != 0)
|
|||
|
DECL_INITIAL (fndecl) = error_mark_node;
|
|||
|
DECL_ARGUMENTS (fndecl) = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (DECL_STATIC_CONSTRUCTOR (fndecl))
|
|||
|
{
|
|||
|
#ifndef ASM_OUTPUT_CONSTRUCTOR
|
|||
|
if (! flag_gnu_linker)
|
|||
|
static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors);
|
|||
|
else
|
|||
|
#endif
|
|||
|
assemble_constructor (IDENTIFIER_POINTER (DECL_NAME (fndecl)));
|
|||
|
}
|
|||
|
if (DECL_STATIC_DESTRUCTOR (fndecl))
|
|||
|
{
|
|||
|
#ifndef ASM_OUTPUT_DESTRUCTOR
|
|||
|
if (! flag_gnu_linker)
|
|||
|
static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors);
|
|||
|
else
|
|||
|
#endif
|
|||
|
assemble_destructor (IDENTIFIER_POINTER (DECL_NAME (fndecl)));
|
|||
|
}
|
|||
|
|
|||
|
if (! nested)
|
|||
|
{
|
|||
|
/* Let the error reporting routines know that we're outside a
|
|||
|
function. For a nested function, this value is used in
|
|||
|
pop_c_function_context and then reset via pop_function_context. */
|
|||
|
current_function_decl = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Save and restore the variables in this file and elsewhere
|
|||
|
that keep track of the progress of compilation of the current function.
|
|||
|
Used for nested functions. */
|
|||
|
|
|||
|
struct c_function
|
|||
|
{
|
|||
|
struct c_function *next;
|
|||
|
tree named_labels;
|
|||
|
tree shadowed_labels;
|
|||
|
int returns_value;
|
|||
|
int returns_null;
|
|||
|
int warn_about_return_type;
|
|||
|
int extern_inline;
|
|||
|
struct binding_level *binding_level;
|
|||
|
};
|
|||
|
|
|||
|
struct c_function *c_function_chain;
|
|||
|
|
|||
|
/* Save and reinitialize the variables
|
|||
|
used during compilation of a C function. */
|
|||
|
|
|||
|
void
|
|||
|
push_c_function_context ()
|
|||
|
{
|
|||
|
struct c_function *p
|
|||
|
= (struct c_function *) xmalloc (sizeof (struct c_function));
|
|||
|
|
|||
|
if (pedantic)
|
|||
|
pedwarn ("ANSI C forbids nested functions");
|
|||
|
|
|||
|
push_function_context ();
|
|||
|
|
|||
|
p->next = c_function_chain;
|
|||
|
c_function_chain = p;
|
|||
|
|
|||
|
p->named_labels = named_labels;
|
|||
|
p->shadowed_labels = shadowed_labels;
|
|||
|
p->returns_value = current_function_returns_value;
|
|||
|
p->returns_null = current_function_returns_null;
|
|||
|
p->warn_about_return_type = warn_about_return_type;
|
|||
|
p->extern_inline = current_extern_inline;
|
|||
|
p->binding_level = current_binding_level;
|
|||
|
}
|
|||
|
|
|||
|
/* Restore the variables used during compilation of a C function. */
|
|||
|
|
|||
|
void
|
|||
|
pop_c_function_context ()
|
|||
|
{
|
|||
|
struct c_function *p = c_function_chain;
|
|||
|
tree link;
|
|||
|
|
|||
|
/* Bring back all the labels that were shadowed. */
|
|||
|
for (link = shadowed_labels; link; link = TREE_CHAIN (link))
|
|||
|
if (DECL_NAME (TREE_VALUE (link)) != 0)
|
|||
|
IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)))
|
|||
|
= TREE_VALUE (link);
|
|||
|
|
|||
|
if (DECL_SAVED_INSNS (current_function_decl) == 0)
|
|||
|
{
|
|||
|
/* Stop pointing to the local nodes about to be freed. */
|
|||
|
/* But DECL_INITIAL must remain nonzero so we know this
|
|||
|
was an actual function definition. */
|
|||
|
DECL_INITIAL (current_function_decl) = error_mark_node;
|
|||
|
DECL_ARGUMENTS (current_function_decl) = 0;
|
|||
|
}
|
|||
|
|
|||
|
pop_function_context ();
|
|||
|
|
|||
|
c_function_chain = p->next;
|
|||
|
|
|||
|
named_labels = p->named_labels;
|
|||
|
shadowed_labels = p->shadowed_labels;
|
|||
|
current_function_returns_value = p->returns_value;
|
|||
|
current_function_returns_null = p->returns_null;
|
|||
|
warn_about_return_type = p->warn_about_return_type;
|
|||
|
current_extern_inline = p->extern_inline;
|
|||
|
current_binding_level = p->binding_level;
|
|||
|
|
|||
|
free (p);
|
|||
|
}
|
|||
|
|
|||
|
/* integrate_decl_tree calls this function, but since we don't use the
|
|||
|
DECL_LANG_SPECIFIC field, this is a no-op. */
|
|||
|
|
|||
|
void
|
|||
|
copy_lang_decl (node)
|
|||
|
tree node;
|
|||
|
{
|
|||
|
}
|