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?
-- >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