diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -538,7 +538,7 @@ bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; } /// Remap path prefix according to -fmacro-prefix-path option. - void remapPathPrefix(SmallString<256> &Path) const; + void remapPathPrefix(SmallVectorImpl &Path) const; }; /// Floating point control options diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2582,6 +2582,10 @@ emitRestrictExpansionWarning(Identifier); } + static void processPathForFileMacro(SmallVectorImpl &Path, + const LangOptions &LangOpts, + const TargetInfo &TI); + private: void emitMacroDeprecationWarning(const Token &Identifier) const; void emitRestrictExpansionWarning(const Token &Identifier) const; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -31,6 +31,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -2190,7 +2191,8 @@ switch (getIdentKind()) { case SourceLocExpr::File: { SmallString<256> Path(PLoc.getFilename()); - Ctx.getLangOpts().remapPathPrefix(Path); + clang::Preprocessor::processPathForFileMacro(Path, Ctx.getLangOpts(), + Ctx.getTargetInfo()); return MakeStringLiteral(Path); } case SourceLocExpr::Function: { @@ -2223,7 +2225,8 @@ StringRef Name = F->getName(); if (Name == "_M_file_name") { SmallString<256> Path(PLoc.getFilename()); - Ctx.getLangOpts().remapPathPrefix(Path); + clang::Preprocessor::processPathForFileMacro(Path, Ctx.getLangOpts(), + Ctx.getTargetInfo()); Value.getStructField(F->getFieldIndex()) = MakeStringLiteral(Path); } else if (Name == "_M_function_name") { // Note: this emits the PrettyFunction name -- different than what diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -62,7 +62,7 @@ llvm_unreachable("Unknown OpenCL version"); } -void LangOptions::remapPathPrefix(SmallString<256> &Path) const { +void LangOptions::remapPathPrefix(SmallVectorImpl &Path) const { for (const auto &Entry : MacroPrefixMap) if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second)) break; diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1511,7 +1511,7 @@ } else { FN += PLoc.getFilename(); } - getLangOpts().remapPathPrefix(FN); + processPathForFileMacro(FN, getLangOpts(), getTargetInfo()); Lexer::Stringify(FN); OS << '"' << FN << '"'; } @@ -1886,3 +1886,18 @@ WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); MI->setIsUsed(true); } + +void Preprocessor::processPathForFileMacro(SmallVectorImpl &Path, + const LangOptions &LangOpts, + const TargetInfo &TI) { + LangOpts.remapPathPrefix(Path); + if (TI.getTriple().isOSWindows()) { + // The path separator character depends on the environment where Clang + // _itself_ is built (backslash for Windows, forward slash for *nix). To + // make the output of the __FILE__ macro deterministic, we make the path + // use forward slashes when targeting Windows independently of how Clang is + // built. + llvm::sys::path::make_preferred(Path, + llvm::sys::path::Style::windows_slash); + } +} diff --git a/clang/test/Preprocessor/file_test_windows.c b/clang/test/Preprocessor/file_test_windows.c --- a/clang/test/Preprocessor/file_test_windows.c +++ b/clang/test/Preprocessor/file_test_windows.c @@ -8,19 +8,19 @@ filename: __FILE__ #include "Inputs/include-file-test/file_test.h" -// CHECK: filename: "A:\\UNLIKELY_PATH\\empty\\file_test_windows.c" -// CHECK: filename: "A:\\UNLIKELY_PATH\\empty/Inputs/include-file-test/file_test.h" -// CHECK: basefile: "A:\\UNLIKELY_PATH\\empty\\file_test_windows.c" +// CHECK: filename: "A:/UNLIKELY_PATH/empty/file_test_windows.c" +// CHECK: filename: "A:/UNLIKELY_PATH/empty/Inputs/include-file-test/file_test.h" +// CHECK: basefile: "A:/UNLIKELY_PATH/empty/file_test_windows.c" // CHECK-NOT: filename: -// CHECK-EVIL: filename: "A:\\UNLIKELY_PATH=empty\\file_test_windows.c" -// CHECK-EVIL: filename: "A:\\UNLIKELY_PATH=empty/Inputs/include-file-test/file_test.h" -// CHECK-EVIL: basefile: "A:\\UNLIKELY_PATH=empty\\file_test_windows.c" +// CHECK-EVIL: filename: "A:/UNLIKELY_PATH=empty/file_test_windows.c" +// CHECK-EVIL: filename: "A:/UNLIKELY_PATH=empty/Inputs/include-file-test/file_test.h" +// CHECK-EVIL: basefile: "A:/UNLIKELY_PATH=empty/file_test_windows.c" // CHECK-EVIL-NOT: filename: -// CHECK-CASE: filename: "A:\\UNLIKELY_PATH_BASE\\file_test_windows.c" -// CHECK-CASE: filename: "A:\\UNLIKELY_PATH_INC\\include-file-test/file_test.h" -// CHECK-CASE: basefile: "A:\\UNLIKELY_PATH_BASE\\file_test_windows.c" +// CHECK-CASE: filename: "A:/UNLIKELY_PATH_BASE/file_test_windows.c" +// CHECK-CASE: filename: "A:/UNLIKELY_PATH_INC/include-file-test/file_test.h" +// CHECK-CASE: basefile: "A:/UNLIKELY_PATH_BASE/file_test_windows.c" // CHECK-CASE-NOT: filename: // CHECK-REMOVE: filename: "file_test_windows.c"