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/Support/AlignOf.h"
20 #include "llvm/Support/system_error.h"
21 #include "llvm/Support/type_traits.h"
24 #if LLVM_HAS_CXX11_TYPETRAITS
25 #include <type_traits>
29 struct ErrorHolderBase {
34 ErrorHolderBase() : RefCount(1) {}
46 virtual ~ErrorHolderBase() {}
50 struct ErrorHolder : ErrorHolderBase {
51 #if LLVM_HAS_RVALUE_REFERENCES
52 ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {}
54 ErrorHolder(T &UD) : UserData(UD) {}
59 template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {};
61 #if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES
62 template<class T, class V>
63 typename std::enable_if< std::is_constructible<T, V>::value
64 , typename std::remove_reference<V>::type>::type &&
65 moveIfMoveConstructible(V &Val) {
66 return std::move(Val);
69 template<class T, class V>
70 typename std::enable_if< !std::is_constructible<T, V>::value
71 , typename std::remove_reference<V>::type>::type &
72 moveIfMoveConstructible(V &Val) {
76 template<class T, class V>
77 V &moveIfMoveConstructible(V &Val) {
82 /// \brief Stores a reference that can be changed.
84 class ReferenceStorage {
88 ReferenceStorage(T &Ref) : Storage(&Ref) {}
90 operator T &() const { return *Storage; }
91 T &get() const { return *Storage; }
94 /// \brief Represents either an error or a value T.
96 /// ErrorOr<T> is a pointer-like class that represents the result of an
97 /// operation. The result is either an error, or a value of type T. This is
98 /// designed to emulate the usage of returning a pointer where nullptr indicates
99 /// failure. However instead of just knowing that the operation failed, we also
100 /// have an error_code and optional user data that describes why it failed.
102 /// It is used like the following.
104 /// ErrorOr<Buffer> getBuffer();
105 /// void handleError(error_code ec);
107 /// auto buffer = getBuffer();
109 /// handleError(buffer);
110 /// buffer->write("adena");
113 /// ErrorOr<T> also supports user defined data for specific error_codes. To use
114 /// this feature you must first add a template specialization of
115 /// ErrorOrUserDataTraits derived from std::true_type for your type in the lld
116 /// namespace. This specialization must have a static error_code error()
117 /// function that returns the error_code this data is used with.
119 /// getError<UserData>() may be called to get either the stored user data, or
120 /// a default constructed UserData if none was stored.
124 /// struct InvalidArgError {
125 /// InvalidArgError() {}
126 /// InvalidArgError(std::string S) : ArgName(S) {}
127 /// std::string ArgName;
132 /// struct ErrorOrUserDataTraits<InvalidArgError> : std::true_type {
133 /// static error_code error() {
134 /// return make_error_code(errc::invalid_argument);
137 /// } // end namespace llvm
139 /// using namespace llvm;
141 /// ErrorOr<int> foo() {
142 /// return InvalidArgError("adena");
147 /// if (!a && error_code(a) == errc::invalid_argument)
148 /// llvm::errs() << a.getError<InvalidArgError>().ArgName << "\n";
152 /// An implicit conversion to bool provides a way to check if there was an
153 /// error. The unary * and -> operators provide pointer like access to the
154 /// value. Accessing the value when there is an error has undefined behavior.
156 /// When T is a reference type the behaivor is slightly different. The reference
157 /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
158 /// there is special handling to make operator -> work as if T was not a
161 /// T cannot be a rvalue reference.
164 static const bool isRef = is_reference<T>::value;
165 typedef ReferenceStorage<typename remove_reference<T>::type> wrap;
172 >::type storage_type;
175 typedef T &reference;
176 typedef typename remove_reference<T>::type *pointer;
179 ErrorOr() : IsValid(false) {}
181 ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
182 Error = new ErrorHolderBase;
184 Error->HasUserData = false;
187 template<class UserDataT>
188 ErrorOr(UserDataT UD, typename
189 enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0)
190 : HasError(true), IsValid(true) {
191 Error = new ErrorHolder<UserDataT>(llvm_move(UD));
192 Error->Error = ErrorOrUserDataTraits<UserDataT>::error();
193 Error->HasUserData = true;
196 ErrorOr(T Val) : HasError(false), IsValid(true) {
197 new (get()) storage_type(moveIfMoveConstructible<storage_type>(Val));
200 ErrorOr(const ErrorOr &Other) : IsValid(false) {
201 // Construct an invalid ErrorOr if other is invalid.
204 if (!Other.HasError) {
205 // Get the other value.
206 new (get()) storage_type(*Other.get());
209 // Get other's error.
218 ErrorOr &operator =(const ErrorOr &Other) {
223 new (this) ErrorOr(Other);
228 #if LLVM_HAS_RVALUE_REFERENCES
229 ErrorOr(ErrorOr &&Other) : IsValid(false) {
230 // Construct an invalid ErrorOr if other is invalid.
233 if (!Other.HasError) {
234 // Get the other value.
236 new (get()) storage_type(std::move(*Other.get()));
238 // Tell other not to do any destruction.
239 Other.IsValid = false;
241 // Get other's error.
244 // Tell other not to do any destruction.
245 Other.IsValid = false;
251 ErrorOr &operator =(ErrorOr &&Other) {
256 new (this) ErrorOr(std::move(Other));
267 get()->~storage_type();
272 ET getError() const {
273 assert(IsValid && "Cannot get the error of a default constructed ErrorOr!");
274 assert(HasError && "Cannot get an error if none exists!");
275 assert(ErrorOrUserDataTraits<ET>::error() == Error->Error &&
276 "Incorrect user error data type for error!");
277 if (!Error->HasUserData)
279 return reinterpret_cast<const ErrorHolder<ET>*>(Error)->UserData;
282 typedef void (*unspecified_bool_type)();
283 static void unspecified_bool_true() {}
285 /// \brief Return false if there is an error.
286 operator unspecified_bool_type() const {
287 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
288 return HasError ? 0 : unspecified_bool_true;
291 operator llvm::error_code() const {
292 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
293 return HasError ? Error->Error : llvm::error_code::success();
296 pointer operator ->() {
297 return toPointer(get());
300 reference operator *() {
305 pointer toPointer(pointer Val) {
309 pointer toPointer(wrap *Val) {
314 storage_type *get() {
315 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
316 assert(!HasError && "Cannot get value when an error exists!");
317 return reinterpret_cast<storage_type*>(TStorage.buffer);
320 const storage_type *get() const {
321 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
322 assert(!HasError && "Cannot get value when an error exists!");
323 return reinterpret_cast<const storage_type*>(TStorage.buffer);
327 AlignedCharArrayUnion<storage_type> TStorage;
328 ErrorHolderBase *Error;
334 template<class T, class E>
335 typename enable_if_c<is_error_code_enum<E>::value ||
336 is_error_condition_enum<E>::value, bool>::type
337 operator ==(ErrorOr<T> &Err, E Code) {
338 return error_code(Err) == Code;
340 } // end namespace llvm