https://github.com/kparzysz updated
https://github.com/llvm/llvm-project/pull/188025
>From fba1271b9b74d00f153d5f1eaa0887e61c64e02d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek
Date: Fri, 20 Mar 2026 11:33:45 -0500
Subject: [PATCH 1/3] [flang][OpenM] Check if loop nest/sequence is well-formed
Check if the code associated with a nest or sequence construct is well
formed. Emit diagnostic messages if not.
Make a clearer separation for checks of loop-nest-associated and loop-
sequence-associated constructs.
Unify structure of some of the more common messages.
Issue: https://github.com/llvm/llvm-project/issues/185287
---
flang/include/flang/Semantics/openmp-utils.h | 3 +
flang/lib/Semantics/check-omp-loop.cpp| 126 ++
flang/lib/Semantics/openmp-utils.cpp | 162 +-
flang/lib/Semantics/resolve-directives.cpp| 5 -
flang/test/Parser/OpenMP/interchange-fail.f90 | 31
flang/test/Parser/OpenMP/tile-fail.f90| 31
flang/test/Semantics/OpenMP/do-collapse.f90 | 3 +-
.../OpenMP/do-concurrent-collapse.f90 | 11 +-
flang/test/Semantics/OpenMP/do09.f90 | 6 +-
flang/test/Semantics/OpenMP/do13.f90 | 10 +-
flang/test/Semantics/OpenMP/do21.f90 | 10 +-
flang/test/Semantics/OpenMP/fuse1.f90 | 2 +-
.../Semantics/OpenMP/interchange-fail.f90 | 18 ++
flang/test/Semantics/OpenMP/interchange01.f90 | 8 +-
.../Semantics/OpenMP/loop-association.f90 | 15 +-
.../loop-transformation-construct01.f90 | 17 +-
.../loop-transformation-construct02.f90 | 11 +-
.../loop-transformation-construct04.f90 | 4 +-
flang/test/Semantics/OpenMP/tile-fail.f90 | 18 ++
flang/test/Semantics/OpenMP/tile02.f90| 3 +-
flang/test/Semantics/OpenMP/tile03.f90| 3 +-
flang/test/Semantics/OpenMP/tile08.f90| 4 +-
flang/test/Semantics/OpenMP/tile09.f90| 3 +-
23 files changed, 269 insertions(+), 235 deletions(-)
delete mode 100644 flang/test/Parser/OpenMP/interchange-fail.f90
delete mode 100644 flang/test/Parser/OpenMP/tile-fail.f90
create mode 100644 flang/test/Semantics/OpenMP/interchange-fail.f90
create mode 100644 flang/test/Semantics/OpenMP/tile-fail.f90
diff --git a/flang/include/flang/Semantics/openmp-utils.h
b/flang/include/flang/Semantics/openmp-utils.h
index 7c95edf81ada2..bf35598177e17 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -202,6 +202,9 @@ struct LoopSequence {
const Depth &depth() const { return depth_; }
const std::vector &children() const { return children_; }
+ WithReason isWellFormedSequence() const;
+ WithReason isWellFormedNest() const;
+
private:
using Construct = ExecutionPartIterator::Construct;
diff --git a/flang/lib/Semantics/check-omp-loop.cpp
b/flang/lib/Semantics/check-omp-loop.cpp
index df9797ac8e56a..962537496e580 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -61,16 +61,6 @@ class AssociatedLoopChecker {
constructNamesAndLevels_.emplace(
constructName.value().ToString(), level_);
}
-if (level_ >= 0) {
- if (dc.IsDoWhile()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
WHILE."_err_en_US);
- }
- if (!dc.GetLoopControl()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
without control."_err_en_US);
- }
-}
return true;
}
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get(x.t)};
+
for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
if (auto *d{parser::Unwrap(stmt)}) {
context_.Say(d->source,
"Compiler directives are not allowed inside OpenMP loop
constructs"_warn_en_US);
-} else if (auto *omp{parser::Unwrap(stmt)}) {
- if (!IsLoopTransforming(omp->BeginDir().DirId())) {
-context_.Say(omp->source,
-"Only loop-transforming OpenMP constructs are allowed inside
OpenMP loop constructs"_err_en_US);
- }
- if (IsFullUnroll(*omp)) {
-context_.Say(x.source,
-"OpenMP loop construct cannot apply to a fully unrolled
loop"_err_en_US);
- }
-} else if (!parser::Unwrap(stmt)) {
- parser::CharBlock source{parser::GetSource(stmt).value_or(x.source)};
- context_.Say(source,
- "OpenMP loop construct can only contain DO loops or
loop-nest-generating OpenMP constructs"_err_en_US);
}
}
LoopSequence sequence(body, version, true);
- // Check if a loop-nest-associated construct has only one top-level loop
- // in it.
+ auto assoc{llvm::omp::getDirectiveAssociation(dir)};
auto needRange{GetAffectedLoopRangeWithReason(beginSpec, version)};
+