https://github.com/kparzysz updated 
https://github.com/llvm/llvm-project/pull/146933

>From 0e9eab649f7a515c0697c3fe58309c478108f6b1 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Wed, 2 Jul 2025 09:43:32 -0500
Subject: [PATCH 01/12] [Frontend][OpenMP] Implement directive name parser

Implement a state machine that consumes tokens (words delimited by white
space), and returns the corresponding directive id, or fails if the tokens
did not form a valid name.
---
 .../Frontend/OpenMP/DirectiveNameParser.h     |  76 ++++++++
 llvm/lib/Frontend/OpenMP/CMakeLists.txt       |   1 +
 .../Frontend/OpenMP/DirectiveNameParser.cpp   |  93 ++++++++++
 llvm/unittests/Frontend/CMakeLists.txt        |   1 +
 .../OpenMPDirectiveNameParserTest.cpp         | 171 ++++++++++++++++++
 5 files changed, 342 insertions(+)
 create mode 100644 llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
 create mode 100644 llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
 create mode 100644 llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp

diff --git a/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h 
b/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
new file mode 100644
index 0000000000000..db8986601b2ca
--- /dev/null
+++ b/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
@@ -0,0 +1,76 @@
+//===- DirectiveNameParser.h  ------------------------------------- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FRONTEND_OPENMP_DIRECTIVENAMEPARSER_H
+#define LLVM_FRONTEND_OPENMP_DIRECTIVENAMEPARSER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Frontend/OpenMP/OMP.h"
+
+#include <memory>
+
+namespace llvm::omp {
+/// Parser class for OpenMP directive names. It only recognizes names listed
+/// in OMP.td, in particular it does not recognize Fortran's end-directives
+/// if they are not explicitly listed in OMP.td.
+///
+/// The class itself may be a singleton, once it's constructed it never
+/// changes.
+///
+/// Usage:
+/// {
+///   DirectiveNameParser Parser;   // Could be static const.
+///
+///   DirectiveNameParser::State *S = Parser.initial();
+///   for (StringRef Token : Tokens)
+///     S = Parser.apply(S, Token); // Passing nullptr is ok.
+///
+///   if (S == nullptr) {
+///     // Error: ended up in a state from which there is no possible path
+///     // to a successful parse.
+///   } else if (S->Value == OMPD_unknown)
+///     // Parsed a sequence of tokens that are not a complete name, but
+///     // parsing more tokens could lead to a successful parse.
+///   } else {
+///     // Success.
+///     ParsedId = S->Value;
+///   }
+/// }
+struct DirectiveNameParser {
+  DirectiveNameParser(SourceLanguage L = SourceLanguage::C);
+
+  struct State {
+    Directive Value = Directive::OMPD_unknown;
+
+  private:
+    using TransitionMapTy = StringMap<State>;
+    std::unique_ptr<TransitionMapTy> Transition;
+
+    State *next(StringRef Tok);
+    bool isValid() const {
+      return Value != Directive::OMPD_unknown || !Transition->empty();
+    }
+    friend struct DirectiveNameParser;
+  };
+
+  const State *initial() const { return &InitialState; }
+  const State *apply(const State *Current, StringRef Tok) const;
+
+  static SmallVector<StringRef> tokenize(StringRef N);
+
+private:
+  void insertName(StringRef Name, Directive D);
+  State *insertTransition(State *From, StringRef Tok);
+
+  State InitialState;
+};
+} // namespace llvm::omp
+
+#endif // LLVM_FRONTEND_OPENMP_DIRECTIVENAMEPARSER_H
diff --git a/llvm/lib/Frontend/OpenMP/CMakeLists.txt 
b/llvm/lib/Frontend/OpenMP/CMakeLists.txt
index 5bf15ca3a8991..e60b59c1203b9 100644
--- a/llvm/lib/Frontend/OpenMP/CMakeLists.txt
+++ b/llvm/lib/Frontend/OpenMP/CMakeLists.txt
@@ -2,6 +2,7 @@ add_llvm_component_library(LLVMFrontendOpenMP
   OMP.cpp
   OMPContext.cpp
   OMPIRBuilder.cpp
+  DirectiveNameParser.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend
diff --git a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp 
b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
new file mode 100644
index 0000000000000..02ff8327a3054
--- /dev/null
+++ b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
@@ -0,0 +1,93 @@
+//===- DirectiveNameParser.cpp 
--------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/OpenMP/DirectiveNameParser.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Frontend/OpenMP/OMP.h"
+
+#include <cassert>
+#include <memory>
+
+namespace llvm::omp {
+DirectiveNameParser::DirectiveNameParser(SourceLanguage L) {
+  // Take every directive, get its name in every version, break the name up
+  // into whitespace-separated tokens, and insert each token.
+  for (size_t I = 0, E = Directive_enumSize; I != E; ++I) {
+    auto D = static_cast<Directive>(I);
+    if (D == Directive::OMPD_unknown || !(getDirectiveLanguages(D) & L))
+      continue;
+    for (unsigned Ver : getOpenMPVersions())
+      insertName(getOpenMPDirectiveName(D, Ver), D);
+  }
+}
+
+const DirectiveNameParser::State *
+DirectiveNameParser::apply(const State *Current, StringRef Tok) const {
+  if (!Current)
+    return Current;
+  assert(Current->isValid() && "Invalid input state");
+  if (const State *Next = const_cast<State *>(Current)->next(Tok))
+    return Next->isValid() ? Next : nullptr;
+  return nullptr;
+}
+
+SmallVector<StringRef> DirectiveNameParser::tokenize(StringRef Str) {
+  SmallVector<StringRef> Tokens;
+
+  auto nextChar = [](StringRef N, size_t I) {
+    while (I < N.size() && N[I] == ' ')
+      ++I;
+    return I;
+  };
+  auto nextSpace = [](StringRef N, size_t I) {
+    size_t S = N.find(' ', I);
+    return S != StringRef::npos ? S : N.size();
+  };
+
+  size_t From = nextChar(Str, 0);
+  size_t To = 0;
+
+  while (From != Str.size()) {
+    To = nextSpace(Str, From);
+    Tokens.push_back(Str.substr(From, To - From));
+    From = nextChar(Str, To);
+  }
+
+  return Tokens;
+}
+
+void DirectiveNameParser::insertName(StringRef Name, Directive D) {
+  State *Where = &InitialState;
+
+  for (StringRef Tok : tokenize(Name))
+    Where = insertTransition(Where, Tok);
+
+  Where->Value = D;
+}
+
+DirectiveNameParser::State *
+DirectiveNameParser::insertTransition(State *From, StringRef Tok) {
+  assert(From && "Expecting state");
+  if (!From->Transition) {
+    From->Transition = std::make_unique<State::TransitionMapTy>();
+  }
+  if (State *Next = From->next(Tok))
+    return Next;
+
+  auto [Where, DidIt] = From->Transition->try_emplace(Tok, State());
+  assert(DidIt && "Map insertion failed");
+  return &Where->second;
+}
+
+DirectiveNameParser::State *DirectiveNameParser::State::next(StringRef Tok) {
+  if (!Transition)
+    return nullptr;
+  auto F = Transition->find(Tok);
+  return F != Transition->end() ? &F->second : nullptr;
+}
+} // namespace llvm::omp
diff --git a/llvm/unittests/Frontend/CMakeLists.txt 
b/llvm/unittests/Frontend/CMakeLists.txt
index 2412cc9d26c7a..281d509227a46 100644
--- a/llvm/unittests/Frontend/CMakeLists.txt
+++ b/llvm/unittests/Frontend/CMakeLists.txt
@@ -20,6 +20,7 @@ add_llvm_unittest(LLVMFrontendTests
   OpenMPCompositionTest.cpp
   OpenMPDecompositionTest.cpp
   OpenMPDirectiveNameTest.cpp
+  OpenMPDirectiveNameParserTest.cpp
 
   DEPENDS
   acc_gen
diff --git a/llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp 
b/llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp
new file mode 100644
index 0000000000000..11fef684dec4c
--- /dev/null
+++ b/llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp
@@ -0,0 +1,171 @@
+//===- llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp 
----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Sequence.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Frontend/OpenMP/DirectiveNameParser.h"
+#include "llvm/Frontend/OpenMP/OMP.h"
+#include "gtest/gtest.h"
+
+#include <cctype>
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <vector>
+
+using namespace llvm;
+
+static const omp::DirectiveNameParser &getParser() {
+  static omp::DirectiveNameParser Parser(omp::SourceLanguage::C |
+                                         omp::SourceLanguage::Fortran);
+  return Parser;
+}
+
+static std::vector<std::string> tokenize(StringRef S) {
+  std::vector<std::string> Tokens;
+
+  using TokenIterator = std::istream_iterator<std::string>;
+  std::string Copy = S.str();
+  std::istringstream Stream(Copy);
+
+  for (auto I = TokenIterator(Stream), E = TokenIterator(); I != E; ++I)
+    Tokens.push_back(*I);
+  return Tokens;
+}
+
+static std::string &prepareParamName(std::string &Name) {
+  for (size_t I = 0, E = Name.size(); I != E; ++I) {
+    // The parameter name must only have alphanumeric characters.
+    if (!isalnum(Name[I]))
+      Name[I] = 'X';
+  }
+  return Name;
+}
+
+namespace llvm {
+template <> struct enum_iteration_traits<omp::Directive> {
+  static constexpr bool is_iterable = true;
+};
+} // namespace llvm
+
+// Test tokenizing.
+
+class Tokenize : public testing::TestWithParam<omp::Directive> {};
+
+static bool isEqual(const SmallVector<StringRef> &A,
+                    const std::vector<std::string> &B) {
+  if (A.size() != B.size())
+    return false;
+
+  for (size_t I = 0, E = A.size(); I != E; ++I) {
+    if (A[I] != StringRef(B[I]))
+      return false;
+  }
+  return true;
+}
+
+TEST_P(Tokenize, T) {
+  omp::Directive DirId = GetParam();
+  StringRef Name = omp::getOpenMPDirectiveName(DirId, omp::FallbackVersion);
+
+  SmallVector<StringRef> tokens1 = omp::DirectiveNameParser::tokenize(Name);
+  std::vector<std::string> tokens2 = tokenize(Name);
+  ASSERT_TRUE(isEqual(tokens1, tokens2));
+}
+
+static std::string
+getParamName1(const testing::TestParamInfo<Tokenize::ParamType> &Info) {
+  omp::Directive DirId = Info.param;
+  std::string Name =
+      omp::getOpenMPDirectiveName(DirId, omp::FallbackVersion).str();
+  return prepareParamName(Name);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    DirectiveNameParserTest, Tokenize,
+    testing::ValuesIn(
+        llvm::enum_seq(static_cast<omp::Directive>(0),
+                       static_cast<omp::Directive>(omp::Directive_enumSize))),
+    getParamName1);
+
+// Test parsing of valid names.
+
+using ValueType = std::tuple<omp::Directive, unsigned>;
+
+class ParseValid : public testing::TestWithParam<ValueType> {};
+
+TEST_P(ParseValid, T) {
+  auto [DirId, Version] = GetParam();
+  if (DirId == omp::Directive::OMPD_unknown)
+    return;
+
+  std::string Name = omp::getOpenMPDirectiveName(DirId, Version).str();
+
+  // Tokenize and parse
+  auto &Parser = getParser();
+  auto *State = Parser.initial();
+  ASSERT_TRUE(State != nullptr);
+
+  std::vector<std::string> Tokens = tokenize(Name);
+  for (auto &Tok : Tokens) {
+    State = Parser.apply(State, Tok);
+    ASSERT_TRUE(State != nullptr);
+  }
+
+  ASSERT_EQ(State->Value, DirId);
+}
+
+static std::string
+getParamName2(const testing::TestParamInfo<ParseValid::ParamType> &Info) {
+  auto [DirId, Version] = Info.param;
+  std::string Name = omp::getOpenMPDirectiveName(DirId, Version).str() + "v" +
+                     std::to_string(Version);
+  return prepareParamName(Name);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    DirectiveNameParserTest, ParseValid,
+    testing::Combine(testing::ValuesIn(llvm::enum_seq(
+                         static_cast<omp::Directive>(0),
+                         
static_cast<omp::Directive>(omp::Directive_enumSize))),
+                     testing::ValuesIn(omp::getOpenMPVersions())),
+    getParamName2);
+
+// Test parsing of invalid names
+
+class ParseInvalid : public testing::TestWithParam<std::string> {};
+
+TEST_P(ParseInvalid, T) {
+  std::string Name = GetParam();
+
+  auto &Parser = getParser();
+  auto *State = Parser.initial();
+  ASSERT_TRUE(State != nullptr);
+
+  std::vector<std::string> Tokens = tokenize(Name);
+  for (auto &Tok : Tokens)
+    State = Parser.apply(State, Tok);
+
+  ASSERT_TRUE(State == nullptr || State->Value == 
omp::Directive::OMPD_unknown);
+}
+
+namespace {
+using namespace std;
+
+INSTANTIATE_TEST_SUITE_P(DirectiveNameParserTest, ParseInvalid,
+                         testing::Values(
+                             // Names that contain invalid tokens
+                             "bad"s, "target teams invalid"s,
+                             "target sections parallel"s,
+                             "target teams distribute parallel for wrong"s,
+                             // Valid beginning, but not a complete name
+                             "begin declare"s,
+                             // Complete name with extra tokens
+                             "distribute simd target"s));
+} // namespace

>From ab3f0cc9d240f12e07be452effa75b5c7d010d9b Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Wed, 2 Jul 2025 11:25:00 -0500
Subject: [PATCH 02/12] [clang][OpenMP] Use DirectiveNameParser to parse
 directive names

This simplifies the parsing code in clang quite a bit.
---
 clang/lib/Parse/ParseOpenMP.cpp | 181 ++++----------------------------
 1 file changed, 19 insertions(+), 162 deletions(-)

diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index f694ae1d0d112..c0a17d0e9537d 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -25,6 +25,7 @@
 #include "clang/Sema/SemaOpenMP.h"
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/Frontend/OpenMP/DirectiveNameParser.h"
 #include "llvm/Frontend/OpenMP/OMPAssume.h"
 #include "llvm/Frontend/OpenMP/OMPContext.h"
 #include <optional>
@@ -37,48 +38,6 @@ using namespace llvm::omp;
 
//===----------------------------------------------------------------------===//
 
 namespace {
-enum OpenMPDirectiveKindEx {
-  OMPD_cancellation = llvm::omp::Directive_enumSize + 1,
-  OMPD_data,
-  OMPD_declare,
-  OMPD_end,
-  OMPD_end_declare,
-  OMPD_enter,
-  OMPD_exit,
-  OMPD_point,
-  OMPD_reduction,
-  OMPD_target_enter,
-  OMPD_target_exit,
-  OMPD_update,
-  OMPD_distribute_parallel,
-  OMPD_teams_distribute_parallel,
-  OMPD_target_teams_distribute_parallel,
-  OMPD_mapper,
-  OMPD_variant,
-  OMPD_begin,
-  OMPD_begin_declare,
-};
-
-// Helper to unify the enum class OpenMPDirectiveKind with its extension
-// the OpenMPDirectiveKindEx enum which allows to use them together as if they
-// are unsigned values.
-struct OpenMPDirectiveKindExWrapper {
-  OpenMPDirectiveKindExWrapper(unsigned Value) : Value(Value) {}
-  OpenMPDirectiveKindExWrapper(OpenMPDirectiveKind DK) : Value(unsigned(DK)) {}
-  bool operator==(OpenMPDirectiveKindExWrapper V) const {
-    return Value == V.Value;
-  }
-  bool operator!=(OpenMPDirectiveKindExWrapper V) const {
-    return Value != V.Value;
-  }
-  bool operator==(OpenMPDirectiveKind V) const { return Value == unsigned(V); }
-  bool operator!=(OpenMPDirectiveKind V) const { return Value != unsigned(V); }
-  bool operator<(OpenMPDirectiveKind V) const { return Value < unsigned(V); }
-  operator unsigned() const { return Value; }
-  operator OpenMPDirectiveKind() const { return OpenMPDirectiveKind(Value); }
-  unsigned Value;
-};
-
 class DeclDirectiveListParserHelper final {
   SmallVector<Expr *, 4> Identifiers;
   Parser *P;
@@ -97,130 +56,32 @@ class DeclDirectiveListParserHelper final {
 };
 } // namespace
 
-// Map token string to extended OMP token kind that are
-// OpenMPDirectiveKind + OpenMPDirectiveKindEx.
-static unsigned getOpenMPDirectiveKindEx(StringRef S) {
-  OpenMPDirectiveKindExWrapper DKind = getOpenMPDirectiveKind(S);
-  if (DKind != OMPD_unknown)
-    return DKind;
-
-  return llvm::StringSwitch<OpenMPDirectiveKindExWrapper>(S)
-      .Case("cancellation", OMPD_cancellation)
-      .Case("data", OMPD_data)
-      .Case("declare", OMPD_declare)
-      .Case("end", OMPD_end)
-      .Case("enter", OMPD_enter)
-      .Case("exit", OMPD_exit)
-      .Case("point", OMPD_point)
-      .Case("reduction", OMPD_reduction)
-      .Case("update", OMPD_update)
-      .Case("mapper", OMPD_mapper)
-      .Case("variant", OMPD_variant)
-      .Case("begin", OMPD_begin)
-      .Default(OMPD_unknown);
-}
+static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) {
+  static const DirectiveNameParser DNP;
+
+  const DirectiveNameParser::State *S = DNP.initial();
 
-static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) {
-  // Array of foldings: F[i][0] F[i][1] ===> F[i][2].
-  // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
-  // TODO: add other combined directives in topological order.
-  static const OpenMPDirectiveKindExWrapper F[][3] = {
-      {OMPD_begin, OMPD_declare, OMPD_begin_declare},
-      {OMPD_begin, OMPD_assumes, OMPD_begin_assumes},
-      {OMPD_end, OMPD_declare, OMPD_end_declare},
-      {OMPD_end, OMPD_assumes, OMPD_end_assumes},
-      {OMPD_cancellation, OMPD_point, OMPD_cancellation_point},
-      {OMPD_declare, OMPD_reduction, OMPD_declare_reduction},
-      {OMPD_declare, OMPD_mapper, OMPD_declare_mapper},
-      {OMPD_declare, OMPD_simd, OMPD_declare_simd},
-      {OMPD_declare, OMPD_target, OMPD_declare_target},
-      {OMPD_declare, OMPD_variant, OMPD_declare_variant},
-      {OMPD_begin_declare, OMPD_target, OMPD_begin_declare_target},
-      {OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant},
-      {OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant},
-      {OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel},
-      {OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for},
-      {OMPD_distribute_parallel_for, OMPD_simd,
-       OMPD_distribute_parallel_for_simd},
-      {OMPD_distribute, OMPD_simd, OMPD_distribute_simd},
-      {OMPD_end_declare, OMPD_target, OMPD_end_declare_target},
-      {OMPD_target, OMPD_data, OMPD_target_data},
-      {OMPD_target, OMPD_enter, OMPD_target_enter},
-      {OMPD_target, OMPD_exit, OMPD_target_exit},
-      {OMPD_target, OMPD_update, OMPD_target_update},
-      {OMPD_target_enter, OMPD_data, OMPD_target_enter_data},
-      {OMPD_target_exit, OMPD_data, OMPD_target_exit_data},
-      {OMPD_for, OMPD_simd, OMPD_for_simd},
-      {OMPD_parallel, OMPD_for, OMPD_parallel_for},
-      {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd},
-      {OMPD_parallel, OMPD_loop, OMPD_parallel_loop},
-      {OMPD_parallel, OMPD_sections, OMPD_parallel_sections},
-      {OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd},
-      {OMPD_target, OMPD_parallel, OMPD_target_parallel},
-      {OMPD_target, OMPD_simd, OMPD_target_simd},
-      {OMPD_target_parallel, OMPD_loop, OMPD_target_parallel_loop},
-      {OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for},
-      {OMPD_target_parallel_for, OMPD_simd, OMPD_target_parallel_for_simd},
-      {OMPD_teams, OMPD_distribute, OMPD_teams_distribute},
-      {OMPD_teams_distribute, OMPD_simd, OMPD_teams_distribute_simd},
-      {OMPD_teams_distribute, OMPD_parallel, OMPD_teams_distribute_parallel},
-      {OMPD_teams_distribute_parallel, OMPD_for,
-       OMPD_teams_distribute_parallel_for},
-      {OMPD_teams_distribute_parallel_for, OMPD_simd,
-       OMPD_teams_distribute_parallel_for_simd},
-      {OMPD_teams, OMPD_loop, OMPD_teams_loop},
-      {OMPD_target, OMPD_teams, OMPD_target_teams},
-      {OMPD_target_teams, OMPD_distribute, OMPD_target_teams_distribute},
-      {OMPD_target_teams, OMPD_loop, OMPD_target_teams_loop},
-      {OMPD_target_teams_distribute, OMPD_parallel,
-       OMPD_target_teams_distribute_parallel},
-      {OMPD_target_teams_distribute, OMPD_simd,
-       OMPD_target_teams_distribute_simd},
-      {OMPD_target_teams_distribute_parallel, OMPD_for,
-       OMPD_target_teams_distribute_parallel_for},
-      {OMPD_target_teams_distribute_parallel_for, OMPD_simd,
-       OMPD_target_teams_distribute_parallel_for_simd},
-      {OMPD_master, OMPD_taskloop, OMPD_master_taskloop},
-      {OMPD_masked, OMPD_taskloop, OMPD_masked_taskloop},
-      {OMPD_master_taskloop, OMPD_simd, OMPD_master_taskloop_simd},
-      {OMPD_masked_taskloop, OMPD_simd, OMPD_masked_taskloop_simd},
-      {OMPD_parallel, OMPD_master, OMPD_parallel_master},
-      {OMPD_parallel, OMPD_masked, OMPD_parallel_masked},
-      {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop},
-      {OMPD_parallel_masked, OMPD_taskloop, OMPD_parallel_masked_taskloop},
-      {OMPD_parallel_master_taskloop, OMPD_simd,
-       OMPD_parallel_master_taskloop_simd},
-      {OMPD_parallel_masked_taskloop, OMPD_simd,
-       OMPD_parallel_masked_taskloop_simd}};
-  enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 };
   Token Tok = P.getCurToken();
-  OpenMPDirectiveKindExWrapper DKind =
-      Tok.isAnnotation()
-          ? static_cast<unsigned>(OMPD_unknown)
-          : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));
-  if (DKind == OMPD_unknown)
+  if (Tok.isAnnotation())
     return OMPD_unknown;
 
-  for (const auto &I : F) {
-    if (DKind != I[0])
-      continue;
+  S = DNP.apply(S, P.getPreprocessor().getSpelling(Tok));
+  if (S == nullptr)
+    return OMPD_unknown;
 
+  while (!Tok.isAnnotation()) {
+    OpenMPDirectiveKind DKind = S->Value;
     Tok = P.getPreprocessor().LookAhead(0);
-    OpenMPDirectiveKindExWrapper SDKind =
-        Tok.isAnnotation()
-            ? static_cast<unsigned>(OMPD_unknown)
-            : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));
-    if (SDKind == OMPD_unknown)
-      continue;
-
-    if (SDKind == I[1]) {
+    if (!Tok.isAnnotation()) {
+      S = DNP.apply(S, P.getPreprocessor().getSpelling(Tok));
+      if (S == nullptr)
+        return DKind;
       P.ConsumeToken();
-      DKind = I[2];
     }
   }
-  return unsigned(DKind) < llvm::omp::Directive_enumSize
-             ? static_cast<OpenMPDirectiveKind>(DKind)
-             : OMPD_unknown;
+
+  assert(S && "Should have exited early");
+  return S->Value;
 }
 
 static DeclarationName parseOpenMPReductionId(Parser &P) {
@@ -2629,10 +2490,6 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
     Diag(Tok, diag::err_omp_unknown_directive);
     return StmtError();
   }
-  if (!(getDirectiveLanguages(DKind) & SourceLanguage::C)) {
-    // Treat directives that are not allowed in C/C++ as unknown.
-    DKind = OMPD_unknown;
-  }
 
   StmtResult Directive = StmtError();
 
@@ -4014,7 +3871,7 @@ OMPClause 
*Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,
     KLoc.push_back(Tok.getLocation());
     TentativeParsingAction TPA(*this);
     auto DK = parseOpenMPDirectiveKind(*this);
-    Arg.push_back(DK);
+    Arg.push_back(static_cast<unsigned>(DK));
     if (DK != OMPD_unknown) {
       ConsumeToken();
       if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) {

>From f49ba8b84a8218e52c09713be49a4a04bfa36920 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Wed, 2 Jul 2025 16:49:32 -0500
Subject: [PATCH 03/12] Use llvm::seq

---
 llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp 
b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
index 02ff8327a3054..b560858b44df6 100644
--- a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
+++ b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
@@ -7,6 +7,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "llvm/Frontend/OpenMP/DirectiveNameParser.h"
+#include "llvm/ADT/Sequence.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Frontend/OpenMP/OMP.h"
 
@@ -17,7 +18,7 @@ namespace llvm::omp {
 DirectiveNameParser::DirectiveNameParser(SourceLanguage L) {
   // Take every directive, get its name in every version, break the name up
   // into whitespace-separated tokens, and insert each token.
-  for (size_t I = 0, E = Directive_enumSize; I != E; ++I) {
+  for (size_t I : llvm::seq<size_t>(Directive_enumSize)) {
     auto D = static_cast<Directive>(I);
     if (D == Directive::OMPD_unknown || !(getDirectiveLanguages(D) & L))
       continue;

>From 538cfcdd285c34d08ff6a67253e20343547982f1 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Wed, 2 Jul 2025 16:49:36 -0500
Subject: [PATCH 04/12] Add const version of next()

---
 .../include/llvm/Frontend/OpenMP/DirectiveNameParser.h |  1 +
 llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp       | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h 
b/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
index db8986601b2ca..9996375c9023e 100644
--- a/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
+++ b/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
@@ -54,6 +54,7 @@ struct DirectiveNameParser {
     std::unique_ptr<TransitionMapTy> Transition;
 
     State *next(StringRef Tok);
+    const State *next(StringRef Tok) const;
     bool isValid() const {
       return Value != Directive::OMPD_unknown || !Transition->empty();
     }
diff --git a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp 
b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
index b560858b44df6..4aaf25cc32e05 100644
--- a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
+++ b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
@@ -32,7 +32,7 @@ DirectiveNameParser::apply(const State *Current, StringRef 
Tok) const {
   if (!Current)
     return Current;
   assert(Current->isValid() && "Invalid input state");
-  if (const State *Next = const_cast<State *>(Current)->next(Tok))
+  if (const State *Next = Current->next(Tok))
     return Next->isValid() ? Next : nullptr;
   return nullptr;
 }
@@ -85,6 +85,14 @@ DirectiveNameParser::insertTransition(State *From, StringRef 
Tok) {
   return &Where->second;
 }
 
+const DirectiveNameParser::State *
+DirectiveNameParser::State::next(StringRef Tok) const {
+  if (!Transition)
+    return nullptr;
+  auto F = Transition->find(Tok);
+  return F != Transition->end() ? &F->second : nullptr;
+}
+
 DirectiveNameParser::State *DirectiveNameParser::State::next(StringRef Tok) {
   if (!Transition)
     return nullptr;

>From 9d35e461829665e3eb1d9c4cc03548b02b2c0925 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Wed, 2 Jul 2025 16:52:09 -0500
Subject: [PATCH 05/12] Add missing brace in comment

---
 llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h 
b/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
index 9996375c9023e..b1ff34c003295 100644
--- a/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
+++ b/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
@@ -35,7 +35,7 @@ namespace llvm::omp {
 ///   if (S == nullptr) {
 ///     // Error: ended up in a state from which there is no possible path
 ///     // to a successful parse.
-///   } else if (S->Value == OMPD_unknown)
+///   } else if (S->Value == OMPD_unknown) {
 ///     // Parsed a sequence of tokens that are not a complete name, but
 ///     // parsing more tokens could lead to a successful parse.
 ///   } else {

>From 5d2a8a367eb4e13b298897f85120e785dd97e39b Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Thu, 3 Jul 2025 10:03:58 -0500
Subject: [PATCH 06/12] Rename apply to consume

---
 llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h   | 4 ++--
 llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp          | 2 +-
 llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h 
b/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
index b1ff34c003295..898c32aa4b8f2 100644
--- a/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
+++ b/llvm/include/llvm/Frontend/OpenMP/DirectiveNameParser.h
@@ -30,7 +30,7 @@ namespace llvm::omp {
 ///
 ///   DirectiveNameParser::State *S = Parser.initial();
 ///   for (StringRef Token : Tokens)
-///     S = Parser.apply(S, Token); // Passing nullptr is ok.
+///     S = Parser.consume(S, Token); // Passing nullptr is ok.
 ///
 ///   if (S == nullptr) {
 ///     // Error: ended up in a state from which there is no possible path
@@ -62,7 +62,7 @@ struct DirectiveNameParser {
   };
 
   const State *initial() const { return &InitialState; }
-  const State *apply(const State *Current, StringRef Tok) const;
+  const State *consume(const State *Current, StringRef Tok) const;
 
   static SmallVector<StringRef> tokenize(StringRef N);
 
diff --git a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp 
b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
index 4aaf25cc32e05..037ffe2c13f1e 100644
--- a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
+++ b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
@@ -28,7 +28,7 @@ DirectiveNameParser::DirectiveNameParser(SourceLanguage L) {
 }
 
 const DirectiveNameParser::State *
-DirectiveNameParser::apply(const State *Current, StringRef Tok) const {
+DirectiveNameParser::consume(const State *Current, StringRef Tok) const {
   if (!Current)
     return Current;
   assert(Current->isValid() && "Invalid input state");
diff --git a/llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp 
b/llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp
index 11fef684dec4c..0363a08cc0f03 100644
--- a/llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp
@@ -114,7 +114,7 @@ TEST_P(ParseValid, T) {
 
   std::vector<std::string> Tokens = tokenize(Name);
   for (auto &Tok : Tokens) {
-    State = Parser.apply(State, Tok);
+    State = Parser.consume(State, Tok);
     ASSERT_TRUE(State != nullptr);
   }
 
@@ -150,7 +150,7 @@ TEST_P(ParseInvalid, T) {
 
   std::vector<std::string> Tokens = tokenize(Name);
   for (auto &Tok : Tokens)
-    State = Parser.apply(State, Tok);
+    State = Parser.consume(State, Tok);
 
   ASSERT_TRUE(State == nullptr || State->Value == 
omp::Directive::OMPD_unknown);
 }

>From cde46dc3d14d224c4f4f1ec9ef8eafb4d9d12828 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Thu, 3 Jul 2025 10:04:23 -0500
Subject: [PATCH 07/12] Use isspace instead of ' '

---
 .../Frontend/OpenMP/DirectiveNameParser.cpp    | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp 
b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
index 037ffe2c13f1e..d42a3e98adb37 100644
--- a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
+++ b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
@@ -12,6 +12,7 @@
 #include "llvm/Frontend/OpenMP/OMP.h"
 
 #include <cassert>
+#include <cctype>
 #include <memory>
 
 namespace llvm::omp {
@@ -40,23 +41,24 @@ DirectiveNameParser::consume(const State *Current, 
StringRef Tok) const {
 SmallVector<StringRef> DirectiveNameParser::tokenize(StringRef Str) {
   SmallVector<StringRef> Tokens;
 
-  auto nextChar = [](StringRef N, size_t I) {
-    while (I < N.size() && N[I] == ' ')
+  auto NextChar = [](StringRef N, size_t I) {
+    while (I < N.size() && isspace(N[I]))
       ++I;
     return I;
   };
-  auto nextSpace = [](StringRef N, size_t I) {
-    size_t S = N.find(' ', I);
-    return S != StringRef::npos ? S : N.size();
+  auto NextSpace = [](StringRef N, size_t I) {
+    while (I < N.size() && !isspace(N[I]))
+      ++I;
+    return I;
   };
 
-  size_t From = nextChar(Str, 0);
+  size_t From = NextChar(Str, 0);
   size_t To = 0;
 
   while (From != Str.size()) {
-    To = nextSpace(Str, From);
+    To = NextSpace(Str, From);
     Tokens.push_back(Str.substr(From, To - From));
-    From = nextChar(Str, To);
+    From = NextChar(Str, To);
   }
 
   return Tokens;

>From e86ac032518655d19f0f5b00d6987a20edbf42ba Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Thu, 3 Jul 2025 10:40:35 -0500
Subject: [PATCH 08/12] Use StringSplit

---
 .../Frontend/OpenMP/DirectiveNameParser.cpp   | 24 ++-----------------
 1 file changed, 2 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp 
b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
index d42a3e98adb37..2246fed78aa72 100644
--- a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
+++ b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
@@ -8,11 +8,11 @@
 
 #include "llvm/Frontend/OpenMP/DirectiveNameParser.h"
 #include "llvm/ADT/Sequence.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Frontend/OpenMP/OMP.h"
 
 #include <cassert>
-#include <cctype>
 #include <memory>
 
 namespace llvm::omp {
@@ -40,27 +40,7 @@ DirectiveNameParser::consume(const State *Current, StringRef 
Tok) const {
 
 SmallVector<StringRef> DirectiveNameParser::tokenize(StringRef Str) {
   SmallVector<StringRef> Tokens;
-
-  auto NextChar = [](StringRef N, size_t I) {
-    while (I < N.size() && isspace(N[I]))
-      ++I;
-    return I;
-  };
-  auto NextSpace = [](StringRef N, size_t I) {
-    while (I < N.size() && !isspace(N[I]))
-      ++I;
-    return I;
-  };
-
-  size_t From = NextChar(Str, 0);
-  size_t To = 0;
-
-  while (From != Str.size()) {
-    To = NextSpace(Str, From);
-    Tokens.push_back(Str.substr(From, To - From));
-    From = NextChar(Str, To);
-  }
-
+  SplitString(Str, Tokens);
   return Tokens;
 }
 

>From 2768326ecd62c2831cda66f1123f302c377fe79d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Thu, 3 Jul 2025 10:42:06 -0500
Subject: [PATCH 09/12] Remove {} around single statement

---
 llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp 
b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
index 2246fed78aa72..62e24825111f6 100644
--- a/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
+++ b/llvm/lib/Frontend/OpenMP/DirectiveNameParser.cpp
@@ -56,9 +56,8 @@ void DirectiveNameParser::insertName(StringRef Name, 
Directive D) {
 DirectiveNameParser::State *
 DirectiveNameParser::insertTransition(State *From, StringRef Tok) {
   assert(From && "Expecting state");
-  if (!From->Transition) {
+  if (!From->Transition)
     From->Transition = std::make_unique<State::TransitionMapTy>();
-  }
   if (State *Next = From->next(Tok))
     return Next;
 

>From ca31af4bbb783cbecab3d4c7af3c2f240e435fc1 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Thu, 3 Jul 2025 11:16:03 -0500
Subject: [PATCH 10/12] Use consume instead ofof apply

---
 clang/lib/Parse/ParseOpenMP.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index c0a17d0e9537d..c3c6149d9de1a 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -65,7 +65,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser 
&P) {
   if (Tok.isAnnotation())
     return OMPD_unknown;
 
-  S = DNP.apply(S, P.getPreprocessor().getSpelling(Tok));
+  S = DNP.consume(S, P.getPreprocessor().getSpelling(Tok));
   if (S == nullptr)
     return OMPD_unknown;
 
@@ -73,7 +73,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser 
&P) {
     OpenMPDirectiveKind DKind = S->Value;
     Tok = P.getPreprocessor().LookAhead(0);
     if (!Tok.isAnnotation()) {
-      S = DNP.apply(S, P.getPreprocessor().getSpelling(Tok));
+      S = DNP.consume(S, P.getPreprocessor().getSpelling(Tok));
       if (S == nullptr)
         return DKind;
       P.ConsumeToken();

>From 49ef393290309ea9c0caed965b0b182c02356529 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Thu, 3 Jul 2025 12:18:55 -0500
Subject: [PATCH 11/12] Rename DNP to DirParser

---
 clang/lib/Parse/ParseOpenMP.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index c3c6149d9de1a..5256d08259b60 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -57,15 +57,15 @@ class DeclDirectiveListParserHelper final {
 } // namespace
 
 static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) {
-  static const DirectiveNameParser DNP;
+  static const DirectiveNameParser DirParser;
 
-  const DirectiveNameParser::State *S = DNP.initial();
+  const DirectiveNameParser::State *S = DirParser.initial();
 
   Token Tok = P.getCurToken();
   if (Tok.isAnnotation())
     return OMPD_unknown;
 
-  S = DNP.consume(S, P.getPreprocessor().getSpelling(Tok));
+  S = DirParser.consume(S, P.getPreprocessor().getSpelling(Tok));
   if (S == nullptr)
     return OMPD_unknown;
 
@@ -73,7 +73,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser 
&P) {
     OpenMPDirectiveKind DKind = S->Value;
     Tok = P.getPreprocessor().LookAhead(0);
     if (!Tok.isAnnotation()) {
-      S = DNP.consume(S, P.getPreprocessor().getSpelling(Tok));
+      S = DirParser.consume(S, P.getPreprocessor().getSpelling(Tok));
       if (S == nullptr)
         return DKind;
       P.ConsumeToken();

>From 5ad103e08e8a06cfc3708ba83601e073a022bb7e Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com>
Date: Wed, 2 Jul 2025 12:49:04 -0500
Subject: [PATCH 12/12] [clang][OpenMP] Issue a warning when parsing future
 directive spelling

OpenMP 6.0 introduced alternative spelling for some directives, with the
previous spellings still being allowed.

Warn the user when a new spelling is encountered with OpenMP version set
to an older value.
---
 clang/include/clang/Basic/DiagnosticGroups.td |  4 +-
 .../clang/Basic/DiagnosticParseKinds.td       |  3 +
 clang/lib/Parse/ParseOpenMP.cpp               | 28 ++++++++--
 .../test/OpenMP/openmp-6-future-spellings.cpp | 55 +++++++++++++++++++
 4 files changed, 85 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/OpenMP/openmp-6-future-spellings.cpp

diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 36fa3227fd6a6..ace8663b73a4a 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1530,9 +1530,11 @@ def OpenMPPre51Compat : 
DiagGroup<"pre-openmp-51-compat">;
 def OpenMP51Ext : DiagGroup<"openmp-51-extensions">;
 def OpenMPExtensions : DiagGroup<"openmp-extensions">;
 def OpenMPTargetException : DiagGroup<"openmp-target-exception">;
+def OpenMPFuture : DiagGroup<"openmp-future">;
 def OpenMP : DiagGroup<"openmp", [
     SourceUsesOpenMP, OpenMPClauses, OpenMPLoopForm, OpenMPTarget,
-    OpenMPMapping, OpenMP51Ext, OpenMPExtensions, OpenMPTargetException
+    OpenMPMapping, OpenMP51Ext, OpenMPExtensions, OpenMPTargetException,
+    OpenMPFuture
   ]>;
 
 // OpenACC warnings.
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 6c30da376dafb..87eb2b724b297 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1488,6 +1488,9 @@ def err_omp_multiple_step_or_linear_modifier : Error<
   "multiple %select{'step size'|'linear modifier'}0 found in linear clause">;
 def err_omp_deprecate_old_syntax: Error<
   "old syntax '%0' on '%1' clause was deprecated, use new syntax '%2'">;
+def warn_omp_future_directive_spelling: Warning<
+  "directive spelling '%0' is introduced in a later OpenMP version">,
+  InGroup<OpenMPFuture>;
 def warn_pragma_expected_colon_r_paren : Warning<
   "missing ':' or ')' after %0 - ignoring">, InGroup<IgnoredPragmas>;
 def err_omp_unknown_directive : Error<
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 5256d08259b60..cb9eb3304c317 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -56,6 +56,21 @@ class DeclDirectiveListParserHelper final {
 };
 } // namespace
 
+static OpenMPDirectiveKind checkOpenMPDirectiveName(Parser &P,
+                                                    SourceLocation Loc,
+                                                    OpenMPDirectiveKind Kind,
+                                                    StringRef Name) {
+  unsigned Version = P.getLangOpts().OpenMP;
+  auto [D, VR] = getOpenMPDirectiveKindAndVersions(Name);
+  assert(D == Kind && "Directive kind mismatch");
+  // Ignore the case Version > VR.Max: In OpenMP 6.0 all prior spellings
+  // are explicitly allowed.
+  if (Version < VR.Min)
+    P.Diag(Loc, diag::warn_omp_future_directive_spelling) << Name;
+
+  return Kind;
+}
+
 static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) {
   static const DirectiveNameParser DirParser;
 
@@ -65,7 +80,10 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser 
&P) {
   if (Tok.isAnnotation())
     return OMPD_unknown;
 
-  S = DirParser.consume(S, P.getPreprocessor().getSpelling(Tok));
+  std::string Concat = P.getPreprocessor().getSpelling(Tok);
+  SourceLocation Loc = Tok.getLocation();
+
+  S = DirParser.consume(S, Concat);
   if (S == nullptr)
     return OMPD_unknown;
 
@@ -73,15 +91,17 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser 
&P) {
     OpenMPDirectiveKind DKind = S->Value;
     Tok = P.getPreprocessor().LookAhead(0);
     if (!Tok.isAnnotation()) {
-      S = DirParser.consume(S, P.getPreprocessor().getSpelling(Tok));
+      std::string TS = P.getPreprocessor().getSpelling(Tok);
+      S = DirParser.consume(S, TS);
       if (S == nullptr)
-        return DKind;
+        return checkOpenMPDirectiveName(P, Loc, DKind, Concat);
+      Concat += ' ' + TS;
       P.ConsumeToken();
     }
   }
 
   assert(S && "Should have exited early");
-  return S->Value;
+  return checkOpenMPDirectiveName(P, Loc, S->Value, Concat);
 }
 
 static DeclarationName parseOpenMPReductionId(Parser &P) {
diff --git a/clang/test/OpenMP/openmp-6-future-spellings.cpp 
b/clang/test/OpenMP/openmp-6-future-spellings.cpp
new file mode 100644
index 0000000000000..642ed3502d475
--- /dev/null
+++ b/clang/test/OpenMP/openmp-6-future-spellings.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=52 -ferror-limit 100 -o - 
%s
+
+// expected-warning@+1 {{directive spelling 'begin declare_target' is 
introduced in a later OpenMP version}}
+#pragma omp begin declare_target
+void f0();
+// expected-warning@+1 {{directive spelling 'end declare_target' is introduced 
in a later OpenMP version}}
+#pragma omp end declare_target
+
+// expected-warning@+1 {{directive spelling 'begin declare_variant' is 
introduced in a later OpenMP version}}
+#pragma omp begin declare_variant match(user={condition(true)})
+void f1();
+// expected-warning@+1 {{directive spelling 'end declare_variant' is 
introduced in a later OpenMP version}}
+#pragma omp end declare_variant
+
+int x;
+// expected-warning@+1 {{directive spelling 'declare_target' is introduced in 
a later OpenMP version}}
+#pragma omp declare_target(x)
+
+struct A {
+  int x, y;
+};
+// expected-warning@+1 {{directive spelling 'declare_mapper' is introduced in 
a later OpenMP version}}
+#pragma omp declare_mapper(mymapper: A a) map(tofrom:a.x, a.y)
+A add(A, A);
+// expected-warning@+1 {{directive spelling 'declare_reduction' is introduced 
in a later OpenMP version}}
+#pragma omp declare_reduction(+: A: omp_out = add(omp_in, omp_out))
+
+// expected-warning@+1 {{directive spelling 'declare_simd' is introduced in a 
later OpenMP version}}
+#pragma omp declare_simd
+void f2();
+
+void g3();
+// expected-warning@+1 {{directive spelling 'declare_variant' is introduced in 
a later OpenMP version}}
+#pragma omp declare_variant(g3) match(user={condition(true)})
+void f3() {}
+
+void fred() {
+  #pragma omp parallel
+  {
+    // expected-warning@+1 {{directive spelling 'cancellation_point' is 
introduced in a later OpenMP version}}
+    #pragma omp cancellation_point parallel
+  }
+
+  // expected-warning@+1 {{directive spelling 'target_data' is introduced in a 
later OpenMP version}}
+  #pragma omp target_data map(tofrom: x)
+  {}
+
+  // expected-warning@+1 {{directive spelling 'target_enter_data' is 
introduced in a later OpenMP version}}
+  #pragma omp target_enter_data map(to: x)
+  // expected-warning@+1 {{directive spelling 'target_exit_data' is introduced 
in a later OpenMP version}}
+  #pragma omp target_exit_data map(from: x)
+  // expected-warning@+1 {{directive spelling 'target_update' is introduced in 
a later OpenMP version}}
+  #pragma omp target_update from(x)
+}
+

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to