[flang-commits] [flang] [flang][OpenMP][Semantics] Disallow NOWAIT and ORDERED with CANCEL (PR #135991)
via flang-commits
flang-commits at lists.llvm.org
Wed Apr 16 10:09:32 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: Tom Eccles (tblah)
<details>
<summary>Changes</summary>
NOWAIT was a tricky one because the clause can be on either the start or the end directive. I couldn't find a convenient way to access the end directive from the CANCEL directive nested inside of the construct, but there are convenient ways to access the start directive. I have added a list to the start directive context containing the clauses from the end directive.
---
Full diff: https://github.com/llvm/llvm-project/pull/135991.diff
4 Files Affected:
- (modified) flang/lib/Semantics/check-directive-structure.h (+1)
- (modified) flang/lib/Semantics/check-omp-structure.cpp (+45-1)
- (modified) flang/lib/Semantics/check-omp-structure.h (+2)
- (modified) flang/test/Semantics/OpenMP/cancel.f90 (+51)
``````````diff
diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 91ffda6404c23..4a4893fe805a2 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -202,6 +202,7 @@ class DirectiveStructureChecker : public virtual BaseChecker {
const PC *clause{nullptr};
ClauseMapTy clauseInfo;
std::list<C> actualClauses;
+ std::list<C> endDirectiveClauses;
std::list<C> crtGroup;
Symbol *loopIV{nullptr};
};
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 717982f66027c..7b26e20620269 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -15,6 +15,7 @@
#include "flang/Semantics/expression.h"
#include "flang/Semantics/openmp-modifiers.h"
#include "flang/Semantics/tools.h"
+#include "llvm/ADT/STLExtras.h"
#include <variant>
namespace Fortran::semantics {
@@ -682,11 +683,20 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeConstruct &x) {
ExitDirectiveNest(DeclarativeNest);
}
+void OmpStructureChecker::AddEndStatementClauses(
+ const parser::OmpClauseList &clauses) {
+ for (const parser::OmpClause &clause : clauses.v) {
+ GetContext().endDirectiveClauses.push_back(clause.Id());
+ }
+}
+
void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
loopStack_.push_back(&x);
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
+ PushContextAndClauseSets(beginDir.source, beginDir.v);
+
// check matching, End directive is optional
if (const auto &endLoopDir{
std::get<std::optional<parser::OmpEndLoopDirective>>(x.t)}) {
@@ -694,9 +704,10 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
std::get<parser::OmpLoopDirective>(endLoopDir.value().t)};
CheckMatching<parser::OmpLoopDirective>(beginDir, endDir);
+
+ AddEndStatementClauses(std::get<parser::OmpClauseList>(endLoopDir->t));
}
- PushContextAndClauseSets(beginDir.source, beginDir.v);
if (llvm::omp::allSimdSet.test(GetContext().directive)) {
EnterDirectiveNest(SIMDNest);
}
@@ -1429,6 +1440,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
CheckMatching<parser::OmpSectionsDirective>(beginDir, endDir);
PushContextAndClauseSets(beginDir.source, beginDir.v);
+ AddEndStatementClauses(std::get<parser::OmpClauseList>(endSectionsDir.t));
+
const auto §ionBlocks{std::get<parser::OmpSectionBlocks>(x.t)};
for (const parser::OpenMPConstruct &block : sectionBlocks.v) {
CheckNoBranching(std::get<parser::OpenMPSectionConstruct>(block.u).v,
@@ -2288,6 +2301,37 @@ void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
if (auto maybeConstruct{GetCancelType(
llvm::omp::Directive::OMPD_cancel, x.source, maybeClauses)}) {
CheckCancellationNest(dirName.source, *maybeConstruct);
+
+ if (CurrentDirectiveIsNested()) {
+ // nowait can be put on the end directive rather than the start directive
+ // so we need to check both
+ auto getParentClauses{[&]() {
+ const DirectiveContext &parent{GetContextParent()};
+ return llvm::concat<const llvm::omp::Clause>(
+ parent.actualClauses, parent.endDirectiveClauses);
+ }};
+
+ if (llvm::omp::nestedCancelDoAllowedSet.test(*maybeConstruct)) {
+ for (llvm::omp::Clause clause : getParentClauses()) {
+ if (clause == llvm::omp::Clause::OMPC_nowait) {
+ context_.Say(dirName.source,
+ "The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause"_err_en_US);
+ }
+ if (clause == llvm::omp::Clause::OMPC_ordered) {
+ context_.Say(dirName.source,
+ "The CANCEL construct cannot be nested inside of a worksharing construct with the ORDERED clause"_err_en_US);
+ }
+ }
+ } else if (llvm::omp::nestedCancelSectionsAllowedSet.test(
+ *maybeConstruct)) {
+ for (llvm::omp::Clause clause : getParentClauses()) {
+ if (clause == llvm::omp::Clause::OMPC_nowait) {
+ context_.Say(dirName.source,
+ "The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause"_err_en_US);
+ }
+ }
+ }
+ }
}
}
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index a8869561cf5ea..dd9d3ee306b84 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -318,6 +318,8 @@ class OmpStructureChecker
void CheckAlignValue(const parser::OmpClause &);
+ void AddEndStatementClauses(const parser::OmpClauseList &clauses);
+
void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
int GetDirectiveNest(const int index) { return directiveNest_[index]; }
diff --git a/flang/test/Semantics/OpenMP/cancel.f90 b/flang/test/Semantics/OpenMP/cancel.f90
index 581c4bdb97646..6f3a255312ccf 100644
--- a/flang/test/Semantics/OpenMP/cancel.f90
+++ b/flang/test/Semantics/OpenMP/cancel.f90
@@ -27,3 +27,54 @@ subroutine f03
!$omp cancellation point parallel parallel
!$omp end parallel
end
+
+subroutine do_nowait1
+!$omp parallel
+!$omp do nowait
+ do i=1,2
+!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause
+ !$omp cancel do
+ enddo
+!$omp end do
+!$omp end parallel
+end subroutine
+
+subroutine do_nowait2
+!$omp parallel
+!$omp do
+ do i=1,2
+!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause
+ !$omp cancel do
+ enddo
+!$omp end do nowait
+!$omp end parallel
+end subroutine
+
+subroutine do_ordered
+!$omp parallel do ordered
+ do i=1,2
+!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the ORDERED clause
+ !$omp cancel do
+ enddo
+!$omp end parallel do
+end subroutine
+
+subroutine sections_nowait1
+!$omp parallel
+!$omp sections nowait
+ !$omp section
+!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause
+ !$omp cancel sections
+!$omp end sections
+!$omp end parallel
+end subroutine
+
+subroutine sections_nowait2
+!$omp parallel
+!$omp sections
+ !$omp section
+!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause
+ !$omp cancel sections
+!$omp end sections nowait
+!$omp end parallel
+end subroutine
``````````
</details>
https://github.com/llvm/llvm-project/pull/135991
More information about the flang-commits
mailing list