PR c++/42329 - deducing base template for template template arg

* pt.c (unify_bound_ttp_args): Split out from unify.
	(try_class_unification): Handle BOUND_TEMPLATE_TEMPLATE_PARM.
	(unify): Check for type/non-type mismatch early.
	[BOUND_TEMPLATE_TEMPLATE_PARM]: Try get_template_base.

From-SVN: r243870
This commit is contained in:
Jason Merrill 2016-12-21 14:38:50 -05:00 committed by Jason Merrill
parent 57a6add274
commit 3c75aaa3d8
6 changed files with 124 additions and 93 deletions

View File

@ -1,5 +1,11 @@
2016-12-21 Jason Merrill <jason@redhat.com>
PR c++/42329
* pt.c (unify_bound_ttp_args): Split out from unify.
(try_class_unification): Handle BOUND_TEMPLATE_TEMPLATE_PARM.
(unify): Check for type/non-type mismatch early.
[BOUND_TEMPLATE_TEMPLATE_PARM]: Try get_template_base.
* pt.c (coerce_template_parms): Consider variadic_args_p before
complaining about too many template arguments.

View File

@ -6863,6 +6863,27 @@ coerce_template_template_parm (tree parm,
return 1;
}
/* Subroutine of unify for the case when PARM is a
BOUND_TEMPLATE_TEMPLATE_PARM. */
static int
unify_bound_ttp_args (tree tparms, tree targs, tree parm, tree arg,
bool explain_p)
{
tree parmvec = TYPE_TI_ARGS (parm);
tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
/* The template template parm might be variadic and the argument
not, so flatten both argument lists. */
parmvec = expand_template_argument_pack (parmvec);
argvec = expand_template_argument_pack (argvec);
if (unify (tparms, targs, parmvec, argvec,
UNIFY_ALLOW_NONE, explain_p))
return 1;
return 0;
}
/* Return 1 if PARM_PARMS and ARG_PARMS matches using rule for
template template parameters. Both PARM_PARMS and ARG_PARMS are
@ -19391,9 +19412,12 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg,
{
tree copy_of_targs;
if (!CLASSTYPE_TEMPLATE_INFO (arg)
|| (most_general_template (CLASSTYPE_TI_TEMPLATE (arg))
!= most_general_template (CLASSTYPE_TI_TEMPLATE (parm))))
if (!CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
return NULL_TREE;
else if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
/* Matches anything. */;
else if (most_general_template (CLASSTYPE_TI_TEMPLATE (arg))
!= most_general_template (CLASSTYPE_TI_TEMPLATE (parm)))
return NULL_TREE;
/* We need to make a new template argument vector for the call to
@ -19428,6 +19452,13 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg,
would reject the possibility I=1. */
copy_of_targs = make_tree_vec (TREE_VEC_LENGTH (targs));
if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
{
if (unify_bound_ttp_args (tparms, copy_of_targs, parm, arg, explain_p))
return NULL_TREE;
return arg;
}
/* If unification failed, we're done. */
if (unify (tparms, copy_of_targs, CLASSTYPE_TI_ARGS (parm),
CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE, explain_p))
@ -19832,6 +19863,25 @@ unify_array_domain (tree tparms, tree targs,
UNIFY_ALLOW_INTEGER, explain_p);
}
/* Returns whether T, a P or A in unify, is a type, template or expression. */
enum pa_kind_t { pa_type, pa_tmpl, pa_expr };
static pa_kind_t
pa_kind (tree t)
{
if (PACK_EXPANSION_P (t))
t = PACK_EXPANSION_PATTERN (t);
if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
|| TREE_CODE (t) == UNBOUND_CLASS_TEMPLATE
|| DECL_TYPE_TEMPLATE_P (t))
return pa_tmpl;
else if (TYPE_P (t))
return pa_type;
else
return pa_expr;
}
/* Deduce the value of template parameters. TPARMS is the (innermost)
set of template parameters to a template. TARGS is the bindings
for those template parameters, as determined thus far; TARGS may
@ -19985,6 +20035,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
return unify_success (explain_p);
}
/* If parm and arg aren't the same kind of thing (template, type, or
expression), fail early. */
if (pa_kind (parm) != pa_kind (arg))
return unify_invalid (explain_p);
/* Immediately reject some pairs that won't unify because of
cv-qualification mismatches. */
if (TREE_CODE (arg) == TREE_CODE (parm)
@ -20053,100 +20108,32 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
{
if (strict_in & UNIFY_ALLOW_DERIVED)
{
/* First try to match ARG directly. */
tree t = try_class_unification (tparms, targs, parm, arg,
explain_p);
if (!t)
{
/* Otherwise, look for a suitable base of ARG, as below. */
enum template_base_result r;
r = get_template_base (tparms, targs, parm, arg,
explain_p, &t);
if (!t)
return unify_no_common_base (explain_p, r, parm, arg);
arg = t;
}
}
/* ARG must be constructed from a template class or a template
template parameter. */
if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
else if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
&& !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
return unify_template_deduction_failure (explain_p, parm, arg);
{
tree parmvec = TYPE_TI_ARGS (parm);
tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
tree full_argvec = add_to_template_args (targs, argvec);
tree parm_parms
= DECL_INNERMOST_TEMPLATE_PARMS
(TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (parm));
int i, len;
int parm_variadic_p = 0;
/* The resolution to DR150 makes clear that default
arguments for an N-argument may not be used to bind T
to a template template parameter with fewer than N
parameters. It is not safe to permit the binding of
default arguments as an extension, as that may change
the meaning of a conforming program. Consider:
struct Dense { static const unsigned int dim = 1; };
template <template <typename> class View,
typename Block>
void operator+(float, View<Block> const&);
template <typename Block,
unsigned int Dim = Block::dim>
struct Lvalue_proxy { operator float() const; };
void
test_1d (void) {
Lvalue_proxy<Dense> p;
float b;
b + p;
}
Here, if Lvalue_proxy is permitted to bind to View, then
the global operator+ will be used; if they are not, the
Lvalue_proxy will be converted to float. */
if (coerce_template_parms (parm_parms,
full_argvec,
TYPE_TI_TEMPLATE (parm),
complain,
/*require_all_args=*/true,
/*use_default_args=*/false)
== error_mark_node)
/* Deduce arguments T, i from TT<T> or TT<i>. */
if (unify_bound_ttp_args (tparms, targs, parm, arg, explain_p))
return 1;
/* 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. */
parmvec = expand_template_argument_pack (parmvec);
argvec = expand_template_argument_pack (argvec);
len = TREE_VEC_LENGTH (parmvec);
/* Check if the parameters end in a pack, making them
variadic. */
if (len > 0
&& PACK_EXPANSION_P (TREE_VEC_ELT (parmvec, len - 1)))
parm_variadic_p = 1;
for (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 (i = 0; i < len - parm_variadic_p; ++i)
{
RECUR_AND_CHECK_FAILURE (tparms, targs,
TREE_VEC_ELT (parmvec, i),
TREE_VEC_ELT (argvec, i),
UNIFY_ALLOW_NONE, explain_p);
}
if (parm_variadic_p
&& unify_pack_expansion (tparms, targs,
parmvec, argvec,
DEDUCE_EXACT,
/*subr=*/true, explain_p))
return 1;
}
arg = TYPE_TI_TEMPLATE (arg);
/* Fall through to deduce template name. */

View File

@ -22,7 +22,7 @@ template<class T> using Vec = Vector<T, Alloc<T> >;
template<class T> void g(Vector<T, Alloc<T> >);
template<template<class T> class TT> void h(TT<int>); // { dg-message "provided for" }
template<template<class T> class TT> void h(TT<int>); // { dg-message "" }
void
bar()

View File

@ -0,0 +1,10 @@
// { dg-do compile { target c++11 } }
template <class T> struct A { using type = T; };
template <template <class...> class C, class... Ts>
struct A<C<Ts...>> { };
template <class T2, template <class> class TT> struct B { };
template <class T3> struct C { };
A<B<int,C>>::type a;

View File

@ -0,0 +1,12 @@
// PR c++/60177
template<class> struct Base { };
struct Derived : Base<void> { };
template<template<typename> class TT, typename T>
void func (TT<T>) { }
int main () {
func (Derived ());
}

View File

@ -0,0 +1,16 @@
// PR c++/42329
template <typename T1, typename T2>
class B {};
template <typename T>
class D : public B<T, T> {};
template <template <typename, typename> class U, typename T1, typename T2>
void g(U<T1, T2>*) {}
int main()
{
D<long> dl;
g(&dl); // error: no matching function for call to g(D<long int>*)
}