Index: COFF/Config.h =================================================================== --- COFF/Config.h +++ COFF/Config.h @@ -80,8 +80,12 @@ SymbolBody *Entry = nullptr; bool NoEntry = false; std::string OutputFile; + bool ColorDiagnostics = false; bool DoGC = true; bool DoICF = true; + uint64_t ErrorLimit = 20; + bool ExitEarly = true; + bool FatalWarnings; bool Relocatable = true; bool Force = false; bool Debug = false; Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -55,7 +55,10 @@ StringSaver Saver{BAlloc}; std::vector SpecificAllocBase::Instances; -bool link(ArrayRef Args) { +bool link(ArrayRef Args, raw_ostream &Diag) { + ErrorCount = 0; + ErrorOS = &Diag; + Argv0 = Args[0]; Config = make(); Driver = make(); Driver->link(Args); Index: COFF/Error.h =================================================================== --- COFF/Error.h +++ COFF/Error.h @@ -16,6 +16,15 @@ namespace lld { namespace coff { +extern uint64_t ErrorCount; +extern llvm::raw_ostream *ErrorOS; +extern llvm::StringRef Argv0; + +void warn(const Twine &Msg); + +void error(const Twine &Msg); +void error(std::error_code EC, const Twine &Prefix); + LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix); LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix); Index: COFF/Error.cpp =================================================================== --- COFF/Error.cpp +++ COFF/Error.cpp @@ -8,11 +8,14 @@ //===----------------------------------------------------------------------===// #include "Error.h" +#include "Config.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" +#include #if !defined(_MSC_VER) && !defined(__MINGW32__) #include @@ -21,7 +24,57 @@ using namespace llvm; namespace lld { +// The functions defined in this file can be called from multiple threads, +// but outs() or errs() are not thread-safe. We protect them using a mutex. +static std::mutex Mu; + namespace coff { +StringRef Argv0; +uint64_t ErrorCount; +raw_ostream *ErrorOS; + +static void exitLld(int Val) { + // Dealloc/destroy ManagedStatic variables before calling + // _exit(). In a non-LTO build, this is a nop. In an LTO + // build allows us to get the output of -time-passes. + llvm_shutdown(); + + outs().flush(); + errs().flush(); + _exit(Val); +} + +static void print(StringRef S, raw_ostream::Colors C) { + *ErrorOS << Argv0 + ": "; + if (Config->ColorDiagnostics) { + ErrorOS->changeColor(C, true); + *ErrorOS << S; + ErrorOS->resetColor(); + } else { + *ErrorOS << S; + } +} + +void error(const Twine &Msg) { + std::lock_guard Lock(Mu); + + if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << Msg << "\n"; + } else if (ErrorCount == Config->ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << "too many errors emitted, stopping now" + << " (use -error-limit=0 to see all errors)\n"; + if (Config->ExitEarly) + exitLld(1); + } + + ++ErrorCount; +} + +void error(std::error_code EC, const Twine &Prefix) { + error(Prefix + ": " + EC.message()); +} void fatal(const Twine &Msg) { if (sys::Process::StandardErrHasColors()) { @@ -46,5 +99,15 @@ fatal(errorToErrorCode(std::move(Err)), Msg); } +void warn(const Twine &Msg) { + if (Config->FatalWarnings) { + error(Msg); + return; + } + std::lock_guard Lock(Mu); + print("warning: ", raw_ostream::MAGENTA); + *ErrorOS << Msg << "\n"; +} + } // namespace coff } // namespace lld Index: include/lld/Driver/Driver.h =================================================================== --- include/lld/Driver/Driver.h +++ include/lld/Driver/Driver.h @@ -15,7 +15,8 @@ namespace lld { namespace coff { -bool link(llvm::ArrayRef Args); +bool link(llvm::ArrayRef Args, + llvm::raw_ostream &Diag = llvm::errs()); } namespace elf {