[clang] clang: normalise inputs for Windows more aggresively (PR #181306)
Saleem Abdulrasool via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 13 21:46:13 PST 2026
https://github.com/compnerd updated https://github.com/llvm/llvm-project/pull/181306
>From 23140956adf733273428d421a2825bf921e9167b Mon Sep 17 00:00:00 2001
From: Saleem Abdulrasool <compnerd at compnerd.org>
Date: Thu, 12 Feb 2026 20:35:34 -0800
Subject: [PATCH] clang: normalise directories in FileManager uniformly
Adjust the `FileManager` by extracting the key normalization logic and
apply it at a second site. This is important to ensure that we use the
same key everywhere.
---
clang/lib/Basic/FileManager.cpp | 43 ++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp
index 6d6ea5b84369b..3ad9c79c8969a 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_path(Path))) {
+ Storage = Path.str() + ".";
+ Path = *Storage;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// Common logic.
//===----------------------------------------------------------------------===//
@@ -104,6 +125,9 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
if (DirName.empty())
DirName = ".";
+ std::optional<std::string> Storage;
+ normalizeCacheKey(DirName, Storage);
+
auto &NamedDirEnt = *SeenDirEntries.insert(
{DirName, std::errc::no_such_file_or_directory}).first;
@@ -136,23 +160,8 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
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;
- }
- }
+ std::optional<std::string> Storage;
+ normalizeCacheKey(DirName, Storage);
++NumDirLookups;
More information about the cfe-commits
mailing list