Patchwork C++ PATCH for c++/23055 (function parms with only non-deducible template parameters)

login
register
mail settings
Submitter Jason Merrill
Date April 11, 2013, 1:16 p.m.
Message ID <5166B7A8.30706@redhat.com>
Download mbox | patch
Permalink /patch/235739/
State New
Headers show

Comments

Jason Merrill - April 11, 2013, 1:16 p.m.
This bug has accumulated a lot of duplicates over the years.  The issue 
is that the standard says that

"Implicit conversions (Clause 4) will be performed on a function 
argument to convert it to the type of the corresponding function 
parameter if the parameter type contains no template-parameters that 
participate in template argument deduction."

We were doing this for types that contain no template-parameters at all, 
but not for types that contain template-parameters that only appear in 
non-deduced locations.

Tested x86_64-pc-linux-gnu, applying to trunk.
Paolo Carlini - April 11, 2013, 2 p.m.
Thanks!

Paolo.

Patch

commit 1af65c13d382c9ce0ec26b9d79fa68517343a844
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Apr 9 17:24:30 2013 -0400

    	PR c++/23055
    	* pt.c (uses_deducible_template_parms): New.
    	(deducible_array_bound, deducible_expression): New.
    	(deducible_template_args): New.
    	(unify_one_argument): Call uses_deducible_template_parms.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7367a3a..1c0b3ec 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15390,6 +15390,135 @@  check_non_deducible_conversion (tree parm, tree arg, int strict,
     return unify_arg_conversion (explain_p, parm, type, arg);
 }
 
+static bool uses_deducible_template_parms (tree type);
+
+/* Returns true iff the expression EXPR is one from which a template
+   argument can be deduced.  In other words, if it's an undecorated
+   use of a template non-type parameter.  */
+
+static bool
+deducible_expression (tree expr)
+{
+  return (TREE_CODE (expr) == TEMPLATE_PARM_INDEX);
+}
+
+/* Returns true iff the array domain DOMAIN uses a template parameter in a
+   deducible way; that is, if it has a max value of <PARM> - 1.  */
+
+static bool
+deducible_array_bound (tree domain)
+{
+  if (domain == NULL_TREE)
+    return false;
+
+  tree max = TYPE_MAX_VALUE (domain);
+  if (TREE_CODE (max) != MINUS_EXPR)
+    return false;
+
+  return deducible_expression (TREE_OPERAND (max, 0));
+}
+
+/* Returns true iff the template arguments ARGS use a template parameter
+   in a deducible way.  */
+
+static bool
+deducible_template_args (tree args)
+{
+  for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
+    {
+      bool deducible;
+      tree elt = TREE_VEC_ELT (args, i);
+      if (ARGUMENT_PACK_P (elt))
+	deducible = deducible_template_args (ARGUMENT_PACK_ARGS (elt));
+      else
+	{
+	  if (PACK_EXPANSION_P (elt))
+	    elt = PACK_EXPANSION_PATTERN (elt);
+	  if (TREE_CODE (elt) == TEMPLATE_TEMPLATE_PARM)
+	    deducible = true;
+	  else if (TYPE_P (elt))
+	    deducible = uses_deducible_template_parms (elt);
+	  else
+	    deducible = deducible_expression (elt);
+	}
+      if (deducible)
+	return true;
+    }
+  return false;
+}
+
+/* Returns true iff TYPE contains any deducible references to template
+   parameters, as per 14.8.2.5.  */
+
+static bool
+uses_deducible_template_parms (tree type)
+{
+  if (PACK_EXPANSION_P (type))
+    type = PACK_EXPANSION_PATTERN (type);
+
+  /* T
+     cv-list T
+     TT<T>
+     TT<i>
+     TT<> */
+  if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+    return true;
+
+  /* T*
+     T&
+     T&&  */
+  if (POINTER_TYPE_P (type))
+    return uses_deducible_template_parms (TREE_TYPE (type));
+
+  /* T[integer-constant ]
+     type [i]  */
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    return (uses_deducible_template_parms (TREE_TYPE (type))
+	    || deducible_array_bound (TYPE_DOMAIN (type)));
+
+  /* T type ::*
+     type T::*
+     T T::*
+     T (type ::*)()
+     type (T::*)()
+     type (type ::*)(T)
+     type (T::*)(T)
+     T (type ::*)(T)
+     T (T::*)()
+     T (T::*)(T) */
+  if (TYPE_PTRMEM_P (type))
+    return (uses_deducible_template_parms (TYPE_PTRMEM_CLASS_TYPE (type))
+	    || (uses_deducible_template_parms
+		(TYPE_PTRMEM_POINTED_TO_TYPE (type))));
+
+  /* template-name <T> (where template-name refers to a class template)
+     template-name <i> (where template-name refers to a class template) */
+  if (CLASS_TYPE_P (type)
+      && CLASSTYPE_TEMPLATE_INFO (type)
+      && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)))
+    return deducible_template_args (INNERMOST_TEMPLATE_ARGS
+				    (CLASSTYPE_TI_ARGS (type)));
+
+  /* type (T)
+     T()
+     T(T)  */
+  if (TREE_CODE (type) == FUNCTION_TYPE
+      || TREE_CODE (type) == METHOD_TYPE)
+    {
+      if (uses_deducible_template_parms (TREE_TYPE (type)))
+	return true;
+      tree parm = TYPE_ARG_TYPES (type);
+      if (TREE_CODE (type) == METHOD_TYPE)
+	parm = TREE_CHAIN (parm);
+      for (; parm; parm = TREE_CHAIN (parm))
+	if (uses_deducible_template_parms (TREE_VALUE (parm)))
+	  return true;
+    }
+
+  return false;
+}
+
 /* Subroutine of type_unification_real and unify_pack_expansion to
    handle unification of a single P/A pair.  Parameters are as
    for those functions.  */
@@ -15409,10 +15538,21 @@  unify_one_argument (tree tparms, tree targs, tree parm, tree arg,
        template args from other function args.  */
     return unify_success (explain_p);
 
-  /* FIXME uses_deducible_template_parms */
+  /* Implicit conversions (Clause 4) will be performed on a function
+     argument to convert it to the type of the corresponding function
+     parameter if the parameter type contains no template-parameters that
+     participate in template argument deduction.  */
   if (TYPE_P (parm) && !uses_template_parms (parm))
+    /* For function parameters that contain no template-parameters at all,
+       we have historically checked for convertibility in order to shortcut
+       consideration of this candidate.  */
     return check_non_deducible_conversion (parm, arg, strict, flags,
 					   explain_p);
+  else if (strict == DEDUCE_CALL
+	   && TYPE_P (parm) && !uses_deducible_template_parms (parm))
+    /* For function parameters with only non-deducible template parameters,
+       just return.  */
+    return unify_success (explain_p);
 
   switch (strict)
     {
diff --git a/gcc/testsuite/g++.dg/template/non-deducible1.C b/gcc/testsuite/g++.dg/template/non-deducible1.C
new file mode 100644
index 0000000..4213524
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-deducible1.C
@@ -0,0 +1,8 @@ 
+// PR c++/23055
+
+template <class> struct S { typedef int type; };
+
+template <class T>
+int foo(T, typename S<T>::type * ret);
+
+int j = foo(1, 0);
diff --git a/gcc/testsuite/g++.dg/template/nontype25.C b/gcc/testsuite/g++.dg/template/nontype25.C
index bcdcce5..f399408 100644
--- a/gcc/testsuite/g++.dg/template/nontype25.C
+++ b/gcc/testsuite/g++.dg/template/nontype25.C
@@ -7,7 +7,7 @@  template<const A* a> class C {};
 template<const B* b> class D {};
 template<B* b> class E {};
 
-template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} // { dg-error "" "" { target c++98 } }
+template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} // { dg-error "" "" }
 template<const B* b> void g(D<b> &, E<const_cast<B*>(b)> &) {} // { dg-error "" "" { target c++98 } }
 
 B b;