[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
Tue Dec 23 13:36:37 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/7] 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/7] 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/7] 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/7] 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/7] 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;

>From a00007060210cdd89b4b58052c54733082b84e89 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 23 Dec 2025 16:30:10 -0500
Subject: [PATCH 6/7] Final clean up of triviality test

---
 .../optional/optional.object/triviality.pass.cpp         | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

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 58aff6fb69e9b..24d864c2fdcff 100644
--- a/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/triviality.pass.cpp
@@ -21,7 +21,6 @@
 // Also test that std::optional<T&> is always trivially copyable.
 
 #include <optional>
-#include <string>
 #include <type_traits>
 
 #include "archetypes.h"
@@ -64,6 +63,7 @@ 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&>>);
     static_assert(std::is_trivially_copy_constructible_v<std::optional<T&>>);
@@ -75,7 +75,6 @@ struct SpecialMemberTest {
     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
 };
 
@@ -111,11 +110,5 @@ int main(int, char**) {
         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 0e1adb6e3efd7418d9be895b893fdc7dc8e40c3e Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 23 Dec 2025 16:36:25 -0500
Subject: [PATCH 7/7] Select trivial base classes all the way through

---
 libcxx/include/optional | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/optional b/libcxx/include/optional
index f92dd46416e57..440fdf73a4310 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -549,7 +549,7 @@ struct __optional_storage_base<_Tp, true> {
   }
 };
 
-template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
+template <class _Tp, bool = is_trivially_copy_constructible_v<_Tp> || is_lvalue_reference_v<_Tp>>
 struct __optional_copy_base : __optional_storage_base<_Tp> {
   using __optional_storage_base<_Tp>::__optional_storage_base;
 };
@@ -569,7 +569,7 @@ struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp> {
   _LIBCPP_HIDE_FROM_ABI __optional_copy_base& operator=(__optional_copy_base&&)      = default;
 };
 
-template <class _Tp, bool = is_trivially_move_constructible<_Tp>::value>
+template <class _Tp, bool = is_trivially_move_constructible_v<_Tp> || is_lvalue_reference_v<_Tp>>
 struct __optional_move_base : __optional_copy_base<_Tp> {
   using __optional_copy_base<_Tp>::__optional_copy_base;
 };



More information about the libcxx-commits mailing list