{"id":2216023,"url":"http://patchwork.ozlabs.org/api/patches/2216023/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/acQSYCLQ-MCBsZBO@tucnak/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<acQSYCLQ-MCBsZBO@tucnak>","list_archive_url":null,"date":"2026-03-25T16:50:40","name":"[RFC] c++: Handle annotations in data_member_spec/define_aggregate","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"029d321bcf3e8e49bfb13003140f147ac5178c80","submitter":{"id":671,"url":"http://patchwork.ozlabs.org/api/people/671/?format=json","name":"Jakub Jelinek","email":"jakub@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/acQSYCLQ-MCBsZBO@tucnak/mbox/","series":[{"id":497474,"url":"http://patchwork.ozlabs.org/api/series/497474/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=497474","date":"2026-03-25T16:50:40","name":"[RFC] c++: Handle annotations in data_member_spec/define_aggregate","version":1,"mbox":"http://patchwork.ozlabs.org/series/497474/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2216023/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2216023/checks/","tags":{},"related":[],"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=e058mvFN;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=e058mvFN","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.129.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fgtGh0vDdz1xy1\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 26 Mar 2026 03:51:40 +1100 (AEDT)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 0F9FF4B9DB44\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 16:51:38 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id E8EE34BA2E0E\n for <gcc-patches@gcc.gnu.org>; Wed, 25 Mar 2026 16:50:58 +0000 (GMT)","from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-659-tNTPdVawOsK18KfBSVsm5A-1; Wed,\n 25 Mar 2026 12:50:50 -0400","from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 14A4B1955D4E\n for <gcc-patches@gcc.gnu.org>; Wed, 25 Mar 2026 16:50:45 +0000 (UTC)","from tucnak.zalov.cz (unknown [10.45.225.193])\n by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with\n ESMTPS\n id CA04F19560B1; Wed, 25 Mar 2026 16:50:43 +0000 (UTC)","from tucnak.zalov.cz (localhost [127.0.0.1])\n by tucnak.zalov.cz (8.18.1/8.18.1) with ESMTPS id 62PGoex33827674\n (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);\n Wed, 25 Mar 2026 17:50:41 +0100","(from jakub@localhost)\n by tucnak.zalov.cz (8.18.1/8.18.1/Submit) id 62PGoeYI3827673;\n Wed, 25 Mar 2026 17:50:40 +0100"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 0F9FF4B9DB44","OpenDKIM Filter v2.11.0 sourceware.org E8EE34BA2E0E"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org E8EE34BA2E0E","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org E8EE34BA2E0E","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774457459; cv=none;\n b=r4nriSQt4Pbk4NaZUyglEqab+tWXt253XcH4XoqUWM5degnWd9IY1y5xBGKzkCLyvXh3RHnkJb3XS2eHDq/8g8ZHAkFCsDyGxgWX9MfTl64kzmPolFBM07CFcL9JzYss4SxAxFeMa5ZUObf7mV0PRg4sIrSimvdGNPa3E5KhJP0=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1774457459; c=relaxed/simple;\n bh=/FoJFa9vPcTmeBJ2Y5YyWYcAFqln3YXofR46Qj7Mrb8=;\n h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version;\n b=h1I8mf0nFvCWUGs8/LRVZaeVjMGpNK+i2gNGelAgSjult4kDntyKLQwGNzCZdJoqG1abG4UHip+cJeUWuo5BmVuuEIa5mCZNnf/m7BN0AlvYw6Yg0TNz15c0t7cTGT8FtnuzBTB/TiL8N8biMykQz9iMyjyUKr1tEtEOI3NXQAE=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1774457458;\n h=from:from:reply-to:reply-to:subject:subject:date:date:\n message-id:message-id:to:to:cc:cc:mime-version:mime-version:\n content-type:content-type; bh=sWUye9q56qTm3foGTdUfUDvFCqkAmOjjtc6VGghP6Mg=;\n b=e058mvFNWpMK7hi7+1ha0X61w5LXDUrerg4kKyOcxMH+sMHYhss7c0JzfYWtqfksN+vYG0\n epqOwUI/RZSBgK2CmOJiUQrgVQlmGHo2OBqpietsWpR1JUDQXGueG4tqZrfkWpISH2+0X8\n SOWKrD3FgNEHQEAugqgsu9/IvdUYomA=","X-MC-Unique":"tNTPdVawOsK18KfBSVsm5A-1","X-Mimecast-MFC-AGG-ID":"tNTPdVawOsK18KfBSVsm5A_1774457446","Date":"Wed, 25 Mar 2026 17:50:40 +0100","From":"Jakub Jelinek <jakub@redhat.com>","To":"Jason Merrill <jason@redhat.com>, Marek Polacek <polacek@redhat.com>,\n Jonathan Wakely <jwakely@redhat.com>","Cc":"gcc-patches@gcc.gnu.org","Subject":"[RFC PATCH] c++: Handle annotations in\n data_member_spec/define_aggregate","Message-ID":"<acQSYCLQ-MCBsZBO@tucnak>","MIME-Version":"1.0","X-Scanned-By":"MIMEDefang 3.0 on 10.30.177.12","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"W29VLBSJAtvRZVjMHlmUPTGfutk5cu1_409vWad-yAE_1774457446","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Reply-To":"Jakub Jelinek <jakub@redhat.com>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"Hi!\n\nThe following patch attempts to implement another part of P3795R1\n(though with some changes Barry has queued for P3795R2, in particular\nthrowing on !has-type(r) in the annotations sequence or when the\nannotations are non-empty and name is not specified), in particular\nthe addition of annotations to data_member_options and handling it in\ndata_member_spec/define_aggregate etc.\n\nThis is on top of the earlier data_member_spec patch, though even if\nit is decided to revert that part of changes, it shouldn't be hard\nto adjust this patch to apply.\n\nTested on x86_64-linux.\n\n2026-03-25  Jakub Jelinek  <jakub@redhat.com>\n\nlibstdc++-v3/\n\t* include/std/meta (std::meta::data_member_options): Add annotations\n\tmember.\ngcc/cp/\n\t* reflect.cc (get_range_elts): If N is negative, just use the tree\n\tas object to extract range from instead of finding Nth argument\n\tof a call.\n\t(eval_display_string_of): Handle annotations in\n\tREFLECT_DATA_MEMBER_SPEC.\n\t(eval_data_member_spec): Read and diagnose annotations.\n\t(eval_define_aggregate): Create annotations.\n\t(compare_reflections): Compare REFLECT_DATA_MEMBER_SPEC annotations.\n\t* mangle.cc (write_reflection): Mangle REFLECT_DATA_MEMBER_SPEC\n\tannotations.\ngcc/testsuite/\n\t* g++.dg/reflect/data_member_spec5.C: New test.\n\t* g++.dg/reflect/data_member_spec6.C: New test.\n\t* g++.dg/reflect/display_string_of1.C: Expect extra \", {}\" before\n\t\")\" for empty annotations, otherwise a list of annotations.\n\t* g++.dg/reflect/u8display_string_of1.C: Likewise.\n\t* g++.dg/reflect/define_aggregate9.C: New test.\n\t* g++.dg/reflect/mangle1.C: Test mangling of REFLECT_DATA_MEMBER_SPEC\n\tannotations.\n\n\n\tJakub","diff":"--- libstdc++-v3/include/std/meta.jj\t2026-03-25 08:14:07.297917425 +0100\n+++ libstdc++-v3/include/std/meta\t2026-03-25 10:34:52.732153013 +0100\n@@ -423,6 +423,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n       optional<int> alignment;\n       optional<int> bit_width;\n       bool no_unique_address = false;\n+      vector<info> annotations;\n     };\n     consteval info data_member_spec(data_member_options);\n     consteval bool is_data_member_spec(info);\n--- gcc/cp/reflect.cc.jj\t2026-03-25 08:15:13.865777063 +0100\n+++ gcc/cp/reflect.cc\t2026-03-25 17:14:12.428239630 +0100\n@@ -383,18 +383,25 @@ enum get_range_elts_kind {\n    eval_reflect_constant_array.  For GET_INFO_VEC kind, <meta> ensures\n    the argument is reference to reflection_range concept and so both\n    range_value_t is info and range_refernce_t is cv info or cv info & or\n-   cv info &&.  */\n+   cv info &&.  If N is negative, CALL is the expression to extract\n+   values from rather than N-th argument from CALL.  */\n \n static tree\n get_range_elts (location_t loc, const constexpr_ctx *ctx, tree call, int n,\n \t\tbool *non_constant_p, bool *overflow_p, tree *jump_target,\n \t\tget_range_elts_kind kind, tree fun)\n {\n-  gcc_checking_assert (call_expr_nargs (call) > n);\n-  tree arg = get_nth_callarg (call, n);\n-  tree parm = DECL_ARGUMENTS (cp_get_callee_fndecl_nofold (call));\n-  for (int i = 0; i < n; ++i)\n-    parm = DECL_CHAIN (parm);\n+  tree arg, parm;\n+  if (n < 0)\n+    arg = parm = call;\n+  else\n+    {\n+      gcc_checking_assert (call_expr_nargs (call) > n);\n+      arg = get_nth_callarg (call, n);\n+      parm = DECL_ARGUMENTS (cp_get_callee_fndecl_nofold (call));\n+      for (int i = 0; i < n; ++i)\n+\tparm = DECL_CHAIN (parm);\n+    }\n   tree type = TREE_TYPE (arg);\n   gcc_checking_assert (TYPE_REF_P (type));\n   arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, non_constant_p,\n@@ -539,7 +546,8 @@ get_range_elts (location_t loc, const co\n     tree call = finish_call_expr (obj, &args, true, false, complain);\n     if (call == error_mark_node)\n       return call;\n-    cp_walk_tree (&call, replace_parm_r, map, NULL);\n+    if (n >= 0)\n+      cp_walk_tree (&call, replace_parm_r, map, NULL);\n     if (complain != tf_none)\n       return call;\n     call = cxx_eval_constant_expression (ctx, call, vc_prvalue, non_constant_p,\n@@ -3643,10 +3651,16 @@ eval_display_string_of (location_t loc,\n       pp_printf (&pp, \"%T: %T\", d, BINFO_TYPE (r));\n     }\n   else if (kind == REFLECT_DATA_MEMBER_SPEC)\n-    pp_printf (&pp, \"(%T, %E, %E, %E, %s)\", TREE_VEC_ELT (r, 0),\n-\t       TREE_VEC_ELT (r, 1), TREE_VEC_ELT (r, 2), TREE_VEC_ELT (r, 3),\n-\t       TREE_VEC_ELT (r, 4) == boolean_true_node\n-\t       ? \"true\" : \"false\");\n+    {\n+      pp_printf (&pp, \"(%T, %E, %E, %E, %s, {\", TREE_VEC_ELT (r, 0),\n+\t\t TREE_VEC_ELT (r, 1), TREE_VEC_ELT (r, 2), TREE_VEC_ELT (r, 3),\n+\t\t TREE_VEC_ELT (r, 4) == boolean_true_node\n+\t\t ? \"true\" : \"false\");\n+      for (int i = 5; i < TREE_VEC_LENGTH (r); ++i)\n+\tpp_printf (&pp, \"%s%E\", i == 5 ? \"\" : \", \",\n+\t\t   REFLECT_EXPR_HANDLE (TREE_VEC_ELT (r, i)));\n+      pp_printf (&pp, \"})\");\n+    }\n   else if (eval_is_annotation (r, kind) == boolean_true_node)\n     pp_printf (&pp, \"[[=%E]]\",\n \t       tree_strip_any_location_wrapper (TREE_VALUE (TREE_VALUE (r))));\n@@ -5560,7 +5574,8 @@ eval_data_member_spec (location_t loc, c\n       *non_constant_p = true;\n       return NULL_TREE;\n     }\n-  tree args[5] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };\n+  tree args[6] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,\n+\t\t   NULL_TREE};\n   for (tree field = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (opts)));\n        field; field = next_aggregate_field (DECL_CHAIN (field)))\n     if (tree name = DECL_NAME (field))\n@@ -5575,8 +5590,10 @@ eval_data_member_spec (location_t loc, c\n \t  args[3] = field;\n \telse if (id_equal (name, \"no_unique_address\"))\n \t  args[4] = field;\n+\telse if (id_equal (name, \"annotations\"))\n+\t  args[5] = field;\n       }\n-  for (int i = 0; i < 5; ++i)\n+  for (int i = 0; i < 6; ++i)\n     {\n       if (args[i] == NULL_TREE)\n \tgoto fail;\n@@ -5623,6 +5640,19 @@ eval_data_member_spec (location_t loc, c\n \t    args[i] = boolean_true_node;\n \t  continue;\n \t}\n+      if (i == 5)\n+\t{\n+\t  tree rtype\n+\t    = cp_build_reference_type (TREE_TYPE (opt), /*rval*/false);\n+\t  opt = build_address (opt);\n+\t  opt = fold_convert (rtype, opt);\n+\t  opt = get_info_vec (loc, ctx, opt, -1, non_constant_p, overflow_p,\n+\t\t\t      jump_target, fun);\n+\t  if (*jump_target || *non_constant_p)\n+\t    return NULL_TREE;\n+\t  args[i] = opt;\n+\t  continue;\n+\t}\n       /* Otherwise the member is optional<something>.  */\n       if (!CLASS_TYPE_P (TREE_TYPE (opt)))\n \tgoto fail;\n@@ -5854,6 +5884,10 @@ eval_data_member_spec (location_t loc, c\n     return throw_exception (loc, ctx,\n \t\t\t    \"neither name nor bit_width specified\",\n \t\t\t    fun, non_constant_p, jump_target);\n+  if (args[1] == NULL_TREE && TREE_VEC_LENGTH (args[5]))\n+    return throw_exception (loc, ctx,\n+\t\t\t    \"no name and non-empty annotations specified\",\n+\t\t\t    fun, non_constant_p, jump_target);\n   if (args[3])\n     {\n       if (!CP_INTEGRAL_TYPE_P (type) && TREE_CODE (type) != ENUMERAL_TYPE)\n@@ -5895,9 +5929,30 @@ eval_data_member_spec (location_t loc, c\n \t\t\t\t\"alignment is smaller than alignment_of\",\n \t\t\t\tfun, non_constant_p, jump_target);\n     }\n-  tree ret = make_tree_vec (5);\n+  for (int i = 0; i < TREE_VEC_LENGTH (args[5]); ++i)\n+    {\n+      tree r = REFLECT_EXPR_HANDLE (TREE_VEC_ELT (args[5], i));\n+      reflect_kind kind = REFLECT_EXPR_KIND (TREE_VEC_ELT (args[5], i));\n+      if (!has_type (r, kind))\n+\treturn throw_exception (loc, ctx, \"reflection does not have a type\",\n+\t\t\t\tfun, non_constant_p, jump_target);\n+      tree type = type_of (r, kind);\n+      if (eval_is_array_type (loc, type) == boolean_true_node\n+\t  || eval_is_object_type (loc, type) == boolean_false_node)\n+\treturn throw_exception (loc, ctx, \"reflection does not have \"\n+\t\t\t\t\t  \"non-array object type\",\n+\t\t\t\tfun, non_constant_p, jump_target);\n+      tree cst = eval_constant_of (loc, ctx, r, kind, non_constant_p,\n+\t\t\t\t   overflow_p, jump_target, fun);\n+      if (cst == NULL_TREE)\n+\treturn NULL_TREE;\n+      TREE_VEC_ELT (args[5], i) = cst;\n+    }\n+  tree ret = make_tree_vec (5 + TREE_VEC_LENGTH (args[5]));\n   for (int i = 0; i < 5; ++i)\n     TREE_VEC_ELT (ret, i) = args[i];\n+  for (int i = 0; i < TREE_VEC_LENGTH (args[5]); ++i)\n+    TREE_VEC_ELT (ret, i + 5) = TREE_VEC_ELT (args[5], i);\n   return get_reflection_raw (loc, ret, REFLECT_DATA_MEMBER_SPEC);\n }\n \n@@ -6187,12 +6242,24 @@ eval_define_aggregate (location_t loc, c\n \t\t\t      * BITS_PER_UNIT);\n \t  DECL_USER_ALIGN (f) = 1;\n \t}\n-      if (TREE_VEC_ELT (a, 4) == boolean_true_node)\n+      if (TREE_VEC_ELT (a, 4) == boolean_true_node\n+\t  || TREE_VEC_LENGTH (a) != 5)\n \t{\n-\t  tree attr = build_tree_list (NULL_TREE,\n-\t\t\t\t       get_identifier (\"no_unique_address\"));\n-\t  attr = build_tree_list (attr, NULL_TREE);\n-\t  cplus_decl_attributes (&f, attr, 0);\n+\t  tree attrs = NULL_TREE, attr;\n+\t  if (TREE_VEC_ELT (a, 4) == boolean_true_node)\n+\t    {\n+\t      attr = build_tree_list (NULL_TREE,\n+\t\t\t\t      get_identifier (\"no_unique_address\"));\n+\t      attrs = build_tree_list (attr, NULL_TREE);\n+\t    }\n+\t  for (int i = TREE_VEC_LENGTH (a) - 1; i >= 5; --i)\n+\t    {\n+\t      attr = build_tree_list (internal_identifier,\n+\t\t\t\t      annotation_identifier);\n+\t      tree val = REFLECT_EXPR_HANDLE (TREE_VEC_ELT (a, i));\n+\t      attrs = tree_cons (attr, build_tree_list (NULL_TREE, val), attrs);\n+\t    }\n+\t  cplus_decl_attributes (&f, attrs, 0);\n \t}\n       fields = f;\n     }\n@@ -8395,13 +8462,24 @@ compare_reflections (tree lhs, tree rhs)\n       rhs = maybe_update_function_parm (rhs);\n     }\n   else if (lkind == REFLECT_DATA_MEMBER_SPEC)\n-    return (TREE_VEC_ELT (lhs, 0) == TREE_VEC_ELT (rhs, 0)\n-\t    && TREE_VEC_ELT (lhs, 1) == TREE_VEC_ELT (rhs, 1)\n-\t    && tree_int_cst_equal (TREE_VEC_ELT (lhs, 2),\n-\t\t\t\t   TREE_VEC_ELT (rhs, 2))\n-\t    && tree_int_cst_equal (TREE_VEC_ELT (lhs, 3),\n-\t\t\t\t   TREE_VEC_ELT (rhs, 3))\n-\t    && TREE_VEC_ELT (lhs, 4) == TREE_VEC_ELT (rhs, 4));\n+    {\n+      if (typedef_variant_p (TREE_VEC_ELT (lhs, 0))\n+\t  != typedef_variant_p (TREE_VEC_ELT (rhs, 0))\n+\t  || !same_type_p (TREE_VEC_ELT (lhs, 0), TREE_VEC_ELT (rhs, 0))\n+\t  || TREE_VEC_ELT (lhs, 1) != TREE_VEC_ELT (rhs, 1)\n+\t  || !tree_int_cst_equal (TREE_VEC_ELT (lhs, 2),\n+\t\t\t\t  TREE_VEC_ELT (rhs, 2))\n+\t  || !tree_int_cst_equal (TREE_VEC_ELT (lhs, 3),\n+\t\t\t\t  TREE_VEC_ELT (rhs, 3))\n+\t  || TREE_VEC_ELT (lhs, 4) != TREE_VEC_ELT (rhs, 4)\n+\t  || TREE_VEC_LENGTH (lhs) != TREE_VEC_LENGTH (rhs))\n+\treturn false;\n+      for (int i = 5; i < TREE_VEC_LENGTH (lhs); ++i)\n+\tif (!compare_reflections (TREE_VEC_ELT (lhs, i),\n+\t\t\t\t  TREE_VEC_ELT (rhs, i)))\n+\t  return false;\n+      return true;\n+    }\n   else if (lkind == REFLECT_ANNOTATION)\n     return TREE_VALUE (lhs) == TREE_VALUE (rhs);\n   else if (TYPE_P (lhs) && TYPE_P (rhs))\n--- gcc/cp/mangle.cc.jj\t2026-03-23 11:26:45.800386996 +0100\n+++ gcc/cp/mangle.cc\t2026-03-25 17:25:42.742618257 +0100\n@@ -4254,6 +4254,8 @@ write_reflection (tree refl)\n       write_char ('_');\n       if (integer_nonzerop (TREE_VEC_ELT (arg, 4)))\n \twrite_char ('n');\n+      for (int i = 5; i < TREE_VEC_LENGTH (arg); ++i)\n+\twrite_template_arg (REFLECT_EXPR_HANDLE (TREE_VEC_ELT (arg, i)));\n     }\n }\n \n--- gcc/testsuite/g++.dg/reflect/data_member_spec5.C.jj\t2026-03-25 13:48:30.599086322 +0100\n+++ gcc/testsuite/g++.dg/reflect/data_member_spec5.C\t2026-03-25 15:07:54.567723729 +0100\n@@ -0,0 +1,107 @@\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+// Test std::meta::data_member_spec.\n+\n+#include <meta>\n+\n+using namespace std::meta;\n+\n+consteval bool\n+valid_data_member_spec (data_member_options opts)\n+{\n+  try { data_member_spec (opts); }\n+  catch (std::meta::exception &) { return false; }\n+  return true;\n+}\n+\n+struct S { int a, b; };\n+\n+consteval bool\n+foo ()\n+{\n+  constexpr int two = 2;\n+  [[=1]] int three = 3;\n+  constexpr int fourtytwo = 42;\n+  constexpr double fourtytwoandhalf = 42.5;\n+  data_member_options a = { .type = ^^int, .name = \"_\",\n+\t\t\t    .annotations = { ^^two, reflect_constant (42),\n+\t\t\t\t\t     annotations_of (^^three)[0],\n+\t\t\t\t\t     reflect_constant (42.5),\n+\t\t\t\t\t     reflect_constant (S { 1, 2 }) } };\n+  auto dmsa = data_member_spec (a);\n+  if (!is_data_member_spec (dmsa))\n+    throw 1;\n+  if (dmsa\n+      != data_member_spec ({ .type = ^^int, .name = \"_\",\n+\t\t\t     .annotations = { reflect_constant (2),\n+\t\t\t\t\t      ^^fourtytwo,\n+\t\t\t\t\t      reflect_constant (1),\n+\t\t\t\t\t      ^^fourtytwoandhalf,\n+\t\t\t\t\t      reflect_constant (S { 1, 2 }) } }))\n+    throw 2;\n+  if (dmsa == data_member_spec ({ .type = ^^int, .name = \"_\" }))\n+    throw 3;\n+  if (dmsa\n+      == data_member_spec ({ .type = ^^int, .name = \"_\",\n+\t\t\t     .annotations = { reflect_constant (2L),\n+\t\t\t\t\t      ^^fourtytwo,\n+\t\t\t\t\t      reflect_constant (1),\n+\t\t\t\t\t      ^^fourtytwoandhalf,\n+\t\t\t\t\t      reflect_constant (S { 1, 2 }) } }))\n+    throw 4;\n+  if (dmsa\n+      == data_member_spec ({ .type = ^^int, .name = \"_\",\n+\t\t\t     .annotations = { reflect_constant (2),\n+\t\t\t\t\t      ^^two,\n+\t\t\t\t\t      reflect_constant (1),\n+\t\t\t\t\t      ^^fourtytwoandhalf,\n+\t\t\t\t\t      reflect_constant (S { 1, 2 }) } }))\n+    throw 4;\n+  if (dmsa\n+      == data_member_spec ({ .type = ^^int, .name = \"_\",\n+\t\t\t     .annotations = { reflect_constant (2),\n+\t\t\t\t\t      ^^fourtytwo,\n+\t\t\t\t\t      reflect_constant (3),\n+\t\t\t\t\t      ^^fourtytwoandhalf,\n+\t\t\t\t\t      reflect_constant (S { 1, 2 }) } }))\n+    throw 5;\n+  if (dmsa\n+      == data_member_spec ({ .type = ^^int, .name = \"_\",\n+\t\t\t     .annotations = { reflect_constant (2),\n+\t\t\t\t\t      ^^fourtytwo,\n+\t\t\t\t\t      reflect_constant (1),\n+\t\t\t\t\t      reflect_constant (42.25),\n+\t\t\t\t\t      reflect_constant (S { 1, 2 }) } }))\n+    throw 6;\n+  if (dmsa\n+      == data_member_spec ({ .type = ^^int, .name = \"_\",\n+\t\t\t     .annotations = { reflect_constant (2),\n+\t\t\t\t\t      ^^fourtytwo,\n+\t\t\t\t\t      reflect_constant (1),\n+\t\t\t\t\t      reflect_constant (42.25),\n+\t\t\t\t\t      reflect_constant (S { 1, 2 }) } }))\n+    throw 7;\n+  if (dmsa\n+      == data_member_spec ({ .type = ^^int, .name = \"_\",\n+\t\t\t     .annotations = { reflect_constant (2),\n+\t\t\t\t\t      ^^fourtytwo,\n+\t\t\t\t\t      reflect_constant (1),\n+\t\t\t\t\t      reflect_constant (42.5),\n+\t\t\t\t\t      reflect_constant (S { 2, 2 }) } }))\n+    throw 8;\n+  return true;\n+}\n+\n+static_assert (foo ());\n+\n+constexpr int arr[1] = { 1 };\n+constexpr int i = 42;\n+constexpr S s = { 42, 43 };\n+\n+static_assert (!valid_data_member_spec ({ .type = ^^int, .name = \"a\", .annotations = { ^^:: } }));\n+static_assert (!valid_data_member_spec ({ .type = ^^int, .name = \"a\", .annotations = { ^^foo } }));\n+static_assert (!valid_data_member_spec ({ .type = ^^int, .name = \"a\", .annotations = { ^^arr } }));\n+static_assert (!valid_data_member_spec ({ .type = ^^int, .name = \"a\", .annotations = { ^^arr } }));\n+static_assert (valid_data_member_spec ({ .type = ^^int, .name = \"a\", .annotations = { ^^i } }));\n+static_assert (valid_data_member_spec ({ .type = ^^int, .name = \"a\", .annotations = { ^^s } }));\n+static_assert (!valid_data_member_spec ({ .type = ^^int, .bit_width = 0, .annotations = { ^^i } }));\n--- gcc/testsuite/g++.dg/reflect/data_member_spec6.C.jj\t2026-03-25 13:48:38.373955304 +0100\n+++ gcc/testsuite/g++.dg/reflect/data_member_spec6.C\t2026-03-25 13:58:47.664661356 +0100\n@@ -0,0 +1,12 @@\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+// Test std::meta::data_member_spec.\n+\n+#include <meta>\n+\n+using namespace std::meta;\n+\n+struct T { constexpr T () : t (42) {} constexpr int bar () const { return t; } protected: int t; };\n+constexpr T t;\n+\n+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\" }\n--- gcc/testsuite/g++.dg/reflect/display_string_of1.C.jj\t2026-03-24 23:13:58.419214921 +0100\n+++ gcc/testsuite/g++.dg/reflect/display_string_of1.C\t2026-03-25 17:12:51.955591801 +0100\n@@ -115,10 +115,12 @@ foo (int a, const long b, T c, int d[4],\n   static_assert (display_string_of (^^NSAlias) == \"NSAlias\");\n   static_assert (display_string_of (^^NS) == \"NS\");\n   static_assert (display_string_of (bases_of (^^S, ctx)[0]) == \"S: B\");\n-  static_assert (display_string_of (data_member_spec ({ .type = ^^int, .name = \"member\", .alignment = 128, .no_unique_address = true })) == \"(int, member, 128, , true)\");\n-  static_assert (display_string_of (data_member_spec ({ .type = ^^const int, .name = \"member\", .bit_width = 6 })) == \"(const int, member, , 6, false)\");\n-  static_assert (display_string_of (data_member_spec ({ .type = ^^int, .bit_width = 0 })) == \"(int, , , 0, false)\");\n-  static_assert (display_string_of (data_member_spec ({ .type = ^^long, .bit_width = 5 })) == \"(long int, , , 5, false)\");\n+  static_assert (display_string_of (data_member_spec ({ .type = ^^int, .name = \"member\", .alignment = 128, .no_unique_address = true })) == \"(int, member, 128, , true, {})\");\n+  static_assert (display_string_of (data_member_spec ({ .type = ^^const int, .name = \"member\", .bit_width = 6 })) == \"(const int, member, , 6, false, {})\");\n+  static_assert (display_string_of (data_member_spec ({ .type = ^^int, .bit_width = 0 })) == \"(int, , , 0, false, {})\");\n+  static_assert (display_string_of (data_member_spec ({ .type = ^^long, .bit_width = 5 })) == \"(long int, , , 5, false, {})\");\n+  static_assert (display_string_of (data_member_spec ({ .type = ^^long, .bit_width = 5 })) == \"(long int, , , 5, false, {})\");\n+  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})\");\n   static_assert (display_string_of (annotations_of (^^bar)[0]) == \"[[=1]]\");\n   static_assert (display_string_of (annotations_of (^^bar)[1]) == \"[[=AN{1, 42, ' '}]]\");\n   static_assert (display_string_of (^^int) == \"int\");\n--- gcc/testsuite/g++.dg/reflect/u8display_string_of1.C.jj\t2026-03-24 23:13:58.597110034 +0100\n+++ gcc/testsuite/g++.dg/reflect/u8display_string_of1.C\t2026-03-25 17:13:10.900273473 +0100\n@@ -115,10 +115,11 @@ foo (int a, const long b, T c, int d[4],\n   static_assert (u8display_string_of (^^NSAlias) == u8\"NSAlias\");\n   static_assert (u8display_string_of (^^NS) == u8\"NS\");\n   static_assert (u8display_string_of (bases_of (^^S, ctx)[0]) == u8\"S: B\");\n-  static_assert (u8display_string_of (data_member_spec ({ .type = ^^int, .name = \"member\", .alignment = 128, .no_unique_address = true })) == u8\"(int, member, 128, , true)\");\n-  static_assert (u8display_string_of (data_member_spec ({ .type = ^^const int, .name = \"member\", .bit_width = 6 })) == u8\"(const int, member, , 6, false)\");\n-  static_assert (u8display_string_of (data_member_spec ({ .type = ^^int, .bit_width = 0 })) == u8\"(int, , , 0, false)\");\n-  static_assert (u8display_string_of (data_member_spec ({ .type = ^^long, .bit_width = 5 })) == u8\"(long int, , , 5, false)\");\n+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^int, .name = \"member\", .alignment = 128, .no_unique_address = true })) == u8\"(int, member, 128, , true, {})\");\n+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^const int, .name = \"member\", .bit_width = 6 })) == u8\"(const int, member, , 6, false, {})\");\n+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^int, .bit_width = 0 })) == u8\"(int, , , 0, false, {})\");\n+  static_assert (u8display_string_of (data_member_spec ({ .type = ^^long, .bit_width = 5 })) == u8\"(long int, , , 5, false, {})\");\n+  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})\");\n   static_assert (u8display_string_of (annotations_of (^^bar)[0]) == u8\"[[=1]]\");\n   static_assert (u8display_string_of (annotations_of (^^bar)[1]) == u8\"[[=AN{1, 42, ' '}]]\");\n   static_assert (u8display_string_of (^^int) == u8\"int\");\n--- gcc/testsuite/g++.dg/reflect/define_aggregate9.C.jj\t2026-03-25 17:04:54.522614030 +0100\n+++ gcc/testsuite/g++.dg/reflect/define_aggregate9.C\t2026-03-25 17:17:38.458776225 +0100\n@@ -0,0 +1,35 @@\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+// Test std::meta::define_aggregate.\n+\n+#include <meta>\n+\n+using namespace std::meta;\n+\n+struct S { int a, b; };\n+struct T;\n+\n+consteval\n+{\n+  constexpr int two = 2;\n+  [[=1]] int three = 3;\n+  constexpr int fourtytwo = 42;\n+  constexpr double fourtytwoandhalf = 42.5;\n+  data_member_options a = { .type = ^^int, .name = \"_\",\n+\t\t\t    .annotations = { ^^two, reflect_constant (42),\n+\t\t\t\t\t     annotations_of (^^three)[0],\n+\t\t\t\t\t     reflect_constant (42.5),\n+\t\t\t\t\t     reflect_constant (S { 1, 2 }) } };\n+  auto dmsa = data_member_spec (a);\n+  define_aggregate (^^T, { dmsa });\n+}\n+consteval\n+{\n+  static_assert (annotations_of (^^T::_).size () == 5);\n+  static_assert ([: constant_of (annotations_of (^^T::_)[0]) :] == 2);\n+  static_assert ([: constant_of (annotations_of (^^T::_)[1]) :] == 42);\n+  static_assert ([: constant_of (annotations_of (^^T::_)[2]) :] == 1);\n+  static_assert ([: constant_of (annotations_of (^^T::_)[3]) :] == 42.5);\n+  static_assert ([: constant_of (annotations_of (^^T::_)[4]) :].a == 1);\n+  static_assert ([: constant_of (annotations_of (^^T::_)[4]) :].b == 2);\n+}\n--- gcc/testsuite/g++.dg/reflect/mangle1.C.jj\t2026-03-24 23:41:54.125019058 +0100\n+++ gcc/testsuite/g++.dg/reflect/mangle1.C\t2026-03-25 17:35:37.373600962 +0100\n@@ -63,6 +63,7 @@ namespace NS2 {\n   };\n   struct Z {\n   };\n+  struct AA { int a, b; };\n }\n \n constexpr auto ctx = std::meta::access_context::current ();\n@@ -165,6 +166,10 @@ baz (int x)\n   bar <332, std::meta::data_member_spec ({ .type = ^^unsigned short, .name = \"b\", .bit_width = 5 })> (); // data member description\n   bar <333, std::meta::data_member_spec ({ .type = ^^long, .bit_width = 3 })> (); // data member description\n   bar <334, std::meta::data_member_spec ({ .type = ^^int, .bit_width = 0 })> (); // data member description\n+  bar <335, std::meta::data_member_spec ({ .type = ^^int, .name = \"_\",\n+\t\t\t\t\t   .annotations = { std::meta::reflect_constant (42),\n+\t\t\t\t\t\t\t    std::meta::reflect_constant (43L),\n+\t\t\t\t\t\t\t    std::meta::reflect_constant (NS2::AA { 1, 2 }) } })> (); // data member description\n   bar <340, ^^NS2::X::~X> (); // function\n }\n \n@@ -250,4 +255,5 @@ baz (int x)\n // { dg-final { scan-assembler \"_Z3barILi332ELDmdst_1b__5_EEvv\" } }\n // { dg-final { scan-assembler \"_Z3barILi333ELDmdsl___3_EEvv\" } }\n // { dg-final { scan-assembler \"_Z3barILi334ELDmdsi___0_EEvv\" } }\n+// { dg-final { scan-assembler \"_Z3barILi335ELDmdsi_1____Li42ELl43EXtlN3NS22AAELi1ELi2EEEEEvv\" } }\n // { dg-final { scan-assembler \"_Z3barILi340ELDmfnN3NS21XD4EvEEvv\" } }\n","prefixes":["RFC"]}