1112aa105SLang Hames //===-------- error.h - Enforced error checking for ORC RT ------*- C++ -*-===// 21dfa4791SLang Hames // 31dfa4791SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 41dfa4791SLang Hames // See https://llvm.org/LICENSE.txt for license information. 51dfa4791SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61dfa4791SLang Hames // 71dfa4791SLang Hames //===----------------------------------------------------------------------===// 81dfa4791SLang Hames 91dfa4791SLang Hames #ifndef ORC_RT_ERROR_H 101dfa4791SLang Hames #define ORC_RT_ERROR_H 111dfa4791SLang Hames 121dfa4791SLang Hames #include "compiler.h" 131dfa4791SLang Hames #include "extensible_rtti.h" 141dfa4791SLang Hames #include "stl_extras.h" 151dfa4791SLang Hames 161dfa4791SLang Hames #include <cassert> 171dfa4791SLang Hames #include <memory> 181dfa4791SLang Hames #include <string> 191dfa4791SLang Hames #include <type_traits> 201dfa4791SLang Hames 21*3e04ad42SLang Hames namespace orc_rt { 221dfa4791SLang Hames 231dfa4791SLang Hames /// Base class for all errors. 241dfa4791SLang Hames class ErrorInfoBase : public RTTIExtends<ErrorInfoBase, RTTIRoot> { 251dfa4791SLang Hames public: 261dfa4791SLang Hames virtual std::string toString() const = 0; 271dfa4791SLang Hames }; 281dfa4791SLang Hames 291dfa4791SLang Hames /// Represents an environmental error. 301dfa4791SLang Hames class ORC_RT_NODISCARD Error { 311dfa4791SLang Hames 321dfa4791SLang Hames template <typename ErrT, typename... ArgTs> 331dfa4791SLang Hames friend Error make_error(ArgTs &&...Args); 341dfa4791SLang Hames 351dfa4791SLang Hames friend Error repackage_error(std::unique_ptr<ErrorInfoBase>); 361dfa4791SLang Hames 371dfa4791SLang Hames template <typename ErrT> friend std::unique_ptr<ErrT> error_cast(Error &); 381dfa4791SLang Hames 391dfa4791SLang Hames template <typename T> friend class Expected; 401dfa4791SLang Hames 411dfa4791SLang Hames public: 421dfa4791SLang Hames /// Destroy this error. Aborts if error was not checked, or was checked but 431dfa4791SLang Hames /// not handled. 441dfa4791SLang Hames ~Error() { assertIsChecked(); } 451dfa4791SLang Hames 461dfa4791SLang Hames Error(const Error &) = delete; 471dfa4791SLang Hames Error &operator=(const Error &) = delete; 481dfa4791SLang Hames 491dfa4791SLang Hames /// Move-construct an error. The newly constructed error is considered 501dfa4791SLang Hames /// unchecked, even if the source error had been checked. The original error 511dfa4791SLang Hames /// becomes a checked success value. 521dfa4791SLang Hames Error(Error &&Other) { 531dfa4791SLang Hames setChecked(true); 541dfa4791SLang Hames *this = std::move(Other); 551dfa4791SLang Hames } 561dfa4791SLang Hames 571dfa4791SLang Hames /// Move-assign an error value. The current error must represent success, you 581dfa4791SLang Hames /// you cannot overwrite an unhandled error. The current error is then 591dfa4791SLang Hames /// considered unchecked. The source error becomes a checked success value, 601dfa4791SLang Hames /// regardless of its original state. 611dfa4791SLang Hames Error &operator=(Error &&Other) { 621dfa4791SLang Hames // Don't allow overwriting of unchecked values. 631dfa4791SLang Hames assertIsChecked(); 641dfa4791SLang Hames setPtr(Other.getPtr()); 651dfa4791SLang Hames 661dfa4791SLang Hames // This Error is unchecked, even if the source error was checked. 671dfa4791SLang Hames setChecked(false); 681dfa4791SLang Hames 691dfa4791SLang Hames // Null out Other's payload and set its checked bit. 701dfa4791SLang Hames Other.setPtr(nullptr); 711dfa4791SLang Hames Other.setChecked(true); 721dfa4791SLang Hames 731dfa4791SLang Hames return *this; 741dfa4791SLang Hames } 751dfa4791SLang Hames 761dfa4791SLang Hames /// Create a success value. 771dfa4791SLang Hames static Error success() { return Error(); } 781dfa4791SLang Hames 791dfa4791SLang Hames /// Error values convert to true for failure values, false otherwise. 801dfa4791SLang Hames explicit operator bool() { 811dfa4791SLang Hames setChecked(getPtr() == nullptr); 821dfa4791SLang Hames return getPtr() != nullptr; 831dfa4791SLang Hames } 841dfa4791SLang Hames 851dfa4791SLang Hames /// Return true if this Error contains a failure value of the given type. 861dfa4791SLang Hames template <typename ErrT> bool isA() const { 871dfa4791SLang Hames return getPtr() && getPtr()->isA<ErrT>(); 881dfa4791SLang Hames } 891dfa4791SLang Hames 901dfa4791SLang Hames private: 911dfa4791SLang Hames Error() = default; 921dfa4791SLang Hames 931dfa4791SLang Hames Error(std::unique_ptr<ErrorInfoBase> ErrInfo) { 941dfa4791SLang Hames auto RawErrPtr = reinterpret_cast<uintptr_t>(ErrInfo.release()); 951dfa4791SLang Hames assert((RawErrPtr & 0x1) == 0 && "ErrorInfo is insufficiently aligned"); 961dfa4791SLang Hames ErrPtr = RawErrPtr | 0x1; 971dfa4791SLang Hames } 981dfa4791SLang Hames 991dfa4791SLang Hames void assertIsChecked() { 1001dfa4791SLang Hames if (ORC_RT_UNLIKELY(!isChecked() || getPtr())) { 1011dfa4791SLang Hames fprintf(stderr, "Error must be checked prior to destruction.\n"); 1021dfa4791SLang Hames abort(); // Some sort of JIT program abort? 1031dfa4791SLang Hames } 1041dfa4791SLang Hames } 1051dfa4791SLang Hames 1061dfa4791SLang Hames template <typename ErrT = ErrorInfoBase> ErrT *getPtr() const { 1071dfa4791SLang Hames return reinterpret_cast<ErrT *>(ErrPtr & ~uintptr_t(1)); 1081dfa4791SLang Hames } 1091dfa4791SLang Hames 1101dfa4791SLang Hames void setPtr(ErrorInfoBase *Ptr) { 1111dfa4791SLang Hames ErrPtr = (reinterpret_cast<uintptr_t>(Ptr) & ~uintptr_t(1)) | (ErrPtr & 1); 1121dfa4791SLang Hames } 1131dfa4791SLang Hames 1141dfa4791SLang Hames bool isChecked() const { return ErrPtr & 0x1; } 1151dfa4791SLang Hames 1169189a266SSunho Kim void setChecked(bool Checked) { ErrPtr = (ErrPtr & ~uintptr_t(1)) | Checked; } 1171dfa4791SLang Hames 1181dfa4791SLang Hames template <typename ErrT = ErrorInfoBase> std::unique_ptr<ErrT> takePayload() { 1191dfa4791SLang Hames static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value, 1201dfa4791SLang Hames "ErrT is not an ErrorInfoBase subclass"); 1211dfa4791SLang Hames std::unique_ptr<ErrT> Tmp(getPtr<ErrT>()); 1221dfa4791SLang Hames setPtr(nullptr); 1231dfa4791SLang Hames setChecked(true); 1241dfa4791SLang Hames return Tmp; 1251dfa4791SLang Hames } 1261dfa4791SLang Hames 1271dfa4791SLang Hames uintptr_t ErrPtr = 0; 1281dfa4791SLang Hames }; 1291dfa4791SLang Hames 1301dfa4791SLang Hames /// Construct an error of ErrT with the given arguments. 1311dfa4791SLang Hames template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&...Args) { 1321dfa4791SLang Hames static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value, 1331dfa4791SLang Hames "ErrT is not an ErrorInfoBase subclass"); 1341dfa4791SLang Hames return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...)); 1351dfa4791SLang Hames } 1361dfa4791SLang Hames 1371dfa4791SLang Hames /// Construct an error of ErrT using a std::unique_ptr<ErrorInfoBase>. The 1381dfa4791SLang Hames /// primary use-case for this is 're-packaging' errors after inspecting them 1391dfa4791SLang Hames /// using error_cast, hence the name. 1401dfa4791SLang Hames inline Error repackage_error(std::unique_ptr<ErrorInfoBase> EIB) { 1411dfa4791SLang Hames return Error(std::move(EIB)); 1421dfa4791SLang Hames } 1431dfa4791SLang Hames 1441dfa4791SLang Hames /// If the argument is an error of type ErrT then this function unpacks it 1451dfa4791SLang Hames /// and returns a std::unique_ptr<ErrT>. Otherwise returns a nullptr and 1461dfa4791SLang Hames /// leaves the error untouched. Common usage looks like: 1471dfa4791SLang Hames /// 1481dfa4791SLang Hames /// \code{.cpp} 1491dfa4791SLang Hames /// if (Error E = foo()) { 1501dfa4791SLang Hames /// if (auto EV1 = error_cast<ErrorType1>(E)) { 1511dfa4791SLang Hames /// // use unwrapped EV1 value. 1521dfa4791SLang Hames /// } else if (EV2 = error_cast<ErrorType2>(E)) { 1531dfa4791SLang Hames /// // use unwrapped EV2 value. 1541dfa4791SLang Hames /// } ... 1551dfa4791SLang Hames /// } 1561dfa4791SLang Hames /// \endcode 1571dfa4791SLang Hames template <typename ErrT> std::unique_ptr<ErrT> error_cast(Error &Err) { 1581dfa4791SLang Hames static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value, 1591dfa4791SLang Hames "ErrT is not an ErrorInfoBase subclass"); 1601dfa4791SLang Hames if (Err.isA<ErrT>()) 1611dfa4791SLang Hames return Err.takePayload<ErrT>(); 1621dfa4791SLang Hames return nullptr; 1631dfa4791SLang Hames } 1641dfa4791SLang Hames 1651dfa4791SLang Hames /// Helper for Errors used as out-parameters. 1661dfa4791SLang Hames /// Sets the 'checked' flag on construction, resets it on destruction. 1671dfa4791SLang Hames class ErrorAsOutParameter { 1681dfa4791SLang Hames public: 1691dfa4791SLang Hames ErrorAsOutParameter(Error *Err) : Err(Err) { 1701dfa4791SLang Hames // Raise the checked bit if Err is success. 1711dfa4791SLang Hames if (Err) 1721dfa4791SLang Hames (void)!!*Err; 1731dfa4791SLang Hames } 1741dfa4791SLang Hames 1751dfa4791SLang Hames ~ErrorAsOutParameter() { 1761dfa4791SLang Hames // Clear the checked bit. 1771dfa4791SLang Hames if (Err && !*Err) 1781dfa4791SLang Hames *Err = Error::success(); 1791dfa4791SLang Hames } 1801dfa4791SLang Hames 1811dfa4791SLang Hames private: 1821dfa4791SLang Hames Error *Err; 1831dfa4791SLang Hames }; 1841dfa4791SLang Hames 1851dfa4791SLang Hames template <typename T> class ORC_RT_NODISCARD Expected { 1861dfa4791SLang Hames 1871dfa4791SLang Hames template <class OtherT> friend class Expected; 1881dfa4791SLang Hames 1891dfa4791SLang Hames static constexpr bool IsRef = std::is_reference<T>::value; 1901dfa4791SLang Hames using wrap = std::reference_wrapper<std::remove_reference_t<T>>; 1911dfa4791SLang Hames using error_type = std::unique_ptr<ErrorInfoBase>; 1921dfa4791SLang Hames using storage_type = std::conditional_t<IsRef, wrap, T>; 1931dfa4791SLang Hames using value_type = T; 1941dfa4791SLang Hames 1951dfa4791SLang Hames using reference = std::remove_reference_t<T> &; 1961dfa4791SLang Hames using const_reference = const std::remove_reference_t<T> &; 1971dfa4791SLang Hames using pointer = std::remove_reference_t<T> *; 1981dfa4791SLang Hames using const_pointer = const std::remove_reference_t<T> *; 1991dfa4791SLang Hames 2001dfa4791SLang Hames public: 2011dfa4791SLang Hames /// Create an Expected from a failure value. 2021dfa4791SLang Hames Expected(Error Err) : HasError(true), Unchecked(true) { 2031dfa4791SLang Hames assert(Err && "Cannot create Expected<T> from Error success value"); 2041dfa4791SLang Hames new (getErrorStorage()) error_type(Err.takePayload()); 2051dfa4791SLang Hames } 2061dfa4791SLang Hames 2071dfa4791SLang Hames /// Create an Expected from a T value. 2081dfa4791SLang Hames template <typename OtherT> 2091dfa4791SLang Hames Expected(OtherT &&Val, 2101dfa4791SLang Hames std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) 2111dfa4791SLang Hames : HasError(false), Unchecked(true) { 2121dfa4791SLang Hames new (getStorage()) storage_type(std::forward<OtherT>(Val)); 2131dfa4791SLang Hames } 2141dfa4791SLang Hames 2151dfa4791SLang Hames /// Move-construct an Expected<T> from an Expected<OtherT>. 2161dfa4791SLang Hames Expected(Expected &&Other) { moveConstruct(std::move(Other)); } 2171dfa4791SLang Hames 2181dfa4791SLang Hames /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT 2191dfa4791SLang Hames /// must be convertible to T. 2201dfa4791SLang Hames template <class OtherT> 2211dfa4791SLang Hames Expected( 2221dfa4791SLang Hames Expected<OtherT> &&Other, 2231dfa4791SLang Hames std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) { 2241dfa4791SLang Hames moveConstruct(std::move(Other)); 2251dfa4791SLang Hames } 2261dfa4791SLang Hames 2271dfa4791SLang Hames /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT 2281dfa4791SLang Hames /// isn't convertible to T. 2291dfa4791SLang Hames template <class OtherT> 2301dfa4791SLang Hames explicit Expected( 2311dfa4791SLang Hames Expected<OtherT> &&Other, 2321dfa4791SLang Hames std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) { 2331dfa4791SLang Hames moveConstruct(std::move(Other)); 2341dfa4791SLang Hames } 2351dfa4791SLang Hames 2361dfa4791SLang Hames /// Move-assign from another Expected<T>. 2371dfa4791SLang Hames Expected &operator=(Expected &&Other) { 2381dfa4791SLang Hames moveAssign(std::move(Other)); 2391dfa4791SLang Hames return *this; 2401dfa4791SLang Hames } 2411dfa4791SLang Hames 2421dfa4791SLang Hames /// Destroy an Expected<T>. 2431dfa4791SLang Hames ~Expected() { 2441dfa4791SLang Hames assertIsChecked(); 2451dfa4791SLang Hames if (!HasError) 2461dfa4791SLang Hames getStorage()->~storage_type(); 2471dfa4791SLang Hames else 2481dfa4791SLang Hames getErrorStorage()->~error_type(); 2491dfa4791SLang Hames } 2501dfa4791SLang Hames 2511dfa4791SLang Hames /// Returns true if this Expected value is in a success state (holding a T), 2521dfa4791SLang Hames /// and false if this Expected value is in a failure state. 2531dfa4791SLang Hames explicit operator bool() { 2541dfa4791SLang Hames Unchecked = HasError; 2551dfa4791SLang Hames return !HasError; 2561dfa4791SLang Hames } 2571dfa4791SLang Hames 2581dfa4791SLang Hames /// Returns true if this Expected value holds an Error of type error_type. 2591dfa4791SLang Hames template <typename ErrT> bool isFailureOfType() const { 2601dfa4791SLang Hames return HasError && (*getErrorStorage())->template isFailureOfType<ErrT>(); 2611dfa4791SLang Hames } 2621dfa4791SLang Hames 2631dfa4791SLang Hames /// Take ownership of the stored error. 2641dfa4791SLang Hames /// 2651dfa4791SLang Hames /// If this Expected value is in a success state (holding a T) then this 2661dfa4791SLang Hames /// method is a no-op and returns Error::success. 2671dfa4791SLang Hames /// 2681dfa4791SLang Hames /// If thsi Expected value is in a failure state (holding an Error) then this 2691dfa4791SLang Hames /// method returns the contained error and leaves this Expected in an 2701dfa4791SLang Hames /// 'empty' state from which it may be safely destructed but not otherwise 2711dfa4791SLang Hames /// accessed. 2721dfa4791SLang Hames Error takeError() { 2731dfa4791SLang Hames Unchecked = false; 2741dfa4791SLang Hames return HasError ? Error(std::move(*getErrorStorage())) : Error::success(); 2751dfa4791SLang Hames } 2761dfa4791SLang Hames 2771dfa4791SLang Hames /// Returns a pointer to the stored T value. 2781dfa4791SLang Hames pointer operator->() { 2791dfa4791SLang Hames assertIsChecked(); 2801dfa4791SLang Hames return toPointer(getStorage()); 2811dfa4791SLang Hames } 2821dfa4791SLang Hames 2831dfa4791SLang Hames /// Returns a pointer to the stored T value. 2841dfa4791SLang Hames const_pointer operator->() const { 2851dfa4791SLang Hames assertIsChecked(); 2861dfa4791SLang Hames return toPointer(getStorage()); 2871dfa4791SLang Hames } 2881dfa4791SLang Hames 2891dfa4791SLang Hames /// Returns a reference to the stored T value. 2901dfa4791SLang Hames reference operator*() { 2911dfa4791SLang Hames assertIsChecked(); 2921dfa4791SLang Hames return *getStorage(); 2931dfa4791SLang Hames } 2941dfa4791SLang Hames 2951dfa4791SLang Hames /// Returns a reference to the stored T value. 2961dfa4791SLang Hames const_reference operator*() const { 2971dfa4791SLang Hames assertIsChecked(); 2981dfa4791SLang Hames return *getStorage(); 2991dfa4791SLang Hames } 3001dfa4791SLang Hames 3011dfa4791SLang Hames private: 3021dfa4791SLang Hames template <class T1> 3031dfa4791SLang Hames static bool compareThisIfSameType(const T1 &a, const T1 &b) { 3041dfa4791SLang Hames return &a == &b; 3051dfa4791SLang Hames } 3061dfa4791SLang Hames 3071dfa4791SLang Hames template <class T1, class T2> 3081dfa4791SLang Hames static bool compareThisIfSameType(const T1 &a, const T2 &b) { 3091dfa4791SLang Hames return false; 3101dfa4791SLang Hames } 3111dfa4791SLang Hames 3121dfa4791SLang Hames template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) { 3131dfa4791SLang Hames HasError = Other.HasError; 3141dfa4791SLang Hames Unchecked = true; 3151dfa4791SLang Hames Other.Unchecked = false; 3161dfa4791SLang Hames 3171dfa4791SLang Hames if (!HasError) 3181dfa4791SLang Hames new (getStorage()) storage_type(std::move(*Other.getStorage())); 3191dfa4791SLang Hames else 3201dfa4791SLang Hames new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage())); 3211dfa4791SLang Hames } 3221dfa4791SLang Hames 3231dfa4791SLang Hames template <class OtherT> void moveAssign(Expected<OtherT> &&Other) { 3241dfa4791SLang Hames assertIsChecked(); 3251dfa4791SLang Hames 3261dfa4791SLang Hames if (compareThisIfSameType(*this, Other)) 3271dfa4791SLang Hames return; 3281dfa4791SLang Hames 3291dfa4791SLang Hames this->~Expected(); 3301dfa4791SLang Hames new (this) Expected(std::move(Other)); 3311dfa4791SLang Hames } 3321dfa4791SLang Hames 3331dfa4791SLang Hames pointer toPointer(pointer Val) { return Val; } 3341dfa4791SLang Hames 3351dfa4791SLang Hames const_pointer toPointer(const_pointer Val) const { return Val; } 3361dfa4791SLang Hames 3371dfa4791SLang Hames pointer toPointer(wrap *Val) { return &Val->get(); } 3381dfa4791SLang Hames 3391dfa4791SLang Hames const_pointer toPointer(const wrap *Val) const { return &Val->get(); } 3401dfa4791SLang Hames 3411dfa4791SLang Hames storage_type *getStorage() { 3421dfa4791SLang Hames assert(!HasError && "Cannot get value when an error exists!"); 3431dfa4791SLang Hames return reinterpret_cast<storage_type *>(&TStorage); 3441dfa4791SLang Hames } 3451dfa4791SLang Hames 3461dfa4791SLang Hames const storage_type *getStorage() const { 3471dfa4791SLang Hames assert(!HasError && "Cannot get value when an error exists!"); 3481dfa4791SLang Hames return reinterpret_cast<const storage_type *>(&TStorage); 3491dfa4791SLang Hames } 3501dfa4791SLang Hames 3511dfa4791SLang Hames error_type *getErrorStorage() { 3521dfa4791SLang Hames assert(HasError && "Cannot get error when a value exists!"); 3531dfa4791SLang Hames return reinterpret_cast<error_type *>(&ErrorStorage); 3541dfa4791SLang Hames } 3551dfa4791SLang Hames 3561dfa4791SLang Hames const error_type *getErrorStorage() const { 3571dfa4791SLang Hames assert(HasError && "Cannot get error when a value exists!"); 3581dfa4791SLang Hames return reinterpret_cast<const error_type *>(&ErrorStorage); 3591dfa4791SLang Hames } 3601dfa4791SLang Hames 3611dfa4791SLang Hames void assertIsChecked() { 3621dfa4791SLang Hames if (ORC_RT_UNLIKELY(Unchecked)) { 3631dfa4791SLang Hames fprintf(stderr, 3641dfa4791SLang Hames "Expected<T> must be checked before access or destruction.\n"); 3651dfa4791SLang Hames abort(); 3661dfa4791SLang Hames } 3671dfa4791SLang Hames } 3681dfa4791SLang Hames 3691dfa4791SLang Hames union { 3701dfa4791SLang Hames std::aligned_union_t<1, storage_type> TStorage; 3711dfa4791SLang Hames std::aligned_union_t<1, error_type> ErrorStorage; 3721dfa4791SLang Hames }; 3731dfa4791SLang Hames 3741dfa4791SLang Hames bool HasError : 1; 3751dfa4791SLang Hames bool Unchecked : 1; 3761dfa4791SLang Hames }; 3771dfa4791SLang Hames 3781dfa4791SLang Hames /// Consume an error without doing anything. 3791dfa4791SLang Hames inline void consumeError(Error Err) { 3801dfa4791SLang Hames if (Err) 3811dfa4791SLang Hames (void)error_cast<ErrorInfoBase>(Err); 3821dfa4791SLang Hames } 3831dfa4791SLang Hames 3841dfa4791SLang Hames /// Consumes success values. It is a programmatic error to call this function 3851dfa4791SLang Hames /// on a failure value. 3861dfa4791SLang Hames inline void cantFail(Error Err) { 3871dfa4791SLang Hames assert(!Err && "cantFail called on failure value"); 3881dfa4791SLang Hames consumeError(std::move(Err)); 3891dfa4791SLang Hames } 3901dfa4791SLang Hames 3911dfa4791SLang Hames /// Auto-unwrap an Expected<T> value in the success state. It is a programmatic 3921dfa4791SLang Hames /// error to call this function on a failure value. 3931dfa4791SLang Hames template <typename T> T cantFail(Expected<T> E) { 3941dfa4791SLang Hames assert(E && "cantFail called on failure value"); 3951dfa4791SLang Hames consumeError(E.takeError()); 3961dfa4791SLang Hames return std::move(*E); 3971dfa4791SLang Hames } 3981dfa4791SLang Hames 3991dfa4791SLang Hames /// Auto-unwrap an Expected<T> value in the success state. It is a programmatic 4001dfa4791SLang Hames /// error to call this function on a failure value. 4011dfa4791SLang Hames template <typename T> T &cantFail(Expected<T &> E) { 4021dfa4791SLang Hames assert(E && "cantFail called on failure value"); 4031dfa4791SLang Hames consumeError(E.takeError()); 4041dfa4791SLang Hames return *E; 4051dfa4791SLang Hames } 4061dfa4791SLang Hames 4071dfa4791SLang Hames /// Convert the given error to a string. The error value is consumed in the 4081dfa4791SLang Hames /// process. 4091dfa4791SLang Hames inline std::string toString(Error Err) { 4101dfa4791SLang Hames if (auto EIB = error_cast<ErrorInfoBase>(Err)) 4111dfa4791SLang Hames return EIB->toString(); 4121dfa4791SLang Hames return {}; 4131dfa4791SLang Hames } 4141dfa4791SLang Hames 4151dfa4791SLang Hames class StringError : public RTTIExtends<StringError, ErrorInfoBase> { 4161dfa4791SLang Hames public: 4171dfa4791SLang Hames StringError(std::string ErrMsg) : ErrMsg(std::move(ErrMsg)) {} 4181dfa4791SLang Hames std::string toString() const override { return ErrMsg; } 4191dfa4791SLang Hames 4201dfa4791SLang Hames private: 4211dfa4791SLang Hames std::string ErrMsg; 4221dfa4791SLang Hames }; 4231dfa4791SLang Hames 424*3e04ad42SLang Hames } // namespace orc_rt 4251dfa4791SLang Hames 4261dfa4791SLang Hames #endif // ORC_RT_ERROR_H 427