xref: /freebsd-src/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===//
2*5f757f3fSDimitry Andric //
3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f757f3fSDimitry Andric //
7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
8*5f757f3fSDimitry Andric //
9*5f757f3fSDimitry Andric // This file implements the parsing logic for OpenACC language features.
10*5f757f3fSDimitry Andric //
11*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
12*5f757f3fSDimitry Andric 
13*5f757f3fSDimitry Andric #include "clang/Basic/OpenACCKinds.h"
14*5f757f3fSDimitry Andric #include "clang/Parse/ParseDiagnostic.h"
15*5f757f3fSDimitry Andric #include "clang/Parse/Parser.h"
16*5f757f3fSDimitry Andric #include "clang/Parse/RAIIObjectsForParser.h"
17*5f757f3fSDimitry Andric #include "llvm/ADT/StringRef.h"
18*5f757f3fSDimitry Andric #include "llvm/ADT/StringSwitch.h"
19*5f757f3fSDimitry Andric 
20*5f757f3fSDimitry Andric using namespace clang;
21*5f757f3fSDimitry Andric using namespace llvm;
22*5f757f3fSDimitry Andric 
23*5f757f3fSDimitry Andric namespace {
24*5f757f3fSDimitry Andric // An enum that contains the extended 'partial' parsed variants. This type
25*5f757f3fSDimitry Andric // should never escape the initial parse functionality, but is useful for
26*5f757f3fSDimitry Andric // simplifying the implementation.
27*5f757f3fSDimitry Andric enum class OpenACCDirectiveKindEx {
28*5f757f3fSDimitry Andric   Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
29*5f757f3fSDimitry Andric   // 'enter data' and 'exit data'
30*5f757f3fSDimitry Andric   Enter,
31*5f757f3fSDimitry Andric   Exit,
32*5f757f3fSDimitry Andric };
33*5f757f3fSDimitry Andric 
34*5f757f3fSDimitry Andric // Translate single-token string representations to the OpenACC Directive Kind.
35*5f757f3fSDimitry Andric // This doesn't completely comprehend 'Compound Constructs' (as it just
36*5f757f3fSDimitry Andric // identifies the first token), and doesn't fully handle 'enter data', 'exit
37*5f757f3fSDimitry Andric // data', nor any of the 'atomic' variants, just the first token of each.  So
38*5f757f3fSDimitry Andric // this should only be used by `ParseOpenACCDirectiveKind`.
39*5f757f3fSDimitry Andric OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
40*5f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
41*5f757f3fSDimitry Andric     return OpenACCDirectiveKindEx::Invalid;
42*5f757f3fSDimitry Andric   OpenACCDirectiveKind DirKind =
43*5f757f3fSDimitry Andric       llvm::StringSwitch<OpenACCDirectiveKind>(
44*5f757f3fSDimitry Andric           Tok.getIdentifierInfo()->getName())
45*5f757f3fSDimitry Andric           .Case("parallel", OpenACCDirectiveKind::Parallel)
46*5f757f3fSDimitry Andric           .Case("serial", OpenACCDirectiveKind::Serial)
47*5f757f3fSDimitry Andric           .Case("kernels", OpenACCDirectiveKind::Kernels)
48*5f757f3fSDimitry Andric           .Case("data", OpenACCDirectiveKind::Data)
49*5f757f3fSDimitry Andric           .Case("host_data", OpenACCDirectiveKind::HostData)
50*5f757f3fSDimitry Andric           .Case("loop", OpenACCDirectiveKind::Loop)
51*5f757f3fSDimitry Andric           .Case("cache", OpenACCDirectiveKind::Cache)
52*5f757f3fSDimitry Andric           .Case("atomic", OpenACCDirectiveKind::Atomic)
53*5f757f3fSDimitry Andric           .Case("routine", OpenACCDirectiveKind::Routine)
54*5f757f3fSDimitry Andric           .Case("declare", OpenACCDirectiveKind::Declare)
55*5f757f3fSDimitry Andric           .Case("init", OpenACCDirectiveKind::Init)
56*5f757f3fSDimitry Andric           .Case("shutdown", OpenACCDirectiveKind::Shutdown)
57*5f757f3fSDimitry Andric           .Case("set", OpenACCDirectiveKind::Shutdown)
58*5f757f3fSDimitry Andric           .Case("update", OpenACCDirectiveKind::Update)
59*5f757f3fSDimitry Andric           .Case("wait", OpenACCDirectiveKind::Wait)
60*5f757f3fSDimitry Andric           .Default(OpenACCDirectiveKind::Invalid);
61*5f757f3fSDimitry Andric 
62*5f757f3fSDimitry Andric   if (DirKind != OpenACCDirectiveKind::Invalid)
63*5f757f3fSDimitry Andric     return static_cast<OpenACCDirectiveKindEx>(DirKind);
64*5f757f3fSDimitry Andric 
65*5f757f3fSDimitry Andric   return llvm::StringSwitch<OpenACCDirectiveKindEx>(
66*5f757f3fSDimitry Andric              Tok.getIdentifierInfo()->getName())
67*5f757f3fSDimitry Andric       .Case("enter", OpenACCDirectiveKindEx::Enter)
68*5f757f3fSDimitry Andric       .Case("exit", OpenACCDirectiveKindEx::Exit)
69*5f757f3fSDimitry Andric       .Default(OpenACCDirectiveKindEx::Invalid);
70*5f757f3fSDimitry Andric }
71*5f757f3fSDimitry Andric 
72*5f757f3fSDimitry Andric // Since 'atomic' is effectively a compound directive, this will decode the
73*5f757f3fSDimitry Andric // second part of the directive.
74*5f757f3fSDimitry Andric OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
75*5f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
76*5f757f3fSDimitry Andric     return OpenACCAtomicKind::Invalid;
77*5f757f3fSDimitry Andric   return llvm::StringSwitch<OpenACCAtomicKind>(
78*5f757f3fSDimitry Andric              Tok.getIdentifierInfo()->getName())
79*5f757f3fSDimitry Andric       .Case("read", OpenACCAtomicKind::Read)
80*5f757f3fSDimitry Andric       .Case("write", OpenACCAtomicKind::Write)
81*5f757f3fSDimitry Andric       .Case("update", OpenACCAtomicKind::Update)
82*5f757f3fSDimitry Andric       .Case("capture", OpenACCAtomicKind::Capture)
83*5f757f3fSDimitry Andric       .Default(OpenACCAtomicKind::Invalid);
84*5f757f3fSDimitry Andric }
85*5f757f3fSDimitry Andric 
86*5f757f3fSDimitry Andric enum class OpenACCSpecialTokenKind {
87*5f757f3fSDimitry Andric   ReadOnly,
88*5f757f3fSDimitry Andric   DevNum,
89*5f757f3fSDimitry Andric   Queues,
90*5f757f3fSDimitry Andric };
91*5f757f3fSDimitry Andric 
92*5f757f3fSDimitry Andric bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
93*5f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
94*5f757f3fSDimitry Andric     return false;
95*5f757f3fSDimitry Andric 
96*5f757f3fSDimitry Andric   switch (Kind) {
97*5f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::ReadOnly:
98*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("readonly");
99*5f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::DevNum:
100*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("devnum");
101*5f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::Queues:
102*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("queues");
103*5f757f3fSDimitry Andric   }
104*5f757f3fSDimitry Andric   llvm_unreachable("Unknown 'Kind' Passed");
105*5f757f3fSDimitry Andric }
106*5f757f3fSDimitry Andric 
107*5f757f3fSDimitry Andric bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
108*5f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
109*5f757f3fSDimitry Andric     return false;
110*5f757f3fSDimitry Andric 
111*5f757f3fSDimitry Andric   switch (Kind) {
112*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Parallel:
113*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("parallel");
114*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Serial:
115*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("serial");
116*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Kernels:
117*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("kernels");
118*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Data:
119*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("data");
120*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::HostData:
121*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("host_data");
122*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Loop:
123*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("loop");
124*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Cache:
125*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("cache");
126*5f757f3fSDimitry Andric 
127*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::ParallelLoop:
128*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::SerialLoop:
129*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::KernelsLoop:
130*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::EnterData:
131*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::ExitData:
132*5f757f3fSDimitry Andric     return false;
133*5f757f3fSDimitry Andric 
134*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Atomic:
135*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("atomic");
136*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Routine:
137*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("routine");
138*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Declare:
139*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("declare");
140*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Init:
141*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("init");
142*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Shutdown:
143*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("shutdown");
144*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Set:
145*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("set");
146*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Update:
147*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("update");
148*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Wait:
149*5f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("wait");
150*5f757f3fSDimitry Andric   case OpenACCDirectiveKind::Invalid:
151*5f757f3fSDimitry Andric     return false;
152*5f757f3fSDimitry Andric   }
153*5f757f3fSDimitry Andric   llvm_unreachable("Unknown 'Kind' Passed");
154*5f757f3fSDimitry Andric }
155*5f757f3fSDimitry Andric 
156*5f757f3fSDimitry Andric OpenACCDirectiveKind
157*5f757f3fSDimitry Andric ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
158*5f757f3fSDimitry Andric                                    OpenACCDirectiveKindEx ExtDirKind) {
159*5f757f3fSDimitry Andric   Token SecondTok = P.getCurToken();
160*5f757f3fSDimitry Andric 
161*5f757f3fSDimitry Andric   if (SecondTok.isAnnotation()) {
162*5f757f3fSDimitry Andric     P.Diag(FirstTok, diag::err_acc_invalid_directive)
163*5f757f3fSDimitry Andric         << 0 << FirstTok.getIdentifierInfo();
164*5f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
165*5f757f3fSDimitry Andric   }
166*5f757f3fSDimitry Andric 
167*5f757f3fSDimitry Andric   if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) {
168*5f757f3fSDimitry Andric     if (!SecondTok.is(tok::identifier))
169*5f757f3fSDimitry Andric       P.Diag(SecondTok, diag::err_expected) << tok::identifier;
170*5f757f3fSDimitry Andric     else
171*5f757f3fSDimitry Andric       P.Diag(FirstTok, diag::err_acc_invalid_directive)
172*5f757f3fSDimitry Andric           << 1 << FirstTok.getIdentifierInfo()->getName()
173*5f757f3fSDimitry Andric           << SecondTok.getIdentifierInfo()->getName();
174*5f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
175*5f757f3fSDimitry Andric   }
176*5f757f3fSDimitry Andric 
177*5f757f3fSDimitry Andric   P.ConsumeToken();
178*5f757f3fSDimitry Andric 
179*5f757f3fSDimitry Andric   return ExtDirKind == OpenACCDirectiveKindEx::Enter
180*5f757f3fSDimitry Andric              ? OpenACCDirectiveKind::EnterData
181*5f757f3fSDimitry Andric              : OpenACCDirectiveKind::ExitData;
182*5f757f3fSDimitry Andric }
183*5f757f3fSDimitry Andric 
184*5f757f3fSDimitry Andric OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) {
185*5f757f3fSDimitry Andric   Token AtomicClauseToken = P.getCurToken();
186*5f757f3fSDimitry Andric 
187*5f757f3fSDimitry Andric   // #pragma acc atomic is equivilent to update:
188*5f757f3fSDimitry Andric   if (AtomicClauseToken.isAnnotation())
189*5f757f3fSDimitry Andric     return OpenACCAtomicKind::Update;
190*5f757f3fSDimitry Andric 
191*5f757f3fSDimitry Andric   OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken);
192*5f757f3fSDimitry Andric 
193*5f757f3fSDimitry Andric   // If we don't know what this is, treat it as 'nothing', and treat the rest of
194*5f757f3fSDimitry Andric   // this as a clause list, which, despite being invalid, is likely what the
195*5f757f3fSDimitry Andric   // user was trying to do.
196*5f757f3fSDimitry Andric   if (AtomicKind == OpenACCAtomicKind::Invalid)
197*5f757f3fSDimitry Andric     return OpenACCAtomicKind::Update;
198*5f757f3fSDimitry Andric 
199*5f757f3fSDimitry Andric   P.ConsumeToken();
200*5f757f3fSDimitry Andric   return AtomicKind;
201*5f757f3fSDimitry Andric }
202*5f757f3fSDimitry Andric 
203*5f757f3fSDimitry Andric // Parse and consume the tokens for OpenACC Directive/Construct kinds.
204*5f757f3fSDimitry Andric OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
205*5f757f3fSDimitry Andric   Token FirstTok = P.getCurToken();
206*5f757f3fSDimitry Andric 
207*5f757f3fSDimitry Andric   // Just #pragma acc can get us immediately to the end, make sure we don't
208*5f757f3fSDimitry Andric   // introspect on the spelling before then.
209*5f757f3fSDimitry Andric   if (FirstTok.isNot(tok::identifier)) {
210*5f757f3fSDimitry Andric     P.Diag(FirstTok, diag::err_acc_missing_directive);
211*5f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
212*5f757f3fSDimitry Andric   }
213*5f757f3fSDimitry Andric 
214*5f757f3fSDimitry Andric   P.ConsumeToken();
215*5f757f3fSDimitry Andric 
216*5f757f3fSDimitry Andric   OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok);
217*5f757f3fSDimitry Andric 
218*5f757f3fSDimitry Andric   // OpenACCDirectiveKindEx is meant to be an extended list
219*5f757f3fSDimitry Andric   // over OpenACCDirectiveKind, so any value below Invalid is one of the
220*5f757f3fSDimitry Andric   // OpenACCDirectiveKind values.  This switch takes care of all of the extra
221*5f757f3fSDimitry Andric   // parsing required for the Extended values.  At the end of this block,
222*5f757f3fSDimitry Andric   // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
223*5f757f3fSDimitry Andric   // immediately cast it and use it as that.
224*5f757f3fSDimitry Andric   if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
225*5f757f3fSDimitry Andric     switch (ExDirKind) {
226*5f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Invalid: {
227*5f757f3fSDimitry Andric       P.Diag(FirstTok, diag::err_acc_invalid_directive)
228*5f757f3fSDimitry Andric           << 0 << FirstTok.getIdentifierInfo();
229*5f757f3fSDimitry Andric       return OpenACCDirectiveKind::Invalid;
230*5f757f3fSDimitry Andric     }
231*5f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Enter:
232*5f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Exit:
233*5f757f3fSDimitry Andric       return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind);
234*5f757f3fSDimitry Andric     }
235*5f757f3fSDimitry Andric   }
236*5f757f3fSDimitry Andric 
237*5f757f3fSDimitry Andric   OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);
238*5f757f3fSDimitry Andric 
239*5f757f3fSDimitry Andric   // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
240*5f757f3fSDimitry Andric   // other attempt at a combined construct will be diagnosed as an invalid
241*5f757f3fSDimitry Andric   // clause.
242*5f757f3fSDimitry Andric   Token SecondTok = P.getCurToken();
243*5f757f3fSDimitry Andric   if (!SecondTok.isAnnotation() &&
244*5f757f3fSDimitry Andric       isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) {
245*5f757f3fSDimitry Andric     switch (DirKind) {
246*5f757f3fSDimitry Andric     default:
247*5f757f3fSDimitry Andric       // Nothing to do except in the below cases, as they should be diagnosed as
248*5f757f3fSDimitry Andric       // a clause.
249*5f757f3fSDimitry Andric       break;
250*5f757f3fSDimitry Andric     case OpenACCDirectiveKind::Parallel:
251*5f757f3fSDimitry Andric       P.ConsumeToken();
252*5f757f3fSDimitry Andric       return OpenACCDirectiveKind::ParallelLoop;
253*5f757f3fSDimitry Andric     case OpenACCDirectiveKind::Serial:
254*5f757f3fSDimitry Andric       P.ConsumeToken();
255*5f757f3fSDimitry Andric       return OpenACCDirectiveKind::SerialLoop;
256*5f757f3fSDimitry Andric     case OpenACCDirectiveKind::Kernels:
257*5f757f3fSDimitry Andric       P.ConsumeToken();
258*5f757f3fSDimitry Andric       return OpenACCDirectiveKind::KernelsLoop;
259*5f757f3fSDimitry Andric     }
260*5f757f3fSDimitry Andric   }
261*5f757f3fSDimitry Andric 
262*5f757f3fSDimitry Andric   return DirKind;
263*5f757f3fSDimitry Andric }
264*5f757f3fSDimitry Andric 
265*5f757f3fSDimitry Andric void ParseOpenACCClauseList(Parser &P) {
266*5f757f3fSDimitry Andric   // FIXME: In the future, we'll start parsing the clauses here, but for now we
267*5f757f3fSDimitry Andric   // haven't implemented that, so just emit the unimplemented diagnostic and
268*5f757f3fSDimitry Andric   // fail reasonably.
269*5f757f3fSDimitry Andric   if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
270*5f757f3fSDimitry Andric     P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing);
271*5f757f3fSDimitry Andric }
272*5f757f3fSDimitry Andric 
273*5f757f3fSDimitry Andric } // namespace
274*5f757f3fSDimitry Andric 
275*5f757f3fSDimitry Andric /// OpenACC 3.3, section 2.16:
276*5f757f3fSDimitry Andric /// In this section and throughout the specification, the term wait-argument
277*5f757f3fSDimitry Andric /// means:
278*5f757f3fSDimitry Andric /// [ devnum : int-expr : ] [ queues : ] async-argument-list
279*5f757f3fSDimitry Andric bool Parser::ParseOpenACCWaitArgument() {
280*5f757f3fSDimitry Andric   // [devnum : int-expr : ]
281*5f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
282*5f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
283*5f757f3fSDimitry Andric     // Consume devnum.
284*5f757f3fSDimitry Andric     ConsumeToken();
285*5f757f3fSDimitry Andric     // Consume colon.
286*5f757f3fSDimitry Andric     ConsumeToken();
287*5f757f3fSDimitry Andric 
288*5f757f3fSDimitry Andric     ExprResult IntExpr =
289*5f757f3fSDimitry Andric         getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
290*5f757f3fSDimitry Andric     if (IntExpr.isInvalid())
291*5f757f3fSDimitry Andric       return true;
292*5f757f3fSDimitry Andric 
293*5f757f3fSDimitry Andric     if (ExpectAndConsume(tok::colon))
294*5f757f3fSDimitry Andric       return true;
295*5f757f3fSDimitry Andric   }
296*5f757f3fSDimitry Andric 
297*5f757f3fSDimitry Andric   // [ queues : ]
298*5f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
299*5f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
300*5f757f3fSDimitry Andric     // Consume queues.
301*5f757f3fSDimitry Andric     ConsumeToken();
302*5f757f3fSDimitry Andric     // Consume colon.
303*5f757f3fSDimitry Andric     ConsumeToken();
304*5f757f3fSDimitry Andric   }
305*5f757f3fSDimitry Andric 
306*5f757f3fSDimitry Andric   // OpenACC 3.3, section 2.16:
307*5f757f3fSDimitry Andric   // the term 'async-argument' means a nonnegative scalar integer expression, or
308*5f757f3fSDimitry Andric   // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
309*5f757f3fSDimitry Andric   // in the C header file and the Fortran opacc module.
310*5f757f3fSDimitry Andric   //
311*5f757f3fSDimitry Andric   // We are parsing this simply as list of assignment expressions (to avoid
312*5f757f3fSDimitry Andric   // comma being troublesome), and will ensure it is an integral type.  The
313*5f757f3fSDimitry Andric   // 'special' types are defined as macros, so we can't really check those
314*5f757f3fSDimitry Andric   // (other than perhaps as values at one point?), but the standard does say it
315*5f757f3fSDimitry Andric   // is implementation-defined to use any other negative value.
316*5f757f3fSDimitry Andric   //
317*5f757f3fSDimitry Andric   //
318*5f757f3fSDimitry Andric   bool FirstArg = true;
319*5f757f3fSDimitry Andric   while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
320*5f757f3fSDimitry Andric     if (!FirstArg) {
321*5f757f3fSDimitry Andric       if (ExpectAndConsume(tok::comma))
322*5f757f3fSDimitry Andric         return true;
323*5f757f3fSDimitry Andric     }
324*5f757f3fSDimitry Andric     FirstArg = false;
325*5f757f3fSDimitry Andric 
326*5f757f3fSDimitry Andric     ExprResult CurArg =
327*5f757f3fSDimitry Andric         getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
328*5f757f3fSDimitry Andric 
329*5f757f3fSDimitry Andric     if (CurArg.isInvalid())
330*5f757f3fSDimitry Andric       return true;
331*5f757f3fSDimitry Andric   }
332*5f757f3fSDimitry Andric 
333*5f757f3fSDimitry Andric   return false;
334*5f757f3fSDimitry Andric }
335*5f757f3fSDimitry Andric 
336*5f757f3fSDimitry Andric ExprResult Parser::ParseOpenACCIDExpression() {
337*5f757f3fSDimitry Andric   ExprResult Res;
338*5f757f3fSDimitry Andric   if (getLangOpts().CPlusPlus) {
339*5f757f3fSDimitry Andric     Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false);
340*5f757f3fSDimitry Andric   } else {
341*5f757f3fSDimitry Andric     // There isn't anything quite the same as ParseCXXIdExpression for C, so we
342*5f757f3fSDimitry Andric     // need to get the identifier, then call into Sema ourselves.
343*5f757f3fSDimitry Andric 
344*5f757f3fSDimitry Andric     if (Tok.isNot(tok::identifier)) {
345*5f757f3fSDimitry Andric       Diag(Tok, diag::err_expected) << tok::identifier;
346*5f757f3fSDimitry Andric       return ExprError();
347*5f757f3fSDimitry Andric     }
348*5f757f3fSDimitry Andric 
349*5f757f3fSDimitry Andric     Token FuncName = getCurToken();
350*5f757f3fSDimitry Andric     UnqualifiedId Name;
351*5f757f3fSDimitry Andric     CXXScopeSpec ScopeSpec;
352*5f757f3fSDimitry Andric     SourceLocation TemplateKWLoc;
353*5f757f3fSDimitry Andric     Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());
354*5f757f3fSDimitry Andric 
355*5f757f3fSDimitry Andric     // Ensure this is a valid identifier. We don't accept causing implicit
356*5f757f3fSDimitry Andric     // function declarations per the spec, so always claim to not have trailing
357*5f757f3fSDimitry Andric     // L Paren.
358*5f757f3fSDimitry Andric     Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
359*5f757f3fSDimitry Andric                                     Name, /*HasTrailingLParen=*/false,
360*5f757f3fSDimitry Andric                                     /*isAddressOfOperand=*/false);
361*5f757f3fSDimitry Andric   }
362*5f757f3fSDimitry Andric 
363*5f757f3fSDimitry Andric   return getActions().CorrectDelayedTyposInExpr(Res);
364*5f757f3fSDimitry Andric }
365*5f757f3fSDimitry Andric 
366*5f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10:
367*5f757f3fSDimitry Andric /// A 'var' in a cache directive must be a single array element or a simple
368*5f757f3fSDimitry Andric /// subarray.  In C and C++, a simple subarray is an array name followed by an
369*5f757f3fSDimitry Andric /// extended array range specification in brackets, with a start and length such
370*5f757f3fSDimitry Andric /// as:
371*5f757f3fSDimitry Andric ///
372*5f757f3fSDimitry Andric /// arr[lower:length]
373*5f757f3fSDimitry Andric ///
374*5f757f3fSDimitry Andric bool Parser::ParseOpenACCCacheVar() {
375*5f757f3fSDimitry Andric   ExprResult ArrayName = ParseOpenACCIDExpression();
376*5f757f3fSDimitry Andric   if (ArrayName.isInvalid())
377*5f757f3fSDimitry Andric     return true;
378*5f757f3fSDimitry Andric 
379*5f757f3fSDimitry Andric   // If the expression is invalid, just continue parsing the brackets, there
380*5f757f3fSDimitry Andric   // is likely other useful diagnostics we can emit inside of those.
381*5f757f3fSDimitry Andric 
382*5f757f3fSDimitry Andric   BalancedDelimiterTracker SquareBrackets(*this, tok::l_square,
383*5f757f3fSDimitry Andric                                           tok::annot_pragma_openacc_end);
384*5f757f3fSDimitry Andric 
385*5f757f3fSDimitry Andric   // Square brackets are required, so error here, and try to recover by moving
386*5f757f3fSDimitry Andric   // until the next comma, or the close paren/end of pragma.
387*5f757f3fSDimitry Andric   if (SquareBrackets.expectAndConsume()) {
388*5f757f3fSDimitry Andric     SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
389*5f757f3fSDimitry Andric               Parser::StopBeforeMatch);
390*5f757f3fSDimitry Andric     return true;
391*5f757f3fSDimitry Andric   }
392*5f757f3fSDimitry Andric 
393*5f757f3fSDimitry Andric   ExprResult Lower = getActions().CorrectDelayedTyposInExpr(ParseExpression());
394*5f757f3fSDimitry Andric   if (Lower.isInvalid())
395*5f757f3fSDimitry Andric     return true;
396*5f757f3fSDimitry Andric 
397*5f757f3fSDimitry Andric   // The 'length' expression is optional, as this could be a single array
398*5f757f3fSDimitry Andric   // element. If there is no colon, we can treat it as that.
399*5f757f3fSDimitry Andric   if (getCurToken().is(tok::colon)) {
400*5f757f3fSDimitry Andric     ConsumeToken();
401*5f757f3fSDimitry Andric     ExprResult Length =
402*5f757f3fSDimitry Andric         getActions().CorrectDelayedTyposInExpr(ParseExpression());
403*5f757f3fSDimitry Andric     if (Length.isInvalid())
404*5f757f3fSDimitry Andric       return true;
405*5f757f3fSDimitry Andric   }
406*5f757f3fSDimitry Andric 
407*5f757f3fSDimitry Andric   // Diagnose the square bracket being in the wrong place and continue.
408*5f757f3fSDimitry Andric   return SquareBrackets.consumeClose();
409*5f757f3fSDimitry Andric }
410*5f757f3fSDimitry Andric 
411*5f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10:
412*5f757f3fSDimitry Andric /// In C and C++, the syntax of the cache directive is:
413*5f757f3fSDimitry Andric ///
414*5f757f3fSDimitry Andric /// #pragma acc cache ([readonly:]var-list) new-line
415*5f757f3fSDimitry Andric void Parser::ParseOpenACCCacheVarList() {
416*5f757f3fSDimitry Andric   // If this is the end of the line, just return 'false' and count on the close
417*5f757f3fSDimitry Andric   // paren diagnostic to catch the issue.
418*5f757f3fSDimitry Andric   if (getCurToken().isAnnotation())
419*5f757f3fSDimitry Andric     return;
420*5f757f3fSDimitry Andric 
421*5f757f3fSDimitry Andric   // The VarList is an optional `readonly:` followed by a list of a variable
422*5f757f3fSDimitry Andric   // specifications.  First, see if we have `readonly:`, else we back-out and
423*5f757f3fSDimitry Andric   // treat it like the beginning of a reference to a potentially-existing
424*5f757f3fSDimitry Andric   // `readonly` variable.
425*5f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::ReadOnly, Tok) &&
426*5f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
427*5f757f3fSDimitry Andric     // Consume both tokens.
428*5f757f3fSDimitry Andric     ConsumeToken();
429*5f757f3fSDimitry Andric     ConsumeToken();
430*5f757f3fSDimitry Andric     // FIXME: Record that this is a 'readonly' so that we can use that during
431*5f757f3fSDimitry Andric     // Sema/AST generation.
432*5f757f3fSDimitry Andric   }
433*5f757f3fSDimitry Andric 
434*5f757f3fSDimitry Andric   bool FirstArray = true;
435*5f757f3fSDimitry Andric   while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
436*5f757f3fSDimitry Andric     if (!FirstArray)
437*5f757f3fSDimitry Andric       ExpectAndConsume(tok::comma);
438*5f757f3fSDimitry Andric     FirstArray = false;
439*5f757f3fSDimitry Andric     if (ParseOpenACCCacheVar())
440*5f757f3fSDimitry Andric       SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma,
441*5f757f3fSDimitry Andric                 StopBeforeMatch);
442*5f757f3fSDimitry Andric   }
443*5f757f3fSDimitry Andric }
444*5f757f3fSDimitry Andric 
445*5f757f3fSDimitry Andric void Parser::ParseOpenACCDirective() {
446*5f757f3fSDimitry Andric   OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);
447*5f757f3fSDimitry Andric 
448*5f757f3fSDimitry Andric   // Once we've parsed the construct/directive name, some have additional
449*5f757f3fSDimitry Andric   // specifiers that need to be taken care of. Atomic has an 'atomic-clause'
450*5f757f3fSDimitry Andric   // that needs to be parsed.
451*5f757f3fSDimitry Andric   if (DirKind == OpenACCDirectiveKind::Atomic)
452*5f757f3fSDimitry Andric     ParseOpenACCAtomicKind(*this);
453*5f757f3fSDimitry Andric 
454*5f757f3fSDimitry Andric   // We've successfully parsed the construct/directive name, however a few of
455*5f757f3fSDimitry Andric   // the constructs have optional parens that contain further details.
456*5f757f3fSDimitry Andric   BalancedDelimiterTracker T(*this, tok::l_paren,
457*5f757f3fSDimitry Andric                              tok::annot_pragma_openacc_end);
458*5f757f3fSDimitry Andric 
459*5f757f3fSDimitry Andric   if (!T.consumeOpen()) {
460*5f757f3fSDimitry Andric     switch (DirKind) {
461*5f757f3fSDimitry Andric     default:
462*5f757f3fSDimitry Andric       Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
463*5f757f3fSDimitry Andric       T.skipToEnd();
464*5f757f3fSDimitry Andric       break;
465*5f757f3fSDimitry Andric     case OpenACCDirectiveKind::Routine: {
466*5f757f3fSDimitry Andric       // Routine has an optional paren-wrapped name of a function in the local
467*5f757f3fSDimitry Andric       // scope. We parse the name, emitting any diagnostics
468*5f757f3fSDimitry Andric       ExprResult RoutineName = ParseOpenACCIDExpression();
469*5f757f3fSDimitry Andric       // If the routine name is invalid, just skip until the closing paren to
470*5f757f3fSDimitry Andric       // recover more gracefully.
471*5f757f3fSDimitry Andric       if (RoutineName.isInvalid())
472*5f757f3fSDimitry Andric         T.skipToEnd();
473*5f757f3fSDimitry Andric       else
474*5f757f3fSDimitry Andric         T.consumeClose();
475*5f757f3fSDimitry Andric       break;
476*5f757f3fSDimitry Andric     }
477*5f757f3fSDimitry Andric     case OpenACCDirectiveKind::Cache:
478*5f757f3fSDimitry Andric       ParseOpenACCCacheVarList();
479*5f757f3fSDimitry Andric       // The ParseOpenACCCacheVarList function manages to recover from failures,
480*5f757f3fSDimitry Andric       // so we can always consume the close.
481*5f757f3fSDimitry Andric       T.consumeClose();
482*5f757f3fSDimitry Andric       break;
483*5f757f3fSDimitry Andric     case OpenACCDirectiveKind::Wait:
484*5f757f3fSDimitry Andric       // OpenACC has an optional paren-wrapped 'wait-argument'.
485*5f757f3fSDimitry Andric       if (ParseOpenACCWaitArgument())
486*5f757f3fSDimitry Andric         T.skipToEnd();
487*5f757f3fSDimitry Andric       else
488*5f757f3fSDimitry Andric         T.consumeClose();
489*5f757f3fSDimitry Andric       break;
490*5f757f3fSDimitry Andric     }
491*5f757f3fSDimitry Andric   } else if (DirKind == OpenACCDirectiveKind::Cache) {
492*5f757f3fSDimitry Andric     // Cache's paren var-list is required, so error here if it isn't provided.
493*5f757f3fSDimitry Andric     // We know that the consumeOpen above left the first non-paren here, so
494*5f757f3fSDimitry Andric     // diagnose, then continue as if it was completely omitted.
495*5f757f3fSDimitry Andric     Diag(Tok, diag::err_expected) << tok::l_paren;
496*5f757f3fSDimitry Andric   }
497*5f757f3fSDimitry Andric 
498*5f757f3fSDimitry Andric   // Parses the list of clauses, if present.
499*5f757f3fSDimitry Andric   ParseOpenACCClauseList(*this);
500*5f757f3fSDimitry Andric 
501*5f757f3fSDimitry Andric   Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
502*5f757f3fSDimitry Andric   SkipUntil(tok::annot_pragma_openacc_end);
503*5f757f3fSDimitry Andric }
504*5f757f3fSDimitry Andric 
505*5f757f3fSDimitry Andric // Parse OpenACC directive on a declaration.
506*5f757f3fSDimitry Andric Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
507*5f757f3fSDimitry Andric   assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
508*5f757f3fSDimitry Andric 
509*5f757f3fSDimitry Andric   ParsingOpenACCDirectiveRAII DirScope(*this);
510*5f757f3fSDimitry Andric   ConsumeAnnotationToken();
511*5f757f3fSDimitry Andric 
512*5f757f3fSDimitry Andric   ParseOpenACCDirective();
513*5f757f3fSDimitry Andric 
514*5f757f3fSDimitry Andric   return nullptr;
515*5f757f3fSDimitry Andric }
516*5f757f3fSDimitry Andric 
517*5f757f3fSDimitry Andric // Parse OpenACC Directive on a Statement.
518*5f757f3fSDimitry Andric StmtResult Parser::ParseOpenACCDirectiveStmt() {
519*5f757f3fSDimitry Andric   assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
520*5f757f3fSDimitry Andric 
521*5f757f3fSDimitry Andric   ParsingOpenACCDirectiveRAII DirScope(*this);
522*5f757f3fSDimitry Andric   ConsumeAnnotationToken();
523*5f757f3fSDimitry Andric 
524*5f757f3fSDimitry Andric   ParseOpenACCDirective();
525*5f757f3fSDimitry Andric 
526*5f757f3fSDimitry Andric   return StmtEmpty();
527*5f757f3fSDimitry Andric }
528