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 >
