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