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]
Other format: [Raw text]

[C++ PATCH]: Incomplete explicit args


Hi,
this patch fixes a regression with explicit specialization. If
fn_type_unification is given a set of (incomplete) explicit args, it will
tsubst that into the function type, before proceeding with deduction.
(14.8.2/2 3rd bullet tells you to do this). The bug is that the
explicit args need not be the complete arg list and in the above
tsubsting, something could refer to an unspecified arg. There is code
in tsubst which deals with this for a template_parm, but that has become
insufficient now that we deal with non-dependent exprs better.
The test case contains a declaration
	template <int n, int x> R<Trait<n,x>::m> f(A<x>);
and a use as
	ptr = &f<1>;
that has to do unification. We tsubst the single explicit arg
into the scope ref Trait<n,x>::m in the return type. That occurs
when processing_template_decl is false so happens inside
tsubst_qualified_id and ends up looking inside of the partial specialization
Trait<1,x> for an (unfound) m. Thus the substitution fails.

Even if tsubst_qualified_id is told to rebuild the scope ref for that
case (you'll notice there is code to do that should the scope be a
BOUND_TEMPLATE_TEMPLATE_PARM), it is still wrong, because we'll
have been called from tsubst_copy_and_build and later uses of that scope_ref
will die horribly. I believe that BOUND_TEMPLATE_TEMPLATE_PARM code is
unreachable, and am testing a patch to assert so.

This patch changes coerce_template_parms to always produce a full set
of template parms, and makes tsubst_expr ensure that there are no template
parms in the arg vector before using tsubst_copy_and_build.

booted & tested on i686-pc-linux-gnu, ok?

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
          The voices in my head said this was stupid too
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk


2003-07-27  Nathan Sidwell  <nathan@codesourcery.com>

	* pt.c (coerce_template_parms): Use the PARM value when we
	don't require all arguments and run out.
	(tsubst_expr): Use tsubst_copy when ARGS contains template parms.
	(fn_type_unification): Only copy the coerced explicit_targs.

Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.738
diff -c -3 -p -r1.738 pt.c
*** cp/pt.c	25 Jul 2003 16:45:34 -0000	1.738
--- cp/pt.c	27 Jul 2003 18:46:13 -0000
*************** coerce_template_parms (tree parms, 
*** 3640,3663 ****
  	}
        else if (i < nargs)
  	arg = TREE_VEC_ELT (inner_args, i);
!       else
!         /* If no template argument was supplied, look for a default
! 	   value.  */
  	arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
  				   complain, 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)
  	{
! 	  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,
--- 3640,3665 ----
  	}
        else if (i < nargs)
  	arg = TREE_VEC_ELT (inner_args, i);
!       else if (require_all_arguments)
! 	/* There must be a default arg in this case. */
  	arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
  				   complain, in_decl);
!       else
  	{
! 	  /* Do not use a default arg, but the parm itself. Thus
! 	     tsubsting using the resultant vector will not fail due to
! 	     a missing template arg.  */
! 	  arg = TREE_VALUE (parm);
! 	  if (TREE_CODE (arg) == TYPE_DECL
! 	      || TREE_CODE (arg) == TEMPLATE_DECL)
! 	    arg = TREE_TYPE (arg);
! 	  else
! 	    arg = DECL_INITIAL (arg);
  	}
+ 
+       my_friendly_assert (arg, 20030727);
+       if (arg == error_mark_node)
+ 	error ("template argument %d is invalid", i + 1);
        else 
  	arg = convert_template_argument (TREE_VALUE (parm), 
  					 arg, new_args, complain, i,
*************** tsubst_expr (tree t, tree args, tsubst_f
*** 7548,7554 ****
    if (t == NULL_TREE || t == error_mark_node)
      return t;
  
!   if (processing_template_decl)
      return tsubst_copy (t, args, complain, in_decl);
  
    if (!STATEMENT_CODE_P (TREE_CODE (t)))
--- 7549,7555 ----
    if (t == NULL_TREE || t == error_mark_node)
      return t;
  
!   if (processing_template_decl || uses_template_parms (args))
      return tsubst_copy (t, args, complain, in_decl);
  
    if (!STATEMENT_CODE_P (TREE_CODE (t)))
*************** fn_type_unification (tree fn, 
*** 8589,8600 ****
        if (converted_args == error_mark_node)
  	return 1;
  
        fntype = tsubst (fntype, converted_args, tf_none, NULL_TREE);
        if (fntype == error_mark_node)
  	return 1;
  
        /* Place the explicitly specified arguments in TARGS.  */
!       for (i = 0; i < TREE_VEC_LENGTH (targs); i++)
  	TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (converted_args, i);
      }
       
--- 8590,8604 ----
        if (converted_args == error_mark_node)
  	return 1;
  
+       /* Substitute the explicit args into the function type. This is
+          necessary so that, for instance, explicitly declared function
+          arguments can match null pointed constants.  */
        fntype = tsubst (fntype, converted_args, tf_none, NULL_TREE);
        if (fntype == error_mark_node)
  	return 1;
  
        /* Place the explicitly specified arguments in TARGS.  */
!       for (i = NUM_TMPL_ARGS (explicit_targs); i--;)
  	TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (converted_args, i);
      }
       

// { dg-do compile }

// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 27 Jul 2003 <nathan@codesourcery.com>

// Failed to spot specialization using a template-id expr

template <typename n> class A {};
template <int m> class R {};

template <typename n, typename x> struct Trait { enum {m = sizeof (n)}; };

template <typename n, typename x> R<Trait<n,x>::m> f(A<x>);
template <> R<Trait<char,char>::m> f<char>(A<char>) {return R<1>();}

// { dg-do compile }

// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 27 Jul 2003 <nathan@codesourcery.com>

// Failed to spot specialization using a template-id expr

template <int n> class A {};
template <int m> class R {};

template <int n, int x> struct Trait { enum {m = n}; };

template <int n, int x> R<Trait<n,x>::m> f(A<x>);
template <> R<Trait<1,1>::m> f<1>(A<1>) {return R<1>();}

void Baz ()
{
  R<Trait<1,1>::m> (*ptr) (A<1>);

  ptr = &f<1>;
  
}


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