Index: include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- include/clang/Basic/DiagnosticDriverKinds.td +++ include/clang/Basic/DiagnosticDriverKinds.td @@ -115,8 +115,8 @@ "missing argument to '%0'">; def err_drv_invalid_libcxx_deployment : Error< "invalid deployment target for -stdlib=libc++ (requires %0 or later)">; -def err_drv_invalid_argument_to_fdebug_prefix_map : Error< - "invalid argument '%0' to -fdebug-prefix-map">; +def err_drv_invalid_argument_to_prefix_map : Error< + "invalid argument '%0' to -f%1-prefix-map">; def err_drv_malformed_sanitizer_blacklist : Error< "malformed sanitizer blacklist: '%0'">; def err_drv_duplicate_config : Error< Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1831,10 +1831,16 @@ Flags<[CC1Option]>, HelpText<"Provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF">; def fno_split_dwarf_inlining: Flag<["-"], "fno-split-dwarf-inlining">, Group, Flags<[CC1Option]>; +def ffile_prefix_map_EQ + : Joined<["-"], "ffile-prefix-map=">, Group, Flags<[CC1Option]>, + HelpText<"remap file source paths in debug info and predefined preprocessor macros">; def fdebug_prefix_map_EQ : Joined<["-"], "fdebug-prefix-map=">, Group, Flags<[CC1Option,CC1AsOption]>, HelpText<"remap file source paths in debug info">; +def fmacro_prefix_map_EQ + : Joined<["-"], "fmacro-prefix-map=">, Group, Flags<[CC1Option]>, + HelpText<"remap file source paths in predefined preprocessor macros">; def g_Flag : Flag<["-"], "g">, Group, HelpText<"Generate source-level debug information">; def gline_tables_only : Flag<["-"], "gline-tables-only">, Group, Index: include/clang/Lex/PreprocessorOptions.h =================================================================== --- include/clang/Lex/PreprocessorOptions.h +++ include/clang/Lex/PreprocessorOptions.h @@ -170,6 +170,9 @@ /// build it again. std::shared_ptr FailedModules; + /// A prefix map for __FILE__ and __BASE_FILE__ + std::map> MacroPrefixMap; + public: PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {} Index: lib/CodeGen/CGDebugInfo.h =================================================================== --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -83,7 +83,7 @@ /// Cache of previously constructed Types. llvm::DenseMap TypeCache; - llvm::SmallDenseMap DebugPrefixMap; + std::map> DebugPrefixMap; /// Cache that maps VLA types to size expressions for that type, /// represented by instantiated Metadata nodes. Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -610,16 +610,30 @@ /// Add a CC1 and CC1AS option to specify the debug file path prefix map. static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { - for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); if (Map.find('=') == StringRef::npos) - D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; + D.Diag(diag::err_drv_invalid_argument_to_prefix_map) << Map << "debug"; else CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); A->claim(); } } +/// Add a CC1 and CC1AS option to specify the macro file path prefix map. +static void addMacroPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fmacro_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_prefix_map) << Map << "macro"; + else + CmdArgs.push_back(Args.MakeArgString("-fmacro-prefix-map=" + Map)); + A->claim(); + } +} + /// Vectorize at all optimization levels greater than 1 except for -Oz. /// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled. static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) { @@ -1258,6 +1272,8 @@ // For IAMCU add special include arguments. getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs); } + + addMacroPrefixMapArg(D, Args, CmdArgs); } // FIXME: Move to target hook. Index: lib/Driver/ToolChains/FreeBSD.cpp =================================================================== --- lib/Driver/ToolChains/FreeBSD.cpp +++ lib/Driver/ToolChains/FreeBSD.cpp @@ -13,6 +13,7 @@ #include "Arch/Sparc.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" @@ -31,6 +32,7 @@ const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; + const auto &D = getToolChain().getDriver(); // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. @@ -102,6 +104,18 @@ AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } + } + + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_prefix_map) << Map << "debug"; + else { + CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); + CmdArgs.push_back(Args.MakeArgString(Map)); + } + A->claim(); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); Index: lib/Driver/ToolChains/Gnu.cpp =================================================================== --- lib/Driver/ToolChains/Gnu.cpp +++ lib/Driver/ToolChains/Gnu.cpp @@ -799,6 +799,18 @@ } } + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_prefix_map) << Map << "debug"; + else { + CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); + CmdArgs.push_back(Args.MakeArgString(Map)); + } + A->claim(); + } + Args.AddAllArgs(CmdArgs, options::OPT_I); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -3090,6 +3090,9 @@ for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue()); + for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) + Opts.MacroPrefixMap.insert(StringRef(A).split('=')); + if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { StringRef Value(A->getValue()); size_t Comma = Value.find(','); Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -29,6 +29,7 @@ #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorLexer.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -1456,6 +1457,16 @@ return TI.getTriple().getEnvironment() == Env.getEnvironment(); } +static void remapMacroPath( + SmallString<128> &Path, + const std::map> + &MacroPrefixMap) { + for (const auto &Entry : MacroPrefixMap) + if (Path.startswith(Entry.first)) { + Path = (Twine(Entry.second) + Path.substr(Entry.first.size())).str(); + } +} + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { @@ -1523,6 +1534,7 @@ if (PLoc.isValid()) { FN += PLoc.getFilename(); Lexer::Stringify(FN); + remapMacroPath(FN, PPOpts->MacroPrefixMap); OS << '"' << FN << '"'; } Tok.setKind(tok::string_literal); Index: test/CodeGen/debug-prefix-map.c =================================================================== --- test/CodeGen/debug-prefix-map.c +++ test/CodeGen/debug-prefix-map.c @@ -2,6 +2,8 @@ // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH=empty %s -emit-llvm -o - | FileCheck %s -check-prefix CHECK-EVIL // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty %s -emit-llvm -o - -main-file-name debug-prefix-map.c | FileCheck %s // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty %s -emit-llvm -o - -fdebug-compilation-dir %p | FileCheck %s -check-prefix CHECK-COMPILATION-DIR +// RUN: %clang -g -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty -S -c %s -emit-llvm -o - | FileCheck %s +// RUN: %clang -g -ffile-prefix-map=%p=/UNLIKELY_PATH/empty -S -c %s -emit-llvm -o - | FileCheck %s #include "Inputs/stdio.h" Index: test/Preprocessor/file_test.h =================================================================== --- /dev/null +++ test/Preprocessor/file_test.h @@ -0,0 +1,2 @@ +filename: __FILE__ +basefile: __BASE_FILE__ Index: test/Preprocessor/file_test.c =================================================================== --- /dev/null +++ test/Preprocessor/file_test.c @@ -0,0 +1,23 @@ +// RUN: %clang -E -ffile-prefix-map=%p=/UNLIKELY_PATH/empty -c -o - %s | FileCheck %s +// RUN: %clang -E -fmacro-prefix-map=%p=/UNLIKELY_PATH/empty -c -o - %s | FileCheck %s +// RUN: %clang -E -fmacro-prefix-map=%p=/UNLIKELY_PATH=empty -c -o - %s | FileCheck %s -check-prefix CHECK-EVIL +// RUN: %clang -E -fmacro-prefix-map=%p/= -c -o - %s | FileCheck %s --check-prefix CHECK-REMOVE +//This is a comment + +filename: __FILE__ +#include "file_test.h" + +// CHECK: filename: "/UNLIKELY_PATH/empty{{[/\\]}}file_test.c" +// CHECK: filename: "/UNLIKELY_PATH/empty{{[/\\]}}file_test.h" +// CHECK: basefile: "/UNLIKELY_PATH/empty{{[/\\]}}file_test.c" +// CHECK-NOT: filename: + +// CHECK-EVIL: filename: "/UNLIKELY_PATH=empty{{[/\\]}}file_test.c" +// CHECK-EVIL: filename: "/UNLIKELY_PATH=empty{{[/\\]}}file_test.h" +// CHECK-EVIL: basefile: "/UNLIKELY_PATH=empty{{[/\\]}}file_test.c" +// CHECK-EVIL-NOT: filename: + +// CHECK-REMOVE: filename: "file_test.c" +// CHECK-REMOVE: filename: "file_test.h" +// CHECK-REMOVE: basefile: "file_test.c" +// CHECK-REMOVE-NOT: filename: