Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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``
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/22.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Implemented Papers

- P2321R2: ``zip`` (`Github <https://llvm.org/PR105169>`__) (The paper is partially implemented. ``zip_transform_view``
is implemented in this release)
- P2988R12: ``std::optional<T&>`` (`Github <https://llvm.org/PR148131>`__)
- P3044R2: sub-``string_view`` from ``string`` (`Github <https://llvm.org/PR148140>`__)
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)

Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
"`P3293R3 <https://wg21.link/P3293R3>`__","Splicing a base class subobject","2025-06 (Sofia)","","","`#148125 <https://github.com/llvm/llvm-project/issues/148125>`__",""
"`P3491R3 <https://wg21.link/P3491R3>`__","``define_static_{string,object,array}``","2025-06 (Sofia)","","","`#148126 <https://github.com/llvm/llvm-project/issues/148126>`__",""
"`P3096R12 <https://wg21.link/P3096R12>`__","Function Parameter Reflection in Reflection for C++26","2025-06 (Sofia)","","","`#148127 <https://github.com/llvm/llvm-project/issues/148127>`__",""
"`P2988R12 <https://wg21.link/P2988R12>`__","``std::optional<T&>``","2025-06 (Sofia)","","","`#148131 <https://github.com/llvm/llvm-project/issues/148131>`__",""
"`P2988R12 <https://wg21.link/P2988R12>`__","``std::optional<T&>``","2025-06 (Sofia)","|Complete|","22","`#148131 <https://github.com/llvm/llvm-project/issues/148131>`__",""
"`P3348R4 <https://wg21.link/P3348R4>`__","C++26 should refer to C23 not C17","2025-06 (Sofia)","","","`#148133 <https://github.com/llvm/llvm-project/issues/148133>`__",""
"`P3037R6 <https://wg21.link/P3037R6>`__","``constexpr`` ``std::shared_ptr`` and friends","2025-06 (Sofia)","","","`#148135 <https://github.com/llvm/llvm-project/issues/148135>`__",""
"`P3284R4 <https://wg21.link/P3284R4>`__","``write_env`` and ``unstoppable`` Sender Adaptors","2025-06 (Sofia)","","","`#148136 <https://github.com/llvm/llvm-project/issues/148136>`__",""
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__iterator/wrap_iter.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ class __wrap_iter {
friend class span;
template <class _Tp, size_t _Size>
friend struct array;
template <class _Tp>
friend class optional;
template <class _Tp, class>
friend struct __optional_iterator;
};

template <class _Iter1>
Expand Down
215 changes: 152 additions & 63 deletions libcxx/include/optional
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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
{

Expand Down Expand Up @@ -410,39 +416,25 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> {
__construct(std::forward<_That>(__opt).__get());
}
}

template <class _Up>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from_val(_Up&& __val){
this->__get() = std::forward<_Up>(__val);
}
};

// optional<T&> 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 <class _Tp>
struct __optional_storage_base<_Tp, true> {
using value_type = _Tp;
using __raw_type _LIBCPP_NODEBUG = remove_reference_t<_Tp>;
__raw_type* __value_;

template <class _Up>
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<bool,
(is_lvalue_reference<_Up>::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 <class _UArg>
_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");
}
Expand All @@ -458,7 +450,7 @@ struct __optional_storage_base<_Tp, true> {
template <class _UArg>
_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);
Expand All @@ -482,6 +474,11 @@ struct __optional_storage_base<_Tp, true> {
__construct(std::forward<_That>(__opt).__get());
}
}

template <class _Up>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from_val(_Up&& __val){
__value_ = std::addressof(__val);
}
};

template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
Expand Down Expand Up @@ -607,19 +604,19 @@ struct __is_std_optional : false_type {};
template <class _Tp>
struct __is_std_optional<optional<_Tp>> : true_type {};

template <class _Tp>
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 <class _Tp, class = void>
struct __optional_iterator {};

using __pointer _LIBCPP_NODEBUG = std::add_pointer_t<_Tp>;
using __const_pointer _LIBCPP_NODEBUG = std::add_pointer_t<const _Tp>;
template <class _Tp>
struct __optional_iterator<
_Tp,
enable_if_t<!(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>>)> > {
private:
using __pointer _LIBCPP_NODEBUG = std::add_pointer_t<remove_reference_t<_Tp>>;
using __const_pointer _LIBCPP_NODEBUG = std::add_pointer_t<const remove_reference_t<_Tp>>;

public:
using value_type = _Tp;

# if _LIBCPP_STD_VER >= 26
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
using iterator = __bounded_iter<__wrap_iter<__pointer>>;
Expand All @@ -628,18 +625,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<optional<_Tp>&>(*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<const optional<_Tp>&>(*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<optional<_Tp>&>(*this).has_value() ? 1 : 0);
}
_LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept {
return begin() + (static_cast<const optional<_Tp>&>(*this).has_value() ? 1 : 0);
}
# endif
};

template <class _Tp>
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<value_type>, in_place_t>,
"instantiation of optional with in_place_t is ill-formed");
static_assert(!is_same_v<__remove_cvref_t<value_type>, nullopt_t>,
"instantiation of optional with nullopt_t is ill-formed");
static_assert(!is_reference_v<value_type>, "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<value_type>, "instantiation of optional with a non-destructible type is ill-formed");
static_assert(!is_array_v<value_type>, "instantiation of optional with an array type is ill-formed");

Expand Down Expand Up @@ -754,6 +813,41 @@ public:
this->__construct_from(std::move(__v));
}

// deleted optional<T&> constructors
# if _LIBCPP_STD_VER >= 26
template <class _Up,
class... _Args,
enable_if_t<is_constructible_v<value_type, initializer_list<_Up>&, _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 <class _Up = value_type,
enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0>
_LIBCPP_OPT_REF_DELETED_CONS_REQUIRES(_Tp, _Up)
_LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) = delete;

template <class _Up = remove_cv_t<_Tp>,
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 <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::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 <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::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 <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::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 <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::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 <class _Tag,
class _Fp,
Expand All @@ -780,7 +874,7 @@ public:
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(_Up&& __v) {
if (this->has_value())
this->__get() = std::forward<_Up>(__v);
this->__assign_from_val(std::forward<_Up>(__v));
else
this->__construct(std::forward<_Up>(__v));
return *this;
Expand Down Expand Up @@ -809,7 +903,12 @@ public:

template <class _Up,
class... _Args,
enable_if_t<is_constructible_v<value_type, initializer_list<_Up>&, _Args...>, int> = 0>
enable_if_t<is_constructible_v<value_type, initializer_list<_Up>&, _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)...);
Expand All @@ -833,34 +932,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<value_type const> operator->() const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
return std::addressof(this->__get());
Expand Down Expand Up @@ -921,19 +992,37 @@ public:
}

template <class _Up = remove_cv_t<_Tp>>
# 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<value_type>, "optional<T>::value_or: T must be copy constructible");
static_assert(is_convertible_v<_Up, value_type>, "optional<T>::value_or: U must be convertible to T");
return this->has_value() ? this->__get() : static_cast<value_type>(std::forward<_Up>(__v));
}

template <class _Up = remove_cv_t<_Tp>>
# 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<value_type>, "optional<T>::value_or: T must be move constructible");
static_assert(is_convertible_v<_Up, value_type>, "optional<T>::value_or: U must be convertible to T");
return this->has_value() ? std::move(this->__get()) : static_cast<value_type>(std::forward<_Up>(__v));
}

# if _LIBCPP_STD_VER >= 26
template <class _Up = remove_cv_t<_Tp>>
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<value_type>, "optional<T>::value_or: T must be move constructible");
static_assert(is_convertible_v<_Up, value_type>, "optional<T>::value_or: U must be convertible to T");
return this->has_value() ? this->__get() : static_cast<value_type>(std::forward<_Up>(__v));
}
# endif

# if _LIBCPP_STD_VER >= 23
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
Expand Down
5 changes: 4 additions & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ __cpp_lib_nonmember_container_access 201411L <array> <deque>
__cpp_lib_not_fn 202306L <functional>
201603L // C++17
__cpp_lib_null_iterators 201304L <iterator>
__cpp_lib_optional 202110L <optional>
__cpp_lib_optional 202506L <optional>
202110L // C++23
202106L // C++20
201606L // C++17
__cpp_lib_optional_range_support 202406L <optional>
Expand Down Expand Up @@ -586,6 +587,8 @@ __cpp_lib_void_t 201411L <type_traits>
# 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
Expand Down
Loading
Loading