diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 3c7175c73f21e..f3e75ebd115d7 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -480,6 +480,8 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_not_fn`` ``202306L`` ---------------------------------------------------------- ----------------- + ``__cpp_lib_optional`` ``202506L`` + ---------------------------------------------------------- ----------------- ``__cpp_lib_optional_range_support`` ``202406L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_out_ptr`` ``202311L`` diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index b5dcfc7dfef31..87f5af06d6c65 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -40,6 +40,7 @@ Implemented Papers - P2321R2: ``zip`` (`Github `__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release) +- P2988R12: ``std::optional`` (`Github `__) - P3044R2: sub-``string_view`` from ``string`` (`Github `__) - P3168R2: Give ``std::optional`` Range Support (`Github `__) diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 9e1678f22c4be..00a48c5fdab6d 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -122,7 +122,7 @@ "`P3293R3 `__","Splicing a base class subobject","2025-06 (Sofia)","","","`#148125 `__","" "`P3491R3 `__","``define_static_{string,object,array}``","2025-06 (Sofia)","","","`#148126 `__","" "`P3096R12 `__","Function Parameter Reflection in Reflection for C++26","2025-06 (Sofia)","","","`#148127 `__","" -"`P2988R12 `__","``std::optional``","2025-06 (Sofia)","","","`#148131 `__","" +"`P2988R12 `__","``std::optional``","2025-06 (Sofia)","|Complete|","22","`#148131 `__","" "`P3348R4 `__","C++26 should refer to C23 not C17","2025-06 (Sofia)","","","`#148133 `__","" "`P3037R6 `__","``constexpr`` ``std::shared_ptr`` and friends","2025-06 (Sofia)","","","`#148135 `__","" "`P3284R4 `__","``write_env`` and ``unstoppable`` Sender Adaptors","2025-06 (Sofia)","","","`#148136 `__","" diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 7610586ddecbb..8e5c7388812d3 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -117,8 +117,8 @@ class __wrap_iter { friend class span; template friend struct array; - template - friend class optional; + template + friend struct __optional_iterator; }; template diff --git a/libcxx/include/optional b/libcxx/include/optional index ef1bfd3ec44c0..59a4247457edf 100644 --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -240,6 +240,7 @@ namespace std { # include <__type_traits/is_trivially_relocatable.h> # include <__type_traits/is_unbounded_array.h> # include <__type_traits/negation.h> +# include <__type_traits/reference_constructs_from_temporary.h> # include <__type_traits/remove_const.h> # include <__type_traits/remove_cv.h> # include <__type_traits/remove_cvref.h> @@ -265,6 +266,11 @@ namespace std { _LIBCPP_PUSH_MACROS # include <__undef_macros> +# if _LIBCPP_STD_VER >= 26 +# define _LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_TP, _UP) \ + requires(is_lvalue_reference_v<_TP> && reference_constructs_from_temporary_v<_TP, _UP>) +# endif + namespace std // purposefully not using versioning namespace { @@ -412,37 +418,18 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> { } }; -// optional is currently required to be ill-formed. However, it may -// be allowed in the future. For this reason, it has already been implemented -// to ensure we can make the change in an ABI-compatible manner. template struct __optional_storage_base<_Tp, true> { using value_type = _Tp; using __raw_type _LIBCPP_NODEBUG = remove_reference_t<_Tp>; __raw_type* __value_; - template - static _LIBCPP_HIDE_FROM_ABI constexpr bool __can_bind_reference() { - using _RawUp = __libcpp_remove_reference_t<_Up>; - using _UpPtr = _RawUp*; - using _RawTp = __libcpp_remove_reference_t<_Tp>; - using _TpPtr = _RawTp*; - using _CheckLValueArg = - integral_constant::value && is_convertible<_UpPtr, _TpPtr>::value) || - is_same<_RawUp, reference_wrapper<_RawTp>>::value || - is_same<_RawUp, reference_wrapper<__remove_const_t<_RawTp>>>::value >; - return (is_lvalue_reference<_Tp>::value && _CheckLValueArg::value) || - (is_rvalue_reference<_Tp>::value && !is_lvalue_reference<_Up>::value && - is_convertible<_UpPtr, _TpPtr>::value); - } - _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {} template _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg) : __value_(std::addressof(__uarg)) { - static_assert(__can_bind_reference<_UArg>(), + static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>, "Attempted to construct a reference element in tuple from a " "possible temporary"); } @@ -458,7 +445,7 @@ struct __optional_storage_base<_Tp, true> { template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) { _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage"); - static_assert(__can_bind_reference<_UArg>(), + static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>, "Attempted to construct a reference element in tuple from a " "possible temporary"); __value_ = std::addressof(__val); @@ -607,19 +594,19 @@ struct __is_std_optional : false_type {}; template struct __is_std_optional> : true_type {}; -template -class _LIBCPP_DECLSPEC_EMPTY_BASES optional - : private __optional_move_assign_base<_Tp>, - private __optional_sfinae_ctor_base_t<_Tp>, - private __optional_sfinae_assign_base_t<_Tp> { - using __base _LIBCPP_NODEBUG = __optional_move_assign_base<_Tp>; +template +struct __optional_iterator {}; - using __pointer _LIBCPP_NODEBUG = std::add_pointer_t<_Tp>; - using __const_pointer _LIBCPP_NODEBUG = std::add_pointer_t; +template +struct __optional_iterator< + _Tp, + enable_if_t && is_function_v<__libcpp_remove_reference_t<_Tp>>) && + !(is_lvalue_reference_v<_Tp> && is_array_v<__libcpp_remove_reference_t<_Tp>>)> > { +private: + using __pointer _LIBCPP_NODEBUG = std::add_pointer_t>; + using __const_pointer _LIBCPP_NODEBUG = std::add_pointer_t>; public: - using value_type = _Tp; - # if _LIBCPP_STD_VER >= 26 # ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL using iterator = __bounded_iter<__wrap_iter<__pointer>>; @@ -628,18 +615,80 @@ public: using iterator = __wrap_iter<__pointer>; using const_iterator = __wrap_iter<__const_pointer>; # endif + + // [optional.iterators], iterator support + _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept { + auto& __derived_self = static_cast&>(*this); + auto __ptr = [&__derived_self]() { + if constexpr (is_lvalue_reference_v<_Tp>) { + return __derived_self.has_value() ? std::addressof(__derived_self.__get()) : nullptr; + } + return std::addressof(__derived_self.__get()); + }(); + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + return std::__make_bounded_iter( + std::__wrap_iter<__pointer>(__ptr), + std::__wrap_iter<__pointer>(__ptr), + std::__wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)); +# else + return iterator(__ptr); +# endif + } + + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { + auto& __derived_self = static_cast&>(*this); + auto* __ptr = [&__derived_self]() { + if constexpr (is_lvalue_reference_v<_Tp>) { + return __derived_self.has_value() ? std::addressof(__derived_self.__get()) : nullptr; + } + return std::addressof(__derived_self.__get()); + }(); + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + return std::__make_bounded_iter( + std::__wrap_iter<__const_pointer>(__ptr), + std::__wrap_iter<__const_pointer>(__ptr), + std::__wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)); +# else + return const_iterator(__ptr); +# endif + } + + _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept { + return begin() + (static_cast&>(*this).has_value() ? 1 : 0); + } + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { + return begin() + (static_cast&>(*this).has_value() ? 1 : 0); + } # endif +}; + +template +class _LIBCPP_DECLSPEC_EMPTY_BASES optional + : private __optional_move_assign_base<_Tp>, + private __optional_sfinae_ctor_base_t<_Tp>, + private __optional_sfinae_assign_base_t<_Tp>, + public __optional_iterator<_Tp> { + using __base _LIBCPP_NODEBUG = __optional_move_assign_base<_Tp>; + +public: + using value_type = _Tp; + using __trivially_relocatable _LIBCPP_NODEBUG = conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>; using __replaceable _LIBCPP_NODEBUG = conditional_t<__is_replaceable_v<_Tp>, optional, void>; private: - // Disable the reference extension using this static assert. static_assert(!is_same_v<__remove_cvref_t, in_place_t>, "instantiation of optional with in_place_t is ill-formed"); static_assert(!is_same_v<__remove_cvref_t, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed"); - static_assert(!is_reference_v, "instantiation of optional with a reference type is ill-formed"); +# if _LIBCPP_STD_VER >= 26 + static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed"); +# else + static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed"); +# endif static_assert(is_destructible_v, "instantiation of optional with a non-destructible type is ill-formed"); static_assert(!is_array_v, "instantiation of optional with an array type is ill-formed"); @@ -754,6 +803,41 @@ public: this->__construct_from(std::move(__v)); } + // deleted optional constructors +# if _LIBCPP_STD_VER >= 26 + template &, _Args...>, int> = 0> + _LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_Tp, _Up) + _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) = delete; + + template ::template __enable_implicit<_Up>(), int> = 0> + _LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_Tp, _Up) + _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) = delete; + + template , + enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0> + _LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_Tp, _Up) + _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) = delete; + + template ::template __enable_implicit<_Up>(), int> = 0> + _LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_Tp, _Up) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) = delete; + + template ::template __enable_explicit<_Up>(), int> = 0> + _LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_Tp, _Up) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) = delete; + + template ::template __enable_implicit<_Up>(), int> = 0> + _LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_Tp, _Up) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v) = delete; + + template ::template __enable_explicit<_Up>(), int> = 0> + _LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_Tp, _Up) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v) = delete; +# endif + # if _LIBCPP_STD_VER >= 23 template &, _Args...>, int> = 0> + enable_if_t&, _Args...> +# if _LIBCPP_STD_VER >= 26 + && !reference_constructs_from_temporary_v<_Tp&, _Up> +# endif + , + int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { reset(); this->__construct(__il, std::forward<_Args>(__args)...); @@ -833,34 +922,6 @@ public: } } -# if _LIBCPP_STD_VER >= 26 - // [optional.iterators], iterator support - _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept { -# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL - return std::__make_bounded_iter( - std::__wrap_iter<__pointer>(std::addressof(this->__get())), - std::__wrap_iter<__pointer>(std::addressof(this->__get())), - std::__wrap_iter<__pointer>(std::addressof(this->__get()) + (this->has_value() ? 1 : 0))); -# else - return iterator(std::addressof(this->__get())); -# endif - } - - _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { -# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL - return std::__make_bounded_iter( - std::__wrap_iter<__const_pointer>(std::addressof(this->__get())), - std::__wrap_iter<__const_pointer>(std::addressof(this->__get())), - std::__wrap_iter<__const_pointer>(std::addressof(this->__get()) + (this->has_value() ? 1 : 0))); -# else - return const_iterator(std::addressof(this->__get())); -# endif - } - - _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept { return begin() + (this->has_value() ? 1 : 0); } - _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { return begin() + (this->has_value() ? 1 : 0); } -# endif - _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t operator->() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); return std::addressof(this->__get()); @@ -921,6 +982,10 @@ public: } template > +# if _LIBCPP_STD_VER >= 26 + requires(!(is_lvalue_reference_v<_Tp> && is_function_v<__libcpp_remove_reference_t<_Tp>>) && + !(is_lvalue_reference_v<_Tp> && is_array_v<__libcpp_remove_reference_t<_Tp>>)) +# endif _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Up&& __v) const& { static_assert(is_copy_constructible_v, "optional::value_or: T must be copy constructible"); static_assert(is_convertible_v<_Up, value_type>, "optional::value_or: U must be convertible to T"); @@ -928,12 +993,26 @@ public: } template > +# if _LIBCPP_STD_VER >= 26 + requires(!is_lvalue_reference_v<_Tp>) +# endif _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Up&& __v) && { static_assert(is_move_constructible_v, "optional::value_or: T must be move constructible"); static_assert(is_convertible_v<_Up, value_type>, "optional::value_or: U must be convertible to T"); return this->has_value() ? std::move(this->__get()) : static_cast(std::forward<_Up>(__v)); } +# if _LIBCPP_STD_VER >= 26 + template > + requires(is_lvalue_reference_v<_Tp> && + !(is_function_v<__libcpp_remove_reference_t<_Tp>> || is_array_v<__libcpp_remove_reference_t<_Tp>>)) + _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Up&& __v) && { + static_assert(is_move_constructible_v, "optional::value_or: T must be move constructible"); + static_assert(is_convertible_v<_Up, value_type>, "optional::value_or: U must be convertible to T"); + return this->has_value() ? this->__get() : static_cast(std::forward<_Up>(__v)); + } +# endif + # if _LIBCPP_STD_VER >= 23 template _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { diff --git a/libcxx/include/version b/libcxx/include/version index a132f0808aeb8..5f780dbb6fbda 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -184,7 +184,8 @@ __cpp_lib_nonmember_container_access 201411L __cpp_lib_not_fn 202306L 201603L // C++17 __cpp_lib_null_iterators 201304L -__cpp_lib_optional 202110L +__cpp_lib_optional 202506L + 202110L // C++23 202106L // C++20 201606L // C++17 __cpp_lib_optional_range_support 202406L @@ -586,6 +587,8 @@ __cpp_lib_void_t 201411L # define __cpp_lib_mdspan 202406L # undef __cpp_lib_not_fn # define __cpp_lib_not_fn 202306L +# undef __cpp_lib_optional +# define __cpp_lib_optional 202506L # define __cpp_lib_optional_range_support 202406L # undef __cpp_lib_out_ptr # define __cpp_lib_out_ptr 202311L diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp index 3cdd7553e2e5d..b604579e43557 100644 --- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp +++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp @@ -23,8 +23,7 @@ concept has_iterator_aliases = requires { static_assert(has_iterator_aliases>); static_assert(has_iterator_aliases>); - -// TODO: Uncomment these once P2988R12 is implemented, as they would be testing optional - -// static_assert(!has_iterator_aliases>); -// static_assert(!has_iterator_aliases>); +static_assert(has_iterator_aliases>); +static_assert(has_iterator_aliases>); +static_assert(!has_iterator_aliases>); +static_assert(!has_iterator_aliases>); diff --git a/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/value_or.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/value_or.compile.pass.cpp new file mode 100644 index 0000000000000..25df0dd6c1936 --- /dev/null +++ b/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/value_or.compile.pass.cpp @@ -0,0 +1,28 @@ + +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template T optional::value_or(U&&); + +#include +#include + +template +concept has_value_or = requires(Opt opt, T&& t) { + { opt.value_or(t) } -> std::same_as; +}; + +static_assert(has_value_or, int>); +static_assert(has_value_or, int&>); +static_assert(has_value_or, const int&>); +static_assert(!has_value_or&&, int (&)[1]>); +static_assert(!has_value_or&&, int (&)()>); diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp index aca6290f5a4bf..c4e652979a4e6 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp @@ -142,8 +142,8 @@ # ifndef __cpp_lib_optional # error "__cpp_lib_optional should be defined in c++26" # endif -# if __cpp_lib_optional != 202110L -# error "__cpp_lib_optional should have the value 202110L in c++26" +# if __cpp_lib_optional != 202506L +# error "__cpp_lib_optional should have the value 202506L in c++26" # endif # ifndef __cpp_lib_optional_range_support diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index 6aa704a3ead3f..8bb2a5656a65f 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -7453,8 +7453,8 @@ # ifndef __cpp_lib_optional # error "__cpp_lib_optional should be defined in c++26" # endif -# if __cpp_lib_optional != 202110L -# error "__cpp_lib_optional should have the value 202110L in c++26" +# if __cpp_lib_optional != 202506L +# error "__cpp_lib_optional should have the value 202506L in c++26" # endif # ifndef __cpp_lib_optional_range_support diff --git a/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp index df95a8df3793f..81234525923a1 100644 --- a/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp @@ -21,7 +21,8 @@ template constexpr bool test() { - std::optional opt{T{}}; + std::remove_reference_t t = std::remove_reference_t{}; + std::optional opt{t}; { // begin() is marked noexcept static_assert(noexcept(opt.begin())); @@ -53,6 +54,10 @@ constexpr bool tests() { assert(test()); assert(test()); assert(test()); + assert(test()); + assert(test()); + assert(test()); + assert(test()); return true; } diff --git a/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp index 966c3e7441880..c62c9fc7746d6 100644 --- a/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include template @@ -41,7 +42,8 @@ constexpr bool test() { assert(it2 == std::as_const(disengaged).end()); } - std::optional engaged{T{}}; + std::remove_reference_t t = std::remove_reference_t{}; + std::optional engaged{t}; { // end() != begin() if the optional is engaged auto it = engaged.end(); @@ -62,6 +64,10 @@ constexpr bool tests() { assert(test()); assert(test()); assert(test()); + assert(test()); + assert(test()); + assert(test()); + assert(test()); return true; } diff --git a/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp index 1203290a0290a..34d0d6b135564 100644 --- a/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp @@ -20,9 +20,10 @@ #include #include -template +template __val> constexpr bool test() { - std::optional opt{__val}; + std::remove_reference_t v{__val}; + std::optional opt{v}; { // Dereferencing an iterator of an engaged optional will return the same value that the optional holds. auto it = opt.begin(); @@ -41,13 +42,14 @@ constexpr bool test() { assert(std::random_access_iterator); } - { // const_iterator::value_type == std::remove_cv_t, const_iterator::reference == const T&, iterator::value_type = std::remove_cv_t, iterator::reference == T& + { // const_iterator::value_type == std::remove_cvref_t, const_iterator::reference == const T&, iterator::value_type = std::remove_cvref_t, iterator::reference == T& + // std::remove_cv_t is impossible for optional auto it = opt.begin(); auto it2 = std::as_const(opt).begin(); - assert((std::is_same_v>)); - assert((std::is_same_v)); - assert((std::is_same_v>)); - assert((std::is_same_v)); + assert((std::is_same_v>)); + assert((std::is_same_v&>)); + assert((std::is_same_v>)); + assert((std::is_same_v&>)); } { // std::ranges::size for an engaged optional == 1, disengaged optional == 0 @@ -68,13 +70,13 @@ constexpr bool test() { // An optional with value that is reset will have a begin() == end(), then when it is reassigned a value, // begin() != end(), and *begin() will contain the new value. { - std::optional val{__val}; + std::optional val{v}; assert(val.begin() != val.end()); val.reset(); assert(val.begin() == val.end()); - val.emplace(__val); + val.emplace(v); assert(val.begin() != val.end()); - assert(*(val.begin()) == __val); + assert(*(val.begin()) == v); } return true; @@ -86,6 +88,11 @@ constexpr bool tests() { assert((test())); assert((test())); assert((test())); + assert((test())); + assert((test())); + assert((test())); + assert((test())); + assert((test())); return true; } diff --git a/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp b/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp index 97305d976e066..133eed4a606bb 100644 --- a/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp @@ -16,6 +16,7 @@ // template constexpr auto and_then(F&&) const&&; #include +#include #include #include "test_macros.h" @@ -257,8 +258,94 @@ constexpr bool test() { return true; } +#if TEST_STD_VER >= 26 +constexpr bool test_ref() { + // Test & overload + { + // Without & qualifier on F's operator() + { + int j = 42; + std::optional i{j}; + std::same_as> decltype(auto) r = i.and_then(LVal{}); + + assert(r == 1); + assert(i.and_then(NOLVal{}) == std::nullopt); + } + + //With & qualifier on F's operator() + { + int j = 42; + std::optional i{j}; + RefQual l{}; + NORefQual nl{}; + std::same_as> decltype(auto) r = i.and_then(l); + + assert(r == 1); + assert(i.and_then(nl) == std::nullopt); + } + } + + // Test const& overload + { + // Without & qualifier on F's operator() + { + int j = 42; + std::optional i{j}; + std::same_as> decltype(auto) r = i.and_then(CLVal{}); + + assert(r == 1); + assert(i.and_then(NOCLVal{}) == std::nullopt); + } + + //With & qualifier on F's operator() + { + int j = 42; + const std::optional i{j}; + const CRefQual l{}; + const NOCRefQual nl{}; + std::same_as> decltype(auto) r = i.and_then(l); + + assert(r == 1); + assert(i.and_then(nl) == std::nullopt); + } + } + // Test && overload + { + //With & qualifier on F's operator() + { + int j = 42; + std::optional i{j}; + std::same_as> decltype(auto) r = i.and_then(RVRefQual{}); + + assert(r == 1); + assert(i.and_then(NORVRefQual{}) == std::nullopt); + } + } + + // Test const&& overload + { + //With & qualifier on F's operator() + { + int j = 42; + const std::optional i{j}; + const RVCRefQual l{}; + const NORVCRefQual nl{}; + std::same_as> decltype(auto) r = i.and_then(std::move(l)); + + assert(r == 1); + assert(i.and_then(std::move(nl)) == std::nullopt); + } + } + return true; +} +#endif + int main(int, char**) { test(); static_assert(test()); +#if TEST_STD_VER >= 26 + test_ref(); + static_assert(test_ref()); +#endif return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp b/libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp index ccc94ab9be2cb..de0a67c1579ee 100644 --- a/libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp @@ -62,6 +62,32 @@ constexpr bool test() { return std::optional{}; }); } +#if TEST_STD_VER >= 26 + { + int i = 2; + std::optional opt; + assert(opt.or_else([&] { return std::optional{i}; }) == i); + int j = 3; + opt = j; + opt.or_else([] { + assert(false); + return std::optional{}; + }); + assert(opt == j); + } + { + int i = 2; + std::optional opt; + assert(std::move(opt).or_else([&] { return std::optional{i}; }) == i); + int j = 3; + opt = j; + std::move(opt).or_else([] { + assert(false); + return std::optional{}; + }); + assert(opt == j); + } +#endif return true; } diff --git a/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp b/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp index 0a151517b101c..ad2713f2ac5b8 100644 --- a/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp @@ -17,62 +17,64 @@ #include "test_macros.h" #include +#include #include #include +#include struct LVal { constexpr int operator()(int&) { return 1; } - int operator()(const int&) = delete; - int operator()(int&&) = delete; + int operator()(const int&) = delete; + int operator()(int&&) = delete; int operator()(const int&&) = delete; }; struct CLVal { int operator()(int&) = delete; constexpr int operator()(const int&) { return 1; } - int operator()(int&&) = delete; + int operator()(int&&) = delete; int operator()(const int&&) = delete; }; struct RVal { - int operator()(int&) = delete; + int operator()(int&) = delete; int operator()(const int&) = delete; constexpr int operator()(int&&) { return 1; } int operator()(const int&&) = delete; }; struct CRVal { - int operator()(int&) = delete; + int operator()(int&) = delete; int operator()(const int&) = delete; - int operator()(int&&) = delete; + int operator()(int&&) = delete; constexpr int operator()(const int&&) { return 1; } }; struct RefQual { constexpr int operator()(int) & { return 1; } - int operator()(int) const& = delete; - int operator()(int) && = delete; + int operator()(int) const& = delete; + int operator()(int) && = delete; int operator()(int) const&& = delete; }; struct CRefQual { int operator()(int) & = delete; constexpr int operator()(int) const& { return 1; } - int operator()(int) && = delete; + int operator()(int) && = delete; int operator()(int) const&& = delete; }; struct RVRefQual { - int operator()(int) & = delete; + int operator()(int) & = delete; int operator()(int) const& = delete; constexpr int operator()(int) && { return 1; } int operator()(int) const&& = delete; }; struct RVCRefQual { - int operator()(int) & = delete; + int operator()(int) & = delete; int operator()(int) const& = delete; - int operator()(int) && = delete; + int operator()(int) && = delete; constexpr int operator()(int) const&& { return 1; } }; @@ -83,7 +85,7 @@ struct NoCopy { }; struct NoMove { - NoMove() = default; + NoMove() = default; NoMove(NoMove&&) = delete; NoMove operator()(const NoCopy&&) { return NoMove{}; } }; @@ -200,8 +202,111 @@ constexpr bool test() { return true; } +#if TEST_STD_VER >= 26 +constexpr bool test_ref() { + { + std::optional opt1; + std::same_as> decltype(auto) opt1r = opt1.transform([](int i) { return i + 2; }); + assert(!opt1); + assert(!opt1r); + } + + { + int i = 42; + std::optional opt{i}; + std::same_as> decltype(auto) o2 = opt.transform([](int j) { return j + 2; }); + + assert(*o2 == 44); + } + // Test & overload + { + // Without & qualifier on F's operator() + { + int i = 42; + std::optional opt{i}; + std::same_as> decltype(auto) o3 = opt.transform(LVal{}); + + assert(*o3 == 1); + } + + //With & qualifier on F's operator() + { + int i = 42; + std::optional opt{i}; + RefQual l{}; + std::same_as> decltype(auto) o3 = opt.transform(l); + + assert(*o3 == 1); + } + } + // const& overload + { + // Without & qualifier on F's operator() + { + int i = 42; + std::optional opt{i}; + std::same_as> decltype(auto) o3 = std::as_const(opt).transform(CLVal{}); + + assert(*o3 == 1); + } + + //With & qualifier on F's operator() + { + int i = 42; + const std::optional opt{i}; + const CRefQual l{}; + std::same_as> decltype(auto) o3 = opt.transform(l); + + assert(*o3 == 1); + } + } + + // Test && overload + { + // Without & qualifier on F's operator() + { + int i = 42; + std::optional opt{i}; + std::same_as> decltype(auto) o3 = std::move(opt).transform(RVal{}); + + assert(*o3 == 1); + } + + //With & qualifier on F's operator() + { + int i = 42; + std::optional opt{i}; + std::same_as> decltype(auto) o3 = std::move(opt).transform(RVRefQual{}); + assert(*o3 == 1); + } + } + + // const&& overload + { + //With & qualifier on F's operator() + { + int i = 42; + std::optional opt{i}; + const RVCRefQual rvc{}; + std::same_as> decltype(auto) o3 = opt.transform(std::move(rvc)); + assert(*o3 == 1); + } + } + { + std::optional o6 = std::nullopt; + auto o6r = o6.transform([](int) { return 42; }); + assert(!o6r); + } + return true; +} +#endif + int main(int, char**) { test(); static_assert(test()); +#if TEST_STD_VER >= 26 + test_ref(); + static_assert(test_ref()); +#endif return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp index eaca111b72dca..dda461e89e48e 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp @@ -250,6 +250,36 @@ constexpr T pr38638(T v) return *o + 2; } +#if TEST_STD_VER >= 26 + +template _Val> +constexpr void test_with_ref() { + T t{_Val}; + { // to empty + optional opt; + opt = t; + assert(static_cast(opt) == true); + assert(*opt == t); + } + { // to existing + optional opt{t}; + opt = t; + assert(static_cast(opt) == true); + assert(*opt == t); + } + { // test default argument + optional opt; + opt = {t}; + assert(static_cast(opt) == true); + assert(*opt == t); + } + { // test default argument + optional opt{t}; + opt = {}; + assert(static_cast(opt) == false); + } +} +#endif int main(int, char**) { @@ -281,5 +311,8 @@ int main(int, char**) static_assert(pr38638(3) == 5, ""); - return 0; +#if TEST_STD_VER >= 26 + test_with_ref(); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp index 245d8ff3d2146..69709a07616a4 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp @@ -221,6 +221,24 @@ TEST_CONSTEXPR_CXX20 bool test_empty_emplace() { return true; } +#if TEST_STD_VER >= 26 +template _Val> +constexpr bool test_ref() { + using Opt = std::optional; + T t{_Val}; + { + Opt opt; + auto& v = opt.emplace(t); + static_assert(std::is_same_v, ""); + assert(static_cast(opt) == true); + assert(*opt == t); + assert(&v == &*opt); + assert(&t == &*opt); + } + return true; +} +#endif + int main(int, char**) { { @@ -291,6 +309,11 @@ int main(int, char**) } } #endif - - return 0; +#if TEST_STD_VER >= 26 + static_assert(test_ref()); + static_assert(test_ref()); + assert((test_ref())); + assert((test_ref())); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ctor.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ctor.verify.cpp index 775d2bde7d13d..c5281783d4350 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ctor.verify.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ctor.verify.cpp @@ -23,18 +23,26 @@ struct NonDestructible { ~NonDestructible() = delete; }; int main(int, char**) { - { - std::optional o1; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a reference type is ill-formed}} - std::optional o2; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} - std::optional o3; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with an array type is ill-formed}} - } - - { + { +#if TEST_STD_VER >= 26 + std::optional + opt2; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with an rvalue reference type is ill-formed}} +#else + std::optional + o1; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a reference type is ill-formed}} +#endif + std::optional + o2; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} + std::optional + o3; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with an array type is ill-formed}} + } + + { std::optional< std::in_place_t> o1; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} std::optional o2; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} std::optional< volatile std::in_place_t> o3; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} std::optional o4; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} - } + } { std::optional< std::nullopt_t> o1; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} 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 new file mode 100644 index 0000000000000..08141137d353d --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// optional + +#include +#include + +struct X { + int i; + + X(int j) : i(j) {} +}; + +int main(int, char**) { + const std::optional _co(1); + std::optional _o(1); + + // expected-error-re@*:* 8 {{call to deleted constructor of 'std::optional<{{.*}}>'}} + std::optional o1{1}; // optional(U&&) + std::optional o2{std::optional(1)}; // optional(optional&&) + std::optional o3{_co}; // optional(const optional&) + std::optional o4{_o}; // optional(optional&) + std::optional o5{1}; // optional(U&&) + std::optional o6{std::optional(1)}; // optional(optional&&) + std::optional o7{_co}; // optional(const optional&) + std::optional o8{_o}; // optional(optional&) +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_t.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_t.pass.cpp new file mode 100644 index 0000000000000..3ef41f6784615 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_t.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +#include +#include +#include +#include + +template _Val> +constexpr bool test() { + std::remove_reference_t item{_Val}; + std::optional opt{item}; + + { + assert(*opt == item); + assert(&(*opt) == &item); + } + { + assert(*std::as_const(opt) == item); + assert(&(*std::as_const(opt)) == &item); + } + + return true; +} + +int main(int, char**) { + static_assert((test())); + static_assert((test())); + assert((test())); + assert((test())); +} diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp index c0044276ea9ad..a14e2dc21649a 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp @@ -11,9 +11,9 @@ // ~optional(); +#include #include #include -#include #include "test_macros.h" @@ -64,6 +64,12 @@ int main(int, char**) } assert(X::dtor_called == true); } - - return 0; +#if TEST_STD_VER >= 26 + { + typedef int& T; + static_assert(std::is_trivially_destructible::value, ""); + static_assert(std::is_trivially_destructible>::value, ""); + } +#endif + return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp index 7029b37cbecd7..e23e481f6a05d 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp @@ -69,5 +69,16 @@ int main(int, char**) X::dtor_called = false; } - return 0; +#if TEST_STD_VER >= 26 + { + X x{}; + optional opt(x); + X::dtor_called = false; + opt.reset(); + assert(X::dtor_called == false); + assert(static_cast(opt) == false); + } +#endif + + return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference.pass.cpp index 49b4d21a28066..6c1bf8aa15a8d 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference.pass.cpp @@ -50,7 +50,19 @@ int main(int, char**) optional opt(X{}); assert((*opt).test() == 4); } +#if TEST_STD_VER >= 26 + { + X x{}; + optional opt(x); + ASSERT_SAME_TYPE(decltype(*opt), X&); + ASSERT_NOEXCEPT(*opt); + } + { + X x{}; + optional opt(x); + assert((*opt).test() == 4); + } +#endif static_assert(test() == 7, ""); - return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const.pass.cpp index ff86d9534faf6..d2ebafbc3adbb 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const.pass.cpp @@ -43,6 +43,25 @@ int main(int, char**) constexpr optional opt(X{}); static_assert((*opt).test() == 3, ""); } +#if TEST_STD_VER >= 26 + { + X x{}; + const optional opt{x}; + ASSERT_SAME_TYPE(decltype(*opt), X&); + ASSERT_NOEXCEPT(*opt); + } + { + X x{}; + const optional opt{x}; + ASSERT_SAME_TYPE(decltype(*opt), const X&); + ASSERT_NOEXCEPT(*opt); + } + { + static constexpr X x{}; + constexpr optional opt(x); + static_assert((*opt).test() == 3, ""); + } +#endif { constexpr optional opt(Y{}); assert((*opt).test() == 2); diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/has_value.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/has_value.pass.cpp index 6998e023022c5..038de500070fb 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/has_value.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/has_value.pass.cpp @@ -33,6 +33,13 @@ int main(int, char**) constexpr optional opt(0); static_assert(opt.has_value(), ""); } +#if TEST_STD_VER >= 26 + { + static constexpr int i = 0; + constexpr optional opt{i}; + static_assert(opt.has_value(), ""); + } +#endif - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow.pass.cpp index 2b5fba546ef42..96d22743ac7fe 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow.pass.cpp @@ -19,9 +19,9 @@ using std::optional; -struct X -{ - int test() noexcept {return 3;} +struct X { + int test() noexcept { return 3; } + int test() const noexcept { return 3; } }; struct Y @@ -47,6 +47,30 @@ int main(int, char**) optional opt(X{}); assert(opt->test() == 3); } +#if TEST_STD_VER >= 26 + { + X x{}; + std::optional opt(x); + ASSERT_SAME_TYPE(decltype(opt.operator->()), X*); + ASSERT_NOEXCEPT(opt.operator->()); + } + { + X x{}; + std::optional opt(x); + ASSERT_SAME_TYPE(decltype(opt.operator->()), const X*); + ASSERT_NOEXCEPT(opt.operator->()); + } + { + X x{}; + optional opt{x}; + assert(opt->test() == 3); + } + { + X x{}; + optional opt{x}; + assert(opt->test() == 3); + } +#endif { static_assert(test() == 3, ""); } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow_const.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow_const.pass.cpp index d8ce932bd7810..5154679cb6435 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow_const.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow_const.pass.cpp @@ -54,6 +54,25 @@ int main(int, char**) constexpr optional opt(Z{}); static_assert(opt->test() == 1, ""); } +#if TEST_STD_VER >= 26 + { + X x{}; + const std::optional opt(x); + ASSERT_SAME_TYPE(decltype(opt.operator->()), X*); + ASSERT_NOEXCEPT(opt.operator->()); + } + { + X x{}; + const std::optional opt(x); + ASSERT_SAME_TYPE(decltype(opt.operator->()), const X*); + ASSERT_NOEXCEPT(opt.operator->()); + } + { + static constexpr Z z{}; + constexpr optional opt(z); + static_assert(opt->test() == 1, ""); + } +#endif return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value.pass.cpp index 781784c6806a4..22b74f5512d53 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value.pass.cpp @@ -56,6 +56,14 @@ int main(int, char**) opt.emplace(); assert(opt.value().test() == 4); } +#if TEST_STD_VER >= 26 + { + X x; + optional opt{x}; + ASSERT_NOT_NOEXCEPT(opt.value()); + ASSERT_SAME_TYPE(decltype(opt.value()), X&); + } +#endif #ifndef TEST_HAS_NO_EXCEPTIONS { optional opt; diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp index 8c063ae1a799c..66890ff9c9b91 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp @@ -80,6 +80,14 @@ constexpr int test() assert((std::move(opt).value_or({2, 3}) == Z{2, 3})); assert(!opt); } +#if TEST_STD_VER >= 26 + { + int y = 2; + optional opt; + assert(std::move(opt).value_or(y) == 2); + assert(!opt); + } +#endif return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp index ec42890a3b995..6bd308b405605 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp @@ -79,6 +79,12 @@ int main(int, char**) const optional opt; assert(opt.value_or({Y(3)}) == 4); } - - return 0; +#if TEST_STD_VER >= 26 + { + X y{3}; + const optional opt; + assert(opt.value_or(y) == 3); + } +#endif + return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp index a96c3c648f939..d226695d3109f 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp @@ -13,6 +13,8 @@ #include +#include "test_macros.h" + using std::optional; struct X @@ -25,9 +27,14 @@ int main(int, char**) { using std::optional; { - // expected-error-re@optional:* 2 {{static assertion failed{{.*}}instantiation of optional with a reference type is ill-formed}} - optional opt1; - optional opt2; +#if TEST_STD_VER >= 26 + // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with an rvalue reference type is ill-formed}} + optional opt2; +#else + // expected-error-re@optional:* 2 {{static assertion failed{{.*}}instantiation of optional with a reference type is ill-formed}} + optional opt1; + optional opt2; +#endif } { // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 5d469d4914b0b..cf1becaac4985 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1005,6 +1005,7 @@ def add_version_header(tc): "c++17": 201606, "c++20": 202106, # P2231R1 Missing constexpr in std::optional and std::variant "c++23": 202110, # P0798R8 Monadic operations for std::optional + LWG3621 Remove feature-test macro __cpp_lib_monadic_optional + "c++26": 202506, # P2988R12: std::optional }, "headers": ["optional"], },