c++: variadic lambda template and empty pack [PR97246]
authorJason Merrill <jason@redhat.com>
Fri, 12 Feb 2021 00:45:22 +0000 (19:45 -0500)
committerJason Merrill <jason@redhat.com>
Fri, 12 Feb 2021 02:30:24 +0000 (21:30 -0500)
In get<0>, Is is empty, so the first parameter pack of the lambda is empty,
but after the fix for PR94546 we were wrongly associating it with the
partial instantiation of 'v'.

gcc/cp/ChangeLog:

PR c++/97246
PR c++/94546
* pt.c (extract_fnparm_pack): Check DECL_PACK_P here.
(register_parameter_specializations): Not here.

gcc/testsuite/ChangeLog:

PR c++/97246
* g++.dg/cpp2a/lambda-generic-variadic21.C: New test.

gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/lambda-generic-variadic21.C [new file with mode: 0644]

index 37c45a297c2ff7be84265e6ec9b426393eda3fcf..50cdb00310f67b618cbdc27bac3f03f229282e12 100644 (file)
@@ -12302,29 +12302,40 @@ extract_fnparm_pack (tree tmpl_parm, tree *spec_p)
 {
   /* Collect all of the extra "packed" parameters into an
      argument pack.  */
-  tree parmvec;
-  tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+  tree argpack;
   tree spec_parm = *spec_p;
-  int i, len;
+  int len;
 
   for (len = 0; spec_parm; ++len, spec_parm = TREE_CHAIN (spec_parm))
     if (tmpl_parm
        && !function_parameter_expanded_from_pack_p (spec_parm, tmpl_parm))
       break;
 
-  /* Fill in PARMVEC and PARMTYPEVEC with all of the parameters.  */
-  parmvec = make_tree_vec (len);
   spec_parm = *spec_p;
-  for (i = 0; i < len; i++, spec_parm = DECL_CHAIN (spec_parm))
+  if (len == 1 && DECL_PACK_P (spec_parm))
     {
-      tree elt = spec_parm;
-      if (DECL_PACK_P (elt))
-       elt = make_pack_expansion (elt);
-      TREE_VEC_ELT (parmvec, i) = elt;
+      /* The instantiation is still a parameter pack; don't wrap it in a
+        NONTYPE_ARGUMENT_PACK.  */
+      argpack = spec_parm;
+      spec_parm = DECL_CHAIN (spec_parm);
     }
+  else
+    {
+      /* Fill in PARMVEC with all of the parameters.  */
+      tree parmvec = make_tree_vec (len);
+      argpack = make_node (NONTYPE_ARGUMENT_PACK);
+      for (int i = 0; i < len; i++)
+       {
+         tree elt = spec_parm;
+         if (DECL_PACK_P (elt))
+           elt = make_pack_expansion (elt);
+         TREE_VEC_ELT (parmvec, i) = elt;
+         spec_parm = DECL_CHAIN (spec_parm);
+       }
 
-  /* Build the argument packs.  */
-  SET_ARGUMENT_PACK_ARGS (argpack, parmvec);
+      /* Build the argument packs.  */
+      SET_ARGUMENT_PACK_ARGS (argpack, parmvec);
+    }
   *spec_p = spec_parm;
 
   return argpack;
@@ -25716,8 +25727,7 @@ register_parameter_specializations (tree pattern, tree inst)
     }
   for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))
     {
-      if (!DECL_PACK_P (tmpl_parm)
-         || (spec_parm && DECL_PACK_P (spec_parm)))
+      if (!DECL_PACK_P (tmpl_parm))
        {
          register_local_specialization (spec_parm, tmpl_parm);
          spec_parm = DECL_CHAIN (spec_parm);
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-generic-variadic21.C b/gcc/testsuite/g++.dg/cpp2a/lambda-generic-variadic21.C
new file mode 100644 (file)
index 0000000..d6b5656
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/97246
+// { dg-do compile { target c++20 } }
+
+template <int... Is, typename T>
+T arg_T(decltype(Is)..., T, ...);
+
+template <int I, int... Is>
+inline constexpr auto get =
+ []<typename... T>(decltype(Is)..., T... v, ...) {
+   static_assert( sizeof...(T) == sizeof...(v) );
+   if constexpr ( sizeof...(T) == 1 )
+     return (v,...);
+   else {
+     using V = decltype(arg_T<__integer_pack(I)...>(v...));
+     return get<I,__integer_pack(I)...>.template operator()<V>(v...);
+   }
+ };
+
+static_assert( get<0>('\0', short{1}, 2, long{3}) == 0 );