mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
Simplify ErrorOr.
ErrorOr had quiet a bit of complexity and indirection to be able to hold a user type with the error. That feature is not used anymore. This patch removes it, it will live in svn history if we ever need it again. If we do need it again, IMHO there is one thing that should be done differently: Holding extra info in the error is not a property a function also returning a value or not. The ability to hold extra info should be in the error type and ErrorOr templated over it so that we don't need the funny looking ErrorOr<void>. llvm-svn: 194030
This commit is contained in:
parent
26ff1b7453
commit
334fa3d8a8
@ -27,38 +27,6 @@
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
struct ErrorHolderBase {
|
||||
error_code Error;
|
||||
uint16_t RefCount;
|
||||
bool HasUserData;
|
||||
|
||||
ErrorHolderBase() : RefCount(1) {}
|
||||
|
||||
void acquire() {
|
||||
++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
|
||||
@ -185,24 +115,11 @@ public:
|
||||
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;
|
||||
Error = make_error_code(ErrorCode);
|
||||
}
|
||||
|
||||
ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
|
||||
Error = new ErrorHolderBase;
|
||||
Error->Error = EC;
|
||||
Error->HasUserData = false;
|
||||
}
|
||||
|
||||
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;
|
||||
Error = EC;
|
||||
}
|
||||
|
||||
ErrorOr(T Val) : HasError(false), IsValid(true) {
|
||||
@ -254,23 +171,10 @@ public:
|
||||
~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() {}
|
||||
|
||||
@ -282,7 +186,7 @@ public:
|
||||
|
||||
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 ? Error : llvm::error_code::success();
|
||||
}
|
||||
|
||||
pointer operator ->() {
|
||||
@ -308,7 +212,6 @@ private:
|
||||
// Get other's error.
|
||||
Error = Other.Error;
|
||||
HasError = true;
|
||||
Error->acquire();
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,124 +288,12 @@ private:
|
||||
|
||||
union {
|
||||
AlignedCharArrayUnion<storage_type> TStorage;
|
||||
ErrorHolderBase *Error;
|
||||
error_code 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);
|
||||
}
|
||||
|
||||
ErrorOr(const ErrorOr &Other) : Error(0, 0) {
|
||||
Error = Other.Error;
|
||||
if (Other.Error.getPointer()->Error) {
|
||||
Error.getPointer()->acquire();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
template<class T, class E>
|
||||
typename enable_if_c<is_error_code_enum<E>::value ||
|
||||
is_error_condition_enum<E>::value, bool>::type
|
||||
|
@ -45,9 +45,6 @@ TEST(ErrorOr, Types) {
|
||||
*a = 42;
|
||||
EXPECT_EQ(42, x);
|
||||
|
||||
EXPECT_FALSE(ErrorOr<void>(errc::broken_pipe));
|
||||
EXPECT_TRUE(ErrorOr<void>(errc::success));
|
||||
|
||||
#if LLVM_HAS_CXX11_STDLIB
|
||||
// Move only types.
|
||||
EXPECT_EQ(3, **t3());
|
||||
@ -67,38 +64,3 @@ TEST(ErrorOr, Covariant) {
|
||||
#endif
|
||||
}
|
||||
} // end anon namespace
|
||||
|
||||
struct InvalidArgError {
|
||||
InvalidArgError() {}
|
||||
InvalidArgError(std::string S) : ArgName(S) {}
|
||||
std::string ArgName;
|
||||
};
|
||||
|
||||
namespace llvm {
|
||||
template<>
|
||||
struct ErrorOrUserDataTraits<InvalidArgError> : true_type {
|
||||
static error_code error() {
|
||||
return make_error_code(errc::invalid_argument);
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
ErrorOr<int> t4() {
|
||||
return InvalidArgError("adena");
|
||||
}
|
||||
|
||||
ErrorOr<void> t5() {
|
||||
return InvalidArgError("pie");
|
||||
}
|
||||
|
||||
namespace {
|
||||
TEST(ErrorOr, UserErrorData) {
|
||||
ErrorOr<int> a = t4();
|
||||
EXPECT_EQ(errc::invalid_argument, a);
|
||||
EXPECT_EQ("adena", t4().getError<InvalidArgError>().ArgName);
|
||||
|
||||
ErrorOr<void> b = t5();
|
||||
EXPECT_EQ(errc::invalid_argument, b);
|
||||
EXPECT_EQ("pie", b.getError<InvalidArgError>().ArgName);
|
||||
}
|
||||
} // end anon namespace
|
||||
|
Loading…
Reference in New Issue
Block a user