aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp523
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) &&