OptionalStorage implementation for trivial type, take III

This is another attempt at implementating optional storage
for trivially copyable type, using an union instead of a
raw buffer to hold the actual storage. This make it possible
to get rid of the reinterpret_cast, and hopefully to fix the UB
of the previous attempts.

This validates fine on my laptop for gcc 8.2 and gcc 4.8, I'll
revert if it breaks the validation.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354137 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/ADT/Optional.h b/include/llvm/ADT/Optional.h
index 25a3185..55bbfc5 100644
--- a/include/llvm/ADT/Optional.h
+++ b/include/llvm/ADT/Optional.h
@@ -109,6 +109,54 @@
   }
 };
 
+template <typename T> struct OptionalStorage<T, true> {
+  struct empty_type {};
+  union {
+    empty_type empty;
+    T value;
+  };
+  bool hasVal = false;
+
+  OptionalStorage() : empty{} {}
+
+  OptionalStorage(const T &y) : hasVal(true) {
+    new ((void*)std::addressof(value)) T(y);
+  }
+  OptionalStorage(const OptionalStorage &O) = default;
+  OptionalStorage(T &&y) : hasVal(true) {
+    new ((void*)std::addressof(value)) T(std::move(y));
+  }
+
+  OptionalStorage(OptionalStorage &&O) = default;
+
+  OptionalStorage &operator=(T &&y) {
+    hasVal = true;
+    new ((void*)std::addressof(value)) T(std::move(y));
+    return *this;
+  }
+  OptionalStorage &operator=(OptionalStorage &&O) = default;
+
+  OptionalStorage &operator=(const T &y) {
+    hasVal = true;
+    new ((void*)std::addressof(value)) T(y);
+    return *this;
+  }
+  OptionalStorage &operator=(const OptionalStorage &O) = default;
+
+  ~OptionalStorage() = default;
+
+  T *getPointer() {
+    assert(hasVal);
+    return &value;
+  }
+  const T *getPointer() const {
+    assert(hasVal);
+    return &value;
+  }
+
+  void reset() { hasVal = false; }
+};
+
 } // namespace optional_detail
 
 template <typename T> class Optional {
@@ -153,11 +201,11 @@
 
   const T *getPointer() const {
     assert(Storage.hasVal);
-    return reinterpret_cast<const T *>(Storage.storage.buffer);
+    return Storage.getPointer();
   }
   T *getPointer() {
     assert(Storage.hasVal);
-    return reinterpret_cast<T *>(Storage.storage.buffer);
+    return Storage.getPointer();
   }
   const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
   T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }