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