]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/include/llvm/Support/ErrorOr.h
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / include / llvm / Support / ErrorOr.h
1 //===- llvm/Support/ErrorOr.h - Error Smart Pointer -----------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 ///
12 /// Provides ErrorOr<T> smart pointer.
13 ///
14 //===----------------------------------------------------------------------===//
15
16 #ifndef LLVM_SUPPORT_ERROR_OR_H
17 #define LLVM_SUPPORT_ERROR_OR_H
18
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"
23
24 #include <cassert>
25 #if LLVM_HAS_CXX11_TYPETRAITS
26 #include <type_traits>
27 #endif
28
29 namespace llvm {
30 struct ErrorHolderBase {
31   error_code Error;
32   uint16_t RefCount;
33   bool HasUserData;
34
35   ErrorHolderBase() : RefCount(1) {}
36
37   void aquire() {
38     ++RefCount;
39   }
40
41   void release() {
42     if (--RefCount == 0)
43       delete this;
44   }
45
46 protected:
47   virtual ~ErrorHolderBase() {}
48 };
49
50 template<class T>
51 struct ErrorHolder : ErrorHolderBase {
52 #if LLVM_HAS_RVALUE_REFERENCES
53   ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {}
54 #else
55   ErrorHolder(T &UD) : UserData(UD) {}
56 #endif
57   T UserData;
58 };
59
60 template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {};
61
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);
68 }
69
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) {
74   return Val;
75 }
76 #else
77 template<class T, class V>
78 V &moveIfMoveConstructible(V &Val) {
79   return Val;
80 }
81 #endif
82
83 /// \brief Stores a reference that can be changed.
84 template <typename T>
85 class ReferenceStorage {
86   T *Storage;
87
88 public:
89   ReferenceStorage(T &Ref) : Storage(&Ref) {}
90
91   operator T &() const { return *Storage; }
92   T &get() const { return *Storage; }
93 };
94
95 /// \brief Represents either an error or a value T.
96 ///
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.
102 ///
103 /// It is used like the following.
104 /// \code
105 ///   ErrorOr<Buffer> getBuffer();
106 ///   void handleError(error_code ec);
107 ///
108 ///   auto buffer = getBuffer();
109 ///   if (!buffer)
110 ///     handleError(buffer);
111 ///   buffer->write("adena");
112 /// \endcode
113 ///
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.
119 ///
120 /// getError<UserData>() may be called to get either the stored user data, or
121 /// a default constructed UserData if none was stored.
122 ///
123 /// Example:
124 /// \code
125 ///   struct InvalidArgError {
126 ///     InvalidArgError() {}
127 ///     InvalidArgError(std::string S) : ArgName(S) {}
128 ///     std::string ArgName;
129 ///   };
130 ///
131 ///   namespace llvm {
132 ///   template<>
133 ///   struct ErrorOrUserDataTraits<InvalidArgError> : std::true_type {
134 ///     static error_code error() {
135 ///       return make_error_code(errc::invalid_argument);
136 ///     }
137 ///   };
138 ///   } // end namespace llvm
139 ///
140 ///   using namespace llvm;
141 ///
142 ///   ErrorOr<int> foo() {
143 ///     return InvalidArgError("adena");
144 ///   }
145 ///
146 ///   int main() {
147 ///     auto a = foo();
148 ///     if (!a && error_code(a) == errc::invalid_argument)
149 ///       llvm::errs() << a.getError<InvalidArgError>().ArgName << "\n";
150 ///   }
151 /// \endcode
152 ///
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.
156 ///
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
160 /// reference.
161 ///
162 /// T cannot be a rvalue reference.
163 template<class T>
164 class ErrorOr {
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;
168
169 public:
170   typedef typename
171     conditional< isRef
172                , wrap
173                , T
174                >::type storage_type;
175
176 private:
177   typedef typename remove_reference<T>::type &reference;
178   typedef typename remove_reference<T>::type *pointer;
179
180 public:
181   ErrorOr() : IsValid(false) {}
182
183   template <class E>
184   ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value ||
185                                             is_error_condition_enum<E>::value,
186                                             void *>::type = 0)
187       : HasError(true), IsValid(true) {
188     Error = new ErrorHolderBase;
189     Error->Error = make_error_code(ErrorCode);
190     Error->HasUserData = false;
191   }
192
193   ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
194     Error = new ErrorHolderBase;
195     Error->Error = EC;
196     Error->HasUserData = false;
197   }
198
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;
206   }
207
208   ErrorOr(T Val) : HasError(false), IsValid(true) {
209     new (get()) storage_type(moveIfMoveConstructible<storage_type>(Val));
210   }
211
212   ErrorOr(const ErrorOr &Other) : IsValid(false) {
213     copyConstruct(Other);
214   }
215
216   template <class OtherT>
217   ErrorOr(const ErrorOr<OtherT> &Other) : IsValid(false) {
218     copyConstruct(Other);
219   }
220
221   ErrorOr &operator =(const ErrorOr &Other) {
222     copyAssign(Other);
223     return *this;
224   }
225
226   template <class OtherT>
227   ErrorOr &operator =(const ErrorOr<OtherT> &Other) {
228     copyAssign(Other);
229     return *this;
230   }
231
232 #if LLVM_HAS_RVALUE_REFERENCES
233   ErrorOr(ErrorOr &&Other) : IsValid(false) {
234     moveConstruct(std::move(Other));
235   }
236
237   template <class OtherT>
238   ErrorOr(ErrorOr<OtherT> &&Other) : IsValid(false) {
239     moveConstruct(std::move(Other));
240   }
241
242   ErrorOr &operator =(ErrorOr &&Other) {
243     moveAssign(std::move(Other));
244     return *this;
245   }
246
247   template <class OtherT>
248   ErrorOr &operator =(ErrorOr<OtherT> &&Other) {
249     moveAssign(std::move(Other));
250     return *this;
251   }
252 #endif
253
254   ~ErrorOr() {
255     if (!IsValid)
256       return;
257     if (HasError)
258       Error->release();
259     else
260       get()->~storage_type();
261   }
262
263   template<class ET>
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)
270       return ET();
271     return reinterpret_cast<const ErrorHolder<ET>*>(Error)->UserData;
272   }
273
274   typedef void (*unspecified_bool_type)();
275   static void unspecified_bool_true() {}
276
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;
281   }
282
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();
286   }
287
288   pointer operator ->() {
289     return toPointer(get());
290   }
291
292   reference operator *() {
293     return *get();
294   }
295
296 private:
297   template <class OtherT>
298   void copyConstruct(const ErrorOr<OtherT> &Other) {
299     // Construct an invalid ErrorOr if other is invalid.
300     if (!Other.IsValid)
301       return;
302     IsValid = true;
303     if (!Other.HasError) {
304       // Get the other value.
305       HasError = false;
306       new (get()) storage_type(*Other.get());
307     } else {
308       // Get other's error.
309       Error = Other.Error;
310       HasError = true;
311       Error->aquire();
312     }
313   }
314
315   template <class T1>
316   static bool compareThisIfSameType(const T1 &a, const T1 &b) {
317     return &a == &b;
318   }
319
320   template <class T1, class T2>
321   static bool compareThisIfSameType(const T1 &a, const T2 &b) {
322     return false;
323   }
324
325   template <class OtherT>
326   void copyAssign(const ErrorOr<OtherT> &Other) {
327     if (compareThisIfSameType(*this, Other))
328       return;
329
330     this->~ErrorOr();
331     new (this) ErrorOr(Other);
332   }
333
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.
338     if (!Other.IsValid)
339       return;
340     IsValid = true;
341     if (!Other.HasError) {
342       // Get the other value.
343       HasError = false;
344       new (get()) storage_type(std::move(*Other.get()));
345       // Tell other not to do any destruction.
346       Other.IsValid = false;
347     } else {
348       // Get other's error.
349       Error = Other.Error;
350       HasError = true;
351       // Tell other not to do any destruction.
352       Other.IsValid = false;
353     }
354   }
355
356   template <class OtherT>
357   void moveAssign(ErrorOr<OtherT> &&Other) {
358     if (compareThisIfSameType(*this, Other))
359       return;
360
361     this->~ErrorOr();
362     new (this) ErrorOr(std::move(Other));
363   }
364 #endif
365
366   pointer toPointer(pointer Val) {
367     return Val;
368   }
369
370   pointer toPointer(wrap *Val) {
371     return &Val->get();
372   }
373
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);
378   }
379
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);
384   }
385
386   union {
387     AlignedCharArrayUnion<storage_type> TStorage;
388     ErrorHolderBase *Error;
389   };
390   bool HasError : 1;
391   bool IsValid : 1;
392 };
393
394 // ErrorOr specialization for void.
395 template <>
396 class ErrorOr<void> {
397 public:
398   ErrorOr() : Error(0, 0) {}
399
400   template <class E>
401   ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value ||
402                                             is_error_condition_enum<E>::value,
403                                             void *> ::type = 0)
404       : Error(0, 0) {
405     error_code EC = make_error_code(ErrorCode);
406     if (EC == errc::success) {
407       Error.setInt(1);
408       return;
409     }
410     ErrorHolderBase *EHB = new ErrorHolderBase;
411     EHB->Error = EC;
412     EHB->HasUserData = false;
413     Error.setPointer(EHB);
414   }
415
416   ErrorOr(llvm::error_code EC) : Error(0, 0) {
417     if (EC == errc::success) {
418       Error.setInt(1);
419       return;
420     }
421     ErrorHolderBase *E = new ErrorHolderBase;
422     E->Error = EC;
423     E->HasUserData = false;
424     Error.setPointer(E);
425   }
426
427   template<class UserDataT>
428   ErrorOr(UserDataT UD, typename
429           enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0)
430       : Error(0, 0) {
431     ErrorHolderBase *E = new ErrorHolder<UserDataT>(llvm_move(UD));
432     E->Error = ErrorOrUserDataTraits<UserDataT>::error();
433     E->HasUserData = true;
434     Error.setPointer(E);
435   }
436
437   ErrorOr(const ErrorOr &Other) : Error(0, 0) {
438     Error = Other.Error;
439     if (Other.Error.getPointer()->Error) {
440       Error.getPointer()->aquire();
441     }
442   }
443
444   ErrorOr &operator =(const ErrorOr &Other) {
445     if (this == &Other)
446       return *this;
447
448     this->~ErrorOr();
449     new (this) ErrorOr(Other);
450
451     return *this;
452   }
453
454 #if LLVM_HAS_RVALUE_REFERENCES
455   ErrorOr(ErrorOr &&Other) : Error(0) {
456     // Get other's error.
457     Error = Other.Error;
458     // Tell other not to do any destruction.
459     Other.Error.setPointer(0);
460   }
461
462   ErrorOr &operator =(ErrorOr &&Other) {
463     if (this == &Other)
464       return *this;
465
466     this->~ErrorOr();
467     new (this) ErrorOr(std::move(Other));
468
469     return *this;
470   }
471 #endif
472
473   ~ErrorOr() {
474     if (Error.getPointer())
475       Error.getPointer()->release();
476   }
477
478   template<class ET>
479   ET getError() const {
480     assert(ErrorOrUserDataTraits<ET>::error() == *this &&
481            "Incorrect user error data type for error!");
482     if (!Error.getPointer()->HasUserData)
483       return ET();
484     return reinterpret_cast<const ErrorHolder<ET> *>(
485         Error.getPointer())->UserData;
486   }
487
488   typedef void (*unspecified_bool_type)();
489   static void unspecified_bool_true() {}
490
491   /// \brief Return false if there is an error.
492   operator unspecified_bool_type() const {
493     return Error.getInt() ? unspecified_bool_true : 0;
494   }
495
496   operator llvm::error_code() const {
497     return Error.getInt() ? make_error_code(errc::success)
498                           : Error.getPointer()->Error;
499   }
500
501 private:
502   // If the bit is 1, the error is success.
503   llvm::PointerIntPair<ErrorHolderBase *, 1> Error;
504 };
505
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;
511 }
512 } // end namespace llvm
513
514 #endif