[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)

Krzysztof Parzyszek via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Mar 23 05:06:17 PDT 2026


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

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

>From fba1271b9b74d00f153d5f1eaa0887e61c64e02d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 20 Mar 2026 11:33:45 -0500
Subject: [PATCH] [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<LoopSequence> &children() const { return children_; }
 
+  WithReason<bool> isWellFormedSequence() const;
+  WithReason<bool> 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<parser::Block>(x.t)};
+
   for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
     if (auto *d{parser::Unwrap<parser::CompilerDirective>(stmt)}) {
       context_.Say(d->source,
           "Compiler directives are not allowed inside OpenMP loop constructs"_warn_en_US);
-    } else if (auto *omp{parser::Unwrap<parser::OpenMPLoopConstruct>(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<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);
     }
   }
 
   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)};
+  auto haveLength{sequence.length()};
 
-  if (auto haveLength{sequence.length()}) {
-    if (*haveLength.value == 0) {
+  if (assoc == llvm::omp::Association::LoopNest) {
+    if (sequence.children().size() == 0) {
       context_.Say(beginSource,
-          "This construct should contain a DO-loop or a loop-nest-generating OpenMP construct"_err_en_US);
-    } else {
-      auto assoc{llvm::omp::getDirectiveAssociation(dir)};
-      if (*haveLength.value > 1 && assoc == llvm::omp::Association::LoopNest) {
-        auto &msg{context_.Say(beginSource,
-            "This construct applies to a loop nest, but has a loop sequence of "
-            "length %" PRId64 ""_err_en_US,
-            *haveLength.value)};
-        haveLength.reason.AttachTo(msg);
-      }
-      if (assoc == llvm::omp::Association::LoopSeq) {
-        if (auto requiredCount{GetRequiredCount(needRange.value)}) {
-          if (*requiredCount > 0 && *haveLength.value < *requiredCount) {
-            auto &msg{context_.Say(beginSource,
-                "This construct requires a sequence of %" PRId64
-                " loops, but the loop sequence has a length of %" PRId64
-                ""_err_en_US,
-                *requiredCount, *haveLength.value)};
-            haveLength.reason.AttachTo(msg);
-            needRange.reason.AttachTo(msg);
-          }
-        }
-      }
+          "This construct should contain a DO-loop or a loop-nest-generating construct"_err_en_US);
+    } else if (haveLength.value > 1) {
+      auto &msg{context_.Say(beginSource,
+          "This construct applies to a loop nest, but has a loop sequence of "
+          "length %" PRId64 ""_err_en_US,
+          *haveLength.value)};
+      haveLength.reason.AttachTo(msg);
+    }
+    auto [isWellFormed, whyNot]{sequence.isWellFormedNest()};
+    if (isWellFormed && !*isWellFormed) {
+      auto &msg{context_.Say(beginSource,
+          "This construct requires a canonical loop nest"_err_en_US)};
+      whyNot.AttachTo(msg);
     }
-  }
 
-  // Check requirements on nest depth.
-  auto [needDepth, needPerfect]{
-      GetAffectedNestDepthWithReason(beginSpec, version)};
-  auto &[haveSema, havePerf]{sequence.depth()};
+    // Check requirements on nest depth.
+    auto [needDepth, needPerfect]{
+        GetAffectedNestDepthWithReason(beginSpec, version)};
+    auto &[haveSema, havePerf]{sequence.depth()};
+
+    auto haveDepth{needPerfect ? havePerf : haveSema};
+    std::string_view perfectTxt{needPerfect ? " perfect" : ""};
 
-  if (dir != llvm::omp::Directive::OMPD_fuse) {
-    auto haveDepth = needPerfect ? havePerf : haveSema;
     // If the present depth is 0, it's likely that the construct doesn't
     // have any loops in it, which would be diagnosed above.
     if (needDepth && haveDepth.value > 0) {
       if (*needDepth.value > *haveDepth.value) {
-        if (needPerfect) {
+        auto &msg{context_.Say(beginSource,
+            "This construct requires a%s nest of depth %" PRId64
+            ", but the associated nest is a%s nest of depth %" PRId64
+            ""_err_en_US,
+            perfectTxt, *needDepth.value, perfectTxt, *haveDepth.value)};
+        haveDepth.reason.AttachTo(msg);
+        needDepth.reason.AttachTo(msg);
+      }
+    }
+
+  } else if (assoc == llvm::omp::Association::LoopSeq) {
+    if (haveLength.value == 0) {
+      context_.Say(beginSource,
+          "This construct should contain a DO-loop or a loop-sequence-generating construct"_err_en_US);
+    } else {
+      auto [isWellFormed, whyNot]{sequence.isWellFormedSequence()};
+      if (isWellFormed && !*isWellFormed) {
+        auto &msg{context_.Say(beginSource,
+            "This construct requires a canonical loop sequence"_err_en_US)};
+        whyNot.AttachTo(msg);
+      }
+      if (auto requiredCount{GetRequiredCount(needRange.value)}) {
+        if (*requiredCount > 0 && haveLength.value < *requiredCount) {
           auto &msg{context_.Say(beginSource,
-              "This construct requires a perfect nest of depth %" PRId64
-              ", but the associated nest is a perfect nest of depth %" PRId64
+              "This construct requires a sequence of %" PRId64
+              " loops, but the loop sequence has a length of %" PRId64
               ""_err_en_US,
-              *needDepth.value, *haveDepth.value)};
-          haveDepth.reason.AttachTo(msg);
-          needDepth.reason.AttachTo(msg);
-        } else {
-          auto &msg{context_.Say(beginSource,
-              "This construct requires a nest of depth %" PRId64
-              ", but the associated nest has a depth of %" PRId64 ""_err_en_US,
-              *needDepth.value, *haveDepth.value)};
-          haveDepth.reason.AttachTo(msg);
-          needDepth.reason.AttachTo(msg);
+              *requiredCount, *haveLength.value)};
+          haveLength.reason.AttachTo(msg);
+          needRange.reason.AttachTo(msg);
         }
       }
     }
-  } else {
-    // FUSE requires a sequence of perfect nests.
-    // TODO: Defer this check for now.
   }
 }
 
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index 20a4de77a1d7f..d9fe3c4a5d02f 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -532,6 +532,13 @@ MaybeExpr MakeEvaluateExpr(const parser::OmpStylizedInstance &inp) {
       instance.u);
 }
 
+static const auto MsgNotValidAffectedLoop{
+    "%s is not a valid affected loop"_because_en_US};
+static const auto MsgClauseAbsentAssume{
+    "%s clause was not specified, %s is assumed"_because_en_US};
+static const auto MsgConstructDoesNotResult{
+    "%s does not result in %s"_because_en_US};
+
 Reason::Reason(const Reason &other) { //
   CopyFrom(other);
 }
@@ -565,7 +572,7 @@ WithReason<int64_t> GetArgumentValueWithReason(
         Reason reason;
         reason.Say(clause->source,
             "%s clause was specified with argument %" PRId64 ""_because_en_US,
-            name.c_str(), *value);
+            name, *value);
         return {*value, std::move(reason)};
       }
     }
@@ -581,7 +588,7 @@ static WithReason<int64_t> GetNumArgumentsWithReasonForType(
     Reason reason;
     reason.Say(clause.source,
         "%s clause was specified with %" PRId64 " arguments"_because_en_US,
-        name.c_str(), num);
+        name, num);
     return {num, std::move(reason)};
   }
   return {};
@@ -857,9 +864,8 @@ std::pair<WithReason<int64_t>, bool> GetAffectedNestDepthWithReason(
       std::string name{parser::omp::GetUpperName(
           llvm::omp::Clause::OMPC_permutation, version)};
       Reason reason;
-      reason.Say(spec.source,
-          "%s clause was not specified, %s(2, 1) was assumed"_because_en_US,
-          name.c_str(), name.c_str());
+      reason.Say(
+          spec.source, MsgClauseAbsentAssume, name, "a permutation (2, 1)");
       return {{2, std::move(reason)}, true};
     }
     case llvm::omp::Directive::OMPD_stripe:
@@ -879,9 +885,7 @@ std::pair<WithReason<int64_t>, bool> GetAffectedNestDepthWithReason(
       std::string name{
           parser::omp::GetUpperName(llvm::omp::Clause::OMPC_depth, version)};
       Reason reason;
-      reason.Say(spec.source,
-          "%s clause was not specified, a value of 1 was assumed"_because_en_US,
-          name.c_str());
+      reason.Say(spec.source, MsgClauseAbsentAssume, name, "a value of 1");
       return {{1, std::move(reason)}, true};
     }
     case llvm::omp::Directive::OMPD_reverse:
@@ -919,15 +923,14 @@ WithReason<std::pair<int64_t, int64_t>> GetAffectedLoopRangeWithReason(
       reason.Say(clause->source,
           "%s clause was specified with a count of %" PRId64
           " starting at loop %" PRId64 ""_because_en_US,
-          name.c_str(), *count, *first);
+          name, *count, *first);
       return {std::make_pair(*first, *count), std::move(reason)};
     }
     // If LOOPRANGE was not found, return {1, -1}, where -1 means "the whole
     // associated sequence".
     Reason reason;
-    reason.Say(spec.source,
-        "%s clause was not specified, the entire sequence is affected by"_because_en_US,
-        name.c_str());
+    reason.Say(
+        spec.source, MsgClauseAbsentAssume, name, "the entire loop sequence");
     return {std::make_pair(1, -1), std::move(reason)};
   }
 
@@ -1096,8 +1099,8 @@ WithReason<int64_t> LoopSequence::calculateLength() const {
   llvm::omp::Directive dir{beginSpec.DirId()};
   if (!IsLoopTransforming(dir)) {
     Reason reason;
-    reason.Say(beginSpec.DirName().source,
-        "This construct does not result in a loop nest or a loop sequence"_because_en_US);
+    reason.Say(beginSpec.DirName().source, MsgConstructDoesNotResult,
+        GetUpperName(dir, version_), "a loop nest or a loop sequence");
     return {0, std::move(reason)};
   }
 
@@ -1126,9 +1129,9 @@ WithReason<int64_t> LoopSequence::calculateLength() const {
         parser::omp::FindClause(beginSpec, llvm::omp::Clause::OMPC_looprange)};
     if (!clause) {
       Reason reason;
-      reason.Say(beginSpec.DirName().source,
-          "%s clause was not specified, all loops in the sequence are fused"_because_en_US,
-          GetUpperName(llvm::omp::Clause::OMPC_looprange, version_));
+      reason.Say(beginSpec.DirName().source, MsgClauseAbsentAssume,
+          GetUpperName(llvm::omp::Clause::OMPC_looprange, version_),
+          "the entire loop sequence");
       return {1, std::move(reason)};
     }
 
@@ -1141,7 +1144,7 @@ WithReason<int64_t> LoopSequence::calculateLength() const {
       int64_t result{1 + *nestedLength.value - *count};
       Reason reason;
       reason.Say(beginSpec.DirName().source,
-          "Out of %" PRId64 " loops, %" PRId64 " were fused"_because_en_US,
+          "Out of %" PRId64 " loops, %" PRId64 " are fused"_because_en_US,
           *nestedLength.value, *count);
       return {result, std::move(reason)};
     }
@@ -1168,6 +1171,25 @@ WithReason<int64_t> LoopSequence::getNestedLength() const {
   return sum;
 }
 
+static void ResetIfPositiveWithReason(
+    WithReason<int64_t> &quantity, const Reason &reason) {
+  if (quantity.value > 0) {
+    quantity.value = 0;
+    quantity.reason.Append(reason);
+  }
+}
+
+static void ResetIfPositiveWithReason(WithReason<int64_t> &quantity,
+    parser::CharBlock source, parser::MessageFixedText msg) {
+  if (quantity.value > 0) {
+    quantity.value = 0;
+    quantity.reason.Say(source, msg);
+  }
+}
+
+static Reason whyNotWellFormed(
+    const parser::ExecutionPartConstruct &badCode, bool isSequence);
+
 LoopSequence::Depth LoopSequence::calculateDepths() const {
   // Get the length of the nested sequence. The invalidIC_ and opaqueIC_
   // members do not count canonical loop nests, but there can only be one
@@ -1177,38 +1199,22 @@ LoopSequence::Depth LoopSequence::calculateDepths() const {
   // entry_), and use it as the basis for the depths of entry_->owner.
   auto [semaDepth, perfDepth]{getNestedDepths()};
   if (invalidIC_) {
-    parser::CharBlock source{*parser::GetSource(*invalidIC_)};
-    if (semaDepth.value > 9) {
-      semaDepth.value = 0;
-      semaDepth.reason.Say(
-          source, "This is not a valid intervening code"_because_en_US);
-    }
-    if (perfDepth.value > 0) {
-      perfDepth.value = 0;
-      perfDepth.reason.Say(
-          source, "This is not a valid intervening code"_because_en_US);
-    }
+    auto whyNot{whyNotWellFormed(*invalidIC_, false)};
+    ResetIfPositiveWithReason(semaDepth, whyNot);
+    ResetIfPositiveWithReason(perfDepth, whyNot);
   } else if (opaqueIC_) {
+    auto message{"This code prevents perfect nesting"_because_en_US};
     parser::CharBlock source{*parser::GetSource(*opaqueIC_)};
-    if (perfDepth.value > 0) {
-      perfDepth.value = 0;
-      perfDepth.reason.Say(
-          source, "This code prevents perfect nesting"_because_en_US);
-    }
+    ResetIfPositiveWithReason(perfDepth, source, message);
   }
   if (nestedLength.value.value_or(0) != 1) {
     // This may simply be the bottom of the loop nest. Only emit messages
     // if the depths are reset back to 0.
     if (entry_->owner) {
+      auto message{"This construct does not contain a loop nest"_because_en_US};
       parser::CharBlock source{*parser::GetSource(*entry_->owner)};
-      if (semaDepth.value > 0) {
-        semaDepth.reason.Say(source,
-            "This construct does not contain a loop nest"_because_en_US);
-      }
-      if (perfDepth.value > 9) {
-        perfDepth.reason.Say(source,
-            "This construct does not contain a loop nest"_because_en_US);
-      }
+      ResetIfPositiveWithReason(semaDepth, source, message);
+      ResetIfPositiveWithReason(perfDepth, source, message);
     }
     semaDepth.value = perfDepth.value = 0;
   }
@@ -1249,10 +1255,12 @@ LoopSequence::Depth LoopSequence::calculateDepths() const {
           if (*required == -1 || *required == *nestedLength.value) {
             return Depth{value, value};
           }
+          std::string name{
+              GetUpperName(llvm::omp::Directive::OMPD_fuse, version_)};
           Reason reason(std::move(range.reason));
-          reason.Say(beginSpec.DirName().source,
-              "%s construct results in a proper loop-sequence"_because_en_US,
-              GetUpperName(llvm::omp::Directive::OMPD_fuse, version_));
+          reason.Say(beginSpec.DirName().source, MsgConstructDoesNotResult,
+              "This " + name + " construct",
+              "a loop nest, but a proper loop sequence");
           return Depth{{1, reason}, {1, reason}};
         }
       }
@@ -1281,8 +1289,8 @@ LoopSequence::Depth LoopSequence::calculateDepths() const {
   case llvm::omp::Directive::OMPD_unroll:
     if (isFullUnroll) {
       Reason reason;
-      reason.Say(beginSpec.DirName().source,
-          "Fully unrolled loop does not result in a loop nest"_because_en_US);
+      reason.Say(beginSpec.DirName().source, MsgConstructDoesNotResult,
+          "Fully unrolled loop", "a loop nest");
       return Depth{{0, reason}, {0, reason}};
     }
     // If this is not a full unroll then look for a PARTIAL clause.
@@ -1326,4 +1334,64 @@ LoopSequence::Depth LoopSequence::getNestedDepths() const {
   }
   return children_.front().depth_;
 }
+
+static bool IsDoConcurrent(const parser::ExecutionPartConstruct &x) {
+  if (auto *loop{parser::Unwrap<parser::DoConstruct>(x)}) {
+    return loop->IsDoConcurrent();
+  }
+  return false;
+}
+
+static Reason whyNotWellFormed(
+    const parser::ExecutionPartConstruct &badCode, bool isSequence) {
+  Reason reason;
+  parser::CharBlock source{*parser::GetSource(badCode)};
+  if (auto *omp{parser::Unwrap<parser::OpenMPLoopConstruct>(badCode)}) {
+    if (IsFullUnroll(*omp)) {
+      reason.Say(source, MsgConstructDoesNotResult, "Fully unrolled loop",
+          isSequence ? "a loop nest or a loop sequence" : "a loop nest");
+    } else if (!IsLoopTransforming(omp->BeginDir().DirId())) {
+      reason.Say(source,
+          "Only loop-transforming constructs are allowed inside loop constructs"_because_en_US);
+    }
+    return reason;
+  }
+
+  if (auto *loop{parser::Unwrap<parser::DoConstruct>(badCode)}) {
+    if (loop->IsDoWhile()) {
+      reason.Say(source, MsgNotValidAffectedLoop, "DO WHILE loop");
+    } else if (loop->IsDoConcurrent()) {
+      reason.Say(source, MsgNotValidAffectedLoop, "DO CONCURRENT loop");
+    } else if (!loop->GetLoopControl()) {
+      reason.Say(
+          source, MsgNotValidAffectedLoop, "DO loop without loop control");
+    }
+    if (reason) {
+      return reason;
+    }
+  }
+  reason.Say(source,
+      "The %s contains code that prevents it from being canonical at this nesting level"_because_en_US,
+      isSequence ? "sequence" : "nest");
+  return reason;
+}
+
+WithReason<bool> LoopSequence::isWellFormedSequence() const {
+  const parser::ExecutionPartConstruct *badCode{
+      invalidIC_ ? invalidIC_ : opaqueIC_};
+  if (badCode) {
+    return {false, whyNotWellFormed(*badCode, true)};
+  }
+  return {true, Reason()};
+}
+
+WithReason<bool> LoopSequence::isWellFormedNest() const {
+  // DO CONCURRENT is allowed at the top level in OpenMP 6.0+.
+  if (invalidIC_) {
+    if (version_ < 60 || !IsDoConcurrent(*invalidIC_)) {
+      return {false, whyNotWellFormed(*invalidIC_, false)};
+    }
+  }
+  return {true, Reason()};
+}
 } // namespace Fortran::semantics::omp
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 7fca738d43ca6..3d55568c0cd03 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2395,11 +2395,6 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel(
               context_.Say(clause->source,
                   "DO CONCURRENT loops cannot be used with the COLLAPSE clause."_err_en_US);
             }
-          } else {
-            auto &stmt =
-                std::get<parser::Statement<parser::NonLabelDoStmt>>(loop->t);
-            context_.Say(stmt.source,
-                "DO CONCURRENT loops cannot form part of a loop nest."_err_en_US);
           }
         }
         // go through all the nested do-loops and resolve index variables
diff --git a/flang/test/Parser/OpenMP/interchange-fail.f90 b/flang/test/Parser/OpenMP/interchange-fail.f90
deleted file mode 100644
index d83ef1746f30f..0000000000000
--- a/flang/test/Parser/OpenMP/interchange-fail.f90
+++ /dev/null
@@ -1,31 +0,0 @@
-! RUN: split-file %s %t
-! 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
-! Parser error
-
-subroutine stray_end1
-  !CHECK: error: Misplaced OpenMP end-directive
-  !$omp end interchange
-end subroutine
-
-
-!--- stray_end2.f90
-
-subroutine stray_end2
-  print *
-  !CHECK: error: Misplaced OpenMP end-directive
-  !$omp end interchange
-end subroutine
-
-
-!--- stray_begin.f90
-
-subroutine stray_begin
-  !CHECK: error: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
-  !$omp interchange permutation(2,1)
-end subroutine
-
diff --git a/flang/test/Parser/OpenMP/tile-fail.f90 b/flang/test/Parser/OpenMP/tile-fail.f90
deleted file mode 100644
index d5ff39cd1037c..0000000000000
--- a/flang/test/Parser/OpenMP/tile-fail.f90
+++ /dev/null
@@ -1,31 +0,0 @@
-! RUN: split-file %s %t
-! 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
-! Parser error
-
-subroutine stray_end1
-  !CHECK: error: Misplaced OpenMP end-directive
-  !$omp end tile
-end subroutine
-
-
-!--- stray_end2.f90
-
-subroutine stray_end2
-  print *
-  !CHECK: error: Misplaced OpenMP end-directive
-  !$omp end tile
-end subroutine
-
-
-!--- stray_begin.f90
-
-subroutine stray_begin
-  !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/do-collapse.f90 b/flang/test/Semantics/OpenMP/do-collapse.f90
index 9cac2c7f50a4d..86354d6a61a31 100644
--- a/flang/test/Semantics/OpenMP/do-collapse.f90
+++ b/flang/test/Semantics/OpenMP/do-collapse.f90
@@ -29,9 +29,8 @@ program omp_doCollapse
   !BECAUSE: COLLAPSE clause was specified with argument 2
   !$omp parallel do collapse(2)
     do i = 1, 3
-      !BECAUSE: This is not a valid intervening code
+      !BECAUSE: DO loop without loop control is not a valid affected loop
       !ERROR: Loop control is not present in the DO LOOP
-      !ERROR: The associated loop of a loop-associated directive cannot be a DO without control.
       do
       end do
     end do
diff --git a/flang/test/Semantics/OpenMP/do-concurrent-collapse.f90 b/flang/test/Semantics/OpenMP/do-concurrent-collapse.f90
index b84d8d54a6629..4c5f2a85403a0 100644
--- a/flang/test/Semantics/OpenMP/do-concurrent-collapse.f90
+++ b/flang/test/Semantics/OpenMP/do-concurrent-collapse.f90
@@ -6,8 +6,7 @@
 ! ERROR: DO CONCURRENT loops cannot be used with the COLLAPSE clause.
 !$omp parallel do collapse(2)
 do i = 1, 1
-  ! BECAUSE: This is not a valid intervening code
-  ! ERROR: DO CONCURRENT loops cannot form part of a loop nest.
+  ! BECAUSE: DO CONCURRENT loop is not a valid affected loop
   do concurrent (j = 1:2)
     print *, j
   end do
@@ -21,14 +20,16 @@
   end do
 end do
 
+! ERROR: This construct requires a canonical loop nest
 !$omp parallel do
-! ERROR: DO CONCURRENT loops cannot form part of a loop nest.
+! BECAUSE: DO CONCURRENT loop is not a valid affected loop
 do concurrent (j = 1:2)
   print *, j
 end do
 
+! ERROR: This construct requires a canonical loop nest
 !$omp loop
-! Do concurrent is explicitly allowed inside of omp loop
+! BECAUSE: DO CONCURRENT loop is not a valid affected loop
 do concurrent (j = 1:2)
   print *, j
 end do
@@ -38,7 +39,7 @@
 ! ERROR: DO CONCURRENT loops cannot be used with the COLLAPSE clause.
 !$omp loop collapse(2)
 do i = 1, 1
-  ! BECAUSE: This is not a valid intervening code
+  ! BECAUSE: DO CONCURRENT loop is not a valid affected loop
   do concurrent (j = 1:2)
     print *, j
   end do
diff --git a/flang/test/Semantics/OpenMP/do09.f90 b/flang/test/Semantics/OpenMP/do09.f90
index 624a11555f105..86b2f59d3858f 100644
--- a/flang/test/Semantics/OpenMP/do09.f90
+++ b/flang/test/Semantics/OpenMP/do09.f90
@@ -5,16 +5,18 @@
 
 program omp_do
   integer ::  i = 0,k
+  !ERROR: This construct requires a canonical loop nest
   !$omp do
-  !ERROR: The associated loop of a loop-associated directive cannot be a DO WHILE.
+  !BECAUSE: DO WHILE loop is not a valid affected loop
   do while (i <= 10)
     print *, "it",i
     i = i+1
   end do
   !$omp end do
 
+  !ERROR: This construct requires a canonical loop nest
   !$omp do
-  !ERROR: The associated loop of a loop-associated directive cannot be a DO WHILE.
+  !BECAUSE: DO WHILE loop is not a valid affected loop
   do while (i <= 10)
     do while (j <= 10)
       print *, "it",k
diff --git a/flang/test/Semantics/OpenMP/do13.f90 b/flang/test/Semantics/OpenMP/do13.f90
index b4b07432e3800..6d5e799e951b0 100644
--- a/flang/test/Semantics/OpenMP/do13.f90
+++ b/flang/test/Semantics/OpenMP/do13.f90
@@ -9,7 +9,7 @@ program omp
   !BECAUSE: COLLAPSE clause was specified with argument 3
   !$omp do  collapse(3)
   do i = 0, 10
-    !BECAUSE: This is not a valid intervening code
+    !BECAUSE: The nest contains code that prevents it from being canonical at this nesting level
     !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
     cycle
     do j = 0, 10
@@ -25,7 +25,7 @@ program omp
   !$omp do  collapse(3)
   do i = 0, 10
     do j = 0, 10
-      !BECAUSE: This is not a valid intervening code
+      !BECAUSE: The nest contains code that prevents it from being canonical at this nesting level
       !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
       cycle
       do k  = 0, 10
@@ -39,7 +39,7 @@ program omp
   !BECAUSE: COLLAPSE clause was specified with argument 2
   !$omp do  collapse(2)
   do i = 0, 10
-    !BECAUSE: This is not a valid intervening code
+    !BECAUSE: The nest contains code that prevents it from being canonical at this nesting level
     !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
     cycle
     do j = 0, 10
@@ -55,7 +55,7 @@ program omp
   !BECAUSE: COLLAPSE clause was specified with argument 2
   !$omp do  collapse(2)
   foo: do i = 0, 10
-    !BECAUSE: This is not a valid intervening code
+    !BECAUSE: The nest contains code that prevents it from being canonical at this nesting level
     !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
     cycle foo
     do j = 0, 10
@@ -72,7 +72,7 @@ program omp
   !$omp do collapse(3)
   do 60 i=1,10
     do j=1,10
-      !BECAUSE: This is not a valid intervening code
+      !BECAUSE: The nest contains code that prevents it from being canonical at this nesting level
       !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
       cycle
       do k=1,10
diff --git a/flang/test/Semantics/OpenMP/do21.f90 b/flang/test/Semantics/OpenMP/do21.f90
index 683118a5b2182..8d922e2403796 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: This 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 construct
   !$omp do
 end subroutine
 
 subroutine do2
-  !ERROR: This 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 construct
   !$omp parallel do
 end subroutine
 
 subroutine do3
-  !ERROR: This 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 construct
   !$omp simd
 end subroutine
 
 subroutine do4
-  !ERROR: This 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 construct
   !$omp do simd
 end subroutine
 
 subroutine do5
-  !ERROR: This 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 construct
   !$omp loop
 end subroutine
diff --git a/flang/test/Semantics/OpenMP/fuse1.f90 b/flang/test/Semantics/OpenMP/fuse1.f90
index a7dd7e190c16a..8c6576b74a247 100644
--- a/flang/test/Semantics/OpenMP/fuse1.f90
+++ b/flang/test/Semantics/OpenMP/fuse1.f90
@@ -10,7 +10,7 @@ subroutine f
   !ERROR: This construct requires a sequence of 2 loops, but the loop sequence has a length of 1
   !BECAUSE: LOOPRANGE clause was specified with a count of 2 starting at loop 1
   !$omp fuse looprange(1, 2)
-  !BECAUSE: LOOPRANGE clause was not specified, all loops in the sequence are fused
+  !BECAUSE: LOOPRANGE clause was not specified, the entire loop sequence is assumed
   !$omp fuse
   do i = 1, 10
   end do
diff --git a/flang/test/Semantics/OpenMP/interchange-fail.f90 b/flang/test/Semantics/OpenMP/interchange-fail.f90
new file mode 100644
index 0000000000000..61ec46641942b
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/interchange-fail.f90
@@ -0,0 +1,18 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
+
+subroutine stray_end1
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end interchange
+end subroutine
+
+subroutine stray_end2
+  print *
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end interchange
+end subroutine
+
+subroutine stray_begin
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating construct
+  !$omp interchange permutation(2,1)
+end subroutine
+
diff --git a/flang/test/Semantics/OpenMP/interchange01.f90 b/flang/test/Semantics/OpenMP/interchange01.f90
index 0bbd5335dca87..8c1855c4cfe56 100644
--- a/flang/test/Semantics/OpenMP/interchange01.f90
+++ b/flang/test/Semantics/OpenMP/interchange01.f90
@@ -6,8 +6,9 @@ subroutine on_unroll
   implicit none
   integer i, j
 
-  !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop
+  !ERROR: This construct requires a canonical loop nest
   !$omp interchange
+  !BECAUSE: Fully unrolled loop does not result in a loop nest
   !$omp unroll
   do i = 1, 5
     do j = 1, 5
@@ -20,8 +21,9 @@ subroutine loop_assoc
   implicit none
   integer :: i, j
 
+  !ERROR: This construct requires a canonical loop nest
   !$omp interchange
-  !ERROR: The associated loop of a loop-associated directive cannot be a DO WHILE.
+  !BECAUSE: DO WHILE loop is not a valid affected loop
   do while (i <= 10)
     do j = 1, 5
       i = i + 1
@@ -35,7 +37,7 @@ subroutine insufficient_loops
   integer i
 
   !ERROR: This construct requires a perfect nest of depth 2, but the associated nest is a perfect nest of depth 1
-  !BECAUSE: PERMUTATION clause was not specified, PERMUTATION(2, 1) was assumed
+  !BECAUSE: PERMUTATION clause was not specified, a permutation (2, 1) is assumed
   !$omp interchange 
   do i = 1, 5
     print *, i
diff --git a/flang/test/Semantics/OpenMP/loop-association.f90 b/flang/test/Semantics/OpenMP/loop-association.f90
index 7235099210f77..e882b214053ac 100644
--- a/flang/test/Semantics/OpenMP/loop-association.f90
+++ b/flang/test/Semantics/OpenMP/loop-association.f90
@@ -16,14 +16,16 @@
 10   print *, a
   !$omp end parallel
 
+  !ERROR: This construct requires a canonical loop nest
   !$omp parallel do
-  !ERROR: DO CONCURRENT loops cannot form part of a loop nest.
+  !ERROR: DO CONCURRENT loop is not a valid affected loop
   DO CONCURRENT (i = 1:N)
      a = 3.14
   END DO
 
+  !ERROR: This construct requires a canonical loop nest
   !$omp parallel do simd
-  !ERROR: The associated loop of a loop-associated directive cannot be a DO WHILE.
+  !BECAUSE: DO WHILE loop is not a valid affected loop
   outer: DO WHILE (c > 1)
      inner: do while (b > 100)
         a = 3.14
@@ -43,9 +45,10 @@
   !$OMP END PARALLEL DO
 
   c = 16
+  !ERROR: This construct requires a canonical loop nest
   !$omp parallel do
+  !BECAUSE: DO loop without loop control is not a valid affected loop
   !ERROR: Loop control is not present in the DO LOOP
-  !ERROR: The associated loop of a loop-associated directive cannot be a DO without control.
   do
      a = 3.14
      c = c - 1
@@ -104,7 +107,7 @@
   !$omp parallel do private(c)
   do i = 1, N
      do j = 1, N
-        !ERROR: This 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 construct
         !$omp parallel do shared(b)
         a = 3.14
      enddo
@@ -124,7 +127,7 @@
   !ERROR: Misplaced OpenMP end-directive
   !$omp end parallel do
 
-  !ERROR: This 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 construct
   !$omp parallel do private(c)
 5 FORMAT (1PE12.4, I10)
   do i=1, N
@@ -141,7 +144,7 @@
   !ERROR: Misplaced OpenMP end-directive
   !$omp end parallel do simd
 
-  !ERROR: This 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 construct
   !$omp simd
     a = i + 1
   !ERROR: Misplaced OpenMP end-directive
diff --git a/flang/test/Semantics/OpenMP/loop-transformation-construct01.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct01.f90
index 2d27d9ab85c00..902ffc9a7dcd3 100644
--- a/flang/test/Semantics/OpenMP/loop-transformation-construct01.f90
+++ b/flang/test/Semantics/OpenMP/loop-transformation-construct01.f90
@@ -5,9 +5,10 @@
 subroutine loop_transformation_construct1
   implicit none
 
-  !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop
+  !ERROR: This construct requires a canonical loop nest
   !$omp do
-  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !BECAUSE: Fully unrolled loop does not result in a loop nest
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating construct
   !$omp unroll
 end subroutine
 
@@ -33,9 +34,9 @@ subroutine loop_transformation_construct3
   integer :: x
   integer :: v(i)
 
-  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct requires a canonical loop nest
   !$omp do
-  !ERROR: Only loop-transforming OpenMP constructs are allowed inside OpenMP loop constructs
+  !ERROR: Only loop-transforming constructs are allowed inside loop constructs
   !$omp parallel do
   do x = 1, i
     v(x) = v(x) * 2
@@ -52,7 +53,7 @@ subroutine loop_transformation_construct4
   do x = 1, i
     v(x) = v(x) * 2
   end do
-  !ERROR: This 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 construct
   !ERROR: At least one of SIZES clause must appear on the TILE directive
   !$omp tile
 end subroutine
@@ -64,9 +65,10 @@ subroutine loop_transformation_construct5
   integer :: v(i)
 
   !$omp do
-  !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop
+  !ERROR: This construct requires a canonical loop nest
   !ERROR: At least one of SIZES clause must appear on the TILE directive
   !$omp tile
+  !BECAUSE: Fully unrolled loop does not result in a loop nest
   !$omp unroll full
   do x = 1, i
     v(x) = v(x) * 2
@@ -80,9 +82,10 @@ subroutine loop_transformation_construct6
   integer :: v(i)
 
   !$omp do
-  !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop
+  !ERROR: This construct requires a canonical loop nest
   !ERROR: At least one of SIZES clause must appear on the TILE directive
   !$omp tile
+  !BECAUSE: Fully unrolled loop does not result in a loop nest
   !$omp unroll
   do x = 1, i
     v(x) = v(x) * 2
diff --git a/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
index d0169c4b721bf..4832884e7bd03 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: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-sequence-generating construct
   !$omp fuse 
 end subroutine
 
@@ -15,7 +15,7 @@ subroutine loop_transformation_construct2
   implicit none
 
   !$omp do
-  !ERROR: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-sequence-generating 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: This construct should contain a DO-loop or a loop-nest-generating OpenMP construct
+  !ERROR: This construct should contain a DO-loop or a loop-sequence-generating construct
   !$omp fuse
   !$omp end fuse
 end subroutine
@@ -62,8 +62,9 @@ subroutine loop_transformation_construct5
   integer :: v(i)
 
   !$omp do
-  !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop
+  !ERROR: This construct requires a canonical loop sequence
   !$omp fuse
+  !BECAUSE: Fully unrolled loop does not result in a loop nest or a loop sequence
   !$omp unroll full
   do x = 1, i
     v(x) = v(x) * 2
@@ -82,7 +83,7 @@ subroutine loop_transformation_construct6
 
   !ERROR: This construct applies to a loop nest, but has a loop sequence of length 2
   !$omp do
-  !BECAUSE: Out of 2 loops, 1 were fused
+  !BECAUSE: Out of 2 loops, 1 are fused
   !$omp fuse looprange(1,1)
   !$omp unroll partial(2)
   do x = 1, i
diff --git a/flang/test/Semantics/OpenMP/loop-transformation-construct04.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct04.f90
index c23acc2c4c266..d97bafb9fecfe 100644
--- a/flang/test/Semantics/OpenMP/loop-transformation-construct04.f90
+++ b/flang/test/Semantics/OpenMP/loop-transformation-construct04.f90
@@ -10,7 +10,7 @@ subroutine loop_transformation_construct3
 
   !ERROR: This construct applies to a loop nest, but has a loop sequence of length 2
   !$omp do
-  !BECAUSE: Out of 3 loops, 2 were fused
+  !BECAUSE: Out of 3 loops, 2 are fused
   !$omp fuse looprange(1,2)
   do x = 1, i
     v(x) = x * 2
@@ -33,7 +33,7 @@ subroutine loop_transformation_construct4
 
   !ERROR: This construct applies to a loop nest, but has a loop sequence of length 2
   !$omp tile sizes(2)
-  !BECAUSE: Out of 3 loops, 2 were fused
+  !BECAUSE: Out of 3 loops, 2 are fused
   !$omp fuse looprange(1,2)
   do x = 1, i
     v(x) = x * 2
diff --git a/flang/test/Semantics/OpenMP/tile-fail.f90 b/flang/test/Semantics/OpenMP/tile-fail.f90
new file mode 100644
index 0000000000000..da2688912080c
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/tile-fail.f90
@@ -0,0 +1,18 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
+
+subroutine stray_end1
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end tile
+end subroutine
+
+subroutine stray_end2
+  print *
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end tile
+end subroutine
+
+subroutine stray_begin
+  !ERROR: This construct should contain a DO-loop or a loop-nest-generating construct
+  !$omp tile sizes(2)
+end subroutine
+
diff --git a/flang/test/Semantics/OpenMP/tile02.f90 b/flang/test/Semantics/OpenMP/tile02.f90
index 5b70f94afb09e..fd2fb903fe757 100644
--- a/flang/test/Semantics/OpenMP/tile02.f90
+++ b/flang/test/Semantics/OpenMP/tile02.f90
@@ -6,8 +6,9 @@ subroutine on_unroll
   implicit none
   integer i
 
-  !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop
+  !ERROR: This construct requires a canonical loop nest
   !$omp tile sizes(2)
+  !BECAUSE: Fully unrolled loop does not result in a loop nest
   !$omp unroll
   do i = 1, 5
     print *, i
diff --git a/flang/test/Semantics/OpenMP/tile03.f90 b/flang/test/Semantics/OpenMP/tile03.f90
index e5c134638ac8d..618ea906e3aec 100644
--- a/flang/test/Semantics/OpenMP/tile03.f90
+++ b/flang/test/Semantics/OpenMP/tile03.f90
@@ -6,8 +6,9 @@ subroutine loop_assoc
   implicit none
   integer :: i = 0
 
+  !ERROR: This construct requires a canonical loop nest
   !$omp tile sizes(2)
-  !ERROR: The associated loop of a loop-associated directive cannot be a DO WHILE.
+  !BECAUSE: DO WHILE loop is not a valid affected loop
   do while (i <= 10)
     i = i + 1
     print *, i
diff --git a/flang/test/Semantics/OpenMP/tile08.f90 b/flang/test/Semantics/OpenMP/tile08.f90
index f42805cb81b7d..87c7bc96eb4fe 100644
--- a/flang/test/Semantics/OpenMP/tile08.f90
+++ b/flang/test/Semantics/OpenMP/tile08.f90
@@ -6,9 +6,9 @@ subroutine do_concurrent
   implicit none
   integer i, j
 
-
+  !ERROR: This construct requires a canonical loop nest
   !$omp tile sizes(2,2)
-  !ERROR: DO CONCURRENT loops cannot form part of a loop nest.
+  !BECAUSE: DO CONCURRENT loop is not a valid affected loop
   do concurrent (i = 1:42, j = 1:42)
     print *, i, j
   end do
diff --git a/flang/test/Semantics/OpenMP/tile09.f90 b/flang/test/Semantics/OpenMP/tile09.f90
index fc81d22e49b3d..02dea4014eb7b 100644
--- a/flang/test/Semantics/OpenMP/tile09.f90
+++ b/flang/test/Semantics/OpenMP/tile09.f90
@@ -45,9 +45,10 @@ subroutine f03
   !ERROR: This construct requires a perfect nest of depth 3, but the associated nest is a perfect nest of depth 1
   !BECAUSE: SIZES clause was specified with 3 arguments
   !$omp tile sizes(2, 2, 2)
+  !BECAUSE: This construct does not contain a loop nest
   do i = 1, 10
     !BECAUSE: LOOPRANGE clause was specified with a count of 1 starting at loop 1
-    !BECAUSE: FUSE construct results in a proper loop-sequence
+    !BECAUSE: This FUSE construct does not result in a loop nest, but a proper loop sequence
     !$omp fuse depth(2) looprange(1, 1)
     do j = 1, 10
       do k = 1, 10



More information about the llvm-branch-commits mailing list