https://github.com/grqz updated https://github.com/llvm/llvm-project/pull/178585

>From 024e3b5f3cb938f5d8fb957b739ebc21173b4344 Mon Sep 17 00:00:00 2001
From: Hans Wennborg <[email protected]>
Date: Thu, 29 Jan 2026 14:10:14 +1300
Subject: [PATCH 1/2] Add support for case-insensitive path lookup

This is a port of <https://reviews.llvm.org/D21113>.
Adds clang/cc1 option -fcase-insensitive-paths. (wiNdoWS.H -> Windows.h)
This commit also adds a COFF lld-link flag --case-insensitive-paths for
case-insensitive library lookup (uuid.lib -> Uuid.lib).
--case-insensitive-paths is NOT automatically passed to the linker when
-fcase-insensitive-paths is passed.

Co-authored-by: Hans Wennborg <[email protected]>
Co-authored-by: grqz <[email protected]>
---
 .../clang/Frontend/CompilerInvocation.h       |   5 +-
 clang/include/clang/Lex/HeaderSearchOptions.h |   6 +-
 clang/include/clang/Options/Options.td        |   5 +
 clang/lib/Driver/ToolChains/Clang.cpp         |   3 +
 clang/lib/Frontend/ASTUnit.cpp                |   3 +-
 clang/lib/Frontend/CompilerInvocation.cpp     |  26 +++--
 clang/lib/Lex/HeaderSearch.cpp                |   4 +-
 clang/test/Driver/cl-options.c                |   1 +
 clang/test/Frontend/case-insensitive-paths.c  |   8 ++
 lld/COFF/Driver.cpp                           |  34 +++---
 lld/COFF/Options.td                           |   2 +
 lld/test/COFF/case-insensitive-paths.test     |   2 +
 llvm/include/llvm/Support/VirtualFileSystem.h |  36 ++++++
 llvm/lib/Support/VirtualFileSystem.cpp        | 104 ++++++++++++++++++
 .../Support/VirtualFileSystemTest.cpp         |  56 +++++++++-
 15 files changed, 262 insertions(+), 33 deletions(-)
 create mode 100644 clang/test/Frontend/case-insensitive-paths.c
 create mode 100644 lld/test/COFF/case-insensitive-paths.test

diff --git a/clang/include/clang/Frontend/CompilerInvocation.h 
b/clang/include/clang/Frontend/CompilerInvocation.h
index 6fa6cd5d95534..dae212c782fab 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -404,9 +404,8 @@ IntrusiveRefCntPtr<llvm::vfs::FileSystem> 
createVFSFromCompilerInvocation(
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS);
 
 IntrusiveRefCntPtr<llvm::vfs::FileSystem>
-createVFSFromOverlayFiles(ArrayRef<std::string> VFSOverlayFiles,
-                          DiagnosticsEngine &Diags,
-                          IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS);
+createVFSFromHSOpts(const HeaderSearchOptions &HSOpts, DiagnosticsEngine 
&Diags,
+                    IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS);
 
 } // namespace clang
 
diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h 
b/clang/include/clang/Lex/HeaderSearchOptions.h
index 2f33c0749f02a..901ab7a4fb3fc 100644
--- a/clang/include/clang/Lex/HeaderSearchOptions.h
+++ b/clang/include/clang/Lex/HeaderSearchOptions.h
@@ -207,6 +207,10 @@ class HeaderSearchOptions {
   LLVM_PREFERRED_TYPE(bool)
   unsigned Verbose : 1;
 
+  /// Whether header search should be case-insensitive.
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned CaseInsensitive : 1;
+
   /// If true, skip verifying input files used by modules if the
   /// module was already verified during this build session (see
   /// \c BuildSessionTimestamp).
@@ -289,7 +293,7 @@ class HeaderSearchOptions {
         ModuleFileHomeIsCwd(false), EnablePrebuiltImplicitModules(false),
         UseBuiltinIncludes(true), UseStandardSystemIncludes(true),
         UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false),
-        ModulesValidateOncePerBuildSession(false),
+        CaseInsensitive(false), ModulesValidateOncePerBuildSession(false),
         ModulesValidateSystemHeaders(false),
         ModulesForceValidateUserHeaders(true),
         ValidateASTInputFilesContent(false),
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 43727236ed5a4..384c7bdf8fee5 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2034,6 +2034,11 @@ def fansi_escape_codes : Flag<["-"], 
"fansi-escape-codes">, Group<f_Group>,
   Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
   HelpText<"Use ANSI escape codes for diagnostics">,
   MarshallingInfoFlag<DiagnosticOpts<"UseANSIEscapeCodes">>;
+def fcase_insensitive_paths
+    : Flag<["-"], "fcase-insensitive-paths">,
+      Group<f_Group>,
+      Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
+      HelpText<"Treat file paths as case-insensitive">;
 def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, 
Group<f_clang_Group>,
   Visibility<[ClangOption, CC1Option]>,
   HelpText<"Treat each comma separated argument in <arg> as a documentation 
comment block command">,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index ab671d032644b..c40ab4f73f383 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1186,6 +1186,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const 
JobAction &JA,
 
   Args.addOptInFlag(CmdArgs, options::OPT_fdefine_target_os_macros,
                     options::OPT_fno_define_target_os_macros);
+
+  if (Args.hasArg(options::OPT_fcase_insensitive_paths))
+    CmdArgs.push_back("-fcase-insensitive-paths");
 }
 
 // FIXME: Move to target hook.
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index ee22e16bc202d..faeb89f1e43c1 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -749,8 +749,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
     return nullptr;
   }
 
-  VFS = createVFSFromOverlayFiles(AST->HSOpts->VFSOverlayFiles,
-                                  *AST->Diagnostics, std::move(VFS));
+  VFS = createVFSFromHSOpts(*AST->HSOpts, *AST->Diagnostics, std::move(VFS));
 
   AST->FileMgr = llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOpts, VFS);
 
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp 
b/clang/lib/Frontend/CompilerInvocation.cpp
index 5a79634773866..0256ee07f5810 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3382,6 +3382,9 @@ static void GenerateHeaderSearchArgs(const 
HeaderSearchOptions &Opts,
 
   for (const std::string &F : Opts.VFSOverlayFiles)
     GenerateArg(Consumer, OPT_ivfsoverlay, F);
+
+  if (Opts.CaseInsensitive)
+    GenerateArg(Consumer, OPT_fcase_insensitive_paths);
 }
 
 static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
@@ -3502,6 +3505,8 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions 
&Opts, ArgList &Args,
   for (const auto *A : Args.filtered(OPT_ivfsoverlay, OPT_vfsoverlay))
     Opts.AddVFSOverlayFile(A->getValue());
 
+  Opts.CaseInsensitive = Args.hasArg(OPT_fcase_insensitive_paths);
+
   return Diags.getNumErrors() == NumErrorsBefore;
 }
 
@@ -5440,19 +5445,17 @@ IntrusiveRefCntPtr<llvm::vfs::FileSystem>
 clang::createVFSFromCompilerInvocation(
     const CompilerInvocation &CI, DiagnosticsEngine &Diags,
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
-  return createVFSFromOverlayFiles(CI.getHeaderSearchOpts().VFSOverlayFiles,
-                                   Diags, std::move(BaseFS));
+  return createVFSFromHSOpts(CI.getHeaderSearchOpts(), Diags,
+                             std::move(BaseFS));
 }
 
-IntrusiveRefCntPtr<llvm::vfs::FileSystem> clang::createVFSFromOverlayFiles(
-    ArrayRef<std::string> VFSOverlayFiles, DiagnosticsEngine &Diags,
-    IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
-  if (VFSOverlayFiles.empty())
-    return BaseFS;
-
+IntrusiveRefCntPtr<llvm::vfs::FileSystem>
+clang::createVFSFromHSOpts(const HeaderSearchOptions &HSOpts,
+                           DiagnosticsEngine &Diags,
+                           IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> Result = BaseFS;
   // earlier vfs files are on the bottom
-  for (const auto &File : VFSOverlayFiles) {
+  for (const auto &File : HSOpts.VFSOverlayFiles) {
     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
         Result->getBufferForFile(File);
     if (!Buffer) {
@@ -5470,5 +5473,10 @@ IntrusiveRefCntPtr<llvm::vfs::FileSystem> 
clang::createVFSFromOverlayFiles(
 
     Result = FS;
   }
+
+  if (HSOpts.CaseInsensitive)
+    return llvm::makeIntrusiveRefCnt<llvm::vfs::CaseInsensitiveFileSystem>(
+        std::move(Result));
+
   return Result;
 }
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 5f52d62bd36ed..e20180e3f8611 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -148,12 +148,12 @@ std::vector<bool> HeaderSearch::collectVFSUsageAndClear() 
const {
 
   llvm::vfs::FileSystem &RootFS = FileMgr.getVirtualFileSystem();
   // TODO: This only works if the `RedirectingFileSystem`s were all created by
-  //       `createVFSFromOverlayFiles`. But at least exclude the ones with null
+  //       `createVFSFromHSOpts`. But at least exclude the ones with null
   //       OverlayFileDir.
   RootFS.visit([&](llvm::vfs::FileSystem &FS) {
     if (auto *RFS = dyn_cast<llvm::vfs::RedirectingFileSystem>(&FS)) {
       // Skip a `RedirectingFileSystem` with null OverlayFileDir which 
indicates
-      // that they aren't created by createVFSFromOverlayFiles from the 
overlays
+      // that they aren't created by createVFSFromHSOpts from the overlays
       // in HeaderSearchOption::VFSOverlayFiles.
       if (!RFS->getOverlayFileDir().empty()) {
         VFSUsage.push_back(RFS->hasBeenUsed());
diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c
index 611d0d2927c43..3b8e563807017 100644
--- a/clang/test/Driver/cl-options.c
+++ b/clang/test/Driver/cl-options.c
@@ -762,6 +762,7 @@
 // RUN:     -fno-wrapv \
 // RUN:     -fwrapv-pointer \
 // RUN:     -fno-wrapv-pointer \
+// RUN:     -fcase-insensitive-paths \
 // RUN:     --version \
 // RUN:     --warning-suppression-mappings=foo \
 // RUN:     -Werror /Zs -- %s 2>&1
diff --git a/clang/test/Frontend/case-insensitive-paths.c 
b/clang/test/Frontend/case-insensitive-paths.c
new file mode 100644
index 0000000000000..0b99ce671d9eb
--- /dev/null
+++ b/clang/test/Frontend/case-insensitive-paths.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -E -P -verify --show-includes -Wno-nonportable-include-path 
\
+// RUN:     -fcase-insensitive-paths %s 2>&1 | FileCheck %s
+
+#include "inPuts/eMptY.H" // expected-no-diagnostics
+
+// Make sure the exact spelling used in the #include directive is preserved
+// when printing header dependencies (consistent with MSVC /showIncludes).
+// CHECK: Note: including file: {{.*}}inPuts/eMptY.H
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 3bc9c98bcdbc3..a2e7a91e494cd 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -1523,24 +1523,28 @@ std::optional<std::string> getReproduceFile(const 
opt::InputArgList &args) {
 
 static std::unique_ptr<llvm::vfs::FileSystem>
 getVFS(COFFLinkerContext &ctx, const opt::InputArgList &args) {
-  using namespace llvm::vfs;
-
-  const opt::Arg *arg = args.getLastArg(OPT_vfsoverlay);
-  if (!arg)
-    return nullptr;
+  auto overlayFs = [&]() -> std::unique_ptr<vfs::FileSystem> {
+    const opt::Arg *arg = args.getLastArg(OPT_vfsoverlay);
+    if (!arg)
+      return nullptr;
 
-  auto bufOrErr = llvm::MemoryBuffer::getFile(arg->getValue());
-  if (!bufOrErr) {
-    checkError(errorCodeToError(bufOrErr.getError()));
-    return nullptr;
-  }
+    auto bufOrErr = llvm::MemoryBuffer::getFile(arg->getValue());
+    if (!bufOrErr) {
+      checkError(errorCodeToError(bufOrErr.getError()));
+      return nullptr;
+    }
 
-  if (auto ret = vfs::getVFSFromYAML(std::move(*bufOrErr),
-                                     /*DiagHandler*/ nullptr, arg->getValue()))
-    return ret;
+    if (auto ret = vfs::getVFSFromYAML(
+            std::move(*bufOrErr), /*DiagHandler*/ nullptr, arg->getValue()))
+      return ret;
 
-  Err(ctx) << "Invalid vfs overlay";
-  return nullptr;
+    Err(ctx) << "Invalid vfs overlay";
+    return nullptr;
+  }();
+  if (args.hasArg(OPT_case_insensitive_paths))
+    return std::make_unique<vfs::CaseInsensitiveFileSystem>(
+        overlayFs ? std::move(overlayFs) : vfs::getRealFileSystem());
+  return overlayFs;
 }
 
 static StringRef DllDefaultEntryPoint(MachineTypes machine, bool mingw) {
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index fb762b880c2cb..8326f9fe0d7e4 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -35,6 +35,8 @@ def arm64xsameaddress
     : P<"arm64xsameaddress", "Generate a thunk for the symbol with the same "
                              "address in both native and EC views on ARM64X.">;
 def base    : P<"base", "Base address of the program">;
+def case_insensitive_paths : Flag<["--"], "case-insensitive-paths">,
+                             HelpText<"Treat file paths as case-insensitive">;
 def color_diagnostics: Flag<["--"], "color-diagnostics">,
     HelpText<"Alias for --color-diagnostics=always">;
 def no_color_diagnostics: Flag<["--"], "no-color-diagnostics">,
diff --git a/lld/test/COFF/case-insensitive-paths.test 
b/lld/test/COFF/case-insensitive-paths.test
new file mode 100644
index 0000000000000..74d6871b5c88d
--- /dev/null
+++ b/lld/test/COFF/case-insensitive-paths.test
@@ -0,0 +1,2 @@
+# RUN: lld-link %S/Inputs/hello64.obj /out:%t.exe /entry:main \
+# RUN:   /libpath:%p/inPutS /defaultlib:StD64 --case-insensitive-paths
diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h 
b/llvm/include/llvm/Support/VirtualFileSystem.h
index 5b8871b8f3db5..056d601da8cc6 100644
--- a/llvm/include/llvm/Support/VirtualFileSystem.h
+++ b/llvm/include/llvm/Support/VirtualFileSystem.h
@@ -17,6 +17,7 @@
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Chrono.h"
 #include "llvm/Support/Compiler.h"
@@ -500,6 +501,41 @@ class LLVM_ABI ProxyFileSystem
   void anchor() override;
 };
 
+class LLVM_ABI CaseInsensitiveFileSystem
+    : public RTTIExtends<CaseInsensitiveFileSystem, FileSystem> {
+  IntrusiveRefCntPtr<FileSystem> FS;
+
+  /// Map from directory to map from lowercase to real-case filename.
+  StringMap<StringMap<std::string>> Maps;
+
+public:
+  static const char ID;
+  CaseInsensitiveFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
+      : FS(std::move(FS)) {}
+
+  llvm::ErrorOr<Status> status(const Twine &Path) override;
+  llvm::ErrorOr<std::unique_ptr<File>>
+  openFileForRead(const Twine &Path) override;
+  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
+    return FS->getCurrentWorkingDirectory();
+  }
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+    Maps.clear();
+    return FS->setCurrentWorkingDirectory(Path);
+  }
+
+protected:
+  /// Attempt to exclude the possibility that File exists in Dir based on
+  /// previous information.
+  bool exclude(StringRef Dir, uint32_t DirHash, StringRef File);
+
+  /// Try to find Path by means of case-insensitive lookup. Stores the result 
in
+  /// FoundPath on success, or returns an error code otherwise.
+  std::error_code findCaseInsensitivePath(StringRef Path,
+                                          SmallVectorImpl<char> &FoundPath);
+};
+
 namespace detail {
 
 class InMemoryDirectory;
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp 
b/llvm/lib/Support/VirtualFileSystem.cpp
index 49a5cefe6a7d7..a831061f62816 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -658,6 +658,109 @@ directory_iterator OverlayFileSystem::dir_begin(const 
Twine &Dir,
 
 void ProxyFileSystem::anchor() {}
 
+//===-----------------------------------------------------------------------===/
+// CaseInsensitiveFileSystem implementation
+//===-----------------------------------------------------------------------===/
+
+bool CaseInsensitiveFileSystem::exclude(StringRef Dir, uint32_t DirHash,
+                                        StringRef File) {
+  if (auto I = Maps.find(Dir, DirHash); I != Maps.end())
+    return !I->second.contains(File.lower());
+  // We have no map for this Dir, but see if we can exclude the file by
+  // excluding Dir from its parent.
+  StringRef Parent = llvm::sys::path::parent_path(Dir);
+  return (!Parent.empty() &&
+          exclude(Parent, Maps.hash(Parent), llvm::sys::path::filename(Dir)));
+}
+
+std::error_code CaseInsensitiveFileSystem::findCaseInsensitivePath(
+    StringRef Path, SmallVectorImpl<char> &FoundPath) {
+  StringRef FileName = llvm::sys::path::filename(Path);
+  StringRef Dir = llvm::sys::path::parent_path(Path);
+
+  if (Dir.empty())
+    Dir = ".";
+
+  auto DirHash = Maps.hash(Dir);
+  if (exclude(Dir, DirHash, FileName))
+    return llvm::errc::no_such_file_or_directory;
+
+  if (auto It = Maps.find(Dir, DirHash); It != Maps.end()) {
+    // If we have a map for this Dir and File wasn't excluded above, it must
+    // exist.
+    llvm::sys::path::append(FoundPath, Dir, It->second.at(FileName.lower()));
+    return {};
+  }
+
+  std::error_code EC;
+  directory_iterator I = FS->dir_begin(Dir, EC);
+  if (EC == errc::no_such_file_or_directory) {
+    // If the dir doesn't exist, try to find it and try again.
+    SmallString<512> NewDir;
+    if (llvm::sys::path::parent_path(Dir).empty() ||
+        (EC = findCaseInsensitivePath(Dir, NewDir))) {
+      // Insert a dummy map value to mark the dir as non-existent.
+      Maps.try_emplace_with_hash(Dir, DirHash);
+      return EC;
+    }
+    llvm::sys::path::append(NewDir, FileName);
+    return findCaseInsensitivePath(StringRef(NewDir.data(), NewDir.size()),
+                                   FoundPath);
+  }
+
+  // These special entries always exist, but won't show up in the listing 
below.
+  StringMap<std::string> DirMap = {{".", "."}, {"..", ".."}};
+
+  directory_iterator E;
+  while (I != E) {
+    StringRef DirEntry = llvm::sys::path::filename(I->path());
+    // Keep the first match.
+    DirMap.try_emplace(DirEntry.lower(), DirEntry);
+    I.increment(EC);
+    if (EC)
+      return EC;
+  }
+
+  // If there were no problems, insert the map.
+  auto [DirMapIt, Inserted] =
+      Maps.try_emplace_with_hash(Dir, DirHash, std::move(DirMap));
+  assert(Inserted && "Maps[Dir] shouldn't exist");
+  const auto &DirMapRef = DirMapIt->second;
+
+  if (auto MI = DirMapRef.find(FileName.lower()); MI != DirMapRef.end()) {
+    llvm::sys::path::append(FoundPath, Dir, MI->second);
+    return {};
+  }
+
+  return llvm::errc::no_such_file_or_directory;
+}
+
+llvm::ErrorOr<Status> CaseInsensitiveFileSystem::status(const Twine &Path) {
+  SmallString<512> NewPath;
+  if (auto EC = findCaseInsensitivePath(Path.str(), NewPath))
+    return EC;
+
+  return FS->status(NewPath);
+}
+
+llvm::ErrorOr<std::unique_ptr<File>>
+CaseInsensitiveFileSystem::openFileForRead(const Twine &Path) {
+  SmallString<512> NewPath;
+  if (auto EC = findCaseInsensitivePath(Path.str(), NewPath))
+    return EC;
+
+  return FS->openFileForRead(NewPath);
+}
+
+directory_iterator CaseInsensitiveFileSystem::dir_begin(const Twine &Path,
+                                                        std::error_code &EC) {
+  SmallString<512> NewPath;
+  if ((EC = findCaseInsensitivePath(Path.str(), NewPath)))
+    return {};
+
+  return FS->dir_begin(NewPath, EC);
+}
+
 namespace llvm {
 namespace vfs {
 
@@ -3019,6 +3122,7 @@ void TracingFileSystem::printImpl(raw_ostream &OS, 
PrintType Type,
 const char FileSystem::ID = 0;
 const char OverlayFileSystem::ID = 0;
 const char ProxyFileSystem::ID = 0;
+const char CaseInsensitiveFileSystem::ID = 0;
 const char InMemoryFileSystem::ID = 0;
 const char RedirectingFileSystem::ID = 0;
 const char TracingFileSystem::ID = 0;
diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp 
b/llvm/unittests/Support/VirtualFileSystemTest.cpp
index bb0172b28e373..8953923d0f5d2 100644
--- a/llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -137,8 +137,15 @@ class DummyFileSystem : public vfs::FileSystem {
 
   vfs::directory_iterator dir_begin(const Twine &Dir,
                                     std::error_code &EC) override {
-    return vfs::directory_iterator(
+    auto I = vfs::directory_iterator(
         std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
+
+    // Even if there is no entry for /foo, /foo/bar may exist, so only set the
+    // error code if /foo returns an empty iterator.
+    if (I == vfs::directory_iterator())
+      EC = status(Dir).getError();
+
+    return I;
   }
 
   void addEntry(StringRef Path, const vfs::Status &Status) {
@@ -3732,3 +3739,50 @@ TEST(TracingFileSystemTest, PrintOutput) {
             "  InMemoryFileSystem\n",
             Output);
 }
+
+class CaseInsensitiveFileSystemTest : public ::testing::Test {
+protected:
+  vfs::CaseInsensitiveFileSystem FS;
+
+  CaseInsensitiveFileSystemTest()
+      : FS([] {
+          auto Base = makeIntrusiveRefCnt<DummyFileSystem>();
+          Base->addRegularFile("/foo");
+          Base->addDirectory("/bar");
+          Base->addRegularFile("/bar/baz");
+          return Base;
+        }()) {}
+};
+
+TEST_F(CaseInsensitiveFileSystemTest, Basic) {
+  // Not just accepting anything.
+  auto Status = FS.status("/F00");
+  ASSERT_EQ(llvm::errc::no_such_file_or_directory, Status.getError());
+
+  // Case-insensitive file is found.
+  Status = FS.status("/FoO");
+  ASSERT_FALSE(Status.getError());
+
+  // Case-insensitive dir works too.
+  Status = FS.status("/bAr/baZ");
+  ASSERT_FALSE(Status.getError());
+
+  // Test openFileForRead.
+  auto File = FS.openFileForRead("/F00");
+  ASSERT_EQ(llvm::errc::no_such_file_or_directory, File.getError());
+  File = FS.openFileForRead("/Foo");
+  ASSERT_FALSE(File.getError());
+  File = FS.openFileForRead("/Bar/Baz");
+  ASSERT_FALSE(File.getError());
+
+  // Test directory listing.
+  std::error_code EC;
+  auto Dir = FS.dir_begin("/b4r", EC);
+  ASSERT_EQ(llvm::errc::no_such_file_or_directory, EC);
+  Dir = FS.dir_begin("/bAr", EC);
+  ASSERT_FALSE(EC);
+  ASSERT_EQ("/bar/baz", Dir->path());
+  Dir.increment(EC);
+  ASSERT_FALSE(EC);
+  ASSERT_EQ(vfs::directory_iterator(), Dir);
+}

>From 8f3d1a3ea4ae2e8b48747156825d560772a74256 Mon Sep 17 00:00:00 2001
From: grchz <[email protected]>
Date: Thu, 29 Jan 2026 17:32:35 +1300
Subject: [PATCH 2/2] Expect -Wnonportable-include-path warning

---
 clang/test/Frontend/case-insensitive-paths.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/clang/test/Frontend/case-insensitive-paths.c 
b/clang/test/Frontend/case-insensitive-paths.c
index 0b99ce671d9eb..fc75d9d24a104 100644
--- a/clang/test/Frontend/case-insensitive-paths.c
+++ b/clang/test/Frontend/case-insensitive-paths.c
@@ -1,8 +1,10 @@
-// RUN: %clang_cc1 -E -P -verify --show-includes -Wno-nonportable-include-path 
\
-// RUN:     -fcase-insensitive-paths %s 2>&1 | FileCheck %s
-
-#include "inPuts/eMptY.H" // expected-no-diagnostics
-
+// RUN: %clang_cc1 -E -P --show-includes -verify=suppressed \
+// RUN:   -fcase-insensitive-paths -Wno-nonportable-include-path %s 2>&1 \
+// RUN:   | FileCheck %s
 // Make sure the exact spelling used in the #include directive is preserved
 // when printing header dependencies (consistent with MSVC /showIncludes).
 // CHECK: Note: including file: {{.*}}inPuts/eMptY.H
+// suppressed-no-diagnostics@+1
+#include "inPuts/eMptY.H"
+// expected-warning@-1 {{non-portable path to file '"Inputs/empty.h"'; 
specified path differs in case from file name on disk}}
+// RUN: %clang_cc1 -E -P -verify -fcase-insensitive-paths %s

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

Reply via email to