[libcxx-commits] [libcxx] [libc++] Implement P3836R2: Make `optional<T&>` trivially copyable (PR #171528)
William Tran-Viet via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Dec 22 21:40:31 PST 2025
https://github.com/smallp-o-p updated https://github.com/llvm/llvm-project/pull/171528
>From 12ef0d20e149db7c07ea63e61ff6607af431e826 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 9 Dec 2025 17:22:49 -0500
Subject: [PATCH 1/5] Implement P3836R2
---
libcxx/include/optional | 10 ++++++----
.../optional/optional.object/triviality.pass.cpp | 14 +++++++++++++-
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 95b7d548f2560..b40594953561d 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -592,8 +592,9 @@ struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp> {
};
template <class _Tp,
- bool = is_trivially_destructible<_Tp>::value && is_trivially_copy_constructible<_Tp>::value &&
- is_trivially_copy_assignable<_Tp>::value>
+ bool = (is_trivially_destructible_v<_Tp> && is_trivially_copy_constructible_v<_Tp> &&
+ is_trivially_copy_assignable_v<_Tp>) ||
+ is_lvalue_reference_v<_Tp>>
struct __optional_copy_assign_base : __optional_move_base<_Tp> {
using __optional_move_base<_Tp>::__optional_move_base;
};
@@ -616,8 +617,9 @@ struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp> {
};
template <class _Tp,
- bool = is_trivially_destructible<_Tp>::value && is_trivially_move_constructible<_Tp>::value &&
- is_trivially_move_assignable<_Tp>::value>
+ bool = (is_trivially_destructible_v<_Tp> && is_trivially_move_constructible_v<_Tp> &&
+ is_trivially_move_assignable_v<_Tp>) ||
+ is_lvalue_reference_v<_Tp>>
struct __optional_move_assign_base : __optional_copy_assign_base<_Tp> {
using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
};
diff --git a/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp
index fe760e60cb951..f562458333639 100644
--- a/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp
@@ -17,9 +17,11 @@
// constexpr optional(optional&& rhs) noexcept(see below);
// constexpr optional<T>& operator=(const optional& rhs);
// constexpr optional<T>& operator=(optional&& rhs) noexcept(see below);
-
+//
+// Also test that std::optional<T&> is always trivially copyable.
#include <optional>
+#include <string>
#include <type_traits>
#include "archetypes.h"
@@ -62,6 +64,9 @@ struct SpecialMemberTest {
"trivially move constructible, "
"trivially move assignable, and"
"trivially destructible.");
+#if TEST_STD_VER >= 26
+ static_assert(std::is_trivially_copyable_v<std::optional<T&>>);
+#endif
};
template <class ...Args> static void sink(Args&&...) {}
@@ -95,5 +100,12 @@ int main(int, char**) {
NonTrivialTypes::ApplyTypes<DoTestsMetafunction>{},
DoTestsMetafunction<TrivialMoveNonTrivialCopy, TrivialCopyNonTrivialMove>{}
);
+
+#if TEST_STD_VER >= 26
+ static_assert(std::is_trivially_copyable_v<std::optional<TrivialMoveNonTrivialCopy&>>);
+ static_assert(std::is_trivially_copyable_v<std::optional<TrivialCopyNonTrivialMove&>>);
+ static_assert(std::is_trivially_copyable_v<std::optional<std::string&>>);
+ static_assert(std::is_trivially_copyable_v<std::optional<int&>>);
+#endif
return 0;
}
>From fb6815d8360f6c5c9118bedd5a12794b4dd308ce Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 9 Dec 2025 17:47:14 -0500
Subject: [PATCH 2/5] Update release notes
---
libcxx/docs/ReleaseNotes/22.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 36048165003dd..52f88f73f4f76 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -52,6 +52,7 @@ Implemented Papers
- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
- P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
+- P3836R2: Make ``optional<T&>`` trivially copyable (`Github <https://llvm.org/PR171275>`__)
Improvements and New Features
-----------------------------
>From bcd3aa18154c90c25a52ea2ab4faef939adaab07 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 22 Dec 2025 22:53:33 -0500
Subject: [PATCH 3/5] Add more asserts
---
.../optional/optional.object/triviality.pass.cpp | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp
index f562458333639..58aff6fb69e9b 100644
--- a/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp
@@ -66,6 +66,16 @@ struct SpecialMemberTest {
"trivially destructible.");
#if TEST_STD_VER >= 26
static_assert(std::is_trivially_copyable_v<std::optional<T&>>);
+ static_assert(std::is_trivially_copy_constructible_v<std::optional<T&>>);
+ static_assert(std::is_trivially_move_constructible_v<std::optional<T&>>);
+ static_assert(std::is_trivially_constructible_v<std::optional<T&>, std::optional<T&>&>);
+ static_assert(std::is_trivially_constructible_v<std::optional<T&>, const std::optional<T&>&&>);
+ static_assert(std::is_trivially_copy_assignable_v<std::optional<T&>>);
+ static_assert(std::is_trivially_move_assignable_v<std::optional<T&>>);
+ static_assert(std::is_trivially_assignable_v<std::optional<T&>&, std::optional<T&>&>);
+ static_assert(std::is_trivially_assignable_v<std::optional<T&>&, const std::optional<T&>&&>);
+ static_assert(std::is_trivially_destructible_v<std::optional<T&>>);
+
#endif
};
>From d9dc236f811061474e79d690ff79d17ab967af13 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 22 Dec 2025 22:58:09 -0500
Subject: [PATCH 4/5] Update documentation
---
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index a9904e2d38422..0e780ad3aae24 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -162,7 +162,7 @@
"`P3567R2 <https://wg21.link/P3567R2>`__","``flat_meow`` Fixes","2025-11 (Kona)","|Complete|","22","`#171272 <https://github.com/llvm/llvm-project/issues/171272>`__",""
"`P3663R3 <https://wg21.link/P3663R3>`__","Future-proof ``submdspan_mapping``","2025-11 (Kona)","","","`#166089 <https://github.com/llvm/llvm-project/issues/166089>`__",""
"`P3914R0 <https://wg21.link/P3914R0>`__","Assorted NB comment resolutions for Kona 2025","2025-11 (Kona)","","","`#171274 <https://github.com/llvm/llvm-project/issues/171274>`__",""
-"`P3836R2 <https://wg21.link/P3836R2>`__","Make ``optional<T&>`` trivially copyable","2025-11 (Kona)","","","`#171275 <https://github.com/llvm/llvm-project/issues/171275>`__",""
+"`P3836R2 <https://wg21.link/P3836R2>`__","Make ``optional<T&>`` trivially copyable","2025-11 (Kona)","|Complete|","22","`#171275 <https://github.com/llvm/llvm-project/issues/171275>`__",""
"`P3860R1 <https://wg21.link/P3860R1>`__","Proposed Resolution for NB Comment GB13-309 ``atomic_ref<T>`` is not convertible to ``atomic_ref<const T>``","2025-11 (Kona)","","","`#171276 <https://github.com/llvm/llvm-project/issues/171276>`__",""
"`P3388R3 <https://wg21.link/P3388R3>`__","When Do You Know ``connect`` Doesn’t Throw?","2025-11 (Kona)","","","`#171277 <https://github.com/llvm/llvm-project/issues/171277>`__",""
"`P3774R1 <https://wg21.link/P3774R1>`__","Rename ``std::nontype``, and make it broadly useful","2025-11 (Kona)","","","`#171279 <https://github.com/llvm/llvm-project/issues/171279>`__",""
>From e9aa32731b650f07a9dee30ca996a62f0082f495 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 23 Dec 2025 00:30:02 -0500
Subject: [PATCH 5/5] Make assignment possible if reference
---
libcxx/include/optional | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/optional b/libcxx/include/optional
index b40594953561d..f92dd46416e57 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -648,8 +648,8 @@ using __optional_sfinae_ctor_base_t _LIBCPP_NODEBUG =
template <class _Tp>
using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG =
- __sfinae_assign_base< (is_copy_constructible<_Tp>::value && is_copy_assignable<_Tp>::value),
- (is_move_constructible<_Tp>::value && is_move_assignable<_Tp>::value) >;
+ __sfinae_assign_base< (is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Tp>) || is_lvalue_reference_v<_Tp>,
+ (is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp>) || is_lvalue_reference_v<_Tp>>;
template <class _Tp>
class optional;
More information about the libcxx-commits
mailing list