diff options
Diffstat (limited to 'include/llvm/Support/ErrorOr.h')
-rw-r--r-- | include/llvm/Support/ErrorOr.h | 266 |
1 files changed, 23 insertions, 243 deletions
diff --git a/include/llvm/Support/ErrorOr.h b/include/llvm/Support/ErrorOr.h index f3ac305..d5b11cb 100644 --- a/include/llvm/Support/ErrorOr.h +++ b/include/llvm/Support/ErrorOr.h @@ -27,38 +27,6 @@ #endif namespace llvm { -struct ErrorHolderBase { - error_code Error; - uint16_t RefCount; - bool HasUserData; - - ErrorHolderBase() : RefCount(1) {} - - void aquire() { - ++RefCount; - } - - void release() { - if (--RefCount == 0) - delete this; - } - -protected: - virtual ~ErrorHolderBase() {} -}; - -template<class T> -struct ErrorHolder : ErrorHolderBase { -#if LLVM_HAS_RVALUE_REFERENCES - ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {} -#else - ErrorHolder(T &UD) : UserData(UD) {} -#endif - T UserData; -}; - -template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {}; - #if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES template<class T, class V> typename std::enable_if< std::is_constructible<T, V>::value @@ -111,44 +79,6 @@ public: /// buffer->write("adena"); /// \endcode /// -/// ErrorOr<T> also supports user defined data for specific error_codes. To use -/// this feature you must first add a template specialization of -/// ErrorOrUserDataTraits derived from std::true_type for your type in the lld -/// namespace. This specialization must have a static error_code error() -/// function that returns the error_code this data is used with. -/// -/// getError<UserData>() may be called to get either the stored user data, or -/// a default constructed UserData if none was stored. -/// -/// Example: -/// \code -/// struct InvalidArgError { -/// InvalidArgError() {} -/// InvalidArgError(std::string S) : ArgName(S) {} -/// std::string ArgName; -/// }; -/// -/// namespace llvm { -/// template<> -/// struct ErrorOrUserDataTraits<InvalidArgError> : std::true_type { -/// static error_code error() { -/// return make_error_code(errc::invalid_argument); -/// } -/// }; -/// } // end namespace llvm -/// -/// using namespace llvm; -/// -/// ErrorOr<int> foo() { -/// return InvalidArgError("adena"); -/// } -/// -/// int main() { -/// auto a = foo(); -/// if (!a && error_code(a) == errc::invalid_argument) -/// llvm::errs() << a.getError<InvalidArgError>().ArgName << "\n"; -/// } -/// \endcode /// /// An implicit conversion to bool provides a way to check if there was an /// error. The unary * and -> operators provide pointer like access to the @@ -178,43 +108,28 @@ private: typedef typename remove_reference<T>::type *pointer; public: - ErrorOr() : IsValid(false) {} - template <class E> ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value || is_error_condition_enum<E>::value, void *>::type = 0) - : HasError(true), IsValid(true) { - Error = new ErrorHolderBase; - Error->Error = make_error_code(ErrorCode); - Error->HasUserData = false; - } - - ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) { - Error = new ErrorHolderBase; - Error->Error = EC; - Error->HasUserData = false; + : HasError(true) { + new (getError()) error_code(make_error_code(ErrorCode)); } - template<class UserDataT> - ErrorOr(UserDataT UD, typename - enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0) - : HasError(true), IsValid(true) { - Error = new ErrorHolder<UserDataT>(llvm_move(UD)); - Error->Error = ErrorOrUserDataTraits<UserDataT>::error(); - Error->HasUserData = true; + ErrorOr(llvm::error_code EC) : HasError(true) { + new (getError()) error_code(EC); } - ErrorOr(T Val) : HasError(false), IsValid(true) { + ErrorOr(T Val) : HasError(false) { new (get()) storage_type(moveIfMoveConstructible<storage_type>(Val)); } - ErrorOr(const ErrorOr &Other) : IsValid(false) { + ErrorOr(const ErrorOr &Other) { copyConstruct(Other); } template <class OtherT> - ErrorOr(const ErrorOr<OtherT> &Other) : IsValid(false) { + ErrorOr(const ErrorOr<OtherT> &Other) { copyConstruct(Other); } @@ -230,12 +145,12 @@ public: } #if LLVM_HAS_RVALUE_REFERENCES - ErrorOr(ErrorOr &&Other) : IsValid(false) { + ErrorOr(ErrorOr &&Other) { moveConstruct(std::move(Other)); } template <class OtherT> - ErrorOr(ErrorOr<OtherT> &&Other) : IsValid(false) { + ErrorOr(ErrorOr<OtherT> &&Other) { moveConstruct(std::move(Other)); } @@ -252,37 +167,20 @@ public: #endif ~ErrorOr() { - if (!IsValid) - return; - if (HasError) - Error->release(); - else + if (!HasError) get()->~storage_type(); } - template<class ET> - ET getError() const { - assert(IsValid && "Cannot get the error of a default constructed ErrorOr!"); - assert(HasError && "Cannot get an error if none exists!"); - assert(ErrorOrUserDataTraits<ET>::error() == Error->Error && - "Incorrect user error data type for error!"); - if (!Error->HasUserData) - return ET(); - return reinterpret_cast<const ErrorHolder<ET>*>(Error)->UserData; - } - typedef void (*unspecified_bool_type)(); static void unspecified_bool_true() {} /// \brief Return false if there is an error. operator unspecified_bool_type() const { - assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); return HasError ? 0 : unspecified_bool_true; } operator llvm::error_code() const { - assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); - return HasError ? Error->Error : llvm::error_code::success(); + return HasError ? *getError() : llvm::error_code::success(); } pointer operator ->() { @@ -296,19 +194,14 @@ public: private: template <class OtherT> void copyConstruct(const ErrorOr<OtherT> &Other) { - // Construct an invalid ErrorOr if other is invalid. - if (!Other.IsValid) - return; - IsValid = true; if (!Other.HasError) { // Get the other value. HasError = false; new (get()) storage_type(*Other.get()); } else { // Get other's error. - Error = Other.Error; HasError = true; - Error->aquire(); + new (getError()) error_code(Other); } } @@ -334,22 +227,14 @@ private: #if LLVM_HAS_RVALUE_REFERENCES template <class OtherT> void moveConstruct(ErrorOr<OtherT> &&Other) { - // Construct an invalid ErrorOr if other is invalid. - if (!Other.IsValid) - return; - IsValid = true; if (!Other.HasError) { // Get the other value. HasError = false; new (get()) storage_type(std::move(*Other.get())); - // Tell other not to do any destruction. - Other.IsValid = false; } else { // Get other's error. - Error = Other.Error; HasError = true; - // Tell other not to do any destruction. - Other.IsValid = false; + new (getError()) error_code(Other); } } @@ -372,135 +257,30 @@ private: } storage_type *get() { - assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); assert(!HasError && "Cannot get value when an error exists!"); return reinterpret_cast<storage_type*>(TStorage.buffer); } const storage_type *get() const { - assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); assert(!HasError && "Cannot get value when an error exists!"); return reinterpret_cast<const storage_type*>(TStorage.buffer); } - union { - AlignedCharArrayUnion<storage_type> TStorage; - ErrorHolderBase *Error; - }; - bool HasError : 1; - bool IsValid : 1; -}; - -// ErrorOr specialization for void. -template <> -class ErrorOr<void> { -public: - ErrorOr() : Error(0, 0) {} - - template <class E> - ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value || - is_error_condition_enum<E>::value, - void *> ::type = 0) - : Error(0, 0) { - error_code EC = make_error_code(ErrorCode); - if (EC == errc::success) { - Error.setInt(1); - return; - } - ErrorHolderBase *EHB = new ErrorHolderBase; - EHB->Error = EC; - EHB->HasUserData = false; - Error.setPointer(EHB); - } - - ErrorOr(llvm::error_code EC) : Error(0, 0) { - if (EC == errc::success) { - Error.setInt(1); - return; - } - ErrorHolderBase *E = new ErrorHolderBase; - E->Error = EC; - E->HasUserData = false; - Error.setPointer(E); - } - - template<class UserDataT> - ErrorOr(UserDataT UD, typename - enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0) - : Error(0, 0) { - ErrorHolderBase *E = new ErrorHolder<UserDataT>(llvm_move(UD)); - E->Error = ErrorOrUserDataTraits<UserDataT>::error(); - E->HasUserData = true; - Error.setPointer(E); + error_code *getError() { + assert(HasError && "Cannot get error when a value exists!"); + return reinterpret_cast<error_code*>(ErrorStorage.buffer); } - ErrorOr(const ErrorOr &Other) : Error(0, 0) { - Error = Other.Error; - if (Other.Error.getPointer()->Error) { - Error.getPointer()->aquire(); - } + const error_code *getError() const { + return const_cast<ErrorOr<T> *>(this)->getError(); } - ErrorOr &operator =(const ErrorOr &Other) { - if (this == &Other) - return *this; - - this->~ErrorOr(); - new (this) ErrorOr(Other); - return *this; - } - -#if LLVM_HAS_RVALUE_REFERENCES - ErrorOr(ErrorOr &&Other) : Error(0) { - // Get other's error. - Error = Other.Error; - // Tell other not to do any destruction. - Other.Error.setPointer(0); - } - - ErrorOr &operator =(ErrorOr &&Other) { - if (this == &Other) - return *this; - - this->~ErrorOr(); - new (this) ErrorOr(std::move(Other)); - - return *this; - } -#endif - - ~ErrorOr() { - if (Error.getPointer()) - Error.getPointer()->release(); - } - - template<class ET> - ET getError() const { - assert(ErrorOrUserDataTraits<ET>::error() == *this && - "Incorrect user error data type for error!"); - if (!Error.getPointer()->HasUserData) - return ET(); - return reinterpret_cast<const ErrorHolder<ET> *>( - Error.getPointer())->UserData; - } - - typedef void (*unspecified_bool_type)(); - static void unspecified_bool_true() {} - - /// \brief Return false if there is an error. - operator unspecified_bool_type() const { - return Error.getInt() ? unspecified_bool_true : 0; - } - - operator llvm::error_code() const { - return Error.getInt() ? make_error_code(errc::success) - : Error.getPointer()->Error; - } - -private: - // If the bit is 1, the error is success. - llvm::PointerIntPair<ErrorHolderBase *, 1> Error; + union { + AlignedCharArrayUnion<storage_type> TStorage; + AlignedCharArrayUnion<error_code> ErrorStorage; + }; + bool HasError : 1; }; template<class T, class E> |