diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 3c635e5e46bbd..28e8f805e1843 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -476,7 +476,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_not_fn`` ``202306L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_optional_range_support`` *unimplemented* + ``__cpp_lib_optional_range_support`` ``202406L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_out_ptr`` ``202311L`` ---------------------------------------------------------- ----------------- diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 2b5bc489dd44c..1a6f73da993cb 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -117,6 +117,10 @@ class __wrap_iter { friend class span; template friend struct array; +#if _LIBCPP_STD_VER >= 26 + template + friend class optional; +#endif }; template diff --git a/libcxx/include/optional b/libcxx/include/optional index fa32d75ef86dd..25856cb56d75a 100644 --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -102,6 +102,8 @@ namespace std { class optional { public: using value_type = T; + using iterator = implementation-defined; // see [optional.iterators] // since C++26 + using const_iterator = implementation-defined; // see [optional.iterators] // since C++26 // [optional.ctor], constructors constexpr optional() noexcept; @@ -135,6 +137,12 @@ namespace std { // [optional.swap], swap void swap(optional &) noexcept(see below ); // constexpr in C++20 + // [optional.iterators], iterator support + constexpr iterator begin() noexcept; // since C++26 + constexpr const_iterator begin() const noexcept; // since C++26 + constexpr iterator end() noexcept; // since C++26 + constexpr const_iterator end() const noexcept; // since C++26 + // [optional.observe], observers constexpr T const *operator->() const noexcept; constexpr T *operator->() noexcept; @@ -173,6 +181,11 @@ namespace std { template optional(T) -> optional; + template + constexpr bool ranges::enable_view> = true; // since C++26 + template + constexpr auto format_kind> = range_format::disabled; // since C++26 + } // namespace std */ @@ -187,10 +200,12 @@ namespace std { # include <__concepts/invocable.h> # include <__config> # include <__exception/exception.h> +# include <__format/range_default_formatter.h> # include <__functional/hash.h> # include <__functional/invoke.h> # include <__functional/unary_function.h> # include <__fwd/functional.h> +# include <__iterator/wrap_iter.h> # include <__memory/addressof.h> # include <__memory/construct_at.h> # include <__tuple/sfinae_helpers.h> @@ -578,6 +593,16 @@ struct __is_std_optional : false_type {}; template struct __is_std_optional> : true_type {}; +# if _LIBCPP_STD_VER >= 26 + +template +constexpr bool ranges::enable_view> = true; + +template +constexpr auto format_kind> = range_format::disabled; + +# endif + template class _LIBCPP_DECLSPEC_EMPTY_BASES optional : private __optional_move_assign_base<_Tp>, @@ -588,6 +613,11 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional public: using value_type = _Tp; +# if _LIBCPP_STD_VER >= 26 + using iterator = __wrap_iter<_Tp*>; + using const_iterator = __wrap_iter; +# endif // _LIBCPP_STD_VER >= 26 + 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>; @@ -976,6 +1006,27 @@ public: } # endif // _LIBCPP_STD_VER >= 23 +// P3168R2 +# if _LIBCPP_STD_VER >= 26 + + _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() { + if (!this->has_value()) + return end(); + return iterator(static_cast<_Tp*>(this->__get())); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const { + if (!this->has_value()) + return end(); + return const_iterator(static_cast(this->__get())); + } + + _LIBCPP_HIDE_FROM_ABI constexpr iterator end() { return iterator(static_cast<_Tp*>(nullptr)); } + + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const { return const_iterator(static_cast(nullptr)); } + +# endif // _LIBCPP_STD_VER >= 26 + using __base::reset; }; diff --git a/libcxx/include/version b/libcxx/include/version index 91fe48351e161..6096185efc865 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -581,7 +581,7 @@ __cpp_lib_void_t 201411L # define __cpp_lib_mdspan 202406L # undef __cpp_lib_not_fn # define __cpp_lib_not_fn 202306L -// # define __cpp_lib_optional_range_support 202406L +# define __cpp_lib_optional_range_support 202406L # undef __cpp_lib_out_ptr # define __cpp_lib_out_ptr 202311L // # define __cpp_lib_philox_engine 202406L 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 32685972d6019..ece2fe81b7c13 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 @@ -152,17 +152,11 @@ # error "__cpp_lib_optional should have the value 202110L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_optional_range_support -# error "__cpp_lib_optional_range_support should be defined in c++26" -# endif -# if __cpp_lib_optional_range_support != 202406L -# error "__cpp_lib_optional_range_support should have the value 202406L in c++26" -# endif -# else -# ifdef __cpp_lib_optional_range_support -# error "__cpp_lib_optional_range_support should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_optional_range_support +# error "__cpp_lib_optional_range_support should be defined in c++26" +# endif +# if __cpp_lib_optional_range_support != 202406L +# error "__cpp_lib_optional_range_support should have the value 202406L in c++26" # endif #endif // TEST_STD_VER > 23 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 e546719142231..09063e5a80e17 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 @@ -7377,17 +7377,11 @@ # error "__cpp_lib_optional should have the value 202110L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_optional_range_support -# error "__cpp_lib_optional_range_support should be defined in c++26" -# endif -# if __cpp_lib_optional_range_support != 202406L -# error "__cpp_lib_optional_range_support should have the value 202406L in c++26" -# endif -# else -# ifdef __cpp_lib_optional_range_support -# error "__cpp_lib_optional_range_support should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_optional_range_support +# error "__cpp_lib_optional_range_support should be defined in c++26" +# endif +# if __cpp_lib_optional_range_support != 202406L +# error "__cpp_lib_optional_range_support should have the value 202406L in c++26" # endif # ifndef __cpp_lib_out_ptr diff --git a/libcxx/test/std/utilities/optional/optional.range/enable_ranges_view.compile.pass.cpp b/libcxx/test/std/utilities/optional/optional.range/enable_ranges_view.compile.pass.cpp new file mode 100644 index 0000000000000..2337e93e22128 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.range/enable_ranges_view.compile.pass.cpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: std-at-least-c++26 + +#include +#include + +int main() { + static_assert(std::ranges::enable_view>); + return 0; +} diff --git a/libcxx/test/std/utilities/optional/optional.range/format_kind.compile.pass.cpp b/libcxx/test/std/utilities/optional/optional.range/format_kind.compile.pass.cpp new file mode 100644 index 0000000000000..3d812f251fc75 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.range/format_kind.compile.pass.cpp @@ -0,0 +1,14 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: std-at-least-c++26 + +#include +#include + +static_assert(std::format_kind>); diff --git a/libcxx/test/std/utilities/optional/optional.range/iteration.pass.cpp b/libcxx/test/std/utilities/optional/optional.range/iteration.pass.cpp new file mode 100644 index 0000000000000..41139544a68b4 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.range/iteration.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: std-at-least-c++26 + +#include +#include + +constexpr bool test() { + constexpr std::optional val = 2; + for (const auto& elem : val) + if (elem != 2) + return false; + return true; +} + +int main() { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/optional/optional.range/iterator_types.compile.pass.cpp b/libcxx/test/std/utilities/optional/optional.range/iterator_types.compile.pass.cpp new file mode 100644 index 0000000000000..277264d0d9b54 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.range/iterator_types.compile.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: std-at-least-c++26 + +#include +#include +#include +#include + +using iterator = std::optional::iterator; +using const_iterator = std::optional::const_iterator; + +// iterator + +static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); +static_assert(std::is_same_v::value_type, int>); +static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(std::is_same_v::pointer, int*>); +static_assert(std::is_same_v::reference, int&>); +static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + +// const iterator + +static_assert(std::random_access_iterator); +static_assert(std::contiguous_iterator); +static_assert(std::is_same_v::value_type, int>); +static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(std::is_same_v::pointer, int*>); +static_assert(std::is_same_v::reference, int&>); +static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); diff --git a/libcxx/test/std/utilities/optional/optional.range/runtime_error.verify.cpp b/libcxx/test/std/utilities/optional/optional.range/runtime_error.verify.cpp new file mode 100644 index 0000000000000..c0ed1a4b62426 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.range/runtime_error.verify.cpp @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: std-at-least-c++26 + +#include "assert_macros.h" +#include + +int main() { + std::optional val = 2; + auto end = val.end(); + TEST_DOES_NOT_THROW(*end); + return 0; +} diff --git a/libcxx/test/std/utilities/optional/optional.range/satisfies_range_concept.compile.pass.cpp b/libcxx/test/std/utilities/optional/optional.range/satisfies_range_concept.compile.pass.cpp new file mode 100644 index 0000000000000..8559526074b97 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.range/satisfies_range_concept.compile.pass.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: std-at-least-c++26 + +#include +#include + +static_assert(std::ranges::sized_range>); +static_assert(std::ranges::common_range>); +static_assert(std::ranges::contiguous_range>); diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index edd7b124a1fb3..7be4880428d58 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1004,7 +1004,6 @@ def add_version_header(tc): "name": "__cpp_lib_optional_range_support", "values": {"c++26": 202406}, # P3168R2 Give std::optional Range Support "headers": ["optional"], - "unimplemented": True, }, { "name": "__cpp_lib_out_ptr",