@@ -143,6 +143,67 @@ class OmpWorkshareBlockChecker {
143143 parser::CharBlock source_;
144144};
145145
146+ // 'OmpWorkdistributeBlockChecker' is used to check the validity of the
147+ // assignment statements and the expressions enclosed in an OpenMP
148+ // workdistribute construct
149+ class OmpWorkdistributeBlockChecker {
150+ public:
151+ OmpWorkdistributeBlockChecker (
152+ SemanticsContext &context, parser::CharBlock source)
153+ : context_{context}, source_{source} {}
154+
155+ template <typename T> bool Pre (const T &) { return true ; }
156+ template <typename T> void Post (const T &) {}
157+
158+ bool Pre (const parser::AssignmentStmt &assignment) {
159+ const auto &var{std::get<parser::Variable>(assignment.t )};
160+ const auto &expr{std::get<parser::Expr>(assignment.t )};
161+ const auto *lhs{GetExpr (context_, var)};
162+ const auto *rhs{GetExpr (context_, expr)};
163+ if (lhs && rhs) {
164+ Tristate isDefined{semantics::IsDefinedAssignment (
165+ lhs->GetType (), lhs->Rank (), rhs->GetType (), rhs->Rank ())};
166+ if (isDefined == Tristate::Yes) {
167+ context_.Say (expr.source ,
168+ " Defined assignment statement is not "
169+ " allowed in a WORKDISTRIBUTE construct" _err_en_US);
170+ }
171+ }
172+ return true ;
173+ }
174+
175+ bool Pre (const parser::Expr &expr) {
176+ if (const auto *e{GetExpr (context_, expr)}) {
177+ for (const Symbol &symbol : evaluate::CollectSymbols (*e)) {
178+ const Symbol &root{GetAssociationRoot (symbol)};
179+ if (IsFunction (root)) {
180+ std::string attrs{" " };
181+ if (!IsElementalProcedure (root)) {
182+ attrs = " non-ELEMENTAL" ;
183+ }
184+ if (root.attrs ().test (Attr::IMPURE)) {
185+ if (attrs != " " ) {
186+ attrs = " ," + attrs;
187+ }
188+ attrs = " IMPURE" + attrs;
189+ }
190+ if (attrs != " " ) {
191+ context_.Say (expr.source ,
192+ " User defined%s function '%s' is not allowed in a "
193+ " WORKDISTRIBUTE construct" _err_en_US,
194+ attrs, root.name ());
195+ }
196+ }
197+ }
198+ }
199+ return false ;
200+ }
201+
202+ private:
203+ SemanticsContext &context_;
204+ parser::CharBlock source_;
205+ };
206+
146207// `OmpUnitedTaskDesignatorChecker` is used to check if the designator
147208// can appear within the TASK construct
148209class OmpUnitedTaskDesignatorChecker {
@@ -815,6 +876,13 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
815876 " TARGET construct with nested TEAMS region contains statements or "
816877 " directives outside of the TEAMS construct" _err_en_US);
817878 }
879+ if (GetContext ().directive == llvm::omp::Directive::OMPD_workdistribute &&
880+ GetContextParent ().directive != llvm::omp::Directive::OMPD_teams) {
881+ context_.Say (x.BeginDir ().DirName ().source ,
882+ " %s region can only be strictly nested within the "
883+ " teams region" _err_en_US,
884+ ContextDirectiveAsFortran ());
885+ }
818886 }
819887
820888 CheckNoBranching (block, beginSpec.DirId (), beginSpec.source );
@@ -898,6 +966,17 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
898966 HasInvalidWorksharingNesting (
899967 beginSpec.source , llvm::omp::nestedWorkshareErrSet);
900968 break ;
969+ case llvm::omp::OMPD_workdistribute:
970+ if (!CurrentDirectiveIsNested ()) {
971+ context_.Say (beginSpec.source ,
972+ " A workdistribute region must be nested inside teams region only." _err_en_US);
973+ }
974+ CheckWorkdistributeBlockStmts (block, beginSpec.source );
975+ break ;
976+ case llvm::omp::OMPD_teams_workdistribute:
977+ case llvm::omp::OMPD_target_teams_workdistribute:
978+ CheckWorkdistributeBlockStmts (block, beginSpec.source );
979+ break ;
901980 case llvm::omp::Directive::OMPD_scope:
902981 case llvm::omp::Directive::OMPD_single:
903982 // TODO: This check needs to be extended while implementing nesting of
@@ -4546,6 +4625,22 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
45464625 }
45474626}
45484627
4628+ void OmpStructureChecker::CheckWorkdistributeBlockStmts (
4629+ const parser::Block &block, parser::CharBlock source) {
4630+ OmpWorkdistributeBlockChecker ompWorkdistributeBlockChecker{context_, source};
4631+
4632+ for (auto it{block.begin ()}; it != block.end (); ++it) {
4633+ if (parser::Unwrap<parser::AssignmentStmt>(*it)) {
4634+ parser::Walk (*it, ompWorkdistributeBlockChecker);
4635+ } else {
4636+ context_.Say (source,
4637+ " The structured block in a WORKDISTRIBUTE construct may consist of "
4638+ " only "
4639+ " SCALAR or ARRAY assignments" _err_en_US);
4640+ }
4641+ }
4642+ }
4643+
45494644void OmpStructureChecker::CheckIfContiguous (const parser::OmpObject &object) {
45504645 if (auto contig{IsContiguous (context_, object)}; contig && !*contig) {
45514646 const parser::Name *name{GetObjectName (object)};
0 commit comments