teemperor created this revision. teemperor added reviewers: aprantl, shafik. teemperor added a project: C++ modules in LLDB. Herald added subscribers: lldb-commits, jdoerfert, abidh, mgrang. Herald added a project: LLDB.
This patch adds basic support for importing C++ modules in general into the LLDB expression evaluator. It mostly reuses the code we already use for the std module prototype for building/importing the modules, but is using a different logic for querying the modules from the executable. The current functionality is limited - like the first std module patch - to only reading module information but not merging or substituting debug information. Unlike the std module prototype, this feature now requires that we compile with `-gmodules`, as this is the only way we have all modules (even modules that were just imported but not actually used) in the debug information. Without this, we run into frequent build errors as soon as some module includes another module without actually using it. This leads to the situation where Clang will not emit the module in the debug information (as it's unused), but LLDB will fail to compile the C++ module as it still needs the include paths of the unused module. This is why we now have a `GetAllUsedModules` that works similar to `GetImportedModules` but actually creates a complete list of all modules we have used in a given compilation unit. This allows LLDB to fully reconstruct the original include directories. Repository: rLLDB LLDB https://reviews.llvm.org/D61606 Files: lldb/include/lldb/Symbol/CompileUnit.h lldb/include/lldb/Symbol/SourceModule.h lldb/include/lldb/Symbol/SymbolFile.h lldb/include/lldb/Symbol/SymbolVendor.h lldb/include/lldb/Target/Target.h lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/TestFunctionImportCxxModules.py lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/foo.h lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/module.modulemap lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/TestMacroImportCxxModules.py lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/foo.h lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/module.modulemap lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/TestMultiIncDirImportCxxModules.py lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/foo.h lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/a.h lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/module.modulemap lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/b.h lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/module.modulemap lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/module.modulemap lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/TestTemplateImportCxxModules.py lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/foo.h lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/module.modulemap lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h lldb/source/Symbol/CompileUnit.cpp lldb/source/Symbol/SymbolVendor.cpp lldb/source/Target/Target.cpp
Index: lldb/source/Target/Target.cpp =================================================================== --- lldb/source/Target/Target.cpp +++ lldb/source/Target/Target.cpp @@ -3339,6 +3339,9 @@ {"import-std-module", OptionValue::eTypeBoolean, false, false, nullptr, {}, "Import the C++ std module to improve debugging STL containers."}, + {"import-c++-modules", OptionValue::eTypeBoolean, false, false, + nullptr, {}, + "Import the executable's C++ modules to improve debugging."}, {"auto-apply-fixits", OptionValue::eTypeBoolean, false, true, nullptr, {}, "Automatically apply fix-it hints to expressions."}, {"notify-about-fixits", OptionValue::eTypeBoolean, false, true, nullptr, @@ -3478,6 +3481,7 @@ ePropertyClangModuleSearchPaths, ePropertyAutoImportClangModules, ePropertyImportStdModule, + ePropertyImportCxxModules, ePropertyAutoApplyFixIts, ePropertyNotifyAboutFixIts, ePropertySaveObjects, @@ -3911,6 +3915,12 @@ nullptr, idx, g_properties[idx].default_uint_value != 0); } +bool TargetProperties::GetEnableImportCxxModules() const { + const uint32_t idx = ePropertyImportCxxModules; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); +} + bool TargetProperties::GetEnableAutoApplyFixIts() const { const uint32_t idx = ePropertyAutoApplyFixIts; return m_collection_sp->GetPropertyAtIndexAsBoolean( Index: lldb/source/Symbol/SymbolVendor.cpp =================================================================== --- lldb/source/Symbol/SymbolVendor.cpp +++ lldb/source/Symbol/SymbolVendor.cpp @@ -187,6 +187,17 @@ return false; } +bool SymbolVendor::ParseAllUsedModules(const SymbolContext &sc, + std::vector<SourceModule> &all_modules) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + if (m_sym_file_up) + return m_sym_file_up->ParseAllModules(sc, all_modules); + } + return false; +} + size_t SymbolVendor::ParseBlocksRecursive(Function &func) { ModuleSP module_sp(GetModule()); if (module_sp) { Index: lldb/source/Symbol/CompileUnit.cpp =================================================================== --- lldb/source/Symbol/CompileUnit.cpp +++ lldb/source/Symbol/CompileUnit.cpp @@ -397,6 +397,19 @@ return m_imported_modules; } +const std::vector<SourceModule> &CompileUnit::GetAllUsedModules() { + if (m_all_used_modules.empty() && m_flags.IsClear(flagsParsedAllModules)) { + m_flags.Set(flagsParsedAllModules); + if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) { + SymbolContext sc; + CalculateSymbolContext(&sc); + + symbol_vendor->ParseAllUsedModules(sc, m_all_used_modules); + } + } + return m_all_used_modules; +} + FileSpecList &CompileUnit::GetSupportFiles() { if (m_support_files.GetSize() == 0) { if (m_flags.IsClear(flagsParsedSupportFiles)) { Index: lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h =================================================================== --- lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -59,6 +59,12 @@ const lldb_private::SymbolContext &sc, std::vector<lldb_private::SourceModule> &imported_modules) override; + bool ParseAllModules( + const lldb_private::SymbolContext &sc, + std::vector<lldb_private::SourceModule> &imported_modules) override { + return false; + } + size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t Index: lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h =================================================================== --- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -70,6 +70,12 @@ const lldb_private::SymbolContext &sc, std::vector<lldb_private::SourceModule> &imported_modules) override; + bool ParseAllModules( + const lldb_private::SymbolContext &sc, + std::vector<lldb_private::SourceModule> &imported_modules) override { + return false; + } + size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -92,6 +92,12 @@ const SymbolContext &sc, std::vector<lldb_private::SourceModule> &imported_modules) override; + bool ParseAllModules( + const SymbolContext &sc, + std::vector<lldb_private::SourceModule> &imported_modules) override { + return false; + } + size_t ParseBlocksRecursive(Function &func) override; uint32_t FindGlobalVariables(ConstString name, Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -66,6 +66,9 @@ bool ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::SourceModule> &imported_modules) override; + bool ParseAllModules( + const lldb_private::SymbolContext &sc, + std::vector<lldb_private::SourceModule> &imported_modules) override; size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -675,6 +675,14 @@ return false; } +bool SymbolFileDWARFDebugMap::ParseAllModules( + const SymbolContext &sc, std::vector<SourceModule> &imported_modules) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); + if (oso_dwarf) + return oso_dwarf->ParseAllModules(sc, imported_modules); + return false; +} + size_t SymbolFileDWARFDebugMap::ParseBlocksRecursive(Function &func) { CompileUnit *comp_unit = func.GetCompileUnit(); if (!comp_unit) Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -117,6 +117,9 @@ bool ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::SourceModule> &imported_modules) override; + bool ParseAllModules( + const lldb_private::SymbolContext &sc, + std::vector<lldb_private::SourceModule> &imported_modules) override; size_t ParseBlocksRecursive(lldb_private::Function &func) override; Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -896,36 +896,46 @@ return false; } -bool SymbolFileDWARF::ParseImportedModules( - const lldb_private::SymbolContext &sc, - std::vector<SourceModule> &imported_modules) { - ASSERT_MODULE_LOCK(this); - assert(sc.comp_unit); - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); - if (!dwarf_cu) - return false; - if (!ClangModulesDeclVendor::LanguageSupportsClangModules( - sc.comp_unit->GetLanguage())) - return false; - UpdateExternalModuleListIfNeeded(); - +/// Parses the modules in the given DWARFUnit. +/// \param dwarf_cu The DWARFUnit that should be searched for modules. +/// \param only_imported_modules True if only modules that are imported should +/// be parsed. False if all modules should be +/// parsed. +/// \param modules A list of SourceModules found in the DWARFUnit. +/// \return True iff no error occurred while parsing the modules. +static bool ParseModules(DWARFUnit *dwarf_cu, bool only_imported_modules, + std::vector<SourceModule> &modules) { const DWARFDIE die = dwarf_cu->DIE(); if (!die) return false; for (DWARFDIE child_die = die.GetFirstChild(); child_die; child_die = child_die.GetSibling()) { - if (child_die.Tag() != DW_TAG_imported_declaration) - continue; + DWARFDIE module_die; + + if (only_imported_modules) { + if (child_die.Tag() != DW_TAG_imported_declaration) + continue; + + module_die = child_die.GetReferencedDIE(DW_AT_import); + } else + module_die = child_die; - DWARFDIE module_die = child_die.GetReferencedDIE(DW_AT_import); if (module_die.Tag() != DW_TAG_module) continue; - if (const char *name = + if (const char *name_str = module_die.GetAttributeValueAsString(DW_AT_name, nullptr)) { + + ConstString name(name_str); + + // Clang emits some modulemap files as module tags, so we have to + // filter them out here as they are not actual SourceModules. + if (name == "module.modulemap") + continue; + SourceModule module; - module.path.push_back(ConstString(name)); + module.path.push_back(name); DWARFDIE parent_die = module_die; while ((parent_die = parent_die.GetParent())) { @@ -942,12 +952,59 @@ if (const char *sysroot = module_die.GetAttributeValueAsString( DW_AT_LLVM_isysroot, nullptr)) module.sysroot = ConstString(sysroot); - imported_modules.push_back(module); + modules.push_back(module); } } return true; } +bool SymbolFileDWARF::ParseImportedModules( + const lldb_private::SymbolContext &sc, + std::vector<SourceModule> &imported_modules) { + ASSERT_MODULE_LOCK(this); + assert(sc.comp_unit); + + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (!dwarf_cu) + return false; + if (!ClangModulesDeclVendor::LanguageSupportsClangModules( + sc.comp_unit->GetLanguage())) + return false; + UpdateExternalModuleListIfNeeded(); + + return ParseModules(dwarf_cu, /*only_imported*/ true, imported_modules); +} + +bool SymbolFileDWARF::ParseAllModules(const lldb_private::SymbolContext &sc, + std::vector<SourceModule> &all_modules) { + ASSERT_MODULE_LOCK(this); + assert(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (!dwarf_cu) + return false; + if (!ClangModulesDeclVendor::LanguageSupportsClangModules( + sc.comp_unit->GetLanguage())) + return false; + UpdateExternalModuleListIfNeeded(); + + // Recursively descend into the referenced modules and add their used + // modules to our list. + for (auto &n : m_external_type_modules) { + ModuleSP module = n.second; + + // The first compile unit should contain all used modules. + if (module->GetNumCompileUnits() == 0) + continue; + CompUnitSP comp_unit = module->GetCompileUnitAtIndex(0); + + const std::vector<SourceModule> &m = comp_unit->GetAllUsedModules(); + all_modules.insert(all_modules.end(), m.begin(), m.end()); + } + + // Parse all used modules in the current compile unit. + return ParseModules(dwarf_cu, /*only_imported*/ false, all_modules); +} + struct ParseDWARFLineTableCallbackInfo { LineTable *line_table; std::unique_ptr<LineSequence> sequence_up; Index: lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h =================================================================== --- lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -69,6 +69,12 @@ return false; } + bool ParseAllModules( + const SymbolContext &sc, + std::vector<lldb_private::SourceModule> &imported_modules) override { + return false; + } + size_t ParseBlocksRecursive(Function &func) override { return 0; } uint32_t FindGlobalVariables(ConstString name, Index: lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -445,7 +445,11 @@ return {}; Target *target = exe_ctx.GetTargetPtr(); - if (!target || !target->GetEnableImportStdModule()) + if (!target) + return {}; + + if (!target->GetEnableImportStdModule() && + !target->GetEnableImportCxxModules()) return {}; StackFrame *frame = exe_ctx.GetFramePtr(); @@ -461,24 +465,47 @@ if (!sc.comp_unit) return {}; + // Get the list of modules we need to to import. For the `std` module it's + // enough to search the list of directly imported modules, but for a general + // module import we need to get all used modules to reconstruct the relevant + // include directories. + const std::vector<SourceModule> &module_list = + target->GetEnableImportCxxModules() ? sc.comp_unit->GetAllUsedModules() + : sc.comp_unit->GetImportedModules(); + if (log) { - for (const SourceModule &m : sc.comp_unit->GetImportedModules()) { + for (const SourceModule &m : module_list) { LLDB_LOG(log, "Found module in compile unit: {0:$[.]} - include dir: {1}", llvm::make_range(m.path.begin(), m.path.end()), m.search_path); } } - for (const SourceModule &m : sc.comp_unit->GetImportedModules()) - m_include_directories.push_back(m.search_path); + // Build a list of include directories used by these modules. + for (const SourceModule &m : module_list) { + if (!m.search_path.IsEmpty()) + m_include_directories.push_back(m.search_path); + } + + // If we only need the `std` module we can just iterate the list and check + // if `std` or any of its submodule was imported. + if (target->GetEnableImportStdModule()) { + // Check if we imported 'std' or any of its submodules. + for (const SourceModule &m : module_list) + if (!m.path.empty() && m.path.front() == "std") + return {"std"}; + return {}; + } - // Check if we imported 'std' or any of its submodules. - // We currently don't support importing any other modules in the expression - // parser. - for (const SourceModule &m : sc.comp_unit->GetImportedModules()) - if (!m.path.empty() && m.path.front() == "std") - return {"std"}; + // If we want to import all C++ modules we have to + assert(target->GetEnableImportCxxModules()); + std::vector<std::string> result; + for (const SourceModule &m : module_list) + result.push_back(m.path.front().GetCString()); - return {}; + // Filter out any duplicates as importing a module once is enough. + std::sort(result.begin(), result.end()); + result.erase(std::unique(result.begin(), result.end()), result.end()); + return result; } bool ClangUserExpression::PrepareForParsing( Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -220,8 +220,10 @@ HeaderSearchOptions &search_opts = compiler->getHeaderSearchOpts(); + std::set<ConstString> added_inc_dirs; for (ConstString dir : include_directories) { - search_opts.AddPath(dir.AsCString(), frontend::System, false, true); + search_opts.AddPath(dir.AsCString(), frontend::IncludeDirGroup::Angled, + false, true); LLDB_LOG(log, "Added user include dir: {0}", dir); } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/module.modulemap @@ -0,0 +1 @@ +module Foo { header "foo.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char **argv) { + // Set break point at this line. + return 0; +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/foo.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/foo.h @@ -0,0 +1,14 @@ +#ifndef FOO_H +#define FOO_H + +template<typename T> +int add(T a, T b) { + return a + b; +} + +template<unsigned I> +struct Foo { + static unsigned get() { return I; } +}; + +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/TestTemplateImportCxxModules.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/TestTemplateImportCxxModules.py @@ -0,0 +1,25 @@ +""" +Test importing a C++ module and using its templates. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ImportCxxModuleMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["gmodules"]) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # Activate importing of std module. + self.runCmd("settings set target.import-c++-modules true") + # Call our template functions. + self.expect("expr add(2, 3)", substrs=['(int) $0 = 5']) + self.expect("expr Foo<42>::get()", substrs=['(unsigned int)', '= 42']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/module.modulemap @@ -0,0 +1 @@ +module Foo { header "foo.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char **argv) { + // Set break point at this line. + return 0; +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/module.modulemap @@ -0,0 +1 @@ +module Inc2 { header "b.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/b.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/b.h @@ -0,0 +1,4 @@ +#ifndef B_H +#define B_H +int foo() { return 33; } +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/module.modulemap @@ -0,0 +1 @@ +module Inc1 { header "a.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/a.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/a.h @@ -0,0 +1,4 @@ +#ifndef A_H +#define A_H +#include "b.h" +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/foo.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/foo.h @@ -0,0 +1,4 @@ +#ifndef FOO_H +#define FOO_H +#include "a.h" +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/TestMultiIncDirImportCxxModules.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/TestMultiIncDirImportCxxModules.py @@ -0,0 +1,25 @@ +""" +Test importing a C++ module with multiple include directories. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ImportCxxModuleMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["gmodules"]) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # Activate importing of std module. + self.runCmd("settings set target.import-c++-modules true") + self.runCmd("log enable lldb expr") + # Call our function in the nested module. + self.expect("expr foo()", substrs=['(int)', '= 33']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) -I $(SRCDIR)/inc1 -I $(SRCDIR)/inc2 +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/module.modulemap @@ -0,0 +1 @@ +module Foo { header "foo.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char **argv) { + // Set break point at this line. + return 0; +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/foo.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/foo.h @@ -0,0 +1,6 @@ +#ifndef FOO_H +#define FOO_H + +#define my_abs(x) (x)<0?-(x):(x) + +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/TestMacroImportCxxModules.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/TestMacroImportCxxModules.py @@ -0,0 +1,32 @@ +""" +Test importing a C++ module and using its macros. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ImportCxxModuleMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["gmodules"]) + # As ASTReader's generations are currently out of sync when + # multiplexing ExternalASTSources (which is what we do in LLDB), + # this test currently fails. + @expectedFailureAll(bugnumber="reviews.llvm.org/D39714") + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # Activate importing of std module. + self.runCmd("settings set target.import-c++-modules true") + # Call our macro. + self.expect("expr my_abs(-42)", substrs=['(int) $0 = 42']) + # Call it again. The first macro may be defined from the module built + # process, but the second time we are reusing an on-disk module where + # we fail due to out of sync ASTReader generation. + self.expect("expr my_abs(-42)", substrs=['(int) $0 = 42']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/module.modulemap @@ -0,0 +1 @@ +module Foo { header "foo.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char **argv) { + // Set break point at this line. + return 0; +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/foo.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/foo.h @@ -0,0 +1,8 @@ +#ifndef FOO_H +#define FOO_H + +int add(int a, int b) { + return a + b; +} + +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/TestFunctionImportCxxModules.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/TestFunctionImportCxxModules.py @@ -0,0 +1,24 @@ +""" +Test importing a C++ module and using its functions. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ImportCxxModuleMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["gmodules"]) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # Activate importing of std module. + self.runCmd("settings set target.import-c++-modules true") + # Call our functions. + self.expect("expr add(2, 3)", substrs=['(int)', '= 5']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/include/lldb/Target/Target.h =================================================================== --- lldb/include/lldb/Target/Target.h +++ lldb/include/lldb/Target/Target.h @@ -131,6 +131,8 @@ bool GetEnableImportStdModule() const; + bool GetEnableImportCxxModules() const; + bool GetEnableAutoApplyFixIts() const; bool GetEnableNotifyAboutFixIts() const; Index: lldb/include/lldb/Symbol/SymbolVendor.h =================================================================== --- lldb/include/lldb/Symbol/SymbolVendor.h +++ lldb/include/lldb/Symbol/SymbolVendor.h @@ -61,6 +61,9 @@ ParseImportedModules(const SymbolContext &sc, std::vector<SourceModule> &imported_modules); + virtual bool ParseAllUsedModules(const SymbolContext &sc, + std::vector<SourceModule> &all_modules); + virtual size_t ParseBlocksRecursive(Function &func); virtual size_t ParseVariablesForContext(const SymbolContext &sc); Index: lldb/include/lldb/Symbol/SymbolFile.h =================================================================== --- lldb/include/lldb/Symbol/SymbolFile.h +++ lldb/include/lldb/Symbol/SymbolFile.h @@ -125,6 +125,9 @@ virtual bool ParseImportedModules(const SymbolContext &sc, std::vector<SourceModule> &imported_modules) = 0; + virtual bool ParseAllModules(const SymbolContext &sc, + std::vector<SourceModule> &all_modules) = 0; + virtual size_t ParseBlocksRecursive(Function &func) = 0; virtual size_t ParseVariablesForContext(const SymbolContext &sc) = 0; virtual Type *ResolveTypeUID(lldb::user_id_t type_uid) = 0; Index: lldb/include/lldb/Symbol/SourceModule.h =================================================================== --- lldb/include/lldb/Symbol/SourceModule.h +++ lldb/include/lldb/Symbol/SourceModule.h @@ -20,6 +20,18 @@ std::vector<ConstString> path; ConstString search_path; ConstString sysroot; + + /// Comparison operator for two SourceModules. Only useful for imposing a + /// total order on list of SourceModules so that they can be std::sorted. + bool operator<(const SourceModule &o) const { + return std::tie(path, search_path, sysroot) < + std::tie(o.path, o.search_path, o.sysroot); + } + + bool operator==(const SourceModule &o) const { + return std::tie(path, search_path, sysroot) == + std::tie(o.path, o.search_path, o.sysroot); + } }; } // namespace lldb_private Index: lldb/include/lldb/Symbol/CompileUnit.h =================================================================== --- lldb/include/lldb/Symbol/CompileUnit.h +++ lldb/include/lldb/Symbol/CompileUnit.h @@ -243,6 +243,16 @@ /// A list of imported modules. const std::vector<SourceModule> &GetImportedModules(); + /// Get all modules used to compile this compile unit. + /// + /// This reports all modules used directly or indirectly by this compile unit. + /// For example, if this compile unit uses a module A which in turn uses a + /// module B, this function returns both A and B. + /// + /// \return + /// A list of used modules. + const std::vector<SourceModule> &GetAllUsedModules(); + /// Get the SymbolFile plug-in user data. /// /// SymbolFile plug-ins can store user data to internal state or objects to @@ -384,6 +394,9 @@ /// All modules, including the current module, imported by this /// compile unit. std::vector<SourceModule> m_imported_modules; + /// All modules, including the current module, used directly or indirectly + /// by this compile unit. + std::vector<SourceModule> m_all_used_modules; /// Files associated with this compile unit's line table and /// declarations. FileSpecList m_support_files; @@ -404,14 +417,15 @@ flagsParsedVariables = (1u << 1), ///< Have we already parsed globals and statics? flagsParsedSupportFiles = (1u << 2), ///< Have we already parsed the support - ///files for this compile unit? + /// files for this compile unit? flagsParsedLineTable = (1u << 3), ///< Have we parsed the line table already? flagsParsedLanguage = (1u << 4), ///< Have we parsed the language already? flagsParsedImportedModules = (1u << 5), ///< Have we parsed the imported modules already? + flagsParsedAllModules = (1u << 6), ///< Have we parsed all modules already? flagsParsedDebugMacros = - (1u << 6) ///< Have we parsed the debug macros already? + (1u << 7) ///< Have we parsed the debug macros already? }; DISALLOW_COPY_AND_ASSIGN(CompileUnit);
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits