[Flang][OpenMP] Add more sema checks for ordered construct

This patch fixes a bug to allow ordered construct within a non-worksharing loop, also adds more sema checks.

Reviewed By: kiranchandramohan

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

GitOrigin-RevId: e27654f737da8e3a80d8c1e3509868ab7fb4265b
diff --git a/lib/Semantics/check-omp-structure.cpp b/lib/Semantics/check-omp-structure.cpp
index a3a3fd5..3ed8613 100644
--- a/lib/Semantics/check-omp-structure.cpp
+++ b/lib/Semantics/check-omp-structure.cpp
@@ -343,12 +343,22 @@
 void OmpStructureChecker::CheckIfDoOrderedClause(
     const parser::OmpBlockDirective &blkDirective) {
   if (blkDirective.v == llvm::omp::OMPD_ordered) {
-    if (!FindClauseParent(llvm::omp::Clause::OMPC_ordered)) {
+    // Loops
+    if (llvm::omp::doSet.test(GetContextParent().directive) &&
+        !FindClauseParent(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);
     }
+    // Other disallowed nestings, these directives do not support
+    // ordered clause in them, so no need to check
+    else if (llvm::omp::nestedOrderedErrSet.test(
+                 GetContextParent().directive)) {
+      context_.Say(blkDirective.source,
+          "`ORDERED` region may not be closely nested inside of "
+          "`CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region."_err_en_US);
+    }
   }
 }
 
diff --git a/lib/Semantics/check-omp-structure.h b/lib/Semantics/check-omp-structure.h
index f11ddc6..0d11f72 100644
--- a/lib/Semantics/check-omp-structure.h
+++ b/lib/Semantics/check-omp-structure.h
@@ -73,6 +73,9 @@
     Directive::OMPD_teams_distribute_simd};
 static OmpDirectiveSet taskGeneratingSet{
     OmpDirectiveSet{Directive::OMPD_task} | taskloopSet};
+static OmpDirectiveSet nestedOrderedErrSet{Directive::OMPD_critical,
+    Directive::OMPD_ordered, Directive::OMPD_atomic, Directive::OMPD_task,
+    Directive::OMPD_taskloop};
 static OmpClauseSet privateSet{
     Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
 static OmpClauseSet privateReductionSet{
diff --git a/test/Semantics/omp-ordered-simd.f90 b/test/Semantics/omp-ordered-simd.f90
new file mode 100644
index 0000000..d597191
--- /dev/null
+++ b/test/Semantics/omp-ordered-simd.f90
@@ -0,0 +1,95 @@
+! RUN: %S/test_errors.sh %s %t %flang -fopenmp
+! OpenMP Version 4.5
+! Various checks with the ordered construct
+
+SUBROUTINE WORK(I)
+  INTEGER I
+END SUBROUTINE WORK
+
+SUBROUTINE ORDERED_GOOD(N)
+  INTEGER N, I, A(10), B(10), C(10) 
+  !$OMP SIMD
+  DO I = 1,N
+    IF (I <= 10) THEN
+      !$OMP ORDERED SIMD
+      CALL WORK(I)
+      !$OMP END ORDERED
+    ENDIF
+  END DO
+  !$OMP END SIMD
+END SUBROUTINE ORDERED_GOOD
+
+SUBROUTINE ORDERED_BAD(N)
+  INTEGER N, I, A(10), B(10), C(10)
+
+  !$OMP DO SIMD
+  DO I = 1,N
+    IF (I <= 10) THEN
+      !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 WORK(I)
+      !$OMP END ORDERED
+    ENDIF
+  END DO
+  !$OMP END DO SIMD
+
+  !$OMP PARALLEL DO
+  DO I = 1,N
+    IF (I <= 10) THEN
+      !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 WORK(I)
+      !$OMP END ORDERED
+    ENDIF
+  END DO
+  !$OMP END PARALLEL DO
+
+  !$OMP CRITICAL  
+  DO I = 1,N
+    IF (I <= 10) THEN
+      !ERROR: `ORDERED` region may not be closely nested inside of `CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region.
+      !$OMP ORDERED 
+      CALL WORK(I)
+      !$OMP END ORDERED
+    ENDIF
+  END DO
+  !$OMP END CRITICAL
+
+  !$OMP CRITICAL
+    WRITE(*,*) I
+    !ERROR: `ORDERED` region may not be closely nested inside of `CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region.
+    !$OMP ORDERED 
+    CALL WORK(I)
+    !$OMP END ORDERED
+  !$OMP END CRITICAL
+
+  !$OMP ORDERED 
+    WRITE(*,*) I
+    IF (I <= 10) THEN
+      !ERROR: `ORDERED` region may not be closely nested inside of `CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region.
+      !$OMP ORDERED 
+      CALL WORK(I)
+      !$OMP END ORDERED
+    ENDIF
+  !$OMP END ORDERED
+
+  !$OMP TASK  
+    C =  C - A * B
+    !ERROR: `ORDERED` region may not be closely nested inside of `CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region.
+    !$OMP ORDERED 
+    CALL WORK(I)
+    !$OMP END ORDERED
+  !$OMP END TASK
+
+  !$OMP TASKLOOP 
+  DO I = 1,N
+    IF (I <= 10) THEN
+      !ERROR: `ORDERED` region may not be closely nested inside of `CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region.
+      !$OMP ORDERED 
+      CALL WORK(I)
+      !$OMP END ORDERED
+    ENDIF
+  END DO
+  !$OMP END TASKLOOP
+
+END SUBROUTINE ORDERED_BAD