diff --git a/libcxx/include/optional b/libcxx/include/optional index 9eed886aa4636..f7e12f84beba0 100644 --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -893,6 +893,10 @@ private: template constexpr static bool __libcpp_opt_ref_ctor_deleted = is_lvalue_reference_v<_Tp> && reference_constructs_from_temporary_v<_Tp, _Up>; + + template + constexpr static bool __ref_ctor_enabled = + is_lvalue_reference_v<_Tp> && !reference_constructs_from_temporary_v<_Tp, _Up>; # endif // LWG2756: conditionally explicit conversion from _Up @@ -1000,7 +1004,7 @@ public: template ::template __enable_implicit<_Up>(), int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) # if _LIBCPP_STD_VER >= 26 - noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>) + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, const _Up&>) # endif { this->__construct_from(__v); @@ -1008,7 +1012,7 @@ public: template ::template __enable_explicit<_Up>(), int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) # if _LIBCPP_STD_VER >= 26 - noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>) + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, const _Up&>) # endif { this->__construct_from(__v); @@ -1046,25 +1050,25 @@ public: // optional(optional& rhs) template - requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&> + requires __ref_ctor_enabled<_Up&> && (!is_same_v, optional<_Up>>) && (!is_same_v<_Tp&, _Up>) && + is_constructible_v<_Tp&, _Up&> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up&, _Tp&>) optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) { this->__construct_from(__rhs); } template - requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v, optional<_Up>>) && + requires __libcpp_opt_ref_ctor_deleted<_Up&> && (!is_same_v, optional<_Up>>) && (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&> constexpr explicit optional(optional<_Up>& __rhs) noexcept = delete; // optional(const optional&) template ::template __enable_implicit<_Up>(), int> = 0> - requires __libcpp_opt_ref_ctor_deleted<_Up> + requires __libcpp_opt_ref_ctor_deleted optional(const optional<_Up>&) = delete; template ::template __enable_explicit<_Up>(), int> = 0> - requires __libcpp_opt_ref_ctor_deleted<_Up> + requires __libcpp_opt_ref_ctor_deleted explicit optional(const optional<_Up>&) = delete; // optional(optional&&) @@ -1078,16 +1082,16 @@ public: // optional(const optional&&) template - requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up> + requires __ref_ctor_enabled && (!is_same_v, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, const _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v) optional(const optional<_Up>&& __v) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) { this->__construct_from(std::move(__v)); } template - requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up> + requires __libcpp_opt_ref_ctor_deleted && (!is_same_v, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, const _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>&& __v) noexcept = delete; # endif diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp index 597110bcb54fe..844317c8570d9 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp @@ -151,6 +151,37 @@ constexpr bool test_ref() { assert(*o2 == 1); } + { + const std::optional o1{2}; + std::optional o2(o1); + assert(*o2 == 2); + assert(&(*o2) == &(*o1)); + } + + { + const std::optional> o1({1, 2}); + std::optional o2(o1); + assert(o2.has_value()); + assert(&(*o2) == &o1->lvalue); + assert(*o2 == 1); + } + + { + const std::optional> o1({1, 2}); + std::optional o2(std::move(o1)); + assert(o2.has_value()); + assert(&(*o2) == &o1->rvalue); + assert(*o2 == 2); + } + + { + const std::optional> o1({1, 2}); + ASSERT_NOT_NOEXCEPT(std::optional(o1)); + ASSERT_NOT_NOEXCEPT(std::optional(std::move(o1))); + } + + static_assert(!std::is_constructible_v, const std::optional>&&>); + return true; } #endif diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp index 39a80efa475f7..03082033cd4dc 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp @@ -144,6 +144,36 @@ constexpr bool test_ref() { assert(*o2 == 1); } + { + std::optional o1(1); + std::optional o2(o1); + assert(o2.has_value()); + assert(*o2 == 1); + assert(&(*o2) == &(*o1)); + } + + { + std::optional> o1({1, 2}); + std::optional o2(o1); + assert(o2.has_value()); + assert(*o2 == 1); + assert(&(*o2) == &o1->lvalue); + } + + { + std::optional> o1({1, 2}); + std::optional o2(std::move(o1)); + assert(o2.has_value()); + assert(*o2 == 2); + assert(&(*o2) == &o1->rvalue); + } + + { + std::optional> o1({1, 2}); + ASSERT_NOT_NOEXCEPT(std::optional(o1)); + ASSERT_NOT_NOEXCEPT(std::optional(std::move(o1))); + } + return true; } #endif @@ -164,6 +194,11 @@ int main(int, char**) { test(std::move(rhs), true); } +#if TEST_STD_VER >= 26 + // GH: #194415 + static_assert(!std::is_constructible_v, std::optional>&>); +#endif + static_assert(!(std::is_constructible, optional>::value), ""); #if TEST_STD_VER >= 26 diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp index 53ac77a2e5620..d4c95c302d817 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp @@ -29,12 +29,10 @@ void test() { const std::optional co(1); std::optional o0(1); - // expected-error-re@*:* 10 {{call to deleted constructor of 'std::optional<{{.*}}>'}} + // expected-error-re@*:* 8 {{call to deleted constructor of 'std::optional<{{.*}}>'}} std::optional o1{1}; // optional(U&&) - std::optional o2{o0}; // optional(optional&) - std::optional o3{co}; // optional(const optional&) - std::optional o4{std::move(o0)}; // optional(optional&&&) - std::optional o5{std::move(co)}; // optional(optional&&&) + std::optional o4{std::move(o0)}; // optional(optional&&) + std::optional o5{std::move(co)}; // optional(optional&&) std::optional o6{1}; // optional(U&&) std::optional o7{o0}; // optional(optional&) diff --git a/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h b/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h index 704d99acb15e9..d9b17a0b91f3b 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h +++ b/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h @@ -21,8 +21,9 @@ struct ReferenceConversion { constexpr ReferenceConversion(T lval, T rval) : lvalue(lval), rvalue(rval) {} constexpr operator T&() & noexcept { return lvalue; } - + constexpr operator const T&() const& noexcept { return lvalue; } constexpr operator T&() && noexcept { return rvalue; } + constexpr operator const T&() const&& noexcept { return rvalue; } }; template @@ -42,6 +43,14 @@ struct ReferenceConversionThrows { return lvalue; } + constexpr operator const T&() const& { + if (throws) { + TEST_THROW(1); + } + + return lvalue; + } + constexpr operator T&() && { if (throws) { TEST_THROW(2); @@ -49,6 +58,34 @@ struct ReferenceConversionThrows { return rvalue; } + + constexpr operator const T&() const&& { + if (throws) { + TEST_THROW(2); + } + + return rvalue; + } +}; + +template +struct LValueOnly { + T val{}; + + constexpr operator T&() & noexcept { return val; } + constexpr operator T&() const& = delete; + constexpr operator T&() && = delete; + constexpr operator T&() const&& = delete; +}; + +template +struct ConstRValueOnly { + mutable T val{}; + + constexpr operator T&() & = delete; + constexpr operator T&() const& = delete; + constexpr operator T&() && = delete; + constexpr operator T&() const&& { return val; }; }; #endif