xref: /freebsd-src/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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 
72*cb14a3feSDimitry Andric // Translate single-token string representations to the OpenCC Clause Kind.
73*cb14a3feSDimitry Andric OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
74*cb14a3feSDimitry Andric   // auto is a keyword in some language modes, so make sure we parse it
75*cb14a3feSDimitry Andric   // correctly.
76*cb14a3feSDimitry Andric   if (Tok.is(tok::kw_auto))
77*cb14a3feSDimitry Andric     return OpenACCClauseKind::Auto;
78*cb14a3feSDimitry Andric 
79*cb14a3feSDimitry Andric   if (!Tok.is(tok::identifier))
80*cb14a3feSDimitry Andric     return OpenACCClauseKind::Invalid;
81*cb14a3feSDimitry Andric 
82*cb14a3feSDimitry Andric   return llvm::StringSwitch<OpenACCClauseKind>(
83*cb14a3feSDimitry Andric              Tok.getIdentifierInfo()->getName())
84*cb14a3feSDimitry Andric       .Case("auto", OpenACCClauseKind::Auto)
85*cb14a3feSDimitry Andric       .Case("finalize", OpenACCClauseKind::Finalize)
86*cb14a3feSDimitry Andric       .Case("if_present", OpenACCClauseKind::IfPresent)
87*cb14a3feSDimitry Andric       .Case("independent", OpenACCClauseKind::Independent)
88*cb14a3feSDimitry Andric       .Case("nohost", OpenACCClauseKind::NoHost)
89*cb14a3feSDimitry Andric       .Case("seq", OpenACCClauseKind::Seq)
90*cb14a3feSDimitry Andric       .Case("vector", OpenACCClauseKind::Vector)
91*cb14a3feSDimitry Andric       .Case("worker", OpenACCClauseKind::Worker)
92*cb14a3feSDimitry Andric       .Default(OpenACCClauseKind::Invalid);
93*cb14a3feSDimitry Andric }
94*cb14a3feSDimitry Andric 
955f757f3fSDimitry Andric // Since 'atomic' is effectively a compound directive, this will decode the
965f757f3fSDimitry Andric // second part of the directive.
975f757f3fSDimitry Andric OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
985f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
995f757f3fSDimitry Andric     return OpenACCAtomicKind::Invalid;
1005f757f3fSDimitry Andric   return llvm::StringSwitch<OpenACCAtomicKind>(
1015f757f3fSDimitry Andric              Tok.getIdentifierInfo()->getName())
1025f757f3fSDimitry Andric       .Case("read", OpenACCAtomicKind::Read)
1035f757f3fSDimitry Andric       .Case("write", OpenACCAtomicKind::Write)
1045f757f3fSDimitry Andric       .Case("update", OpenACCAtomicKind::Update)
1055f757f3fSDimitry Andric       .Case("capture", OpenACCAtomicKind::Capture)
1065f757f3fSDimitry Andric       .Default(OpenACCAtomicKind::Invalid);
1075f757f3fSDimitry Andric }
1085f757f3fSDimitry Andric 
1095f757f3fSDimitry Andric enum class OpenACCSpecialTokenKind {
1105f757f3fSDimitry Andric   ReadOnly,
1115f757f3fSDimitry Andric   DevNum,
1125f757f3fSDimitry Andric   Queues,
1135f757f3fSDimitry Andric };
1145f757f3fSDimitry Andric 
1155f757f3fSDimitry Andric bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
1165f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
1175f757f3fSDimitry Andric     return false;
1185f757f3fSDimitry Andric 
1195f757f3fSDimitry Andric   switch (Kind) {
1205f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::ReadOnly:
1215f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("readonly");
1225f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::DevNum:
1235f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("devnum");
1245f757f3fSDimitry Andric   case OpenACCSpecialTokenKind::Queues:
1255f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("queues");
1265f757f3fSDimitry Andric   }
1275f757f3fSDimitry Andric   llvm_unreachable("Unknown 'Kind' Passed");
1285f757f3fSDimitry Andric }
1295f757f3fSDimitry Andric 
1305f757f3fSDimitry Andric bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
1315f757f3fSDimitry Andric   if (!Tok.is(tok::identifier))
1325f757f3fSDimitry Andric     return false;
1335f757f3fSDimitry Andric 
1345f757f3fSDimitry Andric   switch (Kind) {
1355f757f3fSDimitry Andric   case OpenACCDirectiveKind::Parallel:
1365f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("parallel");
1375f757f3fSDimitry Andric   case OpenACCDirectiveKind::Serial:
1385f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("serial");
1395f757f3fSDimitry Andric   case OpenACCDirectiveKind::Kernels:
1405f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("kernels");
1415f757f3fSDimitry Andric   case OpenACCDirectiveKind::Data:
1425f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("data");
1435f757f3fSDimitry Andric   case OpenACCDirectiveKind::HostData:
1445f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("host_data");
1455f757f3fSDimitry Andric   case OpenACCDirectiveKind::Loop:
1465f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("loop");
1475f757f3fSDimitry Andric   case OpenACCDirectiveKind::Cache:
1485f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("cache");
1495f757f3fSDimitry Andric 
1505f757f3fSDimitry Andric   case OpenACCDirectiveKind::ParallelLoop:
1515f757f3fSDimitry Andric   case OpenACCDirectiveKind::SerialLoop:
1525f757f3fSDimitry Andric   case OpenACCDirectiveKind::KernelsLoop:
1535f757f3fSDimitry Andric   case OpenACCDirectiveKind::EnterData:
1545f757f3fSDimitry Andric   case OpenACCDirectiveKind::ExitData:
1555f757f3fSDimitry Andric     return false;
1565f757f3fSDimitry Andric 
1575f757f3fSDimitry Andric   case OpenACCDirectiveKind::Atomic:
1585f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("atomic");
1595f757f3fSDimitry Andric   case OpenACCDirectiveKind::Routine:
1605f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("routine");
1615f757f3fSDimitry Andric   case OpenACCDirectiveKind::Declare:
1625f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("declare");
1635f757f3fSDimitry Andric   case OpenACCDirectiveKind::Init:
1645f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("init");
1655f757f3fSDimitry Andric   case OpenACCDirectiveKind::Shutdown:
1665f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("shutdown");
1675f757f3fSDimitry Andric   case OpenACCDirectiveKind::Set:
1685f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("set");
1695f757f3fSDimitry Andric   case OpenACCDirectiveKind::Update:
1705f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("update");
1715f757f3fSDimitry Andric   case OpenACCDirectiveKind::Wait:
1725f757f3fSDimitry Andric     return Tok.getIdentifierInfo()->isStr("wait");
1735f757f3fSDimitry Andric   case OpenACCDirectiveKind::Invalid:
1745f757f3fSDimitry Andric     return false;
1755f757f3fSDimitry Andric   }
1765f757f3fSDimitry Andric   llvm_unreachable("Unknown 'Kind' Passed");
1775f757f3fSDimitry Andric }
1785f757f3fSDimitry Andric 
1795f757f3fSDimitry Andric OpenACCDirectiveKind
1805f757f3fSDimitry Andric ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
1815f757f3fSDimitry Andric                                    OpenACCDirectiveKindEx ExtDirKind) {
1825f757f3fSDimitry Andric   Token SecondTok = P.getCurToken();
1835f757f3fSDimitry Andric 
1845f757f3fSDimitry Andric   if (SecondTok.isAnnotation()) {
1855f757f3fSDimitry Andric     P.Diag(FirstTok, diag::err_acc_invalid_directive)
1865f757f3fSDimitry Andric         << 0 << FirstTok.getIdentifierInfo();
1875f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
1885f757f3fSDimitry Andric   }
1895f757f3fSDimitry Andric 
190*cb14a3feSDimitry Andric   // Consume the second name anyway, this way we can continue on without making
191*cb14a3feSDimitry Andric   // this oddly look like a clause.
192*cb14a3feSDimitry Andric   P.ConsumeAnyToken();
193*cb14a3feSDimitry Andric 
1945f757f3fSDimitry Andric   if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) {
1955f757f3fSDimitry Andric     if (!SecondTok.is(tok::identifier))
1965f757f3fSDimitry Andric       P.Diag(SecondTok, diag::err_expected) << tok::identifier;
1975f757f3fSDimitry Andric     else
1985f757f3fSDimitry Andric       P.Diag(FirstTok, diag::err_acc_invalid_directive)
1995f757f3fSDimitry Andric           << 1 << FirstTok.getIdentifierInfo()->getName()
2005f757f3fSDimitry Andric           << SecondTok.getIdentifierInfo()->getName();
2015f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
2025f757f3fSDimitry Andric   }
2035f757f3fSDimitry Andric 
2045f757f3fSDimitry Andric   return ExtDirKind == OpenACCDirectiveKindEx::Enter
2055f757f3fSDimitry Andric              ? OpenACCDirectiveKind::EnterData
2065f757f3fSDimitry Andric              : OpenACCDirectiveKind::ExitData;
2075f757f3fSDimitry Andric }
2085f757f3fSDimitry Andric 
2095f757f3fSDimitry Andric OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) {
2105f757f3fSDimitry Andric   Token AtomicClauseToken = P.getCurToken();
2115f757f3fSDimitry Andric 
2125f757f3fSDimitry Andric   // #pragma acc atomic is equivilent to update:
2135f757f3fSDimitry Andric   if (AtomicClauseToken.isAnnotation())
2145f757f3fSDimitry Andric     return OpenACCAtomicKind::Update;
2155f757f3fSDimitry Andric 
2165f757f3fSDimitry Andric   OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken);
2175f757f3fSDimitry Andric 
2185f757f3fSDimitry Andric   // If we don't know what this is, treat it as 'nothing', and treat the rest of
2195f757f3fSDimitry Andric   // this as a clause list, which, despite being invalid, is likely what the
2205f757f3fSDimitry Andric   // user was trying to do.
2215f757f3fSDimitry Andric   if (AtomicKind == OpenACCAtomicKind::Invalid)
2225f757f3fSDimitry Andric     return OpenACCAtomicKind::Update;
2235f757f3fSDimitry Andric 
2245f757f3fSDimitry Andric   P.ConsumeToken();
2255f757f3fSDimitry Andric   return AtomicKind;
2265f757f3fSDimitry Andric }
2275f757f3fSDimitry Andric 
2285f757f3fSDimitry Andric // Parse and consume the tokens for OpenACC Directive/Construct kinds.
2295f757f3fSDimitry Andric OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
2305f757f3fSDimitry Andric   Token FirstTok = P.getCurToken();
2315f757f3fSDimitry Andric 
2325f757f3fSDimitry Andric   // Just #pragma acc can get us immediately to the end, make sure we don't
2335f757f3fSDimitry Andric   // introspect on the spelling before then.
2345f757f3fSDimitry Andric   if (FirstTok.isNot(tok::identifier)) {
2355f757f3fSDimitry Andric     P.Diag(FirstTok, diag::err_acc_missing_directive);
236*cb14a3feSDimitry Andric 
237*cb14a3feSDimitry Andric     if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
238*cb14a3feSDimitry Andric       P.ConsumeAnyToken();
239*cb14a3feSDimitry Andric 
2405f757f3fSDimitry Andric     return OpenACCDirectiveKind::Invalid;
2415f757f3fSDimitry Andric   }
2425f757f3fSDimitry Andric 
2435f757f3fSDimitry Andric   P.ConsumeToken();
2445f757f3fSDimitry Andric 
2455f757f3fSDimitry Andric   OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok);
2465f757f3fSDimitry Andric 
2475f757f3fSDimitry Andric   // OpenACCDirectiveKindEx is meant to be an extended list
2485f757f3fSDimitry Andric   // over OpenACCDirectiveKind, so any value below Invalid is one of the
2495f757f3fSDimitry Andric   // OpenACCDirectiveKind values.  This switch takes care of all of the extra
2505f757f3fSDimitry Andric   // parsing required for the Extended values.  At the end of this block,
2515f757f3fSDimitry Andric   // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
2525f757f3fSDimitry Andric   // immediately cast it and use it as that.
2535f757f3fSDimitry Andric   if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
2545f757f3fSDimitry Andric     switch (ExDirKind) {
2555f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Invalid: {
2565f757f3fSDimitry Andric       P.Diag(FirstTok, diag::err_acc_invalid_directive)
2575f757f3fSDimitry Andric           << 0 << FirstTok.getIdentifierInfo();
2585f757f3fSDimitry Andric       return OpenACCDirectiveKind::Invalid;
2595f757f3fSDimitry Andric     }
2605f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Enter:
2615f757f3fSDimitry Andric     case OpenACCDirectiveKindEx::Exit:
2625f757f3fSDimitry Andric       return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind);
2635f757f3fSDimitry Andric     }
2645f757f3fSDimitry Andric   }
2655f757f3fSDimitry Andric 
2665f757f3fSDimitry Andric   OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);
2675f757f3fSDimitry Andric 
2685f757f3fSDimitry Andric   // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
2695f757f3fSDimitry Andric   // other attempt at a combined construct will be diagnosed as an invalid
2705f757f3fSDimitry Andric   // clause.
2715f757f3fSDimitry Andric   Token SecondTok = P.getCurToken();
2725f757f3fSDimitry Andric   if (!SecondTok.isAnnotation() &&
2735f757f3fSDimitry Andric       isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) {
2745f757f3fSDimitry Andric     switch (DirKind) {
2755f757f3fSDimitry Andric     default:
2765f757f3fSDimitry Andric       // Nothing to do except in the below cases, as they should be diagnosed as
2775f757f3fSDimitry Andric       // a clause.
2785f757f3fSDimitry Andric       break;
2795f757f3fSDimitry Andric     case OpenACCDirectiveKind::Parallel:
2805f757f3fSDimitry Andric       P.ConsumeToken();
2815f757f3fSDimitry Andric       return OpenACCDirectiveKind::ParallelLoop;
2825f757f3fSDimitry Andric     case OpenACCDirectiveKind::Serial:
2835f757f3fSDimitry Andric       P.ConsumeToken();
2845f757f3fSDimitry Andric       return OpenACCDirectiveKind::SerialLoop;
2855f757f3fSDimitry Andric     case OpenACCDirectiveKind::Kernels:
2865f757f3fSDimitry Andric       P.ConsumeToken();
2875f757f3fSDimitry Andric       return OpenACCDirectiveKind::KernelsLoop;
2885f757f3fSDimitry Andric     }
2895f757f3fSDimitry Andric   }
2905f757f3fSDimitry Andric 
2915f757f3fSDimitry Andric   return DirKind;
2925f757f3fSDimitry Andric }
2935f757f3fSDimitry Andric 
294*cb14a3feSDimitry Andric // The OpenACC Clause List is a comma or space-delimited list of clauses (see
295*cb14a3feSDimitry Andric // the comment on ParseOpenACCClauseList).  The concept of a 'clause' doesn't
296*cb14a3feSDimitry Andric // really have its owner grammar and each individual one has its own definition.
297*cb14a3feSDimitry Andric // However, they all are named with a single-identifier (or auto!) token,
298*cb14a3feSDimitry Andric // followed in some cases by either braces or parens.
299*cb14a3feSDimitry Andric bool ParseOpenACCClause(Parser &P) {
300*cb14a3feSDimitry Andric   if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto))
301*cb14a3feSDimitry Andric     return P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
302*cb14a3feSDimitry Andric 
303*cb14a3feSDimitry Andric   OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken());
304*cb14a3feSDimitry Andric 
305*cb14a3feSDimitry Andric   if (Kind == OpenACCClauseKind::Invalid)
306*cb14a3feSDimitry Andric     return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause)
307*cb14a3feSDimitry Andric            << P.getCurToken().getIdentifierInfo();
308*cb14a3feSDimitry Andric 
309*cb14a3feSDimitry Andric   // Consume the clause name.
310*cb14a3feSDimitry Andric   P.ConsumeToken();
311*cb14a3feSDimitry Andric 
312*cb14a3feSDimitry Andric   // FIXME: For future clauses, we need to handle parens/etc below.
313*cb14a3feSDimitry Andric   return false;
314*cb14a3feSDimitry Andric }
315*cb14a3feSDimitry Andric 
316*cb14a3feSDimitry Andric // Skip until we see the end of pragma token, but don't consume it. This is us
317*cb14a3feSDimitry Andric // just giving up on the rest of the pragma so we can continue executing. We
318*cb14a3feSDimitry Andric // have to do this because 'SkipUntil' considers paren balancing, which isn't
319*cb14a3feSDimitry Andric // what we want.
320*cb14a3feSDimitry Andric void SkipUntilEndOfDirective(Parser &P) {
321*cb14a3feSDimitry Andric   while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
322*cb14a3feSDimitry Andric     P.ConsumeAnyToken();
323*cb14a3feSDimitry Andric }
324*cb14a3feSDimitry Andric 
325*cb14a3feSDimitry Andric // OpenACC 3.3, section 1.7:
326*cb14a3feSDimitry Andric // To simplify the specification and convey appropriate constraint information,
327*cb14a3feSDimitry Andric // a pqr-list is a comma-separated list of pdr items. The one exception is a
328*cb14a3feSDimitry Andric // clause-list, which is a list of one or more clauses optionally separated by
329*cb14a3feSDimitry Andric // commas.
3305f757f3fSDimitry Andric void ParseOpenACCClauseList(Parser &P) {
331*cb14a3feSDimitry Andric   bool FirstClause = true;
332*cb14a3feSDimitry Andric   while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) {
333*cb14a3feSDimitry Andric     // Comma is optional in a clause-list.
334*cb14a3feSDimitry Andric     if (!FirstClause && P.getCurToken().is(tok::comma))
335*cb14a3feSDimitry Andric       P.ConsumeToken();
336*cb14a3feSDimitry Andric     FirstClause = false;
337*cb14a3feSDimitry Andric 
338*cb14a3feSDimitry Andric     // Recovering from a bad clause is really difficult, so we just give up on
339*cb14a3feSDimitry Andric     // error.
340*cb14a3feSDimitry Andric     if (ParseOpenACCClause(P)) {
341*cb14a3feSDimitry Andric       SkipUntilEndOfDirective(P);
342*cb14a3feSDimitry Andric       return;
343*cb14a3feSDimitry Andric     }
344*cb14a3feSDimitry Andric   }
3455f757f3fSDimitry Andric }
3465f757f3fSDimitry Andric 
3475f757f3fSDimitry Andric } // namespace
3485f757f3fSDimitry Andric 
3495f757f3fSDimitry Andric /// OpenACC 3.3, section 2.16:
3505f757f3fSDimitry Andric /// In this section and throughout the specification, the term wait-argument
3515f757f3fSDimitry Andric /// means:
3525f757f3fSDimitry Andric /// [ devnum : int-expr : ] [ queues : ] async-argument-list
3535f757f3fSDimitry Andric bool Parser::ParseOpenACCWaitArgument() {
3545f757f3fSDimitry Andric   // [devnum : int-expr : ]
3555f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
3565f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
3575f757f3fSDimitry Andric     // Consume devnum.
3585f757f3fSDimitry Andric     ConsumeToken();
3595f757f3fSDimitry Andric     // Consume colon.
3605f757f3fSDimitry Andric     ConsumeToken();
3615f757f3fSDimitry Andric 
3625f757f3fSDimitry Andric     ExprResult IntExpr =
3635f757f3fSDimitry Andric         getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
3645f757f3fSDimitry Andric     if (IntExpr.isInvalid())
3655f757f3fSDimitry Andric       return true;
3665f757f3fSDimitry Andric 
3675f757f3fSDimitry Andric     if (ExpectAndConsume(tok::colon))
3685f757f3fSDimitry Andric       return true;
3695f757f3fSDimitry Andric   }
3705f757f3fSDimitry Andric 
3715f757f3fSDimitry Andric   // [ queues : ]
3725f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
3735f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
3745f757f3fSDimitry Andric     // Consume queues.
3755f757f3fSDimitry Andric     ConsumeToken();
3765f757f3fSDimitry Andric     // Consume colon.
3775f757f3fSDimitry Andric     ConsumeToken();
3785f757f3fSDimitry Andric   }
3795f757f3fSDimitry Andric 
3805f757f3fSDimitry Andric   // OpenACC 3.3, section 2.16:
3815f757f3fSDimitry Andric   // the term 'async-argument' means a nonnegative scalar integer expression, or
3825f757f3fSDimitry Andric   // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
3835f757f3fSDimitry Andric   // in the C header file and the Fortran opacc module.
3845f757f3fSDimitry Andric   //
3855f757f3fSDimitry Andric   // We are parsing this simply as list of assignment expressions (to avoid
3865f757f3fSDimitry Andric   // comma being troublesome), and will ensure it is an integral type.  The
3875f757f3fSDimitry Andric   // 'special' types are defined as macros, so we can't really check those
3885f757f3fSDimitry Andric   // (other than perhaps as values at one point?), but the standard does say it
3895f757f3fSDimitry Andric   // is implementation-defined to use any other negative value.
3905f757f3fSDimitry Andric   //
3915f757f3fSDimitry Andric   //
3925f757f3fSDimitry Andric   bool FirstArg = true;
3935f757f3fSDimitry Andric   while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
3945f757f3fSDimitry Andric     if (!FirstArg) {
3955f757f3fSDimitry Andric       if (ExpectAndConsume(tok::comma))
3965f757f3fSDimitry Andric         return true;
3975f757f3fSDimitry Andric     }
3985f757f3fSDimitry Andric     FirstArg = false;
3995f757f3fSDimitry Andric 
4005f757f3fSDimitry Andric     ExprResult CurArg =
4015f757f3fSDimitry Andric         getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
4025f757f3fSDimitry Andric 
4035f757f3fSDimitry Andric     if (CurArg.isInvalid())
4045f757f3fSDimitry Andric       return true;
4055f757f3fSDimitry Andric   }
4065f757f3fSDimitry Andric 
4075f757f3fSDimitry Andric   return false;
4085f757f3fSDimitry Andric }
4095f757f3fSDimitry Andric 
4105f757f3fSDimitry Andric ExprResult Parser::ParseOpenACCIDExpression() {
4115f757f3fSDimitry Andric   ExprResult Res;
4125f757f3fSDimitry Andric   if (getLangOpts().CPlusPlus) {
4135f757f3fSDimitry Andric     Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false);
4145f757f3fSDimitry Andric   } else {
4155f757f3fSDimitry Andric     // There isn't anything quite the same as ParseCXXIdExpression for C, so we
4165f757f3fSDimitry Andric     // need to get the identifier, then call into Sema ourselves.
4175f757f3fSDimitry Andric 
4185f757f3fSDimitry Andric     if (Tok.isNot(tok::identifier)) {
4195f757f3fSDimitry Andric       Diag(Tok, diag::err_expected) << tok::identifier;
4205f757f3fSDimitry Andric       return ExprError();
4215f757f3fSDimitry Andric     }
4225f757f3fSDimitry Andric 
4235f757f3fSDimitry Andric     Token FuncName = getCurToken();
4245f757f3fSDimitry Andric     UnqualifiedId Name;
4255f757f3fSDimitry Andric     CXXScopeSpec ScopeSpec;
4265f757f3fSDimitry Andric     SourceLocation TemplateKWLoc;
4275f757f3fSDimitry Andric     Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken());
4285f757f3fSDimitry Andric 
4295f757f3fSDimitry Andric     // Ensure this is a valid identifier. We don't accept causing implicit
4305f757f3fSDimitry Andric     // function declarations per the spec, so always claim to not have trailing
4315f757f3fSDimitry Andric     // L Paren.
4325f757f3fSDimitry Andric     Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
4335f757f3fSDimitry Andric                                     Name, /*HasTrailingLParen=*/false,
4345f757f3fSDimitry Andric                                     /*isAddressOfOperand=*/false);
4355f757f3fSDimitry Andric   }
4365f757f3fSDimitry Andric 
4375f757f3fSDimitry Andric   return getActions().CorrectDelayedTyposInExpr(Res);
4385f757f3fSDimitry Andric }
4395f757f3fSDimitry Andric 
4405f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10:
4415f757f3fSDimitry Andric /// A 'var' in a cache directive must be a single array element or a simple
4425f757f3fSDimitry Andric /// subarray.  In C and C++, a simple subarray is an array name followed by an
4435f757f3fSDimitry Andric /// extended array range specification in brackets, with a start and length such
4445f757f3fSDimitry Andric /// as:
4455f757f3fSDimitry Andric ///
4465f757f3fSDimitry Andric /// arr[lower:length]
4475f757f3fSDimitry Andric ///
4485f757f3fSDimitry Andric bool Parser::ParseOpenACCCacheVar() {
4495f757f3fSDimitry Andric   ExprResult ArrayName = ParseOpenACCIDExpression();
4505f757f3fSDimitry Andric   if (ArrayName.isInvalid())
4515f757f3fSDimitry Andric     return true;
4525f757f3fSDimitry Andric 
4535f757f3fSDimitry Andric   // If the expression is invalid, just continue parsing the brackets, there
4545f757f3fSDimitry Andric   // is likely other useful diagnostics we can emit inside of those.
4555f757f3fSDimitry Andric 
4565f757f3fSDimitry Andric   BalancedDelimiterTracker SquareBrackets(*this, tok::l_square,
4575f757f3fSDimitry Andric                                           tok::annot_pragma_openacc_end);
4585f757f3fSDimitry Andric 
4595f757f3fSDimitry Andric   // Square brackets are required, so error here, and try to recover by moving
4605f757f3fSDimitry Andric   // until the next comma, or the close paren/end of pragma.
4615f757f3fSDimitry Andric   if (SquareBrackets.expectAndConsume()) {
4625f757f3fSDimitry Andric     SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
4635f757f3fSDimitry Andric               Parser::StopBeforeMatch);
4645f757f3fSDimitry Andric     return true;
4655f757f3fSDimitry Andric   }
4665f757f3fSDimitry Andric 
4675f757f3fSDimitry Andric   ExprResult Lower = getActions().CorrectDelayedTyposInExpr(ParseExpression());
4685f757f3fSDimitry Andric   if (Lower.isInvalid())
4695f757f3fSDimitry Andric     return true;
4705f757f3fSDimitry Andric 
4715f757f3fSDimitry Andric   // The 'length' expression is optional, as this could be a single array
4725f757f3fSDimitry Andric   // element. If there is no colon, we can treat it as that.
4735f757f3fSDimitry Andric   if (getCurToken().is(tok::colon)) {
4745f757f3fSDimitry Andric     ConsumeToken();
4755f757f3fSDimitry Andric     ExprResult Length =
4765f757f3fSDimitry Andric         getActions().CorrectDelayedTyposInExpr(ParseExpression());
4775f757f3fSDimitry Andric     if (Length.isInvalid())
4785f757f3fSDimitry Andric       return true;
4795f757f3fSDimitry Andric   }
4805f757f3fSDimitry Andric 
4815f757f3fSDimitry Andric   // Diagnose the square bracket being in the wrong place and continue.
4825f757f3fSDimitry Andric   return SquareBrackets.consumeClose();
4835f757f3fSDimitry Andric }
4845f757f3fSDimitry Andric 
4855f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10:
4865f757f3fSDimitry Andric /// In C and C++, the syntax of the cache directive is:
4875f757f3fSDimitry Andric ///
4885f757f3fSDimitry Andric /// #pragma acc cache ([readonly:]var-list) new-line
4895f757f3fSDimitry Andric void Parser::ParseOpenACCCacheVarList() {
4905f757f3fSDimitry Andric   // If this is the end of the line, just return 'false' and count on the close
4915f757f3fSDimitry Andric   // paren diagnostic to catch the issue.
4925f757f3fSDimitry Andric   if (getCurToken().isAnnotation())
4935f757f3fSDimitry Andric     return;
4945f757f3fSDimitry Andric 
4955f757f3fSDimitry Andric   // The VarList is an optional `readonly:` followed by a list of a variable
4965f757f3fSDimitry Andric   // specifications.  First, see if we have `readonly:`, else we back-out and
4975f757f3fSDimitry Andric   // treat it like the beginning of a reference to a potentially-existing
4985f757f3fSDimitry Andric   // `readonly` variable.
4995f757f3fSDimitry Andric   if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::ReadOnly, Tok) &&
5005f757f3fSDimitry Andric       NextToken().is(tok::colon)) {
5015f757f3fSDimitry Andric     // Consume both tokens.
5025f757f3fSDimitry Andric     ConsumeToken();
5035f757f3fSDimitry Andric     ConsumeToken();
5045f757f3fSDimitry Andric     // FIXME: Record that this is a 'readonly' so that we can use that during
5055f757f3fSDimitry Andric     // Sema/AST generation.
5065f757f3fSDimitry Andric   }
5075f757f3fSDimitry Andric 
5085f757f3fSDimitry Andric   bool FirstArray = true;
5095f757f3fSDimitry Andric   while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
5105f757f3fSDimitry Andric     if (!FirstArray)
5115f757f3fSDimitry Andric       ExpectAndConsume(tok::comma);
5125f757f3fSDimitry Andric     FirstArray = false;
5135f757f3fSDimitry Andric     if (ParseOpenACCCacheVar())
5145f757f3fSDimitry Andric       SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma,
5155f757f3fSDimitry Andric                 StopBeforeMatch);
5165f757f3fSDimitry Andric   }
5175f757f3fSDimitry Andric }
5185f757f3fSDimitry Andric 
5195f757f3fSDimitry Andric void Parser::ParseOpenACCDirective() {
5205f757f3fSDimitry Andric   OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);
5215f757f3fSDimitry Andric 
5225f757f3fSDimitry Andric   // Once we've parsed the construct/directive name, some have additional
5235f757f3fSDimitry Andric   // specifiers that need to be taken care of. Atomic has an 'atomic-clause'
5245f757f3fSDimitry Andric   // that needs to be parsed.
5255f757f3fSDimitry Andric   if (DirKind == OpenACCDirectiveKind::Atomic)
5265f757f3fSDimitry Andric     ParseOpenACCAtomicKind(*this);
5275f757f3fSDimitry Andric 
5285f757f3fSDimitry Andric   // We've successfully parsed the construct/directive name, however a few of
5295f757f3fSDimitry Andric   // the constructs have optional parens that contain further details.
5305f757f3fSDimitry Andric   BalancedDelimiterTracker T(*this, tok::l_paren,
5315f757f3fSDimitry Andric                              tok::annot_pragma_openacc_end);
5325f757f3fSDimitry Andric 
5335f757f3fSDimitry Andric   if (!T.consumeOpen()) {
5345f757f3fSDimitry Andric     switch (DirKind) {
5355f757f3fSDimitry Andric     default:
5365f757f3fSDimitry Andric       Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);
5375f757f3fSDimitry Andric       T.skipToEnd();
5385f757f3fSDimitry Andric       break;
5395f757f3fSDimitry Andric     case OpenACCDirectiveKind::Routine: {
5405f757f3fSDimitry Andric       // Routine has an optional paren-wrapped name of a function in the local
5415f757f3fSDimitry Andric       // scope. We parse the name, emitting any diagnostics
5425f757f3fSDimitry Andric       ExprResult RoutineName = ParseOpenACCIDExpression();
5435f757f3fSDimitry Andric       // If the routine name is invalid, just skip until the closing paren to
5445f757f3fSDimitry Andric       // recover more gracefully.
5455f757f3fSDimitry Andric       if (RoutineName.isInvalid())
5465f757f3fSDimitry Andric         T.skipToEnd();
5475f757f3fSDimitry Andric       else
5485f757f3fSDimitry Andric         T.consumeClose();
5495f757f3fSDimitry Andric       break;
5505f757f3fSDimitry Andric     }
5515f757f3fSDimitry Andric     case OpenACCDirectiveKind::Cache:
5525f757f3fSDimitry Andric       ParseOpenACCCacheVarList();
5535f757f3fSDimitry Andric       // The ParseOpenACCCacheVarList function manages to recover from failures,
5545f757f3fSDimitry Andric       // so we can always consume the close.
5555f757f3fSDimitry Andric       T.consumeClose();
5565f757f3fSDimitry Andric       break;
5575f757f3fSDimitry Andric     case OpenACCDirectiveKind::Wait:
5585f757f3fSDimitry Andric       // OpenACC has an optional paren-wrapped 'wait-argument'.
5595f757f3fSDimitry Andric       if (ParseOpenACCWaitArgument())
5605f757f3fSDimitry Andric         T.skipToEnd();
5615f757f3fSDimitry Andric       else
5625f757f3fSDimitry Andric         T.consumeClose();
5635f757f3fSDimitry Andric       break;
5645f757f3fSDimitry Andric     }
5655f757f3fSDimitry Andric   } else if (DirKind == OpenACCDirectiveKind::Cache) {
5665f757f3fSDimitry Andric     // Cache's paren var-list is required, so error here if it isn't provided.
5675f757f3fSDimitry Andric     // We know that the consumeOpen above left the first non-paren here, so
5685f757f3fSDimitry Andric     // diagnose, then continue as if it was completely omitted.
5695f757f3fSDimitry Andric     Diag(Tok, diag::err_expected) << tok::l_paren;
5705f757f3fSDimitry Andric   }
5715f757f3fSDimitry Andric 
5725f757f3fSDimitry Andric   // Parses the list of clauses, if present.
5735f757f3fSDimitry Andric   ParseOpenACCClauseList(*this);
5745f757f3fSDimitry Andric 
5755f757f3fSDimitry Andric   Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
576*cb14a3feSDimitry Andric   assert(Tok.is(tok::annot_pragma_openacc_end) &&
577*cb14a3feSDimitry Andric          "Didn't parse all OpenACC Clauses");
578*cb14a3feSDimitry Andric   ConsumeAnnotationToken();
5795f757f3fSDimitry Andric }
5805f757f3fSDimitry Andric 
5815f757f3fSDimitry Andric // Parse OpenACC directive on a declaration.
5825f757f3fSDimitry Andric Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
5835f757f3fSDimitry Andric   assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
5845f757f3fSDimitry Andric 
5855f757f3fSDimitry Andric   ParsingOpenACCDirectiveRAII DirScope(*this);
5865f757f3fSDimitry Andric   ConsumeAnnotationToken();
5875f757f3fSDimitry Andric 
5885f757f3fSDimitry Andric   ParseOpenACCDirective();
5895f757f3fSDimitry Andric 
5905f757f3fSDimitry Andric   return nullptr;
5915f757f3fSDimitry Andric }
5925f757f3fSDimitry Andric 
5935f757f3fSDimitry Andric // Parse OpenACC Directive on a Statement.
5945f757f3fSDimitry Andric StmtResult Parser::ParseOpenACCDirectiveStmt() {
5955f757f3fSDimitry Andric   assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
5965f757f3fSDimitry Andric 
5975f757f3fSDimitry Andric   ParsingOpenACCDirectiveRAII DirScope(*this);
5985f757f3fSDimitry Andric   ConsumeAnnotationToken();
5995f757f3fSDimitry Andric 
6005f757f3fSDimitry Andric   ParseOpenACCDirective();
6015f757f3fSDimitry Andric 
6025f757f3fSDimitry Andric   return StmtEmpty();
6035f757f3fSDimitry Andric }
604