Commit 4cf36211 by Douglas Gregor Committed by Doug Gregor

re PR c++/32565 (ICE with specialization of variadic template)

2007-12-18  Douglas Gregor  <doug.gregor@gmail.com>
            Jakub Jelinek  <jakub@redhat.com>
	
	PR c++/32565
	PR c++/33943
	PR c++/33965
	* pt.c (template_template_parm_bindings_ok_p): New; verifies
	bindings of template template parameters after all template
	arguments have been deduced.
	(coerce_template_parms): Don't complain when COMPLAIN doesn't
	include tf_error.
	(fn_type_unification): Use template_template_parm_bindings_ok_p. 
	(unify): Deal with variadic, bound template template parameters. 
	(get_class_bindings): Use template_template_parm_bindings_ok_p. 	
	
2007-12-18  Douglas Gregor  <doug.gregor@gmail.com>
	    Jakub Jelinek  <jakub@redhat.com>
	
	PR c++/32565
	PR c++/33943
	PR c++/33965
	* g++.dg/cpp0x/variadic86.C: New.
	* g++.dg/cpp0x/variadic87.C: New.
	* g++.dg/cpp0x/variadic84.C: New.
	* g++.dg/cpp0x/variadic85.C: New.
	* g++.dg/template/ttp25.C: New.
	
	

Co-Authored-By: Jakub Jelinek <jakub@redhat.com>

From-SVN: r131041
parent 3615b8c2
......@@ -158,6 +158,7 @@ static tree get_template_base (tree, tree, tree, tree);
static tree try_class_unification (tree, tree, tree, tree);
static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
tree, tree);
static bool template_template_parm_bindings_ok_p (tree, tree);
static int template_args_equal (tree, tree);
static void tsubst_default_arguments (tree);
static tree for_each_template_parm_r (tree *, int *, void *);
......@@ -4750,6 +4751,77 @@ coerce_template_template_parms (tree parm_parms,
return 1;
}
/* Verifies that the deduced template arguments (in TARGS) for the
template template parameters (in TPARMS) represent valid bindings,
by comparing the template parameter list of each template argument
to the template parameter list of its corresponding template
template parameter, in accordance with DR150. This
routine can only be called after all template arguments have been
deduced. It will return TRUE if all of the template template
parameter bindings are okay, FALSE otherwise. */
bool
template_template_parm_bindings_ok_p (tree tparms, tree targs)
{
int i, ntparms = TREE_VEC_LENGTH (tparms);
targs = INNERMOST_TEMPLATE_ARGS (targs);
for (i = 0; i < ntparms; ++i)
{
tree tparm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
tree targ = TREE_VEC_ELT (targs, i);
if (TREE_CODE (tparm) == TEMPLATE_DECL && targ)
{
tree packed_args = NULL_TREE;
int idx, len = 1;
if (ARGUMENT_PACK_P (targ))
{
/* Look inside the argument pack. */
packed_args = ARGUMENT_PACK_ARGS (targ);
len = TREE_VEC_LENGTH (packed_args);
}
for (idx = 0; idx < len; ++idx)
{
tree targ_parms = NULL_TREE;
if (packed_args)
/* Extract the next argument from the argument
pack. */
targ = TREE_VEC_ELT (packed_args, idx);
if (PACK_EXPANSION_P (targ))
/* Look at the pattern of the pack expansion. */
targ = PACK_EXPANSION_PATTERN (targ);
/* Extract the template parameters from the template
argument. */
if (TREE_CODE (targ) == TEMPLATE_DECL)
targ_parms = DECL_INNERMOST_TEMPLATE_PARMS (targ);
else if (TREE_CODE (targ) == TEMPLATE_TEMPLATE_PARM)
targ_parms = DECL_INNERMOST_TEMPLATE_PARMS (TYPE_NAME (targ));
/* Verify that we can coerce the template template
parameters from the template argument to the template
parameter. This requires an exact match. */
if (targ_parms
&& !coerce_template_template_parms
(DECL_INNERMOST_TEMPLATE_PARMS (tparm),
targ_parms,
tf_none,
tparm,
targs))
return false;
}
}
}
/* Everything is okay. */
return true;
}
/* 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 and
......@@ -5183,16 +5255,19 @@ coerce_template_parms (tree parms,
if (arg && PACK_EXPANSION_P (arg))
{
/* If ARG is a pack expansion, but PARM is not a
template parameter pack (if it were, we would have
handled it above), we're trying to expand into a
fixed-length argument list. */
if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
error ("cannot expand %<%E%> into a fixed-length "
"argument list", arg);
else
error ("cannot expand %<%T%> into a fixed-length "
"argument list", arg);
if (complain & tf_error)
{
/* If ARG is a pack expansion, but PARM is not a
template parameter pack (if it were, we would have
handled it above), we're trying to expand into a
fixed-length argument list. */
if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
error ("cannot expand %<%E%> into a fixed-length "
"argument list", arg);
else
error ("cannot expand %<%T%> into a fixed-length "
"argument list", arg);
}
return error_mark_node;
}
}
......@@ -11627,6 +11702,32 @@ fn_type_unification (tree fn,
}
}
/* Now that we have bindings for all of the template arguments,
ensure that the arguments deduced for the template template
parameters have compatible template parameter lists. We cannot
check this property before we have deduced all template
arguments, because the template parameter types of a template
template parameter might depend on prior template parameters
deduced after the template template parameter. The following
ill-formed example illustrates this issue:
template<typename T, template<T> class C> void f(C<5>, T);
template<int N> struct X {};
void g() {
f(X<5>(), 5l); // error: template argument deduction fails
}
The template parameter list of 'C' depends on the template type
parameter 'T', but 'C' is deduced to 'X' before 'T' is deduced to
'long'. Thus, we can't check that 'C' cannot bind to 'X' at the
time that we deduce 'C'. */
if (result == 0
&& !template_template_parm_bindings_ok_p
(DECL_INNERMOST_TEMPLATE_PARMS (fn), targs))
return 1;
if (result == 0)
/* All is well so far. Now, check:
......@@ -12711,7 +12812,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
tree argtmplvec
= DECL_INNERMOST_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (arg));
int i;
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
......@@ -12753,7 +12855,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
rather than the whole TREE_VEC since they can have
different number of elements. */
for (i = 0; i < TREE_VEC_LENGTH (parmvec); ++i)
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;
if (TREE_VEC_LENGTH (argvec) < len - parm_variadic_p)
return 1;
for (i = 0; i < len - parm_variadic_p; ++i)
{
if (unify (tparms, targs,
TREE_VEC_ELT (parmvec, i),
......@@ -12761,6 +12877,14 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
UNIFY_ALLOW_NONE))
return 1;
}
if (parm_variadic_p
&& unify_pack_expansion (tparms, targs,
parmvec, argvec,
UNIFY_ALLOW_NONE,
/*call_args_p=*/false,
/*subr=*/false))
return 1;
}
arg = TYPE_TI_TEMPLATE (arg);
......@@ -13783,6 +13907,14 @@ get_class_bindings (tree tparms, tree spec_args, tree args)
INNERMOST_TEMPLATE_ARGS (args)))
return NULL_TREE;
/* Now that we have bindings for all of the template arguments,
ensure that the arguments deduced for the template template
parameters have compatible template parameter lists. See the use
of template_template_parm_bindings_ok_p in fn_type_unification
for more information. */
if (!template_template_parm_bindings_ok_p (tparms, deduced_args))
return NULL_TREE;
return deduced_args;
}
......
2007-12-18 Douglas Gregor <doug.gregor@gmail.com>
Jakub Jelinek <jakub@redhat.com>
PR c++/32565
PR c++/33943
PR c++/33965
* g++.dg/cpp0x/variadic86.C: New.
* g++.dg/cpp0x/variadic87.C: New.
* g++.dg/cpp0x/variadic84.C: New.
* g++.dg/cpp0x/variadic85.C: New.
* g++.dg/template/ttp25.C: New.
2007-12-18 Sebastian Pop <sebastian.pop@amd.com>
PR tree-optimization/34123
// PR c++/32565
// { dg-do compile }
// { dg-options "-std=c++0x" }
template<typename...> struct A1;
template<template<int...> class T> struct A1<T<0> > {};
template<typename...> struct A2;
template<template<int...> class T> struct A2<T<0, 1> > {};
template<typename...> struct A3;
template<template<int, int...> class T> struct A3<T<0, 1> > {};
template<typename...> struct A4;
template<template<typename...> class T> struct A4<T<int> > {};
template<typename...> struct A5;
template<template<typename...> class T> struct A5<T<int, long> > {};
template<typename...> struct A6;
template<template<typename, typename...> class T> struct A6<T<int, long> > {};
template<int> struct B1 {};
template<int, int> struct B2 {};
template<typename> struct B3 {};
template<typename, typename> struct B4 {};
A1<B1<0> > a1; // { dg-error "incomplete type" }
A2<B2<0, 1> > a2; // { dg-error "incomplete type" }
A3<B2<0, 1> > a3; // { dg-error "incomplete type" }
A4<B3<int> > a4; // { dg-error "incomplete type" }
A5<B4<int, long> > a5; // { dg-error "incomplete type" }
A6<B4<int, long> > a6; // { dg-error "incomplete type" }
// PR c++/32565
// { dg-do compile }
// { dg-options "-std=c++0x" }
template<typename...> struct A1;
template<template<int, int...> class T> struct A1<T<0, 1> > {};
template<int, int, int...> struct B1 {};
A1<B1<0, 1> > a1; // { dg-error "incomplete type" }
template<int...> struct B2 {};
A1<B2<0, 1> > a2; // { dg-error "incomplete type" }
// PR c++/33943
// { dg-do compile }
// { dg-options "-std=c++0x" }
template<typename... A> struct foo {};
template<typename A0, typename... A1> struct bar {};
template<typename U> struct baz;
template<template<typename...> class T, typename... U> struct baz< T<U...> >
{};
template<template<typename, typename...> class T, typename U, typename... V>
struct baz< T<U, V...> >
{};
baz< foo<int, short> > b1;
baz< bar<int, short> > b2;
// PR c++/33965
// { dg-options -std=c++0x }
template<typename T>
struct foo
{
static bool const value = false;
};
template<template<typename...> class T, typename... Args>
struct foo<T<Args...> >
{
static bool const value = true;
};
template<int I>
struct int_
{};
int main()
{
static_assert(foo<int_<0> >::value == false,
"picked up partial specialization, but should not have");
}
// { dg-do compile }
template<typename T, template<T> class C>
void f1(T, C<5>);
template<typename T, template<T> class C>
void f2(C<5>, T);
template<typename T, template<T> class C>
void f3(C<5>, T);
template<typename T> struct metafun { typedef T type; };
template<> struct metafun<short> { typedef int type; };
template<typename T, template<typename metafun<T>::type> class C>
void f4(T, C<5>);
template<int N> struct X {};
void g() {
f1(5l, X<5>()); // { dg-error "no matching" }
f2(X<5>(), 5);
f3(X<5>(), 5l); // { dg-error "no matching" }
f4(5, X<5>());
f4(5l, X<5>()); // { dg-error "no matching" }
f4((short)5, X<5>());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment