1*0fca6ea1SDimitry Andric //===-------- error.h - Enforced error checking for ORC RT ------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric 9fe6060f1SDimitry Andric #ifndef ORC_RT_ERROR_H 10fe6060f1SDimitry Andric #define ORC_RT_ERROR_H 11fe6060f1SDimitry Andric 12fe6060f1SDimitry Andric #include "compiler.h" 13fe6060f1SDimitry Andric #include "extensible_rtti.h" 14fe6060f1SDimitry Andric #include "stl_extras.h" 15fe6060f1SDimitry Andric 16fe6060f1SDimitry Andric #include <cassert> 17fe6060f1SDimitry Andric #include <memory> 18fe6060f1SDimitry Andric #include <string> 19fe6060f1SDimitry Andric #include <type_traits> 20fe6060f1SDimitry Andric 21fe6060f1SDimitry Andric namespace __orc_rt { 22fe6060f1SDimitry Andric 23fe6060f1SDimitry Andric /// Base class for all errors. 24fe6060f1SDimitry Andric class ErrorInfoBase : public RTTIExtends<ErrorInfoBase, RTTIRoot> { 25fe6060f1SDimitry Andric public: 26fe6060f1SDimitry Andric virtual std::string toString() const = 0; 27fe6060f1SDimitry Andric }; 28fe6060f1SDimitry Andric 29fe6060f1SDimitry Andric /// Represents an environmental error. 30fe6060f1SDimitry Andric class ORC_RT_NODISCARD Error { 31fe6060f1SDimitry Andric 32fe6060f1SDimitry Andric template <typename ErrT, typename... ArgTs> 33fe6060f1SDimitry Andric friend Error make_error(ArgTs &&...Args); 34fe6060f1SDimitry Andric 35fe6060f1SDimitry Andric friend Error repackage_error(std::unique_ptr<ErrorInfoBase>); 36fe6060f1SDimitry Andric 37fe6060f1SDimitry Andric template <typename ErrT> friend std::unique_ptr<ErrT> error_cast(Error &); 38fe6060f1SDimitry Andric 39fe6060f1SDimitry Andric template <typename T> friend class Expected; 40fe6060f1SDimitry Andric 41fe6060f1SDimitry Andric public: 42fe6060f1SDimitry Andric /// Destroy this error. Aborts if error was not checked, or was checked but 43fe6060f1SDimitry Andric /// not handled. 44fe6060f1SDimitry Andric ~Error() { assertIsChecked(); } 45fe6060f1SDimitry Andric 46fe6060f1SDimitry Andric Error(const Error &) = delete; 47fe6060f1SDimitry Andric Error &operator=(const Error &) = delete; 48fe6060f1SDimitry Andric 49fe6060f1SDimitry Andric /// Move-construct an error. The newly constructed error is considered 50fe6060f1SDimitry Andric /// unchecked, even if the source error had been checked. The original error 51fe6060f1SDimitry Andric /// becomes a checked success value. 52fe6060f1SDimitry Andric Error(Error &&Other) { 53fe6060f1SDimitry Andric setChecked(true); 54fe6060f1SDimitry Andric *this = std::move(Other); 55fe6060f1SDimitry Andric } 56fe6060f1SDimitry Andric 57fe6060f1SDimitry Andric /// Move-assign an error value. The current error must represent success, you 58fe6060f1SDimitry Andric /// you cannot overwrite an unhandled error. The current error is then 59fe6060f1SDimitry Andric /// considered unchecked. The source error becomes a checked success value, 60fe6060f1SDimitry Andric /// regardless of its original state. 61fe6060f1SDimitry Andric Error &operator=(Error &&Other) { 62fe6060f1SDimitry Andric // Don't allow overwriting of unchecked values. 63fe6060f1SDimitry Andric assertIsChecked(); 64fe6060f1SDimitry Andric setPtr(Other.getPtr()); 65fe6060f1SDimitry Andric 66fe6060f1SDimitry Andric // This Error is unchecked, even if the source error was checked. 67fe6060f1SDimitry Andric setChecked(false); 68fe6060f1SDimitry Andric 69fe6060f1SDimitry Andric // Null out Other's payload and set its checked bit. 70fe6060f1SDimitry Andric Other.setPtr(nullptr); 71fe6060f1SDimitry Andric Other.setChecked(true); 72fe6060f1SDimitry Andric 73fe6060f1SDimitry Andric return *this; 74fe6060f1SDimitry Andric } 75fe6060f1SDimitry Andric 76fe6060f1SDimitry Andric /// Create a success value. 77fe6060f1SDimitry Andric static Error success() { return Error(); } 78fe6060f1SDimitry Andric 79fe6060f1SDimitry Andric /// Error values convert to true for failure values, false otherwise. 80fe6060f1SDimitry Andric explicit operator bool() { 81fe6060f1SDimitry Andric setChecked(getPtr() == nullptr); 82fe6060f1SDimitry Andric return getPtr() != nullptr; 83fe6060f1SDimitry Andric } 84fe6060f1SDimitry Andric 85fe6060f1SDimitry Andric /// Return true if this Error contains a failure value of the given type. 86fe6060f1SDimitry Andric template <typename ErrT> bool isA() const { 87fe6060f1SDimitry Andric return getPtr() && getPtr()->isA<ErrT>(); 88fe6060f1SDimitry Andric } 89fe6060f1SDimitry Andric 90fe6060f1SDimitry Andric private: 91fe6060f1SDimitry Andric Error() = default; 92fe6060f1SDimitry Andric 93fe6060f1SDimitry Andric Error(std::unique_ptr<ErrorInfoBase> ErrInfo) { 94fe6060f1SDimitry Andric auto RawErrPtr = reinterpret_cast<uintptr_t>(ErrInfo.release()); 95fe6060f1SDimitry Andric assert((RawErrPtr & 0x1) == 0 && "ErrorInfo is insufficiently aligned"); 96fe6060f1SDimitry Andric ErrPtr = RawErrPtr | 0x1; 97fe6060f1SDimitry Andric } 98fe6060f1SDimitry Andric 99fe6060f1SDimitry Andric void assertIsChecked() { 100fe6060f1SDimitry Andric if (ORC_RT_UNLIKELY(!isChecked() || getPtr())) { 101fe6060f1SDimitry Andric fprintf(stderr, "Error must be checked prior to destruction.\n"); 102fe6060f1SDimitry Andric abort(); // Some sort of JIT program abort? 103fe6060f1SDimitry Andric } 104fe6060f1SDimitry Andric } 105fe6060f1SDimitry Andric 106fe6060f1SDimitry Andric template <typename ErrT = ErrorInfoBase> ErrT *getPtr() const { 107fe6060f1SDimitry Andric return reinterpret_cast<ErrT *>(ErrPtr & ~uintptr_t(1)); 108fe6060f1SDimitry Andric } 109fe6060f1SDimitry Andric 110fe6060f1SDimitry Andric void setPtr(ErrorInfoBase *Ptr) { 111fe6060f1SDimitry Andric ErrPtr = (reinterpret_cast<uintptr_t>(Ptr) & ~uintptr_t(1)) | (ErrPtr & 1); 112fe6060f1SDimitry Andric } 113fe6060f1SDimitry Andric 114fe6060f1SDimitry Andric bool isChecked() const { return ErrPtr & 0x1; } 115fe6060f1SDimitry Andric 116bdd1243dSDimitry Andric void setChecked(bool Checked) { ErrPtr = (ErrPtr & ~uintptr_t(1)) | Checked; } 117fe6060f1SDimitry Andric 118fe6060f1SDimitry Andric template <typename ErrT = ErrorInfoBase> std::unique_ptr<ErrT> takePayload() { 119fe6060f1SDimitry Andric static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value, 120fe6060f1SDimitry Andric "ErrT is not an ErrorInfoBase subclass"); 121fe6060f1SDimitry Andric std::unique_ptr<ErrT> Tmp(getPtr<ErrT>()); 122fe6060f1SDimitry Andric setPtr(nullptr); 123fe6060f1SDimitry Andric setChecked(true); 124fe6060f1SDimitry Andric return Tmp; 125fe6060f1SDimitry Andric } 126fe6060f1SDimitry Andric 127fe6060f1SDimitry Andric uintptr_t ErrPtr = 0; 128fe6060f1SDimitry Andric }; 129fe6060f1SDimitry Andric 130fe6060f1SDimitry Andric /// Construct an error of ErrT with the given arguments. 131fe6060f1SDimitry Andric template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&...Args) { 132fe6060f1SDimitry Andric static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value, 133fe6060f1SDimitry Andric "ErrT is not an ErrorInfoBase subclass"); 134fe6060f1SDimitry Andric return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...)); 135fe6060f1SDimitry Andric } 136fe6060f1SDimitry Andric 137fe6060f1SDimitry Andric /// Construct an error of ErrT using a std::unique_ptr<ErrorInfoBase>. The 138fe6060f1SDimitry Andric /// primary use-case for this is 're-packaging' errors after inspecting them 139fe6060f1SDimitry Andric /// using error_cast, hence the name. 140fe6060f1SDimitry Andric inline Error repackage_error(std::unique_ptr<ErrorInfoBase> EIB) { 141fe6060f1SDimitry Andric return Error(std::move(EIB)); 142fe6060f1SDimitry Andric } 143fe6060f1SDimitry Andric 144fe6060f1SDimitry Andric /// If the argument is an error of type ErrT then this function unpacks it 145fe6060f1SDimitry Andric /// and returns a std::unique_ptr<ErrT>. Otherwise returns a nullptr and 146fe6060f1SDimitry Andric /// leaves the error untouched. Common usage looks like: 147fe6060f1SDimitry Andric /// 148fe6060f1SDimitry Andric /// \code{.cpp} 149fe6060f1SDimitry Andric /// if (Error E = foo()) { 150fe6060f1SDimitry Andric /// if (auto EV1 = error_cast<ErrorType1>(E)) { 151fe6060f1SDimitry Andric /// // use unwrapped EV1 value. 152fe6060f1SDimitry Andric /// } else if (EV2 = error_cast<ErrorType2>(E)) { 153fe6060f1SDimitry Andric /// // use unwrapped EV2 value. 154fe6060f1SDimitry Andric /// } ... 155fe6060f1SDimitry Andric /// } 156fe6060f1SDimitry Andric /// \endcode 157fe6060f1SDimitry Andric template <typename ErrT> std::unique_ptr<ErrT> error_cast(Error &Err) { 158fe6060f1SDimitry Andric static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value, 159fe6060f1SDimitry Andric "ErrT is not an ErrorInfoBase subclass"); 160fe6060f1SDimitry Andric if (Err.isA<ErrT>()) 161fe6060f1SDimitry Andric return Err.takePayload<ErrT>(); 162fe6060f1SDimitry Andric return nullptr; 163fe6060f1SDimitry Andric } 164fe6060f1SDimitry Andric 165fe6060f1SDimitry Andric /// Helper for Errors used as out-parameters. 166fe6060f1SDimitry Andric /// Sets the 'checked' flag on construction, resets it on destruction. 167fe6060f1SDimitry Andric class ErrorAsOutParameter { 168fe6060f1SDimitry Andric public: 169fe6060f1SDimitry Andric ErrorAsOutParameter(Error *Err) : Err(Err) { 170fe6060f1SDimitry Andric // Raise the checked bit if Err is success. 171fe6060f1SDimitry Andric if (Err) 172fe6060f1SDimitry Andric (void)!!*Err; 173fe6060f1SDimitry Andric } 174fe6060f1SDimitry Andric 175fe6060f1SDimitry Andric ~ErrorAsOutParameter() { 176fe6060f1SDimitry Andric // Clear the checked bit. 177fe6060f1SDimitry Andric if (Err && !*Err) 178fe6060f1SDimitry Andric *Err = Error::success(); 179fe6060f1SDimitry Andric } 180fe6060f1SDimitry Andric 181fe6060f1SDimitry Andric private: 182fe6060f1SDimitry Andric Error *Err; 183fe6060f1SDimitry Andric }; 184fe6060f1SDimitry Andric 185fe6060f1SDimitry Andric template <typename T> class ORC_RT_NODISCARD Expected { 186fe6060f1SDimitry Andric 187fe6060f1SDimitry Andric template <class OtherT> friend class Expected; 188fe6060f1SDimitry Andric 189fe6060f1SDimitry Andric static constexpr bool IsRef = std::is_reference<T>::value; 190fe6060f1SDimitry Andric using wrap = std::reference_wrapper<std::remove_reference_t<T>>; 191fe6060f1SDimitry Andric using error_type = std::unique_ptr<ErrorInfoBase>; 192fe6060f1SDimitry Andric using storage_type = std::conditional_t<IsRef, wrap, T>; 193fe6060f1SDimitry Andric using value_type = T; 194fe6060f1SDimitry Andric 195fe6060f1SDimitry Andric using reference = std::remove_reference_t<T> &; 196fe6060f1SDimitry Andric using const_reference = const std::remove_reference_t<T> &; 197fe6060f1SDimitry Andric using pointer = std::remove_reference_t<T> *; 198fe6060f1SDimitry Andric using const_pointer = const std::remove_reference_t<T> *; 199fe6060f1SDimitry Andric 200fe6060f1SDimitry Andric public: 201fe6060f1SDimitry Andric /// Create an Expected from a failure value. 202fe6060f1SDimitry Andric Expected(Error Err) : HasError(true), Unchecked(true) { 203fe6060f1SDimitry Andric assert(Err && "Cannot create Expected<T> from Error success value"); 204fe6060f1SDimitry Andric new (getErrorStorage()) error_type(Err.takePayload()); 205fe6060f1SDimitry Andric } 206fe6060f1SDimitry Andric 207fe6060f1SDimitry Andric /// Create an Expected from a T value. 208fe6060f1SDimitry Andric template <typename OtherT> 209fe6060f1SDimitry Andric Expected(OtherT &&Val, 210fe6060f1SDimitry Andric std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) 211fe6060f1SDimitry Andric : HasError(false), Unchecked(true) { 212fe6060f1SDimitry Andric new (getStorage()) storage_type(std::forward<OtherT>(Val)); 213fe6060f1SDimitry Andric } 214fe6060f1SDimitry Andric 215fe6060f1SDimitry Andric /// Move-construct an Expected<T> from an Expected<OtherT>. 216fe6060f1SDimitry Andric Expected(Expected &&Other) { moveConstruct(std::move(Other)); } 217fe6060f1SDimitry Andric 218fe6060f1SDimitry Andric /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT 219fe6060f1SDimitry Andric /// must be convertible to T. 220fe6060f1SDimitry Andric template <class OtherT> 221fe6060f1SDimitry Andric Expected( 222fe6060f1SDimitry Andric Expected<OtherT> &&Other, 223fe6060f1SDimitry Andric std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) { 224fe6060f1SDimitry Andric moveConstruct(std::move(Other)); 225fe6060f1SDimitry Andric } 226fe6060f1SDimitry Andric 227fe6060f1SDimitry Andric /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT 228fe6060f1SDimitry Andric /// isn't convertible to T. 229fe6060f1SDimitry Andric template <class OtherT> 230fe6060f1SDimitry Andric explicit Expected( 231fe6060f1SDimitry Andric Expected<OtherT> &&Other, 232fe6060f1SDimitry Andric std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) { 233fe6060f1SDimitry Andric moveConstruct(std::move(Other)); 234fe6060f1SDimitry Andric } 235fe6060f1SDimitry Andric 236fe6060f1SDimitry Andric /// Move-assign from another Expected<T>. 237fe6060f1SDimitry Andric Expected &operator=(Expected &&Other) { 238fe6060f1SDimitry Andric moveAssign(std::move(Other)); 239fe6060f1SDimitry Andric return *this; 240fe6060f1SDimitry Andric } 241fe6060f1SDimitry Andric 242fe6060f1SDimitry Andric /// Destroy an Expected<T>. 243fe6060f1SDimitry Andric ~Expected() { 244fe6060f1SDimitry Andric assertIsChecked(); 245fe6060f1SDimitry Andric if (!HasError) 246fe6060f1SDimitry Andric getStorage()->~storage_type(); 247fe6060f1SDimitry Andric else 248fe6060f1SDimitry Andric getErrorStorage()->~error_type(); 249fe6060f1SDimitry Andric } 250fe6060f1SDimitry Andric 251fe6060f1SDimitry Andric /// Returns true if this Expected value is in a success state (holding a T), 252fe6060f1SDimitry Andric /// and false if this Expected value is in a failure state. 253fe6060f1SDimitry Andric explicit operator bool() { 254fe6060f1SDimitry Andric Unchecked = HasError; 255fe6060f1SDimitry Andric return !HasError; 256fe6060f1SDimitry Andric } 257fe6060f1SDimitry Andric 258fe6060f1SDimitry Andric /// Returns true if this Expected value holds an Error of type error_type. 259fe6060f1SDimitry Andric template <typename ErrT> bool isFailureOfType() const { 260fe6060f1SDimitry Andric return HasError && (*getErrorStorage())->template isFailureOfType<ErrT>(); 261fe6060f1SDimitry Andric } 262fe6060f1SDimitry Andric 263fe6060f1SDimitry Andric /// Take ownership of the stored error. 264fe6060f1SDimitry Andric /// 265fe6060f1SDimitry Andric /// If this Expected value is in a success state (holding a T) then this 266fe6060f1SDimitry Andric /// method is a no-op and returns Error::success. 267fe6060f1SDimitry Andric /// 268fe6060f1SDimitry Andric /// If thsi Expected value is in a failure state (holding an Error) then this 269fe6060f1SDimitry Andric /// method returns the contained error and leaves this Expected in an 270fe6060f1SDimitry Andric /// 'empty' state from which it may be safely destructed but not otherwise 271fe6060f1SDimitry Andric /// accessed. 272fe6060f1SDimitry Andric Error takeError() { 273fe6060f1SDimitry Andric Unchecked = false; 274fe6060f1SDimitry Andric return HasError ? Error(std::move(*getErrorStorage())) : Error::success(); 275fe6060f1SDimitry Andric } 276fe6060f1SDimitry Andric 277fe6060f1SDimitry Andric /// Returns a pointer to the stored T value. 278fe6060f1SDimitry Andric pointer operator->() { 279fe6060f1SDimitry Andric assertIsChecked(); 280fe6060f1SDimitry Andric return toPointer(getStorage()); 281fe6060f1SDimitry Andric } 282fe6060f1SDimitry Andric 283fe6060f1SDimitry Andric /// Returns a pointer to the stored T value. 284fe6060f1SDimitry Andric const_pointer operator->() const { 285fe6060f1SDimitry Andric assertIsChecked(); 286fe6060f1SDimitry Andric return toPointer(getStorage()); 287fe6060f1SDimitry Andric } 288fe6060f1SDimitry Andric 289fe6060f1SDimitry Andric /// Returns a reference to the stored T value. 290fe6060f1SDimitry Andric reference operator*() { 291fe6060f1SDimitry Andric assertIsChecked(); 292fe6060f1SDimitry Andric return *getStorage(); 293fe6060f1SDimitry Andric } 294fe6060f1SDimitry Andric 295fe6060f1SDimitry Andric /// Returns a reference to the stored T value. 296fe6060f1SDimitry Andric const_reference operator*() const { 297fe6060f1SDimitry Andric assertIsChecked(); 298fe6060f1SDimitry Andric return *getStorage(); 299fe6060f1SDimitry Andric } 300fe6060f1SDimitry Andric 301fe6060f1SDimitry Andric private: 302fe6060f1SDimitry Andric template <class T1> 303fe6060f1SDimitry Andric static bool compareThisIfSameType(const T1 &a, const T1 &b) { 304fe6060f1SDimitry Andric return &a == &b; 305fe6060f1SDimitry Andric } 306fe6060f1SDimitry Andric 307fe6060f1SDimitry Andric template <class T1, class T2> 308fe6060f1SDimitry Andric static bool compareThisIfSameType(const T1 &a, const T2 &b) { 309fe6060f1SDimitry Andric return false; 310fe6060f1SDimitry Andric } 311fe6060f1SDimitry Andric 312fe6060f1SDimitry Andric template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) { 313fe6060f1SDimitry Andric HasError = Other.HasError; 314fe6060f1SDimitry Andric Unchecked = true; 315fe6060f1SDimitry Andric Other.Unchecked = false; 316fe6060f1SDimitry Andric 317fe6060f1SDimitry Andric if (!HasError) 318fe6060f1SDimitry Andric new (getStorage()) storage_type(std::move(*Other.getStorage())); 319fe6060f1SDimitry Andric else 320fe6060f1SDimitry Andric new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage())); 321fe6060f1SDimitry Andric } 322fe6060f1SDimitry Andric 323fe6060f1SDimitry Andric template <class OtherT> void moveAssign(Expected<OtherT> &&Other) { 324fe6060f1SDimitry Andric assertIsChecked(); 325fe6060f1SDimitry Andric 326fe6060f1SDimitry Andric if (compareThisIfSameType(*this, Other)) 327fe6060f1SDimitry Andric return; 328fe6060f1SDimitry Andric 329fe6060f1SDimitry Andric this->~Expected(); 330fe6060f1SDimitry Andric new (this) Expected(std::move(Other)); 331fe6060f1SDimitry Andric } 332fe6060f1SDimitry Andric 333fe6060f1SDimitry Andric pointer toPointer(pointer Val) { return Val; } 334fe6060f1SDimitry Andric 335fe6060f1SDimitry Andric const_pointer toPointer(const_pointer Val) const { return Val; } 336fe6060f1SDimitry Andric 337fe6060f1SDimitry Andric pointer toPointer(wrap *Val) { return &Val->get(); } 338fe6060f1SDimitry Andric 339fe6060f1SDimitry Andric const_pointer toPointer(const wrap *Val) const { return &Val->get(); } 340fe6060f1SDimitry Andric 341fe6060f1SDimitry Andric storage_type *getStorage() { 342fe6060f1SDimitry Andric assert(!HasError && "Cannot get value when an error exists!"); 343fe6060f1SDimitry Andric return reinterpret_cast<storage_type *>(&TStorage); 344fe6060f1SDimitry Andric } 345fe6060f1SDimitry Andric 346fe6060f1SDimitry Andric const storage_type *getStorage() const { 347fe6060f1SDimitry Andric assert(!HasError && "Cannot get value when an error exists!"); 348fe6060f1SDimitry Andric return reinterpret_cast<const storage_type *>(&TStorage); 349fe6060f1SDimitry Andric } 350fe6060f1SDimitry Andric 351fe6060f1SDimitry Andric error_type *getErrorStorage() { 352fe6060f1SDimitry Andric assert(HasError && "Cannot get error when a value exists!"); 353fe6060f1SDimitry Andric return reinterpret_cast<error_type *>(&ErrorStorage); 354fe6060f1SDimitry Andric } 355fe6060f1SDimitry Andric 356fe6060f1SDimitry Andric const error_type *getErrorStorage() const { 357fe6060f1SDimitry Andric assert(HasError && "Cannot get error when a value exists!"); 358fe6060f1SDimitry Andric return reinterpret_cast<const error_type *>(&ErrorStorage); 359fe6060f1SDimitry Andric } 360fe6060f1SDimitry Andric 361fe6060f1SDimitry Andric void assertIsChecked() { 362fe6060f1SDimitry Andric if (ORC_RT_UNLIKELY(Unchecked)) { 363fe6060f1SDimitry Andric fprintf(stderr, 364fe6060f1SDimitry Andric "Expected<T> must be checked before access or destruction.\n"); 365fe6060f1SDimitry Andric abort(); 366fe6060f1SDimitry Andric } 367fe6060f1SDimitry Andric } 368fe6060f1SDimitry Andric 369fe6060f1SDimitry Andric union { 370fe6060f1SDimitry Andric std::aligned_union_t<1, storage_type> TStorage; 371fe6060f1SDimitry Andric std::aligned_union_t<1, error_type> ErrorStorage; 372fe6060f1SDimitry Andric }; 373fe6060f1SDimitry Andric 374fe6060f1SDimitry Andric bool HasError : 1; 375fe6060f1SDimitry Andric bool Unchecked : 1; 376fe6060f1SDimitry Andric }; 377fe6060f1SDimitry Andric 378fe6060f1SDimitry Andric /// Consume an error without doing anything. 379fe6060f1SDimitry Andric inline void consumeError(Error Err) { 380fe6060f1SDimitry Andric if (Err) 381fe6060f1SDimitry Andric (void)error_cast<ErrorInfoBase>(Err); 382fe6060f1SDimitry Andric } 383fe6060f1SDimitry Andric 384fe6060f1SDimitry Andric /// Consumes success values. It is a programmatic error to call this function 385fe6060f1SDimitry Andric /// on a failure value. 386fe6060f1SDimitry Andric inline void cantFail(Error Err) { 387fe6060f1SDimitry Andric assert(!Err && "cantFail called on failure value"); 388fe6060f1SDimitry Andric consumeError(std::move(Err)); 389fe6060f1SDimitry Andric } 390fe6060f1SDimitry Andric 391fe6060f1SDimitry Andric /// Auto-unwrap an Expected<T> value in the success state. It is a programmatic 392fe6060f1SDimitry Andric /// error to call this function on a failure value. 393fe6060f1SDimitry Andric template <typename T> T cantFail(Expected<T> E) { 394fe6060f1SDimitry Andric assert(E && "cantFail called on failure value"); 395fe6060f1SDimitry Andric consumeError(E.takeError()); 396fe6060f1SDimitry Andric return std::move(*E); 397fe6060f1SDimitry Andric } 398fe6060f1SDimitry Andric 399fe6060f1SDimitry Andric /// Auto-unwrap an Expected<T> value in the success state. It is a programmatic 400fe6060f1SDimitry Andric /// error to call this function on a failure value. 401fe6060f1SDimitry Andric template <typename T> T &cantFail(Expected<T &> E) { 402fe6060f1SDimitry Andric assert(E && "cantFail called on failure value"); 403fe6060f1SDimitry Andric consumeError(E.takeError()); 404fe6060f1SDimitry Andric return *E; 405fe6060f1SDimitry Andric } 406fe6060f1SDimitry Andric 407fe6060f1SDimitry Andric /// Convert the given error to a string. The error value is consumed in the 408fe6060f1SDimitry Andric /// process. 409fe6060f1SDimitry Andric inline std::string toString(Error Err) { 410fe6060f1SDimitry Andric if (auto EIB = error_cast<ErrorInfoBase>(Err)) 411fe6060f1SDimitry Andric return EIB->toString(); 412fe6060f1SDimitry Andric return {}; 413fe6060f1SDimitry Andric } 414fe6060f1SDimitry Andric 415fe6060f1SDimitry Andric class StringError : public RTTIExtends<StringError, ErrorInfoBase> { 416fe6060f1SDimitry Andric public: 417fe6060f1SDimitry Andric StringError(std::string ErrMsg) : ErrMsg(std::move(ErrMsg)) {} 418fe6060f1SDimitry Andric std::string toString() const override { return ErrMsg; } 419fe6060f1SDimitry Andric 420fe6060f1SDimitry Andric private: 421fe6060f1SDimitry Andric std::string ErrMsg; 422fe6060f1SDimitry Andric }; 423fe6060f1SDimitry Andric 424fe6060f1SDimitry Andric } // end namespace __orc_rt 425fe6060f1SDimitry Andric 426fe6060f1SDimitry Andric #endif // ORC_RT_ERROR_H 427