xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/orc/error.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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