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.

> 
>       PR c++/121325
> 
> gcc/cp/ChangeLog:
> 
>       * pt.cc (tsubst_pack_index): Don't call tsubst in an unevaluated
>       context.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp26/pack-indexing18.C: New test.
> ---
>  gcc/cp/pt.cc                                 |  7 +++--
>  gcc/testsuite/g++.dg/cpp26/pack-indexing18.C | 32 ++++++++++++++++++++
>  2 files changed, 37 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing18.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index c418edc6931..1e3cb6ac32d 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -14215,11 +14215,14 @@ tsubst_pack_index (tree t, tree args, 
> tsubst_flags_t complain, tree in_decl)
>    tree pack = PACK_INDEX_PACK (t);
>    if (PACK_EXPANSION_P (pack))
>      pack = tsubst_pack_expansion (pack, args, complain, in_decl);
> -  else
> +  else if (!cp_unevaluated_operand)
>      {
>        /* PACK can be {*args#0} whose args#0's value-expr refers to
>        a partially instantiated closure.  Let tsubst find the
> -      fully-instantiated one.  */
> +      fully-instantiated one.  In an unevaluated context we don't
> +      call this because tsubst_template_args switches back to
> +      evaluated context immediately, and we may have parameters
> +      without local specializations.  */
>        gcc_assert (TREE_CODE (pack) == TREE_VEC);
>        pack = tsubst (pack, args, complain, in_decl);
>      }
> 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: a2f4b0466be29c853c32498ae49c1acfa1594f30
> -- 
> 2.51.1
> 
> 

Reply via email to