brintos

brintos / llvm-project-archived public Read only

0
0
Text · 102.3 KiB · bd259a9 Raw
2447 lines · cpp
1//===-- lib/Parser/openmp-parsers.cpp -------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// Top-level grammar specification for OpenMP.10// See OpenMP-4.5-grammar.txt for documentation.11 12#include "basic-parsers.h"13#include "expr-parsers.h"14#include "misc-parsers.h"15#include "stmt-parser.h"16#include "token-parsers.h"17#include "type-parser-implementation.h"18#include "flang/Parser/openmp-utils.h"19#include "flang/Parser/parse-tree.h"20#include "flang/Parser/tools.h"21#include "llvm/ADT/ArrayRef.h"22#include "llvm/ADT/Bitset.h"23#include "llvm/ADT/STLExtras.h"24#include "llvm/ADT/StringRef.h"25#include "llvm/ADT/StringSet.h"26#include "llvm/Frontend/OpenMP/OMP.h"27#include "llvm/Support/MathExtras.h"28 29#include <algorithm>30#include <cctype>31#include <iterator>32#include <list>33#include <optional>34#include <set>35#include <string>36#include <tuple>37#include <type_traits>38#include <utility>39#include <variant>40#include <vector>41 42// OpenMP Directives and Clauses43namespace Fortran::parser {44using namespace Fortran::parser::omp;45 46using DirectiveSet =47    llvm::Bitset<llvm::NextPowerOf2(llvm::omp::Directive_enumSize)>;48 49// Helper function to print the buffer contents starting at the current point.50[[maybe_unused]] static std::string ahead(const ParseState &state) {51  return std::string(52      state.GetLocation(), std::min<size_t>(64, state.BytesRemaining()));53}54 55constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok;56constexpr auto endOmpLine = space >> endOfLine;57 58constexpr auto logicalConstantExpr{logical(constantExpr)};59constexpr auto scalarLogicalConstantExpr{scalar(logicalConstantExpr)};60 61// Parser that wraps the result of another parser into a Block. If the given62// parser succeeds, the result is a block containing the ExecutionPartConstruct63// result of the argument parser. Otherwise the parser fails.64template <typename ExecParser> struct AsBlockParser {65  using resultType = Block;66  static_assert(67      std::is_same_v<typename ExecParser::resultType, ExecutionPartConstruct>);68 69  constexpr AsBlockParser(ExecParser epc) : epc_(epc) {}70  std::optional<resultType> Parse(ParseState &state) const {71    if (auto &&exec{attempt(epc_).Parse(state)}) {72      Block body;73      body.push_back(std::move(*exec));74      return std::move(body); // std::move for GCC 7.5.075    }76    return std::nullopt;77  }78 79private:80  const ExecParser epc_;81};82 83template <typename ExecParser,84    typename = std::enable_if<std::is_same_v<typename ExecParser::resultType,85        ExecutionPartConstruct>>>86constexpr auto asBlock(ExecParser epc) {87  return AsBlockParser<ExecParser>(epc);88}89 90// Given a parser for a single element, and a parser for a list of elements91// of the same type, create a parser that constructs the entire list by having92// the single element be the head of the list, and the rest be the tail.93template <typename ParserH, typename ParserT> struct ConsParser {94  static_assert(std::is_same_v<std::list<typename ParserH::resultType>,95      typename ParserT::resultType>);96 97  using resultType = typename ParserT::resultType;98  constexpr ConsParser(ParserH h, ParserT t) : head_(h), tail_(t) {}99 100  std::optional<resultType> Parse(ParseState &state) const {101    if (auto &&first{head_.Parse(state)}) {102      if (auto rest{tail_.Parse(state)}) {103        rest->push_front(std::move(*first));104        return std::move(*rest);105      }106    }107    return std::nullopt;108  }109 110private:111  const ParserH head_;112  const ParserT tail_;113};114 115template <typename ParserH, typename ParserT,116    typename ValueH = typename ParserH::resultType,117    typename ValueT = typename ParserT::resultType,118    typename = std::enable_if_t<std::is_same_v<std::list<ValueH>, ValueT>>>119constexpr auto cons(ParserH head, ParserT tail) {120  return ConsParser<ParserH, ParserT>(head, tail);121}122 123// Given a parser P for a wrapper class, invoke P, and if it succeeds return124// the wrapped object.125template <typename Parser> struct UnwrapParser {126  static_assert(127      Parser::resultType::WrapperTrait::value && "Wrapper class required");128  using resultType = decltype(Parser::resultType::v);129  constexpr UnwrapParser(Parser p) : parser_(p) {}130 131  std::optional<resultType> Parse(ParseState &state) const {132    if (auto result{parser_.Parse(state)}) {133      return result->v;134    }135    return std::nullopt;136  }137 138private:139  const Parser parser_;140};141 142template <typename Parser> constexpr auto unwrap(const Parser &p) {143  return UnwrapParser<Parser>(p);144}145 146// Check (without advancing the parsing location) if the next thing in the147// input would be accepted by the "checked" parser, and if so, run the "parser"148// parser.149// The intended use is with the "checker" parser being some token, followed150// by a more complex parser that consumes the token plus more things, e.g.151// "PARALLEL"_id >= Parser<OmpDirectiveSpecification>{}.152//153// The >= has a higher precedence than ||, so it can be used just like >>154// in an alternatives parser without parentheses.155template <typename PA, typename PB>156constexpr auto operator>=(PA checker, PB parser) {157  return lookAhead(checker) >> parser;158}159 160// This parser succeeds if the given parser succeeds, and the result161// satisfies the given condition. Specifically, it succeeds if:162// 1. The parser given as the argument succeeds, and163// 2. The condition function (called with PA::resultType) returns true164//    for the result.165template <typename PA, typename CF> struct PredicatedParser {166  using resultType = typename PA::resultType;167 168  constexpr PredicatedParser(PA parser, CF condition)169      : parser_(parser), condition_(condition) {}170 171  std::optional<resultType> Parse(ParseState &state) const {172    if (auto result{parser_.Parse(state)}; result && condition_(*result)) {173      return result;174    }175    return std::nullopt;176  }177 178private:179  const PA parser_;180  const CF condition_;181};182 183template <typename PA, typename CF>184constexpr auto predicated(PA parser, CF condition) {185  return PredicatedParser(parser, condition);186}187 188/// Parse OpenMP directive name (this includes compound directives).189struct OmpDirectiveNameParser {190  using resultType = OmpDirectiveName;191  using Token = TokenStringMatch<false, false>;192 193  std::optional<resultType> Parse(ParseState &state) const {194    if (state.BytesRemaining() == 0) {195      return std::nullopt;196    }197    auto begin{state.GetLocation()};198    char next{static_cast<char>(std::tolower(*begin))};199 200    for (const NameWithId &nid : directives_starting_with(next)) {201      if (attempt(Token(nid.first.data())).Parse(state)) {202        OmpDirectiveName n;203        n.v = nid.second;204        n.source = parser::CharBlock(begin, state.GetLocation());205        return n;206      }207    }208    return std::nullopt;209  }210 211private:212  using NameWithId = std::pair<std::string, llvm::omp::Directive>;213  using ConstIterator = std::vector<NameWithId>::const_iterator;214 215  llvm::iterator_range<ConstIterator> directives_starting_with(216      char initial) const;217  void initTokens(std::vector<NameWithId>[]) const;218};219 220llvm::iterator_range<OmpDirectiveNameParser::ConstIterator>221OmpDirectiveNameParser::directives_starting_with(char initial) const {222  static const std::vector<NameWithId> empty{};223  if (initial < 'a' || initial > 'z') {224    return llvm::make_range(std::cbegin(empty), std::cend(empty));225  }226 227  static std::vector<NameWithId> table['z' - 'a' + 1];228  [[maybe_unused]] static bool init = (initTokens(table), true);229 230  int index = initial - 'a';231  return llvm::make_range(std::cbegin(table[index]), std::cend(table[index]));232}233 234void OmpDirectiveNameParser::initTokens(std::vector<NameWithId> table[]) const {235  for (size_t i{0}, e{llvm::omp::Directive_enumSize}; i != e; ++i) {236    llvm::StringSet spellings;237    auto id{static_cast<llvm::omp::Directive>(i)};238    for (unsigned version : llvm::omp::getOpenMPVersions()) {239      spellings.insert(llvm::omp::getOpenMPDirectiveName(id, version));240    }241    for (auto &[name, _] : spellings) {242      char initial{static_cast<char>(std::tolower(name.front()))};243      table[initial - 'a'].emplace_back(name.str(), id);244    }245  }246  // Sort the table with respect to the directive name length in a descending247  // order. This is to make sure that longer names are tried first, before248  // any potential prefix (e.g. "target update" before "target").249  for (int initial{'a'}; initial != 'z' + 1; ++initial) {250    llvm::stable_sort(table[initial - 'a'],251        [](auto &a, auto &b) { return a.first.size() > b.first.size(); });252  }253}254 255// --- Modifier helpers -----------------------------------------------256 257template <typename Clause, typename Separator> struct ModifierList {258  constexpr ModifierList(Separator sep) : sep_(sep) {}259  constexpr ModifierList(const ModifierList &) = default;260  constexpr ModifierList(ModifierList &&) = default;261 262  using resultType = std::list<typename Clause::Modifier>;263 264  std::optional<resultType> Parse(ParseState &state) const {265    auto listp{nonemptySeparated(Parser<typename Clause::Modifier>{}, sep_)};266    if (auto result{attempt(listp).Parse(state)}) {267      if (!attempt(":"_tok).Parse(state)) {268        return std::nullopt;269      }270      return std::move(result);271    }272    return resultType{};273  }274 275private:276  const Separator sep_;277};278 279// Use a function to create ModifierList because functions allow "partial"280// template argument deduction: "modifierList<Clause>(sep)" would be legal,281// while "ModifierList<Clause>(sep)" would complain about a missing template282// argument "Separator".283template <typename Clause, typename Separator>284constexpr ModifierList<Clause, Separator> modifierList(Separator sep) {285  return ModifierList<Clause, Separator>(sep);286}287 288// Parse the input as any modifier from ClauseTy, but only succeed if289// the result was the SpecificTy. It requires that SpecificTy is one290// of the alternatives in ClauseTy::Modifier.291// The reason to have this is that ClauseTy::Modifier has "source",292// while specific modifiers don't. This class allows to parse a specific293// modifier together with obtaining its location.294template <typename SpecificTy, typename ClauseTy>295struct SpecificModifierParser {296  using resultType = typename ClauseTy::Modifier;297  std::optional<resultType> Parse(ParseState &state) const {298    if (auto result{attempt(Parser<resultType>{}).Parse(state)}) {299      if (std::holds_alternative<SpecificTy>(result->u)) {300        return result;301      }302    }303    return std::nullopt;304  }305};306 307// --- Iterator helpers -----------------------------------------------308 309static EntityDecl MakeEntityDecl(ObjectName &&name) {310  return EntityDecl(311      /*ObjectName=*/std::move(name), std::optional<ArraySpec>{},312      std::optional<CoarraySpec>{}, std::optional<CharLength>{},313      std::optional<Initialization>{});314}315 316// [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not317// specified then the type of that iterator is default integer.318// [5.0:49:14] The iterator-type must be an integer type.319static std::list<EntityDecl> makeEntityList(std::list<ObjectName> &&names) {320  std::list<EntityDecl> entities;321 322  for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) {323    entities.push_back(MakeEntityDecl(std::move(*iter)));324  }325  return entities;326}327 328static TypeDeclarationStmt makeIterSpecDecl(329    DeclarationTypeSpec &&spec, std::list<ObjectName> &&names) {330  return TypeDeclarationStmt(331      std::move(spec), std::list<AttrSpec>{}, makeEntityList(std::move(names)));332}333 334static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {335  // Assume INTEGER without kind selector.336  DeclarationTypeSpec typeSpec(337      IntrinsicTypeSpec{IntegerTypeSpec{std::nullopt}});338 339  return TypeDeclarationStmt(std::move(typeSpec), std::list<AttrSpec>{},340      makeEntityList(std::move(names)));341}342 343// --- Stylized expression handling -----------------------------------344 345// OpenMP has a concept of am "OpenMP stylized expression". Syntactially346// it looks like a typical Fortran expression (or statement), except:347// - the only variables allowed in it are OpenMP special variables, the348//   exact set of these variables depends on the specific case of the349//   stylized expression350// - the special OpenMP variables present may assume one or more types,351//   and the expression should be semantically valid for each type.352//353// The stylized expression can be thought of as a template, which will be354// instantiated for each type provided somewhere in the context in which355// the stylized expression appears.356//357// AST nodes:358// - OmpStylizedExpression: contains the source string for the expression,359//   plus the list of instances (OmpStylizedInstance).360// - OmpStylizedInstance: corresponds to the instantiation of the stylized361//   expression for a specific type. The way that the type is specified is362//   by creating declarations (OmpStylizedDeclaration) for the special363//   variables. Together with the AST tree corresponding to the stylized364//   expression the instantiation has enough information for semantic365//   analysis. Each instance has its own scope, and the special variables366//   have their own Symbol's (local to the scope).367// - OmpStylizedDeclaration: encapsulates the information that the visitors368//   in resolve-names can use to "emulate" a declaration for a special369//   variable and allow name resolution in the instantiation AST to work.370//371// Implementation specifics:372// The semantic analysis stores "evaluate::Expr" in each AST node rooted373// in parser::Expr (in the typedExpr member). The evaluate::Expr is specific374// to a given type, and so to allow different types for a given expression,375// for each type a separate copy of the parser::Expr subtree is created.376// Normally, AST nodes are non-copyable (copy-ctor is deleted), so to create377// several copies of a subtree, the same source string is parsed several378// times. The ParseState member in OmpStylizedExpression is the parser state379// immediately before the stylized expression.380//381// Initially, when OmpStylizedExpression is first created, the expression is382// parsed as if it was an actual code, but this parsing is only done to383// establish where the stylized expression ends (in the source). The source384// and the initial parser state are stored in the object, and the instance385// list is empty.386// Once the parsing of the containing OmpDirectiveSpecification completes,387// a post-processing "parser" (OmpStylizedInstanceCreator) executes. This388// post-processor examines the directive specification to see if it expects389// any stylized expressions to be contained in it, and then instantiates390// them for each such directive.391 392template <typename A> struct NeverParser {393  using resultType = A;394  std::optional<resultType> Parse(ParseState &state) const {395    // Always fail, but without any messages.396    return std::nullopt;397  }398};399 400template <typename A> constexpr auto never() { return NeverParser<A>{}; }401 402// Parser for optional<T> which always succeeds and returns std::nullptr.403// It's only needed to produce "std::optional<CallStmt::Chevrons>" in404// CallStmt.405template <typename A, typename B = void> struct NullParser;406template <typename B> struct NullParser<std::optional<B>> {407  using resultType = std::optional<B>;408  std::optional<resultType> Parse(ParseState &) const {409    return resultType{std::nullopt};410  }411};412 413template <typename A> constexpr auto null() { return NullParser<A>{}; }414 415// OmpStylizedDeclaration and OmpStylizedInstance are helper classes, and416// don't correspond to anything in the source. Their parsers should still417// exist, but they should never be executed.418TYPE_PARSER(construct<OmpStylizedDeclaration>(never<OmpStylizedDeclaration>()))419TYPE_PARSER(construct<OmpStylizedInstance>(never<OmpStylizedInstance>()))420 421TYPE_PARSER( //422    construct<OmpStylizedInstance::Instance>(Parser<AssignmentStmt>{}) ||423    construct<OmpStylizedInstance::Instance>(424        sourced(construct<CallStmt>(Parser<ProcedureDesignator>{},425            null<std::optional<CallStmt::Chevrons>>(),426            parenthesized(optionalList(actualArgSpec))))) ||427    construct<OmpStylizedInstance::Instance>(indirect(expr)))428 429struct OmpStylizedExpressionParser {430  using resultType = OmpStylizedExpression;431 432  std::optional<resultType> Parse(ParseState &state) const {433    auto *saved{new ParseState(state)};434    auto getSource{verbatim(Parser<OmpStylizedInstance::Instance>{} >> ok)};435    if (auto &&ok{getSource.Parse(state)}) {436      OmpStylizedExpression result{std::list<OmpStylizedInstance>{}};437      result.source = ok->source;438      result.state = saved;439      // result.v remains empty440      return std::move(result);441    }442    delete saved;443    return std::nullopt;444  }445};446 447static void Instantiate(OmpStylizedExpression &ose,448    llvm::ArrayRef<const OmpTypeName *> types, llvm::ArrayRef<CharBlock> vars) {449  // 1. For each var in the vars list, declare it with the corresponding450  //    type from types.451  // 2. Run the parser to get the AST for the stylized expression.452  // 3. Create OmpStylizedInstance and append it to the list in ose.453  assert(types.size() == vars.size() && "List size mismatch");454  // A ParseState object is irreversibly modified during parsing (in455  // particular, it cannot be rewound to an earlier position in the source).456  // Because of that we need to create a local copy for each instantiation.457  // If rewinding was possible, we could just use the current one, and we458  // wouldn't need to save it in the AST node.459  ParseState state{DEREF(ose.state)};460 461  std::list<OmpStylizedDeclaration> decls;462  for (auto [type, var] : llvm::zip_equal(types, vars)) {463    decls.emplace_back(OmpStylizedDeclaration{464        common::Reference(*type), MakeEntityDecl(Name{var})});465  }466 467  if (auto &&instance{Parser<OmpStylizedInstance::Instance>{}.Parse(state)}) {468    ose.v.emplace_back(469        OmpStylizedInstance{std::move(decls), std::move(*instance)});470  }471}472 473static void InstantiateForTypes(OmpStylizedExpression &ose,474    const OmpTypeNameList &typeNames, llvm::ArrayRef<CharBlock> vars) {475  // For each type in the type list, declare all variables in vars with476  // that type, and complete the instantiation.477  for (const OmpTypeName &t : typeNames.v) {478    std::vector<const OmpTypeName *> types(vars.size(), &t);479    Instantiate(ose, types, vars);480  }481}482 483static void InstantiateDeclareReduction(OmpDirectiveSpecification &spec) {484  // There can be arguments/clauses that don't make sense, that analysis485  // is left until semantic checks. Tolerate any unexpected stuff.486  auto *rspec{GetFirstArgument<OmpReductionSpecifier>(spec)};487  if (!rspec) {488    return;489  }490 491  const OmpTypeNameList *typeNames{nullptr};492 493  if (auto *cexpr{494          const_cast<OmpCombinerExpression *>(GetCombinerExpr(*rspec))}) {495    typeNames = &std::get<OmpTypeNameList>(rspec->t);496 497    InstantiateForTypes(*cexpr, *typeNames, OmpCombinerExpression::Variables());498    delete cexpr->state;499    cexpr->state = nullptr;500  } else {501    // If there are no types, there is nothing else to do.502    return;503  }504 505  for (const OmpClause &clause : spec.Clauses().v) {506    llvm::omp::Clause id{clause.Id()};507    if (id == llvm::omp::Clause::OMPC_initializer) {508      if (auto *iexpr{const_cast<OmpInitializerExpression *>(509              GetInitializerExpr(clause))}) {510        InstantiateForTypes(511            *iexpr, *typeNames, OmpInitializerExpression::Variables());512        delete iexpr->state;513        iexpr->state = nullptr;514      }515    }516  }517}518 519static void InstantiateStylizedDirective(OmpDirectiveSpecification &spec) {520  const OmpDirectiveName &dirName{spec.DirName()};521  if (dirName.v == llvm::omp::Directive::OMPD_declare_reduction) {522    InstantiateDeclareReduction(spec);523  }524}525 526template <typename P,527    typename = std::enable_if_t<528        std::is_same_v<typename P::resultType, OmpDirectiveSpecification>>>529struct OmpStylizedInstanceCreator {530  using resultType = OmpDirectiveSpecification;531  constexpr OmpStylizedInstanceCreator(P p) : parser_(p) {}532 533  std::optional<resultType> Parse(ParseState &state) const {534    if (auto &&spec{parser_.Parse(state)}) {535      InstantiateStylizedDirective(*spec);536      return std::move(spec);537    }538    return std::nullopt;539  }540 541private:542  const P parser_;543};544 545template <typename P>546OmpStylizedInstanceCreator(P) -> OmpStylizedInstanceCreator<P>;547 548// --- Parsers for types ----------------------------------------------549 550TYPE_PARSER( //551    sourced(construct<OmpTypeName>(Parser<DeclarationTypeSpec>{})) ||552    sourced(construct<OmpTypeName>(Parser<TypeSpec>{})))553 554// --- Parsers for arguments ------------------------------------------555 556// At the moment these are only directive arguments. This is needed for557// parsing directive-specification.558 559TYPE_PARSER( //560    construct<OmpLocator>(Parser<OmpObject>{}) ||561    construct<OmpLocator>(Parser<FunctionReference>{}))562 563TYPE_PARSER(construct<OmpBaseVariantNames>(564    Parser<OmpObject>{} / ":", Parser<OmpObject>{}))565 566// Make the parsing of OmpArgument directive-sensitive. The issue is that567// name1:name2 can match either OmpBaseVariantNames or OmpReductionSpecifier.568// In the former case, "name2" is a name of a function, in the latter, of a569// type. To resolve the conflict we need information provided by name570// resolution, but by that time we can't modify the AST anymore, and the571// name resolution may have implicitly declared a symbol, or issued a message.572template <llvm::omp::Directive Id = llvm::omp::Directive::OMPD_unknown>573struct OmpArgumentParser {574  using resultType = OmpArgument;575 576  std::optional<resultType> Parse(ParseState &state) const {577    constexpr auto parser{sourced(first( //578        construct<OmpArgument>(Parser<OmpMapperSpecifier>{}),579        // By default, prefer OmpReductionSpecifier over OmpBaseVariantNames.580        construct<OmpArgument>(Parser<OmpReductionSpecifier>{}),581        construct<OmpArgument>(Parser<OmpLocator>{})))};582    return parser.Parse(state);583  }584};585 586template <>587struct OmpArgumentParser<llvm::omp::Directive::OMPD_declare_variant> {588  using resultType = OmpArgument;589 590  std::optional<resultType> Parse(ParseState &state) const {591    constexpr auto parser{sourced(first( //592        construct<OmpArgument>(Parser<OmpMapperSpecifier>{}),593        // In DECLARE_VARIANT parse OmpBaseVariantNames instead of594        // OmpReductionSpecifier.595        construct<OmpArgument>(Parser<OmpBaseVariantNames>{}),596        construct<OmpArgument>(Parser<OmpLocator>{})))};597    return parser.Parse(state);598  }599};600 601TYPE_PARSER(construct<OmpLocatorList>(nonemptyList(Parser<OmpLocator>{})))602 603template <llvm::omp::Directive Id = llvm::omp::Directive::OMPD_unknown>604struct OmpArgumentListParser {605  using resultType = OmpArgumentList;606 607  std::optional<resultType> Parse(ParseState &state) const {608    return sourced(609        construct<OmpArgumentList>(nonemptyList(OmpArgumentParser<Id>{})))610        .Parse(state);611  }612};613 614// 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)615TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) ||616    construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{}))617 618TYPE_PARSER(construct<OmpReductionSpecifier>( //619    Parser<OmpReductionIdentifier>{},620    ":"_tok >> nonemptyList(Parser<OmpTypeName>{}),621    maybe(":"_tok >> Parser<OmpCombinerExpression>{})))622 623// --- Parsers for context traits -------------------------------------624 625static std::string nameToString(Name &&name) { return name.ToString(); }626 627TYPE_PARSER(sourced(construct<OmpTraitPropertyName>( //628    construct<OmpTraitPropertyName>(space >> charLiteralConstantWithoutKind) ||629    construct<OmpTraitPropertyName>(630        applyFunction(nameToString, Parser<Name>{})))))631 632TYPE_PARSER(sourced(construct<OmpTraitScore>( //633    "SCORE"_id >> parenthesized(scalarIntExpr))))634 635TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension::Complex>(636    Parser<OmpTraitPropertyName>{},637    parenthesized(nonemptySeparated(638        indirect(Parser<OmpTraitPropertyExtension>{}), ",")))))639 640TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension>(641    construct<OmpTraitPropertyExtension>(642        Parser<OmpTraitPropertyExtension::Complex>{}) ||643    construct<OmpTraitPropertyExtension>(Parser<OmpTraitPropertyName>{}) ||644    construct<OmpTraitPropertyExtension>(scalarExpr))))645 646TYPE_PARSER(construct<OmpTraitSelectorName::Value>(647    "ARCH"_id >> pure(OmpTraitSelectorName::Value::Arch) ||648    "ATOMIC_DEFAULT_MEM_ORDER"_id >>649        pure(OmpTraitSelectorName::Value::Atomic_Default_Mem_Order) ||650    "CONDITION"_id >> pure(OmpTraitSelectorName::Value::Condition) ||651    "DEVICE_NUM"_id >> pure(OmpTraitSelectorName::Value::Device_Num) ||652    "EXTENSION"_id >> pure(OmpTraitSelectorName::Value::Extension) ||653    "ISA"_id >> pure(OmpTraitSelectorName::Value::Isa) ||654    "KIND"_id >> pure(OmpTraitSelectorName::Value::Kind) ||655    "REQUIRES"_id >> pure(OmpTraitSelectorName::Value::Requires) ||656    "SIMD"_id >> pure(OmpTraitSelectorName::Value::Simd) ||657    "UID"_id >> pure(OmpTraitSelectorName::Value::Uid) ||658    "VENDOR"_id >> pure(OmpTraitSelectorName::Value::Vendor)))659 660TYPE_PARSER(sourced(construct<OmpTraitSelectorName>(661    // Parse predefined names first (because of SIMD).662    construct<OmpTraitSelectorName>(Parser<OmpTraitSelectorName::Value>{}) ||663    construct<OmpTraitSelectorName>(unwrap(OmpDirectiveNameParser{})) ||664    // identifier-or-string for extensions665    construct<OmpTraitSelectorName>(666        applyFunction(nameToString, Parser<Name>{})) ||667    construct<OmpTraitSelectorName>(space >> charLiteralConstantWithoutKind))))668 669// Parser for OmpTraitSelector::Properties670template <typename... PropParser>671static constexpr auto propertyListParser(PropParser... pp) {672  // Parse the property list "(score(expr): item1...)" in three steps:673  // 1. Parse the "("674  // 2. Parse the optional "score(expr):"675  // 3. Parse the "item1, ...)", together with the ")".676  // The reason for including the ")" in the 3rd step is to force parsing677  // the entire list in each of the alternative property parsers. Otherwise,678  // the name parser could stop after "foo" in "(foo, bar(1))", without679  // allowing the next parser to give the list a try.680  using P = OmpTraitProperty;681  return maybe("(" >> //682      construct<OmpTraitSelector::Properties>(683          maybe(Parser<OmpTraitScore>{} / ":"),684          (attempt(nonemptyList(sourced(construct<P>(pp))) / ")") || ...)));685}686 687// Parser for OmpTraitSelector688struct TraitSelectorParser {689  using resultType = OmpTraitSelector;690 691  constexpr TraitSelectorParser(Parser<OmpTraitSelectorName> p) : np(p) {}692 693  std::optional<resultType> Parse(ParseState &state) const {694    auto name{attempt(np).Parse(state)};695    if (!name.has_value()) {696      return std::nullopt;697    }698 699    // Default fallback parser for lists that cannot be parser using the700    // primary property parser.701    auto extParser{Parser<OmpTraitPropertyExtension>{}};702 703    if (auto *v{std::get_if<OmpTraitSelectorName::Value>(&name->u)}) {704      // (*) The comments below show the sections of the OpenMP spec that705      // describe given trait. The cases marked with a (*) are those where706      // the spec doesn't assign any list-type to these traits, but for707      // convenience they can be treated as if they were.708      switch (*v) {709      // name-list properties710      case OmpTraitSelectorName::Value::Arch: // [6.0:319:18]711      case OmpTraitSelectorName::Value::Extension: // [6.0:319:30]712      case OmpTraitSelectorName::Value::Isa: // [6.0:319:15]713      case OmpTraitSelectorName::Value::Kind: // [6.0:319:10]714      case OmpTraitSelectorName::Value::Uid: // [6.0:319:23](*)715      case OmpTraitSelectorName::Value::Vendor: { // [6.0:319:27]716        auto pp{propertyListParser(Parser<OmpTraitPropertyName>{}, extParser)};717        return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));718      }719      // clause-list720      case OmpTraitSelectorName::Value::Atomic_Default_Mem_Order:721        // [6.0:321:26-29](*)722      case OmpTraitSelectorName::Value::Requires: // [6.0:319:33]723      case OmpTraitSelectorName::Value::Simd: { // [6.0:318:31]724        auto pp{propertyListParser(indirect(Parser<OmpClause>{}), extParser)};725        return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));726      }727      // expr-list728      case OmpTraitSelectorName::Value::Condition: // [6.0:321:33](*)729      case OmpTraitSelectorName::Value::Device_Num: { // [6.0:321:23-24](*)730        auto pp{propertyListParser(scalarExpr, extParser)};731        return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));732      }733      } // switch734    } else {735      // The other alternatives are `llvm::omp::Directive`, and `std::string`.736      // The former doesn't take any properties[1], the latter is a name of an737      // extension[2].738      // [1] [6.0:319:1-2]739      // [2] [6.0:319:36-37]740      auto pp{propertyListParser(extParser)};741      return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));742    }743 744    llvm_unreachable("Unhandled trait name?");745  }746 747private:748  const Parser<OmpTraitSelectorName> np;749};750 751TYPE_PARSER(sourced(construct<OmpTraitSelector>(752    sourced(TraitSelectorParser(Parser<OmpTraitSelectorName>{})))))753 754TYPE_PARSER(construct<OmpTraitSetSelectorName::Value>(755    "CONSTRUCT"_id >> pure(OmpTraitSetSelectorName::Value::Construct) ||756    "DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Device) ||757    "IMPLEMENTATION"_id >>758        pure(OmpTraitSetSelectorName::Value::Implementation) ||759    "TARGET_DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Target_Device) ||760    "USER"_id >> pure(OmpTraitSetSelectorName::Value::User)))761 762TYPE_PARSER(sourced(construct<OmpTraitSetSelectorName>(763    Parser<OmpTraitSetSelectorName::Value>{})))764 765TYPE_PARSER(sourced(construct<OmpTraitSetSelector>( //766    Parser<OmpTraitSetSelectorName>{},767    "=" >> braced(nonemptySeparated(Parser<OmpTraitSelector>{}, ",")))))768 769TYPE_PARSER(sourced(construct<OmpContextSelectorSpecification>(770    nonemptySeparated(Parser<OmpTraitSetSelector>{}, ","))))771 772// Note: OmpContextSelector is a type alias.773 774// --- Parsers for clause modifiers -----------------------------------775 776TYPE_PARSER(construct<OmpAccessGroup>( //777    "CGROUP" >> pure(OmpAccessGroup::Value::Cgroup)))778 779TYPE_PARSER(construct<OmpAlignment>(scalarIntExpr))780 781TYPE_PARSER(construct<OmpAlignModifier>( //782    "ALIGN" >> parenthesized(scalarIntExpr)))783 784TYPE_PARSER(construct<OmpAllocatorComplexModifier>(785    "ALLOCATOR" >> parenthesized(scalarIntExpr)))786 787TYPE_PARSER(construct<OmpAllocatorSimpleModifier>(scalarIntExpr))788 789TYPE_PARSER(construct<OmpAlwaysModifier>( //790    "ALWAYS" >> pure(OmpAlwaysModifier::Value::Always)))791 792TYPE_PARSER(construct<OmpAttachModifier::Value>(793    "ALWAYS" >> pure(OmpAttachModifier::Value::Always) ||794    "AUTO" >> pure(OmpAttachModifier::Value::Auto) ||795    "NEVER" >> pure(OmpAttachModifier::Value::Never)))796 797TYPE_PARSER(construct<OmpAttachModifier>( //798    "ATTACH" >> parenthesized(Parser<OmpAttachModifier::Value>{})))799 800TYPE_PARSER(construct<OmpAutomapModifier>(801    "AUTOMAP" >> pure(OmpAutomapModifier::Value::Automap)))802 803TYPE_PARSER(construct<OmpChunkModifier>( //804    "SIMD" >> pure(OmpChunkModifier::Value::Simd)))805 806TYPE_PARSER(construct<OmpCloseModifier>( //807    "CLOSE" >> pure(OmpCloseModifier::Value::Close)))808 809TYPE_PARSER(construct<OmpDeleteModifier>( //810    "DELETE" >> pure(OmpDeleteModifier::Value::Delete)))811 812TYPE_PARSER(construct<OmpDependenceType>(813    "SINK" >> pure(OmpDependenceType::Value::Sink) ||814    "SOURCE" >> pure(OmpDependenceType::Value::Source)))815 816TYPE_PARSER(construct<OmpDeviceModifier>(817    "ANCESTOR" >> pure(OmpDeviceModifier::Value::Ancestor) ||818    "DEVICE_NUM" >> pure(OmpDeviceModifier::Value::Device_Num)))819 820TYPE_PARSER(construct<OmpDirectiveNameModifier>(OmpDirectiveNameParser{}))821 822TYPE_PARSER(construct<OmpExpectation>( //823    "PRESENT" >> pure(OmpExpectation::Value::Present)))824 825TYPE_PARSER(construct<OmpFallbackModifier>("FALLBACK"_tok >>826    parenthesized( //827        "ABORT" >> pure(OmpFallbackModifier::Value::Abort) ||828        "DEFAULT_MEM" >> pure(OmpFallbackModifier::Value::Default_Mem) ||829        "NULL" >> pure(OmpFallbackModifier::Value::Null))))830 831TYPE_PARSER(construct<OmpInteropRuntimeIdentifier>(832    construct<OmpInteropRuntimeIdentifier>(charLiteralConstant) ||833    construct<OmpInteropRuntimeIdentifier>(scalarIntConstantExpr)))834 835TYPE_PARSER(construct<OmpInteropPreference>(verbatim("PREFER_TYPE"_tok) >>836    parenthesized(nonemptyList(Parser<OmpInteropRuntimeIdentifier>{}))))837 838TYPE_PARSER(construct<OmpInteropType>(839    "TARGETSYNC" >> pure(OmpInteropType::Value::TargetSync) ||840    "TARGET" >> pure(OmpInteropType::Value::Target)))841 842TYPE_PARSER(construct<OmpIteratorSpecifier>(843    // Using Parser<TypeDeclarationStmt> or Parser<EntityDecl> has the problem844    // that they will attempt to treat what follows the '=' as initialization.845    // There are several issues with that,846    // 1. integer :: i = 0:10 will be parsed as "integer :: i = 0", followed847    // by triplet ":10".848    // 2. integer :: j = i:10 will be flagged as an error because the849    // initializer 'i' must be constant (in declarations). In an iterator850    // specifier the 'j' is not an initializer and can be a variable.851    (applyFunction<TypeDeclarationStmt>(makeIterSpecDecl,852         Parser<DeclarationTypeSpec>{} / maybe("::"_tok),853         nonemptyList(Parser<ObjectName>{}) / "="_tok) ||854        applyFunction<TypeDeclarationStmt>(855            makeIterSpecDecl, nonemptyList(Parser<ObjectName>{}) / "="_tok)),856    subscriptTriplet))857 858// [5.0] 2.1.6 iterator -> iterator-specifier-list859TYPE_PARSER(construct<OmpIterator>( //860    "ITERATOR" >>861    parenthesized(nonemptyList(sourced(Parser<OmpIteratorSpecifier>{})))))862 863TYPE_PARSER(construct<OmpLastprivateModifier>(864    "CONDITIONAL" >> pure(OmpLastprivateModifier::Value::Conditional)))865 866// 2.15.3.7 LINEAR (linear-list: linear-step)867//          linear-list -> list | modifier(list)868//          linear-modifier -> REF | VAL | UVAL869TYPE_PARSER(construct<OmpLinearModifier>( //870    "REF" >> pure(OmpLinearModifier::Value::Ref) ||871    "VAL" >> pure(OmpLinearModifier::Value::Val) ||872    "UVAL" >> pure(OmpLinearModifier::Value::Uval)))873 874TYPE_PARSER(construct<OmpMapper>( //875    "MAPPER"_tok >> parenthesized(Parser<ObjectName>{})))876 877// map-type -> ALLOC | DELETE | FROM | RELEASE | STORAGE | TO | TOFROM878TYPE_PARSER(construct<OmpMapType>( //879    "ALLOC" >> pure(OmpMapType::Value::Alloc) ||880    // Parse "DELETE" as OmpDeleteModifier881    "FROM" >> pure(OmpMapType::Value::From) ||882    "RELEASE" >> pure(OmpMapType::Value::Release) ||883    "STORAGE" >> pure(OmpMapType::Value::Storage) ||884    "TO"_id >> pure(OmpMapType::Value::To) ||885    "TOFROM" >> pure(OmpMapType::Value::Tofrom)))886 887TYPE_PARSER(construct<OmpOrderModifier>(888    "REPRODUCIBLE" >> pure(OmpOrderModifier::Value::Reproducible) ||889    "UNCONSTRAINED" >> pure(OmpOrderModifier::Value::Unconstrained)))890 891TYPE_PARSER(construct<OmpOrderingModifier>(892    "MONOTONIC" >> pure(OmpOrderingModifier::Value::Monotonic) ||893    "NONMONOTONIC" >> pure(OmpOrderingModifier::Value::Nonmonotonic) ||894    "SIMD" >> pure(OmpOrderingModifier::Value::Simd)))895 896TYPE_PARSER(construct<OmpPrescriptiveness>(897    "STRICT" >> pure(OmpPrescriptiveness::Value::Strict)))898 899TYPE_PARSER(construct<OmpPresentModifier>( //900    "PRESENT" >> pure(OmpPresentModifier::Value::Present)))901 902TYPE_PARSER(construct<OmpReductionModifier>(903    "INSCAN" >> pure(OmpReductionModifier::Value::Inscan) ||904    "TASK" >> pure(OmpReductionModifier::Value::Task) ||905    "DEFAULT" >> pure(OmpReductionModifier::Value::Default)))906 907TYPE_PARSER(construct<OmpRefModifier>( //908    "REF_PTEE" >> pure(OmpRefModifier::Value::Ref_Ptee) ||909    "REF_PTR"_id >> pure(OmpRefModifier::Value::Ref_Ptr) ||910    "REF_PTR_PTEE" >> pure(OmpRefModifier::Value::Ref_Ptr_Ptee)))911 912TYPE_PARSER(construct<OmpSelfModifier>( //913    "SELF" >> pure(OmpSelfModifier::Value::Self)))914 915TYPE_PARSER(construct<OmpStepComplexModifier>( //916    "STEP" >> parenthesized(scalarIntExpr)))917 918TYPE_PARSER(construct<OmpStepSimpleModifier>(scalarIntExpr))919 920TYPE_PARSER(construct<OmpTaskDependenceType>(921    "DEPOBJ" >> pure(OmpTaskDependenceType::Value::Depobj) ||922    "IN"_id >> pure(OmpTaskDependenceType::Value::In) ||923    "INOUT"_id >> pure(OmpTaskDependenceType::Value::Inout) ||924    "INOUTSET"_id >> pure(OmpTaskDependenceType::Value::Inoutset) ||925    "MUTEXINOUTSET" >> pure(OmpTaskDependenceType::Value::Mutexinoutset) ||926    "OUT" >> pure(OmpTaskDependenceType::Value::Out)))927 928TYPE_PARSER(construct<OmpVariableCategory>(929    "AGGREGATE" >> pure(OmpVariableCategory::Value::Aggregate) ||930    "ALL"_id >> pure(OmpVariableCategory::Value::All) ||931    "ALLOCATABLE" >> pure(OmpVariableCategory::Value::Allocatable) ||932    "POINTER" >> pure(OmpVariableCategory::Value::Pointer) ||933    "SCALAR" >> pure(OmpVariableCategory::Value::Scalar)))934 935TYPE_PARSER(construct<OmpxHoldModifier>( //936    "OMPX_HOLD" >> pure(OmpxHoldModifier::Value::Ompx_Hold)))937 938// This could be auto-generated.939TYPE_PARSER(940    sourced(construct<OmpAffinityClause::Modifier>(Parser<OmpIterator>{})))941 942TYPE_PARSER(943    sourced(construct<OmpAlignedClause::Modifier>(Parser<OmpAlignment>{})))944 945TYPE_PARSER(sourced(construct<OmpAllocateClause::Modifier>(sourced(946    construct<OmpAllocateClause::Modifier>(Parser<OmpAlignModifier>{}) ||947    construct<OmpAllocateClause::Modifier>(948        Parser<OmpAllocatorComplexModifier>{}) ||949    construct<OmpAllocateClause::Modifier>(950        Parser<OmpAllocatorSimpleModifier>{})))))951 952TYPE_PARSER(sourced(953    construct<OmpDefaultmapClause::Modifier>(Parser<OmpVariableCategory>{})))954 955TYPE_PARSER(sourced(construct<OmpDependClause::TaskDep::Modifier>(sourced(956    construct<OmpDependClause::TaskDep::Modifier>(Parser<OmpIterator>{}) ||957    construct<OmpDependClause::TaskDep::Modifier>(958        Parser<OmpTaskDependenceType>{})))))959 960TYPE_PARSER( //961    sourced(construct<OmpDynGroupprivateClause::Modifier>(962        Parser<OmpAccessGroup>{})) ||963    sourced(construct<OmpDynGroupprivateClause::Modifier>(964        Parser<OmpFallbackModifier>{})))965 966TYPE_PARSER(967    sourced(construct<OmpDeviceClause::Modifier>(Parser<OmpDeviceModifier>{})))968 969TYPE_PARSER(970    sourced(construct<OmpEnterClause::Modifier>(Parser<OmpAutomapModifier>{})))971 972TYPE_PARSER(sourced(construct<OmpFromClause::Modifier>(973    sourced(construct<OmpFromClause::Modifier>(Parser<OmpExpectation>{}) ||974        construct<OmpFromClause::Modifier>(Parser<OmpMapper>{}) ||975        construct<OmpFromClause::Modifier>(Parser<OmpIterator>{})))))976 977TYPE_PARSER(sourced(978    construct<OmpGrainsizeClause::Modifier>(Parser<OmpPrescriptiveness>{})))979 980TYPE_PARSER(sourced(981    construct<OmpIfClause::Modifier>(Parser<OmpDirectiveNameModifier>{})))982 983TYPE_PARSER(sourced(984    construct<OmpInitClause::Modifier>(985        construct<OmpInitClause::Modifier>(Parser<OmpInteropPreference>{})) ||986    construct<OmpInitClause::Modifier>(Parser<OmpInteropType>{})))987 988TYPE_PARSER(sourced(construct<OmpInReductionClause::Modifier>(989    Parser<OmpReductionIdentifier>{})))990 991TYPE_PARSER(sourced(construct<OmpLastprivateClause::Modifier>(992    Parser<OmpLastprivateModifier>{})))993 994TYPE_PARSER(sourced(995    construct<OmpLinearClause::Modifier>(Parser<OmpLinearModifier>{}) ||996    construct<OmpLinearClause::Modifier>(Parser<OmpStepComplexModifier>{}) ||997    construct<OmpLinearClause::Modifier>(Parser<OmpStepSimpleModifier>{})))998 999TYPE_PARSER(sourced(construct<OmpMapClause::Modifier>(1000    sourced(construct<OmpMapClause::Modifier>(Parser<OmpAlwaysModifier>{}) ||1001        construct<OmpMapClause::Modifier>(Parser<OmpAttachModifier>{}) ||1002        construct<OmpMapClause::Modifier>(Parser<OmpCloseModifier>{}) ||1003        construct<OmpMapClause::Modifier>(Parser<OmpDeleteModifier>{}) ||1004        construct<OmpMapClause::Modifier>(Parser<OmpPresentModifier>{}) ||1005        construct<OmpMapClause::Modifier>(Parser<OmpRefModifier>{}) ||1006        construct<OmpMapClause::Modifier>(Parser<OmpSelfModifier>{}) ||1007        construct<OmpMapClause::Modifier>(Parser<OmpMapper>{}) ||1008        construct<OmpMapClause::Modifier>(Parser<OmpIterator>{}) ||1009        construct<OmpMapClause::Modifier>(Parser<OmpMapType>{}) ||1010        construct<OmpMapClause::Modifier>(Parser<OmpxHoldModifier>{})))))1011 1012TYPE_PARSER(1013    sourced(construct<OmpOrderClause::Modifier>(Parser<OmpOrderModifier>{})))1014 1015TYPE_PARSER(sourced(1016    construct<OmpNumTasksClause::Modifier>(Parser<OmpPrescriptiveness>{})))1017 1018TYPE_PARSER(sourced(construct<OmpReductionClause::Modifier>(sourced(1019    construct<OmpReductionClause::Modifier>(Parser<OmpReductionModifier>{}) ||1020    construct<OmpReductionClause::Modifier>(1021        Parser<OmpReductionIdentifier>{})))))1022 1023TYPE_PARSER(sourced(construct<OmpScheduleClause::Modifier>(sourced(1024    construct<OmpScheduleClause::Modifier>(Parser<OmpChunkModifier>{}) ||1025    construct<OmpScheduleClause::Modifier>(Parser<OmpOrderingModifier>{})))))1026 1027TYPE_PARSER(sourced(construct<OmpTaskReductionClause::Modifier>(1028    Parser<OmpReductionIdentifier>{})))1029 1030TYPE_PARSER(sourced(construct<OmpToClause::Modifier>(1031    sourced(construct<OmpToClause::Modifier>(Parser<OmpExpectation>{}) ||1032        construct<OmpToClause::Modifier>(Parser<OmpMapper>{}) ||1033        construct<OmpToClause::Modifier>(Parser<OmpIterator>{})))))1034 1035TYPE_PARSER(sourced(construct<OmpWhenClause::Modifier>( //1036    Parser<OmpContextSelector>{})))1037 1038TYPE_PARSER(construct<OmpAppendArgsClause::OmpAppendOp>(1039    "INTEROP" >> parenthesized(nonemptyList(Parser<OmpInteropType>{}))))1040 1041TYPE_PARSER(construct<OmpAdjustArgsClause::OmpAdjustOp>(1042    "NOTHING" >> pure(OmpAdjustArgsClause::OmpAdjustOp::Value::Nothing) ||1043    "NEED_DEVICE_PTR" >>1044        pure(OmpAdjustArgsClause::OmpAdjustOp::Value::Need_Device_Ptr)))1045 1046// --- Parsers for clauses --------------------------------------------1047 1048/// `MOBClause` is a clause that has a1049///   std::tuple<Modifiers, OmpObjectList, bool>.1050/// Helper function to create a typical modifiers-objects clause, where the1051/// commas separating individual modifiers are optional, and the clause1052/// contains a bool member to indicate whether it was fully comma-separated1053/// or not.1054template <bool CommaSeparated, typename MOBClause>1055static inline MOBClause makeMobClause(1056    std::list<typename MOBClause::Modifier> &&mods, OmpObjectList &&objs) {1057  if (!mods.empty()) {1058    return MOBClause{std::move(mods), std::move(objs), CommaSeparated};1059  } else {1060    using ListTy = std::list<typename MOBClause::Modifier>;1061    return MOBClause{std::optional<ListTy>{}, std::move(objs), CommaSeparated};1062  }1063}1064 1065TYPE_PARSER(construct<OmpAdjustArgsClause>(1066    (Parser<OmpAdjustArgsClause::OmpAdjustOp>{} / ":"),1067    Parser<OmpObjectList>{}))1068 1069// [5.0] 2.10.1 affinity([aff-modifier:] locator-list)1070//              aff-modifier: interator-modifier1071TYPE_PARSER(construct<OmpAffinityClause>(1072    maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"),1073    Parser<OmpObjectList>{}))1074 1075// 2.4 Requires construct [OpenMP 5.0]1076//        atomic-default-mem-order-clause ->1077//                               acq_rel1078//                               acquire1079//                               relaxed1080//                               release1081//                               seq_cst1082TYPE_PARSER(construct<OmpAtomicDefaultMemOrderClause>(1083    "ACQ_REL" >> pure(common::OmpMemoryOrderType::Acq_Rel) ||1084    "ACQUIRE" >> pure(common::OmpMemoryOrderType::Acquire) ||1085    "RELAXED" >> pure(common::OmpMemoryOrderType::Relaxed) ||1086    "RELEASE" >> pure(common::OmpMemoryOrderType::Release) ||1087    "SEQ_CST" >> pure(common::OmpMemoryOrderType::Seq_Cst)))1088 1089TYPE_PARSER(construct<OmpCancellationConstructTypeClause>(1090    OmpDirectiveNameParser{}, maybe(parenthesized(scalarLogicalExpr))))1091 1092TYPE_PARSER(construct<OmpAppendArgsClause>(1093    nonemptyList(Parser<OmpAppendArgsClause::OmpAppendOp>{})))1094 1095// 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)1096TYPE_PARSER(construct<OmpDefaultClause::DataSharingAttribute>(1097    "PRIVATE" >> pure(OmpDefaultClause::DataSharingAttribute::Private) ||1098    "FIRSTPRIVATE" >>1099        pure(OmpDefaultClause::DataSharingAttribute::Firstprivate) ||1100    "SHARED" >> pure(OmpDefaultClause::DataSharingAttribute::Shared) ||1101    "NONE" >> pure(OmpDefaultClause::DataSharingAttribute::None)))1102 1103TYPE_PARSER(construct<OmpDefaultClause>(1104    construct<OmpDefaultClause>(1105        Parser<OmpDefaultClause::DataSharingAttribute>{}) ||1106    construct<OmpDefaultClause>(indirect(Parser<OmpDirectiveSpecification>{}))))1107 1108TYPE_PARSER(construct<OmpDynGroupprivateClause>(1109    maybe(nonemptyList(Parser<OmpDynGroupprivateClause::Modifier>{}) / ":"),1110    scalarIntExpr))1111 1112TYPE_PARSER(construct<OmpEnterClause>(1113    maybe(nonemptyList(Parser<OmpEnterClause::Modifier>{}) / ":"),1114    Parser<OmpObjectList>{}))1115 1116TYPE_PARSER(construct<OmpFailClause>(1117    "ACQ_REL" >> pure(common::OmpMemoryOrderType::Acq_Rel) ||1118    "ACQUIRE" >> pure(common::OmpMemoryOrderType::Acquire) ||1119    "RELAXED" >> pure(common::OmpMemoryOrderType::Relaxed) ||1120    "RELEASE" >> pure(common::OmpMemoryOrderType::Release) ||1121    "SEQ_CST" >> pure(common::OmpMemoryOrderType::Seq_Cst)))1122 1123TYPE_PARSER(construct<OmpGraphIdClause>(scalarIntExpr))1124 1125TYPE_PARSER(construct<OmpGraphResetClause>(scalarLogicalExpr))1126 1127// 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD)1128TYPE_PARSER(construct<OmpProcBindClause>(1129    "CLOSE" >> pure(OmpProcBindClause::AffinityPolicy::Close) ||1130    "MASTER" >> pure(OmpProcBindClause::AffinityPolicy::Master) ||1131    "PRIMARY" >> pure(OmpProcBindClause::AffinityPolicy::Primary) ||1132    "SPREAD" >> pure(OmpProcBindClause::AffinityPolicy::Spread)))1133 1134TYPE_PARSER(construct<OmpMapClause>(1135    applyFunction<OmpMapClause>(makeMobClause<true>,1136        modifierList<OmpMapClause>(","_tok), Parser<OmpObjectList>{}) ||1137    applyFunction<OmpMapClause>(makeMobClause<false>,1138        modifierList<OmpMapClause>(maybe(","_tok)), Parser<OmpObjectList>{})))1139 1140// [OpenMP 5.0]1141// 2.19.7.2 defaultmap(implicit-behavior[:variable-category])1142//  implicit-behavior -> ALLOC | TO | FROM | TOFROM | FIRSRTPRIVATE | NONE |1143//  DEFAULT | PRESENT1144//  variable-category -> ALL | SCALAR | AGGREGATE | ALLOCATABLE | POINTER1145TYPE_PARSER(construct<OmpDefaultmapClause>(1146    construct<OmpDefaultmapClause::ImplicitBehavior>(1147        "ALLOC" >> pure(OmpDefaultmapClause::ImplicitBehavior::Alloc) ||1148        "TO"_id >> pure(OmpDefaultmapClause::ImplicitBehavior::To) ||1149        "FROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::From) ||1150        "TOFROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::Tofrom) ||1151        "FIRSTPRIVATE" >>1152            pure(OmpDefaultmapClause::ImplicitBehavior::Firstprivate) ||1153        "NONE" >> pure(OmpDefaultmapClause::ImplicitBehavior::None) ||1154        "DEFAULT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Default) ||1155        "PRESENT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Present)),1156    maybe(":" >> nonemptyList(Parser<OmpDefaultmapClause::Modifier>{}))))1157 1158TYPE_PARSER(construct<OmpScheduleClause::Kind>(1159    "STATIC" >> pure(OmpScheduleClause::Kind::Static) ||1160    "DYNAMIC" >> pure(OmpScheduleClause::Kind::Dynamic) ||1161    "GUIDED" >> pure(OmpScheduleClause::Kind::Guided) ||1162    "AUTO" >> pure(OmpScheduleClause::Kind::Auto) ||1163    "RUNTIME" >> pure(OmpScheduleClause::Kind::Runtime)))1164 1165TYPE_PARSER(construct<OmpScheduleClause>(1166    maybe(nonemptyList(Parser<OmpScheduleClause::Modifier>{}) / ":"),1167    Parser<OmpScheduleClause::Kind>{}, maybe("," >> scalarIntExpr)))1168 1169// device([ device-modifier :] scalar-integer-expression)1170TYPE_PARSER(construct<OmpDeviceClause>(1171    maybe(nonemptyList(Parser<OmpDeviceClause::Modifier>{}) / ":"),1172    scalarIntExpr))1173 1174// device_type(any | host | nohost)1175TYPE_PARSER(construct<OmpDeviceTypeClause>(1176    "ANY" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Any) ||1177    "HOST" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Host) ||1178    "NOHOST" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Nohost)))1179 1180// 2.12 IF (directive-name-modifier: scalar-logical-expr)1181TYPE_PARSER(construct<OmpIfClause>(1182    maybe(nonemptyList(Parser<OmpIfClause::Modifier>{}) / ":"),1183    scalarLogicalExpr))1184 1185TYPE_PARSER(construct<OmpReductionClause>(1186    maybe(nonemptyList(Parser<OmpReductionClause::Modifier>{}) / ":"),1187    Parser<OmpObjectList>{}))1188 1189TYPE_PARSER(construct<OmpReplayableClause>(scalarLogicalConstantExpr))1190 1191// OMP 5.0 2.19.5.6 IN_REDUCTION (reduction-identifier: variable-name-list)1192TYPE_PARSER(construct<OmpInReductionClause>(1193    maybe(nonemptyList(Parser<OmpInReductionClause::Modifier>{}) / ":"),1194    Parser<OmpObjectList>{}))1195 1196TYPE_PARSER(construct<OmpTaskReductionClause>(1197    maybe(nonemptyList(Parser<OmpTaskReductionClause::Modifier>{}) / ":"),1198    Parser<OmpObjectList>{}))1199 1200TYPE_PARSER(construct<OmpTransparentClause>(scalarIntExpr))1201 1202// OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list)1203// OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier1204//                                   [, allocate-modifier] :]1205//                                   variable-name-list)1206//                allocate-modifier -> allocator | align1207TYPE_PARSER(construct<OmpAllocateClause>(1208    maybe(nonemptyList(Parser<OmpAllocateClause::Modifier>{}) / ":"),1209    Parser<OmpObjectList>{}))1210 1211// iteration-offset -> +/- non-negative-constant-expr1212TYPE_PARSER(construct<OmpIterationOffset>(1213    Parser<DefinedOperator>{}, scalarIntConstantExpr))1214 1215// iteration -> iteration-variable [+/- nonnegative-scalar-integer-constant]1216TYPE_PARSER(construct<OmpIteration>(name, maybe(Parser<OmpIterationOffset>{})))1217 1218TYPE_PARSER(construct<OmpIterationVector>(nonemptyList(Parser<OmpIteration>{})))1219 1220TYPE_PARSER(construct<OmpDoacross>(1221    construct<OmpDoacross>(construct<OmpDoacross::Sink>(1222        "SINK"_tok >> ":"_tok >> Parser<OmpIterationVector>{})) ||1223    construct<OmpDoacross>(construct<OmpDoacross::Source>("SOURCE"_tok))))1224 1225TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,1226    construct<OmpDependClause>(1227        // Try to parse OmpDoacross first, because TaskDep will succeed on1228        // "sink: xxx", interpreting it to not have any modifiers, and "sink"1229        // being an OmpObject. Parsing of the TaskDep variant will stop right1230        // after the "sink", leaving the ": xxx" unvisited.1231        construct<OmpDependClause>(Parser<OmpDoacross>{}) ||1232        // Parse TaskDep after Doacross.1233        construct<OmpDependClause>(construct<OmpDependClause::TaskDep>(1234            maybe(nonemptyList(Parser<OmpDependClause::TaskDep::Modifier>{}) /1235                ": "),1236            Parser<OmpObjectList>{}))))1237 1238TYPE_CONTEXT_PARSER("Omp Doacross clause"_en_US,1239    construct<OmpDoacrossClause>(Parser<OmpDoacross>{}))1240 1241TYPE_PARSER(construct<OmpFromClause>(1242    applyFunction<OmpFromClause>(makeMobClause<true>,1243        modifierList<OmpFromClause>(","_tok), Parser<OmpObjectList>{}) ||1244    applyFunction<OmpFromClause>(makeMobClause<false>,1245        modifierList<OmpFromClause>(maybe(","_tok)), Parser<OmpObjectList>{})))1246 1247TYPE_PARSER(construct<OmpToClause>(1248    applyFunction<OmpToClause>(makeMobClause<true>,1249        modifierList<OmpToClause>(","_tok), Parser<OmpObjectList>{}) ||1250    applyFunction<OmpToClause>(makeMobClause<false>,1251        modifierList<OmpToClause>(maybe(","_tok)), Parser<OmpObjectList>{})))1252 1253OmpLinearClause makeLinearFromOldSyntax(OmpLinearClause::Modifier &&lm,1254    OmpObjectList &&objs, std::optional<OmpLinearClause::Modifier> &&ssm) {1255  std::list<OmpLinearClause::Modifier> mods;1256  mods.emplace_back(std::move(lm));1257  if (ssm) {1258    mods.emplace_back(std::move(*ssm));1259  }1260  return OmpLinearClause{std::move(objs),1261      mods.empty() ? decltype(mods){} : std::move(mods),1262      /*PostModified=*/false};1263}1264 1265TYPE_PARSER(1266    // Parse the "modifier(x)" first, because syntacticaly it will match1267    // an array element (i.e. a list item).1268    // LINEAR(linear-modifier(list) [: step-simple-modifier])1269    construct<OmpLinearClause>( //1270        applyFunction<OmpLinearClause>(makeLinearFromOldSyntax,1271            SpecificModifierParser<OmpLinearModifier, OmpLinearClause>{},1272            parenthesized(Parser<OmpObjectList>{}),1273            maybe(":"_tok >> SpecificModifierParser<OmpStepSimpleModifier,1274                                 OmpLinearClause>{}))) ||1275    // LINEAR(list [: modifiers])1276    construct<OmpLinearClause>( //1277        Parser<OmpObjectList>{},1278        maybe(":"_tok >> nonemptyList(Parser<OmpLinearClause::Modifier>{})),1279        /*PostModified=*/pure(true)))1280 1281TYPE_PARSER(construct<OmpLoopRangeClause>(1282    scalarIntConstantExpr, "," >> scalarIntConstantExpr))1283 1284// OpenMPv5.2 12.5.2 detach-clause -> DETACH (event-handle)1285TYPE_PARSER(construct<OmpDetachClause>(Parser<OmpObject>{}))1286 1287TYPE_PARSER(construct<OmpHintClause>(scalarIntConstantExpr))1288 1289// init clause1290TYPE_PARSER(construct<OmpInitClause>(1291    maybe(nonemptyList(Parser<OmpInitClause::Modifier>{}) / ":"),1292    Parser<OmpObject>{}))1293 1294// 2.8.1 ALIGNED (list: alignment)1295TYPE_PARSER(construct<OmpAlignedClause>(Parser<OmpObjectList>{},1296    maybe(":" >> nonemptyList(Parser<OmpAlignedClause::Modifier>{}))))1297 1298TYPE_PARSER( //1299    construct<OmpUpdateClause>(parenthesized(Parser<OmpDependenceType>{})) ||1300    construct<OmpUpdateClause>(parenthesized(Parser<OmpTaskDependenceType>{})))1301 1302TYPE_PARSER(construct<OmpOrderClause>(1303    maybe(nonemptyList(Parser<OmpOrderClause::Modifier>{}) / ":"),1304    "CONCURRENT" >> pure(OmpOrderClause::Ordering::Concurrent)))1305 1306TYPE_PARSER(construct<OmpMatchClause>(1307    Parser<traits::OmpContextSelectorSpecification>{}))1308 1309TYPE_PARSER(construct<OmpOtherwiseClause>(1310    maybe(indirect(Parser<OmpDirectiveSpecification>{}))))1311 1312TYPE_PARSER(construct<OmpWhenClause>(1313    maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),1314    maybe(indirect(1315        OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{})))))1316 1317// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)1318TYPE_PARSER(construct<OmpGrainsizeClause>(1319    maybe(nonemptyList(Parser<OmpGrainsizeClause::Modifier>{}) / ":"),1320    scalarIntExpr))1321 1322// OMP 5.2 12.6.2 num_tasks([ prescriptiveness :] scalar-integer-expression)1323TYPE_PARSER(construct<OmpNumTasksClause>(1324    maybe(nonemptyList(Parser<OmpNumTasksClause::Modifier>{}) / ":"),1325    scalarIntExpr))1326 1327TYPE_PARSER( //1328    construct<OmpObject>(designator) ||1329    "/" >> construct<OmpObject>(name) / "/" ||1330    construct<OmpObject>(sourced(construct<OmpObject::Invalid>(1331        "//"_tok >> pure(OmpObject::Invalid::Kind::BlankCommonBlock)))))1332 1333// OMP 5.0 2.19.4.5 LASTPRIVATE ([lastprivate-modifier :] list)1334TYPE_PARSER(construct<OmpLastprivateClause>(1335    maybe(nonemptyList(Parser<OmpLastprivateClause::Modifier>{}) / ":"),1336    Parser<OmpObjectList>{}))1337 1338// OMP 5.2 11.7.1 BIND ( PARALLEL | TEAMS | THREAD )1339TYPE_PARSER(construct<OmpBindClause>(1340    "PARALLEL" >> pure(OmpBindClause::Binding::Parallel) ||1341    "TEAMS" >> pure(OmpBindClause::Binding::Teams) ||1342    "THREAD" >> pure(OmpBindClause::Binding::Thread)))1343 1344TYPE_PARSER(construct<OmpAlignClause>(scalarIntConstantExpr))1345 1346TYPE_PARSER(construct<OmpAtClause>(1347    "EXECUTION" >> pure(OmpAtClause::ActionTime::Execution) ||1348    "COMPILATION" >> pure(OmpAtClause::ActionTime::Compilation)))1349 1350TYPE_PARSER(construct<OmpSeverityClause>(1351    "FATAL" >> pure(OmpSeverityClause::Severity::Fatal) ||1352    "WARNING" >> pure(OmpSeverityClause::Severity::Warning)))1353 1354TYPE_PARSER(construct<OmpMessageClause>(expr))1355 1356TYPE_PARSER(construct<OmpHoldsClause>(indirect(expr)))1357TYPE_PARSER(construct<OmpAbsentClause>(many(maybe(","_tok) >>1358    construct<llvm::omp::Directive>(unwrap(OmpDirectiveNameParser{})))))1359TYPE_PARSER(construct<OmpContainsClause>(many(maybe(","_tok) >>1360    construct<llvm::omp::Directive>(unwrap(OmpDirectiveNameParser{})))))1361 1362TYPE_PARSER( //1363    "ABSENT" >> construct<OmpClause>(construct<OmpClause::Absent>(1364                    parenthesized(Parser<OmpAbsentClause>{}))) ||1365    "ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||1366    "ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||1367    "ADJUST_ARGS" >> construct<OmpClause>(construct<OmpClause::AdjustArgs>(1368                         parenthesized(Parser<OmpAdjustArgsClause>{}))) ||1369    "AFFINITY" >> construct<OmpClause>(construct<OmpClause::Affinity>(1370                      parenthesized(Parser<OmpAffinityClause>{}))) ||1371    "ALIGN" >> construct<OmpClause>(construct<OmpClause::Align>(1372                   parenthesized(Parser<OmpAlignClause>{}))) ||1373    "ALIGNED" >> construct<OmpClause>(construct<OmpClause::Aligned>(1374                     parenthesized(Parser<OmpAlignedClause>{}))) ||1375    "ALLOCATE" >> construct<OmpClause>(construct<OmpClause::Allocate>(1376                      parenthesized(Parser<OmpAllocateClause>{}))) ||1377    "APPEND_ARGS" >> construct<OmpClause>(construct<OmpClause::AppendArgs>(1378                         parenthesized(Parser<OmpAppendArgsClause>{}))) ||1379    "ALLOCATOR" >> construct<OmpClause>(construct<OmpClause::Allocator>(1380                       parenthesized(scalarIntExpr))) ||1381    "AT" >> construct<OmpClause>(construct<OmpClause::At>(1382                parenthesized(Parser<OmpAtClause>{}))) ||1383    "ATOMIC_DEFAULT_MEM_ORDER" >>1384        construct<OmpClause>(construct<OmpClause::AtomicDefaultMemOrder>(1385            parenthesized(Parser<OmpAtomicDefaultMemOrderClause>{}))) ||1386    "BIND" >> construct<OmpClause>(construct<OmpClause::Bind>(1387                  parenthesized(Parser<OmpBindClause>{}))) ||1388    "CAPTURE" >> construct<OmpClause>(construct<OmpClause::Capture>()) ||1389    "COLLAPSE" >> construct<OmpClause>(construct<OmpClause::Collapse>(1390                      parenthesized(scalarIntConstantExpr))) ||1391    "COMPARE" >> construct<OmpClause>(construct<OmpClause::Compare>()) ||1392    "CONTAINS" >> construct<OmpClause>(construct<OmpClause::Contains>(1393                      parenthesized(Parser<OmpContainsClause>{}))) ||1394    "COPYIN" >> construct<OmpClause>(construct<OmpClause::Copyin>(1395                    parenthesized(Parser<OmpObjectList>{}))) ||1396    "COPYPRIVATE" >> construct<OmpClause>(construct<OmpClause::Copyprivate>(1397                         (parenthesized(Parser<OmpObjectList>{})))) ||1398    "DEFAULT"_id >> construct<OmpClause>(construct<OmpClause::Default>(1399                        parenthesized(Parser<OmpDefaultClause>{}))) ||1400    "DEFAULTMAP" >> construct<OmpClause>(construct<OmpClause::Defaultmap>(1401                        parenthesized(Parser<OmpDefaultmapClause>{}))) ||1402    "DEPEND" >> construct<OmpClause>(construct<OmpClause::Depend>(1403                    parenthesized(Parser<OmpDependClause>{}))) ||1404    "DESTROY" >>1405        construct<OmpClause>(construct<OmpClause::Destroy>(maybe(parenthesized(1406            construct<OmpDestroyClause>(Parser<OmpObject>{}))))) ||1407    "DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(1408                    parenthesized(Parser<OmpDeviceClause>{}))) ||1409    "DEVICE_SAFESYNC" >>1410        construct<OmpClause>(construct<OmpClause::DeviceSafesync>(1411            maybe(parenthesized(scalarLogicalConstantExpr)))) ||1412    "DEVICE_TYPE" >> construct<OmpClause>(construct<OmpClause::DeviceType>(1413                         parenthesized(Parser<OmpDeviceTypeClause>{}))) ||1414    "DIST_SCHEDULE" >>1415        construct<OmpClause>(construct<OmpClause::DistSchedule>(1416            parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||1417    "DOACROSS" >>1418        construct<OmpClause>(parenthesized(Parser<OmpDoacrossClause>{})) ||1419    "DYNAMIC_ALLOCATORS" >>1420        construct<OmpClause>(construct<OmpClause::DynamicAllocators>(1421            maybe(parenthesized(scalarLogicalConstantExpr)))) ||1422    "DYN_GROUPPRIVATE" >>1423        construct<OmpClause>(construct<OmpClause::DynGroupprivate>(1424            parenthesized(Parser<OmpDynGroupprivateClause>{}))) ||1425    "ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>(1426                   parenthesized(Parser<OmpEnterClause>{}))) ||1427    "EXCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Exclusive>(1428                       parenthesized(Parser<OmpObjectList>{}))) ||1429    "FAIL" >> construct<OmpClause>(construct<OmpClause::Fail>(1430                  parenthesized(Parser<OmpFailClause>{}))) ||1431    "FILTER" >> construct<OmpClause>(construct<OmpClause::Filter>(1432                    parenthesized(scalarIntExpr))) ||1433    "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(1434                   parenthesized(scalarLogicalExpr))) ||1435    "FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(1436                          parenthesized(Parser<OmpObjectList>{}))) ||1437    "FROM" >> construct<OmpClause>(construct<OmpClause::From>(1438                  parenthesized(Parser<OmpFromClause>{}))) ||1439    "FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||1440    "GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(1441                       parenthesized(Parser<OmpGrainsizeClause>{}))) ||1442    "GRAPH_ID" >> construct<OmpClause>(construct<OmpClause::GraphId>(1443                      parenthesized(Parser<OmpGraphIdClause>{}))) ||1444    "GRAPH_RESET" >>1445        construct<OmpClause>(construct<OmpClause::GraphReset>(1446            maybe(parenthesized(Parser<OmpGraphResetClause>{})))) ||1447    "HAS_DEVICE_ADDR" >>1448        construct<OmpClause>(construct<OmpClause::HasDeviceAddr>(1449            parenthesized(Parser<OmpObjectList>{}))) ||1450    "HINT" >> construct<OmpClause>(construct<OmpClause::Hint>(1451                  parenthesized(Parser<OmpHintClause>{}))) ||1452    "HOLDS" >> construct<OmpClause>(construct<OmpClause::Holds>(1453                   parenthesized(Parser<OmpHoldsClause>{}))) ||1454    "IF" >> construct<OmpClause>(construct<OmpClause::If>(1455                parenthesized(Parser<OmpIfClause>{}))) ||1456    "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||1457    "INDIRECT" >> construct<OmpClause>(construct<OmpClause::Indirect>(1458                      maybe(parenthesized(scalarLogicalExpr)))) ||1459    "INIT" >> construct<OmpClause>(construct<OmpClause::Init>(1460                  parenthesized(Parser<OmpInitClause>{}))) ||1461    "INCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Inclusive>(1462                       parenthesized(Parser<OmpObjectList>{}))) ||1463    "INITIALIZER" >> construct<OmpClause>(construct<OmpClause::Initializer>(1464                         parenthesized(Parser<OmpInitializerClause>{}))) ||1465    "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(1466                           parenthesized(Parser<OmpObjectList>{}))) ||1467    "LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(1468                         parenthesized(Parser<OmpLastprivateClause>{}))) ||1469    "LINEAR" >> construct<OmpClause>(construct<OmpClause::Linear>(1470                    parenthesized(Parser<OmpLinearClause>{}))) ||1471    "LINK" >> construct<OmpClause>(construct<OmpClause::Link>(1472                  parenthesized(Parser<OmpObjectList>{}))) ||1473    "LOOPRANGE" >> construct<OmpClause>(construct<OmpClause::Looprange>(1474                       parenthesized(Parser<OmpLoopRangeClause>{}))) ||1475    "MAP" >> construct<OmpClause>(construct<OmpClause::Map>(1476                 parenthesized(Parser<OmpMapClause>{}))) ||1477    "MATCH" >> construct<OmpClause>(construct<OmpClause::Match>(1478                   parenthesized(Parser<OmpMatchClause>{}))) ||1479    "MERGEABLE" >> construct<OmpClause>(construct<OmpClause::Mergeable>()) ||1480    "MESSAGE" >> construct<OmpClause>(construct<OmpClause::Message>(1481                     parenthesized(Parser<OmpMessageClause>{}))) ||1482    "NOCONTEXT" >> construct<OmpClause>(construct<OmpClause::Nocontext>(1483                       parenthesized(scalarLogicalExpr))) ||1484    "NOGROUP" >> construct<OmpClause>(construct<OmpClause::Nogroup>()) ||1485    "NONTEMPORAL" >> construct<OmpClause>(construct<OmpClause::Nontemporal>(1486                         parenthesized(nonemptyList(name)))) ||1487    "NOTINBRANCH" >>1488        construct<OmpClause>(construct<OmpClause::Notinbranch>()) ||1489    "NOVARIANTS" >> construct<OmpClause>(construct<OmpClause::Novariants>(1490                        parenthesized(scalarLogicalExpr))) ||1491    "NOWAIT" >> construct<OmpClause>(construct<OmpClause::Nowait>()) ||1492    "NO_OPENMP"_id >> construct<OmpClause>(construct<OmpClause::NoOpenmp>()) ||1493    "NO_OPENMP_ROUTINES" >>1494        construct<OmpClause>(construct<OmpClause::NoOpenmpRoutines>()) ||1495    "NO_PARALLELISM" >>1496        construct<OmpClause>(construct<OmpClause::NoParallelism>()) ||1497    "NUM_TASKS" >> construct<OmpClause>(construct<OmpClause::NumTasks>(1498                       parenthesized(Parser<OmpNumTasksClause>{}))) ||1499    "NUM_TEAMS" >> construct<OmpClause>(construct<OmpClause::NumTeams>(1500                       parenthesized(scalarIntExpr))) ||1501    "NUM_THREADS" >> construct<OmpClause>(construct<OmpClause::NumThreads>(1502                         parenthesized(scalarIntExpr))) ||1503    "OMPX_BARE" >> construct<OmpClause>(construct<OmpClause::OmpxBare>()) ||1504    "ORDER" >> construct<OmpClause>(construct<OmpClause::Order>(1505                   parenthesized(Parser<OmpOrderClause>{}))) ||1506    "ORDERED" >> construct<OmpClause>(construct<OmpClause::Ordered>(1507                     maybe(parenthesized(scalarIntConstantExpr)))) ||1508    "OTHERWISE" >> construct<OmpClause>(construct<OmpClause::Otherwise>(1509                       maybe(parenthesized(Parser<OmpOtherwiseClause>{})))) ||1510    "PARTIAL" >> construct<OmpClause>(construct<OmpClause::Partial>(1511                     maybe(parenthesized(scalarIntConstantExpr)))) ||1512    "PRIORITY" >> construct<OmpClause>(construct<OmpClause::Priority>(1513                      parenthesized(scalarIntExpr))) ||1514    "PRIVATE" >> construct<OmpClause>(construct<OmpClause::Private>(1515                     parenthesized(Parser<OmpObjectList>{}))) ||1516    "PROC_BIND" >> construct<OmpClause>(construct<OmpClause::ProcBind>(1517                       parenthesized(Parser<OmpProcBindClause>{}))) ||1518    "REDUCTION"_id >> construct<OmpClause>(construct<OmpClause::Reduction>(1519                          parenthesized(Parser<OmpReductionClause>{}))) ||1520    "IN_REDUCTION" >> construct<OmpClause>(construct<OmpClause::InReduction>(1521                          parenthesized(Parser<OmpInReductionClause>{}))) ||1522    "DETACH" >> construct<OmpClause>(construct<OmpClause::Detach>(1523                    parenthesized(Parser<OmpDetachClause>{}))) ||1524    "TASK_REDUCTION" >>1525        construct<OmpClause>(construct<OmpClause::TaskReduction>(1526            parenthesized(Parser<OmpTaskReductionClause>{}))) ||1527    "READ" >> construct<OmpClause>(construct<OmpClause::Read>()) ||1528    "RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>()) ||1529    "RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||1530    "REPLAYABLE" >> construct<OmpClause>(construct<OmpClause::Replayable>(1531                        maybe(parenthesized(Parser<OmpReplayableClause>{})))) ||1532    "REVERSE_OFFLOAD" >>1533        construct<OmpClause>(construct<OmpClause::ReverseOffload>(1534            maybe(parenthesized(scalarLogicalConstantExpr)))) ||1535    "SAFELEN" >> construct<OmpClause>(construct<OmpClause::Safelen>(1536                     parenthesized(scalarIntConstantExpr))) ||1537    "SCHEDULE" >> construct<OmpClause>(construct<OmpClause::Schedule>(1538                      parenthesized(Parser<OmpScheduleClause>{}))) ||1539    "SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) ||1540    "SELF_MAPS" >> construct<OmpClause>(construct<OmpClause::SelfMaps>(1541                       maybe(parenthesized(scalarLogicalConstantExpr)))) ||1542    "SEVERITY" >> construct<OmpClause>(construct<OmpClause::Severity>(1543                      parenthesized(Parser<OmpSeverityClause>{}))) ||1544    "SHARED" >> construct<OmpClause>(construct<OmpClause::Shared>(1545                    parenthesized(Parser<OmpObjectList>{}))) ||1546    "SIMD"_id >> construct<OmpClause>(construct<OmpClause::Simd>()) ||1547    "SIMDLEN" >> construct<OmpClause>(construct<OmpClause::Simdlen>(1548                     parenthesized(scalarIntConstantExpr))) ||1549    "SIZES" >> construct<OmpClause>(construct<OmpClause::Sizes>(1550                   parenthesized(nonemptyList(scalarIntExpr)))) ||1551    "PERMUTATION" >> construct<OmpClause>(construct<OmpClause::Permutation>(1552                         parenthesized(nonemptyList(scalarIntExpr)))) ||1553    "THREADS" >> construct<OmpClause>(construct<OmpClause::Threads>()) ||1554    "THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(1555                          parenthesized(scalarIntExpr))) ||1556    "TO" >> construct<OmpClause>(construct<OmpClause::To>(1557                parenthesized(Parser<OmpToClause>{}))) ||1558    "TRANSPARENT" >>1559        construct<OmpClause>(construct<OmpClause::Transparent>(1560            maybe(parenthesized(Parser<OmpTransparentClause>{})))) ||1561    "USE" >> construct<OmpClause>(construct<OmpClause::Use>(1562                 parenthesized(Parser<OmpObject>{}))) ||1563    "USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(1564                            parenthesized(Parser<OmpObjectList>{}))) ||1565    "USE_DEVICE_ADDR" >>1566        construct<OmpClause>(construct<OmpClause::UseDeviceAddr>(1567            parenthesized(Parser<OmpObjectList>{}))) ||1568    "UNIFIED_ADDRESS" >>1569        construct<OmpClause>(construct<OmpClause::UnifiedAddress>(1570            maybe(parenthesized(scalarLogicalConstantExpr)))) ||1571    "UNIFIED_SHARED_MEMORY" >>1572        construct<OmpClause>(construct<OmpClause::UnifiedSharedMemory>(1573            maybe(parenthesized(scalarLogicalConstantExpr)))) ||1574    "UNIFORM" >> construct<OmpClause>(construct<OmpClause::Uniform>(1575                     parenthesized(nonemptyList(name)))) ||1576    "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()) ||1577    "UPDATE" >> construct<OmpClause>(construct<OmpClause::Update>(1578                    maybe(Parser<OmpUpdateClause>{}))) ||1579    "WHEN" >> construct<OmpClause>(construct<OmpClause::When>(1580                  parenthesized(Parser<OmpWhenClause>{}))) ||1581    "WRITE" >> construct<OmpClause>(construct<OmpClause::Write>()) ||1582    // Cancellable constructs1583    construct<OmpClause>(construct<OmpClause::CancellationConstructType>(1584        Parser<OmpCancellationConstructTypeClause>{})))1585 1586// [Clause, [Clause], ...]1587TYPE_PARSER(sourced(construct<OmpClauseList>(1588    many(maybe(","_tok) >> sourced(Parser<OmpClause>{})))))1589 1590// 2.1 (variable | /common-block/ | array-sections)1591TYPE_PARSER(construct<OmpObjectList>(nonemptyList(Parser<OmpObject>{})))1592 1593// --- Parsers for directives and constructs --------------------------1594 1595static inline constexpr auto IsDirective(llvm::omp::Directive dir) {1596  return [dir](const OmpDirectiveName &name) -> bool { return dir == name.v; };1597}1598 1599static inline constexpr auto IsMemberOf(const DirectiveSet &dirs) {1600  return [&dirs](const OmpDirectiveName &name) -> bool {1601    return dirs.test(llvm::to_underlying(name.v));1602  };1603}1604 1605constexpr auto validEPC{//1606    predicated(executionPartConstruct, [](auto &epc) {1607      return !Unwrap<OpenMPMisplacedEndDirective>(epc) &&1608          !Unwrap<OpenMPMisplacedEndDirective>(epc);1609    })};1610 1611constexpr auto validBlock{many(validEPC)};1612 1613TYPE_PARSER(sourced(construct<OmpDirectiveName>(OmpDirectiveNameParser{})))1614 1615OmpDirectiveSpecification static makeFlushFromOldSyntax(Verbatim &&text,1616    std::optional<OmpClauseList> &&clauses,1617    std::optional<OmpArgumentList> &&args,1618    OmpDirectiveSpecification::Flags &&flags) {1619  return OmpDirectiveSpecification{OmpDirectiveName(text), std::move(args),1620      std::move(clauses), std::move(flags)};1621}1622 1623TYPE_PARSER(1624    // Parse the old syntax: FLUSH [clauses] [(objects)]1625    sourced(construct<OmpDirectiveSpecification>(1626        // Force this old-syntax parser to fail for FLUSH followed by '('.1627        // Otherwise it could succeed on the new syntax but have one of1628        // lists absent in the parsed result.1629        // E.g. for FLUSH(x) SEQ_CST it would find no clauses following1630        // the directive name, parse the argument list "(x)" and stop.1631        applyFunction<OmpDirectiveSpecification>(makeFlushFromOldSyntax,1632            verbatim("FLUSH"_tok) / !lookAhead("("_tok),1633            maybe(Parser<OmpClauseList>{}),1634            maybe(parenthesized(1635                OmpArgumentListParser<llvm::omp::Directive::OMPD_flush>{})),1636            pure(OmpDirectiveSpecification::Flags(1637                {OmpDirectiveSpecification::Flag::DeprecatedSyntax}))))) ||1638    // Parse DECLARE_VARIANT individually, because the "[base:]variant"1639    // argument will conflict with DECLARE_REDUCTION's "ident:types...".1640    predicated(Parser<OmpDirectiveName>{},1641        IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >=1642        sourced(construct<OmpDirectiveSpecification>(1643            sourced(OmpDirectiveNameParser{}),1644            maybe(parenthesized(OmpArgumentListParser<1645                llvm::omp::Directive::OMPD_declare_variant>{})),1646            maybe(Parser<OmpClauseList>{}),1647            pure(OmpDirectiveSpecification::Flags()))) ||1648    // Parse the standard syntax: directive [(arguments)] [clauses]1649    sourced(construct<OmpDirectiveSpecification>( //1650        sourced(OmpDirectiveNameParser{}),1651        maybe(parenthesized(OmpArgumentListParser<>{})),1652        maybe(Parser<OmpClauseList>{}),1653        pure(OmpDirectiveSpecification::Flags()))))1654 1655static bool IsStandaloneOrdered(const OmpDirectiveSpecification &dirSpec) {1656  // An ORDERED construct is standalone if it has DOACROSS or DEPEND clause.1657  return dirSpec.DirId() == llvm::omp::Directive::OMPD_ordered &&1658      llvm::any_of(dirSpec.Clauses().v, [](const OmpClause &clause) {1659        llvm::omp::Clause id{clause.Id()};1660        return id == llvm::omp::Clause::OMPC_depend ||1661            id == llvm::omp::Clause::OMPC_doacross;1662      });1663}1664 1665struct StrictlyStructuredBlockParser {1666  using resultType = Block;1667 1668  std::optional<resultType> Parse(ParseState &state) const {1669    // Detect BLOCK construct without parsing the entire thing.1670    if (lookAhead(skipStuffBeforeStatement >> "BLOCK"_tok).Parse(state)) {1671      if (auto &&epc{executionPartConstruct.Parse(state)}) {1672        if (GetFortranBlockConstruct(*epc) != nullptr) {1673          Block body;1674          body.emplace_back(std::move(*epc));1675          return std::move(body);1676        }1677      }1678    }1679    return std::nullopt;1680  }1681};1682 1683struct LooselyStructuredBlockParser {1684  using resultType = Block;1685 1686  std::optional<resultType> Parse(ParseState &state) const {1687    // Detect BLOCK construct without parsing the entire thing.1688    if (lookAhead(skipStuffBeforeStatement >> "BLOCK"_tok).Parse(state)) {1689      return std::nullopt;1690    }1691    if (auto &&body{validBlock.Parse(state)}) {1692      // Empty body is ok.1693      return std::move(body);1694    }1695    return std::nullopt;1696  }1697};1698 1699struct NonBlockDoConstructParser {1700  using resultType = Block;1701 1702  std::optional<resultType> Parse(ParseState &state) const {1703    std::set<Label> labels;1704    Block body;1705 1706    // Parse nests like1707    // do 20 i = 1, n     LabelDoStmt.t<Label> = 201708    //   do 10 j = 1, m1709    //     ...1710    //   10 continue      Statement<...>.label = 101711    // 20 continue1712 1713    // Keep parsing ExecutionPartConstructs until the set of open label-do1714    // statements becomes empty, or until the EPC parser fails.1715    auto processEpc{[&](ExecutionPartConstruct &&epc) {1716      if (auto &&label{GetStatementLabel(epc)}) {1717        labels.erase(*label);1718      }1719      if (auto *labelDo{Unwrap<LabelDoStmt>(epc)}) {1720        labels.insert(std::get<Label>(labelDo->t));1721      }1722      body.push_back(std::move(epc));1723    }};1724 1725    auto nonBlockDo{predicated(executionPartConstruct,1726        [](auto &epc) { return Unwrap<LabelDoStmt>(epc); })};1727 1728    if (auto &&nbd{nonBlockDo.Parse(state)}) {1729      processEpc(std::move(*nbd));1730      while (auto &&epc{attempt(validEPC).Parse(state)}) {1731        processEpc(std::move(*epc));1732        if (labels.empty()) {1733          break;1734        }1735      }1736    }1737 1738    if (!body.empty()) {1739      return std::move(body);1740    }1741    return std::nullopt;1742  }1743};1744 1745struct LoopNestParser {1746  using resultType = Block;1747 1748  std::optional<resultType> Parse(ParseState &state) const {1749    // Parse !$DIR as an ExecutionPartConstruct1750    auto fortranDirective{predicated(executionPartConstruct,1751        [](auto &epc) { return Unwrap<CompilerDirective>(epc); })};1752    // Parse DO loop as an ExecutionPartConstruct1753    auto fortranDoConstruct{predicated(executionPartConstruct,1754        [&](auto &epc) { return Unwrap<DoConstruct>(epc); })};1755    ParseState backtrack{state};1756 1757    Block body;1758    llvm::move(*many(fortranDirective).Parse(state), std::back_inserter(body));1759 1760    if (auto &&doLoop{attempt(fortranDoConstruct).Parse(state)}) {1761      body.push_back(std::move(*doLoop));1762      return std::move(body);1763    }1764    if (auto &&labelDo{attempt(NonBlockDoConstructParser{}).Parse(state)}) {1765      llvm::move(*labelDo, std::back_inserter(body));1766      return std::move(body);1767    }1768    if (auto &&sblock{attempt(StrictlyStructuredBlockParser{}).Parse(state)}) {1769      llvm::move(*sblock, std::back_inserter(body));1770      return std::move(body);1771    }1772    // If it's neither a DO-loop, nor a BLOCK, undo the parsing of the1773    // directives and fail.1774    state = backtrack;1775    return std::nullopt;1776  }1777};1778 1779TYPE_PARSER(construct<OmpErrorDirective>(1780    predicated(Parser<OmpDirectiveName>{},1781        IsDirective(llvm::omp::Directive::OMPD_error)) >=1782    Parser<OmpDirectiveSpecification>{}))1783 1784TYPE_PARSER(construct<OmpNothingDirective>(1785    predicated(Parser<OmpDirectiveName>{},1786        IsDirective(llvm::omp::Directive::OMPD_nothing)) >=1787    Parser<OmpDirectiveSpecification>{}))1788 1789TYPE_PARSER( //1790    sourced(construct<OpenMPUtilityConstruct>(Parser<OmpErrorDirective>{})) ||1791    sourced(construct<OpenMPUtilityConstruct>(Parser<OmpNothingDirective>{})))1792 1793TYPE_PARSER(construct<OmpMetadirectiveDirective>(1794    predicated(Parser<OmpDirectiveName>{},1795        IsDirective(llvm::omp::Directive::OMPD_metadirective)) >=1796    Parser<OmpDirectiveSpecification>{}))1797 1798struct OmpBeginDirectiveParser {1799  using resultType = OmpDirectiveSpecification;1800 1801  constexpr OmpBeginDirectiveParser(DirectiveSet dirs) : dirs_(dirs) {}1802  constexpr OmpBeginDirectiveParser(llvm::omp::Directive dir) {1803    dirs_.set(llvm::to_underlying(dir));1804  }1805 1806  std::optional<resultType> Parse(ParseState &state) const {1807    auto &&p{predicated(Parser<OmpDirectiveName>{}, IsMemberOf(dirs_)) >=1808        Parser<OmpDirectiveSpecification>{}};1809    return p.Parse(state);1810  }1811 1812private:1813  DirectiveSet dirs_;1814};1815 1816struct OmpEndDirectiveParser {1817  using resultType = OmpDirectiveSpecification;1818 1819  constexpr OmpEndDirectiveParser(DirectiveSet dirs) : dirs_(dirs) {}1820  constexpr OmpEndDirectiveParser(llvm::omp::Directive dir) {1821    dirs_.set(llvm::to_underlying(dir));1822  }1823 1824  std::optional<resultType> Parse(ParseState &state) const {1825    if (startOmpLine.Parse(state)) {1826      if (auto endToken{verbatim("END"_sptok).Parse(state)}) {1827        if (auto &&dirSpec{OmpBeginDirectiveParser(dirs_).Parse(state)}) {1828          // Extend the "source" on both the OmpDirectiveName and the1829          // OmpDirectiveNameSpecification.1830          CharBlock &nameSource{std::get<OmpDirectiveName>(dirSpec->t).source};1831          nameSource.ExtendToCover(endToken->source);1832          dirSpec->source.ExtendToCover(endToken->source);1833          return std::move(*dirSpec);1834        }1835      }1836    }1837    return std::nullopt;1838  }1839 1840private:1841  DirectiveSet dirs_;1842};1843 1844struct OmpStatementConstructParser {1845  using resultType = OmpBlockConstruct;1846 1847  constexpr OmpStatementConstructParser(llvm::omp::Directive dir) : dir_(dir) {}1848 1849  std::optional<resultType> Parse(ParseState &state) const {1850    if (auto begin{OmpBeginDirectiveParser(dir_).Parse(state)}) {1851      Block body;1852      if (auto stmt{attempt(validEPC).Parse(state)}) {1853        body.emplace_back(std::move(*stmt));1854      }1855      // Allow empty block. Check for this in semantics.1856 1857      auto end{maybe(OmpEndDirectiveParser{dir_}).Parse(state)};1858      return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)),1859          std::move(body),1860          llvm::transformOptional(std::move(*end),1861              [](auto &&s) { return OmpEndDirective(std::move(s)); })};1862    }1863    return std::nullopt;1864  }1865 1866private:1867  llvm::omp::Directive dir_;1868};1869 1870struct OmpBlockConstructParser {1871  using resultType = OmpBlockConstruct;1872 1873  constexpr OmpBlockConstructParser(llvm::omp::Directive dir) : dir_(dir) {}1874 1875  std::optional<resultType> Parse(ParseState &state) const {1876    if (auto &&begin{OmpBeginDirectiveParser(dir_).Parse(state)}) {1877      if (IsStandaloneOrdered(*begin)) {1878        return std::nullopt;1879      }1880      if (auto &&body{attempt(StrictlyStructuredBlockParser{}).Parse(state)}) {1881        // Try strictly-structured block with an optional end-directive1882        auto end{maybe(OmpEndDirectiveParser{dir_}).Parse(state)};1883        return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)),1884            std::move(*body),1885            llvm::transformOptional(std::move(*end),1886                [](auto &&s) { return OmpEndDirective(std::move(s)); })};1887      } else if (auto &&body{1888                     attempt(LooselyStructuredBlockParser{}).Parse(state)}) {1889        // Try loosely-structured block with a mandatory end-directive.1890        auto end{maybe(OmpEndDirectiveParser{dir_}).Parse(state)};1891        // Delay the error for a missing end-directive until semantics so that1892        // we have better control over the output.1893        return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)),1894            std::move(*body),1895            llvm::transformOptional(std::move(*end),1896                [](auto &&s) { return OmpEndDirective(std::move(s)); })};1897      }1898    }1899    return std::nullopt;1900  }1901 1902private:1903  llvm::omp::Directive dir_;1904};1905 1906struct OmpLoopConstructParser {1907  using resultType = OpenMPLoopConstruct;1908 1909  constexpr OmpLoopConstructParser(DirectiveSet dirs) : dirs_(dirs) {}1910 1911  std::optional<resultType> Parse(ParseState &state) const {1912    auto ompLoopConstruct{asBlock(predicated(executionPartConstruct,1913        [](auto &epc) { return Unwrap<OpenMPLoopConstruct>(epc); }))};1914    auto loopItem{LoopNestParser{} || ompLoopConstruct};1915 1916    if (auto &&begin{OmpBeginDirectiveParser(dirs_).Parse(state)}) {1917      auto loopDir{begin->DirName().v};1918      auto assoc{llvm::omp::getDirectiveAssociation(loopDir)};1919      if (assoc == llvm::omp::Association::LoopNest) {1920        if (auto &&item{attempt(loopItem).Parse(state)}) {1921          auto end{maybe(OmpEndDirectiveParser{loopDir}).Parse(state)};1922          return OpenMPLoopConstruct{OmpBeginLoopDirective(std::move(*begin)),1923              std::move(*item),1924              llvm::transformOptional(std::move(*end),1925                  [](auto &&s) { return OmpEndLoopDirective(std::move(s)); })};1926        } else if (auto &&empty{pure<Block>().Parse(state)}) {1927          // Allow empty body.1928          auto end{maybe(OmpEndDirectiveParser{loopDir}).Parse(state)};1929          return OpenMPLoopConstruct{OmpBeginLoopDirective(std::move(*begin)),1930              std::move(*empty),1931              llvm::transformOptional(std::move(*end),1932                  [](auto &&s) { return OmpEndLoopDirective(std::move(s)); })};1933        }1934      } else if (assoc == llvm::omp::Association::LoopSeq) {1935        // Parse loop sequence as a block.1936        if (auto &&body{validBlock.Parse(state)}) {1937          auto end{maybe(OmpEndDirectiveParser{loopDir}).Parse(state)};1938          return OpenMPLoopConstruct{OmpBeginLoopDirective(std::move(*begin)),1939              std::move(*body),1940              llvm::transformOptional(std::move(*end),1941                  [](auto &&s) { return OmpEndLoopDirective(std::move(s)); })};1942        }1943      } else {1944        llvm_unreachable("Unexpected association");1945      }1946    }1947    return std::nullopt;1948  }1949 1950private:1951  DirectiveSet dirs_;1952};1953 1954struct OmpDeclarativeAllocateParser {1955  using resultType = OmpAllocateDirective;1956 1957  std::optional<resultType> Parse(ParseState &state) const {1958    constexpr llvm::omp::Directive dir{llvm::omp::Directive::OMPD_allocate};1959    if (auto &&begin{attempt(OmpBeginDirectiveParser(dir)).Parse(state)}) {1960      Block empty;1961      auto end{maybe(OmpEndDirectiveParser{dir}).Parse(state)};1962      return OmpAllocateDirective{std::move(*begin), std::move(empty),1963          llvm::transformOptional(std::move(*end),1964              [](auto &&s) { return OmpEndDirective(std::move(s)); })};1965    }1966    return std::nullopt;1967  }1968};1969 1970struct OmpExecutableAllocateParser {1971  using resultType = OmpAllocateDirective;1972 1973  std::optional<resultType> Parse(ParseState &state) const {1974    OmpStatementConstructParser p{llvm::omp::Directive::OMPD_allocate};1975    return construct<OmpAllocateDirective>(p).Parse(state);1976  }1977};1978 1979TYPE_PARSER(sourced(construct<OpenMPAllocatorsConstruct>(1980    OmpStatementConstructParser{llvm::omp::Directive::OMPD_allocators})))1981 1982TYPE_PARSER(sourced(construct<OpenMPDispatchConstruct>(1983    OmpStatementConstructParser{llvm::omp::Directive::OMPD_dispatch})))1984 1985// Parser for an arbitrary OpenMP ATOMIC construct.1986//1987// Depending on circumstances, an ATOMIC construct applies to one or more1988// following statements. In certain cases when a single statement is1989// expected, the end-directive is optional. The specifics depend on both1990// the clauses used, and the form of the executable statement. To emit1991// more meaningful messages in case of errors, the exact analysis of the1992// structure of the construct will be delayed until semantic checks.1993//1994// The parser will first try the case when the end-directive is present,1995// and will parse at most "BodyLimit" (and potentially zero) constructs1996// while looking for the end-directive before it gives up.1997// Then it will assume that no end-directive is present, and will try to1998// parse a single executable construct as the body of the construct.1999//2000// The limit on the number of constructs is there to reduce the amount of2001// unnecessary parsing when the end-directive is absent. It's higher than2002// the maximum number of statements in any valid construct to accept cases2003// when extra statements are present by mistake.2004// A problem can occur when atomic constructs without end-directive follow2005// each other closely, e.g.2006//   !$omp atomic write2007//     x = v2008//   !$omp atomic update2009//     x = x + 12010//   ...2011// The speculative parsing will become "recursive", and has the potential2012// to take a (practically) infinite amount of time given a sufficiently2013// large number of such constructs in a row. Since atomic constructs cannot2014// contain other OpenMP constructs, guarding against recursive calls to the2015// atomic construct parser solves the problem.2016struct OmpAtomicConstructParser {2017  using resultType = OpenMPAtomicConstruct;2018 2019  static constexpr size_t BodyLimit{5};2020 2021  std::optional<resultType> Parse(ParseState &state) const {2022    if (recursing_) {2023      return std::nullopt;2024    }2025    recursing_ = true;2026 2027    auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)};2028    if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_atomic) {2029      recursing_ = false;2030      return std::nullopt;2031    }2032 2033    TailType tail;2034 2035    if (ParseOne(tail, state)) {2036      if (!tail.first.empty()) {2037        if (auto &&rest{attempt(LimitedTailParser(BodyLimit)).Parse(state)}) {2038          for (auto &&s : rest->first) {2039            tail.first.emplace_back(std::move(s));2040          }2041          assert(!tail.second);2042          tail.second = std::move(rest->second);2043        }2044      }2045      recursing_ = false;2046      return OpenMPAtomicConstruct{OmpBeginDirective(std::move(*dirSpec)),2047          std::move(tail.first),2048          llvm::transformOptional(std::move(tail.second),2049              [](auto &&s) { return OmpEndDirective(std::move(s)); })};2050    }2051 2052    recursing_ = false;2053    return std::nullopt;2054  }2055 2056private:2057  // Begin-directive + TailType = entire construct.2058  using TailType = std::pair<Block, std::optional<OmpDirectiveSpecification>>;2059 2060  // Parse either an ExecutionPartConstruct, or atomic end-directive. When2061  // successful, record the result in the "tail" provided, otherwise fail.2062  static std::optional<Success> ParseOne(TailType &tail, ParseState &state) {2063    auto isUsable{[](const std::optional<ExecutionPartConstruct> &e) {2064      return e && !std::holds_alternative<ErrorRecovery>(e->u);2065    }};2066    auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}};2067    if (auto &&stmt{attempt(validEPC).Parse(state)}; isUsable(stmt)) {2068      tail.first.emplace_back(std::move(*stmt));2069    } else if (auto &&dir{attempt(end).Parse(state)}) {2070      tail.second = std::move(*dir);2071    } else {2072      return std::nullopt;2073    }2074    return Success{};2075  }2076 2077  struct LimitedTailParser {2078    using resultType = TailType;2079 2080    constexpr LimitedTailParser(size_t count) : count_(count) {}2081 2082    std::optional<resultType> Parse(ParseState &state) const {2083      TailType tail;2084 2085      for (size_t i{0}; i != count_; ++i) {2086        if (ParseOne(tail, state)) {2087          if (tail.second) {2088            // Return when the end-directive was parsed.2089            return std::move(tail);2090          }2091        } else {2092          break;2093        }2094      }2095      return std::nullopt;2096    }2097 2098  private:2099    const size_t count_;2100  };2101 2102  // The recursion guard should become thread_local if parsing is ever2103  // parallelized.2104  static bool recursing_;2105};2106 2107bool OmpAtomicConstructParser::recursing_{false};2108 2109TYPE_PARSER(sourced( //2110    construct<OpenMPAtomicConstruct>(OmpAtomicConstructParser{})))2111 2112static bool IsSimpleStandalone(const OmpDirectiveName &name) {2113  switch (name.v) {2114  case llvm::omp::Directive::OMPD_barrier:2115  case llvm::omp::Directive::OMPD_scan:2116  case llvm::omp::Directive::OMPD_target_enter_data:2117  case llvm::omp::Directive::OMPD_target_exit_data:2118  case llvm::omp::Directive::OMPD_target_update:2119  case llvm::omp::Directive::OMPD_taskwait:2120  case llvm::omp::Directive::OMPD_taskyield:2121    return true;2122  default:2123    return false;2124  }2125}2126 2127TYPE_PARSER(sourced( //2128    construct<OpenMPSimpleStandaloneConstruct>(2129        predicated(OmpDirectiveNameParser{}, IsSimpleStandalone) >=2130        Parser<OmpDirectiveSpecification>{}) ||2131    construct<OpenMPSimpleStandaloneConstruct>(2132        predicated(Parser<OmpDirectiveSpecification>{}, IsStandaloneOrdered))))2133 2134TYPE_PARSER(sourced( //2135    construct<OpenMPFlushConstruct>(2136        predicated(OmpDirectiveNameParser{},2137            IsDirective(llvm::omp::Directive::OMPD_flush)) >=2138        Parser<OmpDirectiveSpecification>{})))2139 2140// 2.14.2 Cancellation Point construct2141TYPE_PARSER(sourced( //2142    construct<OpenMPCancellationPointConstruct>(2143        predicated(OmpDirectiveNameParser{},2144            IsDirective(llvm::omp::Directive::OMPD_cancellation_point)) >=2145        Parser<OmpDirectiveSpecification>{})))2146 2147// 2.14.1 Cancel construct2148TYPE_PARSER(sourced( //2149    construct<OpenMPCancelConstruct>(2150        predicated(OmpDirectiveNameParser{},2151            IsDirective(llvm::omp::Directive::OMPD_cancel)) >=2152        Parser<OmpDirectiveSpecification>{})))2153 2154TYPE_PARSER(sourced( //2155    construct<OpenMPDepobjConstruct>(2156        predicated(OmpDirectiveNameParser{},2157            IsDirective(llvm::omp::Directive::OMPD_depobj)) >=2158        Parser<OmpDirectiveSpecification>{})))2159 2160// OMP 5.2 14.1 Interop construct2161TYPE_PARSER(sourced( //2162    construct<OpenMPInteropConstruct>(2163        predicated(OmpDirectiveNameParser{},2164            IsDirective(llvm::omp::Directive::OMPD_interop)) >=2165        Parser<OmpDirectiveSpecification>{})))2166 2167// Standalone Constructs2168TYPE_PARSER(2169    sourced( //2170        construct<OpenMPStandaloneConstruct>(2171            Parser<OpenMPSimpleStandaloneConstruct>{}) ||2172        construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||2173        // Try CANCELLATION POINT before CANCEL.2174        construct<OpenMPStandaloneConstruct>(2175            Parser<OpenMPCancellationPointConstruct>{}) ||2176        construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||2177        construct<OpenMPStandaloneConstruct>(2178            Parser<OmpMetadirectiveDirective>{}) ||2179        construct<OpenMPStandaloneConstruct>(Parser<OpenMPDepobjConstruct>{}) ||2180        construct<OpenMPStandaloneConstruct>(2181            Parser<OpenMPInteropConstruct>{})) /2182    endOfLine)2183 2184TYPE_PARSER(construct<OmpInitializerClause>(Parser<OmpInitializerExpression>{}))2185 2186// OpenMP 5.2: 7.5.4 Declare Variant directive2187TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(2188    predicated(Parser<OmpDirectiveName>{},2189        IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >=2190    Parser<OmpDirectiveSpecification>{})))2191 2192// 2.16 Declare Reduction Construct2193TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(2194    predicated(Parser<OmpDirectiveName>{},2195        IsDirective(llvm::omp::Directive::OMPD_declare_reduction)) >=2196    OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{}))))2197 2198// 2.10.6 Declare Target Construct2199TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(2200    predicated(Parser<OmpDirectiveName>{},2201        IsDirective(llvm::omp::Directive::OMPD_declare_target)) >=2202    Parser<OmpDirectiveSpecification>{})))2203 2204static OmpMapperSpecifier ConstructOmpMapperSpecifier(2205    std::optional<Name> &&mapperName, TypeSpec &&typeSpec, Name &&varName) {2206  // If a name is present, parse: name ":" typeSpec "::" name2207  // This matches the syntax: <mapper-name> : <type-spec> :: <variable-name>2208  if (mapperName.has_value() && mapperName->ToString() != "default") {2209    return OmpMapperSpecifier{2210        mapperName->ToString(), std::move(typeSpec), std::move(varName)};2211  }2212  // If the name is missing, use the DerivedTypeSpec name to construct the2213  // default mapper name.2214  // This matches the syntax: <type-spec> :: <variable-name>2215  if (DerivedTypeSpec * derived{std::get_if<DerivedTypeSpec>(&typeSpec.u)}) {2216    return OmpMapperSpecifier{2217        std::get<Name>(derived->t).ToString() + llvm::omp::OmpDefaultMapperName,2218        std::move(typeSpec), std::move(varName)};2219  }2220  return OmpMapperSpecifier{std::string(llvm::omp::OmpDefaultMapperName),2221      std::move(typeSpec), std::move(varName)};2222}2223 2224// mapper-specifier2225TYPE_PARSER(applyFunction<OmpMapperSpecifier>(ConstructOmpMapperSpecifier,2226    maybe(name / ":" / !":"_tok), typeSpec / "::", name))2227 2228// OpenMP 5.2: 5.8.8 Declare Mapper Construct2229TYPE_PARSER(sourced(construct<OpenMPDeclareMapperConstruct>(2230    predicated(Parser<OmpDirectiveName>{},2231        IsDirective(llvm::omp::Directive::OMPD_declare_mapper)) >=2232    Parser<OmpDirectiveSpecification>{})))2233 2234TYPE_PARSER(construct<OmpCombinerExpression>(OmpStylizedExpressionParser{}))2235TYPE_PARSER(construct<OmpInitializerExpression>(OmpStylizedExpressionParser{}))2236 2237TYPE_PARSER(sourced(construct<OpenMPCriticalConstruct>(2238    OmpBlockConstructParser{llvm::omp::Directive::OMPD_critical})))2239 2240// 2.8.2 Declare Simd construct2241TYPE_PARSER(sourced(construct<OpenMPDeclareSimdConstruct>(2242    predicated(Parser<OmpDirectiveName>{},2243        IsDirective(llvm::omp::Directive::OMPD_declare_simd)) >=2244    Parser<OmpDirectiveSpecification>{})))2245 2246TYPE_PARSER(sourced( //2247    construct<OpenMPGroupprivate>(2248        predicated(OmpDirectiveNameParser{},2249            IsDirective(llvm::omp::Directive::OMPD_groupprivate)) >=2250        Parser<OmpDirectiveSpecification>{})))2251 2252// 2.4 Requires construct2253TYPE_PARSER(sourced(construct<OpenMPRequiresConstruct>(2254    predicated(OmpDirectiveNameParser{},2255        IsDirective(llvm::omp::Directive::OMPD_requires)) >=2256    Parser<OmpDirectiveSpecification>{})))2257 2258// 2.15.2 Threadprivate directive2259TYPE_PARSER(sourced( //2260    construct<OpenMPThreadprivate>(2261        predicated(OmpDirectiveNameParser{},2262            IsDirective(llvm::omp::Directive::OMPD_threadprivate)) >=2263        Parser<OmpDirectiveSpecification>{})))2264 2265// Assumes Construct2266TYPE_PARSER(sourced(construct<OpenMPDeclarativeAssumes>(2267    predicated(OmpDirectiveNameParser{},2268        IsDirective(llvm::omp::Directive::OMPD_assumes)) >=2269    Parser<OmpDirectiveSpecification>{})))2270 2271// Declarative constructs2272TYPE_PARSER(2273    startOmpLine >> withMessage("expected OpenMP construct"_err_en_US,2274                        sourced(construct<OpenMPDeclarativeConstruct>(2275                                    Parser<OpenMPDeclarativeAssumes>{}) ||2276                            construct<OpenMPDeclarativeConstruct>(2277                                Parser<OpenMPDeclareReductionConstruct>{}) ||2278                            construct<OpenMPDeclarativeConstruct>(2279                                Parser<OpenMPDeclareMapperConstruct>{}) ||2280                            construct<OpenMPDeclarativeConstruct>(2281                                Parser<OpenMPDeclareSimdConstruct>{}) ||2282                            construct<OpenMPDeclarativeConstruct>(2283                                Parser<OpenMPDeclareTargetConstruct>{}) ||2284                            construct<OpenMPDeclarativeConstruct>(2285                                Parser<OmpDeclareVariantDirective>{}) ||2286                            construct<OpenMPDeclarativeConstruct>(2287                                sourced(OmpDeclarativeAllocateParser{})) ||2288                            construct<OpenMPDeclarativeConstruct>(2289                                Parser<OpenMPGroupprivate>{}) ||2290                            construct<OpenMPDeclarativeConstruct>(2291                                Parser<OpenMPRequiresConstruct>{}) ||2292                            construct<OpenMPDeclarativeConstruct>(2293                                Parser<OpenMPThreadprivate>{}) ||2294                            construct<OpenMPDeclarativeConstruct>(2295                                Parser<OpenMPUtilityConstruct>{}) ||2296                            construct<OpenMPDeclarativeConstruct>(2297                                Parser<OmpMetadirectiveDirective>{})) /2298                            endOmpLine))2299 2300TYPE_PARSER(sourced(construct<OpenMPAssumeConstruct>(2301    OmpBlockConstructParser{llvm::omp::Directive::OMPD_assume})))2302 2303// Block Construct2304#define MakeBlockConstruct(dir) \2305  sourced(construct<OmpBlockConstruct>(OmpBlockConstructParser{dir}))2306TYPE_PARSER( //2307    MakeBlockConstruct(llvm::omp::Directive::OMPD_masked) ||2308    MakeBlockConstruct(llvm::omp::Directive::OMPD_master) ||2309    MakeBlockConstruct(llvm::omp::Directive::OMPD_ordered) ||2310    MakeBlockConstruct(llvm::omp::Directive::OMPD_parallel_masked) ||2311    MakeBlockConstruct(llvm::omp::Directive::OMPD_parallel_master) ||2312    MakeBlockConstruct(llvm::omp::Directive::OMPD_parallel_workshare) ||2313    MakeBlockConstruct(llvm::omp::Directive::OMPD_parallel) ||2314    MakeBlockConstruct(llvm::omp::Directive::OMPD_scope) ||2315    MakeBlockConstruct(llvm::omp::Directive::OMPD_single) ||2316    MakeBlockConstruct(llvm::omp::Directive::OMPD_target_data) ||2317    MakeBlockConstruct(llvm::omp::Directive::OMPD_target_parallel) ||2318    MakeBlockConstruct(llvm::omp::Directive::OMPD_target_teams) ||2319    MakeBlockConstruct(2320        llvm::omp::Directive::OMPD_target_teams_workdistribute) ||2321    MakeBlockConstruct(llvm::omp::Directive::OMPD_target) ||2322    MakeBlockConstruct(llvm::omp::Directive::OMPD_task) ||2323    MakeBlockConstruct(llvm::omp::Directive::OMPD_taskgraph) ||2324    MakeBlockConstruct(llvm::omp::Directive::OMPD_taskgroup) ||2325    MakeBlockConstruct(llvm::omp::Directive::OMPD_teams) ||2326    MakeBlockConstruct(llvm::omp::Directive::OMPD_teams_workdistribute) ||2327    MakeBlockConstruct(llvm::omp::Directive::OMPD_workshare) ||2328    MakeBlockConstruct(llvm::omp::Directive::OMPD_workdistribute))2329#undef MakeBlockConstruct2330 2331// OMP SECTIONS Directive2332static constexpr DirectiveSet GetSectionsDirectives() {2333  using Directive = llvm::omp::Directive;2334  constexpr DirectiveSet sectionsDirectives{2335      unsigned(Directive::OMPD_sections),2336      unsigned(Directive::OMPD_parallel_sections),2337  };2338  return sectionsDirectives;2339}2340 2341// OMP BEGIN and END SECTIONS Directive2342TYPE_PARSER(construct<OmpBeginSectionsDirective>(2343    OmpBeginDirectiveParser(GetSectionsDirectives())))2344 2345TYPE_PARSER(construct<OmpEndSectionsDirective>(2346    OmpEndDirectiveParser(GetSectionsDirectives())))2347 2348static constexpr auto sectionDir{2349    startOmpLine >> (predicated(OmpDirectiveNameParser{},2350                         IsDirective(llvm::omp::Directive::OMPD_section)) >=2351                        Parser<OmpDirectiveSpecification>{})};2352 2353// OMP SECTIONS (OpenMP 5.0 - 2.8.1), PARALLEL SECTIONS (OpenMP 5.0 - 2.13.3)2354TYPE_PARSER(sourced(construct<OpenMPSectionsConstruct>(2355    Parser<OmpBeginSectionsDirective>{} / endOmpLine,2356    cons( //2357        construct<OpenMPConstruct>(sourced(2358            construct<OpenMPSectionConstruct>(maybe(sectionDir), validBlock))),2359        many(construct<OpenMPConstruct>(sourced(2360            construct<OpenMPSectionConstruct>(sectionDir, validBlock))))),2361    maybe(Parser<OmpEndSectionsDirective>{} / endOmpLine))))2362 2363static bool IsExecutionPart(const OmpDirectiveName &name) {2364  return name.IsExecutionPart();2365}2366 2367TYPE_PARSER(construct<OpenMPExecDirective>(2368    startOmpLine >> predicated(Parser<OmpDirectiveName>{}, IsExecutionPart)))2369 2370TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,2371    startOmpLine >>2372        withMessage("expected OpenMP construct"_err_en_US,2373            first(construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}),2374                construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}),2375                construct<OpenMPConstruct>(2376                    sourced(OmpExecutableAllocateParser{})),2377                construct<OpenMPConstruct>(Parser<OmpBlockConstruct>{}),2378                // OmpBlockConstruct is attempted before2379                // OpenMPStandaloneConstruct to resolve !$OMP ORDERED2380                construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}),2381                construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}),2382                construct<OpenMPConstruct>(Parser<OpenMPUtilityConstruct>{}),2383                construct<OpenMPConstruct>(Parser<OpenMPDispatchConstruct>{}),2384                construct<OpenMPConstruct>(Parser<OpenMPAllocatorsConstruct>{}),2385                construct<OpenMPConstruct>(Parser<OpenMPAssumeConstruct>{}),2386                construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}))))2387 2388static constexpr DirectiveSet GetLoopDirectives() {2389  using Directive = llvm::omp::Directive;2390  constexpr DirectiveSet loopDirectives{2391      unsigned(Directive::OMPD_distribute),2392      unsigned(Directive::OMPD_distribute_parallel_do),2393      unsigned(Directive::OMPD_distribute_parallel_do_simd),2394      unsigned(Directive::OMPD_distribute_simd),2395      unsigned(Directive::OMPD_do),2396      unsigned(Directive::OMPD_do_simd),2397      unsigned(Directive::OMPD_loop),2398      unsigned(Directive::OMPD_masked_taskloop),2399      unsigned(Directive::OMPD_masked_taskloop_simd),2400      unsigned(Directive::OMPD_master_taskloop),2401      unsigned(Directive::OMPD_master_taskloop_simd),2402      unsigned(Directive::OMPD_parallel_do),2403      unsigned(Directive::OMPD_parallel_do_simd),2404      unsigned(Directive::OMPD_parallel_masked_taskloop),2405      unsigned(Directive::OMPD_parallel_masked_taskloop_simd),2406      unsigned(Directive::OMPD_parallel_master_taskloop),2407      unsigned(Directive::OMPD_parallel_master_taskloop_simd),2408      unsigned(Directive::OMPD_simd),2409      unsigned(Directive::OMPD_target_loop),2410      unsigned(Directive::OMPD_target_parallel_do),2411      unsigned(Directive::OMPD_target_parallel_do_simd),2412      unsigned(Directive::OMPD_target_parallel_loop),2413      unsigned(Directive::OMPD_target_simd),2414      unsigned(Directive::OMPD_target_teams_distribute),2415      unsigned(Directive::OMPD_target_teams_distribute_parallel_do),2416      unsigned(Directive::OMPD_target_teams_distribute_parallel_do_simd),2417      unsigned(Directive::OMPD_target_teams_distribute_simd),2418      unsigned(Directive::OMPD_target_teams_loop),2419      unsigned(Directive::OMPD_taskloop),2420      unsigned(Directive::OMPD_taskloop_simd),2421      unsigned(Directive::OMPD_teams_distribute),2422      unsigned(Directive::OMPD_teams_distribute_parallel_do),2423      unsigned(Directive::OMPD_teams_distribute_parallel_do_simd),2424      unsigned(Directive::OMPD_teams_distribute_simd),2425      unsigned(Directive::OMPD_teams_loop),2426      unsigned(Directive::OMPD_fuse),2427      unsigned(Directive::OMPD_tile),2428      unsigned(Directive::OMPD_unroll),2429  };2430  return loopDirectives;2431}2432 2433TYPE_PARSER(sourced(construct<OpenMPLoopConstruct>(2434    OmpLoopConstructParser(GetLoopDirectives()))))2435 2436static constexpr DirectiveSet GetAllDirectives() { //2437  return ~DirectiveSet{};2438}2439 2440TYPE_PARSER(construct<OpenMPMisplacedEndDirective>(2441    OmpEndDirectiveParser{GetAllDirectives()}))2442 2443TYPE_PARSER( //2444    startOmpLine >> sourced(construct<OpenMPInvalidDirective>(2445                        !OmpDirectiveNameParser{} >> SkipTo<'\n'>{})))2446} // namespace Fortran::parser2447