[libcxx-commits] [libcxx] [libc++] Allow a disengaged `optional` to be `constexpr` since C++20 (PR #192888)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Apr 19 20:17:21 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: A. Jiang (frederick-vs-ja)

<details>
<summary>Changes</summary>

Currently, GCC and Clang haven't implemented CWG2424, and still require a union in a `constexpr` object to have exactly one active member. As a result, when a `optional<T>`, where `T` is not trivially destructible, is disengaged, the `__null_state_` member still needs to be activated if we need to create a `constexpr` object.

Fixes #<!-- -->192852.

---
Full diff: https://github.com/llvm/llvm-project/pull/192888.diff


3 Files Affected:

- (modified) libcxx/include/optional (+6) 
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp (+20) 
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp (+19) 


``````````diff
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 9eed886aa4636..9a1a7840180ba 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -402,6 +402,12 @@ struct __optional_destruct_base<_Tp, false> {
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept {
     if (__engaged_) {
       __val_.~value_type();
+      // TODO: Remove the workaround when supported compilers have CWG2424 implemented.
+#    if _LIBCPP_STD_VER >= 20
+      if consteval {
+        __null_state_ = char{};
+      }
+#    endif
       __engaged_ = false;
     }
   }
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 e85c0c435aa37..8aea6c142ff66 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
@@ -62,6 +62,26 @@ TEST_CONSTEXPR_CXX20 bool test()
         assert(static_cast<bool>(opt) == false);
     }
 
+#if TEST_STD_VER >= 20
+    {
+      // https://llvm.org/PR192852
+      // Verify that a disengaged optional<T> can also be constexpr, where T is not trivially destructible.
+
+      struct NonTriviallyDestructible {
+        constexpr NonTriviallyDestructible() {}
+        constexpr ~NonTriviallyDestructible() {}
+      };
+
+      struct Derived : optional<NonTriviallyDestructible> {
+        using Base = optional<NonTriviallyDestructible>;
+
+        constexpr Derived() : Base(std::in_place) { static_cast<Base&>(*this) = nullopt; }
+      };
+
+      [[maybe_unused]] constexpr Derived d;
+    }
+#endif
+
 #if TEST_STD_VER >= 26
     {
       int i = 0;
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 a7ae22861d32e..9cf462284a05d 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
@@ -43,6 +43,25 @@ TEST_CONSTEXPR_CXX20 bool check_reset() {
     opt.reset();
     assert(static_cast<bool>(opt) == false);
   }
+#if TEST_STD_VER >= 20
+  {
+    // https://llvm.org/PR192852
+    // Verify that a disengaged optional<T> can also be constexpr, where T is not trivially destructible.
+
+    struct NonTriviallyDestructible {
+      constexpr NonTriviallyDestructible() {}
+      constexpr ~NonTriviallyDestructible() {}
+    };
+
+    struct Derived : optional<NonTriviallyDestructible> {
+      using Base = optional<NonTriviallyDestructible>;
+
+      constexpr Derived() : Base(std::in_place) { Base::reset(); }
+    };
+
+    [[maybe_unused]] constexpr Derived d;
+  }
+#endif
   return true;
 }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/192888


More information about the libcxx-commits mailing list