Hi!

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.

Tested on x86_64-linux.

2026-03-25  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_display_string_of): Handle annotations in
        REFLECT_DATA_MEMBER_SPEC.
        (eval_data_member_spec): Read and diagnose annotations.
        (eval_define_aggregate): 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 08:14:07.297917425 +0100
+++ libstdc++-v3/include/std/meta       2026-03-25 10:34:52.732153013 +0100
@@ -423,6 +423,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(data_member_options);
     consteval bool is_data_member_spec(info);
--- gcc/cp/reflect.cc.jj        2026-03-25 08:15:13.865777063 +0100
+++ gcc/cp/reflect.cc   2026-03-25 17:14:12.428239630 +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,
@@ -3643,10 +3651,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))));
@@ -5560,7 +5574,8 @@ eval_data_member_spec (location_t loc, c
       *non_constant_p = true;
       return NULL_TREE;
     }
-  tree args[5] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
+  tree args[6] = { NULL_TREE, 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))
@@ -5575,8 +5590,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 = 0; i < 5; ++i)
+  for (int i = 0; i < 6; ++i)
     {
       if (args[i] == NULL_TREE)
        goto fail;
@@ -5623,6 +5640,19 @@ eval_data_member_spec (location_t loc, c
            args[i] = boolean_true_node;
          continue;
        }
+      if (i == 5)
+       {
+         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;
@@ -5854,6 +5884,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)
@@ -5895,9 +5929,30 @@ 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);
 }
 
@@ -6187,12 +6242,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;
     }
@@ -8395,13 +8462,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-23 11:26:45.800386996 +0100
+++ gcc/cp/mangle.cc    2026-03-25 17:25:42.742618257 +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 
13:48:30.599086322 +0100
+++ gcc/testsuite/g++.dg/reflect/data_member_spec5.C    2026-03-25 
15:07:54.567723729 +0100
@@ -0,0 +1,107 @@
+// { 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 (data_member_options opts)
+{
+  try { data_member_spec (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 = { .type = ^^int, .name = "_",
+                           .annotations = { ^^two, reflect_constant (42),
+                                            annotations_of (^^three)[0],
+                                            reflect_constant (42.5),
+                                            reflect_constant (S { 1, 2 }) } };
+  auto dmsa = data_member_spec (a);
+  if (!is_data_member_spec (dmsa))
+    throw 1;
+  if (dmsa
+      != data_member_spec ({ .type = ^^int, .name = "_",
+                            .annotations = { reflect_constant (2),
+                                             ^^fourtytwo,
+                                             reflect_constant (1),
+                                             ^^fourtytwoandhalf,
+                                             reflect_constant (S { 1, 2 }) } 
}))
+    throw 2;
+  if (dmsa == data_member_spec ({ .type = ^^int, .name = "_" }))
+    throw 3;
+  if (dmsa
+      == data_member_spec ({ .type = ^^int, .name = "_",
+                            .annotations = { reflect_constant (2L),
+                                             ^^fourtytwo,
+                                             reflect_constant (1),
+                                             ^^fourtytwoandhalf,
+                                             reflect_constant (S { 1, 2 }) } 
}))
+    throw 4;
+  if (dmsa
+      == data_member_spec ({ .type = ^^int, .name = "_",
+                            .annotations = { reflect_constant (2),
+                                             ^^two,
+                                             reflect_constant (1),
+                                             ^^fourtytwoandhalf,
+                                             reflect_constant (S { 1, 2 }) } 
}))
+    throw 4;
+  if (dmsa
+      == data_member_spec ({ .type = ^^int, .name = "_",
+                            .annotations = { reflect_constant (2),
+                                             ^^fourtytwo,
+                                             reflect_constant (3),
+                                             ^^fourtytwoandhalf,
+                                             reflect_constant (S { 1, 2 }) } 
}))
+    throw 5;
+  if (dmsa
+      == data_member_spec ({ .type = ^^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 ({ .type = ^^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 ({ .type = ^^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 ({ .type = ^^int, .name = "a", 
.annotations = { ^^:: } }));
+static_assert (!valid_data_member_spec ({ .type = ^^int, .name = "a", 
.annotations = { ^^foo } }));
+static_assert (!valid_data_member_spec ({ .type = ^^int, .name = "a", 
.annotations = { ^^arr } }));
+static_assert (!valid_data_member_spec ({ .type = ^^int, .name = "a", 
.annotations = { ^^arr } }));
+static_assert (valid_data_member_spec ({ .type = ^^int, .name = "a", 
.annotations = { ^^i } }));
+static_assert (valid_data_member_spec ({ .type = ^^int, .name = "a", 
.annotations = { ^^s } }));
+static_assert (!valid_data_member_spec ({ .type = ^^int, .bit_width = 0, 
.annotations = { ^^i } }));
--- gcc/testsuite/g++.dg/reflect/data_member_spec6.C.jj 2026-03-25 
13:48:38.373955304 +0100
+++ gcc/testsuite/g++.dg/reflect/data_member_spec6.C    2026-03-25 
13:58:47.664661356 +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 ({ .type = ^^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-24 
23:13:58.419214921 +0100
+++ gcc/testsuite/g++.dg/reflect/display_string_of1.C   2026-03-25 
17:12:51.955591801 +0100
@@ -115,10 +115,12 @@ 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 ({ .type = ^^int, .name = 
"member", .alignment = 128, .no_unique_address = true })) == "(int, member, 
128, , true)");
-  static_assert (display_string_of (data_member_spec ({ .type = ^^const int, 
.name = "member", .bit_width = 6 })) == "(const int, member, , 6, false)");
-  static_assert (display_string_of (data_member_spec ({ .type = ^^int, 
.bit_width = 0 })) == "(int, , , 0, false)");
-  static_assert (display_string_of (data_member_spec ({ .type = ^^long, 
.bit_width = 5 })) == "(long int, , , 5, false)");
+  static_assert (display_string_of (data_member_spec ({ .type = ^^int, .name = 
"member", .alignment = 128, .no_unique_address = true })) == "(int, member, 
128, , true, {})");
+  static_assert (display_string_of (data_member_spec ({ .type = ^^const int, 
.name = "member", .bit_width = 6 })) == "(const int, member, , 6, false, {})");
+  static_assert (display_string_of (data_member_spec ({ .type = ^^int, 
.bit_width = 0 })) == "(int, , , 0, false, {})");
+  static_assert (display_string_of (data_member_spec ({ .type = ^^long, 
.bit_width = 5 })) == "(long int, , , 5, false, {})");
+  static_assert (display_string_of (data_member_spec ({ .type = ^^long, 
.bit_width = 5 })) == "(long int, , , 5, false, {})");
+  static_assert (display_string_of (data_member_spec ({ .type = ^^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-24 
23:13:58.597110034 +0100
+++ gcc/testsuite/g++.dg/reflect/u8display_string_of1.C 2026-03-25 
17:13:10.900273473 +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 ({ .type = ^^int, .name 
= "member", .alignment = 128, .no_unique_address = true })) == u8"(int, member, 
128, , true)");
-  static_assert (u8display_string_of (data_member_spec ({ .type = ^^const int, 
.name = "member", .bit_width = 6 })) == u8"(const int, member, , 6, false)");
-  static_assert (u8display_string_of (data_member_spec ({ .type = ^^int, 
.bit_width = 0 })) == u8"(int, , , 0, false)");
-  static_assert (u8display_string_of (data_member_spec ({ .type = ^^long, 
.bit_width = 5 })) == u8"(long int, , , 5, false)");
+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^int, .name 
= "member", .alignment = 128, .no_unique_address = true })) == u8"(int, member, 
128, , true, {})");
+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^const int, 
.name = "member", .bit_width = 6 })) == u8"(const int, member, , 6, false, 
{})");
+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^int, 
.bit_width = 0 })) == u8"(int, , , 0, false, {})");
+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^long, 
.bit_width = 5 })) == u8"(long int, , , 5, false, {})");
+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^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 
17:04:54.522614030 +0100
+++ gcc/testsuite/g++.dg/reflect/define_aggregate9.C    2026-03-25 
17:17:38.458776225 +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 = { .type = ^^int, .name = "_",
+                           .annotations = { ^^two, reflect_constant (42),
+                                            annotations_of (^^three)[0],
+                                            reflect_constant (42.5),
+                                            reflect_constant (S { 1, 2 }) } };
+  auto dmsa = data_member_spec (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-24 23:41:54.125019058 
+0100
+++ gcc/testsuite/g++.dg/reflect/mangle1.C      2026-03-25 17:35:37.373600962 
+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,10 @@ baz (int x)
   bar <332, std::meta::data_member_spec ({ .type = ^^unsigned short, .name = 
"b", .bit_width = 5 })> (); // data member description
   bar <333, std::meta::data_member_spec ({ .type = ^^long, .bit_width = 3 })> 
(); // data member description
   bar <334, std::meta::data_member_spec ({ .type = ^^int, .bit_width = 0 })> 
(); // data member description
+  bar <335, std::meta::data_member_spec ({ .type = ^^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 +255,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