[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