[PATCH] c++, libstdc++: Implement C++23 P2674R1 - A trait for implicit lifetime types
Tomasz Kaminski
tkaminsk@redhat.com
Thu Aug 28 16:06:28 GMT 2025
On Thu, Aug 28, 2025 at 5:54 PM Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> The following patch attempts to implement the C++23 P2674R1
> paper. As mentioned in the paper, since CWG2605 the trait
> isn't really implementable purely on the library side.
>
> Because it is implemented completely on the compiler side, it
> just uses SCALAR_TYPE_P and so can e.g. accept __int128 even in
> -std=c++23 mode, even when std::is_scalar_v<__int128> is false in
> that case. And as an extention it (like Clang) accepts _Complex
> types and vector types.
> I must say I'm quite surprised that any array types are considered
> implicit-lifetime, even if their element type is not, but perhaps
> there is some reason for that.
>
One of the goals of implicit lifetime and implicit object creation was
to fix UB in vector or in general when some memory is allocated,
and then treated as array:
int* x = (int*)malloc(...);
// before implicit object creation UB, because there is no array object, so
pointer arithmetic does not work.
// with arrays being implicit lifetime, malloc creates array object
x[3] = 20;
There are also additional cases, I do not see being tested. Any aggregate
with no-user provided destructor is implicit lifetime (
https://eel.is/c++draft/class.prop#16.1),
even if the destructor would be non-trivial. So again things like:
struct S { int a; int b; };
S* s = (S*)malloc(...);
s->a = 10;
For example, this type should be implicit lifetime (std:::string obviously
isn't):
struct S1 { std::string a; std::string b; };
And also this one:
struct S2 { std::string a; std::string b; ~S2() = default; };
But not this:
struct S3 { std::string a; std::string b; ~S3() {} };
Because aggregates can also now have base classes, similar rules
apply to base classes.
I would like to see a test for above cases, of course not on std::string,
but one of the implicit lifetime types that you have, like Q.
> Because std::is_array_v<int[0]> is false, it returns false for that
> as well, dunno if that shouldn't be changed for implicit-lifetime.
> It accepts also VLAs.
>
> Tested on x86_64-linux, ok for trunk?
>
> 2025-08-28 Jakub Jelinek <jakub@redhat.com>
>
> gcc/cp/
> * cp-trait.def: Implement C++23 P2674R1 - A trait for implicit
> lifetime types.
> (IS_IMPLICIT_LIFETIME): New unary trait.
> * semantics.cc (trait_expr_value): Handle
> CPTK_IS_IMPLICIT_LIFETIME.
> (finish_trait_expr): Likewise.
> * constraint.cc (diagnose_trait_expr): Likewise.
> gcc/testsuite/
> * g++.dg/ext/is_implicit_lifetime.C: New test.
> libstdc++-v3/
> * include/bits/version.def (is_implicit_lifetime): New.
> * include/bits/version.h: Regenerate.
> * include/std/type_traits (std::is_implicit_lifetime,
> std::is_implicit_lifetime_v): New trait.
> * src/c++23/std.cc.in (std::is_implicit_lifetime,
> std::is_implicit_lifetime_v): Export.
> * testsuite/20_util/is_implicit_lifetime/version.cc: New test.
> * testsuite/20_util/is_implicit_lifetime/value.cc: New test.
>
> --- gcc/cp/cp-trait.def.jj 2025-08-15 22:38:28.866872528 +0200
> +++ gcc/cp/cp-trait.def 2025-08-28 14:40:24.828249392 +0200
> @@ -76,6 +76,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1
> DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
> DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
> DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
> +DEFTRAIT_EXPR (IS_IMPLICIT_LIFETIME, "__builtin_is_implicit_lifetime", 1)
> DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
> DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
> DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
> --- gcc/cp/semantics.cc.jj 2025-08-28 10:50:43.432763513 +0200
> +++ gcc/cp/semantics.cc 2025-08-28 16:52:48.006806831 +0200
> @@ -13591,6 +13591,38 @@ trait_expr_value (cp_trait_kind kind, tr
> case CPTK_IS_FUNCTION:
> return type_code1 == FUNCTION_TYPE;
>
> + case CPTK_IS_IMPLICIT_LIFETIME:
> + if (SCALAR_TYPE_P (type1)
> + || (type_code1 == ARRAY_TYPE
> + && !(TYPE_SIZE (type1) && integer_zerop (TYPE_SIZE (type1))))
> + /* GNU extension. */
> + || type_code1 == VECTOR_TYPE)
> + return true;
> + if (!CLASS_TYPE_P (type1))
> + return false;
> + type1 = TYPE_MAIN_VARIANT (type1);
> + if (CP_AGGREGATE_TYPE_P (type1)
> + && (!CLASSTYPE_DESTRUCTOR (type1)
> + || !user_provided_p (CLASSTYPE_DESTRUCTOR (type1))))
> + return true;
> + if (is_trivially_xible (BIT_NOT_EXPR, type1, NULL_TREE))
> + {
> + if (is_trivially_xible (INIT_EXPR, type1, make_tree_vec (0)))
> + return true;
> + tree arg = make_tree_vec (1);
> + tree ctype1 = cp_build_qualified_type (type1, (cp_type_quals
> (type1)
> + |
> TYPE_QUAL_CONST));
> + TREE_VEC_ELT (arg, 0)
> + = cp_build_reference_type (ctype1, /*rval=*/false);
> + if (is_trivially_xible (INIT_EXPR, type1, arg))
> + return true;
> + TREE_VEC_ELT (arg, 0)
> + = cp_build_reference_type (type1, /*rval=*/true);
> + if (is_trivially_xible (INIT_EXPR, type1, arg))
> + return true;
> + }
> + return false;
> +
> case CPTK_IS_INVOCABLE:
> return !error_operand_p (build_invoke (type1, type2, tf_none));
>
> @@ -13910,6 +13942,7 @@ finish_trait_expr (location_t loc, cp_tr
> type to know whether an array is an aggregate, so use kind=4
> here. */
> case CPTK_IS_AGGREGATE:
> case CPTK_IS_FINAL:
> + case CPTK_IS_IMPLICIT_LIFETIME:
> if (!check_trait_type (type1, /* kind = */ 4))
> return error_mark_node;
> break;
> --- gcc/cp/constraint.cc.jj 2025-08-15 22:38:29.017870706 +0200
> +++ gcc/cp/constraint.cc 2025-08-28 13:02:19.197985274 +0200
> @@ -3170,6 +3170,9 @@ diagnose_trait_expr (location_t loc, tre
> case CPTK_IS_FUNCTION:
> inform (loc, "%qT is not a function", t1);
> break;
> + case CPTK_IS_IMPLICIT_LIFETIME:
> + inform (decl_loc, "%qT is not an implicit lifetime type", t1);
> + break;
> case CPTK_IS_INVOCABLE:
> {
> if (!TREE_VEC_LENGTH (t2))
> --- gcc/testsuite/g++.dg/ext/is_implicit_lifetime.C.jj 2025-08-28
> 14:14:33.475719420 +0200
> +++ gcc/testsuite/g++.dg/ext/is_implicit_lifetime.C 2025-08-28
> 17:01:25.544140044 +0200
> @@ -0,0 +1,122 @@
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +// { dg-add-options float16 }
> +// { dg-add-options float32 }
> +// { dg-add-options float64 }
> +// { dg-add-options float128 }
> +
> +struct A { int a, b, c; };
> +class B { static int a; private: static int b; public: int c; };
> +struct C { C () {} int a, b, c; };
> +struct D { explicit D (int) {} int a, b, c; };
> +struct E : public A { int d, e, f; };
> +struct F : public C { using C::C; int d, e, f; };
> +class G { int a, b; };
> +struct H { private: int a, b; };
> +struct I { protected: int a, b; };
> +struct J { int a, b; void foo (); };
> +struct K { int a, b; virtual void foo (); };
> +struct L : virtual public A { int d, e; };
> +struct M : protected A { int d, e; };
> +struct N : private A { int d, e; };
> +struct O { O () = delete; int a, b, c; };
> +struct P { P () = default; int a, b, c; };
> +struct Q { Q (); Q (const Q &); int a, b, c; };
> +struct R { R (); R (const R &); R (R &&) = default; int a, b, c; };
> +struct S { S (); ~S (); int a, b, c; };
> +struct T { T (); ~T () = default; int a, b, c; };
> +struct U { U (); U (const U &) = default; int a, b, c; };
> +struct V { V () = default; V (const V &); int a, b, c; };
> +enum W { W1 };
> +enum class X : int { X1 };
> +struct Y { int g; int foo (int); };
> +struct Z;
> +
> +#define SA(X) static_assert ((X), #X)
> +
> +SA (!__builtin_is_implicit_lifetime (void));
> +SA (!__builtin_is_implicit_lifetime (const void));
> +SA (!__builtin_is_implicit_lifetime (volatile void));
> +SA (__builtin_is_implicit_lifetime (char));
> +SA (__builtin_is_implicit_lifetime (signed char));
> +SA (__builtin_is_implicit_lifetime (const unsigned char));
> +SA (__builtin_is_implicit_lifetime (short));
> +SA (__builtin_is_implicit_lifetime (volatile unsigned short));
> +SA (__builtin_is_implicit_lifetime (int));
> +SA (__builtin_is_implicit_lifetime (unsigned int));
> +SA (__builtin_is_implicit_lifetime (const volatile long));
> +SA (__builtin_is_implicit_lifetime (unsigned long));
> +SA (__builtin_is_implicit_lifetime (long long));
> +SA (__builtin_is_implicit_lifetime (unsigned long long));
> +#ifdef __SIZEOF_INT128__
> +SA (__builtin_is_implicit_lifetime (__int128));
> +SA (__builtin_is_implicit_lifetime (unsigned __int128));
> +#endif
> +SA (__builtin_is_implicit_lifetime (float));
> +SA (__builtin_is_implicit_lifetime (double));
> +SA (__builtin_is_implicit_lifetime (long double volatile));
> +#ifdef __STDCPP_FLOAT16_T__
> +SA (__builtin_is_implicit_lifetime (_Float16));
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +SA (__builtin_is_implicit_lifetime (_Float32));
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +SA (__builtin_is_implicit_lifetime (const _Float64));
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +SA (__builtin_is_implicit_lifetime (_Float128));
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +SA (__builtin_is_implicit_lifetime (decltype(0.bf16)));
> +#endif
> +SA (__builtin_is_implicit_lifetime (W));
> +SA (__builtin_is_implicit_lifetime (const volatile X));
> +SA (__builtin_is_implicit_lifetime (int *));
> +SA (__builtin_is_implicit_lifetime (int (*) (int)));
> +SA (__builtin_is_implicit_lifetime (int (Y::*)));
> +SA (__builtin_is_implicit_lifetime (int (Y::*) (int)));
> +SA (!__builtin_is_implicit_lifetime (int &));
> +SA (!__builtin_is_implicit_lifetime (char &&));
> +SA (__builtin_is_implicit_lifetime (int []));
> +SA (!__builtin_is_implicit_lifetime (int [0]));
> +SA (__builtin_is_implicit_lifetime (int [1]));
> +SA (__builtin_is_implicit_lifetime (const Y [42]));
> +SA (!__builtin_is_implicit_lifetime (int ()));
> +SA (!__builtin_is_implicit_lifetime (int () &));
> +SA (!__builtin_is_implicit_lifetime (int () const));
> +SA (!__builtin_is_implicit_lifetime (int (&) ()));
> +SA (!__builtin_is_implicit_lifetime (Z)); // { dg-error
> "invalid use of incomplete type 'struct Z'" }
> +SA (__builtin_is_implicit_lifetime (Z []));
> +SA (__builtin_is_implicit_lifetime (Z [5]));
> +SA (__builtin_is_implicit_lifetime (A));
> +SA (__builtin_is_implicit_lifetime (B));
> +SA (__builtin_is_implicit_lifetime (C));
> +SA (__builtin_is_implicit_lifetime (D));
> +SA (__builtin_is_implicit_lifetime (E));
> +SA (__builtin_is_implicit_lifetime (F));
> +SA (__builtin_is_implicit_lifetime (G));
> +SA (__builtin_is_implicit_lifetime (H));
> +SA (__builtin_is_implicit_lifetime (I));
> +SA (__builtin_is_implicit_lifetime (J));
> +SA (!__builtin_is_implicit_lifetime (K));
> +SA (!__builtin_is_implicit_lifetime (L));
> +SA (__builtin_is_implicit_lifetime (M));
> +SA (__builtin_is_implicit_lifetime (N));
> +SA (__builtin_is_implicit_lifetime (O));
> +SA (__builtin_is_implicit_lifetime (P));
> +SA (!__builtin_is_implicit_lifetime (Q));
> +SA (__builtin_is_implicit_lifetime (R));
> +SA (!__builtin_is_implicit_lifetime (S));
> +SA (__builtin_is_implicit_lifetime (S [3]));
> +SA (__builtin_is_implicit_lifetime (T));
> +SA (__builtin_is_implicit_lifetime (U));
> +SA (__builtin_is_implicit_lifetime (V));
> +SA (__builtin_is_implicit_lifetime (_Complex double));
> +SA (__builtin_is_implicit_lifetime (int [[gnu::vector_size (4 * sizeof
> (int))]]));
> +
> +void
> +foo (int n)
> +{
> + SA (__builtin_is_implicit_lifetime (char [n]));
> +}
> --- libstdc++-v3/include/bits/version.def.jj 2025-08-23
> 15:00:05.175775859 +0200
> +++ libstdc++-v3/include/bits/version.def 2025-08-28
> 17:06:44.190031458 +0200
> @@ -2091,6 +2091,15 @@ ftms = {
> };
> };
>
> +ftms = {
> + name = is_implicit_lifetime;
> + values = {
> + v = 202302;
> + cxxmin = 23;
> + extra_cond = "__has_builtin(__builtin_is_implicit_lifetime)";
> + };
> +};
> +
> // Standard test specifications.
> stds[97] = ">= 199711L";
> stds[03] = ">= 199711L";
> --- libstdc++-v3/include/bits/version.h.jj 2025-08-23
> 15:00:05.176775846 +0200
> +++ libstdc++-v3/include/bits/version.h 2025-08-28 17:06:49.160883915 +0200
> @@ -2343,4 +2343,14 @@
> #endif /* !defined(__cpp_lib_constexpr_exceptions) &&
> defined(__glibcxx_want_constexpr_exceptions) */
> #undef __glibcxx_want_constexpr_exceptions
>
> +#if !defined(__cpp_lib_is_implicit_lifetime)
> +# if (__cplusplus >= 202100L) &&
> (__has_builtin(__builtin_is_implicit_lifetime))
> +# define __glibcxx_is_implicit_lifetime 202302L
> +# if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_is_implicit_lifetime)
> +# define __cpp_lib_is_implicit_lifetime 202302L
> +# endif
> +# endif
> +#endif /* !defined(__cpp_lib_is_implicit_lifetime) &&
> defined(__glibcxx_want_is_implicit_lifetime) */
> +#undef __glibcxx_want_is_implicit_lifetime
> +
> #undef __glibcxx_want_all
> --- libstdc++-v3/include/std/type_traits.jj 2025-07-16
> 13:10:11.054411335 +0200
> +++ libstdc++-v3/include/std/type_traits 2025-08-28
> 17:36:11.404329402 +0200
> @@ -46,6 +46,7 @@
> #define __glibcxx_want_is_aggregate
> #define __glibcxx_want_is_constant_evaluated
> #define __glibcxx_want_is_final
> +#define __glibcxx_want_is_implicit_lifetime
> #define __glibcxx_want_is_invocable
> #define __glibcxx_want_is_layout_compatible
> #define __glibcxx_want_is_nothrow_convertible
> @@ -4052,6 +4053,22 @@ template<typename _Ret, typename _Fn, ty
> # endif
> #endif
>
> +#ifdef __cpp_lib_is_implicit_lifetime // C++ >= 23
> + /// True if the type is an implicit-lifetime type.
> + /// @since C++23
> +
> + template<typename _Tp>
> + struct is_implicit_lifetime
> + : bool_constant<__builtin_is_implicit_lifetime(_Tp)>
> + { };
> +
> + /// @ingroup variable_templates
> + /// @since C++23
> + template<typename _Tp>
> + inline constexpr bool is_implicit_lifetime_v
> + = __builtin_is_implicit_lifetime(_Tp);
> +#endif
> +
> #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 &&
> ref_{converts,constructs}_from_temp
> /// True if _Tp is a reference type, a _Up value can be bound to _Tp in
> /// direct-initialization, and a temporary object would be bound to
> --- libstdc++-v3/src/c++23/std.cc.in.jj 2025-08-23 15:00:05.209775407 +0200
> +++ libstdc++-v3/src/c++23/std.cc.in 2025-08-28 17:10:43.784942152
> +0200
> @@ -3216,6 +3216,10 @@ export namespace std
> using std::is_scoped_enum;
> using std::is_scoped_enum_v;
> #endif
> +#if __cpp_lib_is_implicit_lifetime
> + using std::is_implicit_lifetime;
> + using std::is_implicit_lifetime_v;
> +#endif
> }
>
> // <typeindex>
> --- libstdc++-v3/testsuite/20_util/is_implicit_lifetime/version.cc.jj
> 2025-08-28 17:16:17.590650275 +0200
> +++ libstdc++-v3/testsuite/20_util/is_implicit_lifetime/version.cc
> 2025-08-28 17:17:07.215014852 +0200
> @@ -0,0 +1,27 @@
> +// Copyright (C) 2025 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library. This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +// GNU General Public License for more details.
> +
> +// You should have received a copy of the GNU General Public License along
> +// with this library; see the file COPYING3. If not see
> +// <http://www.gnu.org/licenses/>.
> +
> +// { dg-do compile { target c++23 } }
> +// { dg-add-options no_pch }
> +
> +#include <version>
> +
> +#ifndef __cpp_lib_is_implicit_lifetime
> +# error "Feature test macro for is_implicit_lifetime is missing in
> <version>"
> +#elif __cpp_lib_is_implicit_lifetime < 202302L
> +# error "Feature test macro for is_implicit_lifetime has wrong value in
> <version>"
> +#endif
> --- libstdc++-v3/testsuite/20_util/is_implicit_lifetime/value.cc.jj
> 2025-08-28 17:16:20.746609864 +0200
> +++ libstdc++-v3/testsuite/20_util/is_implicit_lifetime/value.cc
> 2025-08-28 17:40:30.406982275 +0200
> @@ -0,0 +1,122 @@
> +// Copyright (C) 2025 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library. This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +// GNU General Public License for more details.
> +
> +// You should have received a copy of the GNU General Public License along
> +// with this library; see the file COPYING3. If not see
> +// <http://www.gnu.org/licenses/>.
> +
> +// { dg-do compile { target c++23 } }
> +// { dg-add-options no_pch }
> +
> +#include <type_traits>
> +
> +#ifndef __cpp_lib_is_implicit_lifetime
> +# error "Feature test macro for is_implicit_lifetime is missing in
> <type_traits>"
> +#elif __cpp_lib_is_implicit_lifetime < 202302L
> +# error "Feature test macro for is_implicit_lifetime has wrong value in
> <type_traits>"
> +#endif
> +
> +#include <testsuite_tr1.h>
> +
> +template<typename T>
> + concept Is_implicit_lifetime
> + = __gnu_test::test_category<std::is_implicit_lifetime, T>(true);
> +
> +struct A { int a, b, c; };
> +class B { static int a; private: static int b; public: int c; };
> +struct C { C () {} int a, b, c; };
> +struct D { explicit D (int) {} int a, b, c; };
> +struct E : public A { int d, e, f; };
> +struct F : public C { using C::C; int d, e, f; };
> +class G { int a, b; };
> +struct H { private: int a, b; };
> +struct I { protected: int a, b; };
> +struct J { int a, b; void foo (); };
> +struct K { int a, b; virtual void foo (); };
> +struct L : virtual public A { int d, e; };
> +struct M : protected A { int d, e; };
> +struct N : private A { int d, e; };
> +struct O { O () = delete; int a, b, c; };
> +struct P { P () = default; int a, b, c; };
> +struct Q { Q (); Q (const Q &); int a, b, c; };
> +struct R { R (); R (const R &); R (R &&) = default; int a, b, c; };
> +struct S { S (); ~S (); int a, b, c; };
> +struct T { T (); ~T () = default; int a, b, c; };
> +struct U { U (); U (const U &) = default; int a, b, c; };
> +struct V { V () = default; V (const V &); int a, b, c; };
> +enum W { W1 };
> +enum class X : int { X1 };
> +struct Y { int g; int foo (int); };
> +struct Z;
> +
> +void
> +test01()
> +{
> + static_assert( ! Is_implicit_lifetime<void> );
> + static_assert( ! Is_implicit_lifetime<const void> );
> + static_assert( ! Is_implicit_lifetime<volatile void> );
> + static_assert( Is_implicit_lifetime<char> );
> + static_assert( Is_implicit_lifetime<signed char> );
> + static_assert( Is_implicit_lifetime<const unsigned char> );
> + static_assert( Is_implicit_lifetime<short> );
> + static_assert( Is_implicit_lifetime<volatile unsigned short> );
> + static_assert( Is_implicit_lifetime<int> );
> + static_assert( Is_implicit_lifetime<unsigned int> );
> + static_assert( Is_implicit_lifetime<const volatile long> );
> + static_assert( Is_implicit_lifetime<unsigned long> );
> + static_assert( Is_implicit_lifetime<long long> );
> + static_assert( Is_implicit_lifetime<unsigned long long> );
> + static_assert( Is_implicit_lifetime<float> );
> + static_assert( Is_implicit_lifetime<double> );
> + static_assert( Is_implicit_lifetime<long double volatile> );
> + static_assert( Is_implicit_lifetime<W> );
> + static_assert( Is_implicit_lifetime<const volatile X> );
> + static_assert( Is_implicit_lifetime<int *> );
> + static_assert( Is_implicit_lifetime<int (*) (int)> );
> + static_assert( Is_implicit_lifetime<int (Y::*)> );
> + static_assert( Is_implicit_lifetime<int (Y::*) (int)> );
> + static_assert( ! Is_implicit_lifetime<int &> );
> + static_assert( ! Is_implicit_lifetime<char &&> );
> + static_assert( Is_implicit_lifetime<int []> );
> + static_assert( Is_implicit_lifetime<int [1]> );
> + static_assert( Is_implicit_lifetime<const Y [42]> );
> + static_assert( ! Is_implicit_lifetime<int ()> );
> + static_assert( ! Is_implicit_lifetime<int () &> );
> + static_assert( ! Is_implicit_lifetime<int () const> );
> + static_assert( ! Is_implicit_lifetime<int (&) ()> );
> + static_assert( Is_implicit_lifetime<Z []> );
> + static_assert( Is_implicit_lifetime<Z [5]> );
> + static_assert( Is_implicit_lifetime<A> );
> + static_assert( Is_implicit_lifetime<B> );
> + static_assert( Is_implicit_lifetime<C> );
> + static_assert( Is_implicit_lifetime<D> );
> + static_assert( Is_implicit_lifetime<E> );
> + static_assert( Is_implicit_lifetime<F> );
> + static_assert( Is_implicit_lifetime<G> );
> + static_assert( Is_implicit_lifetime<H> );
> + static_assert( Is_implicit_lifetime<I> );
> + static_assert( Is_implicit_lifetime<J> );
> + static_assert( ! Is_implicit_lifetime<K> );
> + static_assert( ! Is_implicit_lifetime<L> );
> + static_assert( Is_implicit_lifetime<M> );
> + static_assert( Is_implicit_lifetime<N> );
> + static_assert( Is_implicit_lifetime<O> );
> + static_assert( Is_implicit_lifetime<P> );
> + static_assert( ! Is_implicit_lifetime<Q> );
> + static_assert( Is_implicit_lifetime<R> );
> + static_assert( ! Is_implicit_lifetime<S> );
> + static_assert( Is_implicit_lifetime<S [3]> );
> + static_assert( Is_implicit_lifetime<T> );
> + static_assert( Is_implicit_lifetime<U> );
> + static_assert( Is_implicit_lifetime<V> );
> +}
>
> Jakub
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250828/af8d0b83/attachment-0001.htm>
More information about the Libstdc++
mailing list