commit 74510935cc6b482407a30e53ee27f6f13b8b3d0f
Author: Jason Merrill <jason@redhat.com>
Date: Fri Apr 5 15:39:35 2013 -0400
DR 1430
PR c++/51239
* pt.c (pack_expansion_args_count): Rename from
any_pack_expanson_args_p.
(coerce_template_parms): Reject pack expansion to
non-pack template parameter of alias template.
@@ -6542,18 +6542,22 @@ coerce_template_parameter_pack (tree parms,
return argument_pack;
}
-/* Returns true if the template argument vector ARGS contains
- any pack expansions, false otherwise. */
+/* Returns the number of pack expansions in the template argument vector
+ ARGS. */
-static bool
-any_pack_expanson_args_p (tree args)
+static int
+pack_expansion_args_count (tree args)
{
int i;
+ int count = 0;
if (args)
for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
- if (PACK_EXPANSION_P (TREE_VEC_ELT (args, i)))
- return true;
- return false;
+ {
+ tree elt = TREE_VEC_ELT (args, i);
+ if (elt && PACK_EXPANSION_P (elt))
+ ++count;
+ }
+ return count;
}
/* Convert all template arguments to their appropriate types, and
@@ -6588,6 +6592,7 @@ coerce_template_parms (tree parms,
subtract it from nparms to get the number of non-variadic
parameters. */
int variadic_p = 0;
+ int variadic_args_p = 0;
int post_variadic_parms = 0;
if (args == error_mark_node)
@@ -6617,11 +6622,14 @@ coerce_template_parms (tree parms,
if (!post_variadic_parms)
inner_args = expand_template_argument_pack (inner_args);
+ /* Count any pack expansion args. */
+ variadic_args_p = pack_expansion_args_count (inner_args);
+
nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
if ((nargs > nparms && !variadic_p)
|| (nargs < nparms - variadic_p
&& require_all_args
- && !any_pack_expanson_args_p (inner_args)
+ && !variadic_args_p
&& (!use_default_args
|| (TREE_VEC_ELT (parms, nargs) != error_mark_node
&& !TREE_PURPOSE (TREE_VEC_ELT (parms, nargs))))))
@@ -6644,6 +6652,33 @@ coerce_template_parms (tree parms,
return error_mark_node;
}
+ /* We can't pass a pack expansion to a non-pack parameter of an alias
+ template (DR 1430). */
+ else if (in_decl && DECL_ALIAS_TEMPLATE_P (in_decl)
+ && variadic_args_p
+ && nargs - variadic_args_p < nparms - variadic_p)
+ {
+ if (complain & tf_error)
+ {
+ for (int i = 0; i < TREE_VEC_LENGTH (inner_args); ++i)
+ {
+ tree arg = TREE_VEC_ELT (inner_args, i);
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
+
+ if (PACK_EXPANSION_P (arg)
+ && !template_parameter_pack_p (parm))
+ {
+ error ("pack expansion argument for non-pack parameter "
+ "%qD of alias template %qD", parm, in_decl);
+ inform (DECL_SOURCE_LOCATION (parm), "declared here");
+ goto found;
+ }
+ }
+ gcc_unreachable ();
+ found:;
+ }
+ return error_mark_node;
+ }
/* We need to evaluate the template arguments, even though this
template-id may be nested within a "sizeof". */
new file mode 100644
@@ -0,0 +1,14 @@
+// PR c++/51239
+// { dg-require-effective-target c++11 }
+
+template<class... x>
+class list{};
+template<class a, class... b>
+using tail=list<b...>;
+template <class...T>
+void f(tail<T...>); // { dg-error "alias" }
+
+int main()
+{
+ f<int,int>({});
+}
new file mode 100644
@@ -0,0 +1,21 @@
+// PR c++/57138
+// { dg-do compile { target c++11 } }
+
+template <template <typename ... X> class T, typename ... Y>
+struct D
+{
+ template <typename ... Z>
+ using type = T <Y..., Z...>; // { dg-error "pack expansion" }
+};
+template <typename T>
+class A {};
+template <typename X, typename Y>
+struct B;
+template <typename T>
+struct B <int, T>
+{
+ typedef A <T> type;
+};
+template <typename X, typename Y>
+using C = typename B <X, Y>::type;
+struct E : public D <C> {};
commit 42137e0d2c1a1dd949999080707a95b60266c6aa
Author: Jason Merrill <jason@redhat.com>
Date: Fri Aug 2 20:08:48 2013 -0400
DR 1286
* pt.c (get_underlying_template): New.
(convert_template_argument, lookup_template_class_1): Use it.
@@ -5111,6 +5111,34 @@ alias_template_specialization_p (const_tree t)
&& DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (t)));
}
+/* Return either TMPL or another template that it is equivalent to under DR
+ 1286: An alias that just changes the name of a template is equivalent to
+ the other template. */
+
+static tree
+get_underlying_template (tree tmpl)
+{
+ gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+ while (DECL_ALIAS_TEMPLATE_P (tmpl))
+ {
+ tree result = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+ if (TYPE_TEMPLATE_INFO (result))
+ {
+ tree sub = TYPE_TI_TEMPLATE (result);
+ if (PRIMARY_TEMPLATE_P (sub)
+ && same_type_p (result, TREE_TYPE (sub)))
+ {
+ /* The alias type is equivalent to the pattern of the
+ underlying template, so strip the alias. */
+ tmpl = sub;
+ continue;
+ }
+ }
+ break;
+ }
+ return tmpl;
+}
+
/* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which
must be a function or a pointer-to-function type, as specified
in [temp.arg.nontype]: disambiguate EXPR if it is an overload set,
@@ -6319,6 +6347,9 @@ convert_template_argument (tree parm,
tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
tree argparm;
+ /* Strip alias templates that are equivalent to another
+ template. */
+ arg = get_underlying_template (arg);
argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
if (coerce_template_template_parms (parmparm, argparm,
@@ -7177,6 +7208,13 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
complain &= ~tf_user;
+ /* An alias that just changes the name of a template is equivalent to the
+ other template, so if any of the arguments are pack expansions, strip
+ the alias to avoid problems with a pack expansion passed to a non-pack
+ alias template parameter (DR 1430). */
+ if (pack_expansion_args_count (INNERMOST_TEMPLATE_ARGS (arglist)))
+ templ = get_underlying_template (templ);
+
if (DECL_TEMPLATE_TEMPLATE_PARM_P (templ))
{
/* Create a new TEMPLATE_DECL and TEMPLATE_TEMPLATE_PARM node to store
@@ -10,14 +10,13 @@ void g(X<Z>);
void
foo()
{
- // Below x and y don't have the same type, because Y and Z don't
- // designate the same template ...
+ // Below x and y have the same type (DR 1286)
X<Y> y;
X<Z> z;
- // ... So these must fail to compile.
- f(z); // { dg-error "" }
- g(y); // { dg-error "" }
+ // ... So these must compile.
+ f(z); // { dg-bogus "" }
+ g(y); // { dg-bogus "" }
}
template<class> struct A0 {};
new file mode 100644
@@ -0,0 +1,15 @@
+// PR c++/51239
+// { dg-require-effective-target c++11 }
+// This variant should work because tail is equivalent to list.
+
+template<class y, class... x>
+class list{};
+template<class a, class... b>
+using tail=list<a, b...>;
+template <class...T>
+void f(tail<T...>);
+
+int main()
+{
+ f<int,int>({});
+}
new file mode 100644
@@ -0,0 +1,13 @@
+// DR 1286: An alias template can be equivalent to an underlying template.
+// { dg-do compile { target c++11 } }
+
+template <class T, class U> struct same;
+template <class T> struct same<T,T> {};
+
+template <class T> struct A {};
+template <class T> using B = A<T>;
+
+template <template <class> class T> class C {};
+
+void f(C<B>) { } // { dg-final { scan-assembler "_Z1f1CI1AE" } }
+same<C<A>, C<B> > s;
new file mode 100644
@@ -0,0 +1,60 @@
+// DR 1286
+// { dg-do compile { target c++11 } }
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+template <class,class> struct different {};
+template <class T> struct different<T,T>;
+
+template<typename T, typename U = T> struct A;
+template<template <class...> class> struct X;
+
+// equivalent to A
+template<typename V, typename W>
+using B = A<V, W>;
+
+same<X<A>,X<B>> s1;
+
+// not equivalent to A: not all parameters used
+template<typename V, typename W>
+using C = A<V>;
+
+different<X<A>,X<C>> d1;
+
+// not equivalent to A: different number of parameters
+template<typename V>
+using D = A<V>;
+
+different<X<A>,X<D>> d2;
+
+// not equivalent to A: template-arguments in wrong order
+template<typename V, typename W>
+using E = A<W, V>;
+
+different<X<A>,X<E>> d3;
+
+// equivalent to A: default arguments not considered
+template<typename V, typename W = int>
+using F = A<V, W>;
+
+same<X<A>,X<F>> s2;
+
+// equivalent to A and B
+template<typename V, typename W>
+using G = A<V, W>;
+
+same<X<A>,X<G>> s3;
+same<X<B>,X<G>> s3b;
+
+// equivalent to E
+template<typename V, typename W>
+using H = E<V, W>;
+
+same<X<E>,X<H>> s4;
+
+// not equivalent to A: argument not identifier
+template<typename V, typename W>
+using I = A<V, typename W::type>;
+
+different<X<A>,X<I>> d4;