X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FSupport%2FErrorOr.h;h=ca6ede73e8df1315d6eb7da25569123127e208ff;hb=3c4b3a54581fe5badf08b9a0a32f8b2e5f55151d;hp=653b9e5c88f2d2bbcaec04d6a74ba5ff573b0424;hpb=a33e1fafac7fedb1b080ef07ddf9ad6ddff3a830;p=oota-llvm.git diff --git a/include/llvm/Support/ErrorOr.h b/include/llvm/Support/ErrorOr.h index 653b9e5c88f..ca6ede73e8d 100644 --- a/include/llvm/Support/ErrorOr.h +++ b/include/llvm/Support/ErrorOr.h @@ -1,4 +1,4 @@ -//===- llvm/Support/ErrorOr.h - Error Smart Pointer -----------------------===// +//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===// // // The LLVM Linker // @@ -13,53 +13,16 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_SUPPORT_ERROR_OR_H -#define LLVM_SUPPORT_ERROR_OR_H +#ifndef LLVM_SUPPORT_ERROROR_H +#define LLVM_SUPPORT_ERROROR_H #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/AlignOf.h" -#include "llvm/Support/system_error.h" -#include "llvm/Support/type_traits.h" - #include -#if LLVM_HAS_CXX11_TYPETRAITS +#include #include -#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 -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 struct ErrorOrUserDataTraits : llvm::false_type {}; - -#if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES template typename std::enable_if< std::is_constructible::value , typename std::remove_reference::type>::type && @@ -73,12 +36,6 @@ typename std::enable_if< !std::is_constructible::value moveIfMoveConstructible(V &Val) { return Val; } -#else -template -V &moveIfMoveConstructible(V &Val) { - return Val; -} -#endif /// \brief Stores a reference that can be changed. template @@ -103,56 +60,17 @@ public: /// It is used like the following. /// \code /// ErrorOr getBuffer(); -/// void handleError(error_code ec); /// /// auto buffer = getBuffer(); -/// if (!buffer) -/// handleError(buffer); +/// if (error_code ec = buffer.getError()) +/// return ec; /// buffer->write("adena"); /// \endcode /// -/// ErrorOr 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() 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 : std::true_type { -/// static error_code error() { -/// return make_error_code(errc::invalid_argument); -/// } -/// }; -/// } // end namespace llvm -/// -/// using namespace llvm; -/// -/// ErrorOr foo() { -/// return InvalidArgError("adena"); -/// } -/// -/// int main() { -/// auto a = foo(); -/// if (!a && error_code(a) == errc::invalid_argument) -/// llvm::errs() << a.getError().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 -/// value. Accessing the value when there is an error has undefined behavior. +/// Implicit conversion to bool returns true if there is a usable value. The +/// unary * and -> operators provide pointer like access to the value. Accessing +/// the value when there is an error has undefined behavior. /// /// When T is a reference type the behaivor is slightly different. The reference /// is held in a std::reference_wrapper::type>, and @@ -163,278 +81,217 @@ public: template class ErrorOr { template friend class ErrorOr; - static const bool isRef = is_reference::value; - typedef ReferenceStorage::type> wrap; + static const bool isRef = std::is_reference::value; + typedef ReferenceStorage::type> wrap; public: - typedef typename - conditional< isRef - , wrap - , T - >::type storage_type; + typedef typename std::conditional::type storage_type; private: - typedef typename remove_reference::type &reference; - typedef typename remove_reference::type *pointer; + typedef typename std::remove_reference::type &reference; + typedef const typename std::remove_reference::type &const_reference; + typedef typename std::remove_reference::type *pointer; + typedef const typename std::remove_reference::type *const_pointer; public: - ErrorOr() : IsValid(false) {} + template + ErrorOr(E ErrorCode, + typename std::enable_if::value || + std::is_error_condition_enum::value, + void *>::type = 0) + : HasError(true) { + new (getErrorStorage()) std::error_code(make_error_code(ErrorCode)); + } - ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) { - Error = new ErrorHolderBase; - Error->Error = EC; - Error->HasUserData = false; + ErrorOr(std::error_code EC) : HasError(true) { + new (getErrorStorage()) std::error_code(EC); } - template - ErrorOr(UserDataT UD, typename - enable_if_c::value>::type* = 0) - : HasError(true), IsValid(true) { - Error = new ErrorHolder(llvm_move(UD)); - Error->Error = ErrorOrUserDataTraits::error(); - Error->HasUserData = true; + ErrorOr(T Val) : HasError(false) { + new (getStorage()) storage_type(moveIfMoveConstructible(Val)); } - ErrorOr(T Val) : HasError(false), IsValid(true) { - new (get()) storage_type(moveIfMoveConstructible(Val)); + ErrorOr(const ErrorOr &Other) { + copyConstruct(Other); } template - ErrorOr(ErrorOr &Other) : IsValid(false) { - // Construct an invalid ErrorOr if other is invalid. - if (!Other.IsValid) - return; - if (!Other.HasError) { - // Get the other value. - new (get()) storage_type(*Other.get()); - HasError = false; - } else { - // Get other's error. - Error = Other.Error; - HasError = true; - Error->aquire(); - } - - IsValid = true; + ErrorOr( + const ErrorOr &Other, + typename std::enable_if::value>::type * = + nullptr) { + copyConstruct(Other); } - ErrorOr &operator =(const ErrorOr &Other) { - if (this == &Other) - return *this; - - this->~ErrorOr(); - new (this) ErrorOr(Other); + template + explicit ErrorOr( + const ErrorOr &Other, + typename std::enable_if< + !std::is_convertible::value>::type * = nullptr) { + copyConstruct(Other); + } - return *this; + ErrorOr(ErrorOr &&Other) { + moveConstruct(std::move(Other)); } -#if LLVM_HAS_RVALUE_REFERENCES template - ErrorOr(ErrorOr &&Other) : IsValid(false) { - // Construct an invalid ErrorOr if other is invalid. - if (!Other.IsValid) - return; - if (!Other.HasError) { - // Get the other value. - IsValid = true; - new (get()) storage_type(std::move(*Other.get())); - HasError = false; - // 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; - } - - IsValid = true; + ErrorOr( + ErrorOr &&Other, + typename std::enable_if::value>::type * = + nullptr) { + moveConstruct(std::move(Other)); } - ErrorOr &operator =(ErrorOr &&Other) { - if (this == &Other) - return *this; - - this->~ErrorOr(); - new (this) ErrorOr(std::move(Other)); + // This might eventually need SFINAE but it's more complex than is_convertible + // & I'm too lazy to write it right now. + template + explicit ErrorOr( + ErrorOr &&Other, + typename std::enable_if::value>::type * = + nullptr) { + moveConstruct(std::move(Other)); + } + ErrorOr &operator=(const ErrorOr &Other) { + copyAssign(Other); return *this; } -#endif - ~ErrorOr() { - if (!IsValid) - return; - if (HasError) - Error->release(); - else - get()->~storage_type(); + ErrorOr &operator=(ErrorOr &&Other) { + moveAssign(std::move(Other)); + return *this; } - template - 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::error() == Error->Error && - "Incorrect user error data type for error!"); - if (!Error->HasUserData) - return ET(); - return reinterpret_cast*>(Error)->UserData; + ~ErrorOr() { + if (!HasError) + getStorage()->~storage_type(); } - 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; + explicit operator bool() const { + return !HasError; } - operator llvm::error_code() const { - assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); - return HasError ? Error->Error : llvm::error_code::success(); + reference get() { return *getStorage(); } + const_reference get() const { return const_cast *>(this)->get(); } + + std::error_code getError() const { + return HasError ? *getErrorStorage() : std::error_code(); } pointer operator ->() { - return toPointer(get()); + return toPointer(getStorage()); } + const_pointer operator->() const { return toPointer(getStorage()); } + reference operator *() { - return *get(); + return *getStorage(); } -private: - pointer toPointer(pointer Val) { - return Val; - } + const_reference operator*() const { return *getStorage(); } - pointer toPointer(wrap *Val) { - return &Val->get(); +private: + template + void copyConstruct(const ErrorOr &Other) { + if (!Other.HasError) { + // Get the other value. + HasError = false; + new (getStorage()) storage_type(*Other.getStorage()); + } else { + // Get other's error. + HasError = true; + new (getErrorStorage()) std::error_code(Other.getError()); + } } - 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(TStorage.buffer); + template + static bool compareThisIfSameType(const T1 &a, const T1 &b) { + return &a == &b; } - 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(TStorage.buffer); + template + static bool compareThisIfSameType(const T1 &a, const T2 &b) { + return false; } - union { - AlignedCharArrayUnion TStorage; - ErrorHolderBase *Error; - }; - bool HasError : 1; - bool IsValid : 1; -}; - -// ErrorOr specialization for void. -template <> -class ErrorOr { -public: - ErrorOr() : Error(0, 0) {} - - ErrorOr(llvm::error_code EC) : Error(0, 0) { - if (EC == errc::success) { - Error.setInt(1); + template + void copyAssign(const ErrorOr &Other) { + if (compareThisIfSameType(*this, Other)) return; - } - ErrorHolderBase *E = new ErrorHolderBase; - E->Error = EC; - E->HasUserData = false; - Error.setPointer(E); - } - template - ErrorOr(UserDataT UD, typename - enable_if_c::value>::type* = 0) - : Error(0, 0) { - ErrorHolderBase *E = new ErrorHolder(llvm_move(UD)); - E->Error = ErrorOrUserDataTraits::error(); - E->HasUserData = true; - Error.setPointer(E); + this->~ErrorOr(); + new (this) ErrorOr(Other); } - ErrorOr(const ErrorOr &Other) : Error(0, 0) { - Error = Other.Error; - if (Other.Error.getPointer()->Error) { - Error.getPointer()->aquire(); + template + void moveConstruct(ErrorOr &&Other) { + if (!Other.HasError) { + // Get the other value. + HasError = false; + new (getStorage()) storage_type(std::move(*Other.getStorage())); + } else { + // Get other's error. + HasError = true; + new (getErrorStorage()) std::error_code(Other.getError()); } } - ErrorOr &operator =(const ErrorOr &Other) { - if (this == &Other) - return *this; + template + void moveAssign(ErrorOr &&Other) { + if (compareThisIfSameType(*this, Other)) + return; this->~ErrorOr(); - new (this) ErrorOr(Other); - - return *this; + new (this) ErrorOr(std::move(Other)); } -#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); + pointer toPointer(pointer Val) { + return Val; } - ErrorOr &operator =(ErrorOr &&Other) { - if (this == &Other) - return *this; - - this->~ErrorOr(); - new (this) ErrorOr(std::move(Other)); + const_pointer toPointer(const_pointer Val) const { return Val; } - return *this; + pointer toPointer(wrap *Val) { + return &Val->get(); } -#endif - ~ErrorOr() { - if (Error.getPointer()) - Error.getPointer()->release(); - } + const_pointer toPointer(const wrap *Val) const { return &Val->get(); } - template - ET getError() const { - assert(ErrorOrUserDataTraits::error() == *this && - "Incorrect user error data type for error!"); - if (!Error.getPointer()->HasUserData) - return ET(); - return reinterpret_cast *>( - Error.getPointer())->UserData; + storage_type *getStorage() { + assert(!HasError && "Cannot get value when an error exists!"); + return reinterpret_cast(TStorage.buffer); } - typedef void (*unspecified_bool_type)(); - static void unspecified_bool_true() {} + const storage_type *getStorage() const { + assert(!HasError && "Cannot get value when an error exists!"); + return reinterpret_cast(TStorage.buffer); + } - /// \brief Return false if there is an error. - operator unspecified_bool_type() const { - return Error.getInt() ? unspecified_bool_true : 0; + std::error_code *getErrorStorage() { + assert(HasError && "Cannot get error when a value exists!"); + return reinterpret_cast(ErrorStorage.buffer); } - operator llvm::error_code() const { - return Error.getInt() ? make_error_code(errc::success) - : Error.getPointer()->Error; + const std::error_code *getErrorStorage() const { + return const_cast *>(this)->getErrorStorage(); } -private: - // If the bit is 1, the error is success. - llvm::PointerIntPair Error; + + union { + AlignedCharArrayUnion TStorage; + AlignedCharArrayUnion ErrorStorage; + }; + bool HasError : 1; }; -template -typename enable_if_c::value || - is_error_condition_enum::value, bool>::type -operator ==(ErrorOr &Err, E Code) { - return error_code(Err) == Code; +template +typename std::enable_if::value || + std::is_error_condition_enum::value, + bool>::type +operator==(const ErrorOr &Err, E Code) { + return Err.getError() == Code; } } // end namespace llvm