diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp | 523 |
1 files changed, 435 insertions, 88 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp b/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp index fc82324e235d..9f7e63ecdc95 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp @@ -89,16 +89,43 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { return llvm::StringSwitch<OpenACCClauseKind>( Tok.getIdentifierInfo()->getName()) + .Case("attach", OpenACCClauseKind::Attach) .Case("auto", OpenACCClauseKind::Auto) + .Case("bind", OpenACCClauseKind::Bind) + .Case("create", OpenACCClauseKind::Create) + .Case("collapse", OpenACCClauseKind::Collapse) + .Case("copy", OpenACCClauseKind::Copy) + .Case("copyin", OpenACCClauseKind::CopyIn) + .Case("copyout", OpenACCClauseKind::CopyOut) .Case("default", OpenACCClauseKind::Default) + .Case("default_async", OpenACCClauseKind::DefaultAsync) + .Case("delete", OpenACCClauseKind::Delete) + .Case("detach", OpenACCClauseKind::Detach) + .Case("device", OpenACCClauseKind::Device) + .Case("device_num", OpenACCClauseKind::DeviceNum) + .Case("device_resident", OpenACCClauseKind::DeviceResident) + .Case("device_type", OpenACCClauseKind::DeviceType) + .Case("deviceptr", OpenACCClauseKind::DevicePtr) + .Case("dtype", OpenACCClauseKind::DType) .Case("finalize", OpenACCClauseKind::Finalize) + .Case("firstprivate", OpenACCClauseKind::FirstPrivate) + .Case("host", OpenACCClauseKind::Host) .Case("if", OpenACCClauseKind::If) .Case("if_present", OpenACCClauseKind::IfPresent) .Case("independent", OpenACCClauseKind::Independent) + .Case("link", OpenACCClauseKind::Link) + .Case("no_create", OpenACCClauseKind::NoCreate) + .Case("num_gangs", OpenACCClauseKind::NumGangs) + .Case("num_workers", OpenACCClauseKind::NumWorkers) .Case("nohost", OpenACCClauseKind::NoHost) + .Case("present", OpenACCClauseKind::Present) + .Case("private", OpenACCClauseKind::Private) + .Case("reduction", OpenACCClauseKind::Reduction) .Case("self", OpenACCClauseKind::Self) .Case("seq", OpenACCClauseKind::Seq) + .Case("use_device", OpenACCClauseKind::UseDevice) .Case("vector", OpenACCClauseKind::Vector) + .Case("vector_length", OpenACCClauseKind::VectorLength) .Case("worker", OpenACCClauseKind::Worker) .Default(OpenACCClauseKind::Invalid); } @@ -132,6 +159,10 @@ enum class OpenACCSpecialTokenKind { ReadOnly, DevNum, Queues, + Zero, + Force, + Num, + Length, }; bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) { @@ -145,10 +176,60 @@ bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) { return Tok.getIdentifierInfo()->isStr("devnum"); case OpenACCSpecialTokenKind::Queues: return Tok.getIdentifierInfo()->isStr("queues"); + case OpenACCSpecialTokenKind::Zero: + return Tok.getIdentifierInfo()->isStr("zero"); + case OpenACCSpecialTokenKind::Force: + return Tok.getIdentifierInfo()->isStr("force"); + case OpenACCSpecialTokenKind::Num: + return Tok.getIdentifierInfo()->isStr("num"); + case OpenACCSpecialTokenKind::Length: + return Tok.getIdentifierInfo()->isStr("length"); } llvm_unreachable("Unknown 'Kind' Passed"); } +/// Used for cases where we have a token we want to check against an +/// 'identifier-like' token, but don't want to give awkward error messages in +/// cases where it is accidentially a keyword. +bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) { + if (Tok.is(tok::identifier)) + return true; + + if (!Tok.isAnnotation() && Tok.getIdentifierInfo() && + Tok.getIdentifierInfo()->isKeyword(P.getLangOpts())) + return true; + + return false; +} + +/// Parses and consumes an identifer followed immediately by a single colon, and +/// diagnoses if it is not the 'special token' kind that we require. Used when +/// the tag is the only valid value. +/// Return 'true' if the special token was matched, false if no special token, +/// or an invalid special token was found. +template <typename DirOrClauseTy> +bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind, + DirOrClauseTy DirOrClause) { + Token IdentTok = P.getCurToken(); + // If this is an identifier-like thing followed by ':', it is one of the + // OpenACC 'special' name tags, so consume it. + if (isTokenIdentifierOrKeyword(P, IdentTok) && P.NextToken().is(tok::colon)) { + P.ConsumeToken(); + P.ConsumeToken(); + + if (!isOpenACCSpecialToken(Kind, IdentTok)) { + P.Diag(IdentTok, diag::err_acc_invalid_tag_kind) + << IdentTok.getIdentifierInfo() << DirOrClause + << std::is_same_v<DirOrClauseTy, OpenACCClauseKind>; + return false; + } + + return true; + } + + return false; +} + bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) { if (!Tok.is(tok::identifier)) return false; @@ -198,16 +279,53 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) { llvm_unreachable("Unknown 'Kind' Passed"); } +OpenACCReductionOperator ParseReductionOperator(Parser &P) { + // If there is no colon, treat as if the reduction operator was missing, else + // we probably will not recover from it in the case where an expression starts + // with one of the operator tokens. + if (P.NextToken().isNot(tok::colon)) { + P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator); + return OpenACCReductionOperator::Invalid; + } + Token ReductionKindTok = P.getCurToken(); + // Consume both the kind and the colon. + P.ConsumeToken(); + P.ConsumeToken(); + + switch (ReductionKindTok.getKind()) { + case tok::plus: + return OpenACCReductionOperator::Addition; + case tok::star: + return OpenACCReductionOperator::Multiplication; + case tok::amp: + return OpenACCReductionOperator::BitwiseAnd; + case tok::pipe: + return OpenACCReductionOperator::BitwiseOr; + case tok::caret: + return OpenACCReductionOperator::BitwiseXOr; + case tok::ampamp: + return OpenACCReductionOperator::And; + case tok::pipepipe: + return OpenACCReductionOperator::Or; + case tok::identifier: + if (ReductionKindTok.getIdentifierInfo()->isStr("max")) + return OpenACCReductionOperator::Max; + if (ReductionKindTok.getIdentifierInfo()->isStr("min")) + return OpenACCReductionOperator::Min; + LLVM_FALLTHROUGH; + default: + P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator); + return OpenACCReductionOperator::Invalid; + } + llvm_unreachable("Reduction op token kind not caught by 'default'?"); +} + /// Used for cases where we expect an identifier-like token, but don't want to /// give awkward error messages in cases where it is accidentially a keyword. bool expectIdentifierOrKeyword(Parser &P) { Token Tok = P.getCurToken(); - if (Tok.is(tok::identifier)) - return false; - - if (!Tok.isAnnotation() && Tok.getIdentifierInfo() && - Tok.getIdentifierInfo()->isKeyword(P.getLangOpts())) + if (isTokenIdentifierOrKeyword(P, Tok)) return false; P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; @@ -329,12 +447,73 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { return DirKind; } -bool ClauseHasOptionalParens(OpenACCClauseKind Kind) { - return Kind == OpenACCClauseKind::Self; +enum ClauseParensKind { + None, + Optional, + Required +}; + +ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind, + OpenACCClauseKind Kind) { + switch (Kind) { + case OpenACCClauseKind::Self: + return DirKind == OpenACCDirectiveKind::Update ? ClauseParensKind::Required + : ClauseParensKind::Optional; + case OpenACCClauseKind::Worker: + case OpenACCClauseKind::Vector: + return ClauseParensKind::Optional; + + case OpenACCClauseKind::Default: + case OpenACCClauseKind::If: + case OpenACCClauseKind::Create: + case OpenACCClauseKind::Copy: + case OpenACCClauseKind::CopyIn: + case OpenACCClauseKind::CopyOut: + case OpenACCClauseKind::UseDevice: + case OpenACCClauseKind::NoCreate: + case OpenACCClauseKind::Present: + case OpenACCClauseKind::DevicePtr: + case OpenACCClauseKind::Attach: + case OpenACCClauseKind::Detach: + case OpenACCClauseKind::Private: + case OpenACCClauseKind::FirstPrivate: + case OpenACCClauseKind::Delete: + case OpenACCClauseKind::DeviceResident: + case OpenACCClauseKind::Device: + case OpenACCClauseKind::Link: + case OpenACCClauseKind::Host: + case OpenACCClauseKind::Reduction: + case OpenACCClauseKind::Collapse: + case OpenACCClauseKind::Bind: + case OpenACCClauseKind::VectorLength: + case OpenACCClauseKind::NumGangs: + case OpenACCClauseKind::NumWorkers: + case OpenACCClauseKind::DeviceNum: + case OpenACCClauseKind::DefaultAsync: + case OpenACCClauseKind::DeviceType: + case OpenACCClauseKind::DType: + return ClauseParensKind::Required; + + case OpenACCClauseKind::Auto: + case OpenACCClauseKind::Finalize: + case OpenACCClauseKind::IfPresent: + case OpenACCClauseKind::Independent: + case OpenACCClauseKind::Invalid: + case OpenACCClauseKind::NoHost: + case OpenACCClauseKind::Seq: + return ClauseParensKind::None; + } + llvm_unreachable("Unhandled clause kind"); } -bool ClauseHasRequiredParens(OpenACCClauseKind Kind) { - return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If; +bool ClauseHasOptionalParens(OpenACCDirectiveKind DirKind, + OpenACCClauseKind Kind) { + return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional; +} + +bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind, + OpenACCClauseKind Kind) { + return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required; } ExprResult ParseOpenACCConditionalExpr(Parser &P) { @@ -345,59 +524,266 @@ ExprResult ParseOpenACCConditionalExpr(Parser &P) { return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression()); } -bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { - BalancedDelimiterTracker Parens(P, tok::l_paren, +// Skip until we see the end of pragma token, but don't consume it. This is us +// just giving up on the rest of the pragma so we can continue executing. We +// have to do this because 'SkipUntil' considers paren balancing, which isn't +// what we want. +void SkipUntilEndOfDirective(Parser &P) { + while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) + P.ConsumeAnyToken(); +} + +} // namespace + +// OpenACC 3.3, section 1.7: +// To simplify the specification and convey appropriate constraint information, +// a pqr-list is a comma-separated list of pdr items. The one exception is a +// clause-list, which is a list of one or more clauses optionally separated by +// commas. +void Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) { + bool FirstClause = true; + while (getCurToken().isNot(tok::annot_pragma_openacc_end)) { + // Comma is optional in a clause-list. + if (!FirstClause && getCurToken().is(tok::comma)) + ConsumeToken(); + FirstClause = false; + + // Recovering from a bad clause is really difficult, so we just give up on + // error. + if (ParseOpenACCClause(DirKind)) { + SkipUntilEndOfDirective(*this); + return; + } + } +} + +ExprResult Parser::ParseOpenACCIntExpr() { + // FIXME: this is required to be an integer expression (or dependent), so we + // should ensure that is the case by passing this to SEMA here. + return getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); +} + +bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) { + // FIXME: Future clauses will require 'special word' parsing, check for one, + // then parse it based on whether it is a clause that requires a 'special + // word'. + (void)Kind; + + // If the var parsing fails, skip until the end of the directive as this is + // an expression and gets messy if we try to continue otherwise. + if (ParseOpenACCVar()) + return true; + + while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { + ExpectAndConsume(tok::comma); + + // If the var parsing fails, skip until the end of the directive as this is + // an expression and gets messy if we try to continue otherwise. + if (ParseOpenACCVar()) + return true; + } + return false; +} + +/// OpenACC 3.3 Section 2.4: +/// The argument to the device_type clause is a comma-separated list of one or +/// more device architecture name identifiers, or an asterisk. +/// +/// The syntax of the device_type clause is +/// device_type( * ) +/// device_type( device-type-list ) +/// +/// The device_type clause may be abbreviated to dtype. +bool Parser::ParseOpenACCDeviceTypeList() { + + if (expectIdentifierOrKeyword(*this)) { + SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, + Parser::StopBeforeMatch); + return false; + } + ConsumeToken(); + + while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { + ExpectAndConsume(tok::comma); + + if (expectIdentifierOrKeyword(*this)) { + SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, + Parser::StopBeforeMatch); + return false; + } + ConsumeToken(); + } + return false; +} + +// The OpenACC Clause List is a comma or space-delimited list of clauses (see +// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't +// really have its owner grammar and each individual one has its own definition. +// However, they all are named with a single-identifier (or auto/default!) +// token, followed in some cases by either braces or parens. +bool Parser::ParseOpenACCClause(OpenACCDirectiveKind DirKind) { + // A number of clause names are actually keywords, so accept a keyword that + // can be converted to a name. + if (expectIdentifierOrKeyword(*this)) + return true; + + OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken()); + + if (Kind == OpenACCClauseKind::Invalid) + return Diag(getCurToken(), diag::err_acc_invalid_clause) + << getCurToken().getIdentifierInfo(); + + // Consume the clause name. + ConsumeToken(); + + return ParseOpenACCClauseParams(DirKind, Kind); +} + +bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, + OpenACCClauseKind Kind) { + BalancedDelimiterTracker Parens(*this, tok::l_paren, tok::annot_pragma_openacc_end); - if (ClauseHasRequiredParens(Kind)) { + if (ClauseHasRequiredParens(DirKind, Kind)) { if (Parens.expectAndConsume()) { // We are missing a paren, so assume that the person just forgot the // parameter. Return 'false' so we try to continue on and parse the next // clause. - P.SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, - Parser::StopBeforeMatch); + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, + Parser::StopBeforeMatch); return false; } switch (Kind) { case OpenACCClauseKind::Default: { - Token DefKindTok = P.getCurToken(); + Token DefKindTok = getCurToken(); - if (expectIdentifierOrKeyword(P)) + if (expectIdentifierOrKeyword(*this)) break; - P.ConsumeToken(); + ConsumeToken(); if (getOpenACCDefaultClauseKind(DefKindTok) == OpenACCDefaultClauseKind::Invalid) - P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind); + Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind); break; } case OpenACCClauseKind::If: { - ExprResult CondExpr = ParseOpenACCConditionalExpr(P); + ExprResult CondExpr = ParseOpenACCConditionalExpr(*this); // An invalid expression can be just about anything, so just give up on // this clause list. if (CondExpr.isInvalid()) return true; break; } + case OpenACCClauseKind::CopyIn: + tryParseAndConsumeSpecialTokenKind( + *this, OpenACCSpecialTokenKind::ReadOnly, Kind); + if (ParseOpenACCClauseVarList(Kind)) + return true; + break; + case OpenACCClauseKind::Create: + case OpenACCClauseKind::CopyOut: + tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Zero, + Kind); + if (ParseOpenACCClauseVarList(Kind)) + return true; + break; + case OpenACCClauseKind::Reduction: + // If we're missing a clause-kind (or it is invalid), see if we can parse + // the var-list anyway. + ParseReductionOperator(*this); + if (ParseOpenACCClauseVarList(Kind)) + return true; + break; + case OpenACCClauseKind::Self: + // The 'self' clause is a var-list instead of a 'condition' in the case of + // the 'update' clause, so we have to handle it here. U se an assert to + // make sure we get the right differentiator. + assert(DirKind == OpenACCDirectiveKind::Update); + LLVM_FALLTHROUGH; + case OpenACCClauseKind::Attach: + case OpenACCClauseKind::Copy: + case OpenACCClauseKind::Delete: + case OpenACCClauseKind::Detach: + case OpenACCClauseKind::Device: + case OpenACCClauseKind::DeviceResident: + case OpenACCClauseKind::DevicePtr: + case OpenACCClauseKind::FirstPrivate: + case OpenACCClauseKind::Host: + case OpenACCClauseKind::Link: + case OpenACCClauseKind::NoCreate: + case OpenACCClauseKind::Present: + case OpenACCClauseKind::Private: + case OpenACCClauseKind::UseDevice: + if (ParseOpenACCClauseVarList(Kind)) + return true; + break; + case OpenACCClauseKind::Collapse: { + tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Force, + Kind); + ExprResult NumLoops = + getActions().CorrectDelayedTyposInExpr(ParseConstantExpression()); + if (NumLoops.isInvalid()) + return true; + break; + } + case OpenACCClauseKind::Bind: { + ExprResult BindArg = ParseOpenACCBindClauseArgument(); + if (BindArg.isInvalid()) + return true; + break; + } + case OpenACCClauseKind::NumGangs: + case OpenACCClauseKind::NumWorkers: + case OpenACCClauseKind::DeviceNum: + case OpenACCClauseKind::DefaultAsync: + case OpenACCClauseKind::VectorLength: { + ExprResult IntExpr = ParseOpenACCIntExpr(); + if (IntExpr.isInvalid()) + return true; + break; + } + case OpenACCClauseKind::DType: + case OpenACCClauseKind::DeviceType: + if (getCurToken().is(tok::star)) { + // FIXME: We want to mark that this is an 'everything else' type of + // device_type in Sema. + ConsumeToken(); + } else if (ParseOpenACCDeviceTypeList()) { + return true; + } + break; default: llvm_unreachable("Not a required parens type?"); } return Parens.consumeClose(); - } else if (ClauseHasOptionalParens(Kind)) { + } else if (ClauseHasOptionalParens(DirKind, Kind)) { if (!Parens.consumeOpen()) { switch (Kind) { case OpenACCClauseKind::Self: { - ExprResult CondExpr = ParseOpenACCConditionalExpr(P); + assert(DirKind != OpenACCDirectiveKind::Update); + ExprResult CondExpr = ParseOpenACCConditionalExpr(*this); // An invalid expression can be just about anything, so just give up on // this clause list. if (CondExpr.isInvalid()) return true; break; } + case OpenACCClauseKind::Vector: + case OpenACCClauseKind::Worker: { + tryParseAndConsumeSpecialTokenKind(*this, + Kind == OpenACCClauseKind::Vector + ? OpenACCSpecialTokenKind::Length + : OpenACCSpecialTokenKind::Num, + Kind); + ExprResult IntExpr = ParseOpenACCIntExpr(); + if (IntExpr.isInvalid()) + return true; + break; + } default: llvm_unreachable("Not an optional parens type?"); } @@ -407,62 +793,6 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { return false; } -// The OpenACC Clause List is a comma or space-delimited list of clauses (see -// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't -// really have its owner grammar and each individual one has its own definition. -// However, they all are named with a single-identifier (or auto/default!) -// token, followed in some cases by either braces or parens. -bool ParseOpenACCClause(Parser &P) { - // A number of clause names are actually keywords, so accept a keyword that - // can be converted to a name. - if (expectIdentifierOrKeyword(P)) - return true; - - OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken()); - - if (Kind == OpenACCClauseKind::Invalid) - return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause) - << P.getCurToken().getIdentifierInfo(); - - // Consume the clause name. - P.ConsumeToken(); - - return ParseOpenACCClauseParams(P, Kind); -} - -// Skip until we see the end of pragma token, but don't consume it. This is us -// just giving up on the rest of the pragma so we can continue executing. We -// have to do this because 'SkipUntil' considers paren balancing, which isn't -// what we want. -void SkipUntilEndOfDirective(Parser &P) { - while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) - P.ConsumeAnyToken(); -} - -// OpenACC 3.3, section 1.7: -// To simplify the specification and convey appropriate constraint information, -// a pqr-list is a comma-separated list of pdr items. The one exception is a -// clause-list, which is a list of one or more clauses optionally separated by -// commas. -void ParseOpenACCClauseList(Parser &P) { - bool FirstClause = true; - while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) { - // Comma is optional in a clause-list. - if (!FirstClause && P.getCurToken().is(tok::comma)) - P.ConsumeToken(); - FirstClause = false; - - // Recovering from a bad clause is really difficult, so we just give up on - // error. - if (ParseOpenACCClause(P)) { - SkipUntilEndOfDirective(P); - return; - } - } -} - -} // namespace - /// OpenACC 3.3, section 2.16: /// In this section and throughout the specification, the term wait-argument /// means: @@ -527,7 +857,7 @@ bool Parser::ParseOpenACCWaitArgument() { ExprResult Parser::ParseOpenACCIDExpression() { ExprResult Res; if (getLangOpts().CPlusPlus) { - Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false); + Res = ParseCXXIdExpression(/*isAddressOfOperand=*/true); } else { // There isn't anything quite the same as ParseCXXIdExpression for C, so we // need to get the identifier, then call into Sema ourselves. @@ -554,6 +884,25 @@ ExprResult Parser::ParseOpenACCIDExpression() { return getActions().CorrectDelayedTyposInExpr(Res); } +ExprResult Parser::ParseOpenACCBindClauseArgument() { + // OpenACC 3.3 section 2.15: + // The bind clause specifies the name to use when calling the procedure on a + // device other than the host. If the name is specified as an identifier, it + // is called as if that name were specified in the language being compiled. If + // the name is specified as a string, the string is used for the procedure + // name unmodified. + if (getCurToken().is(tok::r_paren)) { + Diag(getCurToken(), diag::err_acc_incorrect_bind_arg); + return ExprError(); + } + + if (tok::isStringLiteral(getCurToken().getKind())) + return getActions().CorrectDelayedTyposInExpr(ParseStringLiteralExpression( + /*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true)); + + return ParseOpenACCIDExpression(); +} + /// OpenACC 3.3, section 1.6: /// In this spec, a 'var' (in italics) is one of the following: /// - a variable name (a scalar, array, or compisite variable name) @@ -563,7 +912,8 @@ ExprResult Parser::ParseOpenACCIDExpression() { /// - a common block name between slashes (fortran only) bool Parser::ParseOpenACCVar() { OpenACCArraySectionRAII ArraySections(*this); - ExprResult Res = ParseAssignmentExpression(); + ExprResult Res = + getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); return Res.isInvalid(); } @@ -578,14 +928,11 @@ void Parser::ParseOpenACCCacheVarList() { return; // The VarList is an optional `readonly:` followed by a list of a variable - // specifications. First, see if we have `readonly:`, else we back-out and - // treat it like the beginning of a reference to a potentially-existing - // `readonly` variable. - if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::ReadOnly, Tok) && - NextToken().is(tok::colon)) { - // Consume both tokens. - ConsumeToken(); - ConsumeToken(); + // specifications. Consume something that looks like a 'tag', and diagnose if + // it isn't 'readonly'. + if (tryParseAndConsumeSpecialTokenKind(*this, + OpenACCSpecialTokenKind::ReadOnly, + OpenACCDirectiveKind::Cache)) { // FIXME: Record that this is a 'readonly' so that we can use that during // Sema/AST generation. } @@ -664,7 +1011,7 @@ void Parser::ParseOpenACCDirective() { } // Parses the list of clauses, if present. - ParseOpenACCClauseList(*this); + ParseOpenACCClauseList(DirKind); Diag(getCurToken(), diag::warn_pragma_acc_unimplemented); assert(Tok.is(tok::annot_pragma_openacc_end) && |