Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -93,6 +93,12 @@ llvm::omp::Directive::OMPD_master}); PushContextAndClauseSets(beginDir.source, llvm::omp::Directive::OMPD_do); } + + if (const auto &doConstruct{ + std::get>(x.t)}) { + const auto &doBlock{std::get(doConstruct->t)}; + CheckNoBranching(doBlock, beginDir.v, beginDir.source); + } } void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) { @@ -125,14 +131,7 @@ CheckMatching(beginDir, endDir); PushContextAndClauseSets(beginDir.source, beginDir.v); - - switch (beginDir.v) { - case llvm::omp::OMPD_parallel: - CheckNoBranching(block, llvm::omp::OMPD_parallel, beginDir.source); - break; - default: - break; - } + CheckNoBranching(block, beginDir.v, beginDir.source); } void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) { @@ -149,6 +148,11 @@ CheckMatching(beginDir, endDir); PushContextAndClauseSets(beginDir.source, beginDir.v); + + const auto §ionBlocks{std::get(x.t)}; + for (const auto &block : sectionBlocks.v) { + CheckNoBranching(block, beginDir.v, beginDir.source); + } } void OmpStructureChecker::Leave(const parser::OpenMPSectionsConstruct &) { @@ -252,6 +256,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) { const auto &dir{std::get(x.t)}; PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_critical); + + const auto &block{std::get(x.t)}; + CheckNoBranching(block, llvm::omp::Directive::OMPD_critical, dir.source); } void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) { Index: flang/lib/Semantics/resolve-directives.cpp =================================================================== --- flang/lib/Semantics/resolve-directives.cpp +++ flang/lib/Semantics/resolve-directives.cpp @@ -225,6 +225,54 @@ template bool Pre(const A &) { return true; } template void Post(const A &) {} + template bool Pre(const parser::Statement &statement) { + currentStatementSource_ = statement.source; + if (statement.label) { + auto label{statement.label.value()}; + DirContext *thisContext{nullptr}; + if (!dirContext_.empty()) { + thisContext = &GetContext(); + } + targetLabels_.emplace(label, thisContext); + auto range{gotoLabels_.equal_range(label)}; + for (auto it{range.first}; it != range.second; ++it) { + CheckGotoContext(it->second.first, it->second.second, thisContext); + } + } + return true; + } + + bool Pre(const parser::GotoStmt &stmt) { + auto label{stmt.v}; + DirContext *thisContext{nullptr}; + if (!dirContext_.empty()) { + thisContext = &GetContext(); + } + gotoLabels_.emplace( + label, std::make_pair(currentStatementSource_, thisContext)); + auto it{targetLabels_.find(label)}; + if (it != targetLabels_.end()) { + CheckGotoContext(currentStatementSource_, thisContext, it->second); + } + return true; + } + + bool Pre(const parser::ComputedGotoStmt &stmt) { + DirContext *thisContext{nullptr}; + if (!dirContext_.empty()) { + thisContext = &GetContext(); + } + for (const auto &label : std::get>(stmt.t)) { + gotoLabels_.emplace( + label, std::make_pair(currentStatementSource_, thisContext)); + auto it{targetLabels_.find(label)}; + if (it != targetLabels_.end()) { + CheckGotoContext(currentStatementSource_, thisContext, it->second); + } + } + return true; + } + bool Pre(const parser::SpecificationPart &x) { Walk(std::get>(x.t)); return true; @@ -340,6 +388,10 @@ std::vector allocateNames_; // on one directive SymbolSet privateDataSharingAttributeObjects_; // on one directive + std::map targetLabels_; + std::multimap> + gotoLabels_; + parser::CharBlock currentStatementSource_; void AddAllocateName(const parser::Name *&object) { allocateNames_.push_back(object); @@ -377,6 +429,7 @@ void CheckAssocLoopLevel(std::int64_t level, const parser::OmpClause *clause); void CheckObjectInNamelist( const parser::Name &, const Symbol &, Symbol::Flag); + void CheckGotoContext(const parser::CharBlock, DirContext *, DirContext *); }; template @@ -1278,4 +1331,15 @@ } } +void OmpAttributeVisitor::CheckGotoContext(const parser::CharBlock source, + DirContext *gotoContext, DirContext *labelContext) { + if (labelContext && !gotoContext) { + context_.Say(source, "invalid entry to OpenMP structured block"_err_en_US); + } else if (gotoContext && + (!labelContext || gotoContext->scope != labelContext->scope)) { + context_.Say( + source, "invalid branch to/from OpenMP structured block"_err_en_US); + } +} + } // namespace Fortran::semantics Index: flang/test/Semantics/omp-clause-validity01.f90 =================================================================== --- flang/test/Semantics/omp-clause-validity01.f90 +++ flang/test/Semantics/omp-clause-validity01.f90 @@ -172,6 +172,7 @@ exit exit outer !ERROR: EXIT to construct 'outofparallel' outside of PARALLEL construct is not allowed + !ERROR: EXIT to construct 'outofparallel' outside of DO construct is not allowed exit outofparallel end do inner end do outer Index: flang/test/Semantics/omp-do07.f90 =================================================================== --- flang/test/Semantics/omp-do07.f90 +++ flang/test/Semantics/omp-do07.f90 @@ -1,5 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL:* ! OpenMP Version 4.5 ! 2.7.1 Loop Construct Index: flang/test/Semantics/omp-parallel01.f90 =================================================================== --- flang/test/Semantics/omp-parallel01.f90 +++ flang/test/Semantics/omp-parallel01.f90 @@ -1,5 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * ! OpenMP Version 4.5 ! 2.5 parallel construct. Index: flang/test/Semantics/omp-parallel02.f90 =================================================================== --- flang/test/Semantics/omp-parallel02.f90 +++ flang/test/Semantics/omp-parallel02.f90 @@ -1,5 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * ! OpenMP Version 4.5 ! 2.5 parallel construct. @@ -16,6 +15,7 @@ do i = 1, 10 do j = 1, 10 print *, "Hello" + !ERROR: STOP statement is not allowed in a PARALLEL construct 10 stop end do end do Index: flang/test/Semantics/omp-simd01.f90 =================================================================== --- flang/test/Semantics/omp-simd01.f90 +++ flang/test/Semantics/omp-simd01.f90 @@ -1,5 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * ! OpenMP Version 4.5 ! 2.8.1 simd Construct Index: flang/test/Semantics/omp-task01.f90 =================================================================== --- flang/test/Semantics/omp-task01.f90 +++ flang/test/Semantics/omp-task01.f90 @@ -1,5 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * ! OpenMP Version 4.5 ! 2.9.1 task Construct @@ -18,6 +17,7 @@ if (associated(P%left)) then !$omp task call traverse(P%left) + !ERROR: STOP statement is not allowed in a TASK construct 10 stop !$omp end task endif Index: flang/test/Semantics/omp-taskloop02.f90 =================================================================== --- flang/test/Semantics/omp-taskloop02.f90 +++ flang/test/Semantics/omp-taskloop02.f90 @@ -1,5 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * ! OpenMP Version 4.5 ! 2.9.2 taskloop Construct