[flang-commits] [flang] [flang][OpenMP] Fix counting generated nests (PR #183957)

Krzysztof Parzyszek via flang-commits flang-commits at lists.llvm.org
Sat Feb 28 13:10:17 PST 2026


https://github.com/kparzysz created https://github.com/llvm/llvm-project/pull/183957

The code in `CountGeneratedNests` returned std::nullopt if the LOOPRANGE clause was not present on a FUSE construct. That is incorrect, the answer should be 1 instead, except in cases where the FUSE itself was invalid, such as having no loops nested in it.

Returning std::nullopt will not cause any messages to be emitted. The case of zero loops inside of FUSE will be diagnosed when analyzing the body of the FUSE construct itself, not when checking a construct in which the FUSE is nested.
This prevents error messages caused by the same problem from being emitted for every enclosing loop construct.

>From 3949b087512ac0d2270b91946ede672f065d8b4d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Sat, 28 Feb 2026 14:40:20 -0600
Subject: [PATCH] [flang][OpenMP] Fix counting generated nests

The code in `CountGeneratedNests` returned std::nullopt if the LOOPRANGE
clause was not present on a FUSE construct. That is incorrect, the answer
should be 1 instead, except in cases where the FUSE itself was invalid,
such as having no loops nested in it.

Returning std::nullopt will not cause any messages to be emitted. The case
of zero loops inside of FUSE will be diagnosed when analyzing the body of
the FUSE construct itself, not when checking a construct in which the FUSE
is nested.
This prevents error messages caused by the same problem from being emitted
for every enclosing loop construct.
---
 flang/lib/Semantics/check-omp-loop.cpp | 23 +++++++++++++++++++----
 flang/test/Semantics/OpenMP/fuse1.f90  | 18 ++++++++++++++++++
 2 files changed, 37 insertions(+), 4 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/fuse1.f90

diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index 91b306a2a5ebd..de7a155dd96ef 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -281,6 +281,8 @@ static bool IsFullUnroll(const parser::OpenMPLoopConstruct &x) {
   return false;
 }
 
+// Count the number of loop nests generated by `epc`. This is just a helper
+// function for counting the number of loop nests in a parser::Block.
 static std::optional<size_t> CountGeneratedNests(
     const parser::ExecutionPartConstruct &epc) {
   if (parser::Unwrap<parser::DoConstruct>(epc)) {
@@ -296,12 +298,26 @@ static std::optional<size_t> CountGeneratedNests(
     return std::nullopt;
   }
   if (dir == llvm::omp::Directive::OMPD_fuse) {
+    auto nestedCount{CountGeneratedNests(std::get<parser::Block>(omp.t))};
+    // If there are no loops nested inside of FUSE, then the construct is
+    // invalid. This case will be diagnosed when analyzing the body of the FUSE
+    // construct itself, not when checking a construct in which the FUSE is
+    // nested.
+    // Returning std::nullopt prevents error messages caused by the same
+    // problem from being emitted for every enclosing loop construct, for
+    // example:
+    //   !$omp do         ! error: this should contain a loop (superfluous)
+    //   !$omp fuse       ! error: this should contain a loop
+    //   !$omp end fuse
+    if (!nestedCount || *nestedCount == 0) {
+      return std::nullopt;
+    }
     auto rangeAt{
         llvm::find_if(beginSpec.Clauses().v, [](const parser::OmpClause &c) {
           return c.Id() == llvm::omp::Clause::OMPC_looprange;
         })};
     if (rangeAt == beginSpec.Clauses().v.end()) {
-      return std::nullopt;
+      return 1;
     }
 
     auto *loopRange{parser::Unwrap<parser::OmpLooprangeClause>(*rangeAt)};
@@ -309,9 +325,8 @@ static std::optional<size_t> CountGeneratedNests(
     if (!count || *count <= 0) {
       return std::nullopt;
     }
-    if (auto nestedCount{CountGeneratedNests(std::get<parser::Block>(omp.t))}) {
-      if (static_cast<size_t>(*count) <= *nestedCount)
-        return 1 + *nestedCount - static_cast<size_t>(*count);
+    if (static_cast<size_t>(*count) <= *nestedCount) {
+      return 1 + *nestedCount - static_cast<size_t>(*count);
     }
     return std::nullopt;
   }
diff --git a/flang/test/Semantics/OpenMP/fuse1.f90 b/flang/test/Semantics/OpenMP/fuse1.f90
new file mode 100644
index 0000000000000..0616a3c52786d
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/fuse1.f90
@@ -0,0 +1,18 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
+
+! Make sure we correctly count the number of nests generated by FUSE
+! without a LOOPRANGE clause.
+
+subroutine f
+  integer :: i
+
+  !$omp do
+  !ERROR: The specified loop range requires 2 loops, but the loop sequence has a length of 1
+  !$omp fuse looprange(1, 2)
+  !$omp fuse
+  do i = 1, 10
+  end do
+  !$omp end fuse
+  !$omp end fuse
+end
+



More information about the flang-commits mailing list