public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] PR c++/93286 - ICE with __is_constructible and variadic template.
@ 2020-01-17  7:03 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2020-01-17  7:03 UTC (permalink / raw)
  To: gcc-patches

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.

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

	* pt.c (tsubst) [TREE_LIST]: Handle pack expansion.
	(tsubst_copy_and_build) [TRAIT_EXPR]: Always use tsubst for type2.
---
 gcc/cp/pt.c                                  | 74 ++++++++++++++++++--
 gcc/testsuite/g++.dg/ext/is_constructible4.C | 18 +++++
 2 files changed, 85 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_constructible4.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9bb8cc13e5f..872f8ff8f52 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 00000000000..6dfe3c01661
--- /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);
+}

base-commit: 801f5b96775288e55193a66a746caab1ddd56f4a
-- 
2.18.1

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-01-17  3:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-17  7:03 [C++ PATCH] PR c++/93286 - ICE with __is_constructible and variadic template Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).