1 //===-- lib/Semantics/check-acc-structure.cpp -----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "check-acc-structure.h"
10 #include "flang/Parser/parse-tree.h"
11 #include "flang/Semantics/tools.h"
12
13 #define CHECK_SIMPLE_CLAUSE(X, Y) \
14 void AccStructureChecker::Enter(const parser::AccClause::X &) { \
15 CheckAllowed(llvm::acc::Clause::Y); \
16 }
17
18 #define CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(X, Y) \
19 void AccStructureChecker::Enter(const parser::AccClause::X &c) { \
20 CheckAllowed(llvm::acc::Clause::Y); \
21 RequiresConstantPositiveParameter(llvm::acc::Clause::Y, c.v); \
22 }
23
24 namespace Fortran::semantics {
25
26 static constexpr inline AccClauseSet
27 parallelAndKernelsOnlyAllowedAfterDeviceTypeClauses{
28 llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait,
29 llvm::acc::Clause::ACCC_num_gangs, llvm::acc::Clause::ACCC_num_workers,
30 llvm::acc::Clause::ACCC_vector_length};
31
32 static constexpr inline AccClauseSet serialOnlyAllowedAfterDeviceTypeClauses{
33 llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait};
34
35 static constexpr inline AccClauseSet loopOnlyAllowedAfterDeviceTypeClauses{
36 llvm::acc::Clause::ACCC_auto, llvm::acc::Clause::ACCC_collapse,
37 llvm::acc::Clause::ACCC_independent, llvm::acc::Clause::ACCC_gang,
38 llvm::acc::Clause::ACCC_seq, llvm::acc::Clause::ACCC_tile,
39 llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_worker};
40
41 static constexpr inline AccClauseSet updateOnlyAllowedAfterDeviceTypeClauses{
42 llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait};
43
44 static constexpr inline AccClauseSet routineOnlyAllowedAfterDeviceTypeClauses{
45 llvm::acc::Clause::ACCC_bind, llvm::acc::Clause::ACCC_gang,
46 llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_worker};
47
48 class NoBranchingEnforce {
49 public:
NoBranchingEnforce(SemanticsContext & context,parser::CharBlock sourcePosition,llvm::acc::Directive directive)50 NoBranchingEnforce(SemanticsContext &context,
51 parser::CharBlock sourcePosition, llvm::acc::Directive directive)
52 : context_{context}, sourcePosition_{sourcePosition}, currentDirective_{
53 directive} {}
Pre(const T &)54 template <typename T> bool Pre(const T &) { return true; }
Post(const T &)55 template <typename T> void Post(const T &) {}
56
Pre(const parser::Statement<T> & statement)57 template <typename T> bool Pre(const parser::Statement<T> &statement) {
58 currentStatementSourcePosition_ = statement.source;
59 return true;
60 }
61
Post(const parser::ReturnStmt &)62 void Post(const parser::ReturnStmt &) { emitBranchOutError("RETURN"); }
Post(const parser::ExitStmt &)63 void Post(const parser::ExitStmt &) { emitBranchOutError("EXIT"); }
Post(const parser::StopStmt &)64 void Post(const parser::StopStmt &) { emitBranchOutError("STOP"); }
65
66 private:
GetEnclosingMsg()67 parser::MessageFixedText GetEnclosingMsg() {
68 return "Enclosing block construct"_en_US;
69 }
70
emitBranchOutError(const char * stmt)71 void emitBranchOutError(const char *stmt) {
72 context_
73 .Say(currentStatementSourcePosition_,
74 "%s statement is not allowed in a %s construct"_err_en_US, stmt,
75 parser::ToUpperCaseLetters(
76 llvm::acc::getOpenACCDirectiveName(currentDirective_).str()))
77 .Attach(sourcePosition_, GetEnclosingMsg());
78 }
79
80 SemanticsContext &context_;
81 parser::CharBlock currentStatementSourcePosition_;
82 parser::CharBlock sourcePosition_;
83 llvm::acc::Directive currentDirective_;
84 };
85
Enter(const parser::AccClause & x)86 void AccStructureChecker::Enter(const parser::AccClause &x) {
87 SetContextClause(x);
88 }
89
Leave(const parser::AccClauseList &)90 void AccStructureChecker::Leave(const parser::AccClauseList &) {}
91
Enter(const parser::OpenACCBlockConstruct & x)92 void AccStructureChecker::Enter(const parser::OpenACCBlockConstruct &x) {
93 const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)};
94 const auto &endBlockDir{std::get<parser::AccEndBlockDirective>(x.t)};
95 const auto &beginAccBlockDir{
96 std::get<parser::AccBlockDirective>(beginBlockDir.t)};
97
98 CheckMatching(beginAccBlockDir, endBlockDir.v);
99 PushContextAndClauseSets(beginAccBlockDir.source, beginAccBlockDir.v);
100 }
101
Leave(const parser::OpenACCBlockConstruct & x)102 void AccStructureChecker::Leave(const parser::OpenACCBlockConstruct &x) {
103 const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)};
104 const auto &blockDir{std::get<parser::AccBlockDirective>(beginBlockDir.t)};
105 const parser::Block &block{std::get<parser::Block>(x.t)};
106 switch (blockDir.v) {
107 case llvm::acc::Directive::ACCD_kernels:
108 case llvm::acc::Directive::ACCD_parallel:
109 // Restriction - 880-881 (KERNELS)
110 // Restriction - 843-844 (PARALLEL)
111 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
112 parallelAndKernelsOnlyAllowedAfterDeviceTypeClauses);
113 // Restriction - 877 (KERNELS)
114 // Restriction - 840 (PARALLEL)
115 CheckNoBranching(block, GetContext().directive, blockDir.source);
116 break;
117 case llvm::acc::Directive::ACCD_serial:
118 // Restriction - 919
119 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
120 serialOnlyAllowedAfterDeviceTypeClauses);
121 // Restriction - 916
122 CheckNoBranching(block, llvm::acc::Directive::ACCD_serial, blockDir.source);
123 break;
124 case llvm::acc::Directive::ACCD_data:
125 // Restriction - 1117-1118
126 CheckRequireAtLeastOneOf();
127 break;
128 case llvm::acc::Directive::ACCD_host_data:
129 // Restriction - 1578
130 CheckRequireAtLeastOneOf();
131 break;
132 default:
133 break;
134 }
135 accContext_.pop_back();
136 }
137
CheckNoBranching(const parser::Block & block,const llvm::acc::Directive directive,const parser::CharBlock & directiveSource) const138 void AccStructureChecker::CheckNoBranching(const parser::Block &block,
139 const llvm::acc::Directive directive,
140 const parser::CharBlock &directiveSource) const {
141 NoBranchingEnforce noBranchingEnforce{context_, directiveSource, directive};
142 parser::Walk(block, noBranchingEnforce);
143 }
144
Enter(const parser::OpenACCStandaloneDeclarativeConstruct & x)145 void AccStructureChecker::Enter(
146 const parser::OpenACCStandaloneDeclarativeConstruct &x) {
147 const auto &declarativeDir{std::get<parser::AccDeclarativeDirective>(x.t)};
148 PushContextAndClauseSets(declarativeDir.source, declarativeDir.v);
149 }
150
Leave(const parser::OpenACCStandaloneDeclarativeConstruct &)151 void AccStructureChecker::Leave(
152 const parser::OpenACCStandaloneDeclarativeConstruct &) {
153 // Restriction - 2075
154 CheckAtLeastOneClause();
155 accContext_.pop_back();
156 }
157
Enter(const parser::OpenACCCombinedConstruct & x)158 void AccStructureChecker::Enter(const parser::OpenACCCombinedConstruct &x) {
159 const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
160 const auto &combinedDir{
161 std::get<parser::AccCombinedDirective>(beginBlockDir.t)};
162 PushContextAndClauseSets(combinedDir.source, combinedDir.v);
163 }
164
Leave(const parser::OpenACCCombinedConstruct & x)165 void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) {
166 const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
167 const auto &combinedDir{
168 std::get<parser::AccCombinedDirective>(beginBlockDir.t)};
169 switch (combinedDir.v) {
170 case llvm::acc::Directive::ACCD_kernels_loop:
171 case llvm::acc::Directive::ACCD_parallel_loop:
172 // Restriction - 1962 -> (880-881) (KERNELS LOOP)
173 // Restriction - 1962 -> (843-844) (PARALLEL LOOP)
174 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
175 {llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait,
176 llvm::acc::Clause::ACCC_num_gangs,
177 llvm::acc::Clause::ACCC_num_workers,
178 llvm::acc::Clause::ACCC_vector_length});
179 break;
180 case llvm::acc::Directive::ACCD_serial_loop:
181 // Restriction - 1962 -> (919) (SERIAL LOOP)
182 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
183 {llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait});
184 break;
185 default:
186 break;
187 }
188 accContext_.pop_back();
189 }
190
ContextDirectiveAsFortran()191 std::string AccStructureChecker::ContextDirectiveAsFortran() {
192 return parser::ToUpperCaseLetters(
193 llvm::acc::getOpenACCDirectiveName(GetContext().directive).str());
194 }
195
Enter(const parser::OpenACCLoopConstruct & x)196 void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) {
197 const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
198 const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)};
199 PushContextAndClauseSets(loopDir.source, loopDir.v);
200 }
201
Leave(const parser::OpenACCLoopConstruct & x)202 void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) {
203 const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
204 const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)};
205 if (loopDir.v == llvm::acc::Directive::ACCD_loop) {
206 // Restriction - 1615-1616
207 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
208 loopOnlyAllowedAfterDeviceTypeClauses);
209 // Restriction - 1622
210 CheckNotAllowedIfClause(llvm::acc::Clause::ACCC_seq,
211 {llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector,
212 llvm::acc::Clause::ACCC_worker});
213 }
214 accContext_.pop_back();
215 }
216
Enter(const parser::OpenACCStandaloneConstruct & x)217 void AccStructureChecker::Enter(const parser::OpenACCStandaloneConstruct &x) {
218 const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)};
219 PushContextAndClauseSets(standaloneDir.source, standaloneDir.v);
220 }
221
Leave(const parser::OpenACCStandaloneConstruct & x)222 void AccStructureChecker::Leave(const parser::OpenACCStandaloneConstruct &x) {
223 const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)};
224 switch (standaloneDir.v) {
225 case llvm::acc::Directive::ACCD_enter_data:
226 case llvm::acc::Directive::ACCD_exit_data:
227 case llvm::acc::Directive::ACCD_set:
228 // Restriction - 1117-1118 (ENTER DATA)
229 // Restriction - 1161-1162 (EXIT DATA)
230 // Restriction - 2254 (SET)
231 CheckRequireAtLeastOneOf();
232 break;
233 case llvm::acc::Directive::ACCD_update:
234 // Restriction - 2301
235 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
236 updateOnlyAllowedAfterDeviceTypeClauses);
237 break;
238 default:
239 break;
240 }
241 accContext_.pop_back();
242 }
243
Enter(const parser::OpenACCRoutineConstruct & x)244 void AccStructureChecker::Enter(const parser::OpenACCRoutineConstruct &x) {
245 PushContextAndClauseSets(x.source, llvm::acc::Directive::ACCD_routine);
246 }
Leave(const parser::OpenACCRoutineConstruct &)247 void AccStructureChecker::Leave(const parser::OpenACCRoutineConstruct &) {
248 // Restriction - 2409
249 CheckRequireAtLeastOneOf();
250 // Restriction - 2407-2408
251 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
252 routineOnlyAllowedAfterDeviceTypeClauses);
253 accContext_.pop_back();
254 }
255
256 // Clause checkers
CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(Collapse,ACCC_collapse)257 CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(Collapse, ACCC_collapse)
258
259 CHECK_SIMPLE_CLAUSE(Auto, ACCC_auto)
260 CHECK_SIMPLE_CLAUSE(Async, ACCC_async)
261 CHECK_SIMPLE_CLAUSE(Attach, ACCC_attach)
262 CHECK_SIMPLE_CLAUSE(Bind, ACCC_bind)
263 CHECK_SIMPLE_CLAUSE(Capture, ACCC_capture)
264 CHECK_SIMPLE_CLAUSE(Copy, ACCC_copy)
265 CHECK_SIMPLE_CLAUSE(Default, ACCC_default)
266 CHECK_SIMPLE_CLAUSE(DefaultAsync, ACCC_default_async)
267 CHECK_SIMPLE_CLAUSE(Delete, ACCC_delete)
268 CHECK_SIMPLE_CLAUSE(Detach, ACCC_detach)
269 CHECK_SIMPLE_CLAUSE(Device, ACCC_device)
270 CHECK_SIMPLE_CLAUSE(DeviceNum, ACCC_device_num)
271 CHECK_SIMPLE_CLAUSE(DevicePtr, ACCC_deviceptr)
272 CHECK_SIMPLE_CLAUSE(DeviceResident, ACCC_device_resident)
273 CHECK_SIMPLE_CLAUSE(DeviceType, ACCC_device_type)
274 CHECK_SIMPLE_CLAUSE(Finalize, ACCC_finalize)
275 CHECK_SIMPLE_CLAUSE(FirstPrivate, ACCC_firstprivate)
276 CHECK_SIMPLE_CLAUSE(Gang, ACCC_gang)
277 CHECK_SIMPLE_CLAUSE(Host, ACCC_host)
278 CHECK_SIMPLE_CLAUSE(If, ACCC_if)
279 CHECK_SIMPLE_CLAUSE(IfPresent, ACCC_if_present)
280 CHECK_SIMPLE_CLAUSE(Independent, ACCC_independent)
281 CHECK_SIMPLE_CLAUSE(Link, ACCC_link)
282 CHECK_SIMPLE_CLAUSE(NoCreate, ACCC_no_create)
283 CHECK_SIMPLE_CLAUSE(NoHost, ACCC_nohost)
284 CHECK_SIMPLE_CLAUSE(NumGangs, ACCC_num_gangs)
285 CHECK_SIMPLE_CLAUSE(NumWorkers, ACCC_num_workers)
286 CHECK_SIMPLE_CLAUSE(Present, ACCC_present)
287 CHECK_SIMPLE_CLAUSE(Private, ACCC_private)
288 CHECK_SIMPLE_CLAUSE(Read, ACCC_read)
289 CHECK_SIMPLE_CLAUSE(Reduction, ACCC_reduction)
290 CHECK_SIMPLE_CLAUSE(Self, ACCC_self)
291 CHECK_SIMPLE_CLAUSE(Seq, ACCC_seq)
292 CHECK_SIMPLE_CLAUSE(Tile, ACCC_tile)
293 CHECK_SIMPLE_CLAUSE(UseDevice, ACCC_use_device)
294 CHECK_SIMPLE_CLAUSE(Vector, ACCC_vector)
295 CHECK_SIMPLE_CLAUSE(VectorLength, ACCC_vector_length)
296 CHECK_SIMPLE_CLAUSE(Wait, ACCC_wait)
297 CHECK_SIMPLE_CLAUSE(Worker, ACCC_worker)
298 CHECK_SIMPLE_CLAUSE(Write, ACCC_write)
299
300 void AccStructureChecker::Enter(const parser::AccClause::Create &c) {
301 CheckAllowed(llvm::acc::Clause::ACCC_create);
302 const auto &modifierClause{c.v};
303 if (const auto &modifier{
304 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) {
305 if (modifier->v != parser::AccDataModifier::Modifier::Zero) {
306 context_.Say(GetContext().clauseSource,
307 "Only the ZERO modifier is allowed for the %s clause "
308 "on the %s directive"_err_en_US,
309 parser::ToUpperCaseLetters(
310 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_create)
311 .str()),
312 ContextDirectiveAsFortran());
313 }
314 }
315 }
316
Enter(const parser::AccClause::Copyin & c)317 void AccStructureChecker::Enter(const parser::AccClause::Copyin &c) {
318 CheckAllowed(llvm::acc::Clause::ACCC_copyin);
319 const auto &modifierClause{c.v};
320 if (const auto &modifier{
321 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) {
322 if (modifier->v != parser::AccDataModifier::Modifier::ReadOnly) {
323 context_.Say(GetContext().clauseSource,
324 "Only the READONLY modifier is allowed for the %s clause "
325 "on the %s directive"_err_en_US,
326 parser::ToUpperCaseLetters(
327 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyin)
328 .str()),
329 ContextDirectiveAsFortran());
330 }
331 }
332 }
333
Enter(const parser::AccClause::Copyout & c)334 void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) {
335 CheckAllowed(llvm::acc::Clause::ACCC_copyout);
336 const auto &modifierClause{c.v};
337 if (const auto &modifier{
338 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) {
339 if (modifier->v != parser::AccDataModifier::Modifier::Zero) {
340 context_.Say(GetContext().clauseSource,
341 "Only the ZERO modifier is allowed for the %s clause "
342 "on the %s directive"_err_en_US,
343 parser::ToUpperCaseLetters(
344 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyout)
345 .str()),
346 ContextDirectiveAsFortran());
347 }
348 }
349 }
350
CheckAllowed(llvm::acc::Clause clause)351 void AccStructureChecker::CheckAllowed(llvm::acc::Clause clause) {
352 if (!GetContext().allowedClauses.test(clause) &&
353 !GetContext().allowedOnceClauses.test(clause) &&
354 !GetContext().allowedExclusiveClauses.test(clause) &&
355 !GetContext().requiredClauses.test(clause)) {
356 context_.Say(GetContext().clauseSource,
357 "%s clause is not allowed on the %s directive"_err_en_US,
358 parser::ToUpperCaseLetters(
359 llvm::acc::getOpenACCClauseName(clause).str()),
360 parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
361 return;
362 }
363 if ((GetContext().allowedOnceClauses.test(clause) ||
364 GetContext().allowedExclusiveClauses.test(clause)) &&
365 FindClause(clause)) {
366 context_.Say(GetContext().clauseSource,
367 "At most one %s clause can appear on the %s directive"_err_en_US,
368 parser::ToUpperCaseLetters(
369 llvm::acc::getOpenACCClauseName(clause).str()),
370 parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
371 return;
372 }
373 if (GetContext().allowedExclusiveClauses.test(clause)) {
374 std::vector<llvm::acc::Clause> others;
375 GetContext().allowedExclusiveClauses.IterateOverMembers(
376 [&](llvm::acc::Clause o) {
377 if (FindClause(o)) {
378 others.emplace_back(o);
379 }
380 });
381 for (const auto &e : others) {
382 context_.Say(GetContext().clauseSource,
383 "%s and %s clauses are mutually exclusive and may not appear on the "
384 "same %s directive"_err_en_US,
385 parser::ToUpperCaseLetters(
386 llvm::acc::getOpenACCClauseName(clause).str()),
387 parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(e).str()),
388 parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
389 }
390 if (!others.empty()) {
391 return;
392 }
393 }
394 SetContextClauseInfo(clause);
395 AddClauseToCrtContext(clause);
396 }
397
CheckOnlyAllowedAfter(llvm::acc::Clause clause,AccClauseSet set)398 void AccStructureChecker::CheckOnlyAllowedAfter(
399 llvm::acc::Clause clause, AccClauseSet set) {
400 bool enforceCheck = false;
401 for (auto cl : GetContext().actualClauses) {
402 if (cl == clause) {
403 enforceCheck = true;
404 continue;
405 } else if (enforceCheck && !set.test(cl)) {
406 auto parserClause = GetContext().clauseInfo.find(cl);
407 context_.Say(parserClause->second->source,
408 "Clause %s is not allowed after clause %s on the %s "
409 "directive"_err_en_US,
410 parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(cl).str()),
411 parser::ToUpperCaseLetters(
412 llvm::acc::getOpenACCClauseName(clause).str()),
413 ContextDirectiveAsFortran());
414 }
415 }
416 }
417
CheckRequireAtLeastOneOf()418 void AccStructureChecker::CheckRequireAtLeastOneOf() {
419 for (auto cl : GetContext().actualClauses) {
420 if (GetContext().requiredClauses.test(cl))
421 return;
422 }
423 // No clause matched in the actual clauses list
424 context_.Say(GetContext().directiveSource,
425 "At least one of %s clause must appear on the %s directive"_err_en_US,
426 ClauseSetToString(GetContext().requiredClauses),
427 ContextDirectiveAsFortran());
428 }
429
CheckAtLeastOneClause()430 void AccStructureChecker::CheckAtLeastOneClause() {
431 if (GetContext().actualClauses.empty()) {
432 context_.Say(GetContext().directiveSource,
433 "At least one clause is required on the %s directive"_err_en_US,
434 ContextDirectiveAsFortran());
435 }
436 }
437
438 // Enforce restriction where clauses in the given set are not allowed if the
439 // given clause appears.
CheckNotAllowedIfClause(llvm::acc::Clause clause,AccClauseSet set)440 void AccStructureChecker::CheckNotAllowedIfClause(
441 llvm::acc::Clause clause, AccClauseSet set) {
442 if (std::find(GetContext().actualClauses.begin(),
443 GetContext().actualClauses.end(),
444 clause) == GetContext().actualClauses.end()) {
445 return; // Clause is not present
446 }
447
448 for (auto cl : GetContext().actualClauses) {
449 if (set.test(cl)) {
450 context_.Say(GetContext().directiveSource,
451 "Clause %s is not allowed if clause %s appears on the %s directive"_err_en_US,
452 parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(cl).str()),
453 parser::ToUpperCaseLetters(
454 llvm::acc::getOpenACCClauseName(clause).str()),
455 ContextDirectiveAsFortran());
456 }
457 }
458 }
459
RequiresConstantPositiveParameter(const llvm::acc::Clause & clause,const parser::ScalarIntConstantExpr & i)460 void AccStructureChecker::RequiresConstantPositiveParameter(
461 const llvm::acc::Clause &clause, const parser::ScalarIntConstantExpr &i) {
462 if (const auto v{GetIntValue(i)}) {
463 if (*v <= 0) {
464 context_.Say(GetContext().clauseSource,
465 "The parameter of the %s clause on the %s directive must be "
466 "a constant positive integer expression"_err_en_US,
467 parser::ToUpperCaseLetters(
468 llvm::acc::getOpenACCClauseName(clause).str()),
469 ContextDirectiveAsFortran());
470 }
471 }
472 }
473
OptionalConstantPositiveParameter(const llvm::acc::Clause & clause,const std::optional<parser::ScalarIntConstantExpr> & o)474 void AccStructureChecker::OptionalConstantPositiveParameter(
475 const llvm::acc::Clause &clause,
476 const std::optional<parser::ScalarIntConstantExpr> &o) {
477 if (o != std::nullopt) {
478 RequiresConstantPositiveParameter(clause, o.value());
479 }
480 }
481
ClauseSetToString(const AccClauseSet set)482 std::string AccStructureChecker::ClauseSetToString(const AccClauseSet set) {
483 std::string list;
484 set.IterateOverMembers([&](llvm::acc::Clause o) {
485 if (!list.empty())
486 list.append(", ");
487 list.append(
488 parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(o).str()));
489 });
490 return list;
491 }
492
SayNotMatching(const parser::CharBlock & beginSource,const parser::CharBlock & endSource)493 void AccStructureChecker::SayNotMatching(
494 const parser::CharBlock &beginSource, const parser::CharBlock &endSource) {
495 context_
496 .Say(endSource, "Unmatched %s directive"_err_en_US,
497 parser::ToUpperCaseLetters(endSource.ToString()))
498 .Attach(beginSource, "Does not match directive"_en_US);
499 }
500
501 } // namespace Fortran::semantics
502