On Sat, 28 Mar 2026 at 16:57, Jakub Jelinek <[email protected]> wrote:
>
> On Wed, Mar 25, 2026 at 09:06:31PM +0100, Jakub Jelinek wrote:
> > On Wed, Mar 25, 2026 at 05:50:40PM +0100, Jakub Jelinek wrote:
> > > The following patch attempts to implement another part of P3795R1
> > > (though with some changes Barry has queued for P3795R2, in particular
> > > throwing on !has-type(r) in the annotations sequence or when the
> > > annotations are non-empty and name is not specified), in particular
> > > the addition of annotations to data_member_options and handling it in
> > > data_member_spec/define_aggregate etc.
> > >
> > > This is on top of the earlier data_member_spec patch, though even if
> > > it is decided to revert that part of changes, it shouldn't be hard
> > > to adjust this patch to apply.
> >
> > Here is an updated patch which is not on top of the earlier data_member_spec
> > patch.  And updates various function comments to include ANN etc.
>
> Now reposted as no longer RFC PATCH given that it has been voted in and
> properly successfully bootstrapped/regtested on x86_64-linux and i686-linux.

The one line library change is OK, thanks.


>
> 2026-03-28  Jakub Jelinek  <[email protected]>
>
> libstdc++-v3/
>         * include/std/meta (std::meta::data_member_options): Add annotations
>         member.
> gcc/cp/
>         * reflect.cc (get_range_elts): If N is negative, just use the tree
>         as object to extract range from instead of finding Nth argument
>         of a call.
>         (eval_is_bit_field, eval_type_of, eval_size_of, eval_alignment_of,
>         eval_bit_size_of, eval_has_identifier, eval_identifier_of): Adjust
>         function comments from P3795R2.
>         (eval_display_string_of): Handle annotations in
>         REFLECT_DATA_MEMBER_SPEC.
>         (eval_annotations_of): Adjust function comments from P3795R2.
>         (eval_data_member_spec): Likewise.  Read and diagnose annotations.
>         (eval_define_aggregate): Adjust function comments from P3795R2.
>         Create annotations.
>         (compare_reflections): Compare REFLECT_DATA_MEMBER_SPEC annotations.
>         * mangle.cc (write_reflection): Mangle REFLECT_DATA_MEMBER_SPEC
>         annotations.
> gcc/testsuite/
>         * g++.dg/reflect/data_member_spec5.C: New test.
>         * g++.dg/reflect/data_member_spec6.C: New test.
>         * g++.dg/reflect/display_string_of1.C: Expect extra ", {}" before
>         ")" for empty annotations, otherwise a list of annotations.
>         * g++.dg/reflect/u8display_string_of1.C: Likewise.
>         * g++.dg/reflect/define_aggregate9.C: New test.
>         * g++.dg/reflect/mangle1.C: Test mangling of REFLECT_DATA_MEMBER_SPEC
>         annotations.
>
> --- libstdc++-v3/include/std/meta.jj    2026-03-25 20:19:10.759162427 +0100
> +++ libstdc++-v3/include/std/meta       2026-03-25 20:19:53.791992428 +0100
> @@ -422,6 +422,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        optional<int> alignment;
>        optional<int> bit_width;
>        bool no_unique_address = false;
> +      vector<info> annotations;
>      };
>      consteval info data_member_spec(info, data_member_options);
>      consteval bool is_data_member_spec(info);
> --- gcc/cp/reflect.cc.jj        2026-03-25 20:19:10.715163161 +0100
> +++ gcc/cp/reflect.cc   2026-03-25 20:32:38.262640083 +0100
> @@ -383,18 +383,25 @@ enum get_range_elts_kind {
>     eval_reflect_constant_array.  For GET_INFO_VEC kind, <meta> ensures
>     the argument is reference to reflection_range concept and so both
>     range_value_t is info and range_refernce_t is cv info or cv info & or
> -   cv info &&.  */
> +   cv info &&.  If N is negative, CALL is the expression to extract
> +   values from rather than N-th argument from CALL.  */
>
>  static tree
>  get_range_elts (location_t loc, const constexpr_ctx *ctx, tree call, int n,
>                 bool *non_constant_p, bool *overflow_p, tree *jump_target,
>                 get_range_elts_kind kind, tree fun)
>  {
> -  gcc_checking_assert (call_expr_nargs (call) > n);
> -  tree arg = get_nth_callarg (call, n);
> -  tree parm = DECL_ARGUMENTS (cp_get_callee_fndecl_nofold (call));
> -  for (int i = 0; i < n; ++i)
> -    parm = DECL_CHAIN (parm);
> +  tree arg, parm;
> +  if (n < 0)
> +    arg = parm = call;
> +  else
> +    {
> +      gcc_checking_assert (call_expr_nargs (call) > n);
> +      arg = get_nth_callarg (call, n);
> +      parm = DECL_ARGUMENTS (cp_get_callee_fndecl_nofold (call));
> +      for (int i = 0; i < n; ++i)
> +       parm = DECL_CHAIN (parm);
> +    }
>    tree type = TREE_TYPE (arg);
>    gcc_checking_assert (TYPE_REF_P (type));
>    arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, non_constant_p,
> @@ -539,7 +546,8 @@ get_range_elts (location_t loc, const co
>      tree call = finish_call_expr (obj, &args, true, false, complain);
>      if (call == error_mark_node)
>        return call;
> -    cp_walk_tree (&call, replace_parm_r, map, NULL);
> +    if (n >= 0)
> +      cp_walk_tree (&call, replace_parm_r, map, NULL);
>      if (complain != tf_none)
>        return call;
>      call = cxx_eval_constant_expression (ctx, call, vc_prvalue, 
> non_constant_p,
> @@ -1853,7 +1861,7 @@ eval_is_explicit (tree r)
>
>  /* Process std::meta::is_bit_field.
>     Returns: true if r represents a bit-field, or if r represents a data 
> member
> -   description (T,N,A,W,NUA) for which W is not _|_.  Otherwise, false.  */
> +   description (T,N,A,W,NUA,ANN) for which W is not _|_.  Otherwise, false.  
> */
>
>  static tree
>  eval_is_bit_field (const_tree r, reflect_kind kind)
> @@ -2518,8 +2526,8 @@ type_of (tree r, reflect_kind kind)
>          of the enum-specifier as specified in [dcl.enum].
>     -- Otherwise, if r represents a direct base class relationship (D,B), then
>        a reflection of B.
> -   -- Otherwise, for a data member description (T,N,A,W,NUA), a reflection of
> -      the type T.  */
> +   -- Otherwise, for a data member description (T,N,A,W,NUA,ANN), a 
> reflection
> +      of the type T.  */
>
>  static tree
>  eval_type_of (location_t loc, const constexpr_ctx *ctx, tree r,
> @@ -3169,7 +3177,7 @@ eval_offset_of (location_t loc, const co
>  /* Process std::meta::size_of.
>     Returns: If r represents
>       -- a non-static data member of type T,
> -     -- a data member description (T,N,A,W,NUA), or
> +     -- a data member description (T,N,A,W,NUA,ANN), or
>       -- dealias(r) represents a type T,
>     then sizeof(T) if T is not a reference type and size_of(add_pointer(^^T))
>     otherwise.  Otherwise, size_of(type_of(r)).
> @@ -3178,7 +3186,7 @@ eval_offset_of (location_t loc, const co
>       -- dealias(r) is a reflection of a type, object, value, variable of
>         non-reference type, non-static data member that is not a bit-field,
>         direct base class relationship, or data member description
> -       (T,N,A,W,NUA) where W is not _|_.
> +       (T,N,A,W,NUA,ANN) where W is not _|_.
>       -- If dealias(r) represents a type, then is_complete_type(r) is true.  
> */
>
>  static tree
> @@ -3229,12 +3237,13 @@ eval_size_of (location_t loc, const cons
>     -- Otherwise, if r represents a non-static data member M of a class C,
>        then the alignment of the direct member subobject corresponding to M 
> of a
>        complete object of type C.
> -   -- Otherwise, r represents a data member description (T,N,A,W,NUA).
> +   -- Otherwise, r represents a data member description (T,N,A,W,NUA,ANN).
>        If A is not _|_, then the value A.  Otherwise, alignment_of(^^T).
>     Throws: meta::exception unless all of the following conditions are met:
>     -- dealias(r) is a reflection of a type, object, variable of non-reference
>        type, non-static data member that is not a bit-field, direct base class
> -      relationship, or data member description (T,N,A,W,NUA) where W is _|_.
> +      relationship, or data member description (T,N,A,W,NUA,ANN) where W is
> +      _|_.
>     -- If dealias(r) represents a type, then is_complete_type(r) is true.  */
>
>  static tree
> @@ -3303,7 +3312,7 @@ eval_alignment_of (location_t loc, const
>     Returns:
>       -- If r represents an unnamed bit-field or a non-static data member that
>         is a bit-field with width W, then W.
> -     -- Otherwise, if r represents a data member description (T,N,A,W,NUA)
> +     -- Otherwise, if r represents a data member description 
> (T,N,A,W,NUA,ANN)
>         and W is not _|_, then W.
>       -- Otherwise, CHAR_BIT * size_of(r).
>
> @@ -3400,8 +3409,8 @@ eval_bit_size_of (location_t loc, const
>        namespace, or namespace alias, then true.
>     -- Otherwise, if r represents a direct base class relationship, then
>        has_identifier(type_of(r)).
> -   -- Otherwise, r represents a data member description (T,N,A,W,NUA); true 
> if
> -      N is not _|_.  Otherwise, false.  */
> +   -- Otherwise, r represents a data member description (T,N,A,W,NUA,ANN);
> +      true if N is not _|_.  Otherwise, false.  */
>
>  static tree
>  eval_has_identifier (tree r, reflect_kind kind)
> @@ -3516,7 +3525,7 @@ eval_has_identifier (tree r, reflect_kin
>        the declaration of that entity.
>     -- Otherwise, if r represents a direct base class relationship, then
>        identifier_of(type_of(r)) or u8identifier_of(type_of(r)), respectively.
> -   -- Otherwise, r represents a data member description (T,N,A,W,NUA);
> +   -- Otherwise, r represents a data member description (T,N,A,W,NUA,ANN);
>        a string_view or u8string_view, respectively, containing the identifier
>        N.
>     Throws: meta::exception unless has_identifier(r) is true and the 
> identifier
> @@ -3643,10 +3652,16 @@ eval_display_string_of (location_t loc,
>        pp_printf (&pp, "%T: %T", d, BINFO_TYPE (r));
>      }
>    else if (kind == REFLECT_DATA_MEMBER_SPEC)
> -    pp_printf (&pp, "(%T, %E, %E, %E, %s)", TREE_VEC_ELT (r, 0),
> -              TREE_VEC_ELT (r, 1), TREE_VEC_ELT (r, 2), TREE_VEC_ELT (r, 3),
> -              TREE_VEC_ELT (r, 4) == boolean_true_node
> -              ? "true" : "false");
> +    {
> +      pp_printf (&pp, "(%T, %E, %E, %E, %s, {", TREE_VEC_ELT (r, 0),
> +                TREE_VEC_ELT (r, 1), TREE_VEC_ELT (r, 2), TREE_VEC_ELT (r, 
> 3),
> +                TREE_VEC_ELT (r, 4) == boolean_true_node
> +                ? "true" : "false");
> +      for (int i = 5; i < TREE_VEC_LENGTH (r); ++i)
> +       pp_printf (&pp, "%s%E", i == 5 ? "" : ", ",
> +                  REFLECT_EXPR_HANDLE (TREE_VEC_ELT (r, i)));
> +      pp_printf (&pp, "})");
> +    }
>    else if (eval_is_annotation (r, kind) == boolean_true_node)
>      pp_printf (&pp, "[[=%E]]",
>                tree_strip_any_location_wrapper (TREE_VALUE (TREE_VALUE (r))));
> @@ -3762,15 +3777,21 @@ remove_const (tree type)
>  }
>
>  /* Process std::meta::annotations_of and annotations_of_with_type.
> -   Let E be
> -   -- the corresponding base-specifier if item represents a direct base class
> -      relationship,
> -   -- otherwise, the entity represented by item.
> +   For a function F, let S(F) be the set of declarations, ignoring any 
> explicit
> +   instantiations, that declare either F or a templated function of which F 
> is
> +   a specialization.
>     Returns: A vector containing all of the reflections R representing each
> -   annotation applying to each declaration of E that precedes either some
> -   point in the evaluation context or a point immediately following the
> -   class-specifier of the outermost class for which such a point is in a
> -   complete-class context.
> +   annotation applying to:
> +   -- if item represents a function parameter P of a function F, then the
> +      declaration of P in each declaration of F in S(F),
> +   -- otherwise, if item represents a function F, then each declaration of F
> +      in S(F),
> +   -- otherwise, if item represents a direct base class relationship (D,B),
> +      then the corresponding base-specifier in the definition of D,
> +   -- otherwise, each declaration of the entity represented by item,
> +   such that precedes either some point in the evaluation context or a point
> +   immediately following the class-specifier of the outermost class for which
> +   such a point is in a complete-class context.
>     For any two reflections R1 and R2 in the returned vector, if the 
> annotation
>     represented by R1 precedes the annotation represented by R2, then R1
>     appears before R2.
> @@ -3779,8 +3800,8 @@ remove_const (tree type)
>     from T.
>
>     Throws: meta::exception unless item represents a type, type alias,
> -   variable, function, namespace, enumerator, direct base class relationship,
> -   or non-static data member.  */
> +   variable, function, function parameter, namespace, enumerator, direct base
> +   class relationship, or non-static data member.  */
>
>  static tree
>  eval_annotations_of (location_t loc, const constexpr_ctx *ctx, tree r,
> @@ -5517,15 +5538,17 @@ eval_variant_alternative (location_t loc
>  }
>
>  /* Process std::meta::data_member_spec.
> -   Returns: A reflection of a data member description (T,N,A,W,NUA) where
> +   Returns: A reflection of a data member description (T,N,A,W,NUA,ANN) where
>     -- T is the type represented by dealias(type),
>     -- N is either the identifier encoded by options.name or _|_ if
>        options.name does not contain a value,
>     -- A is either the alignment value held by options.alignment or _|_ if
>        options.alignment does not contain a value,
>     -- W is either the value held by options.bit_width or _|_ if
> -      options.bit_width does not contain a value, and
> -   -- NUA is the value held by options.no_unique_address.
> +      options.bit_width does not contain a value,
> +   -- NUA is the value held by options.no_unique_address, and
> +   -- ANN is the sequence of values constant_of(r) for each r in
> +      options.annotations.
>     Throws: meta::exception unless the following conditions are met:
>     -- dealias(type) represents either an object type or a reference type;
>     -- if options.name contains a value, then:
> @@ -5537,15 +5560,18 @@ eval_variant_alternative (location_t loc
>          that is not a keyword when interpreted with the ordinary literal
>          encoding;
>     -- if options.name does not contain a value, then options.bit_width
> -      contains a value;
> +      contains a value and options.annotations is empty;
>     -- if options.bit_width contains a value V, then
>        -- is_integral_type(type) || is_enum_type(type) is true,
>        -- options.alignment does not contain a value,
>        -- options.no_unique_address is false,
>        -- V is not negative, and
> -      -- if V equals 0, then options.name does not contain a value; and
> +      -- if V equals 0, then options.name does not contain a value;
>     -- if options.alignment contains a value, it is an alignment value not 
> less
> -      than alignment_of(type).  */
> +      than alignment_of(type); and
> +   -- for every reflection r in options.annotations, has-type(r) is true,
> +      type_of(r) represents a non-array object type, and evaluation of
> +      constant_of(r) does not exit via an exception.  */
>
>  static tree
>  eval_data_member_spec (location_t loc, const constexpr_ctx *ctx,
> @@ -5564,7 +5590,8 @@ eval_data_member_spec (location_t loc, c
>        *non_constant_p = true;
>        return NULL_TREE;
>      }
> -  tree args[5] = { type, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
> +  tree args[6] = { type, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
> +                  NULL_TREE };
>    for (tree field = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (opts)));
>         field; field = next_aggregate_field (DECL_CHAIN (field)))
>      if (tree name = DECL_NAME (field))
> @@ -5577,8 +5604,10 @@ eval_data_member_spec (location_t loc, c
>           args[3] = field;
>         else if (id_equal (name, "no_unique_address"))
>           args[4] = field;
> +       else if (id_equal (name, "annotations"))
> +         args[5] = field;
>        }
> -  for (int i = 1; i < 5; ++i)
> +  for (int i = 1; i < 6; ++i)
>      {
>        if (args[i] == NULL_TREE)
>         goto fail;
> @@ -5602,6 +5631,21 @@ eval_data_member_spec (location_t loc, c
>             args[i] = boolean_true_node;
>           continue;
>         }
> +      if (i == 5)
> +       {
> +         /* To handle annotations, read it using input range from
> +            std::vector<info>.  */
> +         tree rtype
> +           = cp_build_reference_type (TREE_TYPE (opt), /*rval*/false);
> +         opt = build_address (opt);
> +         opt = fold_convert (rtype, opt);
> +         opt = get_info_vec (loc, ctx, opt, -1, non_constant_p, overflow_p,
> +                             jump_target, fun);
> +         if (*jump_target || *non_constant_p)
> +           return NULL_TREE;
> +         args[i] = opt;
> +         continue;
> +       }
>        /* Otherwise the member is optional<something>.  */
>        if (!CLASS_TYPE_P (TREE_TYPE (opt)))
>         goto fail;
> @@ -5833,6 +5877,10 @@ eval_data_member_spec (location_t loc, c
>      return throw_exception (loc, ctx,
>                             "neither name nor bit_width specified",
>                             fun, non_constant_p, jump_target);
> +  if (args[1] == NULL_TREE && TREE_VEC_LENGTH (args[5]))
> +    return throw_exception (loc, ctx,
> +                           "no name and non-empty annotations specified",
> +                           fun, non_constant_p, jump_target);
>    if (args[3])
>      {
>        if (!CP_INTEGRAL_TYPE_P (type) && TREE_CODE (type) != ENUMERAL_TYPE)
> @@ -5874,17 +5922,38 @@ eval_data_member_spec (location_t loc, c
>                                 "alignment is smaller than alignment_of",
>                                 fun, non_constant_p, jump_target);
>      }
> -  tree ret = make_tree_vec (5);
> +  for (int i = 0; i < TREE_VEC_LENGTH (args[5]); ++i)
> +    {
> +      tree r = REFLECT_EXPR_HANDLE (TREE_VEC_ELT (args[5], i));
> +      reflect_kind kind = REFLECT_EXPR_KIND (TREE_VEC_ELT (args[5], i));
> +      if (!has_type (r, kind))
> +       return throw_exception (loc, ctx, "reflection does not have a type",
> +                               fun, non_constant_p, jump_target);
> +      tree type = type_of (r, kind);
> +      if (eval_is_array_type (loc, type) == boolean_true_node
> +         || eval_is_object_type (loc, type) == boolean_false_node)
> +       return throw_exception (loc, ctx, "reflection does not have "
> +                                         "non-array object type",
> +                               fun, non_constant_p, jump_target);
> +      tree cst = eval_constant_of (loc, ctx, r, kind, non_constant_p,
> +                                  overflow_p, jump_target, fun);
> +      if (cst == NULL_TREE)
> +       return NULL_TREE;
> +      TREE_VEC_ELT (args[5], i) = cst;
> +    }
> +  tree ret = make_tree_vec (5 + TREE_VEC_LENGTH (args[5]));
>    for (int i = 0; i < 5; ++i)
>      TREE_VEC_ELT (ret, i) = args[i];
> +  for (int i = 0; i < TREE_VEC_LENGTH (args[5]); ++i)
> +    TREE_VEC_ELT (ret, i + 5) = TREE_VEC_ELT (args[5], i);
>    return get_reflection_raw (loc, ret, REFLECT_DATA_MEMBER_SPEC);
>  }
>
>  /* Process std::meta::define_aggregate.
>     Let C be the type represented by class_type and r_K be the Kth reflection
>     value in mdescrs.
> -   For every r_K in mdescrs, let (T_K,N_K,A_K,W_K,NUA_K) be the corresponding
> -   data member description represented by r_K.
> +   For every r_K in mdescrs, let (T_K,N_K,A_K,W_K,NUA_K,ANN_K) be the
> +   corresponding data member description represented by r_K.
>     Constant When:
>     -- class_type represents a cv-unqualified class type;
>     -- C is incomplete from every point in the evaluation context;
> @@ -5915,6 +5984,8 @@ eval_data_member_spec (location_t loc, c
>          Otherwise, M_K is not a bit-field.
>        -- If A_K is not _|_, M_K has the alignment-specifier alignas(A_K).
>          Otherwise, M_K has no alignment-specifier.
> +      -- M_K has an annotation whose underlying constant is r for every
> +        reflection r in ANN_K.
>     -- For every r_L in mdescrs such that K<L, the declaration corresponding 
> to
>        r_K precedes the declaration corresponding to r_L.
>     Returns: class_type.
> @@ -6166,12 +6237,24 @@ eval_define_aggregate (location_t loc, c
>                               * BITS_PER_UNIT);
>           DECL_USER_ALIGN (f) = 1;
>         }
> -      if (TREE_VEC_ELT (a, 4) == boolean_true_node)
> +      if (TREE_VEC_ELT (a, 4) == boolean_true_node
> +         || TREE_VEC_LENGTH (a) != 5)
>         {
> -         tree attr = build_tree_list (NULL_TREE,
> -                                      get_identifier ("no_unique_address"));
> -         attr = build_tree_list (attr, NULL_TREE);
> -         cplus_decl_attributes (&f, attr, 0);
> +         tree attrs = NULL_TREE, attr;
> +         if (TREE_VEC_ELT (a, 4) == boolean_true_node)
> +           {
> +             attr = build_tree_list (NULL_TREE,
> +                                     get_identifier ("no_unique_address"));
> +             attrs = build_tree_list (attr, NULL_TREE);
> +           }
> +         for (int i = TREE_VEC_LENGTH (a) - 1; i >= 5; --i)
> +           {
> +             attr = build_tree_list (internal_identifier,
> +                                     annotation_identifier);
> +             tree val = REFLECT_EXPR_HANDLE (TREE_VEC_ELT (a, i));
> +             attrs = tree_cons (attr, build_tree_list (NULL_TREE, val), 
> attrs);
> +           }
> +         cplus_decl_attributes (&f, attrs, 0);
>         }
>        fields = f;
>      }
> @@ -8373,13 +8456,24 @@ compare_reflections (tree lhs, tree rhs)
>        rhs = maybe_update_function_parm (rhs);
>      }
>    else if (lkind == REFLECT_DATA_MEMBER_SPEC)
> -    return (TREE_VEC_ELT (lhs, 0) == TREE_VEC_ELT (rhs, 0)
> -           && TREE_VEC_ELT (lhs, 1) == TREE_VEC_ELT (rhs, 1)
> -           && tree_int_cst_equal (TREE_VEC_ELT (lhs, 2),
> -                                  TREE_VEC_ELT (rhs, 2))
> -           && tree_int_cst_equal (TREE_VEC_ELT (lhs, 3),
> -                                  TREE_VEC_ELT (rhs, 3))
> -           && TREE_VEC_ELT (lhs, 4) == TREE_VEC_ELT (rhs, 4));
> +    {
> +      if (typedef_variant_p (TREE_VEC_ELT (lhs, 0))
> +         != typedef_variant_p (TREE_VEC_ELT (rhs, 0))
> +         || !same_type_p (TREE_VEC_ELT (lhs, 0), TREE_VEC_ELT (rhs, 0))
> +         || TREE_VEC_ELT (lhs, 1) != TREE_VEC_ELT (rhs, 1)
> +         || !tree_int_cst_equal (TREE_VEC_ELT (lhs, 2),
> +                                 TREE_VEC_ELT (rhs, 2))
> +         || !tree_int_cst_equal (TREE_VEC_ELT (lhs, 3),
> +                                 TREE_VEC_ELT (rhs, 3))
> +         || TREE_VEC_ELT (lhs, 4) != TREE_VEC_ELT (rhs, 4)
> +         || TREE_VEC_LENGTH (lhs) != TREE_VEC_LENGTH (rhs))
> +       return false;
> +      for (int i = 5; i < TREE_VEC_LENGTH (lhs); ++i)
> +       if (!compare_reflections (TREE_VEC_ELT (lhs, i),
> +                                 TREE_VEC_ELT (rhs, i)))
> +         return false;
> +      return true;
> +    }
>    else if (lkind == REFLECT_ANNOTATION)
>      return TREE_VALUE (lhs) == TREE_VALUE (rhs);
>    else if (TYPE_P (lhs) && TYPE_P (rhs))
> --- gcc/cp/mangle.cc.jj 2026-03-25 20:19:10.715163161 +0100
> +++ gcc/cp/mangle.cc    2026-03-25 20:19:53.793444246 +0100
> @@ -4254,6 +4254,8 @@ write_reflection (tree refl)
>        write_char ('_');
>        if (integer_nonzerop (TREE_VEC_ELT (arg, 4)))
>         write_char ('n');
> +      for (int i = 5; i < TREE_VEC_LENGTH (arg); ++i)
> +       write_template_arg (REFLECT_EXPR_HANDLE (TREE_VEC_ELT (arg, i)));
>      }
>  }
>
> --- gcc/testsuite/g++.dg/reflect/data_member_spec5.C.jj 2026-03-25 
> 20:19:53.793845668 +0100
> +++ gcc/testsuite/g++.dg/reflect/data_member_spec5.C    2026-03-25 
> 20:57:51.968202948 +0100
> @@ -0,0 +1,114 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +// Test std::meta::data_member_spec.
> +
> +#include <meta>
> +
> +using namespace std::meta;
> +
> +consteval bool
> +valid_data_member_spec (info type, data_member_options opts)
> +{
> +  try { data_member_spec (type, opts); }
> +  catch (std::meta::exception &) { return false; }
> +  return true;
> +}
> +
> +struct S { int a, b; };
> +
> +consteval bool
> +foo ()
> +{
> +  constexpr int two = 2;
> +  [[=1]] int three = 3;
> +  constexpr int fourtytwo = 42;
> +  constexpr double fourtytwoandhalf = 42.5;
> +  data_member_options a = { .name = "_",
> +                           .annotations = { ^^two, reflect_constant (42),
> +                                            annotations_of (^^three)[0],
> +                                            reflect_constant (42.5),
> +                                            reflect_constant (S { 1, 2 }) } 
> };
> +  auto dmsa = data_member_spec (^^int, a);
> +  if (!is_data_member_spec (dmsa))
> +    throw 1;
> +  if (dmsa
> +      != data_member_spec (^^int,
> +                          { .name = "_",
> +                            .annotations = { reflect_constant (2),
> +                                             ^^fourtytwo,
> +                                             reflect_constant (1),
> +                                             ^^fourtytwoandhalf,
> +                                             reflect_constant (S { 1, 2 }) } 
> }))
> +    throw 2;
> +  if (dmsa == data_member_spec (^^int, { .name = "_" }))
> +    throw 3;
> +  if (dmsa
> +      == data_member_spec (^^int,
> +                          { .name = "_",
> +                            .annotations = { reflect_constant (2L),
> +                                             ^^fourtytwo,
> +                                             reflect_constant (1),
> +                                             ^^fourtytwoandhalf,
> +                                             reflect_constant (S { 1, 2 }) } 
> }))
> +    throw 4;
> +  if (dmsa
> +      == data_member_spec (^^int,
> +                          { .name = "_",
> +                            .annotations = { reflect_constant (2),
> +                                             ^^two,
> +                                             reflect_constant (1),
> +                                             ^^fourtytwoandhalf,
> +                                             reflect_constant (S { 1, 2 }) } 
> }))
> +    throw 4;
> +  if (dmsa
> +      == data_member_spec (^^int,
> +                          { .name = "_",
> +                            .annotations = { reflect_constant (2),
> +                                             ^^fourtytwo,
> +                                             reflect_constant (3),
> +                                             ^^fourtytwoandhalf,
> +                                             reflect_constant (S { 1, 2 }) } 
> }))
> +    throw 5;
> +  if (dmsa
> +      == data_member_spec (^^int,
> +                          { .name = "_",
> +                            .annotations = { reflect_constant (2),
> +                                             ^^fourtytwo,
> +                                             reflect_constant (1),
> +                                             reflect_constant (42.25),
> +                                             reflect_constant (S { 1, 2 }) } 
> }))
> +    throw 6;
> +  if (dmsa
> +      == data_member_spec (^^int,
> +                          { .name = "_",
> +                            .annotations = { reflect_constant (2),
> +                                             ^^fourtytwo,
> +                                             reflect_constant (1),
> +                                             reflect_constant (42.25),
> +                                             reflect_constant (S { 1, 2 }) } 
> }))
> +    throw 7;
> +  if (dmsa
> +      == data_member_spec (^^int,
> +                          { .name = "_",
> +                            .annotations = { reflect_constant (2),
> +                                             ^^fourtytwo,
> +                                             reflect_constant (1),
> +                                             reflect_constant (42.5),
> +                                             reflect_constant (S { 2, 2 }) } 
> }))
> +    throw 8;
> +  return true;
> +}
> +
> +static_assert (foo ());
> +
> +constexpr int arr[1] = { 1 };
> +constexpr int i = 42;
> +constexpr S s = { 42, 43 };
> +
> +static_assert (!valid_data_member_spec (^^int, { .name = "a", .annotations = 
> { ^^:: } }));
> +static_assert (!valid_data_member_spec (^^int, { .name = "a", .annotations = 
> { ^^foo } }));
> +static_assert (!valid_data_member_spec (^^int, { .name = "a", .annotations = 
> { ^^arr } }));
> +static_assert (!valid_data_member_spec (^^int, { .name = "a", .annotations = 
> { ^^arr } }));
> +static_assert (valid_data_member_spec (^^int, { .name = "a", .annotations = 
> { ^^i } }));
> +static_assert (valid_data_member_spec (^^int, { .name = "a", .annotations = 
> { ^^s } }));
> +static_assert (!valid_data_member_spec (^^int, { .bit_width = 0, 
> .annotations = { ^^i } }));
> --- gcc/testsuite/g++.dg/reflect/data_member_spec6.C.jj 2026-03-25 
> 20:19:53.793938985 +0100
> +++ gcc/testsuite/g++.dg/reflect/data_member_spec6.C    2026-03-25 
> 20:36:46.230470634 +0100
> @@ -0,0 +1,12 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +// Test std::meta::data_member_spec.
> +
> +#include <meta>
> +
> +using namespace std::meta;
> +
> +struct T { constexpr T () : t (42) {} constexpr int bar () const { return t; 
> } protected: int t; };
> +constexpr T t;
> +
> +constexpr auto a = data_member_spec (^^int, { .name = "a", .annotations = { 
> ^^t } }); // { dg-error "'T' must be a cv-unqualified structural type that is 
> not a reference type" }
> --- gcc/testsuite/g++.dg/reflect/display_string_of1.C.jj        2026-03-25 
> 20:19:10.716163144 +0100
> +++ gcc/testsuite/g++.dg/reflect/display_string_of1.C   2026-03-25 
> 20:38:11.399038570 +0100
> @@ -115,10 +115,11 @@ foo (int a, const long b, T c, int d[4],
>    static_assert (display_string_of (^^NSAlias) == "NSAlias");
>    static_assert (display_string_of (^^NS) == "NS");
>    static_assert (display_string_of (bases_of (^^S, ctx)[0]) == "S: B");
> -  static_assert (display_string_of (data_member_spec (^^int, { .name = 
> "member", .alignment = 128, .no_unique_address = true })) == "(int, member, 
> 128, , true)");
> -  static_assert (display_string_of (data_member_spec (^^const int, { .name = 
> "member", .bit_width = 6 })) == "(const int, member, , 6, false)");
> -  static_assert (display_string_of (data_member_spec (^^int, { .bit_width = 
> 0 })) == "(int, , , 0, false)");
> -  static_assert (display_string_of (data_member_spec (^^long, { .bit_width = 
> 5 })) == "(long int, , , 5, false)");
> +  static_assert (display_string_of (data_member_spec (^^int, { .name = 
> "member", .alignment = 128, .no_unique_address = true })) == "(int, member, 
> 128, , true, {})");
> +  static_assert (display_string_of (data_member_spec (^^const int, { .name = 
> "member", .bit_width = 6 })) == "(const int, member, , 6, false, {})");
> +  static_assert (display_string_of (data_member_spec (^^int, { .bit_width = 
> 0 })) == "(int, , , 0, false, {})");
> +  static_assert (display_string_of (data_member_spec (^^long, { .bit_width = 
> 5 })) == "(long int, , , 5, false, {})");
> +  static_assert (display_string_of (data_member_spec (^^int, { .name = "_", 
> .annotations = { reflect_constant (42), reflect_constant (42.5) }})) == 
> "(int, _, , , false, {42, 4.25e+1})");
>    static_assert (display_string_of (annotations_of (^^bar)[0]) == "[[=1]]");
>    static_assert (display_string_of (annotations_of (^^bar)[1]) == "[[=AN{1, 
> 42, ' '}]]");
>    static_assert (display_string_of (^^int) == "int");
> --- gcc/testsuite/g++.dg/reflect/u8display_string_of1.C.jj      2026-03-25 
> 20:19:10.719163094 +0100
> +++ gcc/testsuite/g++.dg/reflect/u8display_string_of1.C 2026-03-25 
> 20:39:33.691654866 +0100
> @@ -115,10 +115,11 @@ foo (int a, const long b, T c, int d[4],
>    static_assert (u8display_string_of (^^NSAlias) == u8"NSAlias");
>    static_assert (u8display_string_of (^^NS) == u8"NS");
>    static_assert (u8display_string_of (bases_of (^^S, ctx)[0]) == u8"S: B");
> -  static_assert (u8display_string_of (data_member_spec (^^int, { .name = 
> "member", .alignment = 128, .no_unique_address = true })) == u8"(int, member, 
> 128, , true)");
> -  static_assert (u8display_string_of (data_member_spec (^^const int, { .name 
> = "member", .bit_width = 6 })) == u8"(const int, member, , 6, false)");
> -  static_assert (u8display_string_of (data_member_spec (^^int, { .bit_width 
> = 0 })) == u8"(int, , , 0, false)");
> -  static_assert (u8display_string_of (data_member_spec (^^long, { .bit_width 
> = 5 })) == u8"(long int, , , 5, false)");
> +  static_assert (u8display_string_of (data_member_spec (^^int, { .name = 
> "member", .alignment = 128, .no_unique_address = true })) == u8"(int, member, 
> 128, , true, {})");
> +  static_assert (u8display_string_of (data_member_spec (^^const int, { .name 
> = "member", .bit_width = 6 })) == u8"(const int, member, , 6, false, {})");
> +  static_assert (u8display_string_of (data_member_spec (^^int, { .bit_width 
> = 0 })) == u8"(int, , , 0, false, {})");
> +  static_assert (u8display_string_of (data_member_spec (^^long, { .bit_width 
> = 5 })) == u8"(long int, , , 5, false, {})");
> +  static_assert (u8display_string_of (data_member_spec (^^int, { .name = 
> u8"_", .annotations = { reflect_constant (42), reflect_constant (42.5) }})) 
> == u8"(int, _, , , false, {42, 4.25e+1})");
>    static_assert (u8display_string_of (annotations_of (^^bar)[0]) == 
> u8"[[=1]]");
>    static_assert (u8display_string_of (annotations_of (^^bar)[1]) == 
> u8"[[=AN{1, 42, ' '}]]");
>    static_assert (u8display_string_of (^^int) == u8"int");
> --- gcc/testsuite/g++.dg/reflect/define_aggregate9.C.jj 2026-03-25 
> 20:19:53.794445393 +0100
> +++ gcc/testsuite/g++.dg/reflect/define_aggregate9.C    2026-03-25 
> 20:37:16.232966156 +0100
> @@ -0,0 +1,35 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +// Test std::meta::define_aggregate.
> +
> +#include <meta>
> +
> +using namespace std::meta;
> +
> +struct S { int a, b; };
> +struct T;
> +
> +consteval
> +{
> +  constexpr int two = 2;
> +  [[=1]] int three = 3;
> +  constexpr int fourtytwo = 42;
> +  constexpr double fourtytwoandhalf = 42.5;
> +  data_member_options a = { .name = "_",
> +                           .annotations = { ^^two, reflect_constant (42),
> +                                            annotations_of (^^three)[0],
> +                                            reflect_constant (42.5),
> +                                            reflect_constant (S { 1, 2 }) } 
> };
> +  auto dmsa = data_member_spec (^^int, a);
> +  define_aggregate (^^T, { dmsa });
> +}
> +consteval
> +{
> +  static_assert (annotations_of (^^T::_).size () == 5);
> +  static_assert ([: constant_of (annotations_of (^^T::_)[0]) :] == 2);
> +  static_assert ([: constant_of (annotations_of (^^T::_)[1]) :] == 42);
> +  static_assert ([: constant_of (annotations_of (^^T::_)[2]) :] == 1);
> +  static_assert ([: constant_of (annotations_of (^^T::_)[3]) :] == 42.5);
> +  static_assert ([: constant_of (annotations_of (^^T::_)[4]) :].a == 1);
> +  static_assert ([: constant_of (annotations_of (^^T::_)[4]) :].b == 2);
> +}
> --- gcc/testsuite/g++.dg/reflect/mangle1.C.jj   2026-03-25 20:19:14.911093136 
> +0100
> +++ gcc/testsuite/g++.dg/reflect/mangle1.C      2026-03-25 20:58:44.185325865 
> +0100
> @@ -63,6 +63,7 @@ namespace NS2 {
>    };
>    struct Z {
>    };
> +  struct AA { int a, b; };
>  }
>
>  constexpr auto ctx = std::meta::access_context::current ();
> @@ -165,6 +166,11 @@ baz (int x)
>    bar <332, data_member_spec (^^unsigned short, { .name = "b", .bit_width = 
> 5 })> (); // data member description
>    bar <333, data_member_spec (^^long, { .bit_width = 3 })> (); // data 
> member description
>    bar <334, data_member_spec (^^int, { .bit_width = 0 })> (); // data member 
> description
> +  bar <335, std::meta::data_member_spec (^^int,
> +                                        { .name = "_",
> +                                          .annotations = { 
> std::meta::reflect_constant (42),
> +                                                           
> std::meta::reflect_constant (43L),
> +                                                           
> std::meta::reflect_constant (NS2::AA { 1, 2 }) } })> (); // data member 
> description
>    bar <340, ^^NS2::X::~X> (); // function
>  }
>
> @@ -250,4 +256,5 @@ baz (int x)
>  // { dg-final { scan-assembler "_Z3barILi332ELDmdst_1b__5_EEvv" } }
>  // { dg-final { scan-assembler "_Z3barILi333ELDmdsl___3_EEvv" } }
>  // { dg-final { scan-assembler "_Z3barILi334ELDmdsi___0_EEvv" } }
> +// { dg-final { scan-assembler 
> "_Z3barILi335ELDmdsi_1____Li42ELl43EXtlN3NS22AAELi1ELi2EEEEEvv" } }
>  // { dg-final { scan-assembler "_Z3barILi340ELDmfnN3NS21XD4EvEEvv" } }
>
>
>         Jakub
>

Reply via email to