[gcc r16-8372] c++: Handle annotations in data_member_spec/define_aggregate
Jakub Jelinek
jakub@gcc.gnu.org
Tue Mar 31 22:17:04 GMT 2026
https://gcc.gnu.org/g:ec5605dafee9275eb01b0cea594c6f401061ff82
commit r16-8372-gec5605dafee9275eb01b0cea594c6f401061ff82
Author: Jakub Jelinek <jakub@redhat.com>
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 <jakub@redhat.com>
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 <jason@redhat.com>
Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
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);
More information about the Libstdc++-cvs
mailing list