[flang][OpenMP] Add semantic check for occurrence of multiple list items in aligned clause for simd directive

Reviewed By: kiranchandramohan, clementval

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

GitOrigin-RevId: e361afb6c5c9e0360d1782a23f143f80da94cee8
diff --git a/lib/Semantics/check-directive-structure.h b/lib/Semantics/check-directive-structure.h
index 468aa07..5d0750e 100644
--- a/lib/Semantics/check-directive-structure.h
+++ b/lib/Semantics/check-directive-structure.h
@@ -123,6 +123,7 @@
       : context_{context}, directiveClausesMap_(directiveClausesMap) {}
   virtual ~DirectiveStructureChecker() {}
 
+  using ClauseMapTy = std::multimap<C, const PC *>;
   struct DirectiveContext {
     DirectiveContext(parser::CharBlock source, D d)
         : directiveSource{source}, directive{d} {}
@@ -136,7 +137,7 @@
     common::EnumSet<C, ClauseEnumSize> requiredClauses{};
 
     const PC *clause{nullptr};
-    std::multimap<C, const PC *> clauseInfo;
+    ClauseMapTy clauseInfo;
     std::list<C> actualClauses;
     Symbol *loopIV{nullptr};
   };
@@ -205,6 +206,12 @@
     return nullptr;
   }
 
+  std::pair<typename ClauseMapTy::iterator, typename ClauseMapTy::iterator>
+  FindClauses(C type) {
+    auto it{GetContext().clauseInfo.equal_range(type)};
+    return it;
+  }
+
   void PushContext(const parser::CharBlock &source, D dir) {
     dirContext_.emplace_back(source, dir);
   }
diff --git a/lib/Semantics/check-omp-structure.cpp b/lib/Semantics/check-omp-structure.cpp
index 790072b..d41e37f 100644
--- a/lib/Semantics/check-omp-structure.cpp
+++ b/lib/Semantics/check-omp-structure.cpp
@@ -606,7 +606,24 @@
         }
       }
     }
-    // TODO: A list-item cannot appear in more than one aligned clause
+    // A list-item cannot appear in more than one aligned clause
+    semantics::SymbolSet alignedVars;
+    auto clauseAll = FindClauses(llvm::omp::Clause::OMPC_aligned);
+    for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) {
+      const auto &alignedClause{
+          std::get<parser::OmpClause::Aligned>(itr->second->u)};
+      const auto &alignedNameList{
+          std::get<std::list<parser::Name>>(alignedClause.v.t)};
+      for (auto const &var : alignedNameList) {
+        if (alignedVars.count(*(var.symbol)) == 1) {
+          context_.Say(itr->second->source,
+              "List item '%s' present at multiple ALIGNED clauses"_err_en_US,
+              var.ToString());
+          break;
+        }
+        alignedVars.insert(*(var.symbol));
+      }
+    }
   } // SIMD
 
   // 2.7.3 Single Construct Restriction
diff --git a/test/Semantics/omp-simd-aligned.f90 b/test/Semantics/omp-simd-aligned.f90
new file mode 100644
index 0000000..5626608
--- /dev/null
+++ b/test/Semantics/omp-simd-aligned.f90
@@ -0,0 +1,54 @@
+! RUN: %S/test_errors.sh %s %t %flang -fopenmp
+
+! OpenMP Version 4.5
+! 2.8.1 simd Construct
+! Semantic error for correct test case
+
+program omp_simd
+  integer i, j, k
+  integer, allocatable :: a(:), b(:)
+
+  allocate(a(10))
+  allocate(b(10))
+
+  !ERROR: List item 'a' present at multiple ALIGNED clauses
+  !$omp simd aligned(a, a)
+  do i = 1, 10
+    a(i) = i
+  end do
+  !$omp end simd
+
+  !ERROR: List item 'a' present at multiple ALIGNED clauses
+  !ERROR: List item 'b' present at multiple ALIGNED clauses
+  !$omp simd aligned(a,a) aligned(b) aligned(b)
+  do i = 1, 10
+    a(i) = i
+    b(i) = i
+  end do
+  !$omp end simd
+
+  !ERROR: List item 'a' present at multiple ALIGNED clauses
+  !$omp simd aligned(a) aligned(a)
+  do i = 1, 10
+    a(i) = i
+  end do
+  !$omp end simd
+
+  !$omp simd aligned(a) aligned(b)
+  do i = 1, 10
+    a(i) = i
+    b(i) = i
+  end do
+  !$omp end simd
+
+  !ERROR: List item 'a' present at multiple ALIGNED clauses
+  !$omp simd aligned(a) private(a) aligned(a)
+  do i = 1, 10
+    a(i) = i
+    b(i) = i
+  end do
+  !$omp end simd
+
+  print *, a
+
+end program omp_simd