https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123597
--- Comment #20 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The releases/gcc-15 branch has been updated by Jakub Jelinek <[email protected]>: https://gcc.gnu.org/g:786def4bda52096c50b4294d402c33bc41da9807 commit r15-10729-g786def4bda52096c50b4294d402c33bc41da9807 Author: Jakub Jelinek <[email protected]> Date: Fri Jan 23 08:37:36 2026 +0100 openmp: Fix up OpenMP loop parsing in templates [PR123597] The following testcase is miscompiled, because since r14-3490 because in this case the sum variable is moved out of the loop's body into an outer BIND_EXPR and becomes shared, so from what has been previously private can result in data races. In the C++ FE, BIND_EXPRs are mostly created for 2 reasons. One is when something calls c_build_bind_expr and that function creates a BIND_EXPR because there are decls to attach to it, this happens for !processing_template_decl e.g. from do_poplevel or poplevel (the latter for sk_cleanup which I think don't appear if processing_template_decl). And the other case are BIND_EXPRs created by begin_compound_stmt if processing_template_decl, those don't stand for the need to collect decls inside of it, but to say the source had {} at this point, take it into account when instantiating the template. Now, on the testcase when parsing the body of the inner collapsed loop we call cp_parser_statement -> cp_parser_compound_statement -> begin_compound_statement because the body is surrounded by {}s and that returns a BIND_EXPR with the processing_template_decl meaning, the source had {} here. But the r14-3490 code then calls substitute_in_tree in a loop, trying to replace placeholders it created with the parsed bodies. And while doing that, considers all BIND_EXPRs with !BIND_EXPR_VARS redundant and just throws them away. They are redundant when !processing_template_decl, but when processing_template_decl they I think always have !BIND_EXPR_VARS, the vars inside of such bodies aren't pushed into any BIND_EXPR yet, they just have a DECL_EXPR somewhere, and the pushing of the instantiated copies of those will be done only during instantiation. The following patch fixes it by not treating BIND_EXPRs with !BIND_EXPR_VARS as redundant if processing_template_decl, it is fine to merge two BIND_EXPRs with nothing in between them. 2026-01-23 Jakub Jelinek <[email protected]> PR c++/123597 * parser.cc (substitute_in_tree_walker, substitute_in_tree): Don't consider BIND_EXPRs with !BIND_EXPR_VARS redundant if processing_template_decl. * g++.dg/gomp/pr123597.C: New test. (cherry picked from commit 1ae53b20c2474c28da13835719cceeee0702c966)
