|
15 | 15 | #include "flang/Semantics/expression.h"
|
16 | 16 | #include "flang/Semantics/openmp-modifiers.h"
|
17 | 17 | #include "flang/Semantics/tools.h"
|
| 18 | +#include "llvm/ADT/STLExtras.h" |
18 | 19 | #include <variant>
|
19 | 20 |
|
20 | 21 | namespace Fortran::semantics {
|
@@ -682,21 +683,31 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeConstruct &x) {
|
682 | 683 | ExitDirectiveNest(DeclarativeNest);
|
683 | 684 | }
|
684 | 685 |
|
| 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 | + |
685 | 693 | void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
|
686 | 694 | loopStack_.push_back(&x);
|
687 | 695 | const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
|
688 | 696 | const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
|
689 | 697 |
|
| 698 | + PushContextAndClauseSets(beginDir.source, beginDir.v); |
| 699 | + |
690 | 700 | // check matching, End directive is optional
|
691 | 701 | if (const auto &endLoopDir{
|
692 | 702 | std::get<std::optional<parser::OmpEndLoopDirective>>(x.t)}) {
|
693 | 703 | const auto &endDir{
|
694 | 704 | std::get<parser::OmpLoopDirective>(endLoopDir.value().t)};
|
695 | 705 |
|
696 | 706 | CheckMatching<parser::OmpLoopDirective>(beginDir, endDir);
|
| 707 | + |
| 708 | + AddEndDirectiveClauses(std::get<parser::OmpClauseList>(endLoopDir->t)); |
697 | 709 | }
|
698 | 710 |
|
699 |
| - PushContextAndClauseSets(beginDir.source, beginDir.v); |
700 | 711 | if (llvm::omp::allSimdSet.test(GetContext().directive)) {
|
701 | 712 | EnterDirectiveNest(SIMDNest);
|
702 | 713 | }
|
@@ -1429,6 +1440,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
|
1429 | 1440 | CheckMatching<parser::OmpSectionsDirective>(beginDir, endDir);
|
1430 | 1441 |
|
1431 | 1442 | PushContextAndClauseSets(beginDir.source, beginDir.v);
|
| 1443 | + AddEndDirectiveClauses(std::get<parser::OmpClauseList>(endSectionsDir.t)); |
| 1444 | + |
1432 | 1445 | const auto §ionBlocks{std::get<parser::OmpSectionBlocks>(x.t)};
|
1433 | 1446 | for (const parser::OpenMPConstruct &block : sectionBlocks.v) {
|
1434 | 1447 | CheckNoBranching(std::get<parser::OpenMPSectionConstruct>(block.u).v,
|
@@ -2288,6 +2301,37 @@ void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
|
2288 | 2301 | if (auto maybeConstruct{GetCancelType(
|
2289 | 2302 | llvm::omp::Directive::OMPD_cancel, x.source, maybeClauses)}) {
|
2290 | 2303 | 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 | + } |
2291 | 2335 | }
|
2292 | 2336 | }
|
2293 | 2337 |
|
|
0 commit comments