Add Semantic check for Flang OpenMP 4.5 - 2.7.1  Do Loop restrictions.
Implementation of Do loop iteration variable check, Do while loop check, Do loop cycle restrictions.
Also to check whether the ordered clause is present on the loop construct if any ordered region ever
 binds to a loop region arising from the loop construct.

Files:

check-omp-structure.h
check-omp-structure.cpp
resolve-directives.cpp

Testcases:

omp-do06-positivecases.f90
omp-do06.f90
omp-do08.f90
omp-do09.f90
omp-do10.f90
omp-do11.f90
omp-do12.f90
omp-do13.f90
omp-do14.f90
omp-do15.f90
omp-do16.f90
omp-do17.f90

Reviewed by: Kiran Chandramohan @kiranchandramohan , Valentin Clement @clementval

Differential Revision: https://reviews.llvm.org/D92732

GitOrigin-RevId: 20e3a6cb6270b68139f74529ab8efdfad1263533
diff --git a/lib/Semantics/check-omp-structure.cpp b/lib/Semantics/check-omp-structure.cpp
index bb642dc..4a9192d 100644
--- a/lib/Semantics/check-omp-structure.cpp
+++ b/lib/Semantics/check-omp-structure.cpp
@@ -84,6 +84,49 @@
   parser::CharBlock source_;
 };
 
+class OmpCycleChecker {
+public:
+  OmpCycleChecker(SemanticsContext &context, std::int64_t cycleLevel)
+      : context_{context}, cycleLevel_{cycleLevel} {}
+
+  template <typename T> bool Pre(const T &) { return true; }
+  template <typename T> void Post(const T &) {}
+
+  bool Pre(const parser::DoConstruct &dc) {
+    cycleLevel_--;
+    const auto &labelName{std::get<0>(std::get<0>(dc.t).statement.t)};
+    if (labelName) {
+      labelNamesandLevels_.emplace(labelName.value().ToString(), cycleLevel_);
+    }
+    return true;
+  }
+
+  bool Pre(const parser::CycleStmt &cyclestmt) {
+    std::map<std::string, std::int64_t>::iterator it;
+    bool err{false};
+    if (cyclestmt.v) {
+      it = labelNamesandLevels_.find(cyclestmt.v->source.ToString());
+      err = (it != labelNamesandLevels_.end() && it->second > 0);
+    }
+    if (cycleLevel_ > 0 || err) {
+      context_.Say(*cycleSource_,
+          "CYCLE statement to non-innermost associated loop of an OpenMP DO construct"_err_en_US);
+    }
+    return true;
+  }
+
+  bool Pre(const parser::Statement<parser::ActionStmt> &actionstmt) {
+    cycleSource_ = &actionstmt.source;
+    return true;
+  }
+
+private:
+  SemanticsContext &context_;
+  const parser::CharBlock *cycleSource_;
+  std::int64_t cycleLevel_;
+  std::map<std::string, std::int64_t> labelNamesandLevels_;
+};
+
 bool OmpStructureChecker::HasInvalidWorksharingNesting(
     const parser::CharBlock &source, const OmpDirectiveSet &set) {
   // set contains all the invalid closely nested directives
@@ -147,6 +190,9 @@
     const auto &doBlock{std::get<parser::Block>(doConstruct->t)};
     CheckNoBranching(doBlock, beginDir.v, beginDir.source);
   }
+  CheckDoWhile(x);
+  CheckLoopItrVariableIsInt(x);
+  CheckCycleConstraints(x);
 }
 const parser::Name OmpStructureChecker::GetLoopIndex(
     const parser::DoConstruct *x) {
@@ -163,6 +209,85 @@
     }
   }
 }
+void OmpStructureChecker::CheckDoWhile(const parser::OpenMPLoopConstruct &x) {
+  const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
+  const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
+  if (beginDir.v == llvm::omp::Directive::OMPD_do) {
+    if (const auto &doConstruct{
+            std::get<std::optional<parser::DoConstruct>>(x.t)}) {
+      if (doConstruct.value().IsDoWhile()) {
+        const auto &doStmt{std::get<parser::Statement<parser::NonLabelDoStmt>>(
+            doConstruct.value().t)};
+        context_.Say(doStmt.source,
+            "The DO loop cannot be a DO WHILE with DO directive."_err_en_US);
+      }
+    }
+  }
+}
+
+void OmpStructureChecker::CheckLoopItrVariableIsInt(
+    const parser::OpenMPLoopConstruct &x) {
+  if (const auto &loopConstruct{
+          std::get<std::optional<parser::DoConstruct>>(x.t)}) {
+
+    for (const parser::DoConstruct *loop{&*loopConstruct}; loop;) {
+      if (loop->IsDoNormal()) {
+        const parser::Name &itrVal{GetLoopIndex(loop)};
+        if (itrVal.symbol) {
+          const auto *type{itrVal.symbol->GetType()};
+          if (!type->IsNumeric(TypeCategory::Integer)) {
+            context_.Say(itrVal.source,
+                "The DO loop iteration"
+                " variable must be of the type integer."_err_en_US,
+                itrVal.ToString());
+          }
+        }
+      }
+      // Get the next DoConstruct if block is not empty.
+      const auto &block{std::get<parser::Block>(loop->t)};
+      const auto it{block.begin()};
+      loop = it != block.end() ? parser::Unwrap<parser::DoConstruct>(*it)
+                               : nullptr;
+    }
+  }
+}
+
+std::int64_t OmpStructureChecker::GetOrdCollapseLevel(
+    const parser::OpenMPLoopConstruct &x) {
+  const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
+  const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
+  std::int64_t orderedCollapseLevel{1};
+  std::int64_t orderedLevel{0};
+  std::int64_t collapseLevel{0};
+
+  for (const auto &clause : clauseList.v) {
+    if (const auto *collapseClause{
+            std::get_if<parser::OmpClause::Collapse>(&clause.u)}) {
+      if (const auto v{GetIntValue(collapseClause->v)}) {
+        collapseLevel = *v;
+      }
+    }
+    if (const auto *orderedClause{
+            std::get_if<parser::OmpClause::Ordered>(&clause.u)}) {
+      if (const auto v{GetIntValue(orderedClause->v)}) {
+        orderedLevel = *v;
+      }
+    }
+  }
+  if (orderedLevel >= collapseLevel) {
+    orderedCollapseLevel = orderedLevel;
+  } else {
+    orderedCollapseLevel = collapseLevel;
+  }
+  return orderedCollapseLevel;
+}
+
+void OmpStructureChecker::CheckCycleConstraints(
+    const parser::OpenMPLoopConstruct &x) {
+  std::int64_t ordCollapseLevel{GetOrdCollapseLevel(x)};
+  OmpCycleChecker ompCycleChecker{context_, ordCollapseLevel};
+  parser::Walk(x, ompCycleChecker);
+}
 
 void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) {
   dirContext_.pop_back();
@@ -199,6 +324,7 @@
     HasInvalidWorksharingNesting(
         beginDir.source, {llvm::omp::Directive::OMPD_do});
   }
+  CheckIfDoOrderedClause(beginDir);
 
   PushContextAndClauseSets(beginDir.source, beginDir.v);
   CheckNoBranching(block, beginDir.v, beginDir.source);
@@ -213,6 +339,18 @@
   }
 }
 
+void OmpStructureChecker::CheckIfDoOrderedClause(
+    const parser::OmpBlockDirective &blkDirective) {
+  if (blkDirective.v == llvm::omp::OMPD_ordered) {
+    if (!FindClause(llvm::omp::Clause::OMPC_ordered)) {
+      context_.Say(blkDirective.source,
+          "The ORDERED clause must be present on the loop"
+          " construct if any ORDERED region ever binds"
+          " to a loop region arising from the loop construct."_err_en_US);
+    }
+  }
+}
+
 void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
   dirContext_.pop_back();
 }
@@ -583,7 +721,6 @@
 
 void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
     const parser::OmpObjectList &objList) {
-
   for (const auto &ompObject : objList.v) {
     std::visit(
         common::visitors{
diff --git a/lib/Semantics/check-omp-structure.h b/lib/Semantics/check-omp-structure.h
index 0f42079..c5d98d3 100644
--- a/lib/Semantics/check-omp-structure.h
+++ b/lib/Semantics/check-omp-structure.h
@@ -165,6 +165,12 @@
   void CheckIsLoopIvPartOfClause(
       llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
   void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
+
+  void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
+  void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
+  void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
+  std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
+  void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv);
 };
 } // namespace Fortran::semantics
 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
diff --git a/lib/Semantics/resolve-directives.cpp b/lib/Semantics/resolve-directives.cpp
index a733571..59cdf20 100644
--- a/lib/Semantics/resolve-directives.cpp
+++ b/lib/Semantics/resolve-directives.cpp
@@ -1070,6 +1070,15 @@
   }
   ClearDataSharingAttributeObjects();
   SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList));
+
+  if (beginDir.v == llvm::omp::Directive::OMPD_do) {
+    if (const auto &doConstruct{
+            std::get<std::optional<parser::DoConstruct>>(x.t)}) {
+      if (doConstruct.value().IsDoWhile()) {
+        return true;
+      }
+    }
+  }
   PrivatizeAssociatedLoopIndexAndCheckLoopLevel(x);
   return true;
 }
diff --git a/test/Semantics/omp-do06-positivecases.f90 b/test/Semantics/omp-do06-positivecases.f90
new file mode 100644
index 0000000..0776817
--- /dev/null
+++ b/test/Semantics/omp-do06-positivecases.f90
@@ -0,0 +1,23 @@
+! RUN: %S/test_symbols.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.7.1 Loop Construct
+! The ordered clause must be present on the loop construct if any ordered
+! region ever binds to a loop region arising from the loop construct.
+
+! A positive case
+!DEF: /omp_do MainProgram
+program omp_do
+  !DEF: /omp_do/i ObjectEntity INTEGER(4)
+  !DEF: /omp_do/j ObjectEntity INTEGER(4)
+  !DEF: /omp_do/k ObjectEntity INTEGER(4)
+  integer i, j, k
+  !$omp do  ordered
+    !DEF: /omp_do/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+    do i=1,10
+      !$omp ordered
+      !DEF: /my_func EXTERNAL (Subroutine) ProcEntity
+      call my_func
+      !$omp end ordered
+    end do
+  !$omp end do
+end program omp_do
diff --git a/test/Semantics/omp-do06.f90 b/test/Semantics/omp-do06.f90
index bcba318..d687679 100644
--- a/test/Semantics/omp-do06.f90
+++ b/test/Semantics/omp-do06.f90
@@ -1,6 +1,4 @@
 ! RUN: %S/test_errors.sh %s %t %flang -fopenmp
-! XFAIL:*
-
 ! OpenMP Version 4.5
 ! 2.7.1 Loop Construct
 ! The ordered clause must be present on the loop construct if any ordered
@@ -11,11 +9,25 @@
 
   !$omp do
   do i = 1, 10
-    !ERROR: ‘ordered’ region inside a loop region without an ordered clause.
+    !ERROR: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct.
     !$omp ordered
     call my_func()
     !$omp end ordered
   end do
   !$omp end do
 
+  !$omp do ordered private(i)
+  do i = 1, 10
+    !$omp parallel do
+    do j = 1, 10
+      print *,i
+      !ERROR: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct.
+      !$omp ordered
+      print *,i
+      !$omp end ordered
+    end do
+    !$omp end parallel do
+  end do
+  !$omp end do
+
 end program omp_do
diff --git a/test/Semantics/omp-do08.f90 b/test/Semantics/omp-do08.f90
index 58e77b7..3ec7ac3 100644
--- a/test/Semantics/omp-do08.f90
+++ b/test/Semantics/omp-do08.f90
@@ -1,19 +1,138 @@
 ! RUN: %S/test_errors.sh %s %t %flang -fopenmp
-! XFAIL: *
-
 ! OpenMP Version 4.5
 ! 2.7.1 Loop Construct
 
-program omp_do
+program omp
   integer i, j, k
-  !$omp do collapse(2)
-  do i = 1, 10
-    !ERROR: CYCLE statement to non-innermost collapsed !$OMP DO loop
-    if (i .lt. 5) cycle
-    do j = 1, 10
-      print *, "Hello"
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  do i = 0, 10
+    !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+    if (i .lt. 1) cycle
+    do j = 0, 10
+      do k  = 0, 10
+        print *, i, j, k
+      end do
     end do
   end do
   !$omp end do
 
-end program omp_do
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  do i = 0, 10
+    do j = 0, 10
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      if (i .lt. 1) cycle
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(2)
+  do i = 0, 10
+    !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+    if (i .lt. 1) cycle
+    do j = 0, 10
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(2)
+  foo: do i = 0, 10
+    !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+    if (i .lt. 1) cycle foo
+    do j = 0, 10
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do foo
+  !$omp end do
+
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do collapse(3)
+  do 60 i=2,200,2
+    do j=1,10
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      if(i==100) cycle
+      do k=1,10
+        print *,i
+      end do
+    end do
+  60 continue
+  !$omp end do
+
+  !$omp do  collapse(3)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+         foo2:  do k  = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             if (k .lt. 1) cycle foo
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+  !$omp do  collapse(3)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+         foo2:  do k  = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             if (k .lt. 1) cycle foo1
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+
+  !$omp do  collapse(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+         foo2:  do k  = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             if (k .lt. 1) cycle foo
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+
+  !$omp do  ordered(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             if (k .lt. 1) cycle foo
+         foo2:  do k  = 0, 10
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(2) ordered(3)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             if (k .lt. 1) cycle foo
+         foo2:  do k  = 0, 10
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+end program omp
diff --git a/test/Semantics/omp-do09.f90 b/test/Semantics/omp-do09.f90
index 22a9b56..9ce2757 100644
--- a/test/Semantics/omp-do09.f90
+++ b/test/Semantics/omp-do09.f90
@@ -1,22 +1,26 @@
-! RUN: %S/test_errors.sh %s %t %flang -fopenmp
-! XFAIL: *
-
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
 ! OpenMP Version 4.5
 ! 2.7.1 Loop Construct
 ! The do-loop cannot be a DO WHILE or a DO loop without loop control.
 
 program omp_do
-  integer i, j, k
-  i = 0
-
+  integer ::  i = 0,k
   !$omp do
-  !ERROR: !$OMP DO cannot be a DO WHILE or DO without loop control
-  do while (i .lt. 10)
-    do j = 1, 10
-      print *, "Hello"
-    end do
-    i = i + 1
+  !ERROR: The DO loop cannot be a DO WHILE with DO directive.
+  do while (i <= 10)
+    print *, "it",i
+    i = i+1
   end do
   !$omp end do
 
+  !$omp do
+  !ERROR: The DO loop cannot be a DO WHILE with DO directive.
+  do while (i <= 10)
+    do while (j <= 10)
+      print *, "it",k
+      j = j+1
+    end do
+    i = i+1
+  end do
+  !$omp end do
 end program omp_do
diff --git a/test/Semantics/omp-do10.f90 b/test/Semantics/omp-do10.f90
index cc2071d..b06065c 100644
--- a/test/Semantics/omp-do10.f90
+++ b/test/Semantics/omp-do10.f90
@@ -1,18 +1,37 @@
-! RUN: %S/test_errors.sh %s %t %flang -fopenmp
-! XFAIL: *
-
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
 ! OpenMP Version 4.5
 ! 2.7.1 Loop Construct
-! The do-loop iteration variable must be of type integer.
+! The DO loop iteration variable must be of type integer.
 
 program omp_do
   real i, j, k
-
   !$omp do
-  !ERROR: The do-loop iteration variable must be of type integer.
+  !ERROR: The DO loop iteration variable must be of the type integer.
   do i = 1, 10
+    !ERROR: The DO loop iteration variable must be of the type integer.
     do j = 1, 10
-      print *, "Hello"
+      print *, "it", i, j
+    end do
+  end do
+  !$omp end do
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do collapse(3)
+  !ERROR: The DO loop iteration variable must be of the type integer.
+  do i = 1, 10
+    !ERROR: The DO loop iteration variable must be of the type integer.
+    do j = 1, 10
+      print *, "it", i, j
+    end do
+  end do
+  !$omp end do
+
+  !$omp do collapse(2)
+  !ERROR: The DO loop iteration variable must be of the type integer.
+  do i = 1, 10
+    !ERROR: The DO loop iteration variable must be of the type integer.
+    do j = 1, 10
+      print *, "it", i, j
     end do
   end do
   !$omp end do
diff --git a/test/Semantics/omp-do11.f90 b/test/Semantics/omp-do11.f90
new file mode 100644
index 0000000..7ce034c
--- /dev/null
+++ b/test/Semantics/omp-do11.f90
@@ -0,0 +1,36 @@
+! RUN: %S/test_symbols.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.7.1 Do Loop Constructs
+
+!DEF: /omp_do MainProgram
+program omp_do
+  !DEF: /omp_do/i ObjectEntity INTEGER(4)
+  !DEF: /omp_do/j ObjectEntity INTEGER(4)
+  !DEF: /omp_do/k ObjectEntity INTEGER(4)
+  integer i, j, k
+  !$omp do
+  !DEF: /omp_do/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=1,10
+    !REF: /omp_do/j
+    do j=1,10
+      !REF: /omp_do/Block1/i
+      !REF: /omp_do/j
+      print *, "it", i, j
+    end do
+  end do
+  !$omp end do
+end program omp_do
+
+!DEF: /omp_do2 MainProgram
+program omp_do2
+  !DEF: /omp_do2/i ObjectEntity INTEGER(4)
+  !DEF: /omp_do2/k ObjectEntity INTEGER(4)
+  integer :: i = 0, k
+  !$omp do
+  !DEF: /omp_do2/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=1,10
+    !REF: /omp_do2/Block1/i
+    print *, "it", i
+  end do
+  !$omp end do
+end program omp_do2
diff --git a/test/Semantics/omp-do12.f90 b/test/Semantics/omp-do12.f90
new file mode 100644
index 0000000..baabb7e
--- /dev/null
+++ b/test/Semantics/omp-do12.f90
@@ -0,0 +1,96 @@
+! RUN: %S/test_symbols.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.7.1 Do Loop constructs.
+
+!DEF: /omp_cycle MainProgram
+program omp_cycle
+  !$omp do  collapse(1)
+  !DEF: /omp_cycle/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=0,10
+    !REF: /omp_cycle/Block1/i
+    if (i<1) cycle
+    !DEF: /omp_cycle/j (Implicit) ObjectEntity INTEGER(4)
+    do j=0,10
+      !DEF: /omp_cycle/k (Implicit) ObjectEntity INTEGER(4)
+      do k=0,10
+        !REF: /omp_cycle/Block1/i
+        !REF: /omp_cycle/j
+        !REF: /omp_cycle/k
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  collapse(1)
+  !DEF: /omp_cycle/Block2/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=0,10
+    !REF: /omp_cycle/j
+    do j=0,10
+      !REF: /omp_cycle/Block2/i
+      if (i<1) cycle
+      !REF: /omp_cycle/k
+      do k=0,10
+        !REF: /omp_cycle/Block2/i
+        !REF: /omp_cycle/j
+        !REF: /omp_cycle/k
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  collapse(2)
+  !DEF: /omp_cycle/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=0,10
+    !DEF: /omp_cycle/Block3/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+    do j=0,10
+      !REF: /omp_cycle/k
+      do k=0,10
+        !REF: /omp_cycle/Block3/i
+        if (i<1) cycle
+        !REF: /omp_cycle/Block3/i
+        !REF: /omp_cycle/Block3/j
+        !REF: /omp_cycle/k
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  collapse(3)
+  !DEF: /omp_cycle/Block4/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=0,10
+    !DEF: /omp_cycle/Block4/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+    do j=0,10
+      !DEF: /omp_cycle/Block4/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+      do k=0,10
+        !REF: /omp_cycle/Block4/i
+        if (i<1) cycle
+        !REF: /omp_cycle/Block4/i
+        !REF: /omp_cycle/Block4/j
+        !REF: /omp_cycle/Block4/k
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  collapse(3)
+  !DEF: /omp_cycle/Block5/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  foo:do i=0,10
+    !DEF: /omp_cycle/Block5/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+    foo1:do j=0,10
+      !DEF: /omp_cycle/Block5/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+      foo2:do k=0,10
+        !REF: /omp_cycle/Block5/i
+        if (i<1) cycle foo2
+        !REF: /omp_cycle/Block5/i
+        !REF: /omp_cycle/Block5/j
+        !REF: /omp_cycle/Block5/k
+        print *, i, j, k
+      end do foo2
+    end do foo1
+  end do foo
+  !$omp end do
+end program omp_cycle
diff --git a/test/Semantics/omp-do13.f90 b/test/Semantics/omp-do13.f90
new file mode 100644
index 0000000..3a4fb9a
--- /dev/null
+++ b/test/Semantics/omp-do13.f90
@@ -0,0 +1,185 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.7.1 Loop Construct
+
+program omp
+  integer i, j, k
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  do i = 0, 10
+    !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+    cycle
+    do j = 0, 10
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  do i = 0, 10
+    do j = 0, 10
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      cycle
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(2)
+  do i = 0, 10
+    !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+    cycle
+    do j = 0, 10
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(2)
+  foo: do i = 0, 10
+    !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+    cycle foo
+    do j = 0, 10
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do foo
+  !$omp end do
+
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do collapse(3)
+  do 60 i=1,10
+    do j=1,10
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      cycle
+      do k=1,10
+        print *,i
+      end do
+    end do
+  60 continue
+  !$omp end do
+
+  !$omp do  collapse(3)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+         foo2:  do k  = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             cycle foo
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+  !$omp do  collapse(3)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+         foo2:  do k  = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+              cycle foo1
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+
+  !$omp do  collapse(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+         foo2:  do k  = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             cycle foo
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+
+  !$omp do  collapse(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             cycle foo
+         foo2:  do k  = 0, 10
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+  !$omp do  ordered(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      cycle foo
+      !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
+      !$omp do  collapse(1)
+      foo2:  do k  = 0, 10
+        print *, i, j, k
+        end do foo2
+     !$omp end do
+     end do foo1
+  end do foo
+  !$omp end do
+
+  !$omp parallel
+  !$omp do collapse(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      cycle foo
+      !$omp parallel
+      !$omp do collapse(2)
+      foo2:  do k  = 0, 10
+        foo3:  do l  = 0, 10
+          print *, i, j, k, l
+          !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+          cycle foo2
+        end do foo3
+      end do foo2
+      !$omp end do
+      !$omp end parallel
+    end do foo1
+  end do foo
+  !$omp end do
+  !$omp end parallel
+
+  !$omp parallel
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp parallel do ordered(3) collapse(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      cycle foo
+      !$omp parallel
+      !$omp parallel do collapse(2)
+      foo2:  do k  = 0, 10
+        foo3:  do l  = 0, 10
+          print *, i, j, k, l
+          !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+          cycle foo2
+        end do foo3
+      end do foo2
+      !$omp end parallel do
+      !$omp end parallel
+    end do foo1
+  end do foo
+!$omp end parallel do
+!$omp end parallel
+
+end program omp
diff --git a/test/Semantics/omp-do14.f90 b/test/Semantics/omp-do14.f90
new file mode 100644
index 0000000..df4a369
--- /dev/null
+++ b/test/Semantics/omp-do14.f90
@@ -0,0 +1,91 @@
+! RUN: %S/test_symbols.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.7.1 Do Loop constructs.
+
+!DEF: /omp_cycle MainProgram
+program omp_cycle
+  !$omp do  collapse(1)
+  !DEF: /omp_cycle/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=0,10
+    cycle
+    !DEF: /omp_cycle/j (Implicit) ObjectEntity INTEGER(4)
+    do j=0,10
+      !DEF: /omp_cycle/k (Implicit) ObjectEntity INTEGER(4)
+      do k=0,10
+        !REF: /omp_cycle/Block1/i
+        !REF: /omp_cycle/j
+        !REF: /omp_cycle/k
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  collapse(1)
+  !DEF: /omp_cycle/Block2/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=0,10
+    !REF: /omp_cycle/j
+    do j=0,10
+      cycle
+      !REF: /omp_cycle/k
+      do k=0,10
+        !REF: /omp_cycle/Block2/i
+        !REF: /omp_cycle/j
+        !REF: /omp_cycle/k
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  collapse(2)
+  !DEF: /omp_cycle/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=0,10
+    !DEF: /omp_cycle/Block3/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+    do j=0,10
+      !REF: /omp_cycle/k
+      do k=0,10
+        cycle
+        !REF: /omp_cycle/Block3/i
+        !REF: /omp_cycle/Block3/j
+        !REF: /omp_cycle/k
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  collapse(3)
+  !DEF: /omp_cycle/Block4/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  do i=0,10
+    !DEF: /omp_cycle/Block4/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+    do j=0,10
+      !DEF: /omp_cycle/Block4/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+      do k=0,10
+        cycle
+        !REF: /omp_cycle/Block4/i
+        !REF: /omp_cycle/Block4/j
+        !REF: /omp_cycle/Block4/k
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  ordered(3)
+  !DEF: /omp_cycle/Block5/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  foo:do i=0,10
+    !DEF: /omp_cycle/Block5/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+    foo1:do j=0,10
+      !DEF: /omp_cycle/Block5/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+      foo2:do k=0,10
+        cycle foo2
+        !REF: /omp_cycle/Block5/i
+        !REF: /omp_cycle/Block5/j
+        !REF: /omp_cycle/Block5/k
+        print *, i, j, k
+      end do foo2
+    end do foo1
+  end do foo
+  !$omp end do
+end program omp_cycle
diff --git a/test/Semantics/omp-do15.f90 b/test/Semantics/omp-do15.f90
new file mode 100644
index 0000000..955e6aa
--- /dev/null
+++ b/test/Semantics/omp-do15.f90
@@ -0,0 +1,94 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.7.1 Loop Construct
+
+program omp
+  integer i, j, k
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  do i = 0, 10
+    if (i .lt. 1) then
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      cycle
+    end if
+    do j = 0, 10
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  do i = 0, 10
+    do j = 0, 10
+      if (i .lt. 1) then
+        !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+        cycle
+      end if
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !!ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+      if (i .lt. 1) then
+        !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+        cycle foo
+      else if (i .gt. 3) then
+        cycle foo1
+      end if
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do foo1
+  end do foo
+  !$omp end do
+
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+      if (i .lt. 1) then
+        !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+        cycle foo
+      else if (i .gt. 3) then
+        !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+        cycle foo1
+      end if
+         foo2:  do k  = 0, 10
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+  !$omp do  ordered(3)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+         foo2:  do k  = 0, 10
+           if (i .lt. 1) then
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             cycle foo
+           else if (i .gt. 3) then
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             cycle foo1
+          else
+             !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+             cycle foo
+          end if
+             print *, i, j, k
+           end do foo2
+         end do foo1
+  end do foo
+  !$omp end do
+
+end program omp
diff --git a/test/Semantics/omp-do16.f90 b/test/Semantics/omp-do16.f90
new file mode 100644
index 0000000..05cd817
--- /dev/null
+++ b/test/Semantics/omp-do16.f90
@@ -0,0 +1,77 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.7.1 Loop Construct
+
+program omp
+  integer i, j, k
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  do i = 0, 10
+    select case (i)
+    case(1)
+      !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+      cycle
+    end select
+    do j = 0, 10
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
+  !$omp do  collapse(3)
+  do i = 0, 10
+    do j = 0, 10
+      select case (i)
+      case(1)
+        !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+        cycle
+      end select
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do
+  end do
+  !$omp end do
+
+  !$omp do  collapse(2)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+      select case (i)
+      case(1)
+        !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+        cycle foo
+      case(5)
+        cycle foo1
+      end select
+      do k  = 0, 10
+        print *, i, j, k
+      end do
+    end do foo1
+  end do foo
+  !$omp end do
+
+  !$omp do  ordered(3)
+  foo: do i = 0, 10
+    foo1: do j = 0, 10
+      foo2: do k  = 0, 10
+        select case (i)
+        case(1)
+          !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+          cycle foo
+        case(5)
+          !ERROR: CYCLE statement to non-innermost associated loop of an OpenMP DO construct
+          cycle foo1
+        case(7)
+          cycle foo2
+        end select
+        print *, i, j, k
+      end do foo2
+    end do foo1
+  end do foo
+  !$omp end do
+
+end program omp
diff --git a/test/Semantics/omp-do17.f90 b/test/Semantics/omp-do17.f90
new file mode 100644
index 0000000..54f315c
--- /dev/null
+++ b/test/Semantics/omp-do17.f90
@@ -0,0 +1,57 @@
+! RUN: %S/test_symbols.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.7.1 Do Loop constructs.
+
+!DEF: /test MainProgram
+program test
+ !DEF: /test/i ObjectEntity INTEGER(4)
+ !DEF: /test/j ObjectEntity INTEGER(4)
+ !DEF: /test/k ObjectEntity INTEGER(4)
+ integer i, j, k
+ !$omp do  collapse(2)
+ !DEF: /test/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+ foo: do i=0,10
+  !DEF: /test/Block1/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  foo1: do j=0,10
+   !REF: /test/k
+   foo2: do k=0,10
+    !REF: /test/Block1/i
+    select case (i)
+    case (5)
+     cycle foo1
+    case (7)
+     cycle foo2
+    end select
+    !REF: /test/Block1/i
+    !REF: /test/Block1/j
+    !REF: /test/k
+    print *, i, j, k
+   end do foo2
+  end do foo1
+ end do foo
+
+ !$omp do  collapse(2)
+ !DEF: /test/Block2/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+ foo: do i=0,10
+  !DEF: /test/Block2/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+  foo1: do j=0,10
+   !REF: /test/k
+   foo2: do k=0,10
+    !REF: /test/Block2/i
+    if (i<3) then
+     cycle foo1
+     !REF: /test/Block2/i
+    else if (i>8) then
+     cycle foo1
+    else
+     cycle foo2
+    end if
+    !REF: /test/Block2/i
+    !REF: /test/Block2/j
+    !REF: /test/k
+    print *, i, j, k
+   end do foo2
+  end do foo1
+ end do foo
+!$omp end do
+end program test