[flang-commits] [flang] d9d2f32 - [flang][OpenMP] Refactor semantic check of SINGLE construct (#204339)

via flang-commits flang-commits at lists.llvm.org
Mon Jun 22 08:38:27 PDT 2026


Author: Krzysztof Parzyszek
Date: 2026-06-22T10:38:22-05:00
New Revision: d9d2f3221b9e499f183acb1d3bece3c1d8f1462a

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

LOG: [flang][OpenMP] Refactor semantic check of SINGLE construct (#204339)

Extract it into a separate function and simplify the code. Avoid making
the distinction between a clause appearing on the "begin" and the "end"
directives for the purposes of emitting diagnostic messages.

One change in behavior is that using the same list item multiple times
in COPYPRIVATE clause(s) is an error regardless of the placement of the
clauses. Previously in some cases it was treated as a warning.

Part of the motivation is the goal of eliminating explicit definitions
of end-directives for directives that are not delimited, e.g. "end
single", but not "end declare_variant".

Added: 
    

Modified: 
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h
    flang/test/Semantics/OpenMP/clause-validity01.f90
    flang/test/Semantics/OpenMP/single03.f90
    flang/test/Semantics/OpenMP/single04.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index b61662995ad57..e643ceb25ce34 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1283,63 +1283,7 @@ void OmpStructureChecker::Enter(const parser::OmpBlockConstruct &x) {
   }
 
   if (GetContext().directive == llvm::omp::Directive::OMPD_single) {
-    std::set<Symbol *> singleCopyprivateSyms;
-    std::set<Symbol *> endSingleCopyprivateSyms;
-    bool foundNowait{false};
-    parser::CharBlock NowaitSource;
-
-    auto catchCopyPrivateNowaitClauses = [&](const auto &dirSpec, bool isEnd) {
-      for (auto &clause : dirSpec.Clauses().v) {
-        if (clause.Id() == llvm::omp::Clause::OMPC_copyprivate) {
-          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 (isEnd) {
-                  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 (isEnd) {
-                  endSingleCopyprivateSyms.insert(symbol);
-                } else {
-                  singleCopyprivateSyms.insert(symbol);
-                }
-              }
-            }
-          }
-        } 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 = !isEnd;
-          }
-          if (!NowaitSource.ToString().size()) {
-            NowaitSource = clause.source;
-          }
-        }
-      }
-    };
-    catchCopyPrivateNowaitClauses(beginSpec, false);
-    if (endSpec) {
-      catchCopyPrivateNowaitClauses(*endSpec, true);
-    }
-    unsigned version{context_.langOptions().OpenMPVersion};
-    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);
-    }
+    CheckSingleConstruct(x);
   }
 
   switch (beginSpec.DirId()) {
@@ -1387,6 +1331,78 @@ void OmpStructureChecker::Enter(const parser::OmpBlockConstruct &x) {
   }
 }
 
+void OmpStructureChecker::CheckSingleConstruct(
+    const parser::OmpBlockConstruct &x) {
+  const parser::OmpDirectiveSpecification &beginSpec{x.BeginDir()};
+  unsigned version{context_.langOptions().OpenMPVersion};
+  SymbolSourceMap copyPrivateSyms;
+  parser::CharBlock nowaitSource1, nowaitSource2;
+
+  auto catchCopyPrivateNowaitClauses =
+      [&](const parser::OmpDirectiveSpecification &spec,
+          parser::CharBlock &nowaitSource) {
+        for (auto &clause : spec.Clauses().v) {
+          llvm::omp::Clause clauseId{clause.Id()};
+          if (clauseId == llvm::omp::Clause::OMPC_copyprivate) {
+            GetSymbolsInObjectList(*GetOmpObjectList(clause), copyPrivateSyms);
+          } else if (clauseId == llvm::omp::Clause::OMPC_nowait) {
+            if (nowaitSource.empty()) {
+              nowaitSource = clause.source;
+            }
+          }
+        }
+      };
+
+  catchCopyPrivateNowaitClauses(beginSpec, nowaitSource1);
+  if (auto &endSpec{x.EndDir()}) {
+    catchCopyPrivateNowaitClauses(*endSpec, nowaitSource2);
+  }
+
+  std::string nowaitName{//
+      GetUpperName(llvm::omp::Clause::OMPC_nowait, version)};
+  std::string copyPrivateName{
+      GetUpperName(llvm::omp::Clause::OMPC_copyprivate, version)};
+  std::string singleName{
+      GetUpperName(llvm::omp::Directive::OMPD_single, version)};
+
+  std::pair<const Symbol *, parser::CharBlock> last{nullptr, {}};
+  bool reported{false};
+
+  for (auto [symbol, source] : copyPrivateSyms) {
+    if (symbol == last.first) {
+      if (!reported) {
+        context_
+            .Say(source, "'%s' appears more than once in a %s clause"_err_en_US,
+                symbol->name().ToString(), copyPrivateName)
+            .Attach(last.second, "Previous occurrence of '%s'"_en_US,
+                symbol->name().ToString());
+        reported = true;
+      }
+    } else {
+      reported = false;
+    }
+    last = std::make_pair(symbol, source);
+  }
+
+  if (!nowaitSource1.empty() && !nowaitSource2.empty()) {
+    context_
+        .Say(nowaitSource2,
+            // Match the message text with the one emitted by "CheckAllowed".
+            "At most one %s clause can appear on the %s directive"_err_en_US,
+            nowaitName, singleName)
+        .Attach(nowaitSource1, "Previous occurrence of %s"_en_US, nowaitName);
+  }
+
+  if (version <= 52 && !copyPrivateSyms.empty() &&
+      (!nowaitSource1.empty() || !nowaitSource2.empty())) {
+    parser::CharBlock source{
+        !nowaitSource1.empty() ? nowaitSource1 : nowaitSource2};
+    context_.Say(source,
+        "%s clause must not be used with %s clause on %s directive"_err_en_US,
+        nowaitName, copyPrivateName, singleName);
+  }
+}
+
 void OmpStructureChecker::CheckMasterNesting(
     const parser::OmpBlockConstruct &x) {
   // A MASTER region may not be `closely nested` inside a worksharing, loop,

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 1154fce5e00a7..1283feb32ef5f 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -345,6 +345,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
       const parser::OmpReductionIdentifier &ident);
   void CheckReductionModifier(const parser::OmpReductionModifier &);
   void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
+  void CheckSingleConstruct(const parser::OmpBlockConstruct &x);
   void CheckMasterNesting(const parser::OmpBlockConstruct &x);
   void ChecksOnOrderedAsBlock();
   void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);

diff  --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index bd8b9f343de77..ec89afd53ab0d 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -330,12 +330,11 @@
   !$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
+  !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on SINGLE directive
   !$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
   !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 e64155c845c86..64fedc414829b 100644
--- a/flang/test/Semantics/OpenMP/single03.f90
+++ b/flang/test/Semantics/OpenMP/single03.f90
@@ -1,17 +1,12 @@
 ! 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
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on SINGLE directive
     !$omp single copyprivate(i) nowait
         print *, "omp single", i
     !$omp end single
@@ -23,7 +18,7 @@ subroutine omp_single
     !$omp end parallel
 
     !$omp parallel
-        !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+        !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on SINGLE directive
         !$omp single nowait
             print *, "omp single", i
         !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context
@@ -32,14 +27,14 @@ subroutine omp_single
         !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
+        !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on 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: 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 [-Wopenmp-usage]
+        !ERROR: 'j' appears more than once in a COPYPRIVATE clause
         !$omp end single copyprivate(j)
 
         !$omp single nowait

diff  --git a/flang/test/Semantics/OpenMP/single04.f90 b/flang/test/Semantics/OpenMP/single04.f90
index 7daa74ab62218..58d6e6f0582cb 100644
--- a/flang/test/Semantics/OpenMP/single04.f90
+++ b/flang/test/Semantics/OpenMP/single04.f90
@@ -1,10 +1,5 @@
 ! 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
@@ -26,17 +21,17 @@ program single
     ! Invalid testcases
     !$omp single
         print *, x
-    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on SINGLE directive
     !$omp end single copyprivate(x) nowait
 
-    !ERROR: 'x' appears in more than one COPYPRIVATE clause on the SINGLE directive
+    !ERROR: 'x' appears more than once in a COPYPRIVATE clause
     !$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
+    !ERROR: 'x' appears more than once in a COPYPRIVATE clause
     !$omp end single copyprivate(x) copyprivate(x)
 
     !ERROR: At most one NOWAIT clause can appear on the SINGLE directive
@@ -49,33 +44,33 @@ program single
     !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
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on SINGLE directive
     !$omp single copyprivate(x) nowait
         print *, x
-    !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive [-Wopenmp-usage]
+    !ERROR: 'x' appears more than once in a COPYPRIVATE clause
     !ERROR: At most one NOWAIT clause can appear 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 [-Wopenmp-usage]
-    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !ERROR: 'x' appears more than once in a COPYPRIVATE clause
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on SINGLE directive
     !$omp end single copyprivate(x) nowait
 
-    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on SINGLE directive
     !$omp single copyprivate(x, y) nowait
         print *, x
-    !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive [-Wopenmp-usage]
-    !ERROR: 'z' appears in more than one COPYPRIVATE clause on the END SINGLE directive
+    !ERROR: 'x' appears more than once in a COPYPRIVATE clause
+    !ERROR: 'z' appears more than once in a COPYPRIVATE clause
     !ERROR: At most one NOWAIT clause can appear 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
+    !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on 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 [-Wopenmp-usage]
-    !WARNING: The COPYPRIVATE clause with 'y' is already used on the SINGLE directive [-Wopenmp-usage]
-    !WARNING: The COPYPRIVATE clause with 'z' is already used on the SINGLE directive [-Wopenmp-usage]
+    !ERROR: 'x' appears more than once in a COPYPRIVATE clause
+    !ERROR: 'y' appears more than once in a COPYPRIVATE clause
+    !ERROR: 'z' appears more than once in a COPYPRIVATE clause
     !ERROR: At most one NOWAIT clause can appear on the SINGLE directive
     !$omp end single copyprivate(x, y, z) nowait
 end program


        


More information about the flang-commits mailing list