[libcxx-commits] [libcxx] [libc++] Add `optional<T&>(optional<U>...)` constraints for ctors shared with `optional<T>` (PR #195759)
William Tran-Viet via libcxx-commits
libcxx-commits at lists.llvm.org
Mon May 4 16:48:48 PDT 2026
https://github.com/smallp-o-p created https://github.com/llvm/llvm-project/pull/195759
- Constraints were missing for some `optional<U>` constructors that were shared with `optional<T>`:
- `const optional<U>&`
- `optional<U>&&`
- Add some tests to verify the `is_constructible<...>` parts of the constraints for all four `optional<U>` constructors.
- As per the LLVM AI policy: Tests were created with assistance of AI.
>From 3b3cf22409bb2e764a9daf1fd147c91d0720e65d Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 4 May 2026 18:40:31 -0400
Subject: [PATCH 1/2] Constraints for optional<T&> optional<U> ctors shared
with optional<T>
---
libcxx/include/optional | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/optional b/libcxx/include/optional
index f7e12f84beba0..ec36cd57412aa 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -953,11 +953,35 @@ private:
}
};
+ template <class _QualUp>
+ struct _CheckOptionalLikeRefConstructor {
+ template <class>
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() {
+ return !is_convertible_v<_QualUp, _Tp&>;
+ }
+
+ template <class>
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() {
+ return is_convertible_v<_QualUp, _Tp&>;
+ }
+
+ template <class>
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_assign() {
+ return false;
+ }
+ };
+
template <class _Up, class _QualUp>
using _CheckOptionalLikeCtor _LIBCPP_NODEBUG =
- _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp> >::value,
- _CheckOptionalLikeConstructor<_QualUp>,
- __check_tuple_constructor_fail >;
+ _If<_And<is_lvalue_reference<_Tp>, // optional<T&>
+ _IsNotSame<__remove_cvref_t<_Tp>, optional<_Up>>,
+ _IsNotSame<_Tp&, _Up>,
+ is_constructible<_Tp&, _QualUp>>::value,
+ _CheckOptionalLikeRefConstructor<_QualUp>,
+ _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp> >::value, // optional<T>
+ _CheckOptionalLikeConstructor<_QualUp>,
+ __check_tuple_constructor_fail > >;
+
template <class _Up, class _QualUp>
using _CheckOptionalLikeAssign _LIBCPP_NODEBUG =
_If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>, is_assignable<_Tp&, _QualUp> >::value,
>From 3151f1540eb5de908bce640dbc5b54e791ed9fb2 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 4 May 2026 19:42:12 -0400
Subject: [PATCH 2/2] Some best-effort tests [AI-assisted]
---
.../const_optional_U.pass.cpp | 12 ++++++++++++
.../optional.object.ctor/optional_U.pass.cpp | 9 +++++++++
.../optional.object/optional_helper_types.h | 16 ++++++++++++++++
3 files changed, 37 insertions(+)
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 844317c8570d9..0961fb21effd6 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
@@ -182,6 +182,18 @@ constexpr bool test_ref() {
static_assert(!std::is_constructible_v<std::optional<int>, const std::optional<ConstRValueOnly<int>>&&>);
+ // optional(const optional<U>&) !is_constructible_v<T&, const U&>.
+ static_assert(std::is_constructible_v<std::optional<int&>, const std::optional<ConstLValueOnly<int>>&>);
+ static_assert(!std::is_constructible_v<std::optional<int&>, const std::optional<LValueOnly<int>>&>);
+ static_assert(!std::is_constructible_v<std::optional<int&>, const std::optional<RValueOnly<int>>&>);
+ static_assert(!std::is_constructible_v<std::optional<int&>, const std::optional<ConstRValueOnly<int>>&>);
+
+ // optional(const optional<U>&&) !is_constructible_v<T&, const U>.
+ static_assert(std::is_constructible_v<std::optional<int&>, const std::optional<ConstLValueOnly<int>>&&>);
+ static_assert(std::is_constructible_v<std::optional<int&>, const std::optional<ConstRValueOnly<int>>&&>);
+ static_assert(!std::is_constructible_v<std::optional<int&>, const std::optional<LValueOnly<int>>&&>);
+ static_assert(!std::is_constructible_v<std::optional<int&>, const std::optional<RValueOnly<int>>&&>);
+
return true;
}
#endif
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 03082033cd4dc..a5d1c50494a75 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
@@ -174,6 +174,15 @@ constexpr bool test_ref() {
ASSERT_NOT_NOEXCEPT(std::optional<const int&>(std::move(o1)));
}
+ // optional(optional<U>&) !is_constructible_v<T&, U&>.
+ static_assert(std::is_constructible_v<std::optional<int&>, std::optional<LValueOnly<int>>&>);
+ static_assert(!std::is_constructible_v<std::optional<int&>, std::optional<RValueOnly<int>>&>);
+ static_assert(!std::is_constructible_v<std::optional<int&>, std::optional<ConstRValueOnly<int>>&>);
+
+ // optional(optional<U>&&) !is_constructible_v<T&, U>.
+ static_assert(std::is_constructible_v<std::optional<int&>, std::optional<RValueOnly<int>>&&>);
+ static_assert(!std::is_constructible_v<std::optional<int&>, std::optional<LValueOnly<int>>&&>);
+
return true;
}
#endif
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
index d9b17a0b91f3b..cf7e12992d224 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h
+++ b/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h
@@ -78,6 +78,22 @@ struct LValueOnly {
constexpr operator T&() const&& = delete;
};
+template <typename T>
+struct ConstLValueOnly {
+ operator T&() & = delete;
+ operator T&() const&;
+ operator T&() && = delete;
+ operator T&() const&& = delete;
+};
+
+template <typename T>
+struct RValueOnly {
+ operator T&() & = delete;
+ operator T&() const& = delete;
+ operator T&() &&;
+ operator T&() const&& = delete;
+};
+
template <typename T>
struct ConstRValueOnly {
mutable T val{};
More information about the libcxx-commits
mailing list