@@ -69,6 +69,29 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
69
69
.Default (OpenACCDirectiveKindEx::Invalid);
70
70
}
71
71
72
+ // Translate single-token string representations to the OpenCC Clause Kind.
73
+ OpenACCClauseKind getOpenACCClauseKind (Token Tok) {
74
+ // auto is a keyword in some language modes, so make sure we parse it
75
+ // correctly.
76
+ if (Tok.is (tok::kw_auto))
77
+ return OpenACCClauseKind::Auto;
78
+
79
+ if (!Tok.is (tok::identifier))
80
+ return OpenACCClauseKind::Invalid;
81
+
82
+ return llvm::StringSwitch<OpenACCClauseKind>(
83
+ Tok.getIdentifierInfo ()->getName ())
84
+ .Case (" auto" , OpenACCClauseKind::Auto)
85
+ .Case (" finalize" , OpenACCClauseKind::Finalize)
86
+ .Case (" if_present" , OpenACCClauseKind::IfPresent)
87
+ .Case (" independent" , OpenACCClauseKind::Independent)
88
+ .Case (" nohost" , OpenACCClauseKind::NoHost)
89
+ .Case (" seq" , OpenACCClauseKind::Seq)
90
+ .Case (" vector" , OpenACCClauseKind::Vector)
91
+ .Case (" worker" , OpenACCClauseKind::Worker)
92
+ .Default (OpenACCClauseKind::Invalid);
93
+ }
94
+
72
95
// Since 'atomic' is effectively a compound directive, this will decode the
73
96
// second part of the directive.
74
97
OpenACCAtomicKind getOpenACCAtomicKind (Token Tok) {
@@ -164,6 +187,10 @@ ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
164
187
return OpenACCDirectiveKind::Invalid;
165
188
}
166
189
190
+ // Consume the second name anyway, this way we can continue on without making
191
+ // this oddly look like a clause.
192
+ P.ConsumeAnyToken ();
193
+
167
194
if (!isOpenACCDirectiveKind (OpenACCDirectiveKind::Data, SecondTok)) {
168
195
if (!SecondTok.is (tok::identifier))
169
196
P.Diag (SecondTok, diag::err_expected) << tok::identifier;
@@ -174,8 +201,6 @@ ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
174
201
return OpenACCDirectiveKind::Invalid;
175
202
}
176
203
177
- P.ConsumeToken ();
178
-
179
204
return ExtDirKind == OpenACCDirectiveKindEx::Enter
180
205
? OpenACCDirectiveKind::EnterData
181
206
: OpenACCDirectiveKind::ExitData;
@@ -208,6 +233,10 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
208
233
// introspect on the spelling before then.
209
234
if (FirstTok.isNot (tok::identifier)) {
210
235
P.Diag (FirstTok, diag::err_acc_missing_directive);
236
+
237
+ if (P.getCurToken ().isNot (tok::annot_pragma_openacc_end))
238
+ P.ConsumeAnyToken ();
239
+
211
240
return OpenACCDirectiveKind::Invalid;
212
241
}
213
242
@@ -262,12 +291,57 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
262
291
return DirKind;
263
292
}
264
293
294
+ // The OpenACC Clause List is a comma or space-delimited list of clauses (see
295
+ // the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
296
+ // really have its owner grammar and each individual one has its own definition.
297
+ // However, they all are named with a single-identifier (or auto!) token,
298
+ // followed in some cases by either braces or parens.
299
+ bool ParseOpenACCClause (Parser &P) {
300
+ if (!P.getCurToken ().isOneOf (tok::identifier, tok::kw_auto))
301
+ return P.Diag (P.getCurToken (), diag::err_expected) << tok::identifier;
302
+
303
+ OpenACCClauseKind Kind = getOpenACCClauseKind (P.getCurToken ());
304
+
305
+ if (Kind == OpenACCClauseKind::Invalid)
306
+ return P.Diag (P.getCurToken (), diag::err_acc_invalid_clause)
307
+ << P.getCurToken ().getIdentifierInfo ();
308
+
309
+ // Consume the clause name.
310
+ P.ConsumeToken ();
311
+
312
+ // FIXME: For future clauses, we need to handle parens/etc below.
313
+ return false ;
314
+ }
315
+
316
+ // Skip until we see the end of pragma token, but don't consume it. This is us
317
+ // just giving up on the rest of the pragma so we can continue executing. We
318
+ // have to do this because 'SkipUntil' considers paren balancing, which isn't
319
+ // what we want.
320
+ void SkipUntilEndOfDirective (Parser &P) {
321
+ while (P.getCurToken ().isNot (tok::annot_pragma_openacc_end))
322
+ P.ConsumeAnyToken ();
323
+ }
324
+
325
+ // OpenACC 3.3, section 1.7:
326
+ // To simplify the specification and convey appropriate constraint information,
327
+ // a pqr-list is a comma-separated list of pdr items. The one exception is a
328
+ // clause-list, which is a list of one or more clauses optionally separated by
329
+ // commas.
265
330
void ParseOpenACCClauseList (Parser &P) {
266
- // FIXME: In the future, we'll start parsing the clauses here, but for now we
267
- // haven't implemented that, so just emit the unimplemented diagnostic and
268
- // fail reasonably.
269
- if (P.getCurToken ().isNot (tok::annot_pragma_openacc_end))
270
- P.Diag (P.getCurToken (), diag::warn_pragma_acc_unimplemented_clause_parsing);
331
+ bool FirstClause = true ;
332
+ while (P.getCurToken ().isNot (tok::annot_pragma_openacc_end)) {
333
+ // Comma is optional in a clause-list.
334
+ if (!FirstClause && P.getCurToken ().is (tok::comma))
335
+ P.ConsumeToken ();
336
+ FirstClause = false ;
337
+
338
+ // Recovering from a bad clause is really difficult, so we just give up on
339
+ // error.
340
+ if (ParseOpenACCClause (P)) {
341
+ SkipUntilEndOfDirective (P);
342
+ return ;
343
+ }
344
+ }
271
345
}
272
346
273
347
} // namespace
@@ -499,7 +573,9 @@ void Parser::ParseOpenACCDirective() {
499
573
ParseOpenACCClauseList (*this );
500
574
501
575
Diag (getCurToken (), diag::warn_pragma_acc_unimplemented);
502
- SkipUntil (tok::annot_pragma_openacc_end);
576
+ assert (Tok.is (tok::annot_pragma_openacc_end) &&
577
+ " Didn't parse all OpenACC Clauses" );
578
+ ConsumeAnnotationToken ();
503
579
}
504
580
505
581
// Parse OpenACC directive on a declaration.
0 commit comments