[clang] [Clang] only convert dependency filename to native form when MS-compatible (PR #160903)
Ruoyu Zhong via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 19 11:33:49 PDT 2025
https://github.com/ZhongRuoyu updated https://github.com/llvm/llvm-project/pull/160903
>From 181c4d65060405cdba484c18ae09b3fe1255414d Mon Sep 17 00:00:00 2001
From: Ruoyu Zhong <zhongruoyu at outlook.com>
Date: Fri, 26 Sep 2025 23:17:32 +0800
Subject: [PATCH] [Clang] only convert dependency filename to native form when
MS-compatible
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Currently, llvm::sys::path::native is called unconditionally when
generating dependency filenames. This is correct on Windows, where
backslashes are valid path separators, but can be incorrect on
non-Windows platforms when the Clang invocation is not MS-compatible
(-fno-ms-compatibility), because in that case backslashes in the
filename are converted by llvm::sys::path::native to forward slashes,
while they should be treated as ordinary characters.
This fixes the following inconsistency on non-Windows platforms (notice
how the dependency output always converts the backslash to a forward
slash, assuming it's a path separator, while the actual include
directive treats it as an ordinary character when -fno-ms-compatibility
is set):
$ tree
.
└── foo
├── a
│ └── b.h
└── a\b.h
3 directories, 2 files
$ cat foo/a/b.h
#warning a/b.h
$ cat foo/a\\b.h
#warning a\\b.h
$ echo '#include "foo/a\\b.h"' | clang -c -xc - -fms-compatibility -o /dev/null
In file included from <stdin>:1:
./foo/a/b.h:1:2: warning: a/b.h [-W#warnings]
1 | #warning a/b.h
| ^
1 warning generated.
$ echo '#include "foo/a\\b.h"' | clang -xc - -fms-compatibility -M -MG
-.o: foo/a/b.h
$ echo '#include "foo/a\\b.h"' | clang -c -xc - -fno-ms-compatibility -o /dev/null
In file included from <stdin>:1:
./foo/a\b.h:1:2: warning: a\\b.h [-W#warnings]
1 | #warning a\\b.h
| ^
1 warning generated.
$ echo '#include "foo/a\\b.h"' | clang -xc - -fno-ms-compatibility -M -MG
-.o: foo/a/b.h
Signed-off-by: Ruoyu Zhong <zhongruoyu at outlook.com>
---
clang/include/clang/Frontend/Utils.h | 4 +++
clang/lib/Frontend/DependencyFile.cpp | 25 +++++++++++++------
.../dependency-gen-posix-ms-compatible.c | 17 +++++++++++++
3 files changed, 39 insertions(+), 7 deletions(-)
create mode 100644 clang/test/Frontend/dependency-gen-posix-ms-compatible.c
diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h
index 49fd920d1ec43..8fe63d7c2141b 100644
--- a/clang/include/clang/Frontend/Utils.h
+++ b/clang/include/clang/Frontend/Utils.h
@@ -118,6 +118,9 @@ class DependencyFileGenerator : public DependencyCollector {
void outputDependencyFile(llvm::raw_ostream &OS);
private:
+ void outputDependencyFilename(llvm::raw_ostream &OS,
+ StringRef Filename) const;
+
void outputDependencyFile(DiagnosticsEngine &Diags);
std::string OutputFile;
@@ -128,6 +131,7 @@ class DependencyFileGenerator : public DependencyCollector {
bool SeenMissingHeader;
bool IncludeModuleFiles;
DependencyOutputFormat OutputFormat;
+ bool MSCompatible;
unsigned InputFileIndex;
};
diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp
index 15fa7de35df97..fc5b7949afa22 100644
--- a/clang/lib/Frontend/DependencyFile.cpp
+++ b/clang/lib/Frontend/DependencyFile.cpp
@@ -223,7 +223,7 @@ DependencyFileGenerator::DependencyFileGenerator(
PhonyTarget(Opts.UsePhonyTargets),
AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false),
IncludeModuleFiles(Opts.IncludeModuleFiles),
- OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
+ OutputFormat(Opts.OutputFormat), MSCompatible(false), InputFileIndex(0) {
for (const auto &ExtraDep : Opts.ExtraDeps) {
if (addDependency(ExtraDep.first))
++InputFileIndex;
@@ -235,6 +235,8 @@ void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {
if (AddMissingHeaderDeps)
PP.SetSuppressIncludeNotFoundError(true);
+ MSCompatible = PP.getLangOpts().MicrosoftExt;
+
DependencyCollector::attachToPreprocessor(PP);
}
@@ -312,11 +314,20 @@ void DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) {
/// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
/// for Windows file-naming info.
-static void PrintFilename(raw_ostream &OS, StringRef Filename,
- DependencyOutputFormat OutputFormat) {
- // Convert filename to platform native path
+///
+/// Whether backslashes in the filename are treated as path separators or
+/// ordinary characters depends on whether the Clang invocation is MS-compatible
+/// (-fms-compatibility). If it is, backslashes are treated as path separators,
+/// and are converted to the native path separator (backslash on Windows,
+/// forward slash on other platforms); if not, backslashes are treated as
+/// ordinary characters, and are not converted.
+void DependencyFileGenerator::outputDependencyFilename(
+ raw_ostream &OS, StringRef Filename) const {
llvm::SmallString<256> NativePath;
- llvm::sys::path::native(Filename.str(), NativePath);
+ if (MSCompatible)
+ llvm::sys::path::native(Filename.str(), NativePath);
+ else
+ NativePath = Filename;
if (OutputFormat == DependencyOutputFormat::NMake) {
// Add quotes if needed. These are the characters listed as "special" to
@@ -400,7 +411,7 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
Columns = 2;
}
OS << ' ';
- PrintFilename(OS, File, OutputFormat);
+ outputDependencyFilename(OS, File);
Columns += N + 1;
}
OS << '\n';
@@ -411,7 +422,7 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
if (Index++ == InputFileIndex)
continue;
- PrintFilename(OS, *I, OutputFormat);
+ outputDependencyFilename(OS, *I);
OS << ":\n";
}
}
diff --git a/clang/test/Frontend/dependency-gen-posix-ms-compatible.c b/clang/test/Frontend/dependency-gen-posix-ms-compatible.c
new file mode 100644
index 0000000000000..208240b03a844
--- /dev/null
+++ b/clang/test/Frontend/dependency-gen-posix-ms-compatible.c
@@ -0,0 +1,17 @@
+// REQUIRES: !system-windows
+// RUN: rm -rf %t.dir
+// RUN: mkdir -p %t.dir/include/foo
+// RUN: echo > %t.dir/include/foo/bar.h
+// RUN: echo > %t.dir/include/foo\\bar.h
+
+// RUN: %clang -MD -MF - %s -fsyntax-only -fms-compatibility -I %t.dir/include | FileCheck -check-prefix=CHECK-ONE %s
+// CHECK-ONE: foo/bar.h
+// CHECK-ONE-NOT: foo\bar.h
+// CHECK-ONE-NOT: foo\\bar.h
+
+// RUN: %clang -MD -MF - %s -fsyntax-only -fno-ms-compatibility -I %t.dir/include | FileCheck -check-prefix=CHECK-TWO %s
+// CHECK-TWO: foo\bar.h
+// CHECK-TWO-NOT: foo/bar.h
+// CHECK-TWO-NOT: foo\\bar.h
+
+#include "foo\bar.h"
More information about the cfe-commits
mailing list