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]

C++ PATCH for enum problem



Thanks for your report.  The bug actually had nothing to do with
function-at-a-time mode; it was a latent bug triggered by some other
work.

Here's the fix, which consists largely of an indentation fix-up and
some simplifications to the code.  (It's nice to see that often, now,
C++ bugs are fixed by removing code rather than adding it...)

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

1999-11-10  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (build_enumerator): Change prototype.
	* decl.c (enum_next_value): Remove.
	(enum_overflow): Likewise.
	(init_decl_processing): Don't register enum_next_value as a root.
	(start_enum): Clear TYPE_VALUES for a redefined enum.
	(finish_enum): Reset the type of enumeration constants.
	(build_enumerator): Fix indentation.  Don't copy CONST_DECLs when
	we don't need to.  Maintain the TYPE_VALUES list and look there
	for the previously defined enumeration constant.  Let enumeration
	constants have the type of their values until the enumeration type
	is complete.
	* parse.y (enumlist_opt, enumlist, enumerator): Don't return a value.
	(structsp): Adjust.
	* parse.c: Regenerated.
	* pt.c (tsubst_enum): Adjust according to build_enumerator changes.
	
Index: g++.pt/enum13.C
===================================================================
RCS file: enum13.C
diff -N enum13.C
*** /dev/null	Tue May  5 13:32:27 1998
--- enum13.C	Wed Nov 10 13:37:51 1999
***************
*** 0 ****
--- 1,9 ----
+ // Build don't link:
+ // Origin: Theodore Papadopoulo <Theodore.Papadopoulo@sophia.inria.fr>
+ 
+ template <typename T>
+ struct foo {
+     enum { A = 4 >= 4, B = (1 ? true : A) };
+ };
+  
+ foo<int> bar;
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.343
diff -c -p -r1.343 cp-tree.h
*** cp-tree.h	1999/11/09 08:15:07	1.343
--- cp-tree.h	1999/11/10 21:33:18
*************** extern tree xref_tag_from_type			PROTO((
*** 3466,3472 ****
  extern void xref_basetypes			PROTO((tree, tree, tree, tree));
  extern tree start_enum				PROTO((tree));
  extern tree finish_enum				PROTO((tree));
! extern tree build_enumerator			PROTO((tree, tree, tree));
  extern int start_function			PROTO((tree, tree, tree, int));
  extern void expand_start_early_try_stmts	PROTO((void));
  extern void store_parm_decls			PROTO((void));
--- 3466,3472 ----
  extern void xref_basetypes			PROTO((tree, tree, tree, tree));
  extern tree start_enum				PROTO((tree));
  extern tree finish_enum				PROTO((tree));
! extern void build_enumerator			PROTO((tree, tree, tree));
  extern int start_function			PROTO((tree, tree, tree, int));
  extern void expand_start_early_try_stmts	PROTO((void));
  extern void store_parm_decls			PROTO((void));
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.497
diff -c -p -r1.497 decl.c
*** decl.c	1999/11/09 08:15:07	1.497
--- decl.c	1999/11/10 21:33:30
*************** tree static_aggregates;
*** 288,302 ****
  
  tree integer_two_node, integer_three_node;
  
- /* While defining an enum type, this is 1 plus the last enumerator
-    constant value.  */
- 
- static tree enum_next_value;
- 
- /* Nonzero means that there was overflow computing enum_next_value.  */
- 
- static int enum_overflow;
- 
  /* Parsing a function declarator leaves here a chain of structure
     and enum types declared in the parmlist.  */
  
--- 288,293 ----
*************** init_decl_processing ()
*** 6357,6363 ****
    ggc_add_tree_root (&static_dtors, 1);
    ggc_add_tree_root (&lastiddecl, 1);
  
-   ggc_add_tree_root (&enum_next_value, 1);
    ggc_add_tree_root (&last_function_parm_tags, 1);
    ggc_add_tree_root (&current_function_return_value, 1);
    ggc_add_tree_root (&current_function_parms, 1);
--- 6348,6353 ----
*************** start_enum (name)
*** 12381,12386 ****
--- 12371,12378 ----
      {
        cp_error ("multiple definition of `%#T'", enumtype);
        cp_error_at ("previous definition here", enumtype);
+       /* Clear out TYPE_VALUES, and start again.  */
+       TYPE_VALUES (enumtype) = NULL_TREE;
      }
    else
      {
*************** start_enum (name)
*** 12391,12400 ****
    if (current_class_type)
      TREE_ADDRESSABLE (b->tags) = 1;
  
-   /* We don't copy this value because build_enumerator needs to do it.  */
-   enum_next_value = integer_zero_node;
-   enum_overflow = 0;
- 
    GNU_xref_decl (current_function_decl, enumtype);
    return enumtype;
  }
--- 12383,12388 ----
*************** finish_enum (enumtype)
*** 12425,12430 ****
--- 12413,12426 ----
  	     constant.  */
  	  decl = TREE_VALUE (pair);
  
+ 	  /* [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;
+ 
  	  /* The DECL_INITIAL will be NULL if we are processing a
  	     template declaration and this enumeration constant had no
  	     explicit initializer.  */
*************** finish_enum (enumtype)
*** 12530,12630 ****
  }
  
  /* Build and install a CONST_DECL for an enumeration constant of the
!    enumeration type TYPE whose NAME and VALUE (if any) are provided.
     Assignment of sequential values by default is handled here.  */
  
! tree
! build_enumerator (name, value, type)
       tree name;
       tree value;
!      tree type;
  {
!   tree decl, result;
    tree context;
  
    /* Remove no-op casts from the value.  */
    if (value)
      STRIP_TYPE_NOPS (value);
  
!  if (! processing_template_decl)
!    {
!      /* Validate and default VALUE.  */
!      if (value != NULL_TREE)
!        {
! 	 if (TREE_READONLY_DECL_P (value))
! 	   value = decl_constant_value (value);
! 
! 	 if (TREE_CODE (value) == INTEGER_CST)
! 	   {
! 	     value = default_conversion (value);
! 	     constant_expression_warning (value);
! 	   }
! 	 else
! 	   {
! 	     cp_error ("enumerator value for `%D' not integer constant", name);
! 	     value = NULL_TREE;
! 	   }
!        }
  
!      /* Default based on previous value.  */
!      if (value == NULL_TREE && ! processing_template_decl)
!        {
! 	 value = enum_next_value;
! 	 if (enum_overflow)
! 	   cp_error ("overflow in enumeration values at `%D'", name);
!        }
! 
!      /* Remove no-op casts from the value.  */
!      if (value)
!        STRIP_TYPE_NOPS (value);
  #if 0
!      /* To fix MAX_VAL enum consts. (bkoz)  */
!      TREE_TYPE (value) = integer_type_node;
  #endif
!    }
  
!  /* We always have to copy here; not all INTEGER_CSTs are unshared.
!     Even in other cases, we will later (in finish_enum) be setting the
!     type of VALUE.  */
!  if (value != NULL_TREE)
!    value = copy_node (value);
  
    /* C++ associates enums with global, function, or class declarations.  */
!  
!  context = current_scope ();
!  if (context && context == current_class_type)
!    /* This enum declaration is local to the class.  */
!    decl = build_lang_decl (CONST_DECL, name, type);
!  else
!    /* It's a global enum, or it's local to a function.  (Note local to
        a function could mean local to a class method.  */
!    decl = build_decl (CONST_DECL, name, type);
  
!  DECL_CONTEXT (decl) = FROB_CONTEXT (context);
!  DECL_INITIAL (decl) = value;
!  TREE_READONLY (decl) = 1;
  
!  if (context && context == current_class_type)
!    /* In something like `struct S { enum E { i = 7 }; };' we put `i'
        on the TYPE_FIELDS list for `S'.  (That's so that you can say
        things like `S::i' later.)  */
!    finish_member_declaration (decl);
!  else
!    {
!      pushdecl (decl);
!      GNU_xref_decl (current_function_decl, decl);
!    }
! 
!  if (! processing_template_decl)
!    {
!      /* Set basis for default for next value.  */
!      enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value,
! 						  integer_one_node, PLUS_EXPR);
!      enum_overflow = tree_int_cst_lt (enum_next_value, value);
!    }
  
!   result = tree_cons (name, decl, NULL_TREE);
!   return result;
  }
  
  
--- 12526,12656 ----
  }
  
  /* 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.  */
  
! void
! build_enumerator (name, value, enumtype)
       tree name;
       tree value;
!      tree enumtype;
  {
!   tree decl;
    tree context;
+   tree type;
+   tree values;
  
    /* Remove no-op casts from the value.  */
    if (value)
      STRIP_TYPE_NOPS (value);
  
!   if (! processing_template_decl)
!     {
!       /* Validate and default VALUE.  */
!       if (value != NULL_TREE)
! 	{
! 	  if (TREE_READONLY_DECL_P (value))
! 	    value = decl_constant_value (value);
  
! 	  if (TREE_CODE (value) == INTEGER_CST)
! 	    {
! 	      value = default_conversion (value);
! 	      constant_expression_warning (value);
! 	    }
! 	  else
! 	    {
! 	      cp_error ("enumerator value for `%D' not integer constant", name);
! 	      value = NULL_TREE;
! 	    }
! 	}
! 
!       /* Default based on previous value.  */
!       if (value == NULL_TREE && ! processing_template_decl)
! 	{
! 	  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 = build_binary_op_nodefault (PLUS_EXPR,
! 						 prev_value,
! 						 integer_one_node,
! 						 PLUS_EXPR);
! 	      
! 	      if (tree_int_cst_lt (value, prev_value))
! 		cp_error ("overflow in enumeration values at `%D'", name);
! 	    }
! 	  else
! 	    value = integer_zero_node;
! 	}
! 
!       /* Remove no-op casts from the value.  */
!       if (value)
! 	STRIP_TYPE_NOPS (value);
  #if 0
!       /* To fix MAX_VAL enum consts. (bkoz)  */
!       TREE_TYPE (value) = integer_type_node;
  #endif
!     }
  
!   /* We always have to copy here; not all INTEGER_CSTs are unshared.
!      Even in other cases, we will later (in finish_enum) be setting
!      the type of VALUE.  But, we don't need to make a copy if this
!      VALUE is one of the enumeration constants for this same
!      enumeration type.  */
!   for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values))
!     if (TREE_VALUE (values) == value)
!       break;
!   /* If we didn't break out of the loop, then we do need a copy.  */
!   if (!values && value)
!     value = copy_node (value);
  
    /* C++ associates enums with global, function, or class declarations.  */
!   context = current_scope ();
! 
!   /* Build the actual enumeration constant.  Note that the enumeration
!     constants have the type of their initializers until the
!     enumeration is complete:
! 
!       [ dcl.enum ]
! 
!       Following the closing brace of an enum-specifier, each enumer-
!       ator has the type of its enumeration.  Prior to the closing
!       brace, the type of each enumerator is the type of its
!       initializing value.
! 
!     In finish_enum we will reset the type.  Of course, if we're
!     processing a template, there may be no value.   */
!   type = value ? TREE_TYPE (value) : NULL_TREE;
! 
!   if (context && context == current_class_type)
!     /* This enum declaration is local to the class.  We need the full
!       lang_decl so that we can record DECL_CLASS_CONTEXT, for example.  */
!     decl = build_lang_decl (CONST_DECL, name, type);
!   else
!     /* It's a global enum, or it's local to a function.  (Note local to
        a function could mean local to a class method.  */
!     decl = build_decl (CONST_DECL, name, type);
  
!   DECL_CONTEXT (decl) = FROB_CONTEXT (context);
!   DECL_INITIAL (decl) = value;
!   TREE_READONLY (decl) = 1;
  
!   if (context && context == current_class_type)
!     /* In something like `struct S { enum E { i = 7 }; };' we put `i'
        on the TYPE_FIELDS list for `S'.  (That's so that you can say
        things like `S::i' later.)  */
!     finish_member_declaration (decl);
!   else
!     {
!       pushdecl (decl);
!       GNU_xref_decl (current_function_decl, decl);
!     }
  
!   /* Add this enumeration constant to the list for this type.  */
!   TYPE_VALUES (enumtype) = tree_cons (name, decl, TYPE_VALUES (enumtype));
  }
  
  
Index: parse.y
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/parse.y,v
retrieving revision 1.154
diff -c -p -r1.154 parse.y
*** parse.y	1999/11/07 22:21:28	1.154
--- parse.y	1999/11/10 21:33:37
*************** empty_parms ()
*** 215,221 ****
  %type <ttype> component_declarator component_declarator0
  %type <ttype> notype_component_declarator notype_component_declarator0
  %type <ttype> after_type_component_declarator after_type_component_declarator0
- %type <ttype> enumlist_opt enumlist enumerator
  %type <ttype> absdcl cv_qualifiers
  %type <ttype> direct_abstract_declarator conversion_declarator
  %type <ttype> new_declarator direct_new_declarator
--- 215,220 ----
*************** structsp:
*** 2066,2073 ****
  		{ $<ttype>$ = current_enum_type;
  		  current_enum_type = start_enum ($2); }
  	  enumlist_opt '}'
! 		{ TYPE_VALUES (current_enum_type) = $5;
! 		  $$.t = finish_enum (current_enum_type);
  		  $$.new_type_flag = 1;
  		  current_enum_type = $<ttype>4;
  		  check_for_missing_semicolon ($$.t); }
--- 2065,2071 ----
  		{ $<ttype>$ = current_enum_type;
  		  current_enum_type = start_enum ($2); }
  	  enumlist_opt '}'
! 		{ $$.t = finish_enum (current_enum_type);
  		  $$.new_type_flag = 1;
  		  current_enum_type = $<ttype>4;
  		  check_for_missing_semicolon ($$.t); }
*************** structsp:
*** 2075,2082 ****
  		{ $<ttype>$ = current_enum_type;
  		  current_enum_type = start_enum (make_anon_name ()); }
  	  enumlist_opt '}'
!                 { TYPE_VALUES (current_enum_type) = $4;
! 		  $$.t = finish_enum (current_enum_type);
  		  $$.new_type_flag = 1;
  		  current_enum_type = $<ttype>3;
  		  check_for_missing_semicolon ($$.t); }
--- 2073,2079 ----
  		{ $<ttype>$ = current_enum_type;
  		  current_enum_type = start_enum (make_anon_name ()); }
  	  enumlist_opt '}'
!                 { $$.t = finish_enum (current_enum_type);
  		  $$.new_type_flag = 1;
  		  current_enum_type = $<ttype>3;
  		  check_for_missing_semicolon ($$.t); }
*************** notype_component_declarator:
*** 2582,2588 ****
  enumlist_opt:
  	  enumlist maybecomma_warn
  	| maybecomma_warn
- 	  { $$ = NULL_TREE; }
  	;
  
  /* We chain the enumerators in reverse order.
--- 2579,2584 ----
*************** enumlist_opt:
*** 2592,2605 ****
  enumlist:
  	  enumerator
  	| enumlist ',' enumerator
- 		{ TREE_CHAIN ($3) = $$; $$ = $3; }
  	;
  
  enumerator:
  	  identifier
! 		{ $$ = build_enumerator ($$, NULL_TREE, current_enum_type); }
  	| identifier '=' expr_no_commas
! 		{ $$ = build_enumerator ($$, $3, current_enum_type); }
  	;
  
  /* ANSI new-type-id (5.3.4) */
--- 2588,2600 ----
  enumlist:
  	  enumerator
  	| enumlist ',' enumerator
  	;
  
  enumerator:
  	  identifier
! 		{ build_enumerator ($1, NULL_TREE, current_enum_type); }
  	| identifier '=' expr_no_commas
! 		{ build_enumerator ($1, $3, current_enum_type); }
  	;
  
  /* ANSI new-type-id (5.3.4) */
Index: pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.379
diff -c -p -r1.379 pt.c
*** pt.c	1999/11/07 22:21:29	1.379
--- pt.c	1999/11/10 21:33:42
*************** tsubst_enum (tag, newtag, args)
*** 9755,9762 ****
    for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e))
      {
        tree value;
!       tree elt;
! 
        /* Note that in a template enum, the TREE_VALUE is the
  	 CONST_DECL, not the corresponding INTEGER_CST.  */
        value = tsubst_expr (DECL_INITIAL (TREE_VALUE (e)), 
--- 9755,9761 ----
    for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e))
      {
        tree value;
!       
        /* Note that in a template enum, the TREE_VALUE is the
  	 CONST_DECL, not the corresponding INTEGER_CST.  */
        value = tsubst_expr (DECL_INITIAL (TREE_VALUE (e)), 
*************** tsubst_enum (tag, newtag, args)
*** 9767,9780 ****
        set_current_access_from_decl (TREE_VALUE (e));
  
        /* Actually build the enumerator itself.  */
!       elt = build_enumerator (TREE_PURPOSE (e), value, newtag); 
! 
!       /* We save the enumerators we have built so far in the
! 	 TYPE_VALUES so that if the enumeration constants for
! 	 subsequent enumerators involve those for previous ones,
! 	 tsubst_copy will be able to find them.  */
!       TREE_CHAIN (elt) = TYPE_VALUES (newtag);
!       TYPE_VALUES (newtag) = elt;
      }
  
    finish_enum (newtag);
--- 9766,9772 ----
        set_current_access_from_decl (TREE_VALUE (e));
  
        /* Actually build the enumerator itself.  */
!       build_enumerator (TREE_PURPOSE (e), value, newtag); 
      }
  
    finish_enum (newtag);


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