[flang-commits] [flang] [flang][openacc] Accept enclosing labeled DO loops sharing a label with an ACC loop (PR #229502)
Valentin Clement バレンタイン クレメン via flang-commits
flang-commits at lists.llvm.org
Tue Oct 6 10:51:07 PDT 2026
https://github.com/clementval created https://github.com/llvm/llvm-project/pull/229502
When an `!$acc loop` or combined construct is associated with a labeled DO,
AccNonBlockDoConstruct builds a DoConstruct for it during parsing. If an
enclosing labeled DO without a directive shares the same terminating label,
that outer loop remains a LabelDoStmt until CanonicalizeDo, while its
terminator is now nested inside the DoConstruct. AnalyzeLabels runs before
CanonicalizeDo and treats every DoConstruct as a new scope, so it rejected
the outer loop with "Label 'N' is not in DO loop scope":
do 10 k = 1, m
!$acc loop
do 10 i = 1, n
10 a(i, k) = 0.
In label analysis, recognize DO constructs built from a non-block DO by
their synthesized END DO statement, which has no source, and analyze them
as the original labeled DO statement: do not open a new scope and record a
DO reference to the terminating label. This restores the label checks on
the loop itself (e.g. "This statement cannot terminate the DO loop"), which
were silently skipped since the loop became a DoConstruct.
>From e7cf93c82186029861088de020f3fabefc0f229e Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Tue, 6 Oct 2026 10:48:43 -0700
Subject: [PATCH] [flang][openacc] Accept enclosing labeled DO loops sharing a
label with an ACC loop
---
flang/lib/Semantics/resolve-labels.cpp | 34 ++++++++++++
flang/test/Semantics/OpenACC/acc-label-do.f90 | 55 +++++++++++++++++++
2 files changed, 89 insertions(+)
create mode 100644 flang/test/Semantics/OpenACC/acc-label-do.f90
diff --git a/flang/lib/Semantics/resolve-labels.cpp b/flang/lib/Semantics/resolve-labels.cpp
index 52b35a90302460..734317b16eb1ec 100644
--- a/flang/lib/Semantics/resolve-labels.cpp
+++ b/flang/lib/Semantics/resolve-labels.cpp
@@ -10,6 +10,7 @@
#include "flang/Common/enum-set.h"
#include "flang/Common/template.h"
#include "flang/Parser/parse-tree-visitor.h"
+#include "flang/Parser/tools.h"
#include "flang/Semantics/semantics.h"
#include <type_traits>
@@ -286,6 +287,9 @@ class ParseTreeAnalyzer {
return PushConstructName(criticalConstruct);
}
bool Pre(const parser::DoConstruct &doConstruct) {
+ if (IsNonBlockDoConstruct(doConstruct)) {
+ return PreNonBlockDoConstruct(doConstruct);
+ }
const auto &optionalName{std::get<std::optional<parser::Name>>(
std::get<parser::Statement<parser::NonLabelDoStmt>>(doConstruct.t)
.statement.t)};
@@ -642,6 +646,36 @@ class ParseTreeAnalyzer {
return true;
}
+ // The parser builds a DO construct, with a synthesized END DO statement
+ // that has no source, from a non-block (labeled) DO loop associated with an
+ // OpenACC LOOP or combined construct. Such a loop may share its terminating
+ // label with enclosing labeled DO statements that are only turned into DO
+ // constructs later by CanonicalizeDo.
+ static bool IsNonBlockDoConstruct(const parser::DoConstruct &doConstruct) {
+ return std::get<parser::Statement<parser::EndDoStmt>>(doConstruct.t)
+ .source.empty();
+ }
+
+ // Analyze a DO construct built from a non-block DO loop as the original
+ // labeled DO statement: it does not open a new scope, and it references
+ // its terminating label.
+ bool PreNonBlockDoConstruct(const parser::DoConstruct &doConstruct) {
+ const auto &doStmt{
+ std::get<parser::Statement<parser::NonLabelDoStmt>>(doConstruct.t)};
+ currentPosition_ = doStmt.source;
+ if (doStmt.label) {
+ AddTargetLabelDefinition(*doStmt.label,
+ ConstructBranchTargetFlags(doStmt), currentScope_,
+ /*isExecutableConstructEndStmt=*/false, currentPosition_);
+ }
+ const auto &block{std::get<parser::Block>(doConstruct.t)};
+ if (auto label{parser::GetFinalLabel(block)}) {
+ AddLabelReferenceFromDoStmt(*label);
+ }
+ Walk(block, *this);
+ return false;
+ }
+
template <typename A> bool PushConstructName(const A &a) {
const auto &optionalName{std::get<0>(std::get<0>(a.t).statement.t)};
if (optionalName) {
diff --git a/flang/test/Semantics/OpenACC/acc-label-do.f90 b/flang/test/Semantics/OpenACC/acc-label-do.f90
new file mode 100644
index 00000000000000..a88a8ee168c1dd
--- /dev/null
+++ b/flang/test/Semantics/OpenACC/acc-label-do.f90
@@ -0,0 +1,55 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenacc
+
+! Labeled DO loops that share their terminating label with an inner labeled DO
+! loop associated with an OpenACC LOOP construct.
+
+subroutine outer_without_directive(a, n, m)
+ integer :: i, k, n, m
+ real :: a(n, m)
+ do 10 k = 1, m
+!$acc loop gang vector
+ do 10 i = 1, n
+10 a(i, k) = a(i, k) + 1.
+end
+
+subroutine outer_without_directive_atomic(a, b, n, m)
+ integer :: i, k, n, m
+ real :: a(n, m), b(n, m)
+ do 20 k = 1, m
+!$acc loop gang vector
+ do 20 i = 1, n
+!$acc atomic update
+ a(i, k) = a(i, k) + b(i, k)
+!$acc atomic update
+20 b(i, k) = b(i, k) + a(i, k)
+end
+
+subroutine two_outer_without_directive(a, n, m)
+ integer :: i, j, k, n, m
+ real :: a(n, m)
+ do 30 k = 1, m
+ do 30 j = 1, m
+!$acc loop
+ do 30 i = 1, n
+30 a(i, k) = a(i, j)
+end
+
+subroutine bad_terminator(n)
+ integer :: i, k, n
+ do 40 k = 1, n
+!$acc loop
+ do 40 i = 1, n
+!ERROR: This statement cannot terminate the DO loop
+!ERROR: This statement cannot terminate the DO loop
+40 goto 40
+end
+
+subroutine missing_label(a, n)
+ integer :: i, k, n
+ real :: a(n)
+ !ERROR: Label '50' cannot be found
+ do 50 k = 1, n
+!$acc loop
+ do 60 i = 1, n
+60 a(i) = 0.
+end
More information about the flang-commits
mailing list