Author: Saleem Abdulrasool Date: 2026-02-18T13:58:38-08:00 New Revision: 7548ad01ab17a6892264032b19cf19be1d182bea
URL: https://github.com/llvm/llvm-project/commit/7548ad01ab17a6892264032b19cf19be1d182bea DIFF: https://github.com/llvm/llvm-project/commit/7548ad01ab17a6892264032b19cf19be1d182bea.diff LOG: clang: normalise directory cache keys consistently in `FileManager` (#181306) Extract the directory path normalisation logic into a shared `normalizeCacheKey` helper and apply it in `addAncestorsAsVirtualDirs` in addition to `getDirectoryRef`. This ensures that cache lookups and insertions use a consistent key at all call sites. Co-authored-by: Corentin Jabot <[email protected]> Added: Modified: clang/lib/Basic/FileManager.cpp Removed: ################################################################################ diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index 6d6ea5b84369b..44092efd74717 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -38,6 +38,27 @@ using namespace clang; #define DEBUG_TYPE "file-search" +static void normalizeCacheKey(StringRef &Path, + std::optional<std::string> &Storage) { + using namespace llvm::sys::path; + + // Drop trailing separators for non-root paths so that cache keys and `stat` + // queries use a single spelling. Keep root paths (`/`, `[A-Z]:\`) unchanged. + if (Path.size() > 1 && root_path(Path) != Path && is_separator(Path.back())) + Path = Path.drop_back(); + + // A bare drive path like "[A-Z]:" is drive-relative (current directory on the + // drive). As `[A-Z]:` is not a path specification, we must canonicalise it + // to `[A-Z]:.`. + if (is_style_windows(Style::native)) { + if (Path.size() > 1 && Path.back() == ':' && + Path.equals_insensitive(root_name(Path))) { + Storage = Path.str() + "."; + Path = *Storage; + } + } +} + //===----------------------------------------------------------------------===// // Common logic. //===----------------------------------------------------------------------===// @@ -104,6 +125,13 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { if (DirName.empty()) DirName = "."; + // Normalize the key for cache lookup/insert, but keep the original DirName + // for recursive processing since normalization can create paths that don't + // work well with parent_path() (e.g., "C:" -> "C:."). + std::optional<std::string> Storage; + StringRef OriginalDirName = DirName; + normalizeCacheKey(DirName, Storage); + auto &NamedDirEnt = *SeenDirEntries.insert( {DirName, std::errc::no_such_file_or_directory}).first; @@ -131,28 +159,13 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { } // Recursively add the other ancestors. - addAncestorsAsVirtualDirs(DirName); + addAncestorsAsVirtualDirs(OriginalDirName); } llvm::Expected<DirectoryEntryRef> FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { - // stat doesn't like trailing separators except for root directory. - // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'. - // (though it can strip '\\') - if (DirName.size() > 1 && - DirName != llvm::sys::path::root_path(DirName) && - llvm::sys::path::is_separator(DirName.back())) - DirName = DirName.drop_back(); std::optional<std::string> DirNameStr; - if (is_style_windows(llvm::sys::path::Style::native)) { - // Fixing a problem with "clang C:test.c" on Windows. - // Stat("C:") does not recognize "C:" as a valid directory - if (DirName.size() > 1 && DirName.back() == ':' && - DirName.equals_insensitive(llvm::sys::path::root_name(DirName))) { - DirNameStr = DirName.str() + '.'; - DirName = *DirNameStr; - } - } + normalizeCacheKey(DirName, DirNameStr); ++NumDirLookups; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
