C identifier lookup speedups, 2/2
Zack Weinberg
zack@codesourcery.com
Fri Apr 11 04:27:00 GMT 2003
This half does tag lookups. It is more invasive than it might
otherwise have been, because part of the change is that the C front
end no longer puts parameter decls in their own binding contour; they
go in the same contour as variables declared at the outermost block
scope of a function. This makes a lot of special case gook (needed to
enforce the C standard's rules, which assume that the above two things
are indeed in the same contour) vanish. However, it also exposed
issues with language-independent code, *sigh*. And making this work
without rewriting large parts of c-parse.in is, well, a kludge.
The change to pushdecl is a bug fix, but the bug cannot be triggered
except in this new regime.
Bootstrapped i686-linux, and will apply simultaneously with part 1.
zw
* 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.
cp:
* decl.c: Update all calls to shadow_warning.
testsuite:
* gcc.dg/Wshadow-1.c: Update error regexps.
--- c-ids-1/gcc/c-common.c 2003-04-10 12:49:44.000000000 -0700
+++ c-ids-2/gcc/c-common.c 2003-04-10 12:52:32.000000000 -0700
@@ -4778,12 +4778,10 @@
}
/* 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 @@
/* 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");
--- c-ids-1/gcc/c-common.h 2003-04-10 12:49:44.000000000 -0700
+++ c-ids-2/gcc/c-common.h 2003-04-10 12:52:32.000000000 -0700
@@ -335,7 +335,7 @@
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
--- c-ids-1/gcc/c-decl.c 2003-04-10 12:49:46.000000000 -0700
+++ c-ids-2/gcc/c-decl.c 2003-04-10 12:52:32.000000000 -0700
@@ -184,29 +184,28 @@
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;
@@ -240,12 +239,6 @@
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;
@@ -276,9 +269,7 @@
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));
@@ -352,14 +343,18 @@
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 result;
}
/* Remove a binding level from a list and add it to the level chain. */
@@ -399,8 +394,7 @@
&& 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.
@@ -423,41 +417,45 @@
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;
- }
+ named_labels = 0;
- newlevel = make_binding_level ();
+ if (keep_next_if_subblocks)
+ {
+ /* 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;
- /* Add this level to the front of the chain (stack) of levels that
- are active. */
+ keep_next_level_flag = 0;
+ keep_next_if_subblocks = 0;
+ }
+ else
+ {
+ struct binding_level *newlevel = make_binding_level ();
- *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;
+ 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.
@@ -482,77 +480,25 @@
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;
-
- /* 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;
- }
+ functionbody |= current_binding_level->function_body;
+ keep |= (current_binding_level->keep || functionbody
+ || (current_binding_level->keep_if_subblocks && subblocks != 0));
/* 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 ());
-
- /* If there were any declarations or structure tags in that level,
- or if this level is a function body,
- create a BLOCK to record them for the life of this function. */
-
- block = 0;
- block_previously_created = (current_binding_level->this_block != 0);
- if (block_previously_created)
- block = current_binding_level->this_block;
- else if (keep || functionbody
- || (current_binding_level->keep_if_subblocks && subblocks != 0))
- block = make_node (BLOCK);
- if (block != 0)
- {
- BLOCK_VARS (block) = decls;
- BLOCK_SUBBLOCKS (block) = subblocks;
- }
-
- /* In each subblock, record that this is its superior. */
-
- for (link = subblocks; link; link = TREE_CHAIN (link))
- BLOCK_SUPERCONTEXT (link) = block;
-
- /* Clear out the meanings of the local variables of this level. */
+ 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)
@@ -564,31 +510,105 @@
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 (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);
- /* 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. */
+ /* Restore all tag-meanings of the outer levels
+ that were shadowed by this level. */
- if (functionbody)
+ 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 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. */
+ 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)
+ 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;
+ if (keep)
+ {
+ block = make_node (BLOCK);
+ BLOCK_VARS (block) = decls;
+ BLOCK_SUBBLOCKS (block) = subblocks;
+ TREE_USED (block) = 1;
+ }
+
+ /* In each subblock, record that this is its superior. */
+
+ for (link = subblocks; link; link = TREE_CHAIN (link))
+ BLOCK_SUPERCONTEXT (link) = block;
+
+ /* 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. */
+ decl = functionbody ? current_function_decl : block;
+ if (decl)
+ for (link = tags; link; link = TREE_CHAIN (link))
+ TYPE_CONTEXT (TREE_VALUE (link)) = decl;
+
+ /* If the level being exited is the top level of a function, check
+ over all the labels, and clear out the current (function local)
+ meanings of their names. Then add them to BLOCK_VARS. */
+
+ if (functionbody)
+ {
for (link = named_labels; link; link = TREE_CHAIN (link))
{
tree label = TREE_VALUE (link);
@@ -619,11 +639,8 @@
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)
@@ -633,30 +650,6 @@
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;
}
@@ -673,18 +666,14 @@
= 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
@@ -768,12 +757,7 @@
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)
{
@@ -781,6 +765,11 @@
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);
@@ -1595,46 +1584,31 @@
{
const char *name;
- if (old == 0)
- /* Nothing to shadow. */
+ /* 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));
- /* Warn unconditionally (constraint violation, C99 6.7p3 - params
- and locals declared at the outermost block scope of a function
- have the same scope, even though we give them different binding
- contours) if shadowing an argument at the top level of the body.
- This warning doesn't apply to the parms of a nested fcn. */
- if (! current_binding_level->parm_flag
- /* Check that this is one level down from the parms. */
- && current_binding_level->level_chain
- && current_binding_level->level_chain->parm_flag
- /* Check that the decl being shadowed
- comes from the parm level, one level up. */
- && chain_member (old, current_binding_level->level_chain->names))
- shadow_warning (SW_PARAM, true, name, old);
- /* Warnings for other cases of shadowing are optional. */
- 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)
- /* 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))
- {
- if (TREE_CODE (old) == PARM_DECL)
- shadow_warning (SW_PARAM, false, name, old);
- else if (DECL_CONTEXT (old) == 0)
- shadow_warning (SW_GLOBAL, false, name, old);
- else
- shadow_warning (SW_LOCAL, false, name, old);
- }
+ 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);
}
@@ -1771,14 +1745,18 @@
if (TREE_CODE (x) == TYPE_DECL)
clone_underlying_type (x);
- old = IDENTIFIER_SYMBOL_VALUE (name);
- if (scope != global_binding_level && old)
- {
- /* If storing a local value, there may already be one
- (inherited). If so, record it for restoration when this
- binding level ends. */
- warn_if_shadowing (x, old);
- scope->shadowed = tree_cons (name, old, scope->shadowed);
+ /* 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)
+ {
+ warn_if_shadowing (x, IDENTIFIER_SYMBOL_VALUE (name));
+ scope->shadowed = tree_cons (name, IDENTIFIER_SYMBOL_VALUE (name),
+ scope->shadowed);
}
/* Install the new declaration in the requested binding level. */
@@ -1860,8 +1838,10 @@
struct binding_level *scope;
scope = current_binding_level;
- while (scope->level_chain->parm_flag == 0)
+ 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),
@@ -2174,55 +2154,50 @@
/* 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;
+
+ if (!tag)
+ return 0;
- for (level = binding_level; level; level = level->level_chain)
+ /* We only care about whether it's in this level if
+ thislevel_only was set or it might be a type clash. */
+ if (thislevel_only || TREE_CODE (tag) != code)
{
- tree tail;
- for (tail = level->tags; tail; tail = TREE_CHAIN (tail))
- {
- if (TREE_PURPOSE (tail) == name)
- {
- if (TREE_CODE (TREE_VALUE (tail)) != code)
- {
- /* Definition isn't the kind we were looking for. */
- pending_invalid_xref = name;
- pending_invalid_xref_file = input_filename;
- pending_invalid_xref_line = lineno;
- /* If in the same binding level as a declaration as a tag
- of a different type, this must not be allowed to
- shadow that tag, so give the error immediately.
- (For example, "struct foo; union foo;" is invalid.) */
- if (thislevel)
- pending_xref_error ();
- }
- return TREE_VALUE (tail);
- }
- }
- if (! level->tag_transparent)
- {
- if (thislevel_only)
- return NULL_TREE;
- thislevel = 0;
- }
+ if (current_binding_level == global_binding_level
+ || purpose_member (name, current_binding_level->tags))
+ thislevel = 1;
}
- return NULL_TREE;
+
+ if (thislevel_only && !thislevel)
+ return 0;
+
+ if (TREE_CODE (tag) != code)
+ {
+ /* Definition isn't the kind we were looking for. */
+ pending_invalid_xref = name;
+ pending_invalid_xref_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
@@ -2241,26 +2216,6 @@
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.
@@ -2491,7 +2446,7 @@
/* 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++;
@@ -2507,7 +2462,7 @@
}
else
{
- t = lookup_tag (code, name, current_binding_level, 1);
+ t = lookup_tag (code, name, 1);
if (t == 0)
{
@@ -4761,7 +4716,7 @@
/* 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
@@ -4815,7 +4770,7 @@
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))
@@ -5243,7 +5198,7 @@
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)
{
@@ -5672,7 +5627,6 @@
pushlevel (0);
declare_parm_level (1);
- current_binding_level->subblocks_tag_transparent = 1;
make_decl_rtl (current_function_decl, NULL);
@@ -6147,13 +6101,27 @@
{
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. */
--- c-ids-1/gcc/cfglayout.c 2003-04-10 12:49:46.000000000 -0700
+++ c-ids-2/gcc/cfglayout.c 2003-04-10 12:52:33.000000000 -0700
@@ -239,6 +239,8 @@
break;
case NOTE_INSN_BLOCK_END:
block = BLOCK_SUPERCONTEXT (block);
+ if (block && TREE_CODE (block) == FUNCTION_DECL)
+ block = 0;
delete_insn (insn);
break;
default:
--- c-ids-1/gcc/cp/decl.c 2003-04-10 12:49:57.000000000 -0700
+++ c-ids-2/gcc/cp/decl.c 2003-04-10 12:52:48.000000000 -0700
@@ -4001,7 +4001,7 @@
}
if (warn_shadow && !err)
- shadow_warning (SW_PARAM, false,
+ shadow_warning (SW_PARAM,
IDENTIFIER_POINTER (name), oldlocal);
}
@@ -4019,12 +4019,12 @@
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);
}
}
--- c-ids-1/gcc/function.c 2003-04-10 12:49:48.000000000 -0700
+++ c-ids-2/gcc/function.c 2003-04-10 12:52:37.000000000 -0700
@@ -5994,10 +5994,16 @@
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)
--- c-ids-1/gcc/testsuite/gcc.dg/Wshadow-1.c 2003-03-26 13:23:56.000000000 -0800
+++ c-ids-2/gcc/testsuite/gcc.dg/Wshadow-1.c 2003-04-10 12:45:30.000000000 -0700
@@ -10,10 +10,10 @@
{
}
-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" } */
More information about the Gcc-patches
mailing list