On Mon, 14 Sept 2026 at 07:47, Tomasz Kaminski <[email protected]> wrote:
>
>
>
> On Fri, Sep 11, 2026 at 5:01 PM Jakub Jelinek <[email protected]> wrote:
>>
>> Hi!
>>
>> The following patch on top of either of the
>> https://gcc.gnu.org/pipermail/gcc-patches/2026-September/730963.html
>> or
>> https://gcc.gnu.org/pipermail/gcc-patches/2026-September/730509.html
>> patches implements the C++26 P3450R1: Extend std::is_within_lifetime paper
>
> Update the commit description, to list only one that landed now.
>>
>> purely in library by using __builtin_constant_p to verify if the static_cast
>> mandated by the standard is a constant expression.
>>
>> Tested on x86_64-linux (but sure, dependent on the static_cast constexpr
>> diagnostics).
>
> The library parts and test looks good to me.
>>
>>
>> 2026-09-11 Jakub Jelinek <[email protected]>
>>
>> libstdc++-v3/
>> * include/bits/version.def (within_lifetime): Change value from
>> 202306
>> to 202603.
>> * include/bits/version.h: Regenerate.
>> * include/std/type_traits: Implement C++26 P3450R1: Extend
>> std::is_within_lifetime paper.
>> (std::is_within_lifetime): Add _Up template argument defaulted to
>> void
>> and verify static_cast<const volatile _Up*>(__p) is a constant
>> expression.
>> gcc/testsuite/
>> * g++.dg/cpp26/within-lifetime1.C: Fix up C++26 paper number and
>> name.
>> * g++.dg/cpp26/within-lifetime2.C: Likewise.
>> * g++.dg/cpp26/within-lifetime3.C: Likewise.
>> * g++.dg/cpp26/within-lifetime4.C: Likewise.
>> * g++.dg/cpp26/within-lifetime5.C: Likewise.
>> * g++.dg/cpp26/within-lifetime6.C: Likewise.
>> * g++.dg/cpp26/within-lifetime7.C: Likewise.
>> * g++.dg/cpp26/within-lifetime8.C: Likewise.
>> * g++.dg/cpp26/within-lifetime9.C: Likewise.
>> * g++.dg/cpp26/within-lifetime10.C: New test.
>> * g++.dg/cpp26/within-lifetime11.C: New test.
>> * g++.dg/cpp26/within-lifetime12.C: New test.
>>
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C 2026-09-02
>> 10:05:24.582758679 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C 2026-09-11
>> 15:35:07.066126131 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++20 } }
>>
>> #if __has_builtin(__builtin_is_within_lifetime)
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime2.C 2026-09-02
>> 10:05:24.582848012 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime2.C 2026-09-11
>> 15:35:07.066475051 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++20 } }
>>
>> #include "../cpp2a/construct_at.h"
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime3.C 2026-09-10
>> 16:56:41.692638816 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime3.C 2026-09-11
>> 15:35:07.097538005 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++20 } }
>>
>> #include "../cpp2a/construct_at.h"
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime4.C 2026-09-02
>> 10:05:24.583067848 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime4.C 2026-09-11
>> 15:35:07.099604612 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++20 } }
>>
>> template <typename T>
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime5.C 2026-09-02
>> 10:05:24.583169590 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime5.C 2026-09-11
>> 15:35:07.099815970 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++23 } }
>> // { dg-skip-if "sizeof (bool) > 1" { powerpc-*-darwin* } }
>>
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime6.C 2026-09-02
>> 10:05:24.583243076 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime6.C 2026-09-11
>> 15:35:07.099934224 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++26 } }
>> // { dg-skip-if "sizeof (bool) > 1" { powerpc-*-darwin* } }
>>
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime7.C 2026-09-02
>> 10:05:24.583323901 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime7.C 2026-09-11
>> 15:35:07.100119553 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++20 } }
>> // { dg-options "" }
>>
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime8.C 2026-09-10
>> 16:56:41.692638816 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime8.C 2026-09-11
>> 15:35:07.100363967 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++20 } }
>>
>> namespace std {
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime9.C 2026-09-10
>> 16:56:41.692638816 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime9.C 2026-09-11
>> 15:35:07.100529909 +0200
>> @@ -1,4 +1,4 @@
>> -// P3450R1 - Extend std::is_within_lifetime
>> +// P2641R4 - Checking if a union alternative is active
>> // { dg-do compile { target c++20 } }
>>
>> namespace std {
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime10.C 2026-09-11
>> 15:33:06.674144521 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime10.C 2026-09-11
>> 16:11:05.823484997 +0200
>> @@ -0,0 +1,184 @@
>> +// P3450R1 - Extend std::is_within_lifetime
>> +// { dg-do compile { target c++20 } }
>> +
>> +#ifndef USE_HEADER
>> +#if __has_builtin(__builtin_is_within_lifetime)
>> +namespace std {
>> + template <typename U = void, typename T>
>> + consteval bool
>> + is_within_lifetime (const T *p) noexcept
>> + {
>> + return (__builtin_is_within_lifetime (p)
>> + && __builtin_constant_p (static_cast <const volatile U *> (p)
>> + && true));
>> + }
>> +}
>> +#endif
>> +#endif
>> +
>> +consteval int
>> +foo ()
>> +{
>> + char a = 0;
>> + struct B {} b;
>> + struct C : B {} c;
>> + struct D : C {} d;
>> + struct E : B {} e;
>> + if (!std::is_within_lifetime (&a))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <char> (&a))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <char const> (&a))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <char volatile const> (&a))
>> + return __LINE__;
>> + if (!std::is_within_lifetime (&b))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (&b))
>> + return __LINE__;
>> + if (std::is_within_lifetime <C> (&b))
>> + return __LINE__;
>> + if (!std::is_within_lifetime (&c))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (&c))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (&c))
>> + return __LINE__;
>> + B *pb = &b;
>> + B *pc = &c;
>> + B *pd = &d;
>> + B *pe = &e;
>> + if (!std::is_within_lifetime <B> (pb))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pc))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pd))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pe))
>> + return __LINE__;
>> + if (std::is_within_lifetime <C> (pb))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (pc))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (pd))
>> + return __LINE__;
>> + if (std::is_within_lifetime <C> (pe))
>> + return __LINE__;
>> + if (std::is_within_lifetime <D> (pb))
>> + return __LINE__;
>> + if (std::is_within_lifetime <D> (pc))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <D> (pd))
>> + return __LINE__;
>> + if (std::is_within_lifetime <D> (pe))
>> + return __LINE__;
>> + if (std::is_within_lifetime <E> (pb))
>> + return __LINE__;
>> + if (std::is_within_lifetime <E> (pc))
>> + return __LINE__;
>> + if (std::is_within_lifetime <E> (pd))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <E> (pe))
>> + return __LINE__;
>> + C *pf = &c;
>> + C *pg = &d;
>> + if (!std::is_within_lifetime <B> (pf))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pg))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (pf))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (pg))
>> + return __LINE__;
>> + if (std::is_within_lifetime <D> (pf))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <D> (pg))
>> + return __LINE__;
>> + return 0;
>> +}
>> +
>> +static_assert (foo () == 0);
>> +
>> +static constexpr char a = 0;
>> +static constexpr struct B { int b; } b {};
>> +static constexpr struct C : B {} c {};
>> +static constexpr struct D : C {} d {};
>> +static constexpr struct E : B {} e {};
>> +static constexpr const B *pb = &b;
>> +static constexpr const B *pc = &c;
>> +static constexpr const B *pd = &d;
>> +static constexpr const B *pe = &e;
>> +static constexpr const C *pf = &c;
>> +static constexpr const C *pg = &d;
>> +
>> +consteval int
>> +bar ()
>> +{
>> + if (!std::is_within_lifetime (&a))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <char> (&a))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <char const> (&a))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <char volatile const> (&a))
>> + return __LINE__;
>> + if (!std::is_within_lifetime (&b))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (&b))
>> + return __LINE__;
>> + if (std::is_within_lifetime <C> (&b))
>> + return __LINE__;
>> + if (!std::is_within_lifetime (&c))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (&c))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (&c))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pb))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pc))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pd))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pe))
>> + return __LINE__;
>> + if (std::is_within_lifetime <C> (pb))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (pc))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (pd))
>> + return __LINE__;
>> + if (std::is_within_lifetime <C> (pe))
>> + return __LINE__;
>> + if (std::is_within_lifetime <D> (pb))
>> + return __LINE__;
>> + if (std::is_within_lifetime <D> (pc))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <D> (pd))
>> + return __LINE__;
>> + if (std::is_within_lifetime <D> (pe))
>> + return __LINE__;
>> + if (std::is_within_lifetime <E> (pb))
>> + return __LINE__;
>> + if (std::is_within_lifetime <E> (pc))
>> + return __LINE__;
>> + if (std::is_within_lifetime <E> (pd))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <E> (pe))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pf))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <B> (pg))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (pf))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <C> (pg))
>> + return __LINE__;
>> + if (std::is_within_lifetime <D> (pf))
>> + return __LINE__;
>> + if (!std::is_within_lifetime <D> (pg))
>> + return __LINE__;
>> + return 0;
>> +}
>> +
>> +static_assert (bar () == 0);
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime11.C 2026-09-11
>> 16:11:09.842431531 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime11.C 2026-09-11
>> 16:44:42.318753894 +0200
>> @@ -0,0 +1,6 @@
>> +// P3450R1 - Extend std::is_within_lifetime
>> +// { dg-do compile { target c++26 } }
>> +
>> +#include <type_traits>
>> +#define USE_HEADER
>> +#include "within-lifetime10.C"
>> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime12.C 2026-09-11
>> 16:43:26.336762102 +0200
>> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime12.C 2026-09-11
>> 16:49:05.319268463 +0200
>> @@ -0,0 +1,46 @@
>> +// P3450R1 - Extend std::is_within_lifetime
>> +// { dg-do compile { target c++20 } }
>> +
>> +#if __has_builtin(__builtin_is_within_lifetime)
>> +namespace std {
>> + template <typename U = void, typename T>
>> + consteval bool
>> + is_within_lifetime (const T *p) noexcept
>> + {
>> + return (__builtin_is_within_lifetime (p)
>> + && __builtin_constant_p (static_cast <const volatile U *> (p)
>> + && true));
>> +// { dg-error "invalid 'static_cast' from type 'void \\\(\\\*\\\)\\\(\\\)'
>> to type 'const volatile void\\\*'" "" { target *-*-* } .-2 }
>> +// { dg-error "invalid 'static_cast' from type 'const int\\\*' to type
>> 'const volatile long int\\\*'" "" { target *-*-* } .-3 }
>> +// { dg-error "invalid 'static_cast' from type 'const int\\\*' to type 'int
>> \\\(\\\*\\\)\\\(\\\)'" "" { target *-*-* } .-4 }
>> +// { dg-error "'A' is an inaccessible base of 'C'" "" { target *-*-* } .-5 }
>> +// { dg-error "'A' is an inaccessible base of 'D'" "" { target *-*-* } .-6 }
>> +// { dg-error "'A' is an ambiguous base of 'E'" "" { target *-*-* } .-7 }
>> +// { dg-error "cannot convert from pointer to base class 'A' to pointer to
>> derived class 'F' because the base is virtual" "" { target *-*-* } .-8 }
>> + }
>> +}
>> +#endif
>> +
>> +template <typename U, typename T>
>> +consteval bool
>> +baz (T *p)
>> +{
>> + return p ? std::is_within_lifetime <U, T> (p) : false;
>> +}
>> +
>> +static_assert (!baz <void, int> (nullptr));
>> +bool a = baz <void, void ()> (nullptr); // { dg-message
>> "required from here" }
>> +bool b = baz <long, int> (nullptr); // { dg-message "required
>> from here" }
>> +bool c = baz <int (), int> (nullptr); // { dg-message "required
>> from here" }
>> +
>> +struct A {};
>> +struct B : A {};
>> +struct C : protected A {};
>> +struct D : private A {};
>> +struct E : B, C, D {};
>> +struct F : virtual A {};
>> +
>> +bool d = baz <C, A> (nullptr); // { dg-message "required
>> from here" }
>> +bool e = baz <D, A> (nullptr); // { dg-message "required
>> from here" }
>> +bool f = baz <E, A> (nullptr); // { dg-message "required
>> from here" }
>> +bool g = baz <F, A> (nullptr); // { dg-message "required
>> from here" }
>> --- a/libstdc++-v3/include/bits/version.def 2026-09-11
>> 09:31:04.133777237 +0200
>> +++ b/libstdc++-v3/include/bits/version.def 2026-09-11
>> 15:29:05.587360771 +0200
>> @@ -2503,7 +2503,7 @@ ftms = {
>> ftms = {
>> name = within_lifetime;
>> values = {
>> - v = 202306;
>
> If there are multiple values of FTM in one standard, I prefer to have a
> comment listing them,
> like:
> // 202306 P2641R4 Checking if a union alternative is active
> // 202603 P3450R1 Extend std::is_within_lifetime
Yes please.
The library parts are OK with Tomasz's suggestions.
>>
>> + v = 202603;
>> cxxmin = 26;
>> extra_cond = "__has_builtin(__builtin_is_within_lifetime)";
>> };
>> --- a/libstdc++-v3/include/bits/version.h 2026-09-11
>> 09:31:04.134777224 +0200
>> +++ b/libstdc++-v3/include/bits/version.h 2026-09-11
>> 15:29:13.205141481 +0200
>> @@ -2756,9 +2756,9 @@
>>
>> #if !defined(__cpp_lib_within_lifetime)
>> # if (__cplusplus > 202302L) &&
>> (__has_builtin(__builtin_is_within_lifetime))
>> -# define __glibcxx_within_lifetime 202306L
>> +# define __glibcxx_within_lifetime 202603L
>> # if defined(__glibcxx_want_all) || defined(__glibcxx_want_within_lifetime)
>> -# define __cpp_lib_within_lifetime 202306L
>> +# define __cpp_lib_within_lifetime 202603L
>> # endif
>> # endif
>> #endif /* !defined(__cpp_lib_within_lifetime) */
>> --- a/libstdc++-v3/include/std/type_traits 2026-09-02
>> 10:05:24.584679822 +0200
>> +++ b/libstdc++-v3/include/std/type_traits 2026-09-11
>> 15:50:40.296411640 +0200
>> @@ -4402,10 +4402,14 @@ template<typename _Ret, typename _Fn, ty
>> #endif // C++11
>>
>> #if __cpp_lib_within_lifetime >= 202306L // C++ >= 26
>
> I would update the value checked here, as we have a different signature than
> the one required for 202306L,
> or just say #ifdef __glibcxx_within_lifetime
>>
>> - template<typename _Tp>
>> + template<typename _Up = void, typename _Tp>
>> 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
>>
>> /// @} group metaprogramming
>>
>> Jakub
>>