[flang-commits] [flang] [Flang][OpenMP] Allow copyprivate and nowait on the directive clauses (PR #127769)

Thirumalai Shaktivel via flang-commits flang-commits at lists.llvm.org
Fri Feb 28 03:46:24 PST 2025


https://github.com/Thirumalai-Shaktivel updated https://github.com/llvm/llvm-project/pull/127769

>From 50cdcf65c9f21dc80f3867960bc8b3daa6b09bd5 Mon Sep 17 00:00:00 2001
From: Thirumalai-Shaktivel <thirumalaishaktivel at gmail.com>
Date: Wed, 19 Feb 2025 08:54:19 +0000
Subject: [PATCH 1/7] [Flang][OpenMP] Allow copyprivate and nowait on the
 directive clauses

Issue:
- Single construct used to throw semantic error for copyprivate and
  nowiat clause when used in the single directive.
- Also, the Nowait and copyprivate restrictions has be removed from
  OpenMP 6.0

Fix:
- The above mentioned semantic error was valid until OpenMP 5.1.
- From OpenMP 5.2, copyprivate and nowait is allowed in both
  clause and end-clause

>From Reference guide (OpenMP 5.2, 2.10.2):
```
!$omp single [clause[ [,]clause] ... ]
loosely-structured-block
!$omp end single [end-clause[ [,]end-clause] ...]

clause:
  copyprivate (list)
  nowait
  [...]

end-clause:
  copyprivate (list)
  nowait
```
---
 flang/lib/Semantics/check-omp-structure.cpp   | 57 ++++++++++++++++---
 .../Semantics/OpenMP/clause-validity01.f90    |  6 +-
 flang/test/Semantics/OpenMP/single03.f90      | 54 ++++++++++++++++++
 .../test/Semantics/OpenMP/threadprivate04.f90 |  2 +-
 4 files changed, 106 insertions(+), 13 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/single03.f90

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 1d6fe6c8d4249..93f71c1951658 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1203,6 +1203,40 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
     deviceConstructFound_ = true;
   }
 
+  unsigned version{context_.langOptions().OpenMPVersion};
+  if (version >= 52 &&
+      GetContext().directive == llvm::omp::Directive::OMPD_single) {
+    bool foundCopyPrivate{false};
+    bool foundNowait{false};
+    parser::CharBlock NowaitSource{""};
+    auto catchCopyPrivateNowaitClauses = [&](const auto &dir) {
+      for (auto &clause : std::get<parser::OmpClauseList>(dir.t).v) {
+        if (clause.Id() == llvm::omp::Clause::OMPC_copyprivate) {
+          if (foundCopyPrivate) {
+            context_.Say(clause.source,
+                "At most one COPYPRIVATE clause can appear on the SINGLE directive"_err_en_US);
+          } else {
+            foundCopyPrivate = true;
+          }
+        } else if (clause.Id() == llvm::omp::Clause::OMPC_nowait) {
+          if (foundNowait) {
+            context_.Say(clause.source,
+                "At most one NOWAIT clause can appear on the SINGLE directive"_err_en_US);
+          } else {
+            foundNowait = true;
+            NowaitSource = clause.source;
+          }
+        }
+      }
+    };
+    catchCopyPrivateNowaitClauses(beginBlockDir);
+    catchCopyPrivateNowaitClauses(endBlockDir);
+    if (version == 52 && foundCopyPrivate && foundNowait) {
+      context_.Say(NowaitSource,
+          "NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive"_err_en_US);
+    }
+  }
+
   switch (beginDir.v) {
   case llvm::omp::Directive::OMPD_target:
     if (CheckTargetBlockOnlyTeams(block)) {
@@ -2853,7 +2887,8 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
   CheckMultListItems();
 
   // 2.7.3 Single Construct Restriction
-  if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
+  if (context_.langOptions().OpenMPVersion < 52 &&
+      GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
     CheckNotAllowedIfClause(
         llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait});
   }
@@ -3481,14 +3516,16 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) {
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Nowait &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_nowait);
-  if (llvm::omp::noWaitClauseNotAllowedSet.test(GetContext().directive)) {
+  if (context_.langOptions().OpenMPVersion < 52 &&
+      llvm::omp::noWaitClauseNotAllowedSet.test(GetContext().directive)) {
+    std::string dirName{
+        parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())};
     context_.Say(GetContext().clauseSource,
         "%s clause is not allowed on the OMP %s directive,"
-        " use it on OMP END %s directive "_err_en_US,
+        " use it on OMP END %s directive or %s"_err_en_US,
         parser::ToUpperCaseLetters(
             getClauseName(llvm::omp::Clause::OMPC_nowait).str()),
-        parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()),
-        parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
+        dirName, dirName, TryVersion(52));
   }
 }
 
@@ -4220,14 +4257,16 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
   CheckIntentInPointer(symbols, llvm::omp::Clause::OMPC_copyprivate);
   CheckCopyingPolymorphicAllocatable(
       symbols, llvm::omp::Clause::OMPC_copyprivate);
-  if (GetContext().directive == llvm::omp::Directive::OMPD_single) {
+  if (context_.langOptions().OpenMPVersion < 52 &&
+      GetContext().directive == llvm::omp::Directive::OMPD_single) {
+    std::string dirName{
+        parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())};
     context_.Say(GetContext().clauseSource,
         "%s clause is not allowed on the OMP %s directive,"
-        " use it on OMP END %s directive "_err_en_US,
+        " use it on OMP END %s directive or %s"_err_en_US,
         parser::ToUpperCaseLetters(
             getClauseName(llvm::omp::Clause::OMPC_copyprivate).str()),
-        parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()),
-        parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
+        dirName, dirName, TryVersion(52));
   }
 }
 
diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index e8114154a809b..0349a5a760753 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -330,7 +330,7 @@
   !$omp parallel
   b = 1
   !ERROR: LASTPRIVATE clause is not allowed on the SINGLE directive
-  !ERROR: NOWAIT clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive 
+  !ERROR: NOWAIT clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive or try -fopenmp-version=52
   !$omp single private(a) lastprivate(c) nowait
   a = 3.14
   !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive
@@ -351,7 +351,7 @@
   a = 1.0
   !ERROR: COPYPRIVATE clause is not allowed on the END WORKSHARE directive
   !$omp end workshare nowait copyprivate(a)
-  !ERROR: NOWAIT clause is not allowed on the OMP WORKSHARE directive, use it on OMP END WORKSHARE directive 
+  !ERROR: NOWAIT clause is not allowed on the OMP WORKSHARE directive, use it on OMP END WORKSHARE directive or try -fopenmp-version=52
   !$omp workshare nowait
   !$omp end workshare
   !$omp end parallel
@@ -420,7 +420,7 @@
   !$omp parallel
   !ERROR: No ORDERED clause with a parameter can be specified on the DO SIMD directive
   !ERROR: NOGROUP clause is not allowed on the DO SIMD directive
-  !ERROR: NOWAIT clause is not allowed on the OMP DO SIMD directive, use it on OMP END DO SIMD directive 
+  !ERROR: NOWAIT clause is not allowed on the OMP DO SIMD directive, use it on OMP END DO SIMD directive or try -fopenmp-version=52
   !$omp do simd ordered(2) NOGROUP nowait
   do i = 1, N
      do j = 1, N
diff --git a/flang/test/Semantics/OpenMP/single03.f90 b/flang/test/Semantics/OpenMP/single03.f90
new file mode 100644
index 0000000000000..bc7647b66e39f
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/single03.f90
@@ -0,0 +1,54 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=52
+!
+! OpenMP Version 5.2
+!
+! 2.10.2 single Construct
+! Copyprivate and Nowait clauses are allowed in both clause and end clause
+
+subroutine omp_single
+    integer, save :: i
+    integer       :: j
+    i = 10; j = 11
+
+    !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !$omp single copyprivate(i) nowait
+        print *, "omp single", i
+    !$omp end single
+
+    !$omp parallel private(i)
+        !$omp single copyprivate(i)
+            print *, "omp single", i
+        !$omp end single
+    !$omp end parallel
+
+    !$omp parallel
+        !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+        !$omp single nowait
+            print *, "omp single", i
+        !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context
+        !$omp end single copyprivate(i)
+
+        !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context
+        !$omp single copyprivate(i)
+            print *, "omp single", i
+        !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+        !$omp end single nowait
+
+        !ERROR: COPYPRIVATE variable 'j' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct
+        !$omp single private(j) copyprivate(j)
+            print *, "omp single", j
+        !ERROR: At most one COPYPRIVATE clause can appear on the SINGLE directive
+        !ERROR: COPYPRIVATE variable 'j' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct
+        !$omp end single copyprivate(j)
+
+        !$omp single nowait
+            print *, "omp single", j
+        !ERROR: At most one NOWAIT clause can appear on the SINGLE directive
+        !$omp end single nowait
+    !$omp end parallel
+
+    !$omp single nowait
+        print *, "omp single", i
+    !$omp end single
+end subroutine omp_single
diff --git a/flang/test/Semantics/OpenMP/threadprivate04.f90 b/flang/test/Semantics/OpenMP/threadprivate04.f90
index 3d8c7fb8de8fa..db23cdb06ed96 100644
--- a/flang/test/Semantics/OpenMP/threadprivate04.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate04.f90
@@ -14,7 +14,7 @@ program main
   !$omp parallel num_threads(x1)
   !$omp end parallel
 
-  !ERROR: COPYPRIVATE clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive 
+  !ERROR: COPYPRIVATE clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive or try -fopenmp-version=52
   !$omp single copyprivate(x2, /blk1/)
   !$omp end single
 

>From 2ebb099bac421c7faa310227d0c97e84899b689c Mon Sep 17 00:00:00 2001
From: Thirumalai-Shaktivel <thirumalaishaktivel at gmail.com>
Date: Mon, 24 Feb 2025 06:18:34 +0000
Subject: [PATCH 2/7] [Flang] Remove semantic checks for Copyprivate and nowait

---
 flang/lib/Semantics/check-omp-structure.cpp   | 32 +++----------------
 .../Semantics/OpenMP/clause-validity01.f90    |  9 ++----
 .../test/Semantics/OpenMP/threadprivate04.f90 |  1 -
 3 files changed, 7 insertions(+), 35 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 93f71c1951658..af609cc89a336 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1203,9 +1203,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
     deviceConstructFound_ = true;
   }
 
-  unsigned version{context_.langOptions().OpenMPVersion};
-  if (version >= 52 &&
-      GetContext().directive == llvm::omp::Directive::OMPD_single) {
+  if (GetContext().directive == llvm::omp::Directive::OMPD_single) {
     bool foundCopyPrivate{false};
     bool foundNowait{false};
     parser::CharBlock NowaitSource{""};
@@ -1231,7 +1229,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
     };
     catchCopyPrivateNowaitClauses(beginBlockDir);
     catchCopyPrivateNowaitClauses(endBlockDir);
-    if (version == 52 && foundCopyPrivate && foundNowait) {
+    unsigned version{context_.langOptions().OpenMPVersion};
+    if (version <= 52 && foundCopyPrivate && foundNowait) {
       context_.Say(NowaitSource,
           "NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive"_err_en_US);
     }
@@ -2887,8 +2886,7 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
   CheckMultListItems();
 
   // 2.7.3 Single Construct Restriction
-  if (context_.langOptions().OpenMPVersion < 52 &&
-      GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
+  if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
     CheckNotAllowedIfClause(
         llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait});
   }
@@ -3516,17 +3514,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) {
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Nowait &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_nowait);
-  if (context_.langOptions().OpenMPVersion < 52 &&
-      llvm::omp::noWaitClauseNotAllowedSet.test(GetContext().directive)) {
-    std::string dirName{
-        parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())};
-    context_.Say(GetContext().clauseSource,
-        "%s clause is not allowed on the OMP %s directive,"
-        " use it on OMP END %s directive or %s"_err_en_US,
-        parser::ToUpperCaseLetters(
-            getClauseName(llvm::omp::Clause::OMPC_nowait).str()),
-        dirName, dirName, TryVersion(52));
-  }
 }
 
 bool OmpStructureChecker::IsDataRefTypeParamInquiry(
@@ -4257,17 +4244,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
   CheckIntentInPointer(symbols, llvm::omp::Clause::OMPC_copyprivate);
   CheckCopyingPolymorphicAllocatable(
       symbols, llvm::omp::Clause::OMPC_copyprivate);
-  if (context_.langOptions().OpenMPVersion < 52 &&
-      GetContext().directive == llvm::omp::Directive::OMPD_single) {
-    std::string dirName{
-        parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())};
-    context_.Say(GetContext().clauseSource,
-        "%s clause is not allowed on the OMP %s directive,"
-        " use it on OMP END %s directive or %s"_err_en_US,
-        parser::ToUpperCaseLetters(
-            getClauseName(llvm::omp::Clause::OMPC_copyprivate).str()),
-        dirName, dirName, TryVersion(52));
-  }
 }
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {
diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index 0349a5a760753..f6a252d8c7535 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -330,7 +330,6 @@
   !$omp parallel
   b = 1
   !ERROR: LASTPRIVATE clause is not allowed on the SINGLE directive
-  !ERROR: NOWAIT clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive or try -fopenmp-version=52
   !$omp single private(a) lastprivate(c) nowait
   a = 3.14
   !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive
@@ -351,7 +350,6 @@
   a = 1.0
   !ERROR: COPYPRIVATE clause is not allowed on the END WORKSHARE directive
   !$omp end workshare nowait copyprivate(a)
-  !ERROR: NOWAIT clause is not allowed on the OMP WORKSHARE directive, use it on OMP END WORKSHARE directive or try -fopenmp-version=52
   !$omp workshare nowait
   !$omp end workshare
   !$omp end parallel
@@ -420,7 +418,6 @@
   !$omp parallel
   !ERROR: No ORDERED clause with a parameter can be specified on the DO SIMD directive
   !ERROR: NOGROUP clause is not allowed on the DO SIMD directive
-  !ERROR: NOWAIT clause is not allowed on the OMP DO SIMD directive, use it on OMP END DO SIMD directive or try -fopenmp-version=52
   !$omp do simd ordered(2) NOGROUP nowait
   do i = 1, N
      do j = 1, N
@@ -428,7 +425,7 @@
      enddo
   enddo
   !omp end do nowait
-  !$omp end parallel 
+  !$omp end parallel
 
 ! 2.11.4 parallel-do-simd-clause -> parallel-clause |
 !                                   do-simd-clause
@@ -586,7 +583,7 @@
      allc = 3.14
   enddo
 
-  !$omp target enter data map(alloc:A) device(0) 
-  !$omp target exit data map(delete:A) device(0) 
+  !$omp target enter data map(alloc:A) device(0)
+  !$omp target exit data map(delete:A) device(0)
 
 end program
diff --git a/flang/test/Semantics/OpenMP/threadprivate04.f90 b/flang/test/Semantics/OpenMP/threadprivate04.f90
index db23cdb06ed96..d261f33b4dbd7 100644
--- a/flang/test/Semantics/OpenMP/threadprivate04.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate04.f90
@@ -14,7 +14,6 @@ program main
   !$omp parallel num_threads(x1)
   !$omp end parallel
 
-  !ERROR: COPYPRIVATE clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive or try -fopenmp-version=52
   !$omp single copyprivate(x2, /blk1/)
   !$omp end single
 

>From 656864e62a088d432e25b8b62a3ed2a1ef74c7c9 Mon Sep 17 00:00:00 2001
From: Thirumalai-Shaktivel <thirumalaishaktivel at gmail.com>
Date: Mon, 24 Feb 2025 07:32:33 +0000
Subject: [PATCH 3/7] Fix failures

---
 flang/test/Semantics/OpenMP/clause-validity01.f90 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index f6a252d8c7535..9d1c932b59456 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -330,10 +330,13 @@
   !$omp parallel
   b = 1
   !ERROR: LASTPRIVATE clause is not allowed on the SINGLE directive
+  !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
   !$omp single private(a) lastprivate(c) nowait
   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 SINGLE directive
+  !ERROR: At most one NOWAIT clause can appear on the SINGLE directive
   !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive
   !$omp end single copyprivate(a) nowait nowait
   c = 2

>From 6cbaf66bc0041f223307d95b97d88a53a97cb8cb Mon Sep 17 00:00:00 2001
From: Thirumalai-Shaktivel <thirumalaishaktivel at gmail.com>
Date: Mon, 24 Feb 2025 09:01:51 +0000
Subject: [PATCH 4/7] Remove duplicate checks

---
 flang/lib/Semantics/check-omp-structure.cpp       | 6 ------
 flang/test/Semantics/OpenMP/clause-validity01.f90 | 7 +++----
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index af609cc89a336..e2afff9d4120a 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2885,12 +2885,6 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
   // clause
   CheckMultListItems();
 
-  // 2.7.3 Single Construct Restriction
-  if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
-    CheckNotAllowedIfClause(
-        llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait});
-  }
-
   auto testThreadprivateVarErr = [&](Symbol sym, parser::Name name,
                                      llvmOmpClause clauseTy) {
     if (sym.test(Symbol::Flag::OmpThreadprivate))
diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index 9d1c932b59456..5e0d91914c441 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -333,7 +333,6 @@
   !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
   !$omp single private(a) lastprivate(c) nowait
   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 SINGLE directive
   !ERROR: At most one NOWAIT clause can appear on the SINGLE directive
@@ -428,7 +427,7 @@
      enddo
   enddo
   !omp end do nowait
-  !$omp end parallel
+  !$omp end parallel 
 
 ! 2.11.4 parallel-do-simd-clause -> parallel-clause |
 !                                   do-simd-clause
@@ -586,7 +585,7 @@
      allc = 3.14
   enddo
 
-  !$omp target enter data map(alloc:A) device(0)
-  !$omp target exit data map(delete:A) device(0)
+  !$omp target enter data map(alloc:A) device(0) 
+  !$omp target exit data map(delete:A) device(0) 
 
 end program

>From eebd6c6a3c69dcd3d5fbf29a0f1114717f6c11d4 Mon Sep 17 00:00:00 2001
From: Thirumalai-Shaktivel <thirumalaishaktivel at gmail.com>
Date: Fri, 28 Feb 2025 10:47:14 +0000
Subject: [PATCH 5/7] Fix Copyprivate clause semantics check

Changes:
- Throw error for repeated list items in the copyprivate clause
- Throw warnings for repeated use of copyprivate and nowait in the
  end directive
---
 flang/lib/Semantics/check-omp-structure.cpp   | 72 ++++++++++++++-----
 .../Semantics/OpenMP/clause-validity01.f90    |  4 +-
 flang/test/Semantics/OpenMP/single03.f90      |  4 +-
 3 files changed, 59 insertions(+), 21 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index e2afff9d4120a..9d75d308b28f8 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1204,33 +1204,71 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
   }
 
   if (GetContext().directive == llvm::omp::Directive::OMPD_single) {
-    bool foundCopyPrivate{false};
-    bool foundNowait{false};
-    parser::CharBlock NowaitSource{""};
-    auto catchCopyPrivateNowaitClauses = [&](const auto &dir) {
+    std::set<Symbol *> singleCopyprivateSyms;
+    std::set<Symbol *> endSingleCopyprivateSyms;
+    bool singleNowait{false};
+    bool endSingleNowait{false};
+    parser::CharBlock NowaitSource;
+
+    auto catchCopyPrivateNowaitClauses = [&](const auto &dir, bool endDir) {
       for (auto &clause : std::get<parser::OmpClauseList>(dir.t).v) {
         if (clause.Id() == llvm::omp::Clause::OMPC_copyprivate) {
-          if (foundCopyPrivate) {
-            context_.Say(clause.source,
-                "At most one COPYPRIVATE clause can appear on the SINGLE directive"_err_en_US);
-          } else {
-            foundCopyPrivate = true;
+          for (const auto &ompObject : GetOmpObjectList(clause)->v) {
+            const auto *name{parser::Unwrap<parser::Name>(ompObject)};
+            if (Symbol * symbol{name->symbol}) {
+              if (singleCopyprivateSyms.count(symbol)) {
+                if (endDir) {
+                  context_.Warn(common::UsageWarning::OpenMPUsage, name->source,
+                      "The COPYPRIVATE clause with '%s' is already used on the SINGLE directive"_warn_en_US,
+                      name->ToString());
+                } else {
+                  context_.Say(name->source,
+                      "'%s' appears in more than one COPYPRIVATE clause on the SINGLE directive"_err_en_US,
+                      name->ToString());
+                }
+              } else if (endSingleCopyprivateSyms.count(symbol)) {
+                context_.Say(name->source,
+                    "'%s' appears in more than one COPYPRIVATE clause on the END SINGLE directive"_err_en_US,
+                    name->ToString());
+              } else {
+                if (endDir) {
+                  endSingleCopyprivateSyms.insert(symbol);
+                } else {
+                  singleCopyprivateSyms.insert(symbol);
+                }
+              }
+            }
           }
         } else if (clause.Id() == llvm::omp::Clause::OMPC_nowait) {
-          if (foundNowait) {
+          if (singleNowait) {
+            if (endDir) {
+              context_.Warn(common::UsageWarning::OpenMPUsage, clause.source,
+                  "NOWAIT clause is already used on the SINGLE directive"_warn_en_US);
+            } else {
+              context_.Say(clause.source,
+                  "At most one NOWAIT clause can appear on the SINGLE directive"_err_en_US);
+            }
+          } else if (endSingleNowait) {
             context_.Say(clause.source,
-                "At most one NOWAIT clause can appear on the SINGLE directive"_err_en_US);
+                "At most one NOWAIT clause can appear on the END SINGLE directive"_err_en_US);
           } else {
-            foundNowait = true;
+            if (endDir) {
+              endSingleNowait = true;
+            } else {
+              singleNowait = true;
+            }
+          }
+          if (!NowaitSource.ToString().size()) {
             NowaitSource = clause.source;
           }
         }
       }
     };
-    catchCopyPrivateNowaitClauses(beginBlockDir);
-    catchCopyPrivateNowaitClauses(endBlockDir);
+    catchCopyPrivateNowaitClauses(beginBlockDir, false);
+    catchCopyPrivateNowaitClauses(endBlockDir, true);
     unsigned version{context_.langOptions().OpenMPVersion};
-    if (version <= 52 && foundCopyPrivate && foundNowait) {
+    if (version <= 52 && NowaitSource.ToString().size() &&
+        (singleCopyprivateSyms.size() || endSingleCopyprivateSyms.size())) {
       context_.Say(NowaitSource,
           "NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive"_err_en_US);
     }
@@ -1818,8 +1856,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPDispatchConstruct &x) {
 
   auto it{block.begin()};
   bool passChecks{false};
-  if (const parser::AssignmentStmt *
-      assignStmt{parser::Unwrap<parser::AssignmentStmt>(*it)}) {
+  if (const parser::AssignmentStmt *assignStmt{
+          parser::Unwrap<parser::AssignmentStmt>(*it)}) {
     if (parser::Unwrap<parser::FunctionReference>(assignStmt->t)) {
       passChecks = true;
     }
diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index 5e0d91914c441..9b9981306f15b 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -334,8 +334,8 @@
   !$omp single private(a) lastprivate(c) nowait
   a = 3.14
   !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 SINGLE directive
-  !ERROR: At most one NOWAIT clause can appear on the SINGLE directive
+  !WARNING: NOWAIT clause is already used on the SINGLE directive
+  !WARNING: NOWAIT clause is already used on the SINGLE directive
   !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive
   !$omp end single copyprivate(a) nowait nowait
   c = 2
diff --git a/flang/test/Semantics/OpenMP/single03.f90 b/flang/test/Semantics/OpenMP/single03.f90
index bc7647b66e39f..86b46546b971a 100644
--- a/flang/test/Semantics/OpenMP/single03.f90
+++ b/flang/test/Semantics/OpenMP/single03.f90
@@ -38,13 +38,13 @@ subroutine omp_single
         !ERROR: COPYPRIVATE variable 'j' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct
         !$omp single private(j) copyprivate(j)
             print *, "omp single", j
-        !ERROR: At most one COPYPRIVATE clause can appear on the SINGLE directive
         !ERROR: COPYPRIVATE variable 'j' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct
+        !WARNING: The COPYPRIVATE clause with 'j' is already used on the SINGLE directive
         !$omp end single copyprivate(j)
 
         !$omp single nowait
             print *, "omp single", j
-        !ERROR: At most one NOWAIT clause can appear on the SINGLE directive
+        !WARNING: NOWAIT clause is already used on the SINGLE directive
         !$omp end single nowait
     !$omp end parallel
 

>From 292203e6e290669ee2a10f108cde22c0b474250f Mon Sep 17 00:00:00 2001
From: Thirumalai-Shaktivel <thirumalaishaktivel at gmail.com>
Date: Fri, 28 Feb 2025 10:47:33 +0000
Subject: [PATCH 6/7] Add a test

---
 flang/test/Semantics/OpenMP/single04.f90 | 81 ++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 flang/test/Semantics/OpenMP/single04.f90

diff --git a/flang/test/Semantics/OpenMP/single04.f90 b/flang/test/Semantics/OpenMP/single04.f90
new file mode 100644
index 0000000000000..c223b8c83db20
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/single04.f90
@@ -0,0 +1,81 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=52
+!
+! OpenMP Version 5.2
+!
+! 2.10.2 single Construct
+! Valid and invalid testcases for copyprivate and nowait clause on the single directive
+
+program single
+    ! Valid testcases
+    !$omp single
+        print *, x
+    !$omp end single
+
+    !$omp single nowait
+        print *, x
+    !$omp end single
+
+    !$omp single copyprivate(x, y, z)
+        print *, x
+    !$omp end single
+
+    !$omp single
+        print *, x
+    !$omp end single copyprivate(x)
+
+    ! Invalid testcases
+    !$omp single
+        print *, x
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !$omp end single copyprivate(x) nowait
+
+    !ERROR: 'x' appears in more than one COPYPRIVATE clause on the SINGLE directive
+    !$omp single copyprivate(x) copyprivate(x)
+        print *, x
+    !$omp end single
+
+    !$omp single
+        print *, x
+    !ERROR: 'x' appears in more than one COPYPRIVATE clause on the END SINGLE directive
+    !$omp end single copyprivate(x) copyprivate(x)
+
+    !ERROR: At most one NOWAIT clause can appear on the SINGLE directive
+    !$omp single nowait nowait
+        print *, x
+    !$omp end single
+
+    !$omp single
+        print *, x
+    !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive
+    !$omp end single nowait nowait
+
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !$omp single copyprivate(x) nowait
+        print *, x
+    !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive
+    !WARNING: NOWAIT clause is already used on the SINGLE directive
+    !$omp end single copyprivate(x) nowait
+
+    !$omp single copyprivate(x)
+        print *, x
+    !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !$omp end single copyprivate(x) nowait
+
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !$omp single copyprivate(x, y) nowait
+        print *, x
+    !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive
+    !ERROR: 'z' appears in more than one COPYPRIVATE clause on the END SINGLE directive
+    !WARNING: NOWAIT clause is already used on the SINGLE directive
+    !$omp end single copyprivate(x, z) copyprivate(z) nowait
+
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !$omp single copyprivate(x) nowait copyprivate(y) copyprivate(z)
+        print *, x
+    !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive
+    !WARNING: The COPYPRIVATE clause with 'y' is already used on the SINGLE directive
+    !WARNING: The COPYPRIVATE clause with 'z' is already used on the SINGLE directive
+    !WARNING: NOWAIT clause is already used on the SINGLE directive
+    !$omp end single copyprivate(x, y, z) nowait
+end program

>From 5168d4e1f1045638ac49a03f72ec3348eca14bfc Mon Sep 17 00:00:00 2001
From: Thirumalai-Shaktivel <thirumalaishaktivel at gmail.com>
Date: Fri, 28 Feb 2025 11:46:05 +0000
Subject: [PATCH 7/7] Fix clang format

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

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 9d75d308b28f8..f4cd6dc47f6a9 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1856,8 +1856,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPDispatchConstruct &x) {
 
   auto it{block.begin()};
   bool passChecks{false};
-  if (const parser::AssignmentStmt *assignStmt{
-          parser::Unwrap<parser::AssignmentStmt>(*it)}) {
+  if (const parser::AssignmentStmt *
+      assignStmt{parser::Unwrap<parser::AssignmentStmt>(*it)}) {
     if (parser::Unwrap<parser::FunctionReference>(assignStmt->t)) {
       passChecks = true;
     }



More information about the flang-commits mailing list