/* Process declarations and variables for C compiler.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002 Free Software Foundation, Inc.
+ 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "intl.h"
#include "tree.h"
#include "tree-inline.h"
#include "output.h"
#include "expr.h"
#include "c-tree.h"
-#include "c-lex.h"
#include "toplev.h"
#include "ggc.h"
#include "tm_p.h"
#include "timevar.h"
#include "c-common.h"
#include "c-pragma.h"
+#include "cgraph.h"
+#include "hashtab.h"
+#include "libfuncs.h"
+#include "except.h"
/* In grokdeclarator, distinguish syntactic contexts of declarators. */
enum decl_context
tree pending_invalid_xref;
/* File and line to appear in the eventual error message. */
-const char *pending_invalid_xref_file;
-int pending_invalid_xref_line;
+location_t pending_invalid_xref_location;
/* 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'
/* Similar, for the file and line that the prototype came from if this is
an old-style definition. */
-static const char *current_function_prototype_file;
-static int current_function_prototype_line;
+static location_t current_function_prototype_locus;
/* The current statement tree. */
-static struct stmt_tree_s c_stmt_tree;
+static GTY(()) struct stmt_tree_s c_stmt_tree;
/* The current scope statement stack. */
-static tree c_scope_stmt_stack;
+static GTY(()) tree c_scope_stmt_stack;
/* 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;
+static GTY(()) tree named_labels;
/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */
-static tree shadowed_labels;
+static GTY(()) 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;
+/* A list of external DECLs that appeared at block scope when there was
+ some other global meaning for that identifier. */
+static GTY(()) tree truly_local_externals;
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */
* 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
+struct binding_level GTY(())
{
/* A chain of _DECL nodes for all variables, constants, functions,
and typedef types. These are in the reverse of the order supplied.
*/
tree tags;
- /* For each level, a list of shadowed outer-level local definitions
+ /* For each level, a list of shadowed outer-level 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, a list of shadowed outer-level tag 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 ..._TYPE node). */
+ tree shadowed_tags;
+
/* 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. */
+ /* Nonzero if we are currently filling this level with parameter
+ declarations. */
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 if this is the outermost block scope of a function body.
+ This scope contains both the parameters and the local variables
+ declared in the outermost block. */
+ char function_body;
/* 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;
+ /* List of decls in `names' that have incomplete structure or
+ union types. */
+ tree incomplete_list;
/* A list of decls giving the (reversed) specified order of parms,
not including any forward-decls in the parmlist.
/* The binding level currently in effect. */
-static struct binding_level *current_binding_level;
+static GTY(()) struct binding_level *current_binding_level;
/* A chain of binding_level structures awaiting reuse. */
-static struct binding_level *free_binding_level;
+static GTY((deletable (""))) 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};
+static GTY(()) struct binding_level *global_binding_level;
/* Nonzero means unconditionally make a BLOCK for the next level pushed. */
saved values of named_labels and shadowed_labels for
a label binding level outside the current one. */
-static struct binding_level *label_level_chain;
+static GTY(()) struct binding_level *label_level_chain;
/* Functions called automatically at the beginning and end of execution. */
/* Forward declarations. */
-static struct binding_level * make_binding_level PARAMS ((void));
-static void mark_binding_level PARAMS ((void *));
-static void clear_limbo_values PARAMS ((tree));
-static int duplicate_decls PARAMS ((tree, tree, int));
-static int redeclaration_error_message PARAMS ((tree, tree));
-static void storedecls PARAMS ((tree));
-static void storetags PARAMS ((tree));
-static tree lookup_tag PARAMS ((enum tree_code, tree,
- struct binding_level *, int));
-static tree lookup_tag_reverse PARAMS ((tree));
-static tree grokdeclarator PARAMS ((tree, tree, enum decl_context,
- int));
-static tree grokparms PARAMS ((tree, int));
-static void layout_array_type PARAMS ((tree));
-static tree c_make_fname_decl PARAMS ((tree, int));
-static void c_expand_body PARAMS ((tree, int, int));
-static void warn_if_shadowing PARAMS ((tree, tree));
+static struct binding_level *make_binding_level (void);
+static void pop_binding_level (struct binding_level **);
+static int duplicate_decls (tree, tree, int);
+static int redeclaration_error_message (tree, tree);
+static void implicit_decl_warning (tree);
+static void storedecls (tree);
+static void storetags (tree);
+static tree lookup_tag (enum tree_code, tree, int);
+static tree lookup_name_current_level (tree);
+static tree grokdeclarator (tree, tree, enum decl_context, int);
+static tree grokparms (tree, int);
+static void layout_array_type (tree);
+static tree c_make_fname_decl (tree, int);
+static void c_expand_body_1 (tree, int);
+static tree any_external_decl (tree);
+static void record_external_decl (tree);
+static void warn_if_shadowing (tree, tree);
+static void clone_underlying_type (tree);
+static bool flexible_array_type_p (tree);
\f
-/* C-specific option variables. */
-
-/* Nonzero means allow type mismatches in conditional expressions;
- just make their values `void'. */
-
-int flag_cond_mismatch;
-
-/* Nonzero means don't recognize the keyword `asm'. */
-
-int flag_no_asm;
-
-/* Nonzero means enable C89 Amendment 1 features. */
-
-int flag_isoc94 = 0;
-
-/* Nonzero means use the ISO C99 dialect of C. */
-
-int flag_isoc99 = 0;
-
-/* Nonzero means that we have builtin functions, and main is an int */
-
-int flag_hosted = 1;
-
-/* Nonzero means add default format_arg attributes for functions not
- in ISO C. */
-
-int flag_noniso_default_format_attributes = 1;
-
-/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */
-
-int flag_signed_bitfields = 1;
-int explicit_flag_signed_bitfields = 0;
-
-/* Nonzero means warn about use of implicit int. */
-
-int warn_implicit_int;
-
-/* Nonzero means warn about usage of long long when `-pedantic'. */
-
-int warn_long_long = 1;
-
-/* Nonzero means message about use of implicit function declarations;
- 1 means warning; 2 means error. */
-
-int mesg_implicit_function_declaration = -1;
-
-/* 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 flag_const_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 functions which might be candidates for format attributes. */
-
-int warn_missing_format_attribute;
-
-/* 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 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 #pragma directives that are not recognised. */
-
-int warn_unknown_pragmas = 0; /* Tri state variable. */
-
-/* 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;
-
-/* Warn about testing equality of floating point numbers. */
-
-int warn_float_equal = 0;
-
-/* Nonzero means `$' can be in an identifier. */
-
-#ifndef DOLLARS_IN_IDENTIFIERS
-#define DOLLARS_IN_IDENTIFIERS 1
-#endif
-int dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
-
/* States indicating how grokdeclarator() should handle declspecs marked
with __attribute__((deprecated)). An object declared as
__attribute__((deprecated)) suppresses warnings of uses of other
deprecated items. */
-
+
enum deprecated_states {
DEPRECATED_NORMAL,
DEPRECATED_SUPPRESS
static enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
-/* Decode the string P as a language-specific option for C.
- Return the number of strings consumed. Should not complain
- if it does not recognise the option. */
-
-int
-c_decode_option (argc, argv)
- int argc ATTRIBUTE_UNUSED;
- char **argv;
-{
- int strings_processed;
- char *p = argv[0];
-
- static const struct {
- /* The name of the option. */
- const char *option;
- /* If non-NULL, a flag variable to set to 0 or 1. If NULL,
- this means that cpp handles this option. */
- int *flag;
- } warn_options[] = {
- /* This list is in alphabetical order. Keep it like that. */
- { "bad-function-cast", &warn_bad_function_cast },
- { "cast-qual", &warn_cast_qual },
- { "char-subscripts", &warn_char_subscripts },
- { "comment", NULL },
- { "comments", NULL },
- { "conversion", &warn_conversion },
- { "div-by-zero", &warn_div_by_zero },
- { "float-equal", &warn_float_equal },
- { "format-extra-args", &warn_format_extra_args },
- { "format-nonliteral", &warn_format_nonliteral },
- { "format-security", &warn_format_security },
- { "format-y2k", &warn_format_y2k },
- { "implicit-function-declaration", &mesg_implicit_function_declaration },
- { "implicit-int", &warn_implicit_int },
- { "import", NULL },
- { "long-long", &warn_long_long },
- { "main", &warn_main },
- { "missing-braces", &warn_missing_braces },
- { "missing-declarations", &warn_missing_declarations },
- { "missing-format-attribute", &warn_missing_format_attribute },
- { "missing-prototypes", &warn_missing_prototypes },
- { "multichar", &warn_multichar },
- { "nested-externs", &warn_nested_externs },
- { "parentheses", &warn_parentheses },
- { "pointer-arith", &warn_pointer_arith },
- { "redundant-decls", &warn_redundant_decls },
- { "return-type", &warn_return_type },
- { "sequence-point", &warn_sequence_point },
- { "sign-compare", &warn_sign_compare },
- { "strict-prototypes", &warn_strict_prototypes },
- { "traditional", &warn_traditional },
- { "trigraphs", NULL },
- { "undef", NULL },
- { "write-strings", &flag_const_strings }
- };
-
- strings_processed = cpp_handle_option (parse_in, argc, argv, 0);
-
- 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 (!strncmp (p, "-std=", 5))
- {
- /* Select the appropriate language standard. We currently
- recognize:
- -std=iso9899:1990 same as -ansi
- -std=iso9899:199409 ISO C as modified in amend. 1
- -std=iso9899:1999 ISO C 99
- -std=c89 same as -std=iso9899:1990
- -std=c99 same as -std=iso9899:1999
- -std=gnu89 default, iso9899:1990 + gnu extensions
- -std=gnu99 iso9899:1999 + gnu extensions
- */
- const char *const argstart = &p[5];
-
- if (!strcmp (argstart, "iso9899:1990")
- || !strcmp (argstart, "c89"))
- {
- iso_1990:
- flag_isoc94 = 0;
- iso_1994:
- flag_writable_strings = 0;
- flag_no_asm = 1;
- flag_no_nonansi_builtin = 1;
- flag_noniso_default_format_attributes = 0;
- flag_isoc99 = 0;
- flag_iso = 1;
- }
- else if (!strcmp (argstart, "iso9899:199409"))
- {
- flag_isoc94 = 1;
- goto iso_1994;
- }
- else if (!strcmp (argstart, "iso9899:199x")
- || !strcmp (argstart, "iso9899:1999")
- || !strcmp (argstart, "c9x")
- || !strcmp (argstart, "c99"))
- {
- flag_writable_strings = 0;
- flag_no_asm = 1;
- flag_no_nonansi_builtin = 1;
- flag_noniso_default_format_attributes = 0;
- flag_isoc99 = 1;
- flag_isoc94 = 1;
- flag_iso = 1;
- }
- else if (!strcmp (argstart, "gnu89"))
- {
- flag_writable_strings = 0;
- flag_no_asm = 0;
- flag_no_nonansi_builtin = 0;
- flag_noniso_default_format_attributes = 1;
- flag_isoc99 = 0;
- flag_isoc94 = 0;
- }
- else if (!strcmp (argstart, "gnu9x") || !strcmp (argstart, "gnu99"))
- {
- flag_writable_strings = 0;
- flag_no_asm = 0;
- flag_no_nonansi_builtin = 0;
- flag_noniso_default_format_attributes = 1;
- flag_isoc99 = 1;
- flag_isoc94 = 1;
- }
- else if (!strcmp (argstart, "c++98"))
- ; /* Handled by cpplib. */
- else
- error ("unknown C standard `%s'", argstart);
- }
- else if (!strcmp (p, "-fdollars-in-identifiers"))
- dollars_in_ident = 1;
- else if (!strcmp (p, "-fno-dollars-in-identifiers"))
- 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, "-fshort-wchar"))
- flag_short_wchar = 1;
- else if (!strcmp (p, "-fno-short-wchar"))
- flag_short_wchar = 0;
- else if (!strcmp (p, "-fcond-mismatch"))
- flag_cond_mismatch = 1;
- else if (!strcmp (p, "-fno-cond-mismatch"))
- 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 (!strncmp (p, "-fno-builtin-", strlen ("-fno-builtin-")))
- disable_builtin_function (p + strlen ("-fno-builtin-"));
- else if (p[0] == '-' && p[1] == 'f' && dump_switch_p (p + 2))
- ;
- else if (!strcmp (p, "-ansi"))
- goto iso_1990;
- else if (!strcmp (p, "-undef"))
- flag_undef = 1;
- else if (!strcmp (p, "-Werror-implicit-function-declaration"))
- mesg_implicit_function_declaration = 2;
- else if (!strncmp (p, "-Wformat=", 9))
- set_Wformat (atoi (p + 9));
- else if (!strcmp (p, "-Wformat"))
- set_Wformat (1);
- else if (!strcmp (p, "-Wno-format"))
- set_Wformat (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, "-Wno-main"))
- warn_main = -1;
- else if (!strcmp (p, "-Wunknown-pragmas"))
- /* Set to greater than 1, so that even unknown pragmas in system
- headers will be warned about. */
- warn_unknown_pragmas = 2;
- else if (!strcmp (p, "-Wno-unknown-pragmas"))
- warn_unknown_pragmas = 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;
- set_Wunused (1);
- warn_switch = 1;
- set_Wformat (1);
- warn_char_subscripts = 1;
- warn_parentheses = 1;
- warn_sequence_point = 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;
- /* Only warn about unknown pragmas that are not in system headers. */
- warn_unknown_pragmas = 1;
- }
- else if (!strcmp (p, "-E"))
- flag_preprocess_only = 1;
- else
- {
- size_t i;
- for (i = 0; i < sizeof (warn_options) / sizeof (warn_options[0]); i++)
- if (strncmp (p, "-W", 2) == 0
- && warn_options[i].flag
- && (strcmp (p+2, warn_options[i].option) == 0
- || (strncmp (p+2, "no-", 3) == 0
- && strcmp (p+5, warn_options[i].option) == 0)))
- {
- *(warn_options[i].flag) = strncmp (p+2, "no-", 3) != 0;
- return 1;
- }
- return strings_processed;
- }
-
- return 1;
-}
-
void
-c_print_identifier (file, node, indent)
- FILE *file;
- tree node;
- int indent;
+c_print_identifier (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, "symbol", IDENTIFIER_SYMBOL_VALUE (node), indent + 4);
+ print_node (file, "tag", IDENTIFIER_TAG_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);
if (C_IS_RESERVED_WORD (node))
{
tree rid = ridpointers[C_RID_CODE (node)];
indent_to (file, indent + 4);
- fprintf (file, "rid ");
- fprintf (file, HOST_PTR_PRINTF, (void *)rid);
- fprintf (file, " \"%s\"", IDENTIFIER_POINTER (rid));
+ fprintf (file, "rid " HOST_PTR_PRINTF " \"%s\"",
+ (void *) rid, IDENTIFIER_POINTER (rid));
}
}
\f
for a top-level tentative array defn that wasn't complete before. */
void
-c_finish_incomplete_decl (decl)
- tree decl;
+c_finish_incomplete_decl (tree decl)
{
if (TREE_CODE (decl) == VAR_DECL)
{
}
}
\f
-/* Create a new `struct binding_level'. */
+/* Reuse or create a struct for this binding level. */
static struct binding_level *
-make_binding_level ()
+make_binding_level (void)
{
- /* NOSTRICT */
- return (struct binding_level *) xmalloc (sizeof (struct binding_level));
+ struct binding_level *result;
+ if (free_binding_level)
+ {
+ result = free_binding_level;
+ free_binding_level = result->level_chain;
+ memset (result, 0, sizeof(struct binding_level));
+ }
+ else
+ result = (struct binding_level *)
+ ggc_alloc_cleared (sizeof (struct binding_level));
+
+ return result;
+}
+
+/* Remove a binding level from a list and add it to the level chain. */
+
+static void
+pop_binding_level (struct binding_level **lp)
+{
+ struct binding_level *l = *lp;
+ *lp = l->level_chain;
+
+ memset (l, 0, sizeof (struct binding_level));
+ l->level_chain = free_binding_level;
+ free_binding_level = l;
}
/* Nonzero if we are currently in the global binding level. */
int
-global_bindings_p ()
+global_bindings_p (void)
{
return current_binding_level == global_binding_level;
}
void
-keep_next_level ()
+keep_next_level (void)
{
keep_next_level_flag = 1;
}
/* Nonzero if the current level needs to have a BLOCK made. */
int
-kept_level_p ()
+kept_level_p (void)
{
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));
+ || current_binding_level->tags != 0);
}
/* Identify this binding level as a level of parameters.
DEFINITION_FLAG, so we ignore it. */
void
-declare_parm_level (definition_flag)
- int definition_flag ATTRIBUTE_UNUSED;
+declare_parm_level (int definition_flag ATTRIBUTE_UNUSED)
{
current_binding_level->parm_flag = 1;
}
/* Nonzero if currently making parm declarations. */
int
-in_parm_level_p ()
+in_parm_level_p (void)
{
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. */
+/* Enter a new binding level. */
void
-pushlevel (tag_transparent)
- int tag_transparent;
+pushlevel (int dummy ATTRIBUTE_UNUSED)
{
- 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 this is the top level of a function, make sure that
+ NAMED_LABELS is 0. */
if (current_binding_level == global_binding_level)
+ named_labels = 0;
+
+ if (keep_next_if_subblocks)
{
- named_labels = 0;
- }
+ /* This is the transition from the parameters to the top level
+ of the function body. These are the same scope
+ (C99 6.2.1p4,6) so we do not push another binding level.
- /* Reuse or create a struct for this binding level. */
+ XXX Note kludge - keep_next_if_subblocks is set only by
+ store_parm_decls, which in turn is called when and only
+ when we are about to encounter the opening curly brace for
+ the function body. */
+ current_binding_level->parm_flag = 0;
+ current_binding_level->function_body = 1;
+ current_binding_level->keep |= keep_next_level_flag;
+ current_binding_level->keep_if_subblocks = 1;
- if (free_binding_level)
- {
- newlevel = free_binding_level;
- free_binding_level = free_binding_level->level_chain;
+ keep_next_level_flag = 0;
+ keep_next_if_subblocks = 0;
}
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. */
+ struct binding_level *newlevel = make_binding_level ();
-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);
+ newlevel->keep = keep_next_level_flag;
+ newlevel->level_chain = current_binding_level;
+ current_binding_level = newlevel;
+ keep_next_level_flag = 0;
+ }
}
/* Exit a binding level.
them into the BLOCK. */
tree
-poplevel (keep, reverse, functionbody)
- int keep;
- int reverse;
- int functionbody;
+poplevel (int keep, int reverse, int functionbody)
{
tree link;
- /* The chain of decls was accumulated in reverse order.
- Put it into forward order, just for cleanliness. */
- tree decls;
+ tree block;
+ tree decl;
+ tree decls = current_binding_level->names;
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;
+ functionbody |= current_binding_level->function_body;
+ keep |= (current_binding_level->keep || functionbody
+ || (current_binding_level->keep_if_subblocks && subblocks != 0));
- /* 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. */
+ /* We used to warn about unused variables in expand_end_bindings,
+ i.e. while generating RTL. But in function-at-a-time mode we may
+ choose to never expand a function at all (e.g. auto inlining), so
+ we do this explicitly now. */
+ warn_about_unused_variables (decls);
+
+ /* Clear out the name-meanings declared on this level.
+ Propagate TREE_ADDRESSABLE from nested functions to their
+ containing functions. */
+ for (link = decls; link; link = TREE_CHAIN (link))
+ {
+ if (DECL_NAME (link) != 0)
+ {
+ if (DECL_EXTERNAL (link))
+ /* External decls stay in the symbol-value slot but are
+ inaccessible. */
+ C_DECL_INVISIBLE (link) = 1;
+ else
+ IDENTIFIER_SYMBOL_VALUE (DECL_NAME (link)) = 0;
+ }
+
+ if (TREE_CODE (link) == FUNCTION_DECL
+ && ! TREE_ASM_WRITTEN (link)
+ && DECL_INITIAL (link) != 0
+ && TREE_ADDRESSABLE (link)
+ && DECL_ABSTRACT_ORIGIN (link) != 0
+ && DECL_ABSTRACT_ORIGIN (link) != link)
+ TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (link)) = 1;
+ }
+
+ /* Clear out the tag-meanings declared on this level. */
for (link = tags; link; link = TREE_CHAIN (link))
- if (!COMPLETE_TYPE_P (TREE_VALUE (link)))
- {
- tree type = TREE_VALUE (link);
- tree type_name = TYPE_NAME (type);
- char *id = IDENTIFIER_POINTER (TREE_CODE (type_name) == IDENTIFIER_NODE
- ? type_name
- : DECL_NAME (type_name));
- switch (TREE_CODE (type))
- {
- case RECORD_TYPE:
- error ("`struct %s' incomplete in scope ending here", id);
- break;
- case UNION_TYPE:
- error ("`union %s' incomplete in scope ending here", id);
- break;
- case ENUMERAL_TYPE:
- error ("`enum %s' incomplete in scope ending here", id);
- break;
- }
- }
-#endif /* 0 */
+ if (TREE_PURPOSE (link))
+ IDENTIFIER_TAG_VALUE (TREE_PURPOSE (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_SYMBOL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+
+ /* Restore all tag-meanings of the outer levels
+ that were shadowed by this level. */
+
+ for (link = current_binding_level->shadowed_tags; link;
+ link = TREE_CHAIN (link))
+ IDENTIFIER_TAG_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+
+ /* If this is the top level block of a function, remove all
+ PARM_DECLs from current_binding_level->names; they are already
+ stored in DECL_ARGUMENTS of cfun->decl in proper order, should
+ not be put in BLOCK_VARS, and furthermore reversing them will
+ cause trouble later. They are all together at the end of the
+ list. */
+ if (functionbody && decls)
+ {
+ if (TREE_CODE (decls) == PARM_DECL)
+ decls = 0;
+ else
+ {
+ link = decls;
+ while (TREE_CHAIN (link)
+ && TREE_CODE (TREE_CHAIN (link)) != PARM_DECL)
+ link = TREE_CHAIN (link);
+
+ TREE_CHAIN (link) = 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;
- }
-
- /* We used to warn about unused variables in expand_end_bindings,
- i.e. while generating RTL. But in function-at-a-time mode we may
- choose to never expand a function at all (e.g. auto inlining), so
- we do this explicitly now. */
- warn_about_unused_variables (getdecls ());
+ decls = nreverse (decls);
/* 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)
+ if (keep)
{
+ block = make_node (BLOCK);
BLOCK_VARS (block) = decls;
BLOCK_SUBBLOCKS (block) = subblocks;
+ TREE_USED (block) = 1;
}
/* 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;
- }
- }
+ /* 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.
- /* Restore all name-meanings of the outer levels
- that were shadowed by this level. */
+ 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. */
- for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
- IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+ decl = functionbody ? current_function_decl : block;
+ if (decl)
+ for (link = tags; link; link = TREE_CHAIN (link))
+ TYPE_CONTEXT (TREE_VALUE (link)) = decl;
- /* 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 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. Then add them to BLOCK_VARS. */
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))
{
tree label = TREE_VALUE (link);
{
error_with_decl (label, "label `%s' used but not defined");
/* Avoid crashing later. */
- define_label (input_filename, lineno,
- DECL_NAME (label));
+ define_label (input_location, DECL_NAME (label));
}
else if (warn_unused_label && !TREE_USED (label))
warning_with_decl (label, "label `%s' defined but not used");
/* Pop the current level, and free the structure for reuse. */
- {
- 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;
- }
+ pop_binding_level (¤t_binding_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);
- }
+ 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)
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;
}
to handle the BLOCK node inside the BIND_EXPR. */
void
-insert_block (block)
- tree block;
+insert_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). */
+/* Set the BLOCK node for the innermost scope (the one we are
+ currently in). The RTL expansion machinery requires us to provide
+ this hook, but it is not useful in function-at-a-time mode. */
void
-set_block (block)
- tree block;
+set_block (tree block ATTRIBUTE_UNUSED)
{
- current_binding_level->this_block = block;
- current_binding_level->names = chainon (current_binding_level->names,
- BLOCK_VARS (block));
- current_binding_level->blocks = chainon (current_binding_level->blocks,
- BLOCK_SUBBLOCKS (block));
}
\f
void
-push_label_level ()
+push_label_level (void)
{
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 ();
- }
+ newlevel = make_binding_level ();
/* Add this level to the front of the chain (stack) of label levels. */
}
void
-pop_label_level ()
+pop_label_level (void)
{
struct binding_level *level = label_level_chain;
tree link, prev;
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)));
+ define_label (input_location, DECL_NAME (TREE_VALUE (link)));
}
else if (warn_unused_label && !TREE_USED (TREE_VALUE (link)))
warning_with_decl (TREE_VALUE (link),
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;
+ pop_binding_level (&label_level_chain);
}
\f
/* Push a definition or a declaration of struct, union or enum tag "name".
In that case, the TYPE_SIZE will be zero. */
void
-pushtag (name, type)
- tree name, type;
+pushtag (tree name, tree type)
{
- 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;
+ struct binding_level *b = current_binding_level;
if (name)
{
if (TYPE_NAME (type) == 0)
TYPE_NAME (type) = name;
+
+ if (IDENTIFIER_TAG_VALUE (name))
+ b->shadowed_tags = tree_cons (name, IDENTIFIER_TAG_VALUE (name),
+ b->shadowed_tags);
+ IDENTIFIER_TAG_VALUE (name) = type;
}
b->tags = tree_cons (name, type, b->tags);
and OLDDECL is in an outer binding level and should thus not be changed. */
static int
-duplicate_decls (newdecl, olddecl, different_binding_level)
- tree newdecl, olddecl;
- int different_binding_level;
+duplicate_decls (tree newdecl, tree olddecl, int different_binding_level)
{
int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
{
if (TREE_CODE (olddecl) == FUNCTION_DECL
- && (DECL_BUILT_IN (olddecl)
- || DECL_BUILT_IN_NONANSI (olddecl)))
+ && DECL_BUILT_IN (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))
+ if (warn_shadow)
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");
return 0;
}
- /* For real parm decl following a forward decl,
- return 1 so old decl will be reused. */
+ /* For real parm decl following a forward decl, return 1 so old decl
+ will be reused. Only allow this to happen once. */
if (types_match && TREE_CODE (newdecl) == PARM_DECL
&& TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl))
- return 1;
+ {
+ TREE_ASM_WRITTEN (olddecl) = 0;
+ 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
we will come back here again. */
DECL_IN_SYSTEM_HEADER (newdecl) = 1;
}
+ /* Permit void foo (...) to match int foo (...) if the latter is the
+ definition and implicit int was used. See c-torture/compile/920625-2.c. */
+ else if (!types_match && new_is_definition
+ && TREE_CODE (olddecl) == FUNCTION_DECL
+ && TREE_CODE (newdecl) == FUNCTION_DECL
+ && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node
+ && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node
+ && C_FUNCTION_IMPLICIT_INT (newdecl))
+ {
+ pedwarn_with_decl (newdecl, "conflicting types for `%s'");
+ /* Make sure we keep void as the return type. */
+ TREE_TYPE (newdecl) = newtype = oldtype;
+ C_FUNCTION_IMPLICIT_INT (newdecl) = 0;
+ }
else if (!types_match
/* Permit char *foo (int, ...); followed by char *foo ();
if not pedantic. */
}
}
}
+ if (C_DECL_IMPLICIT (olddecl))
+ error_with_decl (olddecl, "previous implicit declaration of `%s'");
+ else
+ error_with_decl (olddecl, "previous declaration of `%s'");
+
+ /* This is safer because the initializer might contain references
+ to variables that were declared between olddecl and newdecl. This
+ will make the initializer invalid for olddecl in case it gets
+ assigned to olddecl below. */
+ if (TREE_CODE (newdecl) == VAR_DECL)
+ DECL_INITIAL (newdecl) = 0;
+ }
+ /* TLS cannot follow non-TLS declaration. */
+ else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL
+ && !DECL_THREAD_LOCAL (olddecl) && DECL_THREAD_LOCAL (newdecl))
+ {
+ error_with_decl (newdecl, "thread-local declaration of `%s' follows non thread-local declaration");
+ error_with_decl (olddecl, "previous declaration of `%s'");
+ }
+ /* non-TLS declaration cannot follow TLS declaration. */
+ else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL
+ && DECL_THREAD_LOCAL (olddecl) && !DECL_THREAD_LOCAL (newdecl))
+ {
+ error_with_decl (newdecl, "non thread-local declaration of `%s' follows thread-local declaration");
error_with_decl (olddecl, "previous declaration of `%s'");
}
else
COPY_DECL_RTL (olddecl, newdecl);
/* Merge the type qualifiers. */
- if (TREE_CODE (olddecl) == FUNCTION_DECL
- && DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl)
- && ! TREE_THIS_VOLATILE (newdecl))
- TREE_THIS_VOLATILE (write_olddecl) = 0;
-
if (TREE_READONLY (newdecl))
TREE_READONLY (write_olddecl) = 1;
DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
|= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+ TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+ TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+ DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
+ DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
}
}
/* If cannot merge, then use the new type and qualifiers,
inline, make sure we emit debug info for the inline before we
throw it away, in case it was inlined into a function that hasn't
been written out yet. */
- if (new_is_definition && DECL_INITIAL (olddecl) && TREE_USED (olddecl))
+ if (new_is_definition && DECL_INITIAL (olddecl))
{
- (*debug_hooks->outlining_inline_function) (olddecl);
+ if (TREE_USED (olddecl))
+ (*debug_hooks->outlining_inline_function) (olddecl);
/* The new defn must not be inline. */
DECL_INLINE (newdecl) = 0;
Update OLDDECL to be the same. */
DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
+ /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl
+ so that encode_section_info has a chance to look at the new decl
+ flags and attributes. */
+ if (DECL_RTL_SET_P (olddecl)
+ && (TREE_CODE (olddecl) == FUNCTION_DECL
+ || (TREE_CODE (olddecl) == VAR_DECL
+ && TREE_STATIC (olddecl))))
+ make_decl_rtl (olddecl, NULL);
+
return 1;
}
+/* Return any external DECL associated with ID, whether or not it is
+ currently in scope. */
+
+static tree
+any_external_decl (tree id)
+{
+ tree decl = IDENTIFIER_SYMBOL_VALUE (id);
+ tree t;
+
+ if (decl == 0 || TREE_CODE (decl) == ERROR_MARK)
+ return 0;
+ else if (TREE_CODE (decl) != TYPE_DECL && DECL_EXTERNAL (decl))
+ return decl;
+
+ t = purpose_member (id, truly_local_externals);
+ if (t)
+ return TREE_VALUE (t);
+
+ return 0;
+}
+
+/* Record an external decl DECL. This only does something if a
+ shadowing decl already exists. */
+static void
+record_external_decl (tree decl)
+{
+ tree name = DECL_NAME (decl);
+ if (!IDENTIFIER_SYMBOL_VALUE (name))
+ return;
+
+ truly_local_externals = tree_cons (name, decl, truly_local_externals);
+}
+
/* Check whether decl-node X shadows an existing declaration.
- OLDLOCAL is the old IDENTIFIER_LOCAL_VALUE of the DECL_NAME of X,
+ OLD is the old IDENTIFIER_SYMBOL_VALUE of the DECL_NAME of X,
which might be a NULL_TREE. */
static void
-warn_if_shadowing (x, oldlocal)
- tree x, oldlocal;
+warn_if_shadowing (tree x, tree old)
{
- tree name;
+ const char *name;
- if (DECL_EXTERNAL (x))
+ /* Nothing to shadow? */
+ if (old == 0
+ /* Shadow warnings not wanted? */
+ || !warn_shadow
+ /* No shadow warnings for internally generated vars. */
+ || DECL_SOURCE_LINE (x) == 0
+ /* No shadow warnings for vars made for inlining. */
+ || DECL_FROM_INLINE (x)
+ /* 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. */
+ || (TREE_CODE (x) == PARM_DECL
+ && current_binding_level->level_chain->parm_flag))
return;
- name = DECL_NAME (x);
+ name = IDENTIFIER_POINTER (DECL_NAME (x));
+
+ if (TREE_CODE (old) == PARM_DECL)
+ shadow_warning (SW_PARAM, name, old);
+ else if (DECL_CONTEXT (old) == 0)
+ shadow_warning (SW_GLOBAL, name, old);
+ else
+ shadow_warning (SW_LOCAL, name, old);
+}
+
+
+/* Subroutine of pushdecl.
+
+ X is a TYPE_DECL for a typedef statement. Create a brand new
+ ..._TYPE node (which will be just a variant of the existing
+ ..._TYPE node with identical properties) and then install X
+ 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 it 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:
- /* Warn if shadowing an argument at the top level of the body. */
- if (oldlocal != 0
- /* 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))
+ 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. */
+
+static void
+clone_underlying_type (tree x)
+{
+ if (DECL_SOURCE_LINE (x) == 0)
{
- 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));
+ if (TYPE_NAME (TREE_TYPE (x)) == 0)
+ TYPE_NAME (TREE_TYPE (x)) = x;
}
- /* Maybe warn if shadowing something else. */
- else if (warn_shadow
- /* No shadow warnings for internally generated vars. */
- && DECL_SOURCE_LINE (x) != 0
- /* No shadow warnings for vars made for inlining. */
- && ! DECL_FROM_INLINE (x))
+ else if (TREE_TYPE (x) != error_mark_node
+ && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
{
- 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)
- {
- if (TREE_CODE (oldlocal) == PARM_DECL)
- shadow_warning ("a parameter", name, oldlocal);
- else
- shadow_warning ("a previous local", name, oldlocal);
- }
- else if (IDENTIFIER_GLOBAL_VALUE (name) != 0
- && IDENTIFIER_GLOBAL_VALUE (name) != error_mark_node)
- shadow_warning ("a global declaration", name,
- IDENTIFIER_GLOBAL_VALUE (name));
+ tree tt = TREE_TYPE (x);
+ DECL_ORIGINAL_TYPE (x) = tt;
+ tt = build_type_copy (tt);
+ TYPE_NAME (tt) = x;
+ TREE_USED (tt) = TREE_USED (x);
+ TREE_TYPE (x) = tt;
}
}
to agree with what X says. */
tree
-pushdecl (x)
- tree x;
+pushdecl (tree x)
{
- tree t;
tree name = DECL_NAME (x);
- struct binding_level *b = current_binding_level;
+ struct binding_level *scope = current_binding_level;
+
+#ifdef ENABLE_CHECKING
+ if (error_mark_node == 0)
+ /* Called too early. */
+ abort ();
+#endif
/* Functions need the lang_decl data. */
if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_LANG_SPECIFIC (x))
DECL_LANG_SPECIFIC (x) = (struct lang_decl *)
ggc_alloc_cleared (sizeof (struct lang_decl));
- 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 || TREE_CODE (x) == VAR_DECL)
&& DECL_INITIAL (x) == 0 && DECL_EXTERNAL (x))
DECL_CONTEXT (x) = 0;
+ else
+ DECL_CONTEXT (x) = current_function_decl;
if (name)
{
- int different_binding_level = 0;
+ tree old;
if (warn_nested_externs
+ && scope != global_binding_level
&& DECL_EXTERNAL (x)
- && b != global_binding_level
- && x != IDENTIFIER_IMPLICIT_DECL (name)
- /* No error messages for __FUNCTION__ and __PRETTY_FUNCTION__. */
&& !DECL_IN_SYSTEM_HEADER (x))
warning ("nested extern declaration of `%s'",
IDENTIFIER_POINTER (name));
- t = lookup_name_current_level (name);
- if (! t && DECL_EXTERNAL (x) && TREE_PUBLIC (x))
- {
- 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)
- /* If there's no visible global declaration, try for an
- invisible one. */
- t = IDENTIFIER_LIMBO_VALUE (name);
- 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 this decl is `static' and an implicit decl was seen previously,
- warn. */
- if (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)
+ old = lookup_name_current_level (name);
+ if (old && duplicate_decls (x, old, 0))
+ return old;
+ if (DECL_EXTERNAL (x) || scope == global_binding_level)
{
- 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));
- TREE_THIS_VOLATILE (name) = 1;
- }
-
- if (t != 0 && duplicate_decls (x, t, different_binding_level))
- {
- if (TREE_CODE (t) == PARM_DECL)
+ /* Find and check against a previous, not-in-scope, external
+ decl for this identifier. (C99 s???: If two declarations
+ with external linkage, referring to the same object, have
+ incompatible types, the behavior is undefined). */
+ tree ext = any_external_decl (name);
+ if (ext)
{
- /* Don't allow more than one "real" duplicate
- of a forward parm decl. */
- TREE_ASM_WRITTEN (t) = TREE_ASM_WRITTEN (x);
- return t;
+ if (duplicate_decls (x, ext, scope != global_binding_level))
+ x = copy_node (ext);
}
- return t;
+ else
+ record_external_decl (x);
}
- /* 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 it 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)
+ clone_underlying_type (x);
+
+ /* If storing a local value, there may already be one
+ (inherited). If so, record it for restoration when this
+ binding level ends. Take care not to do this if we are
+ replacing an older decl in the same binding level (i.e.
+ duplicate_decls returned false, above). */
+ if (scope != global_binding_level
+ && IDENTIFIER_SYMBOL_VALUE (name)
+ && IDENTIFIER_SYMBOL_VALUE (name) != old)
{
- 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_USED (tt) = TREE_USED (x);
- TREE_TYPE (x) = tt;
- }
+ warn_if_shadowing (x, IDENTIFIER_SYMBOL_VALUE (name));
+ scope->shadowed = tree_cons (name, IDENTIFIER_SYMBOL_VALUE (name),
+ scope->shadowed);
}
- /* Multiple external decls of the same identifier ought to match.
- We get warnings about inline functions where they are defined.
- Avoid duplicate warnings where they are used. */
- if (TREE_PUBLIC (x)
- && ! (TREE_CODE (x) == FUNCTION_DECL && DECL_INLINE (x)))
- {
- tree decl;
-
- 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;
+ /* Install the new declaration in the requested binding level. */
+ IDENTIFIER_SYMBOL_VALUE (name) = x;
+ C_DECL_INVISIBLE (x) = 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'");
- }
-
- /* 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))
- {
- if (! TREE_THIS_VOLATILE (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
- && oldglobal != 0
- && TREE_CODE (x) == FUNCTION_DECL
- && TREE_CODE (oldglobal) == FUNCTION_DECL
- && DECL_EXTERNAL (x)
- && ! DECL_DECLARED_INLINE_P (x))
- {
- /* 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_DECLARED_INLINE_P (oldglobal))
- {
- DECL_DECLARED_INLINE_P (x)
- = DECL_DECLARED_INLINE_P (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_NUM_STMTS (x) = DECL_NUM_STMTS (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)
- = DECL_ABSTRACT_ORIGIN (oldglobal);
- }
- /* Inner extern decl is built-in if global one is. */
- if (DECL_BUILT_IN (oldglobal))
- {
- DECL_BUILT_IN_CLASS (x) = DECL_BUILT_IN_CLASS (oldglobal);
- DECL_FUNCTION_CODE (x) = DECL_FUNCTION_CODE (oldglobal);
- }
- /* Keep the arg types from a file-scope fcn defn. */
- 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 (x, oldlocal);
-
- /* 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.
+ /* Keep list of variables in this level with incomplete type.
If the input is erroneous, we can have error_mark in the type
slot (e.g. "f(void a, ...)") - that doesn't count as an
incomplete type. */
element = TREE_TYPE (element);
if (TREE_CODE (element) == RECORD_TYPE
|| TREE_CODE (element) == UNION_TYPE)
- ++b->n_incomplete;
+ scope->incomplete_list = tree_cons (NULL_TREE, x,
+ scope->incomplete_list);
}
}
/* Put decls on list in reverse order.
We will reverse them later if necessary. */
- TREE_CHAIN (x) = b->names;
- b->names = x;
+ TREE_CHAIN (x) = scope->names;
+ scope->names = x;
return x;
}
-/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate. */
-
+/* Record X as belonging to the global scope (C99 "file scope").
+ This is used only internally by the Objective-C front end,
+ and is limited to its needs. It will hork if there is _any_
+ visible binding for X (not just a global one). */
tree
-pushdecl_top_level (x)
- tree x;
+pushdecl_top_level (tree x)
{
- tree t;
- struct binding_level *b = current_binding_level;
+ tree name, old;
- current_binding_level = global_binding_level;
- t = pushdecl (x);
- current_binding_level = b;
- return t;
+ if (TREE_CODE (x) != VAR_DECL)
+ abort ();
+
+ name = DECL_NAME (x);
+ old = IDENTIFIER_SYMBOL_VALUE (name);
+
+ if (old)
+ {
+ if (DECL_CONTEXT (old))
+ abort ();
+
+ if (!duplicate_decls (x, old, 0))
+ abort ();
+
+ return old;
+ }
+
+ DECL_CONTEXT (x) = 0;
+ IDENTIFIER_SYMBOL_VALUE (name) = x;
+ TREE_CHAIN (x) = global_binding_level->names;
+ global_binding_level->names = x;
+ return x;
}
-\f
-/* Generate an implicit declaration for identifier FUNCTIONID
- as a function of type int (). Print a warning if appropriate. */
+/* Record X as belonging to the outermost scope of the current
+ function. This is used only internally, by c_make_fname_decl and
+ build_external_ref, and is limited to their needs. The NAME is
+ provided as a separate argument because build_external_ref wants to
+ use error_mark_node for X. For VAR_DECLs, duplicate_decls is not
+ called; if there is any preexisting decl for this identifier, it is
+ an ICE. */
tree
-implicitly_declare (functionid)
- tree functionid;
+pushdecl_function_level (tree x, tree name)
{
- tree decl;
- int traditional_warning = 0;
- /* Only one "implicit declaration" warning per identifier. */
- int implicit_warning;
+ struct binding_level *scope;
- /* We used to reuse an old implicit decl here,
- but this loses with inline functions because it can clobber
- the saved decl chains. */
-#if 0
- if (IDENTIFIER_IMPLICIT_DECL (functionid) != 0)
- decl = IDENTIFIER_IMPLICIT_DECL (functionid);
- else
-#endif
- decl = build_decl (FUNCTION_DECL, functionid, default_function_type);
+ scope = current_binding_level;
+ while (scope->function_body == 0)
+ scope = scope->level_chain;
+ if (!scope)
+ abort ();
- /* 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;
+ if (x == error_mark_node)
+ scope->shadowed = tree_cons (name, IDENTIFIER_SYMBOL_VALUE (name),
+ scope->shadowed);
+ else if (TREE_CODE (x) == VAR_DECL)
+ {
+ if (name != DECL_NAME (x))
+ abort ();
+ if (IDENTIFIER_SYMBOL_VALUE (name))
+ abort ();
+
+ DECL_CONTEXT (x) = current_function_decl;
+ TREE_CHAIN (x) = scope->names;
+ scope->names = x;
+ }
- /* Warn once of an implicit declaration. */
- implicit_warning = (IDENTIFIER_IMPLICIT_DECL (functionid) == 0);
+ IDENTIFIER_SYMBOL_VALUE (name) = x;
+ return x;
+}
+\f
+/* Generate an implicit declaration for identifier FUNCTIONID as a
+ function of type int (). */
+tree
+implicitly_declare (tree functionid)
+{
+ tree decl = any_external_decl (functionid);
+
+ if (decl && decl != error_mark_node)
+ {
+ /* Implicit declaration of a function already declared
+ (somehow) in a different scope, or as a built-in.
+ If this is the first time this has happened, warn;
+ then recycle the old declaration. */
+ if (!C_DECL_IMPLICIT (decl))
+ {
+ implicit_decl_warning (DECL_NAME (decl));
+ if (DECL_CONTEXT (decl))
+ warning_with_decl (decl, "previous declaration of `%s'");
+ C_DECL_IMPLICIT (decl) = 1;
+ }
+ /* If this function is global, then it must already be in the
+ global binding level, so there's no need to push it again. */
+ if (current_binding_level == global_binding_level)
+ return decl;
+ /* If this is a local declaration, make a copy; we can't have
+ the same DECL listed in two different binding levels. */
+ return pushdecl (copy_node (decl));
+ }
+
+ /* Not seen before. */
+ decl = build_decl (FUNCTION_DECL, functionid, default_function_type);
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
-
- /* Record that we have an implicit decl and this is it. */
- IDENTIFIER_IMPLICIT_DECL (functionid) = decl;
+ C_DECL_IMPLICIT (decl) = 1;
+ implicit_decl_warning (functionid);
/* ANSI standard says implicit declarations are in the innermost block.
So we record the decl in the standard fashion. */
- pushdecl (decl);
-
- /* This is a no-op in c-lang.c or something real in objc-actions.c. */
- maybe_objc_check_decl (decl);
+ decl = pushdecl (decl);
+ /* No need to call objc_check_decl here - it's a function type. */
rest_of_decl_compilation (decl, NULL, 0, 0);
- if (implicit_warning)
- implicit_decl_warning (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). */
return decl;
}
-void
-implicit_decl_warning (id)
- tree id;
+static void
+implicit_decl_warning (tree id)
{
const char *name = IDENTIFIER_POINTER (id);
if (mesg_implicit_function_declaration == 2)
and 3 if it is a conflicting declaration. */
static int
-redeclaration_error_message (newdecl, olddecl)
- tree newdecl, olddecl;
+redeclaration_error_message (tree newdecl, tree olddecl)
{
if (TREE_CODE (newdecl) == TYPE_DECL)
{
This function is called for both label definitions and label references. */
tree
-lookup_label (id)
- tree id;
+lookup_label (tree id)
{
tree decl = IDENTIFIER_LABEL_VALUE (id);
/* 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;
+ DECL_SOURCE_LOCATION (decl) = input_location;
IDENTIFIER_LABEL_VALUE (id) = decl;
requires calling declare_nonlocal_label right away. */
tree
-shadow_label (name)
- tree name;
+shadow_label (tree name)
{
tree decl = IDENTIFIER_LABEL_VALUE (name);
Otherwise return 0. */
tree
-define_label (filename, line, name)
- const char *filename;
- int line;
- tree name;
+define_label (location_t location, tree name)
{
tree decl = lookup_label (name);
}
if (warn_traditional && !in_system_header && lookup_name (name))
- warning_with_file_and_line (filename, line,
- "traditional C lacks a separate namespace for labels, identifier `%s' conflicts",
- IDENTIFIER_POINTER (name));
+ warning ("%Htraditional C lacks a separate namespace for labels, "
+ "identifier `%s' conflicts", &location, IDENTIFIER_POINTER (name));
if (DECL_INITIAL (decl) != 0)
{
- error_with_file_and_line (filename, line, "duplicate label `%s'",
- IDENTIFIER_POINTER (name));
+ error ("%Hduplicate label `%s'", &location, 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;
+ DECL_SOURCE_LOCATION (decl) = location;
return decl;
}
}
store the result back using `storedecls' or you will lose. */
tree
-getdecls ()
+getdecls (void)
{
return current_binding_level->names;
}
/* Return the list of type-tags (for structs, etc) of the current level. */
tree
-gettags ()
+gettags (void)
{
return current_binding_level->tags;
}
after they are modified in the light of any missing parameters. */
static void
-storedecls (decls)
- tree decls;
+storedecls (tree decls)
{
current_binding_level->names = decls;
}
/* Similarly, store the list of tags of the current level. */
static void
-storetags (tags)
- tree tags;
+storetags (tree tags)
{
current_binding_level->tags = tags;
}
\f
/* Given NAME, an IDENTIFIER_NODE,
return the structure (or union or enum) definition for that name.
- Searches binding levels from BINDING_LEVEL up to the global level.
- If THISLEVEL_ONLY is nonzero, searches only the specified context
- (but skips any tag-transparent contexts to find one that is
- meaningful for tags).
+ If THISLEVEL_ONLY is nonzero, searches only the current_binding_level.
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;
+lookup_tag (enum tree_code code, tree name, int thislevel_only)
{
- struct binding_level *level;
- int thislevel = 1;
+ tree tag = IDENTIFIER_TAG_VALUE (name);
+ int thislevel = 0;
+
+ if (!tag)
+ return 0;
- for (level = binding_level; level; level = level->level_chain)
+ /* We only care about whether it's in this level if
+ thislevel_only was set or it might be a type clash. */
+ if (thislevel_only || TREE_CODE (tag) != code)
{
- 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;
- /* If in the same binding level as a declaration as a tag
- of a different type, this must not be allowed to
- shadow that tag, so give the error immediately.
- (For example, "struct foo; union foo;" is invalid.) */
- if (thislevel)
- pending_xref_error ();
- }
- return TREE_VALUE (tail);
- }
- }
- if (! level->tag_transparent)
- {
- if (thislevel_only)
- return NULL_TREE;
- thislevel = 0;
- }
+ if (current_binding_level == global_binding_level
+ || purpose_member (name, current_binding_level->tags))
+ thislevel = 1;
}
- return NULL_TREE;
+
+ if (thislevel_only && !thislevel)
+ return 0;
+
+ if (TREE_CODE (tag) != code)
+ {
+ /* Definition isn't the kind we were looking for. */
+ pending_invalid_xref = name;
+ pending_invalid_xref_location = input_location;
+
+ /* If in the same binding level as a declaration as a tag
+ of a different type, this must not be allowed to
+ shadow that tag, so give the error immediately.
+ (For example, "struct foo; union foo;" is invalid.) */
+ if (thislevel)
+ pending_xref_error ();
+ }
+ return tag;
}
/* Print an error message now
when used in the `struct foo;' construct for shadowing. */
void
-pending_xref_error ()
+pending_xref_error (void)
{
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));
+ error ("%H`%s' defined as wrong kind of tag",
+ &pending_invalid_xref_location,
+ 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;
-{
- struct binding_level *level;
-
- for (level = current_binding_level; level; level = level->level_chain)
- {
- tree tail;
- for (tail = level->tags; tail; tail = TREE_CHAIN (tail))
- {
- if (TREE_VALUE (tail) == type)
- return TREE_PURPOSE (tail);
- }
- }
- return NULL_TREE;
-}
\f
/* Look up NAME in the current binding level and its superiors
in the namespace of variables, functions and typedefs.
or return 0 if it is undefined. */
tree
-lookup_name (name)
- tree name;
+lookup_name (tree name)
{
- 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;
+ tree decl = IDENTIFIER_SYMBOL_VALUE (name);
+ if (decl == 0 || decl == error_mark_node)
+ return decl;
+ if (C_DECL_INVISIBLE (decl))
+ return 0;
+ return decl;
}
-/* Similar to `lookup_name' but look only at current binding level. */
+/* Similar to `lookup_name' but look only at the current binding level. */
-tree
-lookup_name_current_level (name)
- tree name;
+static tree
+lookup_name_current_level (tree name)
{
- tree t;
+ tree decl = IDENTIFIER_SYMBOL_VALUE (name);
- if (current_binding_level == global_binding_level)
- return IDENTIFIER_GLOBAL_VALUE (name);
-
- if (IDENTIFIER_LOCAL_VALUE (name) == 0)
+ if (decl == 0 || decl == error_mark_node || C_DECL_INVISIBLE (decl))
return 0;
- for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
- if (DECL_NAME (t) == name)
- break;
-
- return t;
-}
-\f
-/* Mark ARG for GC. */
+ if (current_binding_level == global_binding_level)
+ return decl;
-static void
-mark_binding_level (arg)
- void *arg;
-{
- struct binding_level *level = *(struct binding_level **) arg;
+ /* Scan the current scope for a decl with name NAME. */
+ if (chain_member (decl, current_binding_level->names))
+ return decl;
- for (; level != 0; level = level->level_chain)
- {
- ggc_mark_tree (level->names);
- ggc_mark_tree (level->tags);
- ggc_mark_tree (level->shadowed);
- ggc_mark_tree (level->blocks);
- ggc_mark_tree (level->this_block);
- ggc_mark_tree (level->parm_order);
- }
+ return 0;
}
-
+\f
/* Create the predefined scalar types of C,
and some nodes representing standard constants (0, 1, (void *) 0).
Initialize the global binding level.
Make definitions for built-in primitive functions. */
void
-c_init_decl_processing ()
+c_init_decl_processing (void)
{
tree endlink;
tree ptr_ftype_void, ptr_ftype_ptr;
-
+ location_t save_loc = input_location;
+
/* Adds some ggc roots, and reserved words for c-parse.in. */
c_parse_init ();
/* Make the binding_level structure for global names. */
pushlevel (0);
global_binding_level = current_binding_level;
+ /* Declarations from c_common_nodes_and_builtins must not be associated
+ with this input file, lest we get differences between using and not
+ using preprocessed headers. */
+ input_location.file = "<internal>";
+ input_location.line = 0;
build_common_tree_nodes (flag_signed_char);
= build_function_type (ptr_type_node,
tree_cons (NULL_TREE, ptr_type_node, endlink));
+ input_location = save_loc;
+
pedantic_lvalues = pedantic;
make_fname_decl = c_make_fname_decl;
start_fname_decls ();
-
- /* Record our roots. */
-
- ggc_add_tree_root (c_global_trees, CTI_MAX);
- ggc_add_root (&c_stmt_tree, 1, sizeof c_stmt_tree, mark_stmt_tree);
- ggc_add_tree_root (&c_scope_stmt_stack, 1);
- ggc_add_tree_root (&named_labels, 1);
- ggc_add_tree_root (&shadowed_labels, 1);
- ggc_add_root (¤t_binding_level, 1, sizeof current_binding_level,
- mark_binding_level);
- ggc_add_root (&label_level_chain, 1, sizeof label_level_chain,
- mark_binding_level);
- ggc_add_tree_root (&static_ctors, 1);
- ggc_add_tree_root (&static_dtors, 1);
}
/* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
are string merging candidates, which is wrong for C99's __func__. FIXME. */
static tree
-c_make_fname_decl (id, type_dep)
- tree id;
- int type_dep;
+c_make_fname_decl (tree id, int type_dep)
{
const char *name = fname_as_string (type_dep);
tree decl, type, init;
build_index_type (size_int (length)));
decl = build_decl (VAR_DECL, id, type);
- /* We don't push the decl, so have to set its context here. */
- DECL_CONTEXT (decl) = current_function_decl;
-
+
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
-
+
init = build_string (length + 1, name);
TREE_TYPE (init) = type;
DECL_INITIAL (decl) = init;
TREE_USED (decl) = 1;
-
+
+ if (current_function_decl)
+ pushdecl_function_level (decl, DECL_NAME (decl));
+
finish_decl (decl, init, NULL_TREE);
return decl;
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. */
+ the name to be called if we can't opencode the function. If
+ ATTRS is nonzero, use that for the function's attribute list. */
tree
-builtin_function (name, type, function_code, class, library_name)
- const char *name;
- tree type;
- int function_code;
- enum built_in_class class;
- const char *library_name;
+builtin_function (const char *name, tree type, int function_code,
+ enum built_in_class class, const char *library_name,
+ tree attrs)
{
tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type);
DECL_EXTERNAL (decl) = 1;
DECL_BUILT_IN_CLASS (decl) = class;
DECL_FUNCTION_CODE (decl) = function_code;
- /* The return builtins leave the current function. */
- if (function_code == BUILT_IN_RETURN || function_code == BUILT_IN_EH_RETURN)
- TREE_THIS_VOLATILE (decl) = 1;
-
/* 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;
+ C_DECL_INVISIBLE (decl) = 1;
/* Possibly apply some default attributes to this built-in function. */
- decl_attributes (&decl, NULL_TREE, 0);
+ if (attrs)
+ decl_attributes (&decl, attrs, ATTR_FLAG_BUILT_IN);
+ else
+ decl_attributes (&decl, NULL_TREE, 0);
return decl;
}
attributes. */
void
-c_insert_default_attributes (decl)
- tree decl;
+c_insert_default_attributes (tree decl)
{
if (!TREE_PUBLIC (decl))
return;
Otherwise, it is an error. */
void
-shadow_tag (declspecs)
- tree declspecs;
+shadow_tag (tree declspecs)
{
shadow_tag_warned (declspecs, 0);
}
void
-shadow_tag_warned (declspecs, warned)
- tree declspecs;
- int warned;
+shadow_tag_warned (tree declspecs, int warned)
+
+
/* 1 => we have done a pedwarn. 2 => we have done a warning, but
no pedwarn. */
{
/* Used to test also that TYPE_SIZE (value) != 0.
That caused warning for `struct foo;' at top level in the file. */
{
- tree name = lookup_tag_reverse (value);
+ tree name = TYPE_NAME (value);
tree t;
found_tag++;
}
else
{
- t = lookup_tag (code, name, current_binding_level, 1);
+ t = lookup_tag (code, name, 1);
if (t == 0)
{
/* Construct an array declarator. EXPR is the expression inside [], or
NULL_TREE. QUALS are the type qualifiers inside the [] (to be applied
to the pointer to which a parameter array is converted). STATIC_P is
- non-zero if "static" is inside the [], zero otherwise. VLA_UNSPEC_P
- is non-zero is the array is [*], a VLA of unspecified length which is
+ nonzero if "static" is inside the [], zero otherwise. VLA_UNSPEC_P
+ is nonzero is the array is [*], a VLA of unspecified length which is
nevertheless a complete type (not currently implemented by GCC),
zero otherwise. The declarator is constructed as an ARRAY_REF
(to be decoded by grokdeclarator), whose operand 0 is what's on the
which has TREE_STATIC set if "static" is used. */
tree
-build_array_declarator (expr, quals, static_p, vla_unspec_p)
- tree expr;
- tree quals;
- int static_p;
- int vla_unspec_p;
+build_array_declarator (tree expr, tree quals, int static_p, int vla_unspec_p)
{
tree decl;
decl = build_nt (ARRAY_REF, NULL_TREE, expr);
if (pedantic && !flag_isoc99)
{
if (static_p || quals != NULL_TREE)
- pedwarn ("ISO C89 does not support `static' or type qualifiers in parameter array declarators");
+ pedwarn ("ISO C90 does not support `static' or type qualifiers in parameter array declarators");
if (vla_unspec_p)
- pedwarn ("ISO C89 does not support `[*]' array declarators");
+ pedwarn ("ISO C90 does not support `[*]' array declarators");
}
if (vla_unspec_p)
warning ("GCC does not yet properly implement `[*]' array declarators");
/* Set the type of an array declarator. DECL is the declarator, as
constructed by build_array_declarator; TYPE is what appears on the left
- of the [] and goes in operand 0. ABSTRACT_P is non-zero if it is an
+ of the [] and goes in operand 0. ABSTRACT_P is nonzero if it is an
abstract declarator, zero otherwise; this is used to reject static and
type qualifiers in abstract declarators, where they are not in the
C99 grammar. */
tree
-set_array_declarator_type (decl, type, abstract_p)
- tree decl;
- tree type;
- int abstract_p;
+set_array_declarator_type (tree decl, tree type, int abstract_p)
{
TREE_OPERAND (decl, 0) = type;
if (abstract_p && (TREE_TYPE (decl) != NULL_TREE || TREE_STATIC (decl)))
/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
tree
-groktypename (typename)
- tree typename;
+groktypename (tree typename)
{
tree specs, attrs;
/* Return a PARM_DECL node for a given pair of specs and declarator. */
tree
-groktypename_in_parm_context (typename)
- tree typename;
+groktypename_in_parm_context (tree typename)
{
if (TREE_CODE (typename) != TREE_LIST)
return typename;
grokfield and not through here. */
tree
-start_decl (declarator, declspecs, initialized, attributes)
- tree declarator, declspecs;
- int initialized;
- tree attributes;
+start_decl (tree declarator, tree declspecs, int initialized, tree attributes)
{
tree decl;
tree tem;
-
+
/* An object declared as __attribute__((deprecated)) suppresses
warnings of uses of other deprecated items. */
if (lookup_attribute ("deprecated", attributes))
decl = grokdeclarator (declarator, declspecs,
NORMAL, initialized);
-
+
deprecated_state = DEPRECATED_NORMAL;
if (warn_main > 0 && TREE_CODE (decl) != FUNCTION_DECL
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;
- }
+ error ("typedef `%s' is initialized (use __typeof__ instead)",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ initialized = 0;
break;
case FUNCTION_DECL:
/* 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 (!initialized && (! flag_no_common || ! TREE_PUBLIC (decl)))
+
+ -fno-common gives strict ANSI behavior, though this tends to break
+ a large body of code that grew up without this rule.
+
+ Thread-local variables are never common, since there's no entrenched
+ body of code to break, and it allows more efficient variable references
+ in the presence of dynamic linking. */
+
+ if (TREE_CODE (decl) == VAR_DECL
+ && !initialized
+ && TREE_PUBLIC (decl)
+ && !DECL_THREAD_LOCAL (decl)
+ && !flag_no_common)
DECL_COMMON (decl) = 1;
/* Set attributes here so if duplicate decl, will have proper attributes. */
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;
+finish_decl (tree decl, tree init, tree asmspec_tree)
{
tree type = TREE_TYPE (decl);
int was_incomplete = (DECL_SIZE (decl) == 0);
/* If `start_decl' didn't like having an initialization, ignore it now. */
if (init != 0 && DECL_INITIAL (decl) == 0)
init = 0;
-
+
/* Don't crash if parm is initialized. */
if (TREE_CODE (decl) == PARM_DECL)
init = 0;
if (init)
- {
- if (TREE_CODE (decl) != TYPE_DECL)
- store_init_value (decl, init);
- else
- {
- /* typedef foo = bar; store the type of bar as the type of foo. */
- TREE_TYPE (decl) = TREE_TYPE (init);
- DECL_INITIAL (decl) = init = 0;
- }
- }
+ store_init_value (decl, init);
/* Deduce size of array from initialization, if not already known */
if (TREE_CODE (type) == ARRAY_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 this is a function and an assembler name is specified, reset DECL_RTL
+ so we can give it its new name. Also, update built_in_decls if it
+ was a normal built-in. */
if (TREE_CODE (decl) == FUNCTION_DECL && asmspec)
{
- DECL_BUILT_IN_CLASS (decl) = NOT_BUILT_IN;
+ /* ASMSPEC is given, and not the name of a register. Mark the
+ name with a star so assemble_name won't munge it. */
+ char *starred = alloca (strlen (asmspec) + 2);
+ starred[0] = '*';
+ strcpy (starred + 1, asmspec);
+
+ if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+ {
+ tree builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
+ SET_DECL_RTL (builtin, NULL_RTX);
+ SET_DECL_ASSEMBLER_NAME (builtin, get_identifier (starred));
+#ifdef TARGET_MEM_FUNCTIONS
+ if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY)
+ init_block_move_fn (starred);
+ else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET)
+ init_block_clear_fn (starred);
+#else
+ if (DECL_FUNCTION_CODE (decl) == BUILT_IN_BCOPY)
+ init_block_move_fn (starred);
+ else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_BZERO)
+ init_block_clear_fn (starred);
+#endif
+ }
SET_DECL_RTL (decl, NULL_RTX);
- SET_DECL_ASSEMBLER_NAME (decl, get_identifier (asmspec));
+ SET_DECL_ASSEMBLER_NAME (decl, get_identifier (starred));
}
/* Output the assembler code and/or RTL code for variables and functions,
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
{
- /* This is a no-op in c-lang.c or something real in objc-actions.c. */
- maybe_objc_check_decl (decl);
+ /* This is a no-op in c-lang.c or something real in objc-act.c. */
+ if (c_dialect_objc ())
+ objc_check_decl (decl);
if (!DECL_CONTEXT (decl))
{
ordinary, non-register local variable. Historically,
GCC has accepted -- but ignored -- the ASMSPEC in
this case. */
- if (TREE_CODE (decl) == VAR_DECL
+ if (TREE_CODE (decl) == VAR_DECL
&& !DECL_REGISTER (decl)
&& !TREE_STATIC (decl))
warning_with_decl (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);
+ /* This is a no-op in c-lang.c or something real in objc-act.c. */
+ if (c_dialect_objc ())
+ objc_check_decl (decl);
rest_of_decl_compilation (decl, NULL, DECL_CONTEXT (decl) == 0, 0);
}
computing them in the following function definition. */
if (current_binding_level == global_binding_level)
get_pending_sizes ();
+
+ /* Install a cleanup (aka destructor) if one was given. */
+ if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
+ {
+ tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl));
+ if (attr)
+ {
+ static bool eh_initialized_p;
+
+ tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
+ tree cleanup_decl = lookup_name (cleanup_id);
+ tree cleanup;
+
+ /* Build "cleanup(&decl)" for the destructor. */
+ cleanup = build_unary_op (ADDR_EXPR, decl, 0);
+ cleanup = build_tree_list (NULL_TREE, cleanup);
+ cleanup = build_function_call (cleanup_decl, cleanup);
+
+ /* Don't warn about decl unused; the cleanup uses it. */
+ TREE_USED (decl) = 1;
+
+ /* Initialize EH, if we've been told to do so. */
+ if (flag_exceptions && !eh_initialized_p)
+ {
+ eh_initialized_p = true;
+ eh_personality_libfunc
+ = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+ ? "__gcc_personality_sj0"
+ : "__gcc_personality_v0");
+ using_eh_for_cleanups ();
+ }
+
+ add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
+ }
+ }
}
/* Given a parsed parameter declaration,
record the given order of parms in `parm_order'. */
void
-push_parm_decl (parm)
- tree parm;
+push_parm_decl (tree parm)
{
tree decl;
int old_immediate_size_expand = immediate_size_expand;
and also at semicolon terminating forward decls. */
void
-clear_parm_order ()
+clear_parm_order (void)
{
current_binding_level->parm_order = NULL_TREE;
}
\f
+static GTY(()) int compound_literal_number;
+
/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound
literal, which may be an incomplete array type completed by the
initializer; INIT is a CONSTRUCTOR that initializes the compound
literal. */
tree
-build_compound_literal (type, init)
- tree type;
- tree init;
+build_compound_literal (tree type, tree init)
{
/* We do not use start_decl here because we have a type, not a declarator;
and do not use finish_decl because the decl should be stored inside
DECL_CONTEXT (decl) = current_function_decl;
TREE_USED (decl) = 1;
TREE_TYPE (decl) = type;
+ TREE_READONLY (decl) = TREE_READONLY (type);
store_init_value (decl, init);
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
if (TREE_STATIC (decl))
{
/* This decl needs a name for the assembler output. We also need
- a unique suffix to be added to the name, for which DECL_CONTEXT
- must be set. */
- DECL_NAME (decl) = get_identifier ("__compound_literal");
- DECL_CONTEXT (decl) = complit;
+ a unique suffix to be added to the name. */
+ char *name;
+
+ ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal",
+ compound_literal_number);
+ compound_literal_number++;
+ DECL_NAME (decl) = get_identifier (name);
+ DECL_DEFER_OUTPUT (decl) = 1;
+ DECL_COMDAT (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ pushdecl (decl);
rest_of_decl_compilation (decl, NULL, 1, 0);
- DECL_CONTEXT (decl) = NULL_TREE;
}
return complit;
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;
+complete_array_type (tree type, tree initial_value, int do_default)
{
tree maxindex = NULL_TREE;
int value = 0;
return value;
}
\f
+/* Determine whether TYPE is a structure with a flexible array member,
+ or a union containing such a structure (possibly recursively). */
+
+static bool
+flexible_array_type_p (tree type)
+{
+ tree x;
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ x = TYPE_FIELDS (type);
+ if (x == NULL_TREE)
+ return false;
+ while (TREE_CHAIN (x) != NULL_TREE)
+ x = TREE_CHAIN (x);
+ if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+ && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+ && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
+ return true;
+ return false;
+ case UNION_TYPE:
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = TREE_CHAIN (x))
+ {
+ if (flexible_array_type_p (TREE_TYPE (x)))
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+\f
/* Given declspecs and a declarator,
determine the name and type of the object declared
and construct a ..._DECL node for it.
and `extern' are interpreted. */
static tree
-grokdeclarator (declarator, declspecs, decl_context, initialized)
- tree declspecs;
- tree declarator;
- enum decl_context decl_context;
- int initialized;
+grokdeclarator (tree declarator, tree declspecs,
+ enum decl_context decl_context, int initialized)
{
int specbits = 0;
tree spec;
enum rid i = C_RID_CODE (id);
if ((int) i <= (int) RID_LAST_MODIFIER)
{
- if (i == RID_LONG && (specbits & (1 << (int) i)))
+ if (i == RID_LONG && (specbits & (1 << (int) RID_LONG)))
{
if (longlong)
error ("`long long long' is too long for GCC");
{
if (pedantic && !flag_isoc99 && ! in_system_header
&& warn_long_long)
- pedwarn ("ISO C89 does not support `long long'");
+ pedwarn ("ISO C90 does not support `long long'");
longlong = 1;
}
}
else if (specbits & (1 << (int) i))
- pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
+ {
+ if (i == RID_CONST || i == RID_VOLATILE || i == RID_RESTRICT)
+ {
+ if (!flag_isoc99)
+ pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
+ }
+ else
+ error ("duplicate `%s'", IDENTIFIER_POINTER (id));
+ }
+
+ /* Diagnose "__thread extern". Recall that this list
+ is in the reverse order seen in the text. */
+ if (i == RID_THREAD
+ && (specbits & (1 << (int) RID_EXTERN
+ | 1 << (int) RID_STATIC)))
+ {
+ if (specbits & 1 << (int) RID_EXTERN)
+ error ("`__thread' before `extern'");
+ else
+ error ("`__thread' before `static'");
+ }
+
specbits |= 1 << (int) i;
goto found;
}
else
{
ok = 1;
- if (!explicit_int && !defaulted_int && !explicit_char && pedantic)
+ if (!explicit_int && !defaulted_int && !explicit_char)
{
- pedwarn ("long, short, signed or unsigned used invalidly for `%s'",
- name);
- if (flag_pedantic_errors)
- ok = 0;
+ error ("long, short, signed or unsigned used invalidly for `%s'",
+ name);
+ ok = 0;
}
}
if (specbits & 1 << (int) RID_COMPLEX)
{
if (pedantic && !flag_isoc99)
- pedwarn ("ISO C89 does not support complex types");
+ pedwarn ("ISO C90 does not support complex types");
/* 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
if (specbits & 1 << (int) RID_REGISTER) nclasses++;
if (specbits & 1 << (int) RID_TYPEDEF) nclasses++;
+ /* "static __thread" and "extern __thread" are allowed. */
+ if ((specbits & (1 << (int) RID_THREAD
+ | 1 << (int) RID_STATIC
+ | 1 << (int) RID_EXTERN)) == (1 << (int) RID_THREAD))
+ nclasses++;
+
/* Warn about storage classes that are invalid for certain
kinds of declarations (parameters, typenames, etc.). */
&& (specbits
& ((1 << (int) RID_REGISTER)
| (1 << (int) RID_AUTO)
- | (1 << (int) RID_TYPEDEF))))
+ | (1 << (int) RID_TYPEDEF)
+ | (1 << (int) RID_THREAD))))
{
if (specbits & 1 << (int) RID_AUTO
&& (pedantic || current_binding_level == global_binding_level))
error ("function definition declared `register'");
if (specbits & 1 << (int) RID_TYPEDEF)
error ("function definition declared `typedef'");
+ if (specbits & 1 << (int) RID_THREAD)
+ error ("function definition declared `__thread'");
specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
- | (1 << (int) RID_AUTO));
+ | (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD));
}
else if (decl_context != NORMAL && nclasses > 0)
{
}
specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
| (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
- | (1 << (int) RID_EXTERN));
+ | (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD));
}
}
else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
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 (current_binding_level == global_binding_level)
+ {
+ if (specbits & 1 << (int) RID_AUTO)
+ error ("top-level declaration of `%s' specifies `auto'", name);
+ }
+ else
+ {
+ if (specbits & 1 << (int) RID_EXTERN && funcdef_flag)
+ error ("nested function `%s' declared `extern'", name);
+ else if ((specbits & (1 << (int) RID_THREAD
+ | 1 << (int) RID_EXTERN
+ | 1 << (int) RID_STATIC))
+ == (1 << (int) RID_THREAD))
+ {
+ error ("function-scope `%s' implicitly auto and declared `__thread'",
+ name);
+ specbits &= ~(1 << (int) RID_THREAD);
+ }
+ }
}
/* Now figure out the structure of the declarator proper.
type = error_mark_node;
}
+ if (pedantic && flexible_array_type_p (type))
+ pedwarn ("invalid use of structure with flexible array member");
+
if (size == error_mark_node)
type = error_mark_node;
if (!flag_isoc99 && pedantic)
{
if (TREE_CONSTANT (size))
- pedwarn ("ISO C89 forbids array `%s' whose size can't be evaluated",
+ pedwarn ("ISO C90 forbids array `%s' whose size can't be evaluated",
name);
else
- pedwarn ("ISO C89 forbids variable-size array `%s'",
+ pedwarn ("ISO C90 forbids variable-size array `%s'",
name);
}
}
}
if (size_varies)
- itype = variable_size (itype);
+ {
+ /* We must be able to distinguish the
+ SAVE_EXPR_CONTEXT for the variably-sized type
+ so that we can set it correctly in
+ set_save_expr_context. The convention is
+ that all SAVE_EXPRs that need to be reset
+ have NULL_TREE for their SAVE_EXPR_CONTEXT. */
+ tree cfd = current_function_decl;
+ if (decl_context == PARM)
+ current_function_decl = NULL_TREE;
+ itype = variable_size (itype);
+ if (decl_context == PARM)
+ current_function_decl = cfd;
+ }
itype = build_index_type (itype);
}
}
else if (decl_context == FIELD)
{
if (pedantic && !flag_isoc99 && !in_system_header)
- pedwarn ("ISO C89 does not support flexible array members");
+ pedwarn ("ISO C90 does not support flexible array members");
/* ISO C99 Flexible array members are effectively identical
to GCC's zero-length array extension. */
{
/* Type qualifiers on a function return type are normally
permitted by the standard but have no effect, so give a
- warning at -W. Qualifiers on a void return type have
+ warning at -Wextra. Qualifiers on a void return type have
meaning as a GNU extension, and are banned on function
definitions in ISO C. FIXME: strictly we shouldn't
pedwarn for qualified void return types except on function
}
else if (type_quals)
type = c_build_qualified_type (type, type_quals);
-
+
type_as_written = type;
decl = build_decl (PARM_DECL, declarator, type);
pedwarn ("invalid storage class for function `%s'", name);
if (specbits & (1 << (int) RID_REGISTER))
error ("invalid storage class for function `%s'", name);
+ if (specbits & (1 << (int) RID_THREAD))
+ 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. */
needed, and let dwarf2 know that the function is inlinable. */
else if (flag_inline_trees == 2 && initialized)
{
+ if (!DECL_INLINE (decl))
+ DID_INLINE_FUNC (decl) = 1;
DECL_INLINE (decl) = 1;
DECL_DECLARED_INLINE_P (decl) = 0;
}
}
else if (type_quals)
type = c_build_qualified_type (type, type_quals);
-
+
+ /* It is invalid to create an `extern' declaration for a
+ variable if there is a global declaration that is
+ `static'. */
+ if (extern_ref && current_binding_level != global_binding_level)
+ {
+ tree global_decl;
+
+ global_decl = identifier_global_value (declarator);
+ if (global_decl
+ && TREE_CODE (global_decl) == VAR_DECL
+ && !TREE_PUBLIC (global_decl))
+ error ("variable previously declared `static' redeclared "
+ "`extern'");
+ }
+
decl = build_decl (VAR_DECL, declarator, type);
if (size_varies)
C_DECL_VARIABLE_SIZE (decl) = 1;
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);
+ TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC)
+ | (1 << (int) RID_REGISTER)));
+ TREE_STATIC (decl) = !extern_ref;
}
/* 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);
+ TREE_PUBLIC (decl) = extern_ref;
+ }
+
+ if (specbits & 1 << (int) RID_THREAD)
+ {
+ if (targetm.have_tls)
+ DECL_THREAD_LOCAL (decl) = 1;
+ else
+ /* A mere warning is sure to result in improper semantics
+ at runtime. Don't bother to allow this to compile. */
+ error ("thread-local storage not supported for this target");
}
}
when FUNCDEF_FLAG is zero. */
static tree
-grokparms (parms_info, funcdef_flag)
- tree parms_info;
- int funcdef_flag;
+grokparms (tree parms_info, int funcdef_flag)
{
tree first_parm = TREE_CHAIN (parms_info);
Zero means the parmlist ended with an ellipsis so don't append `void'. */
tree
-get_parm_info (void_at_end)
- int void_at_end;
+get_parm_info (int void_at_end)
{
tree decl, t;
tree types = 0;
defined within. Do so because these types cannot ever become complete. */
void
-parmlist_tags_warning ()
+parmlist_tags_warning (void)
{
tree elt;
static int already;
Define the tag as a forward-reference if it is not defined. */
tree
-xref_tag (code, name)
- enum tree_code code;
- tree name;
+xref_tag (enum tree_code code, tree name)
{
/* If a cross reference is requested, look up the type
already defined for this tag and return it. */
- tree ref = lookup_tag (code, name, current_binding_level, 0);
+ tree ref = lookup_tag (code, name, 0);
/* If this is the right type of tag, return what we found.
(This reference will be shadowed by shadow_tag later if appropriate.)
If this is the wrong type of tag, do not return it. If it was the
CODE says which kind of tag NAME ought to be. */
tree
-start_struct (code, name)
- enum tree_code code;
- tree name;
+start_struct (enum tree_code code, tree name)
{
/* If there is already a tag defined at this binding level
(as a forward reference), just return it. */
tree ref = 0;
if (name != 0)
- ref = lookup_tag (code, name, current_binding_level, 1);
+ ref = lookup_tag (code, name, 1);
if (ref && TREE_CODE (ref) == code)
{
- C_TYPE_BEING_DEFINED (ref) = 1;
- TYPE_PACKED (ref) = flag_pack_struct;
if (TYPE_FIELDS (ref))
{
if (code == UNION_TYPE)
- error ("redefinition of `union %s'",
- IDENTIFIER_POINTER (name));
+ error ("redefinition of `union %s'", IDENTIFIER_POINTER (name));
else
- error ("redefinition of `struct %s'",
- IDENTIFIER_POINTER (name));
- }
-
- return ref;
+ error ("redefinition of `struct %s'", IDENTIFIER_POINTER (name));
+ }
}
+ else
+ {
+ /* Otherwise create a forward-reference just so the tag is in scope. */
- /* Otherwise create a forward-reference just so the tag is in scope. */
+ ref = make_node (code);
+ pushtag (name, ref);
+ }
- ref = make_node (code);
- pushtag (name, ref);
C_TYPE_BEING_DEFINED (ref) = 1;
TYPE_PACKED (ref) = flag_pack_struct;
return ref;
are ultimately passed to `build_struct' to make the RECORD_TYPE node. */
tree
-grokfield (filename, line, declarator, declspecs, width)
- const char *filename ATTRIBUTE_UNUSED;
- int line ATTRIBUTE_UNUSED;
- tree declarator, declspecs, width;
+grokfield (tree declarator, tree declspecs, tree width)
{
tree value;
if (declarator == NULL_TREE && width == NULL_TREE)
{
- /* This is an unnamed decl. We only support unnamed
- structs/unions, so check for other things and refuse them. */
- if (TREE_CODE (TREE_VALUE (declspecs)) != RECORD_TYPE
- && TREE_CODE (TREE_VALUE (declspecs)) != UNION_TYPE)
+ /* This is an unnamed decl.
+
+ If we have something of the form "union { list } ;" then this
+ is the anonymous union extension. Similarly for struct.
+
+ If this is something of the form "struct foo;", then
+ If MS extensions are enabled, this is handled as an
+ anonymous struct.
+ Otherwise this is a forward declaration of a structure tag.
+
+ If this is something of the form "foo;" and foo is a TYPE_DECL, then
+ If MS extensions are enabled and foo names a structure, then
+ again this is an anonymous struct.
+ Otherwise this is an error.
+
+ Oh what a horrid tangled web we weave. I wonder if MS consciously
+ took this from Plan 9 or if it was an accident of implementation
+ that took root before someone noticed the bug... */
+
+ tree type = TREE_VALUE (declspecs);
+
+ if (flag_ms_extensions && TREE_CODE (type) == TYPE_DECL)
+ type = TREE_TYPE (type);
+ if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)
+ {
+ if (flag_ms_extensions)
+ ; /* ok */
+ else if (flag_iso)
+ goto warn_unnamed_field;
+ else if (TYPE_NAME (type) == NULL)
+ ; /* ok */
+ else
+ goto warn_unnamed_field;
+ }
+ else
{
- error ("unnamed fields of type other than struct or union are not allowed");
+ warn_unnamed_field:
+ warning ("declaration does not declare anything");
return NULL_TREE;
}
}
finish_decl (value, NULL_TREE, NULL_TREE);
DECL_INITIAL (value) = width;
- maybe_objc_check_decl (value);
+ if (c_dialect_objc ())
+ objc_check_decl (value);
return value;
}
\f
+/* Generate an error for any duplicate field names in FIELDLIST. Munge
+ the list such that this does not present a problem later. */
+
+static void
+detect_field_duplicates (tree fieldlist)
+{
+ tree x, y;
+ int timeout = 10;
+
+ /* First, see if there are more than "a few" fields.
+ This is trivially true if there are zero or one fields. */
+ if (!fieldlist)
+ return;
+ x = TREE_CHAIN (fieldlist);
+ if (!x)
+ return;
+ do {
+ timeout--;
+ x = TREE_CHAIN (x);
+ } while (timeout > 0 && x);
+
+ /* If there were "few" fields, avoid the overhead of allocating
+ a hash table. Instead just do the nested traversal thing. */
+ if (timeout > 0)
+ {
+ for (x = TREE_CHAIN (fieldlist); x ; x = TREE_CHAIN (x))
+ if (DECL_NAME (x))
+ {
+ for (y = fieldlist; y != x; y = TREE_CHAIN (y))
+ if (DECL_NAME (y) == DECL_NAME (x))
+ {
+ error_with_decl (x, "duplicate member `%s'");
+ DECL_NAME (x) = NULL_TREE;
+ }
+ }
+ }
+ else
+ {
+ htab_t htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
+ void **slot;
+
+ for (x = fieldlist; x ; x = TREE_CHAIN (x))
+ if ((y = DECL_NAME (x)) != 0)
+ {
+ slot = htab_find_slot (htab, y, INSERT);
+ if (*slot)
+ {
+ error_with_decl (x, "duplicate member `%s'");
+ DECL_NAME (x) = NULL_TREE;
+ }
+ *slot = y;
+ }
+
+ htab_delete (htab);
+ }
+}
+
/* 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. */
tree
-finish_struct (t, fieldlist, attributes)
- tree t;
- tree fieldlist;
- tree attributes;
+finish_struct (tree t, tree fieldlist, tree attributes)
{
tree x;
int toplevel = global_binding_level == current_binding_level;
DECL_SIZE (x) = bitsize_int (width);
DECL_BIT_FIELD (x) = 1;
SET_DECL_C_BIT_FIELD (x);
-
- if (width == 0
- && ! (* targetm.ms_bitfield_layout_p) (t))
- {
- /* 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)));
- DECL_USER_ALIGN (x) |= TYPE_USER_ALIGN (TREE_TYPE (x));
- }
-#endif
- }
}
}
- else if (TREE_TYPE (x) != error_mark_node)
- {
- unsigned int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT
- : TYPE_ALIGN (TREE_TYPE (x)));
-
- /* 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);
- if (! DECL_PACKED (x))
- DECL_USER_ALIGN (x) |= TYPE_USER_ALIGN (TREE_TYPE (x));
- }
-
DECL_INITIAL (x) = 0;
/* Detect flexible array member in an invalid context. */
else if (! saw_named_field)
error_with_decl (x, "flexible array member in otherwise empty struct");
}
+
+ if (pedantic && TREE_CODE (t) == RECORD_TYPE
+ && flexible_array_type_p (TREE_TYPE (x)))
+ pedwarn_with_decl (x, "invalid use of structure with flexible array member");
+
if (DECL_NAME (x))
saw_named_field = 1;
}
- /* 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
- {
- 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);
- }
+ detect_field_duplicates (fieldlist);
/* Now we have the nearly final fieldlist. Record it,
then lay out the structure or union (including the fields). */
/* 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)
+ if (current_binding_level->incomplete_list != NULL_TREE)
{
- tree decl;
- for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl))
- {
+ tree prev = NULL_TREE;
+
+ for (x = current_binding_level->incomplete_list; x; x = TREE_CHAIN (x))
+ {
+ tree decl = TREE_VALUE (x);
+
if (TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == TYPE_MAIN_VARIANT (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);
+ /* This is a no-op in c-lang.c or something real in objc-act.c. */
+ if (c_dialect_objc ())
+ objc_check_decl (decl);
rest_of_decl_compilation (decl, NULL, toplevel, 0);
if (! toplevel)
expand_decl (decl);
- if (--current_binding_level->n_incomplete == 0)
- break;
+ /* Unlink X from the incomplete list. */
+ if (prev)
+ TREE_CHAIN (prev) = TREE_CHAIN (x);
+ else
+ current_binding_level->incomplete_list = TREE_CHAIN (x);
}
else if (!COMPLETE_TYPE_P (TREE_TYPE (decl))
&& TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
if (TREE_CODE (decl) != TYPE_DECL)
{
layout_decl (decl, 0);
- maybe_objc_check_decl (decl);
+ if (c_dialect_objc ())
+ objc_check_decl (decl);
rest_of_decl_compilation (decl, NULL, toplevel, 0);
if (! toplevel)
expand_decl (decl);
}
- if (--current_binding_level->n_incomplete == 0)
- break;
+ /* Unlink X from the incomplete list. */
+ if (prev)
+ TREE_CHAIN (prev) = TREE_CHAIN (x);
+ else
+ current_binding_level->incomplete_list = TREE_CHAIN (x);
}
}
}
/* Lay out the type T, and its element type, and so on. */
static void
-layout_array_type (t)
- tree t;
+layout_array_type (tree t)
{
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
layout_array_type (TREE_TYPE (t));
may be used to declare the individual values as they are read. */
tree
-start_enum (name)
- tree name;
+start_enum (tree name)
{
tree enumtype = 0;
forward reference. */
if (name != 0)
- enumtype = lookup_tag (ENUMERAL_TYPE, name, current_binding_level, 1);
+ enumtype = lookup_tag (ENUMERAL_TYPE, name, 1);
if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE)
{
Returns ENUMTYPE. */
tree
-finish_enum (enumtype, values, attributes)
- tree enumtype;
- tree values;
- tree attributes;
+finish_enum (tree enumtype, tree values, tree attributes)
{
tree pair, tem;
tree minnode = 0, maxnode = 0, enum_value_type;
tree enu = TREE_PURPOSE (pair);
TREE_TYPE (enu) = enumtype;
- DECL_SIZE (enu) = TYPE_SIZE (enumtype);
- DECL_SIZE_UNIT (enu) = TYPE_SIZE_UNIT (enumtype);
- DECL_ALIGN (enu) = TYPE_ALIGN (enumtype);
- DECL_USER_ALIGN (enu) = TYPE_USER_ALIGN (enumtype);
- DECL_MODE (enu) = TYPE_MODE (enumtype);
/* The ISO C Standard mandates enumerators to have type int,
even though the underlying type of an enum type is
Assignment of sequential values by default is handled here. */
tree
-build_enumerator (name, value)
- tree name, value;
+build_enumerator (tree name, tree value)
{
tree decl, type;
yyparse to report a parse error. */
int
-start_function (declspecs, declarator, attributes)
- tree declarator, declspecs, attributes;
+start_function (tree declspecs, tree declarator, tree attributes)
{
tree decl1, old_decl;
tree restype;
current_function_returns_abnormally = 0;
warn_about_return_type = 0;
current_extern_inline = 0;
- c_function_varargs = 0;
named_labels = 0;
shadowed_labels = 0;
&& 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);
+ current_function_prototype_locus = DECL_SOURCE_LOCATION (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
- || (DECL_BUILT_IN (old_decl)
- && ! C_DECL_ANTICIPATED (old_decl)))))
+ && C_DECL_ISNT_PROTOTYPE (old_decl))
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
- || (DECL_BUILT_IN (old_decl)
- && ! C_DECL_ANTICIPATED (old_decl))))
- && ! MAIN_NAME_P (DECL_NAME (decl1)))
+ && ! MAIN_NAME_P (DECL_NAME (decl1))
+ && C_DECL_ISNT_PROTOTYPE (old_decl))
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. */
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)))
+ && C_DECL_IMPLICIT (old_decl))
warning_with_decl (decl1,
"`%s' was used with no declaration before its definition");
pushlevel (0);
declare_parm_level (1);
- current_binding_level->subblocks_tag_transparent = 1;
make_decl_rtl (current_function_decl, NULL);
immediate_size_expand = old_immediate_size_expand;
start_fname_decls ();
-
- 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;
+ return 1;
}
\f
/* Store the parameter declarations into the current function declaration.
to specify at least the number of arguments. */
void
-store_parm_decls ()
+store_parm_decls (void)
{
tree fndecl = current_function_decl;
tree parm;
/* Nonzero if this definition is written with a prototype. */
int prototype = 0;
- int saved_warn_shadow = warn_shadow;
+ bool saved_warn_shadow = warn_shadow;
/* Don't re-emit shadow warnings. */
- warn_shadow = 0;
+ warn_shadow = false;
if (specparms != 0 && TREE_CODE (specparms) != TREE_LIST)
{
for (decl = current_binding_level->names;
decl; decl = TREE_CHAIN (decl))
if (DECL_NAME (decl))
- IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) = 0;
+ IDENTIFIER_SYMBOL_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);
+ IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
current_binding_level->names = 0;
current_binding_level->shadowed = 0;
}
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);
+ DECL_SOURCE_LOCATION (found) = DECL_SOURCE_LOCATION (fndecl);
if (flag_isoc99)
pedwarn_with_decl (found, "type of `%s' defaults to `int'");
else if (extra_warnings)
|| 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");
+ error ("%Hprototype declaration",
+ ¤t_function_prototype_locus);
break;
}
/* Type for passing arg must be consistent with that
{
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");
+ warning ("%Hprototype declaration",
+ ¤t_function_prototype_locus);
}
}
else
{
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");
+ error ("%Hprototype declaration",
+ ¤t_function_prototype_locus);
}
}
}
gen_aux_info_record (fndecl, 1, 0, prototype);
/* Initialize the RTL code for the function. */
- init_function_start (fndecl, input_filename, lineno);
+ init_function_start (fndecl);
/* Begin the statement tree for this function. */
begin_stmt_tree (&DECL_SAVED_TREE (current_function_decl));
{
tree t;
- DECL_LANG_SPECIFIC (fndecl)->pending_sizes
+ DECL_LANG_SPECIFIC (fndecl)->pending_sizes
= nreverse (get_pending_sizes ());
for (t = DECL_LANG_SPECIFIC (fndecl)->pending_sizes;
t;
CAN_DEFER_P is nonzero if the function may be deferred. */
void
-finish_function (nested, can_defer_p)
- int nested;
- int can_defer_p;
+finish_function (int nested, int can_defer_p)
{
tree fndecl = current_function_decl;
+ /* When a function declaration is totally empty, e.g.
+ void foo(void) { }
+ (the argument list is irrelevant) the compstmt rule will not
+ bother calling pushlevel/poplevel, which means we get here with
+ the binding_level stack out of sync. Detect this situation by
+ noticing that the current_binding_level is still as
+ store_parm_decls left it, and do a dummy push/pop to get back to
+ consistency. Note that the call to pushlevel does not actually
+ push another binding level - see there for details. */
+ if (current_binding_level->parm_flag && keep_next_if_subblocks)
+ {
+ pushlevel (0);
+ poplevel (1, 0, 1);
+ }
+
#if 0
/* This caused &foo to be of type ptr-to-const-function which then
got a warning when stored in a ptr-to-function variable. */
TREE_READONLY (fndecl) = 1;
#endif
- poplevel (1, 0, 1);
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
/* Must mark the RESULT_DECL as being in this function. */
#endif
}
}
-
+
finish_fname_decls ();
/* Tie off the statement tree for this function. */
free_after_compilation (cfun);
cfun = NULL;
+ if (flag_unit_at_a_time && can_defer_p)
+ {
+ cgraph_finalize_function (fndecl, DECL_SAVED_TREE (fndecl));
+ current_function_decl = NULL;
+ return;
+ }
+
if (! nested)
{
- /* Generate RTL for the body of this function. */
- c_expand_body (fndecl, nested, can_defer_p);
+ /* Function is parsed.
+ Generate RTL for the body of this function or defer
+ it for later expansion. */
+ int uninlinable = 1;
+
+ /* There's no reason to do any of the work here if we're only doing
+ semantic analysis; this code just generates RTL. */
+ if (flag_syntax_only)
+ {
+ current_function_decl = NULL;
+ DECL_SAVED_TREE (fndecl) = NULL_TREE;
+ return;
+ }
+
+ if (flag_inline_trees)
+ {
+ /* First, cache whether the current function is inlinable. Some
+ predicates depend on cfun and current_function_decl to
+ function completely. */
+ timevar_push (TV_INTEGRATION);
+ uninlinable = ! tree_inlinable_function_p (fndecl, 0);
+
+ if (can_defer_p
+ /* We defer functions marked inline *even if* the function
+ itself is not inlinable. This is because we don't yet
+ know if the function will actually be used; we may be
+ able to avoid emitting it entirely. */
+ && (! uninlinable || DECL_DECLARED_INLINE_P (fndecl))
+ /* Save function tree for inlining. Should return 0 if the
+ language does not support function deferring or the
+ function could not be deferred. */
+ && defer_fn (fndecl))
+ {
+ /* Let the back-end know that this function exists. */
+ (*debug_hooks->deferred_inline_function) (fndecl);
+ timevar_pop (TV_INTEGRATION);
+ current_function_decl = NULL;
+ return;
+ }
+
+ /* Then, inline any functions called in it. */
+ optimize_inline_calls (fndecl);
+ timevar_pop (TV_INTEGRATION);
+ }
+
+ c_expand_body (fndecl);
+
+ /* Keep the function body if it's needed for inlining or dumping. */
+ if (uninlinable && !dump_enabled_p (TDI_all))
+ {
+ /* Allow the body of the function to be garbage collected. */
+ DECL_SAVED_TREE (fndecl) = NULL_TREE;
+ }
/* Let the error reporting routines know that we're outside a
function. For a nested function, this value is used in
/* Generate the RTL for a deferred function FNDECL. */
void
-c_expand_deferred_function (fndecl)
- tree fndecl;
+c_expand_deferred_function (tree fndecl)
{
/* DECL_INLINE or DECL_RESULT might got cleared after the inline
function was deferred, e.g. in duplicate_decls. */
if (DECL_INLINE (fndecl) && DECL_RESULT (fndecl))
{
- c_expand_body (fndecl, 0, 0);
+ if (flag_inline_trees)
+ {
+ timevar_push (TV_INTEGRATION);
+ optimize_inline_calls (fndecl);
+ timevar_pop (TV_INTEGRATION);
+ }
+ c_expand_body (fndecl);
current_function_decl = NULL;
}
}
-/* Generate the RTL for the body of FNDECL. If NESTED_P is non-zero,
+/* Called to move the SAVE_EXPRs for parameter declarations in a
+ nested function into the nested function. DATA is really the
+ nested FUNCTION_DECL. */
+
+static tree
+set_save_expr_context (tree *tp,
+ int *walk_subtrees,
+ void *data)
+{
+ if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp))
+ SAVE_EXPR_CONTEXT (*tp) = (tree) data;
+ /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause
+ circularity. */
+ else if (DECL_P (*tp))
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
+}
+
+/* Generate the RTL for the body of FNDECL. If NESTED_P is nonzero,
then we are already in the process of generating RTL for another
function. If can_defer_p is zero, we won't attempt to defer the
generation of RTL. */
static void
-c_expand_body (fndecl, nested_p, can_defer_p)
- tree fndecl;
- int nested_p, can_defer_p;
+c_expand_body_1 (tree fndecl, int nested_p)
{
- int uninlinable = 1;
-
- /* There's no reason to do any of the work here if we're only doing
- semantic analysis; this code just generates RTL. */
- if (flag_syntax_only)
- return;
-
- if (flag_inline_trees)
- {
- /* First, cache whether the current function is inlinable. Some
- predicates depend on cfun and current_function_decl to
- function completely. */
- timevar_push (TV_INTEGRATION);
- uninlinable = ! tree_inlinable_function_p (fndecl);
-
- if (! uninlinable && can_defer_p
- /* Save function tree for inlining. Should return 0 if the
- language does not support function deferring or the
- function could not be deferred. */
- && defer_fn (fndecl))
- {
- /* Let the back-end know that this function exists. */
- (*debug_hooks->deferred_inline_function) (fndecl);
- timevar_pop (TV_INTEGRATION);
- return;
- }
-
- /* Then, inline any functions called in it. */
- optimize_inline_calls (fndecl);
- timevar_pop (TV_INTEGRATION);
- }
-
timevar_push (TV_EXPAND);
if (nested_p)
/* Initialize the RTL code for the function. */
current_function_decl = fndecl;
- input_filename = DECL_SOURCE_FILE (fndecl);
- init_function_start (fndecl, input_filename, DECL_SOURCE_LINE (fndecl));
+ input_location = DECL_SOURCE_LOCATION (fndecl);
+ init_function_start (fndecl);
/* This function is being processed in whole-function mode. */
cfun->x_whole_function_mode_p = 1;
immediate_size_expand = 0;
cfun->x_dont_save_pending_sizes_p = 1;
- /* If this is a varargs function, inform function.c. */
- if (c_function_varargs)
- mark_varargs ();
-
/* Set up parameters and prepare for return, for the function. */
expand_function_start (fndecl, 0);
+ /* If the function has a variably modified type, there may be
+ SAVE_EXPRs in the parameter types. Their context must be set to
+ refer to this function; they cannot be expanded in the containing
+ function. */
+ if (decl_function_context (fndecl)
+ && variably_modified_type_p (TREE_TYPE (fndecl)))
+ walk_tree (&TREE_TYPE (fndecl), set_save_expr_context, fndecl,
+ NULL);
+
/* If this function is `main', emit a call to `__main'
to run global initializers, etc. */
if (DECL_NAME (fndecl)
/* Generate the RTL for this function. */
expand_stmt (DECL_SAVED_TREE (fndecl));
- if (uninlinable)
- {
- /* Allow the body of the function to be garbage collected. */
- DECL_SAVED_TREE (fndecl) = NULL_TREE;
- }
/* We hard-wired immediate_size_expand to zero above.
expand_function_end will decrement this variable. So, we set the
(*lang_expand_function_end) ();
/* Generate rtl for function exit. */
- expand_function_end (input_filename, lineno, 0);
+ expand_function_end ();
/* If this is a nested function, protect the local variables in the stack
above us from being collected while we're compiling this function. */
if (nested_p)
ggc_pop_context ();
- /* With just -W, complain only if function returns both with
+ /* With just -Wextra, complain only if function returns both with
and without a value. */
if (extra_warnings
&& current_function_returns_value
pop_function_context ();
timevar_pop (TV_EXPAND);
}
+
+/* Like c_expand_body_1 but only for unnested functions. */
+
+void
+c_expand_body (tree fndecl)
+{
+ c_expand_body_1 (fndecl, 0);
+}
\f
/* Check the declarations given in a for-loop for satisfying the C99
constraints. */
void
-check_for_loop_decls ()
+check_for_loop_decls (void)
{
tree t;
if (TREE_PURPOSE (t) != 0)
{
enum tree_code code = TREE_CODE (TREE_VALUE (t));
-
+
if (code == RECORD_TYPE)
error ("`struct %s' declared in `for' loop initial declaration",
IDENTIFIER_POINTER (TREE_PURPOSE (t)));
that keep track of the progress of compilation of the current function.
Used for nested functions. */
-struct c_language_function
+struct language_function GTY(())
{
- struct language_function base;
+ struct c_language_function base;
tree named_labels;
tree shadowed_labels;
int returns_value;
used during compilation of a C function. */
void
-c_push_function_context (f)
- struct function *f;
+c_push_function_context (struct function *f)
{
- struct c_language_function *p;
- p = ((struct c_language_function *)
- xmalloc (sizeof (struct c_language_function)));
- f->language = (struct language_function *) p;
+ struct language_function *p;
+ p = ((struct language_function *)
+ ggc_alloc (sizeof (struct language_function)));
+ f->language = p;
p->base.x_stmt_tree = c_stmt_tree;
p->base.x_scope_stmt_stack = c_scope_stmt_stack;
/* Restore the variables used during compilation of a C function. */
void
-c_pop_function_context (f)
- struct function *f;
+c_pop_function_context (struct function *f)
{
- struct c_language_function *p
- = (struct c_language_function *) f->language;
+ struct language_function *p = f->language;
tree link;
/* Bring back all the labels that were shadowed. */
current_extern_inline = p->extern_inline;
current_binding_level = p->binding_level;
- free (p);
- f->language = 0;
-}
-
-/* Mark the language specific parts of F for GC. */
-
-void
-c_mark_function_context (f)
- struct function *f;
-{
- struct c_language_function *p
- = (struct c_language_function *) f->language;
-
- if (p == 0)
- return;
-
- mark_c_language_function (&p->base);
- ggc_mark_tree (p->shadowed_labels);
- ggc_mark_tree (p->named_labels);
- mark_binding_level (&p->binding_level);
+ f->language = NULL;
}
/* Copy the DECL_LANG_SPECIFIC data associated with DECL. */
void
-c_dup_lang_specific_decl (decl)
- tree decl;
+c_dup_lang_specific_decl (tree decl)
{
struct lang_decl *ld;
DECL_LANG_SPECIFIC (decl) = ld;
}
-/* Mark the language specific bits in T for GC. */
-
-void
-c_mark_tree (t)
- tree t;
-{
- if (TREE_CODE (t) == IDENTIFIER_NODE)
- {
- struct lang_identifier *i = (struct lang_identifier *) t;
- ggc_mark_tree (i->global_value);
- ggc_mark_tree (i->local_value);
- ggc_mark_tree (i->label_value);
- ggc_mark_tree (i->implicit_decl);
- ggc_mark_tree (i->error_locus);
- ggc_mark_tree (i->limbo_value);
- }
- else if (TYPE_P (t) && TYPE_LANG_SPECIFIC (t))
- ggc_mark (TYPE_LANG_SPECIFIC (t));
- else if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
- {
- ggc_mark (DECL_LANG_SPECIFIC (t));
- c_mark_lang_decl (&DECL_LANG_SPECIFIC (t)->base);
- ggc_mark_tree (DECL_LANG_SPECIFIC (t)->pending_sizes);
- }
-}
-
/* The functions below are required for functionality of doing
function at once processing in the C front end. Currently these
functions are not called from anywhere in the C front end, but as
these changes continue, that will change. */
-/* Returns non-zero if the current statement is a full expression,
+/* Returns nonzero if the current statement is a full expression,
i.e. temporaries created during that statement should be destroyed
at the end of the statement. */
int
-stmts_are_full_exprs_p ()
+stmts_are_full_exprs_p (void)
{
return 0;
}
returned. */
stmt_tree
-current_stmt_tree ()
+current_stmt_tree (void)
{
return &c_stmt_tree;
}
/* Returns the stack of SCOPE_STMTs for the current function. */
tree *
-current_scope_stmt_stack ()
+current_scope_stmt_stack (void)
{
return &c_scope_stmt_stack;
}
C. */
int
-anon_aggr_type_p (node)
- tree node ATTRIBUTE_UNUSED;
+anon_aggr_type_p (tree node ATTRIBUTE_UNUSED)
{
return 0;
}
/* Dummy function in place of callback used by C++. */
void
-extract_interface_info ()
+extract_interface_info (void)
{
}
statement tree. */
tree
-c_begin_compound_stmt ()
+c_begin_compound_stmt (void)
{
tree stmt;
common code. */
void
-c_expand_decl_stmt (t)
- tree t;
+c_expand_decl_stmt (tree t)
{
tree decl = DECL_STMT_DECL (t);
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_CONTEXT (decl) == current_function_decl
&& DECL_SAVED_TREE (decl))
- c_expand_body (decl, /*nested_p=*/1, /*can_defer_p=*/0);
+ c_expand_body_1 (decl, 1);
}
-/* Return the IDENTIFIER_GLOBAL_VALUE of T, for use in common code, since
- the definition of IDENTIFIER_GLOBAL_VALUE is different for C and C++. */
+/* Return the global value of T as a symbol. */
tree
-identifier_global_value (t)
- tree t;
+identifier_global_value (tree t)
{
- return IDENTIFIER_GLOBAL_VALUE (t);
+ tree decl = IDENTIFIER_SYMBOL_VALUE (t);
+ if (decl == 0 || DECL_CONTEXT (decl) == 0)
+ return decl;
+
+ /* Shadowed by something else; find the true global value. */
+ for (decl = global_binding_level->names; decl; decl = TREE_CHAIN (decl))
+ if (DECL_NAME (decl) == t)
+ return decl;
+
+ /* Only local values for this decl. */
+ return 0;
}
/* Record a builtin type for C. If NAME is non-NULL, it is the name used;
otherwise the name is found in ridpointers from RID_INDEX. */
void
-record_builtin_type (rid_index, name, type)
- enum rid rid_index;
- const char *name;
- tree type;
+record_builtin_type (enum rid rid_index, const char *name, tree type)
{
tree id;
if (name == 0)
/* Build the void_list_node (void_type_node having been created). */
tree
-build_void_list_node ()
+build_void_list_node (void)
{
tree t = build_tree_list (NULL_TREE, void_type_node);
return t;
}
+
+/* Return something to represent absolute declarators containing a *.
+ TARGET is the absolute declarator that the * contains.
+ TYPE_QUALS_ATTRS is a list of modifiers such as const or volatile
+ to apply to the pointer type, represented as identifiers, possible mixed
+ with attributes.
+
+ We return an INDIRECT_REF whose "contents" are TARGET (inside a TREE_LIST,
+ if attributes are present) and whose type is the modifier list. */
+
+tree
+make_pointer_declarator (tree type_quals_attrs, tree target)
+{
+ tree quals, attrs;
+ tree itarget = target;
+ split_specs_attrs (type_quals_attrs, &quals, &attrs);
+ if (attrs != NULL_TREE)
+ itarget = tree_cons (attrs, target, NULL_TREE);
+ return build1 (INDIRECT_REF, quals, itarget);
+}
+
+#include "gt-c-decl.h"