From 5194b51ed9714808d88827531e91474895b6c706 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 16 Jan 2020 16:55:39 -0500 Subject: [PATCH] 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. --- 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(-) create mode 100644 gcc/testsuite/g++.dg/ext/is_constructible4.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3ca5d7a11b4..c37e461bcc5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2020-01-16 Jason Merrill + 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 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 using __bool_constant = A; +template +struct B : __bool_constant<__is_constructible(int, _Args...)> {}; +template using enable_if_t = int; +template bool is_constructible_v = B<_Args...>::value; +class C { + template >> + C(_Tp &&); +}; +using Effect_t = C; +void fn1(Effect_t effect) { + int i; + [](int &effect) {}(i); +} -- 2.30.2