]> git.ipfire.org Git - thirdparty/gcc.git/commit
c++: generic targs and identity substitution [PR105956]
authorPatrick Palka <ppalka@redhat.com>
Thu, 7 Jul 2022 20:46:29 +0000 (16:46 -0400)
committerPatrick Palka <ppalka@redhat.com>
Thu, 7 Jul 2022 20:46:29 +0000 (16:46 -0400)
commit7b90f07f778caa5e09f3dc20a8c3da1f4cf60c20
treece5b7e4e6e7f79679efeb04fbe90cda6a3963b69
parent52f538fa4a13d5d439f6db2c2657791fbddd934c
c++: generic targs and identity substitution [PR105956]

In r13-1045-gcb7fd1ea85feea I assumed that substitution into generic
DECL_TI_ARGS corresponds to an identity mapping of the given arguments,
and hence its safe to always elide such substitution.  But this PR
demonstrates that such a substitution isn't always the identity mapping,
in particular when there's an ARGUMENT_PACK_SELECT argument, which gets
handled specially during substitution:

  * when substituting an APS into a template parameter, we strip the
    APS to its underlying argument;
  * and when substituting an APS into a pack expansion, we strip the
    APS to its underlying argument pack.

In this testcase, when expanding the pack expansion pattern (idx + Ns)...
with Ns={0,1}, we specialize idx twice, first with Ns=APS<0,{0,1}> and
then Ns=APS<1,{0,1}>.  The DECL_TI_ARGS of idx are the generic template
arguments of the enclosing class template impl, so before r13-1045,
we'd substitute into its DECL_TI_ARGS which gave Ns={0,1} as desired.
But after r13-1045, we elide this substitution and end up attempting to
hash the original Ns argument, an APS, which ICEs.

So this patch reverts that part of r13-1045.  I considered using
preserve_args in this case instead, but that'd break the static_assert
in the testcase because preserve_args always strips APS to its
underlying argument, but here we want to strip it to its underlying
argument pack, so we'd incorrectly end up forming the specializations
impl<0>::idx and impl<1>::idx instead of impl<0,1>::idx.

Although we can't elide the substitution into DECL_TI_ARGS in light of
ARGUMENT_PACK_SELECT, it should still be safe to elide template argument
coercion in the case of a non-template decl, which this patch preserves.

It's unfortunate that we need to remove this optimization just because
it doesn't hold for one special tree code.  So this patch implements a
heuristic in tsubst_template_args to avoid allocating a new TREE_VEC if
the substituted elements are identical to those of a level from ARGS, as
well as a similar heuristic for tsubst_argument_pack.  It turns out that
about 40% of all calls to tsubst_template_args benefit from this, and it
reduces memory usage by about 4% for e.g. range-v3's zip.cpp (relative to
r13-1045) which more than makes up for the reversion.

PR c++/105956

gcc/cp/ChangeLog:

* pt.cc (template_arg_to_parm): Define.
(tsubst_argument_pack): Try to reuse the corresponding
ARGUMENT_PACK from 'args' when substituting into a generic
ARGUMENT_PACK for a variadic template parameter.
(tsubst_template_args): Move variable declarations closer to
their first use.  Replace 'orig_t' with 'r'.  Rename 'need_new'
to 'const_subst_p'.  Heuristically detect if the substituted
elements are identical to that of a level from 'args' and avoid
allocating a new TREE_VEC if so.  Add sanity check for the
length of the new TREE_VEC, and remove dead ARGUMENT_PACK_P test.
(tsubst_decl) <case TYPE_DECL, case VAR_DECL>: Revert
r13-1045-gcb7fd1ea85feea change for avoiding substitution into
DECL_TI_ARGS, but still avoid coercion in this case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/variadic183.C: New test.
gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp0x/variadic183.C [new file with mode: 0644]