[llvm] r174552 - [Support][ErrorOr] Add support for convertable types.

Michael J. Spencer bigcheesegs at gmail.com
Wed Feb 6 14:28:53 PST 2013


Author: mspencer
Date: Wed Feb  6 16:28:53 2013
New Revision: 174552

URL: http://llvm.org/viewvc/llvm-project?rev=174552&view=rev
Log:
[Support][ErrorOr] Add support for convertable types.

Thanks to Andrew, David, and Aaron for helping fix this.

Modified:
    llvm/trunk/include/llvm/Support/ErrorOr.h
    llvm/trunk/unittests/Support/ErrorOrTest.cpp

Modified: llvm/trunk/include/llvm/Support/ErrorOr.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/ErrorOr.h?rev=174552&r1=174551&r2=174552&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/ErrorOr.h (original)
+++ llvm/trunk/include/llvm/Support/ErrorOr.h Wed Feb  6 16:28:53 2013
@@ -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!");

Modified: llvm/trunk/unittests/Support/ErrorOrTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrorOrTest.cpp?rev=174552&r1=174551&r2=174552&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/ErrorOrTest.cpp (original)
+++ llvm/trunk/unittests/Support/ErrorOrTest.cpp Wed Feb  6 16:28:53 2013
@@ -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 {





More information about the llvm-commits mailing list