diff options
author | Jason Merrill <jason@redhat.com> | 2020-01-16 16:55:39 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2020-01-16 22:24:28 -0500 |
commit | 5194b51ed9714808d88827531e91474895b6c706 (patch) | |
tree | 1676c1dcbae6a4b3468682a5b9596653f6d88db9 /gcc | |
parent | 1113de9499dadd2402fa97d0009d5d0b5af0987b (diff) | |
download | gcc-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/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/cp/pt.c | 74 | ||||
-rw-r--r-- | 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); +} |