[PATCH] D32385: [libcxx] Implement LWG 2900 "The copy and move constructors of optional are not constexpr"
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&& rhs); +// constexpr optional(const optional&& rhs); +// If is_trivially_move_constructible_v is true, +//this constructor shall be a constexpr constructor. + #include #include @@ -131,6 +134,31 @@ #endif } +constexpr bool test_constexpr() +{ +{ +using T = int; +optional o1{}; +optional o2 = std::move(o1); +static_cast(o2); +optional o3{T{42}}; +optional o4 = std::move(o3); +static_cast(o4); +} +{ +struct T { +constexpr T(int) {} +T(T&&) = default; +}; +optional o1{}; +optional o2 = std::move(o1); +static_cast(o2); +optional o3{T{42}}; +optional o4 = std::move(o3); +static_cast(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(const optional& rhs); +// constexpr optional(const optional& rhs); +// If is_trivially_copy_constructible_v is true, +//this constructor shall be a constexpr constructor. #include #include @@ -104,6 +106,31 @@ #endif } +constexpr bool test_constexpr() +{ +{ +using T = int; +optional o1{}; +optional o2 = o1; +static_cast(o2); +optional o3{T{42}}; +optional o4 = o3; +static_cast(o4); +} +{ +struct T { +constexpr T(int) {} +}; +optional o1{}; +optional o2 = o1; +static_cast(o2); +optional o3{T{42}}; +optional o4 = o3; +static_cast(o4); +} +return true; +} + int main() { test(); @@ -152,4 +179,7 @@ { test_reference_extension(); } +{ +static_assert(test_constexpr(), ""); +} } Index: include/optional === --- include/optional +++ include/optional @@ -436,46 +436,122 @@ } }; -template ::value> -struct __optional_storage; - -template -struct __optional_storage<_Tp, true> : __optional_storage_base<_Tp> +template ::value> +struct __optional_copy_base : __optional_storage_base<_Tp> { using __optional_storage_base<_Tp>::__optional_storage_base; }; template -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 ::value> +struct __optional_move_base : __optional_copy_base<_Tp> +{ +using __optional_copy_base<_Tp>::__optional_copy_base; +}; + +template +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; +
[PATCH] D32385: [libcxx] Implement LWG 2900 "The copy and move constructors of optional are not constexpr"
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&& rhs); +// constexpr optional(const optional&& rhs); +// If is_trivially_move_constructible_v is true, +//this constructor shall be a constexpr constructor. + #include #include @@ -131,6 +134,31 @@ #endif } +constexpr bool test_constexpr() +{ +{ +using T = int; +optional o1{}; +optional o2 = std::move(o1); +static_cast(o2); +optional o3{T{42}}; +optional o4 = std::move(o3); +static_cast(o4); +} +{ +struct T { +constexpr T(int) {} +T(T&&) = default; +}; +optional o1{}; +optional o2 = std::move(o1); +static_cast(o2); +optional o3{T{42}}; +optional o4 = std::move(o3); +static_cast(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(const optional& rhs); +// constexpr optional(const optional& rhs); +// If is_trivially_copy_constructible_v is true, +//this constructor shall be a constexpr constructor. #include #include @@ -104,6 +106,31 @@ #endif } +constexpr bool test_constexpr() +{ +{ +using T = int; +optional o1{}; +optional o2 = o1; +static_cast(o2); +optional o3{T{42}}; +optional o4 = o3; +static_cast(o4); +} +{ +struct T { +constexpr T(int) {} +}; +optional o1{}; +optional o2 = o1; +static_cast(o2); +optional o3{T{42}}; +optional o4 = o3; +static_cast(o4); +} +return true; +} + int main() { test(); @@ -152,4 +179,7 @@ { test_reference_extension(); } +{ +static_assert(test_constexpr(), ""); +} } Index: include/optional === --- include/optional +++ include/optional @@ -436,46 +436,118 @@ } }; -template ::value> -struct __optional_storage; - -template -struct __optional_storage<_Tp, true> : __optional_storage_base<_Tp> +template ::value> +struct __optional_copy_base : __optional_storage_base<_Tp> { using __optional_storage_base<_Tp>::__optional_storage_base; }; template -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 ::value> +struct __optional_move_base : __optional_copy_base<_Tp> +{ +using __optional_copy_base<_Tp>::__optional_copy_base; +}; + +template +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_IN