https://gcc.gnu.org/g:4442e8b6cbffd113ec7bd25f449cc18f104f7150

commit r17-4233-g4442e8b6cbffd113ec7bd25f449cc18f104f7150
Author: Jakub Jelinek <[email protected]>
Date:   Mon Sep 14 18:17:32 2026 +0200

    libstdc++, testsuite: Implement C++26 P3450R1: Extend 
std::is_within_lifetime paper
    
    Now that r17-4186 fixed constexpr evaluation of static_cast downcasts to 
diagnose
    UB, this patch implements the C++26 P3450R1: Extend std::is_within_lifetime 
paper
    purely in library by using __builtin_constant_p to verify if the static_cast
    mandated by the standard is a constant expression.
    
    2026-09-14  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.
    
    Reviewed-by: Jonathan Wakely <[email protected]>

Diff:
---
 gcc/testsuite/g++.dg/cpp26/within-lifetime1.C  |   2 +-
 gcc/testsuite/g++.dg/cpp26/within-lifetime10.C | 184 +++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp26/within-lifetime11.C |   6 +
 gcc/testsuite/g++.dg/cpp26/within-lifetime12.C |  46 +++++++
 gcc/testsuite/g++.dg/cpp26/within-lifetime2.C  |   2 +-
 gcc/testsuite/g++.dg/cpp26/within-lifetime3.C  |   2 +-
 gcc/testsuite/g++.dg/cpp26/within-lifetime4.C  |   2 +-
 gcc/testsuite/g++.dg/cpp26/within-lifetime5.C  |   2 +-
 gcc/testsuite/g++.dg/cpp26/within-lifetime6.C  |   2 +-
 gcc/testsuite/g++.dg/cpp26/within-lifetime7.C  |   2 +-
 gcc/testsuite/g++.dg/cpp26/within-lifetime8.C  |   2 +-
 gcc/testsuite/g++.dg/cpp26/within-lifetime9.C  |   2 +-
 libstdc++-v3/include/bits/version.def          |   4 +-
 libstdc++-v3/include/bits/version.h            |   4 +-
 libstdc++-v3/include/std/type_traits           |  10 +-
 15 files changed, 257 insertions(+), 15 deletions(-)

diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C
index e5ce7bdb830c..54e21525abfc 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C
@@ -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)
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime10.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime10.C
new file mode 100644
index 000000000000..45cbbaaf52f7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime10.C
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime11.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime11.C
new file mode 100644
index 000000000000..0624abebca43
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime11.C
@@ -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"
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime12.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime12.C
new file mode 100644
index 000000000000..5381118a4b1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime12.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime2.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime2.C
index dc0544848f7f..469e783dde1b 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime2.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime2.C
@@ -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"
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime3.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime3.C
index 36afd2ef3f26..972039c3b700 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime3.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime3.C
@@ -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"
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime4.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime4.C
index b420dea5fe2d..1cb895d4bf1e 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime4.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime4.C
@@ -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>
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime5.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime5.C
index 1f780cf13d58..1b96fe2f3c3c 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime5.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime5.C
@@ -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* } }
 
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime6.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime6.C
index 6e9ddf917bdc..ef2544e445e4 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime6.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime6.C
@@ -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* } }
 
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime7.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime7.C
index d920f5aee0cd..48098e8f2f66 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime7.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime7.C
@@ -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 "" }
 
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime8.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime8.C
index 98bfde2077fc..5a28f92ffb4d 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime8.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime8.C
@@ -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 {
diff --git a/gcc/testsuite/g++.dg/cpp26/within-lifetime9.C 
b/gcc/testsuite/g++.dg/cpp26/within-lifetime9.C
index 905d54400bcd..d9751e4d8737 100644
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime9.C
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime9.C
@@ -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 {
diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 36f8c9c31cf4..9c523581c65a 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -2520,8 +2520,10 @@ ftms = {
 
 ftms = {
   name = within_lifetime;
+  // 202306 P2641R4 Checking if a union alternative is active
+  // 202603 P3450R1 Extend std::is_within_lifetime
   values = {
-    v = 202306;
+    v = 202603;
     cxxmin = 26;
     extra_cond = "__has_builtin(__builtin_is_within_lifetime)";
   };
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index e79ea5043d74..e0003054af68 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2776,9 +2776,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) */
diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index 921ef287f839..83dbad17ade9 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -4401,11 +4401,15 @@ template<typename _Ret, typename _Fn, typename... _Args>
     };
 #endif // C++11
 
-#if __cpp_lib_within_lifetime >= 202306L // C++ >= 26
-  template<typename _Tp>
+#if __cpp_lib_within_lifetime >= 202603L // C++ >= 26
+  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

Reply via email to