From e2795607279966ae05426b812d364519b197d2ca Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Wed, 7 Jun 2023 17:24:36 -0700 Subject: [PATCH] [Frontend] Ignore adjacent swiftmodule in compiler host modules `lib/swift/host` contains modules/libraries that are built by the host compiler. Their `.swiftmodule` will never be able to be read, ignore them entirely. (cherry picked from commit ee3a47b62491c67c049d945e7e5ad7e6e169190f) --- include/swift/AST/DiagnosticsFrontend.def | 3 +- include/swift/Basic/StringExtras.h | 3 ++ lib/AST/Module.cpp | 16 ++-------- lib/Basic/StringExtras.cpp | 13 ++++++++ lib/Frontend/ModuleInterfaceLoader.cpp | 31 +++++++++++++++++-- .../ignore-adjacent-host-module.swift | 26 ++++++++++++++++ 6 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 test/ModuleInterface/ignore-adjacent-host-module.swift diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 3fa76d96073d1..d125861cc90a7 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -440,7 +440,8 @@ NOTE(sdk_version_pbm_version,none, NOTE(compiled_module_ignored_reason,none, "compiled module '%0' was ignored because %select{%error" "|it belongs to a framework in the SDK" - "|loading from module interfaces is preferred}1", + "|loading from module interfaces is preferred" + "|it's a compiler host module}1", (StringRef, unsigned)) NOTE(out_of_date_module_here,none, "%select{compiled|cached|forwarding|prebuilt}0 module is out of date: '%1'", diff --git a/include/swift/Basic/StringExtras.h b/include/swift/Basic/StringExtras.h index 211ea71c801c1..606abf8329b2e 100644 --- a/include/swift/Basic/StringExtras.h +++ b/include/swift/Basic/StringExtras.h @@ -519,6 +519,9 @@ class NullTerminatedStringRef { /// where escaped Unicode characters lead to malformed/invalid JSON. void writeEscaped(llvm::StringRef Str, llvm::raw_ostream &OS); +/// Whether the path components of `path` begin with those from `prefix`. +bool pathStartsWith(StringRef prefix, StringRef path); + } // end namespace swift #endif // SWIFT_BASIC_STRINGEXTRAS_H diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index ff26e73cf039c..f4db87ab55853 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -43,6 +43,7 @@ #include "swift/Basic/Compiler.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" +#include "swift/Basic/StringExtras.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/Parse/Token.h" #include "swift/Strings.h" @@ -4222,18 +4223,6 @@ FrontendStatsTracer::getTraceFormatter() { return &TF; } -static bool prefixMatches(StringRef prefix, StringRef path) { - auto prefixIt = llvm::sys::path::begin(prefix), - prefixEnd = llvm::sys::path::end(prefix); - for (auto pathIt = llvm::sys::path::begin(path), - pathEnd = llvm::sys::path::end(path); - prefixIt != prefixEnd && pathIt != pathEnd; ++prefixIt, ++pathIt) { - if (*prefixIt != *pathIt) - return false; - } - return prefixIt == prefixEnd; -} - bool IsNonUserModuleRequest::evaluate(Evaluator &evaluator, ModuleDecl *mod) const { // stdlib is non-user by definition if (mod->isStdlibModule()) @@ -4261,5 +4250,6 @@ bool IsNonUserModuleRequest::evaluate(Evaluator &evaluator, ModuleDecl *mod) con return false; StringRef runtimePath = searchPathOpts.RuntimeResourcePath; - return (!runtimePath.empty() && prefixMatches(runtimePath, modulePath)) || (!sdkPath.empty() && prefixMatches(sdkPath, modulePath)); + return (!runtimePath.empty() && pathStartsWith(runtimePath, modulePath)) || + (!sdkPath.empty() && pathStartsWith(sdkPath, modulePath)); } diff --git a/lib/Basic/StringExtras.cpp b/lib/Basic/StringExtras.cpp index 99170b27f5e7e..a2cdf482f2493 100644 --- a/lib/Basic/StringExtras.cpp +++ b/lib/Basic/StringExtras.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include @@ -1417,3 +1418,15 @@ void swift::writeEscaped(llvm::StringRef Str, llvm::raw_ostream &OS) { } } } + +bool swift::pathStartsWith(StringRef prefix, StringRef path) { + auto prefixIt = llvm::sys::path::begin(prefix), + prefixEnd = llvm::sys::path::end(prefix); + for (auto pathIt = llvm::sys::path::begin(path), + pathEnd = llvm::sys::path::end(path); + prefixIt != prefixEnd && pathIt != pathEnd; ++prefixIt, ++pathIt) { + if (*prefixIt != *pathIt) + return false; + } + return prefixIt == prefixEnd; +} diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index d5d1fd470c638..d90388db17c6d 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -20,6 +20,7 @@ #include "swift/AST/FileSystem.h" #include "swift/AST/Module.h" #include "swift/Basic/Platform.h" +#include "swift/Basic/StringExtras.h" #include "swift/Frontend/Frontend.h" #include "swift/Frontend/ModuleInterfaceSupport.h" #include "swift/Parse/ParseVersion.h" @@ -227,6 +228,7 @@ struct ModuleRebuildInfo { NotIgnored, PublicFramework, InterfacePreferred, + CompilerHostModule, }; struct CandidateModule { std::string path; @@ -698,7 +700,28 @@ class ModuleInterfaceLoaderImpl { bool isInResourceDir(StringRef path) { StringRef resourceDir = ctx.SearchPathOpts.RuntimeResourcePath; if (resourceDir.empty()) return false; - return path.startswith(resourceDir); + return pathStartsWith(resourceDir, path); + } + + bool isInResourceHostDir(StringRef path) { + StringRef resourceDir = ctx.SearchPathOpts.RuntimeResourcePath; + if (resourceDir.empty()) return false; + + SmallString<128> hostPath; + llvm::sys::path::append(hostPath, + resourceDir, "host"); + return pathStartsWith(hostPath, path); + } + + bool isInSystemFrameworks(StringRef path) { + StringRef sdkPath = ctx.SearchPathOpts.getSDKPath(); + if (sdkPath.empty()) return false; + + SmallString<128> publicFrameworksPath; + llvm::sys::path::append(publicFrameworksPath, + sdkPath, "System", "Library", "Frameworks"); + + return pathStartsWith(publicFrameworksPath, path); } std::pair getCompiledModuleCandidates() { @@ -713,10 +736,12 @@ class ModuleInterfaceLoaderImpl { llvm::sys::path::append(publicFrameworksPath, ctx.SearchPathOpts.getSDKPath(), "System", "Library", "Frameworks"); - if (!ctx.SearchPathOpts.getSDKPath().empty() && - modulePath.startswith(publicFrameworksPath)) { + if (isInSystemFrameworks(modulePath)) { shouldLoadAdjacentModule = false; rebuildInfo.addIgnoredModule(modulePath, ReasonIgnored::PublicFramework); + } else if (isInResourceHostDir(modulePath)) { + shouldLoadAdjacentModule = false; + rebuildInfo.addIgnoredModule(modulePath, ReasonIgnored::CompilerHostModule); } switch (loadMode) { diff --git a/test/ModuleInterface/ignore-adjacent-host-module.swift b/test/ModuleInterface/ignore-adjacent-host-module.swift new file mode 100644 index 0000000000000..1abe459da9e01 --- /dev/null +++ b/test/ModuleInterface/ignore-adjacent-host-module.swift @@ -0,0 +1,26 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/build/host) +// RUN: %empty-directory(%t/cache) +// RUN: split-file %s %t + +/// Modules loaded from within lib/swift/host should also be rebuilt from +/// their interface (which actually means anything within resource-dir/host). + +// RUN: %target-swift-frontend -emit-module %t/Lib.swift \ +// RUN: -swift-version 5 -enable-library-evolution \ +// RUN: -parse-stdlib -module-cache-path %t/cache \ +// RUN: -o %t/build/host -emit-module-interface-path %t/build/host/Lib.swiftinterface + +// RUN: %target-swift-frontend -typecheck %t/Client.swift \ +// RUN: -resource-dir %t/build -I %t/build/host \ +// RUN: -parse-stdlib -module-cache-path %t/cache \ +// RUN: -Rmodule-loading 2>&1 | %FileCheck %s + +// CHECK: remark: loaded module 'Lib'; source: '{{.*}}{{/|\\}}host{{/|\\}}Lib.swiftinterface', loaded: '{{.*}}{{/|\\}}cache{{/|\\}}Lib-{{.*}}.swiftmodule' + +//--- Lib.swift +public func foo() {} + +//--- Client.swift +import Lib +foo()