diff mbox

C++ PATCH for some C++17 class deduction issues

Message ID CADzB+2nA2TXy-H5tX73qqA2zdO7t4q7fvACcTQ=EkfuTpKnTEQ@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Nov. 9, 2016, 8:01 p.m. UTC
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 <jason@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 mbox

Patch

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()