Hi!

For the cases in the new test like
[[=1]] int a [[=2]], b [[=3]];
we want to order the =1 annotation before =2 or =3 because
https://eel.is/c++draft/meta.reflection#annotation-2.sentence-2
and =1 precedes =2 and =3.
The way we merge the attribute lists in grokdeclarator is done
for speed and memory efficiency though, so we attr_chainon
*attrlist (i.e. =1 above) after declarator->std_attributes
(i.e. =2 or =3 above).  That has the advantage that we can keep
sharing the earlier *attrlist between multiple declarations, each one
will have its custom attributes at the start (if any) and then
a shared tail with the shared ones.

The following patch fixes it by checking if annotations are in
both lists (otherwise we keep doing what we've been doing before).
If they are in both, we chainon them the other way but of course
need to copy_list to unshare the shared one for that.

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

2026-03-14  Jakub Jelinek  <[email protected]>

        PR c++/124399
        * decl.cc (grokdeclarator): If both *attrlist and
        declarator->std_attributes list contain annotations, chainon
        declarator->std_attributes to tail of copy_list (*attrlist)
        rather than *attrlist to tail of declarator->std_attributes.

        * g++.dg/reflect/annotations12.C: Uncomment two tests, remove
        temporary test added until that is fixed.
        * g++.dg/reflect/annotations13.C: New test.

--- gcc/cp/decl.cc.jj   2026-03-13 09:07:06.000000000 +0100
+++ gcc/cp/decl.cc      2026-03-13 17:59:45.241445787 +0100
@@ -15892,7 +15892,21 @@ grokdeclarator (const cp_declarator *dec
       /* [dcl.meaning]/1: The optional attribute-specifier-seq following
         a declarator-id appertains to the entity that is declared.  */
       if (declarator->std_attributes != error_mark_node)
-       *attrlist = attr_chainon (declarator->std_attributes, *attrlist);
+       {
+         if (flag_reflection
+             && declarator->std_attributes != error_mark_node
+             && lookup_attribute ("internal ", "annotation ",
+                                  declarator->std_attributes)
+             && *attrlist != error_mark_node
+             && lookup_attribute ("internal ", "annotation ", *attrlist))
+           /* If there are annotations in both lists, ensure
+              declarator->std_attributes go after *attrlist.  See
+              PR124399.  */
+           *attrlist = chainon (copy_list (*attrlist),
+                                declarator->std_attributes);
+         else
+           *attrlist = attr_chainon (declarator->std_attributes, *attrlist);
+       }
       else
        /* We should have already diagnosed the issue (c++/78344).  */
        gcc_assert (seen_error ());
--- gcc/testsuite/g++.dg/reflect/annotations12.C.jj     2026-03-13 
17:21:57.594494388 +0100
+++ gcc/testsuite/g++.dg/reflect/annotations12.C        2026-03-13 
17:32:54.285023507 +0100
@@ -1,6 +1,6 @@
 // PR c++/124399
 // { dg-do compile { target c++26 } }
-// { dg-options "-freflection" }
+// { dg-additional-options "-freflection" }
 
 #include <meta>
 
@@ -17,9 +17,7 @@ static_assert (annotations_of (^^x)[0] =
 int z [[=2]], w [[=2]];
 static_assert (annotations_of (^^z)[0] != annotations_of (^^w)[0]);
 [[=3]] int u [[=3]], v [[=3]];
-static_assert ((annotations_of (^^u)[0] == annotations_of (^^v)[0])
-              != (annotations_of (^^u)[1] == annotations_of (^^v)[1]));
-//static_assert (annotations_of (^^u)[0] == annotations_of (^^v)[0]);
-//static_assert (annotations_of (^^u)[1] != annotations_of (^^v)[1]);
+static_assert (annotations_of (^^u)[0] == annotations_of (^^v)[0]);
+static_assert (annotations_of (^^u)[1] != annotations_of (^^v)[1]);
 static_assert (annotations_of (^^u)[0] != annotations_of (^^u)[1]);
 static_assert (annotations_of (^^v)[0] != annotations_of (^^v)[1]);
--- gcc/testsuite/g++.dg/reflect/annotations13.C.jj     2026-03-13 
17:32:54.285191464 +0100
+++ gcc/testsuite/g++.dg/reflect/annotations13.C        2026-03-13 
19:08:34.324214545 +0100
@@ -0,0 +1,33 @@
+// PR c++/124399
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+[[=1]] int a [[=2]], b [[=3]];
+static_assert ([: constant_of (annotations_of (^^a)[0]) :] == 1);
+static_assert ([: constant_of (annotations_of (^^a)[1]) :] == 2);
+static_assert ([: constant_of (annotations_of (^^b)[0]) :] == 1);
+static_assert ([: constant_of (annotations_of (^^b)[1]) :] == 3);
+
+[[=10, =11]] extern int e;
+[[=1]] [[=2, =3]] int c [[=4, =5]] [[=6]], d [[=7, =8]] (), e [[=9]];
+[[=12]] extern int c;
+static_assert ([: constant_of (annotations_of (^^c)[0]) :] == 1);
+static_assert ([: constant_of (annotations_of (^^c)[1]) :] == 2);
+static_assert ([: constant_of (annotations_of (^^c)[2]) :] == 3);
+static_assert ([: constant_of (annotations_of (^^c)[3]) :] == 4);
+static_assert ([: constant_of (annotations_of (^^c)[4]) :] == 5);
+static_assert ([: constant_of (annotations_of (^^c)[5]) :] == 6);
+static_assert ([: constant_of (annotations_of (^^c)[6]) :] == 12);
+static_assert ([: constant_of (annotations_of (^^d)[0]) :] == 1);
+static_assert ([: constant_of (annotations_of (^^d)[1]) :] == 2);
+static_assert ([: constant_of (annotations_of (^^d)[2]) :] == 3);
+static_assert ([: constant_of (annotations_of (^^d)[3]) :] == 7);
+static_assert ([: constant_of (annotations_of (^^d)[4]) :] == 8);
+static_assert ([: constant_of (annotations_of (^^e)[0]) :] == 10);
+static_assert ([: constant_of (annotations_of (^^e)[1]) :] == 11);
+static_assert ([: constant_of (annotations_of (^^e)[2]) :] == 1);
+static_assert ([: constant_of (annotations_of (^^e)[3]) :] == 2);
+static_assert ([: constant_of (annotations_of (^^e)[4]) :] == 3);
+static_assert ([: constant_of (annotations_of (^^e)[5]) :] == 9);

        Jakub

Reply via email to