Author: Michael Spencer
Date: 2026-10-12T22:01:48-07:00
New Revision: f1e644b1f1d7eeb577925d52dfc8c7e22e88dc57

URL: 
https://github.com/llvm/llvm-project/commit/f1e644b1f1d7eeb577925d52dfc8c7e22e88dc57
DIFF: 
https://github.com/llvm/llvm-project/commit/f1e644b1f1d7eeb577925d52dfc8c7e22e88dc57.diff

LOG: [clang][Serialization] Make directory dependencies absolute when read 
(#231319)

Directory dependencies under a module's base directory are stored
relative to it, and the reader's base directory isn't always absolute:
with relocation checks enabled it is taken from where header search
found the module, which is relative through a relative search path, and
with -fmodule-file-home-is-cwd there is none. These directories were
then read back relative, so `directory-deps` reported them relative and
they never matched the absolute paths a build system reports as
invalidated.

Canonicalize them when reading the same way they are when recorded.

Assisted-by: Claude Code: opus-5.5

Added: 
    

Modified: 
    clang/include/clang/Lex/ModuleMap.h
    clang/lib/Lex/ModuleMap.cpp
    clang/lib/Serialization/ASTReader.cpp
    clang/test/ClangScanDeps/modules-directory-deps.c
    clang/test/Modules/validate-directory-dependencies.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Lex/ModuleMap.h 
b/clang/include/clang/Lex/ModuleMap.h
index d2d15da8c0343..18e77cc28ce4b 100644
--- a/clang/include/clang/Lex/ModuleMap.h
+++ b/clang/include/clang/Lex/ModuleMap.h
@@ -735,6 +735,11 @@ class ModuleMap {
   /// Record that \p Mod depends on the listing of \p Dir. \p Dir is a VFS 
path.
   void recordDirectoryDependencies(Module *Mod, StringRef Dir);
 
+  /// Spell \p Path the way directory dependencies are recorded: absolute, with
+  /// dots removed.
+  static void canonicalizeDirectoryDependency(const FileManager &FileMgr,
+                                              SmallVectorImpl<char> &Path);
+
   /// Sets the umbrella directory of the given module to the given directory.
   void setUmbrellaDirAsWritten(Module *Mod, DirectoryEntryRef UmbrellaDir,
                                const Twine &NameAsWritten,

diff  --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 3187a23fe6c09..b75f5c98ba72b 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -1357,12 +1357,17 @@ void ModuleMap::recordDirectoryDependencies(Module 
*Mod, StringRef Dir) {
   FileMgr.getVirtualFileSystem().getDirectoryContentRealSources(Dir, Sources);
   for (StringRef Source : Sources) {
     SmallString<256> Canonical(Source);
-    FileMgr.makeAbsolutePath(Canonical);
-    llvm::sys::path::remove_dots(Canonical, /*remove_dot_dot=*/true);
+    canonicalizeDirectoryDependency(FileMgr, Canonical);
     Mod->addDirectoryDependency(Canonical);
   }
 }
 
+void ModuleMap::canonicalizeDirectoryDependency(const FileManager &FileMgr,
+                                                SmallVectorImpl<char> &Path) {
+  FileMgr.makeAbsolutePath(Path);
+  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+}
+
 void ModuleMap::setUmbrellaDirAsWritten(
     Module *Mod, DirectoryEntryRef UmbrellaDir, const Twine &NameAsWritten,
     const Twine &PathRelativeToRootModuleDirectory, SourceLocation Loc) {

diff  --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index 16ec15179e5b3..e6f6be496e5e5 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -4881,8 +4881,13 @@ void ASTReader::ReadDirectoryDependencies(const 
RecordData &Record,
   unsigned Idx = 0;
   unsigned N = Record[Idx++];
   F.DirectoryDependencies.reserve(N);
-  for (unsigned I = 0; I != N; ++I)
-    F.DirectoryDependencies.push_back(ReadPath(F, Record, Idx));
+  for (unsigned I = 0; I != N; ++I) {
+    // The base directory is relative if the module was found through a
+    // relative search path, and empty with -fmodule-file-home-is-cwd.
+    SmallString<256> Dir(ReadPath(F, Record, Idx));
+    ModuleMap::canonicalizeDirectoryDependency(FileMgr, Dir);
+    F.DirectoryDependencies.push_back(std::string(Dir));
+  }
 }
 
 bool ASTReader::isDirectoryDependencyOutOfDate(ModuleFile &F, bool Complain) {

diff  --git a/clang/test/ClangScanDeps/modules-directory-deps.c 
b/clang/test/ClangScanDeps/modules-directory-deps.c
index 0199415f46fdc..802c7f1e588fe 100644
--- a/clang/test/ClangScanDeps/modules-directory-deps.c
+++ b/clang/test/ClangScanDeps/modules-directory-deps.c
@@ -122,6 +122,34 @@ module UmbHdr {
 
 // FW-SUB: 
"[[PREFIX]]/frameworks/Inferred.framework/Frameworks/Sub.framework/Headers/Sub.h"
 
+// 7) With -fmodule-file-home-is-cwd the module file has no base directory, so
+//    directories under the working directory are stored relative to it. They
+//    are still reported, and matched, as absolute paths.
+// RUN: sed "s|DIR|%/t|g" %t/home-cdb.json.template > %t/home-cdb.json
+// RUN: clang-scan-deps -compilation-database %t/home-cdb.json \
+// RUN:   -format experimental-full 2>&1 | sed 's:\\\\\?:/:g' \
+// RUN:   | FileCheck %s -DPREFIX=%/t --check-prefix=HOME
+
+// HOME:      "directory-deps": [
+// HOME-NEXT:   "[[PREFIX]]/include/Umb/sub"
+// HOME-NEXT: ]
+// HOME:      "name": "UmbDir"
+
+// RUN: sleep 1
+// RUN: touch %t/include/Umb/sub/d.h
+// RUN: clang-scan-deps -compilation-database %t/home-cdb.json \
+// RUN:   -format experimental-full -invalidated-path=%/t/include/Umb/sub 2>&1 
\
+// RUN:   | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t 
--check-prefix=HOME-FRESH
+
+// HOME-FRESH: "[[PREFIX]]/include/Umb/sub/d.h"
+
+//--- home-cdb.json.template
+[{
+  "file": "DIR/tu.c",
+  "directory": "DIR",
+  "command": "clang -fmodules -fmodules-cache-path=DIR/home-cache -I 
DIR/include -Xclang -fmodule-file-home-is-cwd -c DIR/tu.c -o DIR/tu.o"
+}]
+
 //--- frameworks/module.modulemap
 framework module * {}
 

diff  --git a/clang/test/Modules/validate-directory-dependencies.c 
b/clang/test/Modules/validate-directory-dependencies.c
index e03e295996673..678cb4a04ebb5 100644
--- a/clang/test/Modules/validate-directory-dependencies.c
+++ b/clang/test/Modules/validate-directory-dependencies.c
@@ -61,6 +61,19 @@
 // RUN: %{fw} -fmodules-validate-directory-dependencies \
 // RUN:   | FileCheck %s --check-prefix=NO-BUILD --allow-empty
 
+// A module found through a relative search path still depends on absolute
+// directories.
+// RUN: cd %t && %clang_cc1 -fsyntax-only -fmodules -fimplicit-module-maps \
+// RUN:   -fmodules-cache-path=%t/rel-cache -I include tu.c
+// RUN: sleep 1
+// RUN: touch %t/include/umbrella/nested/added-later.h
+// RUN: cd %t && %clang_cc1 -fsyntax-only -fmodules -fimplicit-module-maps \
+// RUN:   -fmodules-cache-path=%t/rel-cache -I include tu.c \
+// RUN:   -fmodules-validate-directory-dependencies -Rmodule-validation 2>&1 \
+// RUN:   | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t 
--check-prefix=RELATIVE
+
+// RELATIVE: remark: module 'Umbrella' is out of date because the contents of 
directory '[[PREFIX]]/include/umbrella/nested' changed after it was built
+
 // RUN: %clang -### -fmodules -fmodules-validate-directory-dependencies \
 // RUN:   -c %t/tu.c 2>&1 | FileCheck %s --check-prefix=DRIVER
 // RUN: %clang -### -fmodules-validate-directory-dependencies -c %t/tu.c 2>&1 \


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

Reply via email to