diff options
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticDriverKinds.td | 3 | ||||
-rw-r--r-- | include/clang/Config/config.h.cmake | 5 | ||||
-rw-r--r-- | include/clang/Driver/ArgList.h | 11 | ||||
-rw-r--r-- | include/clang/Driver/Compilation.h | 9 | ||||
-rw-r--r-- | include/clang/Driver/Driver.h | 13 | ||||
-rw-r--r-- | include/clang/Driver/Job.h | 3 | ||||
-rw-r--r-- | lib/Driver/ArgList.cpp | 16 | ||||
-rw-r--r-- | lib/Driver/Compilation.cpp | 37 | ||||
-rw-r--r-- | lib/Driver/Driver.cpp | 74 | ||||
-rw-r--r-- | lib/Driver/Job.cpp | 6 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 4 | ||||
-rw-r--r-- | tools/driver/driver.cpp | 10 |
13 files changed, 175 insertions, 19 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ad60eaff5..404b5988bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,3 +272,6 @@ if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 ) file(APPEND "${CLANG_SLN_FILENAME}" "\n# This should be regenerated!\n") endif() endif() + +set(BUG_REPORT_URL "http://llvm.org" CACHE STRING + "Default URL where bug reports are to be submitted.") diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index e33b67ef7a..f76af053d9 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -123,4 +123,7 @@ def warn_drv_objc_gc_unsupported : Warning< def warn_drv_pch_not_first_include : Warning< "precompiled header '%0' was ignored because '%1' is not first '-include'">; +def note_drv_command_failed_diag_msg : Note< + "diagnostic msg: %0">; + } diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake index 5f13d2faa3..6ca625d1d6 100644 --- a/include/clang/Config/config.h.cmake +++ b/include/clang/Config/config.h.cmake @@ -13,5 +13,8 @@ /* Directory with the libstdc++ headers. */ #define CXX_INCLUDE_ROOT "${CXX_INCLUDE_ROOT}" -/* Directories clang will search for headers */ +/* Directories clang will search for headers. */ #define C_INCLUDE_DIRS "${C_INCLUDE_DIRS}" + +/* Define default bug reporting URL. */ +#cmakedefine BUG_REPORT_URL "${BUG_REPORT_URL}" diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h index 617561b0f6..b31eea5b5b 100644 --- a/include/clang/Driver/ArgList.h +++ b/include/clang/Driver/ArgList.h @@ -150,6 +150,13 @@ namespace driver { } /// @} + /// @name Arg Removal + /// @{ + + /// eraseArg - Remove any option matching \arg Id. + void eraseArg(OptSpecifier Id); + + /// @} /// @name Arg Access /// @{ @@ -242,6 +249,10 @@ namespace driver { /// option id. void ClaimAllArgs(OptSpecifier Id0) const; + /// ClaimAllArgs - Claim all arguments. + /// + void ClaimAllArgs() const; + /// @} /// @name Arg Synthesis /// @{ diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h index 4f69d0a420..8c9990909e 100644 --- a/include/clang/Driver/Compilation.h +++ b/include/clang/Driver/Compilation.h @@ -13,6 +13,7 @@ #include "clang/Driver/Job.h" #include "clang/Driver/Util.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Path.h" namespace clang { namespace driver { @@ -55,6 +56,9 @@ class Compilation { /// Result files which should be removed on failure. ArgStringList ResultFiles; + /// Redirection for stdout, stderr, etc. + const llvm::sys::Path **Redirects; + public: Compilation(const Driver &D, const ToolChain &DefaultToolChain, InputArgList *Args, DerivedArgList *TranslatedArgs); @@ -131,6 +135,11 @@ public: /// Command which failed. /// \return The accumulated result code of the job. int ExecuteJob(const Job &J, const Command *&FailingCommand) const; + + /// initCompilationForDiagnostics - Remove stale state and suppress output + /// so compilation can be reexecuted to generate additional diagnostic + /// information (e.g., preprocessed source(s)). + void initCompilationForDiagnostics(); }; } // end namespace driver diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 0e5e81a7e2..8a1e1cbbc0 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -31,6 +31,7 @@ namespace driver { class Action; class Arg; class ArgList; + class Command; class Compilation; class DerivedArgList; class HostInfo; @@ -134,6 +135,9 @@ public: /// format. unsigned CCLogDiagnostics : 1; + /// Whether the driver is generating diagnostics for debugging purposes. + unsigned CCGenDiagnostics : 1; + private: /// Name to use when invoking gcc/g++. std::string CCCGenericGCCName; @@ -268,7 +272,14 @@ public: /// This routine handles additional processing that must be done in addition /// to just running the subprocesses, for example reporting errors, removing /// temporary files, etc. - int ExecuteCompilation(const Compilation &C) const; + int ExecuteCompilation(const Compilation &C, + const Command *&FailingCommand) const; + + /// generateCompilationDiagnostics - Generate diagnostics information + /// including preprocessed source file(s). + /// + void generateCompilationDiagnostics(Compilation &C, + const Command *FailingCommand); /// @} /// @name Helper Methods diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h index f2b6357dfb..367955f59f 100644 --- a/include/clang/Driver/Job.h +++ b/include/clang/Driver/Job.h @@ -97,6 +97,9 @@ public: /// Add a job to the list (taking ownership). void addJob(Job *J) { Jobs.push_back(J); } + /// Clear the job list. + void clear(); + const list_type &getJobs() const { return Jobs; } size_type size() const { return Jobs.size(); } diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index 86da885a40..e5341884ee 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -46,6 +46,16 @@ void ArgList::append(Arg *A) { Args.push_back(A); } +void ArgList::eraseArg(OptSpecifier Id) { + for (iterator it = begin(), ie = end(); it != ie; ++it) { + if ((*it)->getOption().matches(Id)) { + Args.erase(it); + it = begin(); + ie = end(); + } + } +} + Arg *ArgList::getLastArgNoClaim(OptSpecifier Id) const { // FIXME: Make search efficient? for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it) @@ -192,6 +202,12 @@ void ArgList::ClaimAllArgs(OptSpecifier Id0) const { (*it)->claim(); } +void ArgList::ClaimAllArgs() const { + for (const_iterator it = begin(), ie = end(); it != ie; ++it) + if (!(*it)->isClaimed()) + (*it)->claim(); +} + const char *ArgList::MakeArgString(const Twine &T) const { llvm::SmallString<256> Str; T.toVector(Str); diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 47ac1756c8..85a5fc9330 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -16,6 +16,7 @@ #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Program.h" #include <sys/stat.h> @@ -27,7 +28,7 @@ using namespace clang; Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, InputArgList *_Args, DerivedArgList *_TranslatedArgs) : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args), - TranslatedArgs(_TranslatedArgs) { + TranslatedArgs(_TranslatedArgs), Redirects(0) { } Compilation::~Compilation() { @@ -45,6 +46,13 @@ Compilation::~Compilation() { for (ActionList::iterator it = Actions.begin(), ie = Actions.end(); it != ie; ++it) delete *it; + + // Free redirections of stdout/stderr. + if (Redirects) { + delete Redirects[1]; + delete Redirects[2]; + delete [] Redirects; + } } const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC, @@ -137,8 +145,8 @@ int Compilation::ExecuteCommand(const Command &C, std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1); Argv[C.getArguments().size() + 1] = 0; - if (getDriver().CCCEcho || getDriver().CCPrintOptions || - getArgs().hasArg(options::OPT_v)) { + if ((getDriver().CCCEcho || getDriver().CCPrintOptions || + getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { raw_ostream *OS = &llvm::errs(); // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the @@ -169,7 +177,7 @@ int Compilation::ExecuteCommand(const Command &C, std::string Error; int Res = llvm::sys::Program::ExecuteAndWait(Prog, Argv, - /*env*/0, /*redirects*/0, + /*env*/0, Redirects, /*secondsToWait*/0, /*memoryLimit*/0, &Error); if (!Error.empty()) { @@ -197,3 +205,24 @@ int Compilation::ExecuteJob(const Job &J, return 0; } } + +void Compilation::initCompilationForDiagnostics(void) { + // Free actions and jobs. + DeleteContainerPointers(Actions); + Jobs.clear(); + + // Clear temporary/results file lists. + TempFiles.clear(); + ResultFiles.clear(); + + // Remove any user specified output. Claim any unclaimed arguments, so as + // to avoid emitting warnings about unused args. + if (TranslatedArgs->hasArg(options::OPT_o)) + TranslatedArgs->eraseArg(options::OPT_o); + TranslatedArgs->ClaimAllArgs(); + + // Redirect stdout/stderr to /dev/null. + Redirects = new const llvm::sys::Path*[3](); + Redirects[1] = new const llvm::sys::Path(); + Redirects[2] = new const llvm::sys::Path(); +} diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index ac5cedf771..fc2ec673e3 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -60,9 +60,9 @@ Driver::Driver(StringRef ClangExecutable, CCLogDiagnosticsFilename(0), CCCIsCXX(false), CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false), - CCCGenericGCCName(""), CheckInputsExist(true), CCCUseClang(true), - CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true), - SuppressMissingInputWarning(false) { + CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), + CCCUseClang(true), CCCUseClangCXX(true), CCCUseClangCPP(true), + CCCUsePCH(true), SuppressMissingInputWarning(false) { if (IsProduction) { // In a "production" build, only use clang on architectures we expect to // work, and don't use clang C++. @@ -367,7 +367,63 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { return C; } -int Driver::ExecuteCompilation(const Compilation &C) const { +// When clang crashes, produce diagnostic information including the fully +// preprocessed source file(s). Request that the developer attach the +// diagnostic information to a bug report. +void Driver::generateCompilationDiagnostics(Compilation &C, + const Command *FailingCommand) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Please submit a bug report to " BUG_REPORT_URL " and include command" + " line arguments and all diagnostic information."; + + // Suppress driver output and emit preprocessor output to temp file. + CCCIsCPP = true; + CCGenDiagnostics = true; + + // Clear stale state and suppress tool output. + C.initCompilationForDiagnostics(); + + // Construct the list of abstract actions to perform for this compilation. + Diags.Reset(); + if (Host->useDriverDriver()) + BuildUniversalActions(C.getDefaultToolChain(), C.getArgs(), + C.getActions()); + else + BuildActions(C.getDefaultToolChain(), C.getArgs(), C.getActions()); + + BuildJobs(C); + + // If there were errors building the compilation, quit now. + if (Diags.hasErrorOccurred()) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s)."; + return; + } + + // Generate preprocessed output. + FailingCommand = 0; + int Res = C.ExecuteJob(C.getJobs(), FailingCommand); + + // If the command succeeded, we are done. + if (Res == 0) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Preprocessed source(s) are located at:"; + ArgStringList Files = C.getTempFiles(); + for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end(); + it != ie; ++it) + Diag(clang::diag::note_drv_command_failed_diag_msg) << *it; + } else { + // Failure, remove preprocessed files. + if (!C.getArgs().hasArg(options::OPT_save_temps)) + C.CleanupFileList(C.getTempFiles(), true); + + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s)."; + } +} + +int Driver::ExecuteCompilation(const Compilation &C, + const Command *&FailingCommand) const { // Just print if -### was present. if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { C.PrintJob(llvm::errs(), C.getJobs(), "\n", true); @@ -375,10 +431,9 @@ int Driver::ExecuteCompilation(const Compilation &C) const { } // If there were errors building the compilation, quit now. - if (getDiags().hasErrorOccurred()) + if (Diags.hasErrorOccurred()) return 1; - const Command *FailingCommand = 0; int Res = C.ExecuteJob(C.getJobs(), FailingCommand); // Remove temp files. @@ -1226,7 +1281,7 @@ void Driver::BuildJobsForAction(Compilation &C, A->getType(), BaseInput); } - if (CCCPrintBindings) { + if (CCCPrintBindings && !CCGenDiagnostics) { llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"' << " - \"" << T.getName() << "\", inputs: ["; for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) { @@ -1253,11 +1308,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C, } // Default to writing to stdout? - if (AtTopLevel && isa<PreprocessJobAction>(JA)) + if (AtTopLevel && isa<PreprocessJobAction>(JA) && !CCGenDiagnostics) return "-"; // Output to a temporary file? - if (!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) { + if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) || + CCGenDiagnostics) { std::string TmpName = GetTemporaryPath(types::getTypeTempSuffix(JA.getType())); return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str())); diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 51055e93f5..5443d70e82 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -9,6 +9,8 @@ #include "clang/Driver/Job.h" +#include "llvm/ADT/STLExtras.h" + #include <cassert> using namespace clang::driver; @@ -28,6 +30,10 @@ JobList::~JobList() { delete *it; } +void JobList::clear() { + DeleteContainerPointers(Jobs); +} + void Job::addCommand(Command *C) { cast<JobList>(this)->addJob(C); } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 9748da449c..43c3fbd810 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1378,7 +1378,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_v); Args.AddLastArg(CmdArgs, options::OPT_H); - if (D.CCPrintHeaders) { + if (D.CCPrintHeaders && !D.CCGenDiagnostics) { CmdArgs.push_back("-header-include-file"); CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename : "-"); @@ -1386,7 +1386,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); - if (D.CCLogDiagnostics) { + if (D.CCLogDiagnostics && !D.CCGenDiagnostics) { CmdArgs.push_back("-diagnostic-log-file"); CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename : "-"); diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 096260c421..3ae1487118 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -458,9 +458,15 @@ int main(int argc_, const char **argv_) { llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv)); int Res = 0; + const Command *FailingCommand = 0; if (C.get()) - Res = TheDriver.ExecuteCompilation(*C); - + Res = TheDriver.ExecuteCompilation(*C, FailingCommand); + + // If result status is < 0, then the driver command signalled an error. + // In this case, generate additional diagnostic information if possible. + if (Res < 0) + TheDriver.generateCompilationDiagnostics(*C, FailingCommand); + // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); |