summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Support/ErrorOr.h136
-rw-r--r--unittests/Support/ErrorOrTest.cpp13
2 files changed, 107 insertions, 42 deletions
diff --git a/include/llvm/Support/ErrorOr.h b/include/llvm/Support/ErrorOr.h
index 828d77b852..ceec33d185 100644
--- a/include/llvm/Support/ErrorOr.h
+++ b/include/llvm/Support/ErrorOr.h
@@ -162,6 +162,7 @@ public:
/// 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;
@@ -199,60 +200,43 @@ public:
}
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
@@ -300,6 +284,75 @@ 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();
+ }
+ }
+
+ template <class T1>
+ static bool compareThisIfSameType(const T1 &a, const T1 &b) {
+ return &a == &b;
+ }
+
+ template <class T1, class T2>
+ static bool compareThisIfSameType(const T1 &a, const T2 &b) {
+ return false;
+ }
+
+ template <class OtherT>
+ void copyAssign(const ErrorOr<OtherT> &Other) {
+ if (compareThisIfSameType(*this, Other))
+ return;
+
+ this->~ErrorOr();
+ new (this) ErrorOr(Other);
+ }
+
+#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;
+ }
+ }
+
+ template <class OtherT>
+ void moveAssign(ErrorOr<OtherT> &&Other) {
+ if (compareThisIfSameType(*this, Other))
+ return;
+
+ this->~ErrorOr();
+ new (this) ErrorOr(std::move(Other));
+ }
+#endif
+
pointer toPointer(pointer Val) {
return Val;
}
@@ -308,7 +361,6 @@ private:
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!");
diff --git a/unittests/Support/ErrorOrTest.cpp b/unittests/Support/ErrorOrTest.cpp
index a8608860b8..aa0ddd5e79 100644
--- a/unittests/Support/ErrorOrTest.cpp
+++ b/unittests/Support/ErrorOrTest.cpp
@@ -53,6 +53,19 @@ TEST(ErrorOr, Types) {
EXPECT_EQ(3, **t3());
#endif
}
+
+struct B {};
+struct D : B {};
+
+TEST(ErrorOr, Covariant) {
+ ErrorOr<B*> b(ErrorOr<D*>(0));
+ b = ErrorOr<D*>(0);
+
+#if LLVM_HAS_CXX11_STDLIB
+ ErrorOr<std::unique_ptr<B> > b1(ErrorOr<std::unique_ptr<D> >(0));
+ b1 = ErrorOr<std::unique_ptr<D> >(0);
+#endif
+}
} // end anon namespace
struct InvalidArgError {