clang 20.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 case OpenACCDirectiveKind::Loop:
575 return true;
576 }
577 llvm_unreachable("Unhandled directive->assoc stmt");
578}
579
580unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {
581 switch (DirKind) {
582 case OpenACCDirectiveKind::Parallel:
583 case OpenACCDirectiveKind::Serial:
584 case OpenACCDirectiveKind::Kernels:
585 // Mark this as a BreakScope/ContinueScope as well as a compute construct
586 // so that we can diagnose trying to 'break'/'continue' inside of one.
589 case OpenACCDirectiveKind::Invalid:
590 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");
591 default:
592 break;
593 }
594 return 0;
595}
596
597} // namespace
598
599Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() {
600 return {nullptr, OpenACCParseCanContinue::Can};
601}
602
603Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() {
604 return {nullptr, OpenACCParseCanContinue::Cannot};
605}
606
607Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) {
608 return {Clause, OpenACCParseCanContinue::Can};
609}
610
611ExprResult Parser::ParseOpenACCConditionExpr() {
612 // FIXME: It isn't clear if the spec saying 'condition' means the same as
613 // it does in an if/while/etc (See ParseCXXCondition), however as it was
614 // written with Fortran/C in mind, we're going to assume it just means an
615 // 'expression evaluating to boolean'.
617
618 if (!ER.isUsable())
619 return ER;
620
624
625 return R.isInvalid() ? ExprError() : R.get().second;
626}
627
628// OpenACC 3.3, section 1.7:
629// To simplify the specification and convey appropriate constraint information,
630// a pqr-list is a comma-separated list of pdr items. The one exception is a
631// clause-list, which is a list of one or more clauses optionally separated by
632// commas.
634Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {
636 bool FirstClause = true;
637 while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {
638 // Comma is optional in a clause-list.
639 if (!FirstClause && getCurToken().is(tok::comma))
640 ConsumeToken();
641 FirstClause = false;
642
643 OpenACCClauseParseResult Result = ParseOpenACCClause(Clauses, DirKind);
644 if (OpenACCClause *Clause = Result.getPointer()) {
645 Clauses.push_back(Clause);
646 } else if (Result.getInt() == OpenACCParseCanContinue::Cannot) {
647 // Recovering from a bad clause is really difficult, so we just give up on
648 // error.
649 SkipUntilEndOfDirective(*this);
650 return Clauses;
651 }
652 }
653 return Clauses;
654}
655
656Parser::OpenACCIntExprParseResult
657Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
660
661 // If the actual parsing failed, we don't know the state of the parse, so
662 // don't try to continue.
663 if (!ER.isUsable())
664 return {ER, OpenACCParseCanContinue::Cannot};
665
666 // Parsing can continue after the initial assignment expression parsing, so
667 // even if there was a typo, we can continue.
669 if (!ER.isUsable())
670 return {ER, OpenACCParseCanContinue::Can};
671
672 return {getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, ER.get()),
673 OpenACCParseCanContinue::Can};
674}
675
676bool Parser::ParseOpenACCIntExprList(OpenACCDirectiveKind DK,
679 OpenACCIntExprParseResult CurResult = ParseOpenACCIntExpr(DK, CK, Loc);
680
681 if (!CurResult.first.isUsable() &&
682 CurResult.second == OpenACCParseCanContinue::Cannot) {
683 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
685 return true;
686 }
687
688 IntExprs.push_back(CurResult.first.get());
689
690 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
691 ExpectAndConsume(tok::comma);
692
693 CurResult = ParseOpenACCIntExpr(DK, CK, Loc);
694
695 if (!CurResult.first.isUsable() &&
696 CurResult.second == OpenACCParseCanContinue::Cannot) {
697 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
699 return true;
700 }
701 IntExprs.push_back(CurResult.first.get());
702 }
703 return false;
704}
705
706/// OpenACC 3.3 Section 2.4:
707/// The argument to the device_type clause is a comma-separated list of one or
708/// more device architecture name identifiers, or an asterisk.
709///
710/// The syntax of the device_type clause is
711/// device_type( * )
712/// device_type( device-type-list )
713///
714/// The device_type clause may be abbreviated to dtype.
715bool Parser::ParseOpenACCDeviceTypeList(
716 llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>> &Archs) {
717
718 if (expectIdentifierOrKeyword(*this)) {
719 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
721 return true;
722 }
724 Archs.emplace_back(Ident, ConsumeToken());
725
726 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
727 ExpectAndConsume(tok::comma);
728
729 if (expectIdentifierOrKeyword(*this)) {
730 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
732 return true;
733 }
734 Ident = getCurToken().getIdentifierInfo();
735 Archs.emplace_back(Ident, ConsumeToken());
736 }
737 return false;
738}
739
740/// OpenACC 3.3 Section 2.9:
741/// size-expr is one of:
742// *
743// int-expr
744// Note that this is specified under 'gang-arg-list', but also applies to 'tile'
745// via reference.
746bool Parser::ParseOpenACCSizeExpr() {
747 // FIXME: Ensure these are constant expressions.
748
749 // The size-expr ends up being ambiguous when only looking at the current
750 // token, as it could be a deref of a variable/expression.
751 if (getCurToken().is(tok::star) &&
752 NextToken().isOneOf(tok::comma, tok::r_paren,
753 tok::annot_pragma_openacc_end)) {
754 ConsumeToken();
755 return false;
756 }
757
758 return getActions()
760 .isInvalid();
761}
762
763bool Parser::ParseOpenACCSizeExprList() {
764 if (ParseOpenACCSizeExpr()) {
765 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
767 return false;
768 }
769
770 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
771 ExpectAndConsume(tok::comma);
772
773 if (ParseOpenACCSizeExpr()) {
774 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
776 return false;
777 }
778 }
779 return false;
780}
781
782/// OpenACC 3.3 Section 2.9:
783///
784/// where gang-arg is one of:
785/// [num:]int-expr
786/// dim:int-expr
787/// static:size-expr
788bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
789
790 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Static, getCurToken()) &&
791 NextToken().is(tok::colon)) {
792 // 'static' just takes a size-expr, which is an int-expr or an asterisk.
793 ConsumeToken();
794 ConsumeToken();
795 return ParseOpenACCSizeExpr();
796 }
797
798 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Dim, getCurToken()) &&
799 NextToken().is(tok::colon)) {
800 ConsumeToken();
801 ConsumeToken();
802 return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
804 .first.isInvalid();
805 }
806
807 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) &&
808 NextToken().is(tok::colon)) {
809 ConsumeToken();
810 ConsumeToken();
811 // Fallthrough to the 'int-expr' handling for when 'num' is omitted.
812 }
813 // This is just the 'num' case where 'num' is optional.
814 return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
816 .first.isInvalid();
817}
818
819bool Parser::ParseOpenACCGangArgList(SourceLocation GangLoc) {
820 if (ParseOpenACCGangArg(GangLoc)) {
821 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
823 return false;
824 }
825
826 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
827 ExpectAndConsume(tok::comma);
828
829 if (ParseOpenACCGangArg(GangLoc)) {
830 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
832 return false;
833 }
834 }
835 return false;
836}
837
838// The OpenACC Clause List is a comma or space-delimited list of clauses (see
839// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
840// really have its owner grammar and each individual one has its own definition.
841// However, they all are named with a single-identifier (or auto/default!)
842// token, followed in some cases by either braces or parens.
843Parser::OpenACCClauseParseResult
844Parser::ParseOpenACCClause(ArrayRef<const OpenACCClause *> ExistingClauses,
845 OpenACCDirectiveKind DirKind) {
846 // A number of clause names are actually keywords, so accept a keyword that
847 // can be converted to a name.
848 if (expectIdentifierOrKeyword(*this))
849 return OpenACCCannotContinue();
850
851 OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken());
852
853 if (Kind == OpenACCClauseKind::Invalid) {
854 Diag(getCurToken(), diag::err_acc_invalid_clause)
856 return OpenACCCannotContinue();
857 }
858
859 // Consume the clause name.
860 SourceLocation ClauseLoc = ConsumeToken();
861
862 return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc);
863}
864
865Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
866 ArrayRef<const OpenACCClause *> ExistingClauses,
867 OpenACCDirectiveKind DirKind, OpenACCClauseKind ClauseKind,
868 SourceLocation ClauseLoc) {
869 BalancedDelimiterTracker Parens(*this, tok::l_paren,
870 tok::annot_pragma_openacc_end);
871 SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);
872
873 if (ClauseHasRequiredParens(DirKind, ClauseKind)) {
874 if (Parens.expectAndConsume()) {
875 // We are missing a paren, so assume that the person just forgot the
876 // parameter. Return 'false' so we try to continue on and parse the next
877 // clause.
878 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
880 return OpenACCCanContinue();
881 }
882 ParsedClause.setLParenLoc(Parens.getOpenLocation());
883
884 switch (ClauseKind) {
886 Token DefKindTok = getCurToken();
887
888 if (expectIdentifierOrKeyword(*this)) {
889 Parens.skipToEnd();
890 return OpenACCCanContinue();
891 }
892
893 ConsumeToken();
894
896 getOpenACCDefaultClauseKind(DefKindTok);
897
898 if (DefKind == OpenACCDefaultClauseKind::Invalid) {
899 Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
900 Parens.skipToEnd();
901 return OpenACCCanContinue();
902 }
903
904 ParsedClause.setDefaultDetails(DefKind);
905 break;
906 }
908 ExprResult CondExpr = ParseOpenACCConditionExpr();
909 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()
910 : nullptr);
911
912 if (CondExpr.isInvalid()) {
913 Parens.skipToEnd();
914 return OpenACCCanContinue();
915 }
916
917 break;
918 }
922 bool IsReadOnly = tryParseAndConsumeSpecialTokenKind(
923 *this, OpenACCSpecialTokenKind::ReadOnly, ClauseKind);
924 ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),
925 IsReadOnly,
926 /*IsZero=*/false);
927 break;
928 }
935 bool IsZero = tryParseAndConsumeSpecialTokenKind(
936 *this, OpenACCSpecialTokenKind::Zero, ClauseKind);
937 ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),
938 /*IsReadOnly=*/false, IsZero);
939 break;
940 }
942 // If we're missing a clause-kind (or it is invalid), see if we can parse
943 // the var-list anyway.
944 OpenACCReductionOperator Op = ParseReductionOperator(*this);
945 ParsedClause.setReductionDetails(Op, ParseOpenACCVarList(ClauseKind));
946 break;
947 }
949 // The 'self' clause is a var-list instead of a 'condition' in the case of
950 // the 'update' clause, so we have to handle it here. U se an assert to
951 // make sure we get the right differentiator.
952 assert(DirKind == OpenACCDirectiveKind::Update);
953 [[fallthrough]];
961 ParseOpenACCVarList(ClauseKind);
962 break;
965 ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),
966 /*IsReadOnly=*/false, /*IsZero=*/false);
967 break;
975 ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),
976 /*IsReadOnly=*/false, /*IsZero=*/false);
977 break;
979 tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Force,
980 ClauseKind);
981 ExprResult NumLoops =
983 if (NumLoops.isInvalid()) {
984 Parens.skipToEnd();
985 return OpenACCCanContinue();
986 }
987 break;
988 }
990 ExprResult BindArg = ParseOpenACCBindClauseArgument();
991 if (BindArg.isInvalid()) {
992 Parens.skipToEnd();
993 return OpenACCCanContinue();
994 }
995 break;
996 }
999
1000 if (ParseOpenACCIntExprList(OpenACCDirectiveKind::Invalid,
1001 OpenACCClauseKind::NumGangs, ClauseLoc,
1002 IntExprs)) {
1003 Parens.skipToEnd();
1004 return OpenACCCanContinue();
1005 }
1006 ParsedClause.setIntExprDetails(std::move(IntExprs));
1007 break;
1008 }
1013 ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
1014 ClauseKind, ClauseLoc)
1015 .first;
1016 if (IntExpr.isInvalid()) {
1017 Parens.skipToEnd();
1018 return OpenACCCanContinue();
1019 }
1020
1021 // TODO OpenACC: as we implement the 'rest' of the above, this 'if' should
1022 // be removed leaving just the 'setIntExprDetails'.
1023 if (ClauseKind == OpenACCClauseKind::NumWorkers ||
1024 ClauseKind == OpenACCClauseKind::VectorLength)
1025 ParsedClause.setIntExprDetails(IntExpr.get());
1026
1027 break;
1028 }
1032 if (getCurToken().is(tok::star)) {
1033 // FIXME: We want to mark that this is an 'everything else' type of
1034 // device_type in Sema.
1035 ParsedClause.setDeviceTypeDetails({{nullptr, ConsumeToken()}});
1036 } else if (!ParseOpenACCDeviceTypeList(Archs)) {
1037 ParsedClause.setDeviceTypeDetails(std::move(Archs));
1038 } else {
1039 Parens.skipToEnd();
1040 return OpenACCCanContinue();
1041 }
1042 break;
1043 }
1045 if (ParseOpenACCSizeExprList()) {
1046 Parens.skipToEnd();
1047 return OpenACCCanContinue();
1048 }
1049 break;
1050 default:
1051 llvm_unreachable("Not a required parens type?");
1052 }
1053
1054 ParsedClause.setEndLoc(getCurToken().getLocation());
1055
1056 if (Parens.consumeClose())
1057 return OpenACCCannotContinue();
1058
1059 } else if (ClauseHasOptionalParens(DirKind, ClauseKind)) {
1060 if (!Parens.consumeOpen()) {
1061 ParsedClause.setLParenLoc(Parens.getOpenLocation());
1062 switch (ClauseKind) {
1064 assert(DirKind != OpenACCDirectiveKind::Update);
1065 ExprResult CondExpr = ParseOpenACCConditionExpr();
1066 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()
1067 : nullptr);
1068
1069 if (CondExpr.isInvalid()) {
1070 Parens.skipToEnd();
1071 return OpenACCCanContinue();
1072 }
1073 break;
1074 }
1077 tryParseAndConsumeSpecialTokenKind(*this,
1078 ClauseKind ==
1080 ? OpenACCSpecialTokenKind::Length
1081 : OpenACCSpecialTokenKind::Num,
1082 ClauseKind);
1083 ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
1084 ClauseKind, ClauseLoc)
1085 .first;
1086 if (IntExpr.isInvalid()) {
1087 Parens.skipToEnd();
1088 return OpenACCCanContinue();
1089 }
1090 break;
1091 }
1093 ExprResult AsyncArg =
1094 ParseOpenACCAsyncArgument(OpenACCDirectiveKind::Invalid,
1095 OpenACCClauseKind::Async, ClauseLoc)
1096 .first;
1097 ParsedClause.setIntExprDetails(AsyncArg.isUsable() ? AsyncArg.get()
1098 : nullptr);
1099 if (AsyncArg.isInvalid()) {
1100 Parens.skipToEnd();
1101 return OpenACCCanContinue();
1102 }
1103 break;
1104 }
1106 if (ParseOpenACCGangArgList(ClauseLoc)) {
1107 Parens.skipToEnd();
1108 return OpenACCCanContinue();
1109 }
1110 break;
1112 OpenACCWaitParseInfo Info =
1113 ParseOpenACCWaitArgument(ClauseLoc,
1114 /*IsDirective=*/false);
1115 if (Info.Failed) {
1116 Parens.skipToEnd();
1117 return OpenACCCanContinue();
1118 }
1119
1120 ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc,
1121 std::move(Info.QueueIdExprs));
1122 break;
1123 }
1124 default:
1125 llvm_unreachable("Not an optional parens type?");
1126 }
1127 ParsedClause.setEndLoc(getCurToken().getLocation());
1128 if (Parens.consumeClose())
1129 return OpenACCCannotContinue();
1130 } else {
1131 // If we have optional parens, make sure we set the end-location to the
1132 // clause, as we are a 'single token' clause.
1133 ParsedClause.setEndLoc(ClauseLoc);
1134 }
1135 } else {
1136 ParsedClause.setEndLoc(ClauseLoc);
1137 }
1138 return OpenACCSuccess(
1139 Actions.OpenACC().ActOnClause(ExistingClauses, ParsedClause));
1140}
1141
1142/// OpenACC 3.3 section 2.16:
1143/// In this section and throughout the specification, the term async-argument
1144/// means a nonnegative scalar integer expression (int for C or C++, integer for
1145/// Fortran), or one of the special values acc_async_noval or acc_async_sync, as
1146/// defined in the C header file and the Fortran openacc module. The special
1147/// values are negative values, so as not to conflict with a user-specified
1148/// nonnegative async-argument.
1149Parser::OpenACCIntExprParseResult
1150Parser::ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
1152 return ParseOpenACCIntExpr(DK, CK, Loc);
1153}
1154
1155/// OpenACC 3.3, section 2.16:
1156/// In this section and throughout the specification, the term wait-argument
1157/// means:
1158/// [ devnum : int-expr : ] [ queues : ] async-argument-list
1159Parser::OpenACCWaitParseInfo
1160Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
1161 OpenACCWaitParseInfo Result;
1162 // [devnum : int-expr : ]
1163 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
1164 NextToken().is(tok::colon)) {
1165 // Consume devnum.
1166 ConsumeToken();
1167 // Consume colon.
1168 ConsumeToken();
1169
1170 OpenACCIntExprParseResult Res = ParseOpenACCIntExpr(
1171 IsDirective ? OpenACCDirectiveKind::Wait
1174 Loc);
1175 if (Res.first.isInvalid() &&
1176 Res.second == OpenACCParseCanContinue::Cannot) {
1177 Result.Failed = true;
1178 return Result;
1179 }
1180
1181 if (ExpectAndConsume(tok::colon)) {
1182 Result.Failed = true;
1183 return Result;
1184 }
1185
1186 Result.DevNumExpr = Res.first.get();
1187 }
1188
1189 // [ queues : ]
1190 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
1191 NextToken().is(tok::colon)) {
1192 // Consume queues.
1193 Result.QueuesLoc = ConsumeToken();
1194 // Consume colon.
1195 ConsumeToken();
1196 }
1197
1198 // OpenACC 3.3, section 2.16:
1199 // the term 'async-argument' means a nonnegative scalar integer expression, or
1200 // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
1201 // in the C header file and the Fortran opacc module.
1202 bool FirstArg = true;
1203 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
1204 if (!FirstArg) {
1205 if (ExpectAndConsume(tok::comma)) {
1206 Result.Failed = true;
1207 return Result;
1208 }
1209 }
1210 FirstArg = false;
1211
1212 OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(
1213 IsDirective ? OpenACCDirectiveKind::Wait
1216 Loc);
1217
1218 if (Res.first.isInvalid() &&
1219 Res.second == OpenACCParseCanContinue::Cannot) {
1220 Result.Failed = true;
1221 return Result;
1222 }
1223
1224 Result.QueueIdExprs.push_back(Res.first.get());
1225 }
1226
1227 return Result;
1228}
1229
1230ExprResult Parser::ParseOpenACCIDExpression() {
1231 ExprResult Res;
1232 if (getLangOpts().CPlusPlus) {
1233 Res = ParseCXXIdExpression(/*isAddressOfOperand=*/true);
1234 } else {
1235 // There isn't anything quite the same as ParseCXXIdExpression for C, so we
1236 // need to get the identifier, then call into Sema ourselves.
1237
1238 if (Tok.isNot(tok::identifier)) {
1239 Diag(Tok, diag::err_expected) << tok::identifier;
1240 return ExprError();
1241 }
1242
1243 Token FuncName = getCurToken();
1244 UnqualifiedId Name;
1245 CXXScopeSpec ScopeSpec;
1246 SourceLocation TemplateKWLoc;
1247 Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());
1248
1249 // Ensure this is a valid identifier. We don't accept causing implicit
1250 // function declarations per the spec, so always claim to not have trailing
1251 // L Paren.
1252 Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
1253 Name, /*HasTrailingLParen=*/false,
1254 /*isAddressOfOperand=*/false);
1255 }
1256
1258}
1259
1260ExprResult Parser::ParseOpenACCBindClauseArgument() {
1261 // OpenACC 3.3 section 2.15:
1262 // The bind clause specifies the name to use when calling the procedure on a
1263 // device other than the host. If the name is specified as an identifier, it
1264 // is called as if that name were specified in the language being compiled. If
1265 // the name is specified as a string, the string is used for the procedure
1266 // name unmodified.
1267 if (getCurToken().is(tok::r_paren)) {
1268 Diag(getCurToken(), diag::err_acc_incorrect_bind_arg);
1269 return ExprError();
1270 }
1271
1274 /*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true));
1275
1276 return ParseOpenACCIDExpression();
1277}
1278
1279/// OpenACC 3.3, section 1.6:
1280/// In this spec, a 'var' (in italics) is one of the following:
1281/// - a variable name (a scalar, array, or composite variable name)
1282/// - a subarray specification with subscript ranges
1283/// - an array element
1284/// - a member of a composite variable
1285/// - a common block name between slashes (fortran only)
1286Parser::OpenACCVarParseResult Parser::ParseOpenACCVar(OpenACCClauseKind CK) {
1287 OpenACCArraySectionRAII ArraySections(*this);
1288
1290 if (!Res.isUsable())
1291 return {Res, OpenACCParseCanContinue::Cannot};
1292
1294 if (!Res.isUsable())
1295 return {Res, OpenACCParseCanContinue::Can};
1296
1297 Res = getActions().OpenACC().ActOnVar(CK, Res.get());
1298
1299 return {Res, OpenACCParseCanContinue::Can};
1300}
1301
1302llvm::SmallVector<Expr *> Parser::ParseOpenACCVarList(OpenACCClauseKind CK) {
1304
1305 auto [Res, CanContinue] = ParseOpenACCVar(CK);
1306 if (Res.isUsable()) {
1307 Vars.push_back(Res.get());
1308 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {
1309 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, StopBeforeMatch);
1310 return Vars;
1311 }
1312
1313 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
1314 ExpectAndConsume(tok::comma);
1315
1316 auto [Res, CanContinue] = ParseOpenACCVar(CK);
1317
1318 if (Res.isUsable()) {
1319 Vars.push_back(Res.get());
1320 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {
1321 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, StopBeforeMatch);
1322 return Vars;
1323 }
1324 }
1325 return Vars;
1326}
1327
1328/// OpenACC 3.3, section 2.10:
1329/// In C and C++, the syntax of the cache directive is:
1330///
1331/// #pragma acc cache ([readonly:]var-list) new-line
1332void Parser::ParseOpenACCCacheVarList() {
1333 // If this is the end of the line, just return 'false' and count on the close
1334 // paren diagnostic to catch the issue.
1335 if (getCurToken().isAnnotation())
1336 return;
1337
1338 // The VarList is an optional `readonly:` followed by a list of a variable
1339 // specifications. Consume something that looks like a 'tag', and diagnose if
1340 // it isn't 'readonly'.
1341 if (tryParseAndConsumeSpecialTokenKind(*this,
1342 OpenACCSpecialTokenKind::ReadOnly,
1344 // FIXME: Record that this is a 'readonly' so that we can use that during
1345 // Sema/AST generation.
1346 }
1347
1348 // ParseOpenACCVarList should leave us before a r-paren, so no need to skip
1349 // anything here.
1350 ParseOpenACCVarList(OpenACCClauseKind::Invalid);
1351}
1352
1353Parser::OpenACCDirectiveParseInfo
1354Parser::ParseOpenACCDirective() {
1355 SourceLocation StartLoc = ConsumeAnnotationToken();
1357 OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);
1358
1359 getActions().OpenACC().ActOnConstruct(DirKind, DirLoc);
1360
1361 // Once we've parsed the construct/directive name, some have additional
1362 // specifiers that need to be taken care of. Atomic has an 'atomic-clause'
1363 // that needs to be parsed.
1364 if (DirKind == OpenACCDirectiveKind::Atomic)
1365 ParseOpenACCAtomicKind(*this);
1366
1367 // We've successfully parsed the construct/directive name, however a few of
1368 // the constructs have optional parens that contain further details.
1369 BalancedDelimiterTracker T(*this, tok::l_paren,
1370 tok::annot_pragma_openacc_end);
1371
1372 if (!T.consumeOpen()) {
1373 switch (DirKind) {
1374 default:
1375 Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
1376 T.skipToEnd();
1377 break;
1379 // Routine has an optional paren-wrapped name of a function in the local
1380 // scope. We parse the name, emitting any diagnostics
1381 ExprResult RoutineName = ParseOpenACCIDExpression();
1382 // If the routine name is invalid, just skip until the closing paren to
1383 // recover more gracefully.
1384 if (RoutineName.isInvalid())
1385 T.skipToEnd();
1386 else
1387 T.consumeClose();
1388 break;
1389 }
1391 ParseOpenACCCacheVarList();
1392 // The ParseOpenACCCacheVarList function manages to recover from failures,
1393 // so we can always consume the close.
1394 T.consumeClose();
1395 break;
1397 // OpenACC has an optional paren-wrapped 'wait-argument'.
1398 if (ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true).Failed)
1399 T.skipToEnd();
1400 else
1401 T.consumeClose();
1402 break;
1403 }
1404 } else if (DirKind == OpenACCDirectiveKind::Cache) {
1405 // Cache's paren var-list is required, so error here if it isn't provided.
1406 // We know that the consumeOpen above left the first non-paren here, so
1407 // diagnose, then continue as if it was completely omitted.
1408 Diag(Tok, diag::err_expected) << tok::l_paren;
1409 }
1410
1411 // Parses the list of clauses, if present, plus set up return value.
1412 OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, DirLoc,
1414 ParseOpenACCClauseList(DirKind)};
1415
1416 assert(Tok.is(tok::annot_pragma_openacc_end) &&
1417 "Didn't parse all OpenACC Clauses");
1418 ParseInfo.EndLoc = ConsumeAnnotationToken();
1419 assert(ParseInfo.EndLoc.isValid() &&
1420 "Terminating annotation token not present");
1421
1422 return ParseInfo;
1423}
1424
1425// Parse OpenACC directive on a declaration.
1427 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
1428
1429 ParsingOpenACCDirectiveRAII DirScope(*this);
1430
1431 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();
1432
1433 if (getActions().OpenACC().ActOnStartDeclDirective(DirInfo.DirKind,
1434 DirInfo.StartLoc))
1435 return nullptr;
1436
1437 // TODO OpenACC: Do whatever decl parsing is required here.
1438 return DeclGroupPtrTy::make(getActions().OpenACC().ActOnEndDeclDirective());
1439}
1440
1441// Parse OpenACC Directive on a Statement.
1443 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
1444
1445 ParsingOpenACCDirectiveRAII DirScope(*this);
1446
1447 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();
1448 if (getActions().OpenACC().ActOnStartStmtDirective(DirInfo.DirKind,
1449 DirInfo.StartLoc))
1450 return StmtError();
1451
1452 StmtResult AssocStmt;
1453 SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getActions().OpenACC(),
1454 DirInfo.DirKind);
1455 if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) {
1456 ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
1457 ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));
1458
1459 AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(
1460 DirInfo.StartLoc, DirInfo.DirKind, ParseStatement());
1461 }
1462
1464 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.EndLoc,
1465 DirInfo.Clauses, AssocStmt);
1466}
StringRef P
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:1152
Defines some OpenACC-specific enums and functions.
static constexpr bool isOneOf()
SourceLocation Loc
Definition: SemaObjC.cpp:758
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:1172
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:549
DeclGroupPtrTy ParseOpenACCDirectiveDecl()
Placeholder for now, should just ignore the directives after emitting a diagnostic.
Sema & getActions() const
Definition: Parser.h:499
ExprResult ParseConstantExpression()
Definition: ParseExpr.cpp:233
StmtResult ParseOpenACCDirectiveStmt()
Scope * getCurScope() const
Definition: Parser.h:503
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:1295
const Token & getCurToken() const
Definition: Parser.h:502
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:496
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:1276
ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral=false)
const Token & NextToken()
NextToken - This peeks ahead one token and returns it without consuming it.
Definition: Parser.h:873
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
Helper type for the registration/assignment of constructs that need to 'know' about their parent cons...
Definition: SemaOpenACC.h:449
A type to represent all the data for an OpenACC Clause that has been parsed, but not yet created/sema...
Definition: SemaOpenACC.h:46
void setLParenLoc(SourceLocation EndLoc)
Definition: SemaOpenACC.h:250
void setConditionDetails(Expr *ConditionExpr)
Definition: SemaOpenACC.h:259
void setReductionDetails(OpenACCReductionOperator Op, llvm::SmallVector< Expr * > &&VarList)
Definition: SemaOpenACC.h:361
void setDefaultDetails(OpenACCDefaultClauseKind DefKind)
Definition: SemaOpenACC.h:253
void setVarListDetails(ArrayRef< Expr * > VarList, bool IsReadOnly, bool IsZero)
Definition: SemaOpenACC.h:290
void setWaitDetails(Expr *DevNum, SourceLocation QueuesLoc, llvm::SmallVector< Expr * > &&IntExprs)
Definition: SemaOpenACC.h:368
void setEndLoc(SourceLocation EndLoc)
Definition: SemaOpenACC.h:251
void setIntExprDetails(ArrayRef< Expr * > IntExprs)
Definition: SemaOpenACC.h:273
void setDeviceTypeDetails(llvm::SmallVector< DeviceTypeArgument > &&Archs)
Definition: SemaOpenACC.h:375
ExprResult ActOnVar(OpenACCClauseKind CK, 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'.
OpenACCClause * ActOnClause(ArrayRef< const OpenACCClause * > ExistingClauses, OpenACCParsedClause &Clause)
Called after parsing an OpenACC Clause so that it can be checked.
StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc, OpenACCDirectiveKind K, StmtResult AssocStmt)
Called when we encounter an associated statement for our construct, this should check legality of the...
StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef< OpenACCClause * > Clauses, StmtResult AssocStmt)
Called after the directive has been completely parsed, including the declaration group or associated ...
void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation DirLoc)
Called after the construct has been parsed, but clauses haven't been parsed.
bool isInvalid() const
Definition: Sema.h:7335
@ 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:2650
ConditionResult ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, ConditionKind CK, bool MissingOK=false)
Definition: SemaExpr.cpp:20141
SemaOpenACC & OpenACC()
Definition: Sema.h:1209
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:2204
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:56
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