On 8/25/25 10:53 AM, Jakub Jelinek wrote:
On Mon, Aug 25, 2025 at 09:44:29AM -0400, Jason Merrill wrote:
--- gcc/cp/pt.cc.jj     2025-08-23 15:00:04.262787988 +0200
+++ gcc/cp/pt.cc        2025-08-23 15:51:08.726081054 +0200
@@ -22321,6 +22321,13 @@ tsubst_expr (tree t, tree args, tsubst_f
              if (DECL_NAME (t) == this_identifier && current_class_ptr)
                RETURN (current_class_ptr);
+             /* Parameters during expansion stmt body instantiation outside
+                of templates map to themselves.  */
+             if (current_tinst_level
+                 && (TREE_CODE (current_tinst_level->tldcl)
+                     == TEMPLATE_FOR_STMT))
+               RETURN (t);

Rather than checking specifically for an expansion stmt, I'd prefer to check
for the general case of the parameter not being in a template, perhaps with

if (!uses_template_parms (DECL_CONTEXT (t))

since that test is already used in the controlling if?

That works too on
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make check-g++ 
RUNTESTFLAGS="dg.exp='expansion-stmt*'"
too, ok for trunk if it passes full bootstrap/regtest?

OK.

2025-08-25  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.

--- gcc/cp/pt.cc.jj     2025-08-25 16:29:07.122358976 +0200
+++ gcc/cp/pt.cc        2025-08-25 16:45:15.210314704 +0200
@@ -22321,6 +22321,11 @@ tsubst_expr (tree t, tree args, tsubst_f
              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 (!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.  */
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt20.C.jj    2025-08-25 
16:43:07.510020392 +0200
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt20.C       2025-08-25 
16:43:07.510020392 +0200
@@ -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 ();
+}


        Jakub


Reply via email to