Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -195,6 +195,7 @@ const parser::OmpObjectList &, const llvm::omp::Clause); void GetSymbolsInObjectList( const parser::OmpObjectList &, std::vector &); + void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); }; } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -130,6 +130,9 @@ case llvm::omp::OMPD_parallel: CheckNoBranching(block, llvm::omp::OMPD_parallel, beginDir.source); break; + case llvm::omp::OMPD_workshare: + CheckWorkshareBlockStmts(block, beginDir.source); + break; default: break; } @@ -747,4 +750,60 @@ } } +void OmpStructureChecker::CheckWorkshareBlockStmts( + const parser::Block &block, parser::CharBlock source) { + for (auto it{block.begin()}; it != block.end(); ++it) { + if (const auto *assignment{parser::Unwrap(*it)}) { + const auto &var{std::get(assignment->t)}; + const auto &expr{std::get(assignment->t)}; + if (const auto *e{GetExpr(expr)}) { + for (const Symbol &symbol : evaluate::CollectSymbols(*e)) { + if (const Symbol * root{GetAssociationRoot(symbol)}) { + if (IsFunction(*root) && + !(root->attrs().test(Attr::ELEMENTAL) || + root->attrs().test(Attr::INTRINSIC))) { + context_.Say(expr.source, + "User defined non-ELEMENTAL function " + "'%s' is not allowed in a WORKSHARE construct"_err_en_US, + root->name()); + } + } + } + } + + const auto *rhs{GetExpr(expr)}; + const auto *lhs{GetExpr(var)}; + Tristate isDefined{semantics::IsDefinedAssignment( + lhs->GetType(), lhs->Rank(), rhs->GetType(), rhs->Rank())}; + if (isDefined == Tristate::Yes) { + context_.Say(expr.source, + "Defined assignment statement is not " + "allowed in a WORKSHARE construct"_err_en_US); + } + } else if (const auto *ompBlock{ + parser::Unwrap(*it)}) { + const auto &beginBlockDir{ + std::get(ompBlock->t)}; + const auto &beginDir{ + std::get(beginBlockDir.t)}; + if (beginDir.v != llvm::omp::Directive::OMPD_parallel) { + context_.Say(source, + "OpenMP '%s' construct is not allowed " + "in a WORKSHARE construct"_err_en_US, + parser::ToUpperCaseLetters(getDirectiveName(beginDir.v).str())); + } + } else if (!(parser::Unwrap(*it) || + parser::Unwrap(*it) || + parser::Unwrap(*it) || + parser::Unwrap(*it) || + parser::Unwrap(*it) || + parser::Unwrap(*it))) { + context_.Say(source, + "The structured block in a WORKSHARE construct may consist of only " + "scalar or array assignments, forall or where statements, " + "forall, where, atomic, critical or parallel constructs"_err_en_US); + } + } +} + } // namespace Fortran::semantics Index: flang/test/Semantics/omp-workshare01.f90 =================================================================== --- flang/test/Semantics/omp-workshare01.f90 +++ flang/test/Semantics/omp-workshare01.f90 @@ -1,6 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * - ! OpenMP Version 4.5 ! 2.7.4 workshare Construct ! Invalid do construct inside !$omp workshare @@ -9,8 +7,8 @@ integer n, i real aa(n,n), bb(n,n), cc(n,n), dd(n,n), ee(n,n), ff(n,n) + !ERROR: The structured block in a WORKSHARE construct may consist of only scalar or array assignments, forall or where statements, forall, where, atomic, critical or parallel constructs !$omp workshare - !ERROR: Unexpected do stmt inside !$omp workshare do i = 1, n print *, "omp workshare" end do Index: flang/test/Semantics/omp-workshare02.f90 =================================================================== --- flang/test/Semantics/omp-workshare02.f90 +++ flang/test/Semantics/omp-workshare02.f90 @@ -1,6 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * - ! OpenMP Version 4.5 ! 2.7.4 workshare Construct ! The !omp workshare construct must not contain any user defined @@ -20,7 +18,7 @@ real aa(n,n), bb(n,n), cc(n,n), dd(n,n), ee(n,n), ff(n,n) !$omp workshare - !ERROR: Non-ELEMENTAL function is not allowed in !$omp workshare construct + !ERROR: User defined non-ELEMENTAL function 'my_func' is not allowed in a WORKSHARE construct aa = my_func(n) cc = dd ee = ff Index: flang/test/Semantics/omp-workshare03.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-workshare03.f90 @@ -0,0 +1,32 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.7.4 workshare Construct +! All array assignments, scalar assignments, and masked array assignments +! must be intrinsic assignments. + +module defined_assign + interface assignment(=) + module procedure work_assign + end interface + + contains + subroutine work_assign(a,b) + integer , intent(out) :: a + logical , intent(in) :: b(:) + end subroutine work_assign +end module defined_assign + +program omp_workshare + use defined_assign + + integer:: a, aa(10), bb(10) + logical l(10) + l = .TRUE. + + !$omp workshare + !ERROR: Defined assignment statement is not allowed in a WORKSHARE construct + a = l + aa = bb + !$omp end workshare + +end program omp_workshare Index: flang/test/Semantics/omp-workshare04.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-workshare04.f90 @@ -0,0 +1,46 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.7.4 workshare Construct +! Checks for OpenMP Workshare construct + +subroutine omp_workshare(aa, bb, cc, dd, ee, ff, n) + integer i, j, n, a(10), b(10) + integer, pointer :: p + integer, target :: t + real aa(n,n), bb(n,n), cc(n,n), dd(n,n), ee(n,n), ff(n,n) + + !ERROR: The structured block in a WORKSHARE construct may consist of only scalar or array assignments, forall or where statements, forall, where, atomic, critical or parallel constructs + !ERROR: OpenMP 'SINGLE' construct is not allowed in a WORKSHARE construct + !$omp workshare + p => t + + !$omp parallel + cc = dd + !$omp end parallel + + !$omp single + ee = ff + !$omp end single + + where (aa .ne. 0) cc = bb / aa + + where (b .lt. 2) b = sum(a) + + where (aa .ge. 2.0) + cc = aa + bb + elsewhere + cc = dd + ee + end where + + forall (i = 1:10, n > i) a(i) = b(i) + + forall (j = 1:10) + a(j) = a(j) + b(j) + end forall + + !$omp atomic update + j = j + sum(a) + + !$omp end workshare + +end subroutine omp_workshare