@@ -45,6 +45,7 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(StringRef Name) {
4545 .Case (" data" , OpenACCDirectiveKind::Data)
4646 .Case (" host_data" , OpenACCDirectiveKind::HostData)
4747 .Case (" loop" , OpenACCDirectiveKind::Loop)
48+ .Case (" cache" , OpenACCDirectiveKind::Cache)
4849 .Case (" atomic" , OpenACCDirectiveKind::Atomic)
4950 .Case (" routine" , OpenACCDirectiveKind::Routine)
5051 .Case (" declare" , OpenACCDirectiveKind::Declare)
@@ -88,6 +89,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
8889 return Tok == " host_data" ;
8990 case OpenACCDirectiveKind::Loop:
9091 return Tok == " loop" ;
92+ case OpenACCDirectiveKind::Cache:
93+ return Tok == " cache" ;
9194
9295 case OpenACCDirectiveKind::ParallelLoop:
9396 case OpenACCDirectiveKind::SerialLoop:
@@ -237,19 +240,18 @@ void ParseOpenACCClauseList(Parser &P) {
237240
238241} // namespace
239242
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 () {
244244 ExprResult Res;
245245 if (getLangOpts ().CPlusPlus ) {
246246 Res = ParseCXXIdExpression (/* isAddressOfOperand=*/ false );
247247 } else {
248248 // There isn't anything quite the same as ParseCXXIdExpression for C, so we
249249 // need to get the identifier, then call into Sema ourselves.
250250
251- if (expectIdentifier ())
251+ if (Tok.isNot (tok::identifier)) {
252+ Diag (Tok, diag::err_expected) << tok::identifier;
252253 return ExprError ();
254+ }
253255
254256 Token FuncName = getCurToken ();
255257 UnqualifiedId Name;
@@ -268,6 +270,86 @@ ExprResult Parser::ParseOpenACCRoutineName() {
268270 return getActions ().CorrectDelayedTyposInExpr (Res);
269271}
270272
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+
271353void Parser::ParseOpenACCDirective () {
272354 OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind (*this );
273355
@@ -289,7 +371,9 @@ void Parser::ParseOpenACCDirective() {
289371 T.skipToEnd ();
290372 break ;
291373 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 ();
293377 // If the routine name is invalid, just skip until the closing paren to
294378 // recover more gracefully.
295379 if (RoutineName.isInvalid ())
@@ -298,7 +382,18 @@ void Parser::ParseOpenACCDirective() {
298382 T.consumeClose ();
299383 break ;
300384 }
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 ;
301391 }
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;
302397 }
303398
304399 // Parses the list of clauses, if present.
0 commit comments