From cda6396a1b6e6bba2a3b0847931567c3458f2184 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 15 May 2020 14:06:48 -0400 Subject: [PATCH] PR c++/93286 - ICE with __is_constructible and variadic template. My GCC 10 patch for 93286 fixed the missing piece in tsubst's handling of lists vs. that in tsubst_copy_and_build, but it would be better to share the code between them. gcc/cp/ChangeLog 2020-05-15 Jason Merrill PR c++/93286 - ICE with __is_constructible and variadic template. * pt.c (tsubst_tree_list): New. (tsubst, tsubst_copy_and_build): Use it. * decl2.c (is_late_template_attribute): Handle error_mark_node args. --- gcc/cp/ChangeLog | 7 ++ gcc/cp/cp-tree.h | 2 +- gcc/cp/decl2.c | 3 + gcc/cp/pt.c | 272 ++++++++++++++++------------------------------- 4 files changed, 101 insertions(+), 183 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 37705f9f93d..732be07c9c0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2020-05-15 Jason Merrill + + PR c++/93286 - ICE with __is_constructible and variadic template. + * pt.c (tsubst_tree_list): New. + (tsubst, tsubst_copy_and_build): Use it. + * decl2.c (is_late_template_attribute): Handle error_mark_node args. + 2020-05-15 Nathan Sidwell * pt.c (template_args_equal): Fix thinkos in previous 'cleanup'. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 827b03dd5d5..3f7ded4798f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6953,7 +6953,7 @@ extern tree tsubst_default_argument (tree, int, tree, tree, tsubst_flags_t); extern tree tsubst (tree, tree, tsubst_flags_t, tree); extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, - tree, bool, bool); + tree, bool = false, bool = false); extern tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool); extern tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 4767d53adef..449c86c66c9 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1173,6 +1173,9 @@ is_late_template_attribute (tree attr, tree decl) && is_attribute_p ("omp declare simd", name)) return true; + if (args == error_mark_node) + return false; + /* An attribute pack is clearly dependent. */ if (args && PACK_EXPANSION_P (args)) return true; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bfeeebc2b38..cad5b217f3c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -15044,6 +15044,94 @@ tsubst_exception_specification (tree fntype, return new_specs; } +/* Substitute through a TREE_LIST of types or expressions, handling pack + expansions. */ + +tree +tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl) +{ + if (t == void_list_node) + return t; + + tree purpose = TREE_PURPOSE (t); + tree purposevec = NULL_TREE; + if (!purpose) + ; + else if (PACK_EXPANSION_P (purpose)) + { + purpose = tsubst_pack_expansion (purpose, args, complain, in_decl); + if (TREE_CODE (purpose) == TREE_VEC) + purposevec = purpose; + } + else if (TYPE_P (purpose)) + purpose = tsubst (purpose, args, complain, in_decl); + else + purpose = tsubst_copy_and_build (purpose, args, complain, in_decl); + if (purpose == error_mark_node || purposevec == error_mark_node) + return error_mark_node; + + tree value = TREE_VALUE (t); + tree valuevec = NULL_TREE; + if (!value) + ; + else if (PACK_EXPANSION_P (value)) + { + value = tsubst_pack_expansion (value, args, complain, in_decl); + if (TREE_CODE (value) == TREE_VEC) + valuevec = value; + } + else if (TYPE_P (value)) + value = tsubst (value, args, complain, in_decl); + else + value = tsubst_copy_and_build (value, args, complain, in_decl); + if (value == error_mark_node || valuevec == error_mark_node) + return error_mark_node; + + tree chain = TREE_CHAIN (t); + if (!chain) + ; + else if (TREE_CODE (chain) == TREE_LIST) + chain = tsubst_tree_list (chain, args, complain, in_decl); + else if (TYPE_P (chain)) + chain = tsubst (chain, args, complain, in_decl); + else + chain = tsubst_copy_and_build (chain, args, complain, in_decl); + if (chain == error_mark_node) + return error_mark_node; + + if (purpose == TREE_PURPOSE (t) + && value == TREE_VALUE (t) + && chain == TREE_CHAIN (t)) + return t; + + int len; + /* Determine the number of arguments. */ + if (purposevec) + { + len = TREE_VEC_LENGTH (purposevec); + gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec)); + } + else if (valuevec) + len = TREE_VEC_LENGTH (valuevec); + else + len = 1; + + for (int i = len; i-- > 0; ) + { + if (purposevec) + purpose = TREE_VEC_ELT (purposevec, i); + if (valuevec) + value = TREE_VEC_ELT (valuevec, i); + + if (value && TYPE_P (value)) + chain = hash_tree_cons (purpose, value, chain); + else + chain = tree_cons (purpose, value, chain); + } + + return chain; +} + /* Take the tree structure T and replace template parameters used therein with the argument vector ARGS. IN_DECL is an associated decl for diagnostics. If an error occurs, returns ERROR_MARK_NODE. @@ -15463,104 +15551,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) } case TREE_LIST: - { - tree purpose, value, chain; - - 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) - { - purpose = tsubst (purpose, args, complain, in_decl); - if (purpose == error_mark_node) - return error_mark_node; - } - value = TREE_VALUE (t); - if (value) - { - value = tsubst (value, args, complain, in_decl); - if (value == error_mark_node) - return error_mark_node; - } - 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; - } - if (purpose == TREE_PURPOSE (t) - && value == TREE_VALUE (t) - && chain == TREE_CHAIN (t)) - return t; - return hash_tree_cons (purpose, value, chain); - } + return tsubst_tree_list (t, args, complain, in_decl); case TREE_BINFO: /* We should never be tsubsting a binfo. */ @@ -20078,90 +20069,7 @@ tsubst_copy_and_build (tree t, } case TREE_LIST: - { - tree purpose, value, chain; - - 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. */ - tree purposevec = NULL_TREE; - tree valuevec = NULL_TREE; - tree chain; - int i, len = -1; - - /* Expand the argument expressions. */ - if (TREE_PURPOSE (t)) - purposevec = tsubst_pack_expansion (TREE_PURPOSE (t), args, - complain, in_decl); - if (TREE_VALUE (t)) - valuevec = tsubst_pack_expansion (TREE_VALUE (t), args, - complain, in_decl); - - /* Build the rest of the list. */ - chain = TREE_CHAIN (t); - if (chain && chain != void_type_node) - chain = RECUR (chain); - - /* Determine the number of arguments. */ - 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 */ - i = len; - while (i > 0) - { - /* Grab the Ith values. */ - i--; - purpose = purposevec ? TREE_VEC_ELT (purposevec, i) - : NULL_TREE; - value - = valuevec ? convert_from_reference (TREE_VEC_ELT (valuevec, i)) - : NULL_TREE; - - /* Build the list (backwards). */ - chain = tree_cons (purpose, value, chain); - } - - RETURN (chain); - } - - purpose = TREE_PURPOSE (t); - if (purpose) - purpose = RECUR (purpose); - value = TREE_VALUE (t); - if (value) - value = RECUR (value); - chain = TREE_CHAIN (t); - if (chain && chain != void_type_node) - chain = RECUR (chain); - if (purpose == TREE_PURPOSE (t) - && value == TREE_VALUE (t) - && chain == TREE_CHAIN (t)) - RETURN (t); - RETURN (tree_cons (purpose, value, chain)); - } + RETURN (tsubst_tree_list (t, args, complain, in_decl)); case COMPONENT_REF: { -- 2.30.2