[libcxx-commits] [libcxx] [libc++] P3450R1: Extend `std::is_within_lifetime` (PR #201053)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jun 2 01:50:08 PDT 2026
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/201053
>From 49b16ceedaade93b6c749c0a3595d5f1d4ceb937 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 2 Jun 2026 16:16:00 +0800
Subject: [PATCH] [libc++] P3450R1: Extend `std::is_within_lifetime`
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +-
libcxx/docs/ReleaseNotes/23.rst | 1 +
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
.../__type_traits/is_within_lifetime.h | 4 +-
libcxx/include/version | 4 +-
.../meta/is_within_lifetime.verify.cpp | 33 +++++-
.../type_traits.version.compile.pass.cpp | 4 +-
.../version.version.compile.pass.cpp | 4 +-
.../is_within_lifetime.compile.pass.cpp | 110 ++++++++++++++++--
.../generate_feature_test_macro_components.py | 4 +-
10 files changed, 142 insertions(+), 26 deletions(-)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 4eb15fa0eb131..32f19124c6b07 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -490,7 +490,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_is_virtual_base_of`` ``202406L``
---------------------------------------------------------- -----------------
- ``__cpp_lib_is_within_lifetime`` ``202306L``
+ ``__cpp_lib_is_within_lifetime`` ``202603L``
---------------------------------------------------------- -----------------
``__cpp_lib_linalg`` *unimplemented*
---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index e94897ffaf437..d3d45f3829490 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -51,6 +51,7 @@ Implemented Papers
- P2542R8: ``views::concat`` (`Github <https://llvm.org/PR105419>`__)
- P3383R3: ``mdspan.at()`` (`Github <https://llvm.org/PR175213>`__)
- P3508R0: Wording for "constexpr for specialized memory algorithms" (`Github <https://llvm.org/PR118379>`__)
+- P3450R1: Extend ``std::is_within_lifetime`` (`Github <https://llvm.org/PR189610>`__)
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 2132e80251657..6484a238163d6 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -198,7 +198,7 @@
"`P3981R2 <https://wg21.link/P3981R2>`__","Better return types in ``std::inplace_vector`` and ``std::exception_ptr_cast``","2026-03 (Croydon)","","","`#189607 <https://github.com/llvm/llvm-project/issues/189607>`__",""
"`P4022R0 <https://wg21.link/P4022R0>`__","Remove ``try_append_range`` from ``inplace_vector`` for now","2026-03 (Croydon)","","","`#189608 <https://github.com/llvm/llvm-project/issues/189608>`__",""
"`P4037R1 <https://wg21.link/P4037R1>`__","Supporting ``signed char`` and ``unsigned char`` in random number generation","2026-03 (Croydon)","","","`#189609 <https://github.com/llvm/llvm-project/issues/189609>`__",""
-"`P3450R1 <https://wg21.link/P3450R1>`__","Extend ``std::is_within_lifetime``","2026-03 (Croydon)","","","`#189610 <https://github.com/llvm/llvm-project/issues/189610>`__",""
+"`P3450R1 <https://wg21.link/P3450R1>`__","Extend ``std::is_within_lifetime``","2026-03 (Croydon)","|Complete|","23","`#189610 <https://github.com/llvm/llvm-project/issues/189610>`__",""
"`P3982R2 <https://wg21.link/P3982R2>`__","Split ``strided_slice`` into ``extent_slice`` and ``range_slice`` for C++26","2026-03 (Croydon)","","","`#189611 <https://github.com/llvm/llvm-project/issues/189611>`__",""
"`P4144R1 <https://wg21.link/P4144R1>`__","Remove ``span``'s ``initializer_list`` constructor for C++26","2026-03 (Croydon)","|Complete|","23","`#189612 <https://github.com/llvm/llvm-project/issues/189612>`__",""
"`P3804R2 <https://wg21.link/P3804R2>`__","Iterating on ``parallel_scheduler``","2026-03 (Croydon)","","","`#189616 <https://github.com/llvm/llvm-project/issues/189616>`__",""
diff --git a/libcxx/include/__type_traits/is_within_lifetime.h b/libcxx/include/__type_traits/is_within_lifetime.h
index c789481cbd124..5f2c6456f8645 100644
--- a/libcxx/include/__type_traits/is_within_lifetime.h
+++ b/libcxx/include/__type_traits/is_within_lifetime.h
@@ -18,9 +18,9 @@
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_within_lifetime)
-template <class _Tp>
+template <class _Up = void, class _Tp>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI consteval bool is_within_lifetime(const _Tp* __p) noexcept {
- return __builtin_is_within_lifetime(__p);
+ return __builtin_is_within_lifetime(__p) && __builtin_constant_p(static_cast<const volatile _Up*>(__p) && true);
}
#endif
diff --git a/libcxx/include/version b/libcxx/include/version
index 471eb3c104b53..c51bb0bb10cbd 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -162,7 +162,7 @@ __cpp_lib_is_scoped_enum 202011L <type_traits>
__cpp_lib_is_sufficiently_aligned 202411L <memory>
__cpp_lib_is_swappable 201603L <type_traits>
__cpp_lib_is_virtual_base_of 202406L <type_traits>
-__cpp_lib_is_within_lifetime 202306L <type_traits>
+__cpp_lib_is_within_lifetime 202603L <type_traits>
__cpp_lib_jthread 201911L <stop_token> <thread>
__cpp_lib_latch 201907L <latch>
__cpp_lib_launder 201606L <new>
@@ -599,7 +599,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_is_virtual_base_of 202406L
# endif
# if __has_builtin(__builtin_is_within_lifetime)
-# define __cpp_lib_is_within_lifetime 202306L
+# define __cpp_lib_is_within_lifetime 202603L
# endif
// # define __cpp_lib_linalg 202311L
# undef __cpp_lib_mdspan
diff --git a/libcxx/test/libcxx/utilities/meta/is_within_lifetime.verify.cpp b/libcxx/test/libcxx/utilities/meta/is_within_lifetime.verify.cpp
index 0aa0f226d63ca..2db8173fa2cda 100644
--- a/libcxx/test/libcxx/utilities/meta/is_within_lifetime.verify.cpp
+++ b/libcxx/test/libcxx/utilities/meta/is_within_lifetime.verify.cpp
@@ -11,16 +11,41 @@
// <type_traits>
+// template<class U = void, class T>
+// consteval bool is_within_lifetime(const T* p) noexcept;
+// Mandates: static_cast<const volatile U*>(p) is well-formed.
+
// LWG4138 <https://cplusplus.github.io/LWG/issue4138>
// std::is_within_lifetime shouldn't work when a function type is
// explicitly specified, even if it isn't evaluated
#include <type_traits>
-template <class T>
+template <class U, class T>
consteval bool checked_is_within_lifetime(T* p) {
- return p ? std::is_within_lifetime<T>(p) : false;
+ return p ? std::is_within_lifetime<U, T>(p) : false;
}
-static_assert(!checked_is_within_lifetime<int>(nullptr));
-static_assert(!checked_is_within_lifetime<void()>(nullptr));
+static_assert(!checked_is_within_lifetime<void, int>(nullptr));
+static_assert(!checked_is_within_lifetime<void, void()>(nullptr));
// expected-error@*:* {{function pointer argument to '__builtin_is_within_lifetime' is not allowed}}
+
+static_assert(!checked_is_within_lifetime<long, int>(nullptr));
+// expected-error@*:* {{static_cast from 'const int *' to 'const volatile long *' is not allowed}}
+static_assert(!checked_is_within_lifetime<int(), int>(nullptr));
+// expected-error@*:* {{static_cast from 'const int *' to 'int (*)()' is not allowed}}
+
+struct B {};
+struct D1 : B {};
+struct D2 : protected B {};
+struct D3 : private B {};
+struct D4 : D1, D2, D3 {};
+struct D5 : virtual B {};
+
+static_assert(!checked_is_within_lifetime<D2, B>(nullptr));
+// expected-error@*:* {{cannot cast protected base class 'const B' to 'const volatile D2'}}
+static_assert(!checked_is_within_lifetime<D3, B>(nullptr));
+// expected-error@*:* {{cannot cast private base class 'const B' to 'const volatile D3'}}
+static_assert(!checked_is_within_lifetime<D4, B>(nullptr));
+// expected-error@*:* {{ambiguous cast from base 'B' to derived 'D4':}}
+static_assert(!checked_is_within_lifetime<D5, B>(nullptr));
+// expected-error@*:* {{cannot cast 'const B *' to 'const volatile D5 *' via virtual base 'B'}}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
index cb5c008f16bb3..c9f06ab95264c 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
@@ -922,8 +922,8 @@
# ifndef __cpp_lib_is_within_lifetime
# error "__cpp_lib_is_within_lifetime should be defined in c++26"
# endif
-# if __cpp_lib_is_within_lifetime != 202306L
-# error "__cpp_lib_is_within_lifetime should have the value 202306L in c++26"
+# if __cpp_lib_is_within_lifetime != 202603L
+# error "__cpp_lib_is_within_lifetime should have the value 202603L in c++26"
# endif
# else
# ifdef __cpp_lib_is_within_lifetime
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 2aa52a64c6cf0..6a0c55fd236c8 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -7360,8 +7360,8 @@
# ifndef __cpp_lib_is_within_lifetime
# error "__cpp_lib_is_within_lifetime should be defined in c++26"
# endif
-# if __cpp_lib_is_within_lifetime != 202306L
-# error "__cpp_lib_is_within_lifetime should have the value 202306L in c++26"
+# if __cpp_lib_is_within_lifetime != 202603L
+# error "__cpp_lib_is_within_lifetime should have the value 202603L in c++26"
# endif
# else
# ifdef __cpp_lib_is_within_lifetime
diff --git a/libcxx/test/std/utilities/meta/meta.const.eval/is_within_lifetime.compile.pass.cpp b/libcxx/test/std/utilities/meta/meta.const.eval/is_within_lifetime.compile.pass.cpp
index f97b400f9a781..79f7611034f66 100644
--- a/libcxx/test/std/utilities/meta/meta.const.eval/is_within_lifetime.compile.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.const.eval/is_within_lifetime.compile.pass.cpp
@@ -11,7 +11,7 @@
// <type_traits>
-// template <class T>
+// template <class U = void, class T>
// consteval bool is_within_lifetime(const T*) noexcept; // C++26
#include <cassert>
@@ -34,6 +34,9 @@ template <class T>
concept is_within_lifetime_exists = requires(T t) { std::is_within_lifetime(t); };
struct S {};
+struct D1 : S {};
+struct D2 : D1 {};
+struct D3 : S {};
static_assert(is_within_lifetime_exists<int*>);
static_assert(is_within_lifetime_exists<const int*>);
@@ -56,10 +59,55 @@ consteval bool f() {
static_assert(std::is_within_lifetime(const_cast<int*>(&i)));
static_assert(std::is_within_lifetime(static_cast<const void*>(&i)));
static_assert(std::is_within_lifetime(static_cast<void*>(const_cast<int*>(&i))));
- static_assert(std::is_within_lifetime<const int>(&i));
- static_assert(std::is_within_lifetime<int>(const_cast<int*>(&i)));
- static_assert(std::is_within_lifetime<const void>(static_cast<const void*>(&i)));
- static_assert(std::is_within_lifetime<void>(static_cast<void*>(const_cast<int*>(&i))));
+ static_assert(std::is_within_lifetime<void, const int>(&i));
+ static_assert(std::is_within_lifetime<void, int>(const_cast<int*>(&i)));
+ static_assert(std::is_within_lifetime<void, const void>(static_cast<const void*>(&i)));
+ static_assert(std::is_within_lifetime<void, void>(static_cast<void*>(const_cast<int*>(&i))));
+ }
+ // Test well-definedness for casting to derived classes with constexpr variables whose lifetime is in a different
+ // constant expression
+ {
+ static constexpr S s;
+ static constexpr D1 d1;
+ static constexpr D2 d2;
+ static constexpr D3 d3;
+
+ static constexpr const S* pbase0 = &s;
+ static constexpr const S* pbase1 = &d1;
+ static constexpr const S* pbase2 = &d2;
+ static constexpr const S* pbase3 = &d3;
+
+ static_assert(std::is_within_lifetime<S>(pbase0));
+ static_assert(std::is_within_lifetime<S>(pbase1));
+ static_assert(std::is_within_lifetime<S>(pbase2));
+ static_assert(std::is_within_lifetime<S>(pbase3));
+
+ static_assert(!std::is_within_lifetime<D1>(pbase0));
+ static_assert(std::is_within_lifetime<D1>(pbase1));
+ static_assert(std::is_within_lifetime<D1>(pbase2));
+ static_assert(!std::is_within_lifetime<D1>(pbase3));
+
+ static_assert(!std::is_within_lifetime<D2>(pbase0));
+ static_assert(!std::is_within_lifetime<D2>(pbase1));
+ static_assert(std::is_within_lifetime<D2>(pbase2));
+ static_assert(!std::is_within_lifetime<D2>(pbase3));
+
+ static_assert(!std::is_within_lifetime<D3>(pbase0));
+ static_assert(!std::is_within_lifetime<D3>(pbase1));
+ static_assert(!std::is_within_lifetime<D3>(pbase2));
+ static_assert(std::is_within_lifetime<D3>(pbase3));
+
+ static constexpr const D1* pmid0 = &d1;
+ static constexpr const D1* pmid1 = &d2;
+
+ static_assert(std::is_within_lifetime<S>(pmid0));
+ static_assert(std::is_within_lifetime<S>(pmid1));
+
+ static_assert(std::is_within_lifetime<D1>(pmid0));
+ static_assert(std::is_within_lifetime<D1>(pmid1));
+
+ static_assert(!std::is_within_lifetime<D2>(pmid0));
+ static_assert(std::is_within_lifetime<D2>(pmid1));
}
{
@@ -78,10 +126,54 @@ consteval bool f() {
assert(std::is_within_lifetime(const_cast<int*>(&i)));
assert(std::is_within_lifetime(static_cast<const void*>(&i)));
assert(std::is_within_lifetime(static_cast<void*>(const_cast<int*>(&i))));
- assert(std::is_within_lifetime<const int>(&i));
- assert(std::is_within_lifetime<int>(const_cast<int*>(&i)));
- assert(std::is_within_lifetime<const void>(static_cast<const void*>(&i)));
- assert(std::is_within_lifetime<void>(static_cast<void*>(const_cast<int*>(&i))));
+ assert((std::is_within_lifetime<void, const int>(&i)));
+ assert((std::is_within_lifetime<void, int>(const_cast<int*>(&i))));
+ assert((std::is_within_lifetime<void, const void>(static_cast<const void*>(&i))));
+ assert((std::is_within_lifetime<void, void>(static_cast<void*>(const_cast<int*>(&i)))));
+ }
+ // Test well-definedness for casting to derived classes with varibles inside the same constant expression
+ {
+ S s;
+ D1 d1;
+ D2 d2;
+ D3 d3;
+
+ S* pbase0 = &s;
+ S* pbase1 = &d1;
+ S* pbase2 = &d2;
+ S* pbase3 = &d3;
+
+ assert(std::is_within_lifetime<S>(pbase0));
+ assert(std::is_within_lifetime<S>(pbase1));
+ assert(std::is_within_lifetime<S>(pbase2));
+ assert(std::is_within_lifetime<S>(pbase3));
+
+ assert(!std::is_within_lifetime<D1>(pbase0));
+ assert(std::is_within_lifetime<D1>(pbase1));
+ assert(std::is_within_lifetime<D1>(pbase2));
+ assert(!std::is_within_lifetime<D1>(pbase3));
+
+ assert(!std::is_within_lifetime<D2>(pbase0));
+ assert(!std::is_within_lifetime<D2>(pbase1));
+ assert(std::is_within_lifetime<D2>(pbase2));
+ assert(!std::is_within_lifetime<D2>(pbase3));
+
+ assert(!std::is_within_lifetime<D3>(pbase0));
+ assert(!std::is_within_lifetime<D3>(pbase1));
+ assert(!std::is_within_lifetime<D3>(pbase2));
+ assert(std::is_within_lifetime<D3>(pbase3));
+
+ D1* pmid0 = &d1;
+ D1* pmid1 = &d2;
+
+ assert(std::is_within_lifetime<S>(pmid0));
+ assert(std::is_within_lifetime<S>(pmid1));
+
+ assert(std::is_within_lifetime<D1>(pmid0));
+ assert(std::is_within_lifetime<D1>(pmid1));
+
+ assert(!std::is_within_lifetime<D2>(pmid0));
+ assert(std::is_within_lifetime<D2>(pmid1));
}
// Anonymous union
{
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 050dab93bea29..fff955853d159 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -876,10 +876,8 @@ def add_version_header(tc):
},
{
"name": "__cpp_lib_is_within_lifetime",
- # Note this name was changed from "__cpp_lib_within_lifetime" when the paper was adopted
- # https://github.com/cplusplus/draft/commit/0facada4cadd97e1ba15bfaea76a804f1dc5c309
"values": {
- "c++26": 202306 # P2641R4 Checking if a union alternative is active
+ "c++26": 202603,
},
"headers": ["type_traits"],
"test_suite_guard": "__has_builtin(__builtin_is_within_lifetime)",
More information about the libcxx-commits
mailing list