diff options
Diffstat (limited to 'Common/ErrorHandler.cpp')
-rw-r--r-- | Common/ErrorHandler.cpp | 139 |
1 files changed, 85 insertions, 54 deletions
diff --git a/Common/ErrorHandler.cpp b/Common/ErrorHandler.cpp index c87c0609b2601..b91854c51cef8 100644 --- a/Common/ErrorHandler.cpp +++ b/Common/ErrorHandler.cpp @@ -29,16 +29,14 @@ using namespace lld; // but outs() or errs() are not thread-safe. We protect them using a mutex. static std::mutex mu; -// Prints "\n" or does nothing, depending on Msg contents of -// the previous call of this function. -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; - - if (flag) - *errorOS << "\n"; - flag = StringRef(msg.str()).contains('\n'); +// We want to separate multi-line messages with a newline. `sep` is "\n" +// if the last messages was multi-line. Otherwise "". +static StringRef sep; + +static StringRef getSeparator(const Twine &msg) { + if (StringRef(msg.str()).contains('\n')) + return "\n"; + return ""; } ErrorHandler &lld::errorHandler() { @@ -46,6 +44,10 @@ ErrorHandler &lld::errorHandler() { return handler; } +void lld::enableColors(bool enable) { + errorHandler().errorOS->enable_colors(enable); +} + void lld::exitLld(int val) { // Delete any temporary file, while keeping the memory mapping open. if (errorHandler().outputBuffer) @@ -85,56 +87,69 @@ void lld::checkError(Error e) { [&](ErrorInfoBase &eib) { error(eib.message()); }); } -static std::string getLocation(std::string msg, std::string defaultMsg) { - static std::vector<std::regex> Regexes{ - std::regex(R"(^undefined symbol:.*\n>>> referenced by (\S+):(\d+)\n.*)"), +// This is for --vs-diagnostics. +// +// Normally, lld's error message starts with argv[0]. Therefore, it usually +// looks like this: +// +// ld.lld: error: ... +// +// This error message style is unfortunately unfriendly to Visual Studio +// IDE. VS interprets the first word of the first line as an error location +// and make it clickable, thus "ld.lld" in the above message would become a +// clickable text. When you click it, VS opens "ld.lld" executable file with +// a binary editor. +// +// As a workaround, we print out an error location instead of "ld.lld" if +// lld is running in VS diagnostics mode. As a result, error message will +// look like this: +// +// src/foo.c(35): error: ... +// +// This function returns an error location string. An error location is +// extracted from an error message using regexps. +std::string ErrorHandler::getLocation(const Twine &msg) { + if (!vsDiagnostics) + return logName; + + static std::regex regexes[] = { + std::regex( + R"(^undefined (?:\S+ )?symbol:.*\n)" + R"(>>> referenced by .+\((\S+):(\d+)\))"), + std::regex( + R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"), std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), std::regex( R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), std::regex( - R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+).*)"), - std::regex( - R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), + R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"), + std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"), std::regex( - R"(^undefined (internal|hidden|protected) symbol: .*\n>>> referenced by (\S+):(\d+)\n.*)"), + R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"), + std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), std::regex(R"((\S+):(\d+): unclosed quote)"), }; - std::smatch Match; - for (std::regex &Re : Regexes) { - if (std::regex_search(msg, Match, Re)) { - return Match.size() > 2 ? Match.str(1) + "(" + Match.str(2) + ")" - : Match.str(1); - } - } - return defaultMsg; -} - -void ErrorHandler::printHeader(StringRef s, raw_ostream::Colors c, - const Twine &msg) { + std::string str = msg.str(); + for (std::regex &re : regexes) { + std::smatch m; + if (!std::regex_search(str, m, re)) + continue; - if (vsDiagnostics) { - // A Visual Studio-style error message starts with an error location. - // If a location cannot be extracted then we default to LogName. - *errorOS << getLocation(msg.str(), logName) << ": "; - } else { - *errorOS << logName << ": "; + assert(m.size() == 2 || m.size() == 3); + if (m.size() == 2) + return m.str(1); + return m.str(1) + "(" + m.str(2) + ")"; } - if (colorDiagnostics) { - errorOS->changeColor(c, true); - *errorOS << s; - errorOS->resetColor(); - } else { - *errorOS << s; - } + return logName; } void ErrorHandler::log(const Twine &msg) { - if (verbose) { - std::lock_guard<std::mutex> lock(mu); - *errorOS << logName << ": " << msg << "\n"; - } + if (!verbose) + return; + std::lock_guard<std::mutex> lock(mu); + *errorOS << logName << ": " << msg << "\n"; } void ErrorHandler::message(const Twine &msg) { @@ -150,25 +165,41 @@ void ErrorHandler::warn(const Twine &msg) { } std::lock_guard<std::mutex> lock(mu); - newline(errorOS, msg); - printHeader("warning: ", raw_ostream::MAGENTA, msg); - *errorOS << msg << "\n"; + *errorOS << sep << getLocation(msg) << ": " << Colors::MAGENTA + << "warning: " << Colors::RESET << msg << "\n"; + sep = getSeparator(msg); } void ErrorHandler::error(const Twine &msg) { + // If Visual Studio-style error message mode is enabled, + // this particular error is printed out as two errors. + if (vsDiagnostics) { + static std::regex re(R"(^(duplicate symbol: .*))" + R"((\n>>> defined at \S+:\d+.*\n>>>.*))" + R"((\n>>> defined at \S+:\d+.*\n>>>.*))"); + std::string str = msg.str(); + std::smatch m; + + if (std::regex_match(str, m, re)) { + error(m.str(1) + m.str(2)); + error(m.str(1) + m.str(3)); + return; + } + } + std::lock_guard<std::mutex> lock(mu); - newline(errorOS, msg); if (errorLimit == 0 || errorCount < errorLimit) { - printHeader("error: ", raw_ostream::RED, msg); - *errorOS << msg << "\n"; + *errorOS << sep << getLocation(msg) << ": " << Colors::RED + << "error: " << Colors::RESET << msg << "\n"; } else if (errorCount == errorLimit) { - printHeader("error: ", raw_ostream::RED, msg); - *errorOS << errorLimitExceededMsg << "\n"; + *errorOS << sep << getLocation(msg) << ": " << Colors::RED + << "error: " << Colors::RESET << errorLimitExceededMsg << "\n"; if (exitEarly) exitLld(1); } + sep = getSeparator(msg); ++errorCount; } |