[PATCH] c++, libstdc++, v4: Implement C++23 P2674R1 - A trait for implicit lifetime types

Jason Merrill jason@redhat.com
Fri Aug 29 10:56:07 GMT 2025


On 8/29/25 6:22 AM, Jakub Jelinek wrote:
> On Fri, Aug 29, 2025 at 11:40:10AM +0200, Jason Merrill wrote:
>>> --- 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:
>>
>> Please factor this into a predicate (e.g. implicit_lifetime_type_p) that can
>> be used elsewhere in the compiler.
> 
> Done.
> 
>> This is an interesting way to approach "has at least one trivial eligible
>> constructor"; I would expect a loop over CLASSTYPE_CONSTRUCTORS checking
>> eligible_special_memfn_p (which doesn't exist yet) && trivial_fn_p.  But I
>> guess your approach should work, too.
> 
> This came from the paper's chapter 2,
> template<typename T>
> struct is_implicit_lifetime : std::disjunction<
> std::is_scalar<T>,
> std::is_array<T>,
> std::is_aggregate<T>,
> std::conjunction<
> std::is_trivially_destructible<T>,
> std::disjunction<
> std::is_trivially_default_constructible<T>,
> std::is_trivially_copy_constructible<T>,
> std::is_trivially_move_constructible<T>>>> {};
> except that the is_aggregate part is more complex and can't be done purely
> on the library side since CWG2605.
> 
>> For the rvalue case you can just use type1, and build_stub_object will add
>> the rvalue reference.
> 
> Done.
> 
> 2025-08-29  Jakub Jelinek  <jakub@redhat.com>
> 
> gcc/cp/
> 	* cp-tree.h: Implement C++23 P2674R1 - A trait for implicit lifetime
> 	types.
> 	(implicit_lifetime_type_p): Declare.
> 	* tree.cc (implicit_lifetime_type_p): New function.
> 	* cp-trait.def (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-tree.h.jj	2025-08-23 15:00:04.190788945 +0200
> +++ gcc/cp/cp-tree.h	2025-08-29 12:04:55.294023368 +0200
> @@ -8369,6 +8369,7 @@ extern bool std_layout_type_p			(const_t
>   extern bool trivial_type_p			(const_tree);
>   extern bool trivially_relocatable_type_p	(tree);
>   extern bool replaceable_type_p			(tree);
> +extern bool implicit_lifetime_type_p		(tree);
>   extern bool trivially_copyable_p		(const_tree);
>   extern bool type_has_unique_obj_representations (const_tree);
>   extern bool scalarish_type_p			(const_tree);
> --- gcc/cp/tree.cc.jj	2025-08-23 15:00:04.291787603 +0200
> +++ gcc/cp/tree.cc	2025-08-29 12:08:47.617979696 +0200
> @@ -5070,6 +5070,42 @@ replaceable_type_p (tree t)
>     return true;
>   }
>   
> +/* Returns 1 iff type T is an implicit-lifetime type, as defined in
> +   [basic.types.general] and [class.prop].  */
> +
> +bool
> +implicit_lifetime_type_p (tree t)
> +{
> +  if (SCALAR_TYPE_P (t)
> +      || (TREE_CODE (t) == ARRAY_TYPE
> +	  && !(TYPE_SIZE (t) && integer_zerop (TYPE_SIZE (t))))
> +      /* GNU extension.  */
> +      || TREE_CODE (t) == VECTOR_TYPE)
> +    return true;
> +  if (!CLASS_TYPE_P (t))
> +    return false;
> +  t = TYPE_MAIN_VARIANT (t);
> +  if (CP_AGGREGATE_TYPE_P (t)
> +      && (!CLASSTYPE_DESTRUCTOR (t)
> +	  || !user_provided_p (CLASSTYPE_DESTRUCTOR (t))))
> +    return true;
> +  if (is_trivially_xible (BIT_NOT_EXPR, t, NULL_TREE))
> +    {
> +      if (is_trivially_xible (INIT_EXPR, t, make_tree_vec (0)))
> +	return true;
> +      tree arg = make_tree_vec (1);
> +      tree ct
> +	= cp_build_qualified_type (t, (cp_type_quals (t) | TYPE_QUAL_CONST));
> +      TREE_VEC_ELT (arg, 0) = cp_build_reference_type (ct, /*rval=*/false);
> +      if (is_trivially_xible (INIT_EXPR, t, arg))
> +	return true;
> +      TREE_VEC_ELT (arg, 0) = t;
> +      if (is_trivially_xible (INIT_EXPR, t, arg))
> +	return true;
> +    }
> +  return false;
> +}
> +
>   /* Returns 1 iff type T is a POD type, as defined in [basic.types].  */
>   
>   bool
> --- gcc/cp/cp-trait.def.jj	2025-08-29 11:14:27.657997703 +0200
> +++ gcc/cp/cp-trait.def	2025-08-29 11:53:46.940123903 +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-29 11:14:27.687997312 +0200
> +++ gcc/cp/semantics.cc	2025-08-29 12:06:08.162068723 +0200
> @@ -13591,6 +13591,9 @@ trait_expr_value (cp_trait_kind kind, tr
>       case CPTK_IS_FUNCTION:
>         return type_code1 == FUNCTION_TYPE;
>   
> +    case CPTK_IS_IMPLICIT_LIFETIME:
> +      return implicit_lifetime_type_p (type1);
> +
>       case CPTK_IS_INVOCABLE:
>         return !error_operand_p (build_invoke (type1, type2, tf_none));
>   
> @@ -13910,6 +13913,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-29 11:14:27.645997860 +0200
> +++ gcc/cp/constraint.cc	2025-08-29 11:53:46.943123862 +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);

Need a hyphen in "implicit-lifetime".  The front-end changes are OK with 
that tweak.

Jason



More information about the Libstdc++ mailing list