1//===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the parsing logic for OpenACC language features.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/OpenACCClause.h"
14#include "clang/Basic/DiagnosticParse.h"
15#include "clang/Basic/OpenACCKinds.h"
16#include "clang/Parse/Parser.h"
17#include "clang/Parse/RAIIObjectsForParser.h"
18#include "clang/Sema/ParsedAttr.h"
19#include "clang/Sema/SemaOpenACC.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/ADT/StringSwitch.h"
22
23using namespace clang;
24using namespace llvm;
25
26namespace {
27// An enum that contains the extended 'partial' parsed variants. This type
28// should never escape the initial parse functionality, but is useful for
29// simplifying the implementation.
30enum class OpenACCDirectiveKindEx {
31 Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
32 // 'enter data' and 'exit data'
33 Enter,
34 Exit,
35};
36
37// Translate single-token string representations to the OpenACC Directive Kind.
38// This doesn't completely comprehend 'Compound Constructs' (as it just
39// identifies the first token), and doesn't fully handle 'enter data', 'exit
40// data', nor any of the 'atomic' variants, just the first token of each. So
41// this should only be used by `ParseOpenACCDirectiveKind`.
42OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
43 if (!Tok.is(K: tok::identifier))
44 return OpenACCDirectiveKindEx::Invalid;
45 OpenACCDirectiveKind DirKind =
46 llvm::StringSwitch<OpenACCDirectiveKind>(
47 Tok.getIdentifierInfo()->getName())
48 .Case(S: "parallel", Value: OpenACCDirectiveKind::Parallel)
49 .Case(S: "serial", Value: OpenACCDirectiveKind::Serial)
50 .Case(S: "kernels", Value: OpenACCDirectiveKind::Kernels)
51 .Case(S: "data", Value: OpenACCDirectiveKind::Data)
52 .Case(S: "host_data", Value: OpenACCDirectiveKind::HostData)
53 .Case(S: "loop", Value: OpenACCDirectiveKind::Loop)
54 .Case(S: "cache", Value: OpenACCDirectiveKind::Cache)
55 .Case(S: "atomic", Value: OpenACCDirectiveKind::Atomic)
56 .Case(S: "routine", Value: OpenACCDirectiveKind::Routine)
57 .Case(S: "declare", Value: OpenACCDirectiveKind::Declare)
58 .Case(S: "init", Value: OpenACCDirectiveKind::Init)
59 .Case(S: "shutdown", Value: OpenACCDirectiveKind::Shutdown)
60 .Case(S: "set", Value: OpenACCDirectiveKind::Set)
61 .Case(S: "update", Value: OpenACCDirectiveKind::Update)
62 .Case(S: "wait", Value: OpenACCDirectiveKind::Wait)
63 .Default(Value: OpenACCDirectiveKind::Invalid);
64
65 if (DirKind != OpenACCDirectiveKind::Invalid)
66 return static_cast<OpenACCDirectiveKindEx>(DirKind);
67
68 return llvm::StringSwitch<OpenACCDirectiveKindEx>(
69 Tok.getIdentifierInfo()->getName())
70 .Case(S: "enter", Value: OpenACCDirectiveKindEx::Enter)
71 .Case(S: "exit", Value: OpenACCDirectiveKindEx::Exit)
72 .Default(Value: OpenACCDirectiveKindEx::Invalid);
73}
74
75// Translate single-token string representations to the OpenCC Clause Kind.
76OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
77 // auto is a keyword in some language modes, so make sure we parse it
78 // correctly.
79 if (Tok.is(K: tok::kw_auto))
80 return OpenACCClauseKind::Auto;
81
82 // default is a keyword, so make sure we parse it correctly.
83 if (Tok.is(K: tok::kw_default))
84 return OpenACCClauseKind::Default;
85
86 // if is also a keyword, make sure we parse it correctly.
87 if (Tok.is(K: tok::kw_if))
88 return OpenACCClauseKind::If;
89
90 // 'private' is also a keyword, make sure we parse it correctly.
91 if (Tok.is(K: tok::kw_private))
92 return OpenACCClauseKind::Private;
93
94 // 'delete' is a keyword, make sure we parse it correctly.
95 if (Tok.is(K: tok::kw_delete))
96 return OpenACCClauseKind::Delete;
97
98 if (!Tok.is(K: tok::identifier))
99 return OpenACCClauseKind::Invalid;
100
101 return llvm::StringSwitch<OpenACCClauseKind>(
102 Tok.getIdentifierInfo()->getName())
103 .Case(S: "async", Value: OpenACCClauseKind::Async)
104 .Case(S: "attach", Value: OpenACCClauseKind::Attach)
105 .Case(S: "auto", Value: OpenACCClauseKind::Auto)
106 .Case(S: "bind", Value: OpenACCClauseKind::Bind)
107 .Case(S: "create", Value: OpenACCClauseKind::Create)
108 .Case(S: "pcreate", Value: OpenACCClauseKind::PCreate)
109 .Case(S: "present_or_create", Value: OpenACCClauseKind::PresentOrCreate)
110 .Case(S: "collapse", Value: OpenACCClauseKind::Collapse)
111 .Case(S: "copy", Value: OpenACCClauseKind::Copy)
112 .Case(S: "pcopy", Value: OpenACCClauseKind::PCopy)
113 .Case(S: "present_or_copy", Value: OpenACCClauseKind::PresentOrCopy)
114 .Case(S: "copyin", Value: OpenACCClauseKind::CopyIn)
115 .Case(S: "pcopyin", Value: OpenACCClauseKind::PCopyIn)
116 .Case(S: "present_or_copyin", Value: OpenACCClauseKind::PresentOrCopyIn)
117 .Case(S: "copyout", Value: OpenACCClauseKind::CopyOut)
118 .Case(S: "pcopyout", Value: OpenACCClauseKind::PCopyOut)
119 .Case(S: "present_or_copyout", Value: OpenACCClauseKind::PresentOrCopyOut)
120 .Case(S: "default", Value: OpenACCClauseKind::Default)
121 .Case(S: "default_async", Value: OpenACCClauseKind::DefaultAsync)
122 .Case(S: "delete", Value: OpenACCClauseKind::Delete)
123 .Case(S: "detach", Value: OpenACCClauseKind::Detach)
124 .Case(S: "device", Value: OpenACCClauseKind::Device)
125 .Case(S: "device_num", Value: OpenACCClauseKind::DeviceNum)
126 .Case(S: "device_resident", Value: OpenACCClauseKind::DeviceResident)
127 .Case(S: "device_type", Value: OpenACCClauseKind::DeviceType)
128 .Case(S: "deviceptr", Value: OpenACCClauseKind::DevicePtr)
129 .Case(S: "dtype", Value: OpenACCClauseKind::DType)
130 .Case(S: "finalize", Value: OpenACCClauseKind::Finalize)
131 .Case(S: "firstprivate", Value: OpenACCClauseKind::FirstPrivate)
132 .Case(S: "gang", Value: OpenACCClauseKind::Gang)
133 .Case(S: "host", Value: OpenACCClauseKind::Host)
134 .Case(S: "if", Value: OpenACCClauseKind::If)
135 .Case(S: "if_present", Value: OpenACCClauseKind::IfPresent)
136 .Case(S: "independent", Value: OpenACCClauseKind::Independent)
137 .Case(S: "link", Value: OpenACCClauseKind::Link)
138 .Case(S: "no_create", Value: OpenACCClauseKind::NoCreate)
139 .Case(S: "num_gangs", Value: OpenACCClauseKind::NumGangs)
140 .Case(S: "num_workers", Value: OpenACCClauseKind::NumWorkers)
141 .Case(S: "nohost", Value: OpenACCClauseKind::NoHost)
142 .Case(S: "present", Value: OpenACCClauseKind::Present)
143 .Case(S: "private", Value: OpenACCClauseKind::Private)
144 .Case(S: "reduction", Value: OpenACCClauseKind::Reduction)
145 .Case(S: "self", Value: OpenACCClauseKind::Self)
146 .Case(S: "seq", Value: OpenACCClauseKind::Seq)
147 .Case(S: "tile", Value: OpenACCClauseKind::Tile)
148 .Case(S: "use_device", Value: OpenACCClauseKind::UseDevice)
149 .Case(S: "vector", Value: OpenACCClauseKind::Vector)
150 .Case(S: "vector_length", Value: OpenACCClauseKind::VectorLength)
151 .Case(S: "wait", Value: OpenACCClauseKind::Wait)
152 .Case(S: "worker", Value: OpenACCClauseKind::Worker)
153 .Default(Value: OpenACCClauseKind::Invalid);
154}
155
156// Since 'atomic' is effectively a compound directive, this will decode the
157// second part of the directive.
158OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
159 if (!Tok.is(K: tok::identifier))
160 return OpenACCAtomicKind::None;
161 return llvm::StringSwitch<OpenACCAtomicKind>(
162 Tok.getIdentifierInfo()->getName())
163 .Case(S: "read", Value: OpenACCAtomicKind::Read)
164 .Case(S: "write", Value: OpenACCAtomicKind::Write)
165 .Case(S: "update", Value: OpenACCAtomicKind::Update)
166 .Case(S: "capture", Value: OpenACCAtomicKind::Capture)
167 .Default(Value: OpenACCAtomicKind::None);
168}
169
170OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) {
171 if (!Tok.is(K: tok::identifier))
172 return OpenACCDefaultClauseKind::Invalid;
173
174 return llvm::StringSwitch<OpenACCDefaultClauseKind>(
175 Tok.getIdentifierInfo()->getName())
176 .Case(S: "none", Value: OpenACCDefaultClauseKind::None)
177 .Case(S: "present", Value: OpenACCDefaultClauseKind::Present)
178 .Default(Value: OpenACCDefaultClauseKind::Invalid);
179}
180
181enum class OpenACCSpecialTokenKind {
182 ReadOnly,
183 DevNum,
184 Queues,
185 Zero,
186 Force,
187 Num,
188 Length,
189 Dim,
190 Static,
191};
192
193bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
194 if (Tok.is(K: tok::kw_static) && Kind == OpenACCSpecialTokenKind::Static)
195 return true;
196
197 if (!Tok.is(K: tok::identifier))
198 return false;
199
200 switch (Kind) {
201 case OpenACCSpecialTokenKind::ReadOnly:
202 return Tok.getIdentifierInfo()->isStr(Str: "readonly");
203 case OpenACCSpecialTokenKind::DevNum:
204 return Tok.getIdentifierInfo()->isStr(Str: "devnum");
205 case OpenACCSpecialTokenKind::Queues:
206 return Tok.getIdentifierInfo()->isStr(Str: "queues");
207 case OpenACCSpecialTokenKind::Zero:
208 return Tok.getIdentifierInfo()->isStr(Str: "zero");
209 case OpenACCSpecialTokenKind::Force:
210 return Tok.getIdentifierInfo()->isStr(Str: "force");
211 case OpenACCSpecialTokenKind::Num:
212 return Tok.getIdentifierInfo()->isStr(Str: "num");
213 case OpenACCSpecialTokenKind::Length:
214 return Tok.getIdentifierInfo()->isStr(Str: "length");
215 case OpenACCSpecialTokenKind::Dim:
216 return Tok.getIdentifierInfo()->isStr(Str: "dim");
217 case OpenACCSpecialTokenKind::Static:
218 return Tok.getIdentifierInfo()->isStr(Str: "static");
219 }
220 llvm_unreachable("Unknown 'Kind' Passed");
221}
222
223/// Used for cases where we have a token we want to check against an
224/// 'identifier-like' token, but don't want to give awkward error messages in
225/// cases where it is accidentially a keyword.
226bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) {
227 if (Tok.is(K: tok::identifier))
228 return true;
229
230 if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
231 Tok.getIdentifierInfo()->isKeyword(LangOpts: P.getLangOpts()))
232 return true;
233
234 return false;
235}
236
237/// Parses and consumes an identifer followed immediately by a single colon, and
238/// diagnoses if it is not the 'special token' kind that we require. Used when
239/// the tag is the only valid value.
240/// Return 'true' if the special token was matched, false if no special token,
241/// or an invalid special token was found.
242template <typename DirOrClauseTy>
243bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind,
244 DirOrClauseTy DirOrClause) {
245 Token IdentTok = P.getCurToken();
246 // If this is an identifier-like thing followed by ':', it is one of the
247 // OpenACC 'special' name tags, so consume it.
248 if (isTokenIdentifierOrKeyword(P, Tok: IdentTok) && P.NextToken().is(K: tok::colon)) {
249 P.ConsumeToken();
250 P.ConsumeToken();
251
252 if (!isOpenACCSpecialToken(Kind, Tok: IdentTok)) {
253 P.Diag(Tok: IdentTok, DiagID: diag::err_acc_invalid_tag_kind)
254 << IdentTok.getIdentifierInfo() << DirOrClause
255 << std::is_same_v<DirOrClauseTy, OpenACCClauseKind>;
256 return false;
257 }
258
259 return true;
260 }
261
262 return false;
263}
264
265bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
266 if (!Tok.is(K: tok::identifier))
267 return false;
268
269 switch (Kind) {
270 case OpenACCDirectiveKind::Parallel:
271 return Tok.getIdentifierInfo()->isStr(Str: "parallel");
272 case OpenACCDirectiveKind::Serial:
273 return Tok.getIdentifierInfo()->isStr(Str: "serial");
274 case OpenACCDirectiveKind::Kernels:
275 return Tok.getIdentifierInfo()->isStr(Str: "kernels");
276 case OpenACCDirectiveKind::Data:
277 return Tok.getIdentifierInfo()->isStr(Str: "data");
278 case OpenACCDirectiveKind::HostData:
279 return Tok.getIdentifierInfo()->isStr(Str: "host_data");
280 case OpenACCDirectiveKind::Loop:
281 return Tok.getIdentifierInfo()->isStr(Str: "loop");
282 case OpenACCDirectiveKind::Cache:
283 return Tok.getIdentifierInfo()->isStr(Str: "cache");
284
285 case OpenACCDirectiveKind::ParallelLoop:
286 case OpenACCDirectiveKind::SerialLoop:
287 case OpenACCDirectiveKind::KernelsLoop:
288 case OpenACCDirectiveKind::EnterData:
289 case OpenACCDirectiveKind::ExitData:
290 return false;
291
292 case OpenACCDirectiveKind::Atomic:
293 return Tok.getIdentifierInfo()->isStr(Str: "atomic");
294 case OpenACCDirectiveKind::Routine:
295 return Tok.getIdentifierInfo()->isStr(Str: "routine");
296 case OpenACCDirectiveKind::Declare:
297 return Tok.getIdentifierInfo()->isStr(Str: "declare");
298 case OpenACCDirectiveKind::Init:
299 return Tok.getIdentifierInfo()->isStr(Str: "init");
300 case OpenACCDirectiveKind::Shutdown:
301 return Tok.getIdentifierInfo()->isStr(Str: "shutdown");
302 case OpenACCDirectiveKind::Set:
303 return Tok.getIdentifierInfo()->isStr(Str: "set");
304 case OpenACCDirectiveKind::Update:
305 return Tok.getIdentifierInfo()->isStr(Str: "update");
306 case OpenACCDirectiveKind::Wait:
307 return Tok.getIdentifierInfo()->isStr(Str: "wait");
308 case OpenACCDirectiveKind::Invalid:
309 return false;
310 }
311 llvm_unreachable("Unknown 'Kind' Passed");
312}
313
314OpenACCReductionOperator ParseReductionOperator(Parser &P) {
315 // If there is no colon, treat as if the reduction operator was missing, else
316 // we probably will not recover from it in the case where an expression starts
317 // with one of the operator tokens.
318 if (P.NextToken().isNot(K: tok::colon)) {
319 P.Diag(Tok: P.getCurToken(), DiagID: diag::err_acc_expected_reduction_operator);
320 return OpenACCReductionOperator::Invalid;
321 }
322 Token ReductionKindTok = P.getCurToken();
323 // Consume both the kind and the colon.
324 P.ConsumeToken();
325 P.ConsumeToken();
326
327 switch (ReductionKindTok.getKind()) {
328 case tok::plus:
329 return OpenACCReductionOperator::Addition;
330 case tok::star:
331 return OpenACCReductionOperator::Multiplication;
332 case tok::amp:
333 return OpenACCReductionOperator::BitwiseAnd;
334 case tok::pipe:
335 return OpenACCReductionOperator::BitwiseOr;
336 case tok::caret:
337 return OpenACCReductionOperator::BitwiseXOr;
338 case tok::ampamp:
339 return OpenACCReductionOperator::And;
340 case tok::pipepipe:
341 return OpenACCReductionOperator::Or;
342 case tok::identifier:
343 if (ReductionKindTok.getIdentifierInfo()->isStr(Str: "max"))
344 return OpenACCReductionOperator::Max;
345 if (ReductionKindTok.getIdentifierInfo()->isStr(Str: "min"))
346 return OpenACCReductionOperator::Min;
347 [[fallthrough]];
348 default:
349 P.Diag(Tok: ReductionKindTok, DiagID: diag::err_acc_invalid_reduction_operator);
350 return OpenACCReductionOperator::Invalid;
351 }
352 llvm_unreachable("Reduction op token kind not caught by 'default'?");
353}
354
355/// Used for cases where we expect an identifier-like token, but don't want to
356/// give awkward error messages in cases where it is accidentially a keyword.
357bool expectIdentifierOrKeyword(Parser &P) {
358 Token Tok = P.getCurToken();
359
360 if (isTokenIdentifierOrKeyword(P, Tok))
361 return false;
362
363 P.Diag(Tok: P.getCurToken(), DiagID: diag::err_expected) << tok::identifier;
364 return true;
365}
366
367OpenACCDirectiveKind
368ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
369 OpenACCDirectiveKindEx ExtDirKind) {
370 Token SecondTok = P.getCurToken();
371
372 if (SecondTok.isAnnotation()) {
373 P.Diag(Tok: FirstTok, DiagID: diag::err_acc_invalid_directive)
374 << 0 << FirstTok.getIdentifierInfo();
375 return OpenACCDirectiveKind::Invalid;
376 }
377
378 // Consume the second name anyway, this way we can continue on without making
379 // this oddly look like a clause.
380 P.ConsumeAnyToken();
381
382 if (!isOpenACCDirectiveKind(Kind: OpenACCDirectiveKind::Data, Tok: SecondTok)) {
383 if (!SecondTok.is(K: tok::identifier))
384 P.Diag(Tok: SecondTok, DiagID: diag::err_expected) << tok::identifier;
385 else
386 P.Diag(Tok: FirstTok, DiagID: diag::err_acc_invalid_directive)
387 << 1 << FirstTok.getIdentifierInfo()->getName()
388 << SecondTok.getIdentifierInfo()->getName();
389 return OpenACCDirectiveKind::Invalid;
390 }
391
392 return ExtDirKind == OpenACCDirectiveKindEx::Enter
393 ? OpenACCDirectiveKind::EnterData
394 : OpenACCDirectiveKind::ExitData;
395}
396
397OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) {
398 Token AtomicClauseToken = P.getCurToken();
399
400 // #pragma acc atomic is equivilent to update:
401 if (AtomicClauseToken.isAnnotation())
402 return OpenACCAtomicKind::None;
403
404 OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(Tok: AtomicClauseToken);
405
406 // If this isn't a valid atomic-kind, don't consume the token, and treat the
407 // rest as a clause list, which despite there being no permissible clauses,
408 // will diagnose as a clause.
409 if (AtomicKind != OpenACCAtomicKind::None)
410 P.ConsumeToken();
411
412 return AtomicKind;
413}
414
415// Parse and consume the tokens for OpenACC Directive/Construct kinds.
416OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
417 Token FirstTok = P.getCurToken();
418
419 // Just #pragma acc can get us immediately to the end, make sure we don't
420 // introspect on the spelling before then.
421 if (FirstTok.isNot(K: tok::identifier)) {
422 P.Diag(Tok: FirstTok, DiagID: diag::err_acc_missing_directive);
423
424 if (P.getCurToken().isNot(K: tok::annot_pragma_openacc_end))
425 P.ConsumeAnyToken();
426
427 return OpenACCDirectiveKind::Invalid;
428 }
429
430 P.ConsumeToken();
431
432 OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(Tok: FirstTok);
433
434 // OpenACCDirectiveKindEx is meant to be an extended list
435 // over OpenACCDirectiveKind, so any value below Invalid is one of the
436 // OpenACCDirectiveKind values. This switch takes care of all of the extra
437 // parsing required for the Extended values. At the end of this block,
438 // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
439 // immediately cast it and use it as that.
440 if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
441 switch (ExDirKind) {
442 case OpenACCDirectiveKindEx::Invalid: {
443 P.Diag(Tok: FirstTok, DiagID: diag::err_acc_invalid_directive)
444 << 0 << FirstTok.getIdentifierInfo();
445 return OpenACCDirectiveKind::Invalid;
446 }
447 case OpenACCDirectiveKindEx::Enter:
448 case OpenACCDirectiveKindEx::Exit:
449 return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExtDirKind: ExDirKind);
450 }
451 }
452
453 OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);
454
455 // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
456 // other attempt at a combined construct will be diagnosed as an invalid
457 // clause.
458 Token SecondTok = P.getCurToken();
459 if (!SecondTok.isAnnotation() &&
460 isOpenACCDirectiveKind(Kind: OpenACCDirectiveKind::Loop, Tok: SecondTok)) {
461 switch (DirKind) {
462 default:
463 // Nothing to do except in the below cases, as they should be diagnosed as
464 // a clause.
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 {
482 None,
483 Optional,
484 Required
485};
486
487ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind,
488 OpenACCClauseKind Kind) {
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::Shortloop:
541 llvm_unreachable("Shortloop shouldn't be generated in clang");
542 case OpenACCClauseKind::Auto:
543 case OpenACCClauseKind::Finalize:
544 case OpenACCClauseKind::IfPresent:
545 case OpenACCClauseKind::Independent:
546 case OpenACCClauseKind::Invalid:
547 case OpenACCClauseKind::NoHost:
548 case OpenACCClauseKind::Seq:
549 return ClauseParensKind::None;
550 }
551 llvm_unreachable("Unhandled clause kind");
552}
553
554bool ClauseHasOptionalParens(OpenACCDirectiveKind DirKind,
555 OpenACCClauseKind Kind) {
556 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional;
557}
558
559bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind,
560 OpenACCClauseKind Kind) {
561 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required;
562}
563
564// Skip until we see the end of pragma token, but don't consume it. This is us
565// just giving up on the rest of the pragma so we can continue executing. We
566// have to do this because 'SkipUntil' considers paren balancing, which isn't
567// what we want.
568void SkipUntilEndOfDirective(Parser &P) {
569 while (P.getCurToken().isNot(K: tok::annot_pragma_openacc_end))
570 P.ConsumeAnyToken();
571}
572
573bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {
574 switch (DirKind) {
575 case OpenACCDirectiveKind::Routine:
576 // FIXME: Routine MIGHT end up needing to be 'true' here, as it needs a way
577 // to capture a lambda-expression on the next line.
578 case OpenACCDirectiveKind::Cache:
579 case OpenACCDirectiveKind::Declare:
580 case OpenACCDirectiveKind::Set:
581 case OpenACCDirectiveKind::EnterData:
582 case OpenACCDirectiveKind::ExitData:
583 case OpenACCDirectiveKind::Wait:
584 case OpenACCDirectiveKind::Init:
585 case OpenACCDirectiveKind::Shutdown:
586 case OpenACCDirectiveKind::Update:
587 case OpenACCDirectiveKind::Invalid:
588 return false;
589 case OpenACCDirectiveKind::Parallel:
590 case OpenACCDirectiveKind::Serial:
591 case OpenACCDirectiveKind::Kernels:
592 case OpenACCDirectiveKind::ParallelLoop:
593 case OpenACCDirectiveKind::SerialLoop:
594 case OpenACCDirectiveKind::KernelsLoop:
595 case OpenACCDirectiveKind::Loop:
596 case OpenACCDirectiveKind::Data:
597 case OpenACCDirectiveKind::HostData:
598 case OpenACCDirectiveKind::Atomic:
599 return true;
600 }
601 llvm_unreachable("Unhandled directive->assoc stmt");
602}
603
604unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {
605 switch (DirKind) {
606 case OpenACCDirectiveKind::Parallel:
607 case OpenACCDirectiveKind::Serial:
608 case OpenACCDirectiveKind::Kernels:
609 // Mark this as a BreakScope/ContinueScope as well as a compute construct
610 // so that we can diagnose trying to 'break'/'continue' inside of one.
611 return Scope::BreakScope | Scope::ContinueScope |
612 Scope::OpenACCComputeConstructScope;
613 case OpenACCDirectiveKind::ParallelLoop:
614 case OpenACCDirectiveKind::SerialLoop:
615 case OpenACCDirectiveKind::KernelsLoop:
616 // Mark this as a BreakScope/ContinueScope as well as a compute construct
617 // so that we can diagnose trying to 'break'/'continue' inside of one.
618 return Scope::BreakScope | Scope::ContinueScope |
619 Scope::OpenACCComputeConstructScope |
620 Scope::OpenACCLoopConstructScope;
621 case OpenACCDirectiveKind::Loop:
622 return Scope::OpenACCLoopConstructScope;
623 case OpenACCDirectiveKind::Data:
624 case OpenACCDirectiveKind::EnterData:
625 case OpenACCDirectiveKind::ExitData:
626 case OpenACCDirectiveKind::HostData:
627 case OpenACCDirectiveKind::Wait:
628 case OpenACCDirectiveKind::Init:
629 case OpenACCDirectiveKind::Shutdown:
630 case OpenACCDirectiveKind::Cache:
631 case OpenACCDirectiveKind::Atomic:
632 case OpenACCDirectiveKind::Declare:
633 case OpenACCDirectiveKind::Routine:
634 case OpenACCDirectiveKind::Set:
635 case OpenACCDirectiveKind::Update:
636 return 0;
637 case OpenACCDirectiveKind::Invalid:
638 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");
639 }
640 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");
641}
642
643} // namespace
644
645Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() {
646 return {nullptr, OpenACCParseCanContinue::Can};
647}
648
649Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() {
650 return {nullptr, OpenACCParseCanContinue::Cannot};
651}
652
653Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) {
654 return {Clause, OpenACCParseCanContinue::Can};
655}
656
657ExprResult Parser::ParseOpenACCConditionExpr() {
658 // FIXME: It isn't clear if the spec saying 'condition' means the same as
659 // it does in an if/while/etc (See ParseCXXCondition), however as it was
660 // written with Fortran/C in mind, we're going to assume it just means an
661 // 'expression evaluating to boolean'.
662 ExprResult ER = ParseExpression();
663
664 if (!ER.isUsable())
665 return ER;
666
667 Sema::ConditionResult R =
668 getActions().ActOnCondition(S: getCurScope(), Loc: ER.get()->getExprLoc(),
669 SubExpr: ER.get(), CK: Sema::ConditionKind::Boolean);
670
671 return R.isInvalid() ? ExprError() : R.get().second;
672}
673
674OpenACCModifierKind Parser::tryParseModifierList(OpenACCClauseKind CK) {
675 // Use the tentative parsing to decide whether we are a comma-delmited list of
676 // identifers ending in a colon so we can do an actual parse with diagnostics.
677 {
678 RevertingTentativeParsingAction TPA{*this};
679 // capture any <ident><comma> pairs.
680 while (isTokenIdentifierOrKeyword(P&: *this, Tok: getCurToken()) &&
681 NextToken().is(K: tok::comma)) {
682 ConsumeToken();
683 ConsumeToken();
684 }
685
686 if (!isTokenIdentifierOrKeyword(P&: *this, Tok: getCurToken()) ||
687 !NextToken().is(K: tok::colon)) {
688 // No modifiers as this isn't a valid modifier-list.
689 return OpenACCModifierKind::Invalid;
690 }
691 }
692
693 auto GetModKind = [](Token T) {
694 return StringSwitch<OpenACCModifierKind>(T.getIdentifierInfo()->getName())
695 .Case(S: "always", Value: OpenACCModifierKind::Always)
696 .Case(S: "alwaysin", Value: OpenACCModifierKind::AlwaysIn)
697 .Case(S: "alwaysout", Value: OpenACCModifierKind::AlwaysOut)
698 .Case(S: "readonly", Value: OpenACCModifierKind::Readonly)
699 .Case(S: "zero", Value: OpenACCModifierKind::Zero)
700 .Case(S: "capture", Value: OpenACCModifierKind::Capture)
701 .Default(Value: OpenACCModifierKind::Invalid);
702 };
703
704 OpenACCModifierKind CurModList = OpenACCModifierKind::Invalid;
705 auto ConsumeModKind = [&]() {
706 Token IdentToken = getCurToken();
707 OpenACCModifierKind NewKind = GetModKind(IdentToken);
708
709 if (NewKind == OpenACCModifierKind::Invalid)
710 Diag(Loc: IdentToken.getLocation(), DiagID: diag::err_acc_modifier)
711 << diag::ACCModifier::Unknown << IdentToken.getIdentifierInfo() << CK;
712 else if ((NewKind & CurModList) != OpenACCModifierKind::Invalid)
713 Diag(Loc: IdentToken.getLocation(), DiagID: diag::err_acc_modifier)
714 << diag::ACCModifier::Duplicate << IdentToken.getIdentifierInfo()
715 << CK;
716 else
717 CurModList |= NewKind;
718
719 // Consumes the identifier.
720 ConsumeToken();
721 // Consumes the comma or colon.
722 ConsumeToken();
723 };
724
725 // Inspect all but the last item. We inspected enough to know that our current
726 // token is the identifier-like thing, so just check for the comma.
727 while (NextToken().is(K: tok::comma))
728 ConsumeModKind();
729
730 // Above we confirmed that this should be correct/we should be on the last
731 // item.
732 ConsumeModKind();
733
734 return CurModList;
735}
736
737SmallVector<OpenACCClause *>
738Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {
739 SmallVector<OpenACCClause *> Clauses;
740 bool FirstClause = true;
741 while (getCurToken().isNot(K: tok::annot_pragma_openacc_end)) {
742 // Comma is optional in a clause-list.
743 if (!FirstClause && getCurToken().is(K: tok::comma))
744 ConsumeToken();
745 FirstClause = false;
746
747 OpenACCClauseParseResult Result = ParseOpenACCClause(ExistingClauses: Clauses, DirKind);
748 if (OpenACCClause *Clause = Result.getPointer()) {
749 Clauses.push_back(Elt: Clause);
750 } else if (Result.getInt() == OpenACCParseCanContinue::Cannot) {
751 // Recovering from a bad clause is really difficult, so we just give up on
752 // error.
753 SkipUntilEndOfDirective(P&: *this);
754 return Clauses;
755 }
756 }
757 return Clauses;
758}
759
760Parser::OpenACCIntExprParseResult
761Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
762 SourceLocation Loc) {
763 ExprResult ER = ParseAssignmentExpression();
764
765 // If the actual parsing failed, we don't know the state of the parse, so
766 // don't try to continue.
767 if (!ER.isUsable())
768 return {ER, OpenACCParseCanContinue::Cannot};
769
770 return {getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, IntExpr: ER.get()),
771 OpenACCParseCanContinue::Can};
772}
773
774bool Parser::ParseOpenACCIntExprList(OpenACCDirectiveKind DK,
775 OpenACCClauseKind CK, SourceLocation Loc,
776 llvm::SmallVectorImpl<Expr *> &IntExprs) {
777 OpenACCIntExprParseResult CurResult = ParseOpenACCIntExpr(DK, CK, Loc);
778
779 if (!CurResult.first.isUsable() &&
780 CurResult.second == OpenACCParseCanContinue::Cannot) {
781 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
782 Flags: Parser::StopBeforeMatch);
783 return true;
784 }
785
786 IntExprs.push_back(Elt: CurResult.first.get());
787
788 while (!getCurToken().isOneOf(Ks: tok::r_paren, Ks: tok::annot_pragma_openacc_end)) {
789 ExpectAndConsume(ExpectedTok: tok::comma);
790
791 CurResult = ParseOpenACCIntExpr(DK, CK, Loc);
792
793 if (!CurResult.first.isUsable() &&
794 CurResult.second == OpenACCParseCanContinue::Cannot) {
795 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
796 Flags: Parser::StopBeforeMatch);
797 return true;
798 }
799 IntExprs.push_back(Elt: CurResult.first.get());
800 }
801 return false;
802}
803
804bool Parser::ParseOpenACCDeviceTypeList(
805 llvm::SmallVector<IdentifierLoc> &Archs) {
806
807 if (expectIdentifierOrKeyword(P&: *this)) {
808 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
809 Flags: Parser::StopBeforeMatch);
810 return true;
811 }
812 IdentifierInfo *Ident = getCurToken().getIdentifierInfo();
813 Archs.emplace_back(Args: ConsumeToken(), Args&: Ident);
814
815 while (!getCurToken().isOneOf(Ks: tok::r_paren, Ks: tok::annot_pragma_openacc_end)) {
816 ExpectAndConsume(ExpectedTok: tok::comma);
817
818 if (expectIdentifierOrKeyword(P&: *this)) {
819 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
820 Flags: Parser::StopBeforeMatch);
821 return true;
822 }
823 Ident = getCurToken().getIdentifierInfo();
824 Archs.emplace_back(Args: ConsumeToken(), Args&: Ident);
825 }
826 return false;
827}
828
829ExprResult Parser::ParseOpenACCSizeExpr(OpenACCClauseKind CK) {
830 // The size-expr ends up being ambiguous when only looking at the current
831 // token, as it could be a deref of a variable/expression.
832 if (getCurToken().is(K: tok::star) &&
833 NextToken().isOneOf(Ks: tok::comma, Ks: tok::r_paren,
834 Ks: tok::annot_pragma_openacc_end)) {
835 SourceLocation AsteriskLoc = ConsumeToken();
836 return getActions().OpenACC().ActOnOpenACCAsteriskSizeExpr(AsteriskLoc);
837 }
838
839 ExprResult SizeExpr = ParseConstantExpression();
840
841 if (!SizeExpr.isUsable())
842 return SizeExpr;
843
844 SizeExpr = getActions().OpenACC().ActOnIntExpr(
845 DK: OpenACCDirectiveKind::Invalid, CK, Loc: SizeExpr.get()->getBeginLoc(),
846 IntExpr: SizeExpr.get());
847
848 return SizeExpr;
849}
850
851bool Parser::ParseOpenACCSizeExprList(
852 OpenACCClauseKind CK, llvm::SmallVectorImpl<Expr *> &SizeExprs) {
853 ExprResult SizeExpr = ParseOpenACCSizeExpr(CK);
854 if (!SizeExpr.isUsable()) {
855 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
856 Flags: Parser::StopBeforeMatch);
857 return true;
858 }
859
860 SizeExprs.push_back(Elt: SizeExpr.get());
861
862 while (!getCurToken().isOneOf(Ks: tok::r_paren, Ks: tok::annot_pragma_openacc_end)) {
863 ExpectAndConsume(ExpectedTok: tok::comma);
864
865 SizeExpr = ParseOpenACCSizeExpr(CK);
866 if (!SizeExpr.isUsable()) {
867 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
868 Flags: Parser::StopBeforeMatch);
869 return true;
870 }
871 SizeExprs.push_back(Elt: SizeExpr.get());
872 }
873 return false;
874}
875
876Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
877
878 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Static, Tok: getCurToken()) &&
879 NextToken().is(K: tok::colon)) {
880 // 'static' just takes a size-expr, which is an int-expr or an asterisk.
881 ConsumeToken();
882 ConsumeToken();
883 ExprResult Res = ParseOpenACCSizeExpr(CK: OpenACCClauseKind::Gang);
884 return {OpenACCGangKind::Static, Res};
885 }
886
887 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Dim, Tok: getCurToken()) &&
888 NextToken().is(K: tok::colon)) {
889 ConsumeToken();
890 ConsumeToken();
891 // Parse this as a const-expression, and we'll check its integer-ness/value
892 // in CheckGangExpr.
893 ExprResult Res = ParseConstantExpression();
894 return {OpenACCGangKind::Dim, Res};
895 }
896
897 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Num, Tok: getCurToken()) &&
898 NextToken().is(K: tok::colon)) {
899 ConsumeToken();
900 ConsumeToken();
901 // Fallthrough to the 'int-expr' handling for when 'num' is omitted.
902 }
903
904 // This is just the 'num' case where 'num' is optional.
905 ExprResult Res = ParseOpenACCIntExpr(DK: OpenACCDirectiveKind::Invalid,
906 CK: OpenACCClauseKind::Gang, Loc: GangLoc)
907 .first;
908 return {OpenACCGangKind::Num, Res};
909}
910
911bool Parser::ParseOpenACCGangArgList(
912 SourceLocation GangLoc, llvm::SmallVectorImpl<OpenACCGangKind> &GKs,
913 llvm::SmallVectorImpl<Expr *> &IntExprs) {
914
915 Parser::OpenACCGangArgRes Res = ParseOpenACCGangArg(GangLoc);
916 if (!Res.second.isUsable()) {
917 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
918 Flags: Parser::StopBeforeMatch);
919 return true;
920 }
921
922 GKs.push_back(Elt: Res.first);
923 IntExprs.push_back(Elt: Res.second.get());
924
925 while (!getCurToken().isOneOf(Ks: tok::r_paren, Ks: tok::annot_pragma_openacc_end)) {
926 ExpectAndConsume(ExpectedTok: tok::comma);
927
928 Res = ParseOpenACCGangArg(GangLoc);
929 if (!Res.second.isUsable()) {
930 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end,
931 Flags: Parser::StopBeforeMatch);
932 return true;
933 }
934
935 GKs.push_back(Elt: Res.first);
936 IntExprs.push_back(Elt: Res.second.get());
937 }
938 return false;
939}
940
941namespace {
942bool isUnsupportedExtensionClause(Token Tok) {
943 if (!Tok.is(K: tok::identifier))
944 return false;
945
946 return Tok.getIdentifierInfo()->getName().starts_with(Prefix: "__");
947}
948} // namespace
949
950Parser::OpenACCClauseParseResult
951Parser::ParseOpenACCClause(ArrayRef<const OpenACCClause *> ExistingClauses,
952 OpenACCDirectiveKind DirKind) {
953 // A number of clause names are actually keywords, so accept a keyword that
954 // can be converted to a name.
955 if (expectIdentifierOrKeyword(P&: *this))
956 return OpenACCCannotContinue();
957
958 OpenACCClauseKind Kind = getOpenACCClauseKind(Tok: getCurToken());
959
960 if (isUnsupportedExtensionClause(Tok: getCurToken())) {
961 Diag(Tok: getCurToken(), DiagID: diag::warn_acc_unsupported_extension_clause)
962 << getCurToken().getIdentifierInfo();
963
964 // Extension methods optionally contain balanced token sequences, so we are
965 // going to parse this.
966 ConsumeToken(); // Consume the clause name.
967 BalancedDelimiterTracker Parens(*this, tok::l_paren,
968 tok::annot_pragma_openacc_end);
969 // Consume the optional parens and tokens inside of them.
970 if (!Parens.consumeOpen())
971 Parens.skipToEnd();
972
973 return OpenACCCanContinue();
974 } else if (Kind == OpenACCClauseKind::Invalid) {
975 Diag(Tok: getCurToken(), DiagID: diag::err_acc_invalid_clause)
976 << getCurToken().getIdentifierInfo();
977 return OpenACCCannotContinue();
978 }
979
980 // Consume the clause name.
981 SourceLocation ClauseLoc = ConsumeToken();
982
983 return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc);
984}
985
986Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
987 ArrayRef<const OpenACCClause *> ExistingClauses,
988 OpenACCDirectiveKind DirKind, OpenACCClauseKind ClauseKind,
989 SourceLocation ClauseLoc) {
990 BalancedDelimiterTracker Parens(*this, tok::l_paren,
991 tok::annot_pragma_openacc_end);
992 SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);
993
994 if (ClauseHasRequiredParens(DirKind, Kind: ClauseKind)) {
995 if (Parens.expectAndConsume()) {
996 // We are missing a paren, so assume that the person just forgot the
997 // parameter. Return 'false' so we try to continue on and parse the next
998 // clause.
999 SkipUntil(T1: tok::comma, T2: tok::r_paren, T3: tok::annot_pragma_openacc_end,
1000 Flags: Parser::StopBeforeMatch);
1001 return OpenACCCanContinue();
1002 }
1003 ParsedClause.setLParenLoc(Parens.getOpenLocation());
1004
1005 switch (ClauseKind) {
1006 case OpenACCClauseKind::Default: {
1007 Token DefKindTok = getCurToken();
1008
1009 if (expectIdentifierOrKeyword(P&: *this)) {
1010 Parens.skipToEnd();
1011 return OpenACCCanContinue();
1012 }
1013
1014 ConsumeToken();
1015
1016 OpenACCDefaultClauseKind DefKind =
1017 getOpenACCDefaultClauseKind(Tok: DefKindTok);
1018
1019 if (DefKind == OpenACCDefaultClauseKind::Invalid) {
1020 Diag(Tok: DefKindTok, DiagID: diag::err_acc_invalid_default_clause_kind);
1021 Parens.skipToEnd();
1022 return OpenACCCanContinue();
1023 }
1024
1025 ParsedClause.setDefaultDetails(DefKind);
1026 break;
1027 }
1028 case OpenACCClauseKind::If: {
1029 ExprResult CondExpr = ParseOpenACCConditionExpr();
1030 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()
1031 : nullptr);
1032
1033 if (CondExpr.isInvalid()) {
1034 Parens.skipToEnd();
1035 return OpenACCCanContinue();
1036 }
1037
1038 break;
1039 }
1040 case OpenACCClauseKind::Copy:
1041 case OpenACCClauseKind::PCopy:
1042 case OpenACCClauseKind::PresentOrCopy:
1043 case OpenACCClauseKind::CopyIn:
1044 case OpenACCClauseKind::PCopyIn:
1045 case OpenACCClauseKind::PresentOrCopyIn:
1046 case OpenACCClauseKind::CopyOut:
1047 case OpenACCClauseKind::PCopyOut:
1048 case OpenACCClauseKind::PresentOrCopyOut:
1049 case OpenACCClauseKind::Create:
1050 case OpenACCClauseKind::PCreate:
1051 case OpenACCClauseKind::PresentOrCreate: {
1052 OpenACCModifierKind ModList = tryParseModifierList(CK: ClauseKind);
1053 ParsedClause.setVarListDetails(VarList: ParseOpenACCVarList(DK: DirKind, CK: ClauseKind),
1054 ModKind: ModList);
1055 break;
1056 }
1057 case OpenACCClauseKind::Reduction: {
1058 // If we're missing a clause-kind (or it is invalid), see if we can parse
1059 // the var-list anyway.
1060 OpenACCReductionOperator Op = ParseReductionOperator(P&: *this);
1061 ParsedClause.setReductionDetails(
1062 Op, VarList: ParseOpenACCVarList(DK: DirKind, CK: ClauseKind));
1063 break;
1064 }
1065 case OpenACCClauseKind::Self:
1066 // The 'self' clause is a var-list instead of a 'condition' in the case of
1067 // the 'update' clause, so we have to handle it here. Use an assert to
1068 // make sure we get the right differentiator.
1069 assert(DirKind == OpenACCDirectiveKind::Update);
1070 [[fallthrough]];
1071 case OpenACCClauseKind::Device:
1072 case OpenACCClauseKind::Host:
1073 case OpenACCClauseKind::DeviceResident:
1074 case OpenACCClauseKind::Link:
1075 case OpenACCClauseKind::Attach:
1076 case OpenACCClauseKind::Delete:
1077 case OpenACCClauseKind::Detach:
1078 case OpenACCClauseKind::DevicePtr:
1079 case OpenACCClauseKind::UseDevice:
1080 case OpenACCClauseKind::FirstPrivate:
1081 case OpenACCClauseKind::NoCreate:
1082 case OpenACCClauseKind::Present:
1083 case OpenACCClauseKind::Private:
1084 ParsedClause.setVarListDetails(VarList: ParseOpenACCVarList(DK: DirKind, CK: ClauseKind),
1085 ModKind: OpenACCModifierKind::Invalid);
1086 break;
1087 case OpenACCClauseKind::Collapse: {
1088 bool HasForce = tryParseAndConsumeSpecialTokenKind(
1089 P&: *this, Kind: OpenACCSpecialTokenKind::Force, DirOrClause: ClauseKind);
1090 ExprResult LoopCount = ParseConstantExpression();
1091 if (LoopCount.isInvalid()) {
1092 Parens.skipToEnd();
1093 return OpenACCCanContinue();
1094 }
1095
1096 LoopCount = getActions().OpenACC().ActOnIntExpr(
1097 DK: OpenACCDirectiveKind::Invalid, CK: ClauseKind,
1098 Loc: LoopCount.get()->getBeginLoc(), IntExpr: LoopCount.get());
1099
1100 if (LoopCount.isInvalid()) {
1101 Parens.skipToEnd();
1102 return OpenACCCanContinue();
1103 }
1104
1105 ParsedClause.setCollapseDetails(IsForce: HasForce, LoopCount: LoopCount.get());
1106 break;
1107 }
1108 case OpenACCClauseKind::Bind: {
1109 ParsedClause.setBindDetails(ParseOpenACCBindClauseArgument());
1110
1111 // We can create an 'empty' bind clause in the event of an error
1112 if (std::holds_alternative<std::monostate>(
1113 v: ParsedClause.getBindDetails())) {
1114 Parens.skipToEnd();
1115 return OpenACCCanContinue();
1116 }
1117 break;
1118 }
1119 case OpenACCClauseKind::NumGangs: {
1120 llvm::SmallVector<Expr *> IntExprs;
1121
1122 if (ParseOpenACCIntExprList(DK: OpenACCDirectiveKind::Invalid,
1123 CK: OpenACCClauseKind::NumGangs, Loc: ClauseLoc,
1124 IntExprs)) {
1125 Parens.skipToEnd();
1126 return OpenACCCanContinue();
1127 }
1128 ParsedClause.setIntExprDetails(std::move(IntExprs));
1129 break;
1130 }
1131 case OpenACCClauseKind::NumWorkers:
1132 case OpenACCClauseKind::DeviceNum:
1133 case OpenACCClauseKind::DefaultAsync:
1134 case OpenACCClauseKind::VectorLength: {
1135 ExprResult IntExpr = ParseOpenACCIntExpr(DK: OpenACCDirectiveKind::Invalid,
1136 CK: ClauseKind, Loc: ClauseLoc)
1137 .first;
1138 if (IntExpr.isInvalid()) {
1139 Parens.skipToEnd();
1140 return OpenACCCanContinue();
1141 }
1142
1143 ParsedClause.setIntExprDetails(IntExpr.get());
1144 break;
1145 }
1146 case OpenACCClauseKind::DType:
1147 case OpenACCClauseKind::DeviceType: {
1148 llvm::SmallVector<IdentifierLoc> Archs;
1149 if (getCurToken().is(K: tok::star)) {
1150 // FIXME: We want to mark that this is an 'everything else' type of
1151 // device_type in Sema.
1152 ParsedClause.setDeviceTypeDetails(
1153 {IdentifierLoc(ConsumeToken(), nullptr)});
1154 } else if (!ParseOpenACCDeviceTypeList(Archs)) {
1155 ParsedClause.setDeviceTypeDetails(std::move(Archs));
1156 } else {
1157 Parens.skipToEnd();
1158 return OpenACCCanContinue();
1159 }
1160 break;
1161 }
1162 case OpenACCClauseKind::Tile: {
1163 llvm::SmallVector<Expr *> SizeExprs;
1164 if (ParseOpenACCSizeExprList(CK: OpenACCClauseKind::Tile, SizeExprs)) {
1165 Parens.skipToEnd();
1166 return OpenACCCanContinue();
1167 }
1168
1169 ParsedClause.setIntExprDetails(std::move(SizeExprs));
1170 break;
1171 }
1172 default:
1173 llvm_unreachable("Not a required parens type?");
1174 }
1175
1176 ParsedClause.setEndLoc(getCurToken().getLocation());
1177
1178 if (Parens.consumeClose())
1179 return OpenACCCannotContinue();
1180
1181 } else if (ClauseHasOptionalParens(DirKind, Kind: ClauseKind)) {
1182 if (!Parens.consumeOpen()) {
1183 ParsedClause.setLParenLoc(Parens.getOpenLocation());
1184 switch (ClauseKind) {
1185 case OpenACCClauseKind::Self: {
1186 assert(DirKind != OpenACCDirectiveKind::Update);
1187 ExprResult CondExpr = ParseOpenACCConditionExpr();
1188 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()
1189 : nullptr);
1190
1191 if (CondExpr.isInvalid()) {
1192 Parens.skipToEnd();
1193 return OpenACCCanContinue();
1194 }
1195 break;
1196 }
1197 case OpenACCClauseKind::Vector:
1198 case OpenACCClauseKind::Worker: {
1199 tryParseAndConsumeSpecialTokenKind(P&: *this,
1200 Kind: ClauseKind ==
1201 OpenACCClauseKind::Vector
1202 ? OpenACCSpecialTokenKind::Length
1203 : OpenACCSpecialTokenKind::Num,
1204 DirOrClause: ClauseKind);
1205 ExprResult IntExpr = ParseOpenACCIntExpr(DK: OpenACCDirectiveKind::Invalid,
1206 CK: ClauseKind, Loc: ClauseLoc)
1207 .first;
1208 if (IntExpr.isInvalid()) {
1209 Parens.skipToEnd();
1210 return OpenACCCanContinue();
1211 }
1212 ParsedClause.setIntExprDetails(IntExpr.get());
1213 break;
1214 }
1215 case OpenACCClauseKind::Async: {
1216 ExprResult AsyncArg =
1217 ParseOpenACCAsyncArgument(DK: OpenACCDirectiveKind::Invalid,
1218 CK: OpenACCClauseKind::Async, Loc: ClauseLoc)
1219 .first;
1220 ParsedClause.setIntExprDetails(AsyncArg.isUsable() ? AsyncArg.get()
1221 : nullptr);
1222 if (AsyncArg.isInvalid()) {
1223 Parens.skipToEnd();
1224 return OpenACCCanContinue();
1225 }
1226 break;
1227 }
1228 case OpenACCClauseKind::Gang: {
1229 llvm::SmallVector<OpenACCGangKind> GKs;
1230 llvm::SmallVector<Expr *> IntExprs;
1231 if (ParseOpenACCGangArgList(GangLoc: ClauseLoc, GKs, IntExprs)) {
1232 Parens.skipToEnd();
1233 return OpenACCCanContinue();
1234 }
1235 ParsedClause.setGangDetails(GKs: std::move(GKs), IntExprs: std::move(IntExprs));
1236 break;
1237 }
1238 case OpenACCClauseKind::Wait: {
1239 OpenACCWaitParseInfo Info =
1240 ParseOpenACCWaitArgument(Loc: ClauseLoc,
1241 /*IsDirective=*/false);
1242 if (Info.Failed) {
1243 Parens.skipToEnd();
1244 return OpenACCCanContinue();
1245 }
1246
1247 ParsedClause.setWaitDetails(DevNum: Info.DevNumExpr, QueuesLoc: Info.QueuesLoc,
1248 IntExprs: std::move(Info.QueueIdExprs));
1249 break;
1250 }
1251 default:
1252 llvm_unreachable("Not an optional parens type?");
1253 }
1254 ParsedClause.setEndLoc(getCurToken().getLocation());
1255 if (Parens.consumeClose())
1256 return OpenACCCannotContinue();
1257 } else {
1258 // If we have optional parens, make sure we set the end-location to the
1259 // clause, as we are a 'single token' clause.
1260 ParsedClause.setEndLoc(ClauseLoc);
1261 }
1262 } else {
1263 ParsedClause.setEndLoc(ClauseLoc);
1264 }
1265 return OpenACCSuccess(
1266 Clause: Actions.OpenACC().ActOnClause(ExistingClauses, Clause&: ParsedClause));
1267}
1268
1269Parser::OpenACCIntExprParseResult
1270Parser::ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
1271 SourceLocation Loc) {
1272 return ParseOpenACCIntExpr(DK, CK, Loc);
1273}
1274
1275Parser::OpenACCWaitParseInfo
1276Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
1277 OpenACCWaitParseInfo Result;
1278 // [devnum : int-expr : ]
1279 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::DevNum, Tok) &&
1280 NextToken().is(K: tok::colon)) {
1281 // Consume devnum.
1282 ConsumeToken();
1283 // Consume colon.
1284 ConsumeToken();
1285
1286 OpenACCIntExprParseResult Res = ParseOpenACCIntExpr(
1287 DK: IsDirective ? OpenACCDirectiveKind::Wait
1288 : OpenACCDirectiveKind::Invalid,
1289 CK: IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
1290 Loc);
1291 if (Res.first.isInvalid() &&
1292 Res.second == OpenACCParseCanContinue::Cannot) {
1293 Result.Failed = true;
1294 return Result;
1295 }
1296
1297 if (ExpectAndConsume(ExpectedTok: tok::colon)) {
1298 Result.Failed = true;
1299 return Result;
1300 }
1301
1302 Result.DevNumExpr = Res.first.get();
1303 }
1304
1305 // [ queues : ]
1306 if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Queues, Tok) &&
1307 NextToken().is(K: tok::colon)) {
1308 // Consume queues.
1309 Result.QueuesLoc = ConsumeToken();
1310 // Consume colon.
1311 ConsumeToken();
1312 }
1313
1314
1315
1316 // OpenACC 3.3, section 2.16:
1317 // the term 'async-argument' means a nonnegative scalar integer expression, or
1318 // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
1319 // in the C header file and the Fortran opacc module.
1320 OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(
1321 DK: IsDirective ? OpenACCDirectiveKind::Wait
1322 : OpenACCDirectiveKind::Invalid,
1323 CK: IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
1324 Loc);
1325
1326 if (Res.first.isInvalid() &&
1327 Res.second == OpenACCParseCanContinue::Cannot) {
1328 Result.Failed = true;
1329 return Result;
1330 }
1331
1332 if (Res.first.isUsable())
1333 Result.QueueIdExprs.push_back(Elt: Res.first.get());
1334
1335 while (!getCurToken().isOneOf(Ks: tok::r_paren, Ks: tok::annot_pragma_openacc_end)) {
1336 if (ExpectAndConsume(ExpectedTok: tok::comma)) {
1337 Result.Failed = true;
1338 return Result;
1339 }
1340
1341 OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(
1342 DK: IsDirective ? OpenACCDirectiveKind::Wait
1343 : OpenACCDirectiveKind::Invalid,
1344 CK: IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
1345 Loc);
1346
1347 if (Res.first.isInvalid() &&
1348 Res.second == OpenACCParseCanContinue::Cannot) {
1349 Result.Failed = true;
1350 return Result;
1351 }
1352
1353 if (Res.first.isUsable())
1354 Result.QueueIdExprs.push_back(Elt: Res.first.get());
1355 }
1356
1357 return Result;
1358}
1359
1360ExprResult Parser::ParseOpenACCIDExpression() {
1361 ExprResult Res;
1362 if (getLangOpts().CPlusPlus) {
1363 Res = ParseCXXIdExpression(/*isAddressOfOperand=*/true);
1364 } else {
1365 // There isn't anything quite the same as ParseCXXIdExpression for C, so we
1366 // need to get the identifier, then call into Sema ourselves.
1367
1368 if (Tok.isNot(K: tok::identifier)) {
1369 Diag(Tok, DiagID: diag::err_expected) << tok::identifier;
1370 return ExprError();
1371 }
1372
1373 Token FuncName = getCurToken();
1374 UnqualifiedId Name;
1375 CXXScopeSpec ScopeSpec;
1376 SourceLocation TemplateKWLoc;
1377 Name.setIdentifier(Id: FuncName.getIdentifierInfo(), IdLoc: ConsumeToken());
1378
1379 // Ensure this is a valid identifier. We don't accept causing implicit
1380 // function declarations per the spec, so always claim to not have trailing
1381 // L Paren.
1382 Res = Actions.ActOnIdExpression(S: getCurScope(), SS&: ScopeSpec, TemplateKWLoc,
1383 Id&: Name, /*HasTrailingLParen=*/false,
1384 /*isAddressOfOperand=*/IsAddressOfOperand: false);
1385 }
1386
1387 return Res;
1388}
1389
1390std::variant<std::monostate, clang::StringLiteral *, IdentifierInfo *>
1391Parser::ParseOpenACCBindClauseArgument() {
1392 // OpenACC 3.3 section 2.15:
1393 // The bind clause specifies the name to use when calling the procedure on a
1394 // device other than the host. If the name is specified as an identifier, it
1395 // is called as if that name were specified in the language being compiled. If
1396 // the name is specified as a string, the string is used for the procedure
1397 // name unmodified.
1398 if (getCurToken().is(K: tok::r_paren)) {
1399 Diag(Tok: getCurToken(), DiagID: diag::err_acc_incorrect_bind_arg);
1400 return std::monostate{};
1401 }
1402
1403 if (getCurToken().is(K: tok::identifier)) {
1404 IdentifierInfo *II = getCurToken().getIdentifierInfo();
1405 ConsumeToken();
1406 return II;
1407 }
1408
1409 if (!tok::isStringLiteral(K: getCurToken().getKind())) {
1410 Diag(Tok: getCurToken(), DiagID: diag::err_acc_incorrect_bind_arg);
1411 return std::monostate{};
1412 }
1413
1414 ExprResult Res = ParseStringLiteralExpression(
1415 /*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true);
1416 if (!Res.isUsable())
1417 return std::monostate{};
1418 return cast<StringLiteral>(Val: Res.get());
1419}
1420
1421Parser::OpenACCVarParseResult Parser::ParseOpenACCVar(OpenACCDirectiveKind DK,
1422 OpenACCClauseKind CK) {
1423 OpenACCArraySectionRAII ArraySections(*this);
1424
1425 getActions().OpenACC().ActOnStartParseVar(DK, CK);
1426 ExprResult Res = ParseAssignmentExpression();
1427
1428 if (!Res.isUsable()) {
1429 getActions().OpenACC().ActOnInvalidParseVar();
1430 return {Res, OpenACCParseCanContinue::Cannot};
1431 }
1432
1433 Res = getActions().OpenACC().ActOnVar(DK, CK, VarExpr: Res.get());
1434 return {Res, OpenACCParseCanContinue::Can};
1435}
1436
1437llvm::SmallVector<Expr *> Parser::ParseOpenACCVarList(OpenACCDirectiveKind DK,
1438 OpenACCClauseKind CK) {
1439 llvm::SmallVector<Expr *> Vars;
1440
1441 auto [Res, CanContinue] = ParseOpenACCVar(DK, CK);
1442 if (Res.isUsable()) {
1443 Vars.push_back(Elt: Res.get());
1444 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {
1445 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, Flags: StopBeforeMatch);
1446 return Vars;
1447 }
1448
1449 while (!getCurToken().isOneOf(Ks: tok::r_paren, Ks: tok::annot_pragma_openacc_end)) {
1450 ExpectAndConsume(ExpectedTok: tok::comma);
1451
1452 auto [Res, CanContinue] = ParseOpenACCVar(DK, CK);
1453
1454 if (Res.isUsable()) {
1455 Vars.push_back(Elt: Res.get());
1456 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {
1457 SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, Flags: StopBeforeMatch);
1458 return Vars;
1459 }
1460 }
1461 return Vars;
1462}
1463
1464Parser::OpenACCCacheParseInfo Parser::ParseOpenACCCacheVarList() {
1465 // If this is the end of the line, just return 'false' and count on the close
1466 // paren diagnostic to catch the issue.
1467 if (getCurToken().isAnnotation())
1468 return {};
1469
1470 OpenACCCacheParseInfo CacheInfo;
1471
1472 SourceLocation ReadOnlyLoc = getCurToken().getLocation();
1473 // The VarList is an optional `readonly:` followed by a list of a variable
1474 // specifications. Consume something that looks like a 'tag', and diagnose if
1475 // it isn't 'readonly'.
1476 if (tryParseAndConsumeSpecialTokenKind(P&: *this,
1477 Kind: OpenACCSpecialTokenKind::ReadOnly,
1478 DirOrClause: OpenACCDirectiveKind::Cache))
1479 CacheInfo.ReadOnlyLoc = ReadOnlyLoc;
1480
1481 // ParseOpenACCVarList should leave us before a r-paren, so no need to skip
1482 // anything here.
1483 CacheInfo.Vars = ParseOpenACCVarList(DK: OpenACCDirectiveKind::Cache,
1484 CK: OpenACCClauseKind::Invalid);
1485
1486 return CacheInfo;
1487}
1488
1489Parser::OpenACCDirectiveParseInfo
1490Parser::ParseOpenACCDirective() {
1491 SourceLocation StartLoc = ConsumeAnnotationToken();
1492 SourceLocation DirLoc = getCurToken().getLocation();
1493 OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(P&: *this);
1494 Parser::OpenACCWaitParseInfo WaitInfo;
1495 Parser::OpenACCCacheParseInfo CacheInfo;
1496 OpenACCAtomicKind AtomicKind = OpenACCAtomicKind::None;
1497 ExprResult RoutineName;
1498
1499 getActions().OpenACC().ActOnConstruct(K: DirKind, DirLoc);
1500
1501 // Once we've parsed the construct/directive name, some have additional
1502 // specifiers that need to be taken care of. Atomic has an 'atomic-clause'
1503 // that needs to be parsed.
1504 if (DirKind == OpenACCDirectiveKind::Atomic)
1505 AtomicKind = ParseOpenACCAtomicKind(P&: *this);
1506
1507 // We've successfully parsed the construct/directive name, however a few of
1508 // the constructs have optional parens that contain further details.
1509 BalancedDelimiterTracker T(*this, tok::l_paren,
1510 tok::annot_pragma_openacc_end);
1511
1512 if (!T.consumeOpen()) {
1513 switch (DirKind) {
1514 default:
1515 Diag(Loc: T.getOpenLocation(), DiagID: diag::err_acc_invalid_open_paren);
1516 T.skipToEnd();
1517 break;
1518 case OpenACCDirectiveKind::Routine: {
1519 // Routine has an optional paren-wrapped name of a function in the local
1520 // scope. We parse the name, emitting any diagnostics
1521 RoutineName = ParseOpenACCIDExpression();
1522 // If the routine name is invalid, just skip until the closing paren to
1523 // recover more gracefully.
1524 if (!RoutineName.isUsable()) {
1525 T.skipToEnd();
1526 } else {
1527 T.consumeClose();
1528 RoutineName =
1529 getActions().OpenACC().ActOnRoutineName(RoutineName: RoutineName.get());
1530 }
1531 break;
1532 }
1533 case OpenACCDirectiveKind::Cache:
1534 CacheInfo = ParseOpenACCCacheVarList();
1535 // The ParseOpenACCCacheVarList function manages to recover from failures,
1536 // so we can always consume the close.
1537 T.consumeClose();
1538 break;
1539 case OpenACCDirectiveKind::Wait:
1540 // OpenACC has an optional paren-wrapped 'wait-argument'.
1541 WaitInfo = ParseOpenACCWaitArgument(Loc: DirLoc, /*IsDirective=*/true);
1542 if (WaitInfo.Failed)
1543 T.skipToEnd();
1544 else
1545 T.consumeClose();
1546 break;
1547 }
1548 } else if (DirKind == OpenACCDirectiveKind::Cache) {
1549 // Cache's paren var-list is required, so error here if it isn't provided.
1550 // We know that the consumeOpen above left the first non-paren here, so
1551 // diagnose, then continue as if it was completely omitted.
1552 Diag(Tok, DiagID: diag::err_expected) << tok::l_paren;
1553 }
1554
1555 // Parses the list of clauses, if present, plus set up return value.
1556 OpenACCDirectiveParseInfo ParseInfo{.DirKind: DirKind,
1557 .StartLoc: StartLoc,
1558 .DirLoc: DirLoc,
1559 .LParenLoc: T.getOpenLocation(),
1560 .RParenLoc: T.getCloseLocation(),
1561 /*EndLoc=*/SourceLocation{},
1562 .MiscLoc: (DirKind == OpenACCDirectiveKind::Wait
1563 ? WaitInfo.QueuesLoc
1564 : CacheInfo.ReadOnlyLoc),
1565 .AtomicKind: AtomicKind,
1566 .Exprs: {},
1567 .Clauses: {}};
1568
1569 if (DirKind == OpenACCDirectiveKind::Wait)
1570 ParseInfo.Exprs = WaitInfo.getAllExprs();
1571 else if (DirKind == OpenACCDirectiveKind::Cache)
1572 ParseInfo.Exprs = std::move(CacheInfo.Vars);
1573 else if (DirKind == OpenACCDirectiveKind::Routine && RoutineName.isUsable())
1574 ParseInfo.Exprs = llvm::SmallVector<Expr *>(1, RoutineName.get());
1575
1576 ParseInfo.Clauses = ParseOpenACCClauseList(DirKind);
1577
1578 assert(Tok.is(tok::annot_pragma_openacc_end) &&
1579 "Didn't parse all OpenACC Clauses");
1580 ParseInfo.EndLoc = ConsumeAnnotationToken();
1581 assert(ParseInfo.EndLoc.isValid() &&
1582 "Terminating annotation token not present");
1583
1584 return ParseInfo;
1585}
1586
1587Parser::DeclGroupPtrTy Parser::ParseOpenACCAfterRoutineDecl(
1588 AccessSpecifier &AS, ParsedAttributes &Attrs, DeclSpec::TST TagType,
1589 Decl *TagDecl, OpenACCDirectiveParseInfo &DirInfo) {
1590 assert(DirInfo.DirKind == OpenACCDirectiveKind::Routine);
1591
1592 DeclGroupPtrTy Ptr;
1593 if (DirInfo.LParenLoc.isInvalid()) {
1594 if (Tok.isNot(K: tok::r_brace) && !isEofOrEom()) {
1595 if (AS == AS_none) {
1596 // This is either an external declaration, or inside of a C struct. If
1597 // the latter, we have to diagnose if this is the 'implicit' named
1598 // version.
1599 if (TagType == DeclSpec::TST_unspecified) {
1600 ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
1601 MaybeParseCXX11Attributes(Attrs);
1602 ParsingDeclSpec PDS(*this);
1603 Ptr = ParseExternalDeclaration(DeclAttrs&: Attrs, DeclSpecAttrs&: EmptyDeclSpecAttrs, DS: &PDS);
1604 }
1605 // The only way we can have a 'none' access specifier that is in a
1606 // not-unspecified tag-type is a C struct. Member functions and
1607 // lambdas don't work in C, so we can just count on
1608 // ActonRoutineDeclDirective to recognize that Ptr is null and diagnose.
1609 } else {
1610 Ptr = ParseCXXClassMemberDeclarationWithPragmas(AS, AccessAttrs&: Attrs, TagType,
1611 Tag: TagDecl);
1612 }
1613 }
1614 }
1615
1616 return DeclGroupPtrTy::make(
1617 P: getActions().OpenACC().ActOnEndRoutineDeclDirective(
1618 StartLoc: DirInfo.StartLoc, DirLoc: DirInfo.DirLoc, LParenLoc: DirInfo.LParenLoc,
1619 ReferencedFunc: DirInfo.Exprs.empty() ? nullptr : DirInfo.Exprs.front(),
1620 RParenLoc: DirInfo.RParenLoc, Clauses: DirInfo.Clauses, EndLoc: DirInfo.EndLoc, NextDecl: Ptr));
1621}
1622
1623StmtResult
1624Parser::ParseOpenACCAfterRoutineStmt(OpenACCDirectiveParseInfo &DirInfo) {
1625 assert(DirInfo.DirKind == OpenACCDirectiveKind::Routine);
1626 // We have to know the next statement for 1 of 2 reasons:
1627 // Routine without a name needs an associated DeclStmt.
1628 // Routine WITH a name needs to see if it is a DeclStmt to diagnose.
1629 StmtResult NextStmt = StmtEmpty();
1630
1631 // Parse the next statement in the 'implicit' case, not in the 'named' case.
1632 // In the 'named' case we will use the creation of the next decl to determine
1633 // whether we should warn.
1634 if (DirInfo.LParenLoc.isInvalid()) {
1635 ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
1636 NextStmt = ParseStatement();
1637 }
1638
1639 return getActions().OpenACC().ActOnEndRoutineStmtDirective(
1640 StartLoc: DirInfo.StartLoc, DirLoc: DirInfo.DirLoc, LParenLoc: DirInfo.LParenLoc,
1641 ReferencedFunc: DirInfo.Exprs.empty() ? nullptr : DirInfo.Exprs.front(),
1642 RParenLoc: DirInfo.RParenLoc, Clauses: DirInfo.Clauses, EndLoc: DirInfo.EndLoc, NextStmt: NextStmt.get());
1643}
1644
1645Parser::DeclGroupPtrTy
1646Parser::ParseOpenACCDirectiveDecl(AccessSpecifier &AS, ParsedAttributes &Attrs,
1647 DeclSpec::TST TagType, Decl *TagDecl) {
1648 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
1649
1650 ParsingOpenACCDirectiveRAII DirScope(*this);
1651
1652 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();
1653
1654 if (getActions().OpenACC().ActOnStartDeclDirective(
1655 K: DirInfo.DirKind, StartLoc: DirInfo.StartLoc, Clauses: DirInfo.Clauses))
1656 return nullptr;
1657
1658 if (DirInfo.DirKind == OpenACCDirectiveKind::Routine)
1659 return ParseOpenACCAfterRoutineDecl(AS, Attrs, TagType, TagDecl, DirInfo);
1660
1661 return DeclGroupPtrTy::make(P: getActions().OpenACC().ActOnEndDeclDirective(
1662 K: DirInfo.DirKind, StartLoc: DirInfo.StartLoc, DirLoc: DirInfo.DirLoc, LParenLoc: DirInfo.LParenLoc,
1663 RParenLoc: DirInfo.RParenLoc, EndLoc: DirInfo.EndLoc, Clauses: DirInfo.Clauses));
1664}
1665
1666StmtResult Parser::ParseOpenACCDirectiveStmt() {
1667 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
1668
1669 ParsingOpenACCDirectiveRAII DirScope(*this);
1670
1671 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();
1672 if (getActions().OpenACC().ActOnStartStmtDirective(
1673 K: DirInfo.DirKind, StartLoc: DirInfo.StartLoc, Clauses: DirInfo.Clauses))
1674 return StmtError();
1675
1676 if (DirInfo.DirKind == OpenACCDirectiveKind::Routine)
1677 return ParseOpenACCAfterRoutineStmt(DirInfo);
1678
1679 StmtResult AssocStmt;
1680 if (doesDirectiveHaveAssociatedStmt(DirKind: DirInfo.DirKind)) {
1681 SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(
1682 getActions().OpenACC(), DirInfo.DirKind, DirInfo.DirLoc, {},
1683 DirInfo.Clauses);
1684 ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
1685 ParseScope ACCScope(this, getOpenACCScopeFlags(DirKind: DirInfo.DirKind));
1686
1687 AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(
1688 DirectiveLoc: DirInfo.StartLoc, K: DirInfo.DirKind, AtKind: DirInfo.AtomicKind, Clauses: DirInfo.Clauses,
1689 AssocStmt: ParseStatement());
1690 }
1691
1692 return getActions().OpenACC().ActOnEndStmtDirective(
1693 K: DirInfo.DirKind, StartLoc: DirInfo.StartLoc, DirLoc: DirInfo.DirLoc, LParenLoc: DirInfo.LParenLoc,
1694 MiscLoc: DirInfo.MiscLoc, Exprs: DirInfo.Exprs, AK: DirInfo.AtomicKind, RParenLoc: DirInfo.RParenLoc,
1695 EndLoc: DirInfo.EndLoc, Clauses: DirInfo.Clauses, AssocStmt);
1696}
1697