diff options
-rw-r--r-- | gcc/cp/pt.cc | 202 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/variadic183.C | 14 |
2 files changed, 152 insertions, 64 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 8672da1..59ee50c 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see Fixed by: C++20 modules. */ #include "config.h" +#define INCLUDE_ALGORITHM // for std::equal #include "system.h" #include "coretypes.h" #include "cp-tree.h" @@ -4916,6 +4917,32 @@ template_parm_to_arg (tree t) return t; } +/* If T looks like a generic template argument produced by template_parm_to_arg, + return the corresponding template parameter, otherwise return NULL_TREE. */ + +static tree +template_arg_to_parm (tree t) +{ + if (t == NULL_TREE) + return NULL_TREE; + + if (ARGUMENT_PACK_P (t)) + { + tree args = ARGUMENT_PACK_ARGS (t); + if (TREE_VEC_LENGTH (args) == 1 + && PACK_EXPANSION_P (TREE_VEC_ELT (args, 0))) + t = PACK_EXPANSION_PATTERN (TREE_VEC_ELT (args, 0)); + } + + if (REFERENCE_REF_P (t)) + t = TREE_OPERAND (t, 0); + + if (TEMPLATE_PARM_P (t)) + return t; + else + return NULL_TREE; +} + /* Given a single level of template parameters (a TREE_VEC), return it as a set of template arguments. */ @@ -13516,26 +13543,49 @@ tree tsubst_argument_pack (tree orig_arg, tree args, tsubst_flags_t complain, tree in_decl) { + /* This flag is used only during deduction, and we don't expect to + substitute such ARGUMENT_PACKs. */ + gcc_assert (!ARGUMENT_PACK_INCOMPLETE_P (orig_arg)); + /* Substitute into each of the arguments. */ tree pack_args = tsubst_template_args (ARGUMENT_PACK_ARGS (orig_arg), args, complain, in_decl); - tree new_arg = error_mark_node; - if (pack_args != error_mark_node) - { - if (TYPE_P (orig_arg)) - { - new_arg = cxx_make_type (TREE_CODE (orig_arg)); - SET_TYPE_STRUCTURAL_EQUALITY (new_arg); - } - else - { - new_arg = make_node (TREE_CODE (orig_arg)); - TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg); - } + if (pack_args == error_mark_node) + return error_mark_node; - ARGUMENT_PACK_ARGS (new_arg) = pack_args; + if (pack_args == ARGUMENT_PACK_ARGS (orig_arg)) + return orig_arg; + + /* If we're substituting into a generic ARGUMENT_PACK for a variadic + template parameter, we might be able to avoid allocating a new + ARGUMENT_PACK and reuse the corresponding ARGUMENT_PACK from ARGS + if the substituted result is identical to it. */ + if (tree parm = template_arg_to_parm (orig_arg)) + { + int level, index; + template_parm_level_and_index (parm, &level, &index); + if (TMPL_ARGS_DEPTH (args) >= level) + if (tree arg = TMPL_ARG (args, level, index)) + if (TREE_CODE (arg) == TREE_CODE (orig_arg) + && ARGUMENT_PACK_ARGS (arg) == pack_args) + { + gcc_assert (!ARGUMENT_PACK_INCOMPLETE_P (arg)); + return arg; + } } + tree new_arg; + if (TYPE_P (orig_arg)) + { + new_arg = cxx_make_type (TREE_CODE (orig_arg)); + SET_TYPE_STRUCTURAL_EQUALITY (new_arg); + } + else + { + new_arg = make_node (TREE_CODE (orig_arg)); + TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg); + } + ARGUMENT_PACK_ARGS (new_arg) = pack_args; return new_arg; } @@ -13544,17 +13594,17 @@ tsubst_argument_pack (tree orig_arg, tree args, tsubst_flags_t complain, tree tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) { - tree orig_t = t; - int len, need_new = 0, i, expanded_len_adjust = 0, out; - tree *elts; - if (t == error_mark_node) return error_mark_node; - len = TREE_VEC_LENGTH (t); - elts = XALLOCAVEC (tree, len); + const int len = TREE_VEC_LENGTH (t); + tree *elts = XALLOCAVEC (tree, len); + int expanded_len_adjust = 0; - for (i = 0; i < len; i++) + /* True iff the substituted result is identical to T. */ + bool const_subst_p = true; + + for (int i = 0; i < len; i++) { tree orig_arg = TREE_VEC_ELT (t, i); tree new_arg; @@ -13587,49 +13637,84 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) elts[i] = new_arg; if (new_arg != orig_arg) - need_new = 1; + const_subst_p = false; } - if (!need_new) + if (const_subst_p) return t; + tree maybe_reuse = NULL_TREE; + + /* If ARGS and T are both multi-level, the substituted result may be + identical to ARGS. */ + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (t) + && TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) + && TMPL_ARGS_DEPTH (t) == TMPL_ARGS_DEPTH (args)) + maybe_reuse = args; + /* If T appears to be a vector of generic template arguments, the + substituted result may be identical to the corresponding level + from ARGS. */ + else if (tree parm = template_arg_to_parm (TREE_VEC_ELT (t, 0))) + { + int level, index; + template_parm_level_and_index (parm, &level, &index); + if (index == 0 && TMPL_ARGS_DEPTH (args) >= level) + maybe_reuse = TMPL_ARGS_LEVEL (args, level); + } + + /* If the substituted result is identical to MAYBE_REUSE, return + it and avoid allocating a new TREE_VEC, as an optimization. */ + if (maybe_reuse != NULL_TREE + && TREE_VEC_LENGTH (maybe_reuse) == len + && std::equal (elts, elts+len, TREE_VEC_BEGIN (maybe_reuse))) + return maybe_reuse; + + /* If T consists of only a pack expansion for which substitution yielded + a TREE_VEC of the expanded elements, then reuse that TREE_VEC instead + of effectively making a copy. */ + if (len == 1 + && PACK_EXPANSION_P (TREE_VEC_ELT (t, 0)) + && TREE_CODE (elts[0]) == TREE_VEC) + return elts[0]; + /* Make space for the expanded arguments coming from template argument packs. */ - t = make_tree_vec (len + expanded_len_adjust); - /* ORIG_T can contain TREE_VECs. That happens if ORIG_T contains the + tree r = make_tree_vec (len + expanded_len_adjust); + /* T can contain TREE_VECs. That happens if T contains the arguments for a member template. - In that case each TREE_VEC in ORIG_T represents a level of template - arguments, and ORIG_T won't carry any non defaulted argument count. + In that case each TREE_VEC in T represents a level of template + arguments, and T won't carry any non defaulted argument count. It will rather be the nested TREE_VECs that will carry one. - In other words, ORIG_T carries a non defaulted argument count only + In other words, T carries a non defaulted argument count only if it doesn't contain any nested TREE_VEC. */ - if (NON_DEFAULT_TEMPLATE_ARGS_COUNT (orig_t)) + if (NON_DEFAULT_TEMPLATE_ARGS_COUNT (t)) { - int count = GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (orig_t); + int count = GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (t); count += expanded_len_adjust; - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (t, count); + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (r, count); } - for (i = 0, out = 0; i < len; i++) + + int out = 0; + for (int i = 0; i < len; i++) { - tree orig_arg = TREE_VEC_ELT (orig_t, i); + tree orig_arg = TREE_VEC_ELT (t, i); if (orig_arg - && (PACK_EXPANSION_P (orig_arg) || ARGUMENT_PACK_P (orig_arg)) + && PACK_EXPANSION_P (orig_arg) && TREE_CODE (elts[i]) == TREE_VEC) { - int idx; - /* Now expand the template argument pack "in place". */ - for (idx = 0; idx < TREE_VEC_LENGTH (elts[i]); idx++, out++) - TREE_VEC_ELT (t, out) = TREE_VEC_ELT (elts[i], idx); + for (int idx = 0; idx < TREE_VEC_LENGTH (elts[i]); idx++, out++) + TREE_VEC_ELT (r, out) = TREE_VEC_ELT (elts[i], idx); } else { - TREE_VEC_ELT (t, out) = elts[i]; + TREE_VEC_ELT (r, out) = elts[i]; out++; } } + gcc_assert (out == TREE_VEC_LENGTH (r)); - return t; + return r; } /* Substitute ARGS into one level PARMS of template parameters. */ @@ -14965,32 +15050,21 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (!spec) { - int args_depth = TMPL_ARGS_DEPTH (args); - int parms_depth = TMPL_ARGS_DEPTH (DECL_TI_ARGS (t)); tmpl = DECL_TI_TEMPLATE (t); gen_tmpl = most_general_template (tmpl); - if (args_depth == parms_depth - && !PRIMARY_TEMPLATE_P (gen_tmpl)) - /* The DECL_TI_ARGS in this case are the generic template - arguments for the enclosing class template, so we can - shortcut substitution (which would just be the identity - mapping). */ - argvec = args; - else - { - argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl); - /* Coerce the innermost arguments again if necessary. If - there's fewer levels of args than of parms, then the - substitution could not have changed the innermost args - (modulo level lowering). */ - if (args_depth >= parms_depth && argvec != error_mark_node) - argvec = (coerce_innermost_template_parms - (DECL_TEMPLATE_PARMS (gen_tmpl), - argvec, t, complain, - /*all*/true, /*defarg*/true)); - if (argvec == error_mark_node) - RETURN (error_mark_node); - } + argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl); + if (argvec != error_mark_node + && PRIMARY_TEMPLATE_P (gen_tmpl) + && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec)) + /* We're fully specializing a template declaration, so + we need to coerce the innermost arguments corresponding to + the template. */ + argvec = (coerce_innermost_template_parms + (DECL_TEMPLATE_PARMS (gen_tmpl), + argvec, t, complain, + /*all*/true, /*defarg*/true)); + if (argvec == error_mark_node) + RETURN (error_mark_node); hash = spec_hasher::hash (gen_tmpl, argvec); spec = retrieve_specialization (gen_tmpl, argvec, hash); } diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic183.C b/gcc/testsuite/g++.dg/cpp0x/variadic183.C new file mode 100644 index 0000000..27444eb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic183.C @@ -0,0 +1,14 @@ +// PR c++/105956 +// { dg-do compile { target c++11 } } + +template<int...> struct list; + +template<int... Ns> struct impl { + static const int idx = 0; + using type = list<(idx + Ns)...>; + + static constexpr const int* a[2] = {(Ns, &idx)...}; + static_assert(a[0] == &idx && a[1] == &idx, ""); +}; + +template struct impl<0, 1>; |