Skip to content

Conversation

@kparzysz
Copy link
Contributor

@kparzysz kparzysz commented Dec 4, 2025

For an OpenMP loop construct, count how many loops will effectively be contained in its associated block. For constructs that are loop-nest associated this number should be 1. Report cases where this number is different.

Take into account that the block associated with a loop construct can contain compiler directives.

For an OpenMP loop construct, count how many loops will effectively be
contained in its associated block. For constructs that are loop-nest
associated this number should be 1. Report cases where this number is
different.

Take into account that the block associated with a loop construct can
contain compiler directives.
@kparzysz kparzysz requested review from Meinersbur and tblah December 4, 2025 20:16
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:openmp flang:semantics flang:parser labels Dec 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2025

@llvm/pr-subscribers-flang-parser

@llvm/pr-subscribers-flang-openmp

Author: Krzysztof Parzyszek (kparzysz)

Changes

For an OpenMP loop construct, count how many loops will effectively be contained in its associated block. For constructs that are loop-nest associated this number should be 1. Report cases where this number is different.

Take into account that the block associated with a loop construct can contain compiler directives.


Patch is 21.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170735.diff

9 Files Affected:

  • (modified) flang/lib/Semantics/check-omp-loop.cpp (+120-81)
  • (modified) flang/lib/Semantics/check-omp-structure.h (+1-2)
  • (modified) flang/test/Parser/OpenMP/tile-fail.f90 (+4-4)
  • (modified) flang/test/Semantics/OpenMP/do21.f90 (+5-5)
  • (modified) flang/test/Semantics/OpenMP/loop-association.f90 (+3-3)
  • (modified) flang/test/Semantics/OpenMP/loop-transformation-clauses01.f90 (+15-1)
  • (modified) flang/test/Semantics/OpenMP/loop-transformation-construct01.f90 (+2-2)
  • (modified) flang/test/Semantics/OpenMP/loop-transformation-construct02.f90 (+4-4)
  • (modified) flang/test/Semantics/OpenMP/loop-transformation-construct04.f90 (+2-2)
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index fc4b9222d91b3..6414f0028e008 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -37,6 +37,14 @@
 #include <tuple>
 #include <variant>
 
+namespace Fortran::semantics {
+static bool IsLoopTransforming(llvm::omp::Directive dir);
+static bool IsFullUnroll(const parser::OpenMPLoopConstruct &x);
+static std::optional<size_t> CountGeneratedLoops(
+    const parser::ExecutionPartConstruct &epc);
+static std::optional<size_t> CountGeneratedLoops(const parser::Block &block);
+} // namespace Fortran::semantics
+
 namespace {
 using namespace Fortran;
 
@@ -263,22 +271,19 @@ static bool IsLoopTransforming(llvm::omp::Directive dir) {
 }
 
 void OmpStructureChecker::CheckNestedBlock(const parser::OpenMPLoopConstruct &x,
-    const parser::Block &body, size_t &nestedCount) {
+    const parser::Block &body) {
   for (auto &stmt : body) {
     if (auto *dir{parser::Unwrap<parser::CompilerDirective>(stmt)}) {
       context_.Say(dir->source,
           "Compiler directives are not allowed inside OpenMP loop constructs"_warn_en_US);
-    } else if (parser::Unwrap<parser::DoConstruct>(stmt)) {
-      ++nestedCount;
     } else if (auto *omp{parser::Unwrap<parser::OpenMPLoopConstruct>(stmt)}) {
       if (!IsLoopTransforming(omp->BeginDir().DirName().v)) {
         context_.Say(omp->source,
             "Only loop-transforming OpenMP constructs are allowed inside OpenMP loop constructs"_err_en_US);
       }
-      ++nestedCount;
     } else if (auto *block{parser::Unwrap<parser::BlockConstruct>(stmt)}) {
-      CheckNestedBlock(x, std::get<parser::Block>(block->t), nestedCount);
-    } else {
+      CheckNestedBlock(x, std::get<parser::Block>(block->t));
+    } else if (!parser::Unwrap<parser::DoConstruct>(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);
@@ -286,16 +291,96 @@ void OmpStructureChecker::CheckNestedBlock(const parser::OpenMPLoopConstruct &x,
   }
 }
 
+static bool IsFullUnroll(const parser::OpenMPLoopConstruct &x) {
+  const parser::OmpDirectiveSpecification &beginSpec{x.BeginDir()};
+
+  if (beginSpec.DirName().v == llvm::omp::Directive::OMPD_unroll) {
+    return llvm::none_of(beginSpec.Clauses().v, [](const parser::OmpClause &c) {
+      return c.Id() == llvm::omp::Clause::OMPC_partial;
+    });
+  }
+  return false;
+}
+
+static std::optional<size_t> CountGeneratedLoops(
+    const parser::ExecutionPartConstruct &epc) {
+  if (parser::Unwrap<parser::DoConstruct>(epc)) {
+    return 1;
+  }
+
+  auto &omp{DEREF(parser::Unwrap<parser::OpenMPLoopConstruct>(epc))};
+  const parser::OmpDirectiveSpecification &beginSpec{omp.BeginDir()};
+  llvm::omp::Directive dir{beginSpec.DirName().v};
+
+  // TODO: Handle split, apply.
+  if (IsFullUnroll(omp)) {
+    return std::nullopt;
+  }
+  if (dir == llvm::omp::Directive::OMPD_fuse) {
+    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;
+    }
+
+    auto *loopRange{parser::Unwrap<parser::OmpLooprangeClause>(*rangeAt)};
+    std::optional<int64_t> count{GetIntValue(std::get<1>(loopRange->t))};
+    if (!count || *count <= 0) {
+      return std::nullopt;
+    }
+    if (auto nestedCount{CountGeneratedLoops(std::get<parser::Block>(omp.t))}) {
+      return 1 + *nestedCount - static_cast<size_t>(*count);
+    } else {
+      return std::nullopt;
+    }
+  }
+
+  // For every other loop construct return 1.
+  return 1;
+}
+
+static std::optional<size_t> CountGeneratedLoops(const parser::Block &block) {
+  // Count the number of loops in the associated block. If there are any
+  // malformed construct in there, getting the number may be meaningless.
+  // These issues will be diagnosed elsewhere, and we should not emit any
+  // messages about a potentially incorrect loop count.
+  // In such cases reset the count to nullopt. Once it becomes nullopt,
+  // keep it that way.
+  std::optional<size_t> numLoops{0};
+  for (auto &epc : parser::omp::LoopRange(block)) {
+    if (auto genCount{CountGeneratedLoops(epc)}) {
+      *numLoops += *genCount;
+    } else {
+      numLoops = std::nullopt;
+      break;
+    }
+  }
+  return numLoops;
+}
+
 void OmpStructureChecker::CheckNestedConstruct(
     const parser::OpenMPLoopConstruct &x) {
-  size_t nestedCount{0};
-
+  const parser::OmpDirectiveSpecification &beginSpec{x.BeginDir()};
   auto &body{std::get<parser::Block>(x.t)};
-  if (body.empty()) {
-    context_.Say(x.source,
-        "OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct"_err_en_US);
-  } else {
-    CheckNestedBlock(x, body, nestedCount);
+
+  CheckNestedBlock(x, body);
+
+  // Check if a loop-nest-associated construct has only one top-level loop
+  // in it.
+  if (std::optional<size_t> numLoops{CountGeneratedLoops(body)}) {
+    if (*numLoops == 0) {
+      context_.Say(beginSpec.DirName().source,
+          "This construct should contain a DO-loop or a loop-nest-generating OpenMP construct"_err_en_US);
+    } else {
+      auto assoc{llvm::omp::getDirectiveAssociation(beginSpec.DirName().v)};
+      if (*numLoops > 1 && assoc == llvm::omp::Association::LoopNest) {
+        context_.Say(beginSpec.DirName().source,
+            "This construct applies to a loop nest, but has a loop sequence of length %zu"_err_en_US,
+            *numLoops);
+      }
+    }
   }
 }
 
@@ -304,16 +389,9 @@ void OmpStructureChecker::CheckFullUnroll(
   // If the nested construct is a full unroll, then this construct is invalid
   // since it won't contain a loop.
   if (const parser::OpenMPLoopConstruct *nested{x.GetNestedConstruct()}) {
-    auto &nestedSpec{nested->BeginDir()};
-    if (nestedSpec.DirName().v == llvm::omp::Directive::OMPD_unroll) {
-      bool isPartial{
-          llvm::any_of(nestedSpec.Clauses().v, [](const parser::OmpClause &c) {
-            return c.Id() == llvm::omp::Clause::OMPC_partial;
-          })};
-      if (!isPartial) {
-        context_.Say(x.source,
-            "OpenMP loop construct cannot apply to a fully unrolled loop"_err_en_US);
-      }
+    if (IsFullUnroll(*nested)) {
+      context_.Say(x.source,
+          "OpenMP loop construct cannot apply to a fully unrolled loop"_err_en_US);
     }
   }
 }
@@ -387,11 +465,6 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
       beginName.v == llvm::omp::Directive::OMPD_distribute_simd) {
     CheckDistLinear(x);
   }
-  if (beginName.v == llvm::omp::Directive::OMPD_fuse) {
-    CheckLooprangeBounds(x);
-  } else {
-    CheckNestedFuse(x);
-  }
 }
 
 const parser::Name OmpStructureChecker::GetLoopIndex(
@@ -531,57 +604,20 @@ void OmpStructureChecker::CheckDistLinear(
 
 void OmpStructureChecker::CheckLooprangeBounds(
     const parser::OpenMPLoopConstruct &x) {
-  const parser::OmpClauseList &clauseList{x.BeginDir().Clauses()};
-  if (clauseList.v.empty()) {
-    return;
-  }
-  for (auto &clause : clauseList.v) {
-    if (const auto *lrClause{
-            std::get_if<parser::OmpClause::Looprange>(&clause.u)}) {
-      auto first{GetIntValue(std::get<0>((lrClause->v).t))};
-      auto count{GetIntValue(std::get<1>((lrClause->v).t))};
-      if (!first || !count) {
-        return;
-      }
-      auto &loopConsList{std::get<parser::Block>(x.t)};
-      if (*first > 0 && *count > 0 &&
-          loopConsList.size() < (unsigned)(*first + *count - 1)) {
-        context_.Say(clause.source,
-            "The loop range indicated in the %s clause must not be out of the bounds of the Loop Sequence following the construct."_err_en_US,
-            parser::ToUpperCaseLetters(clause.source.ToString()));
-      }
-      return;
-    }
-  }
-}
-
-void OmpStructureChecker::CheckNestedFuse(
-    const parser::OpenMPLoopConstruct &x) {
-  auto &loopConsList{std::get<parser::Block>(x.t)};
-  if (loopConsList.empty()) {
-    return;
-  }
-  const auto *ompConstruct{parser::omp::GetOmpLoop(loopConsList.front())};
-  if (!ompConstruct) {
-    return;
-  }
-  const parser::OmpClauseList &clauseList{ompConstruct->BeginDir().Clauses()};
-  if (clauseList.v.empty()) {
-    return;
-  }
-  for (auto &clause : clauseList.v) {
-    if (const auto *lrClause{
-            std::get_if<parser::OmpClause::Looprange>(&clause.u)}) {
-      auto count{GetIntValue(std::get<1>((lrClause->v).t))};
-      if (!count) {
+  for (const parser::OmpClause &clause : x.BeginDir().Clauses().v) {
+    if (auto *lrClause{parser::Unwrap<parser::OmpLooprangeClause>(clause)}) {
+      auto first{GetIntValue(std::get<0>(lrClause->t))};
+      auto count{GetIntValue(std::get<1>(lrClause->t))};
+      if (!first || !count || *first <= 0 || *count <= 0) {
         return;
       }
-      auto &nestedLoopConsList{std::get<parser::Block>(ompConstruct->t)};
-      if (nestedLoopConsList.size() > (unsigned)(*count)) {
-        context_.Say(x.BeginDir().DirName().source,
-            "The loop sequence following the %s construct must be fully fused first."_err_en_US,
-            parser::ToUpperCaseLetters(
-                x.BeginDir().DirName().source.ToString()));
+      auto requiredCount{static_cast<size_t>(*first + *count - 1)};
+      if (auto loopCount{CountGeneratedLoops(std::get<parser::Block>(x.t))}) {
+        if (*loopCount < requiredCount) {
+          context_.Say(clause.source,
+              "The specified loop range requires %zu loops, but the loop sequence has a length of %zu"_err_en_US,
+              requiredCount, *loopCount);
+        }
       }
       return;
     }
@@ -625,18 +661,21 @@ void OmpStructureChecker::CheckScanModifier(
 }
 
 void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
-  const parser::OmpClauseList &clauseList{x.BeginDir().Clauses()};
+  const parser::OmpDirectiveSpecification &beginSpec{x.BeginDir()};
 
   // A few semantic checks for InScan reduction are performed below as SCAN
   // constructs inside LOOP may add the relevant information. Scan reduction is
   // supported only in loop constructs, so same checks are not applicable to
   // other directives.
-  for (const auto &clause : clauseList.v) {
+  for (const auto &clause : beginSpec.Clauses().v) {
     if (auto *reduction{std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
       CheckScanModifier(*reduction);
     }
   }
-  if (llvm::omp::allSimdSet.test(GetContext().directive)) {
+  if (beginSpec.DirName().v == llvm::omp::Directive::OMPD_fuse) {
+    CheckLooprangeBounds(x);
+  }
+  if (llvm::omp::allSimdSet.test(beginSpec.DirName().v)) {
     ExitDirectiveNest(SIMDNest);
   }
   dirContext_.pop_back();
@@ -782,8 +821,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Sizes &c) {
 void OmpStructureChecker::Enter(const parser::OmpClause::Looprange &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_looprange);
   auto &[first, count]{x.v.t};
-  RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_looprange, count);
   RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_looprange, first);
+  RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_looprange, count);
 }
 
 void OmpStructureChecker::Enter(const parser::DoConstruct &x) {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 5bd5ae050be64..267362b6325f1 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -323,11 +323,10 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
 
   void CheckScanModifier(const parser::OmpClause::Reduction &x);
   void CheckLooprangeBounds(const parser::OpenMPLoopConstruct &x);
-  void CheckNestedFuse(const parser::OpenMPLoopConstruct &x);
   void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
   void CheckSIMDNest(const parser::OpenMPConstruct &x);
   void CheckNestedBlock(const parser::OpenMPLoopConstruct &x,
-      const parser::Block &body, size_t &nestedCount);
+      const parser::Block &body);
   void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);
   void CheckFullUnroll(const parser::OpenMPLoopConstruct &x);
   void CheckTargetNest(const parser::OpenMPConstruct &x);
diff --git a/flang/test/Parser/OpenMP/tile-fail.f90 b/flang/test/Parser/OpenMP/tile-fail.f90
index a69261a927961..d5ff39cd1037c 100644
--- a/flang/test/Parser/OpenMP/tile-fail.f90
+++ b/flang/test/Parser/OpenMP/tile-fail.f90
@@ -1,7 +1,7 @@
 ! RUN: split-file %s %t
-! RUN: not %flang_fc1 -fsyntax-only -fopenmp %t/stray_end1.f90 2>&1 | FileCheck %t/stray_end1.f90
-! RUN: not %flang_fc1 -fsyntax-only -fopenmp %t/stray_end2.f90 2>&1 | FileCheck %t/stray_end2.f90
-! RUN: not %flang_fc1 -fsyntax-only -fopenmp %t/stray_begin.f90 2>&1 | FileCheck %t/stray_begin.f90
+! RUN: not %flang_fc1 -fsyntax-only -fopenmp -fopenmp-version=60 %t/stray_end1.f90 2>&1 | FileCheck %t/stray_end1.f90
+! RUN: not %flang_fc1 -fsyntax-only -fopenmp -fopenmp-version=60 %t/stray_end2.f90 2>&1 | FileCheck %t/stray_end2.f90
+! RUN: not %flang_fc1 -fsyntax-only -fopenmp -fopenmp-version=60 %t/stray_begin.f90 2>&1 | FileCheck %t/stray_begin.f90
 
 
 !--- stray_end1.f90
@@ -25,7 +25,7 @@ subroutine stray_end2
 !--- stray_begin.f90
 
 subroutine stray_begin
-  !CHECK: error: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !CHECK: error: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp tile sizes(2)
 end subroutine
 
diff --git a/flang/test/Semantics/OpenMP/do21.f90 b/flang/test/Semantics/OpenMP/do21.f90
index e6fe7dd39dd3e..683118a5b2182 100644
--- a/flang/test/Semantics/OpenMP/do21.f90
+++ b/flang/test/Semantics/OpenMP/do21.f90
@@ -2,26 +2,26 @@
 ! Check for existence of loop following a DO directive
 
 subroutine do1
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp do
 end subroutine
 
 subroutine do2
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp parallel do
 end subroutine
 
 subroutine do3
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp simd
 end subroutine
 
 subroutine do4
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp do simd
 end subroutine
 
 subroutine do5
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp loop
 end subroutine
diff --git a/flang/test/Semantics/OpenMP/loop-association.f90 b/flang/test/Semantics/OpenMP/loop-association.f90
index 4e63cafb3fda1..4e6cf4ce13486 100644
--- a/flang/test/Semantics/OpenMP/loop-association.f90
+++ b/flang/test/Semantics/OpenMP/loop-association.f90
@@ -103,7 +103,7 @@
   !$omp parallel do private(c)
   do i = 1, N
      do j = 1, N
-        !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+        !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
         !$omp parallel do shared(b)
         a = 3.14
      enddo
@@ -123,7 +123,7 @@
   !ERROR: Misplaced OpenMP end-directive
   !$omp end parallel do
 
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp parallel do private(c)
 5 FORMAT (1PE12.4, I10)
   do i=1, N
@@ -140,7 +140,7 @@
   !ERROR: Misplaced OpenMP end-directive
   !$omp end parallel do simd
 
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp simd
     a = i + 1
   !ERROR: Misplaced OpenMP end-directive
diff --git a/flang/test/Semantics/OpenMP/loop-transformation-clauses01.f90 b/flang/test/Semantics/OpenMP/loop-transformation-clauses01.f90
index 9ca0e8cfc9af1..5e3d32d7c6eff 100644
--- a/flang/test/Semantics/OpenMP/loop-transformation-clauses01.f90
+++ b/flang/test/Semantics/OpenMP/loop-transformation-clauses01.f90
@@ -20,7 +20,7 @@ subroutine loop_transformation_construct1
   end do
   !$omp end fuse
 
-  !ERROR: The loop range indicated in the LOOPRANGE(5,2) clause must not be out of the bounds of the Loop Sequence following the construct.
+  !ERROR: The specified loop range requires 6 loops, but the loop sequence has a length of 2
   !$omp fuse looprange(5,2)
   do x = 1, i
     v(x) = x * 2
@@ -63,4 +63,18 @@ subroutine loop_transformation_construct1
     v(x) = x * 2
   end do
   !$omp end fuse
+
+  ! This is ok aside from the warnings about compiler directives
+  !$omp fuse looprange(1,3)
+    do x = 1, 10; end do        ! 1 loop
+    !WARNING: Compiler directives are not allowed inside OpenMP loop constructs
+    !dir$ novector
+    !$omp fuse looprange(1,2)   ! 2 loops
+      do x = 1, 10; end do
+      !WARNING: Compiler directives are not allowed inside OpenMP loop constructs
+      !dir$ nounroll
+      do x = 1, 10; end do
+      do x = 1, 10; end do
+    !$omp end fuse
+  !$omp end fuse
 end subroutine
diff --git a/flang/test/Semantics/OpenMP/loop-transformation-construct01.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct01.f90
index caa8f3f216fec..4eeb7330ea589 100644
--- a/flang/test/Semantics/OpenMP/loop-transformation-construct01.f90
+++ b/flang/test/Semantics/OpenMP/loop-transformation-construct01.f90
@@ -7,7 +7,7 @@ subroutine loop_transformation_construct1
 
   !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop
   !$omp do
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp unroll
 end subroutine
 
@@ -51,7 +51,7 @@ subroutine loop_transformation_construct4
   do x = 1, i
     v(x) = v(x) * 2
   end do
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !ERROR: At least one of SIZES clause must appear on the TILE directive
   !$omp tile
 end subroutine
diff --git a/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
index 1b15c938915cd..25247c3896cae 100644
--- a/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
+++ b/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
@@ -7,7 +7,7 @@ subroutine loop_transformation_construct1
   implicit none
 
   !$omp do
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp fuse 
 end subroutine
 
@@ -15,7 +15,7 @@ subroutine loop_transformation_construct2
   implicit none
 
   !$omp do
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp fuse 
   !$omp end fuse
 end subroutine
@@ -50,7 +50,7 @@ subroutine loop_transformation_construct4
   do x = 1, i
     v(x) = v(x) * 2
   end do
-  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp fuse
   !$omp end fuse
 end subroutine
@@ -80,7 +80,7 @@ subroutine loop_transformation_const...
[truncated]

@github-actions
Copy link

github-actions bot commented Dec 4, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@kparzysz
Copy link
Contributor Author

kparzysz commented Dec 4, 2025

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🐧 Linux x64 Test Results

  • 4100 tests passed
  • 201 tests skipped

✅ The build succeeded and all tests passed.

@kparzysz
Copy link
Contributor Author

kparzysz commented Dec 9, 2025

Ping

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:openmp flang:parser flang:semantics flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants