Skip to content

[flang][OpenMP][Semantics] Disallow NOWAIT and ORDERED with CANCEL #135991

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions flang/lib/Semantics/check-directive-structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -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};
};
Expand Down
46 changes: 45 additions & 1 deletion flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -682,21 +683,31 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeConstruct &x) {
ExitDirectiveNest(DeclarativeNest);
}

void OmpStructureChecker::AddEndDirectiveClauses(
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)}) {
const auto &endDir{
std::get<parser::OmpLoopDirective>(endLoopDir.value().t)};

CheckMatching<parser::OmpLoopDirective>(beginDir, endDir);

AddEndDirectiveClauses(std::get<parser::OmpClauseList>(endLoopDir->t));
}

PushContextAndClauseSets(beginDir.source, beginDir.v);
if (llvm::omp::allSimdSet.test(GetContext().directive)) {
EnterDirectiveNest(SIMDNest);
}
Expand Down Expand Up @@ -1429,6 +1440,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
CheckMatching<parser::OmpSectionsDirective>(beginDir, endDir);

PushContextAndClauseSets(beginDir.source, beginDir.v);
AddEndDirectiveClauses(std::get<parser::OmpClauseList>(endSectionsDir.t));

const auto &sectionBlocks{std::get<parser::OmpSectionBlocks>(x.t)};
for (const parser::OpenMPConstruct &block : sectionBlocks.v) {
CheckNoBranching(std::get<parser::OpenMPSectionConstruct>(block.u).v,
Expand Down Expand Up @@ -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);
}
}
}
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Semantics/check-omp-structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ class OmpStructureChecker

void CheckAlignValue(const parser::OmpClause &);

void AddEndDirectiveClauses(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]; }
Expand Down
51 changes: 51 additions & 0 deletions flang/test/Semantics/OpenMP/cancel.f90
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading