https://gcc.gnu.org/g:cc85998ba7984e43c1d89d47dfbfc219c142fddf

commit r16-3429-gcc85998ba7984e43c1d89d47dfbfc219c142fddf
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Thu Aug 28 10:46:51 2025 +0200

    c++: Fix ICE with parameter uses in expansion stmts [PR121575]
    
    The following testcase shows an ICE when a parameter of a non-template
    function is referenced in expansion stmt body.
    
    tsubst_expr in that case assumes that either the PARM_DECL has registered
    local specialization, or is this argument or it is in unevaluated context.
    Parameters are always defined outside of the expansion statement
    for-range-declaration or body, so for the instantiation of the body
    outside of templates should always map to themselves.
    It could be fixed by registering local self-specializations for all the
    function parameters, but just handling it in tsubst_expr seems to be easier
    and less costly.
    Some PARM_DECLs, e.g. from concepts, have NULL DECL_CONTEXT, those are
    handled like before (and assert it is unevaluated operand), for others
    this checks if the PARM_DECL is from a non-template and in that case it
    will just return t.
    
    2025-08-28  Jakub Jelinek  <ja...@redhat.com>
                Jason Merrill  <ja...@redhat.com>
    
            PR c++/121575
            * pt.cc (tsubst_expr) <case PARM_DECL>: If DECL_CONTEXT (t) isn't a
            template return t for PARM_DECLs without local specialization.
    
            * g++.dg/cpp26/expansion-stmt20.C: New test.

Diff:
---
 gcc/cp/pt.cc                                  |  5 +++
 gcc/testsuite/g++.dg/cpp26/expansion-stmt20.C | 59 +++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d628744dbfd1..9b79267d16b3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -22321,6 +22321,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
              if (DECL_NAME (t) == this_identifier && current_class_ptr)
                RETURN (current_class_ptr);
 
+             /* Parameters of non-templates map to themselves (e.g. in
+                expansion statement body).  */
+             if (DECL_CONTEXT (t) && !uses_template_parms (DECL_CONTEXT (t)))
+               RETURN (t);
+
              /* This can happen for a parameter name used later in a function
                 declaration (such as in a late-specified return type).  Just
                 make a dummy decl, since it's only used for its type.  */
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt20.C 
b/gcc/testsuite/g++.dg/cpp26/expansion-stmt20.C
new file mode 100644
index 000000000000..4cc0b3853819
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt20.C
@@ -0,0 +1,59 @@
+// PR c++/121575
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+struct A { int x, y; };
+int c;
+
+void
+qux (A p)
+{
+  if (p.x != 1 || p.y != 3)
+    __builtin_abort ();
+  ++c;
+}
+
+void
+foo ()
+{
+  A p { 1, 3 };
+  template for (auto _ : {})                   // { dg-warning "'template for' 
only available with" "" { target c++23_down } }
+    qux (p);
+  template for (auto _ : { 0 })                        // { dg-warning 
"'template for' only available with" "" { target c++23_down } }
+    qux (p);
+}
+
+void
+bar (A p)
+{
+  template for (auto _ : {})                   // { dg-warning "'template for' 
only available with" "" { target c++23_down } }
+    qux (p);
+  template for (auto _ : { 0, 1 })             // { dg-warning "'template for' 
only available with" "" { target c++23_down } }
+    qux (p);
+}
+
+A
+baz ()
+{
+  A p { 1, 3 };
+  template for (auto _ : {})                   // { dg-warning "'template for' 
only available with" "" { target c++23_down } }
+    qux (p);
+  template for (auto _ : { 0, 1, 2 })          // { dg-warning "'template for' 
only available with" "" { target c++23_down } }
+    qux (p);
+  return p;
+}
+
+int
+main ()
+{
+  foo ();
+  if (c != 1)
+    __builtin_abort ();
+  bar ({ 1, 3 });
+  if (c != 3)
+    __builtin_abort ();
+  if (baz ().x != 1 || baz ().y != 3)
+    __builtin_abort ();
+  if (c != 9)
+    __builtin_abort ();
+}

Reply via email to