215 lines · cpp
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-exception6//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 16using namespace llvm;17 18namespace {19 20 enum class ErrorErrorCode : int {21 MultipleErrors = 1,22 FileError,23 InconvertibleError24 };25 26 // FIXME: This class is only here to support the transition to llvm::Error. It27 // will be removed once this transition is complete. Clients should prefer to28 // 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 50ErrorErrorCategory &getErrorErrorCat() {51 static ErrorErrorCategory ErrorErrorCat;52 return ErrorErrorCat;53}54 55namespace llvm {56 57void ErrorInfoBase::anchor() {}58char ErrorInfoBase::ID = 0;59char ErrorList::ID = 0;60void ECError::anchor() {}61char ECError::ID = 0;62char StringError::ID = 0;63char FileError::ID = 0;64 65void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {66 if (!E)67 return;68 OS << ErrorBanner;69 handleAllErrors(std::move(E), [&](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 character76/// is used to separate error messages.77std::string toString(Error E) {78 SmallVector<std::string, 2> Errors;79 handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {80 Errors.push_back(EI.message());81 });82 return join(Errors.begin(), Errors.end(), "\n");83}84 85std::string toStringWithoutConsuming(const Error &E) {86 SmallVector<std::string, 2> Errors;87 visitErrors(E, [&Errors](const ErrorInfoBase &EI) {88 Errors.push_back(EI.message());89 });90 return join(Errors.begin(), Errors.end(), "\n");91}92 93std::error_code ErrorList::convertToErrorCode() const {94 return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),95 getErrorErrorCat());96}97 98std::error_code inconvertibleErrorCode() {99 return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError),100 getErrorErrorCat());101}102 103std::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 111Error errorCodeToError(std::error_code EC) {112 if (!EC)113 return Error::success();114 return Error(std::make_unique<ECError>(ECError(EC)));115}116 117std::error_code errorToErrorCode(Error Err) {118 std::error_code EC;119 handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {120 EC = EI.convertToErrorCode();121 });122 if (EC == inconvertibleErrorCode())123 report_fatal_error(Twine(EC.message()));124 return EC;125}126 127#if LLVM_ENABLE_ABI_BREAKING_CHECKS128void Error::fatalUncheckedError() const {129 dbgs() << "Program aborted due to an unhandled Error:\n";130 if (getPtr()) {131 getPtr()->log(dbgs());132 dbgs() << "\n";133 }else134 dbgs() << "Error value was Success. (Note: Success values must still be "135 "checked prior to being destroyed).\n";136 abort();137}138#endif139 140StringError::StringError(std::error_code EC, const Twine &S)141 : Msg(S.str()), EC(EC) {}142 143StringError::StringError(const Twine &S, std::error_code EC)144 : Msg(S.str()), EC(EC), PrintMsgOnly(true) {}145 146StringError::StringError(std::string &&S, std::error_code EC, bool PrintMsgOnly)147 : Msg(S), EC(EC), PrintMsgOnly(PrintMsgOnly) {}148 149void 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 159std::error_code StringError::convertToErrorCode() const {160 return EC;161}162 163Error createStringError(std::string &&Msg, std::error_code EC) {164 return make_error<StringError>(Msg, EC);165}166 167void 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(std::move(Err), ErrStream);173 }174 report_fatal_error(Twine(ErrMsg), GenCrashDiag);175}176 177void reportFatalInternalError(Error Err) {178 report_fatal_error(std::move(Err), /*GenCrashDiag=*/true);179}180void reportFatalUsageError(Error Err) {181 report_fatal_error(std::move(Err), /*GenCrashDiag=*/false);182}183 184} // end namespace llvm185 186LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) {187 return reinterpret_cast<ErrorInfoBase *>(Err)->dynamicClassID();188}189 190void LLVMConsumeError(LLVMErrorRef Err) { consumeError(unwrap(Err)); }191 192 193 194void LLVMCantFail(LLVMErrorRef Err) {195 cantFail(unwrap(Err));196}197 198char *LLVMGetErrorMessage(LLVMErrorRef Err) {199 std::string Tmp = toString(unwrap(Err));200 char *ErrMsg = new char[Tmp.size() + 1];201 memcpy(ErrMsg, Tmp.data(), Tmp.size());202 ErrMsg[Tmp.size()] = '\0';203 return ErrMsg;204}205 206void LLVMDisposeErrorMessage(char *ErrMsg) { delete[] ErrMsg; }207 208LLVMErrorTypeId LLVMGetStringErrorTypeId() {209 return reinterpret_cast<void *>(&StringError::ID);210}211 212LLVMErrorRef LLVMCreateStringError(const char *ErrMsg) {213 return wrap(make_error<StringError>(ErrMsg, inconvertibleErrorCode()));214}215