diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp | 129 |
1 files changed, 123 insertions, 6 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp b/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp index 67325f0a286a..c9224d3ae910 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp @@ -76,16 +76,27 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { if (Tok.is(tok::kw_auto)) return OpenACCClauseKind::Auto; + // default is a keyword, so make sure we parse it correctly. + if (Tok.is(tok::kw_default)) + return OpenACCClauseKind::Default; + + // if is also a keyword, make sure we parse it correctly. + if (Tok.is(tok::kw_if)) + return OpenACCClauseKind::If; + if (!Tok.is(tok::identifier)) return OpenACCClauseKind::Invalid; return llvm::StringSwitch<OpenACCClauseKind>( Tok.getIdentifierInfo()->getName()) .Case("auto", OpenACCClauseKind::Auto) + .Case("default", OpenACCClauseKind::Default) .Case("finalize", OpenACCClauseKind::Finalize) + .Case("if", OpenACCClauseKind::If) .Case("if_present", OpenACCClauseKind::IfPresent) .Case("independent", OpenACCClauseKind::Independent) .Case("nohost", OpenACCClauseKind::NoHost) + .Case("self", OpenACCClauseKind::Self) .Case("seq", OpenACCClauseKind::Seq) .Case("vector", OpenACCClauseKind::Vector) .Case("worker", OpenACCClauseKind::Worker) @@ -106,6 +117,17 @@ OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) { .Default(OpenACCAtomicKind::Invalid); } +OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) { + if (!Tok.is(tok::identifier)) + return OpenACCDefaultClauseKind::Invalid; + + return llvm::StringSwitch<OpenACCDefaultClauseKind>( + Tok.getIdentifierInfo()->getName()) + .Case("none", OpenACCDefaultClauseKind::None) + .Case("present", OpenACCDefaultClauseKind::Present) + .Default(OpenACCDefaultClauseKind::Invalid); +} + enum class OpenACCSpecialTokenKind { ReadOnly, DevNum, @@ -176,6 +198,22 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) { llvm_unreachable("Unknown 'Kind' Passed"); } +/// 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())) + return false; + + P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; + return true; +} + OpenACCDirectiveKind ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok, OpenACCDirectiveKindEx ExtDirKind) { @@ -291,14 +329,94 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { return DirKind; } +bool ClauseHasOptionalParens(OpenACCClauseKind Kind) { + return Kind == OpenACCClauseKind::Self; +} + +bool ClauseHasRequiredParens(OpenACCClauseKind Kind) { + return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If; +} + +ExprResult ParseOpenACCConditionalExpr(Parser &P) { + // FIXME: It isn't clear if the spec saying 'condition' means the same as + // it does in an if/while/etc (See ParseCXXCondition), however as it was + // written with Fortran/C in mind, we're going to assume it just means an + // 'expression evaluating to boolean'. + return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression()); +} + +bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { + BalancedDelimiterTracker Parens(P, tok::l_paren, + tok::annot_pragma_openacc_end); + + if (ClauseHasRequiredParens(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); + return false; + } + + switch (Kind) { + case OpenACCClauseKind::Default: { + Token DefKindTok = P.getCurToken(); + + if (expectIdentifierOrKeyword(P)) + break; + + P.ConsumeToken(); + + if (getOpenACCDefaultClauseKind(DefKindTok) == + OpenACCDefaultClauseKind::Invalid) + P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind); + + break; + } + case OpenACCClauseKind::If: { + ExprResult CondExpr = ParseOpenACCConditionalExpr(P); + // An invalid expression can be just about anything, so just give up on + // this clause list. + if (CondExpr.isInvalid()) + return true; + break; + } + default: + llvm_unreachable("Not a required parens type?"); + } + + return Parens.consumeClose(); + } else if (ClauseHasOptionalParens(Kind)) { + if (!Parens.consumeOpen()) { + switch (Kind) { + case OpenACCClauseKind::Self: { + ExprResult CondExpr = ParseOpenACCConditionalExpr(P); + // An invalid expression can be just about anything, so just give up on + // this clause list. + if (CondExpr.isInvalid()) + return true; + break; + } + default: + llvm_unreachable("Not an optional parens type?"); + } + Parens.consumeClose(); + } + } + 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!) token, -// followed in some cases by either braces or parens. +// 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) { - if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto)) - return P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; + // 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()); @@ -309,8 +427,7 @@ bool ParseOpenACCClause(Parser &P) { // Consume the clause name. P.ConsumeToken(); - // FIXME: For future clauses, we need to handle parens/etc below. - return false; + return ParseOpenACCClauseParams(P, Kind); } // Skip until we see the end of pragma token, but don't consume it. This is us |
