[flang-commits] [flang] [llvm] [Flang][OpenMP][Sema] Adding parsing and semantic support for scan directive. (PR #102792)

Anchu Rajendran S via flang-commits flang-commits at lists.llvm.org
Thu Nov 14 19:09:04 PST 2024


https://github.com/anchuraj updated https://github.com/llvm/llvm-project/pull/102792

>From ee14b03770f550818618e78b8e0aeb86c6af79a1 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 8 Aug 2024 15:28:26 -0500
Subject: [PATCH 01/10] Adding parsing support for scan directive.

---
 flang/lib/Lower/OpenMP/OpenMP.cpp             |   3 +
 flang/lib/Parser/openmp-parsers.cpp           |   5 +
 flang/lib/Parser/unparse.cpp                  |   3 +
 flang/lib/Semantics/check-omp-structure.cpp   | 113 ++++++++++--------
 flang/lib/Semantics/resolve-directives.cpp    |  16 +++
 flang/test/Parser/OpenMP/scan.f90             |  40 +++++++
 flang/test/Semantics/OpenMP/do05.f90          |   8 +-
 .../test/Semantics/OpenMP/nested-barrier.f90  |   4 +-
 flang/test/Semantics/OpenMP/nested-master.f90 |   2 +-
 flang/test/Semantics/OpenMP/nested-simd.f90   |  34 +++---
 flang/test/Semantics/OpenMP/ordered-simd.f90  |   2 +-
 flang/test/Semantics/OpenMP/scan.f90          |  19 +++
 llvm/include/llvm/Frontend/OpenMP/OMP.td      |   6 +-
 13 files changed, 177 insertions(+), 78 deletions(-)
 create mode 100644 flang/test/Parser/OpenMP/scan.f90
 create mode 100644 flang/test/Semantics/OpenMP/scan.f90

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 91f99ba4b0ca55..b651af3f2a6d98 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2520,6 +2520,9 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
   case llvm::omp::Directive::OMPD_parallel:
     genStandaloneParallel(converter, symTable, semaCtx, eval, loc, queue, item);
     break;
+  case llvm::omp::Directive::OMPD_scan:
+    TODO(loc, "Unhandled directive " + llvm::omp::getOpenMPDirectiveName(dir));
+    break;
   case llvm::omp::Directive::OMPD_section:
     llvm_unreachable("genOMPDispatch: OMPD_section");
     // Lowered in the enclosing genSectionsOp.
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index a46b06dce001f9..d5d870b9f6b75c 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -559,6 +559,8 @@ TYPE_PARSER(
         construct<OmpClause>(construct<OmpClause::DynamicAllocators>()) ||
     "ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>(
                    parenthesized(Parser<OmpObjectList>{}))) ||
+    "EXCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Exclusive>(
+                       parenthesized(Parser<OmpObjectList>{}))) ||
     "FILTER" >> construct<OmpClause>(construct<OmpClause::Filter>(
                     parenthesized(scalarIntExpr))) ||
     "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
@@ -578,6 +580,8 @@ TYPE_PARSER(
     "IF" >> construct<OmpClause>(construct<OmpClause::If>(
                 parenthesized(Parser<OmpIfClause>{}))) ||
     "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||
+    "INCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Inclusive>(
+                       parenthesized(Parser<OmpObjectList>{}))) ||
     "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
                            parenthesized(Parser<OmpObjectList>{}))) ||
     "LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
@@ -790,6 +794,7 @@ TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(verbatim("FLUSH"_tok),
 TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first(
     "BARRIER" >> pure(llvm::omp::Directive::OMPD_barrier),
     "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
+    "SCAN" >> pure(llvm::omp::Directive::OMPD_scan),
     "TARGET ENTER DATA" >> pure(llvm::omp::Directive::OMPD_target_enter_data),
     "TARGET EXIT DATA" >> pure(llvm::omp::Directive::OMPD_target_exit_data),
     "TARGET UPDATE" >> pure(llvm::omp::Directive::OMPD_target_update),
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 4b511da69832c5..10089f8384ebdf 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2393,6 +2393,9 @@ class UnparseVisitor {
     case llvm::omp::Directive::OMPD_barrier:
       Word("BARRIER ");
       break;
+    case llvm::omp::Directive::OMPD_scan:
+      Word("SCAN ");
+      break;
     case llvm::omp::Directive::OMPD_taskwait:
       Word("TASKWAIT ");
       break;
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index db7c15a0e0ec9c..e0d1a22f268faa 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -747,62 +747,70 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
   // current context yet.
   // TODO: Check for declare simd regions.
   bool eligibleSIMD{false};
-  common::visit(Fortran::common::visitors{
-                    // Allow `!$OMP ORDERED SIMD`
-                    [&](const parser::OpenMPBlockConstruct &c) {
-                      const auto &beginBlockDir{
-                          std::get<parser::OmpBeginBlockDirective>(c.t)};
-                      const auto &beginDir{
-                          std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
-                      if (beginDir.v == llvm::omp::Directive::OMPD_ordered) {
-                        const auto &clauses{
-                            std::get<parser::OmpClauseList>(beginBlockDir.t)};
-                        for (const auto &clause : clauses.v) {
-                          if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
-                            eligibleSIMD = true;
-                            break;
-                          }
-                        }
-                      }
-                    },
-                    [&](const parser::OpenMPSimpleStandaloneConstruct &c) {
-                      const auto &dir{
-                          std::get<parser::OmpSimpleStandaloneDirective>(c.t)};
-                      if (dir.v == llvm::omp::Directive::OMPD_ordered) {
-                        const auto &clauses{
-                            std::get<parser::OmpClauseList>(c.t)};
-                        for (const auto &clause : clauses.v) {
-                          if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
-                            eligibleSIMD = true;
-                            break;
-                          }
-                        }
-                      }
-                    },
-                    // Allowing SIMD construct
-                    [&](const parser::OpenMPLoopConstruct &c) {
-                      const auto &beginLoopDir{
-                          std::get<parser::OmpBeginLoopDirective>(c.t)};
-                      const auto &beginDir{
-                          std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
-                      if ((beginDir.v == llvm::omp::Directive::OMPD_simd) ||
-                          (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
-                        eligibleSIMD = true;
-                      }
-                    },
-                    [&](const parser::OpenMPAtomicConstruct &c) {
-                      // Allow `!$OMP ATOMIC`
-                      eligibleSIMD = true;
-                    },
-                    [&](const auto &c) {},
-                },
+  common::visit(
+      Fortran::common::visitors{
+          // Allow `!$OMP ORDERED SIMD`
+          [&](const parser::OpenMPBlockConstruct &c) {
+            const auto &beginBlockDir{
+                std::get<parser::OmpBeginBlockDirective>(c.t)};
+            const auto &beginDir{
+                std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
+            if (beginDir.v == llvm::omp::Directive::OMPD_ordered) {
+              const auto &clauses{
+                  std::get<parser::OmpClauseList>(beginBlockDir.t)};
+              for (const auto &clause : clauses.v) {
+                if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                  eligibleSIMD = true;
+                  break;
+                }
+              }
+            }
+          },
+          [&](const parser::OpenMPStandaloneConstruct &c) {
+            if (const auto &simpleConstruct =
+                    std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
+                        &c.u)) {
+              const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
+                  simpleConstruct->t)};
+              if (dir.v == llvm::omp::Directive::OMPD_ordered) {
+                const auto &clauses{
+                    std::get<parser::OmpClauseList>(simpleConstruct->t)};
+                for (const auto &clause : clauses.v) {
+                  if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                    eligibleSIMD = true;
+                    break;
+                  }
+                }
+              } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
+                eligibleSIMD = true;
+              }
+            }
+          },
+          // Allowing SIMD construct
+          [&](const parser::OpenMPLoopConstruct &c) {
+            const auto &beginLoopDir{
+                std::get<parser::OmpBeginLoopDirective>(c.t)};
+            const auto &beginDir{
+                std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
+            if ((beginDir.v == llvm::omp::Directive::OMPD_simd) ||
+                (beginDir.v == llvm::omp::Directive::OMPD_parallel_do_simd) ||
+                (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
+              eligibleSIMD = true;
+            }
+          },
+          [&](const parser::OpenMPAtomicConstruct &c) {
+            // Allow `!$OMP ATOMIC`
+            eligibleSIMD = true;
+          },
+          [&](const auto &c) {},
+      },
       c.u);
   if (!eligibleSIMD) {
     context_.Say(parser::FindSourceLocation(c),
         "The only OpenMP constructs that can be encountered during execution "
         "of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, "
-        "the `SIMD` construct and the `ORDERED` construct with the `SIMD` "
-        "clause."_err_en_US);
+        "the `SIMD` construct, the `SCAN` construct and the `ORDERED` "
+        "construct with the `SIMD` clause."_err_en_US);
   }
 }
 
@@ -2985,6 +2993,9 @@ void OmpStructureChecker::CheckReductionModifier(
     switch (dirCtx.directive) {
     case llvm::omp::Directive::OMPD_do: // worksharing-loop
     case llvm::omp::Directive::OMPD_do_simd: // worksharing-loop simd
+    case llvm::omp::Directive::
+        OMPD_parallel_do_simd: // worksharing-parallel-loop
+                               // simd
     case llvm::omp::Directive::OMPD_simd: // "simd"
       break;
     default:
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 83d666283a48c8..9963443b2365b9 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1623,9 +1623,11 @@ bool OmpAttributeVisitor::Pre(
     const parser::OpenMPSimpleStandaloneConstruct &x) {
   const auto &standaloneDir{
       std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
+  const auto &parentContext{GetContextIf()};
   switch (standaloneDir.v) {
   case llvm::omp::Directive::OMPD_barrier:
   case llvm::omp::Directive::OMPD_ordered:
+  case llvm::omp::Directive::OMPD_scan:
   case llvm::omp::Directive::OMPD_target_enter_data:
   case llvm::omp::Directive::OMPD_target_exit_data:
   case llvm::omp::Directive::OMPD_target_update:
@@ -1636,6 +1638,20 @@ bool OmpAttributeVisitor::Pre(
   default:
     break;
   }
+  if (standaloneDir.v == llvm::omp::Directive::OMPD_scan) {
+    if ((std::get<parser::OmpClauseList>(x.t).v.size() != 1)) {
+      context_.Say(standaloneDir.source,
+          "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
+    }
+    if (!parentContext ||
+        (llvm::omp::getDirectiveAssociation(parentContext->directive) !=
+            llvm::omp::Association::Loop)) {
+      context_.Say(standaloneDir.source,
+          "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
+          "to enclose the directive in to a worksharing loop, a worksharing "
+          "loop simd or a simd directive."_err_en_US);
+    }
+  }
   ClearDataSharingAttributeObjects();
   return true;
 }
diff --git a/flang/test/Parser/OpenMP/scan.f90 b/flang/test/Parser/OpenMP/scan.f90
new file mode 100644
index 00000000000000..a6e23ac9404882
--- /dev/null
+++ b/flang/test/Parser/OpenMP/scan.f90
@@ -0,0 +1,40 @@
+! RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case %s
+! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+! Check for parsing scan directive
+subroutine test_scan_inclusive()
+  implicit none
+  integer, parameter :: n = 100
+  integer a(n), b(n)
+  integer x, k
+
+  ! initialization
+  x = 0
+  do k = 1, n
+   a(k) = k
+  end do
+
+  ! a(k) is included in the computation of producing results in b(k)
+  !$omp parallel do simd reduction(inscan,+: x)
+  do k = 1, n
+    x = x + a(k)
+    !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+    !PARSE-TREE-NEXT: OmpSimpleStandaloneDirective -> llvm::omp::Directive = scan
+    !PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Inclusive -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+    !CHECK: !$omp scan inclusive(x)
+    !$omp scan inclusive(x)
+      b(k) = x
+  end do
+
+  ! a(k) is not included in the computation of producing results in b(k)
+  !$omp parallel do simd reduction(inscan,+: x)
+  do k = 1, n
+    b(k) = x
+    !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+    !PARSE-TREE-NEXT: OmpSimpleStandaloneDirective -> llvm::omp::Directive = scan
+    !PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Exclusive -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+    !CHECK: !$omp scan exclusive(x)
+    !$omp scan exclusive(x)
+    x = x + a(k)
+  end do
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/do05.f90 b/flang/test/Semantics/OpenMP/do05.f90
index c0f240db57b65b..24844f9fe4f62a 100644
--- a/flang/test/Semantics/OpenMP/do05.f90
+++ b/flang/test/Semantics/OpenMP/do05.f90
@@ -39,7 +39,7 @@ program omp_do
     if( i == 5 ) then
         cycle
     end if
-    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
     !$omp single
     do j=1,10
@@ -70,7 +70,7 @@ program omp_do
     if( i == 3 ) then
         cycle
     end if
-    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
     !$omp single
     do j=1,10
@@ -93,7 +93,7 @@ program omp_do
 
   !$omp target parallel do simd
   do i=1,10
-    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
     !$omp single
     do j=1,10
@@ -116,7 +116,7 @@ program omp_do
 
   !$omp target teams distribute parallel do simd
   do i=1,10
-    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
     !$omp single
     do j=1,10
diff --git a/flang/test/Semantics/OpenMP/nested-barrier.f90 b/flang/test/Semantics/OpenMP/nested-barrier.f90
index 7c635d8e23cc0d..5f51363d59e593 100644
--- a/flang/test/Semantics/OpenMP/nested-barrier.f90
+++ b/flang/test/Semantics/OpenMP/nested-barrier.f90
@@ -17,7 +17,7 @@ program omp_nest_barrier
   !$omp do simd
   do i = 1, 10
     k = k + 1
-    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: `BARRIER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`,`CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region.
     !$omp barrier
     j = j -1
@@ -34,7 +34,7 @@ program omp_nest_barrier
   !$omp parallel do simd
   do i = 1, 10
     k = k + 1
-    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: `BARRIER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`,`CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region.
     !$omp barrier
     j = j -1
diff --git a/flang/test/Semantics/OpenMP/nested-master.f90 b/flang/test/Semantics/OpenMP/nested-master.f90
index b21ca5d1415931..d51e366eb584bb 100644
--- a/flang/test/Semantics/OpenMP/nested-master.f90
+++ b/flang/test/Semantics/OpenMP/nested-master.f90
@@ -64,7 +64,7 @@ program omp_nest_master
   do i = 1, 10
     k = k + 1
     !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead.
-    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region.
     !$omp master
     j = j -1
diff --git a/flang/test/Semantics/OpenMP/nested-simd.f90 b/flang/test/Semantics/OpenMP/nested-simd.f90
index 4149b6d97e9dc7..c9fb90cdeceb25 100644
--- a/flang/test/Semantics/OpenMP/nested-simd.f90
+++ b/flang/test/Semantics/OpenMP/nested-simd.f90
@@ -40,7 +40,7 @@ SUBROUTINE NESTED_BAD(N)
       !$OMP ORDERED SIMD
       DO J = 1,N
         print *, "Hi"
-        !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+        !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
         !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
         !$omp teams 
          DO K = 1,N
@@ -58,25 +58,25 @@ SUBROUTINE NESTED_BAD(N)
     !$OMP ATOMIC
     K =  K + 1
     IF (I <= 10) THEN
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$omp task 
       do J = 1, N
         K = 2
       end do
       !$omp end task
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$omp target 
       do J = 1, N
         K = 2
       end do
       !$omp end target
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP DO
       DO J = 1,N
         A(J) = J
       END DO
       !$OMP END DO
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP PARALLEL DO
       DO J = 1,N
         A(J) = J
@@ -91,26 +91,26 @@ SUBROUTINE NESTED_BAD(N)
     !$OMP ATOMIC
     K =  K + 1
     IF (I <= 10) THEN
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$omp task 
       do J = 1, N
         K = 2
       end do
       !$omp end task
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$omp target 
       do J = 1, N
         K = 2
       end do
       !$omp end target
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
       !$OMP DO
       DO J = 1,N
         A(J) = J
       END DO
       !$OMP END DO
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP PARALLEL DO
       DO J = 1,N
         A(J) = J
@@ -125,26 +125,26 @@ SUBROUTINE NESTED_BAD(N)
     !$OMP ATOMIC
     K =  K + 1
     IF (I <= 10) THEN
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$omp task 
       do J = 1, N
         K = 2
       end do
       !$omp end task
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$omp target 
       do J = 1, N
         K = 2
       end do
       !$omp end target
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
       !$OMP DO
       DO J = 1,N
         A(J) = J
       END DO
       !$OMP END DO
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP PARALLEL DO
       DO J = 1,N
         A(J) = J
@@ -159,25 +159,25 @@ SUBROUTINE NESTED_BAD(N)
     !$OMP ATOMIC
     K =  K + 1
     IF (I <= 10) THEN
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$omp task 
       do J = 1, N
         K = 2
       end do
       !$omp end task
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$omp target 
       do J = 1, N
         K = 2
       end do
       !$omp end target
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP DO
       DO J = 1,N
         A(J) = J
       END DO
       !$OMP END DO
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP PARALLEL DO
       DO J = 1,N
         A(J) = J
diff --git a/flang/test/Semantics/OpenMP/ordered-simd.f90 b/flang/test/Semantics/OpenMP/ordered-simd.f90
index 716dc42c28bb64..c90ffb3bd1c5ff 100644
--- a/flang/test/Semantics/OpenMP/ordered-simd.f90
+++ b/flang/test/Semantics/OpenMP/ordered-simd.f90
@@ -25,7 +25,7 @@ SUBROUTINE ORDERED_BAD(N)
   !$OMP DO SIMD
   DO I = 1,N
     IF (I <= 10) THEN
-      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
       !$OMP ORDERED 
       CALL WORK(I)
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
new file mode 100644
index 00000000000000..76a0379dfec55c
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -0,0 +1,19 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+subroutine test_scan()
+ integer x, k
+ 
+ !ERROR: Orphaned `omp scan` directives are prohibited; perhaps you forgot to enclose the directive in to a worksharing loop, a worksharing loop simd or a simd directive.
+ !$omp scan inclusive(x)
+ !$omp parallel do simd reduction(inscan,+: x)
+ do k = 1, n
+ !ERROR: UNTIED clause is not allowed on the SCAN directive
+   !$omp scan untied
+ end do
+ 
+ !$omp parallel do simd reduction(inscan,+: x)
+ do k = 1, n
+ !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+   !$omp scan
+ end do
+end subroutine
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index fa96c3f367f0ce..77f7e2355bb462 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -173,6 +173,7 @@ def OMPC_Enter : Clause<"enter"> {
 }
 def OMPC_Exclusive : Clause<"exclusive"> {
   let clangClass = "OMPExclusiveClause";
+  let flangClass = "OmpObjectList";
 }
 def OMPC_Fail : Clause<"fail"> {
   let clangClass = "OMPFailClause";
@@ -230,6 +231,7 @@ def OMPC_Inbranch : Clause<"inbranch"> {
 }
 def OMPC_Inclusive : Clause<"inclusive"> {
   let clangClass = "OMPInclusiveClause";
+  let flangClass = "OmpObjectList";
 }
 def OMPC_Indirect : Clause<"indirect"> {
 }
@@ -903,8 +905,8 @@ def OMP_Reverse : Directive<"reverse"> {
 }
 def OMP_Scan : Directive<"scan"> {
   let allowedClauses = [
-    VersionedClause<OMPC_Exclusive, 50>,
-    VersionedClause<OMPC_Inclusive, 50>,
+    VersionedClause<OMPC_Exclusive>,
+    VersionedClause<OMPC_Inclusive>,
   ];
   let association = AS_Separating;
   let category = CA_Subsidiary;

>From 615a759c23449a89b168f18a82abf8e90514a586 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Wed, 28 Aug 2024 17:17:14 -0500
Subject: [PATCH 02/10] R2: Addressing review comments

---
 .../flang/Semantics/openmp-directive-sets.h   |   1 +
 flang/lib/Semantics/check-omp-structure.cpp   | 123 ++++++++----------
 flang/lib/Semantics/resolve-directives.cpp    |   3 +-
 flang/test/Parser/OpenMP/scan.f90             |  36 +++--
 flang/test/Semantics/OpenMP/out               |  37 ++++++
 flang/test/Semantics/OpenMP/scan.f90          |   8 +-
 6 files changed, 130 insertions(+), 78 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/out

diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 5e51c5c7de0e82..8db3e60ab691c6 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -195,6 +195,7 @@ static const OmpDirectiveSet allDistributeParallelDoSimdSet{
 static const OmpDirectiveSet allDistributeSimdSet{
     allDistributeSet & allSimdSet};
 static const OmpDirectiveSet allDoSimdSet{allDoSet & allSimdSet};
+static const OmpDirectiveSet scanAllowedSet{allDoSet | allSimdSet};
 static const OmpDirectiveSet allTaskloopSimdSet{allTaskloopSet & allSimdSet};
 
 static const OmpDirectiveSet compositeConstructSet{
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index e0d1a22f268faa..4661c7c6332fd7 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -12,6 +12,7 @@
 #include "flang/Parser/parse-tree.h"
 #include "flang/Semantics/expression.h"
 #include "flang/Semantics/tools.h"
+#include <variant>
 
 namespace Fortran::semantics {
 
@@ -747,63 +748,61 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
   // current context yet.
   // TODO: Check for declare simd regions.
   bool eligibleSIMD{false};
-  common::visit(
-      Fortran::common::visitors{
-          // Allow `!$OMP ORDERED SIMD`
-          [&](const parser::OpenMPBlockConstruct &c) {
-            const auto &beginBlockDir{
-                std::get<parser::OmpBeginBlockDirective>(c.t)};
-            const auto &beginDir{
-                std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
-            if (beginDir.v == llvm::omp::Directive::OMPD_ordered) {
-              const auto &clauses{
-                  std::get<parser::OmpClauseList>(beginBlockDir.t)};
-              for (const auto &clause : clauses.v) {
-                if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
-                  eligibleSIMD = true;
-                  break;
-                }
-              }
-            }
-          },
-          [&](const parser::OpenMPStandaloneConstruct &c) {
-            if (const auto &simpleConstruct =
-                    std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
-                        &c.u)) {
-              const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
-                  simpleConstruct->t)};
-              if (dir.v == llvm::omp::Directive::OMPD_ordered) {
-                const auto &clauses{
-                    std::get<parser::OmpClauseList>(simpleConstruct->t)};
-                for (const auto &clause : clauses.v) {
-                  if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
-                    eligibleSIMD = true;
-                    break;
-                  }
-                }
-              } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
-                eligibleSIMD = true;
-              }
-            }
-          },
-          // Allowing SIMD construct
-          [&](const parser::OpenMPLoopConstruct &c) {
-            const auto &beginLoopDir{
-                std::get<parser::OmpBeginLoopDirective>(c.t)};
-            const auto &beginDir{
-                std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
-            if ((beginDir.v == llvm::omp::Directive::OMPD_simd) ||
-                (beginDir.v == llvm::omp::Directive::OMPD_parallel_do_simd) ||
-                (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
-              eligibleSIMD = true;
-            }
-          },
-          [&](const parser::OpenMPAtomicConstruct &c) {
-            // Allow `!$OMP ATOMIC`
-            eligibleSIMD = true;
-          },
-          [&](const auto &c) {},
-      },
+  common::visit(Fortran::common::visitors{
+                    // Allow `!$OMP ORDERED SIMD`
+                    [&](const parser::OpenMPBlockConstruct &c) {
+                      const auto &beginBlockDir{
+                          std::get<parser::OmpBeginBlockDirective>(c.t)};
+                      const auto &beginDir{
+                          std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
+                      if (beginDir.v == llvm::omp::Directive::OMPD_ordered) {
+                        const auto &clauses{
+                            std::get<parser::OmpClauseList>(beginBlockDir.t)};
+                        for (const auto &clause : clauses.v) {
+                          if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                            eligibleSIMD = true;
+                            break;
+                          }
+                        }
+                      }
+                    },
+                    [&](const parser::OpenMPStandaloneConstruct &c) {
+                      if (const auto &simpleConstruct =
+                              std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
+                                  &c.u)) {
+                        const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
+                            simpleConstruct->t)};
+                        if (dir.v == llvm::omp::Directive::OMPD_ordered) {
+                          const auto &clauses{
+                              std::get<parser::OmpClauseList>(simpleConstruct->t)};
+                          for (const auto &clause : clauses.v) {
+                            if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                              eligibleSIMD = true;
+                              break;
+                            }
+                          }
+                        } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
+                          eligibleSIMD = true;
+                        }
+                      }
+                    },
+                    // Allowing SIMD construct
+                    [&](const parser::OpenMPLoopConstruct &c) {
+                      const auto &beginLoopDir{
+                          std::get<parser::OmpBeginLoopDirective>(c.t)};
+                      const auto &beginDir{
+                          std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
+                      if ((beginDir.v == llvm::omp::Directive::OMPD_simd) ||
+                          (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
+                        eligibleSIMD = true;
+                      }
+                    },
+                    [&](const parser::OpenMPAtomicConstruct &c) {
+                      // Allow `!$OMP ATOMIC`
+                      eligibleSIMD = true;
+                    },
+                    [&](const auto &c) {},
+                },
       c.u);
   if (!eligibleSIMD) {
     context_.Say(parser::FindSourceLocation(c),
@@ -2990,15 +2989,7 @@ void OmpStructureChecker::CheckReductionModifier(
     // or "simd" directive.
     // The worksharing-loop directives are OMPD_do and OMPD_for. Only the
     // former is allowed in Fortran.
-    switch (dirCtx.directive) {
-    case llvm::omp::Directive::OMPD_do: // worksharing-loop
-    case llvm::omp::Directive::OMPD_do_simd: // worksharing-loop simd
-    case llvm::omp::Directive::
-        OMPD_parallel_do_simd: // worksharing-parallel-loop
-                               // simd
-    case llvm::omp::Directive::OMPD_simd: // "simd"
-      break;
-    default:
+    if (!llvm::omp::scanAllowedSet.test(dirCtx.directive)) {
       context_.Say(GetContext().clauseSource,
           "Modifier 'INSCAN' on REDUCTION clause is only allowed with "
           "worksharing-loop, worksharing-loop simd, "
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 9963443b2365b9..5fda76a0a8622f 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1644,8 +1644,7 @@ bool OmpAttributeVisitor::Pre(
           "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
     }
     if (!parentContext ||
-        (llvm::omp::getDirectiveAssociation(parentContext->directive) !=
-            llvm::omp::Association::Loop)) {
+        (!llvm::omp::scanAllowedSet.test(parentContext->directive))) {
       context_.Say(standaloneDir.source,
           "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
           "to enclose the directive in to a worksharing loop, a worksharing "
diff --git a/flang/test/Parser/OpenMP/scan.f90 b/flang/test/Parser/OpenMP/scan.f90
index a6e23ac9404882..6bc970c922160f 100644
--- a/flang/test/Parser/OpenMP/scan.f90
+++ b/flang/test/Parser/OpenMP/scan.f90
@@ -2,17 +2,11 @@
 ! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
 
 ! Check for parsing scan directive
-subroutine test_scan_inclusive()
+subroutine test_scan(n, a, b)
   implicit none
-  integer, parameter :: n = 100
+  integer n
   integer a(n), b(n)
-  integer x, k
-
-  ! initialization
-  x = 0
-  do k = 1, n
-   a(k) = k
-  end do
+  integer x,y,k
 
   ! a(k) is included in the computation of producing results in b(k)
   !$omp parallel do simd reduction(inscan,+: x)
@@ -37,4 +31,28 @@ subroutine test_scan_inclusive()
     !$omp scan exclusive(x)
     x = x + a(k)
   end do
+
+  !$omp parallel do simd reduction(inscan,+: x)
+  do k = 1, n
+    x = x + a(k)
+    !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+    !PARSE-TREE-NEXT: OmpSimpleStandaloneDirective -> llvm::omp::Directive = scan
+    !PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Inclusive -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+    !PARSE-TREE-NEXT: OmpObject -> Designator -> DataRef -> Name = 'y'
+    !CHECK: !$omp scan inclusive(x,y)
+    !$omp scan inclusive(x, y)
+      b(k) = x
+  end do
+
+  !$omp parallel do simd reduction(inscan,+: x)
+  do k = 1, n
+    x = x + a(k)
+    !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+    !PARSE-TREE-NEXT: OmpSimpleStandaloneDirective -> llvm::omp::Directive = scan
+    !PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Exclusive -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+    !PARSE-TREE-NEXT: OmpObject -> Designator -> DataRef -> Name = 'y'
+    !CHECK: !$omp scan exclusive(x,y)
+    !$omp scan exclusive(x, y)
+      b(k) = x
+  end do
 end subroutine
diff --git a/flang/test/Semantics/OpenMP/out b/flang/test/Semantics/OpenMP/out
new file mode 100644
index 00000000000000..d63b909cdd6c6c
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/out
@@ -0,0 +1,37 @@
+error: Semantic errors in nested-simd.f90
+./nested-simd.f90:45:15: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+          !$omp teams 
+                ^
+./nested-simd.f90:45:15: error: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+          !$omp teams 
+                ^
+./nested-simd.f90:62:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp task 
+              ^
+./nested-simd.f90:68:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp target 
+              ^
+./nested-simd.f90:95:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp task 
+              ^
+./nested-simd.f90:101:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp target 
+              ^
+./nested-simd.f90:108:13: error: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
+        !$OMP DO
+              ^^
+./nested-simd.f90:129:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp task 
+              ^
+./nested-simd.f90:135:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp target 
+              ^
+./nested-simd.f90:142:13: error: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
+        !$OMP DO
+              ^^
+./nested-simd.f90:163:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp task 
+              ^
+./nested-simd.f90:169:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp target 
+              ^
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
index 76a0379dfec55c..fe154c2fa74cd3 100644
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -1,7 +1,7 @@
 ! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
 
 subroutine test_scan()
- integer x, k
+ integer x, y, k
  
  !ERROR: Orphaned `omp scan` directives are prohibited; perhaps you forgot to enclose the directive in to a worksharing loop, a worksharing loop simd or a simd directive.
  !$omp scan inclusive(x)
@@ -16,4 +16,10 @@ subroutine test_scan()
  !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
    !$omp scan
  end do
+
+!$omp parallel do simd reduction(inscan,+: x)
+ do k = 1, n
+ !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+   !$omp scan inclusive(x) exclusive(y)
+ end do
 end subroutine

>From a0480ca86205a130061578220266b3ff00e76cce Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Wed, 28 Aug 2024 18:54:32 -0500
Subject: [PATCH 03/10] R3: Adding formatted file

---
 flang/lib/Semantics/check-omp-structure.cpp | 111 ++++++++++----------
 1 file changed, 56 insertions(+), 55 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 4661c7c6332fd7..2137bfcf5720f9 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -748,61 +748,62 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
   // current context yet.
   // TODO: Check for declare simd regions.
   bool eligibleSIMD{false};
-  common::visit(Fortran::common::visitors{
-                    // Allow `!$OMP ORDERED SIMD`
-                    [&](const parser::OpenMPBlockConstruct &c) {
-                      const auto &beginBlockDir{
-                          std::get<parser::OmpBeginBlockDirective>(c.t)};
-                      const auto &beginDir{
-                          std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
-                      if (beginDir.v == llvm::omp::Directive::OMPD_ordered) {
-                        const auto &clauses{
-                            std::get<parser::OmpClauseList>(beginBlockDir.t)};
-                        for (const auto &clause : clauses.v) {
-                          if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
-                            eligibleSIMD = true;
-                            break;
-                          }
-                        }
-                      }
-                    },
-                    [&](const parser::OpenMPStandaloneConstruct &c) {
-                      if (const auto &simpleConstruct =
-                              std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
-                                  &c.u)) {
-                        const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
-                            simpleConstruct->t)};
-                        if (dir.v == llvm::omp::Directive::OMPD_ordered) {
-                          const auto &clauses{
-                              std::get<parser::OmpClauseList>(simpleConstruct->t)};
-                          for (const auto &clause : clauses.v) {
-                            if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
-                              eligibleSIMD = true;
-                              break;
-                            }
-                          }
-                        } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
-                          eligibleSIMD = true;
-                        }
-                      }
-                    },
-                    // Allowing SIMD construct
-                    [&](const parser::OpenMPLoopConstruct &c) {
-                      const auto &beginLoopDir{
-                          std::get<parser::OmpBeginLoopDirective>(c.t)};
-                      const auto &beginDir{
-                          std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
-                      if ((beginDir.v == llvm::omp::Directive::OMPD_simd) ||
-                          (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
-                        eligibleSIMD = true;
-                      }
-                    },
-                    [&](const parser::OpenMPAtomicConstruct &c) {
-                      // Allow `!$OMP ATOMIC`
-                      eligibleSIMD = true;
-                    },
-                    [&](const auto &c) {},
-                },
+  common::visit(
+      Fortran::common::visitors{
+          // Allow `!$OMP ORDERED SIMD`
+          [&](const parser::OpenMPBlockConstruct &c) {
+            const auto &beginBlockDir{
+                std::get<parser::OmpBeginBlockDirective>(c.t)};
+            const auto &beginDir{
+                std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
+            if (beginDir.v == llvm::omp::Directive::OMPD_ordered) {
+              const auto &clauses{
+                  std::get<parser::OmpClauseList>(beginBlockDir.t)};
+              for (const auto &clause : clauses.v) {
+                if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                  eligibleSIMD = true;
+                  break;
+                }
+              }
+            }
+          },
+          [&](const parser::OpenMPStandaloneConstruct &c) {
+            if (const auto &simpleConstruct =
+                    std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
+                        &c.u)) {
+              const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
+                  simpleConstruct->t)};
+              if (dir.v == llvm::omp::Directive::OMPD_ordered) {
+                const auto &clauses{
+                    std::get<parser::OmpClauseList>(simpleConstruct->t)};
+                for (const auto &clause : clauses.v) {
+                  if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                    eligibleSIMD = true;
+                    break;
+                  }
+                }
+              } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
+                eligibleSIMD = true;
+              }
+            }
+          },
+          // Allowing SIMD construct
+          [&](const parser::OpenMPLoopConstruct &c) {
+            const auto &beginLoopDir{
+                std::get<parser::OmpBeginLoopDirective>(c.t)};
+            const auto &beginDir{
+                std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
+            if ((beginDir.v == llvm::omp::Directive::OMPD_simd) ||
+                (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
+              eligibleSIMD = true;
+            }
+          },
+          [&](const parser::OpenMPAtomicConstruct &c) {
+            // Allow `!$OMP ATOMIC`
+            eligibleSIMD = true;
+          },
+          [&](const auto &c) {},
+      },
       c.u);
   if (!eligibleSIMD) {
     context_.Say(parser::FindSourceLocation(c),

>From 9b8dbd9f22552ab4e92ca00878d3a96dd93176be Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 29 Aug 2024 13:19:04 -0500
Subject: [PATCH 04/10] R4: Addressing review comments

---
 .../flang/Semantics/openmp-directive-sets.h   |  6 ++-
 flang/lib/Semantics/resolve-directives.cpp    |  4 +-
 flang/test/Parser/OpenMP/scan.f90             |  4 +-
 flang/test/Semantics/OpenMP/out               | 37 -------------------
 flang/test/Semantics/OpenMP/scan.f90          |  2 +-
 5 files changed, 9 insertions(+), 44 deletions(-)
 delete mode 100644 flang/test/Semantics/OpenMP/out

diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 8db3e60ab691c6..94b73d39e302c9 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -187,7 +187,10 @@ static const OmpDirectiveSet allTeamsSet{
 // Directive sets for groups of multiple directives
 //===----------------------------------------------------------------------===//
 
-// Composite constructs
+// Directive sets for parent directives that do allow/not allow a construct
+static const OmpDirectiveSet scanAllowedSet{allDoSet | allSimdSet};
+
+// Directive sets that form Composite constructs
 static const OmpDirectiveSet allDistributeParallelDoSet{
     allDistributeSet & allParallelSet & allDoSet};
 static const OmpDirectiveSet allDistributeParallelDoSimdSet{
@@ -195,7 +198,6 @@ static const OmpDirectiveSet allDistributeParallelDoSimdSet{
 static const OmpDirectiveSet allDistributeSimdSet{
     allDistributeSet & allSimdSet};
 static const OmpDirectiveSet allDoSimdSet{allDoSet & allSimdSet};
-static const OmpDirectiveSet scanAllowedSet{allDoSet | allSimdSet};
 static const OmpDirectiveSet allTaskloopSimdSet{allTaskloopSet & allSimdSet};
 
 static const OmpDirectiveSet compositeConstructSet{
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 5fda76a0a8622f..591d534f65569c 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1639,12 +1639,12 @@ bool OmpAttributeVisitor::Pre(
     break;
   }
   if (standaloneDir.v == llvm::omp::Directive::OMPD_scan) {
-    if ((std::get<parser::OmpClauseList>(x.t).v.size() != 1)) {
+    if (std::get<parser::OmpClauseList>(x.t).v.size() != 1) {
       context_.Say(standaloneDir.source,
           "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
     }
     if (!parentContext ||
-        (!llvm::omp::scanAllowedSet.test(parentContext->directive))) {
+        !llvm::omp::scanAllowedSet.test(parentContext->directive)) {
       context_.Say(standaloneDir.source,
           "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
           "to enclose the directive in to a worksharing loop, a worksharing "
diff --git a/flang/test/Parser/OpenMP/scan.f90 b/flang/test/Parser/OpenMP/scan.f90
index 6bc970c922160f..02fa09b6ef3505 100644
--- a/flang/test/Parser/OpenMP/scan.f90
+++ b/flang/test/Parser/OpenMP/scan.f90
@@ -32,7 +32,7 @@ subroutine test_scan(n, a, b)
     x = x + a(k)
   end do
 
-  !$omp parallel do simd reduction(inscan,+: x)
+  !$omp parallel do simd reduction(inscan,+: x, y)
   do k = 1, n
     x = x + a(k)
     !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
@@ -44,7 +44,7 @@ subroutine test_scan(n, a, b)
       b(k) = x
   end do
 
-  !$omp parallel do simd reduction(inscan,+: x)
+  !$omp parallel do simd reduction(inscan,+: x, y)
   do k = 1, n
     x = x + a(k)
     !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
diff --git a/flang/test/Semantics/OpenMP/out b/flang/test/Semantics/OpenMP/out
deleted file mode 100644
index d63b909cdd6c6c..00000000000000
--- a/flang/test/Semantics/OpenMP/out
+++ /dev/null
@@ -1,37 +0,0 @@
-error: Semantic errors in nested-simd.f90
-./nested-simd.f90:45:15: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-          !$omp teams 
-                ^
-./nested-simd.f90:45:15: error: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
-          !$omp teams 
-                ^
-./nested-simd.f90:62:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp task 
-              ^
-./nested-simd.f90:68:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp target 
-              ^
-./nested-simd.f90:95:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp task 
-              ^
-./nested-simd.f90:101:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp target 
-              ^
-./nested-simd.f90:108:13: error: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
-        !$OMP DO
-              ^^
-./nested-simd.f90:129:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp task 
-              ^
-./nested-simd.f90:135:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp target 
-              ^
-./nested-simd.f90:142:13: error: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
-        !$OMP DO
-              ^^
-./nested-simd.f90:163:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp task 
-              ^
-./nested-simd.f90:169:13: error: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp target 
-              ^
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
index fe154c2fa74cd3..e82982f60b9021 100644
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -17,7 +17,7 @@ subroutine test_scan()
    !$omp scan
  end do
 
-!$omp parallel do simd reduction(inscan,+: x)
+!$omp parallel do simd reduction(inscan,+: x, y)
  do k = 1, n
  !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
    !$omp scan inclusive(x) exclusive(y)

>From 865ca2ec7c4cb06d6537d71bffb347d5e2e7d30e Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 29 Aug 2024 14:43:18 -0500
Subject: [PATCH 05/10] R5: Addressing a few more review comments

---
 flang/include/flang/Semantics/openmp-directive-sets.h | 8 +++++---
 flang/lib/Semantics/check-omp-structure.cpp           | 2 +-
 flang/lib/Semantics/resolve-directives.cpp            | 2 +-
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 94b73d39e302c9..bbb054d5a22581 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -187,9 +187,6 @@ static const OmpDirectiveSet allTeamsSet{
 // Directive sets for groups of multiple directives
 //===----------------------------------------------------------------------===//
 
-// Directive sets for parent directives that do allow/not allow a construct
-static const OmpDirectiveSet scanAllowedSet{allDoSet | allSimdSet};
-
 // Directive sets that form Composite constructs
 static const OmpDirectiveSet allDistributeParallelDoSet{
     allDistributeSet & allParallelSet & allDoSet};
@@ -293,6 +290,11 @@ static const OmpDirectiveSet workShareSet{
     } | allDoSet,
 };
 
+//===----------------------------------------------------------------------===//
+// Directive sets for parent directives that do allow/not allow a construct
+static const OmpDirectiveSet scanParentAllowedSet{allDoSet | allSimdSet};
+//===----------------------------------------------------------------------===//
+
 //===----------------------------------------------------------------------===//
 // Directive sets for allowed/not allowed nested directives
 //===----------------------------------------------------------------------===//
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 2137bfcf5720f9..e33b0c2e440759 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2990,7 +2990,7 @@ void OmpStructureChecker::CheckReductionModifier(
     // or "simd" directive.
     // The worksharing-loop directives are OMPD_do and OMPD_for. Only the
     // former is allowed in Fortran.
-    if (!llvm::omp::scanAllowedSet.test(dirCtx.directive)) {
+    if (!llvm::omp::scanParentAllowedSet.test(dirCtx.directive)) {
       context_.Say(GetContext().clauseSource,
           "Modifier 'INSCAN' on REDUCTION clause is only allowed with "
           "worksharing-loop, worksharing-loop simd, "
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 591d534f65569c..575ebcc6603933 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1644,7 +1644,7 @@ bool OmpAttributeVisitor::Pre(
           "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
     }
     if (!parentContext ||
-        !llvm::omp::scanAllowedSet.test(parentContext->directive)) {
+        !llvm::omp::scanParentAllowedSet.test(parentContext->directive)) {
       context_.Say(standaloneDir.source,
           "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
           "to enclose the directive in to a worksharing loop, a worksharing "

>From 6409cd91ad4f52b505df704ca9841f878bbb0cde Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Mon, 9 Sep 2024 13:25:58 -0500
Subject: [PATCH 06/10] R6: Reworked to add a few more semantic checks and
 moved checks to check-omp-structure

---
 .../lib/Semantics/check-directive-structure.h |   4 +
 flang/lib/Semantics/check-omp-structure.cpp   | 146 ++++++++++++++++--
 flang/lib/Semantics/check-omp-structure.h     |   7 +-
 flang/lib/Semantics/resolve-directives.cpp    |  14 --
 .../Lower/OpenMP/Todo/reduction-modifiers.f90 |   1 +
 .../Semantics/OpenMP/reduction-modifiers.f90  |   3 +
 flang/test/Semantics/OpenMP/scan.f90          |  14 +-
 7 files changed, 155 insertions(+), 34 deletions(-)

diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 2a9cb785a882f8..1d8b755dfbab0c 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -201,6 +201,10 @@ class DirectiveStructureChecker : public virtual BaseChecker {
     ClauseMapTy clauseInfo;
     std::list<C> actualClauses;
     std::list<C> crtGroup;
+    std::set<std::string> usedInScanDirective;
+
+    using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+    std::map<const std::string, ReductionModifier> reductionMod;
     Symbol *loopIV{nullptr};
   };
 
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index e33b0c2e440759..08993be16dcc67 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -974,6 +974,42 @@ void OmpStructureChecker::CheckDistLinear(
 }
 
 void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
+  const auto &beginLoopDir = std::get<parser::OmpBeginLoopDirective>(x.t);
+  const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
+  for (const auto &clause : clauseList.v) {
+    if (const auto *reductionClause{
+            std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
+      using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+      const auto &maybeModifier{
+          std::get<std::optional<ReductionModifier>>(reductionClause->v.t)};
+      if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
+
+        const auto &objectList{
+            std::get<parser::OmpObjectList>(reductionClause->v.t)};
+        for (const auto &ompObj : objectList.v) {
+          common::visit(
+              common::visitors{
+                  [&](const parser::Designator &designator) {
+                    if (const auto *name{semantics::getDesignatorNameIfDataRef(
+                            designator)}) {
+                      std::string nameStr = name->symbol->name().ToString();
+                      if (GetContext().usedInScanDirective.find(nameStr) ==
+                          GetContext().usedInScanDirective.end()) {
+                        context_.Say(name->source,
+                            "List item %s must appear in 'inclusive' or "
+                            "'exclusive' clause of an "
+                            "enclosed scan directive"_err_en_US,
+                            nameStr);
+                      }
+                    }
+                  },
+                  [&](const auto &name) {},
+              },
+              ompObj.u);
+        }
+      }
+    }
+  }
   if (llvm::omp::allSimdSet.test(GetContext().directive)) {
     ExitDirectiveNest(SIMDNest);
   }
@@ -1646,19 +1682,32 @@ void OmpStructureChecker::Leave(const parser::OpenMPAllocatorsConstruct &x) {
   dirContext_.pop_back();
 }
 
+void OmpStructureChecker::CheckScan(
+    const parser::OpenMPSimpleStandaloneConstruct &x) {
+  if (std::get<parser::OmpClauseList>(x.t).v.size() != 1) {
+    context_.Say(x.source,
+        "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
+  }
+  if (!CurrentDirectiveIsNested() ||
+      !llvm::omp::scanParentAllowedSet.test(GetContextParent().directive)) {
+    context_.Say(x.source,
+        "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
+        "to enclose the directive in to a worksharing loop, a worksharing "
+        "loop simd or a simd directive."_err_en_US);
+  }
+}
+
 void OmpStructureChecker::CheckBarrierNesting(
     const parser::OpenMPSimpleStandaloneConstruct &x) {
   // A barrier region may not be `closely nested` inside a worksharing, loop,
   // task, taskloop, critical, ordered, atomic, or master region.
   // TODO:  Expand the check to include `LOOP` construct as well when it is
   // supported.
-  if (GetContext().directive == llvm::omp::Directive::OMPD_barrier) {
-    if (IsCloselyNestedRegion(llvm::omp::nestedBarrierErrSet)) {
-      context_.Say(parser::FindSourceLocation(x),
-          "`BARRIER` region may not be closely nested inside of `WORKSHARING`, "
-          "`LOOP`, `TASK`, `TASKLOOP`,"
-          "`CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region."_err_en_US);
-    }
+  if (IsCloselyNestedRegion(llvm::omp::nestedBarrierErrSet)) {
+    context_.Say(parser::FindSourceLocation(x),
+        "`BARRIER` region may not be closely nested inside of `WORKSHARING`, "
+        "`LOOP`, `TASK`, `TASKLOOP`,"
+        "`CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region."_err_en_US);
   }
 }
 
@@ -1842,7 +1891,16 @@ void OmpStructureChecker::Enter(
     const parser::OpenMPSimpleStandaloneConstruct &x) {
   const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
   PushContextAndClauseSets(dir.source, dir.v);
-  CheckBarrierNesting(x);
+  switch (dir.v) {
+  case llvm::omp::Directive::OMPD_barrier:
+    CheckBarrierNesting(x);
+    break;
+  case llvm::omp::Directive::OMPD_scan:
+    CheckScan(x);
+    break;
+  default:
+    break;
+  }
 }
 
 void OmpStructureChecker::Leave(
@@ -2674,7 +2732,6 @@ CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
 CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach)
 CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type)
 CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
-CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive)
 CHECK_SIMPLE_CLAUSE(Final, OMPC_final)
 CHECK_SIMPLE_CLAUSE(Flush, OMPC_flush)
 CHECK_SIMPLE_CLAUSE(Full, OMPC_full)
@@ -2682,7 +2739,6 @@ CHECK_SIMPLE_CLAUSE(Grainsize, OMPC_grainsize)
 CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint)
 CHECK_SIMPLE_CLAUSE(Holds, OMPC_holds)
 CHECK_SIMPLE_CLAUSE(InReduction, OMPC_in_reduction)
-CHECK_SIMPLE_CLAUSE(Inclusive, OMPC_inclusive)
 CHECK_SIMPLE_CLAUSE(Match, OMPC_match)
 CHECK_SIMPLE_CLAUSE(Nontemporal, OMPC_nontemporal)
 CHECK_SIMPLE_CLAUSE(NumTasks, OMPC_num_tasks)
@@ -2775,7 +2831,24 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
   if (CheckReductionOperators(x)) {
     CheckReductionTypeList(x);
   }
-  CheckReductionModifier(x);
+  using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+  if (const auto &maybeModifier{
+          std::get<std::optional<ReductionModifier>>(x.v.t)}) {
+    ReductionModifier modifier{*maybeModifier};
+    const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
+    addModifiertoMap(ompObjectList, modifier);
+    CheckReductionModifier(modifier);
+  }
+}
+
+void OmpStructureChecker::Enter(const parser::OmpClause::Inclusive &x) {
+  CheckAllowed(llvm::omp::Clause::OMPC_inclusive);
+  checkAndAddSymbolsToUsedInScanList(x.v);
+}
+
+void OmpStructureChecker::Enter(const parser::OmpClause::Exclusive &x) {
+  CheckAllowed(llvm::omp::Clause::OMPC_exclusive);
+  checkAndAddSymbolsToUsedInScanList(x.v);
 }
 
 bool OmpStructureChecker::CheckReductionOperators(
@@ -2818,6 +2891,49 @@ bool OmpStructureChecker::CheckReductionOperators(
 
   return ok;
 }
+
+void OmpStructureChecker::addModifiertoMap(const parser::OmpObjectList &x,
+    parser::OmpReductionClause::ReductionModifier &modifier) {
+  for (const auto &ompObject : x.v) {
+    if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
+      if (const auto *symbol{name->symbol}) {
+        GetContext().reductionMod[symbol->name().ToString()] = modifier;
+      }
+    }
+  }
+}
+
+void OmpStructureChecker::checkAndAddSymbolsToUsedInScanList(
+    const parser::OmpObjectList &x) {
+  for (const auto &ompObj : x.v) {
+    common::visit(
+        common::visitors{
+            [&](const parser::Designator &designator) {
+              if (const auto *name{
+                      semantics::getDesignatorNameIfDataRef(designator)}) {
+                if (name->symbol) {
+                  if (CurrentDirectiveIsNested()) {
+                    std::string nameStr = name->symbol->name().ToString();
+                    if (GetContextParent().reductionMod.find(nameStr) ==
+                        GetContextParent().reductionMod.end()) {
+
+                      context_.Say(name->source,
+                          "List item %s must appear in 'reduction' clause "
+                          "with the 'inscan' modifier of the parent "
+                          "directive"_err_en_US,
+                          nameStr);
+                    }
+                    GetContextParent().usedInScanDirective.insert(nameStr);
+                  }
+                }
+              }
+            },
+            [&](const auto &name) {},
+        },
+        ompObj.u);
+  }
+}
+
 bool OmpStructureChecker::CheckIntrinsicOperator(
     const parser::DefinedOperator::IntrinsicOperator &op) {
 
@@ -2952,14 +3068,12 @@ void OmpStructureChecker::CheckReductionTypeList(
 }
 
 void OmpStructureChecker::CheckReductionModifier(
-    const parser::OmpClause::Reduction &x) {
+    const parser::OmpReductionClause::ReductionModifier &modifier) {
   using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
-  const auto &maybeModifier{std::get<std::optional<ReductionModifier>>(x.v.t)};
-  if (!maybeModifier || *maybeModifier == ReductionModifier::Default) {
-    // No modifier, or the default one is always ok.
+  if (modifier == ReductionModifier::Default) {
+    // the default one is always ok.
     return;
   }
-  ReductionModifier modifier{*maybeModifier};
   const DirectiveContext &dirCtx{GetContext()};
   if (dirCtx.directive == llvm::omp::Directive::OMPD_loop) {
     // [5.2:257:33-34]
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 0c5f97f743e2e1..8c254a716ade8f 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -227,10 +227,12 @@ class OmpStructureChecker
   bool CheckIntrinsicOperator(
       const parser::DefinedOperator::IntrinsicOperator &);
   void CheckReductionTypeList(const parser::OmpClause::Reduction &);
-  void CheckReductionModifier(const parser::OmpClause::Reduction &);
+  void CheckReductionModifier(
+      const parser::OmpReductionClause::ReductionModifier &);
   void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
   void ChecksOnOrderedAsBlock();
   void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
+  void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
   void ChecksOnOrderedAsStandalone();
   void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
   void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
@@ -247,6 +249,9 @@ class OmpStructureChecker
       const parser::OmpObjectList &ompObjectList);
   void CheckPredefinedAllocatorRestriction(
       const parser::CharBlock &source, const parser::Name &name);
+  void checkAndAddSymbolsToUsedInScanList(const parser::OmpObjectList &x);
+  void addModifiertoMap(const parser::OmpObjectList &x,
+      parser::OmpReductionClause::ReductionModifier &modifier);
   bool isPredefinedAllocator{false};
 
   void CheckAllowedRequiresClause(llvmOmpClause clause);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 575ebcc6603933..e30c0fbcee85f4 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1623,7 +1623,6 @@ bool OmpAttributeVisitor::Pre(
     const parser::OpenMPSimpleStandaloneConstruct &x) {
   const auto &standaloneDir{
       std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
-  const auto &parentContext{GetContextIf()};
   switch (standaloneDir.v) {
   case llvm::omp::Directive::OMPD_barrier:
   case llvm::omp::Directive::OMPD_ordered:
@@ -1638,19 +1637,6 @@ bool OmpAttributeVisitor::Pre(
   default:
     break;
   }
-  if (standaloneDir.v == llvm::omp::Directive::OMPD_scan) {
-    if (std::get<parser::OmpClauseList>(x.t).v.size() != 1) {
-      context_.Say(standaloneDir.source,
-          "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
-    }
-    if (!parentContext ||
-        !llvm::omp::scanParentAllowedSet.test(parentContext->directive)) {
-      context_.Say(standaloneDir.source,
-          "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
-          "to enclose the directive in to a worksharing loop, a worksharing "
-          "loop simd or a simd directive."_err_en_US);
-    }
-  }
   ClearDataSharingAttributeObjects();
   return true;
 }
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90 b/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
index 5e566466492ceb..82625ed8c5f31c 100644
--- a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
+++ b/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
@@ -8,6 +8,7 @@ subroutine foo()
   j = 0
   !$omp do reduction (inscan, *: j)
   do i = 1, 10
+    !$omp scan inclusive(j)
     j = j + 1
   end do
 end subroutine
diff --git a/flang/test/Semantics/OpenMP/reduction-modifiers.f90 b/flang/test/Semantics/OpenMP/reduction-modifiers.f90
index cf38200ba0a83e..31d21e9d4189cb 100644
--- a/flang/test/Semantics/OpenMP/reduction-modifiers.f90
+++ b/flang/test/Semantics/OpenMP/reduction-modifiers.f90
@@ -39,6 +39,7 @@ subroutine mod_inscan1(x)
   !Correct: worksharing-loop directive
   !$omp do reduction(inscan, +:x)
   do i = 1, 100
+    !$omp scan inclusive(x)
     x = foo(i)
   enddo
   !$omp end do
@@ -50,6 +51,7 @@ subroutine mod_inscan2(x)
   !Correct: worksharing-loop simd directive
   !$omp do simd reduction(inscan, +:x)
   do i = 1, 100
+    !$omp scan inclusive(x)
     x = foo(i)
   enddo
   !$omp end do simd
@@ -61,6 +63,7 @@ subroutine mod_inscan3(x)
   !Correct: "simd" directive
   !$omp simd reduction(inscan, +:x)
   do i = 1, 100
+    !$omp scan inclusive(x)
     x = foo(i)
   enddo
   !$omp end simd
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
index e82982f60b9021..c7526d31df4acb 100644
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -1,17 +1,17 @@
 ! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
 
 subroutine test_scan()
- integer x, y, k
+ integer x, y, k, z
  
  !ERROR: Orphaned `omp scan` directives are prohibited; perhaps you forgot to enclose the directive in to a worksharing loop, a worksharing loop simd or a simd directive.
  !$omp scan inclusive(x)
- !$omp parallel do simd reduction(inscan,+: x)
+ !$omp parallel do simd
  do k = 1, n
  !ERROR: UNTIED clause is not allowed on the SCAN directive
    !$omp scan untied
  end do
  
- !$omp parallel do simd reduction(inscan,+: x)
+ !$omp parallel do simd
  do k = 1, n
  !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
    !$omp scan
@@ -22,4 +22,12 @@ subroutine test_scan()
  !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
    !$omp scan inclusive(x) exclusive(y)
  end do
+
+!ERROR: List item y must appear in 'inclusive' or 'exclusive' clause of an enclosed scan directive
+!$omp parallel do simd reduction(inscan,+: x, y)
+ do k = 1, n
+ !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+ !ERROR: List item z must appear in 'reduction' clause with the 'inscan' modifier of the parent directive
+   !$omp scan inclusive(x) exclusive(z)
+ end do
 end subroutine

>From b10a1986e189488d94e32eb0a1db0b5ab4c2f4c7 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Fri, 20 Sep 2024 13:05:25 -0500
Subject: [PATCH 07/10] R7: Addressed a few review comments

---
 .../flang/Semantics/openmp-directive-sets.h   |  5 +-
 flang/lib/Semantics/check-omp-structure.cpp   | 83 ++++++++++---------
 flang/lib/Semantics/check-omp-structure.h     | 10 +--
 3 files changed, 52 insertions(+), 46 deletions(-)

diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index bbb054d5a22581..7cdca1214e7498 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -187,7 +187,7 @@ static const OmpDirectiveSet allTeamsSet{
 // Directive sets for groups of multiple directives
 //===----------------------------------------------------------------------===//
 
-// Directive sets that form Composite constructs
+// Composite constructs
 static const OmpDirectiveSet allDistributeParallelDoSet{
     allDistributeSet & allParallelSet & allDoSet};
 static const OmpDirectiveSet allDistributeParallelDoSimdSet{
@@ -292,9 +292,10 @@ static const OmpDirectiveSet workShareSet{
 
 //===----------------------------------------------------------------------===//
 // Directive sets for parent directives that do allow/not allow a construct
-static const OmpDirectiveSet scanParentAllowedSet{allDoSet | allSimdSet};
 //===----------------------------------------------------------------------===//
 
+static const OmpDirectiveSet scanParentAllowedSet{allDoSet | allSimdSet};
+
 //===----------------------------------------------------------------------===//
 // Directive sets for allowed/not allowed nested directives
 //===----------------------------------------------------------------------===//
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 08993be16dcc67..38e2f466fadad8 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -974,36 +974,40 @@ void OmpStructureChecker::CheckDistLinear(
 }
 
 void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
-  const auto &beginLoopDir = std::get<parser::OmpBeginLoopDirective>(x.t);
+  const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
   const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
   for (const auto &clause : clauseList.v) {
     if (const auto *reductionClause{
             std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
-      using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
       const auto &maybeModifier{
           std::get<std::optional<ReductionModifier>>(reductionClause->v.t)};
       if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
 
         const auto &objectList{
             std::get<parser::OmpObjectList>(reductionClause->v.t)};
+        auto checkReductionSymbolInScan = [&](const parser::Name *name) {
+          if (name->symbol) {
+            std::string nameStr = name->symbol->name().ToString();
+            if (GetContext().usedInScanDirective.find(nameStr) ==
+                GetContext().usedInScanDirective.end()) {
+              context_.Say(name->source,
+                  "List item %s must appear in 'inclusive' or "
+                  "'exclusive' clause of an "
+                  "enclosed scan directive"_err_en_US,
+                  nameStr);
+            }
+          }
+        };
         for (const auto &ompObj : objectList.v) {
           common::visit(
               common::visitors{
                   [&](const parser::Designator &designator) {
                     if (const auto *name{semantics::getDesignatorNameIfDataRef(
                             designator)}) {
-                      std::string nameStr = name->symbol->name().ToString();
-                      if (GetContext().usedInScanDirective.find(nameStr) ==
-                          GetContext().usedInScanDirective.end()) {
-                        context_.Say(name->source,
-                            "List item %s must appear in 'inclusive' or "
-                            "'exclusive' clause of an "
-                            "enclosed scan directive"_err_en_US,
-                            nameStr);
-                      }
+                      checkReductionSymbolInScan(name);
                     }
                   },
-                  [&](const auto &name) {},
+                  [&](const auto &name) { checkReductionSymbolInScan(&name); },
               },
               ompObj.u);
         }
@@ -2831,24 +2835,23 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
   if (CheckReductionOperators(x)) {
     CheckReductionTypeList(x);
   }
-  using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
   if (const auto &maybeModifier{
           std::get<std::optional<ReductionModifier>>(x.v.t)}) {
-    ReductionModifier modifier{*maybeModifier};
+    const ReductionModifier modifier{*maybeModifier};
     const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
-    addModifiertoMap(ompObjectList, modifier);
+    AddModifierToMap(ompObjectList, modifier);
     CheckReductionModifier(modifier);
   }
 }
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Inclusive &x) {
   CheckAllowed(llvm::omp::Clause::OMPC_inclusive);
-  checkAndAddSymbolsToUsedInScanList(x.v);
+  CheckAndAddSymbolsToUsedInScanList(x.v);
 }
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Exclusive &x) {
   CheckAllowed(llvm::omp::Clause::OMPC_exclusive);
-  checkAndAddSymbolsToUsedInScanList(x.v);
+  CheckAndAddSymbolsToUsedInScanList(x.v);
 }
 
 bool OmpStructureChecker::CheckReductionOperators(
@@ -2892,8 +2895,8 @@ bool OmpStructureChecker::CheckReductionOperators(
   return ok;
 }
 
-void OmpStructureChecker::addModifiertoMap(const parser::OmpObjectList &x,
-    parser::OmpReductionClause::ReductionModifier &modifier) {
+void OmpStructureChecker::AddModifierToMap(
+    const parser::OmpObjectList &x, const ReductionModifier &modifier) {
   for (const auto &ompObject : x.v) {
     if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
       if (const auto *symbol{name->symbol}) {
@@ -2903,32 +2906,35 @@ void OmpStructureChecker::addModifiertoMap(const parser::OmpObjectList &x,
   }
 }
 
-void OmpStructureChecker::checkAndAddSymbolsToUsedInScanList(
+void OmpStructureChecker::CheckAndAddSymbolsToUsedInScanList(
     const parser::OmpObjectList &x) {
   for (const auto &ompObj : x.v) {
+    auto checkScanSymbolInReduction = [&](const parser::Name *name) {
+      if (name->symbol) {
+        if (CurrentDirectiveIsNested()) {
+          std::string nameStr = name->symbol->name().ToString();
+          if (GetContextParent().reductionMod.find(nameStr) ==
+              GetContextParent().reductionMod.end()) {
+
+            context_.Say(name->source,
+                "List item %s must appear in 'reduction' clause "
+                "with the 'inscan' modifier of the parent "
+                "directive"_err_en_US,
+                nameStr);
+          }
+          GetContextParent().usedInScanDirective.insert(nameStr);
+        }
+      }
+    };
     common::visit(
         common::visitors{
             [&](const parser::Designator &designator) {
               if (const auto *name{
                       semantics::getDesignatorNameIfDataRef(designator)}) {
-                if (name->symbol) {
-                  if (CurrentDirectiveIsNested()) {
-                    std::string nameStr = name->symbol->name().ToString();
-                    if (GetContextParent().reductionMod.find(nameStr) ==
-                        GetContextParent().reductionMod.end()) {
-
-                      context_.Say(name->source,
-                          "List item %s must appear in 'reduction' clause "
-                          "with the 'inscan' modifier of the parent "
-                          "directive"_err_en_US,
-                          nameStr);
-                    }
-                    GetContextParent().usedInScanDirective.insert(nameStr);
-                  }
-                }
+                checkScanSymbolInReduction(name);
               }
             },
-            [&](const auto &name) {},
+            [&](const auto &name) { checkScanSymbolInReduction(&name); },
         },
         ompObj.u);
   }
@@ -3068,10 +3074,9 @@ void OmpStructureChecker::CheckReductionTypeList(
 }
 
 void OmpStructureChecker::CheckReductionModifier(
-    const parser::OmpReductionClause::ReductionModifier &modifier) {
-  using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+    const ReductionModifier &modifier) {
   if (modifier == ReductionModifier::Default) {
-    // the default one is always ok.
+    // The default one is always ok.
     return;
   }
   const DirectiveContext &dirCtx{GetContext()};
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 8c254a716ade8f..5fbdfe7b9ab408 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -70,6 +70,7 @@ class OmpStructureChecker
         ) {
   }
   using llvmOmpClause = const llvm::omp::Clause;
+  using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
 
   void Enter(const parser::OpenMPConstruct &);
   void Leave(const parser::OpenMPConstruct &);
@@ -227,8 +228,7 @@ class OmpStructureChecker
   bool CheckIntrinsicOperator(
       const parser::DefinedOperator::IntrinsicOperator &);
   void CheckReductionTypeList(const parser::OmpClause::Reduction &);
-  void CheckReductionModifier(
-      const parser::OmpReductionClause::ReductionModifier &);
+  void CheckReductionModifier(const ReductionModifier &);
   void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
   void ChecksOnOrderedAsBlock();
   void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
@@ -249,9 +249,9 @@ class OmpStructureChecker
       const parser::OmpObjectList &ompObjectList);
   void CheckPredefinedAllocatorRestriction(
       const parser::CharBlock &source, const parser::Name &name);
-  void checkAndAddSymbolsToUsedInScanList(const parser::OmpObjectList &x);
-  void addModifiertoMap(const parser::OmpObjectList &x,
-      parser::OmpReductionClause::ReductionModifier &modifier);
+  void CheckAndAddSymbolsToUsedInScanList(const parser::OmpObjectList &x);
+  void AddModifierToMap(
+      const parser::OmpObjectList &x, const ReductionModifier &modifier);
   bool isPredefinedAllocator{false};
 
   void CheckAllowedRequiresClause(llvmOmpClause clause);

>From 9facbf75c798419c627988034bc044445eb810ba Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 7 Nov 2024 16:19:46 -0600
Subject: [PATCH 08/10] R8: converting string refs to symbol* and merging the
 new changes

---
 .../lib/Semantics/check-directive-structure.h |  4 -
 flang/lib/Semantics/check-omp-structure.cpp   | 78 +++++++++----------
 flang/lib/Semantics/check-omp-structure.h     | 43 +++++++++-
 flang/lib/Semantics/resolve-directives.cpp    | 28 +++++++
 .../Lower/OpenMP/Todo/reduction-inscan.f90    |  1 +
 .../Semantics/OpenMP/reduction-modifiers.f90  |  4 +-
 flang/test/Semantics/OpenMP/scan.f90          | 12 +--
 7 files changed, 116 insertions(+), 54 deletions(-)

diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 1d8b755dfbab0c..2a9cb785a882f8 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -201,10 +201,6 @@ class DirectiveStructureChecker : public virtual BaseChecker {
     ClauseMapTy clauseInfo;
     std::list<C> actualClauses;
     std::list<C> crtGroup;
-    std::set<std::string> usedInScanDirective;
-
-    using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
-    std::map<const std::string, ReductionModifier> reductionMod;
     Symbol *loopIV{nullptr};
   };
 
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 38e2f466fadad8..1e0956a3abb87f 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -976,6 +976,12 @@ void OmpStructureChecker::CheckDistLinear(
 void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
   const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
   const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
+
+  // A few semantic checks for InScan reduction are performed below as SCAN
+  // constructs inside LOOP may add the relevant information. Scan reduction is
+  // supported only in loop constructs, so same checks are not applicable to
+  // other directives.
+
   for (const auto &clause : clauseList.v) {
     if (const auto *reductionClause{
             std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
@@ -987,14 +993,13 @@ void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
             std::get<parser::OmpObjectList>(reductionClause->v.t)};
         auto checkReductionSymbolInScan = [&](const parser::Name *name) {
           if (name->symbol) {
-            std::string nameStr = name->symbol->name().ToString();
-            if (GetContext().usedInScanDirective.find(nameStr) ==
-                GetContext().usedInScanDirective.end()) {
+            if (!scanReductionInfoStack.top().findSymbolInScanConstruct(
+                    name->symbol)) {
               context_.Say(name->source,
-                  "List item %s must appear in 'inclusive' or "
-                  "'exclusive' clause of an "
-                  "enclosed scan directive"_err_en_US,
-                  nameStr);
+                  "List item %s must appear in EXCLUSIVE or "
+                  "INCLUSIVE clause of an "
+                  "enclosed SCAN directive"_err_en_US,
+                  name->ToString());
             }
           }
         };
@@ -1011,6 +1016,7 @@ void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
               },
               ompObj.u);
         }
+        scanReductionInfoStack.pop();
       }
     }
   }
@@ -1690,14 +1696,14 @@ void OmpStructureChecker::CheckScan(
     const parser::OpenMPSimpleStandaloneConstruct &x) {
   if (std::get<parser::OmpClauseList>(x.t).v.size() != 1) {
     context_.Say(x.source,
-        "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
+        "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected"_err_en_US);
   }
   if (!CurrentDirectiveIsNested() ||
       !llvm::omp::scanParentAllowedSet.test(GetContextParent().directive)) {
     context_.Say(x.source,
-        "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
-        "to enclose the directive in to a worksharing loop, a worksharing "
-        "loop simd or a simd directive."_err_en_US);
+        "Orphaned SCAN directives are prohibited; perhaps you forgot "
+        "to enclose the directive in to a WORKSHARING LOOP, a WORKSHARING "
+        "LOOP SIMD or a SIMD directive."_err_en_US);
   }
 }
 
@@ -2838,20 +2844,24 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
   if (const auto &maybeModifier{
           std::get<std::optional<ReductionModifier>>(x.v.t)}) {
     const ReductionModifier modifier{*maybeModifier};
-    const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
-    AddModifierToMap(ompObjectList, modifier);
+    if (modifier == ReductionModifier::Inscan) {
+      scanReductionInfoStack.emplace();
+      const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
+      scanReductionInfoStack.top().mapSymbolsToReductionModifiers(
+          ompObjectList, modifier);
+    }
     CheckReductionModifier(modifier);
   }
 }
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Inclusive &x) {
   CheckAllowed(llvm::omp::Clause::OMPC_inclusive);
-  CheckAndAddSymbolsToUsedInScanList(x.v);
+  CheckAndMarkSymbolsUsedInScan(x.v);
 }
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Exclusive &x) {
   CheckAllowed(llvm::omp::Clause::OMPC_exclusive);
-  CheckAndAddSymbolsToUsedInScanList(x.v);
+  CheckAndMarkSymbolsUsedInScan(x.v);
 }
 
 bool OmpStructureChecker::CheckReductionOperators(
@@ -2895,34 +2905,24 @@ bool OmpStructureChecker::CheckReductionOperators(
   return ok;
 }
 
-void OmpStructureChecker::AddModifierToMap(
-    const parser::OmpObjectList &x, const ReductionModifier &modifier) {
-  for (const auto &ompObject : x.v) {
-    if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
-      if (const auto *symbol{name->symbol}) {
-        GetContext().reductionMod[symbol->name().ToString()] = modifier;
-      }
-    }
-  }
-}
-
-void OmpStructureChecker::CheckAndAddSymbolsToUsedInScanList(
+void OmpStructureChecker::CheckAndMarkSymbolsUsedInScan(
     const parser::OmpObjectList &x) {
   for (const auto &ompObj : x.v) {
-    auto checkScanSymbolInReduction = [&](const parser::Name *name) {
+    auto checkAndMark = [&](const parser::Name *name) {
       if (name->symbol) {
         if (CurrentDirectiveIsNested()) {
-          std::string nameStr = name->symbol->name().ToString();
-          if (GetContextParent().reductionMod.find(nameStr) ==
-              GetContextParent().reductionMod.end()) {
-
+          ScanReductionInfo &scanReductionInfo = scanReductionInfoStack.top();
+          std::optional<ReductionModifier> reductionMod =
+              scanReductionInfo.findReductionModifier(name->symbol);
+          if (!reductionMod.has_value() ||
+              reductionMod.value() != ReductionModifier::Inscan) {
             context_.Say(name->source,
-                "List item %s must appear in 'reduction' clause "
-                "with the 'inscan' modifier of the parent "
+                "List item %s must appear in REDUCTION clause "
+                "with the INSCAN modifier of the parent "
                 "directive"_err_en_US,
-                nameStr);
+                name->ToString());
           }
-          GetContextParent().usedInScanDirective.insert(nameStr);
+          scanReductionInfo.markSymbolAsUsedInScanConstruct(name->symbol);
         }
       }
     };
@@ -2931,10 +2931,10 @@ void OmpStructureChecker::CheckAndAddSymbolsToUsedInScanList(
             [&](const parser::Designator &designator) {
               if (const auto *name{
                       semantics::getDesignatorNameIfDataRef(designator)}) {
-                checkScanSymbolInReduction(name);
+                checkAndMark(name);
               }
             },
-            [&](const auto &name) { checkScanSymbolInReduction(&name); },
+            [&](const auto &name) { checkAndMark(&name); },
         },
         ompObj.u);
   }
@@ -3112,7 +3112,7 @@ void OmpStructureChecker::CheckReductionModifier(
     if (!llvm::omp::scanParentAllowedSet.test(dirCtx.directive)) {
       context_.Say(GetContext().clauseSource,
           "Modifier 'INSCAN' on REDUCTION clause is only allowed with "
-          "worksharing-loop, worksharing-loop simd, "
+          "WORKSHARING LOOP, WORKSHARING LOOP SIMD, "
           "or SIMD directive"_err_en_US);
     }
   } else {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 5fbdfe7b9ab408..be14806155caec 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -20,6 +20,8 @@
 #include "flang/Semantics/openmp-directive-sets.h"
 #include "flang/Semantics/semantics.h"
 #include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include <optional>
+#include <stack>
 
 using OmpClauseSet =
     Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
@@ -71,6 +73,43 @@ class OmpStructureChecker
   }
   using llvmOmpClause = const llvm::omp::Clause;
   using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+  using Symbol = Fortran::semantics::Symbol;
+  class ScanReductionInfo {
+
+  public:
+    std::set<Symbol *> usedInScanDirective;
+    std::map<Symbol *, ReductionModifier> reductionMod;
+
+    void mapSymbolsToReductionModifiers(
+        const parser::OmpObjectList &x, const ReductionModifier &modifier) {
+      for (const auto &ompObject : x.v) {
+        if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
+          if (const auto &symbol{name->symbol}) {
+            reductionMod[symbol] = modifier;
+          }
+        }
+      }
+    }
+
+    void markSymbolAsUsedInScanConstruct(Symbol *sym) {
+      usedInScanDirective.insert(sym);
+    }
+
+    bool findSymbolInScanConstruct(Symbol *sym) {
+      if (usedInScanDirective.find(sym) != usedInScanDirective.end()) {
+        return true;
+      }
+      return false;
+    }
+
+    std::optional<ReductionModifier> findReductionModifier(Symbol *sym) {
+      if (reductionMod.find(sym) != reductionMod.end()) {
+        return reductionMod[sym];
+      }
+      return std::nullopt;
+    }
+  };
+  std::stack<class ScanReductionInfo> scanReductionInfoStack;
 
   void Enter(const parser::OpenMPConstruct &);
   void Leave(const parser::OpenMPConstruct &);
@@ -249,9 +288,7 @@ class OmpStructureChecker
       const parser::OmpObjectList &ompObjectList);
   void CheckPredefinedAllocatorRestriction(
       const parser::CharBlock &source, const parser::Name &name);
-  void CheckAndAddSymbolsToUsedInScanList(const parser::OmpObjectList &x);
-  void AddModifierToMap(
-      const parser::OmpObjectList &x, const ReductionModifier &modifier);
+  void CheckAndMarkSymbolsUsedInScan(const parser::OmpObjectList &x);
   bool isPredefinedAllocator{false};
 
   void CheckAllowedRequiresClause(llvmOmpClause clause);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index e30c0fbcee85f4..4b847469169359 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -21,6 +21,7 @@
 #include "flang/Semantics/expression.h"
 #include "flang/Semantics/symbol.h"
 #include "flang/Semantics/tools.h"
+#include <iostream>
 #include <list>
 #include <map>
 #include <sstream>
@@ -458,6 +459,18 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
   }
 
   // 2.15.3 Data-Sharing Attribute Clauses
+  void ResolveNames(const parser::OmpObjectList &objList);
+
+  bool Pre(const parser::OmpClause::Inclusive &x) {
+    const auto &objectList{x.v};
+    ResolveNames(objectList);
+    return false;
+  }
+  bool Pre(const parser::OmpClause::Exclusive &x) {
+    const auto &objectList{x.v};
+    ResolveNames(objectList);
+    return false;
+  }
   void Post(const parser::OmpDefaultClause &);
   bool Pre(const parser::OmpClause::Shared &x) {
     ResolveOmpObjectList(x.v, Symbol::Flag::OmpShared);
@@ -2957,4 +2970,19 @@ void OmpAttributeVisitor::IssueNonConformanceWarning(
   context_.Warn(common::UsageWarning::OpenMPUsage, source, "%s"_warn_en_US,
       warnStrOS.str());
 }
+void OmpAttributeVisitor::ResolveNames(const parser::OmpObjectList &objList) {
+  for (const auto &ompObj : objList.v) {
+    common::visit(
+        common::visitors{
+            [&](const parser::Designator &designator) {
+              if (const auto *name{
+                      semantics::getDesignatorNameIfDataRef(designator)}) {
+                ResolveName(name);
+              }
+            },
+            [&](const auto &name) { ResolveName(&name); },
+        },
+        ompObj.u);
+  }
+}
 } // namespace Fortran::semantics
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90 b/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
index c5f196fe09693a..152d91a16f80fe 100644
--- a/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
+++ b/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
@@ -8,6 +8,7 @@ subroutine reduction_inscan()
 
   !$omp do reduction(inscan, +:i)
   do j=1,10
+     !$omp scan inclusive(i)
      i = i + 1
   end do
   !$omp end do
diff --git a/flang/test/Semantics/OpenMP/reduction-modifiers.f90 b/flang/test/Semantics/OpenMP/reduction-modifiers.f90
index 31d21e9d4189cb..e6238bb8cb7ffc 100644
--- a/flang/test/Semantics/OpenMP/reduction-modifiers.f90
+++ b/flang/test/Semantics/OpenMP/reduction-modifiers.f90
@@ -72,7 +72,7 @@ subroutine mod_inscan3(x)
 subroutine mod_inscan4(x)
   integer, intent(inout) :: x
 
-  !ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with worksharing-loop, worksharing-loop simd, or SIMD directive
+  !ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with WORKSHARING LOOP, WORKSHARING LOOP SIMD, or SIMD directive
   !$omp parallel reduction(inscan, +:x)
   do i = 1, 100
     x = foo(i)
@@ -83,7 +83,7 @@ subroutine mod_inscan4(x)
 subroutine mod_inscan5(x)
   integer, intent(inout) :: x
 
-  !ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with worksharing-loop, worksharing-loop simd, or SIMD directive
+  !ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with WORKSHARING LOOP, WORKSHARING LOOP SIMD, or SIMD directive
   !$omp sections reduction(inscan, +:x)
   do i = 1, 100
     x = foo(i)
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
index c7526d31df4acb..4535a73650cf7d 100644
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -3,7 +3,7 @@
 subroutine test_scan()
  integer x, y, k, z
  
- !ERROR: Orphaned `omp scan` directives are prohibited; perhaps you forgot to enclose the directive in to a worksharing loop, a worksharing loop simd or a simd directive.
+ !ERROR: Orphaned SCAN directives are prohibited; perhaps you forgot to enclose the directive in to a WORKSHARING LOOP, a WORKSHARING LOOP SIMD or a SIMD directive.
  !$omp scan inclusive(x)
  !$omp parallel do simd
  do k = 1, n
@@ -13,21 +13,21 @@ subroutine test_scan()
  
  !$omp parallel do simd
  do k = 1, n
- !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
    !$omp scan
  end do
 
 !$omp parallel do simd reduction(inscan,+: x, y)
  do k = 1, n
- !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
    !$omp scan inclusive(x) exclusive(y)
  end do
 
-!ERROR: List item y must appear in 'inclusive' or 'exclusive' clause of an enclosed scan directive
+!ERROR: List item y must appear in EXCLUSIVE or INCLUSIVE clause of an enclosed SCAN directive
 !$omp parallel do simd reduction(inscan,+: x, y)
  do k = 1, n
- !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
- !ERROR: List item z must appear in 'reduction' clause with the 'inscan' modifier of the parent directive
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
+ !ERROR: List item z must appear in REDUCTION clause with the INSCAN modifier of the parent directive
    !$omp scan inclusive(x) exclusive(z)
  end do
 end subroutine

>From 8464253dbbe7590aa802a58bdaa75a8d6fed76bc Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Wed, 13 Nov 2024 17:23:24 -0600
Subject: [PATCH 09/10] R9: Addressing review comments

---
 flang/include/flang/Semantics/symbol.h      |  2 +-
 flang/lib/Semantics/check-omp-structure.cpp |  2 --
 flang/lib/Semantics/check-omp-structure.h   |  9 +++---
 flang/lib/Semantics/resolve-directives.cpp  | 29 ++++--------------
 flang/test/Semantics/OpenMP/scan1.f90       | 33 +++++++++++++++++++++
 flang/test/Semantics/OpenMP/scan2.f90       | 27 +++++++++++++++++
 6 files changed, 70 insertions(+), 32 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/scan1.f90
 create mode 100644 flang/test/Semantics/OpenMP/scan2.f90

diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index b9512f33eaacd5..6accb0c5b45117 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -755,7 +755,7 @@ class Symbol {
       OmpDeclarativeAllocateDirective, OmpExecutableAllocateDirective,
       OmpDeclareSimd, OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction,
       OmpFlushed, OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined,
-      OmpImplicit, OmpDependObject);
+      OmpImplicit, OmpDependObject, OmpInclusiveScan, OmpExclusiveScan);
   using Flags = common::EnumSet<Flag, Flag_enumSize>;
 
   const Scope &owner() const { return *owner_; }
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 1e0956a3abb87f..31566b2c201a0d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -981,14 +981,12 @@ void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
   // constructs inside LOOP may add the relevant information. Scan reduction is
   // supported only in loop constructs, so same checks are not applicable to
   // other directives.
-
   for (const auto &clause : clauseList.v) {
     if (const auto *reductionClause{
             std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
       const auto &maybeModifier{
           std::get<std::optional<ReductionModifier>>(reductionClause->v.t)};
       if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
-
         const auto &objectList{
             std::get<parser::OmpObjectList>(reductionClause->v.t)};
         auto checkReductionSymbolInScan = [&](const parser::Name *name) {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index be14806155caec..16ed42769d4e25 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -75,11 +75,10 @@ class OmpStructureChecker
   using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
   using Symbol = Fortran::semantics::Symbol;
   class ScanReductionInfo {
-
-  public:
-    std::set<Symbol *> usedInScanDirective;
+    std::set<Symbol *> usedInScan;
     std::map<Symbol *, ReductionModifier> reductionMod;
 
+  public:
     void mapSymbolsToReductionModifiers(
         const parser::OmpObjectList &x, const ReductionModifier &modifier) {
       for (const auto &ompObject : x.v) {
@@ -92,11 +91,11 @@ class OmpStructureChecker
     }
 
     void markSymbolAsUsedInScanConstruct(Symbol *sym) {
-      usedInScanDirective.insert(sym);
+      usedInScan.insert(sym);
     }
 
     bool findSymbolInScanConstruct(Symbol *sym) {
-      if (usedInScanDirective.find(sym) != usedInScanDirective.end()) {
+      if (usedInScan.find(sym) != usedInScan.end()) {
         return true;
       }
       return false;
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 4b847469169359..45478fd876c4cc 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -21,7 +21,6 @@
 #include "flang/Semantics/expression.h"
 #include "flang/Semantics/symbol.h"
 #include "flang/Semantics/tools.h"
-#include <iostream>
 #include <list>
 #include <map>
 #include <sstream>
@@ -459,16 +458,12 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
   }
 
   // 2.15.3 Data-Sharing Attribute Clauses
-  void ResolveNames(const parser::OmpObjectList &objList);
-
   bool Pre(const parser::OmpClause::Inclusive &x) {
-    const auto &objectList{x.v};
-    ResolveNames(objectList);
+    ResolveOmpObjectList(x.v, Symbol::Flag::OmpInclusiveScan);
     return false;
   }
   bool Pre(const parser::OmpClause::Exclusive &x) {
-    const auto &objectList{x.v};
-    ResolveNames(objectList);
+    ResolveOmpObjectList(x.v, Symbol::Flag::OmpExclusiveScan);
     return false;
   }
   void Post(const parser::OmpDefaultClause &);
@@ -705,8 +700,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
       Symbol::Flag::OmpUseDevicePtr, Symbol::Flag::OmpUseDeviceAddr,
       Symbol::Flag::OmpIsDevicePtr, Symbol::Flag::OmpHasDeviceAddr};
 
-  Symbol::Flags ompFlagsRequireMark{
-      Symbol::Flag::OmpThreadprivate, Symbol::Flag::OmpDeclareTarget};
+  Symbol::Flags ompFlagsRequireMark{Symbol::Flag::OmpThreadprivate,
+      Symbol::Flag::OmpDeclareTarget, Symbol::Flag::OmpExclusiveScan,
+      Symbol::Flag::OmpInclusiveScan};
 
   Symbol::Flags dataCopyingAttributeFlags{
       Symbol::Flag::OmpCopyIn, Symbol::Flag::OmpCopyPrivate};
@@ -2970,19 +2966,4 @@ void OmpAttributeVisitor::IssueNonConformanceWarning(
   context_.Warn(common::UsageWarning::OpenMPUsage, source, "%s"_warn_en_US,
       warnStrOS.str());
 }
-void OmpAttributeVisitor::ResolveNames(const parser::OmpObjectList &objList) {
-  for (const auto &ompObj : objList.v) {
-    common::visit(
-        common::visitors{
-            [&](const parser::Designator &designator) {
-              if (const auto *name{
-                      semantics::getDesignatorNameIfDataRef(designator)}) {
-                ResolveName(name);
-              }
-            },
-            [&](const auto &name) { ResolveName(&name); },
-        },
-        ompObj.u);
-  }
-}
 } // namespace Fortran::semantics
diff --git a/flang/test/Semantics/OpenMP/scan1.f90 b/flang/test/Semantics/OpenMP/scan1.f90
new file mode 100644
index 00000000000000..4535a73650cf7d
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/scan1.f90
@@ -0,0 +1,33 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+subroutine test_scan()
+ integer x, y, k, z
+ 
+ !ERROR: Orphaned SCAN directives are prohibited; perhaps you forgot to enclose the directive in to a WORKSHARING LOOP, a WORKSHARING LOOP SIMD or a SIMD directive.
+ !$omp scan inclusive(x)
+ !$omp parallel do simd
+ do k = 1, n
+ !ERROR: UNTIED clause is not allowed on the SCAN directive
+   !$omp scan untied
+ end do
+ 
+ !$omp parallel do simd
+ do k = 1, n
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
+   !$omp scan
+ end do
+
+!$omp parallel do simd reduction(inscan,+: x, y)
+ do k = 1, n
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
+   !$omp scan inclusive(x) exclusive(y)
+ end do
+
+!ERROR: List item y must appear in EXCLUSIVE or INCLUSIVE clause of an enclosed SCAN directive
+!$omp parallel do simd reduction(inscan,+: x, y)
+ do k = 1, n
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
+ !ERROR: List item z must appear in REDUCTION clause with the INSCAN modifier of the parent directive
+   !$omp scan inclusive(x) exclusive(z)
+ end do
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/scan2.f90 b/flang/test/Semantics/OpenMP/scan2.f90
new file mode 100644
index 00000000000000..a53d0caaab363b
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/scan2.f90
@@ -0,0 +1,27 @@
+! RUN: %flang_fc1 -fopenmp -fdebug-dump-symbols -o - %s 2>&1 | FileCheck %s
+! Check scan reduction
+
+! CHECK: MainProgram scope: omp_reduction
+program omp_reduction
+  ! CHECK: i size=4 offset=0: ObjectEntity type: INTEGER(4)
+  integer i
+  ! CHECK: k size=4 offset=4: ObjectEntity type: INTEGER(4) init:10_4
+  integer :: k = 10
+  ! CHECK: m size=4 offset=8: ObjectEntity type: INTEGER(4) init:12_4
+  integer :: m = 12
+
+  ! CHECK: OtherConstruct scope
+  ! CHECK: i (OmpPrivate, OmpPreDetermined): HostAssoc
+  ! CHECK: k (OmpReduction, OmpInclusiveScan): HostAssoc
+  !$omp parallel do  reduction(inscan, +:k)
+  do i=1,10
+   !$omp scan inclusive(k)
+  end do
+  !$omp end parallel do
+  ! CHECK: m (OmpReduction, OmpExclusiveScan): HostAssoc
+  !$omp parallel do  reduction(inscan, +:m)
+  do i=1,10
+   !$omp scan exclusive(m)
+  end do
+  !$omp end parallel do
+end program omp_reduction

>From 4b644ff3cbff664fa6a8bfd94c669cfdfc5eb438 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 14 Nov 2024 21:02:25 -0600
Subject: [PATCH 10/10] R10: Re-implementing a few checks by removing stack

---
 flang/include/flang/Semantics/symbol.h      |  3 +-
 flang/lib/Semantics/check-omp-structure.cpp | 60 ++-------------------
 flang/lib/Semantics/check-omp-structure.h   | 39 --------------
 flang/lib/Semantics/resolve-directives.cpp  | 18 ++++++-
 flang/test/Semantics/OpenMP/scan.f90        | 33 ------------
 flang/test/Semantics/OpenMP/scan1.f90       |  1 +
 flang/test/Semantics/OpenMP/scan2.f90       |  4 +-
 7 files changed, 27 insertions(+), 131 deletions(-)
 delete mode 100644 flang/test/Semantics/OpenMP/scan.f90

diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index 6accb0c5b45117..2f97efddf7f7ba 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -755,7 +755,8 @@ class Symbol {
       OmpDeclarativeAllocateDirective, OmpExecutableAllocateDirective,
       OmpDeclareSimd, OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction,
       OmpFlushed, OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined,
-      OmpImplicit, OmpDependObject, OmpInclusiveScan, OmpExclusiveScan);
+      OmpImplicit, OmpDependObject, OmpInclusiveScan, OmpExclusiveScan,
+      OmpInScanReduction);
   using Flags = common::EnumSet<Flag, Flag_enumSize>;
 
   const Scope &owner() const { return *owner_; }
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 31566b2c201a0d..b9c06853cea67b 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -990,9 +990,9 @@ void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
         const auto &objectList{
             std::get<parser::OmpObjectList>(reductionClause->v.t)};
         auto checkReductionSymbolInScan = [&](const parser::Name *name) {
-          if (name->symbol) {
-            if (!scanReductionInfoStack.top().findSymbolInScanConstruct(
-                    name->symbol)) {
+          if (auto &symbol = name->symbol) {
+            if (!symbol->test(Symbol::Flag::OmpInclusiveScan) &&
+                !symbol->test(Symbol::Flag::OmpExclusiveScan)) {
               context_.Say(name->source,
                   "List item %s must appear in EXCLUSIVE or "
                   "INCLUSIVE clause of an "
@@ -1014,7 +1014,6 @@ void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
               },
               ompObj.u);
         }
-        scanReductionInfoStack.pop();
       }
     }
   }
@@ -2740,12 +2739,14 @@ CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
 CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach)
 CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type)
 CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
+CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive)
 CHECK_SIMPLE_CLAUSE(Final, OMPC_final)
 CHECK_SIMPLE_CLAUSE(Flush, OMPC_flush)
 CHECK_SIMPLE_CLAUSE(Full, OMPC_full)
 CHECK_SIMPLE_CLAUSE(Grainsize, OMPC_grainsize)
 CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint)
 CHECK_SIMPLE_CLAUSE(Holds, OMPC_holds)
+CHECK_SIMPLE_CLAUSE(Inclusive, OMPC_inclusive)
 CHECK_SIMPLE_CLAUSE(InReduction, OMPC_in_reduction)
 CHECK_SIMPLE_CLAUSE(Match, OMPC_match)
 CHECK_SIMPLE_CLAUSE(Nontemporal, OMPC_nontemporal)
@@ -2842,26 +2843,10 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
   if (const auto &maybeModifier{
           std::get<std::optional<ReductionModifier>>(x.v.t)}) {
     const ReductionModifier modifier{*maybeModifier};
-    if (modifier == ReductionModifier::Inscan) {
-      scanReductionInfoStack.emplace();
-      const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
-      scanReductionInfoStack.top().mapSymbolsToReductionModifiers(
-          ompObjectList, modifier);
-    }
     CheckReductionModifier(modifier);
   }
 }
 
-void OmpStructureChecker::Enter(const parser::OmpClause::Inclusive &x) {
-  CheckAllowed(llvm::omp::Clause::OMPC_inclusive);
-  CheckAndMarkSymbolsUsedInScan(x.v);
-}
-
-void OmpStructureChecker::Enter(const parser::OmpClause::Exclusive &x) {
-  CheckAllowed(llvm::omp::Clause::OMPC_exclusive);
-  CheckAndMarkSymbolsUsedInScan(x.v);
-}
-
 bool OmpStructureChecker::CheckReductionOperators(
     const parser::OmpClause::Reduction &x) {
 
@@ -2903,41 +2888,6 @@ bool OmpStructureChecker::CheckReductionOperators(
   return ok;
 }
 
-void OmpStructureChecker::CheckAndMarkSymbolsUsedInScan(
-    const parser::OmpObjectList &x) {
-  for (const auto &ompObj : x.v) {
-    auto checkAndMark = [&](const parser::Name *name) {
-      if (name->symbol) {
-        if (CurrentDirectiveIsNested()) {
-          ScanReductionInfo &scanReductionInfo = scanReductionInfoStack.top();
-          std::optional<ReductionModifier> reductionMod =
-              scanReductionInfo.findReductionModifier(name->symbol);
-          if (!reductionMod.has_value() ||
-              reductionMod.value() != ReductionModifier::Inscan) {
-            context_.Say(name->source,
-                "List item %s must appear in REDUCTION clause "
-                "with the INSCAN modifier of the parent "
-                "directive"_err_en_US,
-                name->ToString());
-          }
-          scanReductionInfo.markSymbolAsUsedInScanConstruct(name->symbol);
-        }
-      }
-    };
-    common::visit(
-        common::visitors{
-            [&](const parser::Designator &designator) {
-              if (const auto *name{
-                      semantics::getDesignatorNameIfDataRef(designator)}) {
-                checkAndMark(name);
-              }
-            },
-            [&](const auto &name) { checkAndMark(&name); },
-        },
-        ompObj.u);
-  }
-}
-
 bool OmpStructureChecker::CheckIntrinsicOperator(
     const parser::DefinedOperator::IntrinsicOperator &op) {
 
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 16ed42769d4e25..e91d3ebcc5b09d 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -20,8 +20,6 @@
 #include "flang/Semantics/openmp-directive-sets.h"
 #include "flang/Semantics/semantics.h"
 #include "llvm/Frontend/OpenMP/OMPConstants.h"
-#include <optional>
-#include <stack>
 
 using OmpClauseSet =
     Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
@@ -73,42 +71,6 @@ class OmpStructureChecker
   }
   using llvmOmpClause = const llvm::omp::Clause;
   using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
-  using Symbol = Fortran::semantics::Symbol;
-  class ScanReductionInfo {
-    std::set<Symbol *> usedInScan;
-    std::map<Symbol *, ReductionModifier> reductionMod;
-
-  public:
-    void mapSymbolsToReductionModifiers(
-        const parser::OmpObjectList &x, const ReductionModifier &modifier) {
-      for (const auto &ompObject : x.v) {
-        if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
-          if (const auto &symbol{name->symbol}) {
-            reductionMod[symbol] = modifier;
-          }
-        }
-      }
-    }
-
-    void markSymbolAsUsedInScanConstruct(Symbol *sym) {
-      usedInScan.insert(sym);
-    }
-
-    bool findSymbolInScanConstruct(Symbol *sym) {
-      if (usedInScan.find(sym) != usedInScan.end()) {
-        return true;
-      }
-      return false;
-    }
-
-    std::optional<ReductionModifier> findReductionModifier(Symbol *sym) {
-      if (reductionMod.find(sym) != reductionMod.end()) {
-        return reductionMod[sym];
-      }
-      return std::nullopt;
-    }
-  };
-  std::stack<class ScanReductionInfo> scanReductionInfoStack;
 
   void Enter(const parser::OpenMPConstruct &);
   void Leave(const parser::OpenMPConstruct &);
@@ -287,7 +249,6 @@ class OmpStructureChecker
       const parser::OmpObjectList &ompObjectList);
   void CheckPredefinedAllocatorRestriction(
       const parser::CharBlock &source, const parser::Name &name);
-  void CheckAndMarkSymbolsUsedInScan(const parser::OmpObjectList &x);
   bool isPredefinedAllocator{false};
 
   void CheckAllowedRequiresClause(llvmOmpClause clause);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 45478fd876c4cc..8e7763fbdd780e 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -546,6 +546,12 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
     }
     const auto &objList{std::get<parser::OmpObjectList>(x.v.t)};
     ResolveOmpObjectList(objList, Symbol::Flag::OmpReduction);
+    using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+    const auto &maybeModifier{
+        std::get<std::optional<ReductionModifier>>(x.v.t)};
+    if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
+      ResolveOmpObjectList(objList, Symbol::Flag::OmpInScanReduction);
+    }
     return false;
   }
 
@@ -702,7 +708,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
 
   Symbol::Flags ompFlagsRequireMark{Symbol::Flag::OmpThreadprivate,
       Symbol::Flag::OmpDeclareTarget, Symbol::Flag::OmpExclusiveScan,
-      Symbol::Flag::OmpInclusiveScan};
+      Symbol::Flag::OmpInclusiveScan, Symbol::Flag::OmpInScanReduction};
 
   Symbol::Flags dataCopyingAttributeFlags{
       Symbol::Flag::OmpCopyIn, Symbol::Flag::OmpCopyPrivate};
@@ -2439,6 +2445,16 @@ void OmpAttributeVisitor::ResolveOmpObject(
                         name->ToString());
                   }
                 }
+                if (ompFlag == Symbol::Flag::OmpInclusiveScan ||
+                    ompFlag == Symbol::Flag::OmpExclusiveScan) {
+                  if (!symbol->test(Symbol::Flag::OmpInScanReduction)) {
+                    context_.Say(name->source,
+                        "List item %s must appear in REDUCTION clause "
+                        "with the INSCAN modifier of the parent "
+                        "directive"_err_en_US,
+                        name->ToString());
+                  }
+                }
                 if (GetContext().directive ==
                     llvm::omp::Directive::OMPD_target_data) {
                   checkExclusivelists(symbol, Symbol::Flag::OmpUseDevicePtr,
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
deleted file mode 100644
index 4535a73650cf7d..00000000000000
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ /dev/null
@@ -1,33 +0,0 @@
-! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
-
-subroutine test_scan()
- integer x, y, k, z
- 
- !ERROR: Orphaned SCAN directives are prohibited; perhaps you forgot to enclose the directive in to a WORKSHARING LOOP, a WORKSHARING LOOP SIMD or a SIMD directive.
- !$omp scan inclusive(x)
- !$omp parallel do simd
- do k = 1, n
- !ERROR: UNTIED clause is not allowed on the SCAN directive
-   !$omp scan untied
- end do
- 
- !$omp parallel do simd
- do k = 1, n
- !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
-   !$omp scan
- end do
-
-!$omp parallel do simd reduction(inscan,+: x, y)
- do k = 1, n
- !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
-   !$omp scan inclusive(x) exclusive(y)
- end do
-
-!ERROR: List item y must appear in EXCLUSIVE or INCLUSIVE clause of an enclosed SCAN directive
-!$omp parallel do simd reduction(inscan,+: x, y)
- do k = 1, n
- !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
- !ERROR: List item z must appear in REDUCTION clause with the INSCAN modifier of the parent directive
-   !$omp scan inclusive(x) exclusive(z)
- end do
-end subroutine
diff --git a/flang/test/Semantics/OpenMP/scan1.f90 b/flang/test/Semantics/OpenMP/scan1.f90
index 4535a73650cf7d..9e8fc9dec1c6bf 100644
--- a/flang/test/Semantics/OpenMP/scan1.f90
+++ b/flang/test/Semantics/OpenMP/scan1.f90
@@ -4,6 +4,7 @@ subroutine test_scan()
  integer x, y, k, z
  
  !ERROR: Orphaned SCAN directives are prohibited; perhaps you forgot to enclose the directive in to a WORKSHARING LOOP, a WORKSHARING LOOP SIMD or a SIMD directive.
+ !ERROR: List item x must appear in REDUCTION clause with the INSCAN modifier of the parent directive
  !$omp scan inclusive(x)
  !$omp parallel do simd
  do k = 1, n
diff --git a/flang/test/Semantics/OpenMP/scan2.f90 b/flang/test/Semantics/OpenMP/scan2.f90
index a53d0caaab363b..5232e63aa6b4f1 100644
--- a/flang/test/Semantics/OpenMP/scan2.f90
+++ b/flang/test/Semantics/OpenMP/scan2.f90
@@ -12,13 +12,13 @@ program omp_reduction
 
   ! CHECK: OtherConstruct scope
   ! CHECK: i (OmpPrivate, OmpPreDetermined): HostAssoc
-  ! CHECK: k (OmpReduction, OmpInclusiveScan): HostAssoc
+  ! CHECK: k (OmpReduction, OmpInclusiveScan, OmpInScanReduction): HostAssoc
   !$omp parallel do  reduction(inscan, +:k)
   do i=1,10
    !$omp scan inclusive(k)
   end do
   !$omp end parallel do
-  ! CHECK: m (OmpReduction, OmpExclusiveScan): HostAssoc
+  ! CHECK: m (OmpReduction, OmpExclusiveScan, OmpInScanReduction): HostAssoc
   !$omp parallel do  reduction(inscan, +:m)
   do i=1,10
    !$omp scan exclusive(m)



More information about the flang-commits mailing list