1//===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===//
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// This file implements the parsing logic for OpenACC language features.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/OpenACCClause.h"
14#include "clang/Basic/OpenACCKinds.h"
15#include "clang/Parse/ParseDiagnostic.h"
16#include "clang/Parse/Parser.h"
17#include "clang/Parse/RAIIObjectsForParser.h"
18#include "clang/Sema/SemaOpenACC.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/StringSwitch.h"
21
22using namespace clang;
23using namespace llvm;
24
25namespace {
26// An enum that contains the extended 'partial' parsed variants. This type
27// should never escape the initial parse functionality, but is useful for
28// simplifying the implementation.
29enum class OpenACCDirectiveKindEx {
30 Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
31 // 'enter data' and 'exit data'
32 Enter,
33 Exit,
34};
35
36// Translate single-token string representations to the OpenACC Directive Kind.
37// This doesn't completely comprehend 'Compound Constructs' (as it just
38// identifies the first token), and doesn't fully handle 'enter data', 'exit
39// data', nor any of the 'atomic' variants, just the first token of each. So
40// this should only be used by `ParseOpenACCDirectiveKind`.
41OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
42 if (!Tok.is(K: tok::identifier))
43 return OpenACCDirectiveKindEx::Invalid;
44 OpenACCDirectiveKind DirKind =
45 llvm::StringSwitch<OpenACCDirectiveKind>(
46 Tok.getIdentifierInfo()->getName())
47 .Case(S: "parallel", Value: OpenACCDirectiveKind::Parallel)
48 .Case(S: "serial", Value: OpenACCDirectiveKind::Serial)
49 .Case(S: "kernels", Value: OpenACCDirectiveKind::Kernels)
50 .Case(S: "data", Value: OpenACCDirectiveKind::Data)
51 .Case(S: "host_data", Value: OpenACCDirectiveKind::HostData)
52 .Case(S: "loop", Value: OpenACCDirectiveKind::Loop)
53 .Case(S: "cache", Value: OpenACCDirectiveKind::Cache)
54 .Case(S: "atomic", Value: OpenACCDirectiveKind::Atomic)
55 .Case(S: "routine", Value: OpenACCDirectiveKind::Routine)
56 .Case(S: "declare", Value: OpenACCDirectiveKind::Declare)
57 .Case(S: "init", Value: OpenACCDirectiveKind::Init)
58 .Case(S: "shutdown", Value: OpenACCDirectiveKind::Shutdown)
59 .Case(S: "set", Value: OpenACCDirectiveKind::Set)
60 .Case(S: "update", Value: OpenACCDirectiveKind::Update)
61 .Case(S: "wait", Value: OpenACCDirectiveKind::Wait)
62 .Default(Value: OpenACCDirectiveKind::Invalid);
63
64 if (DirKind != OpenACCDirectiveKind::Invalid)
65 return static_cast<OpenACCDirectiveKindEx>(DirKind);
66
67 return llvm::StringSwitch<OpenACCDirectiveKindEx>(
68 Tok.getIdentifierInfo()->getName())
69 .Case(S: "enter", Value: OpenACCDirectiveKindEx::Enter)
70 .Case(S: "exit", Value: OpenACCDirectiveKindEx::Exit)
71 .Default(Value: OpenACCDirectiveKindEx::Invalid);
72}
73
74// Translate single-token string representations to the OpenCC Clause Kind.
75OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
76 // auto is a keyword in some language modes, so make sure we parse it
77 // correctly.
78 if (Tok.is(K: tok::kw_auto))
79 return OpenACCClauseKind::Auto;
80
81 // default is a keyword, so make sure we parse it correctly.
82 if (Tok.is(K: tok::kw_default))
83 return OpenACCClauseKind::Default;
84
85 // if is also a keyword, make sure we parse it correctly.
86 if (Tok.is(K: tok::kw_if))
87 return OpenACCClauseKind::If;
88
89 if (!Tok.is(K: tok::identifier))
90 return OpenACCClauseKind::Invalid;
91
92 return llvm::StringSwitch<OpenACCClauseKind>(
93 Tok.getIdentifierInfo()->getName())
94 .Case(S: "async", Value: OpenACCClauseKind::Async)
95 .Case(S: "attach", Value: OpenACCClauseKind::Attach)
96 .Case(S: "auto", Value: OpenACCClauseKind::Auto)
97 .Case(S: "bind", Value: OpenACCClauseKind::Bind)
98 .Case(S: "create", Value: OpenACCClauseKind::Create)
99 .Case(S: "collapse", Value: OpenACCClauseKind::Collapse)
100 .Case(S: "copy", Value: OpenACCClauseKind::Copy)
101 .Case(S: "copyin", Value: OpenACCClauseKind::CopyIn)
102 .Case(S: "copyout", Value: OpenACCClauseKind::CopyOut)
103 .Case(S: "default", Value: OpenACCClauseKind::Default)
104 .Case(S: "default_async", Value: OpenACCClauseKind::DefaultAsync)
105 .Case(S: "delete", Value: OpenACCClauseKind::Delete)
106 .Case(S: "detach", Value: OpenACCClauseKind::Detach)
107 .Case(S: "device", Value: OpenACCClauseKind::Device)
108 .Case(S: "device_num", Value: OpenACCClauseKind::DeviceNum)
109 .Case(S: "device_resident", Value: OpenACCClauseKind::DeviceResident)
110 .Case(S: "device_type", Value: OpenACCClauseKind::DeviceType)
111 .Case(S: "deviceptr", Value: OpenACCClauseKind::DevicePtr)
112 .Case(S: "dtype", Value: OpenACCClauseKind::DType)
113 .Case(S: "finalize", Value: OpenACCClauseKind::Finalize)
114 .Case(S: "firstprivate", Value: OpenACCClauseKind::FirstPrivate)
115 .Case(S: "gang", Value: OpenACCClauseKind::Gang)
116 .Case(S: "host", Value: OpenACCClauseKind::Host)
117 .Case(S: "if", Value: OpenACCClauseKind::If)
118 .Case(S: "if_present", Value: OpenACCClauseKind::IfPresent)
119 .Case(S: "independent", Value: OpenACCClauseKind::Independent)
120 .Case(S: "link", Value: OpenACCClauseKind::Link)
121 .Case(S: "no_create", Value: OpenACCClauseKind::NoCreate)
122 .Case(S: "num_gangs", Value: OpenACCClauseKind::NumGangs)
123 .Case(S: "num_workers", Value: OpenACCClauseKind::NumWorkers)
124 .Case(S: "nohost", Value: OpenACCClauseKind::NoHost)
125 .Case(S: "present", Value: OpenACCClauseKind::Present)
126 .Case(S: "private", Value: OpenACCClauseKind::Private)
127 .Case(S: "reduction", Value: OpenACCClauseKind::Reduction)
128 .Case(S: "self", Value: OpenACCClauseKind::Self)
129 .Case(S: "seq", Value: OpenACCClauseKind::Seq)
130 .Case(S: "tile", Value: OpenACCClauseKind::Tile)
131 .Case(S: "use_device", Value: OpenACCClauseKind::UseDevice)
132 .Case(S: "vector", Value: OpenACCClauseKind::Vector)
133 .Case(S: "vector_length", Value: OpenACCClauseKind::VectorLength)
134 .Case(S: "wait", Value: OpenACCClauseKind::Wait)
135 .Case(S: "worker", Value: OpenACCClauseKind::Worker)
136 .Default(Value: OpenACCClauseKind::Invalid);
137}
138
139// Since 'atomic' is effectively a compound directive, this will decode the
140// second part of the directive.
141OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
142 if (!Tok.is(K: tok::identifier))
143 return OpenACCAtomicKind::Invalid;
144 return llvm::StringSwitch<OpenACCAtomicKind>(
145 Tok.getIdentifierInfo()->getName())
146 .Case(S: "read", Value: OpenACCAtomicKind::Read)
147 .Case(S: "write", Value: OpenACCAtomicKind::Write)
148 .Case(S: "update", Value: OpenACCAtomicKind::Update)
149 .Case(S: "capture", Value: OpenACCAtomicKind::Capture)
150 .Default(Value: OpenACCAtomicKind::Invalid);
151}
152
153OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) {
154 if (!Tok.is(K: tok::identifier))
155 return OpenACCDefaultClauseKind::Invalid;
156
157 return llvm::StringSwitch<OpenACCDefaultClauseKind>(
158 Tok.getIdentifierInfo()->getName())
159 .Case(S: "none", Value: OpenACCDefaultClauseKind::None)
160 .Case(S: "present", Value: OpenACCDefaultClauseKind::Present)
161 .Default(Value: OpenACCDefaultClauseKind::Invalid);
162}
163
164enum class OpenACCSpecialTokenKind {
165 ReadOnly,
166 DevNum,
167 Queues,
168 Zero,
169 Force,
170 Num,
171 Length,
172 Dim,
173 Static,
174};
175
176bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
177 if (Tok.is(K: tok::kw_static) && Kind == OpenACCSpecialTokenKind::Static)
178 return true;
179
180 if (!Tok.is(K: tok::identifier))
181 return false;
182
183 switch (Kind) {
184 case OpenACCSpecialTokenKind::ReadOnly:
185 return Tok.getIdentifierInfo()->isStr(Str: "readonly");
186 case OpenACCSpecialTokenKind::DevNum:
187 return Tok.getIdentifierInfo()->isStr(Str: "devnum");
188 case OpenACCSpecialTokenKind::Queues:
189 return Tok.getIdentifierInfo()->isStr(Str: "queues");
190 case OpenACCSpecialTokenKind::Zero:
191 return Tok.getIdentifierInfo()->isStr(Str: "zero");
192 case OpenACCSpecialTokenKind::Force:
193 return Tok.getIdentifierInfo()->isStr(Str: "force");
194 case OpenACCSpecialTokenKind::Num:
195 return Tok.getIdentifierInfo()->isStr(Str: "num");
196 case OpenACCSpecialTokenKind::Length:
197 return Tok.getIdentifierInfo()->isStr(Str: "length");
198 case OpenACCSpecialTokenKind::Dim:
199 return Tok.getIdentifierInfo()->isStr(Str: "dim");
200 case OpenACCSpecialTokenKind::Static:
201 return Tok.getIdentifierInfo()->isStr(Str: "static");
202 }
203 llvm_unreachable("Unknown 'Kind' Passed");
204}
205
206/// Used for cases where we have a token we want to check against an
207/// 'identifier-like' token, but don't want to give awkward error messages in
208/// cases where it is accidentially a keyword.
209bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) {
210 if (Tok.is(K: tok::identifier))
211 return true;
212
213 if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
214 Tok.getIdentifierInfo()->isKeyword(LangOpts: P.getLangOpts()))
215 return true;
216
217 return false;
218}
219
220/// Parses and consumes an identifer followed immediately by a single colon, and
221/// diagnoses if it is not the 'special token' kind that we require. Used when
222/// the tag is the only valid value.
223/// Return 'true' if the special token was matched, false if no special token,
224/// or an invalid special token was found.
225template <typename DirOrClauseTy>
226bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind,
227 DirOrClauseTy DirOrClause) {
228 Token IdentTok = P.getCurToken();
229 // If this is an identifier-like thing followed by ':', it is one of the
230 // OpenACC 'special' name tags, so consume it.
231 if (isTokenIdentifierOrKeyword(P, Tok: IdentTok) && P.NextToken().is(K: tok::colon)) {
232 P.ConsumeToken();
233 P.ConsumeToken();
234
235 if (!isOpenACCSpecialToken(Kind, Tok: IdentTok)) {
236 P.Diag(IdentTok, diag::err_acc_invalid_tag_kind)
237 << IdentTok.getIdentifierInfo() << DirOrClause
238 << std::is_same_v<DirOrClauseTy, OpenACCClauseKind>;
239 return false;
240 }
241
242 return true;
243 }
244
245 return false;
246}
247
248bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
249 if (!Tok.is(K: tok::identifier))
250 return false;
251
252 switch (Kind) {
253 case OpenACCDirectiveKind::Parallel:
254 return Tok.getIdentifierInfo()->isStr(Str: "parallel");
255 case OpenACCDirectiveKind::Serial:
256 return Tok.getIdentifierInfo()->isStr(Str: "serial");
257 case OpenACCDirectiveKind::Kernels:
258 return Tok.getIdentifierInfo()->isStr(Str: "kernels");
259 case OpenACCDirectiveKind::Data:
260 return Tok.getIdentifierInfo()->isStr(Str: "data");
261 case OpenACCDirectiveKind::HostData:
262 return Tok.getIdentifierInfo()->isStr(Str: "host_data");
263 case OpenACCDirectiveKind::Loop:
264 return Tok.getIdentifierInfo()->isStr(Str: "loop");
265 case OpenACCDirectiveKind::Cache:
266 return Tok.getIdentifierInfo()->isStr(Str: "cache");
267
268 case OpenACCDirectiveKind::ParallelLoop:
269 case OpenACCDirectiveKind::SerialLoop:
270 case OpenACCDirectiveKind::KernelsLoop:
271 case OpenACCDirectiveKind::EnterData:
272 case OpenACCDirectiveKind::ExitData:
273 return false;
274
275 case OpenACCDirectiveKind::Atomic:
276 return Tok.getIdentifierInfo()->isStr(Str: "atomic");
277 case OpenACCDirectiveKind::Routine:
278 return Tok.getIdentifierInfo()->isStr(Str: "routine");
279 case OpenACCDirectiveKind::Declare:
280 return Tok.getIdentifierInfo()->isStr(Str: "declare");
281 case OpenACCDirectiveKind::Init:
282 return Tok.getIdentifierInfo()->isStr(Str: "init");
283 case OpenACCDirectiveKind::Shutdown:
284 return Tok.getIdentifierInfo()->isStr(Str: "shutdown");
285 case OpenACCDirectiveKind::Set:
286 return Tok.getIdentifierInfo()->isStr(Str: "set");
287 case OpenACCDirectiveKind::Update:
288 return Tok.getIdentifierInfo()->isStr(Str: "update");
289 case OpenACCDirectiveKind::Wait:
290 return Tok.getIdentifierInfo()->isStr(Str: "wait");
291 case OpenACCDirectiveKind::Invalid:
292 return false;
293 }
294 llvm_unreachable("Unknown 'Kind' Passed");
295}
296
297OpenACCReductionOperator ParseReductionOperator(Parser &P) {
298 // If there is no colon, treat as if the reduction operator was missing, else
299 // we probably will not recover from it in the case where an expression starts
300 // with one of the operator tokens.
301 if (P.NextToken().isNot(K: tok::colon)) {
302 P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator);
303 return OpenACCReductionOperator::Invalid;
304 }
305 Token ReductionKindTok = P.getCurToken();
306 // Consume both the kind and the colon.
307 P.ConsumeToken();
308 P.ConsumeToken();
309
310 switch (ReductionKindTok.getKind()) {
311 case tok::plus:
312 return OpenACCReductionOperator::Addition;
313 case tok::star:
314 return OpenACCReductionOperator::Multiplication;
315 case tok::amp:
316 return OpenACCReductionOperator::BitwiseAnd;
317 case tok::pipe:
318 return OpenACCReductionOperator::BitwiseOr;
319 case tok::caret:
320 return OpenACCReductionOperator::BitwiseXOr;
321 case tok::ampamp:
322 return OpenACCReductionOperator::And;
323 case tok::pipepipe:
324 return OpenACCReductionOperator::Or;
325 case tok::identifier:
326 if (ReductionKindTok.getIdentifierInfo()->isStr(Str: "max"))
327 return OpenACCReductionOperator::Max;
328 if (ReductionKindTok.getIdentifierInfo()->isStr(Str: "min"))
329 return OpenACCReductionOperator::Min;
330 LLVM_FALLTHROUGH;
331 default:
332 P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator);
333 return OpenACCReductionOperator::Invalid;
334 }
335 llvm_unreachable("Reduction op token kind not caught by 'default'?");
336}
337
338/// Used for cases where we expect an identifier-like token, but don't want to
339/// give awkward error messages in cases where it is accidentially a keyword.
340bool expectIdentifierOrKeyword(Parser &P) {
341 Token Tok = P.getCurToken();
342
343 if (isTokenIdentifierOrKeyword(P, Tok))
344 return false;
345
346 P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
347 return true;
348}
349
350OpenACCDirectiveKind
351ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
352 OpenACCDirectiveKindEx ExtDirKind) {
353 Token SecondTok = P.getCurToken();
354
355 if (SecondTok.isAnnotation()) {
356 P.Diag(FirstTok, diag::err_acc_invalid_directive)
357 << 0 << FirstTok.getIdentifierInfo();
358 return OpenACCDirectiveKind::Invalid;
359 }
360
361 // Consume the second name anyway, this way we can continue on without making
362 // this oddly look like a clause.
363 P.ConsumeAnyToken();
364
365 if (!isOpenACCDirectiveKind(Kind: OpenACCDirectiveKind::Data, Tok: SecondTok)) {
366 if (!SecondTok.is(tok::identifier))
367 P.Diag(SecondTok, diag::err_expected) << tok::identifier;
368 else
369 P.Diag(FirstTok, diag::err_acc_invalid_directive)
370 << 1 << FirstTok.getIdentifierInfo()->getName()
371 << SecondTok.getIdentifierInfo()->getName();
372 return OpenACCDirectiveKind::Invalid;
373 }
374
375 return ExtDirKind == OpenACCDirectiveKindEx::Enter
376 ? OpenACCDirectiveKind::EnterData
377 : OpenACCDirectiveKind::ExitData;
378}
379
380OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) {
381 Token AtomicClauseToken = P.getCurToken();
382
383 // #pragma acc atomic is equivilent to update:
384 if (AtomicClauseToken.isAnnotation())
385 return OpenACCAtomicKind::Update;
386
387 OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(Tok: AtomicClauseToken);
388
389 // If we don't know what this is, treat it as 'nothing', and treat the rest of
390 // this as a clause list, which, despite being invalid, is likely what the
391 // user was trying to do.
392 if (AtomicKind == OpenACCAtomicKind::Invalid)
393 return OpenACCAtomicKind::Update;
394
395 P.ConsumeToken();
396 return AtomicKind;
397}
398
399// Parse and consume the tokens for OpenACC Directive/Construct kinds.
400OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
401 Token FirstTok = P.getCurToken();
402
403 // Just #pragma acc can get us immediately to the end, make sure we don't
404 // introspect on the spelling before then.
405 if (FirstTok.isNot(K: tok::identifier)) {
406 P.Diag(FirstTok, diag::err_acc_missing_directive);
407
408 if (P.getCurToken().isNot(K: tok::annot_pragma_openacc_end))
409 P.ConsumeAnyToken();
410
411 return OpenACCDirectiveKind::Invalid;
412 }
413
414 P.ConsumeToken();
415
416 OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(Tok: FirstTok);
417
418 // OpenACCDirectiveKindEx is meant to be an extended list
419 // over OpenACCDirectiveKind, so any value below Invalid is one of the
420 // OpenACCDirectiveKind values. This switch takes care of all of the extra
421 // parsing required for the Extended values. At the end of this block,
422 // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
423 // immediately cast it and use it as that.
424 if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
425 switch (ExDirKind) {
426 case OpenACCDirectiveKindEx::Invalid: {
427 P.Diag(FirstTok, diag::err_acc_invalid_directive)
428 << 0 << FirstTok.getIdentifierInfo();
429 return OpenACCDirectiveKind::Invalid;
430 }
431 case OpenACCDirectiveKindEx::Enter:
432 case OpenACCDirectiveKindEx::Exit:
433 return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExtDirKind: ExDirKind);
434 }
435 }
436
437 OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);
438
439 // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
440 // other attempt at a combined construct will be diagnosed as an invalid
441 // clause.
442 Token SecondTok = P.getCurToken();
443 if (!SecondTok.isAnnotation() &&
444 isOpenACCDirectiveKind(Kind: OpenACCDirectiveKind::Loop, Tok: SecondTok)) {
445 switch (DirKind) {
446 default:
447 // Nothing to do except in the below cases, as they should be diagnosed as
448 // a clause.
449 break;
450 case OpenACCDirectiveKind::Parallel:
451 P.ConsumeToken();
452 return OpenACCDirectiveKind::ParallelLoop;
453 case OpenACCDirectiveKind::Serial:
454 P.ConsumeToken();
455 return OpenACCDirectiveKind::SerialLoop;
456 case OpenACCDirectiveKind::Kernels:
457 P.ConsumeToken();
458 return OpenACCDirectiveKind::KernelsLoop;
459 }
460 }
461
462 return DirKind;
463}
464
465enum ClauseParensKind {
466 None,
467 Optional,
468 Required
469};
470
471ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind,
472 OpenACCClauseKind Kind) {
473 switch (Kind) {
474 case OpenACCClauseKind::Self:
475 return DirKind == OpenACCDirectiveKind::Update ? ClauseParensKind::Required
476 : ClauseParensKind::Optional;
477 case OpenACCClauseKind::Async:
478 case OpenACCClauseKind::Worker:
479 case OpenACCClauseKind::Vector:
480 case OpenACCClauseKind::Gang:
481 case OpenACCClauseKind::Wait:
482 return ClauseParensKind::Optional;
483
484 case OpenACCClauseKind::Default:
485 case OpenACCClauseKind::If:
486 case OpenACCClauseKind::Create:
487 case OpenACCClauseKind::Copy:
488 case OpenACCClauseKind::CopyIn:
489 case OpenACCClauseKind::CopyOut:
490 case OpenACCClauseKind::UseDevice:
491 case OpenACCClauseKind::NoCreate:
492 case OpenACCClauseKind::Present:
493 case OpenACCClauseKind::DevicePtr:
494 case OpenACCClauseKind::Attach:
495 case OpenACCClauseKind::Detach:
496 case OpenACCClauseKind::Private:
497 case OpenACCClauseKind::FirstPrivate:
498 case OpenACCClauseKind::Delete:
499 case OpenACCClauseKind::DeviceResident:
500 case OpenACCClauseKind::Device:
501 case OpenACCClauseKind::Link:
502 case OpenACCClauseKind::Host:
503 case OpenACCClauseKind::Reduction:
504 case OpenACCClauseKind::Collapse:
505 case OpenACCClauseKind::Bind:
506 case OpenACCClauseKind::VectorLength:
507 case OpenACCClauseKind::NumGangs:
508 case OpenACCClauseKind::NumWorkers:
509 case OpenACCClauseKind::DeviceNum:
510 case OpenACCClauseKind::DefaultAsync:
511 case OpenACCClauseKind::DeviceType:
512 case OpenACCClauseKind::DType:
513 case OpenACCClauseKind::Tile:
514 return ClauseParensKind::Required;
515
516 case OpenACCClauseKind::Auto:
517 case OpenACCClauseKind::Finalize:
518 case OpenACCClauseKind::IfPresent:
519 case OpenACCClauseKind::Independent:
520 case OpenACCClauseKind::Invalid:
521 case OpenACCClauseKind::NoHost:
522 case OpenACCClauseKind::Seq:
523 return ClauseParensKind::None;
524 }
525 llvm_unreachable("Unhandled clause kind");
526}
527
528bool ClauseHasOptionalParens(OpenACCDirectiveKind DirKind,
529 OpenACCClauseKind Kind) {
530 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional;
531}
532
533bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind,
534 OpenACCClauseKind Kind) {
535 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required;
536}
537
538// Skip until we see the end of pragma token, but don't consume it. This is us
539// just giving up on the rest of the pragma so we can continue executing. We
540// have to do this because 'SkipUntil' considers paren balancing, which isn't
541// what we want.
542void SkipUntilEndOfDirective(Parser &P) {
543 while (P.getCurToken().isNot(K: tok::annot_pragma_openacc_end))
544 P.ConsumeAnyToken();
545}
546
547bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {
548 switch (DirKind) {
549 default:
550 return false;
551 case OpenACCDirectiveKind::Parallel:
552 case OpenACCDirectiveKind::Serial:
553 case OpenACCDirectiveKind::Kernels:
554 return true;
555 }
556 llvm_unreachable("Unhandled directive->assoc stmt");
557}
558
559unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {
560 switch (DirKind) {
561 case OpenACCDirectiveKind::Parallel:
562 case OpenACCDirectiveKind::Serial:
563 case OpenACCDirectiveKind::Kernels:
564 // Mark this as a BreakScope/ContinueScope as well as a compute construct
565 // so that we can diagnose trying to 'break'/'continue' inside of one.
566 return Scope::BreakScope | Scope::ContinueScope |
567 Scope::OpenACCComputeConstructScope;
568 case OpenACCDirectiveKind::Invalid:
569 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");
570 default:
571 break;
572 }
573 return 0;
574}
575
576} // namespace
577
578Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() {
579 return {nullptr, OpenACCParseCanContinue::Can};
580}
581
582Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() {
583 return {nullptr, OpenACCParseCanContinue::Cannot};
584}
585
586Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) {
587 return {Clause, OpenACCParseCanContinue::Can};
588}
589
590ExprResult Parser::ParseOpenACCConditionExpr() {
591 // FIXME: It isn't clear if the spec saying 'condition' means the same as
592 // it does in an if/while/etc (See ParseCXXCondition), however as it was
593 // written with Fortran/C in mind, we're going to assume it just means an
594 // 'expression evaluating to boolean'.
595 ExprResult ER = getActions().CorrectDelayedTyposInExpr(ER: ParseExpression());
596
597 if (!ER.isUsable())
598 return ER;
599
600 Sema::ConditionResult R =
601 getActions().ActOnCondition(S: getCurScope(), Loc: ER.get()->getExprLoc(),
602 SubExpr: ER.get(), CK: Sema::ConditionKind::Boolean);
603
604 return R.isInvalid() ? ExprError() : R.get().second;
605}
606
607// OpenACC 3.3, section 1.7:
608// To simplify the specification and convey appropriate constraint information,
609// a pqr-list is a comma-separated list of pdr items. The one exception is a
610// clause-list, which is a list of one or more clauses optionally separated by
611// commas.
612SmallVector<OpenACCClause *>
613Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {
614 SmallVector<OpenACCClause *> Clauses;
615 bool FirstClause = true;
616 while (getCurToken().isNot(K: tok::annot_pragma_openacc_end)) {
617 // Comma is optional in a clause-list.
618 if (!FirstClause && getCurToken().is(K: tok::comma))
619 ConsumeToken();
620 FirstClause = false;
621
622 OpenACCClauseParseResult Result = ParseOpenACCClause(ExistingClauses: Clauses, DirKind);
623 if (OpenACCClause *Clause = Result.getPointer()) {
624 Clauses.push_back(Elt: Clause);
625 } else if (Result.getInt() == OpenACCParseCanContinue::Cannot) {
626 // Recovering from a bad clause is really difficult, so we just give up on
627 // error.
628 SkipUntilEndOfDirective(P&: *this);
629 return Clauses;
630 }
631 }
632 return Clauses;
633}
634
635Parser::OpenACCIntExprParseResult
636Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
637 SourceLocation Loc) {
638 ExprResult ER = ParseAssignmentExpression();
639
640 // If the actual parsing failed, we don't know the state of the parse, so
641 // don't try to continue.
642 if (!ER.isUsable())
643 return {ER, OpenACCParseCanContinue::Cannot};
644
645 // Parsing can continue after the initial assignment expression parsing, so
646 // even if there was a typo, we can continue.
647 ER = getActions().CorrectDelayedTyposInExpr(ER);
648 if (!ER.isUsable())
649 return {ER, OpenACCParseCanContinue::Can};
650
651 return {getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, IntExpr: ER.get()),
652 OpenACCParseCanContinue::Can};
653}
654
655bool Parser::ParseOpenACCIntExprList(OpenACCDirectiveKind DK,
656 OpenACCClauseKind CK, SourceLocation Loc,
657 llvm::SmallVectorImpl<Expr *> &IntExprs) {
658 OpenACCIntExprParseResult CurResult = ParseOpenACCIntExpr(DK, CK, Loc);
659
660 if (!CurResult.first.isUsable() &&
661 CurResult.second == OpenACCParseCanContinue::Cannot) {
662 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
663 Flags: Parser::StopBeforeMatch);
664 return true;
665 }
666
667 IntExprs.push_back(Elt: CurResult.first.get());
668
669 while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) {
670 ExpectAndConsume(ExpectedTok: tok::comma);
671
672 CurResult = ParseOpenACCIntExpr(DK, CK, Loc);
673
674 if (!CurResult.first.isUsable() &&
675 CurResult.second == OpenACCParseCanContinue::Cannot) {
676 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
677 Flags: Parser::StopBeforeMatch);
678 return true;
679 }
680 IntExprs.push_back(Elt: CurResult.first.get());
681 }
682 return false;
683}
684
685bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) {
686 // FIXME: Future clauses will require 'special word' parsing, check for one,
687 // then parse it based on whether it is a clause that requires a 'special
688 // word'.
689 (void)Kind;
690
691 // If the var parsing fails, skip until the end of the directive as this is
692 // an expression and gets messy if we try to continue otherwise.
693 if (ParseOpenACCVar())
694 return true;
695
696 while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) {
697 ExpectAndConsume(ExpectedTok: tok::comma);
698
699 // If the var parsing fails, skip until the end of the directive as this is
700 // an expression and gets messy if we try to continue otherwise.
701 if (ParseOpenACCVar())
702 return true;
703 }
704 return false;
705}
706
707/// OpenACC 3.3 Section 2.4:
708/// The argument to the device_type clause is a comma-separated list of one or
709/// more device architecture name identifiers, or an asterisk.
710///
711/// The syntax of the device_type clause is
712/// device_type( * )
713/// device_type( device-type-list )
714///
715/// The device_type clause may be abbreviated to dtype.
716bool Parser::ParseOpenACCDeviceTypeList() {
717
718 if (expectIdentifierOrKeyword(P&: *this)) {
719 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
720 Flags: Parser::StopBeforeMatch);
721 return false;
722 }
723 ConsumeToken();
724
725 while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) {
726 ExpectAndConsume(ExpectedTok: tok::comma);
727
728 if (expectIdentifierOrKeyword(P&: *this)) {
729 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
730 Flags: Parser::StopBeforeMatch);
731 return false;
732 }
733 ConsumeToken();
734 }
735 return false;
736}
737
738/// OpenACC 3.3 Section 2.9:
739/// size-expr is one of:
740// *
741// int-expr
742// Note that this is specified under 'gang-arg-list', but also applies to 'tile'
743// via reference.
744bool Parser::ParseOpenACCSizeExpr() {
745 // FIXME: Ensure these are constant expressions.
746
747 // The size-expr ends up being ambiguous when only looking at the current
748 // token, as it could be a deref of a variable/expression.
749 if (getCurToken().is(K: tok::star) &&
750 NextToken().isOneOf(K1: tok::comma, Ks: tok::r_paren,
751 Ks: tok::annot_pragma_openacc_end)) {
752 ConsumeToken();
753 return false;
754 }
755
756 return getActions()
757 .CorrectDelayedTyposInExpr(ER: ParseAssignmentExpression())
758 .isInvalid();
759}
760
761bool Parser::ParseOpenACCSizeExprList() {
762 if (ParseOpenACCSizeExpr()) {
763 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
764 Flags: Parser::StopBeforeMatch);
765 return false;
766 }
767
768 while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) {
769 ExpectAndConsume(ExpectedTok: tok::comma);
770
771 if (ParseOpenACCSizeExpr()) {
772 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
773 Flags: Parser::StopBeforeMatch);
774 return false;
775 }
776 }
777 return false;
778}
779
780/// OpenACC 3.3 Section 2.9:
781///
782/// where gang-arg is one of:
783/// [num:]int-expr
784/// dim:int-expr
785/// static:size-expr
786bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
787
788 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Static, Tok: getCurToken()) &&
789 NextToken().is(K: tok::colon)) {
790 // 'static' just takes a size-expr, which is an int-expr or an asterisk.
791 ConsumeToken();
792 ConsumeToken();
793 return ParseOpenACCSizeExpr();
794 }
795
796 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Dim, Tok: getCurToken()) &&
797 NextToken().is(K: tok::colon)) {
798 ConsumeToken();
799 ConsumeToken();
800 return ParseOpenACCIntExpr(DK: OpenACCDirectiveKind::Invalid,
801 CK: OpenACCClauseKind::Gang, Loc: GangLoc)
802 .first.isInvalid();
803 }
804
805 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Num, Tok: getCurToken()) &&
806 NextToken().is(K: tok::colon)) {
807 ConsumeToken();
808 ConsumeToken();
809 // Fallthrough to the 'int-expr' handling for when 'num' is omitted.
810 }
811 // This is just the 'num' case where 'num' is optional.
812 return ParseOpenACCIntExpr(DK: OpenACCDirectiveKind::Invalid,
813 CK: OpenACCClauseKind::Gang, Loc: GangLoc)
814 .first.isInvalid();
815}
816
817bool Parser::ParseOpenACCGangArgList(SourceLocation GangLoc) {
818 if (ParseOpenACCGangArg(GangLoc)) {
819 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
820 Flags: Parser::StopBeforeMatch);
821 return false;
822 }
823
824 while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) {
825 ExpectAndConsume(ExpectedTok: tok::comma);
826
827 if (ParseOpenACCGangArg(GangLoc)) {
828 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
829 Flags: Parser::StopBeforeMatch);
830 return false;
831 }
832 }
833 return false;
834}
835
836// The OpenACC Clause List is a comma or space-delimited list of clauses (see
837// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
838// really have its owner grammar and each individual one has its own definition.
839// However, they all are named with a single-identifier (or auto/default!)
840// token, followed in some cases by either braces or parens.
841Parser::OpenACCClauseParseResult
842Parser::ParseOpenACCClause(ArrayRef<const OpenACCClause *> ExistingClauses,
843 OpenACCDirectiveKind DirKind) {
844 // A number of clause names are actually keywords, so accept a keyword that
845 // can be converted to a name.
846 if (expectIdentifierOrKeyword(P&: *this))
847 return OpenACCCannotContinue();
848
849 OpenACCClauseKind Kind = getOpenACCClauseKind(Tok: getCurToken());
850
851 if (Kind == OpenACCClauseKind::Invalid) {
852 Diag(getCurToken(), diag::err_acc_invalid_clause)
853 << getCurToken().getIdentifierInfo();
854 return OpenACCCannotContinue();
855 }
856
857 // Consume the clause name.
858 SourceLocation ClauseLoc = ConsumeToken();
859
860 return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc);
861}
862
863Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
864 ArrayRef<const OpenACCClause *> ExistingClauses,
865 OpenACCDirectiveKind DirKind, OpenACCClauseKind ClauseKind,
866 SourceLocation ClauseLoc) {
867 BalancedDelimiterTracker Parens(*this, tok::l_paren,
868 tok::annot_pragma_openacc_end);
869 SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);
870
871 if (ClauseHasRequiredParens(DirKind, Kind: ClauseKind)) {
872 ParsedClause.setLParenLoc(getCurToken().getLocation());
873 if (Parens.expectAndConsume()) {
874 // We are missing a paren, so assume that the person just forgot the
875 // parameter. Return 'false' so we try to continue on and parse the next
876 // clause.
877 SkipUntil(T1: tok::comma, T2: tok::r_paren, T3: tok::annot_pragma_openacc_end,
878 Flags: Parser::StopBeforeMatch);
879 return OpenACCCanContinue();
880 }
881
882 switch (ClauseKind) {
883 case OpenACCClauseKind::Default: {
884 Token DefKindTok = getCurToken();
885
886 if (expectIdentifierOrKeyword(P&: *this)) {
887 Parens.skipToEnd();
888 return OpenACCCanContinue();
889 }
890
891 ConsumeToken();
892
893 OpenACCDefaultClauseKind DefKind =
894 getOpenACCDefaultClauseKind(Tok: DefKindTok);
895
896 if (DefKind == OpenACCDefaultClauseKind::Invalid) {
897 Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
898 Parens.skipToEnd();
899 return OpenACCCanContinue();
900 }
901
902 ParsedClause.setDefaultDetails(DefKind);
903 break;
904 }
905 case OpenACCClauseKind::If: {
906 ExprResult CondExpr = ParseOpenACCConditionExpr();
907 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()
908 : nullptr);
909
910 if (CondExpr.isInvalid()) {
911 Parens.skipToEnd();
912 return OpenACCCanContinue();
913 }
914
915 break;
916 }
917 case OpenACCClauseKind::CopyIn:
918 tryParseAndConsumeSpecialTokenKind(
919 P&: *this, Kind: OpenACCSpecialTokenKind::ReadOnly, DirOrClause: ClauseKind);
920 if (ParseOpenACCClauseVarList(Kind: ClauseKind)) {
921 Parens.skipToEnd();
922 return OpenACCCanContinue();
923 }
924 break;
925 case OpenACCClauseKind::Create:
926 case OpenACCClauseKind::CopyOut:
927 tryParseAndConsumeSpecialTokenKind(P&: *this, Kind: OpenACCSpecialTokenKind::Zero,
928 DirOrClause: ClauseKind);
929 if (ParseOpenACCClauseVarList(Kind: ClauseKind)) {
930 Parens.skipToEnd();
931 return OpenACCCanContinue();
932 }
933 break;
934 case OpenACCClauseKind::Reduction:
935 // If we're missing a clause-kind (or it is invalid), see if we can parse
936 // the var-list anyway.
937 ParseReductionOperator(P&: *this);
938 if (ParseOpenACCClauseVarList(Kind: ClauseKind)) {
939 Parens.skipToEnd();
940 return OpenACCCanContinue();
941 }
942 break;
943 case OpenACCClauseKind::Self:
944 // The 'self' clause is a var-list instead of a 'condition' in the case of
945 // the 'update' clause, so we have to handle it here. U se an assert to
946 // make sure we get the right differentiator.
947 assert(DirKind == OpenACCDirectiveKind::Update);
948 LLVM_FALLTHROUGH;
949 case OpenACCClauseKind::Attach:
950 case OpenACCClauseKind::Copy:
951 case OpenACCClauseKind::Delete:
952 case OpenACCClauseKind::Detach:
953 case OpenACCClauseKind::Device:
954 case OpenACCClauseKind::DeviceResident:
955 case OpenACCClauseKind::DevicePtr:
956 case OpenACCClauseKind::FirstPrivate:
957 case OpenACCClauseKind::Host:
958 case OpenACCClauseKind::Link:
959 case OpenACCClauseKind::NoCreate:
960 case OpenACCClauseKind::Present:
961 case OpenACCClauseKind::Private:
962 case OpenACCClauseKind::UseDevice:
963 if (ParseOpenACCClauseVarList(Kind: ClauseKind)) {
964 Parens.skipToEnd();
965 return OpenACCCanContinue();
966 }
967 break;
968 case OpenACCClauseKind::Collapse: {
969 tryParseAndConsumeSpecialTokenKind(P&: *this, Kind: OpenACCSpecialTokenKind::Force,
970 DirOrClause: ClauseKind);
971 ExprResult NumLoops =
972 getActions().CorrectDelayedTyposInExpr(ER: ParseConstantExpression());
973 if (NumLoops.isInvalid()) {
974 Parens.skipToEnd();
975 return OpenACCCanContinue();
976 }
977 break;
978 }
979 case OpenACCClauseKind::Bind: {
980 ExprResult BindArg = ParseOpenACCBindClauseArgument();
981 if (BindArg.isInvalid()) {
982 Parens.skipToEnd();
983 return OpenACCCanContinue();
984 }
985 break;
986 }
987 case OpenACCClauseKind::NumGangs: {
988 llvm::SmallVector<Expr *> IntExprs;
989
990 if (ParseOpenACCIntExprList(DK: OpenACCDirectiveKind::Invalid,
991 CK: OpenACCClauseKind::NumGangs, Loc: ClauseLoc,
992 IntExprs)) {
993 Parens.skipToEnd();
994 return OpenACCCanContinue();
995 }
996 ParsedClause.setIntExprDetails(std::move(IntExprs));
997 break;
998 }
999 case OpenACCClauseKind::NumWorkers:
1000 case OpenACCClauseKind::DeviceNum:
1001 case OpenACCClauseKind::DefaultAsync:
1002 case OpenACCClauseKind::VectorLength: {
1003 ExprResult IntExpr = ParseOpenACCIntExpr(DK: OpenACCDirectiveKind::Invalid,
1004 CK: ClauseKind, Loc: ClauseLoc)
1005 .first;
1006 if (IntExpr.isInvalid()) {
1007 Parens.skipToEnd();
1008 return OpenACCCanContinue();
1009 }
1010
1011 // TODO OpenACC: as we implement the 'rest' of the above, this 'if' should
1012 // be removed leaving just the 'setIntExprDetails'.
1013 if (ClauseKind == OpenACCClauseKind::NumWorkers ||
1014 ClauseKind == OpenACCClauseKind::VectorLength)
1015 ParsedClause.setIntExprDetails(IntExpr.get());
1016
1017 break;
1018 }
1019 case OpenACCClauseKind::DType:
1020 case OpenACCClauseKind::DeviceType:
1021 if (getCurToken().is(K: tok::star)) {
1022 // FIXME: We want to mark that this is an 'everything else' type of
1023 // device_type in Sema.
1024 ConsumeToken();
1025 } else if (ParseOpenACCDeviceTypeList()) {
1026 Parens.skipToEnd();
1027 return OpenACCCanContinue();
1028 }
1029 break;
1030 case OpenACCClauseKind::Tile:
1031 if (ParseOpenACCSizeExprList()) {
1032 Parens.skipToEnd();
1033 return OpenACCCanContinue();
1034 }
1035 break;
1036 default:
1037 llvm_unreachable("Not a required parens type?");
1038 }
1039
1040 ParsedClause.setEndLoc(getCurToken().getLocation());
1041
1042 if (Parens.consumeClose())
1043 return OpenACCCannotContinue();
1044
1045 } else if (ClauseHasOptionalParens(DirKind, Kind: ClauseKind)) {
1046 ParsedClause.setLParenLoc(getCurToken().getLocation());
1047 if (!Parens.consumeOpen()) {
1048 switch (ClauseKind) {
1049 case OpenACCClauseKind::Self: {
1050 assert(DirKind != OpenACCDirectiveKind::Update);
1051 ExprResult CondExpr = ParseOpenACCConditionExpr();
1052 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()
1053 : nullptr);
1054
1055 if (CondExpr.isInvalid()) {
1056 Parens.skipToEnd();
1057 return OpenACCCanContinue();
1058 }
1059 break;
1060 }
1061 case OpenACCClauseKind::Vector:
1062 case OpenACCClauseKind::Worker: {
1063 tryParseAndConsumeSpecialTokenKind(P&: *this,
1064 Kind: ClauseKind ==
1065 OpenACCClauseKind::Vector
1066 ? OpenACCSpecialTokenKind::Length
1067 : OpenACCSpecialTokenKind::Num,
1068 DirOrClause: ClauseKind);
1069 ExprResult IntExpr = ParseOpenACCIntExpr(DK: OpenACCDirectiveKind::Invalid,
1070 CK: ClauseKind, Loc: ClauseLoc)
1071 .first;
1072 if (IntExpr.isInvalid()) {
1073 Parens.skipToEnd();
1074 return OpenACCCanContinue();
1075 }
1076 break;
1077 }
1078 case OpenACCClauseKind::Async: {
1079 ExprResult AsyncArg = ParseOpenACCAsyncArgument();
1080 if (AsyncArg.isInvalid()) {
1081 Parens.skipToEnd();
1082 return OpenACCCanContinue();
1083 }
1084 break;
1085 }
1086 case OpenACCClauseKind::Gang:
1087 if (ParseOpenACCGangArgList(GangLoc: ClauseLoc)) {
1088 Parens.skipToEnd();
1089 return OpenACCCanContinue();
1090 }
1091 break;
1092 case OpenACCClauseKind::Wait:
1093 if (ParseOpenACCWaitArgument(Loc: ClauseLoc,
1094 /*IsDirective=*/false)) {
1095 Parens.skipToEnd();
1096 return OpenACCCanContinue();
1097 }
1098 break;
1099 default:
1100 llvm_unreachable("Not an optional parens type?");
1101 }
1102 ParsedClause.setEndLoc(getCurToken().getLocation());
1103 if (Parens.consumeClose())
1104 return OpenACCCannotContinue();
1105 }
1106 }
1107 return OpenACCSuccess(
1108 Clause: Actions.OpenACC().ActOnClause(ExistingClauses, Clause&: ParsedClause));
1109}
1110
1111/// OpenACC 3.3 section 2.16:
1112/// In this section and throughout the specification, the term async-argument
1113/// means a nonnegative scalar integer expression (int for C or C++, integer for
1114/// Fortran), or one of the special values acc_async_noval or acc_async_sync, as
1115/// defined in the C header file and the Fortran openacc module. The special
1116/// values are negative values, so as not to conflict with a user-specified
1117/// nonnegative async-argument.
1118ExprResult Parser::ParseOpenACCAsyncArgument() {
1119 return getActions().CorrectDelayedTyposInExpr(ER: ParseAssignmentExpression());
1120}
1121
1122/// OpenACC 3.3, section 2.16:
1123/// In this section and throughout the specification, the term wait-argument
1124/// means:
1125/// [ devnum : int-expr : ] [ queues : ] async-argument-list
1126bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
1127 // [devnum : int-expr : ]
1128 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::DevNum, Tok) &&
1129 NextToken().is(K: tok::colon)) {
1130 // Consume devnum.
1131 ConsumeToken();
1132 // Consume colon.
1133 ConsumeToken();
1134
1135 ExprResult IntExpr =
1136 ParseOpenACCIntExpr(DK: IsDirective ? OpenACCDirectiveKind::Wait
1137 : OpenACCDirectiveKind::Invalid,
1138 CK: IsDirective ? OpenACCClauseKind::Invalid
1139 : OpenACCClauseKind::Wait,
1140 Loc)
1141 .first;
1142 if (IntExpr.isInvalid())
1143 return true;
1144
1145 if (ExpectAndConsume(ExpectedTok: tok::colon))
1146 return true;
1147 }
1148
1149 // [ queues : ]
1150 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Queues, Tok) &&
1151 NextToken().is(K: tok::colon)) {
1152 // Consume queues.
1153 ConsumeToken();
1154 // Consume colon.
1155 ConsumeToken();
1156 }
1157
1158 // OpenACC 3.3, section 2.16:
1159 // the term 'async-argument' means a nonnegative scalar integer expression, or
1160 // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
1161 // in the C header file and the Fortran opacc module.
1162 bool FirstArg = true;
1163 while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) {
1164 if (!FirstArg) {
1165 if (ExpectAndConsume(ExpectedTok: tok::comma))
1166 return true;
1167 }
1168 FirstArg = false;
1169
1170 ExprResult CurArg = ParseOpenACCAsyncArgument();
1171
1172 if (CurArg.isInvalid())
1173 return true;
1174 }
1175
1176 return false;
1177}
1178
1179ExprResult Parser::ParseOpenACCIDExpression() {
1180 ExprResult Res;
1181 if (getLangOpts().CPlusPlus) {
1182 Res = ParseCXXIdExpression(/*isAddressOfOperand=*/true);
1183 } else {
1184 // There isn't anything quite the same as ParseCXXIdExpression for C, so we
1185 // need to get the identifier, then call into Sema ourselves.
1186
1187 if (Tok.isNot(K: tok::identifier)) {
1188 Diag(Tok, diag::err_expected) << tok::identifier;
1189 return ExprError();
1190 }
1191
1192 Token FuncName = getCurToken();
1193 UnqualifiedId Name;
1194 CXXScopeSpec ScopeSpec;
1195 SourceLocation TemplateKWLoc;
1196 Name.setIdentifier(Id: FuncName.getIdentifierInfo(), IdLoc: ConsumeToken());
1197
1198 // Ensure this is a valid identifier. We don't accept causing implicit
1199 // function declarations per the spec, so always claim to not have trailing
1200 // L Paren.
1201 Res = Actions.ActOnIdExpression(S: getCurScope(), SS&: ScopeSpec, TemplateKWLoc,
1202 Id&: Name, /*HasTrailingLParen=*/false,
1203 /*isAddressOfOperand=*/IsAddressOfOperand: false);
1204 }
1205
1206 return getActions().CorrectDelayedTyposInExpr(ER: Res);
1207}
1208
1209ExprResult Parser::ParseOpenACCBindClauseArgument() {
1210 // OpenACC 3.3 section 2.15:
1211 // The bind clause specifies the name to use when calling the procedure on a
1212 // device other than the host. If the name is specified as an identifier, it
1213 // is called as if that name were specified in the language being compiled. If
1214 // the name is specified as a string, the string is used for the procedure
1215 // name unmodified.
1216 if (getCurToken().is(K: tok::r_paren)) {
1217 Diag(getCurToken(), diag::err_acc_incorrect_bind_arg);
1218 return ExprError();
1219 }
1220
1221 if (tok::isStringLiteral(K: getCurToken().getKind()))
1222 return getActions().CorrectDelayedTyposInExpr(ER: ParseStringLiteralExpression(
1223 /*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true));
1224
1225 return ParseOpenACCIDExpression();
1226}
1227
1228/// OpenACC 3.3, section 1.6:
1229/// In this spec, a 'var' (in italics) is one of the following:
1230/// - a variable name (a scalar, array, or compisite variable name)
1231/// - a subarray specification with subscript ranges
1232/// - an array element
1233/// - a member of a composite variable
1234/// - a common block name between slashes (fortran only)
1235bool Parser::ParseOpenACCVar() {
1236 OpenACCArraySectionRAII ArraySections(*this);
1237 ExprResult Res =
1238 getActions().CorrectDelayedTyposInExpr(ER: ParseAssignmentExpression());
1239 return Res.isInvalid();
1240}
1241
1242/// OpenACC 3.3, section 2.10:
1243/// In C and C++, the syntax of the cache directive is:
1244///
1245/// #pragma acc cache ([readonly:]var-list) new-line
1246void Parser::ParseOpenACCCacheVarList() {
1247 // If this is the end of the line, just return 'false' and count on the close
1248 // paren diagnostic to catch the issue.
1249 if (getCurToken().isAnnotation())
1250 return;
1251
1252 // The VarList is an optional `readonly:` followed by a list of a variable
1253 // specifications. Consume something that looks like a 'tag', and diagnose if
1254 // it isn't 'readonly'.
1255 if (tryParseAndConsumeSpecialTokenKind(P&: *this,
1256 Kind: OpenACCSpecialTokenKind::ReadOnly,
1257 DirOrClause: OpenACCDirectiveKind::Cache)) {
1258 // FIXME: Record that this is a 'readonly' so that we can use that during
1259 // Sema/AST generation.
1260 }
1261
1262 bool FirstArray = true;
1263 while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) {
1264 if (!FirstArray)
1265 ExpectAndConsume(ExpectedTok: tok::comma);
1266 FirstArray = false;
1267
1268 // OpenACC 3.3, section 2.10:
1269 // A 'var' in a cache directive must be a single array element or a simple
1270 // subarray. In C and C++, a simple subarray is an array name followed by
1271 // an extended array range specification in brackets, with a start and
1272 // length such as:
1273 //
1274 // arr[lower:length]
1275 //
1276 if (ParseOpenACCVar())
1277 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, T3: tok::comma,
1278 Flags: StopBeforeMatch);
1279 }
1280}
1281
1282Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() {
1283 SourceLocation StartLoc = getCurToken().getLocation();
1284 OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(P&: *this);
1285
1286 getActions().OpenACC().ActOnConstruct(K: DirKind, StartLoc);
1287
1288 // Once we've parsed the construct/directive name, some have additional
1289 // specifiers that need to be taken care of. Atomic has an 'atomic-clause'
1290 // that needs to be parsed.
1291 if (DirKind == OpenACCDirectiveKind::Atomic)
1292 ParseOpenACCAtomicKind(P&: *this);
1293
1294 // We've successfully parsed the construct/directive name, however a few of
1295 // the constructs have optional parens that contain further details.
1296 BalancedDelimiterTracker T(*this, tok::l_paren,
1297 tok::annot_pragma_openacc_end);
1298
1299 if (!T.consumeOpen()) {
1300 switch (DirKind) {
1301 default:
1302 Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
1303 T.skipToEnd();
1304 break;
1305 case OpenACCDirectiveKind::Routine: {
1306 // Routine has an optional paren-wrapped name of a function in the local
1307 // scope. We parse the name, emitting any diagnostics
1308 ExprResult RoutineName = ParseOpenACCIDExpression();
1309 // If the routine name is invalid, just skip until the closing paren to
1310 // recover more gracefully.
1311 if (RoutineName.isInvalid())
1312 T.skipToEnd();
1313 else
1314 T.consumeClose();
1315 break;
1316 }
1317 case OpenACCDirectiveKind::Cache:
1318 ParseOpenACCCacheVarList();
1319 // The ParseOpenACCCacheVarList function manages to recover from failures,
1320 // so we can always consume the close.
1321 T.consumeClose();
1322 break;
1323 case OpenACCDirectiveKind::Wait:
1324 // OpenACC has an optional paren-wrapped 'wait-argument'.
1325 if (ParseOpenACCWaitArgument(Loc: StartLoc, /*IsDirective=*/true))
1326 T.skipToEnd();
1327 else
1328 T.consumeClose();
1329 break;
1330 }
1331 } else if (DirKind == OpenACCDirectiveKind::Cache) {
1332 // Cache's paren var-list is required, so error here if it isn't provided.
1333 // We know that the consumeOpen above left the first non-paren here, so
1334 // diagnose, then continue as if it was completely omitted.
1335 Diag(Tok, diag::err_expected) << tok::l_paren;
1336 }
1337
1338 // Parses the list of clauses, if present, plus set up return value.
1339 OpenACCDirectiveParseInfo ParseInfo{.DirKind: DirKind, .StartLoc: StartLoc, .EndLoc: SourceLocation{},
1340 .Clauses: ParseOpenACCClauseList(DirKind)};
1341
1342 assert(Tok.is(tok::annot_pragma_openacc_end) &&
1343 "Didn't parse all OpenACC Clauses");
1344 ParseInfo.EndLoc = ConsumeAnnotationToken();
1345 assert(ParseInfo.EndLoc.isValid() &&
1346 "Terminating annotation token not present");
1347
1348 return ParseInfo;
1349}
1350
1351// Parse OpenACC directive on a declaration.
1352Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
1353 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
1354
1355 ParsingOpenACCDirectiveRAII DirScope(*this);
1356 ConsumeAnnotationToken();
1357
1358 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();
1359
1360 if (getActions().OpenACC().ActOnStartDeclDirective(K: DirInfo.DirKind,
1361 StartLoc: DirInfo.StartLoc))
1362 return nullptr;
1363
1364 // TODO OpenACC: Do whatever decl parsing is required here.
1365 return DeclGroupPtrTy::make(P: getActions().OpenACC().ActOnEndDeclDirective());
1366}
1367
1368// Parse OpenACC Directive on a Statement.
1369StmtResult Parser::ParseOpenACCDirectiveStmt() {
1370 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
1371
1372 ParsingOpenACCDirectiveRAII DirScope(*this);
1373 ConsumeAnnotationToken();
1374
1375 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();
1376 if (getActions().OpenACC().ActOnStartStmtDirective(K: DirInfo.DirKind,
1377 StartLoc: DirInfo.StartLoc))
1378 return StmtError();
1379
1380 StmtResult AssocStmt;
1381
1382 if (doesDirectiveHaveAssociatedStmt(DirKind: DirInfo.DirKind)) {
1383 ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
1384 ParseScope ACCScope(this, getOpenACCScopeFlags(DirKind: DirInfo.DirKind));
1385
1386 AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(K: DirInfo.DirKind,
1387 AssocStmt: ParseStatement());
1388 }
1389
1390 return getActions().OpenACC().ActOnEndStmtDirective(
1391 K: DirInfo.DirKind, StartLoc: DirInfo.StartLoc, EndLoc: DirInfo.EndLoc, Clauses: DirInfo.Clauses,
1392 AssocStmt);
1393}
1394

source code of clang/lib/Parse/ParseOpenACC.cpp