[libcxx-commits] [libcxx] 9f5efd5 - [libc++] Correct `optional<T&>` implementation (#174537)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jan 9 00:33:15 PST 2026
Author: William Tran-Viet
Date: 2026-01-09T16:33:10+08:00
New Revision: 9f5efd5d03710480e5bf29ffa79d556d0d90f456
URL: https://github.com/llvm/llvm-project/commit/9f5efd5d03710480e5bf29ffa79d556d0d90f456
DIFF: https://github.com/llvm/llvm-project/commit/9f5efd5d03710480e5bf29ffa79d556d0d90f456.diff
LOG: [libc++] Correct `optional<T&>` implementation (#174537)
Resolves #174350
- Several issues were found in the current implementation of
`optional<T&>`
- `value()`, `operator*()`, `and_then()`, `transform()`, `operator->()`
still provided their ref-qualified versions for rvalues and `const&`.
- Using the listed methods on an rvalue `optional<T&>` would cause a
compile failure due to a mismatch in return types.
- On the latter, `operator*`, `operator->` would return `const` for a
`optional<T&>`, which is an incorrect deep const.
- A few constructors were missing (`optional<U>&`), and most
constructors relevant to `optional<T&>` were missing `noexcept`
- Constructors and `emplace` were not correctly constructing a `T&` as
specified in _`convert-ref-init-val`_
- Also corrects the behavior of `value_or` which should return
`remove_cv_t<T>` (in our case `decay_t<_Tp>`)
- Add several test cases to verify behavior, update `value_or` tests
Added:
libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.verify.cpp
libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h
Modified:
libcxx/include/optional
libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/value_or.compile.pass.cpp
libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp
libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp
libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/U.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/in_place_t.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/bool.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const_rvalue.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_rvalue.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/has_value.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow_const.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const_rvalue.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp
libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 568c86556d156..91c0167ae8f06 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -477,14 +477,21 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> {
}
}
- template <class _Up>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from_val(_Up&& __val) {
- this->__get() = std::forward<_Up>(__val);
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
+ __swap(__optional_storage_base& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) {
using std::swap;
- swap(this->__get(), __rhs.__get());
+ if (this->has_value() == __rhs.has_value()) {
+ if (this->has_value())
+ swap(this->__get(), __rhs.__get());
+ } else {
+ if (this->has_value()) {
+ __rhs.__construct(std::move(this->__get()));
+ this->reset();
+ } else {
+ this->__construct(std::move(__rhs.__get()));
+ __rhs.reset();
+ }
+ }
}
};
@@ -496,21 +503,25 @@ struct __optional_storage_base<_Tp, true> {
_LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {}
+ template <class _Up>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __convert_init_ref_val(_Up&& __val) noexcept {
+ _Tp& __r(std::forward<_Up>(__val));
+ __value_ = std::addressof(__r);
+ }
+
template <class _UArg>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg)
- : __value_(std::addressof(__uarg)) {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg) {
static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>,
"Attempted to construct a reference element in optional from a "
"possible temporary");
+ __convert_init_ref_val(std::forward<_UArg>(__uarg));
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { __value_ = nullptr; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; }
- _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const& noexcept { return *__value_; }
-
- _LIBCPP_HIDE_FROM_ABI constexpr value_type&& __get() const&& noexcept { return std::forward<value_type>(*__value_); }
+ _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const noexcept { return *__value_; }
template <class _UArg>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) {
@@ -518,7 +529,7 @@ struct __optional_storage_base<_Tp, true> {
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);
+ __convert_init_ref_val(std::forward<_UArg>(__val));
}
template <class _That>
@@ -540,11 +551,6 @@ struct __optional_storage_base<_Tp, true> {
}
}
- template <class _Up>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from_val(_Up&& __val) noexcept {
- __value_ = std::addressof(__val);
- }
-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) noexcept {
std::swap(__value_, __rhs.__value_);
}
@@ -706,7 +712,7 @@ struct __optional_iterator {};
# if _LIBCPP_STD_VER >= 26
template <class _Tp>
-struct __optional_iterator<_Tp, enable_if_t<!is_lvalue_reference_v<_Tp>>> {
+struct __optional_iterator<_Tp, enable_if_t<is_object_v<_Tp>>> {
private:
using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>;
@@ -909,38 +915,61 @@ public:
: __base(in_place, __il, std::forward<_Args>(__args)...) {}
template <class _Up = _Tp, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>)
+# endif
+ : __base(in_place, std::forward<_Up>(__v)) {
+ }
template <class _Up = remove_cv_t<_Tp>,
enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>)
+# endif
+ : __base(in_place, std::forward<_Up>(__v)) {
+ }
// LWG2756: conditionally explicit conversion from const optional<_Up>&
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) {
+ _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&>)
+# endif
+ {
this->__construct_from(__v);
}
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_explicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) {
+ _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&>)
+# endif
+ {
this->__construct_from(__v);
}
// LWG2756: conditionally explicit conversion from optional<_Up>&&
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_implicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>)
+# endif
+ {
this->__construct_from(std::move(__v));
}
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_explicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>)
+# endif
+ {
this->__construct_from(std::move(__v));
}
- // deleted optional<T&> constructors
+ // deleted optional<T&> constructors and additional optional<T&> constructors
# if _LIBCPP_STD_VER >= 26
- template <class _Up, class... _Args, enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, int> = 0>
- requires __libcpp_opt_ref_ctor_deleted<_Up>
- explicit optional(in_place_t, initializer_list<_Up>, _Args&&...) = delete;
-
+ // optional(U&&)
template <class _Up = _Tp, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0>
requires __libcpp_opt_ref_ctor_deleted<_Up>
optional(_Up&&) = delete;
@@ -950,6 +979,21 @@ public:
requires __libcpp_opt_ref_ctor_deleted<_Up>
explicit optional(_Up&&) = delete;
+ // optional(optional<U>& rhs)
+ template <class _Up>
+ requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v<remove_cvref_t<_Tp>, 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 <class _Up>
+ requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v<remove_cvref_t<_Tp>, optional<_Up>>) &&
+ (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&>
+ constexpr explicit optional(optional<_Up>& __rhs) noexcept = delete;
+
+ // optional(const optional<U>&)
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>(), int> = 0>
requires __libcpp_opt_ref_ctor_deleted<_Up>
optional(const optional<_Up>&) = delete;
@@ -958,6 +1002,7 @@ public:
requires __libcpp_opt_ref_ctor_deleted<_Up>
explicit optional(const optional<_Up>&) = delete;
+ // optional(optional<U>&&)
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_implicit<_Up>(), int> = 0>
requires __libcpp_opt_ref_ctor_deleted<_Up>
optional(optional<_Up>&&) = delete;
@@ -965,6 +1010,20 @@ public:
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_explicit<_Up>(), int> = 0>
requires __libcpp_opt_ref_ctor_deleted<_Up>
explicit optional(optional<_Up>&&) = delete;
+
+ // optional(const optional<U>&&)
+ template <class _Up>
+ requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v<remove_cvref_t<_Tp>, optional<_Up>>) &&
+ (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v<const _Up, _Tp&>)
+ optional(const optional<_Up>&& __v) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) {
+ this->__construct_from(std::move(__v));
+ }
+
+ template <class _Up>
+ requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v<remove_cvref_t<_Tp>, optional<_Up>>) &&
+ (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>&& __v) noexcept = delete;
# endif
# if _LIBCPP_STD_VER >= 23
@@ -989,11 +1048,12 @@ public:
enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Up>, optional>,
_Or<_IsNotSame<__remove_cvref_t<_Up>, _Tp>, _Not<is_scalar<_Tp>>>,
is_constructible<_Tp, _Up>,
- is_assignable<_Tp&, _Up>>::value,
+ is_assignable<_Tp&, _Up>,
+ is_object<_Tp>>::value,
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(_Up&& __v) {
if (this->has_value())
- this->__assign_from_val(std::forward<_Up>(__v));
+ this->__get() = std::forward<_Up>(__v);
else
this->__construct(std::forward<_Up>(__v));
return *this;
@@ -1013,8 +1073,12 @@ public:
return *this;
}
- template <class... _Args, enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args) {
+ template <class... _Args, enable_if_t<__is_constructible_for_optional_v<_Tp, _Args...>, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp, _Args...>)
+# endif
+ {
reset();
this->__construct(std::forward<_Args>(__args)...);
return this->__get();
@@ -1022,60 +1086,72 @@ public:
template <class _Up,
class... _Args,
- enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
-# if _LIBCPP_STD_VER >= 26
- && !reference_constructs_from_temporary_v<_Tp&, _Up>
-# endif
- ,
- int> = 0>
+ enable_if_t<__is_constructible_for_optional_initializer_list_v<_Tp, _Up, _Args...>, 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)...);
return this->__get();
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
- swap(optional& __opt) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) {
- if (this->has_value() == __opt.has_value()) {
- if (this->has_value())
- this->__swap(__opt);
- } else {
- if (this->has_value()) {
- __opt.__construct(std::move(this->__get()));
- reset();
- } else {
- this->__construct(std::move(__opt.__get()));
- __opt.reset();
- }
- }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(optional& __opt) noexcept(
+ (is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>)
+# if _LIBCPP_STD_VER >= 26
+ || is_lvalue_reference_v<_Tp>
+# endif
+ ) {
+ this->__swap(__opt);
}
- _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept {
+ _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
return std::addressof(this->__get());
}
- _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept {
+ _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
return std::addressof(this->__get());
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
return this->__get();
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
return this->__get();
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
return std::move(this->__get());
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
return std::move(this->__get());
}
@@ -1085,25 +1161,41 @@ public:
using __base::__get;
using __base::has_value;
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const&
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
if (!this->has_value())
std::__throw_bad_optional_access();
return this->__get();
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() &
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
if (!this->has_value())
std::__throw_bad_optional_access();
return this->__get();
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() &&
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
if (!this->has_value())
std::__throw_bad_optional_access();
return std::move(this->__get());
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&&
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
+ {
if (!this->has_value())
std::__throw_bad_optional_access();
return std::move(this->__get());
@@ -1111,8 +1203,7 @@ 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>>))
+ requires(is_object_v<_Tp>)
# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
static_assert(is_copy_constructible_v<_Tp>, "optional<T>::value_or: T must be copy constructible");
@@ -1122,7 +1213,7 @@ public:
template <class _Up = remove_cv_t<_Tp>>
# if _LIBCPP_STD_VER >= 26
- requires(!is_lvalue_reference_v<_Tp>)
+ requires(is_object_v<_Tp>)
# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
static_assert(is_move_constructible_v<_Tp>, "optional<T>::value_or: T must be move constructible");
@@ -1130,19 +1221,11 @@ public:
return this->has_value() ? std::move(this->__get()) : static_cast<_Tp>(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>>))
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
- static_assert(is_move_constructible_v<_Tp>, "optional<T>::value_or: T must be move constructible");
- static_assert(is_convertible_v<_Up, _Tp>, "optional<T>::value_or: U must be convertible to T");
- return this->has_value() ? this->__get() : static_cast<_Tp>(std::forward<_Up>(__v));
- }
-# endif
-
# if _LIBCPP_STD_VER >= 23
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
using _Up = invoke_result_t<_Func, _Tp&>;
static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
@@ -1153,6 +1236,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
using _Up = invoke_result_t<_Func, const _Tp&>;
static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
@@ -1163,6 +1249,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
using _Up = invoke_result_t<_Func, _Tp&&>;
static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
@@ -1173,6 +1262,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
using _Up = invoke_result_t<_Func, const _Tp&&>;
static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
@@ -1183,6 +1275,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&>>;
static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
@@ -1195,6 +1290,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&>>;
static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
@@ -1207,6 +1305,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&&>>;
static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array");
@@ -1219,8 +1320,11 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(is_object_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
- using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&&>>;
+ using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&&>>;
static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array");
static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t");
static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t");
@@ -1233,6 +1337,9 @@ public:
template <invocable _Func>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const&
requires is_copy_constructible_v<_Tp>
+# if _LIBCPP_STD_VER >= 26
+ && (is_object_v<_Tp>)
+# endif
{
static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
"Result of f() should be the same type as this optional");
@@ -1244,6 +1351,9 @@ public:
template <invocable _Func>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) &&
requires is_move_constructible_v<_Tp>
+# if _LIBCPP_STD_VER >= 26
+ && (is_object_v<_Tp>)
+# endif
{
static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
"Result of f() should be the same type as this optional");
@@ -1254,6 +1364,78 @@ public:
# endif // _LIBCPP_STD_VER >= 23
using __base::reset;
+
+// optional<T&> overloads
+# if _LIBCPP_STD_VER >= 26
+
+ _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept
+ requires(is_lvalue_reference_v<_Tp>)
+ {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+ return std::addressof(this->__get());
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept
+ requires(is_lvalue_reference_v<_Tp>)
+ {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+ return this->__get();
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const
+ requires(is_lvalue_reference_v<_Tp>)
+ {
+ if (!this->has_value())
+ std::__throw_bad_optional_access();
+ return this->__get();
+ }
+
+ template <class _Up = remove_cvref_t<_Tp>>
+ requires(is_lvalue_reference_v<_Tp> && is_object_v<__libcpp_remove_reference_t<_Tp>> &&
+ !is_array_v<__libcpp_remove_reference_t<_Tp>>)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decay_t<_Tp> value_or(_Up&& __v) const {
+ static_assert(
+ is_constructible_v<remove_cvref_t<_Tp>, _Tp&>, "optional<T&>::value_or: remove_cv_t<T> must be constructible");
+ static_assert(
+ is_convertible_v<_Up, remove_cvref_t<_Tp>>, "optional<T&>::value_or: U must be convertible to remove_cv_t<T>");
+ return this->has_value() ? this->__get() : static_cast<remove_cvref_t<_Tp>>(std::forward<_Up>(__v));
+ }
+
+ template <class _Func>
+ requires(is_lvalue_reference_v<_Tp>)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const {
+ using _Up = invoke_result_t<_Func, _Tp&>;
+ static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
+ "Result of f(value()) must be a specialization of std::optional");
+ if (*this)
+ return std::invoke(std::forward<_Func>(__f), value());
+ return remove_cvref_t<_Up>();
+ }
+
+ template <class _Func>
+ requires(is_lvalue_reference_v<_Tp>)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<remove_cv_t<invoke_result_t<_Func, _Tp&>>>
+ transform(_Func&& __f) const {
+ using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&>>;
+ static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
+ static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t");
+ static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t");
+ static_assert(is_object_v<_Up>, "Result of f(value()) should be an object type");
+ if (*this)
+ return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value());
+ return optional<_Up>();
+ }
+
+ template <invocable _Func>
+ requires(is_lvalue_reference_v<_Tp>)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const {
+ static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
+ "Result of f() should be the same type as this optional");
+ if (*this)
+ return *this;
+ return std::forward<_Func>(__f)();
+ }
+# endif
};
template <class _Tp>
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
index 25df0dd6c1936..1071184561dc1 100644
--- 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
@@ -22,7 +22,7 @@ concept has_value_or = requires(Opt opt, T&& t) {
};
static_assert(has_value_or<std::optional<int>, int>);
-static_assert(has_value_or<std::optional<int&>, int&>);
-static_assert(has_value_or<std::optional<const int&>, const int&>);
+static_assert(has_value_or<std::optional<int&>, int>);
+static_assert(has_value_or<std::optional<const int&>, int>);
static_assert(!has_value_or<std::optional<int (&)[1]>&&, int (&)[1]>);
static_assert(!has_value_or<std::optional<int (&)()>&&, int (&)()>);
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 810283a4bc80e..93bbd74cd8678 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
@@ -18,6 +18,7 @@
#include <cassert>
#include <concepts>
#include <optional>
+#include <utility>
#include "test_macros.h"
@@ -260,8 +261,9 @@ constexpr bool test() {
#if TEST_STD_VER >= 26
constexpr bool test_ref() {
- // Test & overload
- {
+ // Test "overloads", only the const (no ref-qualifier) and_then() should be called
+
+ { // &
// Without & qualifier on F's operator()
{
int j = 42;
@@ -276,21 +278,21 @@ constexpr bool test_ref() {
{
int j = 42;
std::optional<int&> i{j};
+ auto& io = i;
RefQual l{};
NORefQual nl{};
- std::same_as<std::optional<int>> decltype(auto) r = i.and_then(l);
+ std::same_as<std::optional<int>> decltype(auto) r = io.and_then(l);
assert(r == 1);
- assert(i.and_then(nl) == std::nullopt);
+ assert(io.and_then(nl) == std::nullopt);
}
}
- // Test const& overload
- {
+ { // const&
// Without & qualifier on F's operator()
{
int j = 42;
- std::optional<const int&> i{j};
+ const std::optional<const int&> i{j};
std::same_as<std::optional<int>> decltype(auto) r = i.and_then(CLVal{});
assert(r == 1);
@@ -309,7 +311,8 @@ constexpr bool test_ref() {
assert(i.and_then(nl) == std::nullopt);
}
}
- // Test && overload
+
+ // &&
{
//With & qualifier on F's operator()
{
@@ -318,11 +321,11 @@ constexpr bool test_ref() {
std::same_as<std::optional<int>> decltype(auto) r = i.and_then(RVRefQual{});
assert(r == 1);
- assert(i.and_then(NORVRefQual{}) == std::nullopt);
+ assert(std::move(i).and_then(NORVRefQual{}) == std::nullopt);
}
}
- // Test const&& overload
+ // const&&
{
//With & qualifier on F's operator()
{
@@ -330,10 +333,10 @@ constexpr bool test_ref() {
const std::optional<int&> i{j};
const RVCRefQual l{};
const NORVCRefQual nl{};
- std::same_as<std::optional<int>> decltype(auto) r = i.and_then(std::move(l));
+ std::same_as<std::optional<int>> decltype(auto) r = std::move(i).and_then(std::move(l));
assert(r == 1);
- assert(i.and_then(std::move(nl)) == std::nullopt);
+ assert(std::move(i).and_then(std::move(nl)) == std::nullopt);
}
}
return true;
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 0c330e30055a2..326013cd6557f 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
@@ -75,6 +75,13 @@ constexpr bool test() {
});
assert(opt == j);
}
+
+ {
+ int i = 2;
+ const std::optional<int&> opt;
+ assert(opt.or_else([&] { return std::optional<int&>{i}; }) == i);
+ }
+
{
int i = 2;
std::optional<int&> opt;
@@ -87,6 +94,16 @@ constexpr bool test() {
});
assert(opt == j);
}
+
+ {
+ int i = 2;
+ const std::optional<int&> opt = i;
+ assert(std::move(opt).or_else([] {
+ assert(false);
+ return std::optional<int&>{};
+ }) == i);
+ }
+
#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 36939f0b6b62e..b8536b790f749 100644
--- a/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp
@@ -204,6 +204,8 @@ constexpr bool test() {
#if TEST_STD_VER >= 26
constexpr bool test_ref() {
+ // Test that no matter the ref qualifier on the object .transform() is invoked on, only the added
+ // const (no ref-qualifier) overload is used
{
std::optional<int&> opt1;
std::same_as<std::optional<int>> decltype(auto) opt1r = opt1.transform([](int i) { return i + 2; });
@@ -218,7 +220,16 @@ constexpr bool test_ref() {
assert(*o2 == 44);
}
- // Test & overload
+
+ {
+ int i = 42;
+ float k = 4.0f;
+ std::optional<int&> opt{i};
+ std::same_as<std::optional<float>> decltype(auto) o2 = opt.transform([&](int&) { return k; });
+ assert(*o2 == 4.0f);
+ }
+
+ // &
{
// Without & qualifier on F's operator()
{
@@ -244,7 +255,7 @@ constexpr bool test_ref() {
// Without & qualifier on F's operator()
{
int i = 42;
- std::optional<const int&> opt{i};
+ const std::optional<const int&> opt{i};
std::same_as<std::optional<int>> decltype(auto) o3 = std::as_const(opt).transform(CLVal{});
assert(*o3 == 1);
@@ -266,8 +277,8 @@ constexpr bool test_ref() {
// Without & qualifier on F's operator()
{
int i = 42;
- std::optional<int> opt{i};
- std::same_as<std::optional<int>> decltype(auto) o3 = std::move(opt).transform(RVal{});
+ std::optional<int&> opt{i};
+ std::same_as<std::optional<int>> decltype(auto) o3 = std::move(opt).transform(LVal{});
assert(*o3 == 1);
}
@@ -286,9 +297,9 @@ constexpr bool test_ref() {
//With & qualifier on F's operator()
{
int i = 42;
- std::optional<int&> opt{i};
+ const std::optional<int&> opt{i};
const RVCRefQual rvc{};
- std::same_as<std::optional<int>> decltype(auto) o3 = opt.transform(std::move(rvc));
+ std::same_as<std::optional<int>> decltype(auto) o3 = std::move(opt).transform(std::move(rvc));
assert(*o3 == 1);
}
}
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 ddb9ffc4bf80c..f1e2493954d38 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
@@ -18,6 +18,9 @@
#include "test_macros.h"
#include "archetypes.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
using std::optional;
@@ -252,9 +255,9 @@ constexpr T pr38638(T v)
#if TEST_STD_VER >= 26
-template <typename T, std::remove_reference_t<T> _Val>
-constexpr void test_with_ref() {
- T t{_Val};
+template <typename T>
+constexpr bool test_with_ref(std::decay_t<T> val) {
+ T t{val};
{ // to empty
optional<T&> opt;
opt = t;
@@ -280,7 +283,7 @@ constexpr void test_with_ref() {
}
// test two objects, make sure that the optional only changes what it holds a reference to
{
- T t2{_Val};
+ T t2{val};
optional<T&> opt{t};
opt = t2;
@@ -299,6 +302,20 @@ constexpr void test_with_ref() {
assert(std::addressof(*opt) == std::addressof(j));
assert(*opt == 2);
}
+
+ { // test that no copy is made when assigning
+ TracedCopyMove t1{};
+ TracedCopyMove t2{};
+
+ optional<TracedCopyMove&> o(t1);
+
+ o = t2;
+ assert(std::addressof(*o) == &t2);
+ assert(o->constCopy == 0);
+ assert(o->nonConstCopy == 0);
+ }
+
+ return true;
}
#endif
@@ -333,7 +350,10 @@ int main(int, char**)
static_assert(pr38638(3) == 5, "");
#if TEST_STD_VER >= 26
- test_with_ref<int, 3>();
+ test_with_ref<int>(3);
+ test_with_ref<ConstexprTestTypes::Copyable>({});
+ static_assert(test_with_ref<int>(3));
+ static_assert(test_with_ref<ConstexprTestTypes::Copyable>({}));
#endif
return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp
index 4751f8e60994e..6b6dcbf428380 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp
@@ -195,6 +195,34 @@ void test_ambiguous_assign() {
}
}
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ {
+ int t{2};
+ const std::optional<int&> o1{t};
+ std::optional<int&> o2 = o1;
+
+ assert(&(*o2) == &t);
+ assert(o1.has_value());
+ assert(o2.has_value());
+ assert(*o2 == 2);
+ }
+
+ {
+ int t{2};
+
+ const std::optional<int&> o1{t};
+ std::optional<int> o2 = o1;
+
+ assert(&(*o2) != &t);
+ assert(o1.has_value());
+ assert(o2.has_value());
+ assert(*o2 == 2);
+ }
+
+ return true;
+}
+#endif
int main(int, char**)
{
@@ -251,5 +279,10 @@ int main(int, char**)
}
#endif
- return 0;
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_ref());
+#endif
+
+ return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp
index 9753fdb46b862..b4702baa49e1c 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp
@@ -49,6 +49,55 @@ constexpr bool assign_value(optional<Tp>&& lhs) {
return lhs.has_value() && rhs.has_value() && *lhs == *rhs;
}
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ struct TraceCopyAssign {
+ int copyAssign = 0;
+ mutable int constCopyAssign = 0;
+
+ constexpr TraceCopyAssign() = default;
+ constexpr TraceCopyAssign(TraceCopyAssign& r) : copyAssign(r.copyAssign + 1), constCopyAssign(r.constCopyAssign) {}
+ constexpr TraceCopyAssign(const TraceCopyAssign& r)
+ : copyAssign(r.copyAssign), constCopyAssign(r.constCopyAssign + 1) {}
+ constexpr TraceCopyAssign& operator=(const TraceCopyAssign&) {
+ copyAssign++;
+ return *this;
+ }
+ constexpr const TraceCopyAssign& operator=(const TraceCopyAssign&) const {
+ constCopyAssign++;
+ return *this;
+ }
+ };
+ using T = TraceCopyAssign;
+ {
+ T t{};
+ std::optional<T&> o1{t};
+ std::optional<T&> o2 = o1;
+
+ assert(&(*o2) == &t);
+ assert(&(*o2) == &(*o1));
+ assert(t.constCopyAssign == 0);
+ assert(t.copyAssign == 0);
+ assert(o1.has_value());
+ assert(o2.has_value());
+ }
+ {
+ T t{};
+ std::optional<T&> o1{t};
+ std::optional<T> o2 = o1;
+
+ assert(&(*o2) != &t);
+ assert(&(*o2) != &(*o1));
+ assert(o2->constCopyAssign == 0);
+ assert(o2->copyAssign == 1);
+ assert(o1.has_value());
+ assert(o2.has_value());
+ }
+
+ return true;
+}
+#endif
+
int main(int, char**)
{
{
@@ -100,5 +149,10 @@ int main(int, char**)
}
#endif
- return 0;
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_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 629e315add4d9..3321d55ec5869 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
@@ -231,6 +231,7 @@ constexpr bool test_ref() {
auto& v = opt.emplace(t);
static_assert(std::is_same_v<T&, decltype(v)>);
assert(static_cast<bool>(opt) == true);
+ ASSERT_NOEXCEPT(opt.emplace(t));
assert(*opt == t);
assert(&v == &*opt);
assert(&t == &*opt);
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.verify.cpp
new file mode 100644
index 0000000000000..a0bfa078f189c
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.verify.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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+// <optional>
+
+// template <class U> T& optional<T&>::emplace(U&& arg);
+// Ensure that emplace isn't found if reference_constructs_From_temporary_v == true or is_constructible_v<_Tp&, U> == false
+#include <optional>
+#include <type_traits>
+
+struct X {};
+void test() {
+ int i = 1;
+ std::optional<X&> f{};
+ static_assert(!std::is_constructible_v<X&, int>); // is_constructible_v<_Tp&, U> == false
+ f.emplace(i); // expected-error {{no matching member function for call to 'emplace'}}
+
+ std::optional<const int&> t{}; // reference_constructs_from_temporary_v == false
+ t.emplace(1); // expected-error {{no matching member function for call to 'emplace'}}
+}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp
index 85971e38f7b70..c447557cfa9d4 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp
@@ -20,6 +20,9 @@
#include "test_macros.h"
#include "archetypes.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
using std::optional;
@@ -66,6 +69,23 @@ constexpr bool assign_value(optional<Tp>&& lhs) {
return lhs.has_value() && rhs.has_value() && *lhs == Tp{101};
}
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ using T = TracedAssignment;
+ {
+ T t{};
+ std::optional<T&> o1{t};
+ std::optional<T&> o2 = std::move(o1);
+
+ assert(&(*o2) == &t);
+ assert(o1.has_value());
+ assert(o2.has_value());
+ assert(t.moveAssign == 0);
+ }
+ return true;
+}
+#endif
+
int main(int, char**)
{
{
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp
index 9d0843b7338df..e85c0c435aa37 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp
@@ -61,6 +61,17 @@ TEST_CONSTEXPR_CXX20 bool test()
assert(state == State::destroyed);
assert(static_cast<bool>(opt) == false);
}
+
+#if TEST_STD_VER >= 26
+ {
+ int i = 0;
+ optional<int&> o{i};
+ ASSERT_NOEXCEPT(o = std::nullopt);
+ o = std::nullopt;
+ assert(!o.has_value());
+ assert(static_cast<bool>(o) == false);
+ }
+#endif
return true;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
index cc1b17157f2b4..d23858e9974d5 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
@@ -293,7 +293,18 @@ TEST_CONSTEXPR_CXX20 bool test()
assert(state[0] == state_t::inactive);
assert(state[1] == state_t::copy_assigned);
}
+#if TEST_STD_VER >= 26
+ {
+ state_t state{state_t::constructed};
+ StateTracker t{state};
+ std::optional<StateTracker&> o1{t};
+ std::optional<StateTracker> o2 = std::move(o1);
+ (void)*o2;
+ assert(state != state_t::move_assigned);
+ assert(state == state_t::constructed);
+ }
+#endif
return true;
}
@@ -301,7 +312,8 @@ TEST_CONSTEXPR_CXX20 bool test()
int main(int, char**)
{
#if TEST_STD_VER > 17
- static_assert(test());
+ assert(test());
+ static_assert(test());
#endif
test_with_test_type();
test_ambiguous_assign();
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/U.pass.cpp
index 1e951ebdf1d74..1cdb429f485e5 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/U.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/U.pass.cpp
@@ -21,6 +21,8 @@
#include "archetypes.h"
#include "test_convertible.h"
+#include "../optional_helper_types.h"
+
using std::optional;
struct ImplicitThrow {
@@ -149,9 +151,72 @@ void test_explicit() {
#endif
}
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ {
+ int i = 0;
+ std::optional<int&> o(i);
+ ASSERT_NOEXCEPT(std::optional<int&>(i));
+ assert(o.has_value());
+ assert(&(*o) == &i);
+ assert(*o == 0);
+ assert(o.value() == 0);
+ }
+
+ {
+ ReferenceConversion<int> t{1, 2};
+ ASSERT_NOEXCEPT(std::optional<int&>(t));
+ std::optional<int&> o(t);
+ assert(o.has_value());
+ assert(&(*o) == &t.lvalue);
+ assert(*o == 1);
+ }
+
+ {
+ ReferenceConversion<int> t{1, 2};
+ ASSERT_NOEXCEPT(std::optional<int&>(std::move(t)));
+ std::optional<int&> o(std::move(t));
+ assert(o.has_value());
+ assert(&(*o) == &t.rvalue);
+ assert(*o == 2);
+ }
+
+# ifndef TEST_HAS_NO_EXCEPTIONS
+ {
+ ReferenceConversionThrows<int> t{1, 2, false};
+ ASSERT_NOT_NOEXCEPT(std::optional<int&>(t));
+ try {
+ std::optional<int&> o(t);
+ assert(o.has_value());
+ assert(&(*o) == &t.lvalue);
+ assert(*o == 1);
+ } catch (int) {
+ assert(false);
+ }
+ }
+ {
+ ReferenceConversionThrows<int> t{1, 2, false};
+ ASSERT_NOT_NOEXCEPT(std::optional<int&>(std::move(t)));
+ try {
+ std::optional<int&> o(std::move(t));
+ assert(o.has_value());
+ assert(&(*o) == &t.rvalue);
+ assert(*o == 2);
+ } catch (int) {
+ assert(false);
+ }
+ }
+# endif
+ return true;
+}
+#endif
+
int main(int, char**) {
test_implicit();
test_explicit();
-
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_ref());
+#endif
return 0;
}
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 70fd76ec6ed0b..597110bcb54fe 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
@@ -11,11 +11,13 @@
// template <class U>
// optional(const optional<U>& rhs);
+//optional<T&>: optional(const optional<U>&& rhs);
#include <cassert>
#include <optional>
#include <type_traits>
+#include "../optional_helper_types.h"
#include "test_macros.h"
using std::optional;
@@ -86,6 +88,73 @@ constexpr bool test_all() {
return true;
}
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ // optional(const optional<U>&)
+ {
+ int i = 1;
+ const std::optional<int&> o1{i};
+ const std::optional<int&> o2{o1};
+
+ ASSERT_NOEXCEPT(std::optional<int&>(o2));
+ assert(o2.has_value());
+ assert(&(*o1) == &(*o2));
+ assert(*o1 == i);
+ assert(*o2 == i);
+ }
+
+ {
+ const std::optional<int&> o1;
+ const std::optional<int&> o2{o1};
+ ASSERT_NOEXCEPT(std::optional<int&>(o2));
+ assert(!o2.has_value());
+ }
+
+ {
+ ReferenceConversion<int> t{1, 2};
+ const std::optional<ReferenceConversion<int>&> o1(t);
+ const std::optional<int&> o2(o1);
+ ASSERT_NOEXCEPT(std::optional<int&>(o1));
+ assert(o2.has_value());
+ assert(&(*o2) == &t.lvalue);
+ assert(*o2 == 1);
+ }
+
+ // optional(const optional<U>&&)
+ {
+ int i = 1;
+ const std::optional<int&> o1{i};
+ const std::optional<int&> o2{std::move(o1)};
+
+ // trivial move constructor should just copy the reference
+ ASSERT_NOEXCEPT(std::optional<int&>(std::move(o2)));
+ assert(o2.has_value());
+ assert(&(*o1) == &(*o2));
+ assert(*o1 == i);
+ assert(*o2 == i);
+ }
+
+ {
+ const std::optional<int&> o1;
+ const std::optional<int&> o2{std::move(o1)};
+ ASSERT_NOEXCEPT(std::optional<int&>(o2));
+ assert(!o2.has_value());
+ }
+
+ {
+ ReferenceConversion<int> t{1, 2};
+ const std::optional<ReferenceConversion<int>&> o1(t);
+ const std::optional<int&> o2(std::move(o1));
+ ASSERT_NOEXCEPT(std::optional<int&>(o1));
+ assert(o2.has_value());
+ assert(&(*o2) == &t.lvalue);
+ assert(*o2 == 1);
+ }
+
+ return true;
+}
+#endif
+
int main(int, char**) {
test_all<int, short>();
test_all<X, int>();
@@ -109,6 +178,9 @@ int main(int, char**) {
}
static_assert(!(std::is_constructible<optional<X>, const optional<Y>&>::value), "");
-
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_ref());
+#endif
return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
index f61a22c23a04d..fd7332f3b422b 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
@@ -69,8 +69,8 @@ void test_ref(InitArgs&&... args) {
assert(&(*lhs) == &(*rhs));
}
+#if TEST_STD_VER >= 26
void test_reference_extension() {
-#if defined(_LIBCPP_VERSION) && 0 // FIXME these extensions are currently disabled.
using T = TestTypes::TestType;
T::reset();
{
@@ -99,12 +99,15 @@ void test_reference_extension() {
}
assert(T::alive == 0);
assert(T::destroyed == 1);
+
+# if 0 // optional<T&&> is not permitted.
{
static_assert(!std::is_copy_constructible<std::optional<T&&>>::value, "");
static_assert(!std::is_copy_constructible<std::optional<T const&&>>::value, "");
}
-#endif
+# endif
}
+#endif
int main(int, char**) {
test<int>();
@@ -153,9 +156,11 @@ int main(int, char**) {
{
test_throwing_ctor();
}
+#if TEST_STD_VER >= 26
{
test_reference_extension();
}
+#endif
{
constexpr std::optional<int> o1{4};
constexpr std::optional<int> o2 = o1;
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/in_place_t.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/in_place_t.pass.cpp
index c8bdfc78225fa..c3b498e56a5a1 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/in_place_t.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/in_place_t.pass.cpp
@@ -78,6 +78,23 @@ constexpr bool test_ref_initializer_list() {
return true;
}
+
+constexpr bool test_ref() {
+ { // optional(in_place_t, _Arg&&)
+ Y y{1, 2};
+ optional<Y&> xo(in_place, y);
+
+ Y x2{1, 2};
+
+ assert(*xo == x2);
+ assert(&(*xo) == &y);
+ }
+
+ assert(test_ref_initializer_list());
+ static_assert(test_ref_initializer_list());
+
+ return true;
+}
#endif
int main(int, char**) {
@@ -148,8 +165,8 @@ int main(int, char**) {
#endif
#if TEST_STD_VER >= 26
- test_ref_initializer_list();
- static_assert(test_ref_initializer_list());
+ test_ref();
+ static_assert(test_ref());
#endif
return 0;
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
index 583debcaac650..bb36283a5e3ea 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
@@ -78,26 +78,34 @@ void test_reference_extension() {
T::reset();
{
T t;
- T::reset_constructors();
- test_ref<T&>();
- test_ref<T&>(t);
+ {
+ T::reset_constructors();
+ test_ref<T&>();
+ test_ref<T&>(t);
+ assert(T::alive == 1);
+ assert(T::constructed == 0);
+ assert(T::assigned == 0);
+ assert(T::destroyed == 0);
+ } // destroying the optional<T&> doesn't destroy the underlying T
assert(T::alive == 1);
- assert(T::constructed == 0);
- assert(T::assigned == 0);
assert(T::destroyed == 0);
}
assert(T::destroyed == 1);
assert(T::alive == 0);
{
T t;
- const T& ct = t;
- T::reset_constructors();
- test_ref<T const&>();
- test_ref<T const&>(t);
- test_ref<T const&>(ct);
+ {
+ const T& ct = t;
+ T::reset_constructors();
+ test_ref<T const&>();
+ test_ref<T const&>(t);
+ test_ref<T const&>(ct);
+ assert(T::alive == 1);
+ assert(T::constructed == 0);
+ assert(T::assigned == 0);
+ assert(T::destroyed == 0);
+ }
assert(T::alive == 1);
- assert(T::constructed == 0);
- assert(T::assigned == 0);
assert(T::destroyed == 0);
}
assert(T::alive == 0);
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 709b106c800a6..39a80efa475f7 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
@@ -12,6 +12,8 @@
// template <class U>
// optional(optional<U>&& rhs);
+// optional<T&>: optional(optional<U>& rhs)
+
#include <cassert>
#include <memory>
#include <optional>
@@ -19,6 +21,11 @@
#include <utility>
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
+
+#include "../optional_helper_types.h"
using std::optional;
@@ -68,6 +75,79 @@ TEST_CONSTEXPR_CXX20 bool test_all() {
return true;
}
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ // optional(optional<U>&)
+ {
+ int i = 1;
+ std::optional<int&> o1{i};
+ std::optional<int&> o2{o1};
+
+ ASSERT_NOEXCEPT(std::optional<int&>(o2));
+ assert(o2.has_value());
+ assert(&(*o1) == &(*o2));
+ assert(*o1 == i);
+ assert(*o2 == i);
+ }
+
+ {
+ std::optional<int&> o1;
+ std::optional<int&> o2{o1};
+ ASSERT_NOEXCEPT(std::optional<int&>(o2));
+ assert(!o2.has_value());
+ }
+
+ {
+ ReferenceConversion<int> t{1, 2};
+ std::optional<ReferenceConversion<int>&> o1(t);
+ std::optional<int&> o2(o1);
+ ASSERT_NOEXCEPT(std::optional<int&>(o1));
+ assert(o2.has_value());
+ assert(&(*o2) == &t.lvalue);
+ assert(*o2 == 1);
+ }
+ // optional(optional<U>&&)
+ {
+ int i = 1;
+ std::optional<int&> o1{i};
+ std::optional<int&> o2{std::move(o1)};
+
+ // trivial move constructor should just copy the reference
+ ASSERT_NOEXCEPT(std::optional<int&>(o2));
+ assert(o2.has_value());
+ assert(&(*o1) == &(*o2));
+ assert(*o1 == i);
+ assert(*o2 == i);
+ }
+
+ {
+ std::optional<int&> o1;
+ std::optional<int&> o2{std::move(o1)};
+ ASSERT_NOEXCEPT(std::optional<int&>(o2));
+ assert(!o2.has_value());
+ }
+ {
+ TracedCopyMove t{};
+ std::optional<TracedCopyMove&> o1{t};
+ std::optional<TracedCopyMove> o2{std::move(o1)};
+ assert(t.constMove == 0);
+ assert(t.nonConstMove == 0);
+ }
+
+ {
+ ReferenceConversion<int> t{1, 2};
+ std::optional<ReferenceConversion<int>&> o1(t);
+ std::optional<int&> o2(std::move(o1));
+ ASSERT_NOEXCEPT(std::optional<int&>(o1));
+ assert(o2.has_value());
+ assert(&(*o2) == &t.lvalue);
+ assert(*o2 == 1);
+ }
+
+ return true;
+}
+#endif
+
int main(int, char**) {
test_all<short, int>();
test_all<int, X>();
@@ -86,5 +166,9 @@ int main(int, char**) {
static_assert(!(std::is_constructible<optional<X>, optional<Z>>::value), "");
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_ref());
+#endif
return 0;
}
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 01b241ffbe79b..53ac77a2e5620 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
@@ -8,7 +8,13 @@
// REQUIRES: std-at-least-c++26
-// optional
+// <optional>
+
+// optional(U&& u) noexcept(is_nothrow_constructible_v<T&, U>);
+// optional(optional<U>& rhs) noexcept(is_nothrow_constructible_v<T&, U&>);
+// optional(const optional<U>& rhs) noexcept(is_nothrow_constructible_v<T&, const U&>);
+// optional(optional<U>&& rhs) noexcept(is_nothrow_constructible_v<T&, U>);
+// optional(const optional<U>&& rhs) noexcept(is_nothrow_constructible_v<T&, const U>);
#include <optional>
#include <utility>
@@ -19,17 +25,20 @@ struct X {
X(int j) : i(j) {}
};
-int main(int, char**) {
- const std::optional<int> _co(1);
- std::optional<int> _o(1);
-
- // expected-error-re@*:* 8 {{call to deleted constructor of 'std::optional<{{.*}}>'}}
- std::optional<const int&> o1{1}; // optional(U&&)
- std::optional<const int&> o2{std::optional<int>(1)}; // optional(optional<U>&&)
- std::optional<const int&> o3{_co}; // optional(const optional<U>&)
- std::optional<const int&> o4{_o}; // optional(optional<U>&)
- std::optional<const X&> o5{1}; // optional(U&&)
- std::optional<const X&> o6{std::optional<int>(1)}; // optional(optional<U>&&)
- std::optional<const X&> o7{_co}; // optional(const optional<U>&)
- std::optional<const X&> o8{_o}; // optional(optional<U>&)
+void test() {
+ const std::optional<int> co(1);
+ std::optional<int> o0(1);
+
+ // expected-error-re@*:* 10 {{call to deleted constructor of 'std::optional<{{.*}}>'}}
+ std::optional<const int&> o1{1}; // optional(U&&)
+ std::optional<const int&> o2{o0}; // optional(optional<U>&)
+ std::optional<const int&> o3{co}; // optional(const optional<U>&)
+ std::optional<const int&> o4{std::move(o0)}; // optional(optional<U>&&&)
+ std::optional<const int&> o5{std::move(co)}; // optional(optional<U>&&&)
+
+ std::optional<const X&> o6{1}; // optional(U&&)
+ std::optional<const X&> o7{o0}; // optional(optional<U>&)
+ std::optional<const X&> o8(co); // optional(const optional<U>&)
+ std::optional<const X&> o9{std::move(o0)}; // optional(optional<U>&&)
+ std::optional<const X&> o10{std::move(co)}; // optional(const optional<U>&&)
}
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 e23e481f6a05d..a7ae22861d32e 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
@@ -75,6 +75,7 @@ int main(int, char**)
optional<X&> opt(x);
X::dtor_called = false;
opt.reset();
+ ASSERT_NOEXCEPT(opt.reset());
assert(X::dtor_called == false);
assert(static_cast<bool>(opt) == false);
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/bool.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/bool.pass.cpp
index 684f18ff3df20..ccc6dea8a111a 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/bool.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/bool.pass.cpp
@@ -10,13 +10,36 @@
// <optional>
// constexpr explicit optional<T>::operator bool() const noexcept;
+// constexpr explicit optional<T&>::operator bool() const noexcept;
+#include <cassert>
#include <optional>
#include <type_traits>
-#include <cassert>
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+
+constexpr bool test_ref() {
+ {
+ std::optional<int&> opt;
+ ASSERT_NOEXCEPT(bool(opt));
+ assert(!opt);
+ static_assert(!std::is_convertible<std::optional<int&>, bool>::value, "");
+ }
+ {
+ int i = 1;
+ std::optional<int&> opt(i);
+ ASSERT_NOEXCEPT(bool(opt));
+ assert(opt);
+ static_assert(!std::is_convertible<std::optional<int&>, bool>::value, "");
+ }
+
+ return true;
+}
+
+#endif
+
int main(int, char**)
{
using std::optional;
@@ -34,5 +57,12 @@ int main(int, char**)
static_assert(opt, "");
}
- return 0;
+#if TEST_STD_VER >= 26
+ {
+ assert(test_ref());
+ static_assert(test_ref());
+ }
+#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 6c1bf8aa15a8d..72cf0446c7eb9 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
@@ -11,11 +11,14 @@
// constexpr T& optional<T>::operator*() &;
-#include <optional>
-#include <type_traits>
#include <cassert>
+#include <memory>
+#include <optional>
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
using std::optional;
@@ -39,6 +42,38 @@ test()
return (*opt).test();
}
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ {
+ TracedCopyMove x{};
+ std::optional<TracedCopyMove&> opt(x);
+ static_assert(noexcept(*opt));
+ ASSERT_SAME_TYPE(decltype(*opt), TracedCopyMove&);
+
+ assert(std::addressof(*opt) == std::addressof(x));
+ assert(x.constMove == 0);
+ assert(x.nonConstMove == 0);
+ assert(x.constCopy == 0);
+ assert(x.nonConstCopy == 0);
+ }
+
+ {
+ TracedCopyMove x{};
+ std::optional<const TracedCopyMove&> opt(x);
+ static_assert(noexcept(*opt));
+ ASSERT_SAME_TYPE(decltype(*opt), const TracedCopyMove&);
+
+ assert(std::addressof(*opt) == std::addressof(x));
+ assert(x.constMove == 0);
+ assert(x.nonConstMove == 0);
+ assert(x.constCopy == 0);
+ assert(x.nonConstCopy == 0);
+ }
+
+ return true;
+}
+#endif
+
int main(int, char**)
{
{
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 c15d4e4af74cc..aefe8d37a142a 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
@@ -11,11 +11,14 @@
// constexpr const T& optional<T>::operator*() const &;
-#include <optional>
-#include <type_traits>
#include <cassert>
+#include <memory>
+#include <optional>
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
using std::optional;
@@ -32,6 +35,39 @@ struct Y
int test() const {return 2;}
};
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ using T = TracedCopyMove;
+ {
+ T x{};
+ const std::optional<T&> opt(x);
+ ASSERT_NOEXCEPT(*opt);
+ ASSERT_SAME_TYPE(decltype(*opt), TracedCopyMove&);
+
+ assert(std::addressof(*opt) == std::addressof(x));
+ assert((*opt).constMove == 0);
+ assert((*opt).nonConstMove == 0);
+ assert((*opt).constCopy == 0);
+ assert((*opt).nonConstCopy == 0);
+ }
+
+ {
+ T x{};
+ const std::optional<const T&> opt(x);
+ ASSERT_NOEXCEPT(*opt);
+ ASSERT_SAME_TYPE(decltype(*opt), const TracedCopyMove&);
+
+ assert(std::addressof(*opt) == std::addressof(x));
+ assert((*opt).constMove == 0);
+ assert((*opt).nonConstMove == 0);
+ assert((*opt).constCopy == 0);
+ assert((*opt).nonConstCopy == 0);
+ }
+
+ return true;
+}
+#endif
+
int main(int, char**)
{
{
@@ -43,29 +79,15 @@ int main(int, char**)
constexpr optional<X> opt(X{});
static_assert((*opt).test() == 3, "");
}
-#if TEST_STD_VER >= 26
- {
- X x{};
- const optional<X&> opt{x};
- ASSERT_SAME_TYPE(decltype(*opt), X&);
- ASSERT_NOEXCEPT(*opt);
- }
{
- X x{};
- const optional<const X&> opt{x};
- ASSERT_SAME_TYPE(decltype(*opt), const X&);
- ASSERT_NOEXCEPT(*opt);
+ constexpr optional<Y> opt(Y{});
+ assert((*opt).test() == 2);
}
+#if TEST_STD_VER >= 26
{
- static constexpr X x{};
- constexpr optional<const X&> opt(x);
- static_assert((*opt).test() == 3);
+ assert(test_ref());
+ static_assert(test_ref());
}
#endif
- {
- constexpr optional<Y> opt(Y{});
- assert((*opt).test() == 2);
- }
-
return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const_rvalue.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const_rvalue.pass.cpp
index 646857fdc0465..cbff9cf3b1d6b 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const_rvalue.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const_rvalue.pass.cpp
@@ -11,11 +11,15 @@
// constexpr T&& optional<T>::operator*() const &&;
-#include <optional>
-#include <type_traits>
#include <cassert>
+#include <memory>
+#include <optional>
+#include <utility>
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
using std::optional;
@@ -32,6 +36,38 @@ struct Y
int test() const && {return 2;}
};
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ { // const&&
+ TracedCopyMove x{};
+ const std::optional<TracedCopyMove&> opt(x);
+ ASSERT_NOEXCEPT(*std::move(opt));
+ ASSERT_SAME_TYPE(decltype(*std::move(opt)), TracedCopyMove&);
+
+ assert(std::addressof(*(std::move(opt))) == std::addressof(x));
+ assert((*std::move(opt)).constMove == 0);
+ assert((*std::move(opt)).nonConstMove == 0);
+ assert((*std::move(opt)).constCopy == 0);
+ assert((*std::move(opt)).nonConstCopy == 0);
+ }
+
+ {
+ TracedCopyMove x{};
+ const std::optional<const TracedCopyMove&> opt(x);
+ ASSERT_NOEXCEPT(*std::move(opt));
+ ASSERT_SAME_TYPE(decltype(*std::move(opt)), const TracedCopyMove&);
+
+ assert(std::addressof(*(std::move(opt))) == std::addressof(x));
+ assert((*std::move(opt)).constMove == 0);
+ assert((*std::move(opt)).nonConstMove == 0);
+ assert((*std::move(opt)).constCopy == 0);
+ assert((*std::move(opt)).nonConstCopy == 0);
+ }
+
+ return true;
+}
+#endif
+
int main(int, char**)
{
{
@@ -48,5 +84,10 @@ int main(int, char**)
assert((*std::move(opt)).test() == 2);
}
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_ref());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_rvalue.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_rvalue.pass.cpp
index 16bf2e4336c69..9c394bb13a2a0 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_rvalue.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_rvalue.pass.cpp
@@ -11,11 +11,13 @@
// constexpr T&& optional<T>::operator*() &&;
-#include <optional>
-#include <type_traits>
#include <cassert>
+#include <optional>
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
using std::optional;
@@ -39,6 +41,40 @@ test()
return (*std::move(opt)).test();
}
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ // ensure underlying value isn't moved from
+ {
+ TracedCopyMove x{};
+ std::optional<TracedCopyMove&> opt(x);
+ ASSERT_NOEXCEPT(*std::move(opt));
+ ASSERT_SAME_TYPE(decltype(*std::move(opt)), TracedCopyMove&);
+
+ assert(std::addressof(*std::move(opt)) == std::addressof(x));
+ assert((*std::move(opt)).constMove == 0);
+ assert((*std::move(opt)).nonConstMove == 0);
+ assert((*std::move(opt)).constCopy == 0);
+ assert((*std::move(opt)).nonConstCopy == 0);
+ }
+
+ {
+ TracedCopyMove x{};
+ std::optional<const TracedCopyMove&> opt(x);
+ ASSERT_NOEXCEPT(*std::move(opt));
+ ASSERT_SAME_TYPE(decltype(*std::move(opt)), const TracedCopyMove&);
+
+ assert(std::addressof(*std::move(opt)) == std::addressof(x));
+ assert((*std::move(opt)).constMove == 0);
+ assert((*std::move(opt)).nonConstMove == 0);
+ assert((*std::move(opt)).constCopy == 0);
+ assert((*std::move(opt)).nonConstCopy == 0);
+ }
+
+ return true;
+}
+
+#endif
+
int main(int, char**)
{
{
@@ -52,5 +88,10 @@ int main(int, char**)
}
static_assert(test() == 7, "");
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_ref());
+#endif
+
return 0;
}
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 9873a767cfbe6..d8c424fc41c74 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
@@ -11,9 +11,8 @@
// constexpr bool optional<T>::has_value() const noexcept;
-#include <optional>
-#include <type_traits>
#include <cassert>
+#include <optional>
#include "test_macros.h"
@@ -37,8 +36,13 @@ int main(int, char**)
{
static constexpr int i = 0;
constexpr optional<const int&> opt{i};
+ ASSERT_NOEXCEPT(opt.has_value());
static_assert(opt.has_value());
}
+ {
+ constexpr optional<const int&> opt{};
+ static_assert(!opt.has_value());
+ }
#endif
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 96d22743ac7fe..bb050f20debe1 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
@@ -11,9 +11,9 @@
// constexpr T* optional<T>::operator->();
-#include <optional>
-#include <type_traits>
#include <cassert>
+#include <memory>
+#include <optional>
#include "test_macros.h"
@@ -53,17 +53,20 @@ int main(int, char**)
std::optional<X&> opt(x);
ASSERT_SAME_TYPE(decltype(opt.operator->()), X*);
ASSERT_NOEXCEPT(opt.operator->());
+ assert(opt.operator->() == std::addressof(x));
}
{
X x{};
std::optional<const X&> opt(x);
ASSERT_SAME_TYPE(decltype(opt.operator->()), const X*);
ASSERT_NOEXCEPT(opt.operator->());
+ assert(opt.operator->() == std::addressof(x));
}
{
X x{};
optional<X&> opt{x};
assert(opt->test() == 3);
+ assert(opt.operator->() == std::addressof(x));
}
{
X x{};
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 e9694fd6d9640..0461a04b85d45 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
@@ -11,9 +11,9 @@
// constexpr const T* optional<T>::operator->() const;
-#include <optional>
-#include <type_traits>
#include <cassert>
+#include <memory>
+#include <optional>
#include "test_macros.h"
@@ -60,17 +60,20 @@ int main(int, char**)
const std::optional<X&> opt(x);
ASSERT_SAME_TYPE(decltype(opt.operator->()), X*);
ASSERT_NOEXCEPT(opt.operator->());
+ assert(opt.operator->() == std::addressof(x));
}
{
X x{};
const std::optional<const X&> opt(x);
ASSERT_SAME_TYPE(decltype(opt.operator->()), const X*);
ASSERT_NOEXCEPT(opt.operator->());
+ assert(opt.operator->() == std::addressof(x));
}
{
static constexpr Z z{};
constexpr optional<const Z&> opt(z);
static_assert(opt->test() == 1);
+ static_assert(opt.operator->() == std::addressof(z));
}
#endif
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const.pass.cpp
index ea62f76d4082a..044134126a374 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const.pass.cpp
@@ -12,11 +12,14 @@
// constexpr const T& optional<T>::value() const &;
-#include <optional>
-#include <type_traits>
#include <cassert>
+#include <memory>
+#include <optional>
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
using std::optional;
using std::in_place_t;
@@ -33,6 +36,38 @@ struct X
int test() && {return 6;}
};
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ {
+ TracedCopyMove x{};
+ const std::optional<TracedCopyMove&> opt(x);
+ ASSERT_NOT_NOEXCEPT(opt.value());
+ ASSERT_SAME_TYPE(decltype(opt.value()), TracedCopyMove&);
+
+ assert(std::addressof(opt.value()) == std::addressof(x));
+ assert(opt->constMove == 0);
+ assert(opt->nonConstMove == 0);
+ assert(opt->constCopy == 0);
+ assert(opt->nonConstCopy == 0);
+ }
+
+ {
+ TracedCopyMove x{};
+ const std::optional<const TracedCopyMove&> opt(x);
+ ASSERT_NOT_NOEXCEPT(opt.value());
+ ASSERT_SAME_TYPE(decltype(opt.value()), const TracedCopyMove&);
+
+ assert(std::addressof(opt.value()) == std::addressof(x));
+ assert(opt->constMove == 0);
+ assert(opt->nonConstMove == 0);
+ assert(opt->constCopy == 0);
+ assert(opt->nonConstCopy == 0);
+ }
+
+ return true;
+}
+#endif
+
int main(int, char**)
{
{
@@ -62,5 +97,10 @@ int main(int, char**)
}
#endif
- return 0;
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_ref());
+#endif
+
+ return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const_rvalue.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const_rvalue.pass.cpp
index 49dbe4e58b57d..66911bf85f5fe 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const_rvalue.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const_rvalue.pass.cpp
@@ -12,11 +12,14 @@
// constexpr const T& optional<T>::value() const &&;
+#include <cassert>
#include <optional>
#include <type_traits>
-#include <cassert>
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+# include "copy_move_types.h"
+#endif
using std::optional;
using std::in_place_t;
@@ -33,6 +36,40 @@ struct X
int test() && {return 6;}
};
+#if TEST_STD_VER >= 26
+constexpr bool test_ref() {
+ {
+ TracedCopyMove x{};
+ const std::optional<TracedCopyMove&> opt(x);
+ ASSERT_NOT_NOEXCEPT(std::move(opt).value());
+ ASSERT_SAME_TYPE(decltype(std::move(opt).value()), TracedCopyMove&);
+
+ assert(std::addressof(std::move(opt).value()) == std::addressof(x));
+ auto& val = std::move(opt).value();
+ assert(val.constMove == 0);
+ assert(val.nonConstMove == 0);
+ assert(val.constCopy == 0);
+ assert(val.nonConstCopy == 0);
+ }
+
+ {
+ TracedCopyMove x{};
+ const std::optional<const TracedCopyMove&> opt(x);
+ ASSERT_NOT_NOEXCEPT(std::move(opt).value());
+ ASSERT_SAME_TYPE(decltype(std::move(opt).value()), const TracedCopyMove&);
+
+ assert(std::addressof(std::move(opt).value()) == std::addressof(x));
+ auto& val = std::move(opt).value();
+ assert(val.constMove == 0);
+ assert(val.nonConstMove == 0);
+ assert(val.constCopy == 0);
+ assert(val.nonConstCopy == 0);
+ }
+
+ return true;
+}
+#endif
+
int main(int, char**)
{
{
@@ -61,6 +98,9 @@ int main(int, char**)
}
}
#endif
-
- return 0;
+#if TEST_STD_VER >= 26
+ assert(test_ref());
+ static_assert(test_ref());
+#endif
+ return 0;
}
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 66890ff9c9b91..f4ad896ed9816 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
@@ -84,6 +84,7 @@ constexpr int test()
{
int y = 2;
optional<int&> opt;
+ ASSERT_SAME_TYPE(decltype(std::move(opt).value_or(y)), int);
assert(std::move(opt).value_or(y) == 2);
assert(!opt);
}
@@ -93,7 +94,8 @@ constexpr int test()
int main(int, char**)
{
- static_assert(test() == 0);
+ assert(test() == 0);
+ static_assert(test() == 0);
return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp
index a82ca615e0c8c..afc1617affe3a 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp
@@ -397,6 +397,51 @@ int main(int, char**)
assert(static_cast<bool>(opt2) == true);
assert(*opt2 == 2);
}
+
+# if TEST_STD_VER >= 26
+ {
+ Z z{1};
+ optional<Z&> opt1{z};
+ optional<Z&> opt2;
+ ASSERT_NOEXCEPT(opt1.swap(opt2));
+ assert(opt1);
+ assert(*opt1 == 1);
+ assert(&(*opt1) == &z);
+ assert(!opt2);
+
+ opt1.swap(opt2);
+ assert(*opt2 == 1);
+ assert(&(*opt2) == &z);
+ assert(opt2 && !opt1);
+ }
+
+ {
+ Z z1{1};
+ optional<Z&> opt1;
+ optional<Z&> opt2{z1};
+ ASSERT_NOEXCEPT(opt1.swap(opt2));
+
+ opt1.swap(opt2);
+ assert(opt1 && !opt2);
+ assert(*opt1 == 1);
+ assert(&(*opt1) == &z1);
+ }
+
+ {
+ Z z1{1};
+ Z z2{2};
+ optional<Z&> opt1{z1};
+ optional<Z&> opt2{z2};
+ ASSERT_NOEXCEPT(opt1.swap(opt2));
+
+ opt1.swap(opt2);
+ assert(opt1 && opt2);
+ assert(*opt1 == 2);
+ assert(*opt2 == 1);
+ assert(&(*opt1) == &z2);
+ assert(&(*opt2) == &z1);
+ }
+# endif
#endif
return 0;
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
new file mode 100644
index 0000000000000..704d99acb15e9
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// TODO: We should consolidate all the helper types used in the optional tests into here.
+
+#include "test_macros.h"
+
+#ifndef LIBCXX_UTILITIES_OPTIONAL_HELPER_TYPES_H
+# define LIBCXX_UTILITIES_OPTIONAL_HELPER_TYPES_H
+
+template <typename T>
+struct ReferenceConversion {
+ T lvalue;
+ T rvalue;
+
+ constexpr ReferenceConversion(T lval, T rval) : lvalue(lval), rvalue(rval) {}
+
+ constexpr operator T&() & noexcept { return lvalue; }
+
+ constexpr operator T&() && noexcept { return rvalue; }
+};
+
+template <typename T>
+struct ReferenceConversionThrows {
+ T lvalue;
+ T rvalue;
+ bool throws{false};
+
+ constexpr ReferenceConversionThrows(T lval, T rval, bool except = false)
+ : lvalue(lval), rvalue(rval), throws(except) {}
+
+ constexpr operator T&() & {
+ if (throws) {
+ TEST_THROW(1);
+ }
+
+ return lvalue;
+ }
+
+ constexpr operator T&() && {
+ if (throws) {
+ TEST_THROW(2);
+ }
+
+ return rvalue;
+ }
+};
+
+#endif
More information about the libcxx-commits
mailing list