aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2020-01-16 16:55:39 -0500
committerJason Merrill <jason@redhat.com>2020-01-16 22:24:28 -0500
commit5194b51ed9714808d88827531e91474895b6c706 (patch)
tree1676c1dcbae6a4b3468682a5b9596653f6d88db9 /gcc
parent1113de9499dadd2402fa97d0009d5d0b5af0987b (diff)
downloadgcc-5194b51ed9714808d88827531e91474895b6c706.zip
gcc-5194b51ed9714808d88827531e91474895b6c706.tar.gz
gcc-5194b51ed9714808d88827531e91474895b6c706.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/pt.c74
-rw-r--r--gcc/testsuite/g++.dg/ext/is_constructible4.C18
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);
+}