Index: lld/COFF/CMakeLists.txt =================================================================== --- lld/COFF/CMakeLists.txt +++ lld/COFF/CMakeLists.txt @@ -11,7 +11,6 @@ DLL.cpp Driver.cpp DriverUtils.cpp - Error.cpp ICF.cpp InputFiles.cpp LTO.cpp Index: lld/COFF/Chunks.cpp =================================================================== --- lld/COFF/Chunks.cpp +++ lld/COFF/Chunks.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// #include "Chunks.h" -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" Index: lld/COFF/Config.h =================================================================== --- lld/COFF/Config.h +++ lld/COFF/Config.h @@ -84,13 +84,10 @@ bool NoEntry = false; std::string OutputFile; std::string ImportName; - bool ColorDiagnostics; bool DoGC = true; bool DoICF = true; - uint64_t ErrorLimit = 20; bool Relocatable = true; bool Force = false; - bool FatalWarnings = false; bool Debug = false; bool WriteSymtab = true; unsigned DebugTypes = static_cast(DebugType::None); Index: lld/COFF/Driver.cpp =================================================================== --- lld/COFF/Driver.cpp +++ lld/COFF/Driver.cpp @@ -9,7 +9,6 @@ #include "Driver.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "Memory.h" #include "MinGW.h" @@ -17,6 +16,7 @@ #include "Symbols.h" #include "Writer.h" #include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" @@ -55,12 +55,14 @@ std::vector SpecificAllocBase::Instances; bool link(ArrayRef Args, bool CanExitEarly, raw_ostream &Diag) { - ErrorCount = 0; - ErrorOS = &Diag; - + errorHandler().LogName = Args[0]; + errorHandler().ErrorOS = &Diag; + errorHandler().ColorDiagnostics = Diag.has_colors(); + errorHandler().ErrorLimitExceededMsg = + "too many errors emitted, stopping now" + " (use /ERRORLIMIT:0 to see all errors)"; Config = make(); Config->Argv = {Args.begin(), Args.end()}; - Config->ColorDiagnostics = ErrorOS->has_colors(); Config->CanExitEarly = CanExitEarly; Symtab = make(); @@ -70,10 +72,10 @@ // Call exit() if we can to avoid calling destructors. if (CanExitEarly) - exitLld(ErrorCount ? 1 : 0); + exitLld(errorCount() ? 1 : 0); freeArena(); - return !ErrorCount; + return !errorCount(); } // Drop directory components and replace extension with ".exe" or ".dll". @@ -212,8 +214,8 @@ enqueueTask([=]() { auto MBOrErr = Future->get(); if (MBOrErr.second) - fatal(MBOrErr.second, - "could not get the buffer for the member defining " + SymName); + fatal("could not get the buffer for the member defining " + SymName + + ": " + MBOrErr.second.message()); Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, ParentName); }); @@ -619,7 +621,7 @@ SmallString<128> S; if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), ".lib", S)) - fatal(EC, "cannot create a temporary file"); + fatal("cannot create a temporary file: " + EC.message()); std::string Temp = S.str(); TemporaryFiles.push_back(Temp); @@ -648,7 +650,7 @@ int Fd; if (auto EC = sys::fs::createTemporaryFile( "lld-" + sys::path::filename(Obj->ParentName), ".obj", Fd, S)) - fatal(EC, "cannot create a temporary file"); + fatal("cannot create a temporary file: " + EC.message()); raw_fd_ostream OS(Fd, /*shouldClose*/ true); OS << Obj->MB.getBuffer(); Temps.push_back(S.str()); @@ -736,7 +738,7 @@ StringRef S = Arg->getValue(); if (S.getAsInteger(10, N)) error(Arg->getSpelling() + " number expected, but got " + S); - Config->ErrorLimit = N; + errorHandler().ErrorLimit = N; } // Handle /help @@ -792,6 +794,7 @@ // Handle /verbose if (Args.hasArg(OPT_verbose)) Config->Verbose = true; + errorHandler().Verbose =Config->Verbose; // Handle /force or /force:unresolved if (Args.hasArg(OPT_force) || Args.hasArg(OPT_force_unresolved)) @@ -1010,7 +1013,7 @@ Config->MapFile = getMapFile(Args); - if (ErrorCount) + if (errorCount()) return; bool WholeArchiveFlag = Args.hasArg(OPT_wholearchive_flag); @@ -1191,7 +1194,7 @@ addUndefined(mangle("_load_config_used")); } while (run()); - if (ErrorCount) + if (errorCount()) return; // If /msvclto is given, we use the MSVC linker to link LTO output files. @@ -1208,7 +1211,7 @@ // Make sure we have resolved all symbols. Symtab->reportRemainingUndefines(); - if (ErrorCount) + if (errorCount()) return; // Windows specific -- if no /subsystem is given, we need to infer @@ -1224,7 +1227,7 @@ for (ObjFile *File : ObjFile::Instances) if (!File->SEHCompat) error("/safeseh: " + File->getName() + " is not compatible with SEH"); - if (ErrorCount) + if (errorCount()) return; } Index: lld/COFF/DriverUtils.cpp =================================================================== --- lld/COFF/DriverUtils.cpp +++ lld/COFF/DriverUtils.cpp @@ -15,9 +15,9 @@ #include "Config.h" #include "Driver.h" -#include "Error.h" #include "Memory.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/COFF.h" @@ -57,7 +57,7 @@ void run() { ErrorOr ExeOrErr = sys::findProgramByName(Prog); if (auto EC = ExeOrErr.getError()) - fatal(EC, "unable to find " + Prog + " in PATH"); + fatal("unable to find " + Prog + " in PATH: " + EC.message()); StringRef Exe = Saver.save(*ExeOrErr); Args.insert(Args.begin(), Exe); @@ -288,14 +288,14 @@ TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") { SmallString<128> S; if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S)) - fatal(EC, "cannot create a temporary file"); + fatal("cannot create a temporary file: " + EC.message()); Path = S.str(); if (!Contents.empty()) { std::error_code EC; raw_fd_ostream OS(Path, EC, sys::fs::F_None); if (EC) - fatal(EC, "failed to open " + Path); + fatal("failed to open " + Path + ": " + EC.message()); OS << Contents; } } @@ -363,13 +363,15 @@ windows_manifest::WindowsManifestMerger Merger; if (auto E = Merger.merge(*DefaultXmlCopy.get())) - fatal(E, "internal manifest tool failed on default xml"); + fatal("internal manifest tool failed on default xml: " + + toString(std::move(E))); for (StringRef Filename : Config->ManifestInput) { std::unique_ptr Manifest = check(MemoryBuffer::getFile(Filename)); if (auto E = Merger.merge(*Manifest.get())) - fatal(E, "internal manifest tool failed on file " + Filename); + fatal("internal manifest tool failed on file " + Filename + ": " + + toString(std::move(E))); } return Merger.getMergedManifest().get()->getBuffer(); @@ -381,7 +383,7 @@ std::error_code EC; raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text); if (EC) - fatal(EC, "failed to open " + Default.Path); + fatal("failed to open " + Default.Path + ": " + EC.message()); OS << DefaultXml; OS.close(); @@ -482,7 +484,7 @@ std::error_code EC; raw_fd_ostream Out(Path, EC, sys::fs::F_Text); if (EC) - fatal(EC, "failed to create manifest"); + fatal("failed to create manifest: " + EC.message()); Out << createManifestXml(); } @@ -649,13 +651,13 @@ if (!RF) fatal("cannot compile non-resource file as resource"); if (auto EC = Parser.parse(RF)) - fatal(EC, "failed to parse .res file"); + fatal("failed to parse .res file: " + toString(std::move(EC))); } Expected> E = llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); if (!E) - fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF"); + fatal("failed to write .res to COFF: " + toString(E.takeError())); MemoryBufferRef MBRef = **E; make>(std::move(*E)); // take ownership @@ -739,7 +741,7 @@ } // Handle /WX early since it converts missing argument warnings to errors. - Config->FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); + errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); if (MissingCount) fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); Index: lld/COFF/Error.h =================================================================== --- lld/COFF/Error.h +++ /dev/null @@ -1,64 +0,0 @@ -//===- Error.h --------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_ERROR_H -#define LLD_COFF_ERROR_H - -#include "lld/Common/LLVM.h" -#include "llvm/Support/Error.h" - -namespace lld { -namespace coff { - -extern uint64_t ErrorCount; -extern llvm::raw_ostream *ErrorOS; - -void log(const Twine &Msg); -void message(const Twine &Msg); -void warn(const Twine &Msg); -void error(const Twine &Msg); -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); - -LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); - -template T check(ErrorOr V, const Twine &Prefix) { - if (auto EC = V.getError()) - fatal(EC, Prefix); - return std::move(*V); -} - -template T check(Expected E, const Twine &Prefix) { - if (llvm::Error Err = E.takeError()) - fatal(Err, Prefix); - return std::move(*E); -} - -template T check(ErrorOr EO) { - if (!EO) - fatal(EO.getError().message()); - return std::move(*EO); -} - -template T check(Expected E) { - if (!E) { - std::string Buf; - llvm::raw_string_ostream OS(Buf); - logAllUnhandledErrors(E.takeError(), OS, ""); - OS.flush(); - fatal(Buf); - } - return std::move(*E); -} - -} // namespace coff -} // namespace lld - -#endif Index: lld/COFF/Error.cpp =================================================================== --- lld/COFF/Error.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//===- Error.cpp ----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#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 -#endif - -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 { -uint64_t ErrorCount; -raw_ostream *ErrorOS; - -LLVM_ATTRIBUTE_NORETURN 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 << Config->Argv[0] << ": "; - if (Config->ColorDiagnostics) { - ErrorOS->changeColor(C, true); - *ErrorOS << S; - ErrorOS->resetColor(); - } else { - *ErrorOS << S; - } -} - -void log(const Twine &Msg) { - if (Config->Verbose) { - std::lock_guard Lock(Mu); - outs() << Config->Argv[0] << ": " << Msg << "\n"; - outs().flush(); - } -} - -void message(const Twine &Msg) { - std::lock_guard Lock(Mu); - outs() << Msg << "\n"; - outs().flush(); -} - -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 /ERRORLIMIT:0 to see all errors)\n"; - if (Config->CanExitEarly) - exitLld(1); - } - - ++ErrorCount; -} - -void fatal(const Twine &Msg) { - if (Config->ColorDiagnostics) { - errs().changeColor(raw_ostream::RED, /*bold=*/true); - errs() << "error: "; - errs().resetColor(); - } else { - errs() << "error: "; - } - errs() << Msg << "\n"; - exitLld(1); -} - -void fatal(std::error_code EC, const Twine &Msg) { - fatal(Msg + ": " + EC.message()); -} - -void fatal(llvm::Error &Err, const Twine &Msg) { - 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: lld/COFF/ICF.cpp =================================================================== --- lld/COFF/ICF.cpp +++ lld/COFF/ICF.cpp @@ -19,8 +19,8 @@ //===----------------------------------------------------------------------===// #include "Chunks.h" -#include "Error.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Hashing.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Parallel.h" Index: lld/COFF/InputFiles.cpp =================================================================== --- lld/COFF/InputFiles.cpp +++ lld/COFF/InputFiles.cpp @@ -11,10 +11,10 @@ #include "Chunks.h" #include "Config.h" #include "Driver.h" -#include "Error.h" #include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm-c/lto.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" @@ -127,9 +127,9 @@ const coff_section *Sec; StringRef Name; if (auto EC = COFFObj->getSection(I, Sec)) - fatal(EC, "getSection failed: #" + Twine(I)); + fatal("getSection failed: #" + Twine(I) + ": " + EC.message()); if (auto EC = COFFObj->getSectionName(Sec, Name)) - fatal(EC, "getSectionName failed: #" + Twine(I)); + fatal("getSectionName failed: #" + Twine(I) + ": " + EC.message()); if (Name == ".sxdata") { SXData = Sec; continue; @@ -179,7 +179,6 @@ int32_t LastSectionNumber = 0; for (uint32_t I = 0; I < NumSymbols; ++I) { - // Get a COFFSymbolRef object. COFFSymbolRef Sym = check(COFFObj->getSymbol(I)); const void *AuxP = nullptr; Index: lld/COFF/LTO.cpp =================================================================== --- lld/COFF/LTO.cpp +++ lld/COFF/LTO.cpp @@ -9,9 +9,9 @@ #include "LTO.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" Index: lld/COFF/MapFile.cpp =================================================================== --- lld/COFF/MapFile.cpp +++ lld/COFF/MapFile.cpp @@ -20,11 +20,11 @@ //===----------------------------------------------------------------------===// #include "MapFile.h" -#include "Error.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/raw_ostream.h" Index: lld/COFF/MinGW.cpp =================================================================== --- lld/COFF/MinGW.cpp +++ lld/COFF/MinGW.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "MinGW.h" -#include "Error.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -11,10 +11,10 @@ #include "Chunks.h" #include "Config.h" #include "Driver.h" -#include "Error.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" @@ -188,7 +188,7 @@ return None; TypeServer2Record TS; if (auto EC = TypeDeserializer::deserializeAs(const_cast(Type), TS)) - fatal(EC, "error reading type server record"); + fatal("error reading type server record: " + toString(std::move(EC))); return std::move(TS); } @@ -202,7 +202,7 @@ CVTypeArray Types; BinaryStreamReader Reader(Stream); if (auto EC = Reader.readArray(Types, Reader.getLength())) - fatal(EC, "Reader::readArray failed"); + fatal("Reader::readArray failed: " + toString(std::move(EC))); // Look through type servers. If we've already seen this type server, don't // merge any type information. @@ -213,7 +213,8 @@ // ObjectIndexMap. if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, ObjectIndexMap.TPIMap, Types)) - fatal(Err, "codeview::mergeTypeAndIdRecords failed"); + fatal("codeview::mergeTypeAndIdRecords failed: " + + toString(std::move(Err))); return ObjectIndexMap; } @@ -275,23 +276,23 @@ ExpectedSession = tryToLoadPDB(TS.getGuid(), Path); } if (auto E = ExpectedSession.takeError()) - fatal(E, "Type server PDB was not found"); + fatal("Type server PDB was not found: " + toString(std::move(E))); // Merge TPI first, because the IPI stream will reference type indices. auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream(); if (auto E = ExpectedTpi.takeError()) - fatal(E, "Type server does not have TPI stream"); + fatal("Type server does not have TPI stream: " + toString(std::move(E))); if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap, ExpectedTpi->typeArray())) - fatal(Err, "codeview::mergeTypeRecords failed"); + fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); // Merge IPI. auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream(); if (auto E = ExpectedIpi.takeError()) - fatal(E, "Type server does not have TPI stream"); + fatal("Type server does not have TPI stream: " + toString(std::move(E))); if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap, ExpectedIpi->typeArray())) - fatal(Err, "codeview::mergeIdRecords failed"); + fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); return IndexMap; } Index: lld/COFF/SymbolTable.cpp =================================================================== --- lld/COFF/SymbolTable.cpp +++ lld/COFF/SymbolTable.cpp @@ -10,10 +10,10 @@ #include "SymbolTable.h" #include "Config.h" #include "Driver.h" -#include "Error.h" #include "LTO.h" #include "Memory.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" Index: lld/COFF/Symbols.cpp =================================================================== --- lld/COFF/Symbols.cpp +++ lld/COFF/Symbols.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" -#include "Error.h" #include "InputFiles.h" #include "Memory.h" #include "Strings.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" Index: lld/COFF/Writer.cpp =================================================================== --- lld/COFF/Writer.cpp +++ lld/COFF/Writer.cpp @@ -10,13 +10,13 @@ #include "Writer.h" #include "Config.h" #include "DLL.h" -#include "Error.h" #include "InputFiles.h" #include "MapFile.h" #include "Memory.h" #include "PDB.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -316,7 +316,7 @@ writeMapFile(OutputSections); if (auto EC = Buffer->commit()) - fatal(EC, "failed to write the output file"); + fatal("failed to write the output file: " + EC.message()); } static StringRef getOutputSection(StringRef Name) { Index: lld/Common/CMakeLists.txt =================================================================== --- lld/Common/CMakeLists.txt +++ lld/Common/CMakeLists.txt @@ -3,6 +3,7 @@ endif() add_lld_library(lldCommon + ErrorHandler.cpp Reproduce.cpp TargetOptionsCommandFlags.cpp Threads.cpp Index: lld/Common/ErrorHandler.cpp =================================================================== --- lld/Common/ErrorHandler.cpp +++ lld/Common/ErrorHandler.cpp @@ -1,4 +1,4 @@ -//===- Error.cpp ----------------------------------------------------------===// +//===- ErrorHandler.cpp ---------------------------------------------------===// // // The LLVM Linker // @@ -7,8 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" -#include "Config.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Threads.h" @@ -25,10 +24,6 @@ using namespace llvm; using namespace lld; -using namespace lld::elf; - -uint64_t elf::ErrorCount; -raw_ostream *elf::ErrorOS; // 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. @@ -36,7 +31,7 @@ // Prints "\n" or does nothing, depending on Msg contents of // the previous call of this function. -static void newline(const Twine &Msg) { +static void newline(raw_ostream *ErrorOS, const Twine &Msg) { // True if the previous error message contained "\n". // We want to separate multi-line error messages with a newline. static bool Flag; @@ -46,9 +41,28 @@ Flag = StringRef(Msg.str()).contains('\n'); } -static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Config->Argv[0] << ": "; - if (Config->ColorDiagnostics) { +namespace lld { + +ErrorHandler &errorHandler() { + static ErrorHandler Handler; + return Handler; +} + +void exitLld(int Val) { + waitForBackgroundThreads(); + // 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); +} + +void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { + *ErrorOS << LogName << ": "; + if (ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; ErrorOS->resetColor(); @@ -57,64 +71,52 @@ } } -void elf::log(const Twine &Msg) { - if (Config->Verbose) { +void ErrorHandler::log(const Twine &Msg) { + if (Verbose) { std::lock_guard Lock(Mu); - outs() << Config->Argv[0] << ": " << Msg << "\n"; + outs() << LogName << ": " << Msg << "\n"; outs().flush(); } } -void elf::message(const Twine &Msg) { +void ErrorHandler::message(const Twine &Msg) { std::lock_guard Lock(Mu); outs() << Msg << "\n"; outs().flush(); } -void elf::warn(const Twine &Msg) { - if (Config->FatalWarnings) { +void ErrorHandler::warn(const Twine &Msg) { + if (FatalWarnings) { error(Msg); return; } std::lock_guard Lock(Mu); - newline(Msg); + newline(ErrorOS, Msg); print("warning: ", raw_ostream::MAGENTA); *ErrorOS << Msg << "\n"; } -void elf::error(const Twine &Msg) { +void ErrorHandler::error(const Twine &Msg) { std::lock_guard Lock(Mu); - newline(Msg); + newline(ErrorOS, Msg); - if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) { + if (ErrorLimit == 0 || ErrorCount < ErrorLimit) { print("error: ", raw_ostream::RED); *ErrorOS << Msg << "\n"; - } else if (ErrorCount == Config->ErrorLimit) { + } else if (ErrorCount == 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) + *ErrorOS << ErrorLimitExceededMsg << "\n"; + if (ExitEarly) exitLld(1); } ++ErrorCount; } -void elf::exitLld(int Val) { - waitForBackgroundThreads(); - - // 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); -} - -void elf::fatal(const Twine &Msg) { +void ErrorHandler::fatal(const Twine &Msg) { error(Msg); exitLld(1); } + +} // end namespace lld Index: lld/ELF/Arch/AArch64.cpp =================================================================== --- lld/ELF/Arch/AArch64.cpp +++ lld/ELF/Arch/AArch64.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" Index: lld/ELF/Arch/AMDGPU.cpp =================================================================== --- lld/ELF/Arch/AMDGPU.cpp +++ lld/ELF/Arch/AMDGPU.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" Index: lld/ELF/Arch/ARM.cpp =================================================================== --- lld/ELF/Arch/ARM.cpp +++ lld/ELF/Arch/ARM.cpp @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" Index: lld/ELF/Arch/AVR.cpp =================================================================== --- lld/ELF/Arch/AVR.cpp +++ lld/ELF/Arch/AVR.cpp @@ -26,10 +26,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" Index: lld/ELF/Arch/Mips.cpp =================================================================== --- lld/ELF/Arch/Mips.cpp +++ lld/ELF/Arch/Mips.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" Index: lld/ELF/Arch/MipsArchTree.cpp =================================================================== --- lld/ELF/Arch/MipsArchTree.cpp +++ lld/ELF/Arch/MipsArchTree.cpp @@ -11,11 +11,11 @@ // //===---------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "SymbolTable.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" #include "llvm/Support/MipsABIFlags.h" Index: lld/ELF/Arch/PPC.cpp =================================================================== --- lld/ELF/Arch/PPC.cpp +++ lld/ELF/Arch/PPC.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; Index: lld/ELF/Arch/PPC64.cpp =================================================================== --- lld/ELF/Arch/PPC64.cpp +++ lld/ELF/Arch/PPC64.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; Index: lld/ELF/Arch/SPARCV9.cpp =================================================================== --- lld/ELF/Arch/SPARCV9.cpp +++ lld/ELF/Arch/SPARCV9.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; Index: lld/ELF/Arch/X86.cpp =================================================================== --- lld/ELF/Arch/X86.cpp +++ lld/ELF/Arch/X86.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; Index: lld/ELF/Arch/X86_64.cpp =================================================================== --- lld/ELF/Arch/X86_64.cpp +++ lld/ELF/Arch/X86_64.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" Index: lld/ELF/CMakeLists.txt =================================================================== --- lld/ELF/CMakeLists.txt +++ lld/ELF/CMakeLists.txt @@ -21,7 +21,6 @@ Driver.cpp DriverUtils.cpp EhFrame.cpp - Error.cpp Filesystem.cpp GdbIndex.cpp ICF.cpp Index: lld/ELF/Config.h =================================================================== --- lld/ELF/Config.h +++ lld/ELF/Config.h @@ -105,7 +105,6 @@ bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; - bool ColorDiagnostics = false; bool CompressDebugSections; bool DefineCommon; bool Demangle = true; @@ -114,7 +113,6 @@ bool EmitRelocs; bool EnableNewDtags; bool ExportDynamic; - bool FatalWarnings; bool GcSections; bool GdbIndex; bool GnuHash = false; @@ -163,7 +161,6 @@ ELFKind EKind = ELFNoneKind; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; - uint64_t ErrorLimit = 20; llvm::Optional ImageBase; uint64_t MaxPageSize; uint64_t ZStackSize; Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -25,7 +25,6 @@ #include "Driver.h" #include "Config.h" -#include "Error.h" #include "Filesystem.h" #include "ICF.h" #include "InputFiles.h" @@ -40,6 +39,7 @@ #include "Target.h" #include "Writer.h" #include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" #include "llvm/ADT/StringExtras.h" @@ -72,8 +72,9 @@ bool elf::link(ArrayRef Args, bool CanExitEarly, raw_ostream &Error) { - ErrorCount = 0; - ErrorOS = &Error; + errorHandler().LogName = Args[0]; + errorHandler().ErrorOS = &Error; + errorHandler().ColorDiagnostics = Error.has_colors(); InputSections.clear(); OutputSections.clear(); Tar = nullptr; @@ -95,10 +96,10 @@ // This saves time because the overhead of calling destructors // for all globally-allocated objects is not negligible. if (Config->ExitEarly) - exitLld(ErrorCount ? 1 : 0); + exitLld(errorCount() ? 1 : 0); freeArena(); - return !ErrorCount; + return !errorCount(); } // Parses a linker -m option. @@ -332,7 +333,7 @@ opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); // Interpret this flag early because error() depends on them. - Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20); + errorHandler().ErrorLimit = getInteger(Args, OPT_error_limit, 20); // Handle -help if (Args.hasArg(OPT_help)) { @@ -365,6 +366,7 @@ return; Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); + errorHandler().ExitEarly = Config->ExitEarly; if (const char *Path = getReproduceOption(Args)) { // Note that --reproduce is a debug option so you can ignore it @@ -388,7 +390,7 @@ inferMachineType(); setConfigs(); checkOptions(Args); - if (ErrorCount) + if (errorCount()) return; switch (Config->EKind) { @@ -634,7 +636,7 @@ Config->Entry = Args.getLastArgValue(OPT_entry); Config->ExportDynamic = Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); - Config->FatalWarnings = + errorHandler().FatalWarnings = Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); Config->FilterList = getArgs(Args, OPT_filter); Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); @@ -682,6 +684,7 @@ Config->Undefined = getArgs(Args, OPT_undefined); Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args); Config->Verbose = Args.hasArg(OPT_verbose); + errorHandler().Verbose = Config->Verbose; Config->WarnCommon = Args.hasArg(OPT_warn_common); Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); Config->ZExecstack = hasZOption(Args, "execstack"); @@ -869,7 +872,7 @@ } } - if (Files.empty() && ErrorCount == 0) + if (Files.empty() && errorCount() == 0) error("no input files"); } @@ -997,7 +1000,7 @@ error("cannot open output file " + Config->OutputFile + ": " + E.message()); if (auto E = tryCreateFile(Config->MapFile)) error("cannot open map file " + Config->MapFile + ": " + E.message()); - if (ErrorCount) + if (errorCount()) return; // Use default entry point name if no name was given via the command @@ -1041,7 +1044,7 @@ Symtab->fetchIfLazy(Config->Entry); // Return if there were name resolution errors. - if (ErrorCount) + if (errorCount()) return; // Handle undefined symbols in DSOs. @@ -1063,7 +1066,7 @@ Symtab->addSymbolAlias(Def.first, Def.second); Symtab->addCombinedLTOObject(); - if (ErrorCount) + if (errorCount()) return; // Apply symbol renames for -wrap and -defsym Index: lld/ELF/DriverUtils.cpp =================================================================== --- lld/ELF/DriverUtils.cpp +++ lld/ELF/DriverUtils.cpp @@ -14,8 +14,8 @@ //===----------------------------------------------------------------------===// #include "Driver.h" -#include "Error.h" #include "Memory.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Reproduce.h" #include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" @@ -51,25 +51,26 @@ ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} -// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics. -static bool getColorDiagnostics(opt::InputArgList &Args) { +// Set color diagnostics according to -color-diagnostics={auto,always,never} +// or -no-color-diagnostics flags. +static void handleColorDiagnostics(opt::InputArgList &Args, ErrorHandler &EH) { auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, OPT_no_color_diagnostics); if (!Arg) - return ErrorOS->has_colors(); - if (Arg->getOption().getID() == OPT_color_diagnostics) - return true; - if (Arg->getOption().getID() == OPT_no_color_diagnostics) - return false; - - StringRef S = Arg->getValue(); - if (S == "auto") - return ErrorOS->has_colors(); - if (S == "always") - return true; - if (S != "never") - error("unknown option: -color-diagnostics=" + S); - return false; + return; + else if (Arg->getOption().getID() == OPT_color_diagnostics) + EH.ColorDiagnostics = true; + else if (Arg->getOption().getID() == OPT_no_color_diagnostics) + EH.ColorDiagnostics = false; + else { + StringRef S = Arg->getValue(); + if (S == "always") + EH.ColorDiagnostics = true; + else if (S == "never") + EH.ColorDiagnostics = false; + else if (S != "auto") + error("unknown option: -color-diagnostics=" + S); + } } static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { @@ -103,9 +104,7 @@ cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); Args = this->ParseArgs(Vec, MissingIndex, MissingCount); - // Interpret -color-diagnostics early so that error messages - // for unknown flags are colored. - Config->ColorDiagnostics = getColorDiagnostics(Args); + handleColorDiagnostics(Args, errorHandler()); if (MissingCount) error(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); Index: lld/ELF/EhFrame.cpp =================================================================== --- lld/ELF/EhFrame.cpp +++ lld/ELF/EhFrame.cpp @@ -17,11 +17,11 @@ //===----------------------------------------------------------------------===// #include "EhFrame.h" -#include "Error.h" #include "InputSection.h" #include "Relocations.h" #include "Strings.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" Index: lld/ELF/InputFiles.h =================================================================== --- lld/ELF/InputFiles.h +++ lld/ELF/InputFiles.h @@ -11,9 +11,9 @@ #define LLD_ELF_INPUT_FILES_H #include "Config.h" -#include "Error.h" #include "InputSection.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "lld/Common/Reproduce.h" Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -8,13 +8,13 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "Error.h" #include "InputSection.h" #include "LinkerScript.h" #include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" Index: lld/ELF/InputSection.cpp =================================================================== --- lld/ELF/InputSection.cpp +++ lld/ELF/InputSection.cpp @@ -10,7 +10,6 @@ #include "InputSection.h" #include "Config.h" #include "EhFrame.h" -#include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "Memory.h" @@ -19,6 +18,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" Index: lld/ELF/LTO.cpp =================================================================== --- lld/ELF/LTO.cpp +++ lld/ELF/LTO.cpp @@ -9,11 +9,11 @@ #include "LTO.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" Index: lld/ELF/Relocations.cpp =================================================================== --- lld/ELF/Relocations.cpp +++ lld/ELF/Relocations.cpp @@ -927,7 +927,7 @@ Expr = fromPlt(Expr); Expr = adjustExpr(Body, Expr, Type, Sec, Rel.r_offset); - if (ErrorCount) + if (errorCount()) continue; // This relocation does not require got entry, but it is relative to got and Index: lld/ELF/ScriptLexer.cpp =================================================================== --- lld/ELF/ScriptLexer.cpp +++ lld/ELF/ScriptLexer.cpp @@ -33,7 +33,7 @@ //===----------------------------------------------------------------------===// #include "ScriptLexer.h" -#include "Error.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Twine.h" using namespace llvm; @@ -75,7 +75,7 @@ // We don't want to record cascading errors. Keep only the first one. void ScriptLexer::setError(const Twine &Msg) { - if (ErrorCount) + if (errorCount()) return; std::string S = (getCurrentLocation() + ": " + Msg).str(); @@ -159,7 +159,7 @@ } // An erroneous token is handled as if it were the last token before EOF. -bool ScriptLexer::atEOF() { return ErrorCount || Tokens.size() == Pos; } +bool ScriptLexer::atEOF() { return errorCount() || Tokens.size() == Pos; } // Split a given string as an expression. // This function returns "3", "*" and "5" for "3*5" for example. @@ -207,7 +207,7 @@ // // This function may split the current token into multiple tokens. void ScriptLexer::maybeSplitExpr() { - if (!InExpr || ErrorCount || atEOF()) + if (!InExpr || errorCount() || atEOF()) return; std::vector V = tokenizeExpr(Tokens[Pos]); @@ -220,7 +220,7 @@ StringRef ScriptLexer::next() { maybeSplitExpr(); - if (ErrorCount) + if (errorCount()) return ""; if (atEOF()) { setError("unexpected EOF"); @@ -231,7 +231,7 @@ StringRef ScriptLexer::peek() { StringRef Tok = next(); - if (ErrorCount) + if (errorCount()) return ""; Pos = Pos - 1; return Tok; @@ -260,7 +260,7 @@ void ScriptLexer::skip() { (void)next(); } void ScriptLexer::expect(StringRef Expect) { - if (ErrorCount) + if (errorCount()) return; StringRef Tok = next(); if (Tok != Expect) Index: lld/ELF/ScriptParser.cpp =================================================================== --- lld/ELF/ScriptParser.cpp +++ lld/ELF/ScriptParser.cpp @@ -209,7 +209,7 @@ return; } - while (!atEOF() && !ErrorCount && peek() != "}") { + while (!atEOF() && !errorCount() && peek() != "}") { StringRef VerStr = next(); if (VerStr == "{") { setError("anonymous version definition is used in " @@ -303,7 +303,7 @@ expect("("); bool Orig = Config->AsNeeded; Config->AsNeeded = true; - while (!ErrorCount && !consume(")")) + while (!errorCount() && !consume(")")) addFile(unquote(next())); Config->AsNeeded = Orig; } @@ -319,13 +319,13 @@ void ScriptParser::readExtern() { expect("("); - while (!ErrorCount && !consume(")")) + while (!errorCount() && !consume(")")) Config->Undefined.push_back(next()); } void ScriptParser::readGroup() { expect("("); - while (!ErrorCount && !consume(")")) { + while (!errorCount() && !consume(")")) { if (consume("AS_NEEDED")) readAsNeeded(); else @@ -369,7 +369,7 @@ void ScriptParser::readOutputArch() { // OUTPUT_ARCH is ignored for now. expect("("); - while (!ErrorCount && !consume(")")) + while (!errorCount() && !consume(")")) skip(); } @@ -389,12 +389,12 @@ void ScriptParser::readPhdrs() { expect("{"); - while (!ErrorCount && !consume("}")) { + while (!errorCount() && !consume("}")) { PhdrsCommand Cmd; Cmd.Name = next(); Cmd.Type = readPhdrType(); - while (!ErrorCount && !consume(";")) { + while (!errorCount() && !consume(";")) { if (consume("FILEHDR")) Cmd.HasFilehdr = true; else if (consume("PHDRS")) @@ -442,7 +442,7 @@ Config->SingleRoRx = true; expect("{"); - while (!ErrorCount && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Tok = next(); BaseCommand *Cmd = readProvideOrAssignment(Tok); if (!Cmd) { @@ -467,7 +467,7 @@ StringMatcher ScriptParser::readFilePatterns() { std::vector V; - while (!ErrorCount && !consume(")")) + while (!errorCount() && !consume(")")) V.push_back(next()); return StringMatcher(V); } @@ -499,7 +499,7 @@ // any file but a.o, and section .baz in any file but b.o. std::vector ScriptParser::readInputSectionsList() { std::vector Ret; - while (!ErrorCount && peek() != ")") { + while (!errorCount() && peek() != ")") { StringMatcher ExcludeFilePat; if (consume("EXCLUDE_FILE")) { expect("("); @@ -507,7 +507,7 @@ } std::vector V; - while (!ErrorCount && peek() != ")" && peek() != "EXCLUDE_FILE") + while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE") V.push_back(next()); if (!V.empty()) @@ -534,7 +534,7 @@ auto *Cmd = make(FilePattern); expect("("); - while (!ErrorCount && !consume(")")) { + while (!errorCount() && !consume(")")) { SortSectionPolicy Outer = readSortKind(); SortSectionPolicy Inner = SortSectionPolicy::Default; std::vector V; @@ -664,7 +664,7 @@ Cmd->Constraint = ConstraintKind::ReadWrite; expect("{"); - while (!ErrorCount && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Tok = next(); if (Tok == ";") { // Empty commands are allowed. Do nothing here. @@ -808,7 +808,7 @@ // This is a part of the operator-precedence parser. This function // assumes that the remaining token stream starts with an operator. Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) { - while (!atEOF() && !ErrorCount) { + while (!atEOF() && !errorCount()) { // Read an operator and an expression. if (consume("?")) return readTernary(Lhs); @@ -1086,7 +1086,7 @@ std::vector ScriptParser::readOutputSectionPhdrs() { std::vector Phdrs; - while (!ErrorCount && peek().startswith(":")) { + while (!errorCount() && peek().startswith(":")) { StringRef Tok = next(); Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1)); } @@ -1189,7 +1189,7 @@ std::vector Globals; std::vector *V = &Globals; - while (!ErrorCount) { + while (!errorCount()) { if (consume("}")) break; if (consumeLabel("local")) { @@ -1223,7 +1223,7 @@ expect("{"); std::vector Ret; - while (!ErrorCount && peek() != "}") { + while (!errorCount() && peek() != "}") { StringRef Tok = next(); bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok); Ret.push_back({unquote(Tok), IsCXX, HasWildcard}); @@ -1250,7 +1250,7 @@ // MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... } void ScriptParser::readMemory() { expect("{"); - while (!ErrorCount && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Name = next(); uint32_t Flags = 0; Index: lld/ELF/Strings.cpp =================================================================== --- lld/ELF/Strings.cpp +++ lld/ELF/Strings.cpp @@ -9,7 +9,7 @@ #include "Strings.h" #include "Config.h" -#include "Error.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" Index: lld/ELF/SymbolTable.cpp =================================================================== --- lld/ELF/SymbolTable.cpp +++ lld/ELF/SymbolTable.cpp @@ -16,10 +16,10 @@ #include "SymbolTable.h" #include "Config.h" -#include "Error.h" #include "LinkerScript.h" #include "Memory.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; @@ -91,7 +91,7 @@ if (auto *F = dyn_cast>(File)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); - if (ErrorCount || !SoNames.insert(F->SoName).second) + if (errorCount() || !SoNames.insert(F->SoName).second) return; SharedFiles.push_back(F); F->parseRest(); Index: lld/ELF/Symbols.cpp =================================================================== --- lld/ELF/Symbols.cpp +++ lld/ELF/Symbols.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" -#include "Error.h" #include "InputFiles.h" #include "InputSection.h" #include "OutputSections.h" @@ -17,6 +16,7 @@ #include "Target.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Path.h" #include Index: lld/ELF/SyntheticSections.cpp =================================================================== --- lld/ELF/SyntheticSections.cpp +++ lld/ELF/SyntheticSections.cpp @@ -16,7 +16,6 @@ #include "SyntheticSections.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "Memory.h" @@ -25,6 +24,7 @@ #include "SymbolTable.h" #include "Target.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" #include "llvm/BinaryFormat/Dwarf.h" Index: lld/ELF/Target.h =================================================================== --- lld/ELF/Target.h +++ lld/ELF/Target.h @@ -10,8 +10,8 @@ #ifndef LLD_ELF_TARGET_H #define LLD_ELF_TARGET_H -#include "Error.h" #include "InputSection.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" namespace lld { Index: lld/ELF/Target.cpp =================================================================== --- lld/ELF/Target.cpp +++ lld/ELF/Target.cpp @@ -25,11 +25,11 @@ //===----------------------------------------------------------------------===// #include "Target.h" -#include "Error.h" #include "InputFiles.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" using namespace llvm; Index: lld/ELF/Thunks.cpp =================================================================== --- lld/ELF/Thunks.cpp +++ lld/ELF/Thunks.cpp @@ -23,13 +23,13 @@ #include "Thunks.h" #include "Config.h" -#include "Error.h" #include "InputSection.h" #include "Memory.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -188,7 +188,7 @@ // to the string table, and add entries to .got and .plt. // finalizeSections does that. finalizeSections(); - if (ErrorCount) + if (errorCount()) return; // If -compressed-debug-sections is specified, we need to compress @@ -218,11 +218,11 @@ } // It does not make sense try to open the file if we have error already. - if (ErrorCount) + if (errorCount()) return; // Write the result down to a file. openFile(); - if (ErrorCount) + if (errorCount()) return; if (!Config->OFormatBinary) { @@ -236,12 +236,12 @@ // Backfill .note.gnu.build-id section content. This is done at last // because the content is usually a hash value of the entire output file. writeBuildId(); - if (ErrorCount) + if (errorCount()) return; // Handle -Map option. writeMapFile(); - if (ErrorCount) + if (errorCount()) return; if (auto EC = Buffer->commit()) @@ -1287,7 +1287,7 @@ } // Do not proceed if there was an undefined symbol. - if (ErrorCount) + if (errorCount()) return; addPredefinedSections(); Index: lld/include/lld/Common/ErrorHandler.h =================================================================== --- lld/include/lld/Common/ErrorHandler.h +++ lld/include/lld/Common/ErrorHandler.h @@ -1,4 +1,4 @@ -//===- Error.h --------------------------------------------------*- C++ -*-===// +//===- ErrorHandler.h -------------------------------------------*- C++ -*-===// // // The LLVM Linker // @@ -25,24 +25,55 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_ELF_ERROR_H -#define LLD_ELF_ERROR_H +#ifndef LLD_COMMON_ERRORHANDLER_H +#define LLD_COMMON_ERRORHANDLER_H #include "lld/Common/LLVM.h" #include "llvm/Support/Error.h" namespace lld { -namespace elf { -extern uint64_t ErrorCount; -extern llvm::raw_ostream *ErrorOS; +class ErrorHandler { +public: + uint64_t ErrorCount = 0; + uint64_t ErrorLimit = 20; + StringRef ErrorLimitExceededMsg; + StringRef LogName; + llvm::raw_ostream *ErrorOS; + bool ColorDiagnostics = false; + bool ExitEarly = true; + bool FatalWarnings = false; + bool Verbose = false; -void log(const Twine &Msg); -void message(const Twine &Msg); -void warn(const Twine &Msg); -void error(const Twine &Msg); -LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); + ErrorHandler() : ErrorHandler(&llvm::errs(), "lld") {} + ErrorHandler(llvm::raw_ostream *Stream, StringRef LogName) + : ErrorLimitExceededMsg("too many errors emitted, stopping now (use " + "-error-limit=0 to see all errors)"), + LogName(LogName), ErrorOS(Stream), + ColorDiagnostics(Stream->has_colors()) {} + + void error(const Twine &Msg); + LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); + void log(const Twine &Msg); + void message(const Twine &Msg); + void warn(const Twine &Msg); + +private: + void print(StringRef S, raw_ostream::Colors C); +}; + +/// Returns the default error handler. +ErrorHandler &errorHandler(); + +inline void error(const Twine &Msg) { errorHandler().error(Msg); } +inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg) { + errorHandler().fatal(Msg); +} +inline void log(const Twine &Msg) { errorHandler().log(Msg); } +inline void message(const Twine &Msg) { errorHandler().message(Msg); } +inline void warn(const Twine &Msg) { errorHandler().warn(Msg); } +inline uint64_t errorCount() { return errorHandler().ErrorCount; } LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); @@ -72,7 +103,6 @@ return std::move(*E); } -} // namespace elf } // namespace lld #endif