[Lldb-commits] [clang] [lldb] [lldb] Re-use clang's keyword enable/disable mechanism in CPlusPlusNameParser.cpp (PR #164284)

Daniel Sanders via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 27 14:49:43 PDT 2025


https://github.com/dsandersllvm updated https://github.com/llvm/llvm-project/pull/164284

>From e1175e636933074c6c00f52f9c5287b4a4cf002c Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Fri, 17 Oct 2025 18:10:51 -0700
Subject: [PATCH 1/5] [lldb] Re-use clang's keyword enable/disable mechanism in
 CPlusPlusNameParser.cpp

The problem is that CPlusPlusNameParser doesn't respect the language dialect
for `target variable Class::constant`. If `constant` is a keyword in some
(downstream in this case) dialects then it lexes `constant` as `kw_constant`
instead of `kw_raw_identifier` even if that dialect is not active. As a
result:
* `target variable constant` works
* `target variable Class::constant` fails to look up constant because it sees
  `kw_raw_identifier, kw_coloncolon, kw_constant` instead of
  `kw_raw_identifier, kw_coloncolon, kw_raw_identifier`
* `expr -l c++ -- Class::constant` works because clang is parsing it

Note: There's seemingly a separate bug where GetLangOptions() does not account
for the process/frame language and just uses a pre-defined set of language
options. I have not attempted to fix that since, for now, at least
hardcoding my dialect to be disabled by that function does the
right thing for existing tests.

Also fixed a trivial return-after-else that clangd pointed out in the same
area
---
 clang/include/clang/Basic/IdentifierTable.h   | 53 +++++++++++++++++++
 clang/lib/Basic/IdentifierTable.cpp           | 53 +------------------
 .../CPlusPlus/CPlusPlusNameParser.cpp         | 20 ++++---
 3 files changed, 67 insertions(+), 59 deletions(-)

diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index e4044bcdfcc60..8177029f13ca9 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -46,6 +46,59 @@ class LangOptions;
 class MultiKeywordSelector;
 class SourceLocation;
 
+// This is an inline namespace to allow both clang and lldb to use them without
+// namespace prefixes (via `using namespace` in lldb's case).
+inline namespace TokenKeyEnumerators {
+enum TokenKey : unsigned {
+  KEYC99 = 0x1,
+  KEYCXX = 0x2,
+  KEYCXX11 = 0x4,
+  KEYGNU = 0x8,
+  KEYMS = 0x10,
+  BOOLSUPPORT = 0x20,
+  KEYALTIVEC = 0x40,
+  KEYNOCXX = 0x80,
+  KEYBORLAND = 0x100,
+  KEYOPENCLC = 0x200,
+  KEYC23 = 0x400,
+  KEYNOMS18 = 0x800,
+  KEYNOOPENCL = 0x1000,
+  WCHARSUPPORT = 0x2000,
+  HALFSUPPORT = 0x4000,
+  CHAR8SUPPORT = 0x8000,
+  KEYOBJC = 0x10000,
+  KEYZVECTOR = 0x20000,
+  KEYCOROUTINES = 0x40000,
+  KEYMODULES = 0x80000,
+  KEYCXX20 = 0x100000,
+  KEYOPENCLCXX = 0x200000,
+  KEYMSCOMPAT = 0x400000,
+  KEYSYCL = 0x800000,
+  KEYCUDA = 0x1000000,
+  KEYZOS = 0x2000000,
+  KEYNOZOS = 0x4000000,
+  KEYHLSL = 0x8000000,
+  KEYFIXEDPOINT = 0x10000000,
+  KEYMAX = KEYFIXEDPOINT, // The maximum key
+  KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
+  KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
+           ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.
+};
+} // namespace TokenKeyEnumerators
+
+/// How a keyword is treated in the selected standard. This enum is ordered
+/// intentionally so that the value that 'wins' is the most 'permissive'.
+enum KeywordStatus {
+  KS_Unknown,   // Not yet calculated. Used when figuring out the status.
+  KS_Disabled,  // Disabled
+  KS_Future,    // Is a keyword in future standard
+  KS_Extension, // Is an extension
+  KS_Enabled,   // Enabled
+};
+
+KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
+                               unsigned Flags);
+
 enum class ReservedIdentifierStatus {
   NotReserved = 0,
   StartsWithUnderscoreAtGlobalScope,
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 4a2b77cd16bfc..65ed1273350c5 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -77,57 +77,6 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
 // Language Keyword Implementation
 //===----------------------------------------------------------------------===//
 
-// Constants for TokenKinds.def
-namespace {
-
-enum TokenKey : unsigned {
-  KEYC99 = 0x1,
-  KEYCXX = 0x2,
-  KEYCXX11 = 0x4,
-  KEYGNU = 0x8,
-  KEYMS = 0x10,
-  BOOLSUPPORT = 0x20,
-  KEYALTIVEC = 0x40,
-  KEYNOCXX = 0x80,
-  KEYBORLAND = 0x100,
-  KEYOPENCLC = 0x200,
-  KEYC23 = 0x400,
-  KEYNOMS18 = 0x800,
-  KEYNOOPENCL = 0x1000,
-  WCHARSUPPORT = 0x2000,
-  HALFSUPPORT = 0x4000,
-  CHAR8SUPPORT = 0x8000,
-  KEYOBJC = 0x10000,
-  KEYZVECTOR = 0x20000,
-  KEYCOROUTINES = 0x40000,
-  KEYMODULES = 0x80000,
-  KEYCXX20 = 0x100000,
-  KEYOPENCLCXX = 0x200000,
-  KEYMSCOMPAT = 0x400000,
-  KEYSYCL = 0x800000,
-  KEYCUDA = 0x1000000,
-  KEYZOS = 0x2000000,
-  KEYNOZOS = 0x4000000,
-  KEYHLSL = 0x8000000,
-  KEYFIXEDPOINT = 0x10000000,
-  KEYMAX = KEYFIXEDPOINT, // The maximum key
-  KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
-  KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
-           ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.
-};
-
-/// How a keyword is treated in the selected standard. This enum is ordered
-/// intentionally so that the value that 'wins' is the most 'permissive'.
-enum KeywordStatus {
-  KS_Unknown,   // Not yet calculated. Used when figuring out the status.
-  KS_Disabled,  // Disabled
-  KS_Future,    // Is a keyword in future standard
-  KS_Extension, // Is an extension
-  KS_Enabled,   // Enabled
-};
-
-} // namespace
-
 // This works on a single TokenKey flag and checks the LangOpts to get the
 // KeywordStatus based exclusively on this flag, so that it can be merged in
 // getKeywordStatus. Most should be enabled/disabled, but some might imply
@@ -222,7 +171,7 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
 
 /// Translates flags as specified in TokenKinds.def into keyword status
 /// in the given language standard.
-static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
+KeywordStatus clang::getKeywordStatus(const LangOptions &LangOpts,
                                       unsigned Flags) {
   // KEYALL means always enabled, so special case this one.
   if (Flags == KEYALL) return KS_Enabled;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
index d8c095d6edeb7..13cea5e513005 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -719,9 +719,8 @@ CPlusPlusNameParser::ParseFullNameImpl() {
     }
     start_position.Remove();
     return result;
-  } else {
-    return std::nullopt;
   }
+  return std::nullopt;
 }
 
 llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
@@ -755,12 +754,19 @@ static const clang::LangOptions &GetLangOptions() {
   return g_options;
 }
 
-static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
-  static llvm::StringMap<tok::TokenKind> g_map{
-#define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
+static const llvm::StringMap<tok::TokenKind> GetKeywordsMap() {
+  using namespace clang::TokenKeyEnumerators;
+  llvm::StringMap<tok::TokenKind> g_map;
+
+  auto LangOpts = GetLangOptions();
+
+  clang::KeywordStatus AddResult;
+#define KEYWORD(NAME, FLAGS)                                                   \
+  AddResult = getKeywordStatus(LangOpts, FLAGS);                               \
+  if (AddResult != clang::KS_Disabled)                                         \
+    g_map[llvm::StringRef(#NAME)] = tok::kw_##NAME;
 #include "clang/Basic/TokenKinds.def"
 #undef KEYWORD
-  };
   return g_map;
 }
 
@@ -769,7 +775,7 @@ void CPlusPlusNameParser::ExtractTokens() {
     return;
   clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
                      m_text.data(), m_text.data() + m_text.size());
-  const auto &kw_map = GetKeywordsMap();
+  const auto kw_map = GetKeywordsMap();
   clang::Token token;
   for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
        lexer.LexFromRawLexer(token)) {

>From 0275d00b577c8f273b9d3949122367ddcc311b3c Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Mon, 27 Oct 2025 14:20:10 -0700
Subject: [PATCH 2/5] fixup: use `using namespace clang` instead

---
 clang/include/clang/Basic/IdentifierTable.h                 | 4 ----
 .../Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp      | 6 +++---
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index 8177029f13ca9..54500b95b2c06 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -46,9 +46,6 @@ class LangOptions;
 class MultiKeywordSelector;
 class SourceLocation;
 
-// This is an inline namespace to allow both clang and lldb to use them without
-// namespace prefixes (via `using namespace` in lldb's case).
-inline namespace TokenKeyEnumerators {
 enum TokenKey : unsigned {
   KEYC99 = 0x1,
   KEYCXX = 0x2,
@@ -84,7 +81,6 @@ enum TokenKey : unsigned {
   KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
            ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.
 };
-} // namespace TokenKeyEnumerators
 
 /// How a keyword is treated in the selected standard. This enum is ordered
 /// intentionally so that the value that 'wins' is the most 'permissive'.
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
index 13cea5e513005..8560a44340508 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -755,15 +755,15 @@ static const clang::LangOptions &GetLangOptions() {
 }
 
 static const llvm::StringMap<tok::TokenKind> GetKeywordsMap() {
-  using namespace clang::TokenKeyEnumerators;
+  using namespace clang;
   llvm::StringMap<tok::TokenKind> g_map;
 
   auto LangOpts = GetLangOptions();
 
-  clang::KeywordStatus AddResult;
+  KeywordStatus AddResult;
 #define KEYWORD(NAME, FLAGS)                                                   \
   AddResult = getKeywordStatus(LangOpts, FLAGS);                               \
-  if (AddResult != clang::KS_Disabled)                                         \
+  if (AddResult != KS_Disabled)                                                \
     g_map[llvm::StringRef(#NAME)] = tok::kw_##NAME;
 #include "clang/Basic/TokenKinds.def"
 #undef KEYWORD

>From f221e49028db66859bb0c9ca00a0beee7be3d6a7 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Mon, 27 Oct 2025 14:37:16 -0700
Subject: [PATCH 3/5] Revert "[lldb] Re-use clang's keyword enable/disable
 mechanism in CPlusPlusNameParser.cpp"

This is just to allow me to separate the clang and lldb parts without breaking
the github PR's comment history
---
 clang/include/clang/Basic/IdentifierTable.h   | 49 -----------------
 clang/lib/Basic/IdentifierTable.cpp           | 53 ++++++++++++++++++-
 .../CPlusPlus/CPlusPlusNameParser.cpp         | 20 +++----
 3 files changed, 59 insertions(+), 63 deletions(-)

diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index 54500b95b2c06..e4044bcdfcc60 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -46,55 +46,6 @@ class LangOptions;
 class MultiKeywordSelector;
 class SourceLocation;
 
-enum TokenKey : unsigned {
-  KEYC99 = 0x1,
-  KEYCXX = 0x2,
-  KEYCXX11 = 0x4,
-  KEYGNU = 0x8,
-  KEYMS = 0x10,
-  BOOLSUPPORT = 0x20,
-  KEYALTIVEC = 0x40,
-  KEYNOCXX = 0x80,
-  KEYBORLAND = 0x100,
-  KEYOPENCLC = 0x200,
-  KEYC23 = 0x400,
-  KEYNOMS18 = 0x800,
-  KEYNOOPENCL = 0x1000,
-  WCHARSUPPORT = 0x2000,
-  HALFSUPPORT = 0x4000,
-  CHAR8SUPPORT = 0x8000,
-  KEYOBJC = 0x10000,
-  KEYZVECTOR = 0x20000,
-  KEYCOROUTINES = 0x40000,
-  KEYMODULES = 0x80000,
-  KEYCXX20 = 0x100000,
-  KEYOPENCLCXX = 0x200000,
-  KEYMSCOMPAT = 0x400000,
-  KEYSYCL = 0x800000,
-  KEYCUDA = 0x1000000,
-  KEYZOS = 0x2000000,
-  KEYNOZOS = 0x4000000,
-  KEYHLSL = 0x8000000,
-  KEYFIXEDPOINT = 0x10000000,
-  KEYMAX = KEYFIXEDPOINT, // The maximum key
-  KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
-  KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
-           ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.
-};
-
-/// How a keyword is treated in the selected standard. This enum is ordered
-/// intentionally so that the value that 'wins' is the most 'permissive'.
-enum KeywordStatus {
-  KS_Unknown,   // Not yet calculated. Used when figuring out the status.
-  KS_Disabled,  // Disabled
-  KS_Future,    // Is a keyword in future standard
-  KS_Extension, // Is an extension
-  KS_Enabled,   // Enabled
-};
-
-KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
-                               unsigned Flags);
-
 enum class ReservedIdentifierStatus {
   NotReserved = 0,
   StartsWithUnderscoreAtGlobalScope,
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 65ed1273350c5..4a2b77cd16bfc 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -77,6 +77,57 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
 // Language Keyword Implementation
 //===----------------------------------------------------------------------===//
 
+// Constants for TokenKinds.def
+namespace {
+
+enum TokenKey : unsigned {
+  KEYC99 = 0x1,
+  KEYCXX = 0x2,
+  KEYCXX11 = 0x4,
+  KEYGNU = 0x8,
+  KEYMS = 0x10,
+  BOOLSUPPORT = 0x20,
+  KEYALTIVEC = 0x40,
+  KEYNOCXX = 0x80,
+  KEYBORLAND = 0x100,
+  KEYOPENCLC = 0x200,
+  KEYC23 = 0x400,
+  KEYNOMS18 = 0x800,
+  KEYNOOPENCL = 0x1000,
+  WCHARSUPPORT = 0x2000,
+  HALFSUPPORT = 0x4000,
+  CHAR8SUPPORT = 0x8000,
+  KEYOBJC = 0x10000,
+  KEYZVECTOR = 0x20000,
+  KEYCOROUTINES = 0x40000,
+  KEYMODULES = 0x80000,
+  KEYCXX20 = 0x100000,
+  KEYOPENCLCXX = 0x200000,
+  KEYMSCOMPAT = 0x400000,
+  KEYSYCL = 0x800000,
+  KEYCUDA = 0x1000000,
+  KEYZOS = 0x2000000,
+  KEYNOZOS = 0x4000000,
+  KEYHLSL = 0x8000000,
+  KEYFIXEDPOINT = 0x10000000,
+  KEYMAX = KEYFIXEDPOINT, // The maximum key
+  KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
+  KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
+           ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.
+};
+
+/// How a keyword is treated in the selected standard. This enum is ordered
+/// intentionally so that the value that 'wins' is the most 'permissive'.
+enum KeywordStatus {
+  KS_Unknown,   // Not yet calculated. Used when figuring out the status.
+  KS_Disabled,  // Disabled
+  KS_Future,    // Is a keyword in future standard
+  KS_Extension, // Is an extension
+  KS_Enabled,   // Enabled
+};
+
+} // namespace
+
 // This works on a single TokenKey flag and checks the LangOpts to get the
 // KeywordStatus based exclusively on this flag, so that it can be merged in
 // getKeywordStatus. Most should be enabled/disabled, but some might imply
@@ -171,7 +222,7 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
 
 /// Translates flags as specified in TokenKinds.def into keyword status
 /// in the given language standard.
-KeywordStatus clang::getKeywordStatus(const LangOptions &LangOpts,
+static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
                                       unsigned Flags) {
   // KEYALL means always enabled, so special case this one.
   if (Flags == KEYALL) return KS_Enabled;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
index 8560a44340508..d8c095d6edeb7 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -719,8 +719,9 @@ CPlusPlusNameParser::ParseFullNameImpl() {
     }
     start_position.Remove();
     return result;
+  } else {
+    return std::nullopt;
   }
-  return std::nullopt;
 }
 
 llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
@@ -754,19 +755,12 @@ static const clang::LangOptions &GetLangOptions() {
   return g_options;
 }
 
-static const llvm::StringMap<tok::TokenKind> GetKeywordsMap() {
-  using namespace clang;
-  llvm::StringMap<tok::TokenKind> g_map;
-
-  auto LangOpts = GetLangOptions();
-
-  KeywordStatus AddResult;
-#define KEYWORD(NAME, FLAGS)                                                   \
-  AddResult = getKeywordStatus(LangOpts, FLAGS);                               \
-  if (AddResult != KS_Disabled)                                                \
-    g_map[llvm::StringRef(#NAME)] = tok::kw_##NAME;
+static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
+  static llvm::StringMap<tok::TokenKind> g_map{
+#define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
 #include "clang/Basic/TokenKinds.def"
 #undef KEYWORD
+  };
   return g_map;
 }
 
@@ -775,7 +769,7 @@ void CPlusPlusNameParser::ExtractTokens() {
     return;
   clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
                      m_text.data(), m_text.data() + m_text.size());
-  const auto kw_map = GetKeywordsMap();
+  const auto &kw_map = GetKeywordsMap();
   clang::Token token;
   for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
        lexer.LexFromRawLexer(token)) {

>From 7af1e873756be458855afc9488dd2f95a2f21568 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Fri, 17 Oct 2025 18:10:51 -0700
Subject: [PATCH 4/5] [clang] Refactor clang's keyword enable/disable mechanism
 to allow lldb to re-use it

lldb's CPlusPlusNameParser is currently identifying keywords using it's own
map implemented using clang/Basic/TokenKinds.def. However, it does not respect
the language options so identifiers can incorrectly determined to be keywords
when using languages in which they are not keywords.

Rather than implement the logic to enable/disable keywords in both projects it
makes sense for lldb to use clang's implementation.

See #164284 for more information
---
 clang/include/clang/Basic/IdentifierTable.h | 49 +++++++++++++++++++
 clang/lib/Basic/IdentifierTable.cpp         | 53 +--------------------
 2 files changed, 50 insertions(+), 52 deletions(-)

diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index e4044bcdfcc60..54500b95b2c06 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -46,6 +46,55 @@ class LangOptions;
 class MultiKeywordSelector;
 class SourceLocation;
 
+enum TokenKey : unsigned {
+  KEYC99 = 0x1,
+  KEYCXX = 0x2,
+  KEYCXX11 = 0x4,
+  KEYGNU = 0x8,
+  KEYMS = 0x10,
+  BOOLSUPPORT = 0x20,
+  KEYALTIVEC = 0x40,
+  KEYNOCXX = 0x80,
+  KEYBORLAND = 0x100,
+  KEYOPENCLC = 0x200,
+  KEYC23 = 0x400,
+  KEYNOMS18 = 0x800,
+  KEYNOOPENCL = 0x1000,
+  WCHARSUPPORT = 0x2000,
+  HALFSUPPORT = 0x4000,
+  CHAR8SUPPORT = 0x8000,
+  KEYOBJC = 0x10000,
+  KEYZVECTOR = 0x20000,
+  KEYCOROUTINES = 0x40000,
+  KEYMODULES = 0x80000,
+  KEYCXX20 = 0x100000,
+  KEYOPENCLCXX = 0x200000,
+  KEYMSCOMPAT = 0x400000,
+  KEYSYCL = 0x800000,
+  KEYCUDA = 0x1000000,
+  KEYZOS = 0x2000000,
+  KEYNOZOS = 0x4000000,
+  KEYHLSL = 0x8000000,
+  KEYFIXEDPOINT = 0x10000000,
+  KEYMAX = KEYFIXEDPOINT, // The maximum key
+  KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
+  KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
+           ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.
+};
+
+/// How a keyword is treated in the selected standard. This enum is ordered
+/// intentionally so that the value that 'wins' is the most 'permissive'.
+enum KeywordStatus {
+  KS_Unknown,   // Not yet calculated. Used when figuring out the status.
+  KS_Disabled,  // Disabled
+  KS_Future,    // Is a keyword in future standard
+  KS_Extension, // Is an extension
+  KS_Enabled,   // Enabled
+};
+
+KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
+                               unsigned Flags);
+
 enum class ReservedIdentifierStatus {
   NotReserved = 0,
   StartsWithUnderscoreAtGlobalScope,
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 4a2b77cd16bfc..65ed1273350c5 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -77,57 +77,6 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
 // Language Keyword Implementation
 //===----------------------------------------------------------------------===//
 
-// Constants for TokenKinds.def
-namespace {
-
-enum TokenKey : unsigned {
-  KEYC99 = 0x1,
-  KEYCXX = 0x2,
-  KEYCXX11 = 0x4,
-  KEYGNU = 0x8,
-  KEYMS = 0x10,
-  BOOLSUPPORT = 0x20,
-  KEYALTIVEC = 0x40,
-  KEYNOCXX = 0x80,
-  KEYBORLAND = 0x100,
-  KEYOPENCLC = 0x200,
-  KEYC23 = 0x400,
-  KEYNOMS18 = 0x800,
-  KEYNOOPENCL = 0x1000,
-  WCHARSUPPORT = 0x2000,
-  HALFSUPPORT = 0x4000,
-  CHAR8SUPPORT = 0x8000,
-  KEYOBJC = 0x10000,
-  KEYZVECTOR = 0x20000,
-  KEYCOROUTINES = 0x40000,
-  KEYMODULES = 0x80000,
-  KEYCXX20 = 0x100000,
-  KEYOPENCLCXX = 0x200000,
-  KEYMSCOMPAT = 0x400000,
-  KEYSYCL = 0x800000,
-  KEYCUDA = 0x1000000,
-  KEYZOS = 0x2000000,
-  KEYNOZOS = 0x4000000,
-  KEYHLSL = 0x8000000,
-  KEYFIXEDPOINT = 0x10000000,
-  KEYMAX = KEYFIXEDPOINT, // The maximum key
-  KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
-  KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
-           ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.
-};
-
-/// How a keyword is treated in the selected standard. This enum is ordered
-/// intentionally so that the value that 'wins' is the most 'permissive'.
-enum KeywordStatus {
-  KS_Unknown,   // Not yet calculated. Used when figuring out the status.
-  KS_Disabled,  // Disabled
-  KS_Future,    // Is a keyword in future standard
-  KS_Extension, // Is an extension
-  KS_Enabled,   // Enabled
-};
-
-} // namespace
-
 // This works on a single TokenKey flag and checks the LangOpts to get the
 // KeywordStatus based exclusively on this flag, so that it can be merged in
 // getKeywordStatus. Most should be enabled/disabled, but some might imply
@@ -222,7 +171,7 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
 
 /// Translates flags as specified in TokenKinds.def into keyword status
 /// in the given language standard.
-static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
+KeywordStatus clang::getKeywordStatus(const LangOptions &LangOpts,
                                       unsigned Flags) {
   // KEYALL means always enabled, so special case this one.
   if (Flags == KEYALL) return KS_Enabled;

>From e03585e4f3700c90574065baabb25b093f634090 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Mon, 27 Oct 2025 14:39:42 -0700
Subject: [PATCH 5/5] [lldb] Re-use clang's keyword enable/disable mechanism in
 CPlusPlusNameParser.cpp

The problem is that CPlusPlusNameParser doesn't respect the language dialect
for `target variable Class::constant`. If `constant` is a keyword in some
(downstream in this case) dialects then it lexes `constant` as `kw_constant`
instead of `kw_raw_identifier` even if that dialect is not active. As a
result:
* `target variable constant` works
* `target variable Class::constant` fails to look up constant because it sees
  `kw_raw_identifier, kw_coloncolon, kw_constant` instead of
  `kw_raw_identifier, kw_coloncolon, kw_raw_identifier`
* `expr -l c++ -- Class::constant` works because clang is parsing it

Note: There's seemingly a separate bug where GetLangOptions() does not account
for the process/frame language and just uses a pre-defined set of language
options. I have not attempted to fix that since, for now, at least
hardcoding my dialect to be disabled by that function does the
right thing for existing tests.

Also fixed a trivial return-after-else that clangd pointed out in the same
area
---
 .../CPlusPlus/CPlusPlusNameParser.cpp         | 20 ++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
index d8c095d6edeb7..8560a44340508 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -719,9 +719,8 @@ CPlusPlusNameParser::ParseFullNameImpl() {
     }
     start_position.Remove();
     return result;
-  } else {
-    return std::nullopt;
   }
+  return std::nullopt;
 }
 
 llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
@@ -755,12 +754,19 @@ static const clang::LangOptions &GetLangOptions() {
   return g_options;
 }
 
-static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
-  static llvm::StringMap<tok::TokenKind> g_map{
-#define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
+static const llvm::StringMap<tok::TokenKind> GetKeywordsMap() {
+  using namespace clang;
+  llvm::StringMap<tok::TokenKind> g_map;
+
+  auto LangOpts = GetLangOptions();
+
+  KeywordStatus AddResult;
+#define KEYWORD(NAME, FLAGS)                                                   \
+  AddResult = getKeywordStatus(LangOpts, FLAGS);                               \
+  if (AddResult != KS_Disabled)                                                \
+    g_map[llvm::StringRef(#NAME)] = tok::kw_##NAME;
 #include "clang/Basic/TokenKinds.def"
 #undef KEYWORD
-  };
   return g_map;
 }
 
@@ -769,7 +775,7 @@ void CPlusPlusNameParser::ExtractTokens() {
     return;
   clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
                      m_text.data(), m_text.data() + m_text.size());
-  const auto &kw_map = GetKeywordsMap();
+  const auto kw_map = GetKeywordsMap();
   clang::Token token;
   for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
        lexer.LexFromRawLexer(token)) {



More information about the lldb-commits mailing list