diff mbox series

[pushed] c++: generic lambda forwarding function [PR94546]

Message ID 20200422062047.20722-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: generic lambda forwarding function [PR94546] | expand

Commit Message

Jason Merrill April 22, 2020, 6:20 a.m. UTC
While instantiating test(Plot) we partially instantiate the generic lambda.
We look at forward<T>(rest)... and see that it's just replacing parameter
packs with new parameter packs and tries to do a direct substitution.  But
because register_parameter_specializations had built up a
NONTYPE_ARGUMENT_PACK around the new parameter pack, the substitution
failed.  So let's not wrap it that way.

Tested x86_64-pc-linux-gnu, applying to trunk.

gcc/cp/ChangeLog
2020-04-22  Jason Merrill  <jason@redhat.com>

	PR c++/94546
	* pt.c (register_parameter_specializations): If the instantiation is
	still a parameter pack, don't wrap it in a NONTYPE_ARGUMENT_PACK.
	(tsubst_pack_expansion, tsubst_expr): Adjust.
---
 gcc/cp/pt.c                                   | 28 +++++++------------
 .../g++.dg/cpp2a/lambda-generic-variadic20.C  | 23 +++++++++++++++
 2 files changed, 33 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-generic-variadic20.C


base-commit: 6c0ab626113ef20ee2986cb8a102b5394aeb888a
diff mbox series

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6f74c278c23..a11423c7900 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12720,7 +12720,6 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   tree pattern;
   tree pack, packs = NULL_TREE;
   bool unsubstituted_packs = false;
-  bool unsubstituted_fn_pack = false;
   int i, len = -1;
   tree result;
   bool need_local_specializations = false;
@@ -12800,19 +12799,15 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 	      else
 		arg_pack = make_fnparm_pack (arg_pack);
 	    }
-	  else if (argument_pack_element_is_expansion_p (arg_pack, 0))
-	    /* This argument pack isn't fully instantiated yet.  We set this
-	       flag rather than clear arg_pack because we do want to do the
-	       optimization below, and we don't want to substitute directly
-	       into the pattern (as that would expose a NONTYPE_ARGUMENT_PACK
-	       where it isn't expected).  */
-	    unsubstituted_fn_pack = true;
+	  else if (DECL_PACK_P (arg_pack))
+	    /* This argument pack isn't fully instantiated yet.  */
+	    arg_pack = NULL_TREE;
 	}
       else if (is_capture_proxy (parm_pack))
 	{
 	  arg_pack = retrieve_local_specialization (parm_pack);
-	  if (argument_pack_element_is_expansion_p (arg_pack, 0))
-	    unsubstituted_fn_pack = true;
+	  if (DECL_PACK_P (arg_pack))
+	    arg_pack = NULL_TREE;
 	}
       else
         {
@@ -12847,8 +12842,7 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 
           if (len < 0)
 	    len = my_len;
-          else if (len != my_len
-		   && !unsubstituted_fn_pack)
+	  else if (len != my_len)
             {
 	      if (!(complain & tf_error))
 		/* Fail quietly.  */;
@@ -12871,10 +12865,6 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 	  /* We can't substitute for this parameter pack.  We use a flag as
 	     well as the missing_level counter because function parameter
 	     packs don't have a level.  */
-          if (!(processing_template_decl || is_auto (parm_pack)))
-	    {
-	      gcc_unreachable ();
-	    }
 	  gcc_assert (processing_template_decl || is_auto (parm_pack));
 	  unsubstituted_packs = true;
 	}
@@ -17864,7 +17854,8 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 	      {
 		inst = (retrieve_local_specialization
 			(DECL_CAPTURED_VARIABLE (decl)));
-		gcc_assert (TREE_CODE (inst) == NONTYPE_ARGUMENT_PACK);
+		gcc_assert (TREE_CODE (inst) == NONTYPE_ARGUMENT_PACK
+			    || DECL_PACK_P (inst));
 	      }
 	    else
 	      inst = lookup_init_capture_pack (decl);
@@ -25282,7 +25273,8 @@  register_parameter_specializations (tree pattern, tree inst)
     }
   for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))
     {
-      if (!DECL_PACK_P (tmpl_parm))
+      if (!DECL_PACK_P (tmpl_parm)
+	  || (spec_parm && DECL_PACK_P (spec_parm)))
 	{
 	  register_local_specialization (spec_parm, tmpl_parm);
 	  spec_parm = DECL_CHAIN (spec_parm);
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-generic-variadic20.C b/gcc/testsuite/g++.dg/cpp2a/lambda-generic-variadic20.C
new file mode 100644
index 00000000000..3d69dbb8e98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-generic-variadic20.C
@@ -0,0 +1,23 @@ 
+// PR c++/94546
+// { dg-do compile { target c++2a } }
+
+template <class T> T&& forward(T&& t) { return static_cast<T&&>(t); }
+
+template <class X>
+void test(X&& plot)
+{
+    // Note: For brevity, this lambda function is only
+    // defined, not called nor assigned to a variable.
+    // Doing those things won't fix the error.
+    [&]<class... T>(T&&... rest)
+    {
+        plot(forward<T>(rest)...);
+    };
+}
+int main()
+{
+    auto Plot = [](auto&&...)
+    {
+    };
+    test(Plot);
+}