1 | //===----- lib/Support/Error.cpp - Error and associated utilities ---------===// |
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 "llvm/Support/Error.h" |
10 | #include "llvm/ADT/SmallVector.h" |
11 | #include "llvm/ADT/StringExtras.h" |
12 | #include "llvm/ADT/Twine.h" |
13 | #include "llvm/Support/ErrorHandling.h" |
14 | #include <system_error> |
15 | |
16 | using namespace llvm; |
17 | |
18 | namespace { |
19 | |
20 | enum class ErrorErrorCode : int { |
21 | MultipleErrors = 1, |
22 | FileError, |
23 | InconvertibleError |
24 | }; |
25 | |
26 | // FIXME: This class is only here to support the transition to llvm::Error. It |
27 | // will be removed once this transition is complete. Clients should prefer to |
28 | // deal with the Error value directly, rather than converting to error_code. |
29 | class ErrorErrorCategory : public std::error_category { |
30 | public: |
31 | const char *name() const noexcept override { return "Error" ; } |
32 | |
33 | std::string message(int condition) const override { |
34 | switch (static_cast<ErrorErrorCode>(condition)) { |
35 | case ErrorErrorCode::MultipleErrors: |
36 | return "Multiple errors" ; |
37 | case ErrorErrorCode::InconvertibleError: |
38 | return "Inconvertible error value. An error has occurred that could " |
39 | "not be converted to a known std::error_code. Please file a " |
40 | "bug." ; |
41 | case ErrorErrorCode::FileError: |
42 | return "A file error occurred." ; |
43 | } |
44 | llvm_unreachable("Unhandled error code" ); |
45 | } |
46 | }; |
47 | |
48 | } |
49 | |
50 | ErrorErrorCategory &getErrorErrorCat() { |
51 | static ErrorErrorCategory ErrorErrorCat; |
52 | return ErrorErrorCat; |
53 | } |
54 | |
55 | namespace llvm { |
56 | |
57 | void ErrorInfoBase::anchor() {} |
58 | char ErrorInfoBase::ID = 0; |
59 | char ErrorList::ID = 0; |
60 | void ECError::anchor() {} |
61 | char ECError::ID = 0; |
62 | char StringError::ID = 0; |
63 | char FileError::ID = 0; |
64 | |
65 | void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) { |
66 | if (!E) |
67 | return; |
68 | OS << ErrorBanner; |
69 | handleAllErrors(E: std::move(E), Handlers: [&](const ErrorInfoBase &EI) { |
70 | EI.log(OS); |
71 | OS << "\n" ; |
72 | }); |
73 | } |
74 | |
75 | /// Write all error messages (if any) in E to a string. The newline character |
76 | /// is used to separate error messages. |
77 | std::string toString(Error E) { |
78 | SmallVector<std::string, 2> Errors; |
79 | handleAllErrors(E: std::move(E), Handlers: [&Errors](const ErrorInfoBase &EI) { |
80 | Errors.push_back(Elt: EI.message()); |
81 | }); |
82 | return join(Begin: Errors.begin(), End: Errors.end(), Separator: "\n" ); |
83 | } |
84 | |
85 | std::string toStringWithoutConsuming(const Error &E) { |
86 | SmallVector<std::string, 2> Errors; |
87 | visitErrors(E, H: [&Errors](const ErrorInfoBase &EI) { |
88 | Errors.push_back(Elt: EI.message()); |
89 | }); |
90 | return join(Begin: Errors.begin(), End: Errors.end(), Separator: "\n" ); |
91 | } |
92 | |
93 | std::error_code ErrorList::convertToErrorCode() const { |
94 | return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors), |
95 | getErrorErrorCat()); |
96 | } |
97 | |
98 | std::error_code inconvertibleErrorCode() { |
99 | return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError), |
100 | getErrorErrorCat()); |
101 | } |
102 | |
103 | std::error_code FileError::convertToErrorCode() const { |
104 | std::error_code NestedEC = Err->convertToErrorCode(); |
105 | if (NestedEC == inconvertibleErrorCode()) |
106 | return std::error_code(static_cast<int>(ErrorErrorCode::FileError), |
107 | getErrorErrorCat()); |
108 | return NestedEC; |
109 | } |
110 | |
111 | Error errorCodeToError(std::error_code EC) { |
112 | if (!EC) |
113 | return Error::success(); |
114 | return Error(std::make_unique<ECError>(args: ECError(EC))); |
115 | } |
116 | |
117 | std::error_code errorToErrorCode(Error Err) { |
118 | std::error_code EC; |
119 | handleAllErrors(E: std::move(Err), Handlers: [&](const ErrorInfoBase &EI) { |
120 | EC = EI.convertToErrorCode(); |
121 | }); |
122 | if (EC == inconvertibleErrorCode()) |
123 | report_fatal_error(reason: Twine(EC.message())); |
124 | return EC; |
125 | } |
126 | |
127 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
128 | void Error::fatalUncheckedError() const { |
129 | dbgs() << "Program aborted due to an unhandled Error:\n" ; |
130 | if (getPtr()) { |
131 | getPtr()->log(dbgs()); |
132 | dbgs() << "\n" ; |
133 | }else |
134 | dbgs() << "Error value was Success. (Note: Success values must still be " |
135 | "checked prior to being destroyed).\n" ; |
136 | abort(); |
137 | } |
138 | #endif |
139 | |
140 | StringError::StringError(std::error_code EC, const Twine &S) |
141 | : Msg(S.str()), EC(EC) {} |
142 | |
143 | StringError::StringError(const Twine &S, std::error_code EC) |
144 | : Msg(S.str()), EC(EC), PrintMsgOnly(true) {} |
145 | |
146 | StringError::StringError(std::string &&S, std::error_code EC, bool PrintMsgOnly) |
147 | : Msg(S), EC(EC), PrintMsgOnly(PrintMsgOnly) {} |
148 | |
149 | void StringError::log(raw_ostream &OS) const { |
150 | if (PrintMsgOnly) { |
151 | OS << Msg; |
152 | } else { |
153 | OS << EC.message(); |
154 | if (!Msg.empty()) |
155 | OS << (" " + Msg); |
156 | } |
157 | } |
158 | |
159 | std::error_code StringError::convertToErrorCode() const { |
160 | return EC; |
161 | } |
162 | |
163 | Error createStringError(std::string &&Msg, std::error_code EC) { |
164 | return make_error<StringError>(Args&: Msg, Args&: EC); |
165 | } |
166 | |
167 | void report_fatal_error(Error Err, bool GenCrashDiag) { |
168 | assert(Err && "report_fatal_error called with success value" ); |
169 | std::string ErrMsg; |
170 | { |
171 | raw_string_ostream ErrStream(ErrMsg); |
172 | logAllUnhandledErrors(E: std::move(Err), OS&: ErrStream); |
173 | } |
174 | report_fatal_error(reason: Twine(ErrMsg), gen_crash_diag: GenCrashDiag); |
175 | } |
176 | |
177 | } // end namespace llvm |
178 | |
179 | LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) { |
180 | return reinterpret_cast<ErrorInfoBase *>(Err)->dynamicClassID(); |
181 | } |
182 | |
183 | void LLVMConsumeError(LLVMErrorRef Err) { consumeError(Err: unwrap(ErrRef: Err)); } |
184 | |
185 | char *LLVMGetErrorMessage(LLVMErrorRef Err) { |
186 | std::string Tmp = toString(E: unwrap(ErrRef: Err)); |
187 | char *ErrMsg = new char[Tmp.size() + 1]; |
188 | memcpy(dest: ErrMsg, src: Tmp.data(), n: Tmp.size()); |
189 | ErrMsg[Tmp.size()] = '\0'; |
190 | return ErrMsg; |
191 | } |
192 | |
193 | void LLVMDisposeErrorMessage(char *ErrMsg) { delete[] ErrMsg; } |
194 | |
195 | LLVMErrorTypeId LLVMGetStringErrorTypeId() { |
196 | return reinterpret_cast<void *>(&StringError::ID); |
197 | } |
198 | |
199 | LLVMErrorRef LLVMCreateStringError(const char *ErrMsg) { |
200 | return wrap(Err: make_error<StringError>(Args&: ErrMsg, Args: inconvertibleErrorCode())); |
201 | } |
202 | |