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