diff --git a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp index da4eb759df5b3..1d47d73048a0d 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp @@ -57,6 +57,7 @@ #include "clang/Driver/Driver.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" @@ -64,6 +65,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/TargetSelect.h" @@ -1594,9 +1596,50 @@ void SwiftASTContext::AddExtraClangArgs(const std::vector &source, } } +namespace { + +bool HasNonexistentExplicitModule(const std::vector &args) { + for (const std::string &arg : args) { + StringRef value = arg; + if (!value.consume_front("-fmodule-file=")) + continue; + StringRef path = value; + size_t eq = value.find('='); + // The value that follows is in one of two formats: + // 1. ModuleName=ModulePath + // 2. ModulePath + if (eq != std::string::npos) + // The value appears to be in ModuleName=ModulePath forat. + path = value.drop_front(eq + 1); + // Check both path and value. This is to handle paths containing '='. + if (!llvm::sys::fs::exists(path) && !llvm::sys::fs::exists(value)) { + std::string m_description; + HEALTH_LOG_PRINTF("Nonexistent explicit module file %s", arg.data()); + return true; + } + } + return false; +} + +void RemoveExplicitModules(std::vector &args) { + llvm::erase_if(args, [](const std::string &arg) { + if (arg == "-fno-implicit-modules" || arg == "-fno-implicit-module-maps") + return true; + StringRef s = arg; + if (s.starts_with("-fmodule-file=") || s.starts_with("-fmodule-map-file=")) + return true; + + return false; + }); +} + +} // namespace + void SwiftASTContext::AddExtraClangArgs(const std::vector &ExtraArgs) { swift::ClangImporterOptions &importer_options = GetClangImporterOptions(); AddExtraClangArgs(ExtraArgs, importer_options.ExtraArgs); + if (HasNonexistentExplicitModule(importer_options.ExtraArgs)) + RemoveExplicitModules(importer_options.ExtraArgs); } void SwiftASTContext::AddUserClangArgs(TargetProperties &props) { diff --git a/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/Makefile b/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/Makefile new file mode 100644 index 0000000000000..c5e32f304d138 --- /dev/null +++ b/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/Makefile @@ -0,0 +1,4 @@ +SWIFT_SOURCES := main.swift +SWIFT_ENABLE_EXPLICIT_MODULES := YES +USE_PRIVATE_MODULE_CACHE := YES +include Makefile.rules diff --git a/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/TestSwiftExplicitModulesImplicitFallback.py b/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/TestSwiftExplicitModulesImplicitFallback.py new file mode 100644 index 0000000000000..86fc09ba8474c --- /dev/null +++ b/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/TestSwiftExplicitModulesImplicitFallback.py @@ -0,0 +1,30 @@ +import shutil +import lldb +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbtest as lldbtest +import lldbsuite.test.lldbutil as lldbutil + + +class TestCase(lldbtest.TestBase): + @swiftTest + @skipIf(oslist=["linux"], bugnumber="rdar://124691219") + def test_missing_explicit_modules(self): + """Test missing explicit Swift modules and fallback to implicit modules.""" + self.build() + + # This test verifies the case where explicit modules are missing. + # Remove explicit modules from their place in the module cache. + mod_cache = self.getBuildArtifact("private-module-cache") + shutil.rmtree(mod_cache) + + lldbutil.run_to_source_breakpoint( + self, "Set breakpoint here", lldb.SBFileSpec("main.swift") + ) + + log = self.getBuildArtifact("types.log") + self.runCmd(f"log enable lldb types -f '{log}'") + + self.expect("expression c", substrs=["hello implicit fallback"]) + + self.filecheck(f"platform shell cat {log}", __file__) + # CHECK: Nonexistent explicit module file diff --git a/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/main.swift b/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/main.swift new file mode 100644 index 0000000000000..1481f2c8298a9 --- /dev/null +++ b/lldb/test/API/lang/swift/explicit_modules/implicit_fallback/main.swift @@ -0,0 +1,10 @@ +class Class { + var msg : String = "hello implicit fallback" +} + +func main() { + let c = Class() + print(c) // Set breakpoint here +} + +main()