[stree] Committed: initial stree infrastructure, and stree version of enumerators

Matt Austern austern@apple.com
Tue Mar 9 00:42:00 GMT 2004


First installment of the stree work.  We started with enumerators 
because they're simple, and also because in some environments (e.g. 
files that include Apple's Carbon.h header) there are an awful lot of 
them.  The goal of this work is to avoid having the compiler allocate 
memory for unused declarations, and, in any real program, the vast 
majority of Carbon.h enumerators are never used.

This doesn't break any g++.dg tests.  For files with many enumerators, 
it reduces memory use by about 30%.

Two important points about this work.

First: This patch is Geoff Keating's work, not mine.  I'm doing the CVS 
stuff for him because he's on vacation and we need to get this work 
started.

Second: What makes this work possible is that strees are not a 
replacement for  trees.  We can always convert an stree to a tree when 
we need a tree; and we can always decide to generate a tree if we're 
dealing with something that's too complicated for the stree generation 
machinery.

This is more proof-of-concept than anything else.  Some of the next 
steps:
  - Make sure this doesn't cause omission of debug information.
  - Make sure there aren't any global scans of decls that will cause 
enumerator strees to get expanded unnecessarily.
  - Extend the work to enumeration types, not just the enumerators.
  - Handle more complicated kinds of enum declarations, like enums 
defined in classes.
  - Clean up the infrastructure: see if this complicated memory 
management is really necessary for performance, and encapsulate the 
stree format better so that it's easier to extend to more kinds of 
decls.
  - Define strees for other kinds of classes: most importantly, function 
declarations (not definitions) and class definitions.

(Oh, and in case you're wondering what the 's' in stree stands for, the 
answer is: nothing.)

			--Matt


  Index: ChangeLog.stree
===================================================================
RCS file: ChangeLog.stree
diff -N ChangeLog.stree
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- ChangeLog.stree	9 Mar 2004 00:36:29 -0000
***************
*** 0 ****
--- 1,13 ----
+ 2004-03-08  Matt Austern  <austern@apple.com>
+         * ChangeLog.stree: New.
+ 	* Makefile.in: Add stree.[ch] to the build.
+ 	* stree.c: New.
+ 	* stree.h: New.
+ 	
+ 
+ Local Variables:
+ mode: change-log
+ left-margin: 8
+ fill-column: 76
+ change-log-default-name: "ChangeLog.stree"
+ End:
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1260
diff -p -r1.1260 Makefile.in
*** Makefile.in	5 Mar 2004 10:32:53 -0000	1.1260
--- Makefile.in	9 Mar 2004 00:36:30 -0000
*************** OBJS-common = \
*** 865,871 ****
    sibcall.o simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o 	 
   \
    targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o unroll.o	 
   \
    varasm.o varray.o version.o vmsdbgout.o xcoffout.o alloc-pool.o	   \
!  et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o

   OBJS-md = $(out_object_file)
   OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o 
tree-inline.o	   \
--- 865,872 ----
    sibcall.o simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o 	 
   \
    targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o unroll.o	 
   \
    varasm.o varray.o version.o vmsdbgout.o xcoffout.o alloc-pool.o	   \
!  et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o 
passes.o	   \
!  stree.o

   OBJS-md = $(out_object_file)
   OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o 
tree-inline.o	   \
*************** ifcvt.o : ifcvt.c $(CONFIG_H) $(SYSTEM_H
*** 1860,1865 ****
--- 1861,1867 ----
   params.o : params.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) 
$(PARAMS_H) toplev.h
   hooks.o: hooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) 
$(HOOKS_H)
   pretty-print.o: $(CONFIG_H) $(SYSTEM_H) pretty-print.c 
$(PRETTY_PRINT_H)
+ stree.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h stree.h $(TREE_H) 
gt-stree.h

   $(out_object_file): $(out_file) $(CONFIG_H) coretypes.h $(TM_H) 
$(TREE_H) $(GGC_H) \
      $(RTL_H) $(REGS_H) hard-reg-set.h real.h insn-config.h 
conditions.h \
*************** GTFILES = $(srcdir)/input.h $(srcdir)/co
*** 2092,2097 ****
--- 2094,2100 ----
     $(srcdir)/reg-stack.c $(srcdir)/cfglayout.c $(srcdir)/langhooks.c \
     $(srcdir)/sdbout.c $(srcdir)/stmt.c $(srcdir)/stor-layout.c \
     $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \
+   $(srcdir)/stree.h $(srcdir)/stree.c \
     $(out_file) \
     @all_gtfiles@

*************** gt-expr.h gt-sdbout.h gt-optabs.h gt-bit
*** 2108,2114 ****
   gt-dwarf2out.h gt-ra-build.h gt-reg-stack.h gt-dwarf2asm.h \
   gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parse.h \
   gt-c-pragma.h gtype-c.h gt-input.h gt-cfglayout.h \
! gt-stringpool.h gt-langhooks.h : s-gtype ; @true

   gtyp-gen.h: s-gtyp-gen ; @true
   s-gtyp-gen: Makefile
--- 2111,2117 ----
   gt-dwarf2out.h gt-ra-build.h gt-reg-stack.h gt-dwarf2asm.h \
   gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parse.h \
   gt-c-pragma.h gtype-c.h gt-input.h gt-cfglayout.h \
! gt-stringpool.h gt-langhooks.h gt-stree.h : s-gtype ; @true

   gtyp-gen.h: s-gtyp-gen ; @true
   s-gtyp-gen: Makefile
Index: stree.c
===================================================================
RCS file: stree.c
diff -N stree.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- stree.c	9 Mar 2004 00:36:30 -0000
***************
*** 0 ****
--- 1,172 ----
+ /* S-tree representation manipulation.
+    Copyright (C) 2004 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING.  If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.  */
+
+ #include "config.h"
+ #include "system.h"
+ #include "coretypes.h"
+ #include "stree.h"
+ #include "tree.h"
+ #include "ggc.h"
+
+ /* These are chosen so that tab_chunksize is a power of 2 for
+    efficient lookup, and so that they fill a typical machine's
+    page.  */
+ enum {
+   tab_chunksize = 4096,
+   initial_tabs = 1024
+ };
+
+ struct st_chunk GTY(()) {
+   unsigned char d[1];
+ };
+
+ static GTY(()) s_tree_i last_s_tree;
+ static GTY(()) size_t num_tabs;
+ static GTY((length ("num_tabs"))) struct st_chunk ** tabs;
+
+ void
+ get_s_tree_iter (s_tree_iter * si_p, s_tree_i st)
+ {
+   st--;
+   *si_p = tabs[st / tab_chunksize]->d + (st % tab_chunksize);
+ }
+
+ tree
+ sti_const_int_tree (s_tree_iter * si_p)
+ {
+   unsigned HOST_WIDE_INT l = 0, h = 0, c;
+   unsigned char last;
+   int i = 0;
+
+   do {
+     last = **si_p;
+     c = last & 0x7F;
+     if (i < HOST_BITS_PER_WIDE_INT)
+       l |= c << i;
+     if (i >= HOST_BITS_PER_WIDE_INT)
+       h |= c << (i - HOST_BITS_PER_WIDE_INT);
+     else if (i > HOST_BITS_PER_WIDE_INT - 7)
+       h |= c >> (HOST_BITS_PER_WIDE_INT - i);
+     i += 7;
+     (*si_p)++;
+   } while (last & 0x80);
+   return build_int_2 (l, h);
+ }
+
+ s_tree_i
+ build_s_tree (unsigned char type, ...)
+ {
+   va_list v;
+   int kind;
+   s_tree_i result;
+
+   unsigned char stagea[256];
+   unsigned char *stage = stagea;
+   unsigned char *stagep = stage;
+   size_t stage_size;
+
+   /* FIXME this macro needs to be enhanced to deal with large strees. 
  */
+ #define require(n) do {						\
+     if (stagep - stage + (size_t)(n) >= sizeof (stagea))  abort ();	\
+   } while (0)
+
+ #define pb(b) do {				\
+     require (1);				\
+     *stagep++ = (b);				\
+   } while (0)
+
+   va_start (v, type);
+
+   pb (type);
+   while (1) {
+     kind = va_arg (v, int);
+     switch (kind)
+       {
+       case ST_LAST:
+ 	goto last_item;
+ 	
+       case ST_TREE:
+ 	{
+ 	  tree t = va_arg (v, tree);
+ 	  require (sizeof (tree));
+ 	  memcpy (stagep, &t, sizeof (tree));
+ 	  stagep += sizeof (tree);
+ 	  break;
+ 	}
+
+       case ST_TREE_INT:
+ 	{
+ 	  tree t = va_arg (v, tree);
+ 	  unsigned HOST_WIDE_INT l = TREE_INT_CST_LOW (t);
+ 	  unsigned HOST_WIDE_INT h = TREE_INT_CST_HIGH (t);
+ 	  require ((HOST_BITS_PER_WIDE_INT * 2 + 6) / 7);
+ 	  while (l > 0x7F || h != 0)
+ 	    {
+ 	      *stagep++ = l | 0x80;
+ 	      l = (l >> 7) | (h << (HOST_BITS_PER_WIDE_INT - 7));
+ 	      h >>= 7;
+ 	    }
+ 	  *stagep++ = l;
+ 	  break;
+ 	}
+
+       default:
+ 	abort ();
+       }
+   }
+  last_item:
+
+   stage_size = stagep - stage;
+   if (last_s_tree % tab_chunksize > 0
+       && last_s_tree % tab_chunksize + stage_size > tab_chunksize)
+     last_s_tree += tab_chunksize - last_s_tree % tab_chunksize;
+
+   if (num_tabs <= last_s_tree / tab_chunksize)
+     {
+       if (num_tabs == 0)
+ 	{
+ 	  num_tabs = initial_tabs;
+ 	  tabs = ggc_calloc (initial_tabs, sizeof (*tabs));
+ 	}
+       else
+ 	{
+ 	  size_t i;
+ 	
+ 	  num_tabs += initial_tabs;
+ 	  tabs = ggc_realloc (tabs, num_tabs * sizeof (*tabs));
+ 	  for (i = num_tabs - initial_tabs; i < num_tabs; i++)
+ 	    tabs[i] = NULL;
+ 	}
+     }
+
+   if (tabs[last_s_tree / tab_chunksize] == NULL)
+     {
+       size_t sz = stage_size > tab_chunksize ? stage_size : 
tab_chunksize;
+       tabs[last_s_tree / tab_chunksize] = ggc_alloc (sz);
+     }
+
+   memcpy (tabs[last_s_tree / tab_chunksize]->d + last_s_tree % 
tab_chunksize,
+ 	  stage, stage_size);
+   result = last_s_tree;
+   last_s_tree += stage_size > tab_chunksize ? tab_chunksize : 
stage_size;
+   return result + 1;
+ }
+
+ #include "gt-stree.h"
Index: stree.h
===================================================================
RCS file: stree.h
diff -N stree.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- stree.h	9 Mar 2004 00:36:30 -0000
***************
*** 0 ****
--- 1,73 ----
+ /* S-tree representation manipulation.
+    Copyright (C) 2004 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING.  If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.  */
+
+ #ifndef GCC_STREE_H
+ #define GCC_STREE_H
+
+ /* S-trees are a compressed representation of trees, for declarations
+    (and types).  They are motivated by the observation that GCC spends
+    a lot of its time allocating memory for, and filling in, trees for
+    declarations that are subsequently never used again.  */
+
+ /* An index of a s_tree.  */
+ typedef unsigned long s_tree_i;
+
+ struct s_tree_i_or_tree GTY (()) {
+   tree t;
+   s_tree_i st;
+ };
+
+ #define NULL_S_TREE_I 0
+
+ /* Given an s_tree_i, return the corresponding tree.  */
+ extern tree s_tree_to_tree (tree, s_tree_i);
+
+ /* Parse a s_tree.  */
+ typedef unsigned char * s_tree_iter;
+ extern void get_s_tree_iter (s_tree_iter *, s_tree_i);
+ extern tree sti_const_int_tree (s_tree_iter *);
+
+ static inline unsigned char
+ sti_uchar (s_tree_iter *ti)
+ {
+   unsigned char u = **ti;
+   (*ti)++;
+   return u;
+ }
+
+ static inline tree
+ sti_tree (s_tree_iter *ti)
+ {
+   tree t;
+   memcpy (&t, *ti, sizeof (tree));
+   *ti += sizeof (tree);
+   return t;
+ }
+
+ /* Build a s-tree.  */
+ enum {
+   ST_LAST,
+   ST_TREE,
+   ST_TREE_INT
+ };
+
+ extern s_tree_i build_s_tree (unsigned char, ...);
+
+ #endif /* GCC_STREE_H */
Index: cp/ChangeLog.stree
===================================================================
RCS file: cp/ChangeLog.stree
diff -N cp/ChangeLog.stree
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- cp/ChangeLog.stree	9 Mar 2004 00:36:33 -0000
***************
*** 0 ****
--- 1,49 ----
+ 2004-03-08  Matt Austern  <austern@apple.com>
+
+ 	* ChangeLog.stree: New.
+ 	* cp-tree.h (IDENTIFIER_VALUE): Go through binding_value_tree
+ 	instead of using value field directly.
+ 	* decl.c (poplevel): Fix handling of shadowed declarations.
+ 	(enum_data): New static variable, enumeration currently being built.
+ 	(start_enum): Initialize enum_data.
+ 	(finish_enum): Use enum_data for computing the underlying type.
+ 	(s_tree_to_tree): New function.
+ 	(build_enumerator): Update enum_data.  For simple cases build an
+ 	s-tree instead of a full tree decl.
+ 	* name-lookup.h (cxx_binding): Change value field to be an
+ 	s_tree_i_or_tree tagged union.
+ 	(binding_value_tree): Return tree version of value field, creating
+ 	it from an stree if necessary.
+ 	(push_s_decl): New.  Similar to pushdecl, but for stree decls.
+ 	Fall back to pushdecl in complicated cases.
+ 	* name-lookup.c (cxx_binding_make): Take account of the fact that
+ 	value field is no longer a simple tree pointer.
+ 	(pop_binding): Ditto.
+ 	(supplement_binding): Ditto.
+ 	(push_local_binding): Ditto.
+ 	(maybe_inject_for_scope_var): Ditto.
+ 	(set_identifier_type_value_with_scope): Ditto.
+ 	(push_overloaded_decl): Ditto.
+ 	(do_nonmember_using_decl): Ditto.
+ 	(lookup_tag): Ditto.
+ 	(poplevel_class): Ditto.
+ 	(push_class_binding): Ditto.
+ 	(push_class_binding): Ditto.
+ 	(push_class_level_binding): Ditto.
+ 	(namespace_binding): Ditto.
+ 	(set_namespace_binding): Ditto.
+ 	(do_toplevel_using_decl): Ditto.
+ 	(ambiguous_decl): Ditto.
+ 	(lookup_namespace_name): Ditto.
+ 	(unqualified_namespace_lookup): Ditto.
+ 	(lookup_qualified_name): Ditto.	
+ 	(qualified_lookup_using_namespace): Ditto.
+ 	(lookup_name_real): Ditto.
+ 	
+ 
+ Local Variables:
+ mode: change-log
+ left-margin: 8
+ fill-column: 76
+ change-log-default-name: "ChangeLog.stree"
+ End:
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.954
diff -p -r1.954 cp-tree.h
*** cp/cp-tree.h	17 Feb 2004 18:32:41 -0000	1.954
--- cp/cp-tree.h	9 Mar 2004 00:36:34 -0000
*************** typedef enum cp_id_kind
*** 374,381 ****

   /* The IDENTIFIER_VALUE is the value of the IDENTIFIER_BINDING, or
      NULL_TREE if there is no binding.  */
! #define IDENTIFIER_VALUE(NODE)			\
!   (IDENTIFIER_BINDING (NODE) ? IDENTIFIER_BINDING (NODE)->value : 
NULL)

   /* If IDENTIFIER_CLASS_VALUE is set, then NODE is bound in the current
      class, and IDENTIFIER_CLASS_VALUE is the value binding.  This is
--- 374,383 ----

   /* The IDENTIFIER_VALUE is the value of the IDENTIFIER_BINDING, or
      NULL_TREE if there is no binding.  */
! #define IDENTIFIER_VALUE(NODE)					\
!   (IDENTIFIER_BINDING (NODE)					\
!    ? binding_value_tree ((NODE), IDENTIFIER_BINDING (NODE))	\
!    : NULL)

   /* If IDENTIFIER_CLASS_VALUE is set, then NODE is bound in the current
      class, and IDENTIFIER_CLASS_VALUE is the value binding.  This is
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1191
diff -p -r1.1191 decl.c
*** cp/decl.c	4 Mar 2004 22:42:57 -0000	1.1191
--- cp/decl.c	9 Mar 2004 00:36:35 -0000
*************** poplevel (int keep, int reverse, int fun
*** 582,588 ****
   	       keep the binding of the inner `i' in this case.  */
   	    pop_binding (DECL_NAME (link), link);
   	  else if ((outer_binding
! 		    && (TREE_CODE (outer_binding->value) == TYPE_DECL))
   		   || (ns_binding && TREE_CODE (ns_binding) == TYPE_DECL))
   	    /* Here, we have something like:

--- 582,590 ----
   	       keep the binding of the inner `i' in this case.  */
   	    pop_binding (DECL_NAME (link), link);
   	  else if ((outer_binding
! 		    && (TREE_CODE (binding_value_tree (DECL_NAME (link),
! 						       outer_binding))
! 			== TYPE_DECL))
   		   || (ns_binding && TREE_CODE (ns_binding) == TYPE_DECL))
   	    /* Here, we have something like:

*************** poplevel (int keep, int reverse, int fun
*** 603,610 ****

   	      /* Keep track of what should have happened when we
   		 popped the binding.  */
! 	      if (outer_binding && outer_binding->value)
! 		DECL_SHADOWED_FOR_VAR (link) = outer_binding->value;

   	      /* Add it to the list of dead variables in the next
   		 outermost binding to that we can remove these when we
--- 605,613 ----

   	      /* Keep track of what should have happened when we
   		 popped the binding.  */
! 	      if (outer_binding && binding_value_tree (DECL_NAME (link),
! 						       outer_binding))
! 		DECL_SHADOWED_FOR_VAR (link) = outer_binding->value.t;

   	      /* Add it to the list of dead variables in the next
   		 outermost binding to that we can remove these when we
*************** xref_basetypes (tree ref, tree base_list
*** 9683,9688 ****
--- 9686,9704 ----
   }

   
+ /* The C++ standard doesn't permit you to define any other types while
+    an enum definition is in progress, so it's safe to have these just
+    be static variables.  */
+
+ /* The enum type that is currently being built.  */
+ static struct {
+   tree current_type;
+   tree last_value;
+   tree max_value;
+   tree min_value;
+ } enum_data;
+
+
   /* Begin compiling the definition of an enumeration type.
      NAME is its name (or null if anonymous).
      Returns the type object, as yet incomplete.
*************** start_enum (tree name)
*** 9715,9720 ****
--- 9731,9741 ----
         pushtag (name, enumtype, 0);
       }

+   enum_data.current_type = enumtype;
+   enum_data.last_value = NULL_TREE;
+   enum_data.max_value = NULL_TREE;
+   enum_data.min_value = NULL_TREE;
+
     return enumtype;
   }

*************** finish_enum (tree enumtype)
*** 9728,9735 ****
     tree values;
     tree decl;
     tree value;
-   tree minnode;
-   tree maxnode;
     tree t;
     bool unsignedp;
     int lowprec;
--- 9749,9754 ----
*************** finish_enum (tree enumtype)
*** 9738,9743 ****
--- 9757,9764 ----
     integer_type_kind itk;
     tree underlying_type = NULL_TREE;

+   enum_data.current_type = NULL;
+
     /* We built up the VALUES in reverse order.  */
     TYPE_VALUES (enumtype) = nreverse (TYPE_VALUES (enumtype));

*************** finish_enum (tree enumtype)
*** 9756,9814 ****
         return;
       }

!   /* Determine the minimum and maximum values of the enumerators.  */
!   if (TYPE_VALUES (enumtype))
!     {
!       minnode = maxnode = NULL_TREE;
!
!       for (values = TYPE_VALUES (enumtype);
! 	   values;
! 	   values = TREE_CHAIN (values))
! 	{
! 	  decl = TREE_VALUE (values);
!
! 	  /* [dcl.enum]: Following the closing brace of an enum-specifier,
! 	     each enumerator has the type of its enumeration.  Prior to the
! 	     closing brace, the type of each enumerator is the type of its
! 	     initializing value.  */
! 	  TREE_TYPE (decl) = enumtype;
!
! 	  /* Update the minimum and maximum values, if appropriate.  */
! 	  value = DECL_INITIAL (decl);
! 	  /* Figure out what the minimum and maximum values of the
! 	     enumerators are.  */
! 	  if (!minnode)
! 	    minnode = maxnode = value;
! 	  else if (tree_int_cst_lt (maxnode, value))
! 	    maxnode = value;
! 	  else if (tree_int_cst_lt (value, minnode))
! 	    minnode = value;
!
! 	  /* Set the TREE_TYPE for the values as well.  That's so that when
! 	     we call decl_constant_value we get an entity of the right type
! 	     (but with the constant value).  But first make a copy so we
! 	     don't clobber shared INTEGER_CSTs.  */
! 	  if (TREE_TYPE (value) != enumtype)
! 	    {
! 	      value = DECL_INITIAL (decl) = copy_node (value);
! 	      TREE_TYPE (value) = enumtype;
! 	    }
! 	}
!     }
!   else
!     /* [dcl.enum]
!
!        If the enumerator-list is empty, the underlying type is as if
!        the enumeration had a single enumerator with value 0.  */
!     minnode = maxnode = integer_zero_node;

     /* Compute the number of bits require to represent all values of the
!      enumeration.  We must do this before the type of MINNODE and
!      MAXNODE are transformed, since min_precision relies on the
        TREE_TYPE of the value it is passed.  */
!   unsignedp = tree_int_cst_sgn (minnode) >= 0;
!   lowprec = min_precision (minnode, unsignedp);
!   highprec = min_precision (maxnode, unsignedp);
     precision = MAX (lowprec, highprec);

     /* Determine the underlying type of the enumeration.
--- 9777,9796 ----
         return;
       }

!   /* [dcl.enum]
!
!      If the enumerator-list is empty, the underlying type is as if
!      the enumeration had a single enumerator with value 0.  */
!   if (!enum_data.last_value)
!     enum_data.max_value = enum_data.min_value = integer_zero_node;

     /* Compute the number of bits require to represent all values of the
!      enumeration.  We must do this before the type of 
ENUM_DATA.MIN_VALUE and
!      ENUM_DATA.MAX_VALUE are transformed, since min_precision relies 
on the
        TREE_TYPE of the value it is passed.  */
!   unsignedp = tree_int_cst_sgn (enum_data.min_value) >= 0;
!   lowprec = min_precision (enum_data.min_value, unsignedp);
!   highprec = min_precision (enum_data.max_value, unsignedp);
     precision = MAX (lowprec, highprec);

     /* Determine the underlying type of the enumeration.
*************** finish_enum (tree enumtype)
*** 9871,9885 ****
     TREE_UNSIGNED (enumtype) = TREE_UNSIGNED (underlying_type);

     /* Convert each of the enumerators to the type of the underlying
!      type of the enumeration.  */
     for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN 
(values))
       {
         decl = TREE_VALUE (values);
!       value = perform_implicit_conversion (underlying_type,
! 					   DECL_INITIAL (decl));
         TREE_TYPE (value) = enumtype;
!       DECL_INITIAL (decl) = value;
!       TREE_VALUE (values) = value;
       }

     /* Fix up all variant types of this enum type.  */
--- 9853,9889 ----
     TREE_UNSIGNED (enumtype) = TREE_UNSIGNED (underlying_type);

     /* Convert each of the enumerators to the type of the underlying
!      type of the enumeration.  This might do nothing if all the
!      enumerators are being represented as s_trees.  */
     for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN 
(values))
       {
         decl = TREE_VALUE (values);
!
!       if (TREE_CODE (decl) == CONST_DECL)
! 	{
! 	  /* [dcl.enum]: Following the closing brace of an enum-specifier,
! 	     each enumerator has the type of its enumeration.  Prior to the
! 	     closing brace, the type of each enumerator is the type of its
! 	     initializing value.  */
! 	  TREE_TYPE (decl) = enumtype;
! 	  value = DECL_INITIAL (decl);
! 	}
!       else
! 	value = decl;
!
!       /* Set the TREE_TYPE for the values as well.  That's so that 
when
! 	 we call decl_constant_value we get an entity of the right type
! 	 (but with the constant value).  But first make a copy so we
! 	 don't clobber shared INTEGER_CSTs.  */
!       value = copy_node (value);
!       value = perform_implicit_conversion (underlying_type, value);
         TREE_TYPE (value) = enumtype;
!
!       if (TREE_CODE (decl) == CONST_DECL)
! 	{
! 	  DECL_INITIAL (decl) = value;
! 	  TREE_VALUE (values) = value;
! 	}
       }

     /* Fix up all variant types of this enum type.  */
*************** finish_enum (tree enumtype)
*** 9901,9906 ****
--- 9905,9977 ----
     rest_of_type_compilation (enumtype, namespace_bindings_p ());
   }

+ enum cp_stree {
+   STREE_ENUM_CONSTANT = 1
+ };
+
+ tree
+ s_tree_to_tree (tree name, s_tree_i s)
+ {
+   s_tree_iter si;
+
+   get_s_tree_iter (&si, s);
+
+   switch ((enum cp_stree) sti_uchar (&si))
+     {
+     case STREE_ENUM_CONSTANT:
+       {
+ 	tree enumtype;
+ 	tree value;
+
+ 	enumtype = sti_tree (&si);
+ 	value = sti_const_int_tree (&si);
+ 	if (enumtype == enum_data.current_type)
+ 	  {
+ 	    tree decl;
+ 	    tree context;
+ 	    tree li;
+ 	
+ 	    context = current_scope ();
+ 	    if (!context)
+ 	      context = current_namespace;
+
+ 	    decl = build_decl (CONST_DECL, name, enumtype);
+ 	    DECL_CONTEXT (decl) = FROB_CONTEXT (context);
+ 	    TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1;
+ 	    DECL_INITIAL (decl) = value;
+
+ 	    for (li = TYPE_VALUES (enumtype); li; li = TREE_CHAIN (li))
+ 	      if (TREE_CODE (TREE_VALUE (li)) != CONST_DECL
+ 		  && tree_int_cst_equal (TREE_VALUE (li), value))
+ 		{
+ 		  TREE_VALUE (li) = decl;
+ 		  return decl;
+ 		}
+ 	    abort ();
+ 	  }
+ 	else
+ 	  {
+ 	    tree value_type;
+ 	    tree decl;
+ 	
+ 	    value_type = TREE_TYPE (TREE_VALUE (TYPE_VALUES (enumtype)));
+ 	    value = copy_node (value);
+ 	    TREE_TYPE (value) = enumtype;
+
+ 	    decl = build_decl (CONST_DECL, name, enumtype);
+ 	    DECL_CONTEXT (decl) = FROB_CONTEXT (TYPE_CONTEXT (enumtype));
+ 	    TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1;
+ 	    DECL_INITIAL (decl) = value;
+ 	    return decl;
+ 	  }
+       }
+       break;
+
+     default:
+       abort ();
+     }
+ }
+
   /* Build and install a CONST_DECL for an enumeration constant of the
      enumeration type ENUMTYPE whose NAME and VALUE (if any) are 
provided.
      Assignment of sequential values by default is handled here.  */
*************** build_enumerator (tree name, tree value,
*** 9938,9955 ****
         /* Default based on previous value.  */
         if (value == NULL_TREE)
   	{
! 	  tree prev_value;
!
! 	  if (TYPE_VALUES (enumtype))
   	    {
! 	      /* The next value is the previous value ...  */
! 	      prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES 
(enumtype)));
! 	      /* ... plus one.  */
   	      value = cp_build_binary_op (PLUS_EXPR,
! 					  prev_value,
   					  integer_one_node);

! 	      if (tree_int_cst_lt (value, prev_value))
   		error ("overflow in enumeration values at `%D'", name);
   	    }
   	  else
--- 10009,10022 ----
         /* Default based on previous value.  */
         if (value == NULL_TREE)
   	{
! 	  if (enum_data.last_value)
   	    {
! 	      /* The next value is the previous value plus one.  */
   	      value = cp_build_binary_op (PLUS_EXPR,
! 					  enum_data.last_value,
   					  integer_one_node);

! 	      if (tree_int_cst_lt (value, enum_data.last_value))
   		error ("overflow in enumeration values at `%D'", name);
   	    }
   	  else
*************** build_enumerator (tree name, tree value,
*** 9958,9969 ****
--- 10025,10060 ----

         /* Remove no-op casts from the value.  */
         STRIP_TYPE_NOPS (value);
+
+       /* Update the value information.  */
+       if (!enum_data.last_value)
+ 	enum_data.max_value = enum_data.min_value = value;
+       else if (tree_int_cst_lt (enum_data.max_value, value))
+ 	enum_data.max_value = value;
+       else if (tree_int_cst_lt (value, enum_data.min_value))
+ 	enum_data.min_value = value;
+       enum_data.last_value = value;
       }

     /* C++ associates enums with global, function, or class 
declarations.  */
     context = current_scope ();
     if (!context)
       context = current_namespace;
+
+   /* If this code can handle it, build a s-tree.  */
+   if (!processing_template_decl && (!context || context != 
current_class_type))
+     {
+       s_tree_i s;
+
+       s = build_s_tree (STREE_ENUM_CONSTANT, ST_TREE, enumtype,
+ 			ST_TREE_INT, value, ST_LAST);
+
+       /* Add this enumeration constant to the list for this type.  */
+       TYPE_VALUES (enumtype) = tree_cons (name, value, TYPE_VALUES 
(enumtype));
+
+       push_s_decl (name, s);
+       return;
+     }

     /* Build the actual enumeration constant.  Note that the enumeration
       constants have the type of their initializers until the
Index: cp/name-lookup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.c,v
retrieving revision 1.42
diff -p -r1.42 name-lookup.c
*** cp/name-lookup.c	1 Mar 2004 06:23:38 -0000	1.42
--- cp/name-lookup.c	9 Mar 2004 00:36:35 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 25,30 ****
--- 25,31 ----
   #include "tm.h"
   #include "flags.h"
   #include "tree.h"
+ #include "stree.h"
   #include "cp-tree.h"
   #include "name-lookup.h"
   #include "timevar.h"
*************** Boston, MA 02111-1307, USA.  */
*** 33,39 ****
   #include "debug.h"

   static cxx_scope *innermost_nonclass_level (void);
! static tree select_decl (cxx_binding *, int);
   static cxx_binding *binding_for_name (cxx_scope *, tree);
   static tree lookup_name_current_level (tree);
   static void push_local_binding (tree, tree, int);
--- 34,40 ----
   #include "debug.h"

   static cxx_scope *innermost_nonclass_level (void);
! static tree select_decl (tree, cxx_binding *, int);
   static cxx_binding *binding_for_name (cxx_scope *, tree);
   static tree lookup_name_current_level (tree);
   static void push_local_binding (tree, tree, int);
*************** cxx_binding_make (tree value, tree type)
*** 337,343 ****
     else
       binding = ggc_alloc (sizeof (cxx_binding));

!   binding->value = value;
     binding->type = type;
     binding->previous = NULL;

--- 338,345 ----
     else
       binding = ggc_alloc (sizeof (cxx_binding));

!   binding->value.t = value;
!   binding->value.st = NULL_S_TREE_I;
     binding->type = type;
     binding->previous = NULL;

*************** pop_binding (tree id, tree decl)
*** 394,407 ****

     /* The DECL will be either the ordinary binding or the type
        binding for this identifier.  Remove that binding.  */
!   if (binding->value == decl)
!     binding->value = NULL_TREE;
     else if (binding->type == decl)
       binding->type = NULL_TREE;
     else
       abort ();

!   if (!binding->value && !binding->type)
       {
         /* We're completely done with the innermost binding for this
   	 identifier.  Unhook it from the list of bindings.  */
--- 396,412 ----

     /* The DECL will be either the ordinary binding or the type
        binding for this identifier.  Remove that binding.  */
!   if (binding->value.t == decl)
!     {
!       binding->value.t = NULL_TREE;
!       binding->value.st = NULL_S_TREE_I;
!     }
     else if (binding->type == decl)
       binding->type = NULL_TREE;
     else
       abort ();

!   if (!binding->value.t && !binding->value.st && !binding->type)
       {
         /* We're completely done with the innermost binding for this
   	 identifier.  Unhook it from the list of bindings.  */
*************** pop_binding (tree id, tree decl)
*** 428,442 ****

      It's the responsibility of the caller to check that
      inserting this name is valid here.  Returns nonzero if the new 
binding
!    was successful.  */

   static bool
! supplement_binding (cxx_binding *binding, tree decl)
   {
!   tree bval = binding->value;
     bool ok = true;

     timevar_push (TV_NAME_LOOKUP);
     if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
       /* The new name is the type name.  */
       binding->type = decl;
--- 433,451 ----

      It's the responsibility of the caller to check that
      inserting this name is valid here.  Returns nonzero if the new 
binding
!    was successful.
!
!    You might think that NAME and DECL_NAME (DECL) would be the same,
!    but sometimes DECL is an error_mark_node.  */

   static bool
! supplement_binding (tree name, cxx_binding *binding, tree decl)
   {
!   tree bval = binding_value_tree (name, binding);
     bool ok = true;

     timevar_push (TV_NAME_LOOKUP);
+
     if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
       /* The new name is the type name.  */
       binding->type = decl;
*************** supplement_binding (cxx_binding *binding
*** 447,453 ****
          non-class scope prior declaration.  In that case, we should 
have
          already issued a diagnostic; for graceful error recovery 
purpose,
          pretend this was the intended declaration for that name.  */
!     binding->value = decl;
     else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval))
       {
         /* The old binding was a type name.  It was placed in
--- 456,462 ----
          non-class scope prior declaration.  In that case, we should 
have
          already issued a diagnostic; for graceful error recovery 
purpose,
          pretend this was the intended declaration for that name.  */
!     binding->value.t = decl;
     else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval))
       {
         /* The old binding was a type name.  It was placed in
*************** supplement_binding (cxx_binding *binding
*** 456,462 ****
   	 type name into the type slot; it is now hidden by the new
   	 binding.  */
         binding->type = bval;
!       binding->value = decl;
         binding->value_is_inherited = false;
       }
     else if (TREE_CODE (bval) == TYPE_DECL
--- 465,471 ----
   	 type name into the type slot; it is now hidden by the new
   	 binding.  */
         binding->type = bval;
!       binding->value.t = decl;
         binding->value_is_inherited = false;
       }
     else if (TREE_CODE (bval) == TYPE_DECL
*************** supplement_binding (cxx_binding *binding
*** 488,501 ****
   	   && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval)
   	   && !DECL_CLASS_SCOPE_P (decl))
       {
!       duplicate_decls (decl, binding->value);
         ok = false;
       }
     else
       {
         error ("declaration of `%#D'", decl);
         cp_error_at ("conflicts with previous declaration `%#D'",
! 		   binding->value);
         ok = false;
       }

--- 497,510 ----
   	   && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval)
   	   && !DECL_CLASS_SCOPE_P (decl))
       {
!       duplicate_decls (decl, binding_value_tree (DECL_NAME (decl), 
binding));
         ok = false;
       }
     else
       {
         error ("declaration of `%#D'", decl);
         cp_error_at ("conflicts with previous declaration `%#D'",
! 		   binding_value_tree (DECL_NAME (decl), binding));
         ok = false;
       }

*************** add_decl_to_level (tree decl, cxx_scope
*** 535,540 ****
--- 544,582 ----
       }
   }

+ /* Record a s-tree S, a decl, as being named NAME in the current 
lexical
+    scope, which must be a namespace scope.  Check for errors (such as
+    an incompatible declaration for the same name already seen in the
+    same scope).
+
+    Currently assumes that S is a S_CONST_DECL.  */
+
+ void
+ push_s_decl (tree name, s_tree_i s)
+ {
+   cxx_binding *b;
+
+   timevar_push (TV_NAME_LOOKUP);
+
+   /* Check that this is a namespace-scope declaration and is not a
+      duplicate.  If not, use the full pushdecl().  */
+   if (current_function_decl || !namespace_bindings_p ())
+     goto too_hard;
+   b = binding_for_name (NAMESPACE_LEVEL (current_namespace), name);
+   if (b->value.t || b->value.st)
+     goto too_hard;
+
+   b->value.st = s;
+
+   timevar_pop (TV_NAME_LOOKUP);
+   return;
+
+  too_hard:
+   pushdecl (s_tree_to_tree (name, s));
+   timevar_pop (TV_NAME_LOOKUP);
+   return;
+ }
+
   /* Record a decl-node X as belonging to the current lexical scope.
      Check for errors (such as an incompatible declaration for the same
      name already seen in the same scope).
*************** push_local_binding (tree id, tree decl,
*** 1043,1049 ****
     if (lookup_name_current_level (id))
       {
         /* Supplement the existing binding.  */
!       if (!supplement_binding (IDENTIFIER_BINDING (id), decl))
   	/* It didn't work.  Something else must be bound at this
   	   level.  Do not add DECL to the list of things to pop
   	   later.  */
--- 1085,1091 ----
     if (lookup_name_current_level (id))
       {
         /* Supplement the existing binding.  */
!       if (!supplement_binding (id, IDENTIFIER_BINDING (id), decl))
   	/* It didn't work.  Something else must be bound at this
   	   level.  Do not add DECL to the list of things to pop
   	   later.  */
*************** maybe_inject_for_scope_var (tree decl)
*** 1107,1116 ****
   	= IDENTIFIER_BINDING (DECL_NAME (decl))->previous;

         if (outer_binding && outer_binding->scope == outer
! 	  && (TREE_CODE (outer_binding->value) == VAR_DECL)
! 	  && DECL_DEAD_FOR_LOCAL (outer_binding->value))
   	{
! 	  outer_binding->value = DECL_SHADOWED_FOR_VAR 
(outer_binding->value);
   	  current_binding_level->kind = sk_block;
   	}
       }
--- 1149,1160 ----
   	= IDENTIFIER_BINDING (DECL_NAME (decl))->previous;

         if (outer_binding && outer_binding->scope == outer
! 	  && (TREE_CODE (binding_value_tree (DECL_NAME (decl),
! 					     outer_binding)) == VAR_DECL)
! 	  && DECL_DEAD_FOR_LOCAL (outer_binding->value.t))
   	{
! 	  outer_binding->value.t
! 	    = DECL_SHADOWED_FOR_VAR (outer_binding->value.t);
   	  current_binding_level->kind = sk_block;
   	}
       }
*************** set_identifier_type_value_with_scope (tr
*** 1725,1734 ****
   	binding_for_name (NAMESPACE_LEVEL (current_namespace), id);
         if (decl)
   	{
! 	  if (binding->value)
! 	    supplement_binding (binding, decl);
   	  else
! 	    binding->value = decl;
   	}
         else
   	abort ();
--- 1769,1778 ----
   	binding_for_name (NAMESPACE_LEVEL (current_namespace), id);
         if (decl)
   	{
! 	  if (binding->value.t || binding->value.st)
! 	    supplement_binding (id, binding, decl);
   	  else
! 	    binding->value.t = decl;
   	}
         else
   	abort ();
*************** push_overloaded_decl (tree decl, int fla
*** 2062,2068 ****
   				  TREE_CHAIN (*d));

   		/* And update the cxx_binding node.  */
! 		IDENTIFIER_BINDING (name)->value = new_binding;
   		POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl);
   	      }

--- 2106,2112 ----
   				  TREE_CHAIN (*d));

   		/* And update the cxx_binding node.  */
! 		IDENTIFIER_BINDING (name)->value.t = new_binding;
   		POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl);
   	      }

*************** do_nonmember_using_decl (tree scope, tre
*** 2137,2150 ****
       /* Lookup error */
       return;

!   if (!decls.value && !decls.type)
       {
         error ("`%D' not declared", name);
         return;
       }

     /* Check for using functions.  */
!   if (decls.value && is_overloaded_fn (decls.value))
       {
         tree tmp, tmp1;

--- 2181,2194 ----
       /* Lookup error */
       return;

!   if (! binding_value_tree (name, &decls) && !decls.type)
       {
         error ("`%D' not declared", name);
         return;
       }

     /* Check for using functions.  */
!   if (decls.value.t && is_overloaded_fn (decls.value.t))
       {
         tree tmp, tmp1;

*************** do_nonmember_using_decl (tree scope, tre
*** 2156,2162 ****
   	}

         *newval = oldval;
!       for (tmp = decls.value; tmp; tmp = OVL_NEXT (tmp))
   	{
   	  tree new_fn = OVL_CURRENT (tmp);

--- 2200,2206 ----
   	}

         *newval = oldval;
!       for (tmp = decls.value.t; tmp; tmp = OVL_NEXT (tmp))
   	{
   	  tree new_fn = OVL_CURRENT (tmp);

*************** do_nonmember_using_decl (tree scope, tre
*** 2216,2222 ****
       }
     else
       {
!       *newval = decls.value;
         if (oldval && !decls_match (*newval, oldval))
   	error ("`%D' is already declared in this scope", name);
       }
--- 2260,2266 ----
       }
     else
       {
!       *newval = decls.value.t;
         if (oldval && !decls_match (*newval, oldval))
   	error ("`%D' is already declared in this scope", name);
       }
*************** lookup_tag (enum tree_code form, tree na
*** 2367,2377 ****
   	       class declaration, then we use the _TYPE node for the
   	       template.  See the example below.  */
   	    if (thislevel_only && !allow_template_parms_p
! 		&& binding && binding->value
! 		&& DECL_CLASS_TEMPLATE_P (binding->value))
! 	      old = binding->value;
   	    else if (binding)
! 	      old = select_decl (binding, LOOKUP_PREFER_TYPES);
               else
                 old = NULL_TREE;

--- 2411,2421 ----
   	       class declaration, then we use the _TYPE node for the
   	       template.  See the example below.  */
   	    if (thislevel_only && !allow_template_parms_p
! 		&& binding && binding_value_tree (name, binding)
! 		&& DECL_CLASS_TEMPLATE_P (binding->value.t))
! 	      old = binding->value.t;
   	    else if (binding)
! 	      old = select_decl (name, binding, LOOKUP_PREFER_TYPES);
               else
                 old = NULL_TREE;

*************** poplevel_class (void)
*** 2587,2593 ****

   	    if (binding)
   	      IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed))
! 		= binding->value;
   	  }
       }
     else
--- 2631,2637 ----

   	    if (binding)
   	      IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed))
! 		= binding_value_tree (TREE_PURPOSE (shadowed), binding);
   	  }
       }
     else
*************** push_class_binding (tree id, tree decl)
*** 2635,2641 ****

     if (binding && binding->scope == class_binding_level)
       /* Supplement the existing binding.  */
!     result = supplement_binding (IDENTIFIER_BINDING (id), decl);
     else
       /* Create a new binding.  */
       push_binding (id, decl, class_binding_level);
--- 2679,2685 ----

     if (binding && binding->scope == class_binding_level)
       /* Supplement the existing binding.  */
!     result = supplement_binding (id, IDENTIFIER_BINDING (id), decl);
     else
       /* Create a new binding.  */
       push_binding (id, decl, class_binding_level);
*************** push_class_binding (tree id, tree decl)
*** 2645,2655 ****
        because of the possibility of the `struct stat' hack; if DECL is
        a class-name or enum-name we might prefer a field-name, or some
        such.  */
!   IDENTIFIER_CLASS_VALUE (id) = IDENTIFIER_BINDING (id)->value;

     /* If this is a binding from a base class, mark it as such.  */
     binding = IDENTIFIER_BINDING (id);
!   if (binding->value == decl && TREE_CODE (decl) != TREE_LIST)
       {
         if (TREE_CODE (decl) == OVERLOAD)
   	context = CP_DECL_CONTEXT (OVL_CURRENT (decl));
--- 2689,2699 ----
        because of the possibility of the `struct stat' hack; if DECL is
        a class-name or enum-name we might prefer a field-name, or some
        such.  */
!   IDENTIFIER_CLASS_VALUE (id) = IDENTIFIER_BINDING (id)->value.t;

     /* If this is a binding from a base class, mark it as such.  */
     binding = IDENTIFIER_BINDING (id);
!   if (binding->value.t == decl && TREE_CODE (decl) != TREE_LIST)
       {
         if (TREE_CODE (decl) == OVERLOAD)
   	context = CP_DECL_CONTEXT (OVL_CURRENT (decl));
*************** push_class_binding (tree id, tree decl)
*** 2664,2670 ****
         else
   	INHERITED_VALUE_BINDING_P (binding) = 0;
       }
!   else if (binding->value == decl)
       /* We only encounter a TREE_LIST when push_class_decls detects an
          ambiguity.  Such an ambiguity can be overridden by a definition
          in this class.  */
--- 2708,2714 ----
         else
   	INHERITED_VALUE_BINDING_P (binding) = 0;
       }
!   else if (binding->value.t == decl)
       /* We only encounter a TREE_LIST when push_class_decls detects an
          ambiguity.  Such an ambiguity can be overridden by a definition
          in this class.  */
*************** push_class_level_binding (tree name, tre
*** 2790,2798 ****
        class, then we will need to restore IDENTIFIER_CLASS_VALUE when
        we leave this class.  Record the shadowed declaration here.  */
     binding = IDENTIFIER_BINDING (name);
!   if (binding && binding->value)
       {
!       tree bval = binding->value;
         tree old_decl = NULL_TREE;

         if (INHERITED_VALUE_BINDING_P (binding))
--- 2834,2842 ----
        class, then we will need to restore IDENTIFIER_CLASS_VALUE when
        we leave this class.  Record the shadowed declaration here.  */
     binding = IDENTIFIER_BINDING (name);
!   if (binding && binding_value_tree (name, binding))
       {
!       tree bval = binding->value.t;
         tree old_decl = NULL_TREE;

         if (INHERITED_VALUE_BINDING_P (binding))
*************** push_class_level_binding (tree name, tre
*** 2806,2812 ****
   	    {
   	      old_decl = binding->type;
   	      binding->type = bval;
! 	      binding->value = NULL_TREE;
   	      INHERITED_VALUE_BINDING_P (binding) = 0;
   	    }
   	  else
--- 2850,2857 ----
   	    {
   	      old_decl = binding->type;
   	      binding->type = bval;
! 	      binding->value.t = NULL_TREE;
! 	      binding->value.st = NULL_S_TREE_I;
   	      INHERITED_VALUE_BINDING_P (binding) = 0;
   	    }
   	  else
*************** push_class_level_binding (tree name, tre
*** 2833,2839 ****
   	    if (TREE_PURPOSE (shadow) == name
   		&& TREE_TYPE (shadow) == old_decl)
   	      {
! 		binding->value = x;
   		INHERITED_VALUE_BINDING_P (binding) = 0;
   		TREE_TYPE (shadow) = x;
   		IDENTIFIER_CLASS_VALUE (name) = x;
--- 2878,2884 ----
   	    if (TREE_PURPOSE (shadow) == name
   		&& TREE_TYPE (shadow) == old_decl)
   	      {
! 		binding->value.t = x;
   		INHERITED_VALUE_BINDING_P (binding) = 0;
   		TREE_TYPE (shadow) = x;
   		IDENTIFIER_CLASS_VALUE (name) = x;
*************** namespace_binding (tree name, tree scope
*** 2924,2930 ****
     scope = ORIGINAL_NAMESPACE (scope);
     binding = cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), 
name);

!   return binding ? binding->value : NULL_TREE;
   }

   /* Set the binding value for name in scope.  */
--- 2969,2975 ----
     scope = ORIGINAL_NAMESPACE (scope);
     binding = cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), 
name);

!   return binding ? binding_value_tree (name, binding) : NULL_TREE;
   }

   /* Set the binding value for name in scope.  */
*************** set_namespace_binding (tree name, tree s
*** 2938,2947 ****
     if (scope == NULL_TREE)
       scope = global_namespace;
     b = binding_for_name (NAMESPACE_LEVEL (scope), name);
!   if (!b->value || TREE_CODE (val) == OVERLOAD || val == 
error_mark_node)
!     b->value = val;
     else
!     supplement_binding (b, val);
     timevar_pop (TV_NAME_LOOKUP);
   }

--- 2983,2993 ----
     if (scope == NULL_TREE)
       scope = global_namespace;
     b = binding_for_name (NAMESPACE_LEVEL (scope), name);
!   if (! binding_value_tree (name, b)
!       || TREE_CODE (val) == OVERLOAD || val == error_mark_node)
!     b->value.t = val;
     else
!     supplement_binding (name, b, val);
     timevar_pop (TV_NAME_LOOKUP);
   }

*************** do_toplevel_using_decl (tree decl, tree
*** 3324,3330 ****

     binding = binding_for_name (NAMESPACE_LEVEL (current_namespace), 
name);

!   oldval = binding->value;
     oldtype = binding->type;

     do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, 
&newtype);
--- 3370,3376 ----

     binding = binding_for_name (NAMESPACE_LEVEL (current_namespace), 
name);

!   oldval = binding_value_tree (name, binding);
     oldtype = binding->type;

     do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, 
&newtype);
*************** do_toplevel_using_decl (tree decl, tree
*** 3335,3341 ****

     /* Copy declarations found.  */
     if (newval)
!     binding->value = newval;
     if (newtype)
       binding->type = newtype;
     return;
--- 3381,3387 ----

     /* Copy declarations found.  */
     if (newval)
!     binding->value.t = newval;
     if (newtype)
       binding->type = newtype;
     return;
*************** ambiguous_decl (tree name, cxx_binding *
*** 3497,3503 ****
     tree val, type;
     my_friendly_assert (old != NULL, 393);
     /* Copy the value.  */
!   val = new->value;
     if (val)
       switch (TREE_CODE (val))
         {
--- 3543,3549 ----
     tree val, type;
     my_friendly_assert (old != NULL, 393);
     /* Copy the value.  */
!   val = binding_value_tree (name, new);
     if (val)
       switch (TREE_CODE (val))
         {
*************** ambiguous_decl (tree name, cxx_binding *
*** 3526,3554 ****
             val = NULL_TREE;
         }

!   if (!old->value)
!     old->value = val;
!   else if (val && val != old->value)
       {
!       if (is_overloaded_fn (old->value) && is_overloaded_fn (val))
!         old->value = merge_functions (old->value, val);
         else
   	{
   	  /* Some declarations are functions, some are not.  */
             if (flags & LOOKUP_COMPLAIN)
               {
   	      /* If we've already given this error for this lookup,
! 		 old->value is error_mark_node, so let's not
   		 repeat ourselves.  */
! 	      if (old->value != error_mark_node)
   		{
   		  error ("use of `%D' is ambiguous", name);
   		  cp_error_at ("  first declared as `%#D' here",
! 			       old->value);
   		}
                 cp_error_at ("  also declared as `%#D' here", val);
               }
! 	  old->value = error_mark_node;
   	}
       }
     /* ... and copy the type.  */
--- 3572,3600 ----
             val = NULL_TREE;
         }

!   if (! binding_value_tree (name, old))
!     old->value.t = val;
!   else if (val && val != old->value.t)
       {
!       if (is_overloaded_fn (old->value.t) && is_overloaded_fn (val))
!         old->value.t = merge_functions (old->value.t, val);
         else
   	{
   	  /* Some declarations are functions, some are not.  */
             if (flags & LOOKUP_COMPLAIN)
               {
   	      /* If we've already given this error for this lookup,
! 		 old->value.t is error_mark_node, so let's not
   		 repeat ourselves.  */
! 	      if (old->value.t != error_mark_node)
   		{
   		  error ("use of `%D' is ambiguous", name);
   		  cp_error_at ("  first declared as `%#D' here",
! 			       old->value.t);
   		}
                 cp_error_at ("  also declared as `%#D' here", val);
               }
! 	  old->value.t = error_mark_node;
   	}
       }
     /* ... and copy the type.  */
*************** lookup_namespace_name (tree namespace, t
*** 3650,3658 ****
     if (!qualified_lookup_using_namespace (name, namespace, &binding, 
0))
       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);

!   if (binding.value)
       {
!       val = binding.value;

         if (template_id)
   	{
--- 3696,3704 ----
     if (!qualified_lookup_using_namespace (name, namespace, &binding, 
0))
       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);

!   if (binding_value_tree (name, &binding))
       {
!       val = binding.value.t;

         if (template_id)
   	{
*************** lookup_namespace_name (tree namespace, t
*** 3693,3702 ****
   /* Select the right _DECL from multiple choices.  */

   static tree
! select_decl (cxx_binding *binding, int flags)
   {
     tree val;
!   val = binding->value;

     timevar_push (TV_NAME_LOOKUP);
     if (LOOKUP_NAMESPACES_ONLY (flags))
--- 3739,3748 ----
   /* Select the right _DECL from multiple choices.  */

   static tree
! select_decl (tree name, cxx_binding *binding, int flags)
   {
     tree val;
!   val = binding_value_tree (name, binding);

     timevar_push (TV_NAME_LOOKUP);
     if (LOOKUP_NAMESPACES_ONLY (flags))
*************** unqualified_namespace_lookup (tree name,
*** 3742,3754 ****
            cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), 
name);

         /* Ignore anticipated built-in functions.  */
!       if (b && b->value && DECL_P (b->value)
!           && DECL_LANG_SPECIFIC (b->value) && DECL_ANTICIPATED 
(b->value))
           /* Keep binding cleared.  */;
         else if (b)
           {
             /* Initialize binding for this context.  */
!           binding.value = b->value;
             binding.type = b->type;
           }

--- 3788,3800 ----
            cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), 
name);

         /* Ignore anticipated built-in functions.  */
!       if (b && binding_value_tree (name, b) && DECL_P (b->value.t)
!           && DECL_LANG_SPECIFIC (b->value.t) && DECL_ANTICIPATED 
(b->value.t))
           /* Keep binding cleared.  */;
         else if (b)
           {
             /* Initialize binding for this context.  */
!           binding.value.t = b->value.t;
             binding.type = b->type;
           }

*************** unqualified_namespace_lookup (tree name,
*** 3775,3781 ****
   	  siter = CP_DECL_CONTEXT (siter);
   	}

!       val = select_decl (&binding, flags);
         if (scope == global_namespace)
   	break;
       }
--- 3821,3827 ----
   	  siter = CP_DECL_CONTEXT (siter);
   	}

!       val = select_decl (name, &binding, flags);
         if (scope == global_namespace)
   	break;
       }
*************** lookup_qualified_name (tree scope, tree
*** 3805,3811 ****
         if (is_type_p)
   	flags |= LOOKUP_PREFER_TYPES;
         if (qualified_lookup_using_namespace (name, scope, &binding, 
flags))
! 	return select_decl (&binding, flags);
       }
     else if (is_aggr_type (scope, complain))
       {
--- 3851,3857 ----
         if (is_type_p)
   	flags |= LOOKUP_PREFER_TYPES;
         if (qualified_lookup_using_namespace (name, scope, &binding, 
flags))
! 	return select_decl (name, &binding, flags);
       }
     else if (is_aggr_type (scope, complain))
       {
*************** lookup_using_namespace (tree name, cxx_b
*** 3843,3849 ****
           if (val1)
             val = ambiguous_decl (name, val, val1, flags);
         }
!   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, val->value != 
error_mark_node);
   }

   /* [namespace.qual]
--- 3889,3895 ----
           if (val1)
             val = ambiguous_decl (name, val, val1, flags);
         }
!   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, val->value.t != 
error_mark_node);
   }

   /* [namespace.qual]
*************** qualified_lookup_using_namespace (tree n
*** 3864,3870 ****
     timevar_push (TV_NAME_LOOKUP);
     /* Look through namespace aliases.  */
     scope = ORIGINAL_NAMESPACE (scope);
!   while (scope && result->value != error_mark_node)
       {
         cxx_binding *binding =
   	cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), name);
--- 3910,3916 ----
     timevar_push (TV_NAME_LOOKUP);
     /* Look through namespace aliases.  */
     scope = ORIGINAL_NAMESPACE (scope);
!   while (scope && result->value.t != error_mark_node)
       {
         cxx_binding *binding =
   	cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), name);
*************** qualified_lookup_using_namespace (tree n
*** 3890,3896 ****
   		&& !purpose_member (TREE_PURPOSE (usings), seen)
   		&& !purpose_member (TREE_PURPOSE (usings), todo))
   	      todo = tree_cons (TREE_PURPOSE (usings), NULL_TREE, todo);
! 	    else if ((!result->value && !result->type)
   		     && !purpose_member (TREE_PURPOSE (usings), seen)
   		     && !purpose_member (TREE_PURPOSE (usings), todo)
   		     && !purpose_member (TREE_PURPOSE (usings), todo_maybe))
--- 3936,3942 ----
   		&& !purpose_member (TREE_PURPOSE (usings), seen)
   		&& !purpose_member (TREE_PURPOSE (usings), todo))
   	      todo = tree_cons (TREE_PURPOSE (usings), NULL_TREE, todo);
! 	    else if ((!(result->value.t || result->value.st) && 
!result->type)
   		     && !purpose_member (TREE_PURPOSE (usings), seen)
   		     && !purpose_member (TREE_PURPOSE (usings), todo)
   		     && !purpose_member (TREE_PURPOSE (usings), todo_maybe))
*************** qualified_lookup_using_namespace (tree n
*** 3903,3909 ****
   	  todo = TREE_CHAIN (todo);
   	}
         else if (todo_maybe
! 	       && (!result->value && !result->type))
   	{
   	  scope = TREE_PURPOSE (todo_maybe);
   	  todo = TREE_CHAIN (todo_maybe);
--- 3949,3955 ----
   	  todo = TREE_CHAIN (todo);
   	}
         else if (todo_maybe
! 	       && !(result->value.t || result->value.st) && !result->type)
   	{
   	  scope = TREE_PURPOSE (todo_maybe);
   	  todo = TREE_CHAIN (todo_maybe);
*************** qualified_lookup_using_namespace (tree n
*** 3912,3918 ****
         else
   	scope = NULL_TREE; /* If there never was a todo list.  */
       }
!   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, result->value != 
error_mark_node);
   }

   /* Look up NAME in the current binding level and its superiors in the
--- 3958,3964 ----
         else
   	scope = NULL_TREE; /* If there never was a todo list.  */
       }
!   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, result->value.t != 
error_mark_node);
   }

   /* Look up NAME in the current binding level and its superiors in the
*************** lookup_name_real (tree name, int prefer_
*** 3981,3988 ****
   	continue;

         /* If this is the kind of thing we're looking for, we're done.  
*/
!       if (qualify_lookup (iter->value, flags))
! 	binding = iter->value;
         else if ((flags & LOOKUP_PREFER_TYPES)
   	       && qualify_lookup (iter->type, flags))
   	binding = iter->type;
--- 4027,4034 ----
   	continue;

         /* If this is the kind of thing we're looking for, we're done.  
*/
!       if (qualify_lookup (binding_value_tree (name, iter), flags))
! 	binding = iter->value.t;
         else if ((flags & LOOKUP_PREFER_TYPES)
   	       && qualify_lookup (iter->type, flags))
   	binding = iter->type;
Index: cp/name-lookup.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.h,v
retrieving revision 1.18
diff -p -r1.18 name-lookup.h
*** cp/name-lookup.h	1 Mar 2004 06:23:38 -0000	1.18
--- cp/name-lookup.h	9 Mar 2004 00:36:35 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 23,28 ****
--- 23,29 ----
   #define GCC_CP_NAME_LOOKUP_H

   #include "c-common.h"
+ #include "stree.h"

   /* The type of dictionary used to map names to types declared at
      a given scope.  */
*************** struct cxx_binding GTY(())
*** 75,81 ****
     /* Link to chain together various bindings for this name.  */
     cxx_binding *previous;
     /* The non-type entity this name is bound to.  */
!   tree value;
     /* The type entity this name is bound to.  */
     tree type;
     /* The scope at which this binding was made.  */
--- 76,82 ----
     /* Link to chain together various bindings for this name.  */
     cxx_binding *previous;
     /* The non-type entity this name is bound to.  */
!   struct s_tree_i_or_tree value;
     /* The type entity this name is bound to.  */
     tree type;
     /* The scope at which this binding was made.  */
*************** extern void push_nested_namespace (tree)
*** 276,281 ****
--- 277,283 ----
   extern void pop_nested_namespace (tree);
   extern void pushlevel_class (void);
   extern void poplevel_class (void);
+ extern void push_s_decl (tree name, s_tree_i s);
   extern tree pushdecl_with_scope (tree, cxx_scope *);
   extern tree lookup_tag (enum tree_code, tree, cxx_scope *, int);
   extern tree lookup_tag_reverse (tree, tree);
*************** is_typename_at_global_scope (tree id)
*** 330,335 ****
--- 332,347 ----
     tree global_value = namespace_binding (id, global_namespace);

     return global_value && TREE_CODE (global_value) == TYPE_DECL;
+ }
+
+ /* Return the tree for BINDING->VALUE.  As a side effect,
+    BINDING->VALUE.T will hold that tree.  */
+ static inline tree
+ binding_value_tree (tree name, cxx_binding *binding)
+ {
+   if (!binding->value.t && binding->value.st)
+     binding->value.t = s_tree_to_tree (name, binding->value.st);
+   return binding->value.t;
   }

   #endif /* GCC_CP_NAME_LOOKUP_H */



More information about the Gcc-patches mailing list