This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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 */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]