[flang-commits] [flang] [flang][OpenMP] Refactor semantic check of SINGLE construct (PR #204339)
via flang-commits
flang-commits at lists.llvm.org
Wed Jun 17 04:36:13 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: Krzysztof Parzyszek (kparzysz)
<details>
<summary>Changes</summary>
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".
---
Full diff: https://github.com/llvm/llvm-project/pull/204339.diff
5 Files Affected:
- (modified) flang/lib/Semantics/check-omp-structure.cpp (+73-57)
- (modified) flang/lib/Semantics/check-omp-structure.h (+1)
- (modified) flang/test/Semantics/OpenMP/clause-validity01.f90 (-2)
- (modified) flang/test/Semantics/OpenMP/single03.f90 (+5-10)
- (modified) flang/test/Semantics/OpenMP/single04.f90 (+15-20)
``````````diff
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 7c531ae0046ae..69b8212f4cb96 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1282,63 +1282,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()) {
@@ -1386,6 +1330,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 9fca5ff0f5fca..4842bc10fa7a8 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -372,6 +372,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..faaf4df9b4074 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -330,12 +330,10 @@
!$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: 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..03462c510a1ff 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
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=51
!
-! 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..045fc0b884719 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
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=51
!
-! 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
``````````
</details>
https://github.com/llvm/llvm-project/pull/204339
More information about the flang-commits
mailing list