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 obstack pain


My last checkin revealed a latent bug in declspec handling wrt obstacks;
code like

  static const union { int foo () { } } u;

breaks because the declspecs are thrown away when we finish compiling foo.
We didn't notice this because we handled the case of a single spec
specially, and never tested multiple specs.  This patch uses hash_tree_cons
to avoid the problem.

1999-03-31  Jason Merrill  <jason@yorick.cygnus.com>

	* semantics.c (begin_inline_definitions,
	finish_inline_definitions): Rename from finish_default_args and
	begin_inline_definitions, respectively, to something that isn't a
	total lie.  :)
	* parse.y (structsp): Adjust.

	* tree.c (hash_tree_cons): Remove obsolete via_* parms.
	(list_hash_lookup): Likewise.
	(hash_tree_chain): Adjust.
	* pt.c (tsubst): Adjust.
	(tsubst_arg_types): Use plain hash_tree_cons.
	* cp-tree.h (hash_tree_cons_simple): Lose.
	* parse.y (declmods, nonempty_cv_qualifiers): Use hash_tree_cons.

Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.211
diff -c -p -r1.211 cp-tree.h
*** cp-tree.h	1999/03/30 23:30:05	1.211
--- cp-tree.h	1999/04/01 02:55:21
*************** extern tree begin_class_definition      
*** 3252,3257 ****
--- 3252,3258 ----
  extern tree finish_class_definition             PROTO((tree, tree, int));
  extern void finish_default_args                 PROTO((void));
  extern void begin_inline_definitions            PROTO((void));
+ extern void finish_inline_definitions           PROTO((void));
  extern tree finish_member_class_template        PROTO((tree));
  extern void finish_template_decl                PROTO((tree));
  extern tree finish_template_type                PROTO((tree, tree, int));
*************** extern tree build_cplus_array_type		PROT
*** 3295,3301 ****
  extern int layout_basetypes			PROTO((tree, int));
  extern tree build_vbase_pointer_fields		PROTO((tree));
  extern tree build_base_fields			PROTO((tree));
! extern tree hash_tree_cons			PROTO((int, int, int, tree, tree, tree));
  extern tree hash_tree_chain			PROTO((tree, tree));
  extern tree hash_chainon			PROTO((tree, tree));
  extern tree make_binfo				PROTO((tree, tree, tree, tree));
--- 3296,3302 ----
  extern int layout_basetypes			PROTO((tree, int));
  extern tree build_vbase_pointer_fields		PROTO((tree));
  extern tree build_base_fields			PROTO((tree));
! extern tree hash_tree_cons			PROTO((tree, tree, tree));
  extern tree hash_tree_chain			PROTO((tree, tree));
  extern tree hash_chainon			PROTO((tree, tree));
  extern tree make_binfo				PROTO((tree, tree, tree, tree));
*************** extern tree build_dummy_object			PROTO((
*** 3347,3359 ****
  extern tree maybe_dummy_object			PROTO((tree, tree *));
  extern int is_dummy_object			PROTO((tree));
  extern tree search_tree                         PROTO((tree, tree (*)(tree)));
  #define scratchalloc expralloc
  #define scratch_tree_cons expr_tree_cons
  #define build_scratch_list build_expr_list
  #define make_scratch_vec make_temp_vec
  #define push_scratch_obstack push_expression_obstack
- #define hash_tree_cons_simple(PURPOSE, VALUE, CHAIN) \
-   hash_tree_cons (0, 0, 0, (PURPOSE), (VALUE), (CHAIN))
  
  /* in typeck.c */
  extern int string_conv_p			PROTO((tree, tree, int));
--- 3348,3359 ----
  extern tree maybe_dummy_object			PROTO((tree, tree *));
  extern int is_dummy_object			PROTO((tree));
  extern tree search_tree                         PROTO((tree, tree (*)(tree)));
+ 
  #define scratchalloc expralloc
  #define scratch_tree_cons expr_tree_cons
  #define build_scratch_list build_expr_list
  #define make_scratch_vec make_temp_vec
  #define push_scratch_obstack push_expression_obstack
  
  /* in typeck.c */
  extern int string_conv_p			PROTO((tree, tree, int));
Index: parse.y
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/parse.y,v
retrieving revision 1.112
diff -c -p -r1.112 parse.y
*** parse.y	1999/03/30 23:30:26	1.112
--- parse.y	1999/04/01 02:55:22
*************** reserved_declspecs:
*** 1753,1776 ****
     to redeclare a typedef-name.
     In the result, declspecs have a non-NULL TREE_VALUE, attributes do not.  */
  
  declmods:
  	  nonempty_cv_qualifiers  %prec EMPTY
  		{ $$ = $1.t; TREE_STATIC ($$) = 1; }
  	| SCSPEC
! 		{ $$ = build_decl_list (NULL_TREE, $$); }
  	| declmods CV_QUALIFIER
! 		{ $$ = decl_tree_cons (NULL_TREE, $2, $$);
  		  TREE_STATIC ($$) = 1; }
  	| declmods SCSPEC
  		{ if (extra_warnings && TREE_STATIC ($$))
  		    warning ("`%s' is not at beginning of declaration",
  			     IDENTIFIER_POINTER ($2));
! 		  $$ = decl_tree_cons (NULL_TREE, $2, $$);
  		  TREE_STATIC ($$) = TREE_STATIC ($1); }
  	| declmods attributes
! 		{ $$ = decl_tree_cons ($2, NULL_TREE, $1); }
  	| attributes
! 		{ $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); }
  	;
  
  /* Used instead of declspecs where storage classes are not allowed
--- 1753,1785 ----
     to redeclare a typedef-name.
     In the result, declspecs have a non-NULL TREE_VALUE, attributes do not.  */
  
+ /* We use hash_tree_cons for lists of typeless declspecs so that they end
+    up on a persistent obstack.  Otherwise, they could appear at the
+    beginning of something like
+ 
+       static const struct { int foo () { } } b;
+ 
+    and would be discarded after we finish compiling foo.  We don't need to
+    worry once we see a type.  */
+ 
  declmods:
  	  nonempty_cv_qualifiers  %prec EMPTY
  		{ $$ = $1.t; TREE_STATIC ($$) = 1; }
  	| SCSPEC
! 		{ $$ = hash_tree_cons (NULL_TREE, $$, NULL_TREE); }
  	| declmods CV_QUALIFIER
! 		{ $$ = hash_tree_cons (NULL_TREE, $2, $$);
  		  TREE_STATIC ($$) = 1; }
  	| declmods SCSPEC
  		{ if (extra_warnings && TREE_STATIC ($$))
  		    warning ("`%s' is not at beginning of declaration",
  			     IDENTIFIER_POINTER ($2));
! 		  $$ = hash_tree_cons (NULL_TREE, $2, $$);
  		  TREE_STATIC ($$) = TREE_STATIC ($1); }
  	| declmods attributes
! 		{ $$ = hash_tree_cons ($2, NULL_TREE, $1); }
  	| attributes
! 		{ $$ = hash_tree_cons ($1, NULL_TREE, NULL_TREE); }
  	;
  
  /* Used instead of declspecs where storage classes are not allowed
*************** structsp:
*** 2141,2151 ****
  		  $<ttype>$ = finish_class_definition ($1, $5, semi); 
  		}
  	  pending_defargs
!                 { finish_default_args (); }
  	  pending_inlines
!                 { $$.t = $<ttype>6;
  		  $$.new_type_flag = 1; 
! 		  begin_inline_definitions (); }
  	| class_head  %prec EMPTY
  		{
  		  $$.new_type_flag = 0;
--- 2150,2164 ----
  		  $<ttype>$ = finish_class_definition ($1, $5, semi); 
  		}
  	  pending_defargs
!                 {
! 		  begin_inline_definitions ();
! 		}
  	  pending_inlines
!                 {
! 		  finish_inline_definitions ();
! 		  $$.t = $<ttype>6;
  		  $$.new_type_flag = 1; 
! 		}
  	| class_head  %prec EMPTY
  		{
  		  $$.new_type_flag = 0;
*************** cv_qualifiers:
*** 2689,2698 ****
  
  nonempty_cv_qualifiers:
  	  CV_QUALIFIER
! 		{ $$.t = build_decl_list (NULL_TREE, $1); 
  		  $$.new_type_flag = 0; }
  	| nonempty_cv_qualifiers CV_QUALIFIER
! 		{ $$.t = decl_tree_cons (NULL_TREE, $2, $1.t); 
  		  $$.new_type_flag = $1.new_type_flag; }
  	;
  
--- 2702,2711 ----
  
  nonempty_cv_qualifiers:
  	  CV_QUALIFIER
! 		{ $$.t = hash_tree_cons (NULL_TREE, $1, NULL_TREE);
  		  $$.new_type_flag = 0; }
  	| nonempty_cv_qualifiers CV_QUALIFIER
! 		{ $$.t = hash_tree_cons (NULL_TREE, $2, $1.t); 
  		  $$.new_type_flag = $1.new_type_flag; }
  	;
  
Index: pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.277
diff -c -p -r1.277 pt.c
*** pt.c	1999/03/29 01:09:28	1.277
--- pt.c	1999/04/01 02:55:23
*************** tsubst_arg_types (arg_types, args, compl
*** 5834,5841 ****
    /* Note that we do not substitute into default arguments here.  The
       standard mandates that they be instantiated only when needed,
       which is done in build_over_call.  */
!   return hash_tree_cons_simple (TREE_PURPOSE (arg_types), type,
! 				remaining_arg_types);
  			 
  }
  
--- 5834,5841 ----
    /* Note that we do not substitute into default arguments here.  The
       standard mandates that they be instantiated only when needed,
       which is done in build_over_call.  */
!   return hash_tree_cons (TREE_PURPOSE (arg_types), type,
! 			 remaining_arg_types);
  			 
  }
  
*************** tsubst (t, args, complain, in_decl)
*** 6195,6209 ****
      case TREE_LIST:
        {
  	tree purpose, value, chain, result;
- 	int via_public, via_virtual, via_protected;
  
  	if (t == void_list_node)
  	  return t;
  
- 	via_public = TREE_VIA_PUBLIC (t);
- 	via_protected = TREE_VIA_PROTECTED (t);
- 	via_virtual = TREE_VIA_VIRTUAL (t);
- 
  	purpose = TREE_PURPOSE (t);
  	if (purpose)
  	  {
--- 6195,6204 ----
*************** tsubst (t, args, complain, in_decl)
*** 6229,6236 ****
  	    && value == TREE_VALUE (t)
  	    && chain == TREE_CHAIN (t))
  	  return t;
! 	result = hash_tree_cons (via_public, via_virtual, via_protected,
! 				 purpose, value, chain);
  	TREE_PARMLIST (result) = TREE_PARMLIST (t);
  	return result;
        }
--- 6224,6230 ----
  	    && value == TREE_VALUE (t)
  	    && chain == TREE_CHAIN (t))
  	  return t;
! 	result = hash_tree_cons (purpose, value, chain);
  	TREE_PARMLIST (result) = TREE_PARMLIST (t);
  	return result;
        }
Index: semantics.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/semantics.c,v
retrieving revision 1.44
diff -c -p -r1.44 semantics.c
*** semantics.c	1999/03/30 23:30:31	1.44
--- semantics.c	1999/04/01 02:55:23
*************** finish_class_definition (t, attributes, 
*** 1465,1471 ****
     the processing of a class definition.  */
  
  void
! finish_default_args ()
  {
    if (pending_inlines 
        && current_scope () == current_function_decl)
--- 1465,1471 ----
     the processing of a class definition.  */
  
  void
! begin_inline_definitions ()
  {
    if (pending_inlines 
        && current_scope () == current_function_decl)
*************** finish_default_args ()
*** 1476,1482 ****
     processing of a class definition.  */
  
  void
! begin_inline_definitions ()
  {
    if (current_class_type == NULL_TREE)
      clear_inline_text_obstack (); 
--- 1476,1482 ----
     processing of a class definition.  */
  
  void
! finish_inline_definitions ()
  {
    if (current_class_type == NULL_TREE)
      clear_inline_text_obstack (); 
Index: tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/tree.c,v
retrieving revision 1.102
diff -c -p -r1.102 tree.c
*** tree.c	1999/03/30 23:30:32	1.102
--- tree.c	1999/04/01 02:55:23
*************** static tree perm_manip PROTO((tree));
*** 33,40 ****
  static tree build_cplus_array_type_1 PROTO((tree, tree));
  static void list_hash_add PROTO((int, tree));
  static int list_hash PROTO((tree, tree, tree));
! static tree list_hash_lookup PROTO((int, int, int, int, tree, tree,
! 				    tree));
  static void propagate_binfo_offsets PROTO((tree, tree));
  static int avoid_overlap PROTO((tree, tree));
  static int lvalue_p_1 PROTO((tree, int));
--- 33,39 ----
  static tree build_cplus_array_type_1 PROTO((tree, tree));
  static void list_hash_add PROTO((int, tree));
  static int list_hash PROTO((tree, tree, tree));
! static tree list_hash_lookup PROTO((int, tree, tree, tree));
  static void propagate_binfo_offsets PROTO((tree, tree));
  static int avoid_overlap PROTO((tree, tree));
  static int lvalue_p_1 PROTO((tree, int));
*************** list_hash (purpose, value, chain)
*** 978,995 ****
     If one is found, return it.  Otherwise return 0.  */
  
  static tree
! list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
! 		  purpose, value, chain)
!      int hashcode, via_public, via_virtual, via_protected;
       tree purpose, value, chain;
  {
    register struct list_hash *h;
  
    for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
      if (h->hashcode == hashcode
- 	&& TREE_VIA_VIRTUAL (h->list) == via_virtual
- 	&& TREE_VIA_PUBLIC (h->list) == via_public
- 	&& TREE_VIA_PROTECTED (h->list) == via_protected
  	&& TREE_PURPOSE (h->list) == purpose
  	&& TREE_VALUE (h->list) == value
  	&& TREE_CHAIN (h->list) == chain)
--- 977,990 ----
     If one is found, return it.  Otherwise return 0.  */
  
  static tree
! list_hash_lookup (hashcode, purpose, value, chain)
!      int hashcode;
       tree purpose, value, chain;
  {
    register struct list_hash *h;
  
    for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
      if (h->hashcode == hashcode
  	&& TREE_PURPOSE (h->list) == purpose
  	&& TREE_VALUE (h->list) == value
  	&& TREE_CHAIN (h->list) == chain)
*************** list_hash_add (hashcode, list)
*** 1014,1037 ****
    list_hash_table[hashcode % TYPE_HASH_SIZE] = h;
  }
  
! /* Given TYPE, and HASHCODE its hash code, return the canonical
!    object for an identical list if one already exists.
!    Otherwise, return TYPE, and record it as the canonical object
!    if it is a permanent object.
! 
!    To use this function, first create a list of the sort you want.
!    Then compute its hash code from the fields of the list that
!    make it different from other similar lists.
!    Then call this function and use the value.
!    This function frees the list you pass in if it is a duplicate.  */
  
  /* Set to 1 to debug without canonicalization.  Never set by program.  */
  
  static int debug_no_list_hash = 0;
  
  tree
! hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
!      int via_public, via_virtual, via_protected;
       tree purpose, value, chain;
  {
    struct obstack *ambient_obstack = current_obstack;
--- 1009,1024 ----
    list_hash_table[hashcode % TYPE_HASH_SIZE] = h;
  }
  
! /* Given list components PURPOSE, VALUE, AND CHAIN, return the canonical
!    object for an identical list if one already exists.  Otherwise, build a
!    new one, and record it as the canonical object.  */
  
  /* Set to 1 to debug without canonicalization.  Never set by program.  */
  
  static int debug_no_list_hash = 0;
  
  tree
! hash_tree_cons (purpose, value, chain)
       tree purpose, value, chain;
  {
    struct obstack *ambient_obstack = current_obstack;
*************** hash_tree_cons (via_public, via_virtual,
*** 1041,1048 ****
    if (! debug_no_list_hash)
      {
        hashcode = list_hash (purpose, value, chain);
!       t = list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
! 			    purpose, value, chain);
        if (t)
  	return t;
      }
--- 1028,1034 ----
    if (! debug_no_list_hash)
      {
        hashcode = list_hash (purpose, value, chain);
!       t = list_hash_lookup (hashcode, purpose, value, chain);
        if (t)
  	return t;
      }
*************** hash_tree_cons (via_public, via_virtual,
*** 1050,1058 ****
    current_obstack = &class_obstack;
  
    t = tree_cons (purpose, value, chain);
-   TREE_VIA_PUBLIC (t) = via_public;
-   TREE_VIA_PROTECTED (t) = via_protected;
-   TREE_VIA_VIRTUAL (t) = via_virtual;
  
    /* If this is a new list, record it for later reuse.  */
    if (! debug_no_list_hash)
--- 1036,1041 ----
*************** tree
*** 1068,1074 ****
  hash_tree_chain (value, chain)
       tree value, chain;
  {
!   return hash_tree_cons (0, 0, 0, NULL_TREE, value, chain);
  }
  
  /* Similar, but used for concatenating two lists.  */
--- 1051,1057 ----
  hash_tree_chain (value, chain)
       tree value, chain;
  {
!   return hash_tree_cons (NULL_TREE, value, chain);
  }
  
  /* Similar, but used for concatenating two lists.  */


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