@@ -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 {
@@ -809,6 +870,13 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
809870 " TARGET construct with nested TEAMS region contains statements or "
810871 " directives outside of the TEAMS construct" _err_en_US);
811872 }
873+ if (GetContext ().directive == llvm::omp::Directive::OMPD_workdistribute &&
874+ GetContextParent ().directive != llvm::omp::Directive::OMPD_teams) {
875+ context_.Say (x.BeginDir ().DirName ().source ,
876+ " %s region can only be strictly nested within the "
877+ " teams region" _err_en_US,
878+ ContextDirectiveAsFortran ());
879+ }
812880 }
813881
814882 CheckNoBranching (block, beginSpec.DirId (), beginSpec.source );
@@ -892,6 +960,17 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
892960 HasInvalidWorksharingNesting (
893961 beginSpec.source , llvm::omp::nestedWorkshareErrSet);
894962 break ;
963+ case llvm::omp::OMPD_workdistribute:
964+ if (!CurrentDirectiveIsNested ()) {
965+ context_.Say (beginSpec.source ,
966+ " A workdistribute region must be nested inside teams region only." _err_en_US);
967+ }
968+ CheckWorkdistributeBlockStmts (block, beginSpec.source );
969+ break ;
970+ case llvm::omp::OMPD_teams_workdistribute:
971+ case llvm::omp::OMPD_target_teams_workdistribute:
972+ CheckWorkdistributeBlockStmts (block, beginSpec.source );
973+ break ;
895974 case llvm::omp::Directive::OMPD_scope:
896975 case llvm::omp::Directive::OMPD_single:
897976 // TODO: This check needs to be extended while implementing nesting of
@@ -4470,6 +4549,22 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
44704549 }
44714550}
44724551
4552+ void OmpStructureChecker::CheckWorkdistributeBlockStmts (
4553+ const parser::Block &block, parser::CharBlock source) {
4554+ OmpWorkdistributeBlockChecker ompWorkdistributeBlockChecker{context_, source};
4555+
4556+ for (auto it{block.begin ()}; it != block.end (); ++it) {
4557+ if (parser::Unwrap<parser::AssignmentStmt>(*it)) {
4558+ parser::Walk (*it, ompWorkdistributeBlockChecker);
4559+ } else {
4560+ context_.Say (source,
4561+ " The structured block in a WORKDISTRIBUTE construct may consist of "
4562+ " only "
4563+ " SCALAR or ARRAY assignments" _err_en_US);
4564+ }
4565+ }
4566+ }
4567+
44734568void OmpStructureChecker::CheckIfContiguous (const parser::OmpObject &object) {
44744569 if (auto contig{IsContiguous (context_, object)}; contig && !*contig) {
44754570 const parser::Name *name{GetObjectName (object)};
0 commit comments