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 > + 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 > >
