aboutsummaryrefslogtreecommitdiff
path: root/lib/Driver/Job.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Driver/Job.cpp')
-rw-r--r--lib/Driver/Job.cpp141
1 files changed, 107 insertions, 34 deletions
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 2d99b1f22385..9fd8808af302 100644
--- a/lib/Driver/Job.cpp
+++ b/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) {