brintos

brintos / llvm-project-archived public Read only

0
0
Text · 60.8 KiB · b79a956 Raw
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