[libcxx-commits] [libcxx] [libc++] Implement Resolution of LWG 3886 (PR #155356)
William Tran-Viet via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Sep 22 16:48:06 PDT 2025
https://github.com/smallp-o-p updated https://github.com/llvm/llvm-project/pull/155356
>From 058889ba8aeda9029ea003baa5ce44484e4e4c25 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 25 Aug 2025 23:56:27 -0400
Subject: [PATCH 1/7] Implement resolution of LWG 3886
---
libcxx/include/__expected/expected.h | 8 ++++----
libcxx/include/optional | 17 +++++++++--------
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 38a34121040f6..8b3eeebd38ae7 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -555,7 +555,7 @@ class expected : private __expected_base<_Tp, _Err> {
is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
: __base(__other.__has_val(), std::move(__other.__union())) {}
- template <class _Up = _Tp>
+ template <class _Up = remove_cv_t<_Tp>>
requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> &&
!is_same_v<remove_cvref_t<_Up>, unexpect_t> && is_constructible_v<_Tp, _Up> &&
!__is_std_unexpected<remove_cvref_t<_Up>>::value &&
@@ -669,7 +669,7 @@ class expected : private __expected_base<_Tp, _Err> {
return *this;
}
- template <class _Up = _Tp>
+ template <class _Up = remove_cv_t<_Tp>>
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(_Up&& __v)
requires(!is_same_v<expected, remove_cvref_t<_Up>> && !__is_std_unexpected<remove_cvref_t<_Up>>::value &&
is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up> &&
@@ -887,14 +887,14 @@ class expected : private __expected_base<_Tp, _Err> {
return std::move(this->__unex());
}
- template <class _Up>
+ template <class _Up = remove_cv_t<_Tp>>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
return this->__has_val() ? this->__val() : static_cast<_Tp>(std::forward<_Up>(__v));
}
- template <class _Up>
+ template <class _Up = remove_cv_t<_Tp>>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 39fcaa2c2ec18..ef1bfd3ec44c0 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -119,7 +119,7 @@ namespace std {
constexpr explicit optional(in_place_t, Args &&...);
template<class U, class... Args>
constexpr explicit optional(in_place_t, initializer_list<U>, Args &&...);
- template<class U = T>
+ template<class U = remove_cv_t<T>>
constexpr explicit(see-below) optional(U &&);
template<class U>
explicit(see-below) optional(const optional<U> &); // constexpr in C++20
@@ -133,7 +133,7 @@ namespace std {
optional &operator=(nullopt_t) noexcept; // constexpr in C++20
constexpr optional &operator=(const optional &);
constexpr optional &operator=(optional &&) noexcept(see below);
- template<class U = T> optional &operator=(U &&); // constexpr in C++20
+ template<class U = remove_cv_t<T>> optional &operator=(U &&); // constexpr in C++20
template<class U> optional &operator=(const optional<U> &); // constexpr in C++20
template<class U> optional &operator=(optional<U> &&); // constexpr in C++20
template<class... Args> T& emplace(Args &&...); // constexpr in C++20
@@ -161,8 +161,8 @@ namespace std {
constexpr T &value() &;
constexpr T &&value() &&;
constexpr const T &&value() const &&;
- template<class U> constexpr T value_or(U &&) const &;
- template<class U> constexpr T value_or(U &&) &&;
+ template<class U = remove_cv_t<T>> constexpr T value_or(U &&) const &;
+ template<class U = remove_cv_t<T>> constexpr T value_or(U &&) &&;
// [optional.monadic], monadic operations
template<class F> constexpr auto and_then(F&& f) &; // since C++23
@@ -730,7 +730,8 @@ public:
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)) {}
- template <class _Up, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0>
+ 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)) {}
// LWG2756: conditionally explicit conversion from const optional<_Up>&
@@ -771,7 +772,7 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(optional&&) = default;
// LWG2756
- template <class _Up = value_type,
+ template <class _Up = remove_cv_t<value_type>,
enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Up>, optional>,
_Or<_IsNotSame<__remove_cvref_t<_Up>, value_type>, _Not<is_scalar<value_type>>>,
is_constructible<value_type, _Up>,
@@ -919,14 +920,14 @@ public:
return std::move(this->__get());
}
- template <class _Up>
+ template <class _Up = remove_cv_t<_Tp>>
_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>
+ template <class _Up = remove_cv_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");
>From 60b72d9616eac1ce412d36a55a71ef7a27526f79 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 26 Aug 2025 22:45:09 -0400
Subject: [PATCH 2/7] Add some extra tests
---
.../expected.expected/ctor/ctor.u.pass.cpp | 28 +++++++++++++++++++
.../optional.object.ctor/U.pass.cpp | 12 +++++++-
.../optional.object.observe/value_or.pass.cpp | 5 ++++
.../value_or_const.pass.cpp | 4 +++
4 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
index 13c0da27bc533..4c16176b6e394 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
@@ -80,6 +80,18 @@ struct CopyOnly {
friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; }
};
+struct MoveOnly2{
+ int j;
+ bool used_move1 = false;
+ bool used_move2 = false;
+
+ constexpr explicit MoveOnly2(int j) : j(j) {}
+ constexpr MoveOnly2(const MoveOnly2&) = delete;
+ constexpr MoveOnly2(MoveOnly2&& m) : j(m.j), used_move1(true) {}
+ constexpr MoveOnly2(const MoveOnly2&& m) : j(m.j), used_move2(true) {}
+
+};
+
struct BaseError {};
struct DerivedError : BaseError {};
@@ -164,6 +176,22 @@ constexpr bool test() {
assert(e2.has_value());
assert(!e2.value()); // yes, e2 holds "false" since LWG3836
}
+
+ // Check move constructor selection
+ {
+ MoveOnly2 t{1};
+ std::expected<MoveOnly2, BaseError> e1(std::move(t));
+ assert(e1.has_value());
+ assert(e1.value().used_move1 == true);
+ assert(e1.value().j == 1);
+ }
+ {
+ const MoveOnly2 t2{2};
+ std::expected<MoveOnly2, BaseError> e1(std::move(t2));
+ assert(e1.has_value());
+ assert(e1.value().used_move2 == true);
+ assert(e1.value().j == 2);
+ }
return true;
}
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 a5ee602ab7bce..edf9fa08d307a 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
@@ -59,7 +59,8 @@ constexpr bool explicit_conversion(Input&& in, const Expect& v)
static_assert(!std::is_constructible<O, void*>::value, "");
static_assert(!std::is_constructible<O, Input, int>::value, "");
optional<To> opt(std::forward<Input>(in));
- return opt && *opt == static_cast<To>(v);
+ optional<To> opt2{std::forward<Input>(in)};
+ return opt && *opt == static_cast<To>(v) && (opt2 && *opt2 == static_cast<To>(v));
}
void test_implicit()
@@ -131,6 +132,15 @@ void test_explicit() {
assert(T::copy_constructed == 0);
assert(t.value().value == 42);
}
+ T::reset();
+ {
+ optional<T> t{43};
+ assert(T::alive == 1);
+ assert(T::value_constructed == 1);
+ assert(T::move_constructed == 0);
+ assert(T::copy_constructed == 0);
+ assert(t.value().value == 43);
+ }
assert(T::alive == 0);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
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 4f9b6993c6f4f..deb65dd0a56d0 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
@@ -64,6 +64,11 @@ constexpr int test()
assert(std::move(opt).value_or(Y(3)) == 4);
assert(!opt);
}
+ {
+ optional<X> opt;
+ assert(std::move(opt).value_or<X>({Y(3)}) == 4);
+ assert(!opt);
+ }
return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
index cf782f1137876..355dae0ea498f 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
@@ -75,6 +75,10 @@ int main(int, char**)
const optional<X> opt;
assert(opt.value_or(Y(3)) == 4);
}
+ {
+ const optional<X> opt;
+ assert(opt.value_or<X>({Y(3)}) == 4);
+ }
return 0;
}
>From d6a94d980f4870aa4b94fd3c3b648ffa938236c7 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 26 Aug 2025 22:50:40 -0400
Subject: [PATCH 3/7] Formatting
---
.../expected/expected.expected/ctor/ctor.u.pass.cpp | 3 +--
.../optional.object.observe/value_or.pass.cpp | 6 +++---
.../optional.object.observe/value_or_const.pass.cpp | 4 ++--
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
index 4c16176b6e394..63f2fb5e947f8 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
@@ -80,7 +80,7 @@ struct CopyOnly {
friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; }
};
-struct MoveOnly2{
+struct MoveOnly2 {
int j;
bool used_move1 = false;
bool used_move2 = false;
@@ -89,7 +89,6 @@ struct MoveOnly2{
constexpr MoveOnly2(const MoveOnly2&) = delete;
constexpr MoveOnly2(MoveOnly2&& m) : j(m.j), used_move1(true) {}
constexpr MoveOnly2(const MoveOnly2&& m) : j(m.j), used_move2(true) {}
-
};
struct BaseError {};
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 deb65dd0a56d0..f67643ef2e4cf 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
@@ -65,9 +65,9 @@ constexpr int test()
assert(!opt);
}
{
- optional<X> opt;
- assert(std::move(opt).value_or<X>({Y(3)}) == 4);
- assert(!opt);
+ optional<X> opt;
+ assert(std::move(opt).value_or<X>({Y(3)}) == 4);
+ assert(!opt);
}
return 0;
}
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
index 355dae0ea498f..5b3ff9131e6ce 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
@@ -76,8 +76,8 @@ int main(int, char**)
assert(opt.value_or(Y(3)) == 4);
}
{
- const optional<X> opt;
- assert(opt.value_or<X>({Y(3)}) == 4);
+ const optional<X> opt;
+ assert(opt.value_or<X>({Y(3)}) == 4);
}
return 0;
>From 9ce787b982d6f09a2e09d0582c90b48747f3d91d Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 26 Aug 2025 22:57:05 -0400
Subject: [PATCH 4/7] Deduce value_or template
---
.../optional.object/optional.object.observe/value_or.pass.cpp | 2 +-
.../optional.object.observe/value_or_const.pass.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
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 f67643ef2e4cf..5f3ca4bbb0b6d 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
@@ -66,7 +66,7 @@ constexpr int test()
}
{
optional<X> opt;
- assert(std::move(opt).value_or<X>({Y(3)}) == 4);
+ assert(std::move(opt).value_or({Y(3)}) == 4);
assert(!opt);
}
return 0;
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
index 5b3ff9131e6ce..ec42890a3b995 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or_const.pass.cpp
@@ -77,7 +77,7 @@ int main(int, char**)
}
{
const optional<X> opt;
- assert(opt.value_or<X>({Y(3)}) == 4);
+ assert(opt.value_or({Y(3)}) == 4);
}
return 0;
>From 1cb7b4040a19acefe2eaefa4a3badc6a34df0a88 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 26 Aug 2025 23:16:42 -0400
Subject: [PATCH 5/7] expect assign, formatting and fix shadow
---
.../assign/assign.U.pass.cpp | 35 +++++++++++++++++++
.../expected.expected/ctor/ctor.u.pass.cpp | 2 +-
.../optional.object.ctor/U.pass.cpp | 12 +++----
3 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
index 807a8af5bb5f6..0c0b0e3546006 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
@@ -325,6 +325,41 @@ constexpr bool test() {
}
}
+ // Check move constructor selection
+ {
+ struct MoveOnlyMulti {
+ bool used_move1 = false;
+ bool used_move2 = false;
+
+ constexpr MoveOnlyMulti() = default;
+ constexpr MoveOnlyMulti(const MoveOnlyMulti&) = delete;
+ constexpr MoveOnlyMulti& operator=(const MoveOnlyMulti&) = delete;
+ constexpr MoveOnlyMulti& operator=(MoveOnlyMulti&&) {
+ used_move1 = true;
+ return *this;
+ }
+ constexpr MoveOnlyMulti& operator=(const MoveOnlyMulti&&) {
+ used_move2 = true;
+ return *this;
+ };
+ constexpr MoveOnlyMulti(MoveOnlyMulti&&) : used_move1(true) {}
+ constexpr MoveOnlyMulti(const MoveOnlyMulti&&) : used_move2(true) {}
+ };
+
+ {
+ MoveOnlyMulti t{};
+ std::expected<MoveOnlyMulti, int> e1(std::unexpect);
+ e1 = std::move(t);
+ assert(e1.value().used_move1);
+ }
+ {
+ const MoveOnlyMulti t{};
+ std::expected<MoveOnlyMulti, int> e1(std::unexpect);
+ e1 = std::move(t);
+ assert(e1.value().used_move2);
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
index 63f2fb5e947f8..fe664dfc97cfe 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
@@ -85,7 +85,7 @@ struct MoveOnly2 {
bool used_move1 = false;
bool used_move2 = false;
- constexpr explicit MoveOnly2(int j) : j(j) {}
+ constexpr explicit MoveOnly2(int jj) : j(jj) {}
constexpr MoveOnly2(const MoveOnly2&) = delete;
constexpr MoveOnly2(MoveOnly2&& m) : j(m.j), used_move1(true) {}
constexpr MoveOnly2(const MoveOnly2&& m) : j(m.j), used_move2(true) {}
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 edf9fa08d307a..9d2badbf145b5 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
@@ -134,12 +134,12 @@ void test_explicit() {
}
T::reset();
{
- optional<T> t{43};
- assert(T::alive == 1);
- assert(T::value_constructed == 1);
- assert(T::move_constructed == 0);
- assert(T::copy_constructed == 0);
- assert(t.value().value == 43);
+ optional<T> t{43};
+ assert(T::alive == 1);
+ assert(T::value_constructed == 1);
+ assert(T::move_constructed == 0);
+ assert(T::copy_constructed == 0);
+ assert(t.value().value == 43);
}
assert(T::alive == 0);
}
>From 84df92eeb3a5d822bba5690dd5811c710a47f054 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Thu, 4 Sep 2025 14:12:20 -0400
Subject: [PATCH 6/7] Update tests
---
.../expected.expected/assign/assign.U.pass.cpp | 9 ++++++---
.../optional.object.ctor/U.pass.cpp | 14 +++++---------
.../optional.object.observe/value_or.pass.cpp | 11 +++++++++++
3 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
index 0c0b0e3546006..795fa77e8338c 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
@@ -349,14 +349,17 @@ constexpr bool test() {
{
MoveOnlyMulti t{};
std::expected<MoveOnlyMulti, int> e1(std::unexpect);
- e1 = std::move(t);
+ static_assert(std::is_same_v<decltype(std::move(t)), MoveOnlyMulti&&>);
+ e1 = {std::move(t)};
assert(e1.value().used_move1);
}
{
const MoveOnlyMulti t{};
std::expected<MoveOnlyMulti, int> e1(std::unexpect);
- e1 = std::move(t);
- assert(e1.value().used_move2);
+ static_assert(std::is_same_v<decltype(std::move(t)), const MoveOnlyMulti&&>);
+ // _Up = remove_cv_t<const MoveOnlyMulti&&> --> should use MoveOnlyMulti(MoveOnlyMulti&&)
+ e1 = {std::move(t)};
+ assert(e1.value().used_move1);
}
}
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 9d2badbf145b5..a90fecfd075fe 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
@@ -84,6 +84,11 @@ void test_implicit()
using T = TestTypes::TestType;
assert(implicit_conversion<T>(3, T(3)));
}
+ {
+ using T = TestTypes::TestType;
+ optional<T> opt({3});
+ assert(opt && *opt == static_cast<T>(3));
+ }
{
using O = optional<ImplicitAny>;
static_assert(!test_convertible<O, std::in_place_t>(), "");
@@ -132,15 +137,6 @@ void test_explicit() {
assert(T::copy_constructed == 0);
assert(t.value().value == 42);
}
- T::reset();
- {
- optional<T> t{43};
- assert(T::alive == 1);
- assert(T::value_constructed == 1);
- assert(T::move_constructed == 0);
- assert(T::copy_constructed == 0);
- assert(t.value().value == 43);
- }
assert(T::alive == 0);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
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 5f3ca4bbb0b6d..8c063ae1a799c 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
@@ -40,6 +40,12 @@ struct X
{return x.i_ == y.i_;}
};
+struct Z {
+ int i_, j_;
+ constexpr Z(int i, int j) : i_(i), j_(j) {}
+ friend constexpr bool operator==(const Z& z1, const Z& z2) { return z1.i_ == z2.i_ && z1.j_ == z2.j_; }
+};
+
constexpr int test()
{
{
@@ -69,6 +75,11 @@ constexpr int test()
assert(std::move(opt).value_or({Y(3)}) == 4);
assert(!opt);
}
+ {
+ optional<Z> opt;
+ assert((std::move(opt).value_or({2, 3}) == Z{2, 3}));
+ assert(!opt);
+ }
return 0;
}
>From acfbf36858cf1c249dd605ae5171058e3a3c4ef6 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 22 Sep 2025 19:47:46 -0400
Subject: [PATCH 7/7] Update Cxx2cIssues.csv (resolve conflict)
---
libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index aaf561982e120..7bf7bc95c8281 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -78,7 +78,7 @@
"","","","","",""
"`LWG3216 <https://wg21.link/LWG3216>`__","Rebinding the allocator before calling ``construct``/``destroy`` in ``allocate_shared``","2024-11 (Wrocław)","","","`#118332 <https://github.com/llvm/llvm-project/issues/118332>`__",""
"`LWG3436 <https://wg21.link/LWG3436>`__","``std::construct_at`` should support arrays","2024-11 (Wrocław)","","","`#118335 <https://github.com/llvm/llvm-project/issues/118335>`__",""
-"`LWG3886 <https://wg21.link/LWG3886>`__","Monad mo' problems","2024-11 (Wrocław)","","","`#118336 <https://github.com/llvm/llvm-project/issues/118336>`__",""
+"`LWG3886 <https://wg21.link/LWG3886>`__","Monad mo' problems","2024-11 (Wrocław)","|Complete|","22","`#118336 <https://github.com/llvm/llvm-project/issues/118336>`__",""
"`LWG3899 <https://wg21.link/LWG3899>`__","``co_yield``\ing elements of an lvalue generator is unnecessarily inefficient","2024-11 (Wrocław)","","","`#118337 <https://github.com/llvm/llvm-project/issues/118337>`__",""
"`LWG3900 <https://wg21.link/LWG3900>`__","The ``allocator_arg_t`` overloads of ``generator::promise_type::operator new`` should not be constrained","2024-11 (Wrocław)","","","`#118338 <https://github.com/llvm/llvm-project/issues/118338>`__",""
"`LWG3918 <https://wg21.link/LWG3918>`__","``std::uninitialized_move/_n`` and guaranteed copy elision","2024-11 (Wrocław)","","","`#118339 <https://github.com/llvm/llvm-project/issues/118339>`__",""
More information about the libcxx-commits
mailing list