@@ -45,6 +45,7 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(StringRef Name) {
45
45
.Case (" data" , OpenACCDirectiveKind::Data)
46
46
.Case (" host_data" , OpenACCDirectiveKind::HostData)
47
47
.Case (" loop" , OpenACCDirectiveKind::Loop)
48
+ .Case (" cache" , OpenACCDirectiveKind::Cache)
48
49
.Case (" atomic" , OpenACCDirectiveKind::Atomic)
49
50
.Case (" routine" , OpenACCDirectiveKind::Routine)
50
51
.Case (" declare" , OpenACCDirectiveKind::Declare)
@@ -88,6 +89,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
88
89
return Tok == " host_data" ;
89
90
case OpenACCDirectiveKind::Loop:
90
91
return Tok == " loop" ;
92
+ case OpenACCDirectiveKind::Cache:
93
+ return Tok == " cache" ;
91
94
92
95
case OpenACCDirectiveKind::ParallelLoop:
93
96
case OpenACCDirectiveKind::SerialLoop:
@@ -237,19 +240,18 @@ void ParseOpenACCClauseList(Parser &P) {
237
240
238
241
} // namespace
239
242
240
- // Routine has an optional paren-wrapped name of a function in the local scope.
241
- // We parse the name, emitting any diagnostics
242
- ExprResult Parser::ParseOpenACCRoutineName () {
243
-
243
+ ExprResult Parser::ParseOpenACCIDExpression () {
244
244
ExprResult Res;
245
245
if (getLangOpts ().CPlusPlus ) {
246
246
Res = ParseCXXIdExpression (/* isAddressOfOperand=*/ false );
247
247
} else {
248
248
// There isn't anything quite the same as ParseCXXIdExpression for C, so we
249
249
// need to get the identifier, then call into Sema ourselves.
250
250
251
- if (expectIdentifier ())
251
+ if (Tok.isNot (tok::identifier)) {
252
+ Diag (Tok, diag::err_expected) << tok::identifier;
252
253
return ExprError ();
254
+ }
253
255
254
256
Token FuncName = getCurToken ();
255
257
UnqualifiedId Name;
@@ -268,6 +270,86 @@ ExprResult Parser::ParseOpenACCRoutineName() {
268
270
return getActions ().CorrectDelayedTyposInExpr (Res);
269
271
}
270
272
273
+ // / OpenACC 3.3, section 2.10:
274
+ // / A 'var' in a cache directive must be a single array element or a simple
275
+ // / subarray. In C and C++, a simple subarray is an array name followed by an
276
+ // / extended array range specification in brackets, with a start and length such
277
+ // / as:
278
+ // /
279
+ // / arr[lower:length]
280
+ // /
281
+ bool Parser::ParseOpenACCCacheVar () {
282
+ ExprResult ArrayName = ParseOpenACCIDExpression ();
283
+ if (ArrayName.isInvalid ())
284
+ return true ;
285
+
286
+ // If the expression is invalid, just continue parsing the brackets, there
287
+ // is likely other useful diagnostics we can emit inside of those.
288
+
289
+ BalancedDelimiterTracker SquareBrackets (*this , tok::l_square,
290
+ tok::annot_pragma_openacc_end);
291
+
292
+ // Square brackets are required, so error here, and try to recover by moving
293
+ // until the next comma, or the close paren/end of pragma.
294
+ if (SquareBrackets.expectAndConsume ()) {
295
+ SkipUntil (tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
296
+ Parser::StopBeforeMatch);
297
+ return true ;
298
+ }
299
+
300
+ ExprResult Lower = getActions ().CorrectDelayedTyposInExpr (ParseExpression ());
301
+ if (Lower.isInvalid ())
302
+ return true ;
303
+
304
+ // The 'length' expression is optional, as this could be a single array
305
+ // element. If there is no colon, we can treat it as that.
306
+ if (getCurToken ().is (tok::colon)) {
307
+ ConsumeToken ();
308
+ ExprResult Length =
309
+ getActions ().CorrectDelayedTyposInExpr (ParseExpression ());
310
+ if (Length.isInvalid ())
311
+ return true ;
312
+ }
313
+
314
+ // Diagnose the square bracket being in the wrong place and continue.
315
+ return SquareBrackets.consumeClose ();
316
+ }
317
+
318
+ // / OpenACC 3.3, section 2.10:
319
+ // / In C and C++, the syntax of the cache directive is:
320
+ // /
321
+ // / #pragma acc cache ([readonly:]var-list) new-line
322
+ void Parser::ParseOpenACCCacheVarList () {
323
+ // If this is the end of the line, just return 'false' and count on the close
324
+ // paren diagnostic to catch the issue.
325
+ if (getCurToken ().isAnnotation ())
326
+ return ;
327
+
328
+ // The VarList is an optional `readonly:` followed by a list of a variable
329
+ // specifications. First, see if we have `readonly:`, else we back-out and
330
+ // treat it like the beginning of a reference to a potentially-existing
331
+ // `readonly` variable.
332
+ if (getCurToken ().is (tok::identifier) &&
333
+ getCurToken ().getIdentifierInfo ()->isStr (" readonly" ) &&
334
+ NextToken ().is (tok::colon)) {
335
+ // Consume both tokens.
336
+ ConsumeToken ();
337
+ ConsumeToken ();
338
+ // FIXME: Record that this is a 'readonly' so that we can use that during
339
+ // Sema/AST generation.
340
+ }
341
+
342
+ bool FirstArray = true ;
343
+ while (!getCurToken ().isOneOf (tok::r_paren, tok::annot_pragma_openacc_end)) {
344
+ if (!FirstArray)
345
+ ExpectAndConsume (tok::comma);
346
+ FirstArray = false ;
347
+ if (ParseOpenACCCacheVar ())
348
+ SkipUntil (tok::r_paren, tok::annot_pragma_openacc_end, tok::comma,
349
+ StopBeforeMatch);
350
+ }
351
+ }
352
+
271
353
void Parser::ParseOpenACCDirective () {
272
354
OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind (*this );
273
355
@@ -289,7 +371,9 @@ void Parser::ParseOpenACCDirective() {
289
371
T.skipToEnd ();
290
372
break ;
291
373
case OpenACCDirectiveKind::Routine: {
292
- ExprResult RoutineName = ParseOpenACCRoutineName ();
374
+ // Routine has an optional paren-wrapped name of a function in the local
375
+ // scope. We parse the name, emitting any diagnostics
376
+ ExprResult RoutineName = ParseOpenACCIDExpression ();
293
377
// If the routine name is invalid, just skip until the closing paren to
294
378
// recover more gracefully.
295
379
if (RoutineName.isInvalid ())
@@ -298,7 +382,18 @@ void Parser::ParseOpenACCDirective() {
298
382
T.consumeClose ();
299
383
break ;
300
384
}
385
+ case OpenACCDirectiveKind::Cache:
386
+ ParseOpenACCCacheVarList ();
387
+ // The ParseOpenACCCacheVarList function manages to recover from failures,
388
+ // so we can always consume the close.
389
+ T.consumeClose ();
390
+ break ;
301
391
}
392
+ } else if (DirKind == OpenACCDirectiveKind::Cache) {
393
+ // Cache's paren var-list is required, so error here if it isn't provided.
394
+ // We know that the consumeOpen above left the first non-paren here, so
395
+ // diagnose, then continue as if it was completely omitted.
396
+ Diag (Tok, diag::err_expected) << tok::l_paren;
302
397
}
303
398
304
399
// Parses the list of clauses, if present.
0 commit comments