Index: clang/include/clang/Driver/Compilation.h =================================================================== --- clang/include/clang/Driver/Compilation.h +++ clang/include/clang/Driver/Compilation.h @@ -124,12 +124,20 @@ /// Whether to keep temporary files regardless of -save-temps. bool ForceKeepTempFiles = false; + // XXX comment + // XXX pass Driver Diags object? + int (*CC1Call)(const llvm::opt::ArgStringList &CC1Args) = nullptr; + public: Compilation(const Driver &D, const ToolChain &DefaultToolChain, llvm::opt::InputArgList *Args, llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError); ~Compilation(); + void setCC1Call(int (*CC1CallFn)(const llvm::opt::ArgStringList &CC1Args)) { + CC1Call = CC1CallFn; + } + const Driver &getDriver() const { return TheDriver; } const ToolChain &getDefaultToolChain() const { return DefaultToolChain; } Index: clang/lib/Driver/Compilation.cpp =================================================================== --- clang/lib/Driver/Compilation.cpp +++ clang/lib/Driver/Compilation.cpp @@ -150,6 +150,21 @@ int Compilation::ExecuteCommand(const Command &C, const Command *&FailingCommand) const { + + // XXX do this checking in ExecuteJobs() + // XXX maybe don't do this in the first caller of ExecuteJobs() + // (the one that makes stuff crash detection) + // XXX only do this if the command is actually a clang -cc1 command too + // XXX or cc1as... (P4) + // XXX share code for this conditional + // XXX could do this with more than 1 job too as long as they're all cc1 + // commands. could even do this just for the cc1 commands even if there are + // other commands. this gives a kind of jumbo behavior... + // XXX if doing more than one in-process cc1, maybe reuse SourceManager etc? + // v2... + // XXX only if Redirects is empty too + bool CanExec = Jobs.size() == 1 && isa(*Jobs.begin()); + if ((getDriver().CCPrintOptions || getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { raw_ostream *OS = &llvm::errs(); @@ -174,15 +189,43 @@ if (getDriver().CCPrintOptions) *OS << "[Logging clang options]"; + // XXX want "exec " prefix here too probably + if (CanExec) + *OS << "exec "; C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions); } - std::string Error; bool ExecutionFailed; - int Res = C.Execute(Redirects, &Error, &ExecutionFailed); - if (!Error.empty()) { - assert(Res && "Error string set with 0 result code!"); - getDriver().Diag(diag::err_drv_command_failure) << Error; + int Res; + + if (!CanExec) { + std::string Error; + Res = C.Execute(Redirects, &Error, &ExecutionFailed); + if (!Error.empty()) { + assert(Res && "Error string set with 0 result code!"); + getDriver().Diag(diag::err_drv_command_failure) << Error; + } + } else { + // XXX Driver must not depend on Frontend, hence need a delegate + assert(CC1Call); + // XXX need ensureStackAddressSpace(), ensureSufficientStack + // from cc1_main() when doing in-process stuff + // XXX also the timetrace bits + // XXX also why is --print-supported-cpus a cc1 option and + // implemented so weirdly? + // XXX and the llvm error handler, jeez + // XXX call ExecuteCompilerInvocation + // XXX make sure -disable-free is honored (and do it for driver + // too?) + // XXX this breaks the crash handling (compare + // `#pragma clang __debug parser_crash` with and without exec). Maybe + // in the signal handler for crashes, exec driver again with -fno-exec + // so that that (hopefully) produces a crash report? + const driver::Command &Cmd = cast(*Jobs.begin()); + assert(&Cmd == &C); + const ArgStringList &CCArgs = Cmd.getArguments(); + Res = CC1Call(CCArgs); + ExecutionFailed = Res != 0; } if (Res) Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -1450,6 +1450,7 @@ Compilation &C, SmallVectorImpl> &FailingCommands) { // Just print if -### was present. + // XXX do same change at other OPT__HASH_HASH_HASH handling sites if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { C.getJobs().Print(llvm::errs(), "\n", true); return 0; Index: clang/lib/Driver/Job.cpp =================================================================== --- clang/lib/Driver/Job.cpp +++ clang/lib/Driver/Job.cpp @@ -434,6 +434,10 @@ void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo) const { + // XXX share code for this conditional + bool CanExec = Jobs.size() == 1 && isa(*begin()); + if (CanExec) + OS << "exec "; for (const auto &Job : *this) Job.Print(OS, Terminator, Quote, CrashInfo); } Index: clang/tools/driver/driver.cpp =================================================================== --- clang/tools/driver/driver.cpp +++ clang/tools/driver/driver.cpp @@ -318,6 +318,20 @@ return 1; } +static int cc1call(const ArgStringList& CC1Args) { + void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath; + + ArrayRef argv = CC1Args; + //for (const char *A : argv) { + //fprintf(stderr, "%s ", A); + //} + + // XXX argv[0] is "-cc1" + // XXX also not clear if we want to call cc1_main here or something more + // granular + return cc1_main(argv.slice(1), argv[0], GetExecutablePathVP); +} + int main(int argc_, const char **argv_) { noteBottomOfStack(); llvm::InitLLVM X(argc_, argv_); @@ -459,6 +473,12 @@ int Res = 1; if (C && !C->containsError()) { SmallVector, 4> FailingCommands; + + // XXX should ExecuteCompilation() even return if this is set? + // Probably yes, for TimerGroup flushing and stuff? + // XXX which function do i want to pass? + C->setCC1Call(cc1call); + Res = TheDriver.ExecuteCompilation(*C, FailingCommands); // Force a crash to test the diagnostics.