This revision was automatically updated to reflect the committed changes.
Closed by commit rGa8350ce79d16: [lldb] Add support for using variables with 
C++ keywords names in non-C++… (authored by teemperor).
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82770/new/

https://reviews.llvm.org/D82770

Files:
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
  lldb/test/API/lang/c/cpp_keyword_identifiers/Makefile
  lldb/test/API/lang/c/cpp_keyword_identifiers/TestCppKeywordsAsCIdentifiers.py
  lldb/test/API/lang/c/cpp_keyword_identifiers/main.c
  lldb/test/API/lang/cpp/keywords_enabled/TestCppKeywordsEnabled.py
  lldb/test/API/lang/cpp/struct_with_keyword_name/Makefile
  lldb/test/API/lang/cpp/struct_with_keyword_name/TestStructWithKeywordName.py
  lldb/test/API/lang/cpp/struct_with_keyword_name/main.c
  lldb/test/API/lang/objc/cpp_keyword_identifiers/Makefile
  
lldb/test/API/lang/objc/cpp_keyword_identifiers/TestCppKeywordsAsObjCIdentifiers.py
  lldb/test/API/lang/objc/cpp_keyword_identifiers/main.m
  lldb/test/API/lang/objc/modules/TestObjCModules.py
  lldb/test/API/lang/objcxx/cpp_keywords_enabled/TestObjCppKeywordsEnabled.py

Index: lldb/test/API/lang/objcxx/cpp_keywords_enabled/TestObjCppKeywordsEnabled.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/objcxx/cpp_keywords_enabled/TestObjCppKeywordsEnabled.py
@@ -0,0 +1,16 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    @no_debug_info_test
+    def test_keyword(self):
+      # Make sure that C++ keywords work in the expression parser when using
+      # Objective-C++.
+      self.expect("expr -l objective-c++ -- constexpr int i = 3 + 3; i", substrs=["= 6"])
Index: lldb/test/API/lang/objc/modules/TestObjCModules.py
===================================================================
--- lldb/test/API/lang/objc/modules/TestObjCModules.py
+++ lldb/test/API/lang/objc/modules/TestObjCModules.py
@@ -77,3 +77,5 @@
             "p [NSURL URLWithString:@\"http://lldb.llvm.org\"].scheme";,
             VARIABLES_DISPLAYED_CORRECTLY,
             substrs=["http"])
+        # Test that the NULL macro still works with a loaded module.
+        self.expect_expr("int *i = NULL; i == NULL", result_value="true")
Index: lldb/test/API/lang/objc/cpp_keyword_identifiers/main.m
===================================================================
--- /dev/null
+++ lldb/test/API/lang/objc/cpp_keyword_identifiers/main.m
@@ -0,0 +1,68 @@
+int main() {
+  // Disable clang-format as it gets confused by the keyword identifiers.
+  // clang-format off
+  int alignas = 1;
+  int alignof = 1;
+  int and = 1;
+  int and_eq = 1;
+  int atomic_cancel = 1;
+  int atomic_commit = 1;
+  int atomic_noexcept = 1;
+  int bitand = 1;
+  int bitor = 1;
+  int bool = 1;
+  int catch = 1;
+  int char8_t = 1;
+  int char16_t = 1;
+  int char32_t = 1;
+  int class = 1;
+  int compl = 1;
+  int concept = 1;
+  int consteval = 1;
+  int constexpr = 1;
+  int constinit = 1;
+  int const_cast = 1;
+  int co_await = 1;
+  int co_return = 1;
+  int co_yield = 1;
+  int decltype = 1;
+  int delete = 1;
+  int dynamic_cast = 1;
+  int explicit = 1;
+  int export = 1;
+  int false = 1;
+  int friend = 1;
+  int mutable = 1;
+  int namespace = 1;
+  int new = 1;
+  int noexcept = 1;
+  int not = 1;
+  int not_eq = 1;
+  int operator= 1;
+  int or = 1;
+  int or_eq = 1;
+  int private = 1;
+  int protected = 1;
+  int public = 1;
+  int reflexpr = 1;
+  int reinterpret_cast = 1;
+  int requires = 1;
+  int static_assert = 1;
+  int static_cast = 1;
+  int synchronized = 1;
+  int template = 1;
+  int this = 1;
+  int thread_local = 1;
+  int throw = 1;
+  int true = 1;
+  int try = 1;
+  int typeid = 1;
+  int typename = 1;
+  int using = 1;
+  int virtual = 1;
+  int wchar_t = 1;
+  int xor = 1;
+  int xor_eq = 1;
+  // clang-format on
+  return 0; // break here
+}
Index: lldb/test/API/lang/objc/cpp_keyword_identifiers/TestCppKeywordsAsObjCIdentifiers.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/objc/cpp_keyword_identifiers/TestCppKeywordsAsObjCIdentifiers.py
@@ -0,0 +1,89 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    @no_debug_info_test
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.m"))
+
+        # Test several variables with C++ keyword names and make sure they
+        # work as intended in the expression parser.
+        self.expect_expr("alignas", result_type="int", result_value="1")
+        self.expect_expr("alignof", result_type="int", result_value="1")
+        self.expect_expr("and", result_type="int", result_value="1")
+        self.expect_expr("and_eq", result_type="int", result_value="1")
+        self.expect_expr("atomic_cancel", result_type="int", result_value="1")
+        self.expect_expr("atomic_commit", result_type="int", result_value="1")
+        self.expect_expr("atomic_noexcept", result_type="int", result_value="1")
+        self.expect_expr("bitand", result_type="int", result_value="1")
+        self.expect_expr("bitor", result_type="int", result_value="1")
+        self.expect_expr("catch", result_type="int", result_value="1")
+        self.expect_expr("char8_t", result_type="int", result_value="1")
+        self.expect_expr("char16_t", result_type="int", result_value="1")
+        self.expect_expr("char32_t", result_type="int", result_value="1")
+        self.expect_expr("class", result_type="int", result_value="1")
+        self.expect_expr("compl", result_type="int", result_value="1")
+        self.expect_expr("concept", result_type="int", result_value="1")
+        self.expect_expr("consteval", result_type="int", result_value="1")
+        self.expect_expr("constexpr", result_type="int", result_value="1")
+        self.expect_expr("constinit", result_type="int", result_value="1")
+        self.expect_expr("const_cast", result_type="int", result_value="1")
+        self.expect_expr("co_await", result_type="int", result_value="1")
+        self.expect_expr("co_return", result_type="int", result_value="1")
+        self.expect_expr("co_yield", result_type="int", result_value="1")
+        self.expect_expr("decltype", result_type="int", result_value="1")
+        self.expect_expr("delete", result_type="int", result_value="1")
+        self.expect_expr("dynamic_cast", result_type="int", result_value="1")
+        self.expect_expr("explicit", result_type="int", result_value="1")
+        self.expect_expr("export", result_type="int", result_value="1")
+        self.expect_expr("friend", result_type="int", result_value="1")
+        self.expect_expr("mutable", result_type="int", result_value="1")
+        self.expect_expr("namespace", result_type="int", result_value="1")
+        self.expect_expr("new", result_type="int", result_value="1")
+        self.expect_expr("noexcept", result_type="int", result_value="1")
+        self.expect_expr("not", result_type="int", result_value="1")
+        self.expect_expr("not_eq", result_type="int", result_value="1")
+        self.expect_expr("operator", result_type="int", result_value="1")
+        self.expect_expr("or", result_type="int", result_value="1")
+        self.expect_expr("or_eq", result_type="int", result_value="1")
+        self.expect_expr("private", result_type="int", result_value="1")
+        self.expect_expr("protected", result_type="int", result_value="1")
+        self.expect_expr("public", result_type="int", result_value="1")
+        self.expect_expr("reflexpr", result_type="int", result_value="1")
+        self.expect_expr("reinterpret_cast", result_type="int", result_value="1")
+        self.expect_expr("requires", result_type="int", result_value="1")
+        self.expect_expr("static_assert", result_type="int", result_value="1")
+        self.expect_expr("static_cast", result_type="int", result_value="1")
+        self.expect_expr("synchronized", result_type="int", result_value="1")
+        self.expect_expr("template", result_type="int", result_value="1")
+        self.expect_expr("this", result_type="int", result_value="1")
+        self.expect_expr("thread_local", result_type="int", result_value="1")
+        self.expect_expr("throw", result_type="int", result_value="1")
+        self.expect_expr("try", result_type="int", result_value="1")
+        self.expect_expr("typeid", result_type="int", result_value="1")
+        self.expect_expr("typename", result_type="int", result_value="1")
+        self.expect_expr("virtual", result_type="int", result_value="1")
+        self.expect_expr("xor", result_type="int", result_value="1")
+        self.expect_expr("xor_eq", result_type="int", result_value="1")
+
+
+        # Some keywords are not available in LLDB as their language feature
+        # is enabled by default.
+
+        # 'using' is used by LLDB for local variables.
+        self.expect("expr using", error=True, substrs=["expected unqualified-id"])
+
+        # 'wchar_t' supported is enabled in LLDB.
+        self.expect("expr wchar_t", error=True, substrs=["expected unqualified-id"])
+
+        # LLDB enables 'bool' support by default.
+        self.expect("expr bool", error=True, substrs=["expected unqualified-id"])
+        self.expect("expr false", error=True, substrs=["expected unqualified-id"])
+        self.expect("expr true", error=True, substrs=["expected unqualified-id"])
Index: lldb/test/API/lang/objc/cpp_keyword_identifiers/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lang/objc/cpp_keyword_identifiers/Makefile
@@ -0,0 +1,3 @@
+OBJC_SOURCES := main.m
+
+include Makefile.rules
Index: lldb/test/API/lang/cpp/struct_with_keyword_name/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/struct_with_keyword_name/main.c
@@ -0,0 +1,9 @@
+struct class {
+  int class;
+};
+
+int main() {
+  struct class constexpr;
+  constexpr.class = 3;
+  return constexpr.class; // break here
+}
Index: lldb/test/API/lang/cpp/struct_with_keyword_name/TestStructWithKeywordName.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/struct_with_keyword_name/TestStructWithKeywordName.py
@@ -0,0 +1,21 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c"))
+
+        # First run this in C which should work.
+        self.expect_expr("constexpr.class", result_type="int", result_value="3")
+
+        # Now try running this in a language that explicitly enables C++.
+        # This isn't expected to work, but at least it shouldn't crash LLDB.
+        self.expect("expr -l c++ -- constexpr.class", error=True, substrs=["expected unqualified-id"])
+        self.expect("expr -l objective-c++ -- constexpr.class", error=True, substrs=["expected unqualified-id"])
Index: lldb/test/API/lang/cpp/struct_with_keyword_name/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/struct_with_keyword_name/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/test/API/lang/cpp/keywords_enabled/TestCppKeywordsEnabled.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/keywords_enabled/TestCppKeywordsEnabled.py
@@ -0,0 +1,14 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    def test_keyword(self):
+      # Make sure that C++ keywords work in the expression parser.
+      self.expect("expr -l c++ -- constexpr int i = 3 + 3; i", substrs=["= 6"])
Index: lldb/test/API/lang/c/cpp_keyword_identifiers/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/cpp_keyword_identifiers/main.c
@@ -0,0 +1,68 @@
+int main() {
+  // Disable clang-format as it gets confused by the keyword identifiers.
+  // clang-format off
+  int alignas = 1;
+  int alignof = 1;
+  int and = 1;
+  int and_eq = 1;
+  int atomic_cancel = 1;
+  int atomic_commit = 1;
+  int atomic_noexcept = 1;
+  int bitand = 1;
+  int bitor = 1;
+  int bool = 1;
+  int catch = 1;
+  int char8_t = 1;
+  int char16_t = 1;
+  int char32_t = 1;
+  int class = 1;
+  int compl = 1;
+  int concept = 1;
+  int consteval = 1;
+  int constexpr = 1;
+  int constinit = 1;
+  int const_cast = 1;
+  int co_await = 1;
+  int co_return = 1;
+  int co_yield = 1;
+  int decltype = 1;
+  int delete = 1;
+  int dynamic_cast = 1;
+  int explicit = 1;
+  int export = 1;
+  int false = 1;
+  int friend = 1;
+  int mutable = 1;
+  int namespace = 1;
+  int new = 1;
+  int noexcept = 1;
+  int not = 1;
+  int not_eq = 1;
+  int operator= 1;
+  int or = 1;
+  int or_eq = 1;
+  int private = 1;
+  int protected = 1;
+  int public = 1;
+  int reflexpr = 1;
+  int reinterpret_cast = 1;
+  int requires = 1;
+  int static_assert = 1;
+  int static_cast = 1;
+  int synchronized = 1;
+  int template = 1;
+  int this = 1;
+  int thread_local = 1;
+  int throw = 1;
+  int true = 1;
+  int try = 1;
+  int typeid = 1;
+  int typename = 1;
+  int using = 1;
+  int virtual = 1;
+  int wchar_t = 1;
+  int xor = 1;
+  int xor_eq = 1;
+  // clang-format on
+  return 0; // break here
+}
Index: lldb/test/API/lang/c/cpp_keyword_identifiers/TestCppKeywordsAsCIdentifiers.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/cpp_keyword_identifiers/TestCppKeywordsAsCIdentifiers.py
@@ -0,0 +1,87 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c"))
+
+        # Test several variables with C++ keyword names and make sure they
+        # work as intended in the expression parser.
+        self.expect_expr("alignas", result_type="int", result_value="1")
+        self.expect_expr("alignof", result_type="int", result_value="1")
+        self.expect_expr("and", result_type="int", result_value="1")
+        self.expect_expr("and_eq", result_type="int", result_value="1")
+        self.expect_expr("atomic_cancel", result_type="int", result_value="1")
+        self.expect_expr("atomic_commit", result_type="int", result_value="1")
+        self.expect_expr("atomic_noexcept", result_type="int", result_value="1")
+        self.expect_expr("bitand", result_type="int", result_value="1")
+        self.expect_expr("bitor", result_type="int", result_value="1")
+        self.expect_expr("catch", result_type="int", result_value="1")
+        self.expect_expr("char8_t", result_type="int", result_value="1")
+        self.expect_expr("char16_t", result_type="int", result_value="1")
+        self.expect_expr("char32_t", result_type="int", result_value="1")
+        self.expect_expr("class", result_type="int", result_value="1")
+        self.expect_expr("compl", result_type="int", result_value="1")
+        self.expect_expr("concept", result_type="int", result_value="1")
+        self.expect_expr("consteval", result_type="int", result_value="1")
+        self.expect_expr("constexpr", result_type="int", result_value="1")
+        self.expect_expr("constinit", result_type="int", result_value="1")
+        self.expect_expr("const_cast", result_type="int", result_value="1")
+        self.expect_expr("co_await", result_type="int", result_value="1")
+        self.expect_expr("co_return", result_type="int", result_value="1")
+        self.expect_expr("co_yield", result_type="int", result_value="1")
+        self.expect_expr("decltype", result_type="int", result_value="1")
+        self.expect_expr("delete", result_type="int", result_value="1")
+        self.expect_expr("dynamic_cast", result_type="int", result_value="1")
+        self.expect_expr("explicit", result_type="int", result_value="1")
+        self.expect_expr("export", result_type="int", result_value="1")
+        self.expect_expr("friend", result_type="int", result_value="1")
+        self.expect_expr("mutable", result_type="int", result_value="1")
+        self.expect_expr("namespace", result_type="int", result_value="1")
+        self.expect_expr("new", result_type="int", result_value="1")
+        self.expect_expr("noexcept", result_type="int", result_value="1")
+        self.expect_expr("not", result_type="int", result_value="1")
+        self.expect_expr("not_eq", result_type="int", result_value="1")
+        self.expect_expr("operator", result_type="int", result_value="1")
+        self.expect_expr("or", result_type="int", result_value="1")
+        self.expect_expr("or_eq", result_type="int", result_value="1")
+        self.expect_expr("private", result_type="int", result_value="1")
+        self.expect_expr("protected", result_type="int", result_value="1")
+        self.expect_expr("public", result_type="int", result_value="1")
+        self.expect_expr("reflexpr", result_type="int", result_value="1")
+        self.expect_expr("reinterpret_cast", result_type="int", result_value="1")
+        self.expect_expr("requires", result_type="int", result_value="1")
+        self.expect_expr("static_assert", result_type="int", result_value="1")
+        self.expect_expr("static_cast", result_type="int", result_value="1")
+        self.expect_expr("synchronized", result_type="int", result_value="1")
+        self.expect_expr("template", result_type="int", result_value="1")
+        self.expect_expr("this", result_type="int", result_value="1")
+        self.expect_expr("thread_local", result_type="int", result_value="1")
+        self.expect_expr("throw", result_type="int", result_value="1")
+        self.expect_expr("try", result_type="int", result_value="1")
+        self.expect_expr("typeid", result_type="int", result_value="1")
+        self.expect_expr("typename", result_type="int", result_value="1")
+        self.expect_expr("virtual", result_type="int", result_value="1")
+        self.expect_expr("xor", result_type="int", result_value="1")
+        self.expect_expr("xor_eq", result_type="int", result_value="1")
+
+        # Some keywords are not available in LLDB as their language feature
+        # is enabled by default.
+
+        # 'using' is used by LLDB for local variables.
+        self.expect("expr using", error=True, substrs=["expected unqualified-id"])
+
+        # 'wchar_t' supported is enabled in LLDB.
+        self.expect("expr wchar_t", error=True, substrs=["expected unqualified-id"])
+
+        # LLDB enables 'bool' support by default.
+        self.expect("expr bool", error=True, substrs=["expected unqualified-id"])
+        self.expect("expr false", error=True, substrs=["expected unqualified-id"])
+        self.expect("expr true", error=True, substrs=["expected unqualified-id"])
Index: lldb/test/API/lang/c/cpp_keyword_identifiers/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/cpp_keyword_identifiers/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
@@ -90,13 +90,13 @@
   ///     if module A #defines a macro and module B #undefs it.
   ///
   /// \param[in] handler
-  ///     A function to call with the text of each #define (including the
-  ///     #define directive).  #undef directives are not included; we simply
-  ///     elide any corresponding #define.  If this function returns true,
-  ///     we stop the iteration immediately.
-  virtual void
-  ForEachMacro(const ModuleVector &modules,
-               std::function<bool(const std::string &)> handler) = 0;
+  ///     A function to call with the identifier of this macro and the text of
+  ///     each #define (including the #define directive). #undef directives are
+  ///     not included; we simply elide any corresponding #define. If this
+  ///     function returns true, we stop the iteration immediately.
+  virtual void ForEachMacro(
+      const ModuleVector &modules,
+      std::function<bool(llvm::StringRef, llvm::StringRef)> handler) = 0;
 
   /// Query whether Clang supports modules for a particular language.
   /// LLDB uses this to decide whether to try to find the modules loaded
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -95,8 +95,10 @@
   uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches,
                      std::vector<CompilerDecl> &decls) override;
 
-  void ForEachMacro(const ModuleVector &modules,
-                    std::function<bool(const std::string &)> handler) override;
+  void ForEachMacro(
+      const ModuleVector &modules,
+      std::function<bool(llvm::StringRef, llvm::StringRef)> handler) override;
+
 private:
   void
   ReportModuleExportsHelper(std::set<ClangModulesDeclVendor::ModuleID> &exports,
@@ -420,7 +422,7 @@
 
 void ClangModulesDeclVendorImpl::ForEachMacro(
     const ClangModulesDeclVendor::ModuleVector &modules,
-    std::function<bool(const std::string &)> handler) {
+    std::function<bool(llvm::StringRef, llvm::StringRef)> handler) {
   if (!m_enabled) {
     return;
   }
@@ -490,7 +492,8 @@
 
     if (macro_info) {
       std::string macro_expansion = "#define ";
-      macro_expansion.append(mi->first->getName().str());
+      llvm::StringRef macro_identifier = mi->first->getName();
+      macro_expansion.append(macro_identifier.str());
 
       {
         if (macro_info->isFunctionLike()) {
@@ -575,7 +578,7 @@
           }
         }
 
-        if (handler(macro_expansion)) {
+        if (handler(macro_identifier, macro_expansion)) {
           return;
         }
       }
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -297,6 +297,7 @@
     bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const {
   const char *target_specific_defines = "typedef signed char BOOL;\n";
   std::string module_macros;
+  llvm::raw_string_ostream module_macros_stream(module_macros);
 
   Target *target = exe_ctx.GetTargetPtr();
   if (target) {
@@ -344,9 +345,13 @@
 
       decl_vendor->ForEachMacro(
           modules_for_macros,
-          [&module_macros](const std::string &expansion) -> bool {
-            module_macros.append(expansion);
-            module_macros.append("\n");
+          [&module_macros_stream](llvm::StringRef token,
+                                  llvm::StringRef expansion) -> bool {
+            // Check if the macro hasn't already been defined in the
+            // g_expression_prefix (which defines a few builtin macros).
+            module_macros_stream << "#ifndef " << token << "\n";
+            module_macros_stream << expansion << "\n";
+            module_macros_stream << "#endif\n";
             return false;
           });
     }
@@ -387,8 +392,8 @@
 
     StreamString wrap_stream;
 
-    wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(),
-                       debug_macros_stream.GetData(), g_expression_prefix,
+    wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", g_expression_prefix,
+                       module_macros.c_str(), debug_macros_stream.GetData(),
                        target_specific_defines, m_prefix.c_str());
 
     // First construct a tagged form of the user expression so we can find it
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -302,6 +302,41 @@
   search_opts.ImplicitModuleMaps = true;
 }
 
+/// Iff the given identifier is a C++ keyword, remove it from the
+/// identifier table (i.e., make the token a normal identifier).
+static void RemoveCppKeyword(IdentifierTable &idents, llvm::StringRef token) {
+  // FIXME: 'using' is used by LLDB for local variables, so we can't remove
+  // this keyword without breaking this functionality.
+  if (token == "using")
+    return;
+  // GCC's '__null' is used by LLDB to define NULL/Nil/nil.
+  if (token == "__null")
+    return;
+
+  LangOptions cpp_lang_opts;
+  cpp_lang_opts.CPlusPlus = true;
+  cpp_lang_opts.CPlusPlus11 = true;
+  cpp_lang_opts.CPlusPlus20 = true;
+
+  clang::IdentifierInfo &ii = idents.get(token);
+  // The identifier has to be a C++-exclusive keyword. if not, then there is
+  // nothing to do.
+  if (!ii.isCPlusPlusKeyword(cpp_lang_opts))
+    return;
+  // If the token is already an identifier, then there is nothing to do.
+  if (ii.getTokenID() == clang::tok::identifier)
+    return;
+  // Otherwise the token is a C++ keyword, so turn it back into a normal
+  // identifier.
+  ii.revertTokenIDToIdentifier();
+}
+
+/// Remove all C++ keywords from the given identifier table.
+static void RemoveAllCppKeywords(IdentifierTable &idents) {
+#define KEYWORD(NAME, FLAGS) RemoveCppKeyword(idents, llvm::StringRef(#NAME));
+#include "clang/Basic/TokenKinds.def"
+}
+
 //===----------------------------------------------------------------------===//
 // Implementation of ClangExpressionParser
 //===----------------------------------------------------------------------===//
@@ -627,6 +662,21 @@
     m_compiler->createSourceManager(m_compiler->getFileManager());
   m_compiler->createPreprocessor(TU_Complete);
 
+  switch (language) {
+  case lldb::eLanguageTypeC:
+  case lldb::eLanguageTypeC89:
+  case lldb::eLanguageTypeC99:
+  case lldb::eLanguageTypeC11:
+  case lldb::eLanguageTypeObjC:
+    // This is not a C++ expression but we enabled C++ as explained above.
+    // Remove all C++ keywords from the PP so that the user can still use
+    // variables that have C++ keywords as names (e.g. 'int template;').
+    RemoveAllCppKeywords(m_compiler->getPreprocessor().getIdentifierTable());
+    break;
+  default:
+    break;
+  }
+
   if (ClangModulesDeclVendor *decl_vendor =
           target_sp->GetClangModulesDeclVendor()) {
     if (auto *clang_persistent_vars = llvm::cast<ClangPersistentVariables>(
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to