My GCC 10 patch for 93286 fixed the missing piece in tsubst's handling of
lists vs. that in tsubst_copy_and_build, but it would be better to share the
code between them.

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

gcc/cp/ChangeLog
2020-05-15  Jason Merrill  <ja...@redhat.com>

        PR c++/93286 - ICE with __is_constructible and variadic template.
        * pt.c (tsubst_tree_list): New.
        (tsubst, tsubst_copy_and_build): Use it.
        * decl2.c (is_late_template_attribute): Handle error_mark_node args.
---
 gcc/cp/cp-tree.h |   2 +-
 gcc/cp/decl2.c   |   3 +
 gcc/cp/pt.c      | 272 ++++++++++++++++-------------------------------
 3 files changed, 94 insertions(+), 183 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 827b03dd5d5..3f7ded4798f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6953,7 +6953,7 @@ extern tree tsubst_default_argument               (tree, 
int, tree, tree,
                                                 tsubst_flags_t);
 extern tree tsubst (tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_copy_and_build              (tree, tree, tsubst_flags_t,
-                                                tree, bool, bool);
+                                                tree, bool = false, bool = 
false);
 extern tree tsubst_expr                         (tree, tree, tsubst_flags_t,
                                                  tree, bool);
 extern tree tsubst_pack_expansion              (tree, tree, tsubst_flags_t, 
tree);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 4767d53adef..449c86c66c9 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1173,6 +1173,9 @@ is_late_template_attribute (tree attr, tree decl)
       && is_attribute_p ("omp declare simd", name))
     return true;
 
+  if (args == error_mark_node)
+    return false;
+
   /* An attribute pack is clearly dependent.  */
   if (args && PACK_EXPANSION_P (args))
     return true;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bfeeebc2b38..cad5b217f3c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15044,6 +15044,94 @@ tsubst_exception_specification (tree fntype,
   return new_specs;
 }
 
+/* Substitute through a TREE_LIST of types or expressions, handling pack
+   expansions.  */
+
+tree
+tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  if (t == void_list_node)
+    return t;
+
+  tree purpose = TREE_PURPOSE (t);
+  tree purposevec = NULL_TREE;
+  if (!purpose)
+    ;
+  else if (PACK_EXPANSION_P (purpose))
+    {
+      purpose = tsubst_pack_expansion (purpose, args, complain, in_decl);
+      if (TREE_CODE (purpose) == TREE_VEC)
+       purposevec = purpose;
+    }
+  else if (TYPE_P (purpose))
+    purpose = tsubst (purpose, args, complain, in_decl);
+  else
+    purpose = tsubst_copy_and_build (purpose, args, complain, in_decl);
+  if (purpose == error_mark_node || purposevec == error_mark_node)
+    return error_mark_node;
+
+  tree value = TREE_VALUE (t);
+  tree valuevec = NULL_TREE;
+  if (!value)
+    ;
+  else if (PACK_EXPANSION_P (value))
+    {
+      value = tsubst_pack_expansion (value, args, complain, in_decl);
+      if (TREE_CODE (value) == TREE_VEC)
+       valuevec = value;
+    }
+  else if (TYPE_P (value))
+    value = tsubst (value, args, complain, in_decl);
+  else
+    value = tsubst_copy_and_build (value, args, complain, in_decl);
+  if (value == error_mark_node || valuevec == error_mark_node)
+    return error_mark_node;
+
+  tree chain = TREE_CHAIN (t);
+  if (!chain)
+    ;
+  else if (TREE_CODE (chain) == TREE_LIST)
+    chain = tsubst_tree_list (chain, args, complain, in_decl);
+  else if (TYPE_P (chain))
+    chain = tsubst (chain, args, complain, in_decl);
+  else
+    chain = tsubst_copy_and_build (chain, args, complain, in_decl);
+  if (chain == error_mark_node)
+    return error_mark_node;
+
+  if (purpose == TREE_PURPOSE (t)
+      && value == TREE_VALUE (t)
+      && chain == TREE_CHAIN (t))
+    return t;
+
+  int len;
+  /* Determine the number of arguments.  */
+  if (purposevec)
+    {
+      len = TREE_VEC_LENGTH (purposevec);
+      gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
+    }
+  else if (valuevec)
+    len = TREE_VEC_LENGTH (valuevec);
+  else
+    len = 1;
+
+  for (int i = len; i-- > 0; )
+    {
+      if (purposevec)
+       purpose = TREE_VEC_ELT (purposevec, i);
+      if (valuevec)
+       value = TREE_VEC_ELT (valuevec, i);
+
+      if (value && TYPE_P (value))
+       chain = hash_tree_cons (purpose, value, chain);
+      else
+       chain = tree_cons (purpose, value, chain);
+    }
+
+  return chain;
+}
+
 /* Take the tree structure T and replace template parameters used
    therein with the argument vector ARGS.  IN_DECL is an associated
    decl for diagnostics.  If an error occurs, returns ERROR_MARK_NODE.
@@ -15463,104 +15551,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
       }
 
     case TREE_LIST:
-      {
-       tree purpose, value, chain;
-
-       if (t == void_list_node)
-         return t;
-
-       if ((TREE_PURPOSE (t) && PACK_EXPANSION_P (TREE_PURPOSE (t)))
-           || (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t))))
-         {
-           /* We have pack expansions, so expand those and
-              create a new list out of it.  */
-
-           /* Expand the argument expressions.  */
-           tree purposevec = NULL_TREE;
-           if (TREE_PURPOSE (t))
-             purposevec = tsubst_pack_expansion (TREE_PURPOSE (t), args,
-                                                 complain, in_decl);
-           if (purposevec == error_mark_node)
-             return error_mark_node;
-
-           tree valuevec = NULL_TREE;
-           if (TREE_VALUE (t))
-             valuevec = tsubst_pack_expansion (TREE_VALUE (t), args,
-                                               complain, in_decl);
-           if (valuevec == error_mark_node)
-             return error_mark_node;
-
-           /* Build the rest of the list.  */
-           tree chain = TREE_CHAIN (t);
-           if (chain && chain != void_type_node)
-             chain = tsubst (chain, args, complain, in_decl);
-           if (chain == error_mark_node)
-             return error_mark_node;
-
-           /* Determine the number of arguments.  */
-           int len = -1;
-           if (purposevec && TREE_CODE (purposevec) == TREE_VEC)
-             {
-               len = TREE_VEC_LENGTH (purposevec);
-               gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
-             }
-           else if (TREE_CODE (valuevec) == TREE_VEC)
-             len = TREE_VEC_LENGTH (valuevec);
-           else
-             {
-               /* Since we only performed a partial substitution into
-                  the argument pack, we only RETURN (a single list
-                  node.  */
-               if (purposevec == TREE_PURPOSE (t)
-                   && valuevec == TREE_VALUE (t)
-                   && chain == TREE_CHAIN (t))
-                 return t;
-
-               return tree_cons (purposevec, valuevec, chain);
-             }
-
-           /* Convert the argument vectors into a TREE_LIST.  */
-           for (int i = len; i-- > 0; )
-             {
-               purpose = (purposevec ? TREE_VEC_ELT (purposevec, i)
-                          : NULL_TREE);
-               value = (valuevec ? TREE_VEC_ELT (valuevec, i)
-                        : NULL_TREE);
-
-               /* Build the list (backwards).  */
-               chain = hash_tree_cons (purpose, value, chain);
-             }
-
-           return chain;
-         }
-
-       purpose = TREE_PURPOSE (t);
-       if (purpose)
-         {
-           purpose = tsubst (purpose, args, complain, in_decl);
-           if (purpose == error_mark_node)
-             return error_mark_node;
-         }
-       value = TREE_VALUE (t);
-       if (value)
-         {
-           value = tsubst (value, args, complain, in_decl);
-           if (value == error_mark_node)
-             return error_mark_node;
-         }
-       chain = TREE_CHAIN (t);
-       if (chain && chain != void_type_node)
-         {
-           chain = tsubst (chain, args, complain, in_decl);
-           if (chain == error_mark_node)
-             return error_mark_node;
-         }
-       if (purpose == TREE_PURPOSE (t)
-           && value == TREE_VALUE (t)
-           && chain == TREE_CHAIN (t))
-         return t;
-       return hash_tree_cons (purpose, value, chain);
-      }
+      return tsubst_tree_list (t, args, complain, in_decl);
 
     case TREE_BINFO:
       /* We should never be tsubsting a binfo.  */
@@ -20078,90 +20069,7 @@ tsubst_copy_and_build (tree t,
       }
 
     case TREE_LIST:
-      {
-       tree purpose, value, chain;
-
-       if (t == void_list_node)
-         RETURN (t);
-
-        if ((TREE_PURPOSE (t) && PACK_EXPANSION_P (TREE_PURPOSE (t)))
-            || (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t))))
-          {
-            /* We have pack expansions, so expand those and
-               create a new list out of it.  */
-            tree purposevec = NULL_TREE;
-            tree valuevec = NULL_TREE;
-            tree chain;
-            int i, len = -1;
-
-            /* Expand the argument expressions.  */
-            if (TREE_PURPOSE (t))
-              purposevec = tsubst_pack_expansion (TREE_PURPOSE (t), args,
-                                                 complain, in_decl);
-            if (TREE_VALUE (t))
-              valuevec = tsubst_pack_expansion (TREE_VALUE (t), args,
-                                               complain, in_decl);
-
-            /* Build the rest of the list.  */
-            chain = TREE_CHAIN (t);
-            if (chain && chain != void_type_node)
-              chain = RECUR (chain);
-
-            /* Determine the number of arguments.  */
-            if (purposevec && TREE_CODE (purposevec) == TREE_VEC)
-              {
-                len = TREE_VEC_LENGTH (purposevec);
-                gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
-              }
-            else if (TREE_CODE (valuevec) == TREE_VEC)
-              len = TREE_VEC_LENGTH (valuevec);
-            else
-              {
-                /* Since we only performed a partial substitution into
-                   the argument pack, we only RETURN (a single list
-                   node.  */
-                if (purposevec == TREE_PURPOSE (t)
-                    && valuevec == TREE_VALUE (t)
-                    && chain == TREE_CHAIN (t))
-                  RETURN (t);
-
-                RETURN (tree_cons (purposevec, valuevec, chain));
-              }
-
-            /* Convert the argument vectors into a TREE_LIST */
-            i = len;
-            while (i > 0)
-              {
-                /* Grab the Ith values.  */
-                i--;
-                purpose = purposevec ? TREE_VEC_ELT (purposevec, i) 
-                                    : NULL_TREE;
-                value 
-                 = valuevec ? convert_from_reference (TREE_VEC_ELT (valuevec, 
i))
-                             : NULL_TREE;
-
-                /* Build the list (backwards).  */
-                chain = tree_cons (purpose, value, chain);
-              }
-
-            RETURN (chain);
-          }
-
-       purpose = TREE_PURPOSE (t);
-       if (purpose)
-         purpose = RECUR (purpose);
-       value = TREE_VALUE (t);
-       if (value)
-         value = RECUR (value);
-       chain = TREE_CHAIN (t);
-       if (chain && chain != void_type_node)
-         chain = RECUR (chain);
-       if (purpose == TREE_PURPOSE (t)
-           && value == TREE_VALUE (t)
-           && chain == TREE_CHAIN (t))
-         RETURN (t);
-       RETURN (tree_cons (purpose, value, chain));
-      }
+      RETURN (tsubst_tree_list (t, args, complain, in_decl));
 
     case COMPONENT_REF:
       {

base-commit: 4c1a5d8b71e29b71e0bc1004480c12c5fc427cb7
-- 
2.18.1

Reply via email to