https://gcc.gnu.org/g:3945c6bd7e5d2ba8c776eb94814e4b95f08f3e05

commit r15-10554-g3945c6bd7e5d2ba8c776eb94814e4b95f08f3e05
Author: Marek Polacek <[email protected]>
Date:   Mon Nov 24 17:31:22 2025 -0500

    c++: fix crash with pack indexing in noexcept [PR121325]
    
    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]>
    (cherry picked from commit 856fae983bca6a934b74f47c7cd21e6919035fc0)

Diff:
---
 gcc/cp/pt.cc                                 | 21 +++++++++++++++++-
 gcc/testsuite/g++.dg/cpp26/pack-indexing18.C | 32 ++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 04f1d02e030b..a245b6ef7490 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14093,6 +14093,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
@@ -14110,7 +14129,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 000000000000..d3e3730408cb
--- /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>)));
+}

Reply via email to