diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b156338b9ad..25ecc061659 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,108 @@ +2003-04-10 Zack Weinberg + + * c-decl.c (struct binding_level): Add shadowed_tags and + function_body; remove this_block, tag_transparent, and + subblocks_tag_transparent; update comments. + (clear_binding_level, lookup_tag_reverse): Kill. + (make_binding_level): Use ggc_alloc_cleared or memset. + (lookup_tag): Remove struct binding_level* parameter. All + callers changed. Just look at IDENTIFIER_TAG_VALUE, and + current_binding_level->tags if asked for thislevel_only or if + we might have to diagnose "struct foo; union foo;" + (pushlevel): Ignore argument. Do not push another binding + level on the transition from the parameters to the top level + of the function body; just tweak the flags and proceed. + (poplevel): Overhaul. Clear IDENTIFIER_TAG_VALUEs; on exiting + a function body, separate the parameter list from the + top-level local variables. + (set_block): Do nothing. + (pushtag): Set IDENTIFIER_TAG_VALUE and add an entry to + shadowed_tags if necessary. + (warn_if_shadowing): Nuke the special case for local shadowing + parameter. + (pushdecl): Do not create a shadow entry if we are replacing + an older decl in the same binding level. + (pushdecl_function_level): Tweak for new way of indicating + function scope. + (shadow_tag_warned): Use TYPE_NAME, not lookup_tag_reverse. + (start_function): Don't set subblocks_tag_transparent. + (finish_function): Fix up the binding_level stack for totally + empty functions. Otherwise, don't call poplevel. + + * c-common.c (shadow_warning): MANDATORY argument is no longer + necessary. Always use plain warning. + * c-common.h: Update to match. + + * cfglayout.c (scope_to_insns_initialize): Clear block when we + hit the FUNCTION_DECL. + * function.c: Do not create cyclic tree structure. + +2003-04-10 Zack Weinberg + + * c-tree.h (struct lang_identifier): Replace global_value, + local_value members with symbol_value, tag_value. Kill + implicit_decl and limbo_value. + (IDENTIFIER_GLOBAL_VALUE, IDENTIFIER_LOCAL_VALUE, + IDENTIFIER_LIMBO_VALUE, IDENTIFIER_IMPLICIT_DECL, + C_MISSING_PROTOTYPE_WARNED): Kill. + (IDENTIFIER_SYMBOL_VALUE, IDENTIFIER_TAG_VALUE, + C_DECL_IMPLICIT, C_DECL_ISNT_PROTOTYPE): New. + (C_DECL_ANTICIPATED): Rename to C_DECL_INVISIBLE. + (implicit_decl_warning, lookup_name_current_level, + record_function_scope_shadow): Don't prototype. + (pushdecl_function_level): Prototype. + + * c-decl.c (truly_local_externals): New variable. + (struct binding_level): Adjust commentary. + (get_function_binding_level, clear_limbo_values, + record_function_scope_shadow): Kill. + (lookup_name_current_level, implicit_decl_warning): Are now static. + (any_external_decl, record_external_decl): New static functions. + (clone_underlying type): Split out of pushdecl. + (c_print_identifier): Update to match changes to struct + lang_identifier. + (poplevel): Delete #if 0 block. Make externals invisible + instead of clearing their IDENTIFIER_SYMBOL_VALUEs. Don't + call clear_limbo_values. Refer to IDENTIFIER_SYMBOL_VALUE not + IDENTIFIER_GLOBAL_VALUE or IDENTIFIER_LOCAL_VALUE. + (duplicate-decls): For real parm decl after a forward decl, + set TREE_ASM_WRITTEN here. Allow void foo(...) followed by + foo(...) { } with only a warning. Say whether a previous + declaration was implicit. + (warn_if_shadowing): Now handles all shadowing, not just + local-over-local. Clarify comments. + (pushdecl): Rewritten. There is no longer a distinction + between global and local symbol values; they're all + IDENTIFIER_SYMBOL_VALUE. Call record_external_decl on all + DECL_EXTERNAL decls, and use any_external_decl to check + against previous externals. Kill #if 0 blocks. Don't + tolerate error_mark_node being NULL. + (pushdecl_top_level): Handle only those cases which + Objective C (the only user) needs. + (pushdecl_function_level): New function. + (implicitly_declare): Create ordinary decls with + C_DECL_IMPLICIT set. Recycle old decls, however they got + created. + (lookup_name): It's always IDENTIFIER_SYMBOL_VALUE. Return 0 + for C_DECL_INVISIBLE symbols. + (lookup_name_current_level): Likewise. Use chain_member. + (c_make_fname_decl): Don't muck with DECL_CONTEXT. + Use pushdecl_function_level. + (builtin_function): Use C_DECL_INVISIBLE. + (start_function): Don't muck with IDENTIFIER_IMPLICIT_DECL. + Use C_DECL_ISNT_PROTOTYPE and C_DECL_IMPLICIT. + (store_parm_decls): It's IDENTIFIER_SYMBOL_VALUE now. + (identifier_global_value): Same. Must scan + global_binding_level in extremis. + + * c-typeck.c (undeclared_variable): New static function, split + from build_external_ref. + (build_external_ref): Use DECL_CONTEXT, not + IDENTIFIER_LOCAL_VALUE, to decide whether a local hides + an instance variable. Restructure for clarity. + * objc/objc-act.c: Use identifier_global_value, not + IDENTIFIER_GLOBAL_VALUE. + 2003-04-08 Jonathan Wakely * doc/extend.texi (Template Instantiation): Refer to ISO standard, diff --git a/gcc/c-common.c b/gcc/c-common.c index 7048d9a6100..a2cad233927 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -4778,12 +4778,10 @@ c_common_insert_default_attributes (decl) } /* Output a -Wshadow warning MSGCODE about NAME, and give the location - of the previous declaration DECL. MANDATORY says whether this is a - mandatory warning (i.e. use pedwarn). */ + of the previous declaration DECL. */ void -shadow_warning (msgcode, mandatory, name, decl) +shadow_warning (msgcode, name, decl) enum sw_kind msgcode; - int mandatory; /* really bool */ const char *name; tree decl; { @@ -4793,7 +4791,7 @@ shadow_warning (msgcode, mandatory, name, decl) /* SW_GLOBAL */ N_("declaration of \"%s\" shadows a global declaration") }; - (mandatory ? pedwarn : warning) (msgs[msgcode], name); + warning (msgs[msgcode], name); warning_with_file_and_line (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl), "shadowed declaration is here"); diff --git a/gcc/c-common.h b/gcc/c-common.h index ed67ce6f7d4..432b351da50 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -335,7 +335,7 @@ extern tree c_begin_while_stmt PARAMS ((void)); extern void c_finish_while_stmt_cond PARAMS ((tree, tree)); enum sw_kind { SW_PARAM = 0, SW_LOCAL, SW_GLOBAL }; -extern void shadow_warning PARAMS ((enum sw_kind, int, +extern void shadow_warning PARAMS ((enum sw_kind, const char *, tree)); /* Extra information associated with a DECL. Other C dialects extend diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 200730801e7..4b2e6e13c8a 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -1,6 +1,6 @@ /* Process declarations and variables for C compiler. Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002 Free Software Foundation, Inc. + 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -122,6 +122,10 @@ static GTY(()) tree named_labels; static GTY(()) tree shadowed_labels; +/* A list of external DECLs that appeared at block scope when there was + some other global meaning for that identifier. */ +static GTY(()) tree truly_local_externals; + /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ @@ -159,9 +163,6 @@ static int current_extern_inline; * the current one out to the global one. */ -/* Note that the information in the `names' component of the global contour - is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */ - struct binding_level GTY(()) { /* A chain of _DECL nodes for all variables, constants, functions, @@ -177,35 +178,34 @@ struct binding_level GTY(()) */ tree tags; - /* For each level, a list of shadowed outer-level local definitions + /* For each level, a list of shadowed outer-level definitions to be restored when this level is popped. Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and whose TREE_VALUE is its old definition (a kind of ..._DECL node). */ tree shadowed; + /* For each level, a list of shadowed outer-level tag definitions + to be restored when this level is popped. + Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and + whose TREE_VALUE is its old definition (a kind of ..._TYPE node). */ + tree shadowed_tags; + /* For each level (except not the global one), a chain of BLOCK nodes for all the levels that were entered and exited one level down. */ tree blocks; - /* The BLOCK node for this level, if one has been preallocated. - If 0, the BLOCK is allocated (if needed) when the level is popped. */ - tree this_block; - /* The binding level which this one is contained in (inherits from). */ struct binding_level *level_chain; - /* Nonzero for the level that holds the parameters of a function. */ + /* Nonzero if we are currently filling this level with parameter + declarations. */ char parm_flag; - /* Nonzero if this level "doesn't exist" for tags. */ - char tag_transparent; - - /* Nonzero if sublevels of this level "don't exist" for tags. - This is set in the parm level of a function definition - while reading the function body, so that the outermost block - of the function body will be tag-transparent. */ - char subblocks_tag_transparent; + /* Nonzero if this is the outermost block scope of a function body. + This scope contains both the parameters and the local variables + declared in the outermost block. */ + char function_body; /* Nonzero means make a BLOCK for this level regardless of all else. */ char keep; @@ -239,12 +239,6 @@ static GTY((deletable (""))) struct binding_level *free_binding_level; static GTY(()) struct binding_level *global_binding_level; -/* Binding level structures are initialized by copying this one. */ - -static struct binding_level clear_binding_level - = {NULL, NULL, NULL, NULL, NULL, NULL_BINDING_LEVEL, 0, 0, 0, 0, 0, NULL, - NULL}; - /* Nonzero means unconditionally make a BLOCK for the next level pushed. */ static int keep_next_level_flag; @@ -269,23 +263,24 @@ tree static_ctors, static_dtors; /* Forward declarations. */ static struct binding_level *make_binding_level PARAMS ((void)); -static struct binding_level *get_function_binding_level PARAMS ((void)); static void pop_binding_level PARAMS ((struct binding_level **)); -static void clear_limbo_values PARAMS ((tree)); static int duplicate_decls PARAMS ((tree, tree, int)); static int redeclaration_error_message PARAMS ((tree, tree)); +static void implicit_decl_warning PARAMS ((tree)); static void storedecls PARAMS ((tree)); static void storetags PARAMS ((tree)); -static tree lookup_tag PARAMS ((enum tree_code, tree, - struct binding_level *, int)); -static tree lookup_tag_reverse PARAMS ((tree)); +static tree lookup_tag PARAMS ((enum tree_code, tree, int)); +static tree lookup_name_current_level PARAMS ((tree)); static tree grokdeclarator PARAMS ((tree, tree, enum decl_context, int)); static tree grokparms PARAMS ((tree, int)); static void layout_array_type PARAMS ((tree)); static tree c_make_fname_decl PARAMS ((tree, int)); static void c_expand_body_1 PARAMS ((tree, int)); +static tree any_external_decl PARAMS ((tree)); +static void record_external_decl PARAMS ((tree)); static void warn_if_shadowing PARAMS ((tree, tree)); +static void clone_underlying_type PARAMS ((tree)); static bool flexible_array_type_p PARAMS ((tree)); /* States indicating how grokdeclarator() should handle declspecs marked @@ -306,11 +301,9 @@ c_print_identifier (file, node, indent) tree node; int indent; { - print_node (file, "global", IDENTIFIER_GLOBAL_VALUE (node), indent + 4); - print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4); + print_node (file, "symbol", IDENTIFIER_SYMBOL_VALUE (node), indent + 4); + print_node (file, "tag", IDENTIFIER_TAG_VALUE (node), indent + 4); print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4); - print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4); - print_node (file, "limbo value", IDENTIFIER_LIMBO_VALUE (node), indent + 4); if (C_IS_RESERVED_WORD (node)) { tree rid = ridpointers[C_RID_CODE (node)]; @@ -350,25 +343,18 @@ c_finish_incomplete_decl (decl) static struct binding_level * make_binding_level () { + struct binding_level *result; if (free_binding_level) { - struct binding_level *result = free_binding_level; + result = free_binding_level; free_binding_level = result->level_chain; - return result; + memset (result, 0, sizeof(struct binding_level)); } else - return (struct binding_level *) ggc_alloc (sizeof (struct binding_level)); -} + result = (struct binding_level *) + ggc_alloc_cleared (sizeof (struct binding_level)); -/* Return the outermost binding level for the current function. */ -static struct binding_level * -get_function_binding_level () -{ - struct binding_level *b = current_binding_level; - - while (b->level_chain->parm_flag == 0) - b = b->level_chain; - return b; + return result; } /* Remove a binding level from a list and add it to the level chain. */ @@ -408,8 +394,7 @@ kept_level_p () && current_binding_level->blocks != 0) || current_binding_level->keep || current_binding_level->names != 0 - || (current_binding_level->tags != 0 - && !current_binding_level->tag_transparent)); + || current_binding_level->tags != 0); } /* Identify this binding level as a level of parameters. @@ -432,57 +417,45 @@ in_parm_level_p () return current_binding_level->parm_flag; } -/* Enter a new binding level. - If TAG_TRANSPARENT is nonzero, do so only for the name space of variables, - not for that of tags. */ +/* Enter a new binding level. */ void -pushlevel (tag_transparent) - int tag_transparent; +pushlevel (dummy) + int dummy ATTRIBUTE_UNUSED; { - struct binding_level *newlevel = NULL_BINDING_LEVEL; - - /* If this is the top level of a function, - just make sure that NAMED_LABELS is 0. */ + /* If this is the top level of a function, make sure that + NAMED_LABELS is 0. */ if (current_binding_level == global_binding_level) + named_labels = 0; + + if (keep_next_if_subblocks) { - named_labels = 0; + /* This is the transition from the parameters to the top level + of the function body. These are the same scope + (C99 6.2.1p4,6) so we do not push another binding level. + + XXX Note kludge - keep_next_if_subblocks is set only by + store_parm_decls, which in turn is called when and only + when we are about to encounter the opening curly brace for + the function body. */ + current_binding_level->parm_flag = 0; + current_binding_level->function_body = 1; + current_binding_level->keep |= keep_next_level_flag; + current_binding_level->keep_if_subblocks = 1; + + keep_next_level_flag = 0; + keep_next_if_subblocks = 0; } + else + { + struct binding_level *newlevel = make_binding_level (); - newlevel = make_binding_level (); - - /* Add this level to the front of the chain (stack) of levels that - are active. */ - - *newlevel = clear_binding_level; - newlevel->tag_transparent - = (tag_transparent - || (current_binding_level - ? current_binding_level->subblocks_tag_transparent - : 0)); - newlevel->level_chain = current_binding_level; - current_binding_level = newlevel; - newlevel->keep = keep_next_level_flag; - keep_next_level_flag = 0; - newlevel->keep_if_subblocks = keep_next_if_subblocks; - keep_next_if_subblocks = 0; -} - -/* Clear the limbo values of all identifiers defined in BLOCK or a subblock. */ - -static void -clear_limbo_values (block) - tree block; -{ - tree tem; - - for (tem = BLOCK_VARS (block); tem; tem = TREE_CHAIN (tem)) - if (DECL_NAME (tem) != 0) - IDENTIFIER_LIMBO_VALUE (DECL_NAME (tem)) = 0; - - for (tem = BLOCK_SUBBLOCKS (block); tem; tem = TREE_CHAIN (tem)) - clear_limbo_values (tem); + newlevel->keep = keep_next_level_flag; + newlevel->level_chain = current_binding_level; + current_binding_level = newlevel; + keep_next_level_flag = 0; + } } /* Exit a binding level. @@ -507,95 +480,103 @@ poplevel (keep, reverse, functionbody) int functionbody; { tree link; - /* The chain of decls was accumulated in reverse order. - Put it into forward order, just for cleanliness. */ - tree decls; + tree block; + tree decl; + tree decls = current_binding_level->names; tree tags = current_binding_level->tags; tree subblocks = current_binding_level->blocks; - tree block = 0; - tree decl; - int block_previously_created; - keep |= current_binding_level->keep; + functionbody |= current_binding_level->function_body; + keep |= (current_binding_level->keep || functionbody + || (current_binding_level->keep_if_subblocks && subblocks != 0)); - /* This warning is turned off because it causes warnings for - declarations like `extern struct foo *x'. */ -#if 0 - /* Warn about incomplete structure types in this level. */ + /* We used to warn about unused variables in expand_end_bindings, + i.e. while generating RTL. But in function-at-a-time mode we may + choose to never expand a function at all (e.g. auto inlining), so + we do this explicitly now. */ + warn_about_unused_variables (decls); + + /* Clear out the name-meanings declared on this level. + Propagate TREE_ADDRESSABLE from nested functions to their + containing functions. */ + for (link = decls; link; link = TREE_CHAIN (link)) + { + if (DECL_NAME (link) != 0) + { + if (DECL_EXTERNAL (link)) + /* External decls stay in the symbol-value slot but are + inaccessible. */ + C_DECL_INVISIBLE (link) = 1; + else + IDENTIFIER_SYMBOL_VALUE (DECL_NAME (link)) = 0; + } + + if (TREE_CODE (link) == FUNCTION_DECL + && ! TREE_ASM_WRITTEN (link) + && DECL_INITIAL (link) != 0 + && TREE_ADDRESSABLE (link) + && DECL_ABSTRACT_ORIGIN (link) != 0 + && DECL_ABSTRACT_ORIGIN (link) != link) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (link)) = 1; + } + + /* Clear out the tag-meanings declared on this level. */ for (link = tags; link; link = TREE_CHAIN (link)) - if (!COMPLETE_TYPE_P (TREE_VALUE (link))) - { - tree type = TREE_VALUE (link); - tree type_name = TYPE_NAME (type); - char *id = IDENTIFIER_POINTER (TREE_CODE (type_name) == IDENTIFIER_NODE - ? type_name - : DECL_NAME (type_name)); - switch (TREE_CODE (type)) - { - case RECORD_TYPE: - error ("`struct %s' incomplete in scope ending here", id); - break; - case UNION_TYPE: - error ("`union %s' incomplete in scope ending here", id); - break; - case ENUMERAL_TYPE: - error ("`enum %s' incomplete in scope ending here", id); - break; - } - } -#endif /* 0 */ + if (TREE_PURPOSE (link)) + IDENTIFIER_TAG_VALUE (TREE_PURPOSE (link)) = 0; + + /* Restore all name-meanings of the outer levels + that were shadowed by this level. */ + + for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) + IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + + /* Restore all tag-meanings of the outer levels + that were shadowed by this level. */ + + for (link = current_binding_level->shadowed_tags; link; + link = TREE_CHAIN (link)) + IDENTIFIER_TAG_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + + /* If this is the top level block of a function, remove all + PARM_DECLs from current_binding_level->names; they are already + stored in DECL_ARGUMENTS of cfun->decl in proper order, should + not be put in BLOCK_VARS, and furthermore reversing them will + cause trouble later. They are all together at the end of the + list. */ + if (functionbody && decls) + { + if (TREE_CODE (decls) == PARM_DECL) + decls = 0; + else + { + link = decls; + while (TREE_CHAIN (link) + && TREE_CODE (TREE_CHAIN (link)) != PARM_DECL) + link = TREE_CHAIN (link); + + TREE_CHAIN (link) = 0; + } + } /* Get the decls in the order they were written. Usually current_binding_level->names is in reverse order. But parameter decls were previously put in forward order. */ if (reverse) - current_binding_level->names - = decls = nreverse (current_binding_level->names); - else - decls = current_binding_level->names; - - /* Output any nested inline functions within this block - if they weren't already output. */ - - for (decl = decls; decl; decl = TREE_CHAIN (decl)) - if (TREE_CODE (decl) == FUNCTION_DECL - && ! TREE_ASM_WRITTEN (decl) - && DECL_INITIAL (decl) != 0 - && TREE_ADDRESSABLE (decl)) - { - /* If this decl was copied from a file-scope decl - on account of a block-scope extern decl, - propagate TREE_ADDRESSABLE to the file-scope decl. - - DECL_ABSTRACT_ORIGIN can be set to itself if warn_return_type is - true, since then the decl goes through save_for_inline_copying. */ - if (DECL_ABSTRACT_ORIGIN (decl) != 0 - && DECL_ABSTRACT_ORIGIN (decl) != decl) - TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; - } - - /* We used to warn about unused variables in expand_end_bindings, - i.e. while generating RTL. But in function-at-a-time mode we may - choose to never expand a function at all (e.g. auto inlining), so - we do this explicitly now. */ - warn_about_unused_variables (getdecls ()); + decls = nreverse (decls); /* If there were any declarations or structure tags in that level, or if this level is a function body, create a BLOCK to record them for the life of this function. */ block = 0; - block_previously_created = (current_binding_level->this_block != 0); - if (block_previously_created) - block = current_binding_level->this_block; - else if (keep || functionbody - || (current_binding_level->keep_if_subblocks && subblocks != 0)) - block = make_node (BLOCK); - if (block != 0) + if (keep) { + block = make_node (BLOCK); BLOCK_VARS (block) = decls; BLOCK_SUBBLOCKS (block) = subblocks; + TREE_USED (block) = 1; } /* In each subblock, record that this is its superior. */ @@ -603,50 +584,31 @@ poplevel (keep, reverse, functionbody) for (link = subblocks; link; link = TREE_CHAIN (link)) BLOCK_SUPERCONTEXT (link) = block; - /* Clear out the meanings of the local variables of this level. */ + /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this + binding contour so that they point to the appropriate construct, i.e. + either to the current FUNCTION_DECL node, or else to the BLOCK node + we just constructed. - for (link = decls; link; link = TREE_CHAIN (link)) - { - if (DECL_NAME (link) != 0) - { - /* If the ident. was used or addressed via a local extern decl, - don't forget that fact. */ - if (DECL_EXTERNAL (link)) - { - if (TREE_USED (link)) - TREE_USED (DECL_NAME (link)) = 1; - if (TREE_ADDRESSABLE (link)) - TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1; - } - IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0; - } - } + 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. */ - /* Restore all name-meanings of the outer levels - that were shadowed by this level. */ + decl = functionbody ? current_function_decl : block; + if (decl) + for (link = tags; link; link = TREE_CHAIN (link)) + TYPE_CONTEXT (TREE_VALUE (link)) = decl; - for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) - IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); - - /* If the level being exited is the top level of a function, - check over all the labels, and clear out the current - (function local) meanings of their names. */ + /* If the level being exited is the top level of a function, check + over all the labels, and clear out the current (function local) + meanings of their names. Then add them to BLOCK_VARS. */ if (functionbody) { - clear_limbo_values (block); - - /* If this is the top level block of a function, - the vars are the function's parameters. - Don't leave them in the BLOCK because they are - found in the FUNCTION_DECL instead. */ - - BLOCK_VARS (block) = 0; - - /* Clear out the definitions of all label names, - since their scopes end here, - and add them to BLOCK_VARS. */ - for (link = named_labels; link; link = TREE_CHAIN (link)) { tree label = TREE_VALUE (link); @@ -677,11 +639,8 @@ poplevel (keep, reverse, functionbody) if (functionbody) DECL_INITIAL (current_function_decl) = block; else if (block) - { - if (!block_previously_created) - current_binding_level->blocks - = chainon (current_binding_level->blocks, block); - } + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); /* If we did not make a block for the level just exited, any blocks made for inner levels (since they cannot be recorded as subblocks in that level) @@ -691,30 +650,6 @@ poplevel (keep, reverse, functionbody) current_binding_level->blocks = chainon (current_binding_level->blocks, subblocks); - /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this - binding contour so that they point to the appropriate construct, i.e. - either to the current FUNCTION_DECL node, or else to the BLOCK node - we just constructed. - - Note that for tagged types whose scope is just the formal parameter - list for some function type specification, we can't properly set - their TYPE_CONTEXTs here, because we don't have a pointer to the - appropriate FUNCTION_TYPE node readily available to us. For those - cases, the TYPE_CONTEXTs of the relevant tagged type nodes get set - in `grokdeclarator' as soon as we have created the FUNCTION_TYPE - node which will represent the "scope" for these "parameter list local" - tagged types. */ - - if (functionbody) - for (link = tags; link; link = TREE_CHAIN (link)) - TYPE_CONTEXT (TREE_VALUE (link)) = current_function_decl; - else if (block) - for (link = tags; link; link = TREE_CHAIN (link)) - TYPE_CONTEXT (TREE_VALUE (link)) = block; - - if (block) - TREE_USED (block) = 1; - return block; } @@ -731,18 +666,14 @@ insert_block (block) = chainon (current_binding_level->blocks, block); } -/* Set the BLOCK node for the innermost scope - (the one we are currently in). */ +/* Set the BLOCK node for the innermost scope (the one we are + currently in). The RTL expansion machinery requires us to provide + this hook, but it is not useful in function-at-a-time mode. */ void set_block (block) - tree block; + tree block ATTRIBUTE_UNUSED; { - current_binding_level->this_block = block; - current_binding_level->names = chainon (current_binding_level->names, - BLOCK_VARS (block)); - current_binding_level->blocks = chainon (current_binding_level->blocks, - BLOCK_SUBBLOCKS (block)); } void @@ -826,12 +757,7 @@ void pushtag (name, type) tree name, type; { - struct binding_level *b; - - /* Find the proper binding level for this type tag. */ - - for (b = current_binding_level; b->tag_transparent; b = b->level_chain) - continue; + struct binding_level *b = current_binding_level; if (name) { @@ -839,6 +765,11 @@ pushtag (name, type) 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); @@ -966,11 +897,14 @@ duplicate_decls (newdecl, olddecl, different_binding_level) return 0; } - /* For real parm decl following a forward decl, - return 1 so old decl will be reused. */ + /* For real parm decl following a forward decl, return 1 so old decl + will be reused. Only allow this to happen once. */ if (types_match && TREE_CODE (newdecl) == PARM_DECL && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl)) - return 1; + { + TREE_ASM_WRITTEN (olddecl) = 0; + return 1; + } /* The new declaration is the same kind of object as the old one. The declarations may partially match. Print warnings if they don't @@ -1107,6 +1041,20 @@ duplicate_decls (newdecl, olddecl, different_binding_level) we will come back here again. */ DECL_IN_SYSTEM_HEADER (newdecl) = 1; } + /* Permit void foo (...) to match int foo (...) if the latter is the + definition and implicit int was used. See c-torture/compile/920625-2.c. */ + else if (!types_match && new_is_definition + && TREE_CODE (olddecl) == FUNCTION_DECL + && TREE_CODE (newdecl) == FUNCTION_DECL + && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node + && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node + && C_FUNCTION_IMPLICIT_INT (newdecl)) + { + pedwarn_with_decl (newdecl, "conflicting types for `%s'"); + /* Make sure we keep void as the return type. */ + TREE_TYPE (newdecl) = newtype = oldtype; + C_FUNCTION_IMPLICIT_INT (newdecl) = 0; + } else if (!types_match /* Permit char *foo (int, ...); followed by char *foo (); if not pedantic. */ @@ -1151,7 +1099,10 @@ duplicate_decls (newdecl, olddecl, different_binding_level) } } } - error_with_decl (olddecl, "previous declaration of `%s'"); + if (C_DECL_IMPLICIT (olddecl)) + error_with_decl (olddecl, "previous implicit declaration of `%s'"); + else + error_with_decl (olddecl, "previous declaration of `%s'"); /* This is safer because the initializer might contain references to variables that were declared between olddecl and newdecl. This @@ -1592,58 +1543,137 @@ duplicate_decls (newdecl, olddecl, different_binding_level) return 1; } -/* Check whether decl-node X shadows an existing declaration. - OLDLOCAL is the old IDENTIFIER_LOCAL_VALUE of the DECL_NAME of X, - which might be a NULL_TREE. */ -static void -warn_if_shadowing (x, oldlocal) - tree x, oldlocal; +/* Return any external DECL associated with ID, whether or not it is + currently in scope. */ +static tree +any_external_decl (id) + tree id; { - tree sym; - const char *name; + tree decl = IDENTIFIER_SYMBOL_VALUE (id); + tree t; - if (DECL_EXTERNAL (x)) + if (decl && 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 (decl) + tree decl; +{ + tree name = DECL_NAME (decl); + if (!IDENTIFIER_SYMBOL_VALUE (name)) return; - sym = DECL_NAME (x); - name = IDENTIFIER_POINTER (sym); + truly_local_externals = tree_cons (name, decl, truly_local_externals); +} - /* Warn if shadowing an argument at the top level of the body. */ - if (oldlocal != 0 - /* This warning doesn't apply to the parms of a nested fcn. */ - && ! current_binding_level->parm_flag - /* Check that this is one level down from the parms. */ - && current_binding_level->level_chain->parm_flag - /* Check that the decl being shadowed - comes from the parm level, one level up. */ - && chain_member (oldlocal, current_binding_level->level_chain->names)) - shadow_warning (SW_PARAM, true, name, oldlocal); - /* Maybe warn if shadowing something else. */ - else if (warn_shadow - /* No shadow warnings for internally generated vars. */ - && DECL_SOURCE_LINE (x) != 0 - /* No shadow warnings for vars made for inlining. */ - && ! DECL_FROM_INLINE (x)) +/* 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. */ +static void +warn_if_shadowing (x, old) + tree x, old; +{ + const char *name; + + /* Nothing to shadow? */ + if (old == 0 + /* Shadow warnings not wanted? */ + || !warn_shadow + /* No shadow warnings for internally generated vars. */ + || DECL_SOURCE_LINE (x) == 0 + /* No shadow warnings for vars made for inlining. */ + || DECL_FROM_INLINE (x) + /* Don't warn about the parm names in function declarator + within a function declarator. + It would be nice to avoid warning in any function + declarator in a declaration, as opposed to a definition, + but there is no way to tell it's not a definition. */ + || (TREE_CODE (x) == PARM_DECL + && current_binding_level->level_chain->parm_flag)) + return; + + name = IDENTIFIER_POINTER (DECL_NAME (x)); + + if (TREE_CODE (old) == PARM_DECL) + shadow_warning (SW_PARAM, name, old); + else if (DECL_CONTEXT (old) == 0) + shadow_warning (SW_GLOBAL, name, old); + else + shadow_warning (SW_LOCAL, name, old); +} + + +/* Subroutine of pushdecl. + + X is a TYPE_DECL for a typedef statement. Create a brand new + ..._TYPE node (which will be just a variant of the existing + ..._TYPE node with identical properties) and then install X + as the TYPE_NAME of this brand new (duplicate) ..._TYPE node. + + The whole point here is to end up with a situation where each + and every ..._TYPE node the compiler creates will be uniquely + associated with AT MOST one node representing a typedef name. + This way, even though the compiler substitutes corresponding + ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very + early on, later parts of the compiler can always do the reverse + translation and get back the corresponding typedef name. For + example, given: + + typedef struct S MY_TYPE; + MY_TYPE object; + + Later parts of the compiler might only know that `object' was of + type `struct S' if it were not for code just below. With this + code however, later parts of the compiler see something like: + + struct S' == struct S + typedef struct S' MY_TYPE; + struct S' object; + + And they can then deduce (from the node for type struct S') that + the original object declaration was: + + MY_TYPE object; + + Being able to do this is important for proper support of protoize, + and also for generating precise symbolic debugging information + which takes full account of the programmer's (typedef) vocabulary. + + Obviously, we don't want to generate a duplicate ..._TYPE node if + the TYPE_DECL node that we are now processing really represents a + standard built-in type. + + Since all standard types are effectively declared at line zero + in the source file, we can easily check to see if we are working + on a standard type by checking the current value of lineno. */ + +static void +clone_underlying_type (x) + tree x; +{ + if (DECL_SOURCE_LINE (x) == 0) { - if (TREE_CODE (x) == PARM_DECL - && current_binding_level->level_chain->parm_flag) - /* Don't warn about the parm names in function declarator - within a function declarator. - It would be nice to avoid warning in any function - declarator in a declaration, as opposed to a definition, - but there is no way to tell it's not a definition. */ - ; - else if (oldlocal) - { - if (TREE_CODE (oldlocal) == PARM_DECL) - shadow_warning (SW_PARAM, false, name, oldlocal); - else - shadow_warning (SW_LOCAL, false, name, oldlocal); - } - else if (IDENTIFIER_GLOBAL_VALUE (sym) != 0 - && IDENTIFIER_GLOBAL_VALUE (sym) != error_mark_node) - shadow_warning (SW_GLOBAL, false, name, - IDENTIFIER_GLOBAL_VALUE (sym)); + if (TYPE_NAME (TREE_TYPE (x)) == 0) + TYPE_NAME (TREE_TYPE (x)) = x; + } + else if (TREE_TYPE (x) != error_mark_node + && DECL_ORIGINAL_TYPE (x) == NULL_TREE) + { + tree tt = TREE_TYPE (x); + DECL_ORIGINAL_TYPE (x) = tt; + tt = build_type_copy (tt); + TYPE_NAME (tt) = x; + TREE_USED (tt) = TREE_USED (x); + TREE_TYPE (x) = tt; } } @@ -1659,343 +1689,79 @@ tree pushdecl (x) tree x; { - tree t; tree name = DECL_NAME (x); - struct binding_level *b = current_binding_level; + struct binding_level *scope = current_binding_level; + +#ifdef ENABLE_CHECKING + if (error_mark_node == 0) + /* Called too early. */ + abort (); +#endif /* Functions need the lang_decl data. */ if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_LANG_SPECIFIC (x)) DECL_LANG_SPECIFIC (x) = (struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl)); - DECL_CONTEXT (x) = current_function_decl; /* A local extern declaration for a function doesn't constitute nesting. A local auto declaration does, since it's a forward decl for a nested function coming later. */ if ((TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL) && DECL_INITIAL (x) == 0 && DECL_EXTERNAL (x)) DECL_CONTEXT (x) = 0; + else + DECL_CONTEXT (x) = current_function_decl; if (name) { - int different_binding_level = 0; + tree old; if (warn_nested_externs + && scope != global_binding_level && DECL_EXTERNAL (x) - && b != global_binding_level - && x != IDENTIFIER_IMPLICIT_DECL (name) - /* No error messages for __FUNCTION__ and __PRETTY_FUNCTION__. */ && !DECL_IN_SYSTEM_HEADER (x)) warning ("nested extern declaration of `%s'", IDENTIFIER_POINTER (name)); - t = lookup_name_current_level (name); - if (! t && DECL_EXTERNAL (x) && TREE_PUBLIC (x)) + old = lookup_name_current_level (name); + if (old && duplicate_decls (x, old, 0)) + return old; + if (DECL_EXTERNAL (x) || scope == global_binding_level) { - t = IDENTIFIER_GLOBAL_VALUE (name); - /* Type decls at global scope don't conflict with externs declared - inside lexical blocks. */ - if (! t || TREE_CODE (t) == TYPE_DECL) - /* If there's no visible global declaration, try for an - invisible one. */ - t = IDENTIFIER_LIMBO_VALUE (name); - different_binding_level = 1; - } - if (t != 0 && t == error_mark_node) - /* error_mark_node is 0 for a while during initialization! */ - { - t = 0; - error_with_decl (x, "`%s' used prior to declaration"); - } - - /* If this decl is `static' and an implicit decl was seen previously, - warn. */ - if (TREE_PUBLIC (name) - /* Don't test for DECL_EXTERNAL, because grokdeclarator - sets this for all functions. */ - && ! TREE_PUBLIC (x) - && (TREE_CODE (x) == FUNCTION_DECL || b == global_binding_level) - /* We used to warn also for explicit extern followed by static, - but sometimes you need to do it that way. */ - && IDENTIFIER_IMPLICIT_DECL (name) != 0) - { - pedwarn ("`%s' was declared implicitly `extern' and later `static'", - IDENTIFIER_POINTER (name)); - pedwarn_with_file_and_line - (DECL_SOURCE_FILE (IDENTIFIER_IMPLICIT_DECL (name)), - DECL_SOURCE_LINE (IDENTIFIER_IMPLICIT_DECL (name)), - "previous declaration of `%s'", - IDENTIFIER_POINTER (name)); - TREE_THIS_VOLATILE (name) = 1; - } - - if (t != 0 && duplicate_decls (x, t, different_binding_level)) - { - if (TREE_CODE (t) == PARM_DECL) + /* Find and check against a previous, not-in-scope, external + decl for this identifier. (C99 s???: If two declarations + with external linkage, referring to the same object, have + incompatible types, the behavior is undefined). */ + tree ext = any_external_decl (name); + if (ext) { - /* Don't allow more than one "real" duplicate - of a forward parm decl. */ - TREE_ASM_WRITTEN (t) = TREE_ASM_WRITTEN (x); - return t; + if (duplicate_decls (x, ext, scope != global_binding_level)) + x = copy_node (ext); } - return t; - } - - /* If we are processing a typedef statement, generate a whole new - ..._TYPE node (which will be just a variant of the existing - ..._TYPE node with identical properties) and then install the - TYPE_DECL node generated to represent the typedef name as the - TYPE_NAME of this brand new (duplicate) ..._TYPE node. - - The whole point here is to end up with a situation where each - and every ..._TYPE node the compiler creates will be uniquely - associated with AT MOST one node representing a typedef name. - This way, even though the compiler substitutes corresponding - ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very - early on, later parts of the compiler can always do the reverse - translation and get back the corresponding typedef name. For - example, given: - - typedef struct S MY_TYPE; - MY_TYPE object; - - Later parts of the compiler might only know that `object' was of - type `struct S' if it were not for code just below. With this - code however, later parts of the compiler see something like: - - struct S' == struct S - typedef struct S' MY_TYPE; - struct S' object; - - And they can then deduce (from the node for type struct S') that - the original object declaration was: - - MY_TYPE object; - - Being able to do this is important for proper support of protoize, - and also for generating precise symbolic debugging information - which takes full account of the programmer's (typedef) vocabulary. - - Obviously, we don't want to generate a duplicate ..._TYPE node if - the TYPE_DECL node that we are now processing really represents a - standard built-in type. - - Since all standard types are effectively declared at line zero - in the source file, we can easily check to see if we are working - on a standard type by checking the current value of lineno. */ - - if (TREE_CODE (x) == TYPE_DECL) - { - if (DECL_SOURCE_LINE (x) == 0) - { - if (TYPE_NAME (TREE_TYPE (x)) == 0) - TYPE_NAME (TREE_TYPE (x)) = x; - } - else if (TREE_TYPE (x) != error_mark_node - && DECL_ORIGINAL_TYPE (x) == NULL_TREE) - { - tree tt = TREE_TYPE (x); - DECL_ORIGINAL_TYPE (x) = tt; - tt = build_type_copy (tt); - TYPE_NAME (tt) = x; - TREE_USED (tt) = TREE_USED (x); - TREE_TYPE (x) = tt; - } - } - - /* Multiple external decls of the same identifier ought to match. - We get warnings about inline functions where they are defined. - Avoid duplicate warnings where they are used. */ - if (TREE_PUBLIC (x) - && ! (TREE_CODE (x) == FUNCTION_DECL && DECL_INLINE (x))) - { - tree decl; - - if (IDENTIFIER_LIMBO_VALUE (name) != 0) - /* Decls in limbo are always extern, so no need to check that. */ - decl = IDENTIFIER_LIMBO_VALUE (name); else - decl = 0; - - if (decl && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl)) - /* If old decl is built-in, we already warned if we should. */ - && !DECL_BUILT_IN (decl)) - { - pedwarn_with_decl (x, - "type mismatch with previous external decl"); - pedwarn_with_decl (decl, "previous external decl of `%s'"); - } + record_external_decl (x); } + + if (TREE_CODE (x) == TYPE_DECL) + clone_underlying_type (x); - /* If a function has had an implicit declaration, and then is defined, - make sure they are compatible. */ - - if (IDENTIFIER_IMPLICIT_DECL (name) != 0 - && IDENTIFIER_GLOBAL_VALUE (name) == 0 - && TREE_CODE (x) == FUNCTION_DECL - && ! comptypes (TREE_TYPE (x), - TREE_TYPE (IDENTIFIER_IMPLICIT_DECL (name)))) + /* If storing a local value, there may already be one + (inherited). If so, record it for restoration when this + binding level ends. Take care not to do this if we are + replacing an older decl in the same binding level (i.e. + duplicate_decls returned false, above). */ + if (scope != global_binding_level + && IDENTIFIER_SYMBOL_VALUE (name) + && IDENTIFIER_SYMBOL_VALUE (name) != old) { - warning_with_decl (x, "type mismatch with previous implicit declaration"); - warning_with_decl (IDENTIFIER_IMPLICIT_DECL (name), - "previous implicit declaration of `%s'"); + warn_if_shadowing (x, IDENTIFIER_SYMBOL_VALUE (name)); + scope->shadowed = tree_cons (name, IDENTIFIER_SYMBOL_VALUE (name), + scope->shadowed); } - /* This name is new in its binding level. - Install the new declaration and return it. */ - if (b == global_binding_level) - { - /* Install a global value. */ - - /* If the first global decl has external linkage, - warn if we later see static one. */ - if (IDENTIFIER_GLOBAL_VALUE (name) == 0 && TREE_PUBLIC (x)) - TREE_PUBLIC (name) = 1; - - IDENTIFIER_GLOBAL_VALUE (name) = x; - - /* We no longer care about any previous block level declarations. */ - IDENTIFIER_LIMBO_VALUE (name) = 0; - - /* Don't forget if the function was used via an implicit decl. */ - if (IDENTIFIER_IMPLICIT_DECL (name) - && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name))) - TREE_USED (x) = 1, TREE_USED (name) = 1; - - /* Don't forget if its address was taken in that way. */ - if (IDENTIFIER_IMPLICIT_DECL (name) - && TREE_ADDRESSABLE (IDENTIFIER_IMPLICIT_DECL (name))) - TREE_ADDRESSABLE (x) = 1; - - /* Warn about mismatches against previous implicit decl. */ - if (IDENTIFIER_IMPLICIT_DECL (name) != 0 - /* If this real decl matches the implicit, don't complain. */ - && ! (TREE_CODE (x) == FUNCTION_DECL - && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (x))) - == integer_type_node))) - pedwarn ("`%s' was previously implicitly declared to return `int'", - IDENTIFIER_POINTER (name)); - - /* If this decl is `static' and an `extern' was seen previously, - that is erroneous. */ - if (TREE_PUBLIC (name) - && ! TREE_PUBLIC (x) && ! DECL_EXTERNAL (x)) - { - /* Okay to redeclare an ANSI built-in as static. */ - if (t != 0 && DECL_BUILT_IN (t)) - ; - /* Okay to declare a non-ANSI built-in as anything. */ - else if (t != 0 && DECL_BUILT_IN_NONANSI (t)) - ; - /* Okay to have global type decl after an earlier extern - declaration inside a lexical block. */ - else if (TREE_CODE (x) == TYPE_DECL) - ; - else if (IDENTIFIER_IMPLICIT_DECL (name)) - { - if (! TREE_THIS_VOLATILE (name)) - pedwarn ("`%s' was declared implicitly `extern' and later `static'", - IDENTIFIER_POINTER (name)); - } - else - pedwarn ("`%s' was declared `extern' and later `static'", - IDENTIFIER_POINTER (name)); - } - } - else - { - /* Here to install a non-global value. */ - tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); - tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name); - - IDENTIFIER_LOCAL_VALUE (name) = x; - - /* If this is an extern function declaration, see if we - have a global definition or declaration for the function. */ - if (oldlocal == 0 - && oldglobal != 0 - && TREE_CODE (x) == FUNCTION_DECL - && TREE_CODE (oldglobal) == FUNCTION_DECL - && DECL_EXTERNAL (x) - && ! DECL_DECLARED_INLINE_P (x)) - { - /* We have one. Their types must agree. */ - if (! comptypes (TREE_TYPE (x), - TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)))) - pedwarn_with_decl (x, "extern declaration of `%s' doesn't match global one"); - else - { - /* Inner extern decl is inline if global one is. - Copy enough to really inline it. */ - if (DECL_DECLARED_INLINE_P (oldglobal)) - { - DECL_DECLARED_INLINE_P (x) - = DECL_DECLARED_INLINE_P (oldglobal); - DECL_INLINE (x) = DECL_INLINE (oldglobal); - DECL_INITIAL (x) = (current_function_decl == oldglobal - ? 0 : DECL_INITIAL (oldglobal)); - DECL_SAVED_INSNS (x) = DECL_SAVED_INSNS (oldglobal); - DECL_NUM_STMTS (x) = DECL_NUM_STMTS (oldglobal); - DECL_ARGUMENTS (x) = DECL_ARGUMENTS (oldglobal); - DECL_RESULT (x) = DECL_RESULT (oldglobal); - TREE_ASM_WRITTEN (x) = TREE_ASM_WRITTEN (oldglobal); - DECL_ABSTRACT_ORIGIN (x) - = DECL_ABSTRACT_ORIGIN (oldglobal); - } - /* Inner extern decl is built-in if global one is. */ - if (DECL_BUILT_IN (oldglobal)) - { - DECL_BUILT_IN_CLASS (x) = DECL_BUILT_IN_CLASS (oldglobal); - DECL_FUNCTION_CODE (x) = DECL_FUNCTION_CODE (oldglobal); - } - /* Keep the arg types from a file-scope fcn defn. */ - if (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != 0 - && DECL_INITIAL (oldglobal) - && TYPE_ARG_TYPES (TREE_TYPE (x)) == 0) - TREE_TYPE (x) = TREE_TYPE (oldglobal); - } - } - -#if 0 - /* This case is probably sometimes the right thing to do. */ - /* If we have a local external declaration, - then any file-scope declaration should not - have been static. */ - if (oldlocal == 0 && oldglobal != 0 - && !TREE_PUBLIC (oldglobal) - && DECL_EXTERNAL (x) && TREE_PUBLIC (x)) - warning ("`%s' locally external but globally static", - IDENTIFIER_POINTER (name)); -#endif - - /* If we have a local external declaration, - and no file-scope declaration has yet been seen, - then if we later have a file-scope decl it must not be static. */ - if (oldlocal == 0 - && DECL_EXTERNAL (x) - && TREE_PUBLIC (x)) - { - if (oldglobal == 0) - TREE_PUBLIC (name) = 1; - - /* Save this decl, so that we can do type checking against - other decls after it falls out of scope. - - Only save it once. This prevents temporary decls created in - expand_inline_function from being used here, since this - will have been set when the inline function was parsed. - It also helps give slightly better warnings. */ - if (IDENTIFIER_LIMBO_VALUE (name) == 0) - IDENTIFIER_LIMBO_VALUE (name) = x; - } - - warn_if_shadowing (x, oldlocal); - - /* If storing a local value, there may already be one (inherited). - If so, record it for restoration when this binding level ends. */ - if (oldlocal != 0) - b->shadowed = tree_cons (name, oldlocal, b->shadowed); - } + /* Install the new declaration in the requested binding level. */ + IDENTIFIER_SYMBOL_VALUE (name) = x; + C_DECL_INVISIBLE (x) = 0; /* Keep list of variables in this level with incomplete type. If the input is erroneous, we can have error_mark in the type @@ -2010,96 +1776,131 @@ pushdecl (x) element = TREE_TYPE (element); if (TREE_CODE (element) == RECORD_TYPE || TREE_CODE (element) == UNION_TYPE) - b->incomplete_list = tree_cons (NULL_TREE, x, b->incomplete_list); + scope->incomplete_list = tree_cons (NULL_TREE, x, + scope->incomplete_list); } } /* Put decls on list in reverse order. We will reverse them later if necessary. */ - TREE_CHAIN (x) = b->names; - b->names = x; + TREE_CHAIN (x) = scope->names; + scope->names = x; return x; } -/* Record that the local value of NAME is shadowed at function scope. - This is used by build_external_ref in c-typeck.c. */ -void -record_function_scope_shadow (name) - tree name; -{ - struct binding_level *b = get_function_binding_level (); - b->shadowed = tree_cons (name, IDENTIFIER_LOCAL_VALUE (name), - b->shadowed); -} - -/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate. */ - +/* Record X as belonging to the global scope (C99 "file scope"). + This is used only internally by the Objective C front end, + and is limited to its needs. It will hork if there is _any_ + visible binding for X (not just a global one). */ tree pushdecl_top_level (x) tree x; { - tree t; - struct binding_level *b = current_binding_level; + tree name, old; - current_binding_level = global_binding_level; - t = pushdecl (x); - current_binding_level = b; - return t; + if (TREE_CODE (x) != VAR_DECL) + abort (); + + name = DECL_NAME (x); + old = IDENTIFIER_SYMBOL_VALUE (name); + + if (old) + { + if (DECL_CONTEXT (old)) + abort (); + + if (!duplicate_decls (x, old, 0)) + abort (); + + return old; + } + + DECL_CONTEXT (x) = 0; + IDENTIFIER_SYMBOL_VALUE (name) = x; + TREE_CHAIN (x) = global_binding_level->names; + global_binding_level->names = x; + return x; +} + +/* Record X as belonging to the outermost scope of the current + function. This is used only internally, by c_make_fname_decl and + build_external_ref, and is limited to their needs. The NAME is + provided as a separate argument because build_external_ref wants to + use error_mark_node for X. For VAR_DECLs, duplicate_decls is not + called; if there is any preexisting decl for this identifier, it is + an ICE. */ +tree +pushdecl_function_level (x, name) + tree x; + tree name; +{ + struct binding_level *scope; + + scope = current_binding_level; + while (scope->function_body == 0) + scope = scope->level_chain; + if (!scope) + abort (); + + if (x == error_mark_node) + scope->shadowed = tree_cons (name, IDENTIFIER_SYMBOL_VALUE (name), + scope->shadowed); + else if (TREE_CODE (x) == VAR_DECL) + { + if (name != DECL_NAME (x)) + abort (); + if (IDENTIFIER_SYMBOL_VALUE (name)) + abort (); + + DECL_CONTEXT (x) = current_function_decl; + TREE_CHAIN (x) = scope->names; + scope->names = x; + } + + IDENTIFIER_SYMBOL_VALUE (name) = x; + return x; } -/* Generate an implicit declaration for identifier FUNCTIONID - as a function of type int (). Print a warning if appropriate. */ +/* Generate an implicit declaration for identifier FUNCTIONID as a + function of type int (). */ tree implicitly_declare (functionid) tree functionid; { - tree decl; - int traditional_warning = 0; - /* Only one "implicit declaration" warning per identifier. */ - int implicit_warning; + tree decl = any_external_decl (functionid); - /* We used to reuse an old implicit decl here, - but this loses with inline functions because it can clobber - the saved decl chains. */ -#if 0 - if (IDENTIFIER_IMPLICIT_DECL (functionid) != 0) - decl = IDENTIFIER_IMPLICIT_DECL (functionid); - else -#endif - decl = build_decl (FUNCTION_DECL, functionid, default_function_type); - - /* Warn of implicit decl following explicit local extern decl. - This is probably a program designed for traditional C. */ - if (TREE_PUBLIC (functionid) && IDENTIFIER_GLOBAL_VALUE (functionid) == 0) - traditional_warning = 1; - - /* Warn once of an implicit declaration. */ - implicit_warning = (IDENTIFIER_IMPLICIT_DECL (functionid) == 0); + if (decl && decl != error_mark_node) + { + /* Implicit declaration of a function already declared + (somehow) in a different scope, or as a built-in. + If this is the first time this has happened, warn; + then recycle the old declaration. */ + if (!C_DECL_IMPLICIT (decl)) + { + implicit_decl_warning (DECL_NAME (decl)); + if (DECL_CONTEXT (decl)) + warning_with_decl (decl, "previous declaration of `%s'"); + C_DECL_IMPLICIT (decl) = 1; + } + return pushdecl (decl); + } + /* Not seen before. */ + decl = build_decl (FUNCTION_DECL, functionid, default_function_type); DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 1; - - /* Record that we have an implicit decl and this is it. */ - IDENTIFIER_IMPLICIT_DECL (functionid) = decl; + C_DECL_IMPLICIT (decl) = 1; + implicit_decl_warning (functionid); /* ANSI standard says implicit declarations are in the innermost block. So we record the decl in the standard fashion. */ - pushdecl (decl); - - /* This is a no-op in c-lang.c or something real in objc-act.c. */ - if (flag_objc) - objc_check_decl (decl); + decl = pushdecl (decl); + /* No need to call objc_check_decl here - it's a function type. */ rest_of_decl_compilation (decl, NULL, 0, 0); - if (implicit_warning) - implicit_decl_warning (functionid); - else if (warn_traditional && traditional_warning) - warning ("function `%s' was previously declared within a block", - IDENTIFIER_POINTER (functionid)); - /* Write a record describing this implicit function declaration to the prototypes file (if requested). */ @@ -2111,7 +1912,7 @@ implicitly_declare (functionid) return decl; } -void +static void implicit_decl_warning (id) tree id; { @@ -2353,55 +2154,50 @@ storetags (tags) /* Given NAME, an IDENTIFIER_NODE, return the structure (or union or enum) definition for that name. - Searches binding levels from BINDING_LEVEL up to the global level. - If THISLEVEL_ONLY is nonzero, searches only the specified context - (but skips any tag-transparent contexts to find one that is - meaningful for tags). + If THISLEVEL_ONLY is nonzero, searches only the current_binding_level. CODE says which kind of type the caller wants; it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. If the wrong kind of type is found, an error is reported. */ static tree -lookup_tag (code, name, binding_level, thislevel_only) +lookup_tag (code, name, thislevel_only) enum tree_code code; - struct binding_level *binding_level; tree name; int thislevel_only; { - struct binding_level *level; - int thislevel = 1; + tree tag = IDENTIFIER_TAG_VALUE (name); + int thislevel = 0; - for (level = binding_level; level; level = level->level_chain) + if (!tag) + 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) { - tree tail; - for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) - { - if (TREE_PURPOSE (tail) == name) - { - if (TREE_CODE (TREE_VALUE (tail)) != code) - { - /* Definition isn't the kind we were looking for. */ - pending_invalid_xref = name; - pending_invalid_xref_file = input_filename; - pending_invalid_xref_line = lineno; - /* If in the same binding level as a declaration as a tag - of a different type, this must not be allowed to - shadow that tag, so give the error immediately. - (For example, "struct foo; union foo;" is invalid.) */ - if (thislevel) - pending_xref_error (); - } - return TREE_VALUE (tail); - } - } - if (! level->tag_transparent) - { - if (thislevel_only) - return NULL_TREE; - thislevel = 0; - } + if (current_binding_level == global_binding_level + || purpose_member (name, current_binding_level->tags)) + thislevel = 1; } - return NULL_TREE; + + if (thislevel_only && !thislevel) + return 0; + + if (TREE_CODE (tag) != code) + { + /* Definition isn't the kind we were looking for. */ + pending_invalid_xref = name; + pending_invalid_xref_file = input_filename; + pending_invalid_xref_line = lineno; + + /* If in the same binding level as a declaration as a tag + of a different type, this must not be allowed to + shadow that tag, so give the error immediately. + (For example, "struct foo; union foo;" is invalid.) */ + if (thislevel) + pending_xref_error (); + } + return tag; } /* Print an error message now @@ -2420,26 +2216,6 @@ pending_xref_error () pending_invalid_xref = 0; } -/* Given a type, find the tag that was defined for it and return the tag name. - Otherwise return 0. */ - -static tree -lookup_tag_reverse (type) - tree type; -{ - struct binding_level *level; - - for (level = current_binding_level; level; level = level->level_chain) - { - tree tail; - for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) - { - if (TREE_VALUE (tail) == type) - return TREE_PURPOSE (tail); - } - } - return NULL_TREE; -} /* Look up NAME in the current binding level and its superiors in the namespace of variables, functions and typedefs. @@ -2450,35 +2226,33 @@ tree lookup_name (name) tree name; { - tree val; - - if (current_binding_level != global_binding_level - && IDENTIFIER_LOCAL_VALUE (name)) - val = IDENTIFIER_LOCAL_VALUE (name); - else - val = IDENTIFIER_GLOBAL_VALUE (name); - return val; + tree decl = IDENTIFIER_SYMBOL_VALUE (name); + if (decl == 0 || decl == error_mark_node) + return decl; + if (C_DECL_INVISIBLE (decl)) + return 0; + return decl; } -/* Similar to `lookup_name' but look only at current binding level. */ +/* Similar to `lookup_name' but look only at the current binding level. */ -tree +static tree lookup_name_current_level (name) tree name; { - tree t; + tree decl = IDENTIFIER_SYMBOL_VALUE (name); - if (current_binding_level == global_binding_level) - return IDENTIFIER_GLOBAL_VALUE (name); - - if (IDENTIFIER_LOCAL_VALUE (name) == 0) + if (decl == 0 || decl == error_mark_node || C_DECL_INVISIBLE (decl)) return 0; - for (t = current_binding_level->names; t; t = TREE_CHAIN (t)) - if (DECL_NAME (t) == name) - break; + if (current_binding_level == global_binding_level) + return decl; - return t; + /* Scan the current scope for a decl with name NAME. */ + if (chain_member (decl, current_binding_level->names)) + return decl; + + return 0; } /* Create the predefined scalar types of C, @@ -2558,8 +2332,6 @@ c_make_fname_decl (id, type_dep) build_index_type (size_int (length))); decl = build_decl (VAR_DECL, id, type); - /* We don't push the decl, so have to set its context here. */ - DECL_CONTEXT (decl) = current_function_decl; TREE_STATIC (decl) = 1; TREE_READONLY (decl) = 1; @@ -2572,14 +2344,8 @@ c_make_fname_decl (id, type_dep) TREE_USED (decl) = 1; if (current_function_decl) - { - /* Add the decls to the outermost block. */ - struct binding_level *old = current_binding_level; - current_binding_level = get_function_binding_level (); - pushdecl (decl); - current_binding_level = old; - } - + pushdecl_function_level (decl, DECL_NAME (decl)); + finish_decl (decl, init, NULL_TREE); return decl; @@ -2616,7 +2382,7 @@ builtin_function (name, type, function_code, class, library_name, attrs) /* Warn if a function in the namespace for users is used without an occasion to consider it declared. */ if (name[0] != '_' || name[1] != '_') - C_DECL_ANTICIPATED (decl) = 1; + C_DECL_INVISIBLE (decl) = 1; /* Possibly apply some default attributes to this built-in function. */ if (attrs) @@ -2680,7 +2446,7 @@ shadow_tag_warned (declspecs, warned) /* Used to test also that TYPE_SIZE (value) != 0. That caused warning for `struct foo;' at top level in the file. */ { - tree name = lookup_tag_reverse (value); + tree name = TYPE_NAME (value); tree t; found_tag++; @@ -2696,7 +2462,7 @@ shadow_tag_warned (declspecs, warned) } else { - t = lookup_tag (code, name, current_binding_level, 1); + t = lookup_tag (code, name, 1); if (t == 0) { @@ -4950,7 +4716,7 @@ xref_tag (code, name) /* If a cross reference is requested, look up the type already defined for this tag and return it. */ - tree ref = lookup_tag (code, name, current_binding_level, 0); + tree ref = lookup_tag (code, name, 0); /* If this is the right type of tag, return what we found. (This reference will be shadowed by shadow_tag later if appropriate.) If this is the wrong type of tag, do not return it. If it was the @@ -5004,7 +4770,7 @@ start_struct (code, name) tree ref = 0; if (name != 0) - ref = lookup_tag (code, name, current_binding_level, 1); + ref = lookup_tag (code, name, 1); if (ref && TREE_CODE (ref) == code) { if (TYPE_FIELDS (ref)) @@ -5432,7 +5198,7 @@ start_enum (name) forward reference. */ if (name != 0) - enumtype = lookup_tag (ENUMERAL_TYPE, name, current_binding_level, 1); + enumtype = lookup_tag (ENUMERAL_TYPE, name, 1); if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE) { @@ -5750,27 +5516,16 @@ start_function (declspecs, declarator, attributes) current_function_prototype_line = DECL_SOURCE_LINE (old_decl); } - /* If there is no explicit declaration, look for any out-of-scope implicit - declarations. */ - if (old_decl == 0) - old_decl = IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)); - /* Optionally warn of old-fashioned def with no previous prototype. */ if (warn_strict_prototypes && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0 - && !(old_decl != 0 - && (TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0 - || (DECL_BUILT_IN (old_decl) - && ! C_DECL_ANTICIPATED (old_decl))))) + && C_DECL_ISNT_PROTOTYPE (old_decl)) warning ("function declaration isn't a prototype"); /* Optionally warn of any global def with no previous prototype. */ else if (warn_missing_prototypes && TREE_PUBLIC (decl1) - && !(old_decl != 0 - && (TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0 - || (DECL_BUILT_IN (old_decl) - && ! C_DECL_ANTICIPATED (old_decl)))) - && ! MAIN_NAME_P (DECL_NAME (decl1))) + && ! MAIN_NAME_P (DECL_NAME (decl1)) + && C_DECL_ISNT_PROTOTYPE (old_decl)) warning_with_decl (decl1, "no previous prototype for `%s'"); /* Optionally warn of any def with no previous prototype if the function has already been used. */ @@ -5789,7 +5544,7 @@ start_function (declspecs, declarator, attributes) if the function has already been used. */ else if (warn_missing_declarations && old_decl != 0 && TREE_USED (old_decl) - && old_decl == IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1))) + && C_DECL_IMPLICIT (old_decl)) warning_with_decl (decl1, "`%s' was used with no declaration before its definition"); @@ -5872,7 +5627,6 @@ start_function (declspecs, declarator, attributes) pushlevel (0); declare_parm_level (1); - current_binding_level->subblocks_tag_transparent = 1; make_decl_rtl (current_function_decl, NULL); @@ -5965,10 +5719,10 @@ store_parm_decls () for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl)) if (DECL_NAME (decl)) - IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) = 0; + IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)) = 0; for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) - IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); current_binding_level->names = 0; current_binding_level->shadowed = 0; } @@ -6347,13 +6101,27 @@ finish_function (nested, can_defer_p) { tree fndecl = current_function_decl; + /* When a function declaration is totally empty, e.g. + void foo(void) { } + (the argument list is irrelevant) the compstmt rule will not + bother calling pushlevel/poplevel, which means we get here with + the binding_level stack out of sync. Detect this situation by + noticing that the current_binding_level is still as + store_parm_decls left it, and do a dummy push/pop to get back to + consistency. Note that the call to pushlevel does not actually + push another binding level - see there for details. */ + if (current_binding_level->parm_flag && keep_next_if_subblocks) + { + pushlevel (0); + poplevel (1, 0, 1); + } + #if 0 /* This caused &foo to be of type ptr-to-const-function which then got a warning when stored in a ptr-to-function variable. */ TREE_READONLY (fndecl) = 1; #endif - poplevel (1, 0, 1); BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; /* Must mark the RESULT_DECL as being in this function. */ @@ -6918,14 +6686,23 @@ c_expand_decl_stmt (t) c_expand_body_1 (decl, 1); } -/* Return the IDENTIFIER_GLOBAL_VALUE of T, for use in common code, since - the definition of IDENTIFIER_GLOBAL_VALUE is different for C and C++. */ +/* Return the global value of T as a symbol. */ tree identifier_global_value (t) tree t; { - return IDENTIFIER_GLOBAL_VALUE (t); + tree decl = IDENTIFIER_SYMBOL_VALUE (t); + if (decl == 0 || DECL_CONTEXT (decl) == 0) + return decl; + + /* Shadowed by something else; find the true global value. */ + for (decl = global_binding_level->names; decl; decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl) == t) + return decl; + + /* Only local values for this decl. */ + return 0; } /* Record a builtin type for C. If NAME is non-NULL, it is the name used; diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 29352f5dd43..368c970557e 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -1,6 +1,6 @@ /* Definitions for C parsing and type checking. Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -37,11 +37,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA struct lang_identifier GTY(()) { struct c_common_identifier common_id; - tree global_value; - tree local_value; + tree symbol_value; + tree tag_value; tree label_value; - tree implicit_decl; - tree limbo_value; }; /* The resulting tree type. */ @@ -70,26 +68,17 @@ struct lang_decl GTY(()) /* Macros for access to language-specific slots in an identifier. */ /* Each of these slots contains a DECL node or null. */ -/* This represents the value which the identifier has in the - file-scope namespace. */ -#define IDENTIFIER_GLOBAL_VALUE(NODE) \ - (((struct lang_identifier *) (NODE))->global_value) -/* This represents the value which the identifier has in the current - scope. */ -#define IDENTIFIER_LOCAL_VALUE(NODE) \ - (((struct lang_identifier *) (NODE))->local_value) -/* This represents the value which the identifier has as a label in - the current label scope. */ +/* The value of the identifier in the namespace of "ordinary identifiers" + (data objects, enum constants, functions, typedefs). */ +#define IDENTIFIER_SYMBOL_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->symbol_value) +/* The value of the identifier in the namespace of struct, union, + and enum tags. */ +#define IDENTIFIER_TAG_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->tag_value) +/* The value of the identifier in the namespace of labels. */ #define IDENTIFIER_LABEL_VALUE(NODE) \ (((struct lang_identifier *) (NODE))->label_value) -/* This records the extern decl of this identifier, if it has had one - at any point in this compilation. */ -#define IDENTIFIER_LIMBO_VALUE(NODE) \ - (((struct lang_identifier *) (NODE))->limbo_value) -/* This records the implicit function decl of this identifier, if it - has had one at any point in this compilation. */ -#define IDENTIFIER_IMPLICIT_DECL(NODE) \ - (((struct lang_identifier *) (NODE))->implicit_decl) /* In identifiers, C uses the following fields in a special way: TREE_PUBLIC to record that there was a previous local extern decl. @@ -129,13 +118,6 @@ struct lang_type GTY(()) #define C_TYPE_VARIABLE_SIZE(TYPE) TYPE_LANG_FLAG_1 (TYPE) #define C_DECL_VARIABLE_SIZE(TYPE) DECL_LANG_FLAG_0 (TYPE) -#if 0 /* Not used. */ -/* Record whether a decl for a function or function pointer has - already been mentioned (in a warning) because it was called - but didn't have a prototype. */ -#define C_MISSING_PROTOTYPE_WARNED(DECL) DECL_LANG_FLAG_2 (DECL) -#endif - /* Store a value in that field. */ #define C_SET_EXP_ORIGINAL_CODE(EXP, CODE) \ (TREE_COMPLEXITY (EXP) = (int) (CODE)) @@ -147,10 +129,22 @@ struct lang_type GTY(()) return type. */ #define C_FUNCTION_IMPLICIT_INT(EXP) DECL_LANG_FLAG_1 (EXP) -/* Nonzero for a declaration of a built in function if there has been no - occasion that would declare the function in ordinary C. - Using the function draws a pedantic warning in this case. */ -#define C_DECL_ANTICIPATED(EXP) DECL_LANG_FLAG_3 (EXP) +/* For a FUNCTION_DECL, nonzero if it was an implicit declaration. */ +#define C_DECL_IMPLICIT(EXP) DECL_LANG_FLAG_2 (EXP) + +/* Nonzero for a declaration of an external object which is not + currently in scope. This is either a built-in declaration of + a library function, before a real declaration has been seen, + or a declaration that appeared in an inner scope that has ended. */ +#define C_DECL_INVISIBLE(EXP) DECL_LANG_FLAG_3 (EXP) + +/* Nonzero for a decl which either doesn't exist or isn't a prototype. + N.B. Could be simplified if all built-in decls had complete prototypes + (but this is presently difficult because some of them need FILE*). */ +#define C_DECL_ISNT_PROTOTYPE(EXP) \ + (EXP == 0 \ + || (TYPE_ARG_TYPES (TREE_TYPE (EXP)) == 0 \ + && !DECL_BUILT_IN (EXP))) /* For FUNCTION_TYPE, a hidden list of types of arguments. The same as TYPE_ARG_TYPES for functions with prototypes, but created for functions @@ -207,11 +201,9 @@ extern tree grokfield PARAMS ((const char *, int, tree extern tree groktypename PARAMS ((tree)); extern tree groktypename_in_parm_context PARAMS ((tree)); extern tree implicitly_declare PARAMS ((tree)); -extern void implicit_decl_warning PARAMS ((tree)); extern int in_parm_level_p PARAMS ((void)); extern void keep_next_level PARAMS ((void)); extern tree lookup_name PARAMS ((tree)); -extern tree lookup_name_current_level PARAMS ((tree)); extern void parmlist_tags_warning PARAMS ((void)); extern void pending_xref_error PARAMS ((void)); extern void c_push_function_context PARAMS ((struct function *)); @@ -220,8 +212,8 @@ extern void pop_label_level PARAMS ((void)); extern void push_label_level PARAMS ((void)); extern void push_parm_decl PARAMS ((tree)); extern tree pushdecl_top_level PARAMS ((tree)); +extern tree pushdecl_function_level PARAMS ((tree, tree)); extern void pushtag PARAMS ((tree, tree)); -extern void record_function_scope_shadow PARAMS ((tree)); extern tree set_array_declarator_type PARAMS ((tree, tree, int)); extern tree shadow_label PARAMS ((tree)); extern void shadow_tag PARAMS ((tree)); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index e63865e27a3..ec9418bdc84 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -1,6 +1,6 @@ /* Build expressions with type checking for C compiler. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -59,6 +59,7 @@ static int type_lists_compatible_p PARAMS ((tree, tree)); static tree decl_constant_value_for_broken_optimization PARAMS ((tree)); static tree default_function_array_conversion PARAMS ((tree)); static tree lookup_field PARAMS ((tree, tree)); +static void undeclared_variable PARAMS ((tree)); static tree convert_arguments PARAMS ((tree, tree, tree, tree)); static tree pointer_diff PARAMS ((tree, tree)); static tree unary_complex_lvalue PARAMS ((enum tree_code, tree, int)); @@ -1375,6 +1376,38 @@ build_array_ref (array, index) } } +/* Issue an error message for a reference to an undeclared variable ID, + including a reference to a builtin outside of function-call context. + Arrange to suppress further errors for the same identifier. */ +static void +undeclared_variable (id) + tree id; +{ + if (current_function_decl == 0) + { + error ("`%s' undeclared here (not in a function)", + IDENTIFIER_POINTER (id)); + IDENTIFIER_SYMBOL_VALUE (id) = error_mark_node; + } + else + { + error ("`%s' undeclared (first use in this function)", + IDENTIFIER_POINTER (id)); + + if (! undeclared_variable_notice) + { + error ("(Each undeclared identifier is reported only once"); + error ("for each function it appears in.)"); + undeclared_variable_notice = 1; + } + + /* Set IDENTIFIER_SYMBOL_VALUE (id) to error_mark_node + at function scope. This suppresses further warnings + about this undeclared identifier in this function. */ + pushdecl_function_level (error_mark_node, id); + } +} + /* Build an external reference to identifier ID. FUN indicates whether this will be used for a function call. */ tree @@ -1386,70 +1419,12 @@ build_external_ref (id, fun) tree decl = lookup_name (id); tree objc_ivar = lookup_objc_ivar (id); - if (decl && TREE_DEPRECATED (decl)) - warn_deprecated_use (decl); - - if (!decl || decl == error_mark_node || C_DECL_ANTICIPATED (decl)) - { - if (objc_ivar) - ref = objc_ivar; - else if (fun) - { - if (!decl || decl == error_mark_node) - /* Ordinary implicit function declaration. */ - ref = implicitly_declare (id); - else - { - /* Implicit declaration of built-in function. Don't - change the built-in declaration, but don't let this - go by silently, either. */ - implicit_decl_warning (id); - - /* only issue this warning once */ - C_DECL_ANTICIPATED (decl) = 0; - ref = decl; - } - } - else - { - /* Don't complain about something that's already been - complained about. */ - if (decl == error_mark_node) - return error_mark_node; - - /* Reference to undeclared variable, including reference to - builtin outside of function-call context. */ - if (current_function_decl == 0) - error ("`%s' undeclared here (not in a function)", - IDENTIFIER_POINTER (id)); - else - { - error ("`%s' undeclared (first use in this function)", - IDENTIFIER_POINTER (id)); - - if (! undeclared_variable_notice) - { - error ("(Each undeclared identifier is reported only once"); - error ("for each function it appears in.)"); - undeclared_variable_notice = 1; - } - - /* Set IDENTIFIER_LOCAL_VALUE (id) to error_mark_node and - add a function-scope shadow entry which will undo that. - This suppresses further warnings about this undeclared - identifier in this function. */ - record_function_scope_shadow (id); - IDENTIFIER_LOCAL_VALUE (id) = error_mark_node; - } - return error_mark_node; - } - } - else + if (decl && decl != error_mark_node) { /* Properly declared variable or function reference. */ if (!objc_ivar) ref = decl; - else if (decl != objc_ivar && IDENTIFIER_LOCAL_VALUE (id)) + else if (decl != objc_ivar && DECL_CONTEXT (decl) != 0) { warning ("local declaration of `%s' hides instance variable", IDENTIFIER_POINTER (id)); @@ -1458,10 +1433,27 @@ build_external_ref (id, fun) else ref = objc_ivar; } + else if (objc_ivar) + ref = objc_ivar; + else if (fun) + /* Implicit function declaration. */ + ref = implicitly_declare (id); + else if (decl == error_mark_node) + /* Don't complain about something that's already been + complained about. */ + return error_mark_node; + else + { + undeclared_variable (id); + return error_mark_node; + } if (TREE_TYPE (ref) == error_mark_node) return error_mark_node; + if (TREE_DEPRECATED (ref)) + warn_deprecated_use (ref); + if (!skip_evaluation) assemble_external (ref); TREE_USED (ref) = 1; diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index 3420bd1322a..9c5b85aec16 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -239,6 +239,8 @@ scope_to_insns_initialize () break; case NOTE_INSN_BLOCK_END: block = BLOCK_SUPERCONTEXT (block); + if (block && TREE_CODE (block) == FUNCTION_DECL) + block = 0; delete_insn (insn); break; default: diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3e3e4f3d73c..a272d5e3eb0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2003-04-10 Zack Weinberg + + * decl.c: Update all calls to shadow_warning. + 2003-04-10 Mark Mitchell * class.c (layout_class_type): Correct handling for overlong diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4734d76d006..28d1493f883 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4001,7 +4001,7 @@ pushdecl (tree x) } if (warn_shadow && !err) - shadow_warning (SW_PARAM, false, + shadow_warning (SW_PARAM, IDENTIFIER_POINTER (name), oldlocal); } @@ -4019,12 +4019,12 @@ pushdecl (tree x) IDENTIFIER_POINTER (name)); else if (oldlocal != NULL_TREE && TREE_CODE (oldlocal) == VAR_DECL) - shadow_warning (SW_LOCAL, false, + shadow_warning (SW_LOCAL, IDENTIFIER_POINTER (name), oldlocal); else if (oldglobal != NULL_TREE && TREE_CODE (oldglobal) == VAR_DECL) /* XXX shadow warnings in outer-more namespaces */ - shadow_warning (SW_GLOBAL, false, + shadow_warning (SW_GLOBAL, IDENTIFIER_POINTER (name), oldglobal); } } diff --git a/gcc/function.c b/gcc/function.c index 306e7523654..1f2ed4401af 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -6000,10 +6000,16 @@ reorder_blocks_1 (insns, current_block, p_block_stack) BLOCK_SUBBLOCKS (block) = 0; TREE_ASM_WRITTEN (block) = 1; - BLOCK_SUPERCONTEXT (block) = current_block; - BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block); - BLOCK_SUBBLOCKS (current_block) = block; - current_block = block; + /* When there's only one block for the entire function, + current_block == block and we mustn't do this, it + will cause infinite recursion. */ + if (block != current_block) + { + BLOCK_SUPERCONTEXT (block) = current_block; + BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block); + BLOCK_SUBBLOCKS (current_block) = block; + current_block = block; + } VARRAY_PUSH_TREE (*p_block_stack, block); } else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END) diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index c23c6225787..b9ac3150c1e 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -5298,8 +5298,8 @@ build_protocol_reference (p) objc_protocol_template), NULL_TREE)); - if (IDENTIFIER_GLOBAL_VALUE (ident)) - decl = IDENTIFIER_GLOBAL_VALUE (ident); /* Set by pushdecl. */ + if (identifier_global_value (ident)) + decl = identifier_global_value (ident); /* Set by pushdecl. */ else { decl = build_decl (VAR_DECL, ident, ptype); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 52be21cb002..7b23832937e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2003-04-10 Zack Weinberg + + * gcc.c-torture/execute/builtin-noret-2.c: New. + * gcc.c-torture/execute/builtin-noret-2.x: New. + XFAIL builtin-noret-2.c at -O1 and above. + * gcc.dg/redecl.c: New. + * gcc.dg/Wshadow-1.c: Update error regexps. + 2003-04-10 Mark Mitchell * g++.dg/abi/bitfield10.C: New test. diff --git a/gcc/testsuite/gcc.c-torture/execute/builtin-noret-2.c b/gcc/testsuite/gcc.c-torture/execute/builtin-noret-2.c new file mode 100644 index 00000000000..077153b1cb9 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtin-noret-2.c @@ -0,0 +1,84 @@ +/* Test for builtin noreturn attributes when the visible declarations + are function-local. Doesn't presently work. Modified from + builtin-noret-1.c by Zack Weinberg . */ + +extern void tabort (void); +extern void texit (void); +extern void t_exit (void); +extern void t_Exit (void); + +extern void link_failure (void); + +int +main (void) +{ + volatile int i = 0; + /* The real test here is that the program links. */ + if (i) + tabort (); + if (i) + texit (); + if (i) + t_exit (); + if (i) + t_Exit (); + exit (0); +} + +void +tabort (void) +{ + extern void abort (void); + abort (); + link_failure (); +} + +void +texit (void) +{ + extern void exit (int); + exit (1); + link_failure (); +} + +void +t_exit (void) +{ + extern void _exit (int); + _exit (1); + link_failure (); +} + +/* Some non-Unix libcs might not have _exit. This version should never + get called. */ +static void +_exit (int i) +{ + abort (); +} + +void +t_Exit (void) +{ + extern void _Exit (int); + _Exit (1); + link_failure (); +} + +/* Some libcs might not have _Exit. This version should never get called. */ +static void +_Exit (int i) +{ + abort (); +} + +/* When optimizing, no calls to link_failure should remain. In any case, + link_failure should not be called. */ + +#ifndef __OPTIMIZE__ +void +link_failure (void) +{ + abort (); +} +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtin-noret-2.x b/gcc/testsuite/gcc.c-torture/execute/builtin-noret-2.x new file mode 100644 index 00000000000..7926a94f781 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtin-noret-2.x @@ -0,0 +1,12 @@ +# This test fails at -O1 and higher. +set torture_eval_before_compile { + global compiler_conditional_xfail_data + set compiler_conditional_xfail_data { + "Fails at all optimization levels but -O0, see PR10375." \ + { "*-*-*" } \ + { "-O*" } \ + { "-O0" } + } +} + +return 0 diff --git a/gcc/testsuite/gcc.dg/Wshadow-1.c b/gcc/testsuite/gcc.dg/Wshadow-1.c index 320d4f808da..c9c3acb98c9 100644 --- a/gcc/testsuite/gcc.dg/Wshadow-1.c +++ b/gcc/testsuite/gcc.dg/Wshadow-1.c @@ -10,10 +10,10 @@ void foo (double decl1) /* { dg-warning "shadows a global decl" } */ { } -void foo1 (int d) /* { dg-warning "shadowed declaration" } */ +void foo1 (int d) /* { dg-warning "previous declaration" } */ { double d; /* { dg-bogus "warning" "warning in place of error" } */ - /* { dg-error "shadows a parameter" "" { target *-*-* } 15 } */ + /* { dg-error "redeclared as different" "" { target *-*-* } 15 } */ } void foo2 (int d) /* { dg-warning "shadowed declaration" } */ diff --git a/gcc/testsuite/gcc.dg/redecl-1.c b/gcc/testsuite/gcc.dg/redecl-1.c new file mode 100644 index 00000000000..d2355ba7aa2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/redecl-1.c @@ -0,0 +1,101 @@ +/* Test for various situations where a new declaration of an + identifier conflicts with an earlier declaration which isn't in the + same scope. These are all undefined behavior per C89 sections + 6.1.2.2p7, 6.1.2.6p2, and 6.3.2.2p2/footnote 38 (C99 6.2.2p7 and + 6.2.7p2 - implicit declarations are invalid in C99). */ + +/* { dg-do compile } */ +/* { dg-options "-std=c89 -pedantic -Wall -Wno-unused" } */ + +/* Extern at function scope, clashing with extern at file scope */ + +extern int foo1; /* { dg-error "previous" } */ +extern int bar1(int); /* { dg-error "previous" } */ + +void test1(void) +{ + extern double foo1; /* { dg-error "conflict" } */ + extern double bar1(double); /* { dg-error "conflict" } */ +} + +/* Extern at file scope, clashing with extern at function scope */ + +void test2(void) +{ + extern double foo2; /* { dg-error "previous" } */ + extern double bar2(double); /* { dg-error "previous" } */ +} + +extern int foo2; /* { dg-error "conflict" } */ +extern int bar2(int); /* { dg-error "conflict" } */ + +/* Extern at function scope, clashing with extern at earlier function + scope. Also, don't be fooled by a typedef at file scope. */ + +typedef float baz3; /* { dg-bogus } */ + +void prime3(void) +{ + extern int foo3; /* { dg-error "previous" } */ + extern int bar3(int); /* { dg-error "previous" } */ + extern int baz3; /* { dg-error "previous" } */ +} + +void test3(void) +{ + extern double foo3; /* { dg-error "conflict" } */ + extern double bar3(double); /* { dg-error "conflict" } */ + extern double baz3; /* { dg-error "conflict" } */ +} + +/* Extern at function scope, clashing with previous implicit decl. */ + +void prime4(void) +{ + bar4(); /* { dg-error "previous|implicit" } */ +} + +void test4(void) +{ + extern double bar4(double); /* { dg-error "conflict" } */ +} + +/* Implicit decl, clashing with extern at previous function scope. */ + +void prime5(void) +{ + extern double bar5(double); /* { dg-error "previous" "" { xfail *-*-* } } */ +} + +void test5(void) +{ + bar5(1); /* { dg-error "implicit" } */ +} + +/* Extern then static, both at file scope. */ + +extern int test6(int); /* { dg-warning "previous" "" { xfail *-*-* } } */ +static int test6(int x) +{ return x; } /* { dg-warning "follows non-static" } */ + + +/* Extern then static, extern at previous function scope. */ + +void prime7(void) +{ + extern int test7(int); /* { dg-warning "previous" "" { xfail *-*-* } } */ +} + +static int test7(int x) +{ return x; } /* { dg-warning "follows non-static" } */ + +/* Implicit decl then static. */ + +void prime8(void) +{ + test8(); /* { dg-warning "previous" "" { xfail *-*-* } } */ + /* { dg-warning "implicit" "" { target *-*-* } 96 } */ +} + +static int test8(int x) +{ return x; } /* { dg-warning "follows non-static" } */