https://gcc.gnu.org/g:1655a3fc1a80021f6bf39f0ae72c4d7d1f99b37f
commit r16-8482-g1655a3fc1a80021f6bf39f0ae72c4d7d1f99b37f Author: Jakub Jelinek <[email protected]> Date: Mon Apr 6 23:08:48 2026 +0200 c++: Implement the annotations_of on parms part of P3795R2 The current behavior of GCC is that we list all annotations gathered from all the PARM_DECLs merged together on ^^fnparm or variable_of (parameters_of (^^fn)[0]) and throw on annotations_of on parameters_of (^^fn)[0]. The paper requires that the last one works like we currently handle the former two, and for the former two we filter out annotations that have not appeared on the function definition. The following patch marks the annotations in grokfndecl before pushdecl etc. merges it with other decls. 2026-04-06 Jakub Jelinek <[email protected]> * decl.cc (grokfndecl): For -freflection mark annotations of PARM_DECLs in a function definition. * reflect.cc (eval_annotations_of): Allow annotations_of on function parameters. For r which is a PARM_DECL without REFLECT_PARM, filter out annotations not marked by grokfndecl. (reflection_mangle_prefix): Preserve the grokfndecl marking of annotations during mangling. * g++.dg/reflect/annotations15.C: New test. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/decl.cc | 23 ++++++++++++++- gcc/cp/reflect.cc | 31 +++++++++++++++++--- gcc/testsuite/g++.dg/reflect/annotations15.C | 44 ++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 5 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index eb9699529126..930253d96460 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -12218,7 +12218,28 @@ grokfndecl (tree ctype, DECL_ARGUMENTS (decl) = parms; for (t = parms; t; t = DECL_CHAIN (t)) - DECL_CONTEXT (t) = decl; + { + DECL_CONTEXT (t) = decl; + if (flag_reflection + && initialized == SD_INITIALIZED + && DECL_ATTRIBUTES (t)) + for (tree a = DECL_ATTRIBUTES (t); + (a = lookup_attribute ("internal ", "annotation ", a)); + a = TREE_CHAIN (a)) + { + gcc_checking_assert (TREE_CODE (TREE_VALUE (a)) == TREE_LIST); + /* Mark TREE_PURPOSE of the value that it is an annotation + on an argument of a function definition (rather than + annotation from function declaration). For function parameter + reflection all annotations are listed, while for variable_of + only those marked here. Annotation is marked as coming from + function definition's argument if it has TREE_PURPOSE + void_node or INTEGER_CST with signed type. */ + tree val = TREE_VALUE (a); + gcc_assert (TREE_PURPOSE (val) == NULL_TREE); + TREE_PURPOSE (val) = void_node; + } + } /* Propagate volatile out from type to decl. */ if (TYPE_VOLATILE (type)) diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index d2bcf26ca814..6e3b8d2e9be0 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -3840,14 +3840,16 @@ eval_annotations_of (location_t loc, const constexpr_ctx *ctx, tree r, || eval_is_type_alias (r) == boolean_true_node || eval_is_variable (r, kind) == boolean_true_node || eval_is_function (r) == boolean_true_node + || eval_is_function_parameter (r, kind) == boolean_true_node || eval_is_namespace (r) == boolean_true_node || eval_is_enumerator (r) == boolean_true_node || eval_is_base (r, kind) == boolean_true_node || eval_is_nonstatic_data_member (r) == boolean_true_node)) return throw_exception (loc, ctx, "reflection does not represent a type," - " type alias, variable, function, namespace," - " enumerator, direct base class relationship," + " type alias, variable, function, function" + " parameter, namespace, enumerator," + " direct base class relationship," " or non-static data member", fun, non_constant_p, jump_target); @@ -3864,6 +3866,7 @@ eval_annotations_of (location_t loc, const constexpr_ctx *ctx, tree r, } r = maybe_get_first_fn (r); + bool var_of = false; if (kind == REFLECT_BASE) { gcc_assert (TREE_CODE (r) == TREE_BINFO); @@ -3888,7 +3891,11 @@ eval_annotations_of (location_t loc, const constexpr_ctx *ctx, tree r, r = TYPE_ATTRIBUTES (r); } else if (DECL_P (r)) - r = DECL_ATTRIBUTES (r); + { + if (TREE_CODE (r) == PARM_DECL && kind != REFLECT_PARM) + var_of = true; + r = DECL_ATTRIBUTES (r); + } else gcc_unreachable (); vec<constructor_elt, va_gc> *elts = nullptr; @@ -3897,6 +3904,16 @@ eval_annotations_of (location_t loc, const constexpr_ctx *ctx, tree r, { gcc_checking_assert (TREE_CODE (TREE_VALUE (a)) == TREE_LIST); tree val = TREE_VALUE (TREE_VALUE (a)); + tree purpose = TREE_PURPOSE (TREE_VALUE (a)); + if (var_of + && (purpose == NULL_TREE + || (TREE_CODE (purpose) == INTEGER_CST + && !TYPE_UNSIGNED (TREE_TYPE (purpose))))) + /* For ^^fnparm or variable_of (parameters_of (^^fn)[N]) + filter out annotations not specified on the function + definition. TREE_PURPOSE is set in grokfndecl and/or in + reflection_mangle_prefix. */ + continue; if (type) { tree at = TREE_TYPE (val); @@ -9023,7 +9040,13 @@ reflection_mangle_prefix (tree refl, char prefix[3]) strcpy (prefix, "an"); if (TREE_PURPOSE (TREE_VALUE (h)) == NULL_TREE) TREE_PURPOSE (TREE_VALUE (h)) - = build_int_cst (integer_type_node, annotation_idx++); + = bitsize_int (annotation_idx++); + /* TREE_PURPOSE void_node or INTEGER_CST with signed type + means it is annotation which should appear in + variable_of list. */ + else if (TREE_PURPOSE (TREE_VALUE (h)) == void_node) + TREE_PURPOSE (TREE_VALUE (h)) + = sbitsize_int (annotation_idx++); return TREE_PURPOSE (TREE_VALUE (h)); } if (eval_is_type_alias (h) == boolean_true_node) diff --git a/gcc/testsuite/g++.dg/reflect/annotations15.C b/gcc/testsuite/g++.dg/reflect/annotations15.C new file mode 100644 index 000000000000..0682cd4283d4 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/annotations15.C @@ -0,0 +1,44 @@ +// P3795R2 - Miscellaneous Reflection Cleanup +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include <meta> + +void foo ([[=1]] int x); +constexpr auto rf = parameters_of (^^foo)[0]; +void foo ([[=2, =3]] int x); + +void +foo ([[=4, =5]] int x) +{ + static_assert (annotations_of (^^x).size () == 2); + static_assert ([: constant_of (annotations_of (^^x)[0]) :] == 4); + static_assert ([: constant_of (annotations_of (^^x)[1]) :] == 5); + static_assert (annotations_of (rf).size () == 5); + static_assert ([: constant_of (annotations_of (rf)[0]) :] == 1); + static_assert ([: constant_of (annotations_of (rf)[1]) :] == 2); + static_assert ([: constant_of (annotations_of (rf)[2]) :] == 3); + static_assert ([: constant_of (annotations_of (rf)[3]) :] == 4); + static_assert ([: constant_of (annotations_of (rf)[4]) :] == 5); + static_assert (annotations_of (variable_of (rf)).size () == 2); + static_assert ([: constant_of (annotations_of (variable_of (rf))[0]) :] == 4); + static_assert ([: constant_of (annotations_of (variable_of (rf))[1]) :] == 5); + static_assert (annotations_of (parameters_of (^^foo)[0]).size () == 5); + static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[0]) :] == 1); + static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[1]) :] == 2); + static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[2]) :] == 3); + static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[3]) :] == 4); + static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[4]) :] == 5); + static_assert (annotations_of (^^x)[0] == annotations_of (rf)[3]); + static_assert (annotations_of (^^x)[0] == annotations_of (variable_of (rf))[0]); + static_assert (annotations_of (^^x)[0] == annotations_of (parameters_of (^^foo)[0])[3]); +} + +void foo ([[=6]] int x); +static_assert (annotations_of (parameters_of (^^foo)[0]).size () == 6); +static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[0]) :] == 1); +static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[1]) :] == 2); +static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[2]) :] == 3); +static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[3]) :] == 4); +static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[4]) :] == 5); +static_assert ([: constant_of (annotations_of (parameters_of (^^foo)[0])[5]) :] == 6);
