diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 1401f7324fd0f..13cc2bd42b0a4 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -496,6 +496,12 @@ namespace swift { /// Enable verification when every SubstitutionMap is constructed. bool VerifyAllSubstitutionMaps = false; + /// If set to true, the source manager will avoid memory mapping source files + /// with the expectation they may change on disk. This is most useful when + /// opening files under sourcekitd on Windows, as memory mapping on Windows + /// prevents files from being written. + bool OpenSourcesAsVolatile = false; + /// Load swiftmodule files in memory as volatile and avoid mmap. bool EnableVolatileModules = false; diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index 350ea0744d948..ced1aa5b88f7c 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -94,6 +94,7 @@ class SourceManager { private: llvm::SourceMgr LLVMSourceMgr; llvm::IntrusiveRefCntPtr FileSystem; + bool OpenSourcesAsVolatile = false; unsigned IDEInspectionTargetBufferID = 0U; unsigned IDEInspectionTargetOffset; @@ -166,6 +167,12 @@ class SourceManager { return FileSystem; } + // Setting this prevents SourceManager from memory mapping sources (via opening files + // with isVolatile=true); + void setOpenSourcesAsVolatile() { + OpenSourcesAsVolatile = true; + } + void setIDEInspectionTarget(unsigned BufferID, unsigned Offset) { assert(BufferID != 0U && "Buffer should be valid"); diff --git a/lib/Basic/SourceLoc.cpp b/lib/Basic/SourceLoc.cpp index 07e2b5bc743cb..fc201c1f8eeac 100644 --- a/lib/Basic/SourceLoc.cpp +++ b/lib/Basic/SourceLoc.cpp @@ -695,7 +695,11 @@ unsigned SourceManager::getExternalSourceBufferID(StringRef Path) { return It->getSecond(); } unsigned Id = 0u; - auto InputFileOrErr = swift::vfs::getFileOrSTDIN(*getFileSystem(), Path); + auto InputFileOrErr = + swift::vfs::getFileOrSTDIN(*getFileSystem(), Path, + /* FileSize */ -1, + /* RequiresNullTerminator */ true, + /* isVolatile */ this->OpenSourcesAsVolatile); if (InputFileOrErr) { // This assertion ensures we can look up from the map in the future when // using the same Path. diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 19fef52dca664..2cd914838e57d 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -553,6 +553,10 @@ bool CompilerInstance::setup(const CompilerInvocation &Invoke, Invocation.getSearchPathOptions().dump(LangOpts.Target.isOSDarwin()); } + if (LangOpts.OpenSourcesAsVolatile) { + this->getSourceMgr().setOpenSourcesAsVolatile(); + } + // If we expect an implicit stdlib import, load in the standard library. If we // either fail to find it or encounter an error while loading it, bail early. Continuing will at best // trigger a bunch of other errors due to the stdlib being missing, or at diff --git a/lib/IDETool/CompilerInvocation.cpp b/lib/IDETool/CompilerInvocation.cpp index 47556d28f91a2..a3a7a5cd0e89d 100644 --- a/lib/IDETool/CompilerInvocation.cpp +++ b/lib/IDETool/CompilerInvocation.cpp @@ -225,6 +225,11 @@ bool ide::initCompilerInvocation( LangOpts.AttachCommentsToDecls = true; LangOpts.DiagnosticsEditorMode = true; LangOpts.CollectParsedToken = true; + #if defined(_WIN32) + // Source files that might be open in an editor should not be memory mapped on Windows, + // as they will become read-only. + LangOpts.OpenSourcesAsVolatile = true; + #endif if (LangOpts.PlaygroundTransform) { // The playground instrumenter changes the AST in ways that disrupt the // SourceKit functionality. Since we don't need the instrumenter, and all we