Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[modules] Accept equivalent module caches from different symlink #90925

Merged
merged 4 commits into from
May 7, 2024

Conversation

ellishg
Copy link
Contributor

@ellishg ellishg commented May 3, 2024

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.

Use `fs::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.
```
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:modules C++20 modules and Clang Header Modules labels May 3, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented May 3, 2024

@llvm/pr-subscribers-llvm-support
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-modules

Author: Ellis Hoag (ellishg)

Changes

Use fs::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.

Full diff: https://github.com/llvm/llvm-project/pull/90925.diff

2 Files Affected:

  • (modified) clang/lib/Serialization/ASTReader.cpp (+9-11)
  • (added) clang/test/Modules/module-symlink.m (+11)
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 0ef57a3ea804ef..c20ead8b865692 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -839,17 +839,15 @@ static bool checkHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
                                      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;
+  if (!LangOpts.Modules || PPOpts.AllowPCHWithDifferentModulesCachePath ||
+      SpecificModuleCachePath == ExistingModuleCachePath ||
+      llvm::sys::fs::equivalent(SpecificModuleCachePath,
+                                ExistingModuleCachePath))
+    return false;
+  if (Diags)
+    Diags->Report(diag::err_pch_modulecache_mismatch)
+        << SpecificModuleCachePath << ExistingModuleCachePath;
+  return true;
 }
 
 bool PCHValidator::ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
diff --git a/clang/test/Modules/module-symlink.m b/clang/test/Modules/module-symlink.m
new file mode 100644
index 00000000000000..be447449a0e81e
--- /dev/null
+++ b/clang/test/Modules/module-symlink.m
@@ -0,0 +1,11 @@
+// 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
+
+// expected-no-diagnostics
+
+@import ignored_macros;
+
+struct Point p;

@ellishg ellishg requested review from akyrtzi and rmaz May 3, 2024 00:52
return false;
if (!LangOpts.Modules || PPOpts.AllowPCHWithDifferentModulesCachePath ||
SpecificModuleCachePath == ExistingModuleCachePath ||
llvm::sys::fs::equivalent(SpecificModuleCachePath,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should go through the VirtualFileSystem to be consistent with the code that reads module files. The callers of this API should both have easy access to a VFS to pass in: for SimplePCHValidator it's FileMgr.getVirtualFileSystem() and for PCHValidator it's Reader.getFileManager().getVirtualFileSystem().

You could also add a helper method to VirtualFileSystem for equivalent that does status(Path1).equivalent(status(Path2)) (plus error handling).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the advice. I realized that this does not handle the case where both paths are equal, but do not exist. In that case, no error will be thrown. Is that acceptable? I guess this was the case before this pr.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, it will fail when it tries to read anything from the cache.

@ellishg
Copy link
Contributor Author

ellishg commented May 7, 2024

@benlangmuir do you have other concerns? Can I get a stamp?

Copy link
Collaborator

@benlangmuir benlangmuir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if we rename the checkHeaderSearchOptions function.

@@ -833,32 +833,33 @@ bool SimpleASTReaderListener::ReadPreprocessorOptions(
/// against the header search options in an existing preprocessor.
///
/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
static bool checkHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
static bool checkHeaderSearchOptions(llvm::vfs::FileSystem &VFS,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize you're not changing the behaviour here, but now that we don't even pass in a HeaderSearchOptions we should probably rename this. Maybe checkModuleCachePath?

@ellishg ellishg merged commit 2ad6917 into llvm:main May 7, 2024
7 of 8 checks passed
@ellishg ellishg deleted the module-symlink branch May 7, 2024 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category llvm:support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants