https://github.com/Bigcheese created 
https://github.com/llvm/llvm-project/pull/192171

There are build systems that put explicitly built modules in the same module 
cache directory as implicitly built modules. Pruning those in an implicit build 
can cause the build to fail due to missing modules.

rdar://174790709

>From 8392cb1880c02e1b1b7f24f896527d11b4cc3a82 Mon Sep 17 00:00:00 2001
From: Michael Spencer <[email protected]>
Date: Tue, 14 Apr 2026 17:52:14 -0700
Subject: [PATCH] [clang][modules] Don't prune the top level module cache for
 implicitly built modules

There are build systems that put explicitly built modules in the same
module cache directory as implicitly built modules. Pruning those in
an implicit build can cause the build to fail.

rdar://174790709
---
 .../include/clang/Serialization/ModuleCache.h |  3 ++-
 clang/lib/Serialization/ModuleCache.cpp       |  5 ++--
 clang/test/Modules/prune-no-toplevel.m        | 24 +++++++++++++++++++
 clang/tools/libclang/BuildSystem.cpp          |  3 ++-
 4 files changed, 31 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/Modules/prune-no-toplevel.m

diff --git a/clang/include/clang/Serialization/ModuleCache.h 
b/clang/include/clang/Serialization/ModuleCache.h
index 82c4cde37c5ff..dcac8ee9890a9 100644
--- a/clang/include/clang/Serialization/ModuleCache.h
+++ b/clang/include/clang/Serialization/ModuleCache.h
@@ -70,7 +70,8 @@ class ModuleCache {
 std::shared_ptr<ModuleCache> createCrossProcessModuleCache();
 
 /// Shared implementation of `ModuleCache::maybePrune()`.
-void maybePruneImpl(StringRef Path, time_t PruneInterval, time_t PruneAfter);
+void maybePruneImpl(StringRef Path, time_t PruneInterval, time_t PruneAfter,
+                    bool PruneTopLevel = false);
 
 /// Shared implementation of `ModuleCache::write()`.
 std::error_code writeImpl(StringRef Path, llvm::MemoryBufferRef Buffer);
diff --git a/clang/lib/Serialization/ModuleCache.cpp 
b/clang/lib/Serialization/ModuleCache.cpp
index 9ea4223a2eb83..d2d3d3fd9ed76 100644
--- a/clang/lib/Serialization/ModuleCache.cpp
+++ b/clang/lib/Serialization/ModuleCache.cpp
@@ -26,7 +26,7 @@ static void writeTimestampFile(StringRef TimestampFile) {
 }
 
 void clang::maybePruneImpl(StringRef Path, time_t PruneInterval,
-                           time_t PruneAfter) {
+                           time_t PruneAfter, bool PruneTopLevel) {
   if (PruneInterval <= 0 || PruneAfter <= 0)
     return;
 
@@ -95,7 +95,8 @@ void clang::maybePruneImpl(StringRef Path, time_t 
PruneInterval,
        Dir != DirEnd && !EC; Dir.increment(EC)) {
     // If we don't have a directory, try to prune it as a file in the root.
     if (!llvm::sys::fs::is_directory(Dir->path())) {
-      TryPruneFile(Dir->path());
+      if (PruneTopLevel)
+        TryPruneFile(Dir->path());
       continue;
     }
 
diff --git a/clang/test/Modules/prune-no-toplevel.m 
b/clang/test/Modules/prune-no-toplevel.m
new file mode 100644
index 0000000000000..93810b66d399c
--- /dev/null
+++ b/clang/test/Modules/prune-no-toplevel.m
@@ -0,0 +1,24 @@
+// NetBSD: noatime mounts currently inhibit 'touch -a' updates
+// UNSUPPORTED: system-netbsd
+
+// Test that implicit module builds don't prune top-level files in the module
+// cache directory.
+
+// Set up a module cache with a timestamp old enough to trigger pruning, a
+// top-level .pcm, and a stale .pcm in a subdirectory.
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/cache/subdir
+// RUN: touch -m -a -t 201101010000 %t/cache/modules.timestamp
+// RUN: touch -a -t 201101010000 %t/cache/toplevel.pcm
+// RUN: touch -a -t 201101010000 %t/cache/subdir/stale.pcm
+
+// Run the compiler to trigger pruning.
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache 
-fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify
+
+// The top-level .pcm file should still exist.
+// RUN: ls %t/cache/toplevel.pcm
+
+// The subdirectory .pcm file should have been pruned.
+// RUN: not ls %t/cache/subdir/stale.pcm
+
+// expected-no-diagnostics
diff --git a/clang/tools/libclang/BuildSystem.cpp 
b/clang/tools/libclang/BuildSystem.cpp
index e81f69d9960f2..c2319e184f5ef 100644
--- a/clang/tools/libclang/BuildSystem.cpp
+++ b/clang/tools/libclang/BuildSystem.cpp
@@ -155,5 +155,6 @@ void 
clang_ModuleMapDescriptor_dispose(CXModuleMapDescriptor MMD) {
 void clang_ModuleCache_prune(const char *Path, time_t PruneInterval,
                              time_t PruneAfter) {
   if (Path)
-    clang::maybePruneImpl(Path, PruneInterval, PruneAfter);
+    clang::maybePruneImpl(Path, PruneInterval, PruneAfter,
+                          /*PruneTopLevel=*/true);
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to