xref: /freebsd-src/contrib/llvm-project/llvm/lib/Support/Error.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===----- lib/Support/Error.cpp - Error and associated utilities ---------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/Support/Error.h"
1006c3fb27SDimitry Andric #include "llvm/ADT/SmallVector.h"
1106c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
120b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
130b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
140b57cec5SDimitry Andric #include <system_error>
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric using namespace llvm;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric namespace {
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric   enum class ErrorErrorCode : int {
210b57cec5SDimitry Andric     MultipleErrors = 1,
220b57cec5SDimitry Andric     FileError,
230b57cec5SDimitry Andric     InconvertibleError
240b57cec5SDimitry Andric   };
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric   // FIXME: This class is only here to support the transition to llvm::Error. It
270b57cec5SDimitry Andric   // will be removed once this transition is complete. Clients should prefer to
280b57cec5SDimitry Andric   // deal with the Error value directly, rather than converting to error_code.
290b57cec5SDimitry Andric   class ErrorErrorCategory : public std::error_category {
300b57cec5SDimitry Andric   public:
310b57cec5SDimitry Andric     const char *name() const noexcept override { return "Error"; }
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric     std::string message(int condition) const override {
340b57cec5SDimitry Andric       switch (static_cast<ErrorErrorCode>(condition)) {
350b57cec5SDimitry Andric       case ErrorErrorCode::MultipleErrors:
360b57cec5SDimitry Andric         return "Multiple errors";
370b57cec5SDimitry Andric       case ErrorErrorCode::InconvertibleError:
380b57cec5SDimitry Andric         return "Inconvertible error value. An error has occurred that could "
390b57cec5SDimitry Andric                "not be converted to a known std::error_code. Please file a "
400b57cec5SDimitry Andric                "bug.";
410b57cec5SDimitry Andric       case ErrorErrorCode::FileError:
420b57cec5SDimitry Andric           return "A file error occurred.";
430b57cec5SDimitry Andric       }
440b57cec5SDimitry Andric       llvm_unreachable("Unhandled error code");
450b57cec5SDimitry Andric     }
460b57cec5SDimitry Andric   };
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
50753f127fSDimitry Andric ErrorErrorCategory &getErrorErrorCat() {
51753f127fSDimitry Andric   static ErrorErrorCategory ErrorErrorCat;
52753f127fSDimitry Andric   return ErrorErrorCat;
53753f127fSDimitry Andric }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric namespace llvm {
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric void ErrorInfoBase::anchor() {}
580b57cec5SDimitry Andric char ErrorInfoBase::ID = 0;
590b57cec5SDimitry Andric char ErrorList::ID = 0;
600b57cec5SDimitry Andric void ECError::anchor() {}
610b57cec5SDimitry Andric char ECError::ID = 0;
620b57cec5SDimitry Andric char StringError::ID = 0;
630b57cec5SDimitry Andric char FileError::ID = 0;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {
660b57cec5SDimitry Andric   if (!E)
670b57cec5SDimitry Andric     return;
680b57cec5SDimitry Andric   OS << ErrorBanner;
690b57cec5SDimitry Andric   handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
700b57cec5SDimitry Andric     EI.log(OS);
710b57cec5SDimitry Andric     OS << "\n";
720b57cec5SDimitry Andric   });
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric 
7506c3fb27SDimitry Andric /// Write all error messages (if any) in E to a string. The newline character
7606c3fb27SDimitry Andric /// is used to separate error messages.
7706c3fb27SDimitry Andric std::string toString(Error E) {
7806c3fb27SDimitry Andric   SmallVector<std::string, 2> Errors;
7906c3fb27SDimitry Andric   handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {
8006c3fb27SDimitry Andric     Errors.push_back(EI.message());
8106c3fb27SDimitry Andric   });
8206c3fb27SDimitry Andric   return join(Errors.begin(), Errors.end(), "\n");
8306c3fb27SDimitry Andric }
840b57cec5SDimitry Andric 
85*0fca6ea1SDimitry Andric std::string toStringWithoutConsuming(const Error &E) {
86*0fca6ea1SDimitry Andric   SmallVector<std::string, 2> Errors;
87*0fca6ea1SDimitry Andric   visitErrors(E, [&Errors](const ErrorInfoBase &EI) {
88*0fca6ea1SDimitry Andric     Errors.push_back(EI.message());
89*0fca6ea1SDimitry Andric   });
90*0fca6ea1SDimitry Andric   return join(Errors.begin(), Errors.end(), "\n");
91*0fca6ea1SDimitry Andric }
92*0fca6ea1SDimitry Andric 
930b57cec5SDimitry Andric std::error_code ErrorList::convertToErrorCode() const {
940b57cec5SDimitry Andric   return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),
95753f127fSDimitry Andric                          getErrorErrorCat());
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric std::error_code inconvertibleErrorCode() {
990b57cec5SDimitry Andric   return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError),
100753f127fSDimitry Andric                          getErrorErrorCat());
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric std::error_code FileError::convertToErrorCode() const {
104349cc55cSDimitry Andric   std::error_code NestedEC = Err->convertToErrorCode();
105349cc55cSDimitry Andric   if (NestedEC == inconvertibleErrorCode())
1060b57cec5SDimitry Andric     return std::error_code(static_cast<int>(ErrorErrorCode::FileError),
107753f127fSDimitry Andric                            getErrorErrorCat());
108349cc55cSDimitry Andric   return NestedEC;
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric Error errorCodeToError(std::error_code EC) {
1120b57cec5SDimitry Andric   if (!EC)
1130b57cec5SDimitry Andric     return Error::success();
1148bcb0991SDimitry Andric   return Error(std::make_unique<ECError>(ECError(EC)));
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric std::error_code errorToErrorCode(Error Err) {
1180b57cec5SDimitry Andric   std::error_code EC;
1190b57cec5SDimitry Andric   handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
1200b57cec5SDimitry Andric     EC = EI.convertToErrorCode();
1210b57cec5SDimitry Andric   });
1220b57cec5SDimitry Andric   if (EC == inconvertibleErrorCode())
123349cc55cSDimitry Andric     report_fatal_error(Twine(EC.message()));
1240b57cec5SDimitry Andric   return EC;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS
1280b57cec5SDimitry Andric void Error::fatalUncheckedError() const {
1290b57cec5SDimitry Andric   dbgs() << "Program aborted due to an unhandled Error:\n";
130480093f4SDimitry Andric   if (getPtr()) {
1310b57cec5SDimitry Andric     getPtr()->log(dbgs());
132480093f4SDimitry Andric     dbgs() << "\n";
133480093f4SDimitry Andric   }else
1340b57cec5SDimitry Andric     dbgs() << "Error value was Success. (Note: Success values must still be "
1350b57cec5SDimitry Andric               "checked prior to being destroyed).\n";
1360b57cec5SDimitry Andric   abort();
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric #endif
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric StringError::StringError(std::error_code EC, const Twine &S)
1410b57cec5SDimitry Andric     : Msg(S.str()), EC(EC) {}
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric StringError::StringError(const Twine &S, std::error_code EC)
1440b57cec5SDimitry Andric     : Msg(S.str()), EC(EC), PrintMsgOnly(true) {}
1450b57cec5SDimitry Andric 
146*0fca6ea1SDimitry Andric StringError::StringError(std::string &&S, std::error_code EC, bool PrintMsgOnly)
147*0fca6ea1SDimitry Andric     : Msg(S), EC(EC), PrintMsgOnly(PrintMsgOnly) {}
148*0fca6ea1SDimitry Andric 
1490b57cec5SDimitry Andric void StringError::log(raw_ostream &OS) const {
1500b57cec5SDimitry Andric   if (PrintMsgOnly) {
1510b57cec5SDimitry Andric     OS << Msg;
1520b57cec5SDimitry Andric   } else {
1530b57cec5SDimitry Andric     OS << EC.message();
1540b57cec5SDimitry Andric     if (!Msg.empty())
1550b57cec5SDimitry Andric       OS << (" " + Msg);
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric std::error_code StringError::convertToErrorCode() const {
1600b57cec5SDimitry Andric   return EC;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
163*0fca6ea1SDimitry Andric Error createStringError(std::string &&Msg, std::error_code EC) {
1640b57cec5SDimitry Andric   return make_error<StringError>(Msg, EC);
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric void report_fatal_error(Error Err, bool GenCrashDiag) {
1680b57cec5SDimitry Andric   assert(Err && "report_fatal_error called with success value");
1690b57cec5SDimitry Andric   std::string ErrMsg;
1700b57cec5SDimitry Andric   {
1710b57cec5SDimitry Andric     raw_string_ostream ErrStream(ErrMsg);
1720b57cec5SDimitry Andric     logAllUnhandledErrors(std::move(Err), ErrStream);
1730b57cec5SDimitry Andric   }
17406c3fb27SDimitry Andric   report_fatal_error(Twine(ErrMsg), GenCrashDiag);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric } // end namespace llvm
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) {
1800b57cec5SDimitry Andric   return reinterpret_cast<ErrorInfoBase *>(Err)->dynamicClassID();
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric void LLVMConsumeError(LLVMErrorRef Err) { consumeError(unwrap(Err)); }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric char *LLVMGetErrorMessage(LLVMErrorRef Err) {
1860b57cec5SDimitry Andric   std::string Tmp = toString(unwrap(Err));
1870b57cec5SDimitry Andric   char *ErrMsg = new char[Tmp.size() + 1];
1880b57cec5SDimitry Andric   memcpy(ErrMsg, Tmp.data(), Tmp.size());
1890b57cec5SDimitry Andric   ErrMsg[Tmp.size()] = '\0';
1900b57cec5SDimitry Andric   return ErrMsg;
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric void LLVMDisposeErrorMessage(char *ErrMsg) { delete[] ErrMsg; }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric LLVMErrorTypeId LLVMGetStringErrorTypeId() {
1960b57cec5SDimitry Andric   return reinterpret_cast<void *>(&StringError::ID);
1970b57cec5SDimitry Andric }
198e8d8bef9SDimitry Andric 
199e8d8bef9SDimitry Andric LLVMErrorRef LLVMCreateStringError(const char *ErrMsg) {
200e8d8bef9SDimitry Andric   return wrap(make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
201e8d8bef9SDimitry Andric }
202