DR 1286
authorJason Merrill <jason@redhat.com>
Sat, 3 Aug 2013 20:32:08 +0000 (16:32 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 3 Aug 2013 20:32:08 +0000 (16:32 -0400)
DR 1286
* pt.c (get_underlying_template): New.
(convert_template_argument, lookup_template_class_1): Use it.

From-SVN: r201470

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C
gcc/testsuite/g++.dg/cpp0x/alias-decl-33a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286a.C [new file with mode: 0644]

index 8b9b997..5587ac1 100644 (file)
@@ -1,5 +1,9 @@
 2013-08-03  Jason Merrill  <jason@redhat.com>
 
+       DR 1286
+       * pt.c (get_underlying_template): New.
+       (convert_template_argument, lookup_template_class_1): Use it.
+
        DR 1430
        PR c++/51239
        * pt.c (pack_expansion_args_count): Rename from
index bbaeb7d..d03c1cf 100644 (file)
@@ -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
index c5760cf..f38f993 100644 (file)
@@ -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 {};
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-33a.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-33a.C
new file mode 100644 (file)
index 0000000..a1c442e
--- /dev/null
@@ -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>({});
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286.C
new file mode 100644 (file)
index 0000000..0c545c7
--- /dev/null
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286a.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286a.C
new file mode 100644 (file)
index 0000000..1780c9a
--- /dev/null
@@ -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;