Author: Ellis Hoag Date: 2024-05-07T13:55:44-07:00 New Revision: 2ad6917c4c524576405f2146424911fd9adb3528
URL: https://github.com/llvm/llvm-project/commit/2ad6917c4c524576405f2146424911fd9adb3528 DIFF: https://github.com/llvm/llvm-project/commit/2ad6917c4c524576405f2146424911fd9adb3528.diff LOG: [modules] Accept equivalent module caches from different symlink (#90925) Use `VFS.equivalent()`, which follows symlinks, to check if two module cache paths are equivalent. This prevents a PCH error when building from a different path that is a symlink of the original. ``` error: PCH was compiled with module cache path '/home/foo/blah/ModuleCache/2IBP1TNT8OR8D', but the path is currently '/data/users/foo/blah/ModuleCache/2IBP1TNT8OR8D' 1 error generated. ``` Added: clang/test/Modules/module-symlink.m Modified: clang/lib/Serialization/ASTReader.cpp llvm/include/llvm/Support/VirtualFileSystem.h llvm/lib/Support/VirtualFileSystem.cpp Removed: ################################################################################ diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index b4b2f999d2259..856c743086c51 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -829,36 +829,37 @@ bool SimpleASTReaderListener::ReadPreprocessorOptions( OptionValidateNone); } -/// Check the header search options deserialized from the control block -/// against the header search options in an existing preprocessor. +/// Check that the specified and the existing module cache paths are equivalent. /// /// \param Diags If non-null, produce diagnostics for any mismatches incurred. -static bool checkHeaderSearchOptions(const HeaderSearchOptions &HSOpts, - StringRef SpecificModuleCachePath, - StringRef ExistingModuleCachePath, - DiagnosticsEngine *Diags, - const LangOptions &LangOpts, - const PreprocessorOptions &PPOpts) { - if (LangOpts.Modules) { - if (SpecificModuleCachePath != ExistingModuleCachePath && - !PPOpts.AllowPCHWithDifferentModulesCachePath) { - if (Diags) - Diags->Report(diag::err_pch_modulecache_mismatch) - << SpecificModuleCachePath << ExistingModuleCachePath; - return true; - } - } - - return false; +/// \returns true when the module cache paths diff er. +static bool checkModuleCachePath(llvm::vfs::FileSystem &VFS, + StringRef SpecificModuleCachePath, + StringRef ExistingModuleCachePath, + DiagnosticsEngine *Diags, + const LangOptions &LangOpts, + const PreprocessorOptions &PPOpts) { + if (!LangOpts.Modules || PPOpts.AllowPCHWithDifferentModulesCachePath || + SpecificModuleCachePath == ExistingModuleCachePath) + return false; + auto EqualOrErr = + VFS.equivalent(SpecificModuleCachePath, ExistingModuleCachePath); + if (EqualOrErr && *EqualOrErr) + return false; + if (Diags) + Diags->Report(diag::err_pch_modulecache_mismatch) + << SpecificModuleCachePath << ExistingModuleCachePath; + return true; } bool PCHValidator::ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) { - return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath, - PP.getHeaderSearchInfo().getModuleCachePath(), - Complain ? &Reader.Diags : nullptr, - PP.getLangOpts(), PP.getPreprocessorOpts()); + return checkModuleCachePath(Reader.getFileManager().getVirtualFileSystem(), + SpecificModuleCachePath, + PP.getHeaderSearchInfo().getModuleCachePath(), + Complain ? &Reader.Diags : nullptr, + PP.getLangOpts(), PP.getPreprocessorOpts()); } void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) { @@ -5376,9 +5377,9 @@ namespace { bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) override { - return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath, - ExistingModuleCachePath, nullptr, - ExistingLangOpts, ExistingPPOpts); + return checkModuleCachePath( + FileMgr.getVirtualFileSystem(), SpecificModuleCachePath, + ExistingModuleCachePath, nullptr, ExistingLangOpts, ExistingPPOpts); } bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, diff --git a/clang/test/Modules/module-symlink.m b/clang/test/Modules/module-symlink.m new file mode 100644 index 0000000000000..efdaf3db0dfef --- /dev/null +++ b/clang/test/Modules/module-symlink.m @@ -0,0 +1,14 @@ +// REQUIRES: shell + +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules-cache-path=%t/modules -fmodules -fimplicit-module-maps -I %S/Inputs -emit-pch -o %t.pch %s -verify + +// RUN: ln -s %t/modules %t/modules.symlink +// RUN: %clang_cc1 -fmodules-cache-path=%t/modules.symlink -fmodules -fimplicit-module-maps -I %S/Inputs -include-pch %t.pch %s -verify +// RUN: not %clang_cc1 -fmodules-cache-path=%t/modules.dne -fmodules -fimplicit-module-maps -I %S/Inputs -include-pch %t.pch %s -verify + +// expected-no-diagnostics + +@import ignored_macros; + +struct Point p; diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h index 49e67e7555a0d..a1e38de74dfcc 100644 --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -320,6 +320,10 @@ class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem>, /// platform-specific error_code. virtual std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const; + /// \returns true if \p A and \p B represent the same file, or an error or + /// false if they do not. + llvm::ErrorOr<bool> equivalent(const Twine &A, const Twine &B); + enum class PrintType { Summary, Contents, RecursiveContents }; void print(raw_ostream &OS, PrintType Type = PrintType::Contents, unsigned IndentLevel = 0) const { diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index 152fcfe695b29..54b9c38f76095 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -151,6 +151,16 @@ bool FileSystem::exists(const Twine &Path) { return Status && Status->exists(); } +llvm::ErrorOr<bool> FileSystem::equivalent(const Twine &A, const Twine &B) { + auto StatusA = status(A); + if (!StatusA) + return StatusA.getError(); + auto StatusB = status(B); + if (!StatusB) + return StatusB.getError(); + return StatusA->equivalent(*StatusB); +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void FileSystem::dump() const { print(dbgs(), PrintType::RecursiveContents); } #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits