[flang-commits] [flang] 06fc87b - [flang][OpenMP] Better diagnostics for invalid or misplaced directives (#168885)

via flang-commits flang-commits at lists.llvm.org
Sun Nov 23 05:55:14 PST 2025


Author: Krzysztof Parzyszek
Date: 2025-11-23T07:55:10-06:00
New Revision: 06fc87bcd3d61a08f8c035e60949631f61bccee7

URL: https://github.com/llvm/llvm-project/commit/06fc87bcd3d61a08f8c035e60949631f61bccee7
DIFF: https://github.com/llvm/llvm-project/commit/06fc87bcd3d61a08f8c035e60949631f61bccee7.diff

LOG: [flang][OpenMP] Better diagnostics for invalid or misplaced directives (#168885)

Add two more AST nodes, one for a misplaced end-directive, and one for
an invalid string following the OpenMP sentinel (e.g. "!$OMP XYZ").

Emit error messages when either node is encountered in semantic
analysis.

Added: 
    

Modified: 
    flang/include/flang/Parser/dump-parse-tree.h
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Parser/executable-parsers.cpp
    flang/lib/Parser/openmp-parsers.cpp
    flang/lib/Parser/program-parsers.cpp
    flang/lib/Parser/type-parsers.h
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h
    flang/lib/Semantics/resolve-directives.cpp
    flang/test/Parser/OpenMP/fail-construct2.f90
    flang/test/Parser/OpenMP/tile-fail.f90
    flang/test/Semantics/OpenMP/clause-validity01.f90
    flang/test/Semantics/OpenMP/loop-association.f90
    flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
    flang/test/Semantics/OpenMP/loop-transformation-construct03.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 5ca9deeb9b7f6..32fcd4182bed7 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -755,7 +755,9 @@ class ParseTreeDumper {
   NODE(parser, OpenMPDispatchConstruct)
   NODE(parser, OpenMPFlushConstruct)
   NODE(parser, OpenMPGroupprivate)
+  NODE(parser, OpenMPInvalidDirective)
   NODE(parser, OpenMPLoopConstruct)
+  NODE(parser, OpenMPMisplacedEndDirective)
   NODE(parser, OpenMPRequiresConstruct)
   NODE(parser, OpenMPSectionConstruct)
   NODE(parser, OpenMPSectionsConstruct)

diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 9795a0d2ae25e..003d11721908e 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -269,8 +269,9 @@ struct AccEndCombinedDirective;
 struct OpenACCDeclarativeConstruct;
 struct OpenACCRoutineConstruct;
 struct OpenMPConstruct;
-struct OpenMPLoopConstruct;
 struct OpenMPDeclarativeConstruct;
+struct OpenMPInvalidDirective;
+struct OpenMPMisplacedEndDirective;
 struct CUFKernelDoConstruct;
 
 // Cooked character stream locations
@@ -406,6 +407,8 @@ struct SpecificationConstruct {
       common::Indirection<StructureDef>,
       common::Indirection<OpenACCDeclarativeConstruct>,
       common::Indirection<OpenMPDeclarativeConstruct>,
+      common::Indirection<OpenMPMisplacedEndDirective>,
+      common::Indirection<OpenMPInvalidDirective>,
       common::Indirection<CompilerDirective>>
       u;
 };
@@ -538,6 +541,8 @@ struct ExecutableConstruct {
       common::Indirection<OpenACCConstruct>,
       common::Indirection<AccEndCombinedDirective>,
       common::Indirection<OpenMPConstruct>,
+      common::Indirection<OpenMPMisplacedEndDirective>,
+      common::Indirection<OpenMPInvalidDirective>,
       common::Indirection<CUFKernelDoConstruct>>
       u;
 };
@@ -5379,6 +5384,19 @@ struct OpenMPConstruct {
       u;
 };
 
+// Orphaned !$OMP END <directive>, i.e. not being a part of a valid OpenMP
+// construct.
+struct OpenMPMisplacedEndDirective : public OmpEndDirective {
+  INHERITED_TUPLE_CLASS_BOILERPLATE(
+      OpenMPMisplacedEndDirective, OmpEndDirective);
+};
+
+// Unrecognized string after the !$OMP sentinel.
+struct OpenMPInvalidDirective {
+  using EmptyTrait = std::true_type;
+  CharBlock source;
+};
+
 // Parse tree nodes for OpenACC 3.3 directives and clauses
 
 struct AccObject {

diff  --git a/flang/lib/Parser/executable-parsers.cpp b/flang/lib/Parser/executable-parsers.cpp
index 8d777a6671495..2241c04f5d26d 100644
--- a/flang/lib/Parser/executable-parsers.cpp
+++ b/flang/lib/Parser/executable-parsers.cpp
@@ -50,6 +50,8 @@ constexpr auto executableConstruct{first(
     construct<ExecutableConstruct>(indirect(whereConstruct)),
     construct<ExecutableConstruct>(indirect(forallConstruct)),
     construct<ExecutableConstruct>(indirect(openmpConstruct)),
+    construct<ExecutableConstruct>(indirect(openmpMisplacedEndDirective)),
+    construct<ExecutableConstruct>(indirect(openmpInvalidDirective)),
     construct<ExecutableConstruct>(indirect(Parser<OpenACCConstruct>{})),
     construct<ExecutableConstruct>(indirect(compilerDirective)),
     construct<ExecutableConstruct>(indirect(Parser<CUFKernelDoConstruct>{})))};

diff  --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index b7f23348328b4..b033206d90c41 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1602,6 +1602,14 @@ static inline constexpr auto IsMemberOf(const DirectiveSet &dirs) {
   };
 }
 
+constexpr auto validEPC{//
+    predicated(executionPartConstruct, [](auto &epc) {
+      return !Unwrap<OpenMPMisplacedEndDirective>(epc) &&
+          !Unwrap<OpenMPMisplacedEndDirective>(epc);
+    })};
+
+constexpr auto validBlock{many(validEPC)};
+
 TYPE_PARSER(sourced(construct<OmpDirectiveName>(OmpDirectiveNameParser{})))
 
 OmpDirectiveSpecification static makeFlushFromOldSyntax(Verbatim &&text,
@@ -1659,7 +1667,7 @@ struct StrictlyStructuredBlockParser {
   std::optional<resultType> Parse(ParseState &state) const {
     // Detect BLOCK construct without parsing the entire thing.
     if (lookAhead(skipStuffBeforeStatement >> "BLOCK"_tok).Parse(state)) {
-      if (auto epc{Parser<ExecutionPartConstruct>{}.Parse(state)}) {
+      if (auto &&epc{executionPartConstruct.Parse(state)}) {
         if (GetFortranBlockConstruct(*epc) != nullptr) {
           Block body;
           body.emplace_back(std::move(*epc));
@@ -1679,7 +1687,7 @@ struct LooselyStructuredBlockParser {
     if (lookAhead(skipStuffBeforeStatement >> "BLOCK"_tok).Parse(state)) {
       return std::nullopt;
     }
-    if (auto &&body{block.Parse(state)}) {
+    if (auto &&body{validBlock.Parse(state)}) {
       // Empty body is ok.
       return std::move(body);
     }
@@ -1718,7 +1726,7 @@ struct NonBlockDoConstructParser {
 
     if (auto &&nbd{nonBlockDo.Parse(state)}) {
       processEpc(std::move(*nbd));
-      while (auto &&epc{attempt(executionPartConstruct).Parse(state)}) {
+      while (auto &&epc{attempt(validEPC).Parse(state)}) {
         processEpc(std::move(*epc));
         if (labels.empty()) {
           break;
@@ -1840,7 +1848,7 @@ struct OmpStatementConstructParser {
   std::optional<resultType> Parse(ParseState &state) const {
     if (auto begin{OmpBeginDirectiveParser(dir_).Parse(state)}) {
       Block body;
-      if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) {
+      if (auto stmt{attempt(validEPC).Parse(state)}) {
         body.emplace_back(std::move(*stmt));
       }
       // Allow empty block. Check for this in semantics.
@@ -1924,7 +1932,7 @@ struct OmpLoopConstructParser {
         }
       } else if (assoc == llvm::omp::Association::LoopSeq) {
         // Parse loop sequence as a block.
-        if (auto &&body{block.Parse(state)}) {
+        if (auto &&body{validBlock.Parse(state)}) {
           auto end{maybe(OmpEndDirectiveParser{loopDir}).Parse(state)};
           return OpenMPLoopConstruct{OmpBeginLoopDirective(std::move(*begin)),
               std::move(*body),
@@ -2021,11 +2029,9 @@ struct OmpAtomicConstructParser {
       return std::nullopt;
     }
 
-    auto exec{Parser<ExecutionPartConstruct>{}};
-    auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}};
     TailType tail;
 
-    if (ParseOne(exec, end, tail, state)) {
+    if (ParseOne(tail, state)) {
       if (!tail.first.empty()) {
         if (auto &&rest{attempt(LimitedTailParser(BodyLimit)).Parse(state)}) {
           for (auto &&s : rest->first) {
@@ -2052,13 +2058,12 @@ struct OmpAtomicConstructParser {
 
   // Parse either an ExecutionPartConstruct, or atomic end-directive. When
   // successful, record the result in the "tail" provided, otherwise fail.
-  static std::optional<Success> ParseOne( //
-      Parser<ExecutionPartConstruct> &exec, OmpEndDirectiveParser &end,
-      TailType &tail, ParseState &state) {
-    auto isRecovery{[](const ExecutionPartConstruct &e) {
-      return std::holds_alternative<ErrorRecovery>(e.u);
+  static std::optional<Success> ParseOne(TailType &tail, ParseState &state) {
+    auto isUsable{[](const std::optional<ExecutionPartConstruct> &e) {
+      return e && !std::holds_alternative<ErrorRecovery>(e->u);
     }};
-    if (auto &&stmt{attempt(exec).Parse(state)}; stmt && !isRecovery(*stmt)) {
+    auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}};
+    if (auto &&stmt{attempt(validEPC).Parse(state)}; isUsable(stmt)) {
       tail.first.emplace_back(std::move(*stmt));
     } else if (auto &&dir{attempt(end).Parse(state)}) {
       tail.second = std::move(*dir);
@@ -2074,12 +2079,10 @@ struct OmpAtomicConstructParser {
     constexpr LimitedTailParser(size_t count) : count_(count) {}
 
     std::optional<resultType> Parse(ParseState &state) const {
-      auto exec{Parser<ExecutionPartConstruct>{}};
-      auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}};
       TailType tail;
 
       for (size_t i{0}; i != count_; ++i) {
-        if (ParseOne(exec, end, tail, state)) {
+        if (ParseOne(tail, state)) {
           if (tail.second) {
             // Return when the end-directive was parsed.
             return std::move(tail);
@@ -2351,9 +2354,9 @@ TYPE_PARSER(sourced(construct<OpenMPSectionsConstruct>(
     Parser<OmpBeginSectionsDirective>{} / endOmpLine,
     cons( //
         construct<OpenMPConstruct>(sourced(
-            construct<OpenMPSectionConstruct>(maybe(sectionDir), block))),
-        many(construct<OpenMPConstruct>(
-            sourced(construct<OpenMPSectionConstruct>(sectionDir, block))))),
+            construct<OpenMPSectionConstruct>(maybe(sectionDir), validBlock))),
+        many(construct<OpenMPConstruct>(sourced(
+            construct<OpenMPSectionConstruct>(sectionDir, validBlock))))),
     maybe(Parser<OmpEndSectionsDirective>{} / endOmpLine))))
 
 static bool IsExecutionPart(const OmpDirectiveName &name) {
@@ -2429,4 +2432,14 @@ static constexpr DirectiveSet GetLoopDirectives() {
 TYPE_PARSER(sourced(construct<OpenMPLoopConstruct>(
     OmpLoopConstructParser(GetLoopDirectives()))))
 
+static constexpr DirectiveSet GetAllDirectives() { //
+  return ~DirectiveSet{};
+}
+
+TYPE_PARSER(construct<OpenMPMisplacedEndDirective>(
+    OmpEndDirectiveParser{GetAllDirectives()}))
+
+TYPE_PARSER( //
+    startOmpLine >> sourced(construct<OpenMPInvalidDirective>(
+                        !OmpDirectiveNameParser{} >> SkipTo<'\n'>{})))
 } // namespace Fortran::parser

diff  --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index 740dbbfab9db7..303335934a37a 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -201,6 +201,9 @@ TYPE_CONTEXT_PARSER("specification construct"_en_US,
         construct<SpecificationConstruct>(
             indirect(openaccDeclarativeConstruct)),
         construct<SpecificationConstruct>(indirect(openmpDeclarativeConstruct)),
+        construct<SpecificationConstruct>(
+            indirect(openmpMisplacedEndDirective)),
+        construct<SpecificationConstruct>(indirect(openmpInvalidDirective)),
         construct<SpecificationConstruct>(indirect(compilerDirective))))
 
 // R513 other-specification-stmt ->

diff  --git a/flang/lib/Parser/type-parsers.h b/flang/lib/Parser/type-parsers.h
index 3900c5a86c874..142aa226893b6 100644
--- a/flang/lib/Parser/type-parsers.h
+++ b/flang/lib/Parser/type-parsers.h
@@ -139,7 +139,8 @@ constexpr Parser<OpenACCDeclarativeConstruct> openaccDeclarativeConstruct;
 constexpr Parser<OpenMPConstruct> openmpConstruct;
 constexpr Parser<OpenMPExecDirective> openmpExecDirective;
 constexpr Parser<OpenMPDeclarativeConstruct> openmpDeclarativeConstruct;
-constexpr Parser<OmpEndLoopDirective> ompEndLoopDirective;
+constexpr Parser<OpenMPMisplacedEndDirective> openmpMisplacedEndDirective;
+constexpr Parser<OpenMPInvalidDirective> openmpInvalidDirective;
 constexpr Parser<IntrinsicVectorTypeSpec> intrinsicVectorTypeSpec; // Extension
 constexpr Parser<VectorTypeSpec> vectorTypeSpec; // Extension
 constexpr Parser<UnsignedTypeSpec> unsignedTypeSpec; // Extension

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index f81200d092b11..3854d33d46d48 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2706,6 +2706,16 @@ class UnparseVisitor {
     Put("\n");
     EndOpenMP();
   }
+  void Unparse(const OpenMPMisplacedEndDirective &x) {
+    Unparse(static_cast<const OmpEndDirective &>(x));
+  }
+  void Unparse(const OpenMPInvalidDirective &x) {
+    BeginOpenMP();
+    Word("!$OMP ");
+    Put(parser::ToUpperCaseLetters(x.source.ToString()));
+    Put("\n");
+    EndOpenMP();
+  }
   void Unparse(const BasedPointer &x) {
     Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t));
     Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')');

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 63751fd0c8abd..b2cc86a5260b4 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -5476,6 +5476,25 @@ void OmpStructureChecker::CheckAllowedRequiresClause(llvmOmpClause clause) {
   }
 }
 
+void OmpStructureChecker::Enter(const parser::OpenMPMisplacedEndDirective &x) {
+  context_.Say(x.DirName().source, "Misplaced OpenMP end-directive"_err_en_US);
+  PushContextAndClauseSets(
+      x.DirName().source, llvm::omp::Directive::OMPD_unknown);
+}
+
+void OmpStructureChecker::Leave(const parser::OpenMPMisplacedEndDirective &x) {
+  dirContext_.pop_back();
+}
+
+void OmpStructureChecker::Enter(const parser::OpenMPInvalidDirective &x) {
+  context_.Say(x.source, "Invalid OpenMP directive"_err_en_US);
+  PushContextAndClauseSets(x.source, llvm::omp::Directive::OMPD_unknown);
+}
+
+void OmpStructureChecker::Leave(const parser::OpenMPInvalidDirective &x) {
+  dirContext_.pop_back();
+}
+
 // Use when clause falls under 'struct OmpClause' in 'parse-tree.h'.
 #define CHECK_SIMPLE_CLAUSE(X, Y) \
   void OmpStructureChecker::Enter(const parser::OmpClause::X &) { \

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 3e5de0071aca7..a99d7c32a3f2b 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -94,6 +94,11 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
   void Enter(const parser::OpenMPDeclarativeConstruct &);
   void Leave(const parser::OpenMPDeclarativeConstruct &);
 
+  void Enter(const parser::OpenMPMisplacedEndDirective &);
+  void Leave(const parser::OpenMPMisplacedEndDirective &);
+  void Enter(const parser::OpenMPInvalidDirective &);
+  void Leave(const parser::OpenMPInvalidDirective &);
+
   void Enter(const parser::OpenMPLoopConstruct &);
   void Leave(const parser::OpenMPLoopConstruct &);
   void Enter(const parser::OmpEndLoopDirective &);

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index bd6c1f8e4c776..673ea4ef10e08 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -532,6 +532,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
   void Post(const parser::OmpBeginLoopDirective &) {
     GetContext().withinConstruct = true;
   }
+  bool Pre(const parser::OpenMPMisplacedEndDirective &x) { return false; }
+  bool Pre(const parser::OpenMPInvalidDirective &x) { return false; }
+
   bool Pre(const parser::DoConstruct &);
 
   bool Pre(const parser::OpenMPSectionsConstruct &);

diff  --git a/flang/test/Parser/OpenMP/fail-construct2.f90 b/flang/test/Parser/OpenMP/fail-construct2.f90
index b7f5736d1329b..3798c3dae3f0d 100644
--- a/flang/test/Parser/OpenMP/fail-construct2.f90
+++ b/flang/test/Parser/OpenMP/fail-construct2.f90
@@ -1,5 +1,5 @@
 ! RUN: not %flang_fc1 -fsyntax-only -fopenmp %s 2>&1 | FileCheck %s
 
-! CHECK: error: expected OpenMP construct
+! CHECK: error: Invalid OpenMP directive
 !$omp dummy
 end

diff  --git a/flang/test/Parser/OpenMP/tile-fail.f90 b/flang/test/Parser/OpenMP/tile-fail.f90
index 3cb0ea96975c8..a69261a927961 100644
--- a/flang/test/Parser/OpenMP/tile-fail.f90
+++ b/flang/test/Parser/OpenMP/tile-fail.f90
@@ -8,7 +8,7 @@
 ! Parser error
 
 subroutine stray_end1
-  !CHECK: error: expected OpenMP construct
+  !CHECK: error: Misplaced OpenMP end-directive
   !$omp end tile
 end subroutine
 
@@ -17,7 +17,7 @@ subroutine stray_end1
 
 subroutine stray_end2
   print *
-  !CHECK: error: expected 'END'
+  !CHECK: error: Misplaced OpenMP end-directive
   !$omp end tile
 end subroutine
 

diff  --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index fda15eb9876ef..ad0b764b2cc28 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -252,6 +252,8 @@
   !$omp parallel do if(target:a>1.)
   do i = 1, N
   enddo
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end simd
 
 ! 2.7.2 sections-clause -> private-clause |
 !                         firstprivate-clause |
@@ -572,7 +574,8 @@
   do i = 1, N
      a = a + 3.14
   enddo
-  !$omp end taskloop simd
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end taskloop
 
   !ERROR: GRAINSIZE and NUM_TASKS clauses are mutually exclusive and may not appear on the same TASKLOOP SIMD directive
   !$omp taskloop simd num_tasks(3) grainsize(2)

diff  --git a/flang/test/Semantics/OpenMP/loop-association.f90 b/flang/test/Semantics/OpenMP/loop-association.f90
index b2898d3967a25..9c79a91429fdf 100644
--- a/flang/test/Semantics/OpenMP/loop-association.f90
+++ b/flang/test/Semantics/OpenMP/loop-association.f90
@@ -82,6 +82,8 @@
   do i = 1, N
   enddo
   !$omp end parallel do
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end parallel do
 
   !$omp parallel
   a = 3.0
@@ -97,6 +99,8 @@
   !$omp end parallel
 
   a = 0.0
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end parallel do
   !$omp parallel do private(c)
   do i = 1, N
      do j = 1, N
@@ -104,8 +108,12 @@
         !$omp parallel do shared(b)
         a = 3.14
      enddo
+     !ERROR: Misplaced OpenMP end-directive
+     !$omp end parallel do
   enddo
   a = 1.414
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end parallel do
 
   do i = 1, N
      !$omp parallel do
@@ -113,6 +121,8 @@
         a = 3.14
      enddo
   enddo
+  !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
   !$omp parallel do private(c)
@@ -120,15 +130,21 @@
   do i=1, N
      a = 3.14
   enddo
+  !ERROR: Misplaced OpenMP end-directive
+  !$omp end parallel do
 
   !$omp parallel do simd
   do i = 1, N
      a = 3.14
   enddo
   !$omp end parallel do simd
+  !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
   !$omp simd
+    a = i + 1
+  !ERROR: Misplaced OpenMP end-directive
   !$omp end simd
    a = i + 1
 end

diff  --git a/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
index 3c07d6d08508a..1b15c938915cd 100644
--- a/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
+++ b/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
@@ -2,13 +2,12 @@
 ! nested Loop Transformation Constructs
 
 !RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
-!XFAIL: *
 
 subroutine loop_transformation_construct1
   implicit none
 
   !$omp do
-  !ERROR: The FUSE construct requires the END FUSE directive
+  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp fuse 
 end subroutine
 
@@ -16,7 +15,7 @@ subroutine loop_transformation_construct2
   implicit none
 
   !$omp do
-  !ERROR: A DO loop must follow the FUSE directive
+  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp fuse 
   !$omp end fuse
 end subroutine
@@ -37,7 +36,7 @@ subroutine loop_transformation_construct3
   end do
   !$omp end fuse
   !$omp end do
-  !ERROR: The END FUSE directive must follow the DO loop associated with the loop construct
+  !ERROR: Misplaced OpenMP end-directive
   !$omp end fuse
 end subroutine
 
@@ -51,7 +50,7 @@ subroutine loop_transformation_construct4
   do x = 1, i
     v(x) = v(x) * 2
   end do
-  !ERROR: A DO loop must follow the FUSE directive
+  !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct
   !$omp fuse
   !$omp end fuse
 end subroutine
@@ -63,7 +62,7 @@ subroutine loop_transformation_construct5
   integer :: v(i)
 
   !$omp do
-  !ERROR: If a loop construct has been fully unrolled, it cannot then be further transformed
+  !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop
   !$omp fuse
   !$omp unroll full
   do x = 1, i
@@ -81,6 +80,7 @@ subroutine loop_transformation_construct6
   integer :: x
   integer :: v(i)
 
+  !ERROR: The loop sequence following the DO construct must be fully fused first.
   !$omp do
   !$omp fuse looprange(1,1)
   !$omp unroll partial(2)

diff  --git a/flang/test/Semantics/OpenMP/loop-transformation-construct03.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct03.f90
index ab6b1bd7d67f9..578c55b3c0aff 100644
--- a/flang/test/Semantics/OpenMP/loop-transformation-construct03.f90
+++ b/flang/test/Semantics/OpenMP/loop-transformation-construct03.f90
@@ -1,7 +1,6 @@
 ! Testing the Semantic failure of forming loop sequences under regular OpenMP directives 
 
 !RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
-!XFAIL: *
 
 subroutine loop_transformation_construct1
   implicit none
@@ -17,7 +16,7 @@ subroutine loop_transformation_construct1
   do x = 1, i
     v(x) = v(x) * 2
   end do
-  !ERROR: The END DO directive must follow the DO loop associated with the loop construct
+  !ERROR: Misplaced OpenMP end-directive
   !$omp end do
 end subroutine
 
@@ -35,6 +34,6 @@ subroutine loop_transformation_construct2
   do x = 1, i
     v(x) = v(x) * 2
   end do
-  !ERROR: The END TILE directive must follow the DO loop associated with the loop construct
+  !ERROR: Misplaced OpenMP end-directive
   !$omp end tile
 end subroutine


        


More information about the flang-commits mailing list