diff mbox

C++ PATCH for c++/81215, deduction failure with variadic TTP

Message ID CADzB+2kS4g_9268qtrW1tHiy-eUH_dv64yc+V5CaL+255E2Ohw@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill June 26, 2017, 6:48 p.m. UTC
For the C++17 changes to handling of template template parameter
matching, I replaced a lot of the old code.  But it seems that this
piece is still necessary when we aren't in C++17 mode, to handle the
case where we are comparing C<V> to set<int,void>, with different
numbers of arguments.  This is handled in C++17 mode by
coerce_ttp_args_for_tta, but that has other effects that we want to
limit to C++17 mode, at least for now.

Tested x86_64-pc-linux-gnu, applying to trunk and 7.
commit 6de84fdaef34cd48649ed501958aa3c93b289f7e
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 26 14:35:52 2017 -0400

            PR c++/81215 - deduction failure with variadic TTP.
    
            * pt.c (unify_bound_ttp_args): Restore old logic for C++14 and down.
diff mbox

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 392fba0..43f9ca8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7170,26 +7170,68 @@  unify_bound_ttp_args (tree tparms, tree targs, tree parm, tree& arg,
   parmvec = expand_template_argument_pack (parmvec);
   argvec = expand_template_argument_pack (argvec);
 
-  tree nparmvec = parmvec;
   if (flag_new_ttp)
     {
       /* In keeping with P0522R0, adjust P's template arguments
 	 to apply to A's template; then flatten it again.  */
+      tree nparmvec = parmvec;
       nparmvec = coerce_ttp_args_for_tta (arg, parmvec, tf_none);
       nparmvec = expand_template_argument_pack (nparmvec);
+
+      if (unify (tparms, targs, nparmvec, argvec,
+		 UNIFY_ALLOW_NONE, explain_p))
+	return 1;
+
+      /* If the P0522 adjustment eliminated a pack expansion, deduce
+	 empty packs.  */
+      if (flag_new_ttp
+	  && TREE_VEC_LENGTH (nparmvec) < TREE_VEC_LENGTH (parmvec)
+	  && unify_pack_expansion (tparms, targs, parmvec, argvec,
+				   DEDUCE_EXACT, /*sub*/true, explain_p))
+	return 1;
     }
+  else
+    {
+      /* Deduce arguments T, i from TT<T> or TT<i>.
+	 We check each element of PARMVEC and ARGVEC individually
+	 rather than the whole TREE_VEC since they can have
+	 different number of elements, which is allowed under N2555.  */
+
+      int len = TREE_VEC_LENGTH (parmvec);
+
+      /* Check if the parameters end in a pack, making them
+	 variadic.  */
+      int parm_variadic_p = 0;
+      if (len > 0
+	  && PACK_EXPANSION_P (TREE_VEC_ELT (parmvec, len - 1)))
+	parm_variadic_p = 1;
 
-  if (unify (tparms, targs, nparmvec, argvec,
-	     UNIFY_ALLOW_NONE, explain_p))
-    return 1;
-
-  /* If the P0522 adjustment eliminated a pack expansion, deduce
-     empty packs.  */
-  if (flag_new_ttp
-      && TREE_VEC_LENGTH (nparmvec) < TREE_VEC_LENGTH (parmvec)
-      && unify_pack_expansion (tparms, targs, parmvec, argvec,
-			       DEDUCE_EXACT, /*sub*/true, explain_p))
-    return 1;
+      for (int i = 0; i < len - parm_variadic_p; ++i)
+	/* If the template argument list of P contains a pack
+	   expansion that is not the last template argument, the
+	   entire template argument list is a non-deduced
+	   context.  */
+	if (PACK_EXPANSION_P (TREE_VEC_ELT (parmvec, i)))
+	  return unify_success (explain_p);
+
+      if (TREE_VEC_LENGTH (argvec) < len - parm_variadic_p)
+	return unify_too_few_arguments (explain_p,
+					TREE_VEC_LENGTH (argvec), len);
+
+      for (int i = 0; i < len - parm_variadic_p; ++i)
+	if (unify (tparms, targs,
+		   TREE_VEC_ELT (parmvec, i),
+		   TREE_VEC_ELT (argvec, i),
+		   UNIFY_ALLOW_NONE, explain_p))
+	  return 1;
+
+      if (parm_variadic_p
+	  && unify_pack_expansion (tparms, targs,
+				   parmvec, argvec,
+				   DEDUCE_EXACT,
+				   /*subr=*/true, explain_p))
+	return 1;
+    }
 
   return 0;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ttp7.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp7.C
new file mode 100644
index 0000000..0dbe904
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp7.C
@@ -0,0 +1,16 @@ 
+// PR c++/81215
+// { dg-do compile { target c++11 } }
+
+template<typename U> struct X { };
+template<typename T, typename U = void> struct set { };
+
+template <typename V, template <typename...> class C>
+void bar (const X<C<V>>&)
+{
+}
+
+void
+foo (X<set<int>>& x)
+{
+  bar (x);
+}