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