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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits