Skip to content

Commit c5e112e

Browse files
authored
[flang][OpenMP][Semantics] Disallow NOWAIT and ORDERED with CANCEL (#135991)
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.
1 parent 121cd7c commit c5e112e

File tree

4 files changed

+99
-1
lines changed

4 files changed

+99
-1
lines changed

flang/lib/Semantics/check-directive-structure.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ class DirectiveStructureChecker : public virtual BaseChecker {
202202
const PC *clause{nullptr};
203203
ClauseMapTy clauseInfo;
204204
std::list<C> actualClauses;
205+
std::list<C> endDirectiveClauses;
205206
std::list<C> crtGroup;
206207
Symbol *loopIV{nullptr};
207208
};

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "flang/Semantics/expression.h"
1616
#include "flang/Semantics/openmp-modifiers.h"
1717
#include "flang/Semantics/tools.h"
18+
#include "llvm/ADT/STLExtras.h"
1819
#include <variant>
1920

2021
namespace Fortran::semantics {
@@ -682,21 +683,31 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeConstruct &x) {
682683
ExitDirectiveNest(DeclarativeNest);
683684
}
684685

686+
void OmpStructureChecker::AddEndDirectiveClauses(
687+
const parser::OmpClauseList &clauses) {
688+
for (const parser::OmpClause &clause : clauses.v) {
689+
GetContext().endDirectiveClauses.push_back(clause.Id());
690+
}
691+
}
692+
685693
void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
686694
loopStack_.push_back(&x);
687695
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
688696
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
689697

698+
PushContextAndClauseSets(beginDir.source, beginDir.v);
699+
690700
// check matching, End directive is optional
691701
if (const auto &endLoopDir{
692702
std::get<std::optional<parser::OmpEndLoopDirective>>(x.t)}) {
693703
const auto &endDir{
694704
std::get<parser::OmpLoopDirective>(endLoopDir.value().t)};
695705

696706
CheckMatching<parser::OmpLoopDirective>(beginDir, endDir);
707+
708+
AddEndDirectiveClauses(std::get<parser::OmpClauseList>(endLoopDir->t));
697709
}
698710

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

14311442
PushContextAndClauseSets(beginDir.source, beginDir.v);
1443+
AddEndDirectiveClauses(std::get<parser::OmpClauseList>(endSectionsDir.t));
1444+
14321445
const auto &sectionBlocks{std::get<parser::OmpSectionBlocks>(x.t)};
14331446
for (const parser::OpenMPConstruct &block : sectionBlocks.v) {
14341447
CheckNoBranching(std::get<parser::OpenMPSectionConstruct>(block.u).v,
@@ -2288,6 +2301,37 @@ void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
22882301
if (auto maybeConstruct{GetCancelType(
22892302
llvm::omp::Directive::OMPD_cancel, x.source, maybeClauses)}) {
22902303
CheckCancellationNest(dirName.source, *maybeConstruct);
2304+
2305+
if (CurrentDirectiveIsNested()) {
2306+
// nowait can be put on the end directive rather than the start directive
2307+
// so we need to check both
2308+
auto getParentClauses{[&]() {
2309+
const DirectiveContext &parent{GetContextParent()};
2310+
return llvm::concat<const llvm::omp::Clause>(
2311+
parent.actualClauses, parent.endDirectiveClauses);
2312+
}};
2313+
2314+
if (llvm::omp::nestedCancelDoAllowedSet.test(*maybeConstruct)) {
2315+
for (llvm::omp::Clause clause : getParentClauses()) {
2316+
if (clause == llvm::omp::Clause::OMPC_nowait) {
2317+
context_.Say(dirName.source,
2318+
"The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause"_err_en_US);
2319+
}
2320+
if (clause == llvm::omp::Clause::OMPC_ordered) {
2321+
context_.Say(dirName.source,
2322+
"The CANCEL construct cannot be nested inside of a worksharing construct with the ORDERED clause"_err_en_US);
2323+
}
2324+
}
2325+
} else if (llvm::omp::nestedCancelSectionsAllowedSet.test(
2326+
*maybeConstruct)) {
2327+
for (llvm::omp::Clause clause : getParentClauses()) {
2328+
if (clause == llvm::omp::Clause::OMPC_nowait) {
2329+
context_.Say(dirName.source,
2330+
"The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause"_err_en_US);
2331+
}
2332+
}
2333+
}
2334+
}
22912335
}
22922336
}
22932337

flang/lib/Semantics/check-omp-structure.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ class OmpStructureChecker
318318

319319
void CheckAlignValue(const parser::OmpClause &);
320320

321+
void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
322+
321323
void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
322324
void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
323325
int GetDirectiveNest(const int index) { return directiveNest_[index]; }

flang/test/Semantics/OpenMP/cancel.f90

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,54 @@ subroutine f03
2727
!$omp cancellation point parallel parallel
2828
!$omp end parallel
2929
end
30+
31+
subroutine do_nowait1
32+
!$omp parallel
33+
!$omp do nowait
34+
do i=1,2
35+
!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause
36+
!$omp cancel do
37+
enddo
38+
!$omp end do
39+
!$omp end parallel
40+
end subroutine
41+
42+
subroutine do_nowait2
43+
!$omp parallel
44+
!$omp do
45+
do i=1,2
46+
!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause
47+
!$omp cancel do
48+
enddo
49+
!$omp end do nowait
50+
!$omp end parallel
51+
end subroutine
52+
53+
subroutine do_ordered
54+
!$omp parallel do ordered
55+
do i=1,2
56+
!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the ORDERED clause
57+
!$omp cancel do
58+
enddo
59+
!$omp end parallel do
60+
end subroutine
61+
62+
subroutine sections_nowait1
63+
!$omp parallel
64+
!$omp sections nowait
65+
!$omp section
66+
!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause
67+
!$omp cancel sections
68+
!$omp end sections
69+
!$omp end parallel
70+
end subroutine
71+
72+
subroutine sections_nowait2
73+
!$omp parallel
74+
!$omp sections
75+
!$omp section
76+
!ERROR: The CANCEL construct cannot be nested inside of a worksharing construct with the NOWAIT clause
77+
!$omp cancel sections
78+
!$omp end sections nowait
79+
!$omp end parallel
80+
end subroutine

0 commit comments

Comments
 (0)