aboutsummaryrefslogtreecommitdiffstats
path: root/Common/ErrorHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Common/ErrorHandler.cpp')
-rw-r--r--Common/ErrorHandler.cpp139
1 files changed, 85 insertions, 54 deletions
diff --git a/Common/ErrorHandler.cpp b/Common/ErrorHandler.cpp
index c87c0609b260..b91854c51cef 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;
}