diff options
author | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2016-12-09 02:22:47 +0000 |
---|---|---|
committer | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2016-12-09 02:22:47 +0000 |
commit | e3a0aef2cf93c7dc144c52798aa5546dc5ec304b (patch) | |
tree | 7556d541434f7d64902f2adcc3b79d7739fc4617 /clang/lib/Driver/Job.cpp | |
parent | 2aeb4564257e16617d718c91550ee28854fd37ce (diff) | |
download | bcm5719-llvm-e3a0aef2cf93c7dc144c52798aa5546dc5ec304b.tar.gz bcm5719-llvm-e3a0aef2cf93c7dc144c52798aa5546dc5ec304b.zip |
[CrashReproducer] Rewrite relative include paths
When -fmodules is on, the reproducer invocation currently leave paths
for include-like flags as is. If the path is relative, the reproducer
doesn't know how to access that file during reproduction time because
the VFS cannot reason about relative paths.
Expand relative paths to absolute ones when creating the reproducer
command line. This allows, for example, the reproducer to work for
crashes while building clang with modules; this wasn't possible before
because building clang requires using relative inc dir from within the
build directory.
rdar://problem/28655070
llvm-svn: 289174
Diffstat (limited to 'clang/lib/Driver/Job.cpp')
-rw-r--r-- | clang/lib/Driver/Job.cpp | 118 |
1 files changed, 94 insertions, 24 deletions
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp index a8f585e82d2..94ea60663ab 100644 --- a/clang/lib/Driver/Job.cpp +++ b/clang/lib/Driver/Job.cpp @@ -19,6 +19,7 @@ #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" @@ -38,46 +39,59 @@ 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", "-include-pch", 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) + .Case("-diagnostic-log-file", true) .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) + .Case("-iframework", 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, StringRef Arg, bool Quote) { @@ -153,6 +167,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. @@ -171,10 +224,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() && |