https://gcc.gnu.org/g:1ae53b20c2474c28da13835719cceeee0702c966

commit r16-6989-g1ae53b20c2474c28da13835719cceeee0702c966
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.

Diff:
---
 gcc/cp/parser.cc                     | 10 +++++++++-
 gcc/testsuite/g++.dg/gomp/pr123597.C | 25 +++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 393c8b2ec44e..9d56ab178b45 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -49853,6 +49853,9 @@ substitute_in_tree_walker (tree *tp, int *walk_subtrees 
ATTRIBUTE_UNUSED,
   else if (TREE_CODE (*tp) == BIND_EXPR
           && BIND_EXPR_BODY (*tp) == sit->orig
           && !BIND_EXPR_VARS (*tp)
+          /* BIND_EXPRs in templates likely have NULL BIND_EXPR_VARS,
+             are created by begin_compound_stmt and are not redundant.  */
+          && !processing_template_decl
           && (sit->flatten || TREE_CODE (sit->repl) == BIND_EXPR))
     {
       *tp = sit->repl;
@@ -49897,7 +49900,12 @@ substitute_in_tree (tree *context, tree orig, tree 
repl, bool flatten)
   struct sit_data data;
 
   gcc_assert (*context && orig && repl);
-  if (TREE_CODE (repl) == BIND_EXPR && !BIND_EXPR_VARS (repl))
+  /* Look through redundant BIND_EXPR.  BIND_EXPRs in templates likely have
+     NULL BIND_EXPR_VARS, are created by begin_compound_stmt and are not
+     redundant.  */
+  if (TREE_CODE (repl) == BIND_EXPR
+      && !BIND_EXPR_VARS (repl)
+      && !processing_template_decl)
     repl = BIND_EXPR_BODY (repl);
   data.orig = orig;
   data.repl = repl;
diff --git a/gcc/testsuite/g++.dg/gomp/pr123597.C 
b/gcc/testsuite/g++.dg/gomp/pr123597.C
new file mode 100644
index 000000000000..9f8417c029a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr123597.C
@@ -0,0 +1,25 @@
+// PR c++/123597
+// { dg-do compile }
+// { dg-additional-options "-fdump-tree-gimple" }
+// { dg-final { scan-tree-dump-not " shared\\\(sum\\\)" "gimple" } }
+
+template <typename T>
+void
+foo (T *x)
+{
+  #pragma omp teams distribute parallel for collapse(2)
+  for (long i = 0; i < 5; i++)
+    for (long j = 0; j < 5; j++)
+      {
+        T sum = 0;
+        for (long k = 0; k < 5; k++)
+          sum += 2;
+        x[i + 5 * j] = sum;
+      }
+}
+
+void
+bar (int *x)
+{
+  foo (x);
+}

Reply via email to