Path: blob/main/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp
35234 views
//===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the parsing logic for OpenACC language features.9//10//===----------------------------------------------------------------------===//1112#include "clang/AST/OpenACCClause.h"13#include "clang/Basic/OpenACCKinds.h"14#include "clang/Parse/ParseDiagnostic.h"15#include "clang/Parse/Parser.h"16#include "clang/Parse/RAIIObjectsForParser.h"17#include "clang/Sema/SemaOpenACC.h"18#include "llvm/ADT/StringRef.h"19#include "llvm/ADT/StringSwitch.h"2021using namespace clang;22using namespace llvm;2324namespace {25// An enum that contains the extended 'partial' parsed variants. This type26// should never escape the initial parse functionality, but is useful for27// simplifying the implementation.28enum class OpenACCDirectiveKindEx {29Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),30// 'enter data' and 'exit data'31Enter,32Exit,33};3435// Translate single-token string representations to the OpenACC Directive Kind.36// This doesn't completely comprehend 'Compound Constructs' (as it just37// identifies the first token), and doesn't fully handle 'enter data', 'exit38// data', nor any of the 'atomic' variants, just the first token of each. So39// this should only be used by `ParseOpenACCDirectiveKind`.40OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {41if (!Tok.is(tok::identifier))42return OpenACCDirectiveKindEx::Invalid;43OpenACCDirectiveKind DirKind =44llvm::StringSwitch<OpenACCDirectiveKind>(45Tok.getIdentifierInfo()->getName())46.Case("parallel", OpenACCDirectiveKind::Parallel)47.Case("serial", OpenACCDirectiveKind::Serial)48.Case("kernels", OpenACCDirectiveKind::Kernels)49.Case("data", OpenACCDirectiveKind::Data)50.Case("host_data", OpenACCDirectiveKind::HostData)51.Case("loop", OpenACCDirectiveKind::Loop)52.Case("cache", OpenACCDirectiveKind::Cache)53.Case("atomic", OpenACCDirectiveKind::Atomic)54.Case("routine", OpenACCDirectiveKind::Routine)55.Case("declare", OpenACCDirectiveKind::Declare)56.Case("init", OpenACCDirectiveKind::Init)57.Case("shutdown", OpenACCDirectiveKind::Shutdown)58.Case("set", OpenACCDirectiveKind::Set)59.Case("update", OpenACCDirectiveKind::Update)60.Case("wait", OpenACCDirectiveKind::Wait)61.Default(OpenACCDirectiveKind::Invalid);6263if (DirKind != OpenACCDirectiveKind::Invalid)64return static_cast<OpenACCDirectiveKindEx>(DirKind);6566return llvm::StringSwitch<OpenACCDirectiveKindEx>(67Tok.getIdentifierInfo()->getName())68.Case("enter", OpenACCDirectiveKindEx::Enter)69.Case("exit", OpenACCDirectiveKindEx::Exit)70.Default(OpenACCDirectiveKindEx::Invalid);71}7273// Translate single-token string representations to the OpenCC Clause Kind.74OpenACCClauseKind getOpenACCClauseKind(Token Tok) {75// auto is a keyword in some language modes, so make sure we parse it76// correctly.77if (Tok.is(tok::kw_auto))78return OpenACCClauseKind::Auto;7980// default is a keyword, so make sure we parse it correctly.81if (Tok.is(tok::kw_default))82return OpenACCClauseKind::Default;8384// if is also a keyword, make sure we parse it correctly.85if (Tok.is(tok::kw_if))86return OpenACCClauseKind::If;8788// 'private' is also a keyword, make sure we pare it correctly.89if (Tok.is(tok::kw_private))90return OpenACCClauseKind::Private;9192if (!Tok.is(tok::identifier))93return OpenACCClauseKind::Invalid;9495return llvm::StringSwitch<OpenACCClauseKind>(96Tok.getIdentifierInfo()->getName())97.Case("async", OpenACCClauseKind::Async)98.Case("attach", OpenACCClauseKind::Attach)99.Case("auto", OpenACCClauseKind::Auto)100.Case("bind", OpenACCClauseKind::Bind)101.Case("create", OpenACCClauseKind::Create)102.Case("pcreate", OpenACCClauseKind::PCreate)103.Case("present_or_create", OpenACCClauseKind::PresentOrCreate)104.Case("collapse", OpenACCClauseKind::Collapse)105.Case("copy", OpenACCClauseKind::Copy)106.Case("pcopy", OpenACCClauseKind::PCopy)107.Case("present_or_copy", OpenACCClauseKind::PresentOrCopy)108.Case("copyin", OpenACCClauseKind::CopyIn)109.Case("pcopyin", OpenACCClauseKind::PCopyIn)110.Case("present_or_copyin", OpenACCClauseKind::PresentOrCopyIn)111.Case("copyout", OpenACCClauseKind::CopyOut)112.Case("pcopyout", OpenACCClauseKind::PCopyOut)113.Case("present_or_copyout", OpenACCClauseKind::PresentOrCopyOut)114.Case("default", OpenACCClauseKind::Default)115.Case("default_async", OpenACCClauseKind::DefaultAsync)116.Case("delete", OpenACCClauseKind::Delete)117.Case("detach", OpenACCClauseKind::Detach)118.Case("device", OpenACCClauseKind::Device)119.Case("device_num", OpenACCClauseKind::DeviceNum)120.Case("device_resident", OpenACCClauseKind::DeviceResident)121.Case("device_type", OpenACCClauseKind::DeviceType)122.Case("deviceptr", OpenACCClauseKind::DevicePtr)123.Case("dtype", OpenACCClauseKind::DType)124.Case("finalize", OpenACCClauseKind::Finalize)125.Case("firstprivate", OpenACCClauseKind::FirstPrivate)126.Case("gang", OpenACCClauseKind::Gang)127.Case("host", OpenACCClauseKind::Host)128.Case("if", OpenACCClauseKind::If)129.Case("if_present", OpenACCClauseKind::IfPresent)130.Case("independent", OpenACCClauseKind::Independent)131.Case("link", OpenACCClauseKind::Link)132.Case("no_create", OpenACCClauseKind::NoCreate)133.Case("num_gangs", OpenACCClauseKind::NumGangs)134.Case("num_workers", OpenACCClauseKind::NumWorkers)135.Case("nohost", OpenACCClauseKind::NoHost)136.Case("present", OpenACCClauseKind::Present)137.Case("private", OpenACCClauseKind::Private)138.Case("reduction", OpenACCClauseKind::Reduction)139.Case("self", OpenACCClauseKind::Self)140.Case("seq", OpenACCClauseKind::Seq)141.Case("tile", OpenACCClauseKind::Tile)142.Case("use_device", OpenACCClauseKind::UseDevice)143.Case("vector", OpenACCClauseKind::Vector)144.Case("vector_length", OpenACCClauseKind::VectorLength)145.Case("wait", OpenACCClauseKind::Wait)146.Case("worker", OpenACCClauseKind::Worker)147.Default(OpenACCClauseKind::Invalid);148}149150// Since 'atomic' is effectively a compound directive, this will decode the151// second part of the directive.152OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {153if (!Tok.is(tok::identifier))154return OpenACCAtomicKind::Invalid;155return llvm::StringSwitch<OpenACCAtomicKind>(156Tok.getIdentifierInfo()->getName())157.Case("read", OpenACCAtomicKind::Read)158.Case("write", OpenACCAtomicKind::Write)159.Case("update", OpenACCAtomicKind::Update)160.Case("capture", OpenACCAtomicKind::Capture)161.Default(OpenACCAtomicKind::Invalid);162}163164OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) {165if (!Tok.is(tok::identifier))166return OpenACCDefaultClauseKind::Invalid;167168return llvm::StringSwitch<OpenACCDefaultClauseKind>(169Tok.getIdentifierInfo()->getName())170.Case("none", OpenACCDefaultClauseKind::None)171.Case("present", OpenACCDefaultClauseKind::Present)172.Default(OpenACCDefaultClauseKind::Invalid);173}174175enum class OpenACCSpecialTokenKind {176ReadOnly,177DevNum,178Queues,179Zero,180Force,181Num,182Length,183Dim,184Static,185};186187bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {188if (Tok.is(tok::kw_static) && Kind == OpenACCSpecialTokenKind::Static)189return true;190191if (!Tok.is(tok::identifier))192return false;193194switch (Kind) {195case OpenACCSpecialTokenKind::ReadOnly:196return Tok.getIdentifierInfo()->isStr("readonly");197case OpenACCSpecialTokenKind::DevNum:198return Tok.getIdentifierInfo()->isStr("devnum");199case OpenACCSpecialTokenKind::Queues:200return Tok.getIdentifierInfo()->isStr("queues");201case OpenACCSpecialTokenKind::Zero:202return Tok.getIdentifierInfo()->isStr("zero");203case OpenACCSpecialTokenKind::Force:204return Tok.getIdentifierInfo()->isStr("force");205case OpenACCSpecialTokenKind::Num:206return Tok.getIdentifierInfo()->isStr("num");207case OpenACCSpecialTokenKind::Length:208return Tok.getIdentifierInfo()->isStr("length");209case OpenACCSpecialTokenKind::Dim:210return Tok.getIdentifierInfo()->isStr("dim");211case OpenACCSpecialTokenKind::Static:212return Tok.getIdentifierInfo()->isStr("static");213}214llvm_unreachable("Unknown 'Kind' Passed");215}216217/// Used for cases where we have a token we want to check against an218/// 'identifier-like' token, but don't want to give awkward error messages in219/// cases where it is accidentially a keyword.220bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) {221if (Tok.is(tok::identifier))222return true;223224if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&225Tok.getIdentifierInfo()->isKeyword(P.getLangOpts()))226return true;227228return false;229}230231/// Parses and consumes an identifer followed immediately by a single colon, and232/// diagnoses if it is not the 'special token' kind that we require. Used when233/// the tag is the only valid value.234/// Return 'true' if the special token was matched, false if no special token,235/// or an invalid special token was found.236template <typename DirOrClauseTy>237bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind,238DirOrClauseTy DirOrClause) {239Token IdentTok = P.getCurToken();240// If this is an identifier-like thing followed by ':', it is one of the241// OpenACC 'special' name tags, so consume it.242if (isTokenIdentifierOrKeyword(P, IdentTok) && P.NextToken().is(tok::colon)) {243P.ConsumeToken();244P.ConsumeToken();245246if (!isOpenACCSpecialToken(Kind, IdentTok)) {247P.Diag(IdentTok, diag::err_acc_invalid_tag_kind)248<< IdentTok.getIdentifierInfo() << DirOrClause249<< std::is_same_v<DirOrClauseTy, OpenACCClauseKind>;250return false;251}252253return true;254}255256return false;257}258259bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {260if (!Tok.is(tok::identifier))261return false;262263switch (Kind) {264case OpenACCDirectiveKind::Parallel:265return Tok.getIdentifierInfo()->isStr("parallel");266case OpenACCDirectiveKind::Serial:267return Tok.getIdentifierInfo()->isStr("serial");268case OpenACCDirectiveKind::Kernels:269return Tok.getIdentifierInfo()->isStr("kernels");270case OpenACCDirectiveKind::Data:271return Tok.getIdentifierInfo()->isStr("data");272case OpenACCDirectiveKind::HostData:273return Tok.getIdentifierInfo()->isStr("host_data");274case OpenACCDirectiveKind::Loop:275return Tok.getIdentifierInfo()->isStr("loop");276case OpenACCDirectiveKind::Cache:277return Tok.getIdentifierInfo()->isStr("cache");278279case OpenACCDirectiveKind::ParallelLoop:280case OpenACCDirectiveKind::SerialLoop:281case OpenACCDirectiveKind::KernelsLoop:282case OpenACCDirectiveKind::EnterData:283case OpenACCDirectiveKind::ExitData:284return false;285286case OpenACCDirectiveKind::Atomic:287return Tok.getIdentifierInfo()->isStr("atomic");288case OpenACCDirectiveKind::Routine:289return Tok.getIdentifierInfo()->isStr("routine");290case OpenACCDirectiveKind::Declare:291return Tok.getIdentifierInfo()->isStr("declare");292case OpenACCDirectiveKind::Init:293return Tok.getIdentifierInfo()->isStr("init");294case OpenACCDirectiveKind::Shutdown:295return Tok.getIdentifierInfo()->isStr("shutdown");296case OpenACCDirectiveKind::Set:297return Tok.getIdentifierInfo()->isStr("set");298case OpenACCDirectiveKind::Update:299return Tok.getIdentifierInfo()->isStr("update");300case OpenACCDirectiveKind::Wait:301return Tok.getIdentifierInfo()->isStr("wait");302case OpenACCDirectiveKind::Invalid:303return false;304}305llvm_unreachable("Unknown 'Kind' Passed");306}307308OpenACCReductionOperator ParseReductionOperator(Parser &P) {309// If there is no colon, treat as if the reduction operator was missing, else310// we probably will not recover from it in the case where an expression starts311// with one of the operator tokens.312if (P.NextToken().isNot(tok::colon)) {313P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator);314return OpenACCReductionOperator::Invalid;315}316Token ReductionKindTok = P.getCurToken();317// Consume both the kind and the colon.318P.ConsumeToken();319P.ConsumeToken();320321switch (ReductionKindTok.getKind()) {322case tok::plus:323return OpenACCReductionOperator::Addition;324case tok::star:325return OpenACCReductionOperator::Multiplication;326case tok::amp:327return OpenACCReductionOperator::BitwiseAnd;328case tok::pipe:329return OpenACCReductionOperator::BitwiseOr;330case tok::caret:331return OpenACCReductionOperator::BitwiseXOr;332case tok::ampamp:333return OpenACCReductionOperator::And;334case tok::pipepipe:335return OpenACCReductionOperator::Or;336case tok::identifier:337if (ReductionKindTok.getIdentifierInfo()->isStr("max"))338return OpenACCReductionOperator::Max;339if (ReductionKindTok.getIdentifierInfo()->isStr("min"))340return OpenACCReductionOperator::Min;341[[fallthrough]];342default:343P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator);344return OpenACCReductionOperator::Invalid;345}346llvm_unreachable("Reduction op token kind not caught by 'default'?");347}348349/// Used for cases where we expect an identifier-like token, but don't want to350/// give awkward error messages in cases where it is accidentially a keyword.351bool expectIdentifierOrKeyword(Parser &P) {352Token Tok = P.getCurToken();353354if (isTokenIdentifierOrKeyword(P, Tok))355return false;356357P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;358return true;359}360361OpenACCDirectiveKind362ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,363OpenACCDirectiveKindEx ExtDirKind) {364Token SecondTok = P.getCurToken();365366if (SecondTok.isAnnotation()) {367P.Diag(FirstTok, diag::err_acc_invalid_directive)368<< 0 << FirstTok.getIdentifierInfo();369return OpenACCDirectiveKind::Invalid;370}371372// Consume the second name anyway, this way we can continue on without making373// this oddly look like a clause.374P.ConsumeAnyToken();375376if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) {377if (!SecondTok.is(tok::identifier))378P.Diag(SecondTok, diag::err_expected) << tok::identifier;379else380P.Diag(FirstTok, diag::err_acc_invalid_directive)381<< 1 << FirstTok.getIdentifierInfo()->getName()382<< SecondTok.getIdentifierInfo()->getName();383return OpenACCDirectiveKind::Invalid;384}385386return ExtDirKind == OpenACCDirectiveKindEx::Enter387? OpenACCDirectiveKind::EnterData388: OpenACCDirectiveKind::ExitData;389}390391OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) {392Token AtomicClauseToken = P.getCurToken();393394// #pragma acc atomic is equivilent to update:395if (AtomicClauseToken.isAnnotation())396return OpenACCAtomicKind::Update;397398OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken);399400// If we don't know what this is, treat it as 'nothing', and treat the rest of401// this as a clause list, which, despite being invalid, is likely what the402// user was trying to do.403if (AtomicKind == OpenACCAtomicKind::Invalid)404return OpenACCAtomicKind::Update;405406P.ConsumeToken();407return AtomicKind;408}409410// Parse and consume the tokens for OpenACC Directive/Construct kinds.411OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {412Token FirstTok = P.getCurToken();413414// Just #pragma acc can get us immediately to the end, make sure we don't415// introspect on the spelling before then.416if (FirstTok.isNot(tok::identifier)) {417P.Diag(FirstTok, diag::err_acc_missing_directive);418419if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))420P.ConsumeAnyToken();421422return OpenACCDirectiveKind::Invalid;423}424425P.ConsumeToken();426427OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok);428429// OpenACCDirectiveKindEx is meant to be an extended list430// over OpenACCDirectiveKind, so any value below Invalid is one of the431// OpenACCDirectiveKind values. This switch takes care of all of the extra432// parsing required for the Extended values. At the end of this block,433// ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can434// immediately cast it and use it as that.435if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {436switch (ExDirKind) {437case OpenACCDirectiveKindEx::Invalid: {438P.Diag(FirstTok, diag::err_acc_invalid_directive)439<< 0 << FirstTok.getIdentifierInfo();440return OpenACCDirectiveKind::Invalid;441}442case OpenACCDirectiveKindEx::Enter:443case OpenACCDirectiveKindEx::Exit:444return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind);445}446}447448OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);449450// Combined Constructs allows parallel loop, serial loop, or kernels loop. Any451// other attempt at a combined construct will be diagnosed as an invalid452// clause.453Token SecondTok = P.getCurToken();454if (!SecondTok.isAnnotation() &&455isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) {456switch (DirKind) {457default:458// Nothing to do except in the below cases, as they should be diagnosed as459// a clause.460break;461case OpenACCDirectiveKind::Parallel:462P.ConsumeToken();463return OpenACCDirectiveKind::ParallelLoop;464case OpenACCDirectiveKind::Serial:465P.ConsumeToken();466return OpenACCDirectiveKind::SerialLoop;467case OpenACCDirectiveKind::Kernels:468P.ConsumeToken();469return OpenACCDirectiveKind::KernelsLoop;470}471}472473return DirKind;474}475476enum ClauseParensKind {477None,478Optional,479Required480};481482ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind,483OpenACCClauseKind Kind) {484switch (Kind) {485case OpenACCClauseKind::Self:486return DirKind == OpenACCDirectiveKind::Update ? ClauseParensKind::Required487: ClauseParensKind::Optional;488case OpenACCClauseKind::Async:489case OpenACCClauseKind::Worker:490case OpenACCClauseKind::Vector:491case OpenACCClauseKind::Gang:492case OpenACCClauseKind::Wait:493return ClauseParensKind::Optional;494495case OpenACCClauseKind::Default:496case OpenACCClauseKind::If:497case OpenACCClauseKind::Create:498case OpenACCClauseKind::PCreate:499case OpenACCClauseKind::PresentOrCreate:500case OpenACCClauseKind::Copy:501case OpenACCClauseKind::PCopy:502case OpenACCClauseKind::PresentOrCopy:503case OpenACCClauseKind::CopyIn:504case OpenACCClauseKind::PCopyIn:505case OpenACCClauseKind::PresentOrCopyIn:506case OpenACCClauseKind::CopyOut:507case OpenACCClauseKind::PCopyOut:508case OpenACCClauseKind::PresentOrCopyOut:509case OpenACCClauseKind::UseDevice:510case OpenACCClauseKind::NoCreate:511case OpenACCClauseKind::Present:512case OpenACCClauseKind::DevicePtr:513case OpenACCClauseKind::Attach:514case OpenACCClauseKind::Detach:515case OpenACCClauseKind::Private:516case OpenACCClauseKind::FirstPrivate:517case OpenACCClauseKind::Delete:518case OpenACCClauseKind::DeviceResident:519case OpenACCClauseKind::Device:520case OpenACCClauseKind::Link:521case OpenACCClauseKind::Host:522case OpenACCClauseKind::Reduction:523case OpenACCClauseKind::Collapse:524case OpenACCClauseKind::Bind:525case OpenACCClauseKind::VectorLength:526case OpenACCClauseKind::NumGangs:527case OpenACCClauseKind::NumWorkers:528case OpenACCClauseKind::DeviceNum:529case OpenACCClauseKind::DefaultAsync:530case OpenACCClauseKind::DeviceType:531case OpenACCClauseKind::DType:532case OpenACCClauseKind::Tile:533return ClauseParensKind::Required;534535case OpenACCClauseKind::Auto:536case OpenACCClauseKind::Finalize:537case OpenACCClauseKind::IfPresent:538case OpenACCClauseKind::Independent:539case OpenACCClauseKind::Invalid:540case OpenACCClauseKind::NoHost:541case OpenACCClauseKind::Seq:542return ClauseParensKind::None;543}544llvm_unreachable("Unhandled clause kind");545}546547bool ClauseHasOptionalParens(OpenACCDirectiveKind DirKind,548OpenACCClauseKind Kind) {549return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional;550}551552bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind,553OpenACCClauseKind Kind) {554return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required;555}556557// Skip until we see the end of pragma token, but don't consume it. This is us558// just giving up on the rest of the pragma so we can continue executing. We559// have to do this because 'SkipUntil' considers paren balancing, which isn't560// what we want.561void SkipUntilEndOfDirective(Parser &P) {562while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))563P.ConsumeAnyToken();564}565566bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {567switch (DirKind) {568default:569return false;570case OpenACCDirectiveKind::Parallel:571case OpenACCDirectiveKind::Serial:572case OpenACCDirectiveKind::Kernels:573case OpenACCDirectiveKind::Loop:574return true;575}576llvm_unreachable("Unhandled directive->assoc stmt");577}578579unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {580switch (DirKind) {581case OpenACCDirectiveKind::Parallel:582case OpenACCDirectiveKind::Serial:583case OpenACCDirectiveKind::Kernels:584// Mark this as a BreakScope/ContinueScope as well as a compute construct585// so that we can diagnose trying to 'break'/'continue' inside of one.586return Scope::BreakScope | Scope::ContinueScope |587Scope::OpenACCComputeConstructScope;588case OpenACCDirectiveKind::Invalid:589llvm_unreachable("Shouldn't be creating a scope for an invalid construct");590default:591break;592}593return 0;594}595596} // namespace597598Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() {599return {nullptr, OpenACCParseCanContinue::Can};600}601602Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() {603return {nullptr, OpenACCParseCanContinue::Cannot};604}605606Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) {607return {Clause, OpenACCParseCanContinue::Can};608}609610ExprResult Parser::ParseOpenACCConditionExpr() {611// FIXME: It isn't clear if the spec saying 'condition' means the same as612// it does in an if/while/etc (See ParseCXXCondition), however as it was613// written with Fortran/C in mind, we're going to assume it just means an614// 'expression evaluating to boolean'.615ExprResult ER = getActions().CorrectDelayedTyposInExpr(ParseExpression());616617if (!ER.isUsable())618return ER;619620Sema::ConditionResult R =621getActions().ActOnCondition(getCurScope(), ER.get()->getExprLoc(),622ER.get(), Sema::ConditionKind::Boolean);623624return R.isInvalid() ? ExprError() : R.get().second;625}626627// OpenACC 3.3, section 1.7:628// To simplify the specification and convey appropriate constraint information,629// a pqr-list is a comma-separated list of pdr items. The one exception is a630// clause-list, which is a list of one or more clauses optionally separated by631// commas.632SmallVector<OpenACCClause *>633Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {634SmallVector<OpenACCClause *> Clauses;635bool FirstClause = true;636while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {637// Comma is optional in a clause-list.638if (!FirstClause && getCurToken().is(tok::comma))639ConsumeToken();640FirstClause = false;641642OpenACCClauseParseResult Result = ParseOpenACCClause(Clauses, DirKind);643if (OpenACCClause *Clause = Result.getPointer()) {644Clauses.push_back(Clause);645} else if (Result.getInt() == OpenACCParseCanContinue::Cannot) {646// Recovering from a bad clause is really difficult, so we just give up on647// error.648SkipUntilEndOfDirective(*this);649return Clauses;650}651}652return Clauses;653}654655Parser::OpenACCIntExprParseResult656Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,657SourceLocation Loc) {658ExprResult ER = ParseAssignmentExpression();659660// If the actual parsing failed, we don't know the state of the parse, so661// don't try to continue.662if (!ER.isUsable())663return {ER, OpenACCParseCanContinue::Cannot};664665// Parsing can continue after the initial assignment expression parsing, so666// even if there was a typo, we can continue.667ER = getActions().CorrectDelayedTyposInExpr(ER);668if (!ER.isUsable())669return {ER, OpenACCParseCanContinue::Can};670671return {getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, ER.get()),672OpenACCParseCanContinue::Can};673}674675bool Parser::ParseOpenACCIntExprList(OpenACCDirectiveKind DK,676OpenACCClauseKind CK, SourceLocation Loc,677llvm::SmallVectorImpl<Expr *> &IntExprs) {678OpenACCIntExprParseResult CurResult = ParseOpenACCIntExpr(DK, CK, Loc);679680if (!CurResult.first.isUsable() &&681CurResult.second == OpenACCParseCanContinue::Cannot) {682SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,683Parser::StopBeforeMatch);684return true;685}686687IntExprs.push_back(CurResult.first.get());688689while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {690ExpectAndConsume(tok::comma);691692CurResult = ParseOpenACCIntExpr(DK, CK, Loc);693694if (!CurResult.first.isUsable() &&695CurResult.second == OpenACCParseCanContinue::Cannot) {696SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,697Parser::StopBeforeMatch);698return true;699}700IntExprs.push_back(CurResult.first.get());701}702return false;703}704705/// OpenACC 3.3 Section 2.4:706/// The argument to the device_type clause is a comma-separated list of one or707/// more device architecture name identifiers, or an asterisk.708///709/// The syntax of the device_type clause is710/// device_type( * )711/// device_type( device-type-list )712///713/// The device_type clause may be abbreviated to dtype.714bool Parser::ParseOpenACCDeviceTypeList(715llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>> &Archs) {716717if (expectIdentifierOrKeyword(*this)) {718SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,719Parser::StopBeforeMatch);720return true;721}722IdentifierInfo *Ident = getCurToken().getIdentifierInfo();723Archs.emplace_back(Ident, ConsumeToken());724725while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {726ExpectAndConsume(tok::comma);727728if (expectIdentifierOrKeyword(*this)) {729SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,730Parser::StopBeforeMatch);731return true;732}733Ident = getCurToken().getIdentifierInfo();734Archs.emplace_back(Ident, ConsumeToken());735}736return false;737}738739/// OpenACC 3.3 Section 2.9:740/// size-expr is one of:741// *742// int-expr743// Note that this is specified under 'gang-arg-list', but also applies to 'tile'744// via reference.745bool Parser::ParseOpenACCSizeExpr() {746// FIXME: Ensure these are constant expressions.747748// The size-expr ends up being ambiguous when only looking at the current749// token, as it could be a deref of a variable/expression.750if (getCurToken().is(tok::star) &&751NextToken().isOneOf(tok::comma, tok::r_paren,752tok::annot_pragma_openacc_end)) {753ConsumeToken();754return false;755}756757return getActions()758.CorrectDelayedTyposInExpr(ParseAssignmentExpression())759.isInvalid();760}761762bool Parser::ParseOpenACCSizeExprList() {763if (ParseOpenACCSizeExpr()) {764SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,765Parser::StopBeforeMatch);766return false;767}768769while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {770ExpectAndConsume(tok::comma);771772if (ParseOpenACCSizeExpr()) {773SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,774Parser::StopBeforeMatch);775return false;776}777}778return false;779}780781/// OpenACC 3.3 Section 2.9:782///783/// where gang-arg is one of:784/// [num:]int-expr785/// dim:int-expr786/// static:size-expr787bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {788789if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Static, getCurToken()) &&790NextToken().is(tok::colon)) {791// 'static' just takes a size-expr, which is an int-expr or an asterisk.792ConsumeToken();793ConsumeToken();794return ParseOpenACCSizeExpr();795}796797if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Dim, getCurToken()) &&798NextToken().is(tok::colon)) {799ConsumeToken();800ConsumeToken();801return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,802OpenACCClauseKind::Gang, GangLoc)803.first.isInvalid();804}805806if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) &&807NextToken().is(tok::colon)) {808ConsumeToken();809ConsumeToken();810// Fallthrough to the 'int-expr' handling for when 'num' is omitted.811}812// This is just the 'num' case where 'num' is optional.813return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,814OpenACCClauseKind::Gang, GangLoc)815.first.isInvalid();816}817818bool Parser::ParseOpenACCGangArgList(SourceLocation GangLoc) {819if (ParseOpenACCGangArg(GangLoc)) {820SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,821Parser::StopBeforeMatch);822return false;823}824825while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {826ExpectAndConsume(tok::comma);827828if (ParseOpenACCGangArg(GangLoc)) {829SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,830Parser::StopBeforeMatch);831return false;832}833}834return false;835}836837// The OpenACC Clause List is a comma or space-delimited list of clauses (see838// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't839// really have its owner grammar and each individual one has its own definition.840// However, they all are named with a single-identifier (or auto/default!)841// token, followed in some cases by either braces or parens.842Parser::OpenACCClauseParseResult843Parser::ParseOpenACCClause(ArrayRef<const OpenACCClause *> ExistingClauses,844OpenACCDirectiveKind DirKind) {845// A number of clause names are actually keywords, so accept a keyword that846// can be converted to a name.847if (expectIdentifierOrKeyword(*this))848return OpenACCCannotContinue();849850OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken());851852if (Kind == OpenACCClauseKind::Invalid) {853Diag(getCurToken(), diag::err_acc_invalid_clause)854<< getCurToken().getIdentifierInfo();855return OpenACCCannotContinue();856}857858// Consume the clause name.859SourceLocation ClauseLoc = ConsumeToken();860861return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc);862}863864Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(865ArrayRef<const OpenACCClause *> ExistingClauses,866OpenACCDirectiveKind DirKind, OpenACCClauseKind ClauseKind,867SourceLocation ClauseLoc) {868BalancedDelimiterTracker Parens(*this, tok::l_paren,869tok::annot_pragma_openacc_end);870SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);871872if (ClauseHasRequiredParens(DirKind, ClauseKind)) {873if (Parens.expectAndConsume()) {874// We are missing a paren, so assume that the person just forgot the875// parameter. Return 'false' so we try to continue on and parse the next876// clause.877SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,878Parser::StopBeforeMatch);879return OpenACCCanContinue();880}881ParsedClause.setLParenLoc(Parens.getOpenLocation());882883switch (ClauseKind) {884case OpenACCClauseKind::Default: {885Token DefKindTok = getCurToken();886887if (expectIdentifierOrKeyword(*this)) {888Parens.skipToEnd();889return OpenACCCanContinue();890}891892ConsumeToken();893894OpenACCDefaultClauseKind DefKind =895getOpenACCDefaultClauseKind(DefKindTok);896897if (DefKind == OpenACCDefaultClauseKind::Invalid) {898Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);899Parens.skipToEnd();900return OpenACCCanContinue();901}902903ParsedClause.setDefaultDetails(DefKind);904break;905}906case OpenACCClauseKind::If: {907ExprResult CondExpr = ParseOpenACCConditionExpr();908ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()909: nullptr);910911if (CondExpr.isInvalid()) {912Parens.skipToEnd();913return OpenACCCanContinue();914}915916break;917}918case OpenACCClauseKind::CopyIn:919case OpenACCClauseKind::PCopyIn:920case OpenACCClauseKind::PresentOrCopyIn: {921bool IsReadOnly = tryParseAndConsumeSpecialTokenKind(922*this, OpenACCSpecialTokenKind::ReadOnly, ClauseKind);923ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),924IsReadOnly,925/*IsZero=*/false);926break;927}928case OpenACCClauseKind::Create:929case OpenACCClauseKind::PCreate:930case OpenACCClauseKind::PresentOrCreate:931case OpenACCClauseKind::CopyOut:932case OpenACCClauseKind::PCopyOut:933case OpenACCClauseKind::PresentOrCopyOut: {934bool IsZero = tryParseAndConsumeSpecialTokenKind(935*this, OpenACCSpecialTokenKind::Zero, ClauseKind);936ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),937/*IsReadOnly=*/false, IsZero);938break;939}940case OpenACCClauseKind::Reduction: {941// If we're missing a clause-kind (or it is invalid), see if we can parse942// the var-list anyway.943OpenACCReductionOperator Op = ParseReductionOperator(*this);944ParsedClause.setReductionDetails(Op, ParseOpenACCVarList(ClauseKind));945break;946}947case OpenACCClauseKind::Self:948// The 'self' clause is a var-list instead of a 'condition' in the case of949// the 'update' clause, so we have to handle it here. U se an assert to950// make sure we get the right differentiator.951assert(DirKind == OpenACCDirectiveKind::Update);952[[fallthrough]];953case OpenACCClauseKind::Delete:954case OpenACCClauseKind::Detach:955case OpenACCClauseKind::Device:956case OpenACCClauseKind::DeviceResident:957case OpenACCClauseKind::Host:958case OpenACCClauseKind::Link:959case OpenACCClauseKind::UseDevice:960ParseOpenACCVarList(ClauseKind);961break;962case OpenACCClauseKind::Attach:963case OpenACCClauseKind::DevicePtr:964ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),965/*IsReadOnly=*/false, /*IsZero=*/false);966break;967case OpenACCClauseKind::Copy:968case OpenACCClauseKind::PCopy:969case OpenACCClauseKind::PresentOrCopy:970case OpenACCClauseKind::FirstPrivate:971case OpenACCClauseKind::NoCreate:972case OpenACCClauseKind::Present:973case OpenACCClauseKind::Private:974ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),975/*IsReadOnly=*/false, /*IsZero=*/false);976break;977case OpenACCClauseKind::Collapse: {978tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Force,979ClauseKind);980ExprResult NumLoops =981getActions().CorrectDelayedTyposInExpr(ParseConstantExpression());982if (NumLoops.isInvalid()) {983Parens.skipToEnd();984return OpenACCCanContinue();985}986break;987}988case OpenACCClauseKind::Bind: {989ExprResult BindArg = ParseOpenACCBindClauseArgument();990if (BindArg.isInvalid()) {991Parens.skipToEnd();992return OpenACCCanContinue();993}994break;995}996case OpenACCClauseKind::NumGangs: {997llvm::SmallVector<Expr *> IntExprs;998999if (ParseOpenACCIntExprList(OpenACCDirectiveKind::Invalid,1000OpenACCClauseKind::NumGangs, ClauseLoc,1001IntExprs)) {1002Parens.skipToEnd();1003return OpenACCCanContinue();1004}1005ParsedClause.setIntExprDetails(std::move(IntExprs));1006break;1007}1008case OpenACCClauseKind::NumWorkers:1009case OpenACCClauseKind::DeviceNum:1010case OpenACCClauseKind::DefaultAsync:1011case OpenACCClauseKind::VectorLength: {1012ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,1013ClauseKind, ClauseLoc)1014.first;1015if (IntExpr.isInvalid()) {1016Parens.skipToEnd();1017return OpenACCCanContinue();1018}10191020// TODO OpenACC: as we implement the 'rest' of the above, this 'if' should1021// be removed leaving just the 'setIntExprDetails'.1022if (ClauseKind == OpenACCClauseKind::NumWorkers ||1023ClauseKind == OpenACCClauseKind::VectorLength)1024ParsedClause.setIntExprDetails(IntExpr.get());10251026break;1027}1028case OpenACCClauseKind::DType:1029case OpenACCClauseKind::DeviceType: {1030llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>> Archs;1031if (getCurToken().is(tok::star)) {1032// FIXME: We want to mark that this is an 'everything else' type of1033// device_type in Sema.1034ParsedClause.setDeviceTypeDetails({{nullptr, ConsumeToken()}});1035} else if (!ParseOpenACCDeviceTypeList(Archs)) {1036ParsedClause.setDeviceTypeDetails(std::move(Archs));1037} else {1038Parens.skipToEnd();1039return OpenACCCanContinue();1040}1041break;1042}1043case OpenACCClauseKind::Tile:1044if (ParseOpenACCSizeExprList()) {1045Parens.skipToEnd();1046return OpenACCCanContinue();1047}1048break;1049default:1050llvm_unreachable("Not a required parens type?");1051}10521053ParsedClause.setEndLoc(getCurToken().getLocation());10541055if (Parens.consumeClose())1056return OpenACCCannotContinue();10571058} else if (ClauseHasOptionalParens(DirKind, ClauseKind)) {1059if (!Parens.consumeOpen()) {1060ParsedClause.setLParenLoc(Parens.getOpenLocation());1061switch (ClauseKind) {1062case OpenACCClauseKind::Self: {1063assert(DirKind != OpenACCDirectiveKind::Update);1064ExprResult CondExpr = ParseOpenACCConditionExpr();1065ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()1066: nullptr);10671068if (CondExpr.isInvalid()) {1069Parens.skipToEnd();1070return OpenACCCanContinue();1071}1072break;1073}1074case OpenACCClauseKind::Vector:1075case OpenACCClauseKind::Worker: {1076tryParseAndConsumeSpecialTokenKind(*this,1077ClauseKind ==1078OpenACCClauseKind::Vector1079? OpenACCSpecialTokenKind::Length1080: OpenACCSpecialTokenKind::Num,1081ClauseKind);1082ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,1083ClauseKind, ClauseLoc)1084.first;1085if (IntExpr.isInvalid()) {1086Parens.skipToEnd();1087return OpenACCCanContinue();1088}1089break;1090}1091case OpenACCClauseKind::Async: {1092ExprResult AsyncArg =1093ParseOpenACCAsyncArgument(OpenACCDirectiveKind::Invalid,1094OpenACCClauseKind::Async, ClauseLoc)1095.first;1096ParsedClause.setIntExprDetails(AsyncArg.isUsable() ? AsyncArg.get()1097: nullptr);1098if (AsyncArg.isInvalid()) {1099Parens.skipToEnd();1100return OpenACCCanContinue();1101}1102break;1103}1104case OpenACCClauseKind::Gang:1105if (ParseOpenACCGangArgList(ClauseLoc)) {1106Parens.skipToEnd();1107return OpenACCCanContinue();1108}1109break;1110case OpenACCClauseKind::Wait: {1111OpenACCWaitParseInfo Info =1112ParseOpenACCWaitArgument(ClauseLoc,1113/*IsDirective=*/false);1114if (Info.Failed) {1115Parens.skipToEnd();1116return OpenACCCanContinue();1117}11181119ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc,1120std::move(Info.QueueIdExprs));1121break;1122}1123default:1124llvm_unreachable("Not an optional parens type?");1125}1126ParsedClause.setEndLoc(getCurToken().getLocation());1127if (Parens.consumeClose())1128return OpenACCCannotContinue();1129} else {1130// If we have optional parens, make sure we set the end-location to the1131// clause, as we are a 'single token' clause.1132ParsedClause.setEndLoc(ClauseLoc);1133}1134} else {1135ParsedClause.setEndLoc(ClauseLoc);1136}1137return OpenACCSuccess(1138Actions.OpenACC().ActOnClause(ExistingClauses, ParsedClause));1139}11401141/// OpenACC 3.3 section 2.16:1142/// In this section and throughout the specification, the term async-argument1143/// means a nonnegative scalar integer expression (int for C or C++, integer for1144/// Fortran), or one of the special values acc_async_noval or acc_async_sync, as1145/// defined in the C header file and the Fortran openacc module. The special1146/// values are negative values, so as not to conflict with a user-specified1147/// nonnegative async-argument.1148Parser::OpenACCIntExprParseResult1149Parser::ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK,1150SourceLocation Loc) {1151return ParseOpenACCIntExpr(DK, CK, Loc);1152}11531154/// OpenACC 3.3, section 2.16:1155/// In this section and throughout the specification, the term wait-argument1156/// means:1157/// [ devnum : int-expr : ] [ queues : ] async-argument-list1158Parser::OpenACCWaitParseInfo1159Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {1160OpenACCWaitParseInfo Result;1161// [devnum : int-expr : ]1162if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&1163NextToken().is(tok::colon)) {1164// Consume devnum.1165ConsumeToken();1166// Consume colon.1167ConsumeToken();11681169OpenACCIntExprParseResult Res = ParseOpenACCIntExpr(1170IsDirective ? OpenACCDirectiveKind::Wait1171: OpenACCDirectiveKind::Invalid,1172IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,1173Loc);1174if (Res.first.isInvalid() &&1175Res.second == OpenACCParseCanContinue::Cannot) {1176Result.Failed = true;1177return Result;1178}11791180if (ExpectAndConsume(tok::colon)) {1181Result.Failed = true;1182return Result;1183}11841185Result.DevNumExpr = Res.first.get();1186}11871188// [ queues : ]1189if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&1190NextToken().is(tok::colon)) {1191// Consume queues.1192Result.QueuesLoc = ConsumeToken();1193// Consume colon.1194ConsumeToken();1195}11961197// OpenACC 3.3, section 2.16:1198// the term 'async-argument' means a nonnegative scalar integer expression, or1199// one of the special values 'acc_async_noval' or 'acc_async_sync', as defined1200// in the C header file and the Fortran opacc module.1201bool FirstArg = true;1202while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {1203if (!FirstArg) {1204if (ExpectAndConsume(tok::comma)) {1205Result.Failed = true;1206return Result;1207}1208}1209FirstArg = false;12101211OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(1212IsDirective ? OpenACCDirectiveKind::Wait1213: OpenACCDirectiveKind::Invalid,1214IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,1215Loc);12161217if (Res.first.isInvalid() &&1218Res.second == OpenACCParseCanContinue::Cannot) {1219Result.Failed = true;1220return Result;1221}12221223Result.QueueIdExprs.push_back(Res.first.get());1224}12251226return Result;1227}12281229ExprResult Parser::ParseOpenACCIDExpression() {1230ExprResult Res;1231if (getLangOpts().CPlusPlus) {1232Res = ParseCXXIdExpression(/*isAddressOfOperand=*/true);1233} else {1234// There isn't anything quite the same as ParseCXXIdExpression for C, so we1235// need to get the identifier, then call into Sema ourselves.12361237if (Tok.isNot(tok::identifier)) {1238Diag(Tok, diag::err_expected) << tok::identifier;1239return ExprError();1240}12411242Token FuncName = getCurToken();1243UnqualifiedId Name;1244CXXScopeSpec ScopeSpec;1245SourceLocation TemplateKWLoc;1246Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());12471248// Ensure this is a valid identifier. We don't accept causing implicit1249// function declarations per the spec, so always claim to not have trailing1250// L Paren.1251Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,1252Name, /*HasTrailingLParen=*/false,1253/*isAddressOfOperand=*/false);1254}12551256return getActions().CorrectDelayedTyposInExpr(Res);1257}12581259ExprResult Parser::ParseOpenACCBindClauseArgument() {1260// OpenACC 3.3 section 2.15:1261// The bind clause specifies the name to use when calling the procedure on a1262// device other than the host. If the name is specified as an identifier, it1263// is called as if that name were specified in the language being compiled. If1264// the name is specified as a string, the string is used for the procedure1265// name unmodified.1266if (getCurToken().is(tok::r_paren)) {1267Diag(getCurToken(), diag::err_acc_incorrect_bind_arg);1268return ExprError();1269}12701271if (tok::isStringLiteral(getCurToken().getKind()))1272return getActions().CorrectDelayedTyposInExpr(ParseStringLiteralExpression(1273/*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true));12741275return ParseOpenACCIDExpression();1276}12771278/// OpenACC 3.3, section 1.6:1279/// In this spec, a 'var' (in italics) is one of the following:1280/// - a variable name (a scalar, array, or composite variable name)1281/// - a subarray specification with subscript ranges1282/// - an array element1283/// - a member of a composite variable1284/// - a common block name between slashes (fortran only)1285Parser::OpenACCVarParseResult Parser::ParseOpenACCVar(OpenACCClauseKind CK) {1286OpenACCArraySectionRAII ArraySections(*this);12871288ExprResult Res = ParseAssignmentExpression();1289if (!Res.isUsable())1290return {Res, OpenACCParseCanContinue::Cannot};12911292Res = getActions().CorrectDelayedTyposInExpr(Res.get());1293if (!Res.isUsable())1294return {Res, OpenACCParseCanContinue::Can};12951296Res = getActions().OpenACC().ActOnVar(CK, Res.get());12971298return {Res, OpenACCParseCanContinue::Can};1299}13001301llvm::SmallVector<Expr *> Parser::ParseOpenACCVarList(OpenACCClauseKind CK) {1302llvm::SmallVector<Expr *> Vars;13031304auto [Res, CanContinue] = ParseOpenACCVar(CK);1305if (Res.isUsable()) {1306Vars.push_back(Res.get());1307} else if (CanContinue == OpenACCParseCanContinue::Cannot) {1308SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, StopBeforeMatch);1309return Vars;1310}13111312while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {1313ExpectAndConsume(tok::comma);13141315auto [Res, CanContinue] = ParseOpenACCVar(CK);13161317if (Res.isUsable()) {1318Vars.push_back(Res.get());1319} else if (CanContinue == OpenACCParseCanContinue::Cannot) {1320SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, StopBeforeMatch);1321return Vars;1322}1323}1324return Vars;1325}13261327/// OpenACC 3.3, section 2.10:1328/// In C and C++, the syntax of the cache directive is:1329///1330/// #pragma acc cache ([readonly:]var-list) new-line1331void Parser::ParseOpenACCCacheVarList() {1332// If this is the end of the line, just return 'false' and count on the close1333// paren diagnostic to catch the issue.1334if (getCurToken().isAnnotation())1335return;13361337// The VarList is an optional `readonly:` followed by a list of a variable1338// specifications. Consume something that looks like a 'tag', and diagnose if1339// it isn't 'readonly'.1340if (tryParseAndConsumeSpecialTokenKind(*this,1341OpenACCSpecialTokenKind::ReadOnly,1342OpenACCDirectiveKind::Cache)) {1343// FIXME: Record that this is a 'readonly' so that we can use that during1344// Sema/AST generation.1345}13461347// ParseOpenACCVarList should leave us before a r-paren, so no need to skip1348// anything here.1349ParseOpenACCVarList(OpenACCClauseKind::Invalid);1350}13511352Parser::OpenACCDirectiveParseInfo1353Parser::ParseOpenACCDirective() {1354SourceLocation StartLoc = ConsumeAnnotationToken();1355SourceLocation DirLoc = getCurToken().getLocation();1356OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);13571358getActions().OpenACC().ActOnConstruct(DirKind, DirLoc);13591360// Once we've parsed the construct/directive name, some have additional1361// specifiers that need to be taken care of. Atomic has an 'atomic-clause'1362// that needs to be parsed.1363if (DirKind == OpenACCDirectiveKind::Atomic)1364ParseOpenACCAtomicKind(*this);13651366// We've successfully parsed the construct/directive name, however a few of1367// the constructs have optional parens that contain further details.1368BalancedDelimiterTracker T(*this, tok::l_paren,1369tok::annot_pragma_openacc_end);13701371if (!T.consumeOpen()) {1372switch (DirKind) {1373default:1374Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);1375T.skipToEnd();1376break;1377case OpenACCDirectiveKind::Routine: {1378// Routine has an optional paren-wrapped name of a function in the local1379// scope. We parse the name, emitting any diagnostics1380ExprResult RoutineName = ParseOpenACCIDExpression();1381// If the routine name is invalid, just skip until the closing paren to1382// recover more gracefully.1383if (RoutineName.isInvalid())1384T.skipToEnd();1385else1386T.consumeClose();1387break;1388}1389case OpenACCDirectiveKind::Cache:1390ParseOpenACCCacheVarList();1391// The ParseOpenACCCacheVarList function manages to recover from failures,1392// so we can always consume the close.1393T.consumeClose();1394break;1395case OpenACCDirectiveKind::Wait:1396// OpenACC has an optional paren-wrapped 'wait-argument'.1397if (ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true).Failed)1398T.skipToEnd();1399else1400T.consumeClose();1401break;1402}1403} else if (DirKind == OpenACCDirectiveKind::Cache) {1404// Cache's paren var-list is required, so error here if it isn't provided.1405// We know that the consumeOpen above left the first non-paren here, so1406// diagnose, then continue as if it was completely omitted.1407Diag(Tok, diag::err_expected) << tok::l_paren;1408}14091410// Parses the list of clauses, if present, plus set up return value.1411OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, DirLoc,1412SourceLocation{},1413ParseOpenACCClauseList(DirKind)};14141415assert(Tok.is(tok::annot_pragma_openacc_end) &&1416"Didn't parse all OpenACC Clauses");1417ParseInfo.EndLoc = ConsumeAnnotationToken();1418assert(ParseInfo.EndLoc.isValid() &&1419"Terminating annotation token not present");14201421return ParseInfo;1422}14231424// Parse OpenACC directive on a declaration.1425Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {1426assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");14271428ParsingOpenACCDirectiveRAII DirScope(*this);14291430OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();14311432if (getActions().OpenACC().ActOnStartDeclDirective(DirInfo.DirKind,1433DirInfo.StartLoc))1434return nullptr;14351436// TODO OpenACC: Do whatever decl parsing is required here.1437return DeclGroupPtrTy::make(getActions().OpenACC().ActOnEndDeclDirective());1438}14391440// Parse OpenACC Directive on a Statement.1441StmtResult Parser::ParseOpenACCDirectiveStmt() {1442assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");14431444ParsingOpenACCDirectiveRAII DirScope(*this);14451446OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();1447if (getActions().OpenACC().ActOnStartStmtDirective(DirInfo.DirKind,1448DirInfo.StartLoc))1449return StmtError();14501451StmtResult AssocStmt;1452SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getActions().OpenACC(),1453DirInfo.DirKind);1454if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) {1455ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);1456ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));14571458AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(1459DirInfo.StartLoc, DirInfo.DirKind, ParseStatement());1460}14611462return getActions().OpenACC().ActOnEndStmtDirective(1463DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.EndLoc,1464DirInfo.Clauses, AssocStmt);1465}146614671468