https://gcc.gnu.org/g:ec5605dafee9275eb01b0cea594c6f401061ff82
commit r16-8372-gec5605dafee9275eb01b0cea594c6f401061ff82 Author: Jakub Jelinek <[email protected]> Date: Wed Apr 1 00:14:04 2026 +0200 c++: Handle annotations in data_member_spec/define_aggregate The following patch attempts to implement another part of P3795R2, in particular the addition of annotations to data_member_options and handling it in data_member_spec/define_aggregate etc. 2026-03-31 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 closing paren 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. Reviewed-by: Jason Merrill <[email protected]> Reviewed-by: Jonathan Wakely <[email protected]> Diff: --- gcc/cp/mangle.cc | 2 + gcc/cp/reflect.cc | 210 +++++++++++++++------ gcc/testsuite/g++.dg/reflect/data_member_spec5.C | 114 +++++++++++ gcc/testsuite/g++.dg/reflect/data_member_spec6.C | 12 ++ gcc/testsuite/g++.dg/reflect/define_aggregate9.C | 35 ++++ gcc/testsuite/g++.dg/reflect/display_string_of1.C | 9 +- gcc/testsuite/g++.dg/reflect/mangle1.C | 7 + .../g++.dg/reflect/u8display_string_of1.C | 9 +- libstdc++-v3/include/std/meta | 1 + 9 files changed, 335 insertions(+), 64 deletions(-) diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 3b8b9ed9d77b..24e1cefbd324 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -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))); } } diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index 8687e3f8fe3c..69b236659d89 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -389,18 +389,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, @@ -545,7 +552,8 @@ get_range_elts (location_t loc, const constexpr_ctx *ctx, tree call, int n, 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, @@ -1859,7 +1867,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) @@ -2524,8 +2532,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, @@ -3175,7 +3183,7 @@ eval_offset_of (location_t loc, const constexpr_ctx *ctx, tree r, /* Process std::meta::size_of. Returns: If -- r represents a non-static data member of type T or a data member - description (T,N,A,W,NUA) or + 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)). @@ -3184,7 +3192,7 @@ eval_offset_of (location_t loc, const constexpr_ctx *ctx, tree r, -- 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 @@ -3235,12 +3243,13 @@ eval_size_of (location_t loc, const constexpr_ctx *ctx, tree r, -- 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 @@ -3309,7 +3318,7 @@ eval_alignment_of (location_t loc, const constexpr_ctx *ctx, tree r, 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). @@ -3406,8 +3415,8 @@ eval_bit_size_of (location_t loc, const constexpr_ctx *ctx, tree r, 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) @@ -3522,7 +3531,7 @@ eval_has_identifier (tree r, reflect_kind kind) 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 @@ -3649,10 +3658,16 @@ eval_display_string_of (location_t loc, const constexpr_ctx *ctx, tree r, 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)))); @@ -3768,15 +3783,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. @@ -3785,8 +3806,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, @@ -5519,15 +5540,17 @@ eval_variant_alternative (location_t loc, const constexpr_ctx *ctx, tree i, } /* 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: @@ -5539,15 +5562,18 @@ eval_variant_alternative (location_t loc, const constexpr_ctx *ctx, tree i, 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, @@ -5566,8 +5592,10 @@ eval_data_member_spec (location_t loc, const constexpr_ctx *ctx, *non_constant_p = true; return NULL_TREE; } - enum { m_name = 1, m_alignment, m_bit_width, m_no_unique_address, n_args }; - tree args[n_args] = { type, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }; + enum { m_name = 1, m_alignment, m_bit_width, m_no_unique_address, + m_annotations, n_args }; + tree args[n_args] = { 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)) @@ -5580,6 +5608,8 @@ eval_data_member_spec (location_t loc, const constexpr_ctx *ctx, args[m_bit_width] = field; else if (id_equal (name, "no_unique_address")) args[m_no_unique_address] = field; + else if (id_equal (name, "annotations")) + args[m_annotations] = field; } for (int i = m_name; i < n_args; ++i) { @@ -5605,6 +5635,21 @@ eval_data_member_spec (location_t loc, const constexpr_ctx *ctx, args[i] = boolean_true_node; continue; } + if (i == m_annotations) + { + /* 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; @@ -5838,6 +5883,10 @@ eval_data_member_spec (location_t loc, const constexpr_ctx *ctx, return throw_exception (loc, ctx, "neither name nor bit_width specified", fun, non_constant_p, jump_target); + if (args[m_name] == NULL_TREE && TREE_VEC_LENGTH (args[m_annotations])) + return throw_exception (loc, ctx, + "no name and non-empty annotations specified", + fun, non_constant_p, jump_target); if (args[m_bit_width]) { if (!CP_INTEGRAL_TYPE_P (type) && TREE_CODE (type) != ENUMERAL_TYPE) @@ -5879,17 +5928,41 @@ eval_data_member_spec (location_t loc, const constexpr_ctx *ctx, "alignment is smaller than alignment_of", fun, non_constant_p, jump_target); } - tree ret = make_tree_vec (n_args); - for (int i = 0; i < n_args; ++i) + for (int i = 0; i < TREE_VEC_LENGTH (args[m_annotations]); ++i) + { + tree r = REFLECT_EXPR_HANDLE (TREE_VEC_ELT (args[m_annotations], i)); + reflect_kind kind + = REFLECT_EXPR_KIND (TREE_VEC_ELT (args[m_annotations], 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[m_annotations], i) = cst; + } + tree ret = make_tree_vec (m_annotations + + TREE_VEC_LENGTH (args[m_annotations])); + for (int i = 0; i < m_annotations; ++i) TREE_VEC_ELT (ret, i) = args[i]; + for (int i = 0; i < TREE_VEC_LENGTH (args[m_annotations]); ++i) + TREE_VEC_ELT (ret, i + m_annotations) + = TREE_VEC_ELT (args[m_annotations], 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; @@ -5920,6 +5993,8 @@ eval_data_member_spec (location_t loc, const constexpr_ctx *ctx, 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. @@ -6171,12 +6246,24 @@ eval_define_aggregate (location_t loc, const constexpr_ctx *ctx, * 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; } @@ -8443,13 +8530,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)) diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec5.C b/gcc/testsuite/g++.dg/reflect/data_member_spec5.C new file mode 100644 index 000000000000..3430cc0da1d2 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/data_member_spec5.C @@ -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 } })); diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec6.C b/gcc/testsuite/g++.dg/reflect/data_member_spec6.C new file mode 100644 index 000000000000..5b53fb4b5337 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/data_member_spec6.C @@ -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" } diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate9.C b/gcc/testsuite/g++.dg/reflect/define_aggregate9.C new file mode 100644 index 000000000000..143ce68f4f3c --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/define_aggregate9.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/reflect/display_string_of1.C b/gcc/testsuite/g++.dg/reflect/display_string_of1.C index b2f2950a5397..ae24aff1e9d2 100644 --- a/gcc/testsuite/g++.dg/reflect/display_string_of1.C +++ b/gcc/testsuite/g++.dg/reflect/display_string_of1.C @@ -115,10 +115,11 @@ foo (int a, const long b, T c, int d[4], T &e) 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"); diff --git a/gcc/testsuite/g++.dg/reflect/mangle1.C b/gcc/testsuite/g++.dg/reflect/mangle1.C index 92b4ec31c735..16e027d4b3dd 100644 --- a/gcc/testsuite/g++.dg/reflect/mangle1.C +++ b/gcc/testsuite/g++.dg/reflect/mangle1.C @@ -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" } } diff --git a/gcc/testsuite/g++.dg/reflect/u8display_string_of1.C b/gcc/testsuite/g++.dg/reflect/u8display_string_of1.C index bce7db52a176..0ff9cc7c992d 100644 --- a/gcc/testsuite/g++.dg/reflect/u8display_string_of1.C +++ b/gcc/testsuite/g++.dg/reflect/u8display_string_of1.C @@ -115,10 +115,11 @@ foo (int a, const long b, T c, int d[4], T &e) 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"); diff --git a/libstdc++-v3/include/std/meta b/libstdc++-v3/include/std/meta index 4e438e8b6536..20cfba10b9f9 100644 --- a/libstdc++-v3/include/std/meta +++ b/libstdc++-v3/include/std/meta @@ -427,6 +427,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);
