1 //===- llvm/Support/ErrorOr.h - Error Smart Pointer -----------------------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 /// Provides ErrorOr<T> smart pointer.
14 //===----------------------------------------------------------------------===//
16 #ifndef LLVM_SUPPORT_ERROR_OR_H
17 #define LLVM_SUPPORT_ERROR_OR_H
19 #include "llvm/ADT/PointerIntPair.h"
20 #include "llvm/Support/AlignOf.h"
21 #include "llvm/Support/system_error.h"
22 #include "llvm/Support/type_traits.h"
25 #if LLVM_HAS_CXX11_TYPETRAITS
26 #include <type_traits>
30 struct ErrorHolderBase {
35 ErrorHolderBase() : RefCount(1) {}
47 virtual ~ErrorHolderBase() {}
51 struct ErrorHolder : ErrorHolderBase {
52 #if LLVM_HAS_RVALUE_REFERENCES
53 ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {}
55 ErrorHolder(T &UD) : UserData(UD) {}
60 template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {};
62 #if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES
63 template<class T, class V>
64 typename std::enable_if< std::is_constructible<T, V>::value
65 , typename std::remove_reference<V>::type>::type &&
66 moveIfMoveConstructible(V &Val) {
67 return std::move(Val);
70 template<class T, class V>
71 typename std::enable_if< !std::is_constructible<T, V>::value
72 , typename std::remove_reference<V>::type>::type &
73 moveIfMoveConstructible(V &Val) {
77 template<class T, class V>
78 V &moveIfMoveConstructible(V &Val) {
83 /// \brief Stores a reference that can be changed.
85 class ReferenceStorage {
89 ReferenceStorage(T &Ref) : Storage(&Ref) {}
91 operator T &() const { return *Storage; }
92 T &get() const { return *Storage; }
95 /// \brief Represents either an error or a value T.
97 /// ErrorOr<T> is a pointer-like class that represents the result of an
98 /// operation. The result is either an error, or a value of type T. This is
99 /// designed to emulate the usage of returning a pointer where nullptr indicates
100 /// failure. However instead of just knowing that the operation failed, we also
101 /// have an error_code and optional user data that describes why it failed.
103 /// It is used like the following.
105 /// ErrorOr<Buffer> getBuffer();
106 /// void handleError(error_code ec);
108 /// auto buffer = getBuffer();
110 /// handleError(buffer);
111 /// buffer->write("adena");
114 /// ErrorOr<T> also supports user defined data for specific error_codes. To use
115 /// this feature you must first add a template specialization of
116 /// ErrorOrUserDataTraits derived from std::true_type for your type in the lld
117 /// namespace. This specialization must have a static error_code error()
118 /// function that returns the error_code this data is used with.
120 /// getError<UserData>() may be called to get either the stored user data, or
121 /// a default constructed UserData if none was stored.
125 /// struct InvalidArgError {
126 /// InvalidArgError() {}
127 /// InvalidArgError(std::string S) : ArgName(S) {}
128 /// std::string ArgName;
133 /// struct ErrorOrUserDataTraits<InvalidArgError> : std::true_type {
134 /// static error_code error() {
135 /// return make_error_code(errc::invalid_argument);
138 /// } // end namespace llvm
140 /// using namespace llvm;
142 /// ErrorOr<int> foo() {
143 /// return InvalidArgError("adena");
148 /// if (!a && error_code(a) == errc::invalid_argument)
149 /// llvm::errs() << a.getError<InvalidArgError>().ArgName << "\n";
153 /// An implicit conversion to bool provides a way to check if there was an
154 /// error. The unary * and -> operators provide pointer like access to the
155 /// value. Accessing the value when there is an error has undefined behavior.
157 /// When T is a reference type the behaivor is slightly different. The reference
158 /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
159 /// there is special handling to make operator -> work as if T was not a
162 /// T cannot be a rvalue reference.
165 template <class OtherT> friend class ErrorOr;
166 static const bool isRef = is_reference<T>::value;
167 typedef ReferenceStorage<typename remove_reference<T>::type> wrap;
174 >::type storage_type;
177 typedef typename remove_reference<T>::type &reference;
178 typedef typename remove_reference<T>::type *pointer;
181 ErrorOr() : IsValid(false) {}
184 ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value ||
185 is_error_condition_enum<E>::value,
187 : HasError(true), IsValid(true) {
188 Error = new ErrorHolderBase;
189 Error->Error = make_error_code(ErrorCode);
190 Error->HasUserData = false;
193 ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
194 Error = new ErrorHolderBase;
196 Error->HasUserData = false;
199 template<class UserDataT>
200 ErrorOr(UserDataT UD, typename
201 enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0)
202 : HasError(true), IsValid(true) {
203 Error = new ErrorHolder<UserDataT>(llvm_move(UD));
204 Error->Error = ErrorOrUserDataTraits<UserDataT>::error();
205 Error->HasUserData = true;
208 ErrorOr(T Val) : HasError(false), IsValid(true) {
209 new (get()) storage_type(moveIfMoveConstructible<storage_type>(Val));
212 ErrorOr(const ErrorOr &Other) : IsValid(false) {
213 copyConstruct(Other);
216 template <class OtherT>
217 ErrorOr(const ErrorOr<OtherT> &Other) : IsValid(false) {
218 copyConstruct(Other);
221 ErrorOr &operator =(const ErrorOr &Other) {
226 template <class OtherT>
227 ErrorOr &operator =(const ErrorOr<OtherT> &Other) {
232 #if LLVM_HAS_RVALUE_REFERENCES
233 ErrorOr(ErrorOr &&Other) : IsValid(false) {
234 moveConstruct(std::move(Other));
237 template <class OtherT>
238 ErrorOr(ErrorOr<OtherT> &&Other) : IsValid(false) {
239 moveConstruct(std::move(Other));
242 ErrorOr &operator =(ErrorOr &&Other) {
243 moveAssign(std::move(Other));
247 template <class OtherT>
248 ErrorOr &operator =(ErrorOr<OtherT> &&Other) {
249 moveAssign(std::move(Other));
260 get()->~storage_type();
264 ET getError() const {
265 assert(IsValid && "Cannot get the error of a default constructed ErrorOr!");
266 assert(HasError && "Cannot get an error if none exists!");
267 assert(ErrorOrUserDataTraits<ET>::error() == Error->Error &&
268 "Incorrect user error data type for error!");
269 if (!Error->HasUserData)
271 return reinterpret_cast<const ErrorHolder<ET>*>(Error)->UserData;
274 typedef void (*unspecified_bool_type)();
275 static void unspecified_bool_true() {}
277 /// \brief Return false if there is an error.
278 operator unspecified_bool_type() const {
279 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
280 return HasError ? 0 : unspecified_bool_true;
283 operator llvm::error_code() const {
284 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
285 return HasError ? Error->Error : llvm::error_code::success();
288 pointer operator ->() {
289 return toPointer(get());
292 reference operator *() {
297 template <class OtherT>
298 void copyConstruct(const ErrorOr<OtherT> &Other) {
299 // Construct an invalid ErrorOr if other is invalid.
303 if (!Other.HasError) {
304 // Get the other value.
306 new (get()) storage_type(*Other.get());
308 // Get other's error.
316 static bool compareThisIfSameType(const T1 &a, const T1 &b) {
320 template <class T1, class T2>
321 static bool compareThisIfSameType(const T1 &a, const T2 &b) {
325 template <class OtherT>
326 void copyAssign(const ErrorOr<OtherT> &Other) {
327 if (compareThisIfSameType(*this, Other))
331 new (this) ErrorOr(Other);
334 #if LLVM_HAS_RVALUE_REFERENCES
335 template <class OtherT>
336 void moveConstruct(ErrorOr<OtherT> &&Other) {
337 // Construct an invalid ErrorOr if other is invalid.
341 if (!Other.HasError) {
342 // Get the other value.
344 new (get()) storage_type(std::move(*Other.get()));
345 // Tell other not to do any destruction.
346 Other.IsValid = false;
348 // Get other's error.
351 // Tell other not to do any destruction.
352 Other.IsValid = false;
356 template <class OtherT>
357 void moveAssign(ErrorOr<OtherT> &&Other) {
358 if (compareThisIfSameType(*this, Other))
362 new (this) ErrorOr(std::move(Other));
366 pointer toPointer(pointer Val) {
370 pointer toPointer(wrap *Val) {
374 storage_type *get() {
375 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
376 assert(!HasError && "Cannot get value when an error exists!");
377 return reinterpret_cast<storage_type*>(TStorage.buffer);
380 const storage_type *get() const {
381 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
382 assert(!HasError && "Cannot get value when an error exists!");
383 return reinterpret_cast<const storage_type*>(TStorage.buffer);
387 AlignedCharArrayUnion<storage_type> TStorage;
388 ErrorHolderBase *Error;
394 // ErrorOr specialization for void.
396 class ErrorOr<void> {
398 ErrorOr() : Error(0, 0) {}
401 ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value ||
402 is_error_condition_enum<E>::value,
405 error_code EC = make_error_code(ErrorCode);
406 if (EC == errc::success) {
410 ErrorHolderBase *EHB = new ErrorHolderBase;
412 EHB->HasUserData = false;
413 Error.setPointer(EHB);
416 ErrorOr(llvm::error_code EC) : Error(0, 0) {
417 if (EC == errc::success) {
421 ErrorHolderBase *E = new ErrorHolderBase;
423 E->HasUserData = false;
427 template<class UserDataT>
428 ErrorOr(UserDataT UD, typename
429 enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0)
431 ErrorHolderBase *E = new ErrorHolder<UserDataT>(llvm_move(UD));
432 E->Error = ErrorOrUserDataTraits<UserDataT>::error();
433 E->HasUserData = true;
437 ErrorOr(const ErrorOr &Other) : Error(0, 0) {
439 if (Other.Error.getPointer()->Error) {
440 Error.getPointer()->aquire();
444 ErrorOr &operator =(const ErrorOr &Other) {
449 new (this) ErrorOr(Other);
454 #if LLVM_HAS_RVALUE_REFERENCES
455 ErrorOr(ErrorOr &&Other) : Error(0) {
456 // Get other's error.
458 // Tell other not to do any destruction.
459 Other.Error.setPointer(0);
462 ErrorOr &operator =(ErrorOr &&Other) {
467 new (this) ErrorOr(std::move(Other));
474 if (Error.getPointer())
475 Error.getPointer()->release();
479 ET getError() const {
480 assert(ErrorOrUserDataTraits<ET>::error() == *this &&
481 "Incorrect user error data type for error!");
482 if (!Error.getPointer()->HasUserData)
484 return reinterpret_cast<const ErrorHolder<ET> *>(
485 Error.getPointer())->UserData;
488 typedef void (*unspecified_bool_type)();
489 static void unspecified_bool_true() {}
491 /// \brief Return false if there is an error.
492 operator unspecified_bool_type() const {
493 return Error.getInt() ? unspecified_bool_true : 0;
496 operator llvm::error_code() const {
497 return Error.getInt() ? make_error_code(errc::success)
498 : Error.getPointer()->Error;
502 // If the bit is 1, the error is success.
503 llvm::PointerIntPair<ErrorHolderBase *, 1> Error;
506 template<class T, class E>
507 typename enable_if_c<is_error_code_enum<E>::value ||
508 is_error_condition_enum<E>::value, bool>::type
509 operator ==(ErrorOr<T> &Err, E Code) {
510 return error_code(Err) == Code;
512 } // end namespace llvm