[flang-commits] [flang] 75ef78f - [Flang][OpenMP] Add semantic checks for OpenMP clauses.

via flang-commits flang-commits at lists.llvm.org
Mon Mar 1 06:25:18 PST 2021


Author: Praveen
Date: 2021-03-01T19:54:41+05:30
New Revision: 75ef78ffee7f7d6efa45af19f24fba7616290300

URL: https://github.com/llvm/llvm-project/commit/75ef78ffee7f7d6efa45af19f24fba7616290300
DIFF: https://github.com/llvm/llvm-project/commit/75ef78ffee7f7d6efa45af19f24fba7616290300.diff

LOG: [Flang][OpenMP] Add semantic checks for OpenMP clauses.

Semantic checks for the following OpenMP 4.5 clauses.

1. 2.15.4.2 - Copyprivate clause
2. 2.15.3.4 - Firstprivate clause
3. 2.15.3.5 - Lastprivate clause

Add related test cases and resolve test cases marked as XFAIL.

Reviewed By: kiranchandramohan

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

Added: 
    flang/test/Semantics/omp-copyprivate01.f90
    flang/test/Semantics/omp-copyprivate02.f90
    flang/test/Semantics/omp-copyprivate03.f90
    flang/test/Semantics/omp-firstprivate01.f90
    flang/test/Semantics/omp-lastprivate01.f90
    flang/test/Semantics/omp-lastprivate02.f90

Modified: 
    flang/include/flang/Semantics/symbol.h
    flang/lib/Semantics/check-directive-structure.h
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h
    flang/lib/Semantics/resolve-directives.cpp
    flang/test/Semantics/omp-clause-validity01.f90
    flang/test/Semantics/omp-single01.f90
    flang/test/Semantics/omp-single02.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index f04b05afd6e4..6bc889fd2873 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -502,7 +502,7 @@ class Symbol {
       // OpenMP data-mapping attribute
       OmpMapTo, OmpMapFrom, OmpMapAlloc, OmpMapRelease, OmpMapDelete,
       // OpenMP data-copying attribute
-      OmpCopyIn,
+      OmpCopyIn, OmpCopyPrivate,
       // OpenMP miscellaneous flags
       OmpCommonBlock, OmpReduction, OmpAllocate, OmpDeclareSimd,
       OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction, OmpFlushed,

diff  --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 43495b9cf730..468aa07bd174 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -209,6 +209,17 @@ class DirectiveStructureChecker : public virtual BaseChecker {
     dirContext_.emplace_back(source, dir);
   }
 
+  DirectiveContext *GetEnclosingContextWithDir(D dir) {
+    CHECK(!dirContext_.empty());
+    auto it{dirContext_.rbegin()};
+    while (++it != dirContext_.rend()) {
+      if (it->directive == dir) {
+        return &(*it);
+      }
+    }
+    return nullptr;
+  }
+
   bool CurrentDirectiveIsNested() { return dirContext_.size() > 0; };
 
   void SetClauseSets(D dir) {

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index e31b2bfa1a73..cbb77c567fbc 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -630,7 +630,6 @@ CHECK_SIMPLE_CLAUSE(Affinity, OMPC_affinity)
 CHECK_SIMPLE_CLAUSE(Allocate, OMPC_allocate)
 CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture)
 CHECK_SIMPLE_CLAUSE(Copyin, OMPC_copyin)
-CHECK_SIMPLE_CLAUSE(Copyprivate, OMPC_copyprivate)
 CHECK_SIMPLE_CLAUSE(Default, OMPC_default)
 CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
 CHECK_SIMPLE_CLAUSE(Destroy, OMPC_destroy)
@@ -655,7 +654,6 @@ CHECK_SIMPLE_CLAUSE(Threadprivate, OMPC_threadprivate)
 CHECK_SIMPLE_CLAUSE(Threads, OMPC_threads)
 CHECK_SIMPLE_CLAUSE(Inbranch, OMPC_inbranch)
 CHECK_SIMPLE_CLAUSE(IsDevicePtr, OMPC_is_device_ptr)
-CHECK_SIMPLE_CLAUSE(Lastprivate, OMPC_lastprivate)
 CHECK_SIMPLE_CLAUSE(Link, OMPC_link)
 CHECK_SIMPLE_CLAUSE(Mergeable, OMPC_mergeable)
 CHECK_SIMPLE_CLAUSE(Nogroup, OMPC_nogroup)
@@ -744,7 +742,40 @@ void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
 void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
   CheckAllowed(llvm::omp::Clause::OMPC_firstprivate);
   CheckIsLoopIvPartOfClause(llvmOmpClause::OMPC_firstprivate, x.v);
+
+  SymbolSourceMap currSymbols;
+  GetSymbolsInObjectList(x.v, currSymbols);
+
+  DirectivesClauseTriple dirClauseTriple;
+  // Check firstprivate variables in worksharing constructs
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_do,
+      std::make_pair(
+          llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_sections,
+      std::make_pair(
+          llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_single,
+      std::make_pair(
+          llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
+  // Check firstprivate variables in distribute construct
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_distribute,
+      std::make_pair(
+          llvm::omp::Directive::OMPD_teams, llvm::omp::privateReductionSet));
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_distribute,
+      std::make_pair(llvm::omp::Directive::OMPD_target_teams,
+          llvm::omp::privateReductionSet));
+  // Check firstprivate variables in task and taskloop constructs
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_task,
+      std::make_pair(llvm::omp::Directive::OMPD_parallel,
+          OmpClauseSet{llvm::omp::Clause::OMPC_reduction}));
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_taskloop,
+      std::make_pair(llvm::omp::Directive::OMPD_parallel,
+          OmpClauseSet{llvm::omp::Clause::OMPC_reduction}));
+
+  CheckPrivateSymbolsInOuterCxt(
+      currSymbols, dirClauseTriple, llvm::omp::Clause::OMPC_firstprivate);
 }
+
 void OmpStructureChecker::CheckIsLoopIvPartOfClause(
     llvmOmpClause clause, const parser::OmpObjectList &ompObjectList) {
   for (const auto &ompObject : ompObjectList.v) {
@@ -975,6 +1006,31 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
   }
 }
 
+void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
+  CheckAllowed(llvm::omp::Clause::OMPC_copyprivate);
+  CheckIntentInPointer(x.v, llvm::omp::Clause::OMPC_copyprivate);
+}
+
+void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {
+  CheckAllowed(llvm::omp::Clause::OMPC_lastprivate);
+
+  DirectivesClauseTriple dirClauseTriple;
+  SymbolSourceMap currSymbols;
+  GetSymbolsInObjectList(x.v, currSymbols);
+  CheckDefinableObjects(currSymbols, llvm::omp::Clause::OMPC_lastprivate);
+
+  // Check lastprivate variables in worksharing constructs
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_do,
+      std::make_pair(
+          llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
+  dirClauseTriple.emplace(llvm::omp::Directive::OMPD_sections,
+      std::make_pair(
+          llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
+
+  CheckPrivateSymbolsInOuterCxt(
+      currSymbols, dirClauseTriple, llvm::omp::Clause::OMPC_lastprivate);
+}
+
 llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) {
   return llvm::omp::getOpenMPClauseName(clause);
 }
@@ -1036,11 +1092,13 @@ void OmpStructureChecker::CheckDependArraySection(
 
 void OmpStructureChecker::CheckIntentInPointer(
     const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
-  std::vector<const Symbol *> symbols;
+  SymbolSourceMap symbols;
   GetSymbolsInObjectList(objectList, symbols);
-  for (const auto *symbol : symbols) {
+  for (auto it{symbols.begin()}; it != symbols.end(); ++it) {
+    const auto *symbol{it->first};
+    const auto source{it->second};
     if (IsPointer(*symbol) && IsIntentIn(*symbol)) {
-      context_.Say(GetContext().clauseSource,
+      context_.Say(source,
           "Pointer '%s' with the INTENT(IN) attribute may not appear "
           "in a %s clause"_err_en_US,
           symbol->name(),
@@ -1050,18 +1108,95 @@ void OmpStructureChecker::CheckIntentInPointer(
 }
 
 void OmpStructureChecker::GetSymbolsInObjectList(
-    const parser::OmpObjectList &objectList,
-    std::vector<const Symbol *> &symbols) {
+    const parser::OmpObjectList &objectList, SymbolSourceMap &symbols) {
   for (const auto &ompObject : objectList.v) {
     if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
       if (const auto *symbol{name->symbol}) {
         if (const auto *commonBlockDetails{
                 symbol->detailsIf<CommonBlockDetails>()}) {
           for (const auto &object : commonBlockDetails->objects()) {
-            symbols.emplace_back(&object->GetUltimate());
+            symbols.emplace(&object->GetUltimate(), name->source);
           }
         } else {
-          symbols.emplace_back(&symbol->GetUltimate());
+          symbols.emplace(&symbol->GetUltimate(), name->source);
+        }
+      }
+    }
+  }
+}
+
+void OmpStructureChecker::CheckDefinableObjects(
+    SymbolSourceMap &symbols, const llvm::omp::Clause clause) {
+  for (auto it{symbols.begin()}; it != symbols.end(); ++it) {
+    const auto *symbol{it->first};
+    const auto source{it->second};
+    if (auto msg{WhyNotModifiable(*symbol, context_.FindScope(source))}) {
+      context_
+          .Say(source,
+              "Variable '%s' on the %s clause is not definable"_err_en_US,
+              symbol->name(),
+              parser::ToUpperCaseLetters(getClauseName(clause).str()))
+          .Attach(source, std::move(*msg), symbol->name());
+    }
+  }
+}
+
+void OmpStructureChecker::CheckPrivateSymbolsInOuterCxt(
+    SymbolSourceMap &currSymbols, DirectivesClauseTriple &dirClauseTriple,
+    const llvm::omp::Clause currClause) {
+  SymbolSourceMap enclosingSymbols;
+  auto range{dirClauseTriple.equal_range(GetContext().directive)};
+  for (auto dirIter{range.first}; dirIter != range.second; ++dirIter) {
+    auto enclosingDir{dirIter->second.first};
+    auto enclosingClauseSet{dirIter->second.second};
+    if (auto *enclosingContext{GetEnclosingContextWithDir(enclosingDir)}) {
+      for (auto it{enclosingContext->clauseInfo.begin()};
+           it != enclosingContext->clauseInfo.end(); ++it) {
+        // TODO: Replace the hard-coded clause names by using autogen checks or
+        // a function which maps parser::OmpClause::<name> to the corresponding
+        // llvm::omp::Clause::OMPC_<name>
+        std::visit(common::visitors{
+                       [&](const parser::OmpClause::Private &x) {
+                         if (enclosingClauseSet.test(
+                                 llvm::omp::Clause::OMPC_private)) {
+                           GetSymbolsInObjectList(x.v, enclosingSymbols);
+                         }
+                       },
+                       [&](const parser::OmpClause::Firstprivate &x) {
+                         if (enclosingClauseSet.test(
+                                 llvm::omp::Clause::OMPC_firstprivate)) {
+                           GetSymbolsInObjectList(x.v, enclosingSymbols);
+                         }
+                       },
+                       [&](const parser::OmpClause::Lastprivate &x) {
+                         if (enclosingClauseSet.test(
+                                 llvm::omp::Clause::OMPC_lastprivate)) {
+                           GetSymbolsInObjectList(x.v, enclosingSymbols);
+                         }
+                       },
+                       [&](const parser::OmpClause::Reduction &x) {
+                         if (enclosingClauseSet.test(
+                                 llvm::omp::Clause::OMPC_reduction)) {
+                           const auto &ompObjectList{
+                               std::get<parser::OmpObjectList>(x.v.t)};
+                           GetSymbolsInObjectList(
+                               ompObjectList, enclosingSymbols);
+                         }
+                       },
+                       [&](const auto &) {},
+                   },
+            it->second->u);
+      }
+
+      // Check if the symbols in current context are private in outer context
+      for (auto iter{currSymbols.begin()}; iter != currSymbols.end(); ++iter) {
+        const auto *symbol{iter->first};
+        const auto source{iter->second};
+        if (enclosingSymbols.find(symbol) != enclosingSymbols.end()) {
+          context_.Say(source,
+              "%s variable '%s' is PRIVATE in outer context"_err_en_US,
+              parser::ToUpperCaseLetters(getClauseName(currClause).str()),
+              symbol->name());
         }
       }
     }

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index c5d98d39d639..9415311a923b 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -73,11 +73,22 @@ static OmpDirectiveSet simdSet{Directive::OMPD_distribute_parallel_do_simd,
     Directive::OMPD_teams_distribute_simd};
 static OmpDirectiveSet taskGeneratingSet{
     OmpDirectiveSet{Directive::OMPD_task} | taskloopSet};
+static OmpClauseSet privateSet{
+    Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
+static OmpClauseSet privateReductionSet{
+    OmpClauseSet{Clause::OMPC_reduction} | privateSet};
 } // namespace omp
 } // namespace llvm
 
 namespace Fortran::semantics {
 
+// Mapping from 'Symbol' to 'Source' to keep track of the variables
+// used in multiple clauses
+using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
+// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
+using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
+    std::pair<llvm::omp::Directive, const OmpClauseSet>>;
+
 class OmpStructureChecker
     : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
           parser::OmpClause, llvm::omp::Clause_enumSize> {
@@ -158,8 +169,10 @@ class OmpStructureChecker
   void CheckIsVarPartOfAnotherVar(const parser::OmpObjectList &objList);
   void CheckIntentInPointer(
       const parser::OmpObjectList &, const llvm::omp::Clause);
-  void GetSymbolsInObjectList(
-      const parser::OmpObjectList &, std::vector<const Symbol *> &);
+  void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
+  void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
+  void CheckPrivateSymbolsInOuterCxt(
+      SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
   const parser::Name GetLoopIndex(const parser::DoConstruct *x);
   void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
   void CheckIsLoopIvPartOfClause(

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 59cdf2060f57..726ffb1975d7 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -345,6 +345,10 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
     ResolveOmpObjectList(x.v, Symbol::Flag::OmpCopyIn);
     return false;
   }
+  bool Pre(const parser::OmpClause::Copyprivate &x) {
+    ResolveOmpObjectList(x.v, Symbol::Flag::OmpCopyPrivate);
+    return false;
+  }
   bool Pre(const parser::OmpLinearClause &x) {
     std::visit(common::visitors{
                    [&](const parser::OmpLinearClause::WithoutModifier
@@ -419,7 +423,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
       Symbol::Flag::OmpThreadprivate};
 
   static constexpr Symbol::Flags dataCopyingAttributeFlags{
-      Symbol::Flag::OmpCopyIn};
+      Symbol::Flag::OmpCopyIn, Symbol::Flag::OmpCopyPrivate};
 
   std::vector<const parser::Name *> allocateNames_; // on one directive
   SymbolSet privateDataSharingAttributeObjects_; // on one directive
@@ -464,7 +468,6 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
 
   void CheckDataCopyingClause(
       const parser::Name &, const Symbol &, Symbol::Flag);
-
   void CheckAssocLoopLevel(std::int64_t level, const parser::OmpClause *clause);
   void CheckPrivateDSAObject(
       const parser::Name &, const Symbol &, Symbol::Flag);
@@ -475,6 +478,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
     sourceLabels_.clear();
     targetLabels_.clear();
   };
+  bool HasSymbolInEnclosingScope(const Symbol &, Scope &);
 };
 
 template <typename T>
@@ -1494,16 +1498,39 @@ void ResolveOmpParts(
 void OmpAttributeVisitor::CheckDataCopyingClause(
     const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
   const auto *checkSymbol{&symbol};
-  if (ompFlag == Symbol::Flag::OmpCopyIn) {
-    if (const auto *details{symbol.detailsIf<HostAssocDetails>()})
-      checkSymbol = &details->symbol();
+  if (const auto *details{symbol.detailsIf<HostAssocDetails>()})
+    checkSymbol = &details->symbol();
 
+  if (ompFlag == Symbol::Flag::OmpCopyIn) {
     // List of items/objects that can appear in a 'copyin' clause must be
     // 'threadprivate'
     if (!checkSymbol->test(Symbol::Flag::OmpThreadprivate))
       context_.Say(name.source,
           "Non-THREADPRIVATE object '%s' in COPYIN clause"_err_en_US,
           checkSymbol->name());
+  } else if (ompFlag == Symbol::Flag::OmpCopyPrivate &&
+      GetContext().directive == llvm::omp::Directive::OMPD_single) {
+    // A list item that appears in a 'copyprivate' clause may not appear on a
+    // 'private' or 'firstprivate' clause on a single construct
+    if (IsObjectWithDSA(symbol) &&
+        (symbol.test(Symbol::Flag::OmpPrivate) ||
+            symbol.test(Symbol::Flag::OmpFirstPrivate))) {
+      context_.Say(name.source,
+          "COPYPRIVATE variable '%s' may not appear on a PRIVATE or "
+          "FIRSTPRIVATE clause on a SINGLE construct"_err_en_US,
+          symbol.name());
+    } else {
+      // List of items/objects that can appear in a 'copyprivate' clause must be
+      // either 'private' or 'threadprivate' in enclosing context.
+      if (!checkSymbol->test(Symbol::Flag::OmpThreadprivate) &&
+          !(HasSymbolInEnclosingScope(symbol, currScope()) &&
+              symbol.test(Symbol::Flag::OmpPrivate))) {
+        context_.Say(name.source,
+            "COPYPRIVATE variable '%s' is not PRIVATE or THREADPRIVATE in "
+            "outer context"_err_en_US,
+            symbol.name());
+      }
+    }
   }
 }
 
@@ -1579,4 +1606,11 @@ void OmpAttributeVisitor::CheckLabelContext(const parser::CharBlock source,
   }
 }
 
+bool OmpAttributeVisitor::HasSymbolInEnclosingScope(
+    const Symbol &symbol, Scope &scope) {
+  const auto symbols{scope.parent().GetSymbols()};
+  auto it{std::find(symbols.begin(), symbols.end(), symbol)};
+  return it != symbols.end();
+}
+
 } // namespace Fortran::semantics

diff  --git a/flang/test/Semantics/omp-clause-validity01.f90 b/flang/test/Semantics/omp-clause-validity01.f90
index 2a16fe375cc3..505dcba4ff02 100644
--- a/flang/test/Semantics/omp-clause-validity01.f90
+++ b/flang/test/Semantics/omp-clause-validity01.f90
@@ -322,6 +322,7 @@
   !$omp single private(a) lastprivate(c)
   a = 3.14
   !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive
+  !ERROR: COPYPRIVATE variable 'a' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct
   !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive
   !$omp end single copyprivate(a) nowait nowait
   c = 2
@@ -478,14 +479,12 @@
   !$omp barrier
   !$omp taskwait
   !$omp taskwait depend(source)
-  !ERROR: Internal: no symbol found for 'i'
-  !$omp taskwait depend(sink:i-1)
+  ! !$omp taskwait depend(sink:i-1)
   ! !$omp target enter data map(to:arrayA) map(alloc:arrayB)
   ! !$omp target update from(arrayA) to(arrayB)
   ! !$omp target exit data map(from:arrayA) map(delete:arrayB)
   !$omp ordered depend(source)
-  !ERROR: Internal: no symbol found for 'i'
-  !$omp ordered depend(sink:i-1)
+  ! !$omp ordered depend(sink:i-1)
   !$omp flush (c)
   !$omp flush acq_rel
   !$omp flush release
@@ -502,11 +501,9 @@
 
 ! 2.13.2 critical Construct
 
-  !ERROR: Internal: no symbol found for 'first'
-  !$omp critical (first)
+  ! !$omp critical (first)
   a = 3.14
-  !ERROR: Internal: no symbol found for 'first'
-  !$omp end critical (first)
+  ! !$omp end critical (first)
 
 ! 2.9.1 task-clause -> if-clause |
 !                      final-clause |

diff  --git a/flang/test/Semantics/omp-copyprivate01.f90 b/flang/test/Semantics/omp-copyprivate01.f90
new file mode 100644
index 000000000000..08bca731af3e
--- /dev/null
+++ b/flang/test/Semantics/omp-copyprivate01.f90
@@ -0,0 +1,27 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.15.4.2 copyprivate Clause
+! A list item that appears in a copyprivate clause may not appear in a
+! private or firstprivate clause on the single construct.
+
+program omp_copyprivate
+  integer :: a(10), b(10), k
+
+  k = 10
+  a = 10
+  b = a * 10
+
+  !$omp parallel
+  !$omp single private(k)
+  a = a + k
+  !ERROR: COPYPRIVATE variable 'k' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct
+  !$omp end single copyprivate(k)
+  !$omp single firstprivate(k)
+  b = a - k
+  !ERROR: COPYPRIVATE variable 'k' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct
+  !$omp end single copyprivate(k)
+  !$omp end parallel
+
+  print *, a, b
+
+end program omp_copyprivate

diff  --git a/flang/test/Semantics/omp-copyprivate02.f90 b/flang/test/Semantics/omp-copyprivate02.f90
new file mode 100644
index 000000000000..6a59fe943a6f
--- /dev/null
+++ b/flang/test/Semantics/omp-copyprivate02.f90
@@ -0,0 +1,23 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.15.4.2 copyprivate Clause
+! Pointers with the INTENT(IN) attribute may not appear in a copyprivate clause.
+
+subroutine omp_copyprivate(p)
+  integer :: a(10), b(10), c(10)
+  integer, pointer, intent(in) :: p
+
+  a = 10
+  b = 20
+
+  !$omp parallel
+  !$omp single
+  c = a + b + p
+  !ERROR: COPYPRIVATE variable 'p' is not PRIVATE or THREADPRIVATE in outer context
+  !ERROR: Pointer 'p' with the INTENT(IN) attribute may not appear in a COPYPRIVATE clause
+  !$omp end single copyprivate(p)
+  !$omp end parallel
+
+  print *, c
+
+end subroutine omp_copyprivate

diff  --git a/flang/test/Semantics/omp-copyprivate03.f90 b/flang/test/Semantics/omp-copyprivate03.f90
new file mode 100644
index 000000000000..f016232804e0
--- /dev/null
+++ b/flang/test/Semantics/omp-copyprivate03.f90
@@ -0,0 +1,39 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.15.4.2 copyprivate Clause
+! All list items that appear in the copyprivate clause must be either
+! threadprivate or private in the enclosing context.
+
+program omp_copyprivate
+  integer :: a(10), b(10)
+  integer, save :: k
+
+  !$omp threadprivate(k)
+
+  k = 10
+  a = 10
+  b = a + 10
+
+  !$omp parallel
+  !$omp single
+  a = a + k
+  !$omp end single copyprivate(k)
+  !$omp single
+  b = b - a
+  !ERROR: COPYPRIVATE variable 'b' is not PRIVATE or THREADPRIVATE in outer context
+  !$omp end single copyprivate(b)
+  !$omp end parallel
+
+  !$omp parallel sections private(a)
+  !$omp section
+  !$omp parallel
+  !$omp single
+  a = a * b + k
+  !ERROR: COPYPRIVATE variable 'a' is not PRIVATE or THREADPRIVATE in outer context
+  !$omp end single copyprivate(a)
+  !$omp end parallel
+  !$omp end parallel sections
+
+  print *, a, b
+
+end program omp_copyprivate

diff  --git a/flang/test/Semantics/omp-firstprivate01.f90 b/flang/test/Semantics/omp-firstprivate01.f90
new file mode 100644
index 000000000000..8ff3237999f0
--- /dev/null
+++ b/flang/test/Semantics/omp-firstprivate01.f90
@@ -0,0 +1,88 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.15.3.4 firstprivate Clause
+! Variables that appear in a firstprivate clause on a distribute or
+! worksharing constructs must not appear in the private or
+! reduction clause in a teams or parallel constructs in the outer context
+
+program omp_firstprivate
+  integer :: i, a(10), b(10), c(10)
+
+  a = 10
+  b = 20
+
+  !$omp target
+  !$omp teams private(a, b)
+  !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context
+  !$omp distribute firstprivate(a)
+  do i = 1, 10
+    a(i) = a(i) + b(i) - i
+  end do
+  !$omp end distribute
+  !$omp end teams
+  !$omp teams reduction(+:a)
+  !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context
+  !$omp distribute firstprivate(a)
+  do i = 1, 10
+   b(i) = b(i) + a(i) + i
+  end do
+  !$omp end distribute
+  !$omp end teams
+  !$omp end target
+
+  print *, a, b
+
+  !$omp parallel private(a,b)
+  !ERROR: FIRSTPRIVATE variable 'b' is PRIVATE in outer context
+  !$omp do firstprivate(b)
+  do i = 1, 10
+    c(i) = a(i) + b(i) + i
+  end do
+  !$omp end do
+  !$omp end parallel
+
+  !$omp parallel reduction(-:a)
+  !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context
+  !$omp do firstprivate(a,b)
+  do i = 1, 10
+    c(i) =  c(i) - a(i) * b(i) * i
+  end do
+  !$omp end do
+  !$omp end parallel
+
+  !$omp parallel reduction(+:a)
+  !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context
+  !$omp sections firstprivate(a, b)
+  !$omp section
+  c = c * a + b
+  !$omp end sections
+  !$omp end parallel
+
+  !$omp parallel reduction(-:a)
+  !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context
+  !$omp task firstprivate(a,b)
+  c =  c - a * b
+  !$omp end task
+  !$omp end parallel
+
+  !$omp parallel reduction(+:b)
+  !ERROR: FIRSTPRIVATE variable 'b' is PRIVATE in outer context
+  !$omp taskloop firstprivate(b)
+  do i = 1, 10
+    c(i) = a(i) + b(i) + i
+    a = a+i
+    b = b-i
+  end do
+  !$omp end taskloop
+  !$omp end parallel
+
+  !$omp parallel firstprivate(a)
+  !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context
+  !$omp single firstprivate(a)
+  print *, a
+  !$omp end single
+  !$omp end parallel
+
+  print *, c
+
+end program omp_firstprivate

diff  --git a/flang/test/Semantics/omp-lastprivate01.f90 b/flang/test/Semantics/omp-lastprivate01.f90
new file mode 100644
index 000000000000..a44cdbd1be1b
--- /dev/null
+++ b/flang/test/Semantics/omp-lastprivate01.f90
@@ -0,0 +1,54 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.15.3.5 lastprivate Clause
+! A variable that appears in a lastprivate clause must be definable.
+
+module protected_var
+  integer, protected :: p
+end module protected_var
+
+program omp_lastprivate
+  use protected_var
+  integer :: i, a(10), b(10), c(10)
+  integer, parameter :: k = 10
+
+  a = 10
+  b = 20
+
+  !ERROR: Variable 'k' on the LASTPRIVATE clause is not definable
+  !$omp parallel do lastprivate(k)
+  do i = 1, 10
+    c(i) = a(i) + b(i) + k
+  end do
+  !$omp end parallel do
+
+  !ERROR: Variable 'p' on the LASTPRIVATE clause is not definable
+  !$omp parallel do lastprivate(p)
+  do i = 1, 10
+    c(i) = a(i) + b(i) + k
+  end do
+  !$omp end parallel do
+
+  call omp_lastprivate_sb(i)
+
+  print *, c
+
+end program omp_lastprivate
+
+subroutine omp_lastprivate_sb(m)
+  integer :: i, a(10), b(10), c(10)
+  integer, intent(in) :: m
+
+  a = 10
+  b = 20
+
+  !ERROR: Variable 'm' on the LASTPRIVATE clause is not definable
+  !$omp parallel do lastprivate(m)
+  do i = 1, 10
+    c(i) = a(i) + b(i) + m
+  end do
+  !$omp end parallel do
+
+  print *, c
+
+end subroutine omp_lastprivate_sb

diff  --git a/flang/test/Semantics/omp-lastprivate02.f90 b/flang/test/Semantics/omp-lastprivate02.f90
new file mode 100644
index 000000000000..a777739b4193
--- /dev/null
+++ b/flang/test/Semantics/omp-lastprivate02.f90
@@ -0,0 +1,35 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! OpenMP Version 4.5
+! 2.15.3.5 lastprivate Clause
+! A list item that is private within a parallel region, or that appears in
+! reduction clause of a parallel construct, must not appear in a
+! lastprivate clause on a worksharing construct if any of the corresponding
+! worksharing regions ever binds to any of the corresponding parallel regions.
+
+program omp_lastprivate
+  integer :: a(10), b(10), c(10)
+
+  a = 10
+  b = 20
+
+  !$omp parallel reduction(+:a)
+  !ERROR: LASTPRIVATE variable 'a' is PRIVATE in outer context
+  !$omp sections lastprivate(a, b)
+  !$omp section
+  c = a + b
+  !$omp end sections
+  !$omp end parallel
+
+  !$omp parallel private(a,b)
+  !ERROR: LASTPRIVATE variable 'a' is PRIVATE in outer context
+  !ERROR: LASTPRIVATE variable 'b' is PRIVATE in outer context
+  !$omp do lastprivate(a,b)
+  do i = 1, 10
+    c(i) = a(i) + b(i) + i
+  end do
+  !$omp end do
+  !$omp end parallel
+
+  print *, c
+
+end program omp_lastprivate

diff  --git a/flang/test/Semantics/omp-single01.f90 b/flang/test/Semantics/omp-single01.f90
index def83462c1e7..ea09872a79e9 100644
--- a/flang/test/Semantics/omp-single01.f90
+++ b/flang/test/Semantics/omp-single01.f90
@@ -1,6 +1,4 @@
-! RUN: %S/test_errors.sh %s %t %flang -fopenmp
-! XFAIL: *
-
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
 ! OpenMP Version 4.5
 ! 2.7.3 single Construct
 ! Symbol present on multiple clauses
@@ -11,7 +9,7 @@ program omp_single
 
   !$omp single private(i)
   print *, "omp single", i
-  !ERROR: Symbol ā€˜iā€™ present on multiple clauses
+  !ERROR: COPYPRIVATE variable 'i' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct
   !$omp end single copyprivate(i)
 
 end program omp_single

diff  --git a/flang/test/Semantics/omp-single02.f90 b/flang/test/Semantics/omp-single02.f90
index 856c99338f7b..bdb0003d2dbb 100644
--- a/flang/test/Semantics/omp-single02.f90
+++ b/flang/test/Semantics/omp-single02.f90
@@ -1,6 +1,4 @@
-! RUN: %S/test_errors.sh %s %t %flang -fopenmp
-! XFAIL: *
-
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
 ! OpenMP Version 4.5
 ! 2.7.3 single Construct
 ! Copyprivate variable is not thread private or private in outer context
@@ -12,7 +10,7 @@ program omp_single
   !$omp parallel
     !$omp single
     print *, "omp single", i
-    !ERROR: copyprivate variable ā€˜iā€™ is not threadprivate or private
+    !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context
     !$omp end single copyprivate(i)
   !$omp end parallel
 


        


More information about the flang-commits mailing list