1697 lines · cpp
1//===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the parsing logic for OpenACC language features.10//11//===----------------------------------------------------------------------===//12 13#include "clang/AST/OpenACCClause.h"14#include "clang/Basic/DiagnosticParse.h"15#include "clang/Basic/OpenACCKinds.h"16#include "clang/Parse/Parser.h"17#include "clang/Parse/RAIIObjectsForParser.h"18#include "clang/Sema/ParsedAttr.h"19#include "clang/Sema/SemaOpenACC.h"20#include "llvm/ADT/StringRef.h"21#include "llvm/ADT/StringSwitch.h"22 23using namespace clang;24using namespace llvm;25 26namespace {27// An enum that contains the extended 'partial' parsed variants. This type28// should never escape the initial parse functionality, but is useful for29// simplifying the implementation.30enum class OpenACCDirectiveKindEx {31 Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),32 // 'enter data' and 'exit data'33 Enter,34 Exit,35};36 37// Translate single-token string representations to the OpenACC Directive Kind.38// This doesn't completely comprehend 'Compound Constructs' (as it just39// identifies the first token), and doesn't fully handle 'enter data', 'exit40// data', nor any of the 'atomic' variants, just the first token of each. So41// this should only be used by `ParseOpenACCDirectiveKind`.42OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {43 if (!Tok.is(tok::identifier))44 return OpenACCDirectiveKindEx::Invalid;45 OpenACCDirectiveKind DirKind =46 llvm::StringSwitch<OpenACCDirectiveKind>(47 Tok.getIdentifierInfo()->getName())48 .Case("parallel", OpenACCDirectiveKind::Parallel)49 .Case("serial", OpenACCDirectiveKind::Serial)50 .Case("kernels", OpenACCDirectiveKind::Kernels)51 .Case("data", OpenACCDirectiveKind::Data)52 .Case("host_data", OpenACCDirectiveKind::HostData)53 .Case("loop", OpenACCDirectiveKind::Loop)54 .Case("cache", OpenACCDirectiveKind::Cache)55 .Case("atomic", OpenACCDirectiveKind::Atomic)56 .Case("routine", OpenACCDirectiveKind::Routine)57 .Case("declare", OpenACCDirectiveKind::Declare)58 .Case("init", OpenACCDirectiveKind::Init)59 .Case("shutdown", OpenACCDirectiveKind::Shutdown)60 .Case("set", OpenACCDirectiveKind::Set)61 .Case("update", OpenACCDirectiveKind::Update)62 .Case("wait", OpenACCDirectiveKind::Wait)63 .Default(OpenACCDirectiveKind::Invalid);64 65 if (DirKind != OpenACCDirectiveKind::Invalid)66 return static_cast<OpenACCDirectiveKindEx>(DirKind);67 68 return llvm::StringSwitch<OpenACCDirectiveKindEx>(69 Tok.getIdentifierInfo()->getName())70 .Case("enter", OpenACCDirectiveKindEx::Enter)71 .Case("exit", OpenACCDirectiveKindEx::Exit)72 .Default(OpenACCDirectiveKindEx::Invalid);73}74 75// Translate single-token string representations to the OpenCC Clause Kind.76OpenACCClauseKind getOpenACCClauseKind(Token Tok) {77 // auto is a keyword in some language modes, so make sure we parse it78 // correctly.79 if (Tok.is(tok::kw_auto))80 return OpenACCClauseKind::Auto;81 82 // default is a keyword, so make sure we parse it correctly.83 if (Tok.is(tok::kw_default))84 return OpenACCClauseKind::Default;85 86 // if is also a keyword, make sure we parse it correctly.87 if (Tok.is(tok::kw_if))88 return OpenACCClauseKind::If;89 90 // 'private' is also a keyword, make sure we parse it correctly.91 if (Tok.is(tok::kw_private))92 return OpenACCClauseKind::Private;93 94 // 'delete' is a keyword, make sure we parse it correctly.95 if (Tok.is(tok::kw_delete))96 return OpenACCClauseKind::Delete;97 98 if (!Tok.is(tok::identifier))99 return OpenACCClauseKind::Invalid;100 101 return llvm::StringSwitch<OpenACCClauseKind>(102 Tok.getIdentifierInfo()->getName())103 .Case("async", OpenACCClauseKind::Async)104 .Case("attach", OpenACCClauseKind::Attach)105 .Case("auto", OpenACCClauseKind::Auto)106 .Case("bind", OpenACCClauseKind::Bind)107 .Case("create", OpenACCClauseKind::Create)108 .Case("pcreate", OpenACCClauseKind::PCreate)109 .Case("present_or_create", OpenACCClauseKind::PresentOrCreate)110 .Case("collapse", OpenACCClauseKind::Collapse)111 .Case("copy", OpenACCClauseKind::Copy)112 .Case("pcopy", OpenACCClauseKind::PCopy)113 .Case("present_or_copy", OpenACCClauseKind::PresentOrCopy)114 .Case("copyin", OpenACCClauseKind::CopyIn)115 .Case("pcopyin", OpenACCClauseKind::PCopyIn)116 .Case("present_or_copyin", OpenACCClauseKind::PresentOrCopyIn)117 .Case("copyout", OpenACCClauseKind::CopyOut)118 .Case("pcopyout", OpenACCClauseKind::PCopyOut)119 .Case("present_or_copyout", OpenACCClauseKind::PresentOrCopyOut)120 .Case("default", OpenACCClauseKind::Default)121 .Case("default_async", OpenACCClauseKind::DefaultAsync)122 .Case("delete", OpenACCClauseKind::Delete)123 .Case("detach", OpenACCClauseKind::Detach)124 .Case("device", OpenACCClauseKind::Device)125 .Case("device_num", OpenACCClauseKind::DeviceNum)126 .Case("device_resident", OpenACCClauseKind::DeviceResident)127 .Case("device_type", OpenACCClauseKind::DeviceType)128 .Case("deviceptr", OpenACCClauseKind::DevicePtr)129 .Case("dtype", OpenACCClauseKind::DType)130 .Case("finalize", OpenACCClauseKind::Finalize)131 .Case("firstprivate", OpenACCClauseKind::FirstPrivate)132 .Case("gang", OpenACCClauseKind::Gang)133 .Case("host", OpenACCClauseKind::Host)134 .Case("if", OpenACCClauseKind::If)135 .Case("if_present", OpenACCClauseKind::IfPresent)136 .Case("independent", OpenACCClauseKind::Independent)137 .Case("link", OpenACCClauseKind::Link)138 .Case("no_create", OpenACCClauseKind::NoCreate)139 .Case("num_gangs", OpenACCClauseKind::NumGangs)140 .Case("num_workers", OpenACCClauseKind::NumWorkers)141 .Case("nohost", OpenACCClauseKind::NoHost)142 .Case("present", OpenACCClauseKind::Present)143 .Case("private", OpenACCClauseKind::Private)144 .Case("reduction", OpenACCClauseKind::Reduction)145 .Case("self", OpenACCClauseKind::Self)146 .Case("seq", OpenACCClauseKind::Seq)147 .Case("tile", OpenACCClauseKind::Tile)148 .Case("use_device", OpenACCClauseKind::UseDevice)149 .Case("vector", OpenACCClauseKind::Vector)150 .Case("vector_length", OpenACCClauseKind::VectorLength)151 .Case("wait", OpenACCClauseKind::Wait)152 .Case("worker", OpenACCClauseKind::Worker)153 .Default(OpenACCClauseKind::Invalid);154}155 156// Since 'atomic' is effectively a compound directive, this will decode the157// second part of the directive.158OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {159 if (!Tok.is(tok::identifier))160 return OpenACCAtomicKind::None;161 return llvm::StringSwitch<OpenACCAtomicKind>(162 Tok.getIdentifierInfo()->getName())163 .Case("read", OpenACCAtomicKind::Read)164 .Case("write", OpenACCAtomicKind::Write)165 .Case("update", OpenACCAtomicKind::Update)166 .Case("capture", OpenACCAtomicKind::Capture)167 .Default(OpenACCAtomicKind::None);168}169 170OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) {171 if (!Tok.is(tok::identifier))172 return OpenACCDefaultClauseKind::Invalid;173 174 return llvm::StringSwitch<OpenACCDefaultClauseKind>(175 Tok.getIdentifierInfo()->getName())176 .Case("none", OpenACCDefaultClauseKind::None)177 .Case("present", OpenACCDefaultClauseKind::Present)178 .Default(OpenACCDefaultClauseKind::Invalid);179}180 181enum class OpenACCSpecialTokenKind {182 ReadOnly,183 DevNum,184 Queues,185 Zero,186 Force,187 Num,188 Length,189 Dim,190 Static,191};192 193bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {194 if (Tok.is(tok::kw_static) && Kind == OpenACCSpecialTokenKind::Static)195 return true;196 197 if (!Tok.is(tok::identifier))198 return false;199 200 switch (Kind) {201 case OpenACCSpecialTokenKind::ReadOnly:202 return Tok.getIdentifierInfo()->isStr("readonly");203 case OpenACCSpecialTokenKind::DevNum:204 return Tok.getIdentifierInfo()->isStr("devnum");205 case OpenACCSpecialTokenKind::Queues:206 return Tok.getIdentifierInfo()->isStr("queues");207 case OpenACCSpecialTokenKind::Zero:208 return Tok.getIdentifierInfo()->isStr("zero");209 case OpenACCSpecialTokenKind::Force:210 return Tok.getIdentifierInfo()->isStr("force");211 case OpenACCSpecialTokenKind::Num:212 return Tok.getIdentifierInfo()->isStr("num");213 case OpenACCSpecialTokenKind::Length:214 return Tok.getIdentifierInfo()->isStr("length");215 case OpenACCSpecialTokenKind::Dim:216 return Tok.getIdentifierInfo()->isStr("dim");217 case OpenACCSpecialTokenKind::Static:218 return Tok.getIdentifierInfo()->isStr("static");219 }220 llvm_unreachable("Unknown 'Kind' Passed");221}222 223/// Used for cases where we have a token we want to check against an224/// 'identifier-like' token, but don't want to give awkward error messages in225/// cases where it is accidentially a keyword.226bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) {227 if (Tok.is(tok::identifier))228 return true;229 230 if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&231 Tok.getIdentifierInfo()->isKeyword(P.getLangOpts()))232 return true;233 234 return false;235}236 237/// Parses and consumes an identifer followed immediately by a single colon, and238/// diagnoses if it is not the 'special token' kind that we require. Used when239/// the tag is the only valid value.240/// Return 'true' if the special token was matched, false if no special token,241/// or an invalid special token was found.242template <typename DirOrClauseTy>243bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind,244 DirOrClauseTy DirOrClause) {245 Token IdentTok = P.getCurToken();246 // If this is an identifier-like thing followed by ':', it is one of the247 // OpenACC 'special' name tags, so consume it.248 if (isTokenIdentifierOrKeyword(P, IdentTok) && P.NextToken().is(tok::colon)) {249 P.ConsumeToken();250 P.ConsumeToken();251 252 if (!isOpenACCSpecialToken(Kind, IdentTok)) {253 P.Diag(IdentTok, diag::err_acc_invalid_tag_kind)254 << IdentTok.getIdentifierInfo() << DirOrClause255 << std::is_same_v<DirOrClauseTy, OpenACCClauseKind>;256 return false;257 }258 259 return true;260 }261 262 return false;263}264 265bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {266 if (!Tok.is(tok::identifier))267 return false;268 269 switch (Kind) {270 case OpenACCDirectiveKind::Parallel:271 return Tok.getIdentifierInfo()->isStr("parallel");272 case OpenACCDirectiveKind::Serial:273 return Tok.getIdentifierInfo()->isStr("serial");274 case OpenACCDirectiveKind::Kernels:275 return Tok.getIdentifierInfo()->isStr("kernels");276 case OpenACCDirectiveKind::Data:277 return Tok.getIdentifierInfo()->isStr("data");278 case OpenACCDirectiveKind::HostData:279 return Tok.getIdentifierInfo()->isStr("host_data");280 case OpenACCDirectiveKind::Loop:281 return Tok.getIdentifierInfo()->isStr("loop");282 case OpenACCDirectiveKind::Cache:283 return Tok.getIdentifierInfo()->isStr("cache");284 285 case OpenACCDirectiveKind::ParallelLoop:286 case OpenACCDirectiveKind::SerialLoop:287 case OpenACCDirectiveKind::KernelsLoop:288 case OpenACCDirectiveKind::EnterData:289 case OpenACCDirectiveKind::ExitData:290 return false;291 292 case OpenACCDirectiveKind::Atomic:293 return Tok.getIdentifierInfo()->isStr("atomic");294 case OpenACCDirectiveKind::Routine:295 return Tok.getIdentifierInfo()->isStr("routine");296 case OpenACCDirectiveKind::Declare:297 return Tok.getIdentifierInfo()->isStr("declare");298 case OpenACCDirectiveKind::Init:299 return Tok.getIdentifierInfo()->isStr("init");300 case OpenACCDirectiveKind::Shutdown:301 return Tok.getIdentifierInfo()->isStr("shutdown");302 case OpenACCDirectiveKind::Set:303 return Tok.getIdentifierInfo()->isStr("set");304 case OpenACCDirectiveKind::Update:305 return Tok.getIdentifierInfo()->isStr("update");306 case OpenACCDirectiveKind::Wait:307 return Tok.getIdentifierInfo()->isStr("wait");308 case OpenACCDirectiveKind::Invalid:309 return false;310 }311 llvm_unreachable("Unknown 'Kind' Passed");312}313 314OpenACCReductionOperator ParseReductionOperator(Parser &P) {315 // If there is no colon, treat as if the reduction operator was missing, else316 // we probably will not recover from it in the case where an expression starts317 // with one of the operator tokens.318 if (P.NextToken().isNot(tok::colon)) {319 P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator);320 return OpenACCReductionOperator::Invalid;321 }322 Token ReductionKindTok = P.getCurToken();323 // Consume both the kind and the colon.324 P.ConsumeToken();325 P.ConsumeToken();326 327 switch (ReductionKindTok.getKind()) {328 case tok::plus:329 return OpenACCReductionOperator::Addition;330 case tok::star:331 return OpenACCReductionOperator::Multiplication;332 case tok::amp:333 return OpenACCReductionOperator::BitwiseAnd;334 case tok::pipe:335 return OpenACCReductionOperator::BitwiseOr;336 case tok::caret:337 return OpenACCReductionOperator::BitwiseXOr;338 case tok::ampamp:339 return OpenACCReductionOperator::And;340 case tok::pipepipe:341 return OpenACCReductionOperator::Or;342 case tok::identifier:343 if (ReductionKindTok.getIdentifierInfo()->isStr("max"))344 return OpenACCReductionOperator::Max;345 if (ReductionKindTok.getIdentifierInfo()->isStr("min"))346 return OpenACCReductionOperator::Min;347 [[fallthrough]];348 default:349 P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator);350 return OpenACCReductionOperator::Invalid;351 }352 llvm_unreachable("Reduction op token kind not caught by 'default'?");353}354 355/// Used for cases where we expect an identifier-like token, but don't want to356/// give awkward error messages in cases where it is accidentially a keyword.357bool expectIdentifierOrKeyword(Parser &P) {358 Token Tok = P.getCurToken();359 360 if (isTokenIdentifierOrKeyword(P, Tok))361 return false;362 363 P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;364 return true;365}366 367OpenACCDirectiveKind368ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,369 OpenACCDirectiveKindEx ExtDirKind) {370 Token SecondTok = P.getCurToken();371 372 if (SecondTok.isAnnotation()) {373 P.Diag(FirstTok, diag::err_acc_invalid_directive)374 << 0 << FirstTok.getIdentifierInfo();375 return OpenACCDirectiveKind::Invalid;376 }377 378 // Consume the second name anyway, this way we can continue on without making379 // this oddly look like a clause.380 P.ConsumeAnyToken();381 382 if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) {383 if (!SecondTok.is(tok::identifier))384 P.Diag(SecondTok, diag::err_expected) << tok::identifier;385 else386 P.Diag(FirstTok, diag::err_acc_invalid_directive)387 << 1 << FirstTok.getIdentifierInfo()->getName()388 << SecondTok.getIdentifierInfo()->getName();389 return OpenACCDirectiveKind::Invalid;390 }391 392 return ExtDirKind == OpenACCDirectiveKindEx::Enter393 ? OpenACCDirectiveKind::EnterData394 : OpenACCDirectiveKind::ExitData;395}396 397OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) {398 Token AtomicClauseToken = P.getCurToken();399 400 // #pragma acc atomic is equivilent to update:401 if (AtomicClauseToken.isAnnotation())402 return OpenACCAtomicKind::None;403 404 OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken);405 406 // If this isn't a valid atomic-kind, don't consume the token, and treat the407 // rest as a clause list, which despite there being no permissible clauses,408 // will diagnose as a clause.409 if (AtomicKind != OpenACCAtomicKind::None)410 P.ConsumeToken();411 412 return AtomicKind;413}414 415// Parse and consume the tokens for OpenACC Directive/Construct kinds.416OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {417 Token FirstTok = P.getCurToken();418 419 // Just #pragma acc can get us immediately to the end, make sure we don't420 // introspect on the spelling before then.421 if (FirstTok.isNot(tok::identifier)) {422 P.Diag(FirstTok, diag::err_acc_missing_directive);423 424 if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))425 P.ConsumeAnyToken();426 427 return OpenACCDirectiveKind::Invalid;428 }429 430 P.ConsumeToken();431 432 OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok);433 434 // OpenACCDirectiveKindEx is meant to be an extended list435 // over OpenACCDirectiveKind, so any value below Invalid is one of the436 // OpenACCDirectiveKind values. This switch takes care of all of the extra437 // parsing required for the Extended values. At the end of this block,438 // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can439 // immediately cast it and use it as that.440 if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {441 switch (ExDirKind) {442 case OpenACCDirectiveKindEx::Invalid: {443 P.Diag(FirstTok, diag::err_acc_invalid_directive)444 << 0 << FirstTok.getIdentifierInfo();445 return OpenACCDirectiveKind::Invalid;446 }447 case OpenACCDirectiveKindEx::Enter:448 case OpenACCDirectiveKindEx::Exit:449 return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind);450 }451 }452 453 OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);454 455 // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any456 // other attempt at a combined construct will be diagnosed as an invalid457 // clause.458 Token SecondTok = P.getCurToken();459 if (!SecondTok.isAnnotation() &&460 isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) {461 switch (DirKind) {462 default:463 // Nothing to do except in the below cases, as they should be diagnosed as464 // a clause.465 break;466 case OpenACCDirectiveKind::Parallel:467 P.ConsumeToken();468 return OpenACCDirectiveKind::ParallelLoop;469 case OpenACCDirectiveKind::Serial:470 P.ConsumeToken();471 return OpenACCDirectiveKind::SerialLoop;472 case OpenACCDirectiveKind::Kernels:473 P.ConsumeToken();474 return OpenACCDirectiveKind::KernelsLoop;475 }476 }477 478 return DirKind;479}480 481enum ClauseParensKind {482 None,483 Optional,484 Required485};486 487ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind,488 OpenACCClauseKind Kind) {489 switch (Kind) {490 case OpenACCClauseKind::Self:491 return DirKind == OpenACCDirectiveKind::Update ? ClauseParensKind::Required492 : ClauseParensKind::Optional;493 case OpenACCClauseKind::Async:494 case OpenACCClauseKind::Worker:495 case OpenACCClauseKind::Vector:496 case OpenACCClauseKind::Gang:497 case OpenACCClauseKind::Wait:498 return ClauseParensKind::Optional;499 500 case OpenACCClauseKind::Default:501 case OpenACCClauseKind::If:502 case OpenACCClauseKind::Create:503 case OpenACCClauseKind::PCreate:504 case OpenACCClauseKind::PresentOrCreate:505 case OpenACCClauseKind::Copy:506 case OpenACCClauseKind::PCopy:507 case OpenACCClauseKind::PresentOrCopy:508 case OpenACCClauseKind::CopyIn:509 case OpenACCClauseKind::PCopyIn:510 case OpenACCClauseKind::PresentOrCopyIn:511 case OpenACCClauseKind::CopyOut:512 case OpenACCClauseKind::PCopyOut:513 case OpenACCClauseKind::PresentOrCopyOut:514 case OpenACCClauseKind::UseDevice:515 case OpenACCClauseKind::NoCreate:516 case OpenACCClauseKind::Present:517 case OpenACCClauseKind::DevicePtr:518 case OpenACCClauseKind::Attach:519 case OpenACCClauseKind::Detach:520 case OpenACCClauseKind::Private:521 case OpenACCClauseKind::FirstPrivate:522 case OpenACCClauseKind::Delete:523 case OpenACCClauseKind::DeviceResident:524 case OpenACCClauseKind::Device:525 case OpenACCClauseKind::Link:526 case OpenACCClauseKind::Host:527 case OpenACCClauseKind::Reduction:528 case OpenACCClauseKind::Collapse:529 case OpenACCClauseKind::Bind:530 case OpenACCClauseKind::VectorLength:531 case OpenACCClauseKind::NumGangs:532 case OpenACCClauseKind::NumWorkers:533 case OpenACCClauseKind::DeviceNum:534 case OpenACCClauseKind::DefaultAsync:535 case OpenACCClauseKind::DeviceType:536 case OpenACCClauseKind::DType:537 case OpenACCClauseKind::Tile:538 return ClauseParensKind::Required;539 540 case OpenACCClauseKind::Shortloop:541 llvm_unreachable("Shortloop shouldn't be generated in clang");542 case OpenACCClauseKind::Auto:543 case OpenACCClauseKind::Finalize:544 case OpenACCClauseKind::IfPresent:545 case OpenACCClauseKind::Independent:546 case OpenACCClauseKind::Invalid:547 case OpenACCClauseKind::NoHost:548 case OpenACCClauseKind::Seq:549 return ClauseParensKind::None;550 }551 llvm_unreachable("Unhandled clause kind");552}553 554bool ClauseHasOptionalParens(OpenACCDirectiveKind DirKind,555 OpenACCClauseKind Kind) {556 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional;557}558 559bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind,560 OpenACCClauseKind Kind) {561 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required;562}563 564// Skip until we see the end of pragma token, but don't consume it. This is us565// just giving up on the rest of the pragma so we can continue executing. We566// have to do this because 'SkipUntil' considers paren balancing, which isn't567// what we want.568void SkipUntilEndOfDirective(Parser &P) {569 while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))570 P.ConsumeAnyToken();571}572 573bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {574 switch (DirKind) {575 case OpenACCDirectiveKind::Routine:576 // FIXME: Routine MIGHT end up needing to be 'true' here, as it needs a way577 // to capture a lambda-expression on the next line.578 case OpenACCDirectiveKind::Cache:579 case OpenACCDirectiveKind::Declare:580 case OpenACCDirectiveKind::Set:581 case OpenACCDirectiveKind::EnterData:582 case OpenACCDirectiveKind::ExitData:583 case OpenACCDirectiveKind::Wait:584 case OpenACCDirectiveKind::Init:585 case OpenACCDirectiveKind::Shutdown:586 case OpenACCDirectiveKind::Update:587 case OpenACCDirectiveKind::Invalid:588 return false;589 case OpenACCDirectiveKind::Parallel:590 case OpenACCDirectiveKind::Serial:591 case OpenACCDirectiveKind::Kernels:592 case OpenACCDirectiveKind::ParallelLoop:593 case OpenACCDirectiveKind::SerialLoop:594 case OpenACCDirectiveKind::KernelsLoop:595 case OpenACCDirectiveKind::Loop:596 case OpenACCDirectiveKind::Data:597 case OpenACCDirectiveKind::HostData:598 case OpenACCDirectiveKind::Atomic:599 return true;600 }601 llvm_unreachable("Unhandled directive->assoc stmt");602}603 604unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {605 switch (DirKind) {606 case OpenACCDirectiveKind::Parallel:607 case OpenACCDirectiveKind::Serial:608 case OpenACCDirectiveKind::Kernels:609 // Mark this as a BreakScope/ContinueScope as well as a compute construct610 // so that we can diagnose trying to 'break'/'continue' inside of one.611 return Scope::BreakScope | Scope::ContinueScope |612 Scope::OpenACCComputeConstructScope;613 case OpenACCDirectiveKind::ParallelLoop:614 case OpenACCDirectiveKind::SerialLoop:615 case OpenACCDirectiveKind::KernelsLoop:616 // Mark this as a BreakScope/ContinueScope as well as a compute construct617 // so that we can diagnose trying to 'break'/'continue' inside of one.618 return Scope::BreakScope | Scope::ContinueScope |619 Scope::OpenACCComputeConstructScope |620 Scope::OpenACCLoopConstructScope;621 case OpenACCDirectiveKind::Loop:622 return Scope::OpenACCLoopConstructScope;623 case OpenACCDirectiveKind::Data:624 case OpenACCDirectiveKind::EnterData:625 case OpenACCDirectiveKind::ExitData:626 case OpenACCDirectiveKind::HostData:627 case OpenACCDirectiveKind::Wait:628 case OpenACCDirectiveKind::Init:629 case OpenACCDirectiveKind::Shutdown:630 case OpenACCDirectiveKind::Cache:631 case OpenACCDirectiveKind::Atomic:632 case OpenACCDirectiveKind::Declare:633 case OpenACCDirectiveKind::Routine:634 case OpenACCDirectiveKind::Set:635 case OpenACCDirectiveKind::Update:636 return 0;637 case OpenACCDirectiveKind::Invalid:638 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");639 }640 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");641}642 643} // namespace644 645Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() {646 return {nullptr, OpenACCParseCanContinue::Can};647}648 649Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() {650 return {nullptr, OpenACCParseCanContinue::Cannot};651}652 653Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) {654 return {Clause, OpenACCParseCanContinue::Can};655}656 657ExprResult Parser::ParseOpenACCConditionExpr() {658 // FIXME: It isn't clear if the spec saying 'condition' means the same as659 // it does in an if/while/etc (See ParseCXXCondition), however as it was660 // written with Fortran/C in mind, we're going to assume it just means an661 // 'expression evaluating to boolean'.662 ExprResult ER = ParseExpression();663 664 if (!ER.isUsable())665 return ER;666 667 Sema::ConditionResult R =668 getActions().ActOnCondition(getCurScope(), ER.get()->getExprLoc(),669 ER.get(), Sema::ConditionKind::Boolean);670 671 return R.isInvalid() ? ExprError() : R.get().second;672}673 674OpenACCModifierKind Parser::tryParseModifierList(OpenACCClauseKind CK) {675 // Use the tentative parsing to decide whether we are a comma-delmited list of676 // identifers ending in a colon so we can do an actual parse with diagnostics.677 {678 RevertingTentativeParsingAction TPA{*this};679 // capture any <ident><comma> pairs.680 while (isTokenIdentifierOrKeyword(*this, getCurToken()) &&681 NextToken().is(tok::comma)) {682 ConsumeToken();683 ConsumeToken();684 }685 686 if (!isTokenIdentifierOrKeyword(*this, getCurToken()) ||687 !NextToken().is(tok::colon)) {688 // No modifiers as this isn't a valid modifier-list.689 return OpenACCModifierKind::Invalid;690 }691 }692 693 auto GetModKind = [](Token T) {694 return StringSwitch<OpenACCModifierKind>(T.getIdentifierInfo()->getName())695 .Case("always", OpenACCModifierKind::Always)696 .Case("alwaysin", OpenACCModifierKind::AlwaysIn)697 .Case("alwaysout", OpenACCModifierKind::AlwaysOut)698 .Case("readonly", OpenACCModifierKind::Readonly)699 .Case("zero", OpenACCModifierKind::Zero)700 .Case("capture", OpenACCModifierKind::Capture)701 .Default(OpenACCModifierKind::Invalid);702 };703 704 OpenACCModifierKind CurModList = OpenACCModifierKind::Invalid;705 auto ConsumeModKind = [&]() {706 Token IdentToken = getCurToken();707 OpenACCModifierKind NewKind = GetModKind(IdentToken);708 709 if (NewKind == OpenACCModifierKind::Invalid)710 Diag(IdentToken.getLocation(), diag::err_acc_modifier)711 << diag::ACCModifier::Unknown << IdentToken.getIdentifierInfo() << CK;712 else if ((NewKind & CurModList) != OpenACCModifierKind::Invalid)713 Diag(IdentToken.getLocation(), diag::err_acc_modifier)714 << diag::ACCModifier::Duplicate << IdentToken.getIdentifierInfo()715 << CK;716 else717 CurModList |= NewKind;718 719 // Consumes the identifier.720 ConsumeToken();721 // Consumes the comma or colon.722 ConsumeToken();723 };724 725 // Inspect all but the last item. We inspected enough to know that our current726 // token is the identifier-like thing, so just check for the comma.727 while (NextToken().is(tok::comma))728 ConsumeModKind();729 730 // Above we confirmed that this should be correct/we should be on the last731 // item.732 ConsumeModKind();733 734 return CurModList;735}736 737SmallVector<OpenACCClause *>738Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {739 SmallVector<OpenACCClause *> Clauses;740 bool FirstClause = true;741 while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {742 // Comma is optional in a clause-list.743 if (!FirstClause && getCurToken().is(tok::comma))744 ConsumeToken();745 FirstClause = false;746 747 OpenACCClauseParseResult Result = ParseOpenACCClause(Clauses, DirKind);748 if (OpenACCClause *Clause = Result.getPointer()) {749 Clauses.push_back(Clause);750 } else if (Result.getInt() == OpenACCParseCanContinue::Cannot) {751 // Recovering from a bad clause is really difficult, so we just give up on752 // error.753 SkipUntilEndOfDirective(*this);754 return Clauses;755 }756 }757 return Clauses;758}759 760Parser::OpenACCIntExprParseResult761Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,762 SourceLocation Loc) {763 ExprResult ER = ParseAssignmentExpression();764 765 // If the actual parsing failed, we don't know the state of the parse, so766 // don't try to continue.767 if (!ER.isUsable())768 return {ER, OpenACCParseCanContinue::Cannot};769 770 return {getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, ER.get()),771 OpenACCParseCanContinue::Can};772}773 774bool Parser::ParseOpenACCIntExprList(OpenACCDirectiveKind DK,775 OpenACCClauseKind CK, SourceLocation Loc,776 llvm::SmallVectorImpl<Expr *> &IntExprs) {777 OpenACCIntExprParseResult CurResult = ParseOpenACCIntExpr(DK, CK, Loc);778 779 if (!CurResult.first.isUsable() &&780 CurResult.second == OpenACCParseCanContinue::Cannot) {781 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,782 Parser::StopBeforeMatch);783 return true;784 }785 786 IntExprs.push_back(CurResult.first.get());787 788 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {789 ExpectAndConsume(tok::comma);790 791 CurResult = ParseOpenACCIntExpr(DK, CK, Loc);792 793 if (!CurResult.first.isUsable() &&794 CurResult.second == OpenACCParseCanContinue::Cannot) {795 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,796 Parser::StopBeforeMatch);797 return true;798 }799 IntExprs.push_back(CurResult.first.get());800 }801 return false;802}803 804bool Parser::ParseOpenACCDeviceTypeList(805 llvm::SmallVector<IdentifierLoc> &Archs) {806 807 if (expectIdentifierOrKeyword(*this)) {808 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,809 Parser::StopBeforeMatch);810 return true;811 }812 IdentifierInfo *Ident = getCurToken().getIdentifierInfo();813 Archs.emplace_back(ConsumeToken(), Ident);814 815 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {816 ExpectAndConsume(tok::comma);817 818 if (expectIdentifierOrKeyword(*this)) {819 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,820 Parser::StopBeforeMatch);821 return true;822 }823 Ident = getCurToken().getIdentifierInfo();824 Archs.emplace_back(ConsumeToken(), Ident);825 }826 return false;827}828 829ExprResult Parser::ParseOpenACCSizeExpr(OpenACCClauseKind CK) {830 // The size-expr ends up being ambiguous when only looking at the current831 // token, as it could be a deref of a variable/expression.832 if (getCurToken().is(tok::star) &&833 NextToken().isOneOf(tok::comma, tok::r_paren,834 tok::annot_pragma_openacc_end)) {835 SourceLocation AsteriskLoc = ConsumeToken();836 return getActions().OpenACC().ActOnOpenACCAsteriskSizeExpr(AsteriskLoc);837 }838 839 ExprResult SizeExpr = ParseConstantExpression();840 841 if (!SizeExpr.isUsable())842 return SizeExpr;843 844 SizeExpr = getActions().OpenACC().ActOnIntExpr(845 OpenACCDirectiveKind::Invalid, CK, SizeExpr.get()->getBeginLoc(),846 SizeExpr.get());847 848 return SizeExpr;849}850 851bool Parser::ParseOpenACCSizeExprList(852 OpenACCClauseKind CK, llvm::SmallVectorImpl<Expr *> &SizeExprs) {853 ExprResult SizeExpr = ParseOpenACCSizeExpr(CK);854 if (!SizeExpr.isUsable()) {855 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,856 Parser::StopBeforeMatch);857 return true;858 }859 860 SizeExprs.push_back(SizeExpr.get());861 862 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {863 ExpectAndConsume(tok::comma);864 865 SizeExpr = ParseOpenACCSizeExpr(CK);866 if (!SizeExpr.isUsable()) {867 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,868 Parser::StopBeforeMatch);869 return true;870 }871 SizeExprs.push_back(SizeExpr.get());872 }873 return false;874}875 876Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {877 878 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Static, getCurToken()) &&879 NextToken().is(tok::colon)) {880 // 'static' just takes a size-expr, which is an int-expr or an asterisk.881 ConsumeToken();882 ConsumeToken();883 ExprResult Res = ParseOpenACCSizeExpr(OpenACCClauseKind::Gang);884 return {OpenACCGangKind::Static, Res};885 }886 887 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Dim, getCurToken()) &&888 NextToken().is(tok::colon)) {889 ConsumeToken();890 ConsumeToken();891 // Parse this as a const-expression, and we'll check its integer-ness/value892 // in CheckGangExpr.893 ExprResult Res = ParseConstantExpression();894 return {OpenACCGangKind::Dim, Res};895 }896 897 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) &&898 NextToken().is(tok::colon)) {899 ConsumeToken();900 ConsumeToken();901 // Fallthrough to the 'int-expr' handling for when 'num' is omitted.902 }903 904 // This is just the 'num' case where 'num' is optional.905 ExprResult Res = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,906 OpenACCClauseKind::Gang, GangLoc)907 .first;908 return {OpenACCGangKind::Num, Res};909}910 911bool Parser::ParseOpenACCGangArgList(912 SourceLocation GangLoc, llvm::SmallVectorImpl<OpenACCGangKind> &GKs,913 llvm::SmallVectorImpl<Expr *> &IntExprs) {914 915 Parser::OpenACCGangArgRes Res = ParseOpenACCGangArg(GangLoc);916 if (!Res.second.isUsable()) {917 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,918 Parser::StopBeforeMatch);919 return true;920 }921 922 GKs.push_back(Res.first);923 IntExprs.push_back(Res.second.get());924 925 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {926 ExpectAndConsume(tok::comma);927 928 Res = ParseOpenACCGangArg(GangLoc);929 if (!Res.second.isUsable()) {930 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,931 Parser::StopBeforeMatch);932 return true;933 }934 935 GKs.push_back(Res.first);936 IntExprs.push_back(Res.second.get());937 }938 return false;939}940 941namespace {942bool isUnsupportedExtensionClause(Token Tok) {943 if (!Tok.is(tok::identifier))944 return false;945 946 return Tok.getIdentifierInfo()->getName().starts_with("__");947}948} // namespace949 950Parser::OpenACCClauseParseResult951Parser::ParseOpenACCClause(ArrayRef<const OpenACCClause *> ExistingClauses,952 OpenACCDirectiveKind DirKind) {953 // A number of clause names are actually keywords, so accept a keyword that954 // can be converted to a name.955 if (expectIdentifierOrKeyword(*this))956 return OpenACCCannotContinue();957 958 OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken());959 960 if (isUnsupportedExtensionClause(getCurToken())) {961 Diag(getCurToken(), diag::warn_acc_unsupported_extension_clause)962 << getCurToken().getIdentifierInfo();963 964 // Extension methods optionally contain balanced token sequences, so we are965 // going to parse this.966 ConsumeToken(); // Consume the clause name.967 BalancedDelimiterTracker Parens(*this, tok::l_paren,968 tok::annot_pragma_openacc_end);969 // Consume the optional parens and tokens inside of them.970 if (!Parens.consumeOpen())971 Parens.skipToEnd();972 973 return OpenACCCanContinue();974 } else if (Kind == OpenACCClauseKind::Invalid) {975 Diag(getCurToken(), diag::err_acc_invalid_clause)976 << getCurToken().getIdentifierInfo();977 return OpenACCCannotContinue();978 }979 980 // Consume the clause name.981 SourceLocation ClauseLoc = ConsumeToken();982 983 return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc);984}985 986Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(987 ArrayRef<const OpenACCClause *> ExistingClauses,988 OpenACCDirectiveKind DirKind, OpenACCClauseKind ClauseKind,989 SourceLocation ClauseLoc) {990 BalancedDelimiterTracker Parens(*this, tok::l_paren,991 tok::annot_pragma_openacc_end);992 SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);993 994 if (ClauseHasRequiredParens(DirKind, ClauseKind)) {995 if (Parens.expectAndConsume()) {996 // We are missing a paren, so assume that the person just forgot the997 // parameter. Return 'false' so we try to continue on and parse the next998 // clause.999 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,1000 Parser::StopBeforeMatch);1001 return OpenACCCanContinue();1002 }1003 ParsedClause.setLParenLoc(Parens.getOpenLocation());1004 1005 switch (ClauseKind) {1006 case OpenACCClauseKind::Default: {1007 Token DefKindTok = getCurToken();1008 1009 if (expectIdentifierOrKeyword(*this)) {1010 Parens.skipToEnd();1011 return OpenACCCanContinue();1012 }1013 1014 ConsumeToken();1015 1016 OpenACCDefaultClauseKind DefKind =1017 getOpenACCDefaultClauseKind(DefKindTok);1018 1019 if (DefKind == OpenACCDefaultClauseKind::Invalid) {1020 Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);1021 Parens.skipToEnd();1022 return OpenACCCanContinue();1023 }1024 1025 ParsedClause.setDefaultDetails(DefKind);1026 break;1027 }1028 case OpenACCClauseKind::If: {1029 ExprResult CondExpr = ParseOpenACCConditionExpr();1030 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()1031 : nullptr);1032 1033 if (CondExpr.isInvalid()) {1034 Parens.skipToEnd();1035 return OpenACCCanContinue();1036 }1037 1038 break;1039 }1040 case OpenACCClauseKind::Copy:1041 case OpenACCClauseKind::PCopy:1042 case OpenACCClauseKind::PresentOrCopy:1043 case OpenACCClauseKind::CopyIn:1044 case OpenACCClauseKind::PCopyIn:1045 case OpenACCClauseKind::PresentOrCopyIn:1046 case OpenACCClauseKind::CopyOut:1047 case OpenACCClauseKind::PCopyOut:1048 case OpenACCClauseKind::PresentOrCopyOut:1049 case OpenACCClauseKind::Create:1050 case OpenACCClauseKind::PCreate:1051 case OpenACCClauseKind::PresentOrCreate: {1052 OpenACCModifierKind ModList = tryParseModifierList(ClauseKind);1053 ParsedClause.setVarListDetails(ParseOpenACCVarList(DirKind, ClauseKind),1054 ModList);1055 break;1056 }1057 case OpenACCClauseKind::Reduction: {1058 // If we're missing a clause-kind (or it is invalid), see if we can parse1059 // the var-list anyway.1060 OpenACCReductionOperator Op = ParseReductionOperator(*this);1061 ParsedClause.setReductionDetails(1062 Op, ParseOpenACCVarList(DirKind, ClauseKind));1063 break;1064 }1065 case OpenACCClauseKind::Self:1066 // The 'self' clause is a var-list instead of a 'condition' in the case of1067 // the 'update' clause, so we have to handle it here. Use an assert to1068 // make sure we get the right differentiator.1069 assert(DirKind == OpenACCDirectiveKind::Update);1070 [[fallthrough]];1071 case OpenACCClauseKind::Device:1072 case OpenACCClauseKind::Host:1073 case OpenACCClauseKind::DeviceResident:1074 case OpenACCClauseKind::Link:1075 case OpenACCClauseKind::Attach:1076 case OpenACCClauseKind::Delete:1077 case OpenACCClauseKind::Detach:1078 case OpenACCClauseKind::DevicePtr:1079 case OpenACCClauseKind::UseDevice:1080 case OpenACCClauseKind::FirstPrivate:1081 case OpenACCClauseKind::NoCreate:1082 case OpenACCClauseKind::Present:1083 case OpenACCClauseKind::Private:1084 ParsedClause.setVarListDetails(ParseOpenACCVarList(DirKind, ClauseKind),1085 OpenACCModifierKind::Invalid);1086 break;1087 case OpenACCClauseKind::Collapse: {1088 bool HasForce = tryParseAndConsumeSpecialTokenKind(1089 *this, OpenACCSpecialTokenKind::Force, ClauseKind);1090 ExprResult LoopCount = ParseConstantExpression();1091 if (LoopCount.isInvalid()) {1092 Parens.skipToEnd();1093 return OpenACCCanContinue();1094 }1095 1096 LoopCount = getActions().OpenACC().ActOnIntExpr(1097 OpenACCDirectiveKind::Invalid, ClauseKind,1098 LoopCount.get()->getBeginLoc(), LoopCount.get());1099 1100 if (LoopCount.isInvalid()) {1101 Parens.skipToEnd();1102 return OpenACCCanContinue();1103 }1104 1105 ParsedClause.setCollapseDetails(HasForce, LoopCount.get());1106 break;1107 }1108 case OpenACCClauseKind::Bind: {1109 ParsedClause.setBindDetails(ParseOpenACCBindClauseArgument());1110 1111 // We can create an 'empty' bind clause in the event of an error1112 if (std::holds_alternative<std::monostate>(1113 ParsedClause.getBindDetails())) {1114 Parens.skipToEnd();1115 return OpenACCCanContinue();1116 }1117 break;1118 }1119 case OpenACCClauseKind::NumGangs: {1120 llvm::SmallVector<Expr *> IntExprs;1121 1122 if (ParseOpenACCIntExprList(OpenACCDirectiveKind::Invalid,1123 OpenACCClauseKind::NumGangs, ClauseLoc,1124 IntExprs)) {1125 Parens.skipToEnd();1126 return OpenACCCanContinue();1127 }1128 ParsedClause.setIntExprDetails(std::move(IntExprs));1129 break;1130 }1131 case OpenACCClauseKind::NumWorkers:1132 case OpenACCClauseKind::DeviceNum:1133 case OpenACCClauseKind::DefaultAsync:1134 case OpenACCClauseKind::VectorLength: {1135 ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,1136 ClauseKind, ClauseLoc)1137 .first;1138 if (IntExpr.isInvalid()) {1139 Parens.skipToEnd();1140 return OpenACCCanContinue();1141 }1142 1143 ParsedClause.setIntExprDetails(IntExpr.get());1144 break;1145 }1146 case OpenACCClauseKind::DType:1147 case OpenACCClauseKind::DeviceType: {1148 llvm::SmallVector<IdentifierLoc> Archs;1149 if (getCurToken().is(tok::star)) {1150 // FIXME: We want to mark that this is an 'everything else' type of1151 // device_type in Sema.1152 ParsedClause.setDeviceTypeDetails(1153 {IdentifierLoc(ConsumeToken(), nullptr)});1154 } else if (!ParseOpenACCDeviceTypeList(Archs)) {1155 ParsedClause.setDeviceTypeDetails(std::move(Archs));1156 } else {1157 Parens.skipToEnd();1158 return OpenACCCanContinue();1159 }1160 break;1161 }1162 case OpenACCClauseKind::Tile: {1163 llvm::SmallVector<Expr *> SizeExprs;1164 if (ParseOpenACCSizeExprList(OpenACCClauseKind::Tile, SizeExprs)) {1165 Parens.skipToEnd();1166 return OpenACCCanContinue();1167 }1168 1169 ParsedClause.setIntExprDetails(std::move(SizeExprs));1170 break;1171 }1172 default:1173 llvm_unreachable("Not a required parens type?");1174 }1175 1176 ParsedClause.setEndLoc(getCurToken().getLocation());1177 1178 if (Parens.consumeClose())1179 return OpenACCCannotContinue();1180 1181 } else if (ClauseHasOptionalParens(DirKind, ClauseKind)) {1182 if (!Parens.consumeOpen()) {1183 ParsedClause.setLParenLoc(Parens.getOpenLocation());1184 switch (ClauseKind) {1185 case OpenACCClauseKind::Self: {1186 assert(DirKind != OpenACCDirectiveKind::Update);1187 ExprResult CondExpr = ParseOpenACCConditionExpr();1188 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()1189 : nullptr);1190 1191 if (CondExpr.isInvalid()) {1192 Parens.skipToEnd();1193 return OpenACCCanContinue();1194 }1195 break;1196 }1197 case OpenACCClauseKind::Vector:1198 case OpenACCClauseKind::Worker: {1199 tryParseAndConsumeSpecialTokenKind(*this,1200 ClauseKind ==1201 OpenACCClauseKind::Vector1202 ? OpenACCSpecialTokenKind::Length1203 : OpenACCSpecialTokenKind::Num,1204 ClauseKind);1205 ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,1206 ClauseKind, ClauseLoc)1207 .first;1208 if (IntExpr.isInvalid()) {1209 Parens.skipToEnd();1210 return OpenACCCanContinue();1211 }1212 ParsedClause.setIntExprDetails(IntExpr.get());1213 break;1214 }1215 case OpenACCClauseKind::Async: {1216 ExprResult AsyncArg =1217 ParseOpenACCAsyncArgument(OpenACCDirectiveKind::Invalid,1218 OpenACCClauseKind::Async, ClauseLoc)1219 .first;1220 ParsedClause.setIntExprDetails(AsyncArg.isUsable() ? AsyncArg.get()1221 : nullptr);1222 if (AsyncArg.isInvalid()) {1223 Parens.skipToEnd();1224 return OpenACCCanContinue();1225 }1226 break;1227 }1228 case OpenACCClauseKind::Gang: {1229 llvm::SmallVector<OpenACCGangKind> GKs;1230 llvm::SmallVector<Expr *> IntExprs;1231 if (ParseOpenACCGangArgList(ClauseLoc, GKs, IntExprs)) {1232 Parens.skipToEnd();1233 return OpenACCCanContinue();1234 }1235 ParsedClause.setGangDetails(std::move(GKs), std::move(IntExprs));1236 break;1237 }1238 case OpenACCClauseKind::Wait: {1239 OpenACCWaitParseInfo Info =1240 ParseOpenACCWaitArgument(ClauseLoc,1241 /*IsDirective=*/false);1242 if (Info.Failed) {1243 Parens.skipToEnd();1244 return OpenACCCanContinue();1245 }1246 1247 ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc,1248 std::move(Info.QueueIdExprs));1249 break;1250 }1251 default:1252 llvm_unreachable("Not an optional parens type?");1253 }1254 ParsedClause.setEndLoc(getCurToken().getLocation());1255 if (Parens.consumeClose())1256 return OpenACCCannotContinue();1257 } else {1258 // If we have optional parens, make sure we set the end-location to the1259 // clause, as we are a 'single token' clause.1260 ParsedClause.setEndLoc(ClauseLoc);1261 }1262 } else {1263 ParsedClause.setEndLoc(ClauseLoc);1264 }1265 return OpenACCSuccess(1266 Actions.OpenACC().ActOnClause(ExistingClauses, ParsedClause));1267}1268 1269Parser::OpenACCIntExprParseResult1270Parser::ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK,1271 SourceLocation Loc) {1272 return ParseOpenACCIntExpr(DK, CK, Loc);1273}1274 1275Parser::OpenACCWaitParseInfo1276Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {1277 OpenACCWaitParseInfo Result;1278 // [devnum : int-expr : ]1279 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&1280 NextToken().is(tok::colon)) {1281 // Consume devnum.1282 ConsumeToken();1283 // Consume colon.1284 ConsumeToken();1285 1286 OpenACCIntExprParseResult Res = ParseOpenACCIntExpr(1287 IsDirective ? OpenACCDirectiveKind::Wait1288 : OpenACCDirectiveKind::Invalid,1289 IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,1290 Loc);1291 if (Res.first.isInvalid() &&1292 Res.second == OpenACCParseCanContinue::Cannot) {1293 Result.Failed = true;1294 return Result;1295 }1296 1297 if (ExpectAndConsume(tok::colon)) {1298 Result.Failed = true;1299 return Result;1300 }1301 1302 Result.DevNumExpr = Res.first.get();1303 }1304 1305 // [ queues : ]1306 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&1307 NextToken().is(tok::colon)) {1308 // Consume queues.1309 Result.QueuesLoc = ConsumeToken();1310 // Consume colon.1311 ConsumeToken();1312 }1313 1314 1315 1316 // OpenACC 3.3, section 2.16:1317 // the term 'async-argument' means a nonnegative scalar integer expression, or1318 // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined1319 // in the C header file and the Fortran opacc module.1320 OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(1321 IsDirective ? OpenACCDirectiveKind::Wait1322 : OpenACCDirectiveKind::Invalid,1323 IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,1324 Loc);1325 1326 if (Res.first.isInvalid() &&1327 Res.second == OpenACCParseCanContinue::Cannot) {1328 Result.Failed = true;1329 return Result;1330 }1331 1332 if (Res.first.isUsable())1333 Result.QueueIdExprs.push_back(Res.first.get());1334 1335 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {1336 if (ExpectAndConsume(tok::comma)) {1337 Result.Failed = true;1338 return Result;1339 }1340 1341 OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(1342 IsDirective ? OpenACCDirectiveKind::Wait1343 : OpenACCDirectiveKind::Invalid,1344 IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,1345 Loc);1346 1347 if (Res.first.isInvalid() &&1348 Res.second == OpenACCParseCanContinue::Cannot) {1349 Result.Failed = true;1350 return Result;1351 }1352 1353 if (Res.first.isUsable())1354 Result.QueueIdExprs.push_back(Res.first.get());1355 }1356 1357 return Result;1358}1359 1360ExprResult Parser::ParseOpenACCIDExpression() {1361 ExprResult Res;1362 if (getLangOpts().CPlusPlus) {1363 Res = ParseCXXIdExpression(/*isAddressOfOperand=*/true);1364 } else {1365 // There isn't anything quite the same as ParseCXXIdExpression for C, so we1366 // need to get the identifier, then call into Sema ourselves.1367 1368 if (Tok.isNot(tok::identifier)) {1369 Diag(Tok, diag::err_expected) << tok::identifier;1370 return ExprError();1371 }1372 1373 Token FuncName = getCurToken();1374 UnqualifiedId Name;1375 CXXScopeSpec ScopeSpec;1376 SourceLocation TemplateKWLoc;1377 Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());1378 1379 // Ensure this is a valid identifier. We don't accept causing implicit1380 // function declarations per the spec, so always claim to not have trailing1381 // L Paren.1382 Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,1383 Name, /*HasTrailingLParen=*/false,1384 /*isAddressOfOperand=*/false);1385 }1386 1387 return Res;1388}1389 1390std::variant<std::monostate, clang::StringLiteral *, IdentifierInfo *>1391Parser::ParseOpenACCBindClauseArgument() {1392 // OpenACC 3.3 section 2.15:1393 // The bind clause specifies the name to use when calling the procedure on a1394 // device other than the host. If the name is specified as an identifier, it1395 // is called as if that name were specified in the language being compiled. If1396 // the name is specified as a string, the string is used for the procedure1397 // name unmodified.1398 if (getCurToken().is(tok::r_paren)) {1399 Diag(getCurToken(), diag::err_acc_incorrect_bind_arg);1400 return std::monostate{};1401 }1402 1403 if (getCurToken().is(tok::identifier)) {1404 IdentifierInfo *II = getCurToken().getIdentifierInfo();1405 ConsumeToken();1406 return II;1407 }1408 1409 if (!tok::isStringLiteral(getCurToken().getKind())) {1410 Diag(getCurToken(), diag::err_acc_incorrect_bind_arg);1411 return std::monostate{};1412 }1413 1414 ExprResult Res = ParseStringLiteralExpression(1415 /*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true);1416 if (!Res.isUsable())1417 return std::monostate{};1418 return cast<StringLiteral>(Res.get());1419}1420 1421Parser::OpenACCVarParseResult Parser::ParseOpenACCVar(OpenACCDirectiveKind DK,1422 OpenACCClauseKind CK) {1423 OpenACCArraySectionRAII ArraySections(*this);1424 1425 getActions().OpenACC().ActOnStartParseVar(DK, CK);1426 ExprResult Res = ParseAssignmentExpression();1427 1428 if (!Res.isUsable()) {1429 getActions().OpenACC().ActOnInvalidParseVar();1430 return {Res, OpenACCParseCanContinue::Cannot};1431 }1432 1433 Res = getActions().OpenACC().ActOnVar(DK, CK, Res.get());1434 return {Res, OpenACCParseCanContinue::Can};1435}1436 1437llvm::SmallVector<Expr *> Parser::ParseOpenACCVarList(OpenACCDirectiveKind DK,1438 OpenACCClauseKind CK) {1439 llvm::SmallVector<Expr *> Vars;1440 1441 auto [Res, CanContinue] = ParseOpenACCVar(DK, CK);1442 if (Res.isUsable()) {1443 Vars.push_back(Res.get());1444 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {1445 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, StopBeforeMatch);1446 return Vars;1447 }1448 1449 while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {1450 ExpectAndConsume(tok::comma);1451 1452 auto [Res, CanContinue] = ParseOpenACCVar(DK, CK);1453 1454 if (Res.isUsable()) {1455 Vars.push_back(Res.get());1456 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {1457 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, StopBeforeMatch);1458 return Vars;1459 }1460 }1461 return Vars;1462}1463 1464Parser::OpenACCCacheParseInfo Parser::ParseOpenACCCacheVarList() {1465 // If this is the end of the line, just return 'false' and count on the close1466 // paren diagnostic to catch the issue.1467 if (getCurToken().isAnnotation())1468 return {};1469 1470 OpenACCCacheParseInfo CacheInfo;1471 1472 SourceLocation ReadOnlyLoc = getCurToken().getLocation();1473 // The VarList is an optional `readonly:` followed by a list of a variable1474 // specifications. Consume something that looks like a 'tag', and diagnose if1475 // it isn't 'readonly'.1476 if (tryParseAndConsumeSpecialTokenKind(*this,1477 OpenACCSpecialTokenKind::ReadOnly,1478 OpenACCDirectiveKind::Cache))1479 CacheInfo.ReadOnlyLoc = ReadOnlyLoc;1480 1481 // ParseOpenACCVarList should leave us before a r-paren, so no need to skip1482 // anything here.1483 CacheInfo.Vars = ParseOpenACCVarList(OpenACCDirectiveKind::Cache,1484 OpenACCClauseKind::Invalid);1485 1486 return CacheInfo;1487}1488 1489Parser::OpenACCDirectiveParseInfo1490Parser::ParseOpenACCDirective() {1491 SourceLocation StartLoc = ConsumeAnnotationToken();1492 SourceLocation DirLoc = getCurToken().getLocation();1493 OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);1494 Parser::OpenACCWaitParseInfo WaitInfo;1495 Parser::OpenACCCacheParseInfo CacheInfo;1496 OpenACCAtomicKind AtomicKind = OpenACCAtomicKind::None;1497 ExprResult RoutineName;1498 1499 getActions().OpenACC().ActOnConstruct(DirKind, DirLoc);1500 1501 // Once we've parsed the construct/directive name, some have additional1502 // specifiers that need to be taken care of. Atomic has an 'atomic-clause'1503 // that needs to be parsed.1504 if (DirKind == OpenACCDirectiveKind::Atomic)1505 AtomicKind = ParseOpenACCAtomicKind(*this);1506 1507 // We've successfully parsed the construct/directive name, however a few of1508 // the constructs have optional parens that contain further details.1509 BalancedDelimiterTracker T(*this, tok::l_paren,1510 tok::annot_pragma_openacc_end);1511 1512 if (!T.consumeOpen()) {1513 switch (DirKind) {1514 default:1515 Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);1516 T.skipToEnd();1517 break;1518 case OpenACCDirectiveKind::Routine: {1519 // Routine has an optional paren-wrapped name of a function in the local1520 // scope. We parse the name, emitting any diagnostics1521 RoutineName = ParseOpenACCIDExpression();1522 // If the routine name is invalid, just skip until the closing paren to1523 // recover more gracefully.1524 if (!RoutineName.isUsable()) {1525 T.skipToEnd();1526 } else {1527 T.consumeClose();1528 RoutineName =1529 getActions().OpenACC().ActOnRoutineName(RoutineName.get());1530 }1531 break;1532 }1533 case OpenACCDirectiveKind::Cache:1534 CacheInfo = ParseOpenACCCacheVarList();1535 // The ParseOpenACCCacheVarList function manages to recover from failures,1536 // so we can always consume the close.1537 T.consumeClose();1538 break;1539 case OpenACCDirectiveKind::Wait:1540 // OpenACC has an optional paren-wrapped 'wait-argument'.1541 WaitInfo = ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true);1542 if (WaitInfo.Failed)1543 T.skipToEnd();1544 else1545 T.consumeClose();1546 break;1547 }1548 } else if (DirKind == OpenACCDirectiveKind::Cache) {1549 // Cache's paren var-list is required, so error here if it isn't provided.1550 // We know that the consumeOpen above left the first non-paren here, so1551 // diagnose, then continue as if it was completely omitted.1552 Diag(Tok, diag::err_expected) << tok::l_paren;1553 }1554 1555 // Parses the list of clauses, if present, plus set up return value.1556 OpenACCDirectiveParseInfo ParseInfo{DirKind,1557 StartLoc,1558 DirLoc,1559 T.getOpenLocation(),1560 T.getCloseLocation(),1561 /*EndLoc=*/SourceLocation{},1562 (DirKind == OpenACCDirectiveKind::Wait1563 ? WaitInfo.QueuesLoc1564 : CacheInfo.ReadOnlyLoc),1565 AtomicKind,1566 {},1567 {}};1568 1569 if (DirKind == OpenACCDirectiveKind::Wait)1570 ParseInfo.Exprs = WaitInfo.getAllExprs();1571 else if (DirKind == OpenACCDirectiveKind::Cache)1572 ParseInfo.Exprs = std::move(CacheInfo.Vars);1573 else if (DirKind == OpenACCDirectiveKind::Routine && RoutineName.isUsable())1574 ParseInfo.Exprs = llvm::SmallVector<Expr *>(1, RoutineName.get());1575 1576 ParseInfo.Clauses = ParseOpenACCClauseList(DirKind);1577 1578 assert(Tok.is(tok::annot_pragma_openacc_end) &&1579 "Didn't parse all OpenACC Clauses");1580 ParseInfo.EndLoc = ConsumeAnnotationToken();1581 assert(ParseInfo.EndLoc.isValid() &&1582 "Terminating annotation token not present");1583 1584 return ParseInfo;1585}1586 1587Parser::DeclGroupPtrTy Parser::ParseOpenACCAfterRoutineDecl(1588 AccessSpecifier &AS, ParsedAttributes &Attrs, DeclSpec::TST TagType,1589 Decl *TagDecl, OpenACCDirectiveParseInfo &DirInfo) {1590 assert(DirInfo.DirKind == OpenACCDirectiveKind::Routine);1591 1592 DeclGroupPtrTy Ptr;1593 if (DirInfo.LParenLoc.isInvalid()) {1594 if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {1595 if (AS == AS_none) {1596 // This is either an external declaration, or inside of a C struct. If1597 // the latter, we have to diagnose if this is the 'implicit' named1598 // version.1599 if (TagType == DeclSpec::TST_unspecified) {1600 ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);1601 MaybeParseCXX11Attributes(Attrs);1602 ParsingDeclSpec PDS(*this);1603 Ptr = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs, &PDS);1604 }1605 // The only way we can have a 'none' access specifier that is in a1606 // not-unspecified tag-type is a C struct. Member functions and1607 // lambdas don't work in C, so we can just count on1608 // ActonRoutineDeclDirective to recognize that Ptr is null and diagnose.1609 } else {1610 Ptr = ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType,1611 TagDecl);1612 }1613 }1614 }1615 1616 return DeclGroupPtrTy::make(1617 getActions().OpenACC().ActOnEndRoutineDeclDirective(1618 DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,1619 DirInfo.Exprs.empty() ? nullptr : DirInfo.Exprs.front(),1620 DirInfo.RParenLoc, DirInfo.Clauses, DirInfo.EndLoc, Ptr));1621}1622 1623StmtResult1624Parser::ParseOpenACCAfterRoutineStmt(OpenACCDirectiveParseInfo &DirInfo) {1625 assert(DirInfo.DirKind == OpenACCDirectiveKind::Routine);1626 // We have to know the next statement for 1 of 2 reasons:1627 // Routine without a name needs an associated DeclStmt.1628 // Routine WITH a name needs to see if it is a DeclStmt to diagnose.1629 StmtResult NextStmt = StmtEmpty();1630 1631 // Parse the next statement in the 'implicit' case, not in the 'named' case.1632 // In the 'named' case we will use the creation of the next decl to determine1633 // whether we should warn.1634 if (DirInfo.LParenLoc.isInvalid()) {1635 ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);1636 NextStmt = ParseStatement();1637 }1638 1639 return getActions().OpenACC().ActOnEndRoutineStmtDirective(1640 DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,1641 DirInfo.Exprs.empty() ? nullptr : DirInfo.Exprs.front(),1642 DirInfo.RParenLoc, DirInfo.Clauses, DirInfo.EndLoc, NextStmt.get());1643}1644 1645Parser::DeclGroupPtrTy1646Parser::ParseOpenACCDirectiveDecl(AccessSpecifier &AS, ParsedAttributes &Attrs,1647 DeclSpec::TST TagType, Decl *TagDecl) {1648 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");1649 1650 ParsingOpenACCDirectiveRAII DirScope(*this);1651 1652 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();1653 1654 if (getActions().OpenACC().ActOnStartDeclDirective(1655 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.Clauses))1656 return nullptr;1657 1658 if (DirInfo.DirKind == OpenACCDirectiveKind::Routine)1659 return ParseOpenACCAfterRoutineDecl(AS, Attrs, TagType, TagDecl, DirInfo);1660 1661 return DeclGroupPtrTy::make(getActions().OpenACC().ActOnEndDeclDirective(1662 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,1663 DirInfo.RParenLoc, DirInfo.EndLoc, DirInfo.Clauses));1664}1665 1666StmtResult Parser::ParseOpenACCDirectiveStmt() {1667 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");1668 1669 ParsingOpenACCDirectiveRAII DirScope(*this);1670 1671 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();1672 if (getActions().OpenACC().ActOnStartStmtDirective(1673 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.Clauses))1674 return StmtError();1675 1676 if (DirInfo.DirKind == OpenACCDirectiveKind::Routine)1677 return ParseOpenACCAfterRoutineStmt(DirInfo);1678 1679 StmtResult AssocStmt;1680 if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) {1681 SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(1682 getActions().OpenACC(), DirInfo.DirKind, DirInfo.DirLoc, {},1683 DirInfo.Clauses);1684 ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);1685 ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));1686 1687 AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(1688 DirInfo.StartLoc, DirInfo.DirKind, DirInfo.AtomicKind, DirInfo.Clauses,1689 ParseStatement());1690 }1691 1692 return getActions().OpenACC().ActOnEndStmtDirective(1693 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,1694 DirInfo.MiscLoc, DirInfo.Exprs, DirInfo.AtomicKind, DirInfo.RParenLoc,1695 DirInfo.EndLoc, DirInfo.Clauses, AssocStmt);1696}1697