diff mbox

C++ PATCHes for c++/79549 and 79556 (ICE with auto parameter pack)

Message ID CADzB+2kJWcoq9bee_AOp1bNoELciw1ORun-pPaKyJ2Bjm=etsQ@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Feb. 17, 2017, 6:41 p.m. UTC
In 79556, we try to deduce an auto type from a dependent initializer
with null TREE_TYPE, which doesn't work; fixed by catching that case
in do_auto_deduction.

In 79549, we try to tsubst into the type of a NONTYPE_ARGUMENT_PACK,
which doesn't make sense for an auto parameter pack; in fact, it
doesn't make sense for the argument pack to have a type at all.  For
GCC 7 I'm fixing this by leaving the auto type in place; for GCC 8
we'll do away with TREE_TYPE on all NONTYPE_ARGUMENT_PACKs.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit d6e7709acaafa96813a2eed1ca7cb51f7f9847a8
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Feb 16 17:24:19 2017 -0500

            PR c++/79556 - C++17 ICE with non-type auto
    
            * pt.c (do_auto_deduction): Don't try to deduce from null type.
commit 1eeb6fca6149f32f711ab2b404ce442c4a40b550
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 17 12:46:52 2017 -0500

            PR c++/79549 - C++17 ICE with non-type auto template parameter pack
    
            * pt.c (convert_template_argument): Just return an auto arg pack.
            (tsubst_template_args): Don't tsubst an auto pack type.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 093c0f9..04479d4 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7612,6 +7612,10 @@ convert_template_argument (tree parm,
 
       if (tree a = type_uses_auto (t))
 	{
+	  if (ARGUMENT_PACK_P (orig_arg))
+	    /* There's nothing to check for an auto argument pack.  */
+	    return orig_arg;
+
 	  t = do_auto_deduction (t, arg, a, complain, adc_unify, args);
 	  if (t == error_mark_node)
 	    return error_mark_node;
@@ -11649,8 +11653,11 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
             new_arg = error_mark_node;
 
           if (TREE_CODE (new_arg) == NONTYPE_ARGUMENT_PACK) {
-            TREE_TYPE (new_arg) = tsubst (TREE_TYPE (orig_arg), args,
-                                          complain, in_decl);
+	    if (type_uses_auto (TREE_TYPE (orig_arg)))
+	      TREE_TYPE (new_arg) = TREE_TYPE (orig_arg);
+	    else
+	      TREE_TYPE (new_arg) = tsubst (TREE_TYPE (orig_arg), args,
+					    complain, in_decl);
             TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg);
 
             if (TREE_TYPE (new_arg) == error_mark_node)
diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto8.C b/gcc/testsuite/g++.dg/cpp1z/nontype-auto8.C
new file mode 100644
index 0000000..da4c88b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto8.C
@@ -0,0 +1,10 @@
+// PR c++/79549
+// { dg-options -std=c++1z }
+
+template <auto...>
+struct meow;
+
+template <auto C>
+struct meow<C> { };
+
+meow<1> m;
commit 677e35c07a536344ce8bb74e97a72ab05cdb4da4
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Feb 16 16:31:26 2017 -0500

            PR c++/79549 - C++17 ICE with non-type auto template parameter pack
    
            * pt.c (convert_template_argument): Just return an argument pack.
            (coerce_template_parameter_pack, template_parm_to_arg)
            (extract_fnparm_pack, make_argument_pack, tsubst_template_args)
            (tsubst_decl, tsubst, type_unification_real, unify_pack_expansion):
            Don't set the type of a NONTYPE_ARGUMENT_PACK.
            * parser.c (make_char_string_pack, make_string_pack): Likewise.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 060962d..7cba266 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4150,7 +4150,6 @@ make_char_string_pack (tree value)
 
   /* Build the argument packs.  */
   SET_ARGUMENT_PACK_ARGS (argpack, charvec);
-  TREE_TYPE (argpack) = char_type_node;
 
   TREE_VEC_ELT (argvec, 0) = argpack;
 
@@ -4186,7 +4185,6 @@ make_string_pack (tree value)
 
   /* Build the argument packs.  */
   SET_ARGUMENT_PACK_ARGS (argpack, charvec);
-  TREE_TYPE (argpack) = str_char_type_node;
 
   TREE_VEC_ELT (argvec, 1) = argpack;
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 04479d4..d04ebc1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -4287,7 +4287,6 @@ template_parm_to_arg (tree t)
 	  /* Turn this argument into a NONTYPE_ARGUMENT_PACK
 	     with a single element, which expands T.  */
 	  tree vec = make_tree_vec (1);
-	  tree type = TREE_TYPE (TEMPLATE_PARM_DECL (t));
 	  if (CHECKING_P)
 	    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
 
@@ -4296,7 +4295,6 @@ template_parm_to_arg (tree t)
 
 	  t  = make_node (NONTYPE_ARGUMENT_PACK);
 	  SET_ARGUMENT_PACK_ARGS (t, vec);
-	  TREE_TYPE (t) = type;
 	}
       else
 	t = convert_from_reference (t);
@@ -7528,13 +7526,14 @@ convert_template_argument (tree parm,
       return error_mark_node;
     }
 
-  if (is_type)
+  if (template_parameter_pack_p (parm) && ARGUMENT_PACK_P (orig_arg))
+    /* We already did the appropriate conversion when packing args.  */
+    val = orig_arg;
+  else if (is_type)
     {
       if (requires_tmpl_type)
 	{
-	  if (template_parameter_pack_p (parm) && ARGUMENT_PACK_P (orig_arg))
-	    val = orig_arg;
-	  else if (TREE_CODE (TREE_TYPE (arg)) == UNBOUND_CLASS_TEMPLATE)
+	  if (TREE_CODE (TREE_TYPE (arg)) == UNBOUND_CLASS_TEMPLATE)
 	    /* The number of argument required is not known yet.
 	       Just accept it for now.  */
 	    val = TREE_TYPE (arg);
@@ -7612,10 +7611,6 @@ convert_template_argument (tree parm,
 
       if (tree a = type_uses_auto (t))
 	{
-	  if (ARGUMENT_PACK_P (orig_arg))
-	    /* There's nothing to check for an auto argument pack.  */
-	    return orig_arg;
-
 	  t = do_auto_deduction (t, arg, a, complain, adc_unify, args);
 	  if (t == error_mark_node)
 	    return error_mark_node;
@@ -7626,20 +7621,8 @@ convert_template_argument (tree parm,
       if (invalid_nontype_parm_type_p (t, complain))
 	return error_mark_node;
 
-      if (template_parameter_pack_p (parm) && ARGUMENT_PACK_P (orig_arg))
-	{
-	  if (same_type_p (t, TREE_TYPE (orig_arg)))
-	    val = orig_arg;
-	  else
-	    {
-	      /* Not sure if this is reachable, but it doesn't hurt
-		 to be robust.  */
-	      error ("type mismatch in nontype parameter pack");
-	      val = error_mark_node;
-	    }
-	}
-      else if (!type_dependent_expression_p (orig_arg)
-	       && !uses_template_parms (t))
+      if (!type_dependent_expression_p (orig_arg)
+	  && !uses_template_parms (t))
 	/* We used to call digest_init here.  However, digest_init
 	   will report errors, which we don't want when complain
 	   is zero.  More importantly, digest_init will try too
@@ -7820,8 +7803,6 @@ coerce_template_parameter_pack (tree parms,
   else
     {
       argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
-      TREE_TYPE (argument_pack) 
-        = tsubst (TREE_TYPE (TREE_VALUE (parm)), new_args, complain, in_decl);
       TREE_CONSTANT (argument_pack) = 1;
     }
 
@@ -10802,9 +10783,7 @@ extract_fnparm_pack (tree tmpl_parm, tree *spec_p)
   /* Collect all of the extra "packed" parameters into an
      argument pack.  */
   tree parmvec;
-  tree parmtypevec;
   tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
-  tree argtypepack = cxx_make_type (TYPE_ARGUMENT_PACK);
   tree spec_parm = *spec_p;
   int i, len;
 
@@ -10815,18 +10794,12 @@ extract_fnparm_pack (tree tmpl_parm, tree *spec_p)
 
   /* Fill in PARMVEC and PARMTYPEVEC with all of the parameters.  */
   parmvec = make_tree_vec (len);
-  parmtypevec = make_tree_vec (len);
   spec_parm = *spec_p;
   for (i = 0; i < len; i++, spec_parm = DECL_CHAIN (spec_parm))
-    {
-      TREE_VEC_ELT (parmvec, i) = spec_parm;
-      TREE_VEC_ELT (parmtypevec, i) = TREE_TYPE (spec_parm);
-    }
+    TREE_VEC_ELT (parmvec, i) = spec_parm;
 
   /* Build the argument packs.  */
   SET_ARGUMENT_PACK_ARGS (argpack, parmvec);
-  SET_ARGUMENT_PACK_ARGS (argtypepack, parmtypevec);
-  TREE_TYPE (argpack) = argtypepack;
   *spec_p = spec_parm;
 
   return argpack;
@@ -11568,7 +11541,6 @@ make_argument_pack (tree vec)
   else
     {
       pack = make_node (NONTYPE_ARGUMENT_PACK);
-      TREE_TYPE (pack) = TREE_TYPE (elt);
       TREE_CONSTANT (pack) = 1;
     }
   SET_ARGUMENT_PACK_ARGS (pack, vec);
@@ -11643,26 +11615,16 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
           new_arg = TYPE_P (orig_arg)
             ? cxx_make_type (TREE_CODE (orig_arg))
             : make_node (TREE_CODE (orig_arg));
-          
-          SET_ARGUMENT_PACK_ARGS (
-            new_arg,
-            tsubst_template_args (ARGUMENT_PACK_ARGS (orig_arg),
-                                  args, complain, in_decl));
 
-          if (ARGUMENT_PACK_ARGS (new_arg) == error_mark_node)
+	  tree pack_args = tsubst_template_args (ARGUMENT_PACK_ARGS (orig_arg),
+						 args, complain, in_decl);
+          if (pack_args == error_mark_node)
             new_arg = error_mark_node;
+	  else
+	    SET_ARGUMENT_PACK_ARGS (new_arg, pack_args);
 
-          if (TREE_CODE (new_arg) == NONTYPE_ARGUMENT_PACK) {
-	    if (type_uses_auto (TREE_TYPE (orig_arg)))
-	      TREE_TYPE (new_arg) = TREE_TYPE (orig_arg);
-	    else
-	      TREE_TYPE (new_arg) = tsubst (TREE_TYPE (orig_arg), args,
-					    complain, in_decl);
-            TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg);
-
-            if (TREE_TYPE (new_arg) == error_mark_node)
-              new_arg = error_mark_node;
-          }
+          if (TREE_CODE (new_arg) == NONTYPE_ARGUMENT_PACK)
+	    TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg);
         }
       else
 	new_arg = tsubst_template_arg (orig_arg, args, complain, in_decl);
@@ -12606,10 +12568,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	  {
 	    r = vec;
 	    tree pack = make_node (NONTYPE_ARGUMENT_PACK);
-	    tree tpack = cxx_make_type (TYPE_ARGUMENT_PACK);
 	    SET_ARGUMENT_PACK_ARGS (pack, vec);
-	    SET_ARGUMENT_PACK_ARGS (tpack, expanded_types);
-	    TREE_TYPE (pack) = tpack;
 	    register_specialization (pack, t, args, false, 0);
 	  }
       }
@@ -14081,11 +14040,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
         tree r;
 
 	if (code == NONTYPE_ARGUMENT_PACK)
-	  {
-	    r = make_node (code);
-	    /* Set the already-substituted type.  */
-	    TREE_TYPE (r) = type;
-	  }
+	  r = make_node (code);
 	else
 	  r = cxx_make_type (code);
 
@@ -19222,7 +19177,6 @@ type_unification_real (tree tparms,
 	      if (TREE_CODE (tparm) == TEMPLATE_PARM_INDEX)
 		{
 		  arg = make_node (NONTYPE_ARGUMENT_PACK);
-		  TREE_TYPE (arg)  = TREE_TYPE (TEMPLATE_PARM_DECL (tparm));
 		  TREE_CONSTANT (arg) = 1;
 		}
 	      else
@@ -20019,8 +19973,6 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
           if (TREE_CODE (TREE_PURPOSE (pack)) == TEMPLATE_PARM_INDEX)
             {
               result = make_node (NONTYPE_ARGUMENT_PACK);
-              TREE_TYPE (result) = 
-                TREE_TYPE (TEMPLATE_PARM_DECL (TREE_PURPOSE (pack)));
               TREE_CONSTANT (result) = 1;
             }
           else

Comments

Jason Merrill May 10, 2017, 3:55 p.m. UTC | #1
On Fri, Feb 17, 2017 at 1:41 PM, Jason Merrill <jason@redhat.com> wrote:
> In 79556, we try to deduce an auto type from a dependent initializer
> with null TREE_TYPE, which doesn't work; fixed by catching that case
> in do_auto_deduction.
>
> In 79549, we try to tsubst into the type of a NONTYPE_ARGUMENT_PACK,
> which doesn't make sense for an auto parameter pack; in fact, it
> doesn't make sense for the argument pack to have a type at all.  For
> GCC 7 I'm fixing this by leaving the auto type in place; for GCC 8
> we'll do away with TREE_TYPE on all NONTYPE_ARGUMENT_PACKs.

And now I'm applying the GCC8 patch.

Jason
diff mbox

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 73d6be3..093c0f9 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -25191,6 +25191,10 @@  do_auto_deduction (tree type, tree init, tree auto_node,
     /* C++17 class template argument deduction.  */
     return do_class_deduction (type, tmpl, init, flags, complain);
 
+  if (TREE_TYPE (init) == NULL_TREE)
+    /* Nothing we can do with this, even in deduction context.  */
+    return type;
+
   /* [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
      initializer is a braced-init-list (8.5.4), with
diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto9.C b/gcc/testsuite/g++.dg/cpp1z/nontype-auto9.C
new file mode 100644
index 0000000..2daa346
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto9.C
@@ -0,0 +1,8 @@ 
+// PR c++/79556
+// { dg-options -std=c++1z }
+
+template <auto> struct A;
+template <auto...> struct B;
+template <int N, auto Dim, auto... Dims> struct B<N, Dim, Dims...> {
+  static auto a = A<B<Dims...>::value>::value;
+};