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
29namespace llvm {
30struct 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
46protected:
47  virtual ~ErrorHolderBase() {}
48};
49
50template<class T>
51struct 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
60template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {};
61
62#if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES
63template<class T, class V>
64typename 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
70template<class T, class V>
71typename std::enable_if< !std::is_constructible<T, V>::value
72                       , typename std::remove_reference<V>::type>::type &
73moveIfMoveConstructible(V &Val) {
74  return Val;
75}
76#else
77template<class T, class V>
78V &moveIfMoveConstructible(V &Val) {
79  return Val;
80}
81#endif
82
83/// \brief Stores a reference that can be changed.
84template <typename T>
85class ReferenceStorage {
86  T *Storage;
87
88public:
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.
163template<class T>
164class 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
169public:
170  typedef typename
171    conditional< isRef
172               , wrap
173               , T
174               >::type storage_type;
175
176private:
177  typedef typename remove_reference<T>::type &reference;
178  typedef typename remove_reference<T>::type *pointer;
179
180public:
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
296private:
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.
395template <>
396class ErrorOr<void> {
397public:
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
501private:
502  // If the bit is 1, the error is success.
503  llvm::PointerIntPair<ErrorHolderBase *, 1> Error;
504};
505
506template<class T, class E>
507typename enable_if_c<is_error_code_enum<E>::value ||
508                     is_error_condition_enum<E>::value, bool>::type
509operator ==(ErrorOr<T> &Err, E Code) {
510  return error_code(Err) == Code;
511}
512} // end namespace llvm
513
514#endif
515