[gcc(refs/vendors/redhat/heads/gcc-10-branch)] PR c++/93286 - ICE with __is_constructible and variadic template.

Jakub Jelinek jakub@gcc.gnu.org
Fri Jan 17 11:51:00 GMT 2020


https://gcc.gnu.org/g:5194b51ed9714808d88827531e91474895b6c706

commit 5194b51ed9714808d88827531e91474895b6c706
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Jan 16 16:55:39 2020 -0500

    PR c++/93286 - ICE with __is_constructible and variadic template.
    
    Here we had been recursing in tsubst_copy_and_build if type2 was a TREE_LIST
    because that function knew how to deal with pack expansions, and tsubst
    didn't.  But tsubst_copy_and_build expects to be dealing with expressions,
    so we crash when trying to convert_from_reference a type.
    
    	* pt.c (tsubst) [TREE_LIST]: Handle pack expansion.
    	(tsubst_copy_and_build) [TRAIT_EXPR]: Always use tsubst for type2.

Diff:
---
 gcc/cp/ChangeLog                             |  4 ++
 gcc/cp/pt.c                                  | 74 +++++++++++++++++++++++++---
 gcc/testsuite/g++.dg/ext/is_constructible4.C | 18 +++++++
 3 files changed, 89 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3ca5d7a..c37e461 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,9 @@
 2020-01-16  Jason Merrill  <jason@redhat.com>
 
+	PR c++/93286 - ICE with __is_constructible and variadic template.
+	* pt.c (tsubst) [TREE_LIST]: Handle pack expansion.
+	(tsubst_copy_and_build) [TRAIT_EXPR]: Always use tsubst for type2.
+
 	PR c++/93280 - ICE with aggregate assignment and DMI.
 	* init.c (get_nsdmi): Set TARGET_EXPR_DIRECT_INIT_P here.
 	* typeck2.c (digest_nsdmi_init): Not here.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9bb8cc1..872f8ff 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15350,6 +15350,71 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	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)
 	  {
@@ -20158,13 +20223,8 @@ tsubst_copy_and_build (tree t,
       {
 	tree type1 = tsubst (TRAIT_EXPR_TYPE1 (t), args,
 			     complain, in_decl);
-
-	tree type2 = TRAIT_EXPR_TYPE2 (t);
-	if (type2 && TREE_CODE (type2) == TREE_LIST)
-	  type2 = RECUR (type2);
-	else if (type2)
-	  type2 = tsubst (type2, args, complain, in_decl);
-
+	tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args,
+			     complain, in_decl);
 	RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t),
 				   TRAIT_EXPR_KIND (t), type1, type2));
       }
diff --git a/gcc/testsuite/g++.dg/ext/is_constructible4.C b/gcc/testsuite/g++.dg/ext/is_constructible4.C
new file mode 100644
index 0000000..6dfe3c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_constructible4.C
@@ -0,0 +1,18 @@
+// PR c++/93286
+// { dg-do compile { target c++14 } }
+
+struct A { static const bool value = true; };
+template <bool> using __bool_constant = A;
+template <typename... _Args>
+struct B : __bool_constant<__is_constructible(int, _Args...)> {};
+template <bool> using enable_if_t = int;
+template <typename... _Args> bool is_constructible_v = B<_Args...>::value;
+class C {
+  template <typename _Tp, typename = enable_if_t<is_constructible_v<_Tp>>>
+  C(_Tp &&);
+};
+using Effect_t = C;
+void fn1(Effect_t effect) {
+  int i;
+  [](int &effect) {}(i);
+}



More information about the Gcc-cvs mailing list