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

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.

>From 9a2d3dca08ab237e7e949fd5642c96cf0fba89b8 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <[email protected]>
Date: Tue, 2 Dec 2025 14:59:34 -0600
Subject: [PATCH] [flang][OpenMP] Generalize checks of loop construct structure

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.
---
 flang/lib/Semantics/check-omp-loop.cpp        | 201 +++++++++++-------
 flang/lib/Semantics/check-omp-structure.h     |   3 +-
 flang/test/Parser/OpenMP/tile-fail.f90        |   8 +-
 flang/test/Semantics/OpenMP/do21.f90          |  10 +-
 .../Semantics/OpenMP/loop-association.f90     |   6 +-
 .../OpenMP/loop-transformation-clauses01.f90  |  16 +-
 .../loop-transformation-construct01.f90       |   4 +-
 .../loop-transformation-construct02.f90       |   8 +-
 .../loop-transformation-construct04.f90       |   4 +-
 9 files changed, 156 insertions(+), 104 deletions(-)

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_construct6
   integer :: x
   integer :: v(i)
 
-  !ERROR: The loop sequence following the DO construct must be fully fused 
first.
+  !ERROR: This construct applies to a loop nest, but has a loop sequence of 
length 2
   !$omp do
   !$omp fuse looprange(1,1)
   !$omp unroll partial(2)
diff --git a/flang/test/Semantics/OpenMP/loop-transformation-construct04.f90 
b/flang/test/Semantics/OpenMP/loop-transformation-construct04.f90
index 2856247329f3b..158b030906e07 100644
--- a/flang/test/Semantics/OpenMP/loop-transformation-construct04.f90
+++ b/flang/test/Semantics/OpenMP/loop-transformation-construct04.f90
@@ -8,7 +8,7 @@ subroutine loop_transformation_construct3
   integer :: x
   integer :: v(i)
 
-  !ERROR: The loop sequence following the DO construct must be fully fused 
first.
+  !ERROR: This construct applies to a loop nest, but has a loop sequence of 
length 2
   !$omp do
   !$omp fuse looprange(1,2)
   do x = 1, i
@@ -30,7 +30,7 @@ subroutine loop_transformation_construct4
   integer :: x
   integer :: v(i)
 
-  !ERROR: The loop sequence following the TILE construct must be fully fused 
first.
+  !ERROR: This construct applies to a loop nest, but has a loop sequence of 
length 2
   !$omp tile sizes(2)
   !$omp fuse looprange(1,2)
   do x = 1, i

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to