CaseyCarter created this revision. .. by injecting base classes that differentiate between trivial/non-trivial implementation of each copy/move constructor/assignment. This actually goes a bit beyond the PR by also making the copy/move assignment operators trivial when the base type has corresponding trivial construction and assignment.
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,118 @@ } }; -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_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_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 +570,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