clang: lib/Parse/ParseOpenACC.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/StringSwitch.h"
21
22using namespace clang;
23using namespace llvm;
24
25namespace {
26
27
28
29enum class OpenACCDirectiveKindEx {
30 Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
31
32 Enter,
33 Exit,
34};
35
36
37
38
39
40
41OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
42 if (!Tok.is(tok::identifier))
43 return OpenACCDirectiveKindEx::Invalid;
45 llvm::StringSwitch(
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(
69 .Case("enter", OpenACCDirectiveKindEx::Enter)
70 .Case("exit", OpenACCDirectiveKindEx::Exit)
71 .Default(OpenACCDirectiveKindEx::Invalid);
72}
73
74
76
77
78 if (Tok.is(tok::kw_auto))
79 return OpenACCClauseKind::Auto;
80
81
82 if (Tok.is(tok::kw_default))
83 return OpenACCClauseKind::Default;
84
85
86 if (Tok.is(tok::kw_if))
87 return OpenACCClauseKind::If;
88
89
90 if (Tok.is(tok::kw_private))
91 return OpenACCClauseKind::Private;
92
93
94 if (Tok.is(tok::kw_delete))
95 return OpenACCClauseKind::Delete;
96
97 if (!Tok.is(tok::identifier))
98 return OpenACCClauseKind::Invalid;
99
100 return llvm::StringSwitch(
102 .Case("async", OpenACCClauseKind::Async)
103 .Case("attach", OpenACCClauseKind::Attach)
104 .Case("auto", OpenACCClauseKind::Auto)
105 .Case("bind", OpenACCClauseKind::Bind)
106 .Case("create", OpenACCClauseKind::Create)
107 .Case("pcreate", OpenACCClauseKind::PCreate)
108 .Case("present_or_create", OpenACCClauseKind::PresentOrCreate)
109 .Case("collapse", OpenACCClauseKind::Collapse)
110 .Case("copy", OpenACCClauseKind::Copy)
111 .Case("pcopy", OpenACCClauseKind::PCopy)
112 .Case("present_or_copy", OpenACCClauseKind::PresentOrCopy)
113 .Case("copyin", OpenACCClauseKind::CopyIn)
114 .Case("pcopyin", OpenACCClauseKind::PCopyIn)
115 .Case("present_or_copyin", OpenACCClauseKind::PresentOrCopyIn)
116 .Case("copyout", OpenACCClauseKind::CopyOut)
117 .Case("pcopyout", OpenACCClauseKind::PCopyOut)
118 .Case("present_or_copyout", OpenACCClauseKind::PresentOrCopyOut)
119 .Case("default", OpenACCClauseKind::Default)
120 .Case("default_async", OpenACCClauseKind::DefaultAsync)
121 .Case("delete", OpenACCClauseKind::Delete)
122 .Case("detach", OpenACCClauseKind::Detach)
123 .Case("device", OpenACCClauseKind::Device)
124 .Case("device_num", OpenACCClauseKind::DeviceNum)
125 .Case("device_resident", OpenACCClauseKind::DeviceResident)
126 .Case("device_type", OpenACCClauseKind::DeviceType)
127 .Case("deviceptr", OpenACCClauseKind::DevicePtr)
128 .Case("dtype", OpenACCClauseKind::DType)
129 .Case("finalize", OpenACCClauseKind::Finalize)
130 .Case("firstprivate", OpenACCClauseKind::FirstPrivate)
131 .Case("gang", OpenACCClauseKind::Gang)
132 .Case("host", OpenACCClauseKind::Host)
133 .Case("if", OpenACCClauseKind::If)
134 .Case("if_present", OpenACCClauseKind::IfPresent)
135 .Case("independent", OpenACCClauseKind::Independent)
136 .Case("link", OpenACCClauseKind::Link)
137 .Case("no_create", OpenACCClauseKind::NoCreate)
138 .Case("num_gangs", OpenACCClauseKind::NumGangs)
139 .Case("num_workers", OpenACCClauseKind::NumWorkers)
140 .Case("nohost", OpenACCClauseKind::NoHost)
141 .Case("present", OpenACCClauseKind::Present)
142 .Case("private", OpenACCClauseKind::Private)
143 .Case("reduction", OpenACCClauseKind::Reduction)
144 .Case("self", OpenACCClauseKind::Self)
145 .Case("seq", OpenACCClauseKind::Seq)
146 .Case("tile", OpenACCClauseKind::Tile)
147 .Case("use_device", OpenACCClauseKind::UseDevice)
148 .Case("vector", OpenACCClauseKind::Vector)
149 .Case("vector_length", OpenACCClauseKind::VectorLength)
150 .Case("wait", OpenACCClauseKind::Wait)
151 .Case("worker", OpenACCClauseKind::Worker)
152 .Default(OpenACCClauseKind::Invalid);
153}
154
155
156
158 if (!Tok.is(tok::identifier))
159 return OpenACCAtomicKind::Invalid;
160 return llvm::StringSwitch(
162 .Case("read", OpenACCAtomicKind::Read)
163 .Case("write", OpenACCAtomicKind::Write)
164 .Case("update", OpenACCAtomicKind::Update)
165 .Case("capture", OpenACCAtomicKind::Capture)
166 .Default(OpenACCAtomicKind::Invalid);
167}
168
170 if (!Tok.is(tok::identifier))
171 return OpenACCDefaultClauseKind::Invalid;
172
173 return llvm::StringSwitch(
175 .Case("none", OpenACCDefaultClauseKind::None)
176 .Case("present", OpenACCDefaultClauseKind::Present)
177 .Default(OpenACCDefaultClauseKind::Invalid);
178}
179
180enum class OpenACCSpecialTokenKind {
181 ReadOnly,
182 DevNum,
183 Queues,
185 Force,
187 Length,
190};
191
192bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
193 if (Tok.is(tok::kw_static) && Kind == OpenACCSpecialTokenKind::Static)
194 return true;
195
196 if (!Tok.is(tok::identifier))
197 return false;
198
199 switch (Kind) {
200 case OpenACCSpecialTokenKind::ReadOnly:
202 case OpenACCSpecialTokenKind::DevNum:
204 case OpenACCSpecialTokenKind::Queues:
206 case OpenACCSpecialTokenKind::Zero:
208 case OpenACCSpecialTokenKind::Force:
210 case OpenACCSpecialTokenKind::Num:
212 case OpenACCSpecialTokenKind::Length:
214 case OpenACCSpecialTokenKind::Dim:
216 case OpenACCSpecialTokenKind::Static:
218 }
219 llvm_unreachable("Unknown 'Kind' Passed");
220}
221
222
223
224
225bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) {
226 if (Tok.is(tok::identifier))
227 return true;
228
231 return true;
232
233 return false;
234}
235
236
237
238
239
240
241template
242bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind,
243 DirOrClauseTy DirOrClause) {
244 Token IdentTok = P.getCurToken();
245
246
247 if (isTokenIdentifierOrKeyword(P, IdentTok) && P.NextToken().is(tok::colon)) {
248 P.ConsumeToken();
249 P.ConsumeToken();
250
251 if (!isOpenACCSpecialToken(Kind, IdentTok)) {
252 P.Diag(IdentTok, diag::err_acc_invalid_tag_kind)
254 << std::is_same_v<DirOrClauseTy, OpenACCClauseKind>;
255 return false;
256 }
257
258 return true;
259 }
260
261 return false;
262}
263
265 if (!Tok.is(tok::identifier))
266 return false;
267
268 switch (Kind) {
269 case OpenACCDirectiveKind::Parallel:
271 case OpenACCDirectiveKind::Serial:
273 case OpenACCDirectiveKind::Kernels:
275 case OpenACCDirectiveKind::Data:
277 case OpenACCDirectiveKind::HostData:
279 case OpenACCDirectiveKind::Loop:
281 case OpenACCDirectiveKind::Cache:
283
284 case OpenACCDirectiveKind::ParallelLoop:
285 case OpenACCDirectiveKind::SerialLoop:
286 case OpenACCDirectiveKind::KernelsLoop:
287 case OpenACCDirectiveKind::EnterData:
288 case OpenACCDirectiveKind::ExitData:
289 return false;
290
291 case OpenACCDirectiveKind::Atomic:
293 case OpenACCDirectiveKind::Routine:
295 case OpenACCDirectiveKind::Declare:
297 case OpenACCDirectiveKind::Init:
299 case OpenACCDirectiveKind::Shutdown:
301 case OpenACCDirectiveKind::Set:
303 case OpenACCDirectiveKind::Update:
305 case OpenACCDirectiveKind::Wait:
307 case OpenACCDirectiveKind::Invalid:
308 return false;
309 }
310 llvm_unreachable("Unknown 'Kind' Passed");
311}
312
314
315
316
317 if (P.NextToken().isNot(tok::colon)) {
318 P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator);
319 return OpenACCReductionOperator::Invalid;
320 }
321 Token ReductionKindTok = P.getCurToken();
322
323 P.ConsumeToken();
324 P.ConsumeToken();
325
326 switch (ReductionKindTok.getKind()) {
327 case tok:➕
328 return OpenACCReductionOperator::Addition;
329 case tok:⭐
330 return OpenACCReductionOperator::Multiplication;
331 case tok::amp:
332 return OpenACCReductionOperator::BitwiseAnd;
333 case tok::pipe:
334 return OpenACCReductionOperator::BitwiseOr;
335 case tok::caret:
336 return OpenACCReductionOperator::BitwiseXOr;
337 case tok::ampamp:
338 return OpenACCReductionOperator::And;
339 case tok::pipepipe:
340 return OpenACCReductionOperator::Or;
341 case tok::identifier:
343 return OpenACCReductionOperator::Max;
345 return OpenACCReductionOperator::Min;
346 [[fallthrough]];
347 default:
348 P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator);
349 return OpenACCReductionOperator::Invalid;
350 }
351 llvm_unreachable("Reduction op token kind not caught by 'default'?");
352}
353
354
355
356bool expectIdentifierOrKeyword(Parser &P) {
357 Token Tok = P.getCurToken();
358
359 if (isTokenIdentifierOrKeyword(P, Tok))
360 return false;
361
362 P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
363 return true;
364}
365
367ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
368 OpenACCDirectiveKindEx ExtDirKind) {
369 Token SecondTok = P.getCurToken();
370
372 P.Diag(FirstTok, diag::err_acc_invalid_directive)
374 return OpenACCDirectiveKind::Invalid;
375 }
376
377
378
379 P.ConsumeAnyToken();
380
381 if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) {
382 if (!SecondTok.is(tok::identifier))
383 P.Diag(SecondTok, diag::err_expected) << tok::identifier;
384 else
385 P.Diag(FirstTok, diag::err_acc_invalid_directive)
388 return OpenACCDirectiveKind::Invalid;
389 }
390
391 return ExtDirKind == OpenACCDirectiveKindEx::Enter
392 ? OpenACCDirectiveKind::EnterData
393 : OpenACCDirectiveKind::ExitData;
394}
395
397 Token AtomicClauseToken = P.getCurToken();
398
399
401 return OpenACCAtomicKind::Update;
402
403 OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken);
404
405
406
407
408 if (AtomicKind == OpenACCAtomicKind::Invalid)
409 return OpenACCAtomicKind::Update;
410
411 P.ConsumeToken();
412 return AtomicKind;
413}
414
415
417 Token FirstTok = P.getCurToken();
418
419
420
421 if (FirstTok.isNot(tok::identifier)) {
422 P.Diag(FirstTok, diag::err_acc_missing_directive);
423
424 if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
425 P.ConsumeAnyToken();
426
427 return OpenACCDirectiveKind::Invalid;
428 }
429
430 P.ConsumeToken();
431
432 OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok);
433
434
435
436
437
438
439
440 if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
441 switch (ExDirKind) {
442 case OpenACCDirectiveKindEx::Invalid: {
443 P.Diag(FirstTok, diag::err_acc_invalid_directive)
445 return OpenACCDirectiveKind::Invalid;
446 }
447 case OpenACCDirectiveKindEx::Enter:
448 case OpenACCDirectiveKindEx::Exit:
449 return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind);
450 }
451 }
452
454
455
456
457
458 Token SecondTok = P.getCurToken();
460 isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) {
461 switch (DirKind) {
462 default:
463
464
465 break;
466 case OpenACCDirectiveKind::Parallel:
467 P.ConsumeToken();
468 return OpenACCDirectiveKind::ParallelLoop;
469 case OpenACCDirectiveKind::Serial:
470 P.ConsumeToken();
471 return OpenACCDirectiveKind::SerialLoop;
472 case OpenACCDirectiveKind::Kernels:
473 P.ConsumeToken();
474 return OpenACCDirectiveKind::KernelsLoop;
475 }
476 }
477
478 return DirKind;
479}
480
481enum ClauseParensKind {
485};
486
489 switch (Kind) {
490 case OpenACCClauseKind::Self:
491 return DirKind == OpenACCDirectiveKind::Update ? ClauseParensKind::Required
492 : ClauseParensKind::Optional;
493 case OpenACCClauseKind::Async:
494 case OpenACCClauseKind::Worker:
495 case OpenACCClauseKind::Vector:
496 case OpenACCClauseKind::Gang:
497 case OpenACCClauseKind::Wait:
498 return ClauseParensKind::Optional;
499
500 case OpenACCClauseKind::Default:
501 case OpenACCClauseKind::If:
502 case OpenACCClauseKind::Create:
503 case OpenACCClauseKind::PCreate:
504 case OpenACCClauseKind::PresentOrCreate:
505 case OpenACCClauseKind::Copy:
506 case OpenACCClauseKind::PCopy:
507 case OpenACCClauseKind::PresentOrCopy:
508 case OpenACCClauseKind::CopyIn:
509 case OpenACCClauseKind::PCopyIn:
510 case OpenACCClauseKind::PresentOrCopyIn:
511 case OpenACCClauseKind::CopyOut:
512 case OpenACCClauseKind::PCopyOut:
513 case OpenACCClauseKind::PresentOrCopyOut:
514 case OpenACCClauseKind::UseDevice:
515 case OpenACCClauseKind::NoCreate:
516 case OpenACCClauseKind::Present:
517 case OpenACCClauseKind::DevicePtr:
518 case OpenACCClauseKind::Attach:
519 case OpenACCClauseKind::Detach:
520 case OpenACCClauseKind::Private:
521 case OpenACCClauseKind::FirstPrivate:
522 case OpenACCClauseKind::Delete:
523 case OpenACCClauseKind::DeviceResident:
524 case OpenACCClauseKind::Device:
525 case OpenACCClauseKind::Link:
526 case OpenACCClauseKind::Host:
527 case OpenACCClauseKind::Reduction:
528 case OpenACCClauseKind::Collapse:
529 case OpenACCClauseKind::Bind:
530 case OpenACCClauseKind::VectorLength:
531 case OpenACCClauseKind::NumGangs:
532 case OpenACCClauseKind::NumWorkers:
533 case OpenACCClauseKind::DeviceNum:
534 case OpenACCClauseKind::DefaultAsync:
535 case OpenACCClauseKind::DeviceType:
536 case OpenACCClauseKind::DType:
537 case OpenACCClauseKind::Tile:
538 return ClauseParensKind::Required;
539
540 case OpenACCClauseKind::Auto:
541 case OpenACCClauseKind::Finalize:
542 case OpenACCClauseKind::IfPresent:
543 case OpenACCClauseKind::Independent:
544 case OpenACCClauseKind::Invalid:
545 case OpenACCClauseKind::NoHost:
546 case OpenACCClauseKind::Seq:
547 return ClauseParensKind::None;
548 }
549 llvm_unreachable("Unhandled clause kind");
550}
551
554 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional;
555}
556
559 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required;
560}
561
562
563
564
565
566void SkipUntilEndOfDirective(Parser &P) {
567 while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
568 P.ConsumeAnyToken();
569}
570
572 switch (DirKind) {
573 default:
574 case OpenACCDirectiveKind::EnterData:
575 case OpenACCDirectiveKind::ExitData:
576 case OpenACCDirectiveKind::Wait:
577 case OpenACCDirectiveKind::Init:
578 case OpenACCDirectiveKind::Shutdown:
579 return false;
580 case OpenACCDirectiveKind::Parallel:
581 case OpenACCDirectiveKind::Serial:
582 case OpenACCDirectiveKind::Kernels:
583 case OpenACCDirectiveKind::ParallelLoop:
584 case OpenACCDirectiveKind::SerialLoop:
585 case OpenACCDirectiveKind::KernelsLoop:
586 case OpenACCDirectiveKind::Loop:
587 case OpenACCDirectiveKind::Data:
588 case OpenACCDirectiveKind::HostData:
589 return true;
590 }
591 llvm_unreachable("Unhandled directive->assoc stmt");
592}
593
595 switch (DirKind) {
596 case OpenACCDirectiveKind::Parallel:
597 case OpenACCDirectiveKind::Serial:
598 case OpenACCDirectiveKind::Kernels:
599 case OpenACCDirectiveKind::ParallelLoop:
600 case OpenACCDirectiveKind::SerialLoop:
601 case OpenACCDirectiveKind::KernelsLoop:
602
603
606 case OpenACCDirectiveKind::Data:
607 case OpenACCDirectiveKind::EnterData:
608 case OpenACCDirectiveKind::ExitData:
609 case OpenACCDirectiveKind::HostData:
610 case OpenACCDirectiveKind::Wait:
611 case OpenACCDirectiveKind::Init:
612 case OpenACCDirectiveKind::Shutdown:
613 return 0;
614 case OpenACCDirectiveKind::Invalid:
615 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");
616 default:
617 break;
618 }
619 return 0;
620}
621
622}
623
624Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() {
625 return {nullptr, OpenACCParseCanContinue::Can};
626}
627
628Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() {
629 return {nullptr, OpenACCParseCanContinue::Cannot};
630}
631
632Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) {
633 return {Clause, OpenACCParseCanContinue::Can};
634}
635
636ExprResult Parser::ParseOpenACCConditionExpr() {
637
638
639
640
642
644 return ER;
645
649
651}
652
653
654
655
656
657
661 bool FirstClause = true;
662 while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {
663
664 if (!FirstClause && getCurToken().is(tok::comma))
666 FirstClause = false;
667
668 OpenACCClauseParseResult Result = ParseOpenACCClause(Clauses, DirKind);
670 Clauses.push_back(Clause);
671 } else if (Result.getInt() == OpenACCParseCanContinue::Cannot) {
672
673
674 SkipUntilEndOfDirective(*this);
675 return Clauses;
676 }
677 }
678 return Clauses;
679}
680
681Parser::OpenACCIntExprParseResult
685
686
687
689 return {ER, OpenACCParseCanContinue::Cannot};
690
691
692
695 return {ER, OpenACCParseCanContinue::Can};
696
698 OpenACCParseCanContinue::Can};
699}
700
704 OpenACCIntExprParseResult CurResult = ParseOpenACCIntExpr(DK, CK, Loc);
705
706 if (!CurResult.first.isUsable() &&
707 CurResult.second == OpenACCParseCanContinue::Cannot) {
708 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
710 return true;
711 }
712
713 IntExprs.push_back(CurResult.first.get());
714
715 while (().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
716 ExpectAndConsume(tok::comma);
717
718 CurResult = ParseOpenACCIntExpr(DK, CK, Loc);
719
720 if (!CurResult.first.isUsable() &&
721 CurResult.second == OpenACCParseCanContinue::Cannot) {
722 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
724 return true;
725 }
726 IntExprs.push_back(CurResult.first.get());
727 }
728 return false;
729}
730
731
732
733
734
735
736
737
738
739
740bool Parser::ParseOpenACCDeviceTypeList(
741 llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>> &Archs) {
742
743 if (expectIdentifierOrKeyword(*this)) {
744 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
746 return true;
747 }
750
751 while (().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
752 ExpectAndConsume(tok::comma);
753
754 if (expectIdentifierOrKeyword(*this)) {
755 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
757 return true;
758 }
761 }
762 return false;
763}
764
765
766
767
768
769
770
772
773
776 tok::annot_pragma_openacc_end)) {
779 }
780
783
785 return SizeExpr;
786
789 SizeExpr.get());
790
791 return SizeExpr;
792}
793
794bool Parser::ParseOpenACCSizeExprList(
796 ExprResult SizeExpr = ParseOpenACCSizeExpr(CK);
798 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
800 return true;
801 }
802
803 SizeExprs.push_back(SizeExpr.get());
804
805 while (().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
806 ExpectAndConsume(tok::comma);
807
808 SizeExpr = ParseOpenACCSizeExpr(CK);
810 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
812 return true;
813 }
814 SizeExprs.push_back(SizeExpr.get());
815 }
816 return false;
817}
818
819
820
821
822
823
824
825Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
826
827 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Static, getCurToken()) &&
829
834 }
835
836 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Dim, getCurToken()) &&
840
841
845 }
846
847 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) &&
851
852 }
853
854
857 .first;
859}
860
861bool Parser::ParseOpenACCGangArgList(
864
865 Parser::OpenACCGangArgRes Res = ParseOpenACCGangArg(GangLoc);
866 if (!Res.second.isUsable()) {
867 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
869 return true;
870 }
871
872 GKs.push_back(Res.first);
873 IntExprs.push_back(Res.second.get());
874
875 while (().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
876 ExpectAndConsume(tok::comma);
877
878 Res = ParseOpenACCGangArg(GangLoc);
879 if (!Res.second.isUsable()) {
880 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
882 return true;
883 }
884
885 GKs.push_back(Res.first);
886 IntExprs.push_back(Res.second.get());
887 }
888 return false;
889}
890
891
892
893
894
895
896Parser::OpenACCClauseParseResult
899
900
901 if (expectIdentifierOrKeyword(*this))
902 return OpenACCCannotContinue();
903
905
909 return OpenACCCannotContinue();
910 }
911
912
914
915 return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc);
916}
917
918Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
923 tok::annot_pragma_openacc_end);
925
926 if (ClauseHasRequiredParens(DirKind, ClauseKind)) {
927 if (Parens.expectAndConsume()) {
928
929
930
931 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
933 return OpenACCCanContinue();
934 }
936
937 switch (ClauseKind) {
940
941 if (expectIdentifierOrKeyword(*this)) {
943 return OpenACCCanContinue();
944 }
945
947
949 getOpenACCDefaultClauseKind(DefKindTok);
950
952 Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
954 return OpenACCCanContinue();
955 }
956
958 break;
959 }
961 ExprResult CondExpr = ParseOpenACCConditionExpr();
963 : nullptr);
964
967 return OpenACCCanContinue();
968 }
969
970 break;
971 }
975 bool IsReadOnly = tryParseAndConsumeSpecialTokenKind(
976 *this, OpenACCSpecialTokenKind::ReadOnly, ClauseKind);
978 IsReadOnly,
979 false);
980 break;
981 }
988 bool IsZero = tryParseAndConsumeSpecialTokenKind(
989 *this, OpenACCSpecialTokenKind::Zero, ClauseKind);
991 false, IsZero);
992 break;
993 }
995
996
999 break;
1000 }
1002
1003
1004
1006 [[fallthrough]];
1010 false, false);
1011 break;
1014 ParseOpenACCVarList(ClauseKind);
1015 break;
1022 false, false);
1023 break;
1032 false, false);
1033 break;
1035 bool HasForce = tryParseAndConsumeSpecialTokenKind(
1036 *this, OpenACCSpecialTokenKind::Force, ClauseKind);
1041 return OpenACCCanContinue();
1042 }
1043
1047
1050 return OpenACCCanContinue();
1051 }
1052
1054 break;
1055 }
1057 ExprResult BindArg = ParseOpenACCBindClauseArgument();
1060 return OpenACCCanContinue();
1061 }
1062 break;
1063 }
1066
1069 IntExprs)) {
1071 return OpenACCCanContinue();
1072 }
1074 break;
1075 }
1081 ClauseKind, ClauseLoc)
1082 .first;
1085 return OpenACCCanContinue();
1086 }
1087
1089 break;
1090 }
1095
1096
1098 } else if (!ParseOpenACCDeviceTypeList(Archs)) {
1100 } else {
1102 return OpenACCCanContinue();
1103 }
1104 break;
1105 }
1110 return OpenACCCanContinue();
1111 }
1112
1114 break;
1115 }
1116 default:
1117 llvm_unreachable("Not a required parens type?");
1118 }
1119
1121
1122 if (Parens.consumeClose())
1123 return OpenACCCannotContinue();
1124
1125 } else if (ClauseHasOptionalParens(DirKind, ClauseKind)) {
1126 if (.consumeOpen()) {
1128 switch (ClauseKind) {
1131 ExprResult CondExpr = ParseOpenACCConditionExpr();
1133 : nullptr);
1134
1137 return OpenACCCanContinue();
1138 }
1139 break;
1140 }
1143 tryParseAndConsumeSpecialTokenKind(*this,
1144 ClauseKind ==
1146 ? OpenACCSpecialTokenKind::Length
1147 : OpenACCSpecialTokenKind::Num,
1148 ClauseKind);
1150 ClauseKind, ClauseLoc)
1151 .first;
1154 return OpenACCCanContinue();
1155 }
1157 break;
1158 }
1163 .first;
1165 : nullptr);
1168 return OpenACCCanContinue();
1169 }
1170 break;
1171 }
1175 if (ParseOpenACCGangArgList(ClauseLoc, GKs, IntExprs)) {
1177 return OpenACCCanContinue();
1178 }
1179 ParsedClause.setGangDetails(std::move(GKs), std::move(IntExprs));
1180 break;
1181 }
1183 OpenACCWaitParseInfo Info =
1184 ParseOpenACCWaitArgument(ClauseLoc,
1185 false);
1186 if (Info.Failed) {
1188 return OpenACCCanContinue();
1189 }
1190
1191 ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc,
1192 std::move(Info.QueueIdExprs));
1193 break;
1194 }
1195 default:
1196 llvm_unreachable("Not an optional parens type?");
1197 }
1199 if (Parens.consumeClose())
1200 return OpenACCCannotContinue();
1201 } else {
1202
1203
1204 ParsedClause.setEndLoc(ClauseLoc);
1205 }
1206 } else {
1207 ParsedClause.setEndLoc(ClauseLoc);
1208 }
1209 return OpenACCSuccess(
1211}
1212
1213
1214
1215
1216
1217
1218
1219
1220Parser::OpenACCIntExprParseResult
1223 return ParseOpenACCIntExpr(DK, CK, Loc);
1224}
1225
1226
1227
1228
1229
1230Parser::OpenACCWaitParseInfo
1231Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
1232 OpenACCWaitParseInfo Result;
1233
1234 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
1236
1238
1240
1241 OpenACCIntExprParseResult Res = ParseOpenACCIntExpr(
1246 if (Res.first.isInvalid() &&
1247 Res.second == OpenACCParseCanContinue::Cannot) {
1248 Result.Failed = true;
1250 }
1251
1252 if (ExpectAndConsume(tok::colon)) {
1253 Result.Failed = true;
1255 }
1256
1257 Result.DevNumExpr = Res.first.get();
1258 }
1259
1260
1261 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
1263
1265
1267 }
1268
1269
1270
1271
1272
1273 bool FirstArg = true;
1274 while (().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
1275 if (!FirstArg) {
1276 if (ExpectAndConsume(tok::comma)) {
1277 Result.Failed = true;
1279 }
1280 }
1281 FirstArg = false;
1282
1283 OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(
1288
1289 if (Res.first.isInvalid() &&
1290 Res.second == OpenACCParseCanContinue::Cannot) {
1291 Result.Failed = true;
1293 }
1294
1295 if (Res.first.isUsable())
1296 Result.QueueIdExprs.push_back(Res.first.get());
1297 }
1298
1300}
1301
1302ExprResult Parser::ParseOpenACCIDExpression() {
1305 Res = ParseCXXIdExpression(true);
1306 } else {
1307
1308
1309
1310 if (Tok.isNot(tok::identifier)) {
1311 Diag(Tok, diag::err_expected) << tok::identifier;
1313 }
1314
1320
1321
1322
1323
1325 Name, false,
1326 false);
1327 }
1328
1330}
1331
1332ExprResult Parser::ParseOpenACCBindClauseArgument() {
1333
1334
1335
1336
1337
1338
1342 }
1343
1346 false, true));
1347
1348 return ParseOpenACCIDExpression();
1349}
1350
1351
1352
1353
1354
1355
1356
1357
1358Parser::OpenACCVarParseResult Parser::ParseOpenACCVar(OpenACCClauseKind CK) {
1359 OpenACCArraySectionRAII ArraySections(*this);
1360
1363 return {Res, OpenACCParseCanContinue::Cannot};
1364
1367 return {Res, OpenACCParseCanContinue::Can};
1368
1370
1371 return {Res, OpenACCParseCanContinue::Can};
1372}
1373
1376
1377 auto [Res, CanContinue] = ParseOpenACCVar(CK);
1379 Vars.push_back(Res.get());
1380 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {
1382 return Vars;
1383 }
1384
1385 while (().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
1386 ExpectAndConsume(tok::comma);
1387
1388 auto [Res, CanContinue] = ParseOpenACCVar(CK);
1389
1391 Vars.push_back(Res.get());
1392 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {
1394 return Vars;
1395 }
1396 }
1397 return Vars;
1398}
1399
1400
1401
1402
1403
1404void Parser::ParseOpenACCCacheVarList() {
1405
1406
1408 return;
1409
1410
1411
1412
1413 if (tryParseAndConsumeSpecialTokenKind(*this,
1414 OpenACCSpecialTokenKind::ReadOnly,
1416
1417
1418 }
1419
1420
1421
1423}
1424
1425Parser::OpenACCDirectiveParseInfo
1426Parser::ParseOpenACCDirective() {
1430 Parser::OpenACCWaitParseInfo WaitInfo;
1431
1433
1434
1435
1436
1438 ParseOpenACCAtomicKind(*this);
1439
1440
1441
1443 tok::annot_pragma_openacc_end);
1444
1445 if (.consumeOpen()) {
1446 switch (DirKind) {
1447 default:
1448 Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
1449 T.skipToEnd();
1450 break;
1452
1453
1454 ExprResult RoutineName = ParseOpenACCIDExpression();
1455
1456
1458 T.skipToEnd();
1459 else
1460 T.consumeClose();
1461 break;
1462 }
1464 ParseOpenACCCacheVarList();
1465
1466
1467 T.consumeClose();
1468 break;
1470
1471 WaitInfo = ParseOpenACCWaitArgument(DirLoc, true);
1472 if (WaitInfo.Failed)
1473 T.skipToEnd();
1474 else
1475 T.consumeClose();
1476 break;
1477 }
1479
1480
1481
1482 Diag(Tok, diag::err_expected) << tok::l_paren;
1483 }
1484
1485
1486 OpenACCDirectiveParseInfo ParseInfo{DirKind,
1487 StartLoc,
1488 DirLoc,
1489 T.getOpenLocation(),
1490 T.getCloseLocation(),
1492 WaitInfo.QueuesLoc,
1493 WaitInfo.getAllExprs(),
1494 ParseOpenACCClauseList(DirKind)};
1495
1496 assert(Tok.is(tok::annot_pragma_openacc_end) &&
1497 "Didn't parse all OpenACC Clauses");
1498 ParseInfo.EndLoc = ConsumeAnnotationToken();
1499 assert(ParseInfo.EndLoc.isValid() &&
1500 "Terminating annotation token not present");
1501
1502 return ParseInfo;
1503}
1504
1505
1507 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
1508
1510
1511 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();
1512
1513 if (getActions().OpenACC().ActOnStartDeclDirective(DirInfo.DirKind,
1514 DirInfo.StartLoc))
1515 return nullptr;
1516
1517
1519}
1520
1521
1523 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
1524
1526
1527 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();
1528 if (getActions().OpenACC().ActOnStartStmtDirective(
1529 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.Clauses))
1531
1533 if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) {
1535 getActions().OpenACC(), DirInfo.DirKind, DirInfo.DirLoc, {},
1536 DirInfo.Clauses);
1538 ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));
1539
1541 DirInfo.StartLoc, DirInfo.DirKind, DirInfo.Clauses, ParseStatement());
1542 }
1543
1545 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,
1546 DirInfo.MiscLoc, DirInfo.Exprs, DirInfo.RParenLoc, DirInfo.EndLoc,
1547 DirInfo.Clauses, AssocStmt);
1548}
static Decl::Kind getKind(const Decl *D)
Defines some OpenACC-specific enums and functions.
static constexpr bool isOneOf()
This file declares semantic analysis for OpenACC constructs and clauses.
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.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
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.
static OpaquePtr make(PtrTy P)
This is the base type for all OpenACC Clauses.
ParseScope - Introduces a new scope for parsing.
Parser - This implements a parser for the C family of languages.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
SourceLocation ConsumeToken()
ConsumeToken - Consume the current 'peek token' and lex the next one.
DeclGroupPtrTy ParseOpenACCDirectiveDecl()
Placeholder for now, should just ignore the directives after emitting a diagnostic.
Sema & getActions() const
ExprResult ParseConstantExpression()
StmtResult ParseOpenACCDirectiveStmt()
Scope * getCurScope() const
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 ...
const Token & getCurToken() const
ExprResult ParseAssignmentExpression(TypeCastState isTypeCast=NotTypeCast)
Parse an expr that doesn't include (top-level) commas.
const LangOptions & getLangOpts() const
ExprResult ParseExpression(TypeCastState isTypeCast=NotTypeCast)
Simple precedence-based parser for binary/ternary operators.
@ StopBeforeMatch
Stop skipping at specified token, but don't skip the token itself.
ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral=false)
const Token & NextToken()
NextToken - This peeks ahead one token and returns it without consuming it.
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.
@ OpenACCComputeConstructScope
This is the scope of an OpenACC Compute Construct, which restricts jumping into/out of it.
@ BreakScope
This is a while, do, switch, for, etc that can have break statements embedded into it.
Helper type for the registration/assignment of constructs that need to 'know' about their parent cons...
A type to represent all the data for an OpenACC Clause that has been parsed, but not yet created/sema...
void setLParenLoc(SourceLocation EndLoc)
void setConditionDetails(Expr *ConditionExpr)
void setCollapseDetails(bool IsForce, Expr *LoopCount)
void setGangDetails(ArrayRef< OpenACCGangKind > GKs, ArrayRef< Expr * > IntExprs)
void setReductionDetails(OpenACCReductionOperator Op, llvm::SmallVector< Expr * > &&VarList)
void setDefaultDetails(OpenACCDefaultClauseKind DefKind)
void setVarListDetails(ArrayRef< Expr * > VarList, bool IsReadOnly, bool IsZero)
void setWaitDetails(Expr *DevNum, SourceLocation QueuesLoc, llvm::SmallVector< Expr * > &&IntExprs)
void setEndLoc(SourceLocation EndLoc)
void setIntExprDetails(ArrayRef< Expr * > IntExprs)
void setDeviceTypeDetails(llvm::SmallVector< DeviceTypeArgument > &&Archs)
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 ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc, SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef< Expr * > Exprs, SourceLocation RParenLoc, 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.
ExprResult ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc)
StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc, OpenACCDirectiveKind K, ArrayRef< const OpenACCClause * > Clauses, StmtResult AssocStmt)
Called when we encounter an associated statement for our construct, this should check legality of the...
@ 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)
ConditionResult ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, ConditionKind CK, bool MissingOK=false)
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.
SourceLocation getBeginLoc() const LLVM_READONLY
Token - This structure provides full information about a lexed token.
IdentifierInfo * getIdentifierInfo() const
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
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)) {....
tok::TokenKind getKind() const
bool isNot(tok::TokenKind K) const
bool isAnnotation() const
Return true if this is any of tok::annot_* kind tokens.
Represents a C++ unqualified-id that has been parsed.
bool Zero(InterpState &S, CodePtr OpPC)
bool isStringLiteral(TokenKind K)
Return true if this is a C or C++ string-literal (or C++11 user-defined-string-literal) token.
bool isAnnotation(TokenKind K)
Return true if this is any of tok::annot_* kinds.
The JSON file list parser is used to communicate input to InstallAPI.
OpenACCClauseKind
Represents the kind of an OpenACC clause.
@ 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'.
@ Invalid
Not a valid option.
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ 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.