Skip to content

Commit 181c4d6

Browse files
committed
[Clang] only convert dependency filename to native form when MS-compatible
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 <[email protected]>
1 parent b2574c9 commit 181c4d6

File tree

3 files changed

+39
-7
lines changed

3 files changed

+39
-7
lines changed

clang/include/clang/Frontend/Utils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ class DependencyFileGenerator : public DependencyCollector {
118118
void outputDependencyFile(llvm::raw_ostream &OS);
119119

120120
private:
121+
void outputDependencyFilename(llvm::raw_ostream &OS,
122+
StringRef Filename) const;
123+
121124
void outputDependencyFile(DiagnosticsEngine &Diags);
122125

123126
std::string OutputFile;
@@ -128,6 +131,7 @@ class DependencyFileGenerator : public DependencyCollector {
128131
bool SeenMissingHeader;
129132
bool IncludeModuleFiles;
130133
DependencyOutputFormat OutputFormat;
134+
bool MSCompatible;
131135
unsigned InputFileIndex;
132136
};
133137

clang/lib/Frontend/DependencyFile.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ DependencyFileGenerator::DependencyFileGenerator(
223223
PhonyTarget(Opts.UsePhonyTargets),
224224
AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false),
225225
IncludeModuleFiles(Opts.IncludeModuleFiles),
226-
OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
226+
OutputFormat(Opts.OutputFormat), MSCompatible(false), InputFileIndex(0) {
227227
for (const auto &ExtraDep : Opts.ExtraDeps) {
228228
if (addDependency(ExtraDep.first))
229229
++InputFileIndex;
@@ -235,6 +235,8 @@ void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {
235235
if (AddMissingHeaderDeps)
236236
PP.SetSuppressIncludeNotFoundError(true);
237237

238+
MSCompatible = PP.getLangOpts().MicrosoftExt;
239+
238240
DependencyCollector::attachToPreprocessor(PP);
239241
}
240242

@@ -312,11 +314,20 @@ void DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) {
312314
/// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
313315
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
314316
/// for Windows file-naming info.
315-
static void PrintFilename(raw_ostream &OS, StringRef Filename,
316-
DependencyOutputFormat OutputFormat) {
317-
// Convert filename to platform native path
317+
///
318+
/// Whether backslashes in the filename are treated as path separators or
319+
/// ordinary characters depends on whether the Clang invocation is MS-compatible
320+
/// (-fms-compatibility). If it is, backslashes are treated as path separators,
321+
/// and are converted to the native path separator (backslash on Windows,
322+
/// forward slash on other platforms); if not, backslashes are treated as
323+
/// ordinary characters, and are not converted.
324+
void DependencyFileGenerator::outputDependencyFilename(
325+
raw_ostream &OS, StringRef Filename) const {
318326
llvm::SmallString<256> NativePath;
319-
llvm::sys::path::native(Filename.str(), NativePath);
327+
if (MSCompatible)
328+
llvm::sys::path::native(Filename.str(), NativePath);
329+
else
330+
NativePath = Filename;
320331

321332
if (OutputFormat == DependencyOutputFormat::NMake) {
322333
// Add quotes if needed. These are the characters listed as "special" to
@@ -400,7 +411,7 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
400411
Columns = 2;
401412
}
402413
OS << ' ';
403-
PrintFilename(OS, File, OutputFormat);
414+
outputDependencyFilename(OS, File);
404415
Columns += N + 1;
405416
}
406417
OS << '\n';
@@ -411,7 +422,7 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
411422
for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
412423
if (Index++ == InputFileIndex)
413424
continue;
414-
PrintFilename(OS, *I, OutputFormat);
425+
outputDependencyFilename(OS, *I);
415426
OS << ":\n";
416427
}
417428
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// REQUIRES: !system-windows
2+
// RUN: rm -rf %t.dir
3+
// RUN: mkdir -p %t.dir/include/foo
4+
// RUN: echo > %t.dir/include/foo/bar.h
5+
// RUN: echo > %t.dir/include/foo\\bar.h
6+
7+
// RUN: %clang -MD -MF - %s -fsyntax-only -fms-compatibility -I %t.dir/include | FileCheck -check-prefix=CHECK-ONE %s
8+
// CHECK-ONE: foo/bar.h
9+
// CHECK-ONE-NOT: foo\bar.h
10+
// CHECK-ONE-NOT: foo\\bar.h
11+
12+
// RUN: %clang -MD -MF - %s -fsyntax-only -fno-ms-compatibility -I %t.dir/include | FileCheck -check-prefix=CHECK-TWO %s
13+
// CHECK-TWO: foo\bar.h
14+
// CHECK-TWO-NOT: foo/bar.h
15+
// CHECK-TWO-NOT: foo\\bar.h
16+
17+
#include "foo\bar.h"

0 commit comments

Comments
 (0)