diff mbox

C++ PATCH for C++17 class template argument deduction issues

Message ID CADzB+2mo60zG=us90tGL=61D0kYtVNrxtcNHJTuNQj3G+-NHtQ@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill March 2, 2017, 1:58 a.m. UTC
On Tue, Feb 28, 2017 at 1:56 PM, Jason Merrill <jason@redhat.com> wrote:
> This patch implements some proposed resolutions to open issues with
> C++17 class template argument deduction.

And some more:
commit 41e5f38da5699736eb02a5b9c65549799c288714
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Mar 1 13:15:11 2017 -1000

            Class template argument deduction in new-expression
            * init.c (build_new): Handle deduction from no initializer.
            * parser.c (cp_parser_new_expression): Don't require a single
            expression for class template deduction.
            * typeck2.c (cxx_incomplete_type_diagnostic): Fix diagnostic for
            class template placeholder.
            * pt.c (tsubst_copy) [TEMPLATE_DECL]: Handle dependent context.
            (tsubst_copy_and_build) [TEMPLATE_ID_EXPR]: Handle SCOPE_REF.
            (redeclare_class_template): Set TEMPLATE_TYPE_PARM_FOR_CLASS.
diff mbox

Patch

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 7ded37e..191fe13 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3478,15 +3478,19 @@  build_new (vec<tree, va_gc> **placement, tree type, tree nelts,
   if (type == error_mark_node)
     return error_mark_node;
 
-  if (nelts == NULL_TREE && vec_safe_length (*init) == 1
+  if (nelts == NULL_TREE
       /* Don't do auto deduction where it might affect mangling.  */
       && (!processing_template_decl || at_function_scope_p ()))
     {
       tree auto_node = type_uses_auto (type);
       if (auto_node)
 	{
-	  tree d_init = (**init)[0];
-	  d_init = resolve_nondeduced_context (d_init, complain);
+	  tree d_init = NULL_TREE;
+	  if (vec_safe_length (*init) == 1)
+	    {
+	      d_init = (**init)[0];
+	      d_init = resolve_nondeduced_context (d_init, complain);
+	    }
 	  type = do_auto_deduction (type, d_init, auto_node);
 	}
     }
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 50528e2..e684870 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8228,7 +8228,8 @@  cp_parser_new_expression (cp_parser* parser)
      contain a new-initializer of the form ( assignment-expression )".
      Additionally, consistently with the spirit of DR 1467, we want to accept
      'new auto { 2 }' too.  */
-  else if (type_uses_auto (type)
+  else if ((ret = type_uses_auto (type))
+	   && !CLASS_PLACEHOLDER_TEMPLATE (ret)
 	   && (vec_safe_length (initializer) != 1
 	       || (BRACE_ENCLOSED_INITIALIZER_P ((*initializer)[0])
 		   && CONSTRUCTOR_NELTS ((*initializer)[0]) != 1)))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ec9d53a..8144ca6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5732,6 +5732,9 @@  redeclare_class_template (tree type, tree parms, tree cons)
 	  gcc_assert (DECL_CONTEXT (parm) == NULL_TREE);
 	  DECL_CONTEXT (parm) = tmpl;
 	}
+
+      if (TREE_CODE (parm) == TYPE_DECL)
+	TEMPLATE_TYPE_PARM_FOR_CLASS (TREE_TYPE (parm)) = true;
     }
 
   // Cannot redeclare a class template with a different set of constraints.
@@ -14638,6 +14641,15 @@  tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	     have to substitute this with one having context `D<int>'.  */
 
 	  tree context = tsubst (DECL_CONTEXT (t), args, complain, in_decl);
+	  if (dependent_scope_p (context))
+	    {
+	      /* When rewriting a constructor into a deduction guide, a
+		 non-dependent name can become dependent, so memtmpl<args>
+		 becomes context::template memtmpl<args>.  */
+	      tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	      return build_qualified_name (type, context, DECL_NAME (t),
+					   /*template*/true);
+	    }
 	  return lookup_field (context, DECL_NAME(t), 0, false);
 	}
       else
@@ -16621,6 +16633,14 @@  tsubst_copy_and_build (tree t,
 	if (targs == error_mark_node)
 	  return error_mark_node;
 
+	if (TREE_CODE (templ) == SCOPE_REF)
+	  {
+	    tree name = TREE_OPERAND (templ, 1);
+	    tree tid = lookup_template_function (name, targs);
+	    TREE_OPERAND (templ, 1) = tid;
+	    return templ;
+	  }
+
 	if (variable_template_p (templ))
 	  RETURN (lookup_and_finish_template_variable (templ, targs, complain));
 
@@ -25144,7 +25164,7 @@  do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
       type = TREE_TYPE (most_general_template (tmpl));
     }
 
-  bool saw_default = false;
+  bool saw_ctor = false;
   bool saw_copy = false;
   if (CLASSTYPE_METHOD_VEC (type))
     // FIXME cache artificial deduction guides
@@ -25154,9 +25174,9 @@  do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
 	tree guide = build_deduction_guide (fn, outer_args, complain);
 	cands = ovl_cons (guide, cands);
 
+	saw_ctor = true;
+
 	tree parms = FUNCTION_FIRST_USER_PARMTYPE (fn);
-	if (sufficient_parms_p (parms))
-	  saw_default = true;
 	if (parms && sufficient_parms_p (TREE_CHAIN (parms)))
 	  {
 	    tree pt = TREE_VALUE (parms);
@@ -25167,7 +25187,7 @@  do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
 	  }
       }
 
-  if (!saw_default && args->length() == 0)
+  if (!saw_ctor && args->length() == 0)
     {
       tree guide = build_deduction_guide (type, outer_args, complain);
       cands = ovl_cons (guide, cands);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 1e0354d..58a01c9 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -523,8 +523,14 @@  cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
 
     case TEMPLATE_TYPE_PARM:
       if (is_auto (type))
-	emit_diagnostic (diag_kind, loc, 0,
-			 "invalid use of %<auto%>");
+	{
+	  if (CLASS_PLACEHOLDER_TEMPLATE (type))
+	    emit_diagnostic (diag_kind, loc, 0,
+			     "invalid use of placeholder %qT", type);
+	  else
+	    emit_diagnostic (diag_kind, loc, 0,
+			     "invalid use of %qT", type);
+	}
       else
 	emit_diagnostic (diag_kind, loc, 0,
 			 "invalid use of template type parameter %qT", type);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction33.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction33.C
new file mode 100644
index 0000000..d135031
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction33.C
@@ -0,0 +1,13 @@ 
+// { dg-options -std=c++1z }
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+template <class T = void> struct A { };
+template <class T> struct B { B(T,T); };
+
+int main()
+{
+  same<decltype(new A),A<void>*>();
+  same<decltype(new B{1,2}),B<int>*>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction34.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction34.C
new file mode 100644
index 0000000..b035879
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction34.C
@@ -0,0 +1,13 @@ 
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  template <class U>
+  static constexpr bool B = U();
+
+  template <class U, bool V = B<U>>
+  A(T, U);
+};
+
+A a (1,2);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction35.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction35.C
new file mode 100644
index 0000000..b0e53d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction35.C
@@ -0,0 +1,10 @@ 
+// { dg-options -std=c++1z }
+
+template <class T> struct A;
+
+template <class T> struct A {
+  A(T&&);
+};
+
+int i;
+A a = i;			// { dg-error "" }