On Fri, 29 Aug 2025, Jakub Jelinek wrote:

> Hi!
> 
> Here is a variant of the patch which pretends there are also stores
> in the inline asms.
> Plus the forgotten std.cc exports.

Can you add a testcase on actual constant objects?  I wonder why
we do not diagnose asm outputs on such?

> 2025-08-29  Jakub Jelinek  <[email protected]>
> 
>       * include/bits/version.def: Implement C++23 P2590R2 - Explicit
>       lifetime management.
>       (start_lifetime_as): New.
>       * include/bits/version.h: Regenerate.
>       * include/std/memory (std::start_lifetime_as,
>       std::start_lifetime_as_array): New function templates.
>       * src/c++23/std.cc.in (std::start_lifetime_as,
>       std::start_lifetime_as_array): Export.
>       * testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc: New test.
> 
> --- libstdc++-v3/include/bits/version.def.jj  2025-08-28 17:06:44.190031458 
> +0200
> +++ libstdc++-v3/include/bits/version.def     2025-08-28 18:44:00.947678928 
> +0200
> @@ -2100,6 +2100,14 @@ ftms = {
>    };
>  };
>  
> +ftms = {
> +  name = start_lifetime_as;
> +  values = {
> +    v =  202207;
> +    cxxmin = 23;
> +  };
> +};
> +
>  // Standard test specifications.
>  stds[97] = ">= 199711L";
>  stds[03] = ">= 199711L";
> --- libstdc++-v3/include/bits/version.h.jj    2025-08-28 17:06:49.160883915 
> +0200
> +++ libstdc++-v3/include/bits/version.h       2025-08-28 18:44:08.431550790 
> +0200
> @@ -2353,4 +2353,14 @@
>  #endif /* !defined(__cpp_lib_is_implicit_lifetime) && 
> defined(__glibcxx_want_is_implicit_lifetime) */
>  #undef __glibcxx_want_is_implicit_lifetime
>  
> +#if !defined(__cpp_lib_start_lifetime_as)
> +# if (__cplusplus >= 202100L)
> +#  define __glibcxx_start_lifetime_as 202207L
> +#  if defined(__glibcxx_want_all) || 
> defined(__glibcxx_want_start_lifetime_as)
> +#   define __cpp_lib_start_lifetime_as 202207L
> +#  endif
> +# endif
> +#endif /* !defined(__cpp_lib_start_lifetime_as) && 
> defined(__glibcxx_want_start_lifetime_as) */
> +#undef __glibcxx_want_start_lifetime_as
> +
>  #undef __glibcxx_want_all
> --- libstdc++-v3/include/std/memory.jj        2025-08-23 15:00:05.208775420 
> +0200
> +++ libstdc++-v3/include/std/memory   2025-08-29 09:21:59.402103595 +0200
> @@ -120,6 +120,7 @@
>  #define __glibcxx_want_shared_ptr_arrays
>  #define __glibcxx_want_shared_ptr_weak_type
>  #define __glibcxx_want_smart_ptr_for_overwrite
> +#define __glibcxx_want_start_lifetime_as
>  #define __glibcxx_want_to_address
>  #define __glibcxx_want_transparent_operators
>  #define __glibcxx_want_smart_ptr_owner_equality
> @@ -172,6 +173,134 @@ _GLIBCXX_END_NAMESPACE_VERSION
>  } // namespace
>  #endif // C++11 to C++20
>  
> +#if __cpp_lib_start_lifetime_as >= 202207L // C++ >= 23
> +namespace std _GLIBCXX_VISIBILITY(default)
> +{
> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
> +  template<typename _Tp>
> +    [[__gnu__::__always_inline__]]
> +    inline _Tp*
> +    start_lifetime_as(void* __p) noexcept
> +    {
> +#if __cpp_lib_is_implicit_lifetime >= 202302L
> +      static_assert(is_implicit_lifetime_v<_Tp>);
> +#endif
> +      auto __q = reinterpret_cast<_Tp*>(__p);
> +      __asm__ __volatile__("" : "=g" (__q), "=m" (*__q)
> +                        : "0" (__q), "m" (*__q));
> +      return __q;
> +    }
> +
> +  template<typename _Tp>
> +    [[__gnu__::__always_inline__]]
> +    inline const _Tp*
> +    start_lifetime_as(const void* __p) noexcept
> +    {
> +#if __cpp_lib_is_implicit_lifetime >= 202302L
> +      static_assert(is_implicit_lifetime_v<_Tp>);
> +#endif
> +      auto __q = reinterpret_cast<const _Tp*>(__p);
> +      auto __r = reinterpret_cast<_Tp*>(const_cast<void*>(__p));
> +      __asm__ __volatile__("" : "=g" (__q), "=m" (*__r)
> +                        : "0" (__q), "m" (*__q));
> +      return __q;
> +    }
> +
> +  template<typename _Tp>
> +    [[__gnu__::__always_inline__]]
> +    inline volatile _Tp*
> +    start_lifetime_as(volatile void* __p) noexcept
> +    {
> +#if __cpp_lib_is_implicit_lifetime >= 202302L
> +      static_assert(is_implicit_lifetime_v<_Tp>);
> +#endif
> +      auto __q = reinterpret_cast<volatile _Tp*>(__p);
> +      auto __r = reinterpret_cast<_Tp*>(const_cast<void*>(__p));
> +      __asm__ __volatile__("" : "=g" (__q), "=m" (*__r)
> +                        : "0" (__q), "m" (*__q));
> +      return __q;
> +    }
> +
> +  template<typename _Tp>
> +    [[__gnu__::__always_inline__]]
> +    inline const volatile _Tp*
> +    start_lifetime_as(const volatile void* __p) noexcept
> +    {
> +#if __cpp_lib_is_implicit_lifetime >= 202302L
> +      static_assert(is_implicit_lifetime_v<_Tp>);
> +#endif
> +      auto __q = reinterpret_cast<const volatile _Tp*>(__p);
> +      auto __r = reinterpret_cast<_Tp*>(const_cast<void*>(__p));
> +      __asm__ __volatile__("" : "=g" (__q), "=m" (*__r)
> +                        : "0" (__q), "m" (*__q));
> +      return __q;
> +    }
> +
> +  template<typename _Tp>
> +    [[__gnu__::__always_inline__]]
> +    inline _Tp*
> +    start_lifetime_as_array(void* __p, size_t __n) noexcept
> +    {
> +      auto __q = reinterpret_cast<_Tp*>(__p);
> +      if (!__n)
> +     return __q;
> +      auto __r = (__extension__ reinterpret_cast<_Tp(*)[__n]>(__p));
> +      __asm__ __volatile__("" : "=g" (__q), "=m" (*__r)
> +                        : "0" (__q), "m" (*__r));
> +      return __q;
> +    }
> +
> +  template<typename _Tp>
> +    [[__gnu__::__always_inline__]]
> +    inline const _Tp*
> +    start_lifetime_as_array(const void* __p, size_t __n) noexcept
> +    {
> +      auto __q = reinterpret_cast<const _Tp*>(__p);
> +      if (!__n)
> +     return __q;
> +      auto __r = (__extension__ reinterpret_cast<const _Tp(*)[__n]>(__p));
> +      auto __s = (__extension__
> +               reinterpret_cast<_Tp(*)[__n]>(const_cast<void*>(__p)));
> +      __asm__ __volatile__("" : "=g" (__q), "=m" (*__s)
> +                        : "0" (__q), "m" (*__r));
> +      return __q;
> +    }
> +
> +  template<typename _Tp>
> +    [[__gnu__::__always_inline__]]
> +    inline volatile _Tp*
> +    start_lifetime_as_array(volatile void* __p, size_t __n) noexcept
> +    {
> +      auto __q = reinterpret_cast<volatile _Tp*>(__p);
> +      if (!__n)
> +     return __q;
> +      auto __r = (__extension__ reinterpret_cast<volatile _Tp(*)[__n]>(__p));
> +      auto __s = (__extension__
> +               reinterpret_cast<_Tp(*)[__n]>(const_cast<void*>(__p)));
> +      __asm__ __volatile__("" : "=g" (__q), "=m" (*__s)
> +                        : "0" (__q), "m" (*__r));
> +      return __q;
> +    }
> +
> +  template<typename _Tp>
> +    [[__gnu__::__always_inline__]]
> +    inline const volatile _Tp*
> +    start_lifetime_as_array(const volatile void* __p, size_t __n) noexcept
> +    {
> +      auto __q = reinterpret_cast<const volatile _Tp*>(__p);
> +      if (!__n)
> +     return __q;
> +      auto __r = (__extension__ reinterpret_cast<const volatile 
> _Tp(*)[__n]>(__p));
> +      auto __s = (__extension__
> +               reinterpret_cast<_Tp(*)[__n]>(const_cast<void*>(__p)));
> +      __asm__ __volatile__("" : "=g" (__q), "=m" (*__s)
> +                        : "0" (__q), "m" (*__r));
> +      return __q;
> +    }
> +_GLIBCXX_END_NAMESPACE_VERSION
> +} // namespace
> +#endif
> +
>  #ifdef __cpp_lib_parallel_algorithm // C++ >= 17 && HOSTED
>  // Parallel STL algorithms
>  # if _PSTL_EXECUTION_POLICIES_DEFINED
> --- libstdc++-v3/src/c++23/std.cc.in.jj       2025-08-28 17:10:43.784942152 
> +0200
> +++ libstdc++-v3/src/c++23/std.cc.in  2025-08-29 09:55:46.164636222 +0200
> @@ -2004,6 +2004,10 @@ export namespace std
>    using std::owner_equal;
>    using std::owner_hash;
>  #endif
> +#if __cpp_lib_start_lifetime_as
> +  using std::start_lifetime_as;
> +  using std::start_lifetime_as_array;
> +#endif
>  }
>  
>  // 20.4 <memory_resource>
> --- 
> libstdc++-v3/testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc.jj   
>     2025-08-28 19:29:12.865001523 +0200
> +++ libstdc++-v3/testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc  
> 2025-08-28 19:56:44.975864728 +0200
> @@ -0,0 +1,68 @@
> +// { dg-do run { target c++23 } }
> +
> +#include <bit>
> +#include <memory>
> +
> +#include <testsuite_hooks.h>
> +#include <testsuite_allocator.h>
> +
> +struct S { int a; int b; };
> +struct T { long long c; };
> +
> +void
> +test01()
> +{
> +  if (sizeof(S) != sizeof(T))
> +    return;
> +
> +  union U { unsigned char a[sizeof(S)]; S b; T c; } u;
> +  u.a[0] = 1;
> +  T v = std::bit_cast<T> (S{1, 2});
> +  union V { unsigned char a[3 * sizeof(S)]; S b[3]; T c[3]; } w;
> +  T x = std::bit_cast<T> (S{3, 4});
> +  T y = std::bit_cast<T> (S{5, 6});
> +  S* d = std::start_lifetime_as<S>(reinterpret_cast<void*>(&u.a));
> +  d->a = 1;
> +  d->b = 2;
> +  T* e = std::start_lifetime_as<T>(reinterpret_cast<void*>(d));
> +  VERIFY( e->c == v.c );
> +  const T* f = std::start_lifetime_as<T>(reinterpret_cast<const void*>(d));
> +  VERIFY( f->c == v.c );
> +  volatile T* g = std::start_lifetime_as<T>(reinterpret_cast<volatile 
> void*>(d));
> +  VERIFY( g->c == v.c );
> +  const volatile T* h = std::start_lifetime_as<T>(reinterpret_cast<const 
> volatile void*>(d));
> +  VERIFY( h->c == v.c );
> +  S* i = std::start_lifetime_as_array<S>(reinterpret_cast<void*>(&w.a), 3);
> +  i[0].a = 1;
> +  i[0].b = 2;
> +  i[1].a = 3;
> +  i[1].b = 4;
> +  i[2].a = 5;
> +  i[2].b = 6;
> +  T* j = std::start_lifetime_as_array<T>(reinterpret_cast<void*>(i), 3);
> +  VERIFY( j[0].c == v.c && j[1].c == x.c && j[2].c == y.c );
> +  const T* k = std::start_lifetime_as_array<T>(reinterpret_cast<const 
> void*>(i), 3);
> +  VERIFY( k[0].c == v.c && k[1].c == x.c && k[2].c == y.c );
> +  volatile T* l = std::start_lifetime_as_array<T>(reinterpret_cast<volatile 
> void*>(i), 3);
> +  VERIFY( l[0].c == v.c && l[1].c == x.c && l[2].c == y.c );
> +  const volatile T* m = 
> std::start_lifetime_as_array<T>(reinterpret_cast<const volatile void*>(i), 3);
> +  VERIFY( m[0].c == v.c && m[1].c == x.c && m[2].c == y.c );
> +  T* n = std::start_lifetime_as_array<T>(static_cast<void*>(nullptr), 0);
> +  VERIFY( n == nullptr );
> +  const T* o = std::start_lifetime_as_array<T>(static_cast<const 
> void*>(nullptr), 0);
> +  VERIFY( o == nullptr );
> +  volatile T* p = std::start_lifetime_as_array<T>(static_cast<volatile 
> void*>(nullptr), 0);
> +  VERIFY( p == nullptr );
> +  const volatile T* q = std::start_lifetime_as_array<T>(static_cast<const 
> volatile void*>(nullptr), 0);
> +  VERIFY( q == nullptr );
> +  VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<void*>(&w.a), 0) 
> == &w.c[0] );
> +  VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<const 
> void*>(&w.a), 0) == static_cast<const T*>(&w.c[0]) );
> +  VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<volatile 
> void*>(&w.a), 0) == static_cast<volatile T*>(&w.c[0]) );
> +  VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<const volatile 
> void*>(&w.a), 0) == static_cast<const volatile T*>(&w.c[0]) );
> +}
> +
> +int
> +main()
> +{
> +  test01();
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to