diff options
Diffstat (limited to 'include/llvm/Support/Error.h')
| -rw-r--r-- | include/llvm/Support/Error.h | 105 |
1 files changed, 100 insertions, 5 deletions
diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h index 8015cab45a06..ee2cbeec97a8 100644 --- a/include/llvm/Support/Error.h +++ b/include/llvm/Support/Error.h @@ -14,8 +14,9 @@ #ifndef LLVM_SUPPORT_ERROR_H #define LLVM_SUPPORT_ERROR_H -#include "llvm/ADT/SmallVector.h" +#include "llvm-c/Error.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/abi-breaking.h" @@ -155,9 +156,10 @@ private: /// they're moved-assigned or constructed from Success values that have already /// been checked. This enforces checking through all levels of the call stack. class LLVM_NODISCARD Error { - // ErrorList needs to be able to yank ErrorInfoBase pointers out of this - // class to add to the error list. + // Both ErrorList and FileError need to be able to yank ErrorInfoBase + // pointers out of this class to add to the error list. friend class ErrorList; + friend class FileError; // handleErrors needs to be able to set the Checked flag. template <typename... HandlerTs> @@ -167,6 +169,9 @@ class LLVM_NODISCARD Error { // error. template <typename T> friend class Expected; + // wrap needs to be able to steal the payload. + friend LLVMErrorRef wrap(Error); + protected: /// Create a success value. Prefer using 'Error::success()' for readability Error() { @@ -317,7 +322,7 @@ private: /// Subclass of Error for the sole purpose of identifying the success path in /// the type system. This allows to catch invalid conversion to Expected<T> at /// compile time. -class ErrorSuccess : public Error {}; +class ErrorSuccess final : public Error {}; inline ErrorSuccess Error::success() { return ErrorSuccess(); } @@ -339,6 +344,8 @@ template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { template <typename ThisErrT, typename ParentErrT = ErrorInfoBase> class ErrorInfo : public ParentErrT { public: + using ParentErrT::ParentErrT; // inherit constructors + static const void *classID() { return &ThisErrT::ID; } const void *dynamicClassID() const override { return &ThisErrT::ID; } @@ -946,10 +953,14 @@ Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath, /// will be printed before the first one is logged. A newline will be printed /// after each error. /// +/// This function is compatible with the helpers from Support/WithColor.h. You +/// can pass any of them as the OS. Please consider using them instead of +/// including 'error: ' in the ErrorBanner. +/// /// This is useful in the base level of your program to allow clean termination /// (allowing clean deallocation of resources, etc.), while reporting error /// information to the user. -void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner); +void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner = {}); /// Write all error messages (if any) in E to a string. The newline character /// is used to separate error messages. @@ -1055,6 +1066,8 @@ private: class ECError : public ErrorInfo<ECError> { friend Error errorCodeToError(std::error_code); + virtual void anchor() override; + public: void setErrorCode(std::error_code EC) { this->EC = EC; } std::error_code convertToErrorCode() const override { return EC; } @@ -1106,10 +1119,33 @@ template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) { /// StringError is useful in cases where the client is not expected to be able /// to consume the specific error message programmatically (for example, if the /// error message is to be presented to the user). +/// +/// StringError can also be used when additional information is to be printed +/// along with a error_code message. Depending on the constructor called, this +/// class can either display: +/// 1. the error_code message (ECError behavior) +/// 2. a string +/// 3. the error_code message and a string +/// +/// These behaviors are useful when subtyping is required; for example, when a +/// specific library needs an explicit error type. In the example below, +/// PDBError is derived from StringError: +/// +/// @code{.cpp} +/// Expected<int> foo() { +/// return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading, +/// "Additional information"); +/// } +/// @endcode +/// class StringError : public ErrorInfo<StringError> { public: static char ID; + // Prints EC + S and converts to EC + StringError(std::error_code EC, const Twine &S = Twine()); + + // Prints S and converts to EC StringError(const Twine &S, std::error_code EC); void log(raw_ostream &OS) const override; @@ -1120,6 +1156,7 @@ public: private: std::string Msg; std::error_code EC; + const bool PrintMsgOnly = false; }; /// Create formatted StringError object. @@ -1134,6 +1171,53 @@ Error createStringError(std::error_code EC, char const *Fmt, Error createStringError(std::error_code EC, char const *Msg); +/// This class wraps a filename and another Error. +/// +/// In some cases, an error needs to live along a 'source' name, in order to +/// show more detailed information to the user. +class FileError final : public ErrorInfo<FileError> { + + friend Error createFileError(std::string, Error); + +public: + void log(raw_ostream &OS) const override { + assert(Err && !FileName.empty() && "Trying to log after takeError()."); + OS << "'" << FileName << "': "; + Err->log(OS); + } + + Error takeError() { return Error(std::move(Err)); } + + std::error_code convertToErrorCode() const override; + + // Used by ErrorInfo::classID. + static char ID; + +private: + FileError(std::string F, std::unique_ptr<ErrorInfoBase> E) { + assert(E && "Cannot create FileError from Error success value."); + assert(!F.empty() && + "The file name provided to FileError must not be empty."); + FileName = F; + Err = std::move(E); + } + + static Error build(std::string F, Error E) { + return Error(std::unique_ptr<FileError>(new FileError(F, E.takePayload()))); + } + + std::string FileName; + std::unique_ptr<ErrorInfoBase> Err; +}; + +/// Concatenate a source file path and/or name with an Error. The resulting +/// Error is unchecked. +inline Error createFileError(std::string F, Error E) { + return FileError::build(F, std::move(E)); +} + +Error createFileError(std::string F, ErrorSuccess) = delete; + /// Helper for check-and-exit error handling. /// /// For tool use only. NOT FOR USE IN LIBRARY CODE. @@ -1183,6 +1267,17 @@ private: std::function<int(const Error &)> GetExitCode; }; +/// Conversion from Error to LLVMErrorRef for C error bindings. +inline LLVMErrorRef wrap(Error Err) { + return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release()); +} + +/// Conversion from LLVMErrorRef to Error for C error bindings. +inline Error unwrap(LLVMErrorRef ErrRef) { + return Error(std::unique_ptr<ErrorInfoBase>( + reinterpret_cast<ErrorInfoBase *>(ErrRef))); +} + } // end namespace llvm #endif // LLVM_SUPPORT_ERROR_H |
