@@ -141,6 +141,67 @@ class OmpWorkshareBlockChecker {
141141 parser::CharBlock source_;
142142};
143143
144+ // 'OmpWorkdistributeBlockChecker' is used to check the validity of the
145+ // assignment statements and the expressions enclosed in an OpenMP
146+ // workdistribute construct
147+ class OmpWorkdistributeBlockChecker {
148+ public:
149+ OmpWorkdistributeBlockChecker (
150+ SemanticsContext &context, parser::CharBlock source)
151+ : context_{context}, source_{source} {}
152+
153+ template <typename T> bool Pre (const T &) { return true ; }
154+ template <typename T> void Post (const T &) {}
155+
156+ bool Pre (const parser::AssignmentStmt &assignment) {
157+ const auto &var{std::get<parser::Variable>(assignment.t )};
158+ const auto &expr{std::get<parser::Expr>(assignment.t )};
159+ const auto *lhs{GetExpr (context_, var)};
160+ const auto *rhs{GetExpr (context_, expr)};
161+ if (lhs && rhs) {
162+ Tristate isDefined{semantics::IsDefinedAssignment (
163+ lhs->GetType (), lhs->Rank (), rhs->GetType (), rhs->Rank ())};
164+ if (isDefined == Tristate::Yes) {
165+ context_.Say (expr.source ,
166+ " Defined assignment statement is not "
167+ " allowed in a WORKDISTRIBUTE construct" _err_en_US);
168+ }
169+ }
170+ return true ;
171+ }
172+
173+ bool Pre (const parser::Expr &expr) {
174+ if (const auto *e{GetExpr (context_, expr)}) {
175+ for (const Symbol &symbol : evaluate::CollectSymbols (*e)) {
176+ const Symbol &root{GetAssociationRoot (symbol)};
177+ if (IsFunction (root)) {
178+ std::string attrs{" " };
179+ if (!IsElementalProcedure (root)) {
180+ attrs = " non-ELEMENTAL" ;
181+ }
182+ if (root.attrs ().test (Attr::IMPURE)) {
183+ if (attrs != " " ) {
184+ attrs = " ," + attrs;
185+ }
186+ attrs = " IMPURE" + attrs;
187+ }
188+ if (attrs != " " ) {
189+ context_.Say (expr.source ,
190+ " User defined%s function '%s' is not allowed in a "
191+ " WORKDISTRIBUTE construct" _err_en_US,
192+ attrs, root.name ());
193+ }
194+ }
195+ }
196+ }
197+ return false ;
198+ }
199+
200+ private:
201+ SemanticsContext &context_;
202+ parser::CharBlock source_;
203+ };
204+
144205// `OmpUnitedTaskDesignatorChecker` is used to check if the designator
145206// can appear within the TASK construct
146207class OmpUnitedTaskDesignatorChecker {
@@ -813,6 +874,13 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
813874 " TARGET construct with nested TEAMS region contains statements or "
814875 " directives outside of the TEAMS construct" _err_en_US);
815876 }
877+ if (GetContext ().directive == llvm::omp::Directive::OMPD_workdistribute &&
878+ GetContextParent ().directive != llvm::omp::Directive::OMPD_teams) {
879+ context_.Say (x.BeginDir ().DirName ().source ,
880+ " %s region can only be strictly nested within the "
881+ " teams region" _err_en_US,
882+ ContextDirectiveAsFortran ());
883+ }
816884 }
817885
818886 CheckNoBranching (block, beginSpec.DirId (), beginSpec.source );
@@ -896,6 +964,17 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
896964 HasInvalidWorksharingNesting (
897965 beginSpec.source , llvm::omp::nestedWorkshareErrSet);
898966 break ;
967+ case llvm::omp::OMPD_workdistribute:
968+ if (!CurrentDirectiveIsNested ()) {
969+ context_.Say (beginSpec.source ,
970+ " A workdistribute region must be nested inside teams region only." _err_en_US);
971+ }
972+ CheckWorkdistributeBlockStmts (block, beginSpec.source );
973+ break ;
974+ case llvm::omp::OMPD_teams_workdistribute:
975+ case llvm::omp::OMPD_target_teams_workdistribute:
976+ CheckWorkdistributeBlockStmts (block, beginSpec.source );
977+ break ;
899978 case llvm::omp::Directive::OMPD_scope:
900979 case llvm::omp::Directive::OMPD_single:
901980 // TODO: This check needs to be extended while implementing nesting of
@@ -4497,6 +4576,22 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
44974576 }
44984577}
44994578
4579+ void OmpStructureChecker::CheckWorkdistributeBlockStmts (
4580+ const parser::Block &block, parser::CharBlock source) {
4581+ OmpWorkdistributeBlockChecker ompWorkdistributeBlockChecker{context_, source};
4582+
4583+ for (auto it{block.begin ()}; it != block.end (); ++it) {
4584+ if (parser::Unwrap<parser::AssignmentStmt>(*it)) {
4585+ parser::Walk (*it, ompWorkdistributeBlockChecker);
4586+ } else {
4587+ context_.Say (source,
4588+ " The structured block in a WORKDISTRIBUTE construct may consist of "
4589+ " only "
4590+ " SCALAR or ARRAY assignments" _err_en_US);
4591+ }
4592+ }
4593+ }
4594+
45004595void OmpStructureChecker::CheckIfContiguous (const parser::OmpObject &object) {
45014596 if (auto contig{IsContiguous (context_, object)}; contig && !*contig) {
45024597 const parser::Name *name{GetObjectName (object)};
0 commit comments