CaseyCarter updated this revision to Diff 96644.
CaseyCarter added a comment.

Assigning an empty optional to a non-empty optional needs to destroy the 
contained value, so we need to also require `is_trivially_destructible` to 
implement trivial assignments.


https://reviews.llvm.org/D32385

Files:
  include/optional
  test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
  test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp

Index: test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
===================================================================
--- test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
+++ test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
@@ -10,7 +10,10 @@
 // UNSUPPORTED: c++98, c++03, c++11, c++14
 // <optional>
 
-// optional(optional<T>&& rhs);
+// constexpr optional(const optional<T>&& rhs);
+//   If is_trivially_move_constructible_v<T> is true,
+//    this constructor shall be a constexpr constructor.
+
 
 #include <optional>
 #include <type_traits>
@@ -131,6 +134,31 @@
 #endif
 }
 
+constexpr bool test_constexpr()
+{
+    {
+        using T = int;
+        optional<T> o1{};
+        optional<T> o2 = std::move(o1);
+        static_cast<void>(o2);
+        optional<T> o3{T{42}};
+        optional<T> o4 = std::move(o3);
+        static_cast<void>(o4);
+    }
+    {
+        struct T {
+            constexpr T(int) {}
+            T(T&&) = default;
+        };
+        optional<T> o1{};
+        optional<T> o2 = std::move(o1);
+        static_cast<void>(o2);
+        optional<T> o3{T{42}};
+        optional<T> o4 = std::move(o3);
+        static_cast<void>(o4);
+    }
+    return true;
+}
 
 int main()
 {
@@ -198,4 +226,7 @@
     {
         test_reference_extension();
     }
+    {
+        static_assert(test_constexpr(), "");
+    }
 }
Index: test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
===================================================================
--- test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
+++ test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
@@ -10,7 +10,9 @@
 // UNSUPPORTED: c++98, c++03, c++11, c++14
 // <optional>
 
-// optional(const optional<T>& rhs);
+// constexpr optional(const optional<T>& rhs);
+//   If is_trivially_copy_constructible_v<T> is true,
+//    this constructor shall be a constexpr constructor.
 
 #include <optional>
 #include <type_traits>
@@ -104,6 +106,31 @@
 #endif
 }
 
+constexpr bool test_constexpr()
+{
+    {
+        using T = int;
+        optional<T> o1{};
+        optional<T> o2 = o1;
+        static_cast<void>(o2);
+        optional<T> o3{T{42}};
+        optional<T> o4 = o3;
+        static_cast<void>(o4);
+    }
+    {
+        struct T {
+            constexpr T(int) {}
+        };
+        optional<T> o1{};
+        optional<T> o2 = o1;
+        static_cast<void>(o2);
+        optional<T> o3{T{42}};
+        optional<T> o4 = o3;
+        static_cast<void>(o4);
+    }
+    return true;
+}
+
 int main()
 {
     test<int>();
@@ -152,4 +179,7 @@
     {
         test_reference_extension();
     }
+    {
+        static_assert(test_constexpr(), "");
+    }
 }
Index: include/optional
===================================================================
--- include/optional
+++ include/optional
@@ -436,46 +436,122 @@
     }
 };
 
-template <class _Tp, bool = is_trivially_copyable<_Tp>::value>
-struct __optional_storage;
-
-template <class _Tp>
-struct __optional_storage<_Tp, true> : __optional_storage_base<_Tp>
+template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
+struct __optional_copy_base : __optional_storage_base<_Tp>
 {
     using __optional_storage_base<_Tp>::__optional_storage_base;
 };
 
 template <class _Tp>
-struct __optional_storage<_Tp, false> : __optional_storage_base<_Tp>
+struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp>
 {
-    using value_type = _Tp;
     using __optional_storage_base<_Tp>::__optional_storage_base;
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage() = default;
+    __optional_copy_base() = default;
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage(const __optional_storage& __opt)
+    __optional_copy_base(const __optional_copy_base& __opt)
     {
         this->__construct_from(__opt);
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage(__optional_storage&& __opt)
+    __optional_copy_base(__optional_copy_base&&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_base& operator=(const __optional_copy_base&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_base& operator=(__optional_copy_base&&) = default;
+};
+
+template <class _Tp, bool = is_trivially_move_constructible<_Tp>::value>
+struct __optional_move_base : __optional_copy_base<_Tp>
+{
+    using __optional_copy_base<_Tp>::__optional_copy_base;
+};
+
+template <class _Tp>
+struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp>
+{
+    using value_type = _Tp;
+    using __optional_copy_base<_Tp>::__optional_copy_base;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_base() = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_base(const __optional_move_base&) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_base(__optional_move_base&& __opt)
         noexcept(is_nothrow_move_constructible_v<value_type>)
     {
         this->__construct_from(_VSTD::move(__opt));
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage& operator=(const __optional_storage& __opt)
+    __optional_move_base& operator=(const __optional_move_base&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_base& operator=(__optional_move_base&&) = default;
+};
+
+template <class _Tp, bool =
+    is_trivially_destructible<_Tp>::value &&
+    is_trivially_copy_constructible<_Tp>::value &&
+    is_trivially_copy_assignable<_Tp>::value>
+struct __optional_copy_assign_base : __optional_move_base<_Tp>
+{
+    using __optional_move_base<_Tp>::__optional_move_base;
+};
+
+template <class _Tp>
+struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp>
+{
+    using __optional_move_base<_Tp>::__optional_move_base;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_assign_base() = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_assign_base(const __optional_copy_assign_base&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_assign_base(__optional_copy_assign_base&&) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_assign_base& operator=(const __optional_copy_assign_base& __opt)
     {
         this->__assign_from(__opt);
         return *this;
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage& operator=(__optional_storage&& __opt)
+    __optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default;
+};
+
+template <class _Tp, bool =
+    is_trivially_destructible<_Tp>::value &&
+    is_trivially_move_constructible<_Tp>::value &&
+    is_trivially_move_assignable<_Tp>::value>
+struct __optional_move_assign_base : __optional_copy_assign_base<_Tp>
+{
+    using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
+};
+
+template <class _Tp>
+struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp>
+{
+    using value_type = _Tp;
+    using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base() = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base(const __optional_move_assign_base& __opt) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base(__optional_move_assign_base&&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base& operator=(__optional_move_assign_base&& __opt)
         noexcept(is_nothrow_move_assignable_v<value_type> &&
                  is_nothrow_move_constructible_v<value_type>)
     {
@@ -498,11 +574,11 @@
 
 template <class _Tp>
 class optional
-    : private __optional_storage<_Tp>
+    : private __optional_move_assign_base<_Tp>
     , private __optional_sfinae_ctor_base_t<_Tp>
     , private __optional_sfinae_assign_base_t<_Tp>
 {
-    using __base = __optional_storage<_Tp>;
+    using __base = __optional_move_assign_base<_Tp>;
 public:
     using value_type = _Tp;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to