diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index c75464d2fa1ad..edb01e0dbc8ef 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -115,6 +115,7 @@ class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks { ClangModulesDeclVendor &m_decl_vendor; ClangPersistentVariables &m_persistent_vars; clang::SourceManager &m_source_mgr; + /// Accumulates error messages across all moduleImport calls. StreamString m_error_stream; bool m_has_errors = false; @@ -140,11 +141,12 @@ class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks { module.path.push_back( ConstString(component.getIdentifierInfo()->getName())); - StreamString error_stream; - ClangModulesDeclVendor::ModuleVector exported_modules; - if (!m_decl_vendor.AddModule(module, &exported_modules, m_error_stream)) + if (auto err = m_decl_vendor.AddModule(module, &exported_modules)) { m_has_errors = true; + m_error_stream.PutCString(llvm::toString(std::move(err))); + m_error_stream.PutChar('\n'); + } for (ClangModulesDeclVendor::ModuleID module : exported_modules) m_persistent_vars.AddHandLoadedClangModule(module); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index ff9ed9c27f70f..ad48d293ab8f0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -383,10 +383,11 @@ bool ClangExpressionSourceCode::GetText( block->CalculateSymbolContext(&sc); if (sc.comp_unit) { - StreamString error_stream; - - decl_vendor->AddModulesForCompileUnit( - *sc.comp_unit, modules_for_macros, error_stream); + if (auto err = decl_vendor->AddModulesForCompileUnit( + *sc.comp_unit, modules_for_macros)) + LLDB_LOG_ERROR( + GetLog(LLDBLog::Expressions), std::move(err), + "Error while loading hand-imported modules:\n{0}"); } } } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index d421d6d8067b4..65709180b3287 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -92,11 +92,11 @@ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor { ~ClangModulesDeclVendorImpl() override = default; - bool AddModule(const SourceModule &module, ModuleVector *exported_modules, - Stream &error_stream) override; + llvm::Error AddModule(const SourceModule &module, + ModuleVector *exported_modules) override; - bool AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules, - Stream &error_stream) override; + llvm::Error AddModulesForCompileUnit(CompileUnit &cu, + ModuleVector &exported_modules) override; uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector &decls) override; @@ -273,16 +273,14 @@ void ClangModulesDeclVendorImpl::ReportModuleExports( exports.push_back(module); } -bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, - ModuleVector *exported_modules, - Stream &error_stream) { +llvm::Error +ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, + ModuleVector *exported_modules) { // Fail early. - if (m_compiler_instance->hadModuleLoaderFatalFailure()) { - error_stream.PutCString("error: Couldn't load a module because the module " - "loader is in a fatal state.\n"); - return false; - } + if (m_compiler_instance->hadModuleLoaderFatalFailure()) + return llvm::createStringError( + "couldn't load a module because the module loader is in a fatal state"); // Check if we've already imported this module. @@ -297,7 +295,7 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, if (mi != m_imported_modules.end()) { if (exported_modules) ReportModuleExports(*exported_modules, mi->second); - return true; + return llvm::Error::success(); } } @@ -315,30 +313,30 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, std::equal(sysroot_begin, sysroot_end, path_begin); // No need to inject search paths to modules in the sysroot. if (!is_system_module) { - auto error = [&]() { - error_stream.Printf("error: No module map file in %s\n", - module.search_path.AsCString()); - return false; - }; - bool is_system = true; bool is_framework = false; auto dir = HS.getFileMgr().getOptionalDirectoryRef( module.search_path.GetStringRef()); if (!dir) - return error(); + return llvm::createStringError( + "couldn't find module search path directory %s", + module.search_path.GetCString()); + auto file = HS.lookupModuleMapFile(*dir, is_framework); if (!file) - return error(); + return llvm::createStringError("couldn't find modulemap file in %s", + module.search_path.GetCString()); + if (HS.loadModuleMapFile(*file, is_system)) - return error(); + return llvm::createStringError( + "failed to parse and load modulemap file in %s", + module.search_path.GetCString()); } } - if (!HS.lookupModule(module.path.front().GetStringRef())) { - error_stream.Printf("error: Header search couldn't locate module '%s'\n", - module.path.front().AsCString()); - return false; - } + + if (!HS.lookupModule(module.path.front().GetStringRef())) + return llvm::createStringError("header search couldn't locate module '%s'", + module.path.front().AsCString()); llvm::SmallVector clang_path; @@ -364,22 +362,29 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, clang::Module *top_level_module = DoGetModule(clang_path.front(), false); if (!top_level_module) { + lldb_private::StreamString error_stream; diagnostic_consumer->DumpDiagnostics(error_stream); - error_stream.Printf("error: Couldn't load top-level module %s\n", - module.path.front().AsCString()); - return false; + + return llvm::createStringError(llvm::formatv( + "couldn't load top-level module {0}:\n{1}", + module.path.front().GetStringRef(), error_stream.GetString())); } clang::Module *submodule = top_level_module; for (auto &component : llvm::ArrayRef(module.path).drop_front()) { - submodule = submodule->findSubmodule(component.GetStringRef()); - if (!submodule) { + clang::Module *found = submodule->findSubmodule(component.GetStringRef()); + if (!found) { + lldb_private::StreamString error_stream; diagnostic_consumer->DumpDiagnostics(error_stream); - error_stream.Printf("error: Couldn't load submodule %s\n", - component.GetCString()); - return false; + + return llvm::createStringError(llvm::formatv( + "couldn't load submodule '{0}' of module '{1}':\n{2}", + component.GetStringRef(), submodule->getFullModuleName(), + error_stream.GetString())); } + + submodule = found; } // If we didn't make the submodule visible here, Clang wouldn't allow LLDB to @@ -399,10 +404,12 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, m_enabled = true; - return true; + return llvm::Error::success(); } - return false; + return llvm::createStringError( + llvm::formatv("unknown error while loading module {0}\n", + module.path.front().GetStringRef())); } bool ClangModulesDeclVendor::LanguageSupportsClangModules( @@ -424,15 +431,18 @@ bool ClangModulesDeclVendor::LanguageSupportsClangModules( } } -bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit( - CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules, - Stream &error_stream) { - if (LanguageSupportsClangModules(cu.GetLanguage())) { - for (auto &imported_module : cu.GetImportedModules()) - if (!AddModule(imported_module, &exported_modules, error_stream)) - return false; - } - return true; +llvm::Error ClangModulesDeclVendorImpl::AddModulesForCompileUnit( + CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules) { + if (!LanguageSupportsClangModules(cu.GetLanguage())) + return llvm::Error::success(); + + llvm::Error errors = llvm::Error::success(); + + for (auto &imported_module : cu.GetImportedModules()) + if (auto err = AddModule(imported_module, &exported_modules)) + errors = llvm::joinErrors(std::move(errors), std::move(err)); + + return errors; } // ClangImporter::lookupValue diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h index d820552a29129..9a85d7d326c6c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h @@ -42,21 +42,16 @@ class ClangModulesDeclVendor : public ClangDeclVendor { /// The path to the exact module to be loaded. E.g., if the desired /// module is std.io, then this should be { "std", "io" }. /// - /// \param[in] exported_modules + /// \param[out] exported_modules /// If non-NULL, a pointer to a vector to populate with the ID of every /// module that is re-exported by the specified module. /// - /// \param[in] error_stream - /// A stream to populate with the output of the Clang parser when - /// it tries to load the module. - /// /// \return /// True if the module could be loaded; false if not. If the /// compiler encountered a fatal error during a previous module /// load, then this will always return false for this ModuleImporter. - virtual bool AddModule(const SourceModule &module, - ModuleVector *exported_modules, - Stream &error_stream) = 0; + virtual llvm::Error AddModule(const SourceModule &module, + ModuleVector *exported_modules) = 0; /// Add all modules referred to in a given compilation unit to the list /// of modules to search. @@ -64,22 +59,17 @@ class ClangModulesDeclVendor : public ClangDeclVendor { /// \param[in] cu /// The compilation unit to scan for imported modules. /// - /// \param[in] exported_modules + /// \param[out] exported_modules /// A vector to populate with the ID of each module loaded (directly /// and via re-exports) in this way. /// - /// \param[in] error_stream - /// A stream to populate with the output of the Clang parser when - /// it tries to load the modules. - /// /// \return /// True if all modules referred to by the compilation unit could be /// loaded; false if one could not be loaded. If the compiler /// encountered a fatal error during a previous module /// load, then this will always return false for this ModuleImporter. - virtual bool AddModulesForCompileUnit(CompileUnit &cu, - ModuleVector &exported_modules, - Stream &error_stream) = 0; + virtual llvm::Error + AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules) = 0; /// Enumerate all the macros that are defined by a given set of modules /// that are already imported. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index e8d5ec3c7fd96..d1feda1f0b629 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -371,26 +371,20 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target, if (!sc.comp_unit) return; - StreamString error_stream; - ClangModulesDeclVendor::ModuleVector modules_for_macros = persistent_state->GetHandLoadedClangModules(); - if (decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros, - error_stream)) - return; - // Failed to load some modules, so emit the error stream as a diagnostic. - if (!error_stream.Empty()) { - // The error stream already contains several Clang diagnostics that might - // be either errors or warnings, so just print them all as one remark - // diagnostic to prevent that the message starts with "error: error:". - diagnostic_manager.PutString(lldb::eSeverityInfo, error_stream.GetString()); + auto err = + decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros); + if (!err) return; - } - diagnostic_manager.PutString(lldb::eSeverityError, - "Unknown error while loading modules needed for " - "current compilation unit."); + // Module load errors aren't fatal to the expression evaluator. Printing + // them as diagnostics to the console would be too noisy and misleading + // Hence just print them to the expression log. + llvm::handleAllErrors(std::move(err), [](const llvm::StringError &e) { + LLDB_LOG(GetLog(LLDBLog::Expressions), "{0}", e.getMessage()); + }); } ClangExpressionSourceCode::WrapKind ClangUserExpression::GetWrapKind() const { diff --git a/lldb/test/API/lang/objc/modules-compile-error/Makefile b/lldb/test/API/lang/objc/modules-compile-error/Makefile deleted file mode 100644 index e031aa0bbbb8d..0000000000000 --- a/lldb/test/API/lang/objc/modules-compile-error/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -OBJC_SOURCES := main.m - -CFLAGS_EXTRAS = $(MANDATORY_MODULE_BUILD_CFLAGS) -I$(BUILDDIR) -DONLY_CLANG=1 - -include Makefile.rules diff --git a/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py b/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py deleted file mode 100644 index db6d74bfdb540..0000000000000 --- a/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py +++ /dev/null @@ -1,28 +0,0 @@ -import lldb -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -from lldbsuite.test import lldbutil - - -class TestCase(TestBase): - @skipIf(compiler="clang", compiler_version=["<", "11.0"]) - def test(self): - self.build() - lldbutil.run_to_source_breakpoint( - self, "// break here", lldb.SBFileSpec("main.m") - ) - - # Try importing our custom module. This will fail as LLDB won't define - # the CLANG_ONLY define when it compiles the module for the expression - # evaluator. - # Check that the error message shows file/line/column, prints the relevant - # line from the source code and mentions the module that failed to build. - self.expect( - "expr @import LLDBTestModule", - error=True, - substrs=[ - "module.h:4:1: error: unknown type name 'syntax_error_for_lldb_to_find'", - "syntax_error_for_lldb_to_find // comment that tests source printing", - "could not build module 'LLDBTestModule'", - ], - ) diff --git a/lldb/test/API/lang/objc/modules-compile-error/main.m b/lldb/test/API/lang/objc/modules-compile-error/main.m deleted file mode 100644 index 35259dd287b01..0000000000000 --- a/lldb/test/API/lang/objc/modules-compile-error/main.m +++ /dev/null @@ -1,5 +0,0 @@ -@import LLDBTestModule; - -int main() { - return foo(); // break here -} diff --git a/lldb/test/API/lang/objc/modules-compile-error/module.h b/lldb/test/API/lang/objc/modules-compile-error/module.h deleted file mode 100644 index 2edd13b0832db..0000000000000 --- a/lldb/test/API/lang/objc/modules-compile-error/module.h +++ /dev/null @@ -1,5 +0,0 @@ -int foo() { return 123; } - -#ifndef ONLY_CLANG -syntax_error_for_lldb_to_find // comment that tests source printing -#endif diff --git a/lldb/test/API/lang/objc/modules-compile-error/module.modulemap b/lldb/test/API/lang/objc/modules-compile-error/module.modulemap deleted file mode 100644 index 3d44faf3e9080..0000000000000 --- a/lldb/test/API/lang/objc/modules-compile-error/module.modulemap +++ /dev/null @@ -1 +0,0 @@ -module LLDBTestModule { header "module.h" export * } diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_CompileFailure.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_CompileFailure.test new file mode 100644 index 0000000000000..49ee2778ea18b --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_CompileFailure.test @@ -0,0 +1,46 @@ +## Tests the case where module compilation fails. +# +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -DSHOULD_COMPILE=1 \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands.input %t.out -o exit 2>&1 | FileCheck %s + +#--- main.m +@import foo; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#ifndef SHOULD_COMPILE +#error "Compilation failure." +#endif + +#--- module.modulemap +module foo { + header "foo.h" + export * +} + +#--- commands.input +log enable lldb expr +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# CHECK: Finished building Clang module foo +# CHECK: couldn't load top-level module foo: +# CHECK: While building module 'foo' imported from LLDBModulesMemoryBuffer +# CHEKC: {{.*}}sources/foo.h{{.*}}: error: "Compilation failure." +# CHECK: LLDBModulesMemoryBuffer:1:1: fatal error: could not build module 'foo' + +# CHECK: Error while loading hand-imported modules: +# CHECK: couldn't load top-level module foo: +# CHECK-NOT: Compilation failure diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_FromExpression.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_FromExpression.test new file mode 100644 index 0000000000000..b964e9b27e914 --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_FromExpression.test @@ -0,0 +1,54 @@ +## Tests the case where we fail to import modules from @import +## statements that are part of the expression being run. +# +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# +# RUN: sed -i '' -e 's/foo\.h/baz\.h/' %t/sources/module.modulemap +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands.input %t.out -o exit 2>&1 | FileCheck %s + +#--- main.m +@import foo; +@import bar; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#--- bar.h +struct bar {}; + +#--- module.modulemap +module foo { + header "foo.h" + export * +} + +module bar { + header "bar.h" + export * +} + +#--- commands.input +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr @import Foo; @import Bar +expr @import foo + +# CHECK: error: while importing modules: +# CHECK-NEXT: header search couldn't locate module 'Foo' +# CHECK-NEXT: header search couldn't locate module 'Bar' +# +# CHECK: expr @import foo +# CHECK: error: while importing modules: +# CHECK-NEXT: couldn't load top-level module foo +## No mention of the previous import errors. +# CHECK-NOT: Foo +# CHECK-NOT: Bar diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidNestedSubmodule.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidNestedSubmodule.test new file mode 100644 index 0000000000000..1e8075dd20fad --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidNestedSubmodule.test @@ -0,0 +1,70 @@ +## Tests the case where we fail to load a submodule of a submodule. We force this +## by removing the submodule 'module qux' of 'module baz' from the modulemap. +# +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# RUN: sed -i '' -e 's/module qux/module quz/' %t/sources/module.modulemap +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=NO_LOG +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands-with-log.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=LOG + +#--- main.m +@import foo.baz.qux; +@import bar; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#--- bar.h +struct bar {}; + +#--- baz.h +struct baz {}; + +#--- qux.h +struct qux {}; + +#--- module.modulemap +module foo { + header "foo.h" + export * + + module baz { + header "baz.h" + export * + + module qux { + header "qux.h" + export * + } + } +} + +module bar { + header "bar.h" + export * +} + +#--- commands.input +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# NO_LOG-NOT: couldn't load submodule 'qux' of module 'foo.baz' + +#--- commands-with-log.input +log enable lldb expr +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# LOG: couldn't load submodule 'qux' of module 'foo.baz' diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidSearchPath.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidSearchPath.test new file mode 100644 index 0000000000000..35ba5802d2add --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidSearchPath.test @@ -0,0 +1,59 @@ +## Tests the case where the DW_AT_LLVM_include_path of the module is invalid. +## We forces this by just removing that directory (which in our case is 'sources'). +# +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# +# RUN: cp %t/sources/commands.input %t/commands.input +# RUN: cp %t/sources/commands-with-log.input %t/commands-with-log.input +# RUN: rm -r %t/sources +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/commands.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=NO_LOG +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/commands-with-log.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=LOG + +#--- main.m +@import foo; +@import bar; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#--- bar.h +struct bar {}; + +#--- module.modulemap +module foo { + header "foo.h" + export * +} + +module bar { + header "bar.h" + export * +} + +#--- commands.input +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# NO_LOG-NOT: couldn't find module search path directory {{.*}}sources +# NO_LOG-NOT: couldn't find module search path directory {{.*}}sources + +#--- commands-with-log.input +log enable lldb expr +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# LOG: couldn't find module search path directory {{.*}}sources +# LOG: couldn't find module search path directory {{.*}}sources diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidSubmodule.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidSubmodule.test new file mode 100644 index 0000000000000..1bfbbcf32ecae --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidSubmodule.test @@ -0,0 +1,62 @@ +## Tests the case where we fail to load a submodule. We force this by removing +## the submodule 'module baz' from the modulemap. +# +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# RUN: sed -i '' -e 's/module baz/module qux/' %t/sources/module.modulemap +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=NO_LOG +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands-with-log.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=LOG + +#--- main.m +@import foo.baz; +@import bar; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#--- bar.h +struct bar {}; + +#--- baz.h +struct baz {}; + +#--- module.modulemap +module foo { + header "foo.h" + export * + + module baz { + header "baz.h" + export * + } +} + +module bar { + header "bar.h" + export * +} + +#--- commands.input +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# NO_LOG-NOT: couldn't load submodule 'baz' of module 'foo' + +#--- commands-with-log.input +log enable lldb expr +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# LOG: couldn't load submodule 'baz' of module 'foo' diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidTopLevelModule.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidTopLevelModule.test new file mode 100644 index 0000000000000..ad181ee7e15e6 --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_InvalidTopLevelModule.test @@ -0,0 +1,59 @@ +## Tests the case where a module fails to load. We force this by +## replacing the contents of the 'module foo' declaration with garbage. +# +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# RUN: sed -i '' -e 's/foo\.h/baz\.h/' %t/sources/module.modulemap +# RUN: sed -i '' -e 's/bar\.h/qux\.h/' %t/sources/module.modulemap +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=NO_LOG +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands-with-log.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=LOG + +#--- main.m +@import foo; +@import bar; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#--- bar.h +struct bar {}; + +#--- module.modulemap +module foo { + header "foo.h" + export * +} + +module bar { + header "bar.h" + export * +} + +#--- commands.input +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# NO_LOG-NOT: couldn't load top-level module foo +# NO_LOG-NOT: error: header + +#--- commands-with-log.input +log enable lldb expr +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# LOG: couldn't load top-level module foo +# LOG: error: header 'baz.h' +# LOG: couldn't load top-level module bar +# LOG: error: header 'qux.h' diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_ModulemapParsing.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_ModulemapParsing.test new file mode 100644 index 0000000000000..6d8e665102b17 --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_ModulemapParsing.test @@ -0,0 +1,57 @@ +## Tests the case where the modulemap is semantically invalid and thus +## Clang fails to load it on behalf of LLDB. We force this error by +## creating a redefinition of 'module bar'. +# +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# RUN: sed -i '' -e 's/module foo/module bar/' %t/sources/module.modulemap +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=NO_LOG +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands-with-log.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=LOG + +#--- main.m +@import foo; +@import bar; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#--- bar.h +struct bar {}; + +#--- module.modulemap +module foo { + header "foo.h" + export * +} + +module bar { + header "bar.h" + export * +} + +#--- commands.input +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# NO_LOG-NOT: failed to parse and load +# NO_LOG-NOT: failed to parse and load + +#--- commands-with-log.input +log enable lldb expr +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# LOG: failed to parse and load modulemap file in {{.*}}sources +# LOG: failed to parse and load modulemap file in {{.*}}sources diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_NoModule.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_NoModule.test new file mode 100644 index 0000000000000..bcb8a7d2c5594 --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_NoModule.test @@ -0,0 +1,58 @@ +## Tests the case where the module LLDB is trying to load isn't +## present in the modulemap. We force this by replacing 'module foo' +## in the modulemap. +# +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# RUN: sed -i '' -e 's/module foo/module baz/' %t/sources/module.modulemap +# RUN: sed -i '' -e 's/module bar/module qux/' %t/sources/module.modulemap +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=NO_LOG +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands-with-log.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=LOG + +#--- main.m +@import foo; +@import bar; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#--- bar.h +struct bar {}; + +#--- module.modulemap +module foo { + header "foo.h" + export * +} + +module bar { + header "bar.h" + export * +} + +#--- commands.input +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# NO_LOG-NOT: header search couldn't locate module 'foo' +# NO_LOG-NOT: header search couldn't locate module 'bar' + +#--- commands-with-log.input +log enable lldb expr +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# LOG: header search couldn't locate module 'foo' +# LOG: header search couldn't locate module 'bar' diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_NoModuleMap.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_NoModuleMap.test new file mode 100644 index 0000000000000..57f7f16cc84dd --- /dev/null +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_NoModuleMap.test @@ -0,0 +1,53 @@ +# REQUIRES: system-darwin +# +# RUN: split-file %s %t/sources +# RUN: %clang_host -g %t/sources/main.m -fmodules -fcxx-modules \ +# RUN: -fmodule-map-file=%t/sources/module.modulemap \ +# RUN: -fmodules-cache-path=%t/ModuleCache -o %t.out +# RUN: rm %t/sources/module.modulemap +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=NO_LOG +# +# RUN: %lldb -x -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -s %t/sources/commands-with-log.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=LOG + +#--- main.m +@import foo; +@import bar; + +int main() { __builtin_debugtrap(); } + +#--- foo.h +struct foo {}; + +#--- bar.h +struct bar {}; + +#--- module.modulemap +module foo { + header "foo.h" + export * +} + +module bar { + header "bar.h" + export * +} + +#--- commands.input +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# NO_LOG-NOT: couldn't find modulemap +# NO_LOG-NOT: couldn't find modulemap + +#--- commands-with-log.input +log enable lldb expr +run +## Make sure expression fails so the 'note' diagnostics get printed. +expr blah + +# LOG: couldn't find modulemap file in {{.*}}sources +# LOG: couldn't find modulemap file in {{.*}}sources