@@ -143,6 +143,64 @@ 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 allowed in a WORKDISTRIBUTE construct" _err_en_US);
169+ }
170+ }
171+ return true ;
172+ }
173+
174+ bool Pre (const parser::Expr &expr) {
175+ if (const auto *e{GetExpr (context_, expr)}) {
176+ if (!e)
177+ return false ;
178+ for (const Symbol &symbol : evaluate::CollectSymbols (*e)) {
179+ const Symbol &root{GetAssociationRoot (symbol)};
180+ if (IsFunction (root)) {
181+ std::vector<std::string> attrs;
182+ if (!IsElementalProcedure (root)) {
183+ attrs.push_back (" non-ELEMENTAL" );
184+ }
185+ if (root.attrs ().test (Attr::IMPURE)) {
186+ attrs.push_back (" IMPURE" );
187+ }
188+ std::string attrsStr =
189+ attrs.empty () ? " " : " " + llvm::join (attrs, " , " );
190+ context_.Say (expr.source ,
191+ " User defined%s function '%s' is not allowed in a WORKDISTRIBUTE construct" _err_en_US,
192+ attrsStr, root.name ());
193+ }
194+ }
195+ }
196+ return false ;
197+ }
198+
199+ private:
200+ SemanticsContext &context_;
201+ parser::CharBlock source_;
202+ };
203+
146204// `OmpUnitedTaskDesignatorChecker` is used to check if the designator
147205// can appear within the TASK construct
148206class OmpUnitedTaskDesignatorChecker {
@@ -815,6 +873,12 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
815873 " TARGET construct with nested TEAMS region contains statements or "
816874 " directives outside of the TEAMS construct" _err_en_US);
817875 }
876+ if (GetContext ().directive == llvm::omp::Directive::OMPD_workdistribute &&
877+ GetContextParent ().directive != llvm::omp::Directive::OMPD_teams) {
878+ context_.Say (x.BeginDir ().DirName ().source ,
879+ " %s region can only be strictly nested within TEAMS region" _err_en_US,
880+ ContextDirectiveAsFortran ());
881+ }
818882 }
819883
820884 CheckNoBranching (block, beginSpec.DirId (), beginSpec.source );
@@ -898,6 +962,17 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
898962 HasInvalidWorksharingNesting (
899963 beginSpec.source , llvm::omp::nestedWorkshareErrSet);
900964 break ;
965+ case llvm::omp::OMPD_workdistribute:
966+ if (!CurrentDirectiveIsNested ()) {
967+ context_.Say (beginSpec.source ,
968+ " A WORKDISTRIBUTE region must be nested inside TEAMS region only." _err_en_US);
969+ }
970+ CheckWorkdistributeBlockStmts (block, beginSpec.source );
971+ break ;
972+ case llvm::omp::OMPD_teams_workdistribute:
973+ case llvm::omp::OMPD_target_teams_workdistribute:
974+ CheckWorkdistributeBlockStmts (block, beginSpec.source );
975+ break ;
901976 case llvm::omp::Directive::OMPD_scope:
902977 case llvm::omp::Directive::OMPD_single:
903978 // TODO: This check needs to be extended while implementing nesting of
@@ -4546,6 +4621,27 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
45464621 }
45474622}
45484623
4624+ void OmpStructureChecker::CheckWorkdistributeBlockStmts (
4625+ const parser::Block &block, parser::CharBlock source) {
4626+ unsigned version{context_.langOptions ().OpenMPVersion };
4627+ unsigned since{60 };
4628+ if (version < since)
4629+ context_.Say (source,
4630+ " WORKDISTRIBUTE construct is not allowed in %s, %s" _err_en_US,
4631+ ThisVersion (version), TryVersion (since));
4632+
4633+ OmpWorkdistributeBlockChecker ompWorkdistributeBlockChecker{context_, source};
4634+
4635+ for (auto it{block.begin ()}; it != block.end (); ++it) {
4636+ if (parser::Unwrap<parser::AssignmentStmt>(*it)) {
4637+ parser::Walk (*it, ompWorkdistributeBlockChecker);
4638+ } else {
4639+ context_.Say (source,
4640+ " The structured block in a WORKDISTRIBUTE construct may consist of only SCALAR or ARRAY assignments" _err_en_US);
4641+ }
4642+ }
4643+ }
4644+
45494645void OmpStructureChecker::CheckIfContiguous (const parser::OmpObject &object) {
45504646 if (auto contig{IsContiguous (context_, object)}; contig && !*contig) {
45514647 const parser::Name *name{GetObjectName (object)};
0 commit comments