On Fri, Apr 03, 2026 at 04:37:20PM -0400, Jason Merrill wrote:
> "void_node"

Changed.

> > +       tree val = TREE_VALUE (a);
> > +       if (TREE_PURPOSE (val) == NULL_TREE)
> > +         TREE_PURPOSE (val) = void_node;
> > +       else if (TREE_CODE (TREE_PURPOSE (val)) == INTEGER_CST)
> 
> It seems impossible to have INTEGER_CST this early, we can't have tried to
> mangle a function we haven't even built yet.  And indeed the testcase
> doesn't exercise this case.  Maybe assert NULL_TREE instead?

Assert added instead.

> > +   /* For ^^fnparm or variable_of (parameters_of (^^fn)[N])
> > +      filter out annotations not specified on the function
> > +      definition.  */
> 
> Let's also mention that purpose is set in grokfndecl or
> reflection_mangle_prefix.

Done.

> Also "void_node".

Changed.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

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.

--- gcc/cp/decl.cc.jj   2026-03-26 07:59:59.527656320 +0100
+++ gcc/cp/decl.cc      2026-03-26 12:31:36.887319793 +0100
@@ -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))
--- gcc/cp/reflect.cc.jj        2026-03-25 20:32:38.262640083 +0100
+++ gcc/cp/reflect.cc   2026-03-26 12:30:48.440143055 +0100
@@ -3812,14 +3812,16 @@ eval_annotations_of (location_t loc, con
        || 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);
 
@@ -3836,6 +3838,7 @@ eval_annotations_of (location_t loc, con
     }
 
   r = maybe_get_first_fn (r);
+  bool var_of = false;
   if (kind == REFLECT_BASE)
     {
       gcc_assert (TREE_CODE (r) == TREE_BINFO);
@@ -3860,7 +3863,11 @@ eval_annotations_of (location_t loc, con
        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;
@@ -3869,6 +3876,16 @@ eval_annotations_of (location_t loc, con
     {
       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);
@@ -8749,7 +8765,13 @@ reflection_mangle_prefix (tree refl, cha
       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)
--- gcc/testsuite/g++.dg/reflect/annotations15.C.jj     2026-03-26 
12:40:48.910963751 +0100
+++ gcc/testsuite/g++.dg/reflect/annotations15.C        2026-03-26 
12:40:37.661154305 +0100
@@ -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);


        Jakub

Reply via email to