On Wed, 26 Nov 2025, Marek Polacek wrote: > On Wed, Nov 26, 2025 at 01:29:35PM -0500, Patrick Palka wrote: > > On Wed, 26 Nov 2025, Patrick Palka wrote: > > > > > On Wed, 26 Nov 2025, Marek Polacek wrote: > > > > > > > On Mon, Nov 24, 2025 at 08:20:10PM -0500, Patrick Palka wrote: > > > > > On Mon, 24 Nov 2025, Marek Polacek wrote: > > > > > > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/15? > > > > > > > > > > > > -- >8 -- > > > > > > In my r15-6792 patch I added a call to tsubst in tsubst_pack_index > > > > > > to fully instantiate args#N in the pack. > > > > > > > > > > > > Here we are in an unevaluated context, but since the pack is > > > > > > a TREE_VEC, we call tsubst_template_args which has cp_evaluated > > > > > > at the beginning. That causes a crash because we trip on the > > > > > > assert in tsubst_expr/PARM_DECL: > > > > > > > > > > > > gcc_assert (cp_unevaluated_operand); > > > > > > > > > > > > because retrieve_local_specialization didn't find anything (becase > > > > > > there are no local_specializations yet). > > > > > > > > > > > > ISTM that we don't need a full instantiation in an unevaluated > > > > > > context > > > > > > so we can avoid the crash like this. > > > > > > > > > > Hmm, it doesn't seem right to avoid doing a substitution solely > > > > > because > > > > > we're in an unevaluated context.. > > > > > > > > > > Here the TREE_VEC is just a subexpression of the templated > > > > > PACK_INDEX_EXPR, not a template argument list, so we should still > > > > > substitute it normally, just without setting cp_evaluated, I think. > > > > > > > > I think you're right. How about I just walk the TREE_VEC and subst > > > > each element, like this? > > > > > > In-place modification of a templated tree is unusual for tsubst, we > > > probably should just return a new TREE_VEC. I think we could use a > > > version of tsubst_template_args that doesn't do cp_evaluated > > > (tsubst_tree_vec?), define tsubst_template_args in terms of that, and > > > also use it here? > > > > Actually never mind about the idea of defining tsubst_template_args > > in terms of tsubst_tree_vec... tsubst_template_args does a lot of > > stuff that's specific to template arguments which wouldn't be suitable > > for TREE_VEC expression substitution. I suppose we could just use a > > standalone tsubst_tree_vec routine that tsubsts each element and returns > > a new TREE_VEC. > > Fair enough. > > > (I believe TRAIT_EXPR is another tree that has a TREE_VEC subexpression > > and probably has a similiar bug wrt cp_evaluated being set, so we could > > use tsubst_tree_vec there as well.) > > I've not done that yet. > > How does this look? Thanks, > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK, thanks! > > -- >8 -- > In my r15-6792 patch I added a call to tsubst in tsubst_pack_index > to fully instantiate args#N in the pack. > > Here we are in an unevaluated context, but since the pack is > a TREE_VEC, we call tsubst_template_args which has cp_evaluated > at the beginning. That causes a crash because we trip on the > assert in tsubst_expr/PARM_DECL: > > gcc_assert (cp_unevaluated_operand); > > because retrieve_local_specialization didn't find anything (becase > there are no local_specializations yet). > > We can avoid the cp_evaluated by calling the new tsubst_tree_vec, > which creates a new TREE_VEC and substitutes each element. > > PR c++/121325 > > gcc/cp/ChangeLog: > > * pt.cc (tsubst_tree_vec): New. > (tsubst_pack_index): Call it. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp26/pack-indexing18.C: New test. > > Reviewed-by: Patrick Palka <[email protected]> > --- > gcc/cp/pt.cc | 21 ++++++++++++- > gcc/testsuite/g++.dg/cpp26/pack-indexing18.C | 32 ++++++++++++++++++++ > 2 files changed, 52 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing18.C > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index e74e34d8149..4dc8f980d0d 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -14203,6 +14203,25 @@ tsubst_pack_expansion (tree t, tree args, > tsubst_flags_t complain, > return result; > } > > +/* Substitute ARGS into T, which is a TREE_VEC. This function creates a new > + TREE_VEC rather than substituting the elements in-place. */ > + > +static tree > +tsubst_tree_vec (tree t, tree args, tsubst_flags_t complain, tree in_decl) > +{ > + const int len = TREE_VEC_LENGTH (t); > + tree r = make_tree_vec (len); > + for (int i = 0; i < len; ++i) > + { > + tree arg = TREE_VEC_ELT (t, i); > + if (TYPE_P (arg)) > + TREE_VEC_ELT (r, i) = tsubst (arg, args, complain, in_decl); > + else > + TREE_VEC_ELT (r, i) = tsubst_expr (arg, args, complain, in_decl); > + } > + return r; > +} > + > /* Substitute ARGS into T, which is a pack index (i.e., PACK_INDEX_TYPE or > PACK_INDEX_EXPR). Returns a single type or expression, a PACK_INDEX_* > node if only a partial substitution could be performed, or ERROR_MARK_NODE > @@ -14220,7 +14239,7 @@ tsubst_pack_index (tree t, tree args, tsubst_flags_t > complain, tree in_decl) > a partially instantiated closure. Let tsubst find the > fully-instantiated one. */ > gcc_assert (TREE_CODE (pack) == TREE_VEC); > - pack = tsubst (pack, args, complain, in_decl); > + pack = tsubst_tree_vec (pack, args, complain, in_decl); > } > if (TREE_CODE (pack) == TREE_VEC && TREE_VEC_LENGTH (pack) == 0) > { > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing18.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing18.C > new file mode 100644 > index 00000000000..d3e3730408c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing18.C > @@ -0,0 +1,32 @@ > +// PR c++/121325 > +// { dg-do compile { target c++26 } } > + > +void f(auto... a) requires requires { []<int i = 0> > noexcept(noexcept(a...[i])) { }(); } {} > +void g(auto... a) requires requires { []<int i = 0> { > static_assert(noexcept(a...[i])); }(); } {} > + > +void > +h () > +{ > + f (0); > + g (0); > +} > + > +void foo () {} > +void bar () noexcept {} > +template<bool B> > +void baz () noexcept(B) {} > + > +template<typename... Ts> > +void > +x (Ts... ts) noexcept (noexcept (ts...[0]())) > +{ > +} > + > +void > +y () > +{ > + static_assert (!noexcept (x (foo))); > + static_assert (noexcept (x (bar))); > + static_assert (noexcept (x (baz<true>))); > + static_assert (!noexcept (x (baz<false>))); > +} > > base-commit: e97550a7d0e1a8b31a76b0877c0e90a0163da7ee > -- > 2.51.1 > >
