Hi!

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.

Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk,
will backport at least to 15 soon.

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.

--- gcc/cp/parser.cc.jj 2026-01-21 14:23:48.925730642 +0100
+++ gcc/cp/parser.cc    2026-01-22 15:34:08.691354819 +0100
@@ -49853,6 +49853,9 @@ substitute_in_tree_walker (tree *tp, int
   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
   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;
--- gcc/testsuite/g++.dg/gomp/pr123597.C.jj     2026-01-22 15:44:58.438399019 
+0100
+++ gcc/testsuite/g++.dg/gomp/pr123597.C        2026-01-22 15:44:32.992828075 
+0100
@@ -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);
+}

        Jakub

Reply via email to