/* Process declarations and variables for C compiler.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#include "timevar.h"
#include "c-common.h"
#include "c-pragma.h"
+#include "langhooks.h"
+#include "tree-mudflap.h"
+#include "tree-gimple.h"
+#include "diagnostic.h"
+#include "tree-dump.h"
#include "cgraph.h"
#include "hashtab.h"
#include "libfuncs.h"
FUNCDEF, /* Function definition */
PARM, /* Declaration of parm before function body */
FIELD, /* Declaration inside struct or union */
- BITFIELD, /* Likewise but with specified width */
TYPENAME}; /* Typename (inside cast or sizeof) */
\f
/* Nonzero if we have seen an invalid cross reference
to a struct, union, or enum, but not yet printed the message. */
-
tree pending_invalid_xref;
+
/* File and line to appear in the eventual error message. */
location_t pending_invalid_xref_location;
+/* True means we've initialized exception handling. */
+bool c_eh_initialized_p;
+
/* While defining an enum type, this is 1 plus the last enumerator
constant value. Note that will do not have to save this or `enum_overflow'
around nested function definition since such a definition could only
static int enum_overflow;
-/* Parsing a function declarator leaves a list of parameter names
- or a chain of parameter decls here. */
-
-static tree last_function_parms;
-
-/* ... and a chain of structure and enum types declared in the
- parmlist here. */
-
-static tree last_function_parm_tags;
-
-/* ... and a chain of all non-parameter declarations (such as
- CONST_DECLs from enumerations) here. */
-
-static tree last_function_parm_others;
+/* These #defines are for clarity in working with the information block
+ returned by get_parm_info. */
+#define ARG_INFO_PARMS(args) TREE_PURPOSE(args)
+#define ARG_INFO_TAGS(args) TREE_VALUE(args)
+#define ARG_INFO_TYPES(args) TREE_CHAIN(args)
+#define ARG_INFO_OTHERS(args) TREE_TYPE(args)
-/* After parsing the declarator that starts a function definition,
- `start_function' puts the list of parameter names or chain of decls here
- for `store_parm_decls' to find. */
-
-static tree current_function_parms;
-
-/* Similar, for last_function_parm_tags. */
-
-static tree current_function_parm_tags;
-
-/* And for last_function_parm_others. */
-
-static tree current_function_parm_others;
-
-/* Similar, for the file and line that the prototype came from if this is
- an old-style definition. */
+/* The file and line that the prototype came from if this is an
+ old-style definition; used for diagnostics in
+ store_parm_decls_oldstyle. */
static location_t current_function_prototype_locus;
static GTY(()) struct stmt_tree_s c_stmt_tree;
-/* The current scope statement stack. */
-
-static GTY(()) tree c_scope_stmt_stack;
+/* State saving variables. */
+tree c_break_label;
+tree c_cont_label;
-/* 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;
+/* Linked list of TRANSLATION_UNIT_DECLS for the translation units
+ included in this invocation. Note that the current translation
+ unit is not included in this list. */
-/* All the builtins; this is a subset of the entries of global_scope. */
+static GTY(()) tree all_translation_units;
-static GTY(()) tree first_builtin_decl;
-static GTY(()) tree last_builtin_decl;
-
-/* A DECL for the current file-scope context. */
-
-static GTY(()) tree current_file_decl;
+/* A list of decls to be made automatically visible in each file scope. */
+static GTY(()) tree visible_builtins;
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */
/* Nonzero when starting a function declared `extern inline'. */
static int current_extern_inline;
+
+/* True means global_bindings_p should return false even if the scope stack
+ says we are in file scope. */
+bool c_override_global_bindings_to_false;
+
\f
-/* Each c_scope structure describes the complete contents of one scope.
- Three scopes are distinguished specially: the innermost or current
- scope, the innermost function scope, and the outermost or file scope.
+/* Each c_binding structure describes one binding of an identifier to
+ a decl. All the decls in a scope - irrespective of namespace - are
+ chained together by the ->prev field, which (as the name implies)
+ runs in reverse order. All the decls in a given namespace bound to
+ a given identifier are chained by the ->shadowed field, which runs
+ from inner to outer scopes.
+
+ The ->decl field usually points to a DECL node, but there are two
+ exceptions. In the namespace of type tags, the bound entity is a
+ RECORD_TYPE, UNION_TYPE, or ENUMERAL_TYPE node. If an undeclared
+ identifier is encountered, it is bound to error_mark_node to
+ suppress further errors about that identifier in the current
+ function.
+
+ The depth field is copied from the scope structure that holds this
+ decl. It is used to preserve the proper ordering of the ->shadowed
+ field (see bind()) and also for a handful of special-case checks.
+ Finally, the invisible bit is true for a decl which should be
+ ignored for purposes of normal name lookup, and the nested bit is
+ true for a decl that's been bound a second time in an inner scope;
+ in all such cases, the binding in the outer scope will have its
+ invisible bit true. */
+
+struct c_binding GTY((chain_next ("%h.prev")))
+{
+ tree decl; /* the decl bound */
+ tree id; /* the identifier it's bound to */
+ struct c_binding *prev; /* the previous decl in this scope */
+ struct c_binding *shadowed; /* the innermost decl shadowed by this one */
+ unsigned int depth : 28; /* depth of this scope */
+ BOOL_BITFIELD invisible : 1; /* normal lookup should ignore this binding */
+ BOOL_BITFIELD nested : 1; /* do not set DECL_CONTEXT when popping */
+ /* two free bits */
+};
+#define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth)
+#define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth)
+#define B_IN_FILE_SCOPE(b) ((b)->depth == 1 /*file_scope->depth*/)
+#define B_IN_EXTERNAL_SCOPE(b) ((b)->depth == 0 /*external_scope->depth*/)
+
+#define I_SYMBOL_BINDING(node) \
+ (((struct lang_identifier *)IDENTIFIER_NODE_CHECK(node))->symbol_binding)
+#define I_SYMBOL_DECL(node) \
+ (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0)
+
+#define I_TAG_BINDING(node) \
+ (((struct lang_identifier *)IDENTIFIER_NODE_CHECK(node))->tag_binding)
+#define I_TAG_DECL(node) \
+ (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0)
+
+#define I_LABEL_BINDING(node) \
+ (((struct lang_identifier *)IDENTIFIER_NODE_CHECK(node))->label_binding)
+#define I_LABEL_DECL(node) \
+ (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0)
+
+/* Each C symbol points to three linked lists of c_binding structures.
+ These describe the values of the identifier in the three different
+ namespaces defined by the language. */
+
+struct lang_identifier GTY(())
+{
+ struct c_common_identifier common_id;
+ struct c_binding *symbol_binding; /* vars, funcs, constants, typedefs */
+ struct c_binding *tag_binding; /* struct/union/enum tags */
+ struct c_binding *label_binding; /* labels */
+};
+
+/* Validate c-lang.c's assumptions. */
+extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate
+[(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1];
+
+/* The resulting tree type. */
+
+union lang_tree_node
+ GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+ chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *)TYPE_NEXT_VARIANT (&%h.generic) : (union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
+{
+ union tree_node GTY ((tag ("0"),
+ desc ("tree_node_structure (&%h)")))
+ generic;
+ struct lang_identifier GTY ((tag ("1"))) identifier;
+};
+
+/* Each c_scope structure describes the complete contents of one
+ scope. Four scopes are distinguished specially: the innermost or
+ current scope, the innermost function scope, the file scope (always
+ the second to outermost) and the outermost or external scope.
Most declarations are recorded in the current scope.
hence the 'innermost' qualifier.) Explicitly declared labels
(using the __label__ extension) appear in the current scope.
- Being in the global scope (current_scope == global_scope) causes
+ Being in the file scope (current_scope == file_scope) causes
special behavior in several places below. Also, under some
conditions the Objective-C front end records declarations in the
- global scope even though that isn't the current scope.
+ file scope even though that isn't the current scope.
+
+ All declarations with external linkage are recorded in the external
+ scope, even if they aren't visible there; this models the fact that
+ such declarations are visible to the entire program, and (with a
+ bit of cleverness, see pushdecl) allows diagnosis of some violations
+ of C99 6.2.2p7 and 6.2.7p2:
- The order of the names, parms, and blocks lists matters, and they
- are frequently appended to. To avoid having to walk all the way to
- the end of the list on each insertion, or reverse the lists later,
- we maintain a pointer to the last list entry for each of the lists.
+ If, within the same translation unit, the same identifier appears
+ with both internal and external linkage, the behavior is
+ undefined.
- The order of the tags, shadowed, and shadowed_tags
- lists does not matter, so we just prepend to these lists. */
+ All declarations that refer to the same object or function shall
+ have compatible type; otherwise, the behavior is undefined.
-struct c_scope GTY(())
+ Initially only the built-in declarations, which describe compiler
+ intrinsic functions plus a subset of the standard library, are in
+ this scope.
+
+ The order of the blocks list matters, and it is frequently appended
+ to. To avoid having to walk all the way to the end of the list on
+ each insertion, or reverse the list later, we maintain a pointer to
+ the last list entry. (FIXME: It should be feasible to use a reversed
+ list here.)
+
+ The bindings list is strictly in reverse order of declarations;
+ pop_scope relies on this. */
+
+
+struct c_scope GTY((chain_next ("%h.outer")))
{
/* The scope containing this one. */
struct c_scope *outer;
/* The next outermost function scope. */
struct c_scope *outer_function;
- /* All variables, constants, functions, labels, and typedef names. */
- tree names;
- tree names_last;
-
- /* All parameter declarations. Used only in the outermost scope of
- a function. */
- tree parms;
- tree parms_last;
-
- /* All structure, union, and enum type tags. */
- tree tags;
-
- /* For each scope, a list of shadowed outer-scope definitions
- to be restored when this scope 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 scope, a list of shadowed outer-scope tag definitions
- to be restored when this scope 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;
+ /* All bindings in this scope. */
+ struct c_binding *bindings;
/* For each scope (except the global one), a chain of BLOCK nodes
for all the scopes that were entered and exited one level down. */
tree blocks;
tree blocks_last;
+ /* The depth of this scope. Used to keep the ->shadowed chain of
+ bindings sorted innermost to outermost. */
+ unsigned int depth : 28;
+
/* True if we are currently filling this scope with parameter
declarations. */
- bool parm_flag : 1;
+ BOOL_BITFIELD parm_flag : 1;
/* True if we already complained about forward parameter decls
in this scope. This prevents double warnings on
foo (int a; int b; ...) */
- bool warned_forward_parm_decls : 1;
+ BOOL_BITFIELD warned_forward_parm_decls : 1;
/* True if this is the outermost block scope of a function body.
This scope contains the parameters, the local variables declared
in the outermost block, and all the labels (except those in
nested functions, or declared at block scope with __label__). */
- bool function_body : 1;
+ BOOL_BITFIELD function_body : 1;
/* True means make a BLOCK for this scope no matter what. */
- bool keep : 1;
+ BOOL_BITFIELD keep : 1;
};
/* The scope currently in effect. */
static GTY(()) struct c_scope *current_scope;
-/* A chain of c_scope structures awaiting reuse. */
-
-static GTY((deletable (""))) struct c_scope *scope_freelist;
-
/* The innermost function scope. Ordinary (not explicitly declared)
labels, bindings to error_mark_node, and the lazily-created
bindings of __func__ and its friends get this scope. */
static GTY(()) struct c_scope *current_function_scope;
-/* The outermost scope, corresponding to the C "file scope". This is
- created when the compiler is started and exists through the entire run. */
+/* The C file scope. This is reset for each input translation unit. */
+
+static GTY(()) struct c_scope *file_scope;
+
+/* The outermost scope. This is used for all declarations with
+ external linkage, and only these, hence the name. */
+
+static GTY(()) struct c_scope *external_scope;
-static GTY(()) struct c_scope *global_scope;
+/* A chain of c_scope structures awaiting reuse. */
+
+static GTY((deletable)) struct c_scope *scope_freelist;
+
+/* A chain of c_binding structures awaiting reuse. */
+
+static GTY((deletable)) struct c_binding *binding_freelist;
/* Append VAR to LIST in scope SCOPE. */
#define SCOPE_LIST_APPEND(scope, list, decl) do { \
static bool keep_next_level_flag;
-/* True means the next call to pushlevel will be the outermost scope
+/* True means the next call to push_scope will be the outermost scope
of a function body, so do not push a new scope, merely cease
expecting parameter decls. */
/* Functions called automatically at the beginning and end of execution. */
-tree static_ctors, static_dtors;
+static GTY(()) tree static_ctors;
+static GTY(()) tree static_dtors;
/* Forward declarations. */
-
-static struct c_scope *make_scope (void);
-static void pop_scope (void);
-static tree match_builtin_function_types (tree, tree);
-static int duplicate_decls (tree, tree, int, int);
-static int redeclaration_error_message (tree, tree);
-static tree make_label (tree, location_t);
-static void bind_label (tree, tree, struct c_scope *);
-static void implicit_decl_warning (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 lookup_name_in_scope (tree, struct c_scope *);
+static tree c_make_fname_decl (tree, int);
+static tree grokdeclarator (tree, tree, enum decl_context, int, tree *);
static tree grokparms (tree, int);
static void layout_array_type (tree);
-static void store_parm_decls_newstyle (void);
-static void store_parm_decls_oldstyle (void);
-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);
-static hashval_t link_hash_hash (const void *);
-static int link_hash_eq (const void *, const void *);
\f
/* States indicating how grokdeclarator() should handle declspecs marked
with __attribute__((deprecated)). An object declared as
void
c_print_identifier (FILE *file, tree node, int indent)
{
- 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, "symbol", I_SYMBOL_DECL (node), indent + 4);
+ print_node (file, "tag", I_TAG_DECL (node), indent + 4);
+ print_node (file, "label", I_LABEL_DECL (node), indent + 4);
if (C_IS_RESERVED_WORD (node))
{
tree rid = ridpointers[C_RID_CODE (node)];
(void *) rid, IDENTIFIER_POINTER (rid));
}
}
+
+/* Establish a binding between NAME, an IDENTIFIER_NODE, and DECL,
+ which may be any of several kinds of DECL or TYPE or error_mark_node,
+ in the scope SCOPE. */
+static void
+bind (tree name, tree decl, struct c_scope *scope, bool invisible, bool nested)
+{
+ struct c_binding *b, **here;
+
+ if (binding_freelist)
+ {
+ b = binding_freelist;
+ binding_freelist = b->prev;
+ }
+ else
+ b = ggc_alloc (sizeof (struct c_binding));
+
+ b->shadowed = 0;
+ b->decl = decl;
+ b->id = name;
+ b->depth = scope->depth;
+ b->invisible = invisible;
+ b->nested = nested;
+
+ b->prev = scope->bindings;
+ scope->bindings = b;
+
+ if (!name)
+ return;
+
+ switch (TREE_CODE (decl))
+ {
+ case LABEL_DECL: here = &I_LABEL_BINDING (name); break;
+ case ENUMERAL_TYPE:
+ case UNION_TYPE:
+ case RECORD_TYPE: here = &I_TAG_BINDING (name); break;
+ case VAR_DECL:
+ case FUNCTION_DECL:
+ case TYPE_DECL:
+ case CONST_DECL:
+ case PARM_DECL:
+ case ERROR_MARK: here = &I_SYMBOL_BINDING (name); break;
+
+ default:
+ abort ();
+ }
+
+ /* Locate the appropriate place in the chain of shadowed decls
+ to insert this binding. Normally, scope == current_scope and
+ this does nothing. */
+ while (*here && (*here)->depth > scope->depth)
+ here = &(*here)->shadowed;
+
+ b->shadowed = *here;
+ *here = b;
+}
+
+/* Clear the binding structure B, stick it on the binding_freelist,
+ and return the former value of b->prev. This is used by pop_scope
+ and get_parm_info to iterate destructively over all the bindings
+ from a given scope. */
+static struct c_binding *
+free_binding_and_advance (struct c_binding *b)
+{
+ struct c_binding *prev = b->prev;
+
+ memset (b, 0, sizeof (struct c_binding));
+ b->prev = binding_freelist;
+ binding_freelist = b;
+
+ return prev;
+}
+
\f
/* Hook called at end of compilation to assume 1 elt
for a file-scope tentative array defn that wasn't complete before. */
}
}
\f
-/* Reuse or create a struct for this scope. */
-
-static struct c_scope *
-make_scope (void)
-{
- struct c_scope *result;
- if (scope_freelist)
- {
- result = scope_freelist;
- scope_freelist = result->outer;
- }
- else
- result = ggc_alloc_cleared (sizeof (struct c_scope));
-
- return result;
-}
-
-/* Remove the topmost scope from the stack and add it to the
- free list, updating current_function_scope if necessary. */
-
-static void
-pop_scope (void)
-{
- struct c_scope *scope = current_scope;
-
- current_scope = scope->outer;
- if (scope->function_body)
- current_function_scope = scope->outer_function;
-
- memset (scope, 0, sizeof (struct c_scope));
- scope->outer = scope_freelist;
- scope_freelist = scope;
-}
-
/* The Objective-C front-end often needs to determine the current scope. */
void *
objc_mark_locals_volatile (void *enclosing_blk)
{
struct c_scope *scope;
-
- for (scope = current_scope;
+ struct c_binding *b;
+
+ for (scope = current_scope;
scope && scope != enclosing_blk;
scope = scope->outer)
{
- tree decl;
-
- for (decl = scope->names; decl; decl = TREE_CHAIN (decl))
+ for (b = scope->bindings; b; b = b->prev)
{
- DECL_REGISTER (decl) = 0;
- TREE_THIS_VOLATILE (decl) = 1;
+ if (TREE_CODE (b->decl) == VAR_DECL
+ || TREE_CODE (b->decl) == PARM_DECL)
+ {
+ C_DECL_REGISTER (b->decl) = 0;
+ DECL_REGISTER (b->decl) = 0;
+ TREE_THIS_VOLATILE (b->decl) = 1;
+ }
}
+
/* Do not climb up past the current function. */
if (scope->function_body)
break;
- }
-}
-
-/* Nonzero if we are currently in the global scope. */
+ }
+}
+
+/* Nonzero if we are currently in file scope. */
int
global_bindings_p (void)
{
- return current_scope == global_scope;
+ return current_scope == file_scope && !c_override_global_bindings_to_false;
}
void
current_scope->parm_flag = true;
}
-/* Nonzero if currently making parm declarations. */
-
-int
-in_parm_level_p (void)
-{
- return current_scope->parm_flag;
-}
-
-/* Enter a new scope. The dummy parameter is for signature
- compatibility with lang_hooks.decls.pushlevel. */
-
void
-pushlevel (int dummy ATTRIBUTE_UNUSED)
+push_scope (void)
{
if (next_is_function_body)
{
}
else
{
- struct c_scope *scope = make_scope ();
+ struct c_scope *scope;
+ if (scope_freelist)
+ {
+ scope = scope_freelist;
+ scope_freelist = scope->outer;
+ }
+ else
+ scope = ggc_alloc_cleared (sizeof (struct c_scope));
scope->keep = keep_next_level_flag;
scope->outer = current_scope;
+ scope->depth = current_scope ? (current_scope->depth + 1) : 0;
+
+ /* Check for scope depth overflow. Unlikely (2^28 == 268,435,456) but
+ possible. */
+ if (current_scope && scope->depth == 0)
+ {
+ scope->depth--;
+ sorry ("GCC supports only %u nested scopes\n", scope->depth);
+ }
+
current_scope = scope;
keep_next_level_flag = false;
}
}
-/* Exit a scope. Restore the state of the identifier-decl mappings
- that were in effect when this scope was entered.
-
- If KEEP is KEEP_YES (1), this scope had explicit declarations, so
- create a BLOCK node to record its declarations and subblocks for
- debugging output. If KEEP is KEEP_MAYBE, do so only if the names
- or tags lists are nonempty.
-
- The second parameter is ignored; it is present only for
- signature compatibility with lang_hooks.decls.poplevel.
+/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT. */
- If FUNCTIONBODY is nonzero, this level is the body of a function,
- even if current_scope->function_body is not set. This is used
- by language-independent code that generates synthetic functions,
- and cannot set current_scope->function_body.
+static void
+set_type_context (tree type, tree context)
+{
+ for (type = TYPE_MAIN_VARIANT (type); type;
+ type = TYPE_NEXT_VARIANT (type))
+ TYPE_CONTEXT (type) = context;
+}
- FIXME: Eliminate the need for all arguments. */
+/* Exit a scope. Restore the state of the identifier-decl mappings
+ that were in effect when this scope was entered. Return a BLOCK
+ node containing all the DECLs in this scope that are of interest
+ to debug info generation. */
tree
-poplevel (int keep, int dummy ATTRIBUTE_UNUSED, int functionbody)
+pop_scope (void)
{
struct c_scope *scope = current_scope;
- tree block;
- tree decl;
- tree p;
+ tree block, context, p;
+ struct c_binding *b;
- /* The following line does not use |= due to a bug in HP's C compiler */
- scope->function_body = scope->function_body | functionbody;
-
- if (keep == KEEP_MAYBE)
- keep = (scope->names || scope->tags);
-
- keep |= scope->keep;
- keep |= scope->function_body;
+ bool functionbody = scope->function_body;
+ bool keep = functionbody || scope->keep || scope->bindings;
/* If appropriate, create a BLOCK to record the decls for the life
of this function. */
if (keep)
{
block = make_node (BLOCK);
- BLOCK_VARS (block) = scope->names;
BLOCK_SUBBLOCKS (block) = scope->blocks;
TREE_USED (block) = 1;
- }
- /* In each subblock, record that this is its superior. */
- for (p = scope->blocks; p; p = TREE_CHAIN (p))
- BLOCK_SUPERCONTEXT (p) = block;
+ /* In each subblock, record that this is its superior. */
+ for (p = scope->blocks; p; p = TREE_CHAIN (p))
+ BLOCK_SUPERCONTEXT (p) = block;
- /* Clear out the variable bindings in this scope.
+ BLOCK_VARS (block) = 0;
+ }
- Propagate TREE_ADDRESSABLE from nested functions to their
- containing functions.
+ /* The TYPE_CONTEXTs for all of the tagged types belonging to this
+ scope must be set 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.
- Issue warnings for unused variables and labels, and errors for
- undefined labels, if there are any. */
+ 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 (scope->function_body)
+ context = current_function_decl;
+ else if (scope == file_scope)
+ {
+ tree file_decl = build_decl (TRANSLATION_UNIT_DECL, 0, 0);
+ TREE_CHAIN (file_decl) = all_translation_units;
+ all_translation_units = file_decl;
+ context = file_decl;
+ }
+ else
+ context = block;
- for (p = scope->names; p; p = TREE_CHAIN (p))
+ /* Clear all bindings in this scope. */
+ for (b = scope->bindings; b; b = free_binding_and_advance (b))
{
+ p = b->decl;
switch (TREE_CODE (p))
{
case LABEL_DECL:
+ /* Warnings for unused labels, errors for undefined labels. */
if (TREE_USED (p) && !DECL_INITIAL (p))
{
error ("%Jlabel `%D' used but not defined", p, p);
else
warning ("%Jlabel `%D' declared but not defined", p, p);
}
+ /* Labels go in BLOCK_VARS. */
+ TREE_CHAIN (p) = BLOCK_VARS (block);
+ BLOCK_VARS (block) = p;
- IDENTIFIER_LABEL_VALUE (DECL_NAME (p)) = 0;
- break;
+#ifdef ENABLE_CHECKING
+ if (I_LABEL_BINDING (b->id) != b) abort ();
+#endif
+ I_LABEL_BINDING (b->id) = b->shadowed;
+ break;
+
+ case ENUMERAL_TYPE:
+ case UNION_TYPE:
+ case RECORD_TYPE:
+ set_type_context (p, context);
+
+ /* Types may not have tag-names, in which case the type
+ appears in the bindings list with b->id NULL. */
+ if (b->id)
+ {
+#ifdef ENABLE_CHECKING
+ if (I_TAG_BINDING (b->id) != b) abort ();
+#endif
+ I_TAG_BINDING (b->id) = b->shadowed;
+ }
+ break;
case FUNCTION_DECL:
+ /* Propagate TREE_ADDRESSABLE from nested functions to their
+ containing functions. */
if (! TREE_ASM_WRITTEN (p)
&& DECL_INITIAL (p) != 0
&& TREE_ADDRESSABLE (p)
&& DECL_ABSTRACT_ORIGIN (p) != 0
&& DECL_ABSTRACT_ORIGIN (p) != p)
TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1;
- goto normal;
+ goto common_symbol;
case VAR_DECL:
- /* Keep this in sync with stmt.c:warn_about_unused_variables.
- No warnings when the global scope is popped because the
- global scope isn't popped for the last translation unit,
- so the warnings are done in c_write_global_declaration. */
- if (warn_unused_variable && scope != global_scope
+ /* Warnings for unused variables. Keep this in sync with
+ stmt.c:warn_about_unused_variables, which we cannot use
+ since it expects a different data structure. */
+ if (warn_unused_variable
&& !TREE_USED (p)
&& !DECL_IN_SYSTEM_HEADER (p)
&& DECL_NAME (p)
- && !DECL_ARTIFICIAL (p))
+ && !DECL_ARTIFICIAL (p)
+ && (scope != file_scope
+ || (TREE_STATIC (p) && !TREE_PUBLIC (p)
+ && !TREE_THIS_VOLATILE (p)))
+ && scope != external_scope)
warning ("%Junused variable `%D'", p, p);
- /* fall through */
- default:
- normal:
- if (DECL_NAME (p))
+ /* Fall through. */
+ case TYPE_DECL:
+ case CONST_DECL:
+ common_symbol:
+ /* All of these go in BLOCK_VARS, but only if this is the
+ binding in the home scope. */
+ if (!b->nested)
{
- if (DECL_EXTERNAL (p) && scope != global_scope)
- /* External decls stay in the symbol-value slot but are
- inaccessible. */
- C_DECL_INVISIBLE (p) = 1;
- else
- IDENTIFIER_SYMBOL_VALUE (DECL_NAME (p)) = 0;
+ TREE_CHAIN (p) = BLOCK_VARS (block);
+ BLOCK_VARS (block) = p;
+ }
+ /* If this is the file scope, and we are processing more
+ than one translation unit in this compilation, set
+ DECL_CONTEXT of each decl to the TRANSLATION_UNIT_DECL.
+ This makes same_translation_unit_p work, and causes
+ static declarations to be given disambiguating suffixes. */
+ if (scope == file_scope && num_in_fnames > 1)
+ {
+ DECL_CONTEXT (p) = context;
+ if (TREE_CODE (p) == TYPE_DECL)
+ set_type_context (TREE_TYPE (p), context);
+ }
+
+ /* Fall through. */
+ /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have
+ already been put there by store_parm_decls. Unused-
+ parameter warnings are handled by function.c.
+ error_mark_node obviously does not go in BLOCK_VARS and
+ does not get unused-variable warnings. */
+ case PARM_DECL:
+ case ERROR_MARK:
+ /* It is possible for a decl not to have a name. We get
+ here with b->id NULL in this case. */
+ if (b->id)
+ {
+#ifdef ENABLE_CHECKING
+ if (I_SYMBOL_BINDING (b->id) != b) abort ();
+#endif
+ I_SYMBOL_BINDING (b->id) = b->shadowed;
}
break;
+
+ default:
+ abort ();
}
}
- /* Clear out the parameter bindings in this scope, if any.
- Unused-parameter warnings are handled by function.c. */
- for (p = scope->parms; p; p = TREE_CHAIN (p))
- if (DECL_NAME (p))
- IDENTIFIER_SYMBOL_VALUE (DECL_NAME (p)) = 0;
-
- /* Clear out the tag-meanings declared in this scope.
- Set the TYPE_CONTEXTs for all of the tagged types belonging to
- this scope 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. */
-
- decl = scope->function_body ? current_function_decl : block;
- for (p = scope->tags; p; p = TREE_CHAIN (p))
+ /* Dispose of the block that we just made inside some higher level. */
+ if ((scope->function_body || scope == file_scope) && context)
{
- if (TREE_PURPOSE (p))
- IDENTIFIER_TAG_VALUE (TREE_PURPOSE (p)) = 0;
- if (decl)
- TYPE_CONTEXT (TREE_VALUE (p)) = decl;
+ DECL_INITIAL (context) = block;
+ BLOCK_SUPERCONTEXT (block) = context;
}
-
- /* Restore all name- and label-meanings from outer scopes that were
- shadowed by this scope. */
- for (p = scope->shadowed; p; p = TREE_CHAIN (p))
- if (TREE_VALUE (p) && TREE_CODE (TREE_VALUE (p)) == LABEL_DECL)
- IDENTIFIER_LABEL_VALUE (TREE_PURPOSE (p)) = TREE_VALUE (p);
- else
- IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (p)) = TREE_VALUE (p);
-
- /* Restore all tag-meanings from outer scopes that were shadowed by
- this scope. */
- for (p = scope->shadowed_tags; p; p = TREE_CHAIN (p))
- IDENTIFIER_TAG_VALUE (TREE_PURPOSE (p)) = TREE_VALUE (p);
-
- /* Dispose of the block that we just made inside some higher level. */
- if (scope->function_body)
- DECL_INITIAL (current_function_decl) = block;
else if (scope->outer)
{
if (block)
}
/* Pop the current scope, and free the structure for reuse. */
- pop_scope ();
+ current_scope = scope->outer;
+ if (scope->function_body)
+ current_function_scope = scope->outer_function;
+
+ memset (scope, 0, sizeof (struct c_scope));
+ scope->outer = scope_freelist;
+ scope_freelist = scope;
return block;
}
+void
+push_file_scope (void)
+{
+ tree decl;
+
+ if (file_scope)
+ return;
+
+ push_scope ();
+ file_scope = current_scope;
+
+ start_fname_decls ();
+
+ for (decl = visible_builtins; decl; decl = TREE_CHAIN (decl))
+ bind (DECL_NAME (decl), decl, file_scope,
+ /*invisible=*/false, /*nested=*/true);
+}
+
+void
+pop_file_scope (void)
+{
+ /* In case there were missing closebraces, get us back to the global
+ binding level. */
+ while (current_scope != file_scope)
+ pop_scope ();
+
+ /* __FUNCTION__ is defined at file scope (""). This
+ call may not be necessary as my tests indicate it
+ still works without it. */
+ finish_fname_decls ();
+
+ /* This is the point to write out a PCH if we're doing that.
+ In that case we do not want to do anything else. */
+ if (pch_file)
+ {
+ c_common_write_pch ();
+ return;
+ }
+
+ /* Pop off the file scope and close this translation unit. */
+ pop_scope ();
+ file_scope = 0;
+ cgraph_finalize_compilation_unit ();
+}
+
/* Insert BLOCK at the end of the list of subblocks of the current
scope. This is used when a BIND_EXPR is expanded, to handle the
BLOCK node inside the BIND_EXPR. */
TREE_USED (block) = 1;
SCOPE_LIST_APPEND (current_scope, blocks, block);
}
-
-/* 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 (tree block ATTRIBUTE_UNUSED)
-{
-}
\f
/* Push a definition or a declaration of struct, union or enum tag "name".
"type" should be the type node.
Note that the definition may really be just a forward reference.
In that case, the TYPE_SIZE will be zero. */
-void
+static void
pushtag (tree name, tree type)
{
- struct c_scope *b = current_scope;
-
/* Record the identifier as the type's name if it has none. */
- 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);
+ if (name && !TYPE_NAME (type))
+ TYPE_NAME (type) = name;
+ bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false);
/* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the
tagged type we just added to the current scope. This fake
TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL_TREE, type));
/* An approximation for now, so we can tell this is a function-scope tag.
- This will be updated in poplevel. */
+ This will be updated in pop_scope. */
TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type));
}
\f
-/* Subroutine of duplicate_decls. Allow harmless mismatches in return
+/* Subroutine of compare_decls. Allow harmless mismatches in return
and argument types provided that the type modes match. This function
return a unified type given a suitable match, and 0 otherwise. */
static tree
-match_builtin_function_types (tree oldtype, tree newtype)
+match_builtin_function_types (tree newtype, tree oldtype)
{
tree newrettype, oldrettype;
tree newargs, oldargs;
return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype));
}
-/* Handle when a new declaration NEWDECL
- has the same name as an old one OLDDECL
- in the same binding contour.
- Prints an error message if appropriate.
+/* Subroutine of diagnose_mismatched_decls. Check for function type
+ mismatch involving an empty arglist vs a nonempty one and give clearer
+ diagnostics. */
+static void
+diagnose_arglist_conflict (tree newdecl, tree olddecl,
+ tree newtype, tree oldtype)
+{
+ tree t;
+
+ if (TREE_CODE (olddecl) != FUNCTION_DECL
+ || !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype))
+ || !((TYPE_ARG_TYPES (oldtype) == 0 && DECL_INITIAL (olddecl) == 0)
+ ||
+ (TYPE_ARG_TYPES (newtype) == 0 && DECL_INITIAL (newdecl) == 0)))
+ return;
- If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
- Otherwise, return 0.
+ t = TYPE_ARG_TYPES (oldtype);
+ if (t == 0)
+ t = TYPE_ARG_TYPES (newtype);
+ for (; t; t = TREE_CHAIN (t))
+ {
+ tree type = TREE_VALUE (t);
- When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external declaration,
- and OLDDECL is in an outer scope and should thus not be changed. */
+ if (TREE_CHAIN (t) == 0
+ && TYPE_MAIN_VARIANT (type) != void_type_node)
+ {
+ inform ("a parameter list with an ellipsis can't match "
+ "an empty parameter name list declaration");
+ break;
+ }
-static int
-duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
- int different_tu)
+ if (c_type_promotes_to (type) != type)
+ {
+ inform ("an argument type that has a default promotion can't match "
+ "an empty parameter name list declaration");
+ break;
+ }
+ }
+}
+
+/* Another subroutine of diagnose_mismatched_decls. OLDDECL is an
+ old-style function definition, NEWDECL is a prototype declaration.
+ Diagnose inconsistencies in the argument list. Returns TRUE if
+ the prototype is compatible, FALSE if not. */
+static bool
+validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
{
- int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl),
- COMPARE_STRICT);
- int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
- && DECL_INITIAL (newdecl) != 0);
- tree oldtype = TREE_TYPE (olddecl);
- tree newtype = TREE_TYPE (newdecl);
- int errmsg = 0;
+ tree newargs, oldargs;
+ int i;
- if (DECL_P (olddecl))
+ /* ??? Elsewhere TYPE_MAIN_VARIANT is not used in this context. */
+#define END_OF_ARGLIST(t) (TYPE_MAIN_VARIANT (t) == void_type_node)
+
+ oldargs = TYPE_ACTUAL_ARG_TYPES (oldtype);
+ newargs = TYPE_ARG_TYPES (newtype);
+ i = 1;
+
+ for (;;)
{
- if (TREE_CODE (newdecl) == FUNCTION_DECL
- && TREE_CODE (olddecl) == FUNCTION_DECL
- && (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)))
+ tree oldargtype = TREE_VALUE (oldargs);
+ tree newargtype = TREE_VALUE (newargs);
+
+ if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype))
+ break;
+
+ /* Reaching the end of just one list means the two decls don't
+ agree on the number of arguments. */
+ if (END_OF_ARGLIST (oldargtype))
{
- if (DECL_DECLARED_INLINE_P (newdecl)
- && DECL_UNINLINABLE (newdecl)
- && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
- /* Already warned elsewhere. */;
- else if (DECL_DECLARED_INLINE_P (olddecl)
- && DECL_UNINLINABLE (olddecl)
- && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
- /* Already warned. */;
- else if (DECL_DECLARED_INLINE_P (newdecl)
- && ! DECL_DECLARED_INLINE_P (olddecl)
- && DECL_UNINLINABLE (olddecl)
- && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
- {
- warning ("%Jfunction '%D' redeclared as inline",
- newdecl, newdecl);
- warning ("%Jprevious declaration of function '%D' "
- "with attribute noinline", olddecl, olddecl);
- }
- else if (DECL_DECLARED_INLINE_P (olddecl)
- && DECL_UNINLINABLE (newdecl)
- && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
- {
- warning ("%Jfunction '%D' redeclared with attribute noinline",
- newdecl, newdecl);
- warning ("%Jprevious declaration of function '%D' was inline",
- olddecl, olddecl);
- }
+ error ("%Jprototype for '%D' declares more arguments "
+ "than previous old-style definition", newdecl, newdecl);
+ return false;
+ }
+ else if (END_OF_ARGLIST (newargtype))
+ {
+ error ("%Jprototype for '%D' declares fewer arguments "
+ "than previous old-style definition", newdecl, newdecl);
+ return false;
+ }
+
+ /* Type for passing arg must be consistent with that declared
+ for the arg. */
+ else if (! comptypes (oldargtype, newargtype))
+ {
+ error ("%Jprototype for '%D' declares arg %d with incompatible type",
+ newdecl, newdecl, i);
+ return false;
}
- DECL_ATTRIBUTES (newdecl)
- = (*targetm.merge_decl_attributes) (olddecl, newdecl);
+ oldargs = TREE_CHAIN (oldargs);
+ newargs = TREE_CHAIN (newargs);
+ i++;
}
- if (TREE_CODE (newtype) == ERROR_MARK
- || TREE_CODE (oldtype) == ERROR_MARK)
- types_match = 0;
+ /* If we get here, no errors were found, but do issue a warning
+ for this poor-style construct. */
+ warning ("%Jprototype for '%D' follows non-prototype definition",
+ newdecl, newdecl);
+ return true;
+#undef END_OF_ARGLIST
+}
+
+/* Subroutine of diagnose_mismatched_decls. Report the location of DECL,
+ first in a pair of mismatched declarations, using the diagnostic
+ function DIAG. */
+static void
+locate_old_decl (tree decl, void (*diag)(const char *, ...))
+{
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
+ ;
+ else if (DECL_INITIAL (decl))
+ diag (N_("%Jprevious definition of '%D' was here"), decl, decl);
+ else if (C_DECL_IMPLICIT (decl))
+ diag (N_("%Jprevious implicit declaration of '%D' was here"), decl, decl);
+ else
+ diag (N_("%Jprevious declaration of '%D' was here"), decl, decl);
+}
+
+/* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL.
+ Returns true if the caller should proceed to merge the two, false
+ if OLDDECL should simply be discarded. As a side effect, issues
+ all necessary diagnostics for invalid or poor-style combinations.
+ If it returns true, writes the types of NEWDECL and OLDDECL to
+ *NEWTYPEP and *OLDTYPEP - these may have been adjusted from
+ TREE_TYPE (NEWDECL, OLDDECL) respectively. */
- /* New decl is completely inconsistent with the old one =>
- tell caller to replace the old one.
- This is always an error except in the case of shadowing a builtin. */
+static bool
+diagnose_mismatched_decls (tree newdecl, tree olddecl,
+ tree *newtypep, tree *oldtypep)
+{
+ tree newtype, oldtype;
+ bool pedwarned = false;
+ bool warned = false;
+
+ /* If we have error_mark_node for either decl or type, just discard
+ the previous decl - we're in an error cascade already. */
+ if (olddecl == error_mark_node || newdecl == error_mark_node)
+ return false;
+ *oldtypep = oldtype = TREE_TYPE (olddecl);
+ *newtypep = newtype = TREE_TYPE (newdecl);
+ if (oldtype == error_mark_node || newtype == error_mark_node)
+ return false;
+
+ /* Two different categories of symbol altogether. This is an error
+ unless OLDDECL is a builtin. OLDDECL will be discarded in any case. */
if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
{
+ if (!(TREE_CODE (olddecl) == FUNCTION_DECL
+ && DECL_BUILT_IN (olddecl)
+ && !C_DECL_DECLARED_BUILTIN (olddecl)))
+ {
+ error ("%J'%D' redeclared as different kind of symbol",
+ newdecl, newdecl);
+ locate_old_decl (olddecl, error);
+ }
+ else if (TREE_PUBLIC (newdecl))
+ warning ("%Jbuilt-in function '%D' declared as non-function",
+ newdecl, newdecl);
+ else if (warn_shadow)
+ warning ("%Jdeclaration of '%D' shadows a built-in function",
+ newdecl, newdecl);
+ return false;
+ }
+
+ if (!comptypes (oldtype, newtype))
+ {
if (TREE_CODE (olddecl) == FUNCTION_DECL
- && DECL_BUILT_IN (olddecl))
+ && DECL_BUILT_IN (olddecl) && !C_DECL_DECLARED_BUILTIN (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))
+ /* Accept harmless mismatch in function types.
+ This is for the ffs and fprintf builtins. */
+ tree trytype = match_builtin_function_types (newtype, oldtype);
+
+ if (trytype && comptypes (newtype, trytype))
+ *oldtypep = oldtype = trytype;
+ else
{
- if (warn_shadow)
- warning ("%Jshadowing built-in function '%D'",
- newdecl, newdecl);
+ /* If types don't match for a built-in, throw away the
+ built-in. No point in calling locate_old_decl here, it
+ won't print anything. */
+ warning ("%Jconflicting types for built-in function '%D'",
+ newdecl, newdecl);
+ return false;
}
- else
- warning ("%Jbuilt-in function '%D' declared as non-function",
- newdecl, newdecl);
+ }
+ else if (TREE_CODE (olddecl) == FUNCTION_DECL
+ && DECL_IS_BUILTIN (olddecl))
+ {
+ /* A conflicting function declaration for a predeclared
+ function that isn't actually built in. Objective C uses
+ these. The new declaration silently overrides everything
+ but the volatility (i.e. noreturn) indication. See also
+ below. FIXME: Make Objective C use normal builtins. */
+ TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+ return false;
+ }
+ /* 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 (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl)
+ && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node
+ && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node
+ && C_FUNCTION_IMPLICIT_INT (newdecl))
+ {
+ pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl);
+ /* Make sure we keep void as the return type. */
+ TREE_TYPE (newdecl) = *newtypep = newtype = oldtype;
+ C_FUNCTION_IMPLICIT_INT (newdecl) = 0;
+ pedwarned = true;
}
else
{
- error ("%J'%D' redeclared as different kind of symbol",
- newdecl, newdecl);
- error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+ if (TYPE_QUALS (newtype) != TYPE_QUALS (oldtype))
+ error ("%J conflicting type qualifiers for '%D'", newdecl, newdecl);
+ else
+ error ("%Jconflicting types for '%D'", newdecl, newdecl);
+ diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
+ locate_old_decl (olddecl, error);
+ return false;
}
-
- return 0;
}
- /* 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))
+ /* Redeclaration of a type is a constraint violation (6.7.2.3p1),
+ but silently ignore the redeclaration if either is in a system
+ header. (Conflicting redeclarations were handled above.) */
+ if (TREE_CODE (newdecl) == TYPE_DECL)
{
- TREE_ASM_WRITTEN (olddecl) = 0;
- return 1;
- }
+ if (DECL_IN_SYSTEM_HEADER (newdecl) || DECL_IN_SYSTEM_HEADER (olddecl))
+ return true; /* Allow OLDDECL to continue in use. */
- /* The new declaration is the same kind of object as the old one.
- The declarations may partially match. Print warnings if they don't
- match enough. Ultimately, copy most of the information from the new
- decl to the old one, and keep using the old one. */
+ error ("%Jredefinition of typedef '%D'", newdecl, newdecl);
+ locate_old_decl (olddecl, error);
+ return false;
+ }
- if (TREE_CODE (olddecl) == FUNCTION_DECL && DECL_BUILT_IN (olddecl))
+ /* Function declarations can either be 'static' or 'extern' (no
+ qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore
+ can never conflict with each other on account of linkage (6.2.2p4).
+ Multiple definitions are not allowed (6.9p3,5) but GCC permits
+ two definitions if one is 'extern inline' and one is not. The non-
+ extern-inline definition supersedes the extern-inline definition. */
+ else if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
- /* A function declaration for a built-in function. */
- if (!TREE_PUBLIC (newdecl))
+ /* If you declare a built-in function name as static, or
+ define the built-in with an old-style definition (so we
+ can't validate the argument list) the built-in definition is
+ overridden, but optionally warn this was a bad choice of name. */
+ if (DECL_BUILT_IN (olddecl)
+ && !C_DECL_DECLARED_BUILTIN (olddecl)
+ && (!TREE_PUBLIC (newdecl)
+ || (DECL_INITIAL (newdecl)
+ && !TYPE_ARG_TYPES (TREE_TYPE (newdecl)))))
{
- /* If you declare a built-in function name as static, the
- built-in definition is overridden,
- but optionally warn this was a bad choice of name. */
if (warn_shadow)
- warning ("%Jshadowing built-in function '%D'", newdecl, newdecl);
+ warning ("%Jdeclaration of '%D' shadows a built-in function",
+ newdecl, newdecl);
/* Discard the old built-in function. */
- return 0;
+ return false;
}
- if (!types_match)
- {
- /* Accept harmless mismatch in function types.
- This is for the ffs and fprintf builtins. */
- tree trytype = match_builtin_function_types (oldtype, newtype);
- if (trytype)
+ if (DECL_INITIAL (newdecl))
+ {
+ if (DECL_INITIAL (olddecl)
+ && !(DECL_DECLARED_INLINE_P (olddecl)
+ && DECL_EXTERNAL (olddecl)
+ && !(DECL_DECLARED_INLINE_P (newdecl)
+ && DECL_EXTERNAL (newdecl)
+ && same_translation_unit_p (olddecl, newdecl))))
{
- types_match = comptypes (newtype, trytype, COMPARE_STRICT);
- if (types_match)
- oldtype = trytype;
- if (! different_binding_level)
- TREE_TYPE (olddecl) = oldtype;
+ error ("%Jredefinition of '%D'", newdecl, newdecl);
+ locate_old_decl (olddecl, error);
+ return false;
}
}
- if (!types_match)
+ /* If we have a prototype after an old-style function definition,
+ the argument types must be checked specially. */
+ else if (DECL_INITIAL (olddecl)
+ && !TYPE_ARG_TYPES (oldtype) && TYPE_ARG_TYPES (newtype)
+ && TYPE_ACTUAL_ARG_TYPES (oldtype)
+ && !validate_proto_after_old_defn (newdecl, newtype, oldtype))
{
- /* If types don't match for a built-in, throw away the built-in. */
- warning ("%Jconflicting types for built-in function '%D'",
- newdecl, newdecl);
- return 0;
+ locate_old_decl (olddecl, error);
+ return false;
+ }
+ /* A non-static declaration (even an "extern") followed by a
+ static declaration is undefined behavior per C99 6.2.2p3-5,7.
+ The same is true for a static forward declaration at block
+ scope followed by a non-static declaration/definition at file
+ scope. Static followed by non-static at the same scope is
+ not undefined behavior, and is the most convenient way to get
+ some effects (see e.g. what unwind-dw2-fde-glibc.c does to
+ the definition of _Unwind_Find_FDE in unwind-dw2-fde.c), but
+ we do diagnose it if -Wtraditional. */
+ if (TREE_PUBLIC (olddecl) && !TREE_PUBLIC (newdecl))
+ {
+ /* Two exceptions to the rule. If olddecl is an extern
+ inline, or a predeclared function that isn't actually
+ built in, newdecl silently overrides olddecl. The latter
+ occur only in Objective C; see also above. (FIXME: Make
+ Objective C use normal builtins.) */
+ if (!DECL_IS_BUILTIN (olddecl)
+ && !(DECL_EXTERNAL (olddecl)
+ && DECL_DECLARED_INLINE_P (olddecl)))
+ {
+ error ("%Jstatic declaration of '%D' follows "
+ "non-static declaration", newdecl, newdecl);
+ locate_old_decl (olddecl, error);
+ }
+ return false;
+ }
+ else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl))
+ {
+ if (DECL_CONTEXT (olddecl))
+ {
+ error ("%Jnon-static declaration of '%D' follows "
+ "static declaration", newdecl, newdecl);
+ locate_old_decl (olddecl, error);
+ return false;
+ }
+ else if (warn_traditional)
+ {
+ warning ("%Jnon-static declaration of '%D' follows "
+ "static declaration", newdecl, newdecl);
+ warned = true;
+ }
}
}
- else if (TREE_CODE (olddecl) == FUNCTION_DECL
- && DECL_SOURCE_LINE (olddecl) == 0)
+ else if (TREE_CODE (newdecl) == VAR_DECL)
{
- /* A function declaration for a predeclared function
- that isn't actually built in. */
- if (!TREE_PUBLIC (newdecl))
+ /* Only variables can be thread-local, and all declarations must
+ agree on this property. */
+ if (DECL_THREAD_LOCAL (newdecl) != DECL_THREAD_LOCAL (olddecl))
{
- /* If you declare it as static, the
- default definition is overridden. */
- return 0;
+ if (DECL_THREAD_LOCAL (newdecl))
+ error ("%Jthread-local declaration of '%D' follows "
+ "non-thread-local declaration", newdecl, newdecl);
+ else
+ error ("%Jnon-thread-local declaration of '%D' follows "
+ "thread-local declaration", newdecl, newdecl);
+
+ locate_old_decl (olddecl, error);
+ return false;
}
- else if (!types_match)
+
+ /* Multiple initialized definitions are not allowed (6.9p3,5). */
+ if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl))
{
- /* If the types don't match, preserve volatility indication.
- Later on, we will discard everything else about the
- default declaration. */
- TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+ error ("%Jredefinition of '%D'", newdecl, newdecl);
+ locate_old_decl (olddecl, error);
+ return false;
}
- }
- /* Permit char *foo () to match void *foo (...) if not pedantic,
- if one of them came from a system header file. */
- else if (!types_match
- && TREE_CODE (olddecl) == FUNCTION_DECL
- && TREE_CODE (newdecl) == FUNCTION_DECL
- && TREE_CODE (TREE_TYPE (oldtype)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (newtype)) == POINTER_TYPE
- && (DECL_IN_SYSTEM_HEADER (olddecl)
- || DECL_IN_SYSTEM_HEADER (newdecl))
- && ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (newtype))) == void_type_node
- && TYPE_ARG_TYPES (oldtype) == 0
- && self_promoting_args_p (TYPE_ARG_TYPES (newtype))
- && TREE_TYPE (TREE_TYPE (oldtype)) == char_type_node)
- ||
- (TREE_TYPE (TREE_TYPE (newtype)) == char_type_node
- && TYPE_ARG_TYPES (newtype) == 0
- && self_promoting_args_p (TYPE_ARG_TYPES (oldtype))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node)))
- {
- if (pedantic)
- pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl);
- /* Make sure we keep void * as ret type, not char *. */
- if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node)
- TREE_TYPE (newdecl) = newtype = oldtype;
-
- /* Set DECL_IN_SYSTEM_HEADER, so that if we see another declaration
- we will come back here again. */
- DECL_IN_SYSTEM_HEADER (newdecl) = 1;
- }
- /* 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 ("%Jconflicting types for '%D'", newdecl, newdecl);
- /* 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. */
- && ! (TREE_CODE (olddecl) == FUNCTION_DECL
- && ! pedantic
- /* Return types must still match. */
- && comptypes (TREE_TYPE (oldtype),
- TREE_TYPE (newtype), COMPARE_STRICT)
- && TYPE_ARG_TYPES (newtype) == 0))
- {
- error ("%Jconflicting types for '%D'", newdecl, newdecl);
- /* Check for function type mismatch
- involving an empty arglist vs a nonempty one. */
- if (TREE_CODE (olddecl) == FUNCTION_DECL
- && comptypes (TREE_TYPE (oldtype),
- TREE_TYPE (newtype), COMPARE_STRICT)
- && ((TYPE_ARG_TYPES (oldtype) == 0
- && DECL_INITIAL (olddecl) == 0)
- ||
- (TYPE_ARG_TYPES (newtype) == 0
- && DECL_INITIAL (newdecl) == 0)))
+
+ /* Objects declared at file scope: if the first declaration had
+ external linkage (even if it was an external reference) the
+ second must have external linkage as well, or the behavior is
+ undefined. If the first declaration had internal linkage, then
+ the second must too, or else be an external reference (in which
+ case the composite declaration still has internal linkage).
+ As for function declarations, we warn about the static-then-
+ extern case only for -Wtraditional. See generally 6.2.2p3-5,7. */
+ if (DECL_FILE_SCOPE_P (newdecl)
+ && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl))
{
- /* Classify the problem further. */
- tree t = TYPE_ARG_TYPES (oldtype);
- if (t == 0)
- t = TYPE_ARG_TYPES (newtype);
- for (; t; t = TREE_CHAIN (t))
+ if (DECL_EXTERNAL (newdecl))
{
- tree type = TREE_VALUE (t);
-
- if (TREE_CHAIN (t) == 0
- && TYPE_MAIN_VARIANT (type) != void_type_node)
+ if (warn_traditional)
{
- error ("a parameter list with an ellipsis can't match an empty parameter name list declaration");
- break;
+ warning ("%Jnon-static declaration of '%D' follows "
+ "static declaration", newdecl, newdecl);
+ warned = true;
}
+ }
+ else
+ {
+ if (TREE_PUBLIC (newdecl))
+ error ("%Jnon-static declaration of '%D' follows "
+ "static declaration", newdecl, newdecl);
+ else
+ error ("%Jstatic declaration of '%D' follows "
+ "non-static declaration", newdecl, newdecl);
- if (c_type_promotes_to (type) != type)
- {
- error ("an argument type that has a default promotion can't match an empty parameter name list declaration");
- break;
- }
+ locate_old_decl (olddecl, error);
+ return false;
}
}
- if (C_DECL_IMPLICIT (olddecl))
- error ("%Jprevious implicit declaration of '%D'", olddecl, olddecl);
- else
- error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+ /* Two objects with the same name declared at the same block
+ scope must both be external references (6.7p3). */
+ else if (!DECL_FILE_SCOPE_P (newdecl)
+ && DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl)
+ && (!DECL_EXTERNAL (newdecl) || !DECL_EXTERNAL (olddecl)))
+ {
+ if (DECL_EXTERNAL (newdecl))
+ error ("%Jextern declaration of '%D' follows "
+ "declaration with no linkage", newdecl, newdecl);
+ else if (DECL_EXTERNAL (olddecl))
+ error ("%Jdeclaration of '%D' with no linkage follows "
+ "extern declaration", newdecl, newdecl);
+ else
+ error ("%Jredeclaration of '%D' with no linkage",
+ newdecl, newdecl);
- /* 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 ("%Jthread-local declaration of '%D' follows non thread-local "
- "declaration", newdecl, newdecl);
- error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+ locate_old_decl (olddecl, error);
+ return false;
+ }
}
- /* 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))
+
+ /* warnings */
+ /* All decls must agree on a non-default visibility. */
+ if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT
+ && DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT
+ && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
{
- error ("%Jnon thread-local declaration of '%D' follows "
- "thread-local declaration", newdecl, newdecl);
- error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+ warning ("%Jredeclaration of '%D' with different visibility "
+ "(old visibility preserved)", newdecl, newdecl);
+ warned = true;
}
- else
+
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
- errmsg = redeclaration_error_message (newdecl, olddecl);
- if (errmsg)
+ /* Diagnose inline __attribute__ ((noinline)) which is silly. */
+ if (DECL_DECLARED_INLINE_P (newdecl)
+ && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
{
- switch (errmsg)
- {
- case 1:
- error ("%Jredefinition of '%D'", newdecl, newdecl);
- break;
- case 2:
- error ("%Jredeclaration of '%D'", newdecl, newdecl);
- break;
- case 3:
- error ("%Jconflicting declarations of '%D'", newdecl, newdecl);
- break;
- default:
- abort ();
- }
-
- if (DECL_INITIAL (olddecl)
- && current_scope == global_scope)
- error ("%J'%D' previously defined here", olddecl, olddecl);
- else
- error ("%J'%D' previously declared here", olddecl, olddecl);
- return 0;
+ warning ("%Jinline declaration of '%D' follows "
+ "declaration with attribute noinline", newdecl, newdecl);
+ warned = true;
}
- else if (TREE_CODE (newdecl) == TYPE_DECL
- && (DECL_IN_SYSTEM_HEADER (olddecl)
- || DECL_IN_SYSTEM_HEADER (newdecl)))
+ else if (DECL_DECLARED_INLINE_P (olddecl)
+ && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
{
- warning ("%Jredefinition of '%D'", newdecl, newdecl);
- if (DECL_INITIAL (olddecl) && current_scope == global_scope)
- warning ("%J'%D' previously defined here", olddecl, olddecl);
- else
- warning ("%J'%D' previously declared here", olddecl, olddecl);
+ warning ("%Jdeclaration of '%D' with attribute noinline follows "
+ "inline declaration ", newdecl, newdecl);
+ warned = true;
}
- else if (TREE_CODE (olddecl) == FUNCTION_DECL
- && DECL_INITIAL (olddecl) != 0
- && TYPE_ARG_TYPES (oldtype) == 0
- && TYPE_ARG_TYPES (newtype) != 0
- && TYPE_ACTUAL_ARG_TYPES (oldtype) != 0)
+
+ /* Inline declaration after use or definition.
+ ??? Should we still warn about this now we have unit-at-a-time
+ mode and can get it right?
+ Definitely don't complain if the decls are in different translation
+ units. */
+ if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl)
+ && same_translation_unit_p (olddecl, newdecl))
{
- tree type, parm;
- int nargs;
- /* Prototype decl follows defn w/o prototype. */
-
- for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype),
- type = TYPE_ARG_TYPES (newtype),
- nargs = 1;
- ;
- parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++)
+ if (TREE_USED (olddecl))
{
- if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node
- && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
- {
- warning ("%Jprototype for '%D' follows", newdecl, newdecl);
- warning ("%Jnon-prototype definition here", olddecl);
- break;
- }
- if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node
- || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
- {
- error ("%Jprototype for '%D' follows and number of "
- "arguments doesn't match", newdecl, newdecl);
- error ("%Jnon-prototype definition here", olddecl);
- errmsg = 1;
- break;
- }
- /* Type for passing arg must be consistent
- with that declared for the arg. */
- if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type),
- COMPARE_STRICT))
- {
- error ("%Jprototype for '%D' follows and argument %d "
- "doesn't match", newdecl, newdecl, nargs);
- error ("%Jnon-prototype definition here", olddecl);
- errmsg = 1;
- break;
- }
+ warning ("%J'%D' declared inline after being called",
+ olddecl, olddecl);
+ warned = true;
+ }
+ else if (DECL_INITIAL (olddecl))
+ {
+ warning ("%J'%D' declared inline after its definition",
+ olddecl, olddecl);
+ warned = true;
}
}
- /* Warn about mismatches in various flags. */
- else
+ }
+ else /* PARM_DECL, VAR_DECL */
+ {
+ /* Redeclaration of a parameter is a constraint violation (this is
+ not explicitly stated, but follows from C99 6.7p3 [no more than
+ one declaration of the same identifier with no linkage in the
+ same scope, except type tags] and 6.2.2p6 [parameters have no
+ linkage]). We must check for a forward parameter declaration,
+ indicated by TREE_ASM_WRITTEN on the old declaration - this is
+ an extension, the mandatory diagnostic for which is handled by
+ mark_forward_parm_decls. */
+
+ if (TREE_CODE (newdecl) == PARM_DECL
+ && (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl)))
{
- /* Warn if function is now inline
- but was previously declared not inline and has been called. */
- if (TREE_CODE (olddecl) == FUNCTION_DECL
- && ! DECL_DECLARED_INLINE_P (olddecl)
- && DECL_DECLARED_INLINE_P (newdecl)
- && TREE_USED (olddecl))
- warning ("%J'%D' declared inline after being called",
- newdecl, newdecl);
- if (TREE_CODE (olddecl) == FUNCTION_DECL
- && ! DECL_DECLARED_INLINE_P (olddecl)
- && DECL_DECLARED_INLINE_P (newdecl)
- && DECL_INITIAL (olddecl) != 0)
- warning ("%J'%D' declared inline after its definition",
- newdecl, newdecl);
+ error ("%Jredefinition of parameter '%D'", newdecl, newdecl);
+ locate_old_decl (olddecl, error);
+ return false;
+ }
+ }
- /* If pedantic, warn when static declaration follows a non-static
- declaration. Otherwise, do so only for functions. */
- if ((pedantic || TREE_CODE (olddecl) == FUNCTION_DECL)
- && TREE_PUBLIC (olddecl)
- && !TREE_PUBLIC (newdecl))
- warning ("%Jstatic declaration for '%D' follows non-static",
- newdecl, newdecl);
+ /* Optional warning for completely redundant decls. */
+ if (!warned && !pedwarned
+ && warn_redundant_decls
+ /* Don't warn about a function declaration followed by a
+ definition. */
+ && !(TREE_CODE (newdecl) == FUNCTION_DECL
+ && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl))
+ /* Don't warn about an extern followed by a definition. */
+ && !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl))
+ /* Don't warn about forward parameter decls. */
+ && !(TREE_CODE (newdecl) == PARM_DECL
+ && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)))
+ {
+ warning ("%Jredundant redeclaration of '%D'", newdecl, newdecl);
+ warned = true;
+ }
- /* If warn_traditional, warn when a non-static function
- declaration follows a static one. */
- if (warn_traditional && !in_system_header
- && TREE_CODE (olddecl) == FUNCTION_DECL
- && !TREE_PUBLIC (olddecl)
- && TREE_PUBLIC (newdecl))
- warning ("%Jnon-static declaration for '%D' follows static",
- newdecl, newdecl);
+ /* Report location of previous decl/defn in a consistent manner. */
+ if (warned || pedwarned)
+ locate_old_decl (olddecl, pedwarned ? pedwarn : warning);
- /* Warn when const declaration follows a non-const
- declaration, but not for functions. */
- if (TREE_CODE (olddecl) != FUNCTION_DECL
- && !TREE_READONLY (olddecl)
- && TREE_READONLY (newdecl))
- warning ("%Jconst declaration for '%D' follows non-const",
- newdecl, newdecl);
- /* These bits are logically part of the type, for variables.
- But not for functions
- (where qualifiers are not valid ANSI anyway). */
- else if (pedantic && TREE_CODE (olddecl) != FUNCTION_DECL
- && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
- || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl)))
- pedwarn ("%Jtype qualifiers for '%D' conflict with previous "
- "declaration", newdecl, newdecl);
- }
+ return true;
+}
+
+/* Subroutine of duplicate_decls. NEWDECL has been found to be
+ consistent with OLDDECL, but carries new information. Merge the
+ new information into OLDDECL. This function issues no
+ diagnostics. */
+
+static void
+merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
+{
+ int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
+ && DECL_INITIAL (newdecl) != 0);
+
+ /* For real parm decl following a forward decl, rechain the old decl
+ in its new location and clear TREE_ASM_WRITTEN (it's not a
+ forward decl anymore). */
+ if (TREE_CODE (newdecl) == PARM_DECL
+ && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl))
+ {
+ struct c_binding *b, **here;
+
+ for (here = ¤t_scope->bindings; *here; here = &(*here)->prev)
+ if ((*here)->decl == olddecl)
+ goto found;
+ abort ();
+
+ found:
+ b = *here;
+ *here = b->prev;
+ b->prev = current_scope->bindings;
+ current_scope->bindings = b;
+
+ TREE_ASM_WRITTEN (olddecl) = 0;
}
- /* Optionally warn about more than one declaration for the same name. */
- if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0
- /* Don't warn about a function declaration
- followed by a definition. */
- && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0
- && DECL_INITIAL (olddecl) == 0)
- /* Don't warn about extern decl followed by (tentative) definition. */
- && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)))
+ DECL_ATTRIBUTES (newdecl)
+ = targetm.merge_decl_attributes (olddecl, newdecl);
+
+ /* Merge the data types specified in the two decls. */
+ TREE_TYPE (newdecl)
+ = TREE_TYPE (olddecl)
+ = composite_type (newtype, oldtype);
+
+ /* Lay the type out, unless already done. */
+ if (oldtype != TREE_TYPE (newdecl))
{
- warning ("%Jredundant redeclaration of '%D' in same scope",
- newdecl, newdecl);
- warning ("%Jprevious declaration of '%D'", olddecl, olddecl);
+ if (TREE_TYPE (newdecl) != error_mark_node)
+ layout_type (TREE_TYPE (newdecl));
+ if (TREE_CODE (newdecl) != FUNCTION_DECL
+ && TREE_CODE (newdecl) != TYPE_DECL
+ && TREE_CODE (newdecl) != CONST_DECL)
+ layout_decl (newdecl, 0);
+ }
+ else
+ {
+ /* Since the type is OLDDECL's, make OLDDECL's size go with. */
+ DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
+ DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
+ DECL_MODE (newdecl) = DECL_MODE (olddecl);
+ if (TREE_CODE (olddecl) != FUNCTION_DECL)
+ if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
+ {
+ DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
+ DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
+ }
}
- /* Copy all the DECL_... slots specified in the new decl
- except for any that we copy here from the old type.
+ /* Keep the old rtl since we can safely use it. */
+ COPY_DECL_RTL (olddecl, newdecl);
- Past this point, we don't change OLDTYPE and NEWTYPE
- even if we change the types of NEWDECL and OLDDECL. */
+ /* Merge the type qualifiers. */
+ if (TREE_READONLY (newdecl))
+ TREE_READONLY (olddecl) = 1;
- if (types_match)
+ if (TREE_THIS_VOLATILE (newdecl))
{
- /* When copying info to olddecl, we store into write_olddecl
- instead. This allows us to avoid modifying olddecl when
- different_binding_level is true. */
- tree write_olddecl = different_binding_level ? newdecl : olddecl;
+ TREE_THIS_VOLATILE (olddecl) = 1;
+ if (TREE_CODE (newdecl) == VAR_DECL)
+ make_var_volatile (newdecl);
+ }
- /* Merge the data types specified in the two decls. */
- if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
- {
- if (different_binding_level)
- {
- if (TYPE_ARG_TYPES (oldtype) != 0
- && TYPE_ARG_TYPES (newtype) == 0)
- TREE_TYPE (newdecl) = common_type (newtype, oldtype);
- else
- TREE_TYPE (newdecl)
- = build_type_attribute_variant
- (newtype,
- merge_attributes (TYPE_ATTRIBUTES (newtype),
- TYPE_ATTRIBUTES (oldtype)));
- }
- else
- TREE_TYPE (newdecl)
- = TREE_TYPE (olddecl)
- = common_type (newtype, oldtype);
- }
+ /* Keep source location of definition rather than declaration. */
+ if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+ DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
- /* Lay the type out, unless already done. */
- if (oldtype != TREE_TYPE (newdecl))
- {
- if (TREE_TYPE (newdecl) != error_mark_node)
- layout_type (TREE_TYPE (newdecl));
- if (TREE_CODE (newdecl) != FUNCTION_DECL
- && TREE_CODE (newdecl) != TYPE_DECL
- && TREE_CODE (newdecl) != CONST_DECL)
- layout_decl (newdecl, 0);
- }
- else
- {
- /* Since the type is OLDDECL's, make OLDDECL's size go with. */
- DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
- DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
- DECL_MODE (newdecl) = DECL_MODE (olddecl);
- if (TREE_CODE (olddecl) != FUNCTION_DECL)
- if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
- {
- DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
- DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
- }
- }
+ /* Merge the unused-warning information. */
+ if (DECL_IN_SYSTEM_HEADER (olddecl))
+ DECL_IN_SYSTEM_HEADER (newdecl) = 1;
+ else if (DECL_IN_SYSTEM_HEADER (newdecl))
+ DECL_IN_SYSTEM_HEADER (olddecl) = 1;
- /* Keep the old rtl since we can safely use it. */
- COPY_DECL_RTL (olddecl, newdecl);
+ /* Merge the initialization information. */
+ if (DECL_INITIAL (newdecl) == 0)
+ DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
- /* Merge the type qualifiers. */
- if (TREE_READONLY (newdecl))
- TREE_READONLY (write_olddecl) = 1;
+ /* Merge the section attribute.
+ We want to issue an error if the sections conflict but that must be
+ done later in decl_attributes since we are called before attributes
+ are assigned. */
+ if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
+ DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
- if (TREE_THIS_VOLATILE (newdecl))
- {
- TREE_THIS_VOLATILE (write_olddecl) = 1;
- if (TREE_CODE (newdecl) == VAR_DECL
- /* If an automatic variable is re-declared in the same
- function scope, but the old declaration was not
- volatile, make_var_volatile() would crash because the
- variable would have been assigned to a pseudo, not a
- MEM. Since this duplicate declaration is invalid
- anyway, we just skip the call. */
- && errmsg == 0)
- make_var_volatile (newdecl);
- }
+ /* Copy the assembler name.
+ Currently, it can only be defined in the prototype. */
+ COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
- /* Keep source location of definition rather than declaration. */
- /* When called with different_binding_level set, keep the old
- information so that meaningful diagnostics can be given. */
- if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0
- && ! different_binding_level)
- {
- DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
- DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
- }
+ /* If either declaration has a nondefault visibility, use it. */
+ if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT)
+ DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
- /* Merge the unused-warning information. */
- if (DECL_IN_SYSTEM_HEADER (olddecl))
- DECL_IN_SYSTEM_HEADER (newdecl) = 1;
- else if (DECL_IN_SYSTEM_HEADER (newdecl))
- DECL_IN_SYSTEM_HEADER (write_olddecl) = 1;
-
- /* Merge the initialization information. */
- /* When called with different_binding_level set, don't copy over
- DECL_INITIAL, so that we don't accidentally change function
- declarations into function definitions. */
- if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level)
- DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
-
- /* Merge the section attribute.
- We want to issue an error if the sections conflict but that must be
- done later in decl_attributes since we are called before attributes
- are assigned. */
- if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
- DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
-
- /* Copy the assembler name.
- Currently, it can only be defined in the prototype. */
- COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
-
- if (TREE_CODE (newdecl) == FUNCTION_DECL)
- {
- DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
- DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
- 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,
- and don't preserve the old rtl. */
- else if (! different_binding_level)
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
- TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
- TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
- TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl);
- TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl);
+ DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
+ DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
+ 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);
}
/* Merge the storage class information. */
TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
/* This is since we don't automatically
copy the attributes of NEWDECL into OLDDECL. */
- /* No need to worry about different_binding_level here because
- then TREE_PUBLIC (newdecl) was true. */
TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
/* If this clears `static', clear it in the identifier too. */
if (! TREE_PUBLIC (olddecl))
}
if (DECL_EXTERNAL (newdecl))
{
- if (! different_binding_level || different_tu)
- {
- /* Don't mess with these flags on local externs; they remain
- external even if there's a declaration at file scope which
- isn't. */
- TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
- DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
- }
+ TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
+ DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
+
/* An extern decl does not override previous storage class. */
TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
if (! DECL_EXTERNAL (newdecl))
{
DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
- /* If we have two non-EXTERNAL file-scope decls that are
- the same, only one of them should be written out. */
- if (different_tu)
- TREE_ASM_WRITTEN (newdecl) = 1;
+ DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
}
}
else
been written out yet. */
if (new_is_definition && DECL_INITIAL (olddecl))
{
- if (TREE_USED (olddecl))
+ if (TREE_USED (olddecl)
+ /* In unit-at-a-time mode we never inline re-defined extern
+ inline functions. */
+ && !flag_unit_at_a_time
+ && cgraph_function_possibly_inlined_p (olddecl))
(*debug_hooks->outlining_inline_function) (olddecl);
/* The new defn must not be inline. */
if (DECL_BUILT_IN (olddecl))
{
- /* Get rid of any built-in function if new arg types don't match it
- or if we have a function definition. */
- if (! types_match || new_is_definition)
- {
- if (! different_binding_level)
- {
- TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
- DECL_BUILT_IN_CLASS (olddecl) = NOT_BUILT_IN;
- }
- }
- else
- {
- /* If redeclaring a builtin function, and not a definition,
- it stays built in. */
- DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
- DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
- }
+ /* If redeclaring a builtin function, it stays built in.
+ But it gets tagged as having been declared. */
+ DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+ DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+ C_DECL_DECLARED_BUILTIN (newdecl) = 1;
}
/* Also preserve various other info from the definition. */
if (! new_is_definition)
{
DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
- /* When called with different_binding_level set, don't copy over
- DECL_INITIAL, so that we don't accidentally change function
- declarations into function definitions. */
- if (! different_binding_level)
- DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
- DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
+ DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+ DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl);
DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
- DECL_ESTIMATED_INSNS (newdecl) = DECL_ESTIMATED_INSNS (olddecl);
DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
/* Set DECL_INLINE on the declaration if we've got a body
{
DECL_INLINE (newdecl) = 1;
DECL_ABSTRACT_ORIGIN (newdecl)
- = (different_binding_level
- ? DECL_ORIGIN (olddecl)
- : DECL_ABSTRACT_ORIGIN (olddecl));
+ = DECL_ABSTRACT_ORIGIN (olddecl);
}
}
else
DECL_INLINE (newdecl) = 1;
}
}
- if (different_binding_level)
- return 0;
/* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
- But preserve OLDDECL's DECL_UID. */
+ But preserve OLDDECL's DECL_UID and DECL_CONTEXT. */
{
unsigned olddecl_uid = DECL_UID (olddecl);
+ tree olddecl_context = DECL_CONTEXT (olddecl);
memcpy ((char *) olddecl + sizeof (struct tree_common),
(char *) newdecl + sizeof (struct tree_common),
sizeof (struct tree_decl) - sizeof (struct tree_common));
DECL_UID (olddecl) = olddecl_uid;
+ DECL_CONTEXT (olddecl) = olddecl_context;
}
- /* NEWDECL contains the merged attribute lists.
- 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. */
|| (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. */
+/* Handle when a new declaration NEWDECL has the same name as an old
+ one OLDDECL in the same binding contour. Prints an error message
+ if appropriate.
-static tree
-any_external_decl (tree id)
-{
- tree decl = IDENTIFIER_SYMBOL_VALUE (id);
- tree t;
+ If safely possible, alter OLDDECL to look like NEWDECL, and return
+ true. Otherwise, return false. */
- 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)
+static bool
+duplicate_decls (tree newdecl, tree olddecl)
{
- tree name = DECL_NAME (decl);
- if (!IDENTIFIER_SYMBOL_VALUE (name))
- return;
+ tree newtype = NULL, oldtype = NULL;
+
+ if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype))
+ return false;
- truly_local_externals = tree_cons (name, decl, truly_local_externals);
+ merge_decls (newdecl, olddecl, newtype, oldtype);
+ return true;
}
-/* Check whether decl-node X shadows an existing declaration.
- OLD is the old IDENTIFIER_SYMBOL_VALUE of the DECL_NAME of X,
- which might be a NULL_TREE. */
+\f
+/* Check whether decl-node NEW shadows an existing declaration. */
static void
-warn_if_shadowing (tree x, tree old)
+warn_if_shadowing (tree new)
{
- const char *name;
+ struct c_binding *b;
- /* Nothing to shadow? */
- if (old == 0
- /* Shadow warnings not wanted? */
- || !warn_shadow
+ /* Shadow warnings wanted? */
+ if (!warn_shadow
/* No shadow warnings for internally generated vars. */
- || DECL_SOURCE_LINE (x) == 0
+ || DECL_IS_BUILTIN (new)
/* No shadow warnings for vars made for inlining. */
- || DECL_FROM_INLINE (x)
+ || DECL_FROM_INLINE (new)
/* 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_scope->outer->parm_flag))
+ 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 at this point. */
+ || (TREE_CODE (new) == PARM_DECL && current_scope->outer->parm_flag))
return;
- name = IDENTIFIER_POINTER (DECL_NAME (x));
- if (TREE_CODE (old) == PARM_DECL)
- shadow_warning (SW_PARAM, name, old);
- else if (DECL_FILE_SCOPE_P (old))
- shadow_warning (SW_GLOBAL, name, old);
- else
- shadow_warning (SW_LOCAL, name, old);
+ /* Is anything being shadowed? Invisible decls do not count. */
+ for (b = I_SYMBOL_BINDING (DECL_NAME (new)); b; b = b->shadowed)
+ if (b->decl && b->decl != new && !b->invisible)
+ {
+ tree old = b->decl;
+
+ if (TREE_CODE (old) == PARM_DECL)
+ warning ("%Jdeclaration of '%D' shadows a parameter", new, new);
+ else if (DECL_FILE_SCOPE_P (old))
+ warning ("%Jdeclaration of '%D' shadows a global declaration",
+ new, new);
+ else if (TREE_CODE (old) == FUNCTION_DECL && DECL_BUILT_IN (old))
+ warning ("%Jdeclaration of '%D' shadows a built-in function",
+ new, new);
+ else
+ warning ("%Jdeclaration of '%D' shadows a previous local", new, new);
+
+ if (TREE_CODE (old) != FUNCTION_DECL || !DECL_BUILT_IN (old))
+ warning ("%Jshadowed declaration is here", old);
+
+ break;
+ }
}
static void
clone_underlying_type (tree x)
{
- if (DECL_SOURCE_LINE (x) == 0)
+ if (DECL_IS_BUILTIN (x))
{
if (TYPE_NAME (TREE_TYPE (x)) == 0)
TYPE_NAME (TREE_TYPE (x)) = x;
{
tree name = DECL_NAME (x);
struct c_scope *scope = current_scope;
-
-#ifdef ENABLE_CHECKING
- if (error_mark_node == 0)
- /* Called too early. */
- abort ();
-#endif
+ struct c_binding *b;
+ bool nested = false;
/* Functions need the lang_decl data. */
if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_LANG_SPECIFIC (x))
DECL_LANG_SPECIFIC (x) = ggc_alloc_cleared (sizeof (struct lang_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 (current_function_decl == NULL
- || ((TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL)
- && DECL_INITIAL (x) == 0 && DECL_EXTERNAL (x)))
- DECL_CONTEXT (x) = current_file_decl;
- else
+ /* Must set DECL_CONTEXT for everything not at file scope or
+ DECL_FILE_SCOPE_P won't work. Local externs don't count
+ unless they have initializers (which generate code). */
+ if (current_function_decl
+ && ((TREE_CODE (x) != FUNCTION_DECL && TREE_CODE (x) != VAR_DECL)
+ || DECL_INITIAL (x) || !DECL_EXTERNAL (x)))
DECL_CONTEXT (x) = current_function_decl;
-
- if (name)
+
+ /* Anonymous decls are just inserted in the scope. */
+ if (!name)
+ {
+ bind (name, x, scope, /*invisible=*/false, /*nested=*/false);
+ return x;
+ }
+
+ /* First, see if there is another declaration with the same name in
+ the current scope. If there is, duplicate_decls may do all the
+ work for us. If duplicate_decls returns false, that indicates
+ two incompatible decls in the same scope; we are to silently
+ replace the old one (duplicate_decls has issued all appropriate
+ diagnostics). In particular, we should not consider possible
+ duplicates in the external scope, or shadowing. */
+ b = I_SYMBOL_BINDING (name);
+ if (b && B_IN_SCOPE (b, scope))
{
- tree old;
+ if (duplicate_decls (x, b->decl))
+ return b->decl;
+ else
+ goto skip_external_and_shadow_checks;
+ }
+
+ /* All declarations with external linkage, and all external
+ references, go in the external scope, no matter what scope is
+ current. However, the binding in that scope is ignored for
+ purposes of normal name lookup. A separate binding structure is
+ created in the requested scope; this governs the normal
+ visibility of the symbol.
+ The binding in the externals scope is used exclusively for
+ detecting duplicate declarations of the same object, no matter
+ what scope they are in; this is what we do here. (C99 6.2.7p2:
+ All declarations that refer to the same object or function shall
+ have compatible type; otherwise, the behavior is undefined.) */
+ if (DECL_EXTERNAL (x) || scope == file_scope)
+ {
if (warn_nested_externs
- && scope != global_scope
- && DECL_EXTERNAL (x)
+ && scope != file_scope
&& !DECL_IN_SYSTEM_HEADER (x))
- warning ("nested extern declaration of `%s'",
- IDENTIFIER_POINTER (name));
-
- old = lookup_name_current_level (name);
- if (old && duplicate_decls (x, old, 0, false))
+ warning ("nested extern declaration of '%D'", x);
+
+ while (b && !B_IN_EXTERNAL_SCOPE (b))
+ b = b->shadowed;
+
+ /* The point of the same_translation_unit_p check here is,
+ we want to detect a duplicate decl for a construct like
+ foo() { extern bar(); } ... static bar(); but not if
+ they are in different translation units. In any case,
+ the static does not go in the externals scope. */
+ if (b
+ && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
+ && duplicate_decls (x, b->decl))
{
- /* For PARM_DECLs, old may be a forward declaration.
- If so, we want to remove it from its old location
- (in the variables chain) and rechain it in the
- location given by the new declaration. */
- if (TREE_CODE (x) == PARM_DECL)
- {
- tree *p;
- for (p = &scope->names; *p; p = &TREE_CHAIN (*p))
- if (*p == old)
- {
- *p = TREE_CHAIN (old);
- SCOPE_LIST_APPEND (scope, parms, old);
- break;
- }
- }
- return old;
+ bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true);
+ return b->decl;
}
- if (DECL_EXTERNAL (x) || scope == global_scope)
+ else if (TREE_PUBLIC (x))
{
- /* 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)
- {
- if (duplicate_decls (x, ext, scope != global_scope,
- false))
- x = copy_node (ext);
- }
- else
- record_external_decl (x);
+ bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false);
+ nested = true;
}
+ }
+ /* Similarly, a declaration of a function with static linkage at
+ block scope must be checked against any existing declaration
+ of that function at file scope. */
+ else if (TREE_CODE (x) == FUNCTION_DECL && scope != file_scope
+ && !TREE_PUBLIC (x) && !DECL_INITIAL (x))
+ {
+ if (warn_nested_externs && !DECL_IN_SYSTEM_HEADER (x))
+ warning ("nested static declaration of '%D'", x);
+
+ while (b && !B_IN_FILE_SCOPE (b))
+ b = b->shadowed;
- 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
- scope ends. Take care not to do this if we are replacing an
- older decl in the same scope (i.e. duplicate_decls returned
- false, above). */
- if (scope != global_scope
- && IDENTIFIER_SYMBOL_VALUE (name)
- && IDENTIFIER_SYMBOL_VALUE (name) != old)
+ if (b && same_translation_unit_p (x, b->decl)
+ && duplicate_decls (x, b->decl))
{
- warn_if_shadowing (x, IDENTIFIER_SYMBOL_VALUE (name));
- scope->shadowed = tree_cons (name, IDENTIFIER_SYMBOL_VALUE (name),
- scope->shadowed);
+ bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true);
+ return b->decl;
}
-
- /* Install the new declaration in the requested scope. */
- IDENTIFIER_SYMBOL_VALUE (name) = x;
- C_DECL_INVISIBLE (x) = 0;
-
- /* If x's type is incomplete because it's based on a
- structure or union which has not yet been fully declared,
- attach it to that structure or union type, so we can go
- back and complete the variable declaration later, if the
- structure or union gets fully declared.
-
- 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. */
- if (TREE_TYPE (x) != error_mark_node
- && !COMPLETE_TYPE_P (TREE_TYPE (x)))
+ else
{
- tree element = TREE_TYPE (x);
-
- while (TREE_CODE (element) == ARRAY_TYPE)
- element = TREE_TYPE (element);
- element = TYPE_MAIN_VARIANT (element);
-
- if ((TREE_CODE (element) == RECORD_TYPE
- || TREE_CODE (element) == UNION_TYPE)
- && (TREE_CODE (x) != TYPE_DECL
- || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE)
- && !COMPLETE_TYPE_P (element))
- C_TYPE_INCOMPLETE_VARS (element)
- = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element));
+ bind (name, x, file_scope, /*invisible=*/true, /*nested=*/false);
+ nested = true;
}
- }
+ }
- if (TREE_CODE (x) == PARM_DECL)
- SCOPE_LIST_APPEND (scope, parms, x);
- else
- SCOPE_LIST_APPEND (scope, names, x);
+ warn_if_shadowing (x);
+ skip_external_and_shadow_checks:
+ if (TREE_CODE (x) == TYPE_DECL)
+ clone_underlying_type (x);
+
+ bind (name, x, scope, /*invisible=*/false, nested);
+
+ /* If x's type is incomplete because it's based on a
+ structure or union which has not yet been fully declared,
+ attach it to that structure or union type, so we can go
+ back and complete the variable declaration later, if the
+ structure or union gets fully declared.
+
+ 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. */
+ if (TREE_TYPE (x) != error_mark_node
+ && !COMPLETE_TYPE_P (TREE_TYPE (x)))
+ {
+ tree element = TREE_TYPE (x);
+
+ while (TREE_CODE (element) == ARRAY_TYPE)
+ element = TREE_TYPE (element);
+ element = TYPE_MAIN_VARIANT (element);
+
+ if ((TREE_CODE (element) == RECORD_TYPE
+ || TREE_CODE (element) == UNION_TYPE)
+ && (TREE_CODE (x) != TYPE_DECL
+ || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE)
+ && !COMPLETE_TYPE_P (element))
+ C_TYPE_INCOMPLETE_VARS (element)
+ = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element));
+ }
return x;
}
-/* Record X as belonging to the global scope (C99 "file scope").
+/* Record X as belonging to file scope.
This is used only internally by the Objective-C front end,
and is limited to its needs. duplicate_decls is not called;
if there is any preexisting decl for this identifier, it is an ICE. */
pushdecl_top_level (tree x)
{
tree name;
+ bool nested = false;
if (TREE_CODE (x) != VAR_DECL)
abort ();
name = DECL_NAME (x);
- if (IDENTIFIER_SYMBOL_VALUE (name))
+ if (I_SYMBOL_BINDING (name))
abort ();
- DECL_CONTEXT (x) = current_file_decl;
- IDENTIFIER_SYMBOL_VALUE (name) = x;
+ if (TREE_PUBLIC (x))
+ {
+ bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false);
+ nested = true;
+ }
+ if (file_scope)
+ bind (name, x, file_scope, /*invisible=*/false, nested);
- SCOPE_LIST_APPEND (global_scope, names, x);
return x;
}
\f
+static void
+implicit_decl_warning (tree id, tree olddecl)
+{
+ void (*diag) (const char *, ...);
+ switch (mesg_implicit_function_declaration)
+ {
+ case 0: return;
+ case 1: diag = warning; break;
+ case 2: diag = error; break;
+ default: abort ();
+ }
+
+ diag (N_("implicit declaration of function '%E'"), id);
+ if (olddecl)
+ locate_old_decl (olddecl, diag);
+}
+
/* Generate an implicit declaration for identifier FUNCTIONID as a
function of type int (). */
tree
implicitly_declare (tree functionid)
{
- tree decl = any_external_decl (functionid);
+ tree decl = lookup_name_in_scope (functionid, external_scope);
if (decl)
{
- /* 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))
+ /* FIXME: Objective-C has weird not-really-builtin functions
+ which are supposed to be visible automatically. They wind up
+ in the external scope because they're pushed before the file
+ scope gets created. Catch this here and rebind them into the
+ file scope. */
+ if (!DECL_BUILT_IN (decl) && DECL_IS_BUILTIN (decl))
{
- implicit_decl_warning (DECL_NAME (decl));
- if (! DECL_FILE_SCOPE_P (decl))
- warning ("%Jprevious declaration of '%D'", decl, decl);
- C_DECL_IMPLICIT (decl) = 1;
+ bind (functionid, decl, file_scope,
+ /*invisible=*/false, /*nested=*/true);
+ return decl;
+ }
+ else
+ {
+ /* 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 (functionid, decl);
+ C_DECL_IMPLICIT (decl) = 1;
+ }
+ bind (functionid, decl, current_scope,
+ /*invisible=*/false, /*nested=*/true);
+ return decl;
}
- /* If this function is global, then it must already be in the
- global scope, so there's no need to push it again. */
- if (current_scope == global_scope)
- return decl;
- /* If this is a local declaration, make a copy; we can't have
- the same DECL listed in two different scopes. */
- return pushdecl (copy_node (decl));
}
/* Not seen before. */
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
C_DECL_IMPLICIT (decl) = 1;
- implicit_decl_warning (functionid);
+ implicit_decl_warning (functionid, 0);
/* C89 says implicit declarations are in the innermost block.
So we record the decl in the standard fashion. */
return decl;
}
-static void
-implicit_decl_warning (tree id)
-{
- const char *name = IDENTIFIER_POINTER (id);
- if (mesg_implicit_function_declaration == 2)
- error ("implicit declaration of function `%s'", name);
- else if (mesg_implicit_function_declaration == 1)
- warning ("implicit declaration of function `%s'", name);
-}
-
-/* Return zero if the declaration NEWDECL is valid
- when the declaration OLDDECL (assumed to be for the same name)
- has already been seen.
- Otherwise return 1 if NEWDECL is a redefinition, 2 if it is a redeclaration,
- and 3 if it is a conflicting declaration. */
-
-static int
-redeclaration_error_message (tree newdecl, tree olddecl)
-{
- if (TREE_CODE (newdecl) == TYPE_DECL)
- {
- /* Do not complain about type redeclarations where at least one
- declaration was in a system header. */
- if (DECL_IN_SYSTEM_HEADER (olddecl) || DECL_IN_SYSTEM_HEADER (newdecl))
- return 0;
- return 1;
- }
- else if (TREE_CODE (newdecl) == FUNCTION_DECL)
- {
- /* Declarations of functions can insist on internal linkage
- but they can't be inconsistent with internal linkage,
- so there can be no error on that account.
- However defining the same name twice is no good. */
- if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0
- /* However, defining once as extern inline and a second
- time in another way is ok. */
- && ! (DECL_DECLARED_INLINE_P (olddecl) && DECL_EXTERNAL (olddecl)
- && ! (DECL_DECLARED_INLINE_P (newdecl)
- && DECL_EXTERNAL (newdecl))))
- return 1;
- return 0;
- }
- else if (DECL_FILE_SCOPE_P (newdecl))
- {
- /* Objects declared at file scope: */
- /* If at least one is a reference, it's ok. */
- if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl))
- return 0;
- /* Reject two definitions. */
- if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0)
- return 1;
- /* Now we have two tentative defs, or one tentative and one real def. */
- /* Insist that the linkage match. */
- if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl))
- return 3;
- return 0;
- }
- else if (current_scope->parm_flag
- && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl))
- return 0;
- else
- {
- /* Newdecl has block scope. If olddecl has block scope also, then
- reject two definitions, and reject a definition together with an
- external reference. Otherwise, it is OK, because newdecl must
- be an extern reference to olddecl. */
- if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl))
- && DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl))
- return 2;
- return 0;
- }
-}
-
/* Issue an error message for a reference to an undeclared variable
ID, including a reference to a builtin outside of function-call
context. Establish a binding of the identifier to error_mark_node
if (current_function_decl == 0)
{
- error ("`%s' undeclared here (not in a function)",
- IDENTIFIER_POINTER (id));
+ error ("'%E' undeclared here (not in a function)", id);
scope = current_scope;
}
else
{
- error ("`%s' undeclared (first use in this function)",
- IDENTIFIER_POINTER (id));
+ error ("'%E' undeclared (first use in this function)", id);
if (! already)
{
already = true;
}
- scope = current_function_scope;
+ /* If we are parsing old-style parameter decls, current_function_decl
+ will be nonnull but current_function_scope will be null. */
+ scope = current_function_scope ? current_function_scope : current_scope;
}
-
- scope->shadowed = tree_cons (id, IDENTIFIER_SYMBOL_VALUE (id),
- scope->shadowed);
- IDENTIFIER_SYMBOL_VALUE (id) = error_mark_node;
+ bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false);
}
\f
/* Subroutine of lookup_label, declare_label, define_label: construct a
return label;
}
-/* Another subroutine of lookup_label, declare_label, define_label:
- set up the binding of name to LABEL_DECL in the given SCOPE. */
-
-static void
-bind_label (tree name, tree label, struct c_scope *scope)
-{
- if (IDENTIFIER_LABEL_VALUE (name))
- scope->shadowed = tree_cons (name, IDENTIFIER_LABEL_VALUE (name),
- scope->shadowed);
- IDENTIFIER_LABEL_VALUE (name) = label;
-
- SCOPE_LIST_APPEND (scope, names, label);
-}
-
/* Get the LABEL_DECL corresponding to identifier NAME as a label.
Create one if none exists so far for the current function.
This is called when a label is used in a goto expression or
/* Use a label already defined or ref'd with this name, but not if
it is inherited from a containing function and wasn't declared
using __label__. */
- label = IDENTIFIER_LABEL_VALUE (name);
+ label = I_LABEL_DECL (name);
if (label && (DECL_CONTEXT (label) == current_function_decl
|| C_DECLARED_LABEL_FLAG (label)))
{
label = make_label (name, input_location);
/* Ordinary labels go in the current function scope. */
- bind_label (name, label, current_function_scope);
+ bind (name, label, current_function_scope,
+ /*invisible=*/false, /*nested=*/false);
return label;
}
any that may be inherited from containing functions or containing
scopes. This is called for __label__ declarations. */
-/* Note that valid use, if the label being shadowed comes from another
- scope in the same function, requires calling declare_nonlocal_label
- right away. (Is this still true? -zw 2003-07-17) */
-
tree
declare_label (tree name)
{
- tree label = IDENTIFIER_LABEL_VALUE (name);
- tree dup;
+ struct c_binding *b = I_LABEL_BINDING (name);
+ tree label;
/* Check to make sure that the label hasn't already been declared
at this scope */
- for (dup = current_scope->names; dup; dup = TREE_CHAIN (dup))
- if (dup == label)
- {
- error ("duplicate label declaration `%s'", IDENTIFIER_POINTER (name));
- error ("%Jthis is a previous declaration", dup);
+ if (b && B_IN_CURRENT_SCOPE (b))
+ {
+ error ("duplicate label declaration `%s'", IDENTIFIER_POINTER (name));
+ locate_old_decl (b->decl, error);
- /* Just use the previous declaration. */
- return dup;
- }
+ /* Just use the previous declaration. */
+ return b->decl;
+ }
label = make_label (name, input_location);
C_DECLARED_LABEL_FLAG (label) = 1;
/* Declared labels go in the current scope. */
- bind_label (name, label, current_scope);
+ bind (name, label, current_scope,
+ /*invisible=*/false, /*nested=*/false);
return label;
}
tree
define_label (location_t location, tree name)
{
- tree label;
-
/* Find any preexisting label with this name. It is an error
if that label has already been defined in this function, or
if there is a containing function with a declared label with
the same name. */
- label = IDENTIFIER_LABEL_VALUE (name);
+ tree label = I_LABEL_DECL (name);
if (label
&& ((DECL_CONTEXT (label) == current_function_decl
&& C_DECLARED_LABEL_FLAG (label))))
{
error ("%Hduplicate label `%D'", &location, label);
- if (DECL_INITIAL (label))
- error ("%J`%D' previously defined here", label, label);
- else
- error ("%J`%D' previously declared here", label, label);
+ locate_old_decl (label, error);
return 0;
}
else if (label && DECL_CONTEXT (label) == current_function_decl)
label = make_label (name, location);
/* Ordinary labels go in the current function scope. */
- bind_label (name, label, current_function_scope);
+ bind (name, label, current_function_scope,
+ /*invisible=*/false, /*nested=*/false);
}
if (warn_traditional && !in_system_header && lookup_name (name))
return label;
}
\f
-/* Return the list of declarations of the current scope. */
-
-tree
-getdecls (void)
-{
- return current_scope->names;
-}
-
-\f
/* Given NAME, an IDENTIFIER_NODE,
return the structure (or union or enum) definition for that name.
If THISLEVEL_ONLY is nonzero, searches only the current_scope.
static tree
lookup_tag (enum tree_code code, tree name, int thislevel_only)
{
- tree tag = IDENTIFIER_TAG_VALUE (name);
+ struct c_binding *b = I_TAG_BINDING (name);
int thislevel = 0;
- if (!tag)
+ if (!b || !b->decl)
return 0;
/* 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)
- {
- if (current_scope == global_scope
- || purpose_member (name, current_scope->tags))
+ if (thislevel_only || TREE_CODE (b->decl) != code)
+ {
+ /* For our purposes, a tag in the external scope is the same as
+ a tag in the file scope. (Primarily relevant to Objective-C
+ and its builtin structure tags, which get pushed before the
+ file scope is created.) */
+ if (B_IN_CURRENT_SCOPE (b)
+ || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b)))
thislevel = 1;
}
if (thislevel_only && !thislevel)
return 0;
- if (TREE_CODE (tag) != code)
+ if (TREE_CODE (b->decl) != code)
{
/* Definition isn't the kind we were looking for. */
pending_invalid_xref = name;
if (thislevel)
pending_xref_error ();
}
- return tag;
+ return b->decl;
}
/* Print an error message now
tree
lookup_name (tree name)
{
- tree decl = IDENTIFIER_SYMBOL_VALUE (name);
- if (decl == 0 || decl == error_mark_node)
- return decl;
- if (C_DECL_INVISIBLE (decl))
- return 0;
- return decl;
+ struct c_binding *b = I_SYMBOL_BINDING (name);
+ if (b && !b->invisible)
+ return b->decl;
+ return 0;
}
-/* Similar to `lookup_name' but look only at the current scope. */
+/* Similar to `lookup_name' but look only at the indicated scope. */
static tree
-lookup_name_current_level (tree name)
+lookup_name_in_scope (tree name, struct c_scope *scope)
{
- tree decl = IDENTIFIER_SYMBOL_VALUE (name);
-
- if (decl == 0 || decl == error_mark_node || C_DECL_INVISIBLE (decl))
- return 0;
-
- if (current_scope == global_scope)
- return decl;
-
- /* Scan the current scope for a decl with name NAME.
- For PARM_DECLs, we have to look at both ->parms and ->names, since
- forward parameter declarations wind up on the ->names list. */
- if (TREE_CODE (decl) == PARM_DECL
- && chain_member (decl, current_scope->parms))
- return decl;
- if (chain_member (decl, current_scope->names))
- return decl;
+ struct c_binding *b;
+ for (b = I_SYMBOL_BINDING (name); b; b = b->shadowed)
+ if (B_IN_SCOPE (b, scope))
+ return b->decl;
return 0;
}
\f
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 ();
current_function_decl = 0;
- /* Make the c_scope structure for global names. */
- pushlevel (0);
- global_scope = current_scope;
+ /* Make the externals scope. */
+ push_scope ();
+ external_scope = current_scope;
/* 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>";
+#ifdef USE_MAPPED_LOCATION
+ input_location = BUILTINS_LOCATION;
+#else
+ input_location.file = "<built-in>";
input_location.line = 0;
-
- /* Make the DECL for the toplevel file scope. */
- current_file_decl = build_decl (TRANSLATION_UNIT_DECL, NULL, NULL);
+#endif
build_common_tree_nodes (flag_signed_char);
input_location = save_loc;
- pedantic_lvalues = pedantic;
+ pedantic_lvalues = true;
make_fname_decl = c_make_fname_decl;
start_fname_decls ();
-
- first_builtin_decl = global_scope->names;
- last_builtin_decl = global_scope->names_last;
}
/* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
DECL_ARTIFICIAL (decl) = 1;
init = build_string (length + 1, name);
+ free ((char *) name);
TREE_TYPE (init) = type;
DECL_INITIAL (decl) = init;
if (current_function_decl)
{
DECL_CONTEXT (decl) = current_function_decl;
- IDENTIFIER_SYMBOL_VALUE (id) = decl;
- SCOPE_LIST_APPEND (current_function_scope, names, decl);
+ bind (id, decl, current_function_scope,
+ /*invisible=*/false, /*nested=*/false);
}
finish_decl (decl, init, NULL_TREE);
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;
+ tree id = get_identifier (name);
+ tree decl = build_decl (FUNCTION_DECL, id, type);
TREE_PUBLIC (decl) = 1;
- if (library_name)
- SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name));
- make_decl_rtl (decl, NULL);
- pushdecl (decl);
+ DECL_EXTERNAL (decl) = 1;
+ DECL_LANG_SPECIFIC (decl) = ggc_alloc_cleared (sizeof (struct lang_decl));
DECL_BUILT_IN_CLASS (decl) = class;
DECL_FUNCTION_CODE (decl) = function_code;
+ if (library_name)
+ SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name));
- /* 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_INVISIBLE (decl) = 1;
+ /* Should never be called on a symbol with a preexisting meaning. */
+ if (I_SYMBOL_BINDING (id))
+ abort ();
+
+ bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false);
+
+ /* Builtins in the implementation namespace are made visible without
+ needing to be explicitly declared. See push_file_scope. */
+ if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1])))
+ {
+ TREE_CHAIN (decl) = visible_builtins;
+ visible_builtins = decl;
+ }
/* Possibly apply some default attributes to this built-in function. */
if (attrs)
build_array_declarator (tree expr, tree quals, int static_p, int vla_unspec_p)
{
tree decl;
- decl = build_nt (ARRAY_REF, NULL_TREE, expr);
+ decl = build_nt (ARRAY_REF, NULL_TREE, expr, NULL_TREE, NULL_TREE);
TREE_TYPE (decl) = quals;
TREE_STATIC (decl) = (static_p ? 1 : 0);
if (pedantic && !flag_isoc99)
split_specs_attrs (TREE_PURPOSE (typename), &specs, &attrs);
- typename = grokdeclarator (TREE_VALUE (typename), specs, TYPENAME, 0);
+ typename = grokdeclarator (TREE_VALUE (typename), specs, TYPENAME, 0,
+ NULL);
/* Apply attributes. */
decl_attributes (&typename, attrs, 0);
return typename;
return grokdeclarator (TREE_VALUE (typename),
TREE_PURPOSE (typename),
- PARM, 0);
+ PARM, 0, NULL);
}
/* Decode a declarator in an ordinary declaration or data definition.
deprecated_state = DEPRECATED_SUPPRESS;
decl = grokdeclarator (declarator, declspecs,
- NORMAL, initialized);
+ NORMAL, initialized, NULL);
deprecated_state = DEPRECATED_NORMAL;
if (initialized)
/* Is it valid for this decl to have an initializer at all?
If not, set INITIALIZED to zero, which will indirectly
- tell `finish_decl' to ignore the initializer once it is parsed. */
+ tell 'finish_decl' to ignore the initializer once it is parsed. */
switch (TREE_CODE (decl))
{
case TYPE_DECL:
- error ("typedef `%s' is initialized (use __typeof__ instead)",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("typedef '%D' is initialized (use __typeof__ instead)", decl);
initialized = 0;
break;
case FUNCTION_DECL:
- error ("function `%s' is initialized like a variable",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("function '%D' is initialized like a variable", decl);
initialized = 0;
break;
case PARM_DECL:
/* DECL_INITIAL in a PARM_DECL is really DECL_ARG_TYPE. */
- error ("parameter `%s' is initialized",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("parameter '%D' is initialized", decl);
initialized = 0;
break;
default:
- /* Don't allow initializations for incomplete types
- except for arrays which might be completed by the initialization. */
+ /* Don't allow initializations for incomplete types except for
+ arrays which might be completed by the initialization. */
- /* This can happen if the array size is an undefined macro. We already
- gave a warning, so we don't need another one. */
+ /* This can happen if the array size is an undefined macro.
+ We already gave a warning, so we don't need another one. */
if (TREE_TYPE (decl) == error_mark_node)
initialized = 0;
else if (COMPLETE_TYPE_P (TREE_TYPE (decl)))
}
else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
{
- error ("variable `%s' has initializer but incomplete type",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("variable '%D' has initializer but incomplete type", decl);
initialized = 0;
}
else if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
{
- error ("elements of array `%s' have incomplete type",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("elements of array '%D' have incomplete type", decl);
initialized = 0;
}
}
if (initialized)
{
DECL_EXTERNAL (decl) = 0;
- if (current_scope == global_scope)
+ if (current_scope == file_scope)
TREE_STATIC (decl) = 1;
- /* Tell `pushdecl' this is an initialized decl
+ /* Tell 'pushdecl' this is an initialized decl
even though we don't yet have the initializer expression.
- Also tell `finish_decl' it may store the real initializer. */
+ Also tell 'finish_decl' it may store the real initializer. */
DECL_INITIAL (decl) = error_mark_node;
}
for (; args; args = TREE_CHAIN (args))
{
tree type = TREE_TYPE (args);
- if (INTEGRAL_TYPE_P (type)
+ if (type && INTEGRAL_TYPE_P (type)
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
DECL_ARG_TYPE (args) = integer_type_node;
}
TEM may equal DECL or it may be a previous decl of the same name. */
tem = pushdecl (decl);
- /* For a local variable, define the RTL now. */
- if (current_scope != global_scope
- /* But not if this is a duplicate decl
- and we preserved the rtl from the previous one
- (which may or may not happen). */
- && !DECL_RTL_SET_P (tem)
- && DECL_FILE_SCOPE_P (tem))
- {
- if (TREE_TYPE (tem) != error_mark_node
- && (COMPLETE_TYPE_P (TREE_TYPE (tem))
- || (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
- && DECL_INITIAL (tem) != 0)))
- expand_decl (tem);
- }
-
return tem;
}
const char *asmspec = 0;
/* If a name was specified, get the string. */
- if (current_scope == global_scope)
+ if (current_scope == file_scope)
asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
if (asmspec_tree)
asmspec = TREE_STRING_POINTER (asmspec_tree);
|| TREE_CODE (decl) == FIELD_DECL))
objc_check_decl (decl);
- /* Deduce size of array from initialization, if not already known */
+ /* Deduce size of array from initialization, if not already known. */
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type) == 0
&& TREE_CODE (decl) != TYPE_DECL)
{
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
+ change_decl_assembler_name (builtin, get_identifier (starred));
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 (starred));
+ change_decl_assembler_name (decl, get_identifier (starred));
}
/* If #pragma weak was used, mark the decl weak now. */
- if (current_scope == global_scope)
+ if (current_scope == file_scope)
maybe_apply_pragma_weak (decl);
/* Output the assembler code and/or RTL code for variables and functions,
/* In conjunction with an ASMSPEC, the `register'
keyword indicates that we should place the variable
in a particular register. */
- if (DECL_REGISTER (decl))
- DECL_C_HARD_REGISTER (decl) = 1;
+ if (C_DECL_REGISTER (decl))
+ {
+ DECL_HARD_REGISTER (decl) = 1;
+ /* This cannot be done for a structure with volatile
+ fields, on which DECL_REGISTER will have been
+ reset. */
+ if (!DECL_REGISTER (decl))
+ error ("cannot put object with volatile field into register");
+ }
/* If this is not a static variable, issue a warning.
It doesn't make any sense to give an ASMSPEC for an
GCC has accepted -- but ignored -- the ASMSPEC in
this case. */
if (TREE_CODE (decl) == VAR_DECL
- && !DECL_REGISTER (decl)
+ && !C_DECL_REGISTER (decl)
&& !TREE_STATIC (decl))
warning ("%Jignoring asm-specifier for non-static local "
"variable '%D'", decl, decl);
else
- SET_DECL_ASSEMBLER_NAME (decl, get_identifier (asmspec));
+ change_decl_assembler_name (decl, get_identifier (asmspec));
}
if (TREE_CODE (decl) != FUNCTION_DECL)
- add_decl_stmt (decl);
+ add_stmt (build_stmt (DECL_EXPR, decl));
}
if (!DECL_FILE_SCOPE_P (decl))
/* If this was marked 'used', be sure it will be output. */
if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
- mark_referenced (DECL_ASSEMBLER_NAME (decl));
+ mark_decl_referenced (decl);
if (TREE_CODE (decl) == TYPE_DECL)
- rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0);
+ {
+ if (!DECL_FILE_SCOPE_P (decl)
+ && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+ add_stmt (build_stmt (DECL_EXPR, decl));
+
+ rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0);
+ }
/* At the end of a declaration, throw away any variable type sizes
of types defined inside that declaration. There is no use
computing them in the following function definition. */
- if (current_scope == global_scope)
+ if (current_scope == file_scope)
get_pending_sizes ();
/* Install a cleanup (aka destructor) if one was given. */
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;
/* Don't warn about decl unused; the cleanup uses it. */
TREE_USED (decl) = 1;
+ TREE_USED (cleanup_decl) = 1;
/* Initialize EH, if we've been told to do so. */
- if (flag_exceptions && !eh_initialized_p)
+ if (flag_exceptions && !c_eh_initialized_p)
{
- eh_initialized_p = true;
+ c_eh_initialized_p = true;
eh_personality_libfunc
= init_one_libfunc (USING_SJLJ_EXCEPTIONS
? "__gcc_personality_sj0"
using_eh_for_cleanups ();
}
- add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
+ push_cleanup (decl, cleanup, false);
}
}
}
{
tree decl;
- /* Don't attempt to expand sizes while parsing this decl.
- (We can get here with i_s_e 1 somehow from Objective-C.) */
- int save_immediate_size_expand = immediate_size_expand;
- immediate_size_expand = 0;
-
decl = grokdeclarator (TREE_VALUE (TREE_PURPOSE (parm)),
- TREE_PURPOSE (TREE_PURPOSE (parm)), PARM, 0);
+ TREE_PURPOSE (TREE_PURPOSE (parm)),
+ PARM, 0, NULL);
decl_attributes (&decl, TREE_VALUE (parm), 0);
decl = pushdecl (decl);
finish_decl (decl, NULL_TREE, NULL_TREE);
-
- immediate_size_expand = save_immediate_size_expand;
}
-/* Mark all the parameter declarations to date as forward decls,
- shift them to the variables list, and reset the parameters list.
+/* Mark all the parameter declarations to date as forward decls.
Also diagnose use of this extension. */
void
mark_forward_parm_decls (void)
{
- tree parm;
+ struct c_binding *b;
if (pedantic && !current_scope->warned_forward_parm_decls)
{
current_scope->warned_forward_parm_decls = true;
}
- for (parm = current_scope->parms; parm; parm = TREE_CHAIN (parm))
- TREE_ASM_WRITTEN (parm) = 1;
-
- SCOPE_LIST_CONCAT (current_scope, names, current_scope, parms);
- current_scope->parms = 0;
- current_scope->parms_last = 0;
+ for (b = current_scope->bindings; b; b = b->prev)
+ if (TREE_CODE (b->decl) == PARM_DECL)
+ TREE_ASM_WRITTEN (b->decl) = 1;
}
\f
static GTY(()) int compound_literal_number;
{
/* 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
- the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_STMT. */
+ the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_EXPR. */
tree decl = build_decl (VAR_DECL, NULL_TREE, type);
tree complit;
tree stmt;
DECL_EXTERNAL (decl) = 0;
TREE_PUBLIC (decl) = 0;
- TREE_STATIC (decl) = (current_scope == global_scope);
+ TREE_STATIC (decl) = (current_scope == file_scope);
DECL_CONTEXT (decl) = current_function_decl;
TREE_USED (decl) = 1;
TREE_TYPE (decl) = type;
- TREE_READONLY (decl) = TREE_READONLY (type);
+ TREE_READONLY (decl) = TYPE_READONLY (type);
store_init_value (decl, init);
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
if (type == error_mark_node || !COMPLETE_TYPE_P (type))
return error_mark_node;
- stmt = build_stmt (DECL_STMT, decl);
+ stmt = build_stmt (DECL_EXPR, decl);
complit = build1 (COMPOUND_LITERAL_EXPR, TREE_TYPE (decl), stmt);
TREE_SIDE_EFFECTS (complit) = 1;
}
}
\f
+/* Performs sanity checks on the TYPE and WIDTH of the bit-field NAME,
+ replacing with appropriate values if they are invalid. */
+static void
+check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
+{
+ tree type_mv;
+ unsigned int max_width;
+ unsigned HOST_WIDE_INT w;
+ const char *name = orig_name ? orig_name: _("<anonymous>");
+
+ /* Necessary? */
+ STRIP_NOPS (*width);
+
+ /* Detect and ignore out of range field width and process valid
+ field widths. */
+ if (TREE_CODE (*width) != INTEGER_CST)
+ {
+ error ("bit-field `%s' width not an integer constant", name);
+ *width = integer_one_node;
+ }
+ else
+ {
+ constant_expression_warning (*width);
+ if (tree_int_cst_sgn (*width) < 0)
+ {
+ error ("negative width in bit-field `%s'", name);
+ *width = integer_one_node;
+ }
+ else if (integer_zerop (*width) && orig_name)
+ {
+ error ("zero width for bit-field `%s'", name);
+ *width = integer_one_node;
+ }
+ }
+
+ /* Detect invalid bit-field type. */
+ if (TREE_CODE (*type) != INTEGER_TYPE
+ && TREE_CODE (*type) != BOOLEAN_TYPE
+ && TREE_CODE (*type) != ENUMERAL_TYPE)
+ {
+ error ("bit-field `%s' has invalid type", name);
+ *type = unsigned_type_node;
+ }
+
+ type_mv = TYPE_MAIN_VARIANT (*type);
+ if (pedantic
+ && type_mv != integer_type_node
+ && type_mv != unsigned_type_node
+ && type_mv != boolean_type_node)
+ pedwarn ("type of bit-field `%s' is a GCC extension", name);
+
+ if (type_mv == boolean_type_node)
+ max_width = CHAR_TYPE_SIZE;
+ else
+ max_width = TYPE_PRECISION (*type);
+
+ if (0 < compare_tree_int (*width, max_width))
+ {
+ error ("width of `%s' exceeds its type", name);
+ w = max_width;
+ *width = build_int_2 (w, 0);
+ }
+ else
+ w = tree_low_cst (*width, 1);
+
+ if (TREE_CODE (*type) == ENUMERAL_TYPE)
+ {
+ struct lang_type *lt = TYPE_LANG_SPECIFIC (*type);
+ if (!lt
+ || w < min_precision (lt->enum_min, TYPE_UNSIGNED (*type))
+ || w < min_precision (lt->enum_max, TYPE_UNSIGNED (*type)))
+ warning ("`%s' is narrower than values of its type", name);
+ }
+}
+\f
/* Given declspecs and a declarator,
determine the name and type of the object declared
and construct a ..._DECL node for it.
TYPENAME if for a typename (in a cast or sizeof).
Don't make a DECL node; just return the ..._TYPE node.
FIELD for a struct or union field; make a FIELD_DECL.
- BITFIELD for a field with specified width.
INITIALIZED is 1 if the decl has an initializer.
+ WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node
+ representing the width of the bit-field.
In the TYPENAME case, DECLARATOR is really an absolute declarator.
It may also be so in the PARM case, for a prototype where the
static tree
grokdeclarator (tree declarator, tree declspecs,
- enum decl_context decl_context, int initialized)
+ enum decl_context decl_context, int initialized, tree *width)
{
int specbits = 0;
tree spec;
int explicit_char = 0;
int defaulted_int = 0;
tree typedef_decl = 0;
- const char *name;
+ const char *name, *orig_name;
tree typedef_type = 0;
int funcdef_flag = 0;
enum tree_code innermost_code = ERROR_MARK;
- int bitfield = 0;
int size_varies = 0;
tree decl_attr = NULL_TREE;
tree array_ptr_quals = NULL_TREE;
int array_parm_static = 0;
tree returned_attrs = NULL_TREE;
-
- if (decl_context == BITFIELD)
- bitfield = 1, decl_context = FIELD;
+ bool bitfield = width != NULL;
+ tree element_type;
+ tree arg_info = NULL_TREE;
if (decl_context == FUNCDEF)
funcdef_flag = 1, decl_context = NORMAL;
default:
abort ();
}
+ orig_name = name;
if (name == 0)
name = "type name";
}
/* If this looks like a function definition, make it one,
even if it occurs where parms are expected.
Then store_parm_decls will reject it and not use it as a parm. */
- if (decl_context == NORMAL && !funcdef_flag
- && current_scope->parm_flag)
+ if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag)
decl_context = PARM;
/* Look through the decl specs and record which ones appear.
{
if (i == RID_CONST || i == RID_VOLATILE || i == RID_RESTRICT)
{
- if (!flag_isoc99)
+ if (pedantic && !flag_isoc99)
pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
}
else
else if (TREE_CODE (id) == IDENTIFIER_NODE)
{
tree t = lookup_name (id);
- if (TREE_TYPE (t) == error_mark_node)
- ;
- else if (!t || TREE_CODE (t) != TYPE_DECL)
+ if (!t || TREE_CODE (t) != TYPE_DECL)
error ("`%s' fails to be a typedef or built in type",
IDENTIFIER_POINTER (id));
+ else if (TREE_TYPE (t) == error_mark_node)
+ ;
else
{
type = TREE_TYPE (t);
}
/* Decide whether an integer type is signed or not.
- Optionally treat bitfields as signed by default. */
+ Optionally treat bit-fields as signed by default. */
if (specbits & 1 << (int) RID_UNSIGNED
|| (bitfield && ! flag_signed_bitfields
&& (explicit_int || defaulted_int || explicit_char
}
}
+ /* Check the type and width of a bit-field. */
+ if (bitfield)
+ check_bitfield_type_and_width (&type, width, orig_name);
+
/* Figure out the type qualifiers for the declaration. There are
two ways a declaration can become qualified. One is something
like `const int i' where the `const' is explicit. Another is
something like `typedef const int CI; CI i' where the type of the
- declaration contains the `const'. */
- constp = !! (specbits & 1 << (int) RID_CONST) + TYPE_READONLY (type);
- restrictp = !! (specbits & 1 << (int) RID_RESTRICT) + TYPE_RESTRICT (type);
- volatilep = !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (type);
+ declaration contains the `const'. A third possibility is that
+ there is a type qualifier on the element type of a typedefed
+ array type, in which case we should extract that qualifier so
+ that c_apply_type_quals_to_decls receives the full list of
+ qualifiers to work with (C90 is not entirely clear about whether
+ duplicate qualifiers should be diagnosed in this case, but it
+ seems most appropriate to do so). */
+ element_type = strip_array_types (type);
+ constp = !! (specbits & 1 << (int) RID_CONST) + TYPE_READONLY (element_type);
+ restrictp
+ = !! (specbits & 1 << (int) RID_RESTRICT) + TYPE_RESTRICT (element_type);
+ volatilep
+ = !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (element_type);
inlinep = !! (specbits & (1 << (int) RID_INLINE));
- if (constp > 1 && ! flag_isoc99)
- pedwarn ("duplicate `const'");
- if (restrictp > 1 && ! flag_isoc99)
- pedwarn ("duplicate `restrict'");
- if (volatilep > 1 && ! flag_isoc99)
- pedwarn ("duplicate `volatile'");
+ if (pedantic && !flag_isoc99)
+ {
+ if (constp > 1)
+ pedwarn ("duplicate `const'");
+ if (restrictp > 1)
+ pedwarn ("duplicate `restrict'");
+ if (volatilep > 1)
+ pedwarn ("duplicate `volatile'");
+ }
if (! flag_gen_aux_info && (TYPE_QUALS (type)))
type = TYPE_MAIN_VARIANT (type);
type_quals = ((constp ? TYPE_QUAL_CONST : 0)
| (1 << (int) RID_THREAD))))
{
if (specbits & 1 << (int) RID_AUTO
- && (pedantic || current_scope == global_scope))
+ && (pedantic || current_scope == file_scope))
pedwarn ("function definition declared `auto'");
if (specbits & 1 << (int) RID_REGISTER)
error ("function definition declared `register'");
else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
{
/* `extern' with initialization is invalid if not at file scope. */
- if (current_scope == global_scope)
+ if (current_scope == file_scope)
warning ("`%s' initialized and declared `extern'", name);
else
error ("`%s' has both `extern' and initializer", name);
}
- else if (current_scope == global_scope)
+ else if (current_scope == file_scope)
{
if (specbits & 1 << (int) RID_AUTO)
error ("file-scope declaration of `%s' specifies `auto'", name);
type = error_mark_node;
}
- if (pedantic && flexible_array_type_p (type))
+ if (pedantic && !in_system_header && flexible_array_type_p (type))
pedwarn ("invalid use of structure with flexible array member");
if (size == error_mark_node)
}
if (size_varies)
- {
- /* 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 = variable_size (itype);
itype = build_index_type (itype);
}
}
TYPE_SIZE (type) = bitsize_zero_node;
TYPE_SIZE_UNIT (type) = size_zero_node;
}
+ else if (declarator && TREE_CODE (declarator) == INDIRECT_REF)
+ /* We can never complete an array type which is the target of a
+ pointer, so go ahead and lay it out. */
+ layout_type (type);
+
if (decl_context != PARM
&& (array_ptr_quals != NULL_TREE || array_parm_static))
{
}
else if (TREE_CODE (declarator) == CALL_EXPR)
{
+ /* Say it's a definition only for the CALL_EXPR closest to
+ the identifier. */
+ bool really_funcdef = (funcdef_flag
+ && (TREE_CODE (TREE_OPERAND (declarator, 0))
+ == IDENTIFIER_NODE));
tree arg_types;
/* Declaring a function type.
/* Construct the function type and go to the next
inner layer of declarator. */
+ arg_info = TREE_OPERAND (declarator, 1);
+ arg_types = grokparms (arg_info, really_funcdef);
- arg_types = grokparms (TREE_OPERAND (declarator, 1),
- funcdef_flag
- /* Say it's a definition
- only for the CALL_EXPR
- closest to the identifier. */
- && TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE);
/* Type qualifiers before the return type of the function
qualify the return type, not the function type. */
if (type_quals)
{
tree link;
- for (link = last_function_parm_tags;
+ for (link = ARG_INFO_TAGS (arg_info);
link;
link = TREE_CHAIN (link))
TYPE_CONTEXT (TREE_VALUE (link)) = type;
if (erred)
error ("invalid type modifier within pointer declarator");
- if (constp > 1 && ! flag_isoc99)
- pedwarn ("duplicate `const'");
- if (volatilep > 1 && ! flag_isoc99)
- pedwarn ("duplicate `volatile'");
- if (restrictp > 1 && ! flag_isoc99)
- pedwarn ("duplicate `restrict'");
+ if (pedantic && !flag_isoc99)
+ {
+ if (constp > 1)
+ pedwarn ("duplicate `const'");
+ if (volatilep > 1)
+ pedwarn ("duplicate `volatile'");
+ if (restrictp > 1)
+ pedwarn ("duplicate `restrict'");
+ }
type_quals = ((constp ? TYPE_QUAL_CONST : 0)
| (restrictp ? TYPE_QUAL_RESTRICT : 0)
if (VOID_TYPE_P (type) && decl_context != PARM
&& ! ((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE)
&& ((specbits & (1 << (int) RID_EXTERN))
- || (current_scope == global_scope
+ || (current_scope == file_scope
&& !(specbits
& ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER)))))))
{
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
- /* Every function declaration is "external"
- except for those which are inside a function body
- in which `auto' is used.
- That is a case not specified by ANSI C,
- and we use it for forward declarations for nested functions. */
- int extern_ref = (!(specbits & (1 << (int) RID_AUTO))
- || current_scope == global_scope);
-
if (specbits & (1 << (int) RID_AUTO)
- && (pedantic || current_scope == global_scope))
+ && (pedantic || current_scope == file_scope))
pedwarn ("invalid storage class for function `%s'", name);
if (specbits & (1 << (int) RID_REGISTER))
error ("invalid storage class for function `%s'", name);
/* Function declaration not at file scope.
Storage classes other than `extern' are not allowed
and `extern' makes no difference. */
- if (current_scope != global_scope
+ if (current_scope != file_scope
&& (specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE)))
&& pedantic)
pedwarn ("invalid storage class for function `%s'", name);
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
warning ("`noreturn' function returns non-void value");
- if (extern_ref)
+ /* Every function declaration is an external reference
+ (DECL_EXTERNAL) except for those which are not at file
+ scope and are explicitly declared "auto". This is
+ forbidden by standard C (C99 6.7.1p5) and is interpreted by
+ GCC to signify a forward declaration of a nested function. */
+ if ((specbits & (1 << RID_AUTO)) && current_scope != file_scope)
+ DECL_EXTERNAL (decl) = 0;
+ else
DECL_EXTERNAL (decl) = 1;
+
/* Record absence of global scope for `static' or `auto'. */
TREE_PUBLIC (decl)
= !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO)));
+ /* For a function definition, record the argument information
+ block in DECL_ARGUMENTS where store_parm_decls will look
+ for it. */
+ if (funcdef_flag)
+ DECL_ARGUMENTS (decl) = arg_info;
+
if (defaulted_int)
C_FUNCTION_IMPLICIT_INT (decl) = 1;
else if (type_quals)
type = c_build_qualified_type (type, type_quals);
- /* It is invalid to create an `extern' declaration for a
+ /* C99 6.2.2p7: It is invalid (compile-time undefined
+ behavior) to create an 'extern' declaration for a
variable if there is a global declaration that is
- `static'. */
- if (extern_ref && current_scope != global_scope)
+ 'static' and the global declaration is not visible.
+ (If the static declaration _is_ currently visible,
+ the 'extern' declaration is taken to refer to that decl.) */
+ if (extern_ref && current_scope != file_scope)
{
- tree global_decl;
+ tree global_decl = identifier_global_value (declarator);
+ tree visible_decl = lookup_name (declarator);
- global_decl = identifier_global_value (declarator);
if (global_decl
+ && global_decl != visible_decl
&& TREE_CODE (global_decl) == VAR_DECL
&& !TREE_PUBLIC (global_decl))
- error ("variable previously declared `static' redeclared "
- "`extern'");
+ error ("variable previously declared 'static' redeclared "
+ "'extern'");
}
decl = build_decl (VAR_DECL, declarator, type);
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_scope == global_scope)
+ if (current_scope == file_scope)
{
TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC)
| (1 << (int) RID_REGISTER)));
and in case doing stupid register allocation. */
if (specbits & (1 << (int) RID_REGISTER))
- DECL_REGISTER (decl) = 1;
+ {
+ C_DECL_REGISTER (decl) = 1;
+ DECL_REGISTER (decl) = 1;
+ }
/* Record constancy and volatility. */
c_apply_type_quals_to_decl (type_quals, decl);
Otherwise, the fact that those components are volatile
will be ignored, and would even crash the compiler. */
if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)))
- c_mark_addressable (decl);
+ {
+ /* It is not an error for a structure with volatile fields to
+ be declared register, but reset DECL_REGISTER since it
+ cannot actually go in a register. */
+ int was_reg = C_DECL_REGISTER (decl);
+ C_DECL_REGISTER (decl) = 0;
+ DECL_REGISTER (decl) = 0;
+ c_mark_addressable (decl);
+ C_DECL_REGISTER (decl) = was_reg;
+ }
#ifdef ENABLE_CHECKING
/* This is the earliest point at which we might know the assembler
of calls is different. The last call to `grokparms' is always the one
that contains the formal parameter names of a function definition.
- Store in `last_function_parms' a chain of the decls of parms.
- Also store in `last_function_parm_tags' a chain of the struct, union,
- and enum tags declared among the parms.
-
Return a list of arg types to use in the FUNCTION_TYPE for this function.
FUNCDEF_FLAG is nonzero for a function definition, 0 for
when FUNCDEF_FLAG is zero. */
static tree
-grokparms (tree parms_info, int funcdef_flag)
+grokparms (tree arg_info, int funcdef_flag)
{
- tree first_parm = TREE_CHAIN (parms_info);
-
- last_function_parms = TREE_PURPOSE (parms_info);
- last_function_parm_tags = TREE_VALUE (parms_info);
- last_function_parm_others = TREE_TYPE (parms_info);
+ tree arg_types = ARG_INFO_TYPES (arg_info);
- if (warn_strict_prototypes && first_parm == 0 && !funcdef_flag
+ if (warn_strict_prototypes && arg_types == 0 && !funcdef_flag
&& !in_system_header)
warning ("function declaration isn't a prototype");
- if (first_parm != 0
- && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE)
+ if (arg_types == error_mark_node)
+ return 0; /* don't set TYPE_ARG_TYPES in this case */
+
+ else if (arg_types && TREE_CODE (TREE_VALUE (arg_types)) == IDENTIFIER_NODE)
{
if (! funcdef_flag)
pedwarn ("parameter names (without types) in function declaration");
- last_function_parms = first_parm;
+ ARG_INFO_PARMS (arg_info) = ARG_INFO_TYPES (arg_info);
+ ARG_INFO_TYPES (arg_info) = 0;
return 0;
}
else
{
- tree parm;
- tree typelt;
- /* If the arg types are incomplete in a declaration,
- they must include undefined tags.
- These tags can never be defined in the scope of the declaration,
- so the types can never be completed,
- and no call can be compiled successfully. */
+ tree parm, type, typelt;
+ unsigned int parmno;
+
+ /* If the arg types are incomplete in a declaration, they must
+ include undefined tags. These tags can never be defined in
+ the scope of the declaration, so the types can never be
+ completed, and no call can be compiled successfully. */
- for (parm = last_function_parms, typelt = first_parm;
+ for (parm = ARG_INFO_PARMS (arg_info), typelt = arg_types, parmno = 1;
parm;
- parm = TREE_CHAIN (parm))
- /* Skip over any enumeration constants declared here. */
- if (TREE_CODE (parm) == PARM_DECL)
- {
- /* Barf if the parameter itself has an incomplete type. */
- tree type = TREE_VALUE (typelt);
- if (type == error_mark_node)
- continue;
- if (!COMPLETE_TYPE_P (type))
- {
- if (funcdef_flag && DECL_NAME (parm) != 0)
- error ("parameter `%s' has incomplete type",
- IDENTIFIER_POINTER (DECL_NAME (parm)));
- else
- warning ("parameter has incomplete type");
- if (funcdef_flag)
- {
- TREE_VALUE (typelt) = error_mark_node;
- TREE_TYPE (parm) = error_mark_node;
- }
- }
- typelt = TREE_CHAIN (typelt);
- }
+ parm = TREE_CHAIN (parm), typelt = TREE_CHAIN (typelt), parmno++)
+ {
+ type = TREE_VALUE (typelt);
+ if (type == error_mark_node)
+ continue;
+
+ if (!COMPLETE_TYPE_P (type))
+ {
+ if (funcdef_flag)
+ {
+ if (DECL_NAME (parm))
+ error ("%Jparameter %u ('%D') has incomplete type",
+ parm, parmno, parm);
+ else
+ error ("%Jparameter %u has incomplete type",
+ parm, parmno);
- return first_parm;
+ TREE_VALUE (typelt) = error_mark_node;
+ TREE_TYPE (parm) = error_mark_node;
+ }
+ else
+ {
+ if (DECL_NAME (parm))
+ warning ("%Jparameter %u ('%D') has incomplete type",
+ parm, parmno, parm);
+ else
+ warning ("%Jparameter %u has incomplete type",
+ parm, parmno);
+ }
+ }
+ }
+ return arg_types;
}
}
-/* Return a tree_list node with info on a parameter list just parsed.
- The TREE_PURPOSE is a list of decls of those parms.
- The TREE_VALUE is a list of structure, union and enum tags defined.
- The TREE_CHAIN is a list of argument types to go in the FUNCTION_TYPE.
- The TREE_TYPE is a list of non-parameter decls which appeared with the
- parameters.
- This tree_list node is later fed to `grokparms'.
+/* Take apart the current scope and return a tree_list node with info
+ on a parameter list just parsed. This tree_list node should be
+ examined using the ARG_INFO_* macros, defined above:
+
+ ARG_INFO_PARMS: a list of parameter decls.
+ ARG_INFO_TAGS: a list of structure, union and enum tags defined.
+ ARG_INFO_TYPES: a list of argument types to go in the FUNCTION_TYPE.
+ ARG_INFO_OTHERS: a list of non-parameter decls (notably enumeration
+ constants) defined with the parameters.
- VOID_AT_END nonzero means append `void' to the end of the type-list.
- Zero means the parmlist ended with an ellipsis so don't append `void'. */
+ This tree_list node is later fed to 'grokparms' and 'store_parm_decls'.
+
+ ELLIPSIS being true means the argument list ended in '...' so don't
+ append a sentinel (void_list_node) to the end of the type-list. */
tree
-get_parm_info (int void_at_end)
+get_parm_info (bool ellipsis)
{
- tree decl, type, list;
- tree types = 0;
- tree *last_type = &types;
- tree tags = current_scope->tags;
- tree parms = current_scope->parms;
- tree others = current_scope->names;
+ struct c_binding *b = current_scope->bindings;
+ tree arg_info = make_node (TREE_LIST);
+ tree parms = 0;
+ tree tags = 0;
+ tree types = 0;
+ tree others = 0;
+
static bool explained_incomplete_types = false;
bool gave_void_only_once_err = false;
- /* Just "void" (and no ellipsis) is special. There are really no parms.
- But if the "void" is qualified (by "const" or "volatile"), or has a
- storage class specifier ("register"), then the behavior is undefined;
- issue an error. Typedefs for "void" are OK (see DR#157). */
- if (void_at_end && parms != 0
- && TREE_CHAIN (parms) == 0
- && VOID_TYPE_P (TREE_TYPE (parms))
- && !DECL_NAME (parms))
+ /* The bindings in this scope must not get put into a block.
+ We will take care of deleting the binding nodes. */
+ current_scope->bindings = 0;
+
+ /* This function is only called if there was *something* on the
+ parameter list. */
+#ifdef ENABLE_CHECKING
+ if (b == 0)
+ abort ();
+#endif
+
+ /* A parameter list consisting solely of 'void' indicates that the
+ function takes no arguments. But if the 'void' is qualified
+ (by 'const' or 'volatile'), or has a storage class specifier
+ ('register'), then the behavior is undefined; issue an error.
+ Typedefs for 'void' are OK (see DR#157). */
+ if (b->prev == 0 /* one binding */
+ && TREE_CODE (b->decl) == PARM_DECL /* which is a parameter */
+ && !DECL_NAME (b->decl) /* anonymous */
+ && VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */
{
- if (TREE_THIS_VOLATILE (parms)
- || TREE_READONLY (parms)
- || DECL_REGISTER (parms))
- error ("\"void\" as only parameter may not be qualified");
+ if (TREE_THIS_VOLATILE (b->decl)
+ || TREE_READONLY (b->decl)
+ || C_DECL_REGISTER (b->decl))
+ error ("'void' as only parameter may not be qualified");
+
+ /* There cannot be an ellipsis. */
+ if (ellipsis)
+ error ("'void' must be the only parameter");
- return tree_cons (0, 0, tree_cons (0, void_type_node, 0));
+ ARG_INFO_TYPES (arg_info) = void_list_node;
+ return arg_info;
}
- /* Sanity check all of the parameter declarations. */
- for (decl = parms; decl; decl = TREE_CHAIN (decl))
- {
- if (TREE_CODE (decl) != PARM_DECL)
- abort ();
- if (TREE_ASM_WRITTEN (decl))
- abort ();
+ if (!ellipsis)
+ types = void_list_node;
- /* Since there is a prototype, args are passed in their
- declared types. The back end may override this. */
- type = TREE_TYPE (decl);
- DECL_ARG_TYPE (decl) = type;
+ /* Break up the bindings list into parms, tags, types, and others;
+ apply sanity checks; purge the name-to-decl bindings. */
+ while (b)
+ {
+ tree decl = b->decl;
+ tree type = TREE_TYPE (decl);
+ const char *keyword;
- /* Check for (..., void, ...) and issue an error. */
- if (VOID_TYPE_P (type) && !DECL_NAME (decl) && !gave_void_only_once_err)
+ switch (TREE_CODE (decl))
{
- error ("\"void\" must be the only parameter");
- gave_void_only_once_err = true;
- }
+ case PARM_DECL:
+ if (b->id)
+ {
+#ifdef ENABLE_CHECKING
+ if (I_SYMBOL_BINDING (b->id) != b) abort ();
+#endif
+ I_SYMBOL_BINDING (b->id) = b->shadowed;
+ }
- type = build_tree_list (0, type);
- *last_type = type;
- last_type = &TREE_CHAIN (type);
- }
+ /* Check for forward decls that never got their actual decl. */
+ if (TREE_ASM_WRITTEN (decl))
+ error ("%Jparameter '%D' has just a forward declaration",
+ decl, decl);
+ /* Check for (..., void, ...) and issue an error. */
+ else if (VOID_TYPE_P (type) && !DECL_NAME (decl))
+ {
+ if (!gave_void_only_once_err)
+ {
+ error ("'void' must be the only parameter");
+ gave_void_only_once_err = true;
+ }
+ }
+ else
+ {
+ /* Valid parameter, add it to the list. */
+ TREE_CHAIN (decl) = parms;
+ parms = decl;
+
+ /* Since there is a prototype, args are passed in their
+ declared types. The back end may override this later. */
+ DECL_ARG_TYPE (decl) = type;
+ types = tree_cons (0, type, types);
+ }
+ break;
- /* Check the list of non-parameter decls for any forward parm decls
- that never got real decls. */
- for (decl = others; decl; decl = TREE_CHAIN (decl))
- if (TREE_CODE (decl) == PARM_DECL)
- {
- if (!TREE_ASM_WRITTEN (decl))
- abort ();
+ case ENUMERAL_TYPE: keyword = "enum"; goto tag;
+ case UNION_TYPE: keyword = "union"; goto tag;
+ case RECORD_TYPE: keyword = "struct"; goto tag;
+ tag:
+ /* Types may not have tag-names, in which case the type
+ appears in the bindings list with b->id NULL. */
+ if (b->id)
+ {
+#ifdef ENABLE_CHECKING
+ if (I_TAG_BINDING (b->id) != b) abort ();
+#endif
+ I_TAG_BINDING (b->id) = b->shadowed;
+ }
- error ("%Jparameter \"%D\" has just a forward declaration",
- decl, decl);
- }
+ /* Warn about any struct, union or enum tags defined in a
+ parameter list. The scope of such types is limited to
+ the parameter list, which is rarely if ever desirable
+ (it's impossible to call such a function with type-
+ correct arguments). An anonymous union parm type is
+ meaningful as a GNU extension, so don't warn for that. */
+ if (TREE_CODE (decl) != UNION_TYPE || b->id != 0)
+ {
+ if (b->id)
+ /* The %s will be one of 'struct', 'union', or 'enum'. */
+ warning ("'%s %E' declared inside parameter list",
+ keyword, b->id);
+ else
+ /* The %s will be one of 'struct', 'union', or 'enum'. */
+ warning ("anonymous %s declared inside parameter list",
+ keyword);
- /* Warn about any struct, union or enum tags defined within this
- list. The scope of such types is limited to this declaration,
- which is rarely if ever desirable (it's impossible to call such
- a function with type-correct arguments). */
- for (decl = tags; decl; decl = TREE_CHAIN (decl))
- {
- enum tree_code code = TREE_CODE (TREE_VALUE (decl));
- const char *keyword;
- /* An anonymous union parm type is meaningful as a GNU extension.
- So don't warn for that. */
- if (code == UNION_TYPE && TREE_PURPOSE (decl) == 0 && !pedantic)
- continue;
+ if (! explained_incomplete_types)
+ {
+ warning ("its scope is only this definition or declaration,"
+ " which is probably not what you want");
+ explained_incomplete_types = true;
+ }
+ }
- /* The keyword should not be translated. */
- switch (code)
- {
- case RECORD_TYPE: keyword = "struct"; break;
- case UNION_TYPE: keyword = "union"; break;
- case ENUMERAL_TYPE: keyword = "enum"; break;
- default: abort ();
- }
+ tags = tree_cons (b->id, decl, tags);
+ break;
- if (TREE_PURPOSE (decl))
- /* The first %s will be one of 'struct', 'union', or 'enum'. */
- warning ("\"%s %s\" declared inside parameter list",
- keyword, IDENTIFIER_POINTER (TREE_PURPOSE (decl)));
- else
- /* The %s will be one of 'struct', 'union', or 'enum'. */
- warning ("anonymous %s declared inside parameter list", keyword);
+ case CONST_DECL:
+ case TYPE_DECL:
+ /* CONST_DECLs appear here when we have an embedded enum,
+ and TYPE_DECLs appear here when we have an embedded struct
+ or union. No warnings for this - we already warned about the
+ type itself. */
+ TREE_CHAIN (decl) = others;
+ others = decl;
+ /* fall through */
- if (! explained_incomplete_types)
- {
- warning ("its scope is only this definition or declaration,"
- " which is probably not what you want");
- explained_incomplete_types = true;
- }
- }
+ case ERROR_MARK:
+ /* error_mark_node appears here when we have an undeclared
+ variable. Just throw it away. */
+ if (b->id)
+ {
+#ifdef ENABLE_CHECKING
+ if (I_SYMBOL_BINDING (b->id) != b) abort ();
+#endif
+ I_SYMBOL_BINDING (b->id) = b->shadowed;
+ }
+ break;
+ /* Other things that might be encountered. */
+ case LABEL_DECL:
+ case FUNCTION_DECL:
+ case VAR_DECL:
+ default:
+ abort ();
+ }
- if (void_at_end)
- {
- type = build_tree_list (0, void_type_node);
- *last_type = type;
+ b = free_binding_and_advance (b);
}
- list = tree_cons (parms, tags, types);
- TREE_TYPE (list) = others;
- return list;
+ ARG_INFO_PARMS (arg_info) = parms;
+ ARG_INFO_TAGS (arg_info) = tags;
+ ARG_INFO_TYPES (arg_info) = types;
+ ARG_INFO_OTHERS (arg_info) = others;
+ return arg_info;
}
\f
/* Get the struct, enum or union (CODE says which) with tag NAME.
TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node);
TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node);
TYPE_USER_ALIGN (ref) = 0;
- TREE_UNSIGNED (ref) = 1;
+ TYPE_UNSIGNED (ref) = 1;
TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node);
TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node);
TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node);
/* Process the specs, declarator (NULL if omitted) and width (NULL if omitted)
of a structure component, returning a FIELD_DECL node.
- WIDTH is non-NULL for bit fields only, and is an INTEGER_CST node.
+ WIDTH is non-NULL for bit-fields only, and is an INTEGER_CST node.
This is done during the parsing of the struct declaration.
The FIELD_DECL nodes are chained together and the lot of them
}
}
- value = grokdeclarator (declarator, declspecs, width ? BITFIELD : FIELD, 0);
+ value = grokdeclarator (declarator, declspecs, FIELD, 0,
+ width ? &width : NULL);
finish_decl (value, NULL_TREE, NULL_TREE);
DECL_INITIAL (value) = width;
finish_struct (tree t, tree fieldlist, tree attributes)
{
tree x;
- int toplevel = global_scope == current_scope;
+ bool toplevel = file_scope == current_scope;
int saw_named_field;
/* If this type was previously laid out as a forward reference,
decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
- /* Nameless union parm types are useful as GCC extension. */
- if (! (TREE_CODE (t) == UNION_TYPE && TYPE_NAME (t) == 0) && !pedantic)
- /* Otherwise, warn about any struct or union def. in parmlist. */
- if (in_parm_level_p ())
- {
- if (pedantic)
- pedwarn ("%s defined inside parms",
- TREE_CODE (t) == UNION_TYPE ? _("union") : _("structure"));
- else
- warning ("%s defined inside parms",
- TREE_CODE (t) == UNION_TYPE ? _("union") : _("structure"));
- }
-
if (pedantic)
{
for (x = fieldlist; x; x = TREE_CHAIN (x))
}
/* Install struct as DECL_CONTEXT of each field decl.
- Also process specified field sizes,m which is found in the DECL_INITIAL.
- Store 0 there, except for ": 0" fields (so we can find them
- and delete them, below). */
+ Also process specified field sizes, found in the DECL_INITIAL,
+ storing 0 there after the type has been changed to precision equal
+ to its width, rather than the precision of the specified standard
+ type. (Correct layout requires the original type to have been preserved
+ until now.) */
saw_named_field = 0;
for (x = fieldlist; x; x = TREE_CHAIN (x))
error ("nested redefinition of `%s'",
IDENTIFIER_POINTER (TYPE_NAME (t)));
- /* Detect invalid bit-field size. */
- if (DECL_INITIAL (x))
- STRIP_NOPS (DECL_INITIAL (x));
- if (DECL_INITIAL (x))
- {
- if (TREE_CODE (DECL_INITIAL (x)) == INTEGER_CST)
- constant_expression_warning (DECL_INITIAL (x));
- else
- {
- error ("%Jbit-field '%D' width not an integer constant", x, x);
- DECL_INITIAL (x) = NULL;
- }
- }
-
- /* Detect invalid bit-field type. */
- if (DECL_INITIAL (x)
- && TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (x)) != BOOLEAN_TYPE
- && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE)
- {
- error ("%Jbit-field '%D' has invalid type", x, x);
- DECL_INITIAL (x) = NULL;
- }
-
- if (DECL_INITIAL (x) && pedantic
- && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != integer_type_node
- && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != unsigned_type_node
- && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != boolean_type_node
- /* Accept an enum that's equivalent to int or unsigned int. */
- && !(TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
- && (TYPE_PRECISION (TREE_TYPE (x))
- == TYPE_PRECISION (integer_type_node))))
- pedwarn ("%Jbit-field '%D' type invalid in ISO C", x, x);
-
- /* Detect and ignore out of range field width and process valid
- field widths. */
if (DECL_INITIAL (x))
{
- int max_width
- = (TYPE_MAIN_VARIANT (TREE_TYPE (x)) == boolean_type_node
- ? CHAR_TYPE_SIZE : TYPE_PRECISION (TREE_TYPE (x)));
-
- if (tree_int_cst_sgn (DECL_INITIAL (x)) < 0)
- error ("%Jnegative width in bit-field '%D'", x, x);
- else if (0 < compare_tree_int (DECL_INITIAL (x), max_width))
- pedwarn ("%Jwidth of '%D' exceeds its type", x, x);
- else if (integer_zerop (DECL_INITIAL (x)) && DECL_NAME (x) != 0)
- error ("%Jzero width for bit-field '%D'", x, x);
- else
- {
- /* The test above has assured us that TREE_INT_CST_HIGH is 0. */
- unsigned HOST_WIDE_INT width
- = tree_low_cst (DECL_INITIAL (x), 1);
-
- if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
- && (width < min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
- TREE_UNSIGNED (TREE_TYPE (x)))
- || (width
- < min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
- TREE_UNSIGNED (TREE_TYPE (x))))))
- warning ("%J'%D' is narrower than values of its type", x, x);
-
- DECL_SIZE (x) = bitsize_int (width);
- DECL_BIT_FIELD (x) = 1;
- SET_DECL_C_BIT_FIELD (x);
- }
+ unsigned HOST_WIDE_INT width = tree_low_cst (DECL_INITIAL (x), 1);
+ DECL_SIZE (x) = bitsize_int (width);
+ DECL_BIT_FIELD (x) = 1;
+ SET_DECL_C_BIT_FIELD (x);
}
- DECL_INITIAL (x) = 0;
-
/* Detect flexible array member in an invalid context. */
if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
&& TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
&& TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
{
if (TREE_CODE (t) == UNION_TYPE)
- error ("%Jflexible array member in union", x);
+ {
+ error ("%Jflexible array member in union", x);
+ TREE_TYPE (x) = error_mark_node;
+ }
else if (TREE_CHAIN (x) != NULL_TREE)
- error ("%Jflexible array member not at end of struct", x);
+ {
+ error ("%Jflexible array member not at end of struct", x);
+ TREE_TYPE (x) = error_mark_node;
+ }
else if (! saw_named_field)
- error ("%Jflexible array member in otherwise empty struct", x);
+ {
+ error ("%Jflexible array member in otherwise empty struct", x);
+ TREE_TYPE (x) = error_mark_node;
+ }
}
- if (pedantic && TREE_CODE (t) == RECORD_TYPE
+ if (pedantic && !in_system_header && TREE_CODE (t) == RECORD_TYPE
&& flexible_array_type_p (TREE_TYPE (x)))
pedwarn ("%Jinvalid use of structure with flexible array member", x);
layout_type (t);
- /* Delete all zero-width bit-fields from the fieldlist */
+ /* Give bit-fields their proper types. */
{
tree *fieldlistp = &fieldlist;
while (*fieldlistp)
- if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp))
- *fieldlistp = TREE_CHAIN (*fieldlistp);
+ if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp)
+ && TREE_TYPE (*fieldlistp) != error_mark_node)
+ {
+ unsigned HOST_WIDE_INT width
+ = tree_low_cst (DECL_INITIAL (*fieldlistp), 1);
+ tree type = TREE_TYPE (*fieldlistp);
+ if (width != TYPE_PRECISION (type))
+ TREE_TYPE (*fieldlistp)
+ = build_nonstandard_integer_type (width, TYPE_UNSIGNED (type));
+ DECL_INITIAL (*fieldlistp) = 0;
+ }
else
fieldlistp = &TREE_CHAIN (*fieldlistp);
}
TYPE_FIELDS (t) = fieldlist;
/* If there are lots of fields, sort so we can look through them fast.
- We arbitrarily consider 16 or more elts to be "a lot". */
+ We arbitrarily consider 16 or more elts to be "a lot". */
{
int len = 0;
tree *field_array;
struct lang_type *space;
struct sorted_fields_type *space2;
-
+
len += list_length (x);
-
+
/* Use the same allocation policy here that make_node uses, to
ensure that this lives as long as the rest of the struct decl.
All decls in an inline function need to be saved. */
-
- space = ggc_alloc (sizeof (struct lang_type));
+
+ space = ggc_alloc_cleared (sizeof (struct lang_type));
space2 = ggc_alloc (sizeof (struct sorted_fields_type) + len * sizeof (tree));
-
+
len = 0;
space->s = space2;
field_array = &space2->elts[0];
for (x = fieldlist; x; x = TREE_CHAIN (x))
{
field_array[len++] = x;
-
+
/* If there is anonymous struct or union, break out of the loop. */
if (DECL_NAME (x) == NULL)
break;
}
}
}
-
+
for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
{
TYPE_FIELDS (x) = TYPE_FIELDS (t);
finish_enum (tree enumtype, tree values, tree attributes)
{
tree pair, tem;
- tree minnode = 0, maxnode = 0, enum_value_type;
+ tree minnode = 0, maxnode = 0;
int precision, unsign;
- int toplevel = (global_scope == current_scope);
-
- if (in_parm_level_p ())
- warning ("enum defined inside parms");
+ bool toplevel = (file_scope == current_scope);
+ struct lang_type *lt;
decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
min_precision (maxnode, unsign));
if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
{
- tree narrowest = c_common_type_for_size (precision, unsign);
- if (narrowest == 0)
+ tem = c_common_type_for_size (precision, unsign);
+ if (tem == NULL)
{
warning ("enumeration values exceed range of largest integer");
- narrowest = long_long_integer_type_node;
+ tem = long_long_integer_type_node;
}
-
- precision = TYPE_PRECISION (narrowest);
}
else
- precision = TYPE_PRECISION (integer_type_node);
-
- if (precision == TYPE_PRECISION (integer_type_node))
- enum_value_type = c_common_type_for_size (precision, 0);
- else
- enum_value_type = enumtype;
+ tem = unsign ? unsigned_type_node : integer_type_node;
- TYPE_MIN_VALUE (enumtype) = minnode;
- TYPE_MAX_VALUE (enumtype) = maxnode;
- TYPE_PRECISION (enumtype) = precision;
- TREE_UNSIGNED (enumtype) = unsign;
+ TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem);
+ TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem);
+ TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem);
+ TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem);
TYPE_SIZE (enumtype) = 0;
layout_type (enumtype);
for (pair = values; pair; pair = TREE_CHAIN (pair))
{
tree enu = TREE_PURPOSE (pair);
+ tree ini = DECL_INITIAL (enu);
TREE_TYPE (enu) = enumtype;
when comparing integers with enumerators that fit in the
int range. When -pedantic is given, build_enumerator()
would have already taken care of those that don't fit. */
- if (int_fits_type_p (DECL_INITIAL (enu), enum_value_type))
- DECL_INITIAL (enu) = convert (enum_value_type, DECL_INITIAL (enu));
+ if (int_fits_type_p (ini, integer_type_node))
+ tem = integer_type_node;
else
- DECL_INITIAL (enu) = convert (enumtype, DECL_INITIAL (enu));
+ tem = enumtype;
+ ini = convert (tem, ini);
+ DECL_INITIAL (enu) = ini;
TREE_PURPOSE (pair) = DECL_NAME (enu);
- TREE_VALUE (pair) = DECL_INITIAL (enu);
+ TREE_VALUE (pair) = ini;
}
TYPE_VALUES (enumtype) = values;
}
+ /* Record the min/max values so that we can warn about bit-field
+ enumerations that are too small for the values. */
+ lt = ggc_alloc_cleared (sizeof (struct lang_type));
+ lt->enum_min = minnode;
+ lt->enum_max = maxnode;
+ TYPE_LANG_SPECIFIC (enumtype) = lt;
+
/* Fix up all variant types of this enum type. */
for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem))
{
TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype);
- TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
+ TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype);
+ TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype);
}
/* Finish debugging output for this type. */
if (value != 0)
{
- if (TREE_CODE (value) == INTEGER_CST)
+ /* Don't issue more errors for error_mark_node (i.e. an
+ undeclared identifier) - just ignore the value expression. */
+ if (value == error_mark_node)
+ value = 0;
+ else if (TREE_CODE (value) != INTEGER_CST)
{
- value = default_conversion (value);
- constant_expression_warning (value);
+ error ("enumerator value for '%E' is not an integer constant", name);
+ value = 0;
}
else
{
- error ("enumerator value for `%s' not integer constant",
- IDENTIFIER_POINTER (name));
- value = 0;
+ value = default_conversion (value);
+ constant_expression_warning (value);
}
}
if (pedantic && ! int_fits_type_p (value, integer_type_node))
{
pedwarn ("ISO C restricts enumerator values to range of `int'");
+ /* XXX This causes -pedantic to change the meaning of the program.
+ Remove? -zw 2004-03-15 */
value = convert (integer_type_node, value);
}
TYPE_PRECISION (integer_type_node)),
(TYPE_PRECISION (type)
>= TYPE_PRECISION (integer_type_node)
- && TREE_UNSIGNED (type)));
+ && TYPE_UNSIGNED (type)));
decl = build_decl (CONST_DECL, name, type);
DECL_INITIAL (decl) = convert (type, value);
{
tree decl1, old_decl;
tree restype;
- int old_immediate_size_expand = immediate_size_expand;
current_function_returns_value = 0; /* Assume, until we see it does. */
current_function_returns_null = 0;
current_function_returns_abnormally = 0;
warn_about_return_type = 0;
current_extern_inline = 0;
+ c_switch_stack = NULL;
- /* Don't expand any sizes in the return type of the function. */
- immediate_size_expand = 0;
+ /* Indicate no valid break/continue context by setting these variables
+ to some non-null, non-label value. We'll notice and emit the proper
+ error message in c_finish_bc_stmt. */
+ c_break_label = c_cont_label = size_zero_node;
- decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1);
+ decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL);
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
if (decl1 == 0)
- {
- immediate_size_expand = old_immediate_size_expand;
- return 0;
- }
+ return 0;
decl_attributes (&decl1, attributes, 0);
if (warn_about_return_type)
pedwarn_c99 ("return type defaults to `int'");
- /* Save the parm names or decls from this function's declarator
- where store_parm_decls will find them. */
- current_function_parms = last_function_parms;
- current_function_parm_tags = last_function_parm_tags;
- current_function_parm_others = last_function_parm_others;
-
/* Make the init_value nonzero so pushdecl knows this is not tentative.
- error_mark_node is replaced below (in poplevel) with the BLOCK. */
+ error_mark_node is replaced below (in pop_scope) with the BLOCK. */
DECL_INITIAL (decl1) = error_mark_node;
/* If this definition isn't a prototype and we had a prototype declaration
before, copy the arg type info from that prototype.
But not if what we had before was a builtin function. */
- old_decl = lookup_name_current_level (DECL_NAME (decl1));
+ old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope);
if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
&& !DECL_BUILT_IN (old_decl)
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
#endif
/* If #pragma weak was used, mark the decl weak now. */
- if (current_scope == global_scope)
+ if (current_scope == file_scope)
maybe_apply_pragma_weak (decl1);
/* Warn for unlikely, improbable, or stupid declarations of `main'. */
current_function_decl = pushdecl (decl1);
- pushlevel (0);
+ push_scope ();
declare_parm_level ();
- make_decl_rtl (current_function_decl, NULL);
-
restype = TREE_TYPE (TREE_TYPE (current_function_decl));
/* Promote the value to int before returning it. */
if (c_promoting_integer_type_p (restype))
{
/* It retains unsignedness if not really getting wider. */
- if (TREE_UNSIGNED (restype)
+ if (TYPE_UNSIGNED (restype)
&& (TYPE_PRECISION (restype)
== TYPE_PRECISION (integer_type_node)))
restype = unsigned_type_node;
DECL_RESULT (current_function_decl)
= build_decl (RESULT_DECL, NULL_TREE, restype);
- /* If this fcn was already referenced via a block-scope `extern' decl
- (or an implicit decl), propagate certain information about the usage. */
- if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl)))
- TREE_ADDRESSABLE (current_function_decl) = 1;
-
- immediate_size_expand = old_immediate_size_expand;
-
start_fname_decls ();
return 1;
need only record them as in effect and complain if any redundant
old-style parm decls were written. */
static void
-store_parm_decls_newstyle (void)
+store_parm_decls_newstyle (tree fndecl, tree arg_info)
{
- tree decl, last;
- tree fndecl = current_function_decl;
- tree parms = current_function_parms;
- tree tags = current_function_parm_tags;
- tree others = current_function_parm_others;
+ tree decl;
+ tree parms = ARG_INFO_PARMS (arg_info);
+ tree tags = ARG_INFO_TAGS (arg_info);
+ tree others = ARG_INFO_OTHERS (arg_info);
- if (current_scope->parms || current_scope->names || current_scope->tags)
+ if (current_scope->bindings)
{
error ("%Jold-style parameter declarations in prototyped "
"function definition", fndecl);
/* Get rid of the old-style declarations. */
- poplevel (0, 0, 0);
- pushlevel (0);
- }
+ pop_scope ();
+ push_scope ();
+ }
+ /* Don't issue this warning for nested functions, and don't issue this
+ warning if we got here because ARG_INFO_TYPES was error_mark_node
+ (this happens when a function definition has just an ellipsis in
+ its parameter list). */
+ else if (warn_traditional && !in_system_header && !current_function_scope
+ && ARG_INFO_TYPES (arg_info) != error_mark_node)
+ warning ("%Jtraditional C rejects ISO C style function definitions",
+ fndecl);
/* Now make all the parameter declarations visible in the function body.
We can bypass most of the grunt work of pushdecl. */
- for (last = 0, decl = parms; decl; last = decl, decl = TREE_CHAIN (decl))
+ for (decl = parms; decl; decl = TREE_CHAIN (decl))
{
DECL_CONTEXT (decl) = current_function_decl;
- if (DECL_NAME (decl) == 0)
- error ("%Jparameter name omitted", decl);
+ if (DECL_NAME (decl))
+ bind (DECL_NAME (decl), decl, current_scope,
+ /*invisible=*/false, /*nested=*/false);
else
- {
- if (IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)))
- current_scope->shadowed
- = tree_cons (DECL_NAME (decl),
- IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)),
- current_scope->shadowed);
- IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)) = decl;
- }
+ error ("%Jparameter name omitted", decl);
}
- current_scope->parms = parms;
- current_scope->parms_last = last;
/* Record the parameter list in the function declaration. */
DECL_ARGUMENTS (fndecl) = parms;
/* Now make all the ancillary declarations visible, likewise. */
- for (last = 0, decl = others; decl; last = decl, decl = TREE_CHAIN (decl))
+ for (decl = others; decl; decl = TREE_CHAIN (decl))
{
DECL_CONTEXT (decl) = current_function_decl;
- if (DECL_NAME (decl)
- && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) != void_type_node)
- {
- if (IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)))
- current_scope->shadowed
- = tree_cons (DECL_NAME (decl),
- IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)),
- current_scope->shadowed);
- IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)) = decl;
- }
+ if (DECL_NAME (decl))
+ bind (DECL_NAME (decl), decl, current_scope,
+ /*invisible=*/false, /*nested=*/false);
}
- current_scope->names = others;
- current_scope->names_last = last;
/* And all the tag declarations. */
for (decl = tags; decl; decl = TREE_CHAIN (decl))
if (TREE_PURPOSE (decl))
- {
- if (IDENTIFIER_TAG_VALUE (TREE_PURPOSE (decl)))
- current_scope->shadowed_tags
- = tree_cons (TREE_PURPOSE (decl),
- IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (decl)),
- current_scope->shadowed_tags);
- IDENTIFIER_TAG_VALUE (TREE_PURPOSE (decl)) = TREE_VALUE (decl);
- }
- current_scope->tags = tags;
+ bind (TREE_PURPOSE (decl), TREE_VALUE (decl), current_scope,
+ /*invisible=*/false, /*nested=*/false);
}
/* Subroutine of store_parm_decls which handles old-style function
definitions (separate parameter list and declarations). */
static void
-store_parm_decls_oldstyle (void)
+store_parm_decls_oldstyle (tree fndecl, tree arg_info)
{
+ struct c_binding *b;
tree parm, decl, last;
- tree fndecl = current_function_decl;
-
- /* This is the identifier list from the function declarator. */
- tree parmids = current_function_parms;
+ tree parmids = ARG_INFO_PARMS (arg_info);
/* We use DECL_WEAK as a flag to show which parameters have been
seen already, since it is not used on PARM_DECL. */
#ifdef ENABLE_CHECKING
- for (parm = current_scope->parms; parm; parm = TREE_CHAIN (parm))
- if (DECL_WEAK (parm))
+ for (b = current_scope->bindings; b; b = b->prev)
+ if (TREE_CODE (b->decl) == PARM_DECL && DECL_WEAK (b->decl))
abort ();
#endif
+ if (warn_old_style_definition && !in_system_header)
+ warning ("%Jold-style function definition", fndecl);
+
/* Match each formal parameter name with its declaration. Save each
decl in the appropriate TREE_PURPOSE slot of the parmids chain. */
for (parm = parmids; parm; parm = TREE_CHAIN (parm))
continue;
}
- decl = IDENTIFIER_SYMBOL_VALUE (TREE_VALUE (parm));
- if (decl && DECL_CONTEXT (decl) == fndecl)
+ b = I_SYMBOL_BINDING (TREE_VALUE (parm));
+ if (b && B_IN_CURRENT_SCOPE (b))
{
+ decl = b->decl;
/* If we got something other than a PARM_DECL it is an error. */
if (TREE_CODE (decl) != PARM_DECL)
- error ("%J\"%D\" declared as a non-parameter", decl, decl);
+ error ("%J'%D' declared as a non-parameter", decl, decl);
/* If the declaration is already marked, we have a duplicate
name. Complain and ignore the duplicate. */
else if (DECL_WEAK (decl))
{
- error ("%Jmultiple parameters named \"%D\"", decl, decl);
+ error ("%Jmultiple parameters named '%D'", decl, decl);
TREE_PURPOSE (parm) = 0;
continue;
}
an int. */
else if (VOID_TYPE_P (TREE_TYPE (decl)))
{
- error ("%Jparameter \"%D\" declared void", decl, decl);
+ error ("%Jparameter '%D' declared with void type", decl, decl);
TREE_TYPE (decl) = integer_type_node;
DECL_ARG_TYPE (decl) = integer_type_node;
layout_decl (decl, 0);
pushdecl (decl);
if (flag_isoc99)
- pedwarn ("%Jtype of \"%D\" defaults to \"int\"", decl, decl);
+ pedwarn ("%Jtype of '%D' defaults to 'int'", decl, decl);
else if (extra_warnings)
- warning ("%Jtype of \"%D\" defaults to \"int\"", decl, decl);
+ warning ("%Jtype of '%D' defaults to 'int'", decl, decl);
}
TREE_PURPOSE (parm) = decl;
/* Now examine the parms chain for incomplete declarations
and declarations with no corresponding names. */
- for (parm = current_scope->parms; parm; parm = TREE_CHAIN (parm))
+ for (b = current_scope->bindings; b; b = b->prev)
{
+ parm = b->decl;
+ if (TREE_CODE (parm) != PARM_DECL)
+ continue;
+
if (!COMPLETE_TYPE_P (TREE_TYPE (parm)))
{
- error ("%Jparameter \"%D\" has incomplete type", parm, parm);
+ error ("%Jparameter '%D' has incomplete type", parm, parm);
TREE_TYPE (parm) = error_mark_node;
}
if (! DECL_WEAK (parm))
{
- error ("%Jdeclaration for parameter \"%D\" but no such parameter",
+ error ("%Jdeclaration for parameter '%D' but no such parameter",
parm, parm);
/* Pretend the parameter was not missing.
{
last = TREE_PURPOSE (parm);
DECL_ARGUMENTS (fndecl) = last;
- current_scope->parms = last;
DECL_WEAK (last) = 0;
for (parm = TREE_CHAIN (parm); parm; parm = TREE_CHAIN (parm))
last = TREE_PURPOSE (parm);
DECL_WEAK (last) = 0;
}
- current_scope->parms_last = last;
TREE_CHAIN (last) = 0;
}
declared for the arg. ISO C says we take the unqualified
type for parameters declared with qualified type. */
if (! comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
- TYPE_MAIN_VARIANT (TREE_VALUE (type)),
- COMPARE_STRICT))
+ TYPE_MAIN_VARIANT (TREE_VALUE (type))))
{
if (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
== TYPE_MAIN_VARIANT (TREE_VALUE (type)))
if (pedantic)
{
- pedwarn ("promoted argument \"%D\" "
+ pedwarn ("promoted argument '%D' "
"doesn't match prototype", parm);
pedwarn ("%Hprototype declaration",
¤t_function_prototype_locus);
}
else
{
- error ("argument \"%D\" doesn't match prototype", parm);
+ error ("argument '%D' doesn't match prototype", parm);
error ("%Hprototype declaration",
¤t_function_prototype_locus);
}
{
tree fndecl = current_function_decl;
- /* The function containing FNDECL, if any. */
- tree context = decl_function_context (fndecl);
+ /* The argument information block for FNDECL. */
+ tree arg_info = DECL_ARGUMENTS (fndecl);
- /* True if this definition is written with a prototype. */
- bool prototype = (current_function_parms
- && TREE_CODE (current_function_parms) != TREE_LIST);
+ /* True if this definition is written with a prototype. Note:
+ despite C99 6.7.5.3p14, we can *not* treat an empty argument
+ list in a function definition as equivalent to (void) -- an
+ empty argument list specifies the function has no parameters,
+ but only (void) sets up a prototype for future calls. */
+ bool proto = ARG_INFO_TYPES (arg_info) != 0;
- if (prototype)
- store_parm_decls_newstyle ();
+ if (proto)
+ store_parm_decls_newstyle (fndecl, arg_info);
else
- store_parm_decls_oldstyle ();
+ store_parm_decls_oldstyle (fndecl, arg_info);
- /* The next call to pushlevel will be a function body. */
+ /* The next call to push_scope will be a function body. */
next_is_function_body = true;
/* Write a record describing this function definition to the prototypes
file (if requested). */
- gen_aux_info_record (fndecl, 1, 0, prototype);
+ gen_aux_info_record (fndecl, 1, 0, proto);
/* Initialize the RTL code for the function. */
allocate_struct_function (fndecl);
/* Begin the statement tree for this function. */
- begin_stmt_tree (&DECL_SAVED_TREE (fndecl));
-
- /* If this is a nested function, save away the sizes of any
- variable-size types so that we can expand them when generating
- RTL. */
- if (context)
- {
- tree t;
-
- DECL_LANG_SPECIFIC (fndecl)->pending_sizes
- = nreverse (get_pending_sizes ());
- for (t = DECL_LANG_SPECIFIC (fndecl)->pending_sizes;
- t;
- t = TREE_CHAIN (t))
- SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = context;
- }
+ DECL_SAVED_TREE (fndecl) = push_stmt_list ();
- /* This function is being processed in whole-function mode. */
- cfun->x_whole_function_mode_p = 1;
+ /* ??? Insert the contents of the pending sizes list into the function
+ to be evaluated. This just changes mis-behaviour until assign_parms
+ phase ordering problems are resolved. */
+ {
+ tree t;
+ for (t = nreverse (get_pending_sizes ()); t ; t = TREE_CHAIN (t))
+ add_stmt (TREE_VALUE (t));
+ }
/* Even though we're inside a function body, we still don't want to
call expand_expr to calculate the size of a variable-sized array.
We haven't necessarily assigned RTL to all variables yet, so it's
not safe to try to expand expressions involving them. */
- immediate_size_expand = 0;
cfun->x_dont_save_pending_sizes_p = 1;
}
\f
+/* Give FNDECL and all its nested functions to cgraph for compilation. */
+
+static void
+c_finalize (tree fndecl)
+{
+ struct cgraph_node *cgn;
+
+ /* Handle attribute((warn_unused_result)). Relies on gimple input. */
+ c_warn_unused_result (&DECL_SAVED_TREE (fndecl));
+
+ /* ??? Objc emits functions after finalizing the compilation unit.
+ This should be cleaned up later and this conditional removed. */
+ if (cgraph_global_info_ready)
+ {
+ c_expand_body (fndecl);
+ return;
+ }
+
+ /* Finalize all nested functions now. */
+ cgn = cgraph_node (fndecl);
+ for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
+ c_finalize (cgn->decl);
+
+ cgraph_finalize_function (fndecl, false);
+}
+
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
for the function definition.
This is called after parsing the body of the function definition. */
void
-finish_function ()
+finish_function (void)
{
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 scope stack out of sync. Detect this situation by noticing
- that current_scope 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
- scope - see there for details. */
-
- if (current_scope->parm_flag && next_is_function_body)
- {
- pushlevel (0);
- poplevel (0, 0, 0);
- }
-
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& targetm.calls.promote_prototypes (TREE_TYPE (fndecl)))
{
}
}
- BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+ if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node)
+ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
/* Must mark the RESULT_DECL as being in this function. */
- DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
+ if (DECL_RESULT (fndecl) && DECL_RESULT (fndecl) != error_mark_node)
+ DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted)
{
}
else
{
-#ifdef DEFAULT_MAIN_RETURN
- /* Make it so that `main' always returns success by default. */
- DEFAULT_MAIN_RETURN;
-#else
if (flag_isoc99)
- c_expand_return (integer_zero_node);
-#endif
+ c_finish_return (integer_zero_node);
}
}
- finish_fname_decls ();
-
/* Tie off the statement tree for this function. */
- finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
+ DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
+
+ finish_fname_decls ();
/* Complain if there's just no return statement. */
if (warn_return_type
&& current_function_returns_null)
warning ("this function may return with or without a value");
- /* We're leaving the context of this function, so zap cfun. It's still in
- DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation. */
- cfun = NULL;
-
- /* ??? Objc emits functions after finalizing the compilation unit.
- This should be cleaned up later and this conditional removed. */
- if (!cgraph_global_info_ready)
- cgraph_finalize_function (fndecl, false);
- else
- c_expand_body (fndecl);
- current_function_decl = NULL;
-}
-
-/* Generate the RTL for a deferred function FNDECL. */
-
-void
-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))
- {
- 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 nonzero,
- then we are already in the process of generating RTL for another
- function. */
-
-static void
-c_expand_body_1 (tree fndecl, int nested_p)
-{
- if (nested_p)
- {
- /* Make sure that we will evaluate variable-sized types involved
- in our function's type. */
- expand_pending_sizes (DECL_LANG_SPECIFIC (fndecl)->pending_sizes);
-
- /* Squirrel away our current state. */
- push_function_context ();
- }
+ /* Store the end of the function, so that we get good line number
+ info for the epilogue. */
+ cfun->function_end_locus = input_location;
- tree_rest_of_compilation (fndecl, nested_p);
+ /* If we don't have ctors/dtors sections, and this is a static
+ constructor or destructor, it must be recorded now. */
+ if (DECL_STATIC_CONSTRUCTOR (fndecl)
+ && !targetm.have_ctors_dtors)
+ static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
+ if (DECL_STATIC_DESTRUCTOR (fndecl)
+ && !targetm.have_ctors_dtors)
+ static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
- if (nested_p)
- /* Return to the enclosing function. */
- pop_function_context ();
+ /* Genericize before inlining. Delay genericizing nested functions
+ until their parent function is genericized. Since finalizing
+ requires GENERIC, delay that as well. */
- if (DECL_STATIC_CONSTRUCTOR (fndecl))
+ if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node)
{
- if (targetm.have_ctors_dtors)
- (* targetm.asm_out.constructor) (XEXP (DECL_RTL (fndecl), 0),
- DEFAULT_INIT_PRIORITY);
+ if (!decl_function_context (fndecl))
+ {
+ c_genericize (fndecl);
+ lower_nested_functions (fndecl);
+ c_finalize (fndecl);
+ }
else
- static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
+ {
+ /* Register this function with cgraph just far enough to get it
+ added to our parent's nested function list. Handy, since the
+ C front end doesn't have such a list. */
+ (void) cgraph_node (fndecl);
+ }
}
- if (DECL_STATIC_DESTRUCTOR (fndecl))
- {
- if (targetm.have_ctors_dtors)
- (* targetm.asm_out.destructor) (XEXP (DECL_RTL (fndecl), 0),
- DEFAULT_INIT_PRIORITY);
- else
- static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
- }
+ /* We're leaving the context of this function, so zap cfun.
+ It's still in DECL_STRUCT_FUNCTION, and we'll restore it in
+ tree_rest_of_compilation. */
+ cfun = NULL;
+ current_function_decl = NULL;
}
-/* Like c_expand_body_1 but only for unnested functions. */
+/* Generate the RTL for the body of FNDECL. */
void
c_expand_body (tree fndecl)
{
- c_expand_body_1 (fndecl, 0);
+
+ if (!DECL_INITIAL (fndecl)
+ || DECL_INITIAL (fndecl) == error_mark_node)
+ return;
+
+ tree_rest_of_compilation (fndecl, false);
+
+ if (DECL_STATIC_CONSTRUCTOR (fndecl)
+ && targetm.have_ctors_dtors)
+ targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0),
+ DEFAULT_INIT_PRIORITY);
+ if (DECL_STATIC_DESTRUCTOR (fndecl)
+ && targetm.have_ctors_dtors)
+ targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0),
+ DEFAULT_INIT_PRIORITY);
}
\f
/* Check the declarations given in a for-loop for satisfying the C99
void
check_for_loop_decls (void)
{
- tree t;
+ struct c_binding *b;
if (!flag_isoc99)
{
interpretation, to avoid creating an extension which later causes
problems. */
- for (t = current_scope->tags; t; t = TREE_CHAIN (t))
+ for (b = current_scope->bindings; b; b = b->prev)
{
- 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)));
- else if (code == UNION_TYPE)
- error ("'union %s' declared in 'for' loop initial declaration",
- IDENTIFIER_POINTER (TREE_PURPOSE (t)));
- else
- error ("'enum %s' declared in 'for' loop initial declaration",
- IDENTIFIER_POINTER (TREE_PURPOSE (t)));
- }
- }
+ tree id = b->id;
+ tree decl = b->decl;
- for (t = getdecls (); t; t = TREE_CHAIN (t))
- {
- if (TREE_CODE (t) != VAR_DECL && DECL_NAME (t))
- error ("%Jdeclaration of non-variable '%D' in 'for' loop "
- "initial declaration", t, t);
- else if (TREE_STATIC (t))
- error ("%Jdeclaration of static variable '%D' in 'for' loop "
- "initial declaration", t, t);
- else if (DECL_EXTERNAL (t))
- error ("%Jdeclaration of 'extern' variable '%D' in 'for' loop "
- "initial declaration", t, t);
+ if (!id)
+ continue;
+
+ switch (TREE_CODE (decl))
+ {
+ case VAR_DECL:
+ if (TREE_STATIC (decl))
+ error ("%Jdeclaration of static variable '%D' in 'for' loop "
+ "initial declaration", decl, decl);
+ else if (DECL_EXTERNAL (decl))
+ error ("%Jdeclaration of 'extern' variable '%D' in 'for' loop "
+ "initial declaration", decl, decl);
+ break;
+
+ case RECORD_TYPE:
+ error ("'struct %E' declared in 'for' loop initial declaration", id);
+ break;
+ case UNION_TYPE:
+ error ("'union %E' declared in 'for' loop initial declaration", id);
+ break;
+ case ENUMERAL_TYPE:
+ error ("'enum %E' declared in 'for' loop initial declaration", id);
+ break;
+ default:
+ error ("%Jdeclaration of non-variable '%D' in 'for' loop "
+ "initial declaration", decl, decl);
+ }
}
}
\f
-/* Save and restore the variables in this file and elsewhere
- that keep track of the progress of compilation of the current function.
- Used for nested functions. */
-
-struct language_function GTY(())
-{
- struct c_language_function base;
- int returns_value;
- int returns_null;
- int returns_abnormally;
- int warn_about_return_type;
- int extern_inline;
-};
-
/* Save and reinitialize the variables
used during compilation of a C function. */
f->language = p;
p->base.x_stmt_tree = c_stmt_tree;
- p->base.x_scope_stmt_stack = c_scope_stmt_stack;
+ p->x_break_label = c_break_label;
+ p->x_cont_label = c_cont_label;
+ p->x_switch_stack = c_switch_stack;
p->returns_value = current_function_returns_value;
p->returns_null = current_function_returns_null;
p->returns_abnormally = current_function_returns_abnormally;
{
struct language_function *p = f->language;
- if (DECL_SAVED_INSNS (current_function_decl) == 0
+ if (DECL_STRUCT_FUNCTION (current_function_decl) == 0
&& DECL_SAVED_TREE (current_function_decl) == NULL_TREE)
{
/* Stop pointing to the local nodes about to be freed. */
}
c_stmt_tree = p->base.x_stmt_tree;
- c_scope_stmt_stack = p->base.x_scope_stmt_stack;
+ c_break_label = p->x_break_label;
+ c_cont_label = p->x_cont_label;
+ c_switch_stack = p->x_switch_stack;
current_function_returns_value = p->returns_value;
current_function_returns_null = p->returns_null;
current_function_returns_abnormally = p->returns_abnormally;
return &c_stmt_tree;
}
-/* Returns the stack of SCOPE_STMTs for the current function. */
-
-tree *
-current_scope_stmt_stack (void)
-{
- return &c_scope_stmt_stack;
-}
-
/* Nonzero if TYPE is an anonymous union or struct type. Always 0 in
C. */
{
}
-/* Return a new COMPOUND_STMT, after adding it to the current
- statement tree. */
-
-tree
-c_begin_compound_stmt (void)
-{
- tree stmt;
-
- /* Create the COMPOUND_STMT. */
- stmt = add_stmt (build_stmt (COMPOUND_STMT, NULL_TREE));
-
- return stmt;
-}
-
-/* Expand T (a DECL_STMT) if it declares an entity not handled by the
- common code. */
-
-void
-c_expand_decl_stmt (tree t)
-{
- tree decl = DECL_STMT_DECL (t);
-
- /* Expand nested functions. */
- if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_CONTEXT (decl) == current_function_decl
- && DECL_SAVED_TREE (decl))
- c_expand_body_1 (decl, 1);
-}
-
/* Return the global value of T as a symbol. */
tree
identifier_global_value (tree t)
{
- tree decl = IDENTIFIER_SYMBOL_VALUE (t);
- if (decl == 0 || DECL_FILE_SCOPE_P (decl))
- return decl;
+ struct c_binding *b;
- /* Shadowed by something else; find the true global value. */
- for (decl = global_scope->names; decl; decl = TREE_CHAIN (decl))
- if (DECL_NAME (decl) == t)
- return decl;
+ for (b = I_SYMBOL_BINDING (t); b; b = b->shadowed)
+ if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b))
+ return b->decl;
- /* Only local values for this decl. */
return 0;
}
return build1 (INDIRECT_REF, quals, itarget);
}
-/* A wrapper around lhd_set_decl_assembler_name that gives static
- variables their C names if they are at file scope and only one
- translation unit is being compiled, for backwards compatibility
- with certain bizarre assembler hacks (like crtstuff.c). */
-
-void
-c_static_assembler_name (tree decl)
+/* Synthesize a function which calls all the global ctors or global
+ dtors in this file. This is only used for targets which do not
+ support .ctors/.dtors sections. FIXME: Migrate into cgraph. */
+static void
+build_cdtor (int method_type, tree cdtors)
{
- if (num_in_fnames == 1
- && !TREE_PUBLIC (decl) && DECL_CONTEXT (decl)
- && TREE_CODE (DECL_CONTEXT (decl)) == TRANSLATION_UNIT_DECL)
- SET_DECL_ASSEMBLER_NAME (decl, DECL_NAME (decl));
- else
- lhd_set_decl_assembler_name (decl);
-}
+ tree body = 0;
-/* Hash and equality functions for link_hash_table: key off
- DECL_ASSEMBLER_NAME. */
+ if (!cdtors)
+ return;
-static hashval_t
-link_hash_hash (const void *x_p)
-{
- tree x = (tree)x_p;
- return (hashval_t) (long)DECL_ASSEMBLER_NAME (x);
-}
+ for (; cdtors; cdtors = TREE_CHAIN (cdtors))
+ append_to_statement_list (build_function_call (TREE_VALUE (cdtors), 0),
+ &body);
-static int
-link_hash_eq (const void *x1_p, const void *x2_p)
-{
- tree x1 = (tree)x1_p;
- tree x2 = (tree)x2_p;
- return DECL_ASSEMBLER_NAME (x1) == DECL_ASSEMBLER_NAME (x2);
+ cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
}
-/* Propagate information between definitions and uses between multiple
- translation units in TU_LIST based on linkage rules. */
-
-void
-merge_translation_unit_decls (void)
+/* Perform final processing on one file scope's declarations (or the
+ external scope's declarations), GLOBALS. */
+static void
+c_write_global_declarations_1 (tree globals)
{
- const tree tu_list = current_file_decl;
- tree tu;
+ size_t len = list_length (globals);
+ tree *vec = xmalloc (sizeof (tree) * len);
+ size_t i;
tree decl;
- htab_t link_hash_table;
- tree block;
-
- /* Create the BLOCK that poplevel would have created, but don't
- actually call poplevel since that's expensive. */
- block = make_node (BLOCK);
- BLOCK_VARS (block) = current_scope->names;
- TREE_USED (block) = 1;
- DECL_INITIAL (current_file_decl) = block;
- /* If only one translation unit seen, no copying necessary. */
- if (TREE_CHAIN (tu_list) == NULL_TREE)
- return;
-
- link_hash_table = htab_create (1021, link_hash_hash, link_hash_eq, NULL);
-
- /* Enter any actual definitions into the hash table. */
- for (tu = tu_list; tu; tu = TREE_CHAIN (tu))
- for (decl = BLOCK_VARS (DECL_INITIAL (tu)); decl; decl = TREE_CHAIN (decl))
- if (TREE_PUBLIC (decl) && ! DECL_EXTERNAL (decl))
- {
- PTR *slot;
- slot = htab_find_slot (link_hash_table, decl, INSERT);
-
- /* If we've already got a definition, work out which one is
- the real one, put it into the hash table, and make the
- other one DECL_EXTERNAL. This is important to avoid
- putting out two definitions of the same symbol in the
- assembly output. */
- if (*slot != NULL)
- {
- tree old_decl = (tree) *slot;
-
- /* If this is weak or common or whatever, suppress it
- in favor of the other definition. */
- if (DECL_WEAK (decl))
- DECL_EXTERNAL (decl) = 1;
- else if (DECL_WEAK (old_decl) && ! DECL_WEAK (decl))
- DECL_EXTERNAL (old_decl) = 1;
- else if (DECL_COMMON (decl) || DECL_ONE_ONLY (decl))
- DECL_EXTERNAL (decl) = 1;
- else if (DECL_COMMON (old_decl) || DECL_ONE_ONLY (old_decl))
- DECL_EXTERNAL (old_decl) = 1;
-
- if (DECL_EXTERNAL (decl))
- {
- DECL_INITIAL (decl) = NULL_TREE;
- DECL_COMMON (decl) = 0;
- DECL_ONE_ONLY (decl) = 0;
- DECL_WEAK (decl) = 0;
- }
- else if (DECL_EXTERNAL (old_decl))
- {
- DECL_INITIAL (old_decl) = NULL_TREE;
- DECL_COMMON (old_decl) = 0;
- DECL_ONE_ONLY (old_decl) = 0;
- DECL_WEAK (old_decl) = 0;
- *slot = decl;
- }
- else
- {
- error ("%Jredefinition of global '%D'", decl, decl);
- error ("%J'%D' previously defined here", old_decl, old_decl);
- }
- }
- else
- *slot = decl;
- }
+ /* Process the decls in the order they were written. */
+ for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
+ vec[i] = decl;
- /* Now insert the desired information from all the definitions
- into any plain declarations. */
- for (tu = tu_list; tu; tu = TREE_CHAIN (tu))
- for (decl = BLOCK_VARS (DECL_INITIAL (tu)); decl; decl = TREE_CHAIN (decl))
- if (TREE_PUBLIC (decl) && DECL_EXTERNAL (decl))
- {
- tree global_decl;
- global_decl = htab_find (link_hash_table, decl);
-
- if (! global_decl)
- continue;
-
- /* Print any appropriate error messages, and partially merge
- the decls. */
- (void) duplicate_decls (decl, global_decl, true, true);
- }
+ wrapup_global_declarations (vec, len);
+ check_global_declarations (vec, len);
- htab_delete (link_hash_table);
+ free (vec);
}
-/* Perform final processing on file-scope data. */
-
void
-c_write_global_declarations(void)
+c_write_global_declarations (void)
{
- tree link;
-
- for (link = current_file_decl; link; link = TREE_CHAIN (link))
- {
- tree globals = BLOCK_VARS (DECL_INITIAL (link));
- int len = list_length (globals);
- tree *vec = xmalloc (sizeof (tree) * len);
- int i;
- tree decl;
-
- /* Process the decls in the order they were written. */
-
- for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
- vec[i] = decl;
-
- wrapup_global_declarations (vec, len);
-
- check_global_declarations (vec, len);
-
- /* Clean up. */
- free (vec);
- }
-}
+ tree ext_block, t;
-/* Reset the parser's state in preparation for a new file. */
+ /* We don't want to do this if generating a PCH. */
+ if (pch_file)
+ return;
-void
-c_reset_state (void)
-{
- tree link;
- tree file_scope_decl;
-
- /* Pop the global scope. */
- if (current_scope != global_scope)
- current_scope = global_scope;
- file_scope_decl = current_file_decl;
- DECL_INITIAL (file_scope_decl) = poplevel (1, 0, 0);
- BLOCK_SUPERCONTEXT (DECL_INITIAL (file_scope_decl)) = file_scope_decl;
- truly_local_externals = NULL_TREE;
-
- /* Start a new global binding level. */
- pushlevel (0);
- global_scope = current_scope;
- current_file_decl = build_decl (TRANSLATION_UNIT_DECL, NULL, NULL);
- TREE_CHAIN (current_file_decl) = file_scope_decl;
-
- /* Reintroduce the builtin declarations. */
- for (link = first_builtin_decl;
- link != TREE_CHAIN (last_builtin_decl);
- link = TREE_CHAIN (link))
- pushdecl (copy_node (link));
+ /* Don't waste time on further processing if -fsyntax-only or we've
+ encountered errors. */
+ if (flag_syntax_only || errorcount || sorrycount || cpp_errors (parse_in))
+ return;
+
+ /* Close the external scope. */
+ ext_block = pop_scope ();
+ external_scope = 0;
+ if (current_scope)
+ abort ();
+
+ /* Process all file scopes in this compilation, and the external_scope,
+ through wrapup_global_declarations and check_global_declarations. */
+ for (t = all_translation_units; t; t = TREE_CHAIN (t))
+ c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
+ c_write_global_declarations_1 (BLOCK_VARS (ext_block));
+
+ /* Generate functions to call static constructors and destructors
+ for targets that do not support .ctors/.dtors sections. These
+ functions have magic names which are detected by collect2. */
+ build_cdtor ('I', static_ctors); static_ctors = 0;
+ build_cdtor ('D', static_dtors); static_dtors = 0;
+
+ /* We're done parsing; proceed to optimize and emit assembly.
+ FIXME: shouldn't be the front end's responsibility to call this. */
+ cgraph_optimize ();
+
+ /* Presently this has to happen after cgraph_optimize.
+ FIXME: shouldn't be the front end's responsibility to call this. */
+ if (flag_mudflap)
+ mudflap_finish_file ();
}
#include "gt-c-decl.h"