diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver/Job.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Job.cpp | 141 |
1 files changed, 107 insertions, 34 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp index 2d99b1f..9fd8808 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp @@ -7,18 +7,20 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/Job.h" #include "InputInfo.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Job.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" #include <cassert> @@ -37,50 +39,62 @@ Command::Command(const Action &Source, const Tool &Creator, InputFilenames.push_back(II.getFilename()); } -static int skipArgs(const char *Flag, bool HaveCrashVFS) { +/// @brief Check if the compiler flag in question should be skipped when +/// emitting a reproducer. Also track how many arguments it has and if the +/// option is some kind of include path. +static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum, + bool &IsInclude) { + SkipNum = 2; // These flags are all of the form -Flag <Arg> and are treated as two // arguments. Therefore, we need to skip the flag and the next argument. - bool Res = llvm::StringSwitch<bool>(Flag) + bool ShouldSkip = llvm::StringSwitch<bool>(Flag) .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true) .Cases("-o", "-coverage-file", "-dependency-file", true) - .Cases("-fdebug-compilation-dir", "-idirafter", true) - .Cases("-include", "-include-pch", "-internal-isystem", true) - .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true) - .Cases("-iwithprefixbefore", "-isystem", "-iquote", true) + .Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true) .Cases("-dwarf-debug-flags", "-ivfsoverlay", true) - .Cases("-header-include-file", "-diagnostic-log-file", true) - // Some include flags shouldn't be skipped if we have a crash VFS - .Cases("-isysroot", "-I", "-F", "-resource-dir", !HaveCrashVFS) .Default(false); - - // Match found. - if (Res) - return 2; + if (ShouldSkip) + return true; + + // Some include flags shouldn't be skipped if we have a crash VFS + IsInclude = llvm::StringSwitch<bool>(Flag) + .Cases("-include", "-header-include-file", true) + .Cases("-idirafter", "-internal-isystem", "-iwithprefix", true) + .Cases("-internal-externc-isystem", "-iprefix", true) + .Cases("-iwithprefixbefore", "-isystem", "-iquote", true) + .Cases("-isysroot", "-I", "-F", "-resource-dir", true) + .Cases("-iframework", "-include-pch", true) + .Default(false); + if (IsInclude) + return HaveCrashVFS ? false : true; // The remaining flags are treated as a single argument. // These flags are all of the form -Flag and have no second argument. - Res = llvm::StringSwitch<bool>(Flag) + ShouldSkip = llvm::StringSwitch<bool>(Flag) .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) .Case("-MMD", true) .Default(false); // Match found. - if (Res) - return 1; + SkipNum = 1; + if (ShouldSkip) + return true; // These flags are treated as a single argument (e.g., -F<Dir>). StringRef FlagRef(Flag); - if ((!HaveCrashVFS && - (FlagRef.startswith("-F") || FlagRef.startswith("-I"))) || - FlagRef.startswith("-fmodules-cache-path=")) - return 1; - - return 0; + IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I"); + if (IsInclude) + return HaveCrashVFS ? false : true; + if (FlagRef.startswith("-fmodules-cache-path=")) + return true; + + SkipNum = 0; + return false; } -void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) { - const bool Escape = std::strpbrk(Arg, "\"\\$"); +void Command::printArg(raw_ostream &OS, StringRef Arg, bool Quote) { + const bool Escape = Arg.find_first_of("\"\\$") != StringRef::npos; if (!Quote && !Escape) { OS << Arg; @@ -89,7 +103,7 @@ void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) { // Quote and escape. This isn't really complete, but good enough. OS << '"'; - while (const char c = *Arg++) { + for (const char c : Arg) { if (c == '"' || c == '\\' || c == '$') OS << '\\'; OS << c; @@ -152,6 +166,45 @@ void Command::buildArgvForResponseFile( } } +/// @brief Rewrite relative include-like flag paths to absolute ones. +static void +rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx, + size_t NumArgs, + llvm::SmallVectorImpl<llvm::SmallString<128>> &IncFlags) { + using namespace llvm; + using namespace sys; + auto getAbsPath = [](StringRef InInc, SmallVectorImpl<char> &OutInc) -> bool { + if (path::is_absolute(InInc)) // Nothing to do here... + return false; + std::error_code EC = fs::current_path(OutInc); + if (EC) + return false; + path::append(OutInc, InInc); + return true; + }; + + SmallString<128> NewInc; + if (NumArgs == 1) { + StringRef FlagRef(Args[Idx + NumArgs - 1]); + assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) && + "Expecting -I or -F"); + StringRef Inc = FlagRef.slice(2, StringRef::npos); + if (getAbsPath(Inc, NewInc)) { + SmallString<128> NewArg(FlagRef.slice(0, 2)); + NewArg += NewInc; + IncFlags.push_back(std::move(NewArg)); + } + return; + } + + assert(NumArgs == 2 && "Not expecting more than two arguments"); + StringRef Inc(Args[Idx + NumArgs - 1]); + if (!getAbsPath(Inc, NewInc)) + return; + IncFlags.push_back(SmallString<128>(Args[Idx])); + IncFlags.push_back(std::move(NewInc)); +} + void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo) const { // Always quote the exe. @@ -170,10 +223,27 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, const char *const Arg = Args[i]; if (CrashInfo) { - if (int Skip = skipArgs(Arg, HaveCrashVFS)) { - i += Skip - 1; + int NumArgs = 0; + bool IsInclude = false; + if (skipArgs(Arg, HaveCrashVFS, NumArgs, IsInclude)) { + i += NumArgs - 1; continue; } + + // Relative includes need to be expanded to absolute paths. + if (HaveCrashVFS && IsInclude) { + SmallVector<SmallString<128>, 2> NewIncFlags; + rewriteIncludes(Args, i, NumArgs, NewIncFlags); + if (!NewIncFlags.empty()) { + for (auto &F : NewIncFlags) { + OS << ' '; + printArg(OS, F.c_str(), Quote); + } + i += NumArgs - 1; + continue; + } + } + auto Found = std::find_if(InputFilenames.begin(), InputFilenames.end(), [&Arg](StringRef IF) { return IF == Arg; }); if (Found != InputFilenames.end() && @@ -181,7 +251,7 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, // Replace the input file name with the crashinfo's file name. OS << ' '; StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); - printArg(OS, ShortName.str().c_str(), Quote); + printArg(OS, ShortName.str(), Quote); continue; } } @@ -194,19 +264,22 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, OS << ' '; printArg(OS, "-ivfsoverlay", Quote); OS << ' '; - printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote); + printArg(OS, CrashInfo->VFSPath.str(), Quote); - // Insert -fmodules-cache-path and use the relative module directory - // <name>.cache/vfs/modules where we already dumped the modules. + // The leftover modules from the crash are stored in + // <name>.cache/vfs/modules + // Leave it untouched for pcm inspection and provide a clean/empty dir + // path to contain the future generated module cache: + // <name>.cache/vfs/repro-modules SmallString<128> RelModCacheDir = llvm::sys::path::parent_path( llvm::sys::path::parent_path(CrashInfo->VFSPath)); - llvm::sys::path::append(RelModCacheDir, "modules"); + llvm::sys::path::append(RelModCacheDir, "repro-modules"); std::string ModCachePath = "-fmodules-cache-path="; ModCachePath.append(RelModCacheDir.c_str()); OS << ' '; - printArg(OS, ModCachePath.c_str(), Quote); + printArg(OS, ModCachePath, Quote); } if (ResponseFile != nullptr) { |