/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/Common/ErrorHandler.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- ErrorHandler.cpp ---------------------------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "lld/Common/ErrorHandler.h" |
10 | | |
11 | | #include "lld/Common/Threads.h" |
12 | | |
13 | | #include "llvm/ADT/Twine.h" |
14 | | #include "llvm/IR/DiagnosticInfo.h" |
15 | | #include "llvm/IR/DiagnosticPrinter.h" |
16 | | #include "llvm/Support/ManagedStatic.h" |
17 | | #include "llvm/Support/raw_ostream.h" |
18 | | #include <mutex> |
19 | | #include <regex> |
20 | | |
21 | | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
22 | | #include <unistd.h> |
23 | | #endif |
24 | | |
25 | | using namespace llvm; |
26 | | using namespace lld; |
27 | | |
28 | | // The functions defined in this file can be called from multiple threads, |
29 | | // but outs() or errs() are not thread-safe. We protect them using a mutex. |
30 | | static std::mutex mu; |
31 | | |
32 | | // Prints "\n" or does nothing, depending on Msg contents of |
33 | | // the previous call of this function. |
34 | 3.65k | static void newline(raw_ostream *errorOS, const Twine &msg) { |
35 | 3.65k | // True if the previous error message contained "\n". |
36 | 3.65k | // We want to separate multi-line error messages with a newline. |
37 | 3.65k | static bool flag; |
38 | 3.65k | |
39 | 3.65k | if (flag) |
40 | 120 | *errorOS << "\n"; |
41 | 3.65k | flag = StringRef(msg.str()).contains('\n'); |
42 | 3.65k | } |
43 | | |
44 | 291k | ErrorHandler &lld::errorHandler() { |
45 | 291k | static ErrorHandler handler; |
46 | 291k | return handler; |
47 | 291k | } |
48 | | |
49 | 0 | void lld::exitLld(int val) { |
50 | 0 | // Delete any temporary file, while keeping the memory mapping open. |
51 | 0 | if (errorHandler().outputBuffer) |
52 | 0 | errorHandler().outputBuffer->discard(); |
53 | 0 |
|
54 | 0 | // Dealloc/destroy ManagedStatic variables before calling |
55 | 0 | // _exit(). In a non-LTO build, this is a nop. In an LTO |
56 | 0 | // build allows us to get the output of -time-passes. |
57 | 0 | llvm_shutdown(); |
58 | 0 |
|
59 | 0 | outs().flush(); |
60 | 0 | errs().flush(); |
61 | 0 | _exit(val); |
62 | 0 | } |
63 | | |
64 | 3 | void lld::diagnosticHandler(const DiagnosticInfo &di) { |
65 | 3 | SmallString<128> s; |
66 | 3 | raw_svector_ostream os(s); |
67 | 3 | DiagnosticPrinterRawOStream dp(os); |
68 | 3 | di.print(dp); |
69 | 3 | switch (di.getSeverity()) { |
70 | 3 | case DS_Error: |
71 | 1 | error(s); |
72 | 1 | break; |
73 | 3 | case DS_Warning: |
74 | 2 | warn(s); |
75 | 2 | break; |
76 | 3 | case DS_Remark: |
77 | 0 | case DS_Note: |
78 | 0 | message(s); |
79 | 0 | break; |
80 | 3 | } |
81 | 3 | } |
82 | | |
83 | 692 | void lld::checkError(Error e) { |
84 | 692 | handleAllErrors(std::move(e), |
85 | 692 | [&](ErrorInfoBase &eib) { error(eib.message()); }4 ); |
86 | 692 | } |
87 | | |
88 | 11 | static std::string getLocation(std::string msg, std::string defaultMsg) { |
89 | 11 | static std::vector<std::regex> Regexes{ |
90 | 11 | std::regex(R"(^undefined symbol:.*\n>>> referenced by (\S+):(\d+)\n.*)"), |
91 | 11 | std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), |
92 | 11 | std::regex( |
93 | 11 | R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), |
94 | 11 | std::regex( |
95 | 11 | R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+).*)"), |
96 | 11 | std::regex( |
97 | 11 | R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), |
98 | 11 | std::regex( |
99 | 11 | R"(^undefined (internal|hidden|protected) symbol: .*\n>>> referenced by (\S+):(\d+)\n.*)"), |
100 | 11 | std::regex(R"((\S+):(\d+): unclosed quote)"), |
101 | 11 | }; |
102 | 11 | |
103 | 11 | std::smatch Match; |
104 | 47 | for (std::regex &Re : Regexes) { |
105 | 47 | if (std::regex_search(msg, Match, Re)) { |
106 | 8 | return Match.size() > 2 ? Match.str(1) + "(" + Match.str(2) + ")"6 |
107 | 8 | : Match.str(1)2 ; |
108 | 8 | } |
109 | 47 | } |
110 | 11 | return defaultMsg3 ; |
111 | 11 | } |
112 | | |
113 | | void ErrorHandler::printHeader(StringRef s, raw_ostream::Colors c, |
114 | 1.85k | const Twine &msg) { |
115 | 1.85k | |
116 | 1.85k | if (vsDiagnostics) { |
117 | 11 | // A Visual Studio-style error message starts with an error location. |
118 | 11 | // If a location cannot be extracted then we default to LogName. |
119 | 11 | *errorOS << getLocation(msg.str(), logName) << ": "; |
120 | 1.84k | } else { |
121 | 1.84k | *errorOS << logName << ": "; |
122 | 1.84k | } |
123 | 1.85k | |
124 | 1.85k | if (colorDiagnostics) { |
125 | 8 | errorOS->changeColor(c, true); |
126 | 8 | *errorOS << s; |
127 | 8 | errorOS->resetColor(); |
128 | 1.84k | } else { |
129 | 1.84k | *errorOS << s; |
130 | 1.84k | } |
131 | 1.85k | } |
132 | | |
133 | 19.0k | void ErrorHandler::log(const Twine &msg) { |
134 | 19.0k | if (verbose) { |
135 | 276 | std::lock_guard<std::mutex> lock(mu); |
136 | 276 | *errorOS << logName << ": " << msg << "\n"; |
137 | 276 | } |
138 | 19.0k | } |
139 | | |
140 | 288 | void ErrorHandler::message(const Twine &msg) { |
141 | 288 | std::lock_guard<std::mutex> lock(mu); |
142 | 288 | outs() << msg << "\n"; |
143 | 288 | outs().flush(); |
144 | 288 | } |
145 | | |
146 | 844 | void ErrorHandler::warn(const Twine &msg) { |
147 | 844 | if (fatalWarnings) { |
148 | 12 | error(msg); |
149 | 12 | return; |
150 | 12 | } |
151 | 832 | |
152 | 832 | std::lock_guard<std::mutex> lock(mu); |
153 | 832 | newline(errorOS, msg); |
154 | 832 | printHeader("warning: ", raw_ostream::MAGENTA, msg); |
155 | 832 | *errorOS << msg << "\n"; |
156 | 832 | } |
157 | | |
158 | 2.82k | void ErrorHandler::error(const Twine &msg) { |
159 | 2.82k | std::lock_guard<std::mutex> lock(mu); |
160 | 2.82k | newline(errorOS, msg); |
161 | 2.82k | |
162 | 2.82k | if (errorLimit == 0 || errorCount < errorLimit2.75k ) { |
163 | 1.01k | printHeader("error: ", raw_ostream::RED, msg); |
164 | 1.01k | *errorOS << msg << "\n"; |
165 | 1.80k | } else if (errorCount == errorLimit) { |
166 | 6 | printHeader("error: ", raw_ostream::RED, msg); |
167 | 6 | *errorOS << errorLimitExceededMsg << "\n"; |
168 | 6 | if (exitEarly) |
169 | 0 | exitLld(1); |
170 | 2.82k | } |
171 | 2.82k | |
172 | 2.82k | ++errorCount; |
173 | 2.82k | } |
174 | | |
175 | 0 | void ErrorHandler::fatal(const Twine &msg) { |
176 | 0 | error(msg); |
177 | 0 | exitLld(1); |
178 | 0 | } |