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