PATCH for memory usage in pt.c plus exception bug-fix

Mark Mitchell mark@markmitchell.com
Fri Sep 4 11:29:00 GMT 1998


This patch slightly reduces memory consumption during template
instantiation.  It also fixes an obscure exception handling bug, which
I found while reading carefully the code in tsubst.  We would call
`unexpected' when we shouldn't have.

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

1998-09-04  Mark Mitchell  <mark@markmitchell.com>

	* cp-tree.h (hash_tree_cons_simple): New macro.
	* pt.c (tsubst_arg_types): New function.  Use hash_tree_cons.
	(coerce_template_parms): Use make_temp_vec, instead of
	make_tree_vec.  Document this behavior.
	(lookup_template_class): Likewise.
	(tsubst, cases METHOD_TYPE, FUNCTION_TYPE): Use tsubst_arg_types.  
	Remove dead code (and add ssertion to check its deadness).  Fix
	bug w.r.t. exception specifications.

Index: testsuite/g++.old-deja/g++.eh/tmpl1.C
===================================================================
RCS file: tmpl1.C
diff -N tmpl1.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- tmpl1.C	Fri Sep  4 11:19:59 1998
***************
*** 0 ****
--- 1,15 ----
+ template <class T>
+ void f() throw (T)
+ {
+   throw 7;
+ }
+ 
+ 
+ int main()
+ {
+   try {
+     f<int>();
+   } catch (...) {
+     return 0;
+   }
+ }
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.132
diff -c -p -r1.132 cp-tree.h
*** cp-tree.h	1998/09/03 19:42:05	1.132
--- cp-tree.h	1998/09/04 18:20:16
*************** extern void push_expression_obstack		PRO
*** 3040,3045 ****
--- 3040,3047 ----
  #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 tree condition_conversion		PROTO((tree));
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.196
diff -c -p -r1.196 pt.c
*** pt.c	1998/09/03 14:15:33	1.196
--- pt.c	1998/09/04 18:20:39
*************** static void set_mangled_name_for_templat
*** 126,131 ****
--- 126,132 ----
  static int template_class_depth_real PROTO((tree, int));
  static tree tsubst_aggr_type PROTO((tree, tree, tree, int));
  static tree tsubst_decl PROTO((tree, tree, tree, tree));
+ static tree tsubst_arg_types PROTO((tree, tree, tree));
  
  /* We use TREE_VECs to hold template arguments.  If there is only one
     level of template arguments, then the TREE_VEC contains the
*************** convert_template_argument (parm, arg, ar
*** 2802,2808 ****
     If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
     provided in ARGLIST, or else trailing parameters must have default
     values.  If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
!    deduction for any unspecified trailing arguments.  */
     
  static tree
  coerce_template_parms (parms, args, in_decl,
--- 2803,2812 ----
     If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
     provided in ARGLIST, or else trailing parameters must have default
     values.  If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
!    deduction for any unspecified trailing arguments.  
! 
!    The resulting TREE_VEC is allocated on a temporary obstack, and
!    must be explicitly copied if it will be permanent.  */
     
  static tree
  coerce_template_parms (parms, args, in_decl,
*************** coerce_template_parms (parms, args, in_d
*** 2839,2845 ****
        return error_mark_node;
      }
  
!   new_inner_args = make_tree_vec (nparms);
    new_args = add_outermost_template_args (args, new_inner_args);
    for (i = 0; i < nparms; i++)
      {
--- 2843,2849 ----
        return error_mark_node;
      }
  
!   new_inner_args = make_temp_vec (nparms);
    new_args = add_outermost_template_args (args, new_inner_args);
    for (i = 0; i < nparms; i++)
      {
*************** lookup_template_class (d1, arglist, in_d
*** 3300,3306 ****
  	  int i;
  	  int saved_depth = TMPL_ARGS_DEPTH (arglist);
  
! 	  tree bound_args = make_tree_vec (parm_depth);
  	  
  	  for (i = saved_depth,
  		 t = DECL_TEMPLATE_PARMS (template); 
--- 3304,3310 ----
  	  int i;
  	  int saved_depth = TMPL_ARGS_DEPTH (arglist);
  
! 	  tree bound_args = make_temp_vec (parm_depth);
  	  
  	  for (i = saved_depth,
  		 t = DECL_TEMPLATE_PARMS (template); 
*************** tsubst_decl (t, args, type, in_decl)
*** 5191,5196 ****
--- 5195,5232 ----
  }
  
  
+ /* Substitue into the ARG_TYPES of a function type.  */
+ 
+ tree
+ tsubst_arg_types (arg_types, args, in_decl)
+      tree arg_types;
+      tree args;
+      tree in_decl;
+ {
+   tree remaining_arg_types;
+   tree result;
+   tree type;
+ 
+   if (!arg_types || arg_types == void_list_node)
+     return arg_types;
+   
+   remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types),
+ 					  args, in_decl);
+ 
+   /* We use TYPE_MAIN_VARIANT is because top-level qualifiers don't
+      matter on function types.  */
+   type = TYPE_MAIN_VARIANT (type_decays_to 
+ 			    (tsubst (TREE_VALUE (arg_types),
+ 				     args, in_decl)));
+ 
+   /* 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);
+ 			 
+ }
+ 
  /* Take the tree structure T and replace template parameters used therein
     with the argument vector ARGS.  IN_DECL is an associated decl for
     diagnostics.
*************** tsubst (t, args, in_decl)
*** 5495,5577 ****
      case FUNCTION_TYPE:
      case METHOD_TYPE:
        {
! 	tree values = TYPE_ARG_TYPES (t);
! 	tree context = TYPE_CONTEXT (t);
! 	tree raises = TYPE_RAISES_EXCEPTIONS (t);
  	tree fntype;
- 
- 	/* Don't bother recursing if we know it won't change anything.	*/
- 	if (values != void_list_node)
- 	  {
- 	    /* This should probably be rewritten to use hash_tree_cons for
-                the memory savings.  */
- 	    tree first = NULL_TREE;
- 	    tree last = NULL_TREE;
- 
- 	    for (; values && values != void_list_node;
- 		 values = TREE_CHAIN (values))
- 	      {
- 		tree value = TYPE_MAIN_VARIANT (type_decays_to
- 		  (tsubst (TREE_VALUE (values), args, in_decl)));
- 		/* Don't instantiate default args unless they are used.
- 		   Handle it in build_over_call instead.  */
- 		tree purpose = TREE_PURPOSE (values);
- 		tree x = build_tree_list (purpose, value);
  
! 		if (first)
! 		  TREE_CHAIN (last) = x;
! 		else
! 		  first = x;
! 		last = x;
! 	      }
! 
! 	    if (values == void_list_node)
! 	      TREE_CHAIN (last) = void_list_node;
! 
! 	    values = first;
! 	  }
! 	if (context)
! 	  context = tsubst (context, args, in_decl);
! 	/* Could also optimize cases where return value and
! 	   values have common elements (e.g., T min(const &T, const T&).  */
! 
! 	/* If the above parameters haven't changed, just return the type.  */
! 	if (type == TREE_TYPE (t)
! 	    && values == TYPE_VALUES (t)
! 	    && context == TYPE_CONTEXT (t))
! 	  return t;
  
  	/* Construct a new type node and return it.  */
! 	if (TREE_CODE (t) == FUNCTION_TYPE
! 	    && context == NULL_TREE)
! 	  {
! 	    fntype = build_function_type (type, values);
! 	  }
! 	else if (context == NULL_TREE)
! 	  {
! 	    tree base = tsubst (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))),
! 				args, in_decl);
! 	    fntype = build_cplus_method_type (base, type,
! 					      TREE_CHAIN (values));
! 	  }
! 	else
! 	  {
! 	    fntype = make_node (TREE_CODE (t));
! 	    TREE_TYPE (fntype) = type;
! 	    TYPE_CONTEXT (fntype) = FROB_CONTEXT (context);
! 	    TYPE_VALUES (fntype) = values;
! 	    TYPE_SIZE (fntype) = TYPE_SIZE (t);
! 	    TYPE_ALIGN (fntype) = TYPE_ALIGN (t);
! 	    TYPE_MODE (fntype) = TYPE_MODE (t);
! 	    if (TYPE_METHOD_BASETYPE (t))
! 	      TYPE_METHOD_BASETYPE (fntype) = tsubst (TYPE_METHOD_BASETYPE (t),
! 						      args, in_decl);
! 	    /* Need to generate hash value.  */
! 	    my_friendly_abort (84);
! 	  }
  	fntype = build_type_variant (fntype,
  				     TYPE_READONLY (t),
  				     TYPE_VOLATILE (t));
  	if (raises)
  	  {
  	    raises = tsubst (raises, args, in_decl);
--- 5531,5561 ----
      case FUNCTION_TYPE:
      case METHOD_TYPE:
        {
! 	tree arg_types;
! 	tree raises;
  	tree fntype;
  
! 	/* The TYPE_CONTEXT is not used for function/method types.  */
! 	my_friendly_assert (TYPE_CONTEXT (t) == NULL_TREE, 0);
! 	
! 	/* Substitue the argument types.  */
! 	arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, in_decl);
  
  	/* Construct a new type node and return it.  */
! 	if (TREE_CODE (t) == FUNCTION_TYPE)
! 	  fntype = build_function_type (type, arg_types);
! 	else 
! 	  fntype 
! 	    = build_cplus_method_type (TREE_TYPE (TREE_VALUE (arg_types)),
! 				       type,
! 				       TREE_CHAIN (arg_types));
! 
  	fntype = build_type_variant (fntype,
  				     TYPE_READONLY (t),
  				     TYPE_VOLATILE (t));
+ 
+ 	/* Substitue the exception specification. */
+ 	raises = TYPE_RAISES_EXCEPTIONS (t);
  	if (raises)
  	  {
  	    raises = tsubst (raises, args, in_decl);



More information about the Gcc-patches mailing list