Skip to content

Commit 2ad6917

Browse files
authored
[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. ```
1 parent a70ad96 commit 2ad6917

File tree

4 files changed

+55
-26
lines changed

4 files changed

+55
-26
lines changed

clang/lib/Serialization/ASTReader.cpp

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -829,36 +829,37 @@ bool SimpleASTReaderListener::ReadPreprocessorOptions(
829829
OptionValidateNone);
830830
}
831831

832-
/// Check the header search options deserialized from the control block
833-
/// against the header search options in an existing preprocessor.
832+
/// Check that the specified and the existing module cache paths are equivalent.
834833
///
835834
/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
836-
static bool checkHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
837-
StringRef SpecificModuleCachePath,
838-
StringRef ExistingModuleCachePath,
839-
DiagnosticsEngine *Diags,
840-
const LangOptions &LangOpts,
841-
const PreprocessorOptions &PPOpts) {
842-
if (LangOpts.Modules) {
843-
if (SpecificModuleCachePath != ExistingModuleCachePath &&
844-
!PPOpts.AllowPCHWithDifferentModulesCachePath) {
845-
if (Diags)
846-
Diags->Report(diag::err_pch_modulecache_mismatch)
847-
<< SpecificModuleCachePath << ExistingModuleCachePath;
848-
return true;
849-
}
850-
}
851-
852-
return false;
835+
/// \returns true when the module cache paths differ.
836+
static bool checkModuleCachePath(llvm::vfs::FileSystem &VFS,
837+
StringRef SpecificModuleCachePath,
838+
StringRef ExistingModuleCachePath,
839+
DiagnosticsEngine *Diags,
840+
const LangOptions &LangOpts,
841+
const PreprocessorOptions &PPOpts) {
842+
if (!LangOpts.Modules || PPOpts.AllowPCHWithDifferentModulesCachePath ||
843+
SpecificModuleCachePath == ExistingModuleCachePath)
844+
return false;
845+
auto EqualOrErr =
846+
VFS.equivalent(SpecificModuleCachePath, ExistingModuleCachePath);
847+
if (EqualOrErr && *EqualOrErr)
848+
return false;
849+
if (Diags)
850+
Diags->Report(diag::err_pch_modulecache_mismatch)
851+
<< SpecificModuleCachePath << ExistingModuleCachePath;
852+
return true;
853853
}
854854

855855
bool PCHValidator::ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
856856
StringRef SpecificModuleCachePath,
857857
bool Complain) {
858-
return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
859-
PP.getHeaderSearchInfo().getModuleCachePath(),
860-
Complain ? &Reader.Diags : nullptr,
861-
PP.getLangOpts(), PP.getPreprocessorOpts());
858+
return checkModuleCachePath(Reader.getFileManager().getVirtualFileSystem(),
859+
SpecificModuleCachePath,
860+
PP.getHeaderSearchInfo().getModuleCachePath(),
861+
Complain ? &Reader.Diags : nullptr,
862+
PP.getLangOpts(), PP.getPreprocessorOpts());
862863
}
863864

864865
void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
@@ -5376,9 +5377,9 @@ namespace {
53765377
bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
53775378
StringRef SpecificModuleCachePath,
53785379
bool Complain) override {
5379-
return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
5380-
ExistingModuleCachePath, nullptr,
5381-
ExistingLangOpts, ExistingPPOpts);
5380+
return checkModuleCachePath(
5381+
FileMgr.getVirtualFileSystem(), SpecificModuleCachePath,
5382+
ExistingModuleCachePath, nullptr, ExistingLangOpts, ExistingPPOpts);
53825383
}
53835384

53845385
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,

clang/test/Modules/module-symlink.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// REQUIRES: shell
2+
3+
// RUN: rm -rf %t
4+
// RUN: %clang_cc1 -fmodules-cache-path=%t/modules -fmodules -fimplicit-module-maps -I %S/Inputs -emit-pch -o %t.pch %s -verify
5+
6+
// RUN: ln -s %t/modules %t/modules.symlink
7+
// RUN: %clang_cc1 -fmodules-cache-path=%t/modules.symlink -fmodules -fimplicit-module-maps -I %S/Inputs -include-pch %t.pch %s -verify
8+
// RUN: not %clang_cc1 -fmodules-cache-path=%t/modules.dne -fmodules -fimplicit-module-maps -I %S/Inputs -include-pch %t.pch %s -verify
9+
10+
// expected-no-diagnostics
11+
12+
@import ignored_macros;
13+
14+
struct Point p;

llvm/include/llvm/Support/VirtualFileSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,10 @@ class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem>,
320320
/// platform-specific error_code.
321321
virtual std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const;
322322

323+
/// \returns true if \p A and \p B represent the same file, or an error or
324+
/// false if they do not.
325+
llvm::ErrorOr<bool> equivalent(const Twine &A, const Twine &B);
326+
323327
enum class PrintType { Summary, Contents, RecursiveContents };
324328
void print(raw_ostream &OS, PrintType Type = PrintType::Contents,
325329
unsigned IndentLevel = 0) const {

llvm/lib/Support/VirtualFileSystem.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ bool FileSystem::exists(const Twine &Path) {
151151
return Status && Status->exists();
152152
}
153153

154+
llvm::ErrorOr<bool> FileSystem::equivalent(const Twine &A, const Twine &B) {
155+
auto StatusA = status(A);
156+
if (!StatusA)
157+
return StatusA.getError();
158+
auto StatusB = status(B);
159+
if (!StatusB)
160+
return StatusB.getError();
161+
return StatusA->equivalent(*StatusB);
162+
}
163+
154164
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
155165
void FileSystem::dump() const { print(dbgs(), PrintType::RecursiveContents); }
156166
#endif

0 commit comments

Comments
 (0)