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
