@@ -143,6 +143,64 @@ class OmpWorkshareBlockChecker {
143
143
parser::CharBlock source_;
144
144
};
145
145
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
+
146
204
// `OmpUnitedTaskDesignatorChecker` is used to check if the designator
147
205
// can appear within the TASK construct
148
206
class OmpUnitedTaskDesignatorChecker {
@@ -815,6 +873,12 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
815
873
" TARGET construct with nested TEAMS region contains statements or "
816
874
" directives outside of the TEAMS construct" _err_en_US);
817
875
}
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
+ }
818
882
}
819
883
820
884
CheckNoBranching (block, beginSpec.DirId (), beginSpec.source );
@@ -898,6 +962,17 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
898
962
HasInvalidWorksharingNesting (
899
963
beginSpec.source , llvm::omp::nestedWorkshareErrSet);
900
964
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 ;
901
976
case llvm::omp::Directive::OMPD_scope:
902
977
case llvm::omp::Directive::OMPD_single:
903
978
// TODO: This check needs to be extended while implementing nesting of
@@ -4546,6 +4621,27 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
4546
4621
}
4547
4622
}
4548
4623
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
+
4549
4645
void OmpStructureChecker::CheckIfContiguous (const parser::OmpObject &object) {
4550
4646
if (auto contig{IsContiguous (context_, object)}; contig && !*contig) {
4551
4647
const parser::Name *name{GetObjectName (object)};
0 commit comments