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]

PATCH to avoid crash with bad template arguments



This patch fixes the attached test case, which used to cause an ICE.
This kind of error can come up easily when using STL, since it makes
heavy use of default template arguments.

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

1998-08-30  Mark Mitchell  <mark@markmitchell.com>

	* pt.c (convert_template_argument): New function, split out
	from...
	(coerce_template_parms): Here.
	(tsubst): Attempt better error-recovery.

Index: testsuite/g++.old-deja/g++.pt/crash22.C
===================================================================
RCS file: crash22.C
diff -N crash22.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- crash22.C	Sun Aug 30 10:41:30 1998
***************
*** 0 ****
--- 1,9 ----
+ // Build don't link:
+ 
+ template <class T>
+ struct S1 {};
+ 
+ template <class T, class U = S1<T> > 
+ struct S2 {};
+ 
+ template struct S2<100>; // ERROR - type/value mismatch
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.191
diff -c -p -r1.191 pt.c
*** pt.c	1998/08/29 01:15:22	1.191
--- pt.c	1998/08/30 17:41:55
*************** static int  type_unification_real PROTO(
*** 95,100 ****
--- 95,102 ----
  static void note_template_header PROTO((int));
  static tree maybe_fold_nontype_arg PROTO((tree));
  static tree convert_nontype_argument PROTO((tree, tree));
+ static tree convert_template_argument PROTO ((tree, tree, tree, int,
+ 					      int , tree));
  static tree get_bindings_overload PROTO((tree, tree, tree));
  static int for_each_template_parm PROTO((tree, tree_fn_t, void*));
  static tree build_template_parm_index PROTO((int, int, int, tree, tree));
*************** coerce_template_template_parms (parm_par
*** 2596,2626 ****
    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.
-    Some error messages are issued even if COMPLAIN is zero; for
-    instance, if a template argument is composed from a local class. 
  
     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 inner_args;
!   tree vec;
  
!   inner_args = innermost_args (arglist);
    nargs = NUM_TMPL_ARGS (inner_args);
    nparms = TREE_VEC_LENGTH (parms);
  
--- 2598,2825 ----
    return 1;
  }
  
  
+ /* Convert the indicated template ARG as necessary to match the
+    indicated template PARM.  Returns the converted ARG, or
+    error_mark_node if the conversion was unsuccessful.  Error messages
+    are issued if COMPLAIN is non-zero.  This conversion is for the Ith
+    parameter in the parameter list.  ARGS is the full set of template
+    arguments deduced so far.  */
+ 
+ static tree
+ convert_template_argument (parm, arg, args, complain, i, in_decl)
+      tree parm;
+      tree arg;
+      tree args;
+      int complain;
+      int i;
+      tree in_decl;
+ {
+   tree val;
+   tree inner_args;
+   int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
+   
+   inner_args = innermost_args (args);
+ 
+   if (TREE_CODE (arg) == TREE_LIST 
+       && TREE_TYPE (arg) != NULL_TREE
+       && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
+     {  
+       /* The template argument was the name of some
+ 	 member function.  That's usually
+ 	 illegal, but static members are OK.  In any
+ 	 case, grab the underlying fields/functions
+ 	 and issue an error later if required.  */
+       arg = TREE_VALUE (arg);
+       TREE_TYPE (arg) = unknown_type_node;
+     }
+ 
+   requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;
+   requires_type = (TREE_CODE (parm) == TYPE_DECL
+ 		   || requires_tmpl_type);
+ 
+   /* Check if it is a class template.  If REQUIRES_TMPL_TYPE is true,
+      we also accept implicitly created TYPE_DECL as a valid argument.
+      This is necessary to handle the case where we pass a template name
+      to a template template parameter in a scope where we've derived from
+      in instantiation of that template, so the template name refers to that
+      instantiation.  We really ought to handle this better.  */
+   is_tmpl_type 
+     = ((TREE_CODE (arg) == TEMPLATE_DECL
+ 	&& TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
+        || (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
+ 	   && !CLASSTYPE_TEMPLATE_INFO (arg))
+        || (TREE_CODE (arg) == RECORD_TYPE
+ 	   && CLASSTYPE_TEMPLATE_INFO (arg)
+ 	   && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
+ 	   && DECL_ARTIFICIAL (TYPE_NAME (arg))
+ 	   && requires_tmpl_type
+ 	   && current_class_type
+ 	   /* FIXME what about nested types?  */
+ 	   && 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)
+     {
+       cp_pedwarn ("to refer to a type member of a template parameter,");
+       cp_pedwarn ("  use `typename %E'", arg);
+       
+       arg = make_typename_type (TREE_OPERAND (arg, 0),
+ 				TREE_OPERAND (arg, 1));
+       is_type = 1;
+     }
+   if (is_type != requires_type)
+     {
+       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_type)
+ 		cp_error ("  expected a constant of type `%T', got `%T'",
+ 			  TREE_TYPE (parm),
+ 			  (is_tmpl_type ? DECL_NAME (arg) : arg));
+ 	      else
+ 		cp_error ("  expected a type, got `%E'", arg);
+ 	    }
+ 	}
+       return error_mark_node;
+     }
+   if (is_tmpl_type ^ requires_tmpl_type)
+     {
+       if (in_decl && 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);
+ 	}
+       return error_mark_node;
+     }
+       
+   if (is_type)
+     {
+       if (requires_tmpl_type)
+ 	{
+ 	  tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
+ 	  tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
+ 
+ 	  if (coerce_template_template_parms (parmparm, argparm, 
+ 					      in_decl, inner_args))
+ 	    {
+ 	      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
+ 	{
+ 	  val = groktypename (arg);
+ 	  if (! processing_template_decl)
+ 	    {
+ 	      /* [basic.link]: A name with no linkage (notably, the
+ 		 name of a class or enumeration declared in a local
+ 		 scope) shall not be used to declare an entity with
+ 		 linkage.  This implies that names with no linkage
+ 		 cannot be used as template arguments.  */
+ 	      tree t = no_linkage_check (val);
+ 	      if (t)
+ 		{
+ 		  if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
+ 		    cp_pedwarn
+ 		      ("template-argument `%T' uses anonymous type", val);
+ 		  else
+ 		    cp_error
+ 		      ("template-argument `%T' uses local type `%T'",
+ 		       val, t);
+ 		  return error_mark_node;
+ 		}
+ 	    }
+ 	}
+     }
+   else
+     {
+       tree t = tsubst (TREE_TYPE (parm), args, in_decl);
+ 
+       if (processing_template_decl)
+ 	arg = maybe_fold_nontype_arg (arg);
+ 
+       if (!uses_template_parms (arg) && !uses_template_parms (t))
+ 	/* We used to call digest_init here.  However, digest_init
+ 	   will report errors, which we don't want when complain
+ 	   is zero.  More importantly, digest_init will try too
+ 	   hard to convert things: for example, `0' should not be
+ 	   converted to pointer type at this point according to
+ 	   the standard.  Accepting this is not merely an
+ 	   extension, since deciding whether or not these
+ 	   conversions can occur is part of determining which
+ 	   function template to call, or whether a given epxlicit
+ 	   argument specification is legal.  */
+ 	val = convert_nontype_argument (t, arg);
+       else
+ 	val = arg;
+ 
+       if (val == NULL_TREE)
+ 	val = error_mark_node;
+       else if (val == error_mark_node && complain)
+ 	cp_error ("could not convert template argument `%E' to `%T'", 
+ 		  arg, t);
+     }
+ 
+   return val;
+ }
+ 
+ /* Convert all template arguments to their appropriate types, and
+    return a vector containing the innermost resulting template
+    arguments.  If any error occurs, return error_mark_node, and, if
+    COMPLAIN is non-zero, issue an error message.  Some error messages
+    are issued even if COMPLAIN is zero; for instance, if a template
+    argument is composed from a local class.
+ 
     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,
  		       complain,
  		       require_all_arguments)
!      tree parms, args;
       tree in_decl;
       int complain;
       int require_all_arguments;
  {
    int nparms, nargs, i, lost = 0;
    tree inner_args;
!   tree new_args;
!   tree new_inner_args;
  
!   inner_args = innermost_args (args);
    nargs = NUM_TMPL_ARGS (inner_args);
    nparms = TREE_VEC_LENGTH (parms);
  
*************** coerce_template_parms (parms, arglist, i
*** 2641,2918 ****
        return error_mark_node;
      }
  
!   /* Create in VEC the appropriate innermost arguments, and reset
!      ARGLIST to contain the complete set of arguments.  */
!   if (inner_args && TREE_CODE (inner_args) == TREE_VEC && nargs == nparms)
!     {
!       /* If we already have all the arguments, we can just use them.
! 	 This is an optimization over the code in the `else' branch
! 	 below, and should be functionally identicial.  */
!       vec = copy_node (inner_args);
!       arglist = add_outermost_template_args (arglist, vec);
!     }
!   else
      {
!       /* If we don't already have all the arguments we must get what
! 	 we can from default template arguments.  The tricky bit is
! 	 that previous arguments can influence the default values,
! 	 e.g.:  
! 
! 	   template <class T, class U = T> void foo();
! 
! 	 If we see `foo<int>' we have to come up with an {int, int}
! 	 vector.  */
  
!       tree new_arglist;
  
!       vec = make_tree_vec (nparms);
!       new_arglist = add_outermost_template_args (arglist, vec);
! 
!       for (i = 0; i < nparms; i++)
  	{
! 	  tree arg;
! 	  tree parm = TREE_VEC_ELT (parms, i);
! 
! 	  if (arglist && TREE_CODE (arglist) == TREE_LIST)
! 	    {
! 	      arg = arglist;
! 	      arglist = TREE_CHAIN (arglist);
! 
! 	      if (arg == error_mark_node)
! 		lost++;
! 	      else
! 		arg = TREE_VALUE (arg);
! 	    }
! 	  else if (i < nargs)
! 	    {
! 	      arg = TREE_VEC_ELT (inner_args, i);
! 	      if (arg == error_mark_node)
! 		lost++;
! 	    }
! 	  /* If no template argument was supplied, look for a default
! 	     value.  */
! 	  else if (TREE_PURPOSE (parm) == NULL_TREE)
! 	    {
! 	      /* There was no default value.  */
! 	      my_friendly_assert (!require_all_arguments, 0);
! 	      break;
! 	    }
! 	  else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL)
! 	    arg = tsubst (TREE_PURPOSE (parm), new_arglist, in_decl);
! 	  else
! 	    arg = tsubst_expr (TREE_PURPOSE (parm), new_arglist, in_decl);
! 
! 	  TREE_VEC_ELT (vec, i) = arg;
  	}
! 
!       /* We've left ARGLIST intact up to this point, in order to allow
! 	 iteration through it in the case that it was a TREE_LIST, but
! 	 from here on it should contain the full set of template
! 	 arguments.  */
!       arglist = new_arglist;
!     }
! 
!   for (i = 0; i < nparms; i++)
!     {
!       tree arg = TREE_VEC_ELT (vec, i);
!       tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
!       tree val = 0;
!       int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
  
        if (arg == NULL_TREE)
  	/* We're out of arguments.  */
  	{
  	  my_friendly_assert (!require_all_arguments, 0);
  	  break;
  	}
! 
!       if (arg == error_mark_node)
  	{
  	  cp_error ("template argument %d is invalid", i + 1);
! 	  lost++;
! 	  continue;
! 	}
! 
!       if (TREE_CODE (arg) == TREE_LIST 
! 	  && TREE_TYPE (arg) != NULL_TREE
! 	  && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
! 	{  
! 	  /* The template argument was the name of some
! 	     member function.  That's usually
! 	     illegal, but static members are OK.  In any
! 	     case, grab the underlying fields/functions
! 	     and issue an error later if required.  */
! 	  arg = TREE_VALUE (arg);
! 	  TREE_TYPE (arg) = unknown_type_node;
! 	}
! 
!       requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;
!       requires_type = TREE_CODE (parm) == TYPE_DECL
! 		      || requires_tmpl_type;
! 
!       /* Check if it is a class template.  If REQUIRES_TMPL_TYPE is true,
! 	 we also accept implicitly created TYPE_DECL as a valid argument.
!          This is necessary to handle the case where we pass a template name
!          to a template template parameter in a scope where we've derived from
!          in instantiation of that template, so the template name refers to that
!          instantiation.  We really ought to handle this better.  */
!       is_tmpl_type = (TREE_CODE (arg) == TEMPLATE_DECL
! 		      && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
! 		     || (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
! 			 && !CLASSTYPE_TEMPLATE_INFO (arg))
! 		     || (TREE_CODE (arg) == RECORD_TYPE
! 		         && CLASSTYPE_TEMPLATE_INFO (arg)
! 		         && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
! 			 && DECL_ARTIFICIAL (TYPE_NAME (arg))
! 			 && requires_tmpl_type
! 			 && current_class_type
! 			 /* FIXME what about nested types?  */
! 			 && 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)
! 	{
! 	  cp_pedwarn ("to refer to a type member of a template parameter,");
! 	  cp_pedwarn ("  use `typename %E'", arg);
! 
! 	  arg = make_typename_type (TREE_OPERAND (arg, 0),
! 				    TREE_OPERAND (arg, 1));
! 	  is_type = 1;
! 	}
!       if (is_type != requires_type)
! 	{
! 	  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_type)
! 		    cp_error ("  expected a constant of type `%T', got `%T'",
! 			      TREE_TYPE (parm),
! 			      (is_tmpl_type ? DECL_NAME (arg) : arg));
! 		  else
! 		    cp_error ("  expected a type, got `%E'", arg);
! 		}
! 	    }
! 	  lost++;
! 	  TREE_VEC_ELT (vec, i) = error_mark_node;
! 	  continue;
! 	}
!       if (is_tmpl_type ^ requires_tmpl_type)
! 	{
! 	  if (in_decl && 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)
! 	{
! 	  if (requires_tmpl_type)
! 	    {
! 	      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
! 	    {
! 	      val = groktypename (arg);
! 	      if (! processing_template_decl)
! 		{
! 		  /* [basic.link]: A name with no linkage (notably, the
!                      name of a class or enumeration declared in a local
!                      scope) shall not be used to declare an entity with
!                      linkage.  This implies that names with no linkage
!                      cannot be used as template arguments.  */
! 		  tree t = no_linkage_check (val);
! 		  if (t)
! 		    {
! 		      if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
! 			cp_pedwarn
! 			  ("template-argument `%T' uses anonymous type", val);
! 		      else
! 			cp_error
! 			  ("template-argument `%T' uses local type `%T'",
! 			   val, t);
! 		      return error_mark_node;
! 		    }
! 		}
! 	    }
! 	}
!       else
! 	{
! 	  tree t = tsubst (TREE_TYPE (parm), arglist, in_decl);
! 
! 	  if (processing_template_decl)
! 	    arg = maybe_fold_nontype_arg (arg);
! 
! 	  if (!uses_template_parms (arg) && !uses_template_parms (t))
! 	    /* We used to call digest_init here.  However, digest_init
! 	       will report errors, which we don't want when complain
! 	       is zero.  More importantly, digest_init will try too
! 	       hard to convert things: for example, `0' should not be
! 	       converted to pointer type at this point according to
! 	       the standard.  Accepting this is not merely an
! 	       extension, since deciding whether or not these
! 	       conversions can occur is part of determining which
! 	       function template to call, or whether a given epxlicit
! 	       argument specification is legal.  */
! 	    val = convert_nontype_argument (t, arg);
! 	  else
! 	    val = arg;
! 
! 	  if (val == NULL_TREE)
! 	    val = error_mark_node;
! 	  else if (val == error_mark_node && complain)
! 	    cp_error ("could not convert template argument `%E' to `%T'", 
! 		      arg, t);
  	}
! 
!       if (val == error_mark_node)
  	lost++;
! 
!       TREE_VEC_ELT (vec, i) = val;
      }
    if (lost)
      return error_mark_node;
!   return vec;
  }
  
  /* Renturns 1 iff the OLDARGS and NEWARGS are in fact identical sets
--- 2840,2902 ----
        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++)
      {
!       tree arg;
!       tree parm;
  
!       /* Get the Ith template parameter.  */
!       parm = TREE_VEC_ELT (parms, i);
  
!       /* Calculate the Ith argument.  */
!       if (inner_args && TREE_CODE (inner_args) == TREE_LIST)
  	{
! 	  arg = TREE_VALUE (inner_args);
! 	  inner_args = TREE_CHAIN (inner_args);
  	}
!       else if (i < nargs)
! 	arg = TREE_VEC_ELT (inner_args, i);
!       /* If no template argument was supplied, look for a default
! 	 value.  */
!       else if (TREE_PURPOSE (parm) == NULL_TREE)
! 	{
! 	  /* There was no default value.  */
! 	  my_friendly_assert (!require_all_arguments, 0);
! 	  break;
! 	}
!       else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL)
! 	arg = tsubst (TREE_PURPOSE (parm), new_args, in_decl);
!       else
! 	arg = tsubst_expr (TREE_PURPOSE (parm), new_args, in_decl);
  
+       /* Now, convert the Ith argument, as necessary.  */
        if (arg == NULL_TREE)
  	/* We're out of arguments.  */
  	{
  	  my_friendly_assert (!require_all_arguments, 0);
  	  break;
  	}
!       else if (arg == error_mark_node)
  	{
  	  cp_error ("template argument %d is invalid", i + 1);
! 	  arg = error_mark_node;
  	}
!       else 
! 	arg = convert_template_argument (TREE_VALUE (parm), 
! 					 arg, new_args, complain, i,
! 					 in_decl); 
!       
!       if (arg == error_mark_node)
  	lost++;
!       TREE_VEC_ELT (new_inner_args, i) = arg;
      }
+ 
    if (lost)
      return error_mark_node;
! 
!   return new_inner_args;
  }
  
  /* Renturns 1 iff the OLDARGS and NEWARGS are in fact identical sets
*************** tsubst (t, args, in_decl)
*** 5317,5323 ****
  	    if (level <= levels)
  	      arg = TMPL_ARG (args, level, idx);
  
! 	    if (arg != NULL_TREE)
  	      {
  		if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
  		  {
--- 5301,5309 ----
  	    if (level <= levels)
  	      arg = TMPL_ARG (args, level, idx);
  
! 	    if (arg == error_mark_node)
! 	      return error_mark_node;
! 	    else if (arg != NULL_TREE)
  	      {
  		if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
  		  {


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