Commit ffaf1e05 by Jason Merrill Committed by Jason Merrill

re PR c++/35297 (Compiling error with variadic template with fixed parameter with default type.)

        PR c++/35297
        PR c++/35477
        PR c++/35784
        PR c++/36846
        PR c++/38276
        * pt.c (check_default_tmpl_args): Don't complain about
        out-of-order parameter packs in the enclosing class
        or parameter packs after default args.
        (coerce_template_parms): If we have more than one
        parameter pack, don't flatten argument packs.
        (template_args_equal): Handle argument packs.
        (comp_template_args): Don't flatten argument packs.
        (check_instantiated_arg): Split out from...
        (check_instantiated_args): Here.  Handle arg packs.
        (convert_template_argument): Just check that nontype argument
        packs have the right type.

From-SVN: r143166
parent 30af0edb
2009-01-06 Jason Merrill <jason@redhat.com>
PR c++/35297
PR c++/35477
PR c++/35784
PR c++/36846
PR c++/38276
* pt.c (check_default_tmpl_args): Don't complain about
out-of-order parameter packs in the enclosing class
or parameter packs after default args.
(coerce_template_parms): If we have more than one
parameter pack, don't flatten argument packs.
(template_args_equal): Handle argument packs.
(comp_template_args): Don't flatten argument packs.
(check_instantiated_arg): Split out from...
(check_instantiated_args): Here. Handle arg packs.
(convert_template_argument): Just check that nontype argument
packs have the right type.
2009-01-05 Dodji Seketeli <dodji@redhat.com> 2009-01-05 Dodji Seketeli <dodji@redhat.com>
PR c++/38472 PR c++/38472
......
...@@ -3590,7 +3590,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, ...@@ -3590,7 +3590,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary,
if (TREE_PURPOSE (parm)) if (TREE_PURPOSE (parm))
seen_def_arg_p = 1; seen_def_arg_p = 1;
else if (seen_def_arg_p) else if (seen_def_arg_p
&& !template_parameter_pack_p (TREE_VALUE (parm)))
{ {
error ("no default argument for %qD", TREE_VALUE (parm)); error ("no default argument for %qD", TREE_VALUE (parm));
/* For better subsequent error-recovery, we indicate that /* For better subsequent error-recovery, we indicate that
...@@ -3601,6 +3602,9 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, ...@@ -3601,6 +3602,9 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary,
else if (is_primary else if (is_primary
&& !is_partial && !is_partial
&& !is_friend_decl && !is_friend_decl
/* Don't complain about an enclosing partial
specialization. */
&& parm_level == parms
&& TREE_CODE (decl) == TYPE_DECL && TREE_CODE (decl) == TYPE_DECL
&& i < ntparms - 1 && i < ntparms - 1
&& template_parameter_pack_p (TREE_VALUE (parm))) && template_parameter_pack_p (TREE_VALUE (parm)))
...@@ -5060,7 +5064,19 @@ convert_template_argument (tree parm, ...@@ -5060,7 +5064,19 @@ convert_template_argument (tree parm,
if (invalid_nontype_parm_type_p (t, complain)) if (invalid_nontype_parm_type_p (t, complain))
return error_mark_node; return error_mark_node;
if (!uses_template_parms (orig_arg) && !uses_template_parms (t)) if (template_parameter_pack_p (parm) && ARGUMENT_PACK_P (orig_arg))
{
if (same_type_p (t, TREE_TYPE (orig_arg)))
val = orig_arg;
else
{
/* Not sure if this is reachable, but it doesn't hurt
to be robust. */
error ("type mismatch in nontype parameter pack");
val = error_mark_node;
}
}
else if (!uses_template_parms (orig_arg) && !uses_template_parms (t))
/* We used to call digest_init here. However, digest_init /* We used to call digest_init here. However, digest_init
will report errors, which we don't want when complain will report errors, which we don't want when complain
is zero. More importantly, digest_init will try too is zero. More importantly, digest_init will try too
...@@ -5233,10 +5249,6 @@ coerce_template_parms (tree parms, ...@@ -5233,10 +5249,6 @@ coerce_template_parms (tree parms,
parameters. */ parameters. */
int variadic_p = 0; int variadic_p = 0;
inner_args
= expand_template_argument_pack (INNERMOST_TEMPLATE_ARGS (args));
nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
nparms = TREE_VEC_LENGTH (parms); nparms = TREE_VEC_LENGTH (parms);
/* Determine if there are any parameter packs. */ /* Determine if there are any parameter packs. */
...@@ -5244,13 +5256,22 @@ coerce_template_parms (tree parms, ...@@ -5244,13 +5256,22 @@ coerce_template_parms (tree parms,
{ {
tree tparm = TREE_VALUE (TREE_VEC_ELT (parms, parm_idx)); tree tparm = TREE_VALUE (TREE_VEC_ELT (parms, parm_idx));
if (template_parameter_pack_p (tparm)) if (template_parameter_pack_p (tparm))
{ ++variadic_p;
variadic_p = 1;
break;
}
} }
if ((nargs > nparms - variadic_p && !variadic_p) inner_args = INNERMOST_TEMPLATE_ARGS (args);
/* If there are 0 or 1 parameter packs, we need to expand any argument
packs so that we can deduce a parameter pack from some non-packed args
followed by an argument pack, as in variadic85.C. If there are more
than that, we need to leave argument packs intact so the arguments are
assigned to the right parameter packs. This should only happen when
dealing with a nested class inside a partial specialization of a class
template, as in variadic92.C. */
if (variadic_p <= 1)
inner_args = expand_template_argument_pack (inner_args);
nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
if ((nargs > nparms && !variadic_p)
|| (nargs < nparms - variadic_p || (nargs < nparms - variadic_p
&& require_all_args && require_all_args
&& (!use_default_args && (!use_default_args
...@@ -5297,42 +5318,48 @@ coerce_template_parms (tree parms, ...@@ -5297,42 +5318,48 @@ coerce_template_parms (tree parms,
} }
/* Calculate the next argument. */ /* Calculate the next argument. */
if (template_parameter_pack_p (TREE_VALUE (parm))) if (arg_idx < nargs)
arg = TREE_VEC_ELT (inner_args, arg_idx);
else
arg = NULL_TREE;
if (template_parameter_pack_p (TREE_VALUE (parm))
&& !(arg && ARGUMENT_PACK_P (arg)))
{ {
/* All remaining arguments will be placed in the /* All remaining arguments will be placed in the
template parameter pack PARM. */ template parameter pack PARM. */
arg = coerce_template_parameter_pack (parms, parm_idx, args, arg = coerce_template_parameter_pack (parms, parm_idx, args,
inner_args, arg_idx, inner_args, arg_idx,
new_args, &lost, new_args, &lost,
in_decl, complain); in_decl, complain);
/* Store this argument. */ /* Store this argument. */
if (arg == error_mark_node) if (arg == error_mark_node)
lost++; lost++;
TREE_VEC_ELT (new_inner_args, parm_idx) = arg; TREE_VEC_ELT (new_inner_args, parm_idx) = arg;
/* We are done with all of the arguments. */ /* We are done with all of the arguments. */
arg_idx = nargs; arg_idx = nargs;
continue; continue;
} }
else if (arg_idx < nargs) else if (arg)
{ {
arg = TREE_VEC_ELT (inner_args, arg_idx); if (PACK_EXPANSION_P (arg))
if (arg && PACK_EXPANSION_P (arg))
{ {
if (complain & tf_error) if (complain & tf_error)
{ {
/* FIXME this restriction was removed by N2555; see
bug 35722. */
/* If ARG is a pack expansion, but PARM is not a /* If ARG is a pack expansion, but PARM is not a
template parameter pack (if it were, we would have template parameter pack (if it were, we would have
handled it above), we're trying to expand into a handled it above), we're trying to expand into a
fixed-length argument list. */ fixed-length argument list. */
if (TREE_CODE (arg) == EXPR_PACK_EXPANSION) if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
error ("cannot expand %<%E%> into a fixed-length " sorry ("cannot expand %<%E%> into a fixed-length "
"argument list", arg); "argument list", arg);
else else
error ("cannot expand %<%T%> into a fixed-length " sorry ("cannot expand %<%T%> into a fixed-length "
"argument list", arg); "argument list", arg);
} }
return error_mark_node; return error_mark_node;
...@@ -5389,6 +5416,25 @@ template_args_equal (tree ot, tree nt) ...@@ -5389,6 +5416,25 @@ template_args_equal (tree ot, tree nt)
return PACK_EXPANSION_P (nt) return PACK_EXPANSION_P (nt)
&& template_args_equal (PACK_EXPANSION_PATTERN (ot), && template_args_equal (PACK_EXPANSION_PATTERN (ot),
PACK_EXPANSION_PATTERN (nt)); PACK_EXPANSION_PATTERN (nt));
else if (ARGUMENT_PACK_P (ot))
{
int i, len;
tree opack, npack;
if (!ARGUMENT_PACK_P (nt))
return 0;
opack = ARGUMENT_PACK_ARGS (ot);
npack = ARGUMENT_PACK_ARGS (nt);
len = TREE_VEC_LENGTH (opack);
if (TREE_VEC_LENGTH (npack) != len)
return 0;
for (i = 0; i < len; ++i)
if (!template_args_equal (TREE_VEC_ELT (opack, i),
TREE_VEC_ELT (npack, i)))
return 0;
return 1;
}
else if (TYPE_P (nt)) else if (TYPE_P (nt))
return TYPE_P (ot) && same_type_p (ot, nt); return TYPE_P (ot) && same_type_p (ot, nt);
else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot)) else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
...@@ -5405,9 +5451,6 @@ comp_template_args (tree oldargs, tree newargs) ...@@ -5405,9 +5451,6 @@ comp_template_args (tree oldargs, tree newargs)
{ {
int i; int i;
oldargs = expand_template_argument_pack (oldargs);
newargs = expand_template_argument_pack (newargs);
if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs)) if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs))
return 0; return 0;
...@@ -11707,58 +11750,76 @@ tsubst_copy_and_build (tree t, ...@@ -11707,58 +11750,76 @@ tsubst_copy_and_build (tree t,
Emit an error under control of COMPLAIN, and return TRUE on error. */ Emit an error under control of COMPLAIN, and return TRUE on error. */
static bool static bool
check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain) check_instantiated_arg (tree tmpl, tree t, tsubst_flags_t complain)
{ {
int ix, len = DECL_NTPARMS (tmpl); if (ARGUMENT_PACK_P (t))
bool result = false; {
tree vec = ARGUMENT_PACK_ARGS (t);
int len = TREE_VEC_LENGTH (vec);
bool result = false;
int i;
for (ix = 0; ix != len; ix++) for (i = 0; i < len; ++i)
if (check_instantiated_arg (tmpl, TREE_VEC_ELT (vec, i), complain))
result = true;
return result;
}
else if (TYPE_P (t))
{ {
tree t = TREE_VEC_ELT (args, ix); /* [basic.link]: A name with no linkage (notably, the name
of a class or enumeration declared in a local scope)
shall not be used to declare an entity with linkage.
This implies that names with no linkage cannot be used as
template arguments. */
tree nt = no_linkage_check (t, /*relaxed_p=*/false);
if (TYPE_P (t)) if (nt)
{ {
/* [basic.link]: A name with no linkage (notably, the name /* DR 488 makes use of a type with no linkage cause
of a class or enumeration declared in a local scope) type deduction to fail. */
shall not be used to declare an entity with linkage. if (complain & tf_error)
This implies that names with no linkage cannot be used as
template arguments. */
tree nt = no_linkage_check (t, /*relaxed_p=*/false);
if (nt)
{
/* DR 488 makes use of a type with no linkage cause
type deduction to fail. */
if (complain & tf_error)
{
if (TYPE_ANONYMOUS_P (nt))
error ("%qT is/uses anonymous type", t);
else
error ("template argument for %qD uses local type %qT",
tmpl, t);
}
result = true;
}
/* In order to avoid all sorts of complications, we do not
allow variably-modified types as template arguments. */
else if (variably_modified_type_p (t, NULL_TREE))
{ {
if (complain & tf_error) if (TYPE_ANONYMOUS_P (nt))
error ("%qT is a variably modified type", t); error ("%qT is/uses anonymous type", t);
result = true; else
error ("template argument for %qD uses local type %qT",
tmpl, t);
} }
return true;
} }
/* A non-type argument of integral or enumerated type must be a /* In order to avoid all sorts of complications, we do not
constant. */ allow variably-modified types as template arguments. */
else if (TREE_TYPE (t) else if (variably_modified_type_p (t, NULL_TREE))
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t))
&& !TREE_CONSTANT (t))
{ {
if (complain & tf_error) if (complain & tf_error)
error ("integral expression %qE is not constant", t); error ("%qT is a variably modified type", t);
result = true; return true;
} }
} }
/* A non-type argument of integral or enumerated type must be a
constant. */
else if (TREE_TYPE (t)
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t))
&& !TREE_CONSTANT (t))
{
if (complain & tf_error)
error ("integral expression %qE is not constant", t);
return true;
}
return false;
}
static bool
check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain)
{
int ix, len = DECL_NTPARMS (tmpl);
bool result = false;
for (ix = 0; ix != len; ix++)
{
if (check_instantiated_arg (tmpl, TREE_VEC_ELT (args, ix), complain))
result = true;
}
if (result && (complain & tf_error)) if (result && (complain & tf_error))
error (" trying to instantiate %qD", tmpl); error (" trying to instantiate %qD", tmpl);
return result; return result;
......
2009-01-07 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/variadic92.C: New test.
* g++.dg/cpp0x/variadic93.C: New test.
2009-01-07 Janis Johnson <janis187@us.ibm.com> 2009-01-07 Janis Johnson <janis187@us.ibm.com>
* lib/target-supports-dg.exp (current_compiler_flags): New. * lib/target-supports-dg.exp (current_compiler_flags): New.
......
...@@ -5,4 +5,4 @@ template<typename T1 = unused, typename T2 = unused, typename T3 = unused, ...@@ -5,4 +5,4 @@ template<typename T1 = unused, typename T2 = unused, typename T3 = unused,
struct tuple {}; struct tuple {};
template<typename... Args> template<typename... Args>
void foo(tuple<Args...>) { } // { dg-error "cannot expand" } void foo(tuple<Args...>) { } // { dg-bogus "cannot expand" "" { xfail *-*-* } }
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
template<typename> struct A; template<typename> struct A;
template<typename... T> struct A<T*...> // { dg-error "cannot expand" } template<typename... T> struct A<T*...> // { dg-bogus "cannot expand" "" { xfail *-*-* } }
{ {
struct B; struct B;
}; };
A<void*> a; // { dg-error "incomplete type" } A<void*> a; // { dg-bogus "incomplete type" "" { xfail *-*-* } }
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
template<typename> struct A; template<typename> struct A;
template<typename... T> struct A<T...> { }; // { dg-error "cannot expand" } template<typename... T> struct A<T...> { }; // { dg-bogus "cannot expand" "" { xfail *-*-* } }
A<int> a; // { dg-error "incomplete type" } A<int> a; // { dg-bogus "incomplete type" "" { xfail *-*-* } }
// Various tests for variadic templates and partial specialization.
// { dg-options "-std=c++0x" }
// PR c++/36846
template<typename A, typename B>
struct pair;
template<typename... T>
struct pairs;
template<typename... AS, typename... BS>
struct pairs<pair<AS, BS>...> {
struct mismatched_packs {};
};
template class pairs<
pair<int, int>,
pair<int, int>
>;
template<int A, int B>
struct point;
template<typename... T>
struct points;
template<int... AS, int... BS>
struct points<point<AS, BS>...> {
struct mismatched_packs {};
};
template class points<
point<0, 1>,
point<0, 1>
>;
// PR c++/35477
template <class...ARGS> struct tuple {};
template <class A, class B> struct test {};
template <class... ARGS, class B> struct test<B, tuple<ARGS...>>
{
template <class T> struct inside {};
};
// PR c++/38276
template<typename...> struct A;
template<typename, typename> struct B;
template<typename... T, typename... U> struct B<A<T...>, A<U...> >
{
static int i;
};
B<A<>, A<int> > b1;
B<A<int>, A<> > b2;
// PR c++/35784
template <typename...> struct p;
template <typename, typename> struct d;
template <typename... A, typename... B>
struct d<p<A...>, p<B...> > { typedef int t; };
typedef d<p<>, p<int, float> >::t q;
typedef d<q, d<p<int>, p<float> >::t> r; // *
typedef d<d<p<>, p<int, float> >::t, d<p<>, p<> >::t> s;
// PR c++/35297
// { dg-options "-std=c++0x" }
template <class T=int, class... ARGS>
struct test2 {};
int main()
{
test2<> a;
return 0;
}
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