Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -231,6 +231,7 @@ const parser::CharBlock &source, const parser::OmpCancelType::Type &type); std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv); + void CheckAllowedOnceClause(const llvm::omp::Clause); bool CheckReductionOperators(const parser::OmpClause::Reduction &); bool CheckIntrinsicOperator( const parser::DefinedOperator::IntrinsicOperator &); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -759,6 +759,22 @@ } } +void OmpStructureChecker::CheckAllowedOnceClause( + const llvm::omp::Clause clause) { + auto clauseAll = FindClauses(clause); + unsigned clauseCnt = 0; + for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) { + clauseCnt++; + if (clauseCnt > 1) { + context_.Say(itr->second->source, + "At most one %s clause can appear on the %s directive"_err_en_US, + parser::ToUpperCaseLetters(getClauseName(clause).str()), + ContextDirectiveAsFortran()); + break; + } + } +} + void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) { if (GetDirectiveNest(TargetBlockOnlyTeams)) { ExitDirectiveNest(TargetBlockOnlyTeams); @@ -1238,6 +1254,30 @@ llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait}); } + // 2.19.9 Ordered Construct Restriction + if (GetContext().directive == llvm::omp::Directive::OMPD_ordered) { + // At most one threads clause can appear on an ordered construct. + CheckAllowedOnceClause(llvm::omp::Clause::OMPC_threads); + // At most one simd clause can appear on an ordered construct. + CheckAllowedOnceClause(llvm::omp::Clause::OMPC_simd); + // At most one depend(source) clause can appear on an ordered construct. + auto clauseAll = FindClauses(llvm::omp::Clause::OMPC_depend); + unsigned dependSourceCnt = 0; + for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) { + const auto &dependClause{ + std::get(itr->second->u)}; + if (std::get_if(&dependClause.v.u)) { + dependSourceCnt++; + if (dependSourceCnt > 1) { + context_.Say(itr->second->source, + "At most one DEPEND(SOURCE) clause can appear on the ORDERED " + "directive"_err_en_US); + break; + } + } + } + } + CheckRequireAtLeastOneOf(); } Index: flang/test/Semantics/omp-ordered01.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-ordered01.f90 @@ -0,0 +1,49 @@ +! RUN: %S/test_errors.sh %s %t %flang_fc1 -fopenmp +! REQUIRES: shell + +! OpenMP Version 5.1 +! Check OpenMP construct validity for the following directives: +! 2.19.9 Ordered Construct + +program main + integer :: i, N = 10 + real :: a, arrayA(10), arrayB(10) + real, external :: foo, bar + + !$omp do ordered + do i = 1, N + !ERROR: At most one THREADS clause can appear on the ORDERED directive + !$omp ordered threads threads + arrayA(i) = i + !$omp end ordered + end do + !$omp end do + + !$omp simd + do i = 1, N + !ERROR: At most one SIMD clause can appear on the ORDERED directive + !$omp ordered simd simd + arrayA(i) = i + !$omp end ordered + end do + !$omp end simd + + !$omp do simd ordered + do i = 1, N + !ERROR: At most one SIMD clause can appear on the ORDERED directive + !$omp ordered simd simd + arrayA(i) = i + !$omp end ordered + end do + !$omp end do simd + + !$omp do ordered(1) + do i = 1, N + arrayA(i) = foo(i) + !ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive + !$omp ordered depend(source) depend(source) + arrayB(i) = bar(arrayA(i)) + end do + !$omp end do + +end program main