Discussion at the meeting led me to notice that class template
deduction wasn't working with template template parameters.  This
patch also improves a few diagnostic issues.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 66d2621abd8ed6bb47d0fda747a572e00aece25e
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Nov 8 10:14:24 2016 -0800

            Fix C++17 template placeholder for template template parm.
    
            * parser.c (cp_parser_simple_type_specifier): Allow placeholder
            for template template parameter.
            (cp_parser_type_id_1): Improve diagnostic.
            * decl.c (grokdeclarator): Handle class deduction diagnostics here.
            * pt.c (splice_late_return_type): Not here.
            (tsubst) [TEMPLATE_TYPE_PARM]: Substitute into placeholder template.
            (do_class_deduction): Handle non-class templates.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bd37faa..4b18d4e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -9490,6 +9490,11 @@ grokdeclarator (const cp_declarator *declarator,
   if (initialized > 1)
     funcdef_flag = true;
 
+  location_t typespec_loc = smallest_type_quals_location (type_quals,
+                                                     declspecs->locations);
+  if (typespec_loc == UNKNOWN_LOCATION)
+    typespec_loc = declspecs->locations[ds_type_spec];
+
   /* Look inside a declarator for the name being declared
      and get it as a string, for an error message.  */
   for (id_declarator = declarator;
@@ -10011,6 +10016,16 @@ grokdeclarator (const cp_declarator *declarator,
   /* We might have ignored or rejected some of the qualifiers.  */
   type_quals = cp_type_quals (type);
 
+  if (cxx_dialect >= cxx1z && type && is_auto (type)
+      && innermost_code != cdk_function
+      && id_declarator && declarator != id_declarator)
+    if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type))
+    {
+      error_at (typespec_loc, "template placeholder type %qT must be followed "
+               "by a simple declarator-id", type);
+      inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", tmpl);
+    }
+
   staticp = 0;
   inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline);
   virtualp =  decl_spec_seq_has_spec_p (declspecs, ds_virtual);
@@ -10247,12 +10262,7 @@ grokdeclarator (const cp_declarator *declarator,
              {
                if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type))
                  {
-                   location_t loc;
-                   loc = smallest_type_quals_location (type_quals,
-                                                       declspecs->locations);
-                   if (loc == UNKNOWN_LOCATION)
-                     loc = declspecs->locations[ds_type_spec];
-                   warning_at (loc, OPT_Wignored_qualifiers, "type "
+                   warning_at (typespec_loc, OPT_Wignored_qualifiers, "type "
                                "qualifiers ignored on function return type");
                  }
                /* We now know that the TYPE_QUALS don't apply to the
@@ -10301,11 +10311,12 @@ grokdeclarator (const cp_declarator *declarator,
            funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id;
 
            /* Handle a late-specified return type.  */
+           tree late_return_type = declarator->u.function.late_return_type;
            if (funcdecl_p)
              {
-               if (type_uses_auto (type))
+               if (tree auto_node = type_uses_auto (type))
                  {
-                   if (!declarator->u.function.late_return_type)
+                   if (!late_return_type)
                      {
                        if (current_class_type
                            && LAMBDA_TYPE_P (current_class_type))
@@ -10333,8 +10344,32 @@ grokdeclarator (const cp_declarator *declarator,
                               name, type);
                        return error_mark_node;
                      }
+                   if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+                     {
+                       if (!late_return_type)
+                         {
+                           if (dguide_name_p (unqualified_id))
+                             error_at (typespec_loc, "deduction guide for "
+                                       "%qT must have trailing return type",
+                                       TREE_TYPE (tmpl));
+                           else
+                             error_at (typespec_loc, "deduced class type %qT "
+                                       "in function return type", type);
+                           inform (DECL_SOURCE_LOCATION (tmpl),
+                                   "%qD declared here", tmpl);
+                         }
+                       else if (CLASS_TYPE_P (late_return_type)
+                                && CLASSTYPE_TEMPLATE_INFO (late_return_type)
+                                && (CLASSTYPE_TI_TEMPLATE (late_return_type)
+                                    == tmpl))
+                         /* OK */;
+                       else
+                         error ("trailing return type %qT of deduction guide "
+                                "is not a specialization of %qT",
+                                late_return_type, TREE_TYPE (tmpl));
+                     }
                  }
-               else if (declarator->u.function.late_return_type
+               else if (late_return_type
                         && sfk != sfk_conversion)
                  {
                    if (cxx_dialect < cxx11)
@@ -10348,12 +10383,11 @@ grokdeclarator (const cp_declarator *declarator,
                    return error_mark_node;
                  }
              }
-           type = splice_late_return_type
-             (type, declarator->u.function.late_return_type);
+           type = splice_late_return_type (type, late_return_type);
            if (type == error_mark_node)
              return error_mark_node;
 
-           if (declarator->u.function.late_return_type)
+           if (late_return_type)
              late_return_type_p = true;
 
            if (ctype == NULL_TREE
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e443648..7b95dba 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -16596,7 +16596,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
                                                 /*ambiguous_decls=*/NULL,
                                                 token->location);
              if (tmpl && tmpl != error_mark_node
-                 && DECL_CLASS_TEMPLATE_P (tmpl))
+                 && (DECL_CLASS_TEMPLATE_P (tmpl)
+                     || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
                type = make_template_placeholder (tmpl);
              else
                {
@@ -20311,26 +20312,35 @@ cp_parser_type_id_1 (cp_parser* parser, bool 
is_template_arg,
       && (!flag_concepts || parser->in_type_id_in_expr_p)
       /* None of the valid uses of 'auto' in C++14 involve the type-id
         nonterminal, but it is valid in a trailing-return-type.  */
-      && !(cxx_dialect >= cxx14 && is_trailing_return)
-      && type_uses_auto (type_specifier_seq.type))
-    {
-      /* A type-id with type 'auto' is only ok if the abstract declarator
-        is a function declarator with a late-specified return type.
+      && !(cxx_dialect >= cxx14 && is_trailing_return))
+    if (tree auto_node = type_uses_auto (type_specifier_seq.type))
+      {
+       /* A type-id with type 'auto' is only ok if the abstract declarator
+          is a function declarator with a late-specified return type.
 
-         A type-id with 'auto' is also valid in a trailing-return-type
-         in a compound-requirement. */
-      if (abstract_declarator
-         && abstract_declarator->kind == cdk_function
-         && abstract_declarator->u.function.late_return_type)
-       /* OK */;
-      else if (parser->in_result_type_constraint_p)
-        /* OK */;
-      else
-       {
-         error ("invalid use of %<auto%>");
-         return error_mark_node;
-       }
-    }
+          A type-id with 'auto' is also valid in a trailing-return-type
+          in a compound-requirement. */
+       if (abstract_declarator
+           && abstract_declarator->kind == cdk_function
+           && abstract_declarator->u.function.late_return_type)
+         /* OK */;
+       else if (parser->in_result_type_constraint_p)
+         /* OK */;
+       else
+         {
+           location_t loc = type_specifier_seq.locations[ds_type_spec];
+           if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+             {
+               error_at (loc, "missing template arguments after %qT",
+                         auto_node);
+               inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here",
+                       tmpl);
+             }
+           else
+             error_at (loc, "invalid use of %qT", auto_node);
+           return error_mark_node;
+         }
+      }
   
   return groktypename (&type_specifier_seq, abstract_declarator,
                       is_template_arg);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 64e566e..e8b6afd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13314,7 +13314,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
                      PLACEHOLDER_TYPE_CONSTRAINTS (r)
                        = tsubst_constraint (constr, args, complain, in_decl);
                    else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t))
-                     CLASS_PLACEHOLDER_TEMPLATE (r) = pl;
+                     {
+                       if (DECL_TEMPLATE_TEMPLATE_PARM_P (pl))
+                         pl = tsubst (pl, args, complain, in_decl);
+                       CLASS_PLACEHOLDER_TEMPLATE (r) = pl;
+                     }
                  }
 
                if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM)
@@ -24625,13 +24629,23 @@ build_deduction_guide (tree ctor, tree outer_args, 
tsubst_flags_t complain)
   return ded_tmpl;
 }
 
-/* Deduce template arguments for the class template TMPL based on the
-   initializer INIT, and return the resulting type.  */
+/* Deduce template arguments for the class template placeholder PTYPE for
+   template TMPL based on the initializer INIT, and return the resulting
+   type.  */
 
 tree
-do_class_deduction (tree tmpl, tree init, tsubst_flags_t complain)
+do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain)
 {
-  gcc_assert (DECL_CLASS_TEMPLATE_P (tmpl));
+  if (!DECL_CLASS_TEMPLATE_P (tmpl))
+    {
+      /* We should have handled this in the caller.  */
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
+       return ptype;
+      if (complain & tf_error)
+       error ("non-class template %qT used without template arguments", tmpl);
+      return error_mark_node;
+    }
+
   tree type = TREE_TYPE (tmpl);
 
   vec<tree,va_gc> *args;
@@ -24733,7 +24747,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 
   if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
     /* C++17 class template argument deduction.  */
-    return do_class_deduction (tmpl, init, complain);
+    return do_class_deduction (type, tmpl, init, complain);
 
   /* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto
      with either a new invented type template parameter U or, if the
@@ -24881,20 +24895,6 @@ splice_late_return_type (tree type, tree 
late_return_type)
 {
   if (is_auto (type))
     {
-      if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type))
-       {
-         if (!late_return_type)
-           error ("deduction guide must have trailing return type");
-         else if (CLASS_TYPE_P (late_return_type)
-                  && CLASSTYPE_TEMPLATE_INFO (late_return_type)
-                  && CLASSTYPE_TI_TEMPLATE (late_return_type) == tmpl)
-           /* OK */;
-         else
-           error ("trailing return type %qT of deduction guide is not "
-                  "a specialization of %qT",
-                  late_return_type, TREE_TYPE (tmpl));
-       }
-
       if (late_return_type)
        return late_return_type;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C 
b/gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C
index b301604..87b4b35 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C
@@ -1,4 +1,4 @@
 // { dg-do compile { target c++11 } }
 template<typename ... Elements> class Tuple;
 Tuple<>* t; // OK: Elements is empty
-Tuple* u; // { dg-error "template-name" }
+Tuple* u; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction21.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction21.C
new file mode 100644
index 0000000..5eebef7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction21.C
@@ -0,0 +1,13 @@
+// { dg-options -std=c++1z }
+
+template<class T, class D = int>
+struct S { T t; };
+template<class U>
+S(U) -> S<typename U::type>;
+
+struct A {
+  using type = short;
+  operator type();
+};
+S s{A()};                      // OK
+S x(A());                      // { dg-error "return type" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction22.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction22.C
new file mode 100644
index 0000000..b15b0c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction22.C
@@ -0,0 +1,21 @@
+// { dg-options -std=c++1z }
+
+template <template <class> class T>
+void f()
+{
+  T t = 42;                    // { dg-error "B" }
+};
+
+template <class T>
+struct A
+{
+  A(T);
+};
+
+template <class T> using B = T;
+
+int main()
+{
+  f<A>();
+  f<B>();                      // { dg-message "here" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction23.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction23.C
new file mode 100644
index 0000000..26795b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction23.C
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  A(T);
+};
+
+A a = 42;
+A *ap = &a;                    // { dg-error "placeholder" }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ttp10.C 
b/gcc/testsuite/g++.old-deja/g++.pt/ttp10.C
index ca04f90..62a6400 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ttp10.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ttp10.C
@@ -20,7 +20,7 @@ template<template<class> class D,class E> class C
 
 template<template<class> class D,class E> int C<D,E>::f()
 {
-       return d.f();                   // { dg-error "" } d not properly 
declared
+       return d.f();                   // { dg-prune-output "was not declared" 
}
 }
 
 int main()

Reply via email to