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 (); +}