PATCH to fix several template template parameter bugs

Kriang Lerdsuwanakij lerdsuwa@scf-fs.usc.edu
Tue Jun 30 00:30:00 GMT 1998


Hi

This patch fixes several bugs inside the function coerce_template_parms.  
The ugly recursion in this function is also removed by introducing a new
function.

Here is the list of bugs fixed by the patch:
- Choosing the right template function from the set of overloading
  functions (testcases ttp47.C, ttp48.C).
- Non-type parameters of template template parameters are checked
  (ttp49.C).
- Parameters of template template parameters that depend on
  preceding parameters (ttp50.C).
- Don't always accessing ARGLIST (TREE_VEC or TREE_LIST) as TREE_LIST
  (ttp51.C).  [Reported by Martin and again by Haakon in
  http://www.cygnus.com/ml/egcs-bugs/1998-Jun/0370.html ]
- Don't call tsubst for default arguments when coercing parameters
  of template template parameters (ttp51.C).
- Don't be too generous about accepting TYPE_DECL for template
  template parameters (ttp52.C).  [Exposed in Haakon's testcase.]

--Kriang


	* pt.c (coerce_template_template_parms): New function equivalent
	to coerce_template_parms when IS_TMPL_PARM is true.
	(coerce_template_parms): Use it.  Remove the IS_TMPL_PARM parameter,
	all callers changed.

	(coerce_template_parms): Access ARGLIST properly when creating a
	new vector.  Only accept implicit TYPE_DECL as valid argument for
	a template template parameter when it is a base class of
	current_class_type.  Don't display error message when COMPLAIN is
	false.


diff -crpN gcc-old/cp/pt.c gcc/cp/pt.c
*** gcc-old/cp/pt.c	Sat Jun 27 23:52:28 1998
--- gcc/cp/pt.c	Sat Jun 27 23:51:50 1998
*************** static char *mangle_class_name_for_templ
*** 84,90 ****
  static tree tsubst_expr_values PROTO((tree, tree));
  static int list_eq PROTO((tree, tree));
  static tree get_class_bindings PROTO((tree, tree, tree, tree));
! static tree coerce_template_parms PROTO((tree, tree, tree, int, int, int));
  static tree tsubst_enum	PROTO((tree, tree, tree *));
  static tree add_to_template_args PROTO((tree, tree));
  static void maybe_adjust_types_for_deduction PROTO((unification_kind_t, tree*,
--- 84,90 ----
  static tree tsubst_expr_values PROTO((tree, tree));
  static int list_eq PROTO((tree, tree));
  static tree get_class_bindings PROTO((tree, tree, tree, tree));
! static tree coerce_template_parms PROTO((tree, tree, tree, int, int));
  static tree tsubst_enum	PROTO((tree, tree, tree *));
  static tree add_to_template_args PROTO((tree, tree));
  static void maybe_adjust_types_for_deduction PROTO((unification_kind_t, tree*,
*************** convert_nontype_argument (type, expr)
*** 2337,2342 ****
--- 2337,2418 ----
    return error_mark_node;
  }
  
+ /* Return 1 if PARM_PARMS and ARG_PARMS matches using rule for 
+    template template parameters.  Both PARM_PARMS and ARG_PARMS are 
+    vectors of TREE_LIST nodes containing TYPE_DECL, TEMPLATE_DECL 
+    or PARM_DECL.
+    
+    ARG_PARMS may contain more parameters than PARM_PARMS.  If this is 
+    the case, then extra parameters must have default arguments.
+ 
+    Consider the example:
+      template <class T, class Allocator = allocator> class vector;
+      template<template <class U> class TT> class C;
+ 
+    C<vector> is a valid instantiation.  PARM_PARMS for the above code 
+    contains a TYPE_DECL (for U),  ARG_PARMS contains two TYPE_DECLs (for 
+    T and Allocator) and OUTER_ARGS contains the argument that is used to 
+    substitute the TT parameter.  */
+ 
+ static int
+ coerce_template_template_parms (parm_parms, arg_parms, in_decl, outer_args)
+      tree parm_parms, arg_parms, in_decl, outer_args;
+ {
+   int nparms, nargs, i;
+   tree parm, arg;
+ 
+   my_friendly_assert (TREE_CODE (parm_parms) == TREE_VEC, 0);
+   my_friendly_assert (TREE_CODE (arg_parms) == TREE_VEC, 0);
+ 
+   nparms = TREE_VEC_LENGTH (parm_parms);
+   nargs = TREE_VEC_LENGTH (arg_parms);
+ 
+   /* The rule here is opposite of coerce_template_parms.  */
+   if (nargs < nparms
+       || (nargs > nparms
+ 	  && TREE_PURPOSE (TREE_VEC_ELT (arg_parms, nparms)) == NULL_TREE))
+     return 0;
+ 
+   for (i = 0; i < nparms; ++i)
+     {
+       parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, i));
+       arg = TREE_VALUE (TREE_VEC_ELT (arg_parms, i));
+ 
+       if (arg == NULL_TREE || arg == error_mark_node
+           || parm == NULL_TREE || parm == error_mark_node)
+ 	return 0;
+ 
+       if (TREE_CODE (arg) != TREE_CODE (parm))
+         return 0;
+ 
+       switch (TREE_CODE (parm))
+ 	{
+ 	case TYPE_DECL:
+ 	  break;
+ 
+ 	case TEMPLATE_DECL:
+ 	  /* We encounter instantiations of templates like
+ 	       template <template <template <class> class> class TT>
+ 	       class C;  */
+ 	  cp_error ("nested template template parameter not implemented");
+ 	  return 0;
+ 
+ 	case PARM_DECL:
+ 	  /* The tsubst call is used to handle cases such as
+ 	       template <class T, template <T> class TT> class D;  
+ 	     i.e. the parameter list of TT depends on earlier parameters.  */
+ 	  if (!comptypes (tsubst (TREE_TYPE (parm), outer_args, in_decl), 
+ 			  TREE_TYPE (arg), 1))
+ 	    return 0;
+ 	  break;
+ 	  
+ 	default:
+ 	  my_friendly_abort (0);
+ 	}
+     }
+   return 1;
+ }
+ 
  /* Convert all template arguments to their appropriate types, and return
     a vector containing the resulting values.  If any error occurs, return
     error_mark_node, and, if COMPLAIN is non-zero, issue an error message.
*************** convert_nontype_argument (type, expr)
*** 2346,2367 ****
     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.
     
-    If IS_TMPL_PARM is non-zero,  we will coercing parameters of template 
-    template arguments.  In this case, ARGLIST is a chain of TREE_LIST
-    nodes containing TYPE_DECL, TEMPLATE_DECL or PARM_DECL.  */
- 
  static tree
  coerce_template_parms (parms, arglist, in_decl,
  		       complain,
! 		       require_all_arguments,
! 		       is_tmpl_parm)
       tree parms, arglist;
       tree in_decl;
       int complain;
       int require_all_arguments;
-      int is_tmpl_parm;
  {
    int nparms, nargs, i, lost = 0;
    tree vec = NULL_TREE;
--- 2422,2437 ----
     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, arglist, in_decl,
  		       complain,
! 		       require_all_arguments)
       tree parms, arglist;
       tree in_decl;
       int complain;
       int require_all_arguments;
  {
    int nparms, nargs, i, lost = 0;
    tree vec = NULL_TREE;
*************** coerce_template_parms (parms, arglist, i
*** 2404,2410 ****
  	  tree arg;
  	  tree parm = TREE_VEC_ELT (parms, i);
  
! 	  if (arglist)
  	    {
  	      arg = arglist;
  	      arglist = TREE_CHAIN (arglist);
--- 2474,2480 ----
  	  tree arg;
  	  tree parm = TREE_VEC_ELT (parms, i);
  
! 	  if (arglist && TREE_CODE (arglist) == TREE_LIST)
  	    {
  	      arg = arglist;
  	      arglist = TREE_CHAIN (arglist);
*************** coerce_template_parms (parms, arglist, i
*** 2414,2420 ****
  	      else
  		arg = TREE_VALUE (arg);
  	    }
! 	  else if (is_tmpl_parm && i < nargs)
  	    {
  	      arg = TREE_VEC_ELT (arglist, i);
  	      if (arg == error_mark_node)
--- 2484,2490 ----
  	      else
  		arg = TREE_VALUE (arg);
  	    }
! 	  else if (i < nargs)
  	    {
  	      arg = TREE_VEC_ELT (arglist, i);
  	      if (arg == error_mark_node)
*************** coerce_template_parms (parms, arglist, i
*** 2440,2455 ****
        tree val = 0;
        int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
  
-       if (is_tmpl_parm && i < nargs)
- 	{
- 	  /* In case we are checking arguments inside a template template
- 	     parameter, ARG that does not come from default argument is 
- 	     also a TREE_LIST node.  Note that ARG can also be a TREE_LIST
- 	     in other cases such as overloaded functions.  */
- 	  if (arg != NULL_TREE && arg != error_mark_node)
- 	    arg = TREE_VALUE (arg);
- 	}
- 
        if (arg == NULL_TREE)
  	/* We're out of arguments.  */
  	{
--- 2510,2515 ----
*************** coerce_template_parms (parms, arglist, i
*** 2491,2506 ****
  		         && CLASSTYPE_TEMPLATE_INFO (arg)
  		         && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
  			 && DECL_ARTIFICIAL (TYPE_NAME (arg))
! 			 && requires_tmpl_type);
        if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
  	arg = TYPE_STUB_DECL (arg);
        else if (is_tmpl_type && TREE_CODE (arg) == RECORD_TYPE)
  	arg = CLASSTYPE_TI_TEMPLATE (arg);
  
!       if (is_tmpl_parm && i < nargs)
! 	is_type = TREE_CODE (arg) == TYPE_DECL || is_tmpl_type;
!       else
! 	is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't' || is_tmpl_type;
  
        if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF
  	  && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
--- 2551,2565 ----
  		         && CLASSTYPE_TEMPLATE_INFO (arg)
  		         && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
  			 && DECL_ARTIFICIAL (TYPE_NAME (arg))
! 			 && requires_tmpl_type
! 			 && current_class_type
! 			 && get_binfo (arg, current_class_type, 0));
        if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
  	arg = TYPE_STUB_DECL (arg);
        else if (is_tmpl_type && TREE_CODE (arg) == RECORD_TYPE)
  	arg = CLASSTYPE_TI_TEMPLATE (arg);
  
!       is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't' || is_tmpl_type;
  
        if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF
  	  && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
*************** coerce_template_parms (parms, arglist, i
*** 2536,2562 ****
  	{
  	  if (in_decl)
  	    {
! 	      cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
! 			i + 1, in_decl);
! 	      if (is_tmpl_type)
! 		cp_error ("  expected a type, got `%T'", DECL_NAME (arg));
! 	      else
! 		cp_error ("  expected a class template, got `%T'", arg);
  	    }
  	  lost++;
  	  TREE_VEC_ELT (vec, i) = error_mark_node;
  	  continue;
  	}
-       if (is_tmpl_parm)
- 	{
- 	  if (requires_tmpl_type)
- 	    {
- 	      cp_error ("nested template template parameter not implemented");
- 	      lost++;
- 	      TREE_VEC_ELT (vec, i) = error_mark_node;
- 	    }
- 	  continue;
- 	}
          
        if (is_type)
  	{
--- 2595,2614 ----
  	{
  	  if (in_decl)
  	    {
! 	      if (complain)
! 		{
! 		  cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
! 			    i + 1, in_decl);
! 		  if (is_tmpl_type)
! 		    cp_error ("  expected a type, got `%T'", DECL_NAME (arg));
! 		  else
! 		    cp_error ("  expected a class template, got `%T'", arg);
! 		}
  	    }
  	  lost++;
  	  TREE_VEC_ELT (vec, i) = error_mark_node;
  	  continue;
  	}
          
        if (is_type)
  	{
*************** coerce_template_parms (parms, arglist, i
*** 2565,2587 ****
  	      tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
  	      tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
  
! 	      /* The parameter and argument roles have to be switched 
! 		 here in order to handle default arguments properly.  
! 		 For example, 
! 		   template<template <class> class TT> void f(TT<int>) 
! 		 should be able to accept vector<int> which comes from 
! 		   template <class T, class Allcator = allocator> 
! 		   class vector.  */
  
! 	      val = coerce_template_parms (argparm, parmparm, in_decl, 1, 1, 1);
! 	      if (val != error_mark_node)
! 		val = arg;
! 		    
! 	      /* TEMPLATE_TEMPLATE_PARM node is preferred over 
! 		 TEMPLATE_DECL.  */
! 	      if (val != error_mark_node 
! 		  && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
! 		val = TREE_TYPE (val);
  	    }
  	  else
  	    {
--- 2617,2644 ----
  	      tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
  	      tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
  
! 	      if (coerce_template_template_parms (parmparm, argparm, 
! 						  in_decl, vec))
! 		{
! 		  val = arg;
  
! 		  /* TEMPLATE_TEMPLATE_PARM node is preferred over 
! 		     TEMPLATE_DECL.  */
! 		  if (val != error_mark_node 
! 		      && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
! 		    val = TREE_TYPE (val);
! 		}
! 	      else
! 		{
! 		  if (in_decl && complain)
! 		    {
! 		      cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
! 				i + 1, in_decl);
! 		      cp_error ("  expected a template of type `%D', got `%D'", parm, arg);
! 		    }
! 
! 		  val = error_mark_node;
! 		}
  	    }
  	  else
  	    {
*************** lookup_template_class (d1, arglist, in_d
*** 3002,3008 ****
        CLASSTYPE_GOT_SEMICOLON (parm) = 1;
        parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
  
!       arglist2 = coerce_template_parms (parmlist, arglist, template, 1, 1, 0);
        if (arglist2 == error_mark_node)
  	return error_mark_node;
  
--- 3059,3065 ----
        CLASSTYPE_GOT_SEMICOLON (parm) = 1;
        parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
  
!       arglist2 = coerce_template_parms (parmlist, arglist, template, 1, 1);
        if (arglist2 == error_mark_node)
  	return error_mark_node;
  
*************** lookup_template_class (d1, arglist, in_d
*** 3038,3050 ****
  	    TREE_VEC_ELT (new_args, i) =
  	      coerce_template_parms (TREE_VALUE (t),
  				     TREE_VEC_ELT (arglist, i),
! 				     template, 1, 1, 0);
  	  arglist = new_args;
  	}
        else
  	arglist = coerce_template_parms (parmlist, 
  					 innermost_args (arglist, 0),
! 					 template, 1, 1, 0);
       if (arglist == error_mark_node)
  	return error_mark_node;
        if (uses_template_parms (arglist))
--- 3095,3107 ----
  	    TREE_VEC_ELT (new_args, i) =
  	      coerce_template_parms (TREE_VALUE (t),
  				     TREE_VEC_ELT (arglist, i),
! 				     template, 1, 1);
  	  arglist = new_args;
  	}
        else
  	arglist = coerce_template_parms (parmlist, 
  					 innermost_args (arglist, 0),
! 					 template, 1, 1);
       if (arglist == error_mark_node)
  	return error_mark_node;
        if (uses_template_parms (arglist))
*************** type_unification (tparms, targs, parms, 
*** 5831,5837 ****
      {
        tree arg_vec;
        arg_vec = coerce_template_parms (tparms, explicit_targs, NULL_TREE, 0,
! 				       0, 0);
  
        if (arg_vec == error_mark_node)
  	return 1;
--- 5888,5894 ----
      {
        tree arg_vec;
        arg_vec = coerce_template_parms (tparms, explicit_targs, NULL_TREE, 0,
! 				       0);
  
        if (arg_vec == error_mark_node)
  	return 1;
*************** unify (tparms, targs, parm, arg, strict,
*** 6247,6256 ****
  		   in order to handle default arguments properly.  For example, 
  		   template<template <class> class TT> void f(TT<int>) 
  		   should be able to accept vector<int> which comes from 
! 		   template <class T, class Allcator = allocator> 
  		   class vector.  */
  
! 		if (coerce_template_parms (argtmplvec, parmvec, parmtmpl, 1, 1, 0)
  		    == error_mark_node)
  		  return 1;
  	  
--- 6304,6313 ----
  		   in order to handle default arguments properly.  For example, 
  		   template<template <class> class TT> void f(TT<int>) 
  		   should be able to accept vector<int> which comes from 
! 		   template <class T, class Allocator = allocator> 
  		   class vector.  */
  
! 		if (coerce_template_parms (argtmplvec, parmvec, parmtmpl, 1, 1)
  		    == error_mark_node)
  		  return 1;
  	  
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp3.C gcc/testsuite/g++.old-deja/g++.pt/ttp3.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp3.C	Sat Jun 27 23:54:39 1998
--- gcc/testsuite/g++.old-deja/g++.pt/ttp3.C	Sat Jun 27 23:55:00 1998
*************** template<class E,class F> class D
*** 5,11 ****
  };
  
  template<template<class> class D,class E> class C
! {				// ERROR - ref below
  };
  
  int main()
--- 5,11 ----
  };
  
  template<template<class> class D,class E> class C
! {
  };
  
  int main()
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp47.C gcc/testsuite/g++.old-deja/g++.pt/ttp47.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp47.C	Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp47.C	Sat Jun 27 23:57:12 1998
***************
*** 0 ****
--- 1,16 ----
+ template <template<class,class> class TT, class T> void f(T)
+ {
+ }
+ 
+ template <template<class> class TT, class T> void f(T)
+ {
+ }
+ 
+ template <class T> class C {};
+ template <class T,class U> class D {};
+ 
+ int main()
+ {
+ 	f<C>(1);
+ 	f<D>(1);
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp48.C gcc/testsuite/g++.old-deja/g++.pt/ttp48.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp48.C	Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp48.C	Sat Jun 27 23:57:39 1998
***************
*** 0 ****
--- 1,16 ----
+ template <template<int> class TT, class T> void f(T)
+ {
+ }
+ 
+ template <template<class> class TT, class T> void f(T)
+ {
+ }
+ 
+ template <class T> class C {};
+ template <int> class D {};
+ 
+ int main()
+ {
+ 	f<C>(1);
+ 	f<D>(1);
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp49.C gcc/testsuite/g++.old-deja/g++.pt/ttp49.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp49.C	Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp49.C	Sat Jun 27 23:58:04 1998
***************
*** 0 ****
--- 1,9 ----
+ // Build don't link:
+ 
+ template <int i> class C {};
+ template <template <long> class TT> class D {};
+ 
+ int main()
+ {
+ 	D<C> d;		// ERROR - args not match
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp50.C gcc/testsuite/g++.old-deja/g++.pt/ttp50.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp50.C	Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp50.C	Sat Jun 27 23:58:48 1998
***************
*** 0 ****
--- 1,7 ----
+ template <class T, template <T> class TT> class C {};
+ template <int> class D {};
+ 
+ int main()
+ {
+   C<int,D> c;
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp51.C gcc/testsuite/g++.old-deja/g++.pt/ttp51.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp51.C	Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp51.C	Sat Jun 27 23:59:06 1998
***************
*** 0 ****
--- 1,13 ----
+ template<class E, int i, class F, class G=int, int j=i, class H=E> class D
+ {
+ };
+ 
+ template<template<class,int,class,class> class D,class E> class C
+ {
+ 	D<E,2,char,bool>	d;
+ };
+ 
+ int main()
+ {
+ 	C<D,int> c;
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp52.C gcc/testsuite/g++.old-deja/g++.pt/ttp52.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp52.C	Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp52.C	Sun Jun 28 00:16:58 1998
***************
*** 0 ****
--- 1,18 ----
+ // Build don't link:
+ 
+ template<class A,class B> class mymap {};
+ 
+ template<class Key, 
+          class Value, 
+          template<class, class > class MapT> 
+ class base 
+ {
+   
+ };
+ 
+ // specialization
+ template<class Key, class Value>
+ class base<Key, Value, mymap<int, int > >	// ERROR - mymap<...> is not a template
+ {						// ERROR - Bad class name
+   
+ };




More information about the Gcc-patches mailing list