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.
This commit is contained in:
Jason Merrill 2020-01-16 16:55:39 -05:00
parent 1113de9499
commit 5194b51ed9
3 changed files with 89 additions and 7 deletions

View file

@ -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.

View file

@ -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));
}

View file

@ -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);
}