xref: /freebsd-src/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp (revision 297eecfb02bb25902531dbb5c3b9a88caf8adf29)
15f757f3fSDimitry Andric //===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric //
95f757f3fSDimitry Andric // This file implements the parsing logic for OpenACC language features.
105f757f3fSDimitry Andric //
115f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
125f757f3fSDimitry Andric 
135f757f3fSDimitry Andric #include "clang/Basic/OpenACCKinds.h"
145f757f3fSDimitry Andric #include "clang/Parse/ParseDiagnostic.h"
155f757f3fSDimitry Andric #include "clang/Parse/Parser.h"
165f757f3fSDimitry Andric #include "clang/Parse/RAIIObjectsForParser.h"
175f757f3fSDimitry Andric #include "llvm/ADT/StringRef.h"
185f757f3fSDimitry Andric #include "llvm/ADT/StringSwitch.h"
195f757f3fSDimitry Andric 
205f757f3fSDimitry Andric using namespace clang;
215f757f3fSDimitry Andric using namespace llvm;
225f757f3fSDimitry Andric 
235f757f3fSDimitry Andric namespace {
245f757f3fSDimitry Andric // An enum that contains the extended 'partial' parsed variants. This type
255f757f3fSDimitry Andric // should never escape the initial parse functionality, but is useful for
265f757f3fSDimitry Andric // simplifying the implementation.
275f757f3fSDimitry Andric enum class OpenACCDirectiveKindEx {
285f757f3fSDimitry Andric   Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
295f757f3fSDimitry Andric   // 'enter data' and 'exit data'
305f757f3fSDimitry Andric   Enter,
315f757f3fSDimitry Andric   Exit,
325f757f3fSDimitry Andric };
335f757f3fSDimitry Andric 
345f757f3fSDimitry Andric // Translate single-token string representations to the OpenACC Directive Kind.
355f757f3fSDimitry Andric // This doesn't completely comprehend 'Compound Constructs' (as it just
365f757f3fSDimitry Andric // identifies the first token), and doesn't fully handle 'enter data', 'exit
375f757f3fSDimitry Andric // data', nor any of the 'atomic' variants, just the first token of each.  So
385f757f3fSDimitry Andric // this should only be used by `ParseOpenACCDirectiveKind`.
395f757f3fSDimitry Andric OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
405f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
415f757f3fSDimitry Andric     return OpenACCDirectiveKindEx::Invalid;
425f757f3fSDimitry Andric   OpenACCDirectiveKind DirKind =
435f757f3fSDimitry Andric       llvm::StringSwitch<OpenACCDirectiveKind>(
445f757f3fSDimitry Andric           Tok.getIdentifierInfo()->getName())
455f757f3fSDimitry Andric           .Case("parallel", OpenACCDirectiveKind::Parallel)
465f757f3fSDimitry Andric           .Case("serial", OpenACCDirectiveKind::Serial)
475f757f3fSDimitry Andric           .Case("kernels", OpenACCDirectiveKind::Kernels)
485f757f3fSDimitry Andric           .Case("data", OpenACCDirectiveKind::Data)
495f757f3fSDimitry Andric           .Case("host_data", OpenACCDirectiveKind::HostData)
505f757f3fSDimitry Andric           .Case("loop", OpenACCDirectiveKind::Loop)
515f757f3fSDimitry Andric           .Case("cache", OpenACCDirectiveKind::Cache)
525f757f3fSDimitry Andric           .Case("atomic", OpenACCDirectiveKind::Atomic)
535f757f3fSDimitry Andric           .Case("routine", OpenACCDirectiveKind::Routine)
545f757f3fSDimitry Andric           .Case("declare", OpenACCDirectiveKind::Declare)
555f757f3fSDimitry Andric           .Case("init", OpenACCDirectiveKind::Init)
565f757f3fSDimitry Andric           .Case("shutdown", OpenACCDirectiveKind::Shutdown)
575f757f3fSDimitry Andric           .Case("set", OpenACCDirectiveKind::Shutdown)
585f757f3fSDimitry Andric           .Case("update", OpenACCDirectiveKind::Update)
595f757f3fSDimitry Andric           .Case("wait", OpenACCDirectiveKind::Wait)
605f757f3fSDimitry Andric           .Default(OpenACCDirectiveKind::Invalid);
615f757f3fSDimitry Andric 
625f757f3fSDimitry Andric   if (DirKind != OpenACCDirectiveKind::Invalid)
635f757f3fSDimitry Andric     return static_cast<OpenACCDirectiveKindEx>(DirKind);
645f757f3fSDimitry Andric 
655f757f3fSDimitry Andric   return llvm::StringSwitch<OpenACCDirectiveKindEx>(
665f757f3fSDimitry Andric              Tok.getIdentifierInfo()->getName())
675f757f3fSDimitry Andric       .Case("enter", OpenACCDirectiveKindEx::Enter)
685f757f3fSDimitry Andric       .Case("exit", OpenACCDirectiveKindEx::Exit)
695f757f3fSDimitry Andric       .Default(OpenACCDirectiveKindEx::Invalid);
705f757f3fSDimitry Andric }
715f757f3fSDimitry Andric 
72cb14a3feSDimitry Andric // Translate single-token string representations to the OpenCC Clause Kind.
73cb14a3feSDimitry Andric OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
74cb14a3feSDimitry Andric   // auto is a keyword in some language modes, so make sure we parse it
75cb14a3feSDimitry Andric   // correctly.
76cb14a3feSDimitry Andric   if (Tok.is(tok::kw_auto))
77cb14a3feSDimitry Andric     return OpenACCClauseKind::Auto;
78cb14a3feSDimitry Andric 
791db9f3b2SDimitry Andric   // default is a keyword, so make sure we parse it correctly.
801db9f3b2SDimitry Andric   if (Tok.is(tok::kw_default))
811db9f3b2SDimitry Andric     return OpenACCClauseKind::Default;
821db9f3b2SDimitry Andric 
831db9f3b2SDimitry Andric   // if is also a keyword, make sure we parse it correctly.
841db9f3b2SDimitry Andric   if (Tok.is(tok::kw_if))
851db9f3b2SDimitry Andric     return OpenACCClauseKind::If;
861db9f3b2SDimitry Andric 
87cb14a3feSDimitry Andric   if (!Tok.is(tok::identifier))
88cb14a3feSDimitry Andric     return OpenACCClauseKind::Invalid;
89cb14a3feSDimitry Andric 
90cb14a3feSDimitry Andric   return llvm::StringSwitch<OpenACCClauseKind>(
91cb14a3feSDimitry Andric              Tok.getIdentifierInfo()->getName())
92cb14a3feSDimitry Andric       .Case("auto", OpenACCClauseKind::Auto)
931db9f3b2SDimitry Andric       .Case("default", OpenACCClauseKind::Default)
94cb14a3feSDimitry Andric       .Case("finalize", OpenACCClauseKind::Finalize)
951db9f3b2SDimitry Andric       .Case("if", OpenACCClauseKind::If)
96cb14a3feSDimitry Andric       .Case("if_present", OpenACCClauseKind::IfPresent)
97cb14a3feSDimitry Andric       .Case("independent", OpenACCClauseKind::Independent)
98cb14a3feSDimitry Andric       .Case("nohost", OpenACCClauseKind::NoHost)
991db9f3b2SDimitry Andric       .Case("self", OpenACCClauseKind::Self)
100cb14a3feSDimitry Andric       .Case("seq", OpenACCClauseKind::Seq)
101cb14a3feSDimitry Andric       .Case("vector", OpenACCClauseKind::Vector)
102cb14a3feSDimitry Andric       .Case("worker", OpenACCClauseKind::Worker)
103cb14a3feSDimitry Andric       .Default(OpenACCClauseKind::Invalid);
104cb14a3feSDimitry Andric }
105cb14a3feSDimitry Andric 
1065f757f3fSDimitry Andric // Since 'atomic' is effectively a compound directive, this will decode the
1075f757f3fSDimitry Andric // second part of the directive.
1085f757f3fSDimitry Andric OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
1095f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
1105f757f3fSDimitry Andric     return OpenACCAtomicKind::Invalid;
1115f757f3fSDimitry Andric   return llvm::StringSwitch<OpenACCAtomicKind>(
1125f757f3fSDimitry Andric              Tok.getIdentifierInfo()->getName())
1135f757f3fSDimitry Andric       .Case("read", OpenACCAtomicKind::Read)
1145f757f3fSDimitry Andric       .Case("write", OpenACCAtomicKind::Write)
1155f757f3fSDimitry Andric       .Case("update", OpenACCAtomicKind::Update)
1165f757f3fSDimitry Andric       .Case("capture", OpenACCAtomicKind::Capture)
1175f757f3fSDimitry Andric       .Default(OpenACCAtomicKind::Invalid);
1185f757f3fSDimitry Andric }
1195f757f3fSDimitry Andric 
1201db9f3b2SDimitry Andric OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) {
1211db9f3b2SDimitry Andric   if (!Tok.is(tok::identifier))
1221db9f3b2SDimitry Andric     return OpenACCDefaultClauseKind::Invalid;
1231db9f3b2SDimitry Andric 
1241db9f3b2SDimitry Andric   return llvm::StringSwitch<OpenACCDefaultClauseKind>(
1251db9f3b2SDimitry Andric              Tok.getIdentifierInfo()->getName())
1261db9f3b2SDimitry Andric       .Case("none", OpenACCDefaultClauseKind::None)
1271db9f3b2SDimitry Andric       .Case("present", OpenACCDefaultClauseKind::Present)
1281db9f3b2SDimitry Andric       .Default(OpenACCDefaultClauseKind::Invalid);
1291db9f3b2SDimitry Andric }
1301db9f3b2SDimitry Andric 
1315f757f3fSDimitry Andric enum class OpenACCSpecialTokenKind {
1325f757f3fSDimitry Andric   ReadOnly,
1335f757f3fSDimitry Andric   DevNum,
1345f757f3fSDimitry Andric   Queues,
1355f757f3fSDimitry Andric };
1365f757f3fSDimitry Andric 
1375f757f3fSDimitry Andric bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
1385f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
1395f757f3fSDimitry Andric     return false;
1405f757f3fSDimitry Andric 
1415f757f3fSDimitry Andric   switch (Kind) {
1425f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::ReadOnly:
1435f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("readonly");
1445f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::DevNum:
1455f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("devnum");
1465f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::Queues:
1475f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("queues");
1485f757f3fSDimitry Andric   }
1495f757f3fSDimitry Andric   llvm_unreachable("Unknown 'Kind' Passed");
1505f757f3fSDimitry Andric }
1515f757f3fSDimitry Andric 
1525f757f3fSDimitry Andric bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
1535f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
1545f757f3fSDimitry Andric     return false;
1555f757f3fSDimitry Andric 
1565f757f3fSDimitry Andric   switch (Kind) {
1575f757f3fSDimitry Andric   case OpenACCDirectiveKind::Parallel:
1585f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("parallel");
1595f757f3fSDimitry Andric   case OpenACCDirectiveKind::Serial:
1605f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("serial");
1615f757f3fSDimitry Andric   case OpenACCDirectiveKind::Kernels:
1625f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("kernels");
1635f757f3fSDimitry Andric   case OpenACCDirectiveKind::Data:
1645f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("data");
1655f757f3fSDimitry Andric   case OpenACCDirectiveKind::HostData:
1665f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("host_data");
1675f757f3fSDimitry Andric   case OpenACCDirectiveKind::Loop:
1685f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("loop");
1695f757f3fSDimitry Andric   case OpenACCDirectiveKind::Cache:
1705f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("cache");
1715f757f3fSDimitry Andric 
1725f757f3fSDimitry Andric   case OpenACCDirectiveKind::ParallelLoop:
1735f757f3fSDimitry Andric   case OpenACCDirectiveKind::SerialLoop:
1745f757f3fSDimitry Andric   case OpenACCDirectiveKind::KernelsLoop:
1755f757f3fSDimitry Andric   case OpenACCDirectiveKind::EnterData:
1765f757f3fSDimitry Andric   case OpenACCDirectiveKind::ExitData:
1775f757f3fSDimitry Andric     return false;
1785f757f3fSDimitry Andric 
1795f757f3fSDimitry Andric   case OpenACCDirectiveKind::Atomic:
1805f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("atomic");
1815f757f3fSDimitry Andric   case OpenACCDirectiveKind::Routine:
1825f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("routine");
1835f757f3fSDimitry Andric   case OpenACCDirectiveKind::Declare:
1845f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("declare");
1855f757f3fSDimitry Andric   case OpenACCDirectiveKind::Init:
1865f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("init");
1875f757f3fSDimitry Andric   case OpenACCDirectiveKind::Shutdown:
1885f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("shutdown");
1895f757f3fSDimitry Andric   case OpenACCDirectiveKind::Set:
1905f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("set");
1915f757f3fSDimitry Andric   case OpenACCDirectiveKind::Update:
1925f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("update");
1935f757f3fSDimitry Andric   case OpenACCDirectiveKind::Wait:
1945f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("wait");
1955f757f3fSDimitry Andric   case OpenACCDirectiveKind::Invalid:
1965f757f3fSDimitry Andric     return false;
1975f757f3fSDimitry Andric   }
1985f757f3fSDimitry Andric   llvm_unreachable("Unknown 'Kind' Passed");
1995f757f3fSDimitry Andric }
2005f757f3fSDimitry Andric 
2011db9f3b2SDimitry Andric /// Used for cases where we expect an identifier-like token, but don't want to
2021db9f3b2SDimitry Andric /// give awkward error messages in cases where it is accidentially a keyword.
2031db9f3b2SDimitry Andric bool expectIdentifierOrKeyword(Parser &P) {
2041db9f3b2SDimitry Andric   Token Tok = P.getCurToken();
2051db9f3b2SDimitry Andric 
2061db9f3b2SDimitry Andric   if (Tok.is(tok::identifier))
2071db9f3b2SDimitry Andric     return false;
2081db9f3b2SDimitry Andric 
2091db9f3b2SDimitry Andric   if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
2101db9f3b2SDimitry Andric       Tok.getIdentifierInfo()->isKeyword(P.getLangOpts()))
2111db9f3b2SDimitry Andric     return false;
2121db9f3b2SDimitry Andric 
2131db9f3b2SDimitry Andric   P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
2141db9f3b2SDimitry Andric   return true;
2151db9f3b2SDimitry Andric }
2161db9f3b2SDimitry Andric 
2175f757f3fSDimitry Andric OpenACCDirectiveKind
2185f757f3fSDimitry Andric ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
2195f757f3fSDimitry Andric                                    OpenACCDirectiveKindEx ExtDirKind) {
2205f757f3fSDimitry Andric   Token SecondTok = P.getCurToken();
2215f757f3fSDimitry Andric 
2225f757f3fSDimitry Andric   if (SecondTok.isAnnotation()) {
2235f757f3fSDimitry Andric     P.Diag(FirstTok, diag::err_acc_invalid_directive)
2245f757f3fSDimitry Andric         << 0 << FirstTok.getIdentifierInfo();
2255f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
2265f757f3fSDimitry Andric   }
2275f757f3fSDimitry Andric 
228cb14a3feSDimitry Andric   // Consume the second name anyway, this way we can continue on without making
229cb14a3feSDimitry Andric   // this oddly look like a clause.
230cb14a3feSDimitry Andric   P.ConsumeAnyToken();
231cb14a3feSDimitry Andric 
2325f757f3fSDimitry Andric   if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) {
2335f757f3fSDimitry Andric     if (!SecondTok.is(tok::identifier))
2345f757f3fSDimitry Andric       P.Diag(SecondTok, diag::err_expected) << tok::identifier;
2355f757f3fSDimitry Andric     else
2365f757f3fSDimitry Andric       P.Diag(FirstTok, diag::err_acc_invalid_directive)
2375f757f3fSDimitry Andric           << 1 << FirstTok.getIdentifierInfo()->getName()
2385f757f3fSDimitry Andric           << SecondTok.getIdentifierInfo()->getName();
2395f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
2405f757f3fSDimitry Andric   }
2415f757f3fSDimitry Andric 
2425f757f3fSDimitry Andric   return ExtDirKind == OpenACCDirectiveKindEx::Enter
2435f757f3fSDimitry Andric              ? OpenACCDirectiveKind::EnterData
2445f757f3fSDimitry Andric              : OpenACCDirectiveKind::ExitData;
2455f757f3fSDimitry Andric }
2465f757f3fSDimitry Andric 
2475f757f3fSDimitry Andric OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) {
2485f757f3fSDimitry Andric   Token AtomicClauseToken = P.getCurToken();
2495f757f3fSDimitry Andric 
2505f757f3fSDimitry Andric   // #pragma acc atomic is equivilent to update:
2515f757f3fSDimitry Andric   if (AtomicClauseToken.isAnnotation())
2525f757f3fSDimitry Andric     return OpenACCAtomicKind::Update;
2535f757f3fSDimitry Andric 
2545f757f3fSDimitry Andric   OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken);
2555f757f3fSDimitry Andric 
2565f757f3fSDimitry Andric   // If we don't know what this is, treat it as 'nothing', and treat the rest of
2575f757f3fSDimitry Andric   // this as a clause list, which, despite being invalid, is likely what the
2585f757f3fSDimitry Andric   // user was trying to do.
2595f757f3fSDimitry Andric   if (AtomicKind == OpenACCAtomicKind::Invalid)
2605f757f3fSDimitry Andric     return OpenACCAtomicKind::Update;
2615f757f3fSDimitry Andric 
2625f757f3fSDimitry Andric   P.ConsumeToken();
2635f757f3fSDimitry Andric   return AtomicKind;
2645f757f3fSDimitry Andric }
2655f757f3fSDimitry Andric 
2665f757f3fSDimitry Andric // Parse and consume the tokens for OpenACC Directive/Construct kinds.
2675f757f3fSDimitry Andric OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
2685f757f3fSDimitry Andric   Token FirstTok = P.getCurToken();
2695f757f3fSDimitry Andric 
2705f757f3fSDimitry Andric   // Just #pragma acc can get us immediately to the end, make sure we don't
2715f757f3fSDimitry Andric   // introspect on the spelling before then.
2725f757f3fSDimitry Andric   if (FirstTok.isNot(tok::identifier)) {
2735f757f3fSDimitry Andric     P.Diag(FirstTok, diag::err_acc_missing_directive);
274cb14a3feSDimitry Andric 
275cb14a3feSDimitry Andric     if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
276cb14a3feSDimitry Andric       P.ConsumeAnyToken();
277cb14a3feSDimitry Andric 
2785f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
2795f757f3fSDimitry Andric   }
2805f757f3fSDimitry Andric 
2815f757f3fSDimitry Andric   P.ConsumeToken();
2825f757f3fSDimitry Andric 
2835f757f3fSDimitry Andric   OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok);
2845f757f3fSDimitry Andric 
2855f757f3fSDimitry Andric   // OpenACCDirectiveKindEx is meant to be an extended list
2865f757f3fSDimitry Andric   // over OpenACCDirectiveKind, so any value below Invalid is one of the
2875f757f3fSDimitry Andric   // OpenACCDirectiveKind values.  This switch takes care of all of the extra
2885f757f3fSDimitry Andric   // parsing required for the Extended values.  At the end of this block,
2895f757f3fSDimitry Andric   // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
2905f757f3fSDimitry Andric   // immediately cast it and use it as that.
2915f757f3fSDimitry Andric   if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
2925f757f3fSDimitry Andric     switch (ExDirKind) {
2935f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Invalid: {
2945f757f3fSDimitry Andric       P.Diag(FirstTok, diag::err_acc_invalid_directive)
2955f757f3fSDimitry Andric           << 0 << FirstTok.getIdentifierInfo();
2965f757f3fSDimitry Andric       return OpenACCDirectiveKind::Invalid;
2975f757f3fSDimitry Andric     }
2985f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Enter:
2995f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Exit:
3005f757f3fSDimitry Andric       return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind);
3015f757f3fSDimitry Andric     }
3025f757f3fSDimitry Andric   }
3035f757f3fSDimitry Andric 
3045f757f3fSDimitry Andric   OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);
3055f757f3fSDimitry Andric 
3065f757f3fSDimitry Andric   // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
3075f757f3fSDimitry Andric   // other attempt at a combined construct will be diagnosed as an invalid
3085f757f3fSDimitry Andric   // clause.
3095f757f3fSDimitry Andric   Token SecondTok = P.getCurToken();
3105f757f3fSDimitry Andric   if (!SecondTok.isAnnotation() &&
3115f757f3fSDimitry Andric       isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) {
3125f757f3fSDimitry Andric     switch (DirKind) {
3135f757f3fSDimitry Andric     default:
3145f757f3fSDimitry Andric       // Nothing to do except in the below cases, as they should be diagnosed as
3155f757f3fSDimitry Andric       // a clause.
3165f757f3fSDimitry Andric       break;
3175f757f3fSDimitry Andric     case OpenACCDirectiveKind::Parallel:
3185f757f3fSDimitry Andric       P.ConsumeToken();
3195f757f3fSDimitry Andric       return OpenACCDirectiveKind::ParallelLoop;
3205f757f3fSDimitry Andric     case OpenACCDirectiveKind::Serial:
3215f757f3fSDimitry Andric       P.ConsumeToken();
3225f757f3fSDimitry Andric       return OpenACCDirectiveKind::SerialLoop;
3235f757f3fSDimitry Andric     case OpenACCDirectiveKind::Kernels:
3245f757f3fSDimitry Andric       P.ConsumeToken();
3255f757f3fSDimitry Andric       return OpenACCDirectiveKind::KernelsLoop;
3265f757f3fSDimitry Andric     }
3275f757f3fSDimitry Andric   }
3285f757f3fSDimitry Andric 
3295f757f3fSDimitry Andric   return DirKind;
3305f757f3fSDimitry Andric }
3315f757f3fSDimitry Andric 
3321db9f3b2SDimitry Andric bool ClauseHasOptionalParens(OpenACCClauseKind Kind) {
3331db9f3b2SDimitry Andric   return Kind == OpenACCClauseKind::Self;
3341db9f3b2SDimitry Andric }
3351db9f3b2SDimitry Andric 
3361db9f3b2SDimitry Andric bool ClauseHasRequiredParens(OpenACCClauseKind Kind) {
3371db9f3b2SDimitry Andric   return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If;
3381db9f3b2SDimitry Andric }
3391db9f3b2SDimitry Andric 
3401db9f3b2SDimitry Andric ExprResult ParseOpenACCConditionalExpr(Parser &P) {
3411db9f3b2SDimitry Andric   // FIXME: It isn't clear if the spec saying 'condition' means the same as
3421db9f3b2SDimitry Andric   // it does in an if/while/etc (See ParseCXXCondition), however as it was
3431db9f3b2SDimitry Andric   // written with Fortran/C in mind, we're going to assume it just means an
3441db9f3b2SDimitry Andric   // 'expression evaluating to boolean'.
3451db9f3b2SDimitry Andric   return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression());
3461db9f3b2SDimitry Andric }
3471db9f3b2SDimitry Andric 
3481db9f3b2SDimitry Andric bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
3491db9f3b2SDimitry Andric   BalancedDelimiterTracker Parens(P, tok::l_paren,
3501db9f3b2SDimitry Andric                                   tok::annot_pragma_openacc_end);
3511db9f3b2SDimitry Andric 
3521db9f3b2SDimitry Andric   if (ClauseHasRequiredParens(Kind)) {
3531db9f3b2SDimitry Andric     if (Parens.expectAndConsume()) {
3541db9f3b2SDimitry Andric       // We are missing a paren, so assume that the person just forgot the
3551db9f3b2SDimitry Andric       // parameter.  Return 'false' so we try to continue on and parse the next
3561db9f3b2SDimitry Andric       // clause.
3571db9f3b2SDimitry Andric       P.SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
3581db9f3b2SDimitry Andric                   Parser::StopBeforeMatch);
3591db9f3b2SDimitry Andric       return false;
3601db9f3b2SDimitry Andric     }
3611db9f3b2SDimitry Andric 
3621db9f3b2SDimitry Andric     switch (Kind) {
3631db9f3b2SDimitry Andric     case OpenACCClauseKind::Default: {
3641db9f3b2SDimitry Andric       Token DefKindTok = P.getCurToken();
3651db9f3b2SDimitry Andric 
3661db9f3b2SDimitry Andric       if (expectIdentifierOrKeyword(P))
3671db9f3b2SDimitry Andric         break;
3681db9f3b2SDimitry Andric 
3691db9f3b2SDimitry Andric       P.ConsumeToken();
3701db9f3b2SDimitry Andric 
3711db9f3b2SDimitry Andric       if (getOpenACCDefaultClauseKind(DefKindTok) ==
3721db9f3b2SDimitry Andric           OpenACCDefaultClauseKind::Invalid)
3731db9f3b2SDimitry Andric         P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
3741db9f3b2SDimitry Andric 
3751db9f3b2SDimitry Andric       break;
3761db9f3b2SDimitry Andric     }
3771db9f3b2SDimitry Andric     case OpenACCClauseKind::If: {
3781db9f3b2SDimitry Andric       ExprResult CondExpr = ParseOpenACCConditionalExpr(P);
3791db9f3b2SDimitry Andric       // An invalid expression can be just about anything, so just give up on
3801db9f3b2SDimitry Andric       // this clause list.
3811db9f3b2SDimitry Andric       if (CondExpr.isInvalid())
3821db9f3b2SDimitry Andric         return true;
3831db9f3b2SDimitry Andric       break;
3841db9f3b2SDimitry Andric     }
3851db9f3b2SDimitry Andric     default:
3861db9f3b2SDimitry Andric       llvm_unreachable("Not a required parens type?");
3871db9f3b2SDimitry Andric     }
3881db9f3b2SDimitry Andric 
3891db9f3b2SDimitry Andric     return Parens.consumeClose();
3901db9f3b2SDimitry Andric   } else if (ClauseHasOptionalParens(Kind)) {
3911db9f3b2SDimitry Andric     if (!Parens.consumeOpen()) {
3921db9f3b2SDimitry Andric       switch (Kind) {
3931db9f3b2SDimitry Andric       case OpenACCClauseKind::Self: {
3941db9f3b2SDimitry Andric         ExprResult CondExpr = ParseOpenACCConditionalExpr(P);
3951db9f3b2SDimitry Andric         // An invalid expression can be just about anything, so just give up on
3961db9f3b2SDimitry Andric         // this clause list.
3971db9f3b2SDimitry Andric         if (CondExpr.isInvalid())
3981db9f3b2SDimitry Andric           return true;
3991db9f3b2SDimitry Andric         break;
4001db9f3b2SDimitry Andric       }
4011db9f3b2SDimitry Andric       default:
4021db9f3b2SDimitry Andric         llvm_unreachable("Not an optional parens type?");
4031db9f3b2SDimitry Andric       }
4041db9f3b2SDimitry Andric       Parens.consumeClose();
4051db9f3b2SDimitry Andric     }
4061db9f3b2SDimitry Andric   }
4071db9f3b2SDimitry Andric   return false;
4081db9f3b2SDimitry Andric }
4091db9f3b2SDimitry Andric 
410cb14a3feSDimitry Andric // The OpenACC Clause List is a comma or space-delimited list of clauses (see
411cb14a3feSDimitry Andric // the comment on ParseOpenACCClauseList).  The concept of a 'clause' doesn't
412cb14a3feSDimitry Andric // really have its owner grammar and each individual one has its own definition.
4131db9f3b2SDimitry Andric // However, they all are named with a single-identifier (or auto/default!)
4141db9f3b2SDimitry Andric // token, followed in some cases by either braces or parens.
415cb14a3feSDimitry Andric bool ParseOpenACCClause(Parser &P) {
4161db9f3b2SDimitry Andric   // A number of clause names are actually keywords, so accept a keyword that
4171db9f3b2SDimitry Andric   // can be converted to a name.
4181db9f3b2SDimitry Andric   if (expectIdentifierOrKeyword(P))
4191db9f3b2SDimitry Andric     return true;
420cb14a3feSDimitry Andric 
421cb14a3feSDimitry Andric   OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken());
422cb14a3feSDimitry Andric 
423cb14a3feSDimitry Andric   if (Kind == OpenACCClauseKind::Invalid)
424cb14a3feSDimitry Andric     return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause)
425cb14a3feSDimitry Andric            << P.getCurToken().getIdentifierInfo();
426cb14a3feSDimitry Andric 
427cb14a3feSDimitry Andric   // Consume the clause name.
428cb14a3feSDimitry Andric   P.ConsumeToken();
429cb14a3feSDimitry Andric 
4301db9f3b2SDimitry Andric   return ParseOpenACCClauseParams(P, Kind);
431cb14a3feSDimitry Andric }
432cb14a3feSDimitry Andric 
433cb14a3feSDimitry Andric // Skip until we see the end of pragma token, but don't consume it. This is us
434cb14a3feSDimitry Andric // just giving up on the rest of the pragma so we can continue executing. We
435cb14a3feSDimitry Andric // have to do this because 'SkipUntil' considers paren balancing, which isn't
436cb14a3feSDimitry Andric // what we want.
437cb14a3feSDimitry Andric void SkipUntilEndOfDirective(Parser &P) {
438cb14a3feSDimitry Andric   while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
439cb14a3feSDimitry Andric     P.ConsumeAnyToken();
440cb14a3feSDimitry Andric }
441cb14a3feSDimitry Andric 
442cb14a3feSDimitry Andric // OpenACC 3.3, section 1.7:
443cb14a3feSDimitry Andric // To simplify the specification and convey appropriate constraint information,
444cb14a3feSDimitry Andric // a pqr-list is a comma-separated list of pdr items. The one exception is a
445cb14a3feSDimitry Andric // clause-list, which is a list of one or more clauses optionally separated by
446cb14a3feSDimitry Andric // commas.
4475f757f3fSDimitry Andric void ParseOpenACCClauseList(Parser &P) {
448cb14a3feSDimitry Andric   bool FirstClause = true;
449cb14a3feSDimitry Andric   while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) {
450cb14a3feSDimitry Andric     // Comma is optional in a clause-list.
451cb14a3feSDimitry Andric     if (!FirstClause && P.getCurToken().is(tok::comma))
452cb14a3feSDimitry Andric       P.ConsumeToken();
453cb14a3feSDimitry Andric     FirstClause = false;
454cb14a3feSDimitry Andric 
455cb14a3feSDimitry Andric     // Recovering from a bad clause is really difficult, so we just give up on
456cb14a3feSDimitry Andric     // error.
457cb14a3feSDimitry Andric     if (ParseOpenACCClause(P)) {
458cb14a3feSDimitry Andric       SkipUntilEndOfDirective(P);
459cb14a3feSDimitry Andric       return;
460cb14a3feSDimitry Andric     }
461cb14a3feSDimitry Andric   }
4625f757f3fSDimitry Andric }
4635f757f3fSDimitry Andric 
4645f757f3fSDimitry Andric } // namespace
4655f757f3fSDimitry Andric 
4665f757f3fSDimitry Andric /// OpenACC 3.3, section 2.16:
4675f757f3fSDimitry Andric /// In this section and throughout the specification, the term wait-argument
4685f757f3fSDimitry Andric /// means:
4695f757f3fSDimitry Andric /// [ devnum : int-expr : ] [ queues : ] async-argument-list
4705f757f3fSDimitry Andric bool Parser::ParseOpenACCWaitArgument() {
4715f757f3fSDimitry Andric   // [devnum : int-expr : ]
4725f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
4735f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
4745f757f3fSDimitry Andric     // Consume devnum.
4755f757f3fSDimitry Andric     ConsumeToken();
4765f757f3fSDimitry Andric     // Consume colon.
4775f757f3fSDimitry Andric     ConsumeToken();
4785f757f3fSDimitry Andric 
4795f757f3fSDimitry Andric     ExprResult IntExpr =
4805f757f3fSDimitry Andric         getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
4815f757f3fSDimitry Andric     if (IntExpr.isInvalid())
4825f757f3fSDimitry Andric       return true;
4835f757f3fSDimitry Andric 
4845f757f3fSDimitry Andric     if (ExpectAndConsume(tok::colon))
4855f757f3fSDimitry Andric       return true;
4865f757f3fSDimitry Andric   }
4875f757f3fSDimitry Andric 
4885f757f3fSDimitry Andric   // [ queues : ]
4895f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
4905f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
4915f757f3fSDimitry Andric     // Consume queues.
4925f757f3fSDimitry Andric     ConsumeToken();
4935f757f3fSDimitry Andric     // Consume colon.
4945f757f3fSDimitry Andric     ConsumeToken();
4955f757f3fSDimitry Andric   }
4965f757f3fSDimitry Andric 
4975f757f3fSDimitry Andric   // OpenACC 3.3, section 2.16:
4985f757f3fSDimitry Andric   // the term 'async-argument' means a nonnegative scalar integer expression, or
4995f757f3fSDimitry Andric   // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
5005f757f3fSDimitry Andric   // in the C header file and the Fortran opacc module.
5015f757f3fSDimitry Andric   //
5025f757f3fSDimitry Andric   // We are parsing this simply as list of assignment expressions (to avoid
5035f757f3fSDimitry Andric   // comma being troublesome), and will ensure it is an integral type.  The
5045f757f3fSDimitry Andric   // 'special' types are defined as macros, so we can't really check those
5055f757f3fSDimitry Andric   // (other than perhaps as values at one point?), but the standard does say it
5065f757f3fSDimitry Andric   // is implementation-defined to use any other negative value.
5075f757f3fSDimitry Andric   //
5085f757f3fSDimitry Andric   //
5095f757f3fSDimitry Andric   bool FirstArg = true;
5105f757f3fSDimitry Andric   while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
5115f757f3fSDimitry Andric     if (!FirstArg) {
5125f757f3fSDimitry Andric       if (ExpectAndConsume(tok::comma))
5135f757f3fSDimitry Andric         return true;
5145f757f3fSDimitry Andric     }
5155f757f3fSDimitry Andric     FirstArg = false;
5165f757f3fSDimitry Andric 
5175f757f3fSDimitry Andric     ExprResult CurArg =
5185f757f3fSDimitry Andric         getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
5195f757f3fSDimitry Andric 
5205f757f3fSDimitry Andric     if (CurArg.isInvalid())
5215f757f3fSDimitry Andric       return true;
5225f757f3fSDimitry Andric   }
5235f757f3fSDimitry Andric 
5245f757f3fSDimitry Andric   return false;
5255f757f3fSDimitry Andric }
5265f757f3fSDimitry Andric 
5275f757f3fSDimitry Andric ExprResult Parser::ParseOpenACCIDExpression() {
5285f757f3fSDimitry Andric   ExprResult Res;
5295f757f3fSDimitry Andric   if (getLangOpts().CPlusPlus) {
5305f757f3fSDimitry Andric     Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false);
5315f757f3fSDimitry Andric   } else {
5325f757f3fSDimitry Andric     // There isn't anything quite the same as ParseCXXIdExpression for C, so we
5335f757f3fSDimitry Andric     // need to get the identifier, then call into Sema ourselves.
5345f757f3fSDimitry Andric 
5355f757f3fSDimitry Andric     if (Tok.isNot(tok::identifier)) {
5365f757f3fSDimitry Andric       Diag(Tok, diag::err_expected) << tok::identifier;
5375f757f3fSDimitry Andric       return ExprError();
5385f757f3fSDimitry Andric     }
5395f757f3fSDimitry Andric 
5405f757f3fSDimitry Andric     Token FuncName = getCurToken();
5415f757f3fSDimitry Andric     UnqualifiedId Name;
5425f757f3fSDimitry Andric     CXXScopeSpec ScopeSpec;
5435f757f3fSDimitry Andric     SourceLocation TemplateKWLoc;
5445f757f3fSDimitry Andric     Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());
5455f757f3fSDimitry Andric 
5465f757f3fSDimitry Andric     // Ensure this is a valid identifier. We don't accept causing implicit
5475f757f3fSDimitry Andric     // function declarations per the spec, so always claim to not have trailing
5485f757f3fSDimitry Andric     // L Paren.
5495f757f3fSDimitry Andric     Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
5505f757f3fSDimitry Andric                                     Name, /*HasTrailingLParen=*/false,
5515f757f3fSDimitry Andric                                     /*isAddressOfOperand=*/false);
5525f757f3fSDimitry Andric   }
5535f757f3fSDimitry Andric 
5545f757f3fSDimitry Andric   return getActions().CorrectDelayedTyposInExpr(Res);
5555f757f3fSDimitry Andric }
5565f757f3fSDimitry Andric 
557*297eecfbSDimitry Andric /// OpenACC 3.3, section 1.6:
558*297eecfbSDimitry Andric /// In this spec, a 'var' (in italics) is one of the following:
559*297eecfbSDimitry Andric /// - a variable name (a scalar, array, or compisite variable name)
560*297eecfbSDimitry Andric /// - a subarray specification with subscript ranges
561*297eecfbSDimitry Andric /// - an array element
562*297eecfbSDimitry Andric /// - a member of a composite variable
563*297eecfbSDimitry Andric /// - a common block name between slashes (fortran only)
564*297eecfbSDimitry Andric bool Parser::ParseOpenACCVar() {
565*297eecfbSDimitry Andric   OpenACCArraySectionRAII ArraySections(*this);
566*297eecfbSDimitry Andric   ExprResult Res = ParseAssignmentExpression();
567*297eecfbSDimitry Andric   return Res.isInvalid();
5685f757f3fSDimitry Andric }
5695f757f3fSDimitry Andric 
5705f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10:
5715f757f3fSDimitry Andric /// In C and C++, the syntax of the cache directive is:
5725f757f3fSDimitry Andric ///
5735f757f3fSDimitry Andric /// #pragma acc cache ([readonly:]var-list) new-line
5745f757f3fSDimitry Andric void Parser::ParseOpenACCCacheVarList() {
5755f757f3fSDimitry Andric   // If this is the end of the line, just return 'false' and count on the close
5765f757f3fSDimitry Andric   // paren diagnostic to catch the issue.
5775f757f3fSDimitry Andric   if (getCurToken().isAnnotation())
5785f757f3fSDimitry Andric     return;
5795f757f3fSDimitry Andric 
5805f757f3fSDimitry Andric   // The VarList is an optional `readonly:` followed by a list of a variable
5815f757f3fSDimitry Andric   // specifications.  First, see if we have `readonly:`, else we back-out and
5825f757f3fSDimitry Andric   // treat it like the beginning of a reference to a potentially-existing
5835f757f3fSDimitry Andric   // `readonly` variable.
5845f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::ReadOnly, Tok) &&
5855f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
5865f757f3fSDimitry Andric     // Consume both tokens.
5875f757f3fSDimitry Andric     ConsumeToken();
5885f757f3fSDimitry Andric     ConsumeToken();
5895f757f3fSDimitry Andric     // FIXME: Record that this is a 'readonly' so that we can use that during
5905f757f3fSDimitry Andric     // Sema/AST generation.
5915f757f3fSDimitry Andric   }
5925f757f3fSDimitry Andric 
5935f757f3fSDimitry Andric   bool FirstArray = true;
5945f757f3fSDimitry Andric   while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
5955f757f3fSDimitry Andric     if (!FirstArray)
5965f757f3fSDimitry Andric       ExpectAndConsume(tok::comma);
5975f757f3fSDimitry Andric     FirstArray = false;
598*297eecfbSDimitry Andric 
599*297eecfbSDimitry Andric     // OpenACC 3.3, section 2.10:
600*297eecfbSDimitry Andric     // A 'var' in a cache directive must be a single array element or a simple
601*297eecfbSDimitry Andric     // subarray.  In C and C++, a simple subarray is an array name followed by
602*297eecfbSDimitry Andric     // an extended array range specification in brackets, with a start and
603*297eecfbSDimitry Andric     // length such as:
604*297eecfbSDimitry Andric     //
605*297eecfbSDimitry Andric     // arr[lower:length]
606*297eecfbSDimitry Andric     //
607*297eecfbSDimitry Andric     if (ParseOpenACCVar())
6085f757f3fSDimitry Andric       SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma,
6095f757f3fSDimitry Andric                 StopBeforeMatch);
6105f757f3fSDimitry Andric   }
6115f757f3fSDimitry Andric }
6125f757f3fSDimitry Andric 
6135f757f3fSDimitry Andric void Parser::ParseOpenACCDirective() {
6145f757f3fSDimitry Andric   OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);
6155f757f3fSDimitry Andric 
6165f757f3fSDimitry Andric   // Once we've parsed the construct/directive name, some have additional
6175f757f3fSDimitry Andric   // specifiers that need to be taken care of. Atomic has an 'atomic-clause'
6185f757f3fSDimitry Andric   // that needs to be parsed.
6195f757f3fSDimitry Andric   if (DirKind == OpenACCDirectiveKind::Atomic)
6205f757f3fSDimitry Andric     ParseOpenACCAtomicKind(*this);
6215f757f3fSDimitry Andric 
6225f757f3fSDimitry Andric   // We've successfully parsed the construct/directive name, however a few of
6235f757f3fSDimitry Andric   // the constructs have optional parens that contain further details.
6245f757f3fSDimitry Andric   BalancedDelimiterTracker T(*this, tok::l_paren,
6255f757f3fSDimitry Andric                              tok::annot_pragma_openacc_end);
6265f757f3fSDimitry Andric 
6275f757f3fSDimitry Andric   if (!T.consumeOpen()) {
6285f757f3fSDimitry Andric     switch (DirKind) {
6295f757f3fSDimitry Andric     default:
6305f757f3fSDimitry Andric       Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
6315f757f3fSDimitry Andric       T.skipToEnd();
6325f757f3fSDimitry Andric       break;
6335f757f3fSDimitry Andric     case OpenACCDirectiveKind::Routine: {
6345f757f3fSDimitry Andric       // Routine has an optional paren-wrapped name of a function in the local
6355f757f3fSDimitry Andric       // scope. We parse the name, emitting any diagnostics
6365f757f3fSDimitry Andric       ExprResult RoutineName = ParseOpenACCIDExpression();
6375f757f3fSDimitry Andric       // If the routine name is invalid, just skip until the closing paren to
6385f757f3fSDimitry Andric       // recover more gracefully.
6395f757f3fSDimitry Andric       if (RoutineName.isInvalid())
6405f757f3fSDimitry Andric         T.skipToEnd();
6415f757f3fSDimitry Andric       else
6425f757f3fSDimitry Andric         T.consumeClose();
6435f757f3fSDimitry Andric       break;
6445f757f3fSDimitry Andric     }
6455f757f3fSDimitry Andric     case OpenACCDirectiveKind::Cache:
6465f757f3fSDimitry Andric       ParseOpenACCCacheVarList();
6475f757f3fSDimitry Andric       // The ParseOpenACCCacheVarList function manages to recover from failures,
6485f757f3fSDimitry Andric       // so we can always consume the close.
6495f757f3fSDimitry Andric       T.consumeClose();
6505f757f3fSDimitry Andric       break;
6515f757f3fSDimitry Andric     case OpenACCDirectiveKind::Wait:
6525f757f3fSDimitry Andric       // OpenACC has an optional paren-wrapped 'wait-argument'.
6535f757f3fSDimitry Andric       if (ParseOpenACCWaitArgument())
6545f757f3fSDimitry Andric         T.skipToEnd();
6555f757f3fSDimitry Andric       else
6565f757f3fSDimitry Andric         T.consumeClose();
6575f757f3fSDimitry Andric       break;
6585f757f3fSDimitry Andric     }
6595f757f3fSDimitry Andric   } else if (DirKind == OpenACCDirectiveKind::Cache) {
6605f757f3fSDimitry Andric     // Cache's paren var-list is required, so error here if it isn't provided.
6615f757f3fSDimitry Andric     // We know that the consumeOpen above left the first non-paren here, so
6625f757f3fSDimitry Andric     // diagnose, then continue as if it was completely omitted.
6635f757f3fSDimitry Andric     Diag(Tok, diag::err_expected) << tok::l_paren;
6645f757f3fSDimitry Andric   }
6655f757f3fSDimitry Andric 
6665f757f3fSDimitry Andric   // Parses the list of clauses, if present.
6675f757f3fSDimitry Andric   ParseOpenACCClauseList(*this);
6685f757f3fSDimitry Andric 
6695f757f3fSDimitry Andric   Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
670cb14a3feSDimitry Andric   assert(Tok.is(tok::annot_pragma_openacc_end) &&
671cb14a3feSDimitry Andric          "Didn't parse all OpenACC Clauses");
672cb14a3feSDimitry Andric   ConsumeAnnotationToken();
6735f757f3fSDimitry Andric }
6745f757f3fSDimitry Andric 
6755f757f3fSDimitry Andric // Parse OpenACC directive on a declaration.
6765f757f3fSDimitry Andric Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
6775f757f3fSDimitry Andric   assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
6785f757f3fSDimitry Andric 
6795f757f3fSDimitry Andric   ParsingOpenACCDirectiveRAII DirScope(*this);
6805f757f3fSDimitry Andric   ConsumeAnnotationToken();
6815f757f3fSDimitry Andric 
6825f757f3fSDimitry Andric   ParseOpenACCDirective();
6835f757f3fSDimitry Andric 
6845f757f3fSDimitry Andric   return nullptr;
6855f757f3fSDimitry Andric }
6865f757f3fSDimitry Andric 
6875f757f3fSDimitry Andric // Parse OpenACC Directive on a Statement.
6885f757f3fSDimitry Andric StmtResult Parser::ParseOpenACCDirectiveStmt() {
6895f757f3fSDimitry Andric   assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
6905f757f3fSDimitry Andric 
6915f757f3fSDimitry Andric   ParsingOpenACCDirectiveRAII DirScope(*this);
6925f757f3fSDimitry Andric   ConsumeAnnotationToken();
6935f757f3fSDimitry Andric 
6945f757f3fSDimitry Andric   ParseOpenACCDirective();
6955f757f3fSDimitry Andric 
6965f757f3fSDimitry Andric   return StmtEmpty();
6975f757f3fSDimitry Andric }
698