diff options
Diffstat (limited to 'include/llvm/Support/Error.h')
-rw-r--r-- | include/llvm/Support/Error.h | 102 |
1 files changed, 96 insertions, 6 deletions
diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h index f13c9484b5fd5..a3482f5a58b53 100644 --- a/include/llvm/Support/Error.h +++ b/include/llvm/Support/Error.h @@ -64,6 +64,12 @@ public: /// using std::error_code. It will be removed in the future. virtual std::error_code convertToErrorCode() const = 0; + // Returns the class ID for this type. + static const void *classID() { return &ID; } + + // Returns the class ID for the dynamic type of this ErrorInfoBase instance. + virtual const void *dynamicClassID() const = 0; + // Check whether this instance is a subclass of the class identified by // ClassID. virtual bool isA(const void *const ClassID) const { @@ -75,9 +81,6 @@ public: return isA(ErrorInfoT::classID()); } - // Returns the class ID for this type. - static const void *classID() { return &ID; } - private: virtual void anchor(); @@ -233,6 +236,14 @@ public: return getPtr() && getPtr()->isA(ErrT::classID()); } + /// Returns the dynamic class id of this error, or null if this is a success + /// value. + const void* dynamicClassID() const { + if (!getPtr()) + return nullptr; + return getPtr()->dynamicClassID(); + } + private: void assertIsChecked() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS @@ -316,11 +327,14 @@ template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { template <typename ThisErrT, typename ParentErrT = ErrorInfoBase> class ErrorInfo : public ParentErrT { public: + + static const void *classID() { return &ThisErrT::ID; } + + const void *dynamicClassID() const override { return &ThisErrT::ID; } + bool isA(const void *const ClassID) const override { return ClassID == classID() || ParentErrT::isA(ClassID); } - - static const void *classID() { return &ThisErrT::ID; } }; /// Special ErrorInfo subclass representing a list of ErrorInfos. @@ -629,6 +643,7 @@ private: /// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the /// error class type. template <class T> class LLVM_NODISCARD Expected { + template <class T1> friend class ExpectedAsOutParameter; template <class OtherT> friend class Expected; static const bool isRef = std::is_reference<T>::value; typedef ReferenceStorage<typename std::remove_reference<T>::type> wrap; @@ -737,7 +752,7 @@ public: /// \brief Check that this Expected<T> is an error of type ErrT. template <typename ErrT> bool errorIsA() const { - return HasError && getErrorStorage()->template isA<ErrT>(); + return HasError && (*getErrorStorage())->template isA<ErrT>(); } /// \brief Take ownership of the stored error. @@ -832,6 +847,18 @@ private: return reinterpret_cast<error_type *>(ErrorStorage.buffer); } + const error_type *getErrorStorage() const { + assert(HasError && "Cannot get error when a value exists!"); + return reinterpret_cast<const error_type *>(ErrorStorage.buffer); + } + + // Used by ExpectedAsOutParameter to reset the checked flag. + void setUnchecked() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + Unchecked = true; +#endif + } + void assertIsChecked() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS if (Unchecked) { @@ -858,6 +885,28 @@ private: #endif }; +/// Helper for Expected<T>s used as out-parameters. +/// +/// See ErrorAsOutParameter. +template <typename T> +class ExpectedAsOutParameter { +public: + + ExpectedAsOutParameter(Expected<T> *ValOrErr) + : ValOrErr(ValOrErr) { + if (ValOrErr) + (void)!!*ValOrErr; + } + + ~ExpectedAsOutParameter() { + if (ValOrErr) + ValOrErr->setUnchecked(); + } + +private: + Expected<T> *ValOrErr; +}; + /// This class wraps a std::error_code in a Error. /// /// This is useful if you're writing an interface that returns a Error @@ -926,6 +975,8 @@ public: void log(raw_ostream &OS) const override; std::error_code convertToErrorCode() const override; + const std::string &getMessage() const { return Msg; } + private: std::string Msg; std::error_code EC; @@ -985,6 +1036,45 @@ private: LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag = true); +/// Report a fatal error if Err is a failure value. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns +/// // Error::success(). +/// Error foo(bool DoFallibleOperation); +/// +/// cantFail(foo(false)); +/// @endcode +inline void cantFail(Error Err) { + if (Err) + llvm_unreachable("Failure value returned from cantFail wrapped call"); +} + +/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and +/// returns the contained value. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns an int. +/// Expected<int> foo(bool DoFallibleOperation); +/// +/// int X = cantFail(foo(false)); +/// @endcode +template <typename T> +T cantFail(Expected<T> ValOrErr) { + if (ValOrErr) + return std::move(*ValOrErr); + else + llvm_unreachable("Failure value returned from cantFail wrapped call"); +} + } // end namespace llvm #endif // LLVM_SUPPORT_ERROR_H |