[clang] f1e644b - [clang][Serialization] Make directory dependencies absolute when read (#231319)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 12 22:01:55 PDT 2026
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 \
More information about the cfe-commits
mailing list