#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
/// 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
/// T cannot be a rvalue reference.
template<class T>
class ErrorOr {
+ template <class OtherT> friend class ErrorOr;
static const bool isRef = is_reference<T>::value;
typedef ReferenceStorage<typename remove_reference<T>::type> wrap;
public:
ErrorOr() : IsValid(false) {}
- ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
- Error = new ErrorHolderBase;
- Error->Error = EC;
- Error->HasUserData = 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) {
+ 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), IsValid(true) {
+ new (getError()) error_code(EC);
}
ErrorOr(T Val) : HasError(false), IsValid(true) {
}
ErrorOr(const ErrorOr &Other) : IsValid(false) {
- // 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();
- }
+ copyConstruct(Other);
}
- ErrorOr &operator =(const ErrorOr &Other) {
- if (this == &Other)
- return *this;
+ template <class OtherT>
+ ErrorOr(const ErrorOr<OtherT> &Other) : IsValid(false) {
+ copyConstruct(Other);
+ }
- this->~ErrorOr();
- new (this) ErrorOr(Other);
+ ErrorOr &operator =(const ErrorOr &Other) {
+ copyAssign(Other);
+ return *this;
+ }
+ template <class OtherT>
+ ErrorOr &operator =(const ErrorOr<OtherT> &Other) {
+ copyAssign(Other);
return *this;
}
#if LLVM_HAS_RVALUE_REFERENCES
ErrorOr(ErrorOr &&Other) : IsValid(false) {
- // 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;
- }
+ moveConstruct(std::move(Other));
}
- ErrorOr &operator =(ErrorOr &&Other) {
- if (this == &Other)
- return *this;
+ template <class OtherT>
+ ErrorOr(ErrorOr<OtherT> &&Other) : IsValid(false) {
+ moveConstruct(std::move(Other));
+ }
- this->~ErrorOr();
- new (this) ErrorOr(std::move(Other));
+ ErrorOr &operator =(ErrorOr &&Other) {
+ moveAssign(std::move(Other));
+ return *this;
+ }
+ template <class OtherT>
+ ErrorOr &operator =(ErrorOr<OtherT> &&Other) {
+ moveAssign(std::move(Other));
return *this;
}
#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() {}
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 ->() {
}
private:
- pointer toPointer(pointer Val) {
- return Val;
- }
-
- pointer toPointer(wrap *Val) {
- return &Val->get();
- }
-
-protected:
- 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) {}
-
- ErrorOr(llvm::error_code EC) : Error(0, 0) {
- if (EC == errc::success) {
- Error.setInt(1);
+ 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.
+ HasError = true;
+ new (getError()) error_code(Other);
}
- 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);
+ template <class T1>
+ static bool compareThisIfSameType(const T1 &a, const T1 &b) {
+ return &a == &b;
}
- ErrorOr(const ErrorOr &Other) : Error(0, 0) {
- Error = Other.Error;
- if (Other.Error.getPointer()->Error) {
- Error.getPointer()->aquire();
- }
+ template <class T1, class T2>
+ static bool compareThisIfSameType(const T1 &a, const T2 &b) {
+ return false;
}
- ErrorOr &operator =(const ErrorOr &Other) {
- if (this == &Other)
- return *this;
+ template <class OtherT>
+ void copyAssign(const ErrorOr<OtherT> &Other) {
+ if (compareThisIfSameType(*this, Other))
+ return;
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);
+ 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.
+ HasError = true;
+ new (getError()) error_code(Other);
+ // Tell other not to do any destruction.
+ Other.IsValid = false;
+ }
}
- ErrorOr &operator =(ErrorOr &&Other) {
- if (this == &Other)
- return *this;
+ template <class OtherT>
+ void moveAssign(ErrorOr<OtherT> &&Other) {
+ if (compareThisIfSameType(*this, Other))
+ return;
this->~ErrorOr();
new (this) ErrorOr(std::move(Other));
-
- return *this;
}
#endif
- ~ErrorOr() {
- if (Error.getPointer())
- Error.getPointer()->release();
+ pointer toPointer(pointer Val) {
+ return Val;
}
- 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;
+ pointer toPointer(wrap *Val) {
+ return &Val->get();
}
- typedef void (*unspecified_bool_type)();
- static void unspecified_bool_true() {}
+ 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);
+ }
- /// \brief Return false if there is an error.
- operator unspecified_bool_type() const {
- return Error.getInt() ? unspecified_bool_true : 0;
+ 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);
}
- operator llvm::error_code() const {
- return Error.getInt() ? make_error_code(errc::success)
- : Error.getPointer()->Error;
+ error_code *getError() {
+ assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<error_code*>(ErrorStorage.buffer);
}
-private:
- // If the bit is 1, the error is success.
- llvm::PointerIntPair<ErrorHolderBase *, 1> Error;
+ const error_code *getError() const {
+ return const_cast<ErrorOr<T> *>(this)->getError();
+ }
+
+
+ union {
+ AlignedCharArrayUnion<storage_type> TStorage;
+ AlignedCharArrayUnion<error_code> ErrorStorage;
+ };
+ bool HasError : 1;
+ bool IsValid : 1;
};
template<class T, class E>