On Mon, Jul 20, 2026 at 05:25:19PM -0400, Jason Merrill wrote:
> > + if (ANON_AGGR_TYPE_P (type))
> > + {
> > + /* [class.union.anon]/1: Each object of such an unnamed type shall be
> > + such an unnamed object. */
> > + auto_diagnostic_group d;
> > + location_t aloc
> > + = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (TYPE_MAIN_VARIANT (type)));
> > + if (decl && VAR_P (decl) && DECL_NAME (decl) == NULL_TREE)
> > + ;
>
> This could use a comment about why this doesn't allow temporaries.
Well, there is a comment a few lines above which includes the (admittedly
bad) CWG3130 wording, so anything that can construct an object is considered
bad except for the namespace scope anonymous union declaring an unnamed
variable. Added ANON_UNION_TYPE_P test to the condition and added a comment
why is that case allowed.
> > + case ACU_CATCH:
> > + error ("%<catch%> parameter with anonymous union type %qT",
> > + type);
> > + break;
> > + case ACU_THROW:
> > + error ("trying to throw anonymous union type %qT object",
>
> Let's avoid "trying". Perhaps "%<throw%> operand has anonymous union type"?
Ok.
> Also, this doesn't seem to appear in the testcase?
Added, in anon6.C (foo (U &), foo (V &)) and anon7.C (foo (U &)).
> Incidentally, I also don't see a functional cast like U() in the testcase.
Added in anon6.C (foo (U), foo (V &)) and anon7.C (foo (U)).
>
> > + type);
> > + break;
> > + case ACU_ARRAY:
> > + error ("trying to create array of anonymous union type %qT",
>
> Similarly, just "array of anonymous union type".
Array of anonymous union/struct type itself is not diagnosed (like gcc
doesn't diagnose
struct S { virtual void foo () = 0; };
using T = S[2][2];
(though clang++ apparently does, dunno what is right)), only trying to
create objects of that type (variables, temporaries, ...).
I've added "object with " in front of your proposed wording.
> > @@ -4279,12 +4281,69 @@ finish_member_declaration (tree decl)
> > if (TREE_CODE (decl) != CONST_DECL)
> > DECL_CONTEXT (decl) = current_class_type;
> > - /* Remember the single FIELD_DECL an anonymous aggregate type is used
> > for. */
> > - if (TREE_CODE (decl) == FIELD_DECL
> > - && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
> > + if (TREE_TYPE (decl)
> > + && ANON_AGGR_TYPE_P (TREE_TYPE (decl))
> > + && TREE_CODE (decl) != TYPE_DECL)
>
> The change from == FIELD_DECL to != TYPE_DECL looks to be for diagnosing
> static data members of anon aggr type, but I don't see any such in the
> testcase.
Added now, anon6.C (G::g, H::h, I::i, J::j) and anon7.C (F::f, G::g).
> > + {
> > + /* [class.union.anon]/1: Each object of such an unnamed type shall
> > + be such an unnamed object. */
> > + tree adecl = TYPE_MAIN_DECL (TYPE_MAIN_VARIANT (type));
> > + auto_diagnostic_group d;
> > + if (ANON_UNION_TYPE_P (TREE_TYPE (decl)))
During retesting I found that this should have been ANON_UNION_TYPE_P (type)
instead.
> > + {
> > + error_at (location_of (decl),
> > + "declaration of member %qD with array of anonymous "
> > + "unions type %qT", decl, TREE_TYPE (decl));
>
> Singular "union"
Fixed.
> > + inform (DECL_SOURCE_LOCATION (adecl),
> > + "anonymous union declared here");
> > + }
> > + else
> > + {
> > + error_at (location_of (decl),
> > + "declaration of member %qD with array of anonymous "
> > + "structs type %qT", decl, TREE_TYPE (decl));
>
> and "struct"
Fixed.
Here is the updated patch, lightly tested so far -
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26,29 make check-g++ -j32 -k
RUNTESTFLAGS="dg.exp='reflect/* anon*union* anon*struct*'"
-, ok for trunk if it passes full bootstrap/regtest?
2026-07-22 Jakub Jelinek <[email protected]>
gcc/cp/
* typeck2.cc: Implement part of CWG3130 - Naming function members of
anonymous unions.
(abstract_virtuals_error): Diagnose trying to create
an object with anonymous union or struct type.
* semantics.cc (finish_compound_literal): Call abstract_virtuals_error.
(finish_member_declaration): Diagnose named members with anonymous
union or struct type.
* decl.cc (xref_basetypes): Diagnose anonymous structs as bases.
gcc/testsuite/
* g++.dg/cpp0x/anon-union4.C: New test.
* g++.dg/reflect/anon6.C: New test.
* g++.dg/reflect/anon7.C: New test.
* g++.dg/reflect/anon8.C: New test.
* g++.dg/reflect/anon9.C: New test.
* g++.dg/template/anonunion3.C: Expect an error.
--- gcc/cp/typeck2.cc.jj 2026-07-20 16:54:59.939704369 +0200
+++ gcc/cp/typeck2.cc 2026-07-22 14:37:55.156490163 +0200
@@ -151,6 +151,98 @@ abstract_virtuals_error (tree decl, tree
be abstract. */
if (!CLASS_TYPE_P (type))
return 0;
+
+ if (ANON_AGGR_TYPE_P (type))
+ {
+ /* [class.union.anon]/1: Each object of such an unnamed type shall be
+ such an unnamed object. */
+ auto_diagnostic_group d;
+ location_t aloc
+ = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (TYPE_MAIN_VARIANT (type)));
+ if (decl
+ && VAR_P (decl)
+ && DECL_NAME (decl) == NULL_TREE
+ && ANON_UNION_TYPE_P (type))
+ /* Unnamed variables are ok, those are assumed to be the variable
+ created for namespace scope anonymous union. */;
+ else if (!(complain & tf_error))
+ return 1;
+ else if (ANON_UNION_TYPE_P (type))
+ {
+ if (!decl)
+ switch (use)
+ {
+ default:
+ error ("temporary object with anonymous union type %qT", type);
+ break;
+ case ACU_CATCH:
+ error ("%<catch%> parameter with anonymous union type %qT",
+ type);
+ break;
+ case ACU_THROW:
+ error ("%<throw%> operand has anonymous union type %qT", type);
+ break;
+ case ACU_ARRAY:
+ error ("object with array of anonymous union type %qT", type);
+ break;
+ }
+ else if (VAR_P (decl))
+ error_at (location_of (decl),
+ "declaration of variable %qD with anonymous union type "
+ "%qT", decl, type);
+ else if (TREE_CODE (decl) == PARM_DECL && DECL_NAME (decl))
+ error_at (location_of (decl),
+ "declaration of parameter %qD with anonymous union type "
+ "%qT", decl, type);
+ else if (TREE_CODE (decl) == PARM_DECL)
+ error_at (location_of (decl),
+ "declaration of a parameter with anonymous union type "
+ "%qT", type);
+ inform (aloc, "anonymous union declared here");
+ if (decl)
+ TREE_TYPE (decl) = error_mark_node;
+ return 1;
+ }
+ else
+ {
+ if (!decl)
+ switch (use)
+ {
+ default:
+ error ("temporary object with anonymous struct type %qT",
+ type);
+ break;
+ case ACU_CATCH:
+ error ("%<catch%> parameter with anonymous struct type %qT",
+ type);
+ break;
+ case ACU_THROW:
+ error ("%<throw%> operand has anonymous struct type %qT",
+ type);
+ break;
+ case ACU_ARRAY:
+ error ("object with array of anonymous struct type %qT", type);
+ break;
+ }
+ else if (VAR_P (decl))
+ error_at (location_of (decl),
+ "declaration of variable %qD with anonymous struct type "
+ "%qT", decl, type);
+ else if (TREE_CODE (decl) == PARM_DECL && DECL_NAME (decl))
+ error_at (location_of (decl),
+ "declaration of parameter %qD with anonymous struct type "
+ "%qT", decl, type);
+ else if (TREE_CODE (decl) == PARM_DECL)
+ error_at (location_of (decl),
+ "declaration of a parameter with anonymous struct type "
+ "%qT", type);
+ inform (aloc, "anonymous struct declared here");
+ if (decl)
+ TREE_TYPE (decl) = error_mark_node;
+ return 1;
+ }
+ }
+
type = TYPE_MAIN_VARIANT (type);
#if 0
--- gcc/cp/semantics.cc.jj 2026-07-20 19:25:59.075610995 +0200
+++ gcc/cp/semantics.cc 2026-07-22 13:54:45.106856849 +0200
@@ -3946,6 +3946,8 @@ finish_compound_literal (tree type, tree
if (type == error_mark_node)
return error_mark_node;
}
+ if (abstract_virtuals_error (ACU_UNKNOWN, type, complain))
+ return error_mark_node;
compound_literal = digest_init_flags (type, compound_literal,
LOOKUP_NORMAL | LOOKUP_NO_NARROWING,
complain);
@@ -4279,12 +4281,69 @@ finish_member_declaration (tree decl)
if (TREE_CODE (decl) != CONST_DECL)
DECL_CONTEXT (decl) = current_class_type;
- /* Remember the single FIELD_DECL an anonymous aggregate type is used for.
*/
- if (TREE_CODE (decl) == FIELD_DECL
- && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
+ if (TREE_TYPE (decl)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (decl))
+ && TREE_CODE (decl) != TYPE_DECL)
+ {
+ /* Remember the single FIELD_DECL an anonymous aggregate type is used
+ for. */
+ if (TREE_CODE (decl) == FIELD_DECL && DECL_NAME (decl) == NULL_TREE)
+ {
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
+ gcc_assert (!ANON_AGGR_TYPE_FIELD (type));
+ SET_ANON_AGGR_TYPE_FIELD (type, decl);
+ }
+ /* [class.union.anon]/1: Each object of such an unnamed type shall
+ be such an unnamed object. */
+ else if (ANON_UNION_TYPE_P (TREE_TYPE (decl)))
+ {
+ tree adecl = TYPE_MAIN_DECL (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+ auto_diagnostic_group d;
+ error_at (location_of (decl),
+ "declaration of member %qD with anonymous union type %qT",
+ decl, TREE_TYPE (decl));
+ inform (DECL_SOURCE_LOCATION (adecl),
+ "anonymous union declared here");
+ }
+ else
+ {
+ tree adecl = TYPE_MAIN_DECL (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+ auto_diagnostic_group d;
+ error_at (location_of (decl),
+ "declaration of member %qD with anonymous struct type %qT",
+ decl, TREE_TYPE (decl));
+ inform (DECL_SOURCE_LOCATION (adecl),
+ "anonymous struct declared here");
+ }
+ }
+ else if (TREE_TYPE (decl)
+ && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+ && TREE_CODE (decl) != TYPE_DECL)
{
- gcc_assert (!ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE
(decl))));
- SET_ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl)), decl);
+ tree type = strip_array_types (TREE_TYPE (decl));
+ if (ANON_AGGR_TYPE_P (type))
+ {
+ /* [class.union.anon]/1: Each object of such an unnamed type shall
+ be such an unnamed object. */
+ tree adecl = TYPE_MAIN_DECL (TYPE_MAIN_VARIANT (type));
+ auto_diagnostic_group d;
+ if (ANON_UNION_TYPE_P (type))
+ {
+ error_at (location_of (decl),
+ "declaration of member %qD with array of anonymous "
+ "union type %qT", decl, TREE_TYPE (decl));
+ inform (DECL_SOURCE_LOCATION (adecl),
+ "anonymous union declared here");
+ }
+ else
+ {
+ error_at (location_of (decl),
+ "declaration of member %qD with array of anonymous "
+ "struct type %qT", decl, TREE_TYPE (decl));
+ inform (DECL_SOURCE_LOCATION (adecl),
+ "anonymous struct declared here");
+ }
+ }
}
if (TREE_CODE (decl) == USING_DECL)
--- gcc/cp/decl.cc.jj 2026-07-20 19:25:59.073611021 +0200
+++ gcc/cp/decl.cc 2026-07-22 13:44:01.205748961 +0200
@@ -18758,6 +18758,11 @@ xref_basetypes (tree ref, tree base_list
basetype);
goto dropped_base;
}
+ else if (ANON_AGGR_TYPE_P (basetype))
+ {
+ error ("base type %qT is anonymous struct type", basetype);
+ goto dropped_base;
+ }
base_binfo = NULL_TREE;
if (CLASS_TYPE_P (basetype) && !dependent_scope_p (basetype))
--- gcc/testsuite/g++.dg/cpp0x/anon-union4.C.jj 2026-07-22 13:44:01.206899377
+0200
+++ gcc/testsuite/g++.dg/cpp0x/anon-union4.C 2026-07-22 13:44:01.206899377
+0200
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++11 } }
+
+struct A { A () = default; A (int); int a; };
+struct B { union { int a; A b; }; };
+
+B *
+foo ()
+{
+ return new B ();
+}
--- gcc/testsuite/g++.dg/reflect/anon6.C.jj 2026-07-22 13:44:01.207100060
+0200
+++ gcc/testsuite/g++.dg/reflect/anon6.C 2026-07-22 14:27:10.932001251
+0200
@@ -0,0 +1,104 @@
+// CWG3130 - Naming function members of anonymous unions
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct A { union { int a; long b; }; }; // { dg-message "anonymous
union declared here" }
+using U = typename [: parent_of (^^A::a) :];
+U b; // { dg-error "declaration of variable
'b' with anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+struct B { U b; }; // { dg-error "declaration of member
'B::b' with anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+U &plugh ();
+auto c = plugh (); // { dg-error "declaration of variable
'c' with anonymous union type 'A::<unnamed union>'" }
+ // { dg-error "temporary object with
anonymous union type 'A::<unnamed union>'" "" { target *-*-* } .-1 }
+static union { int d; long e; }; // { dg-message "anonymous union
declared here" }
+using V = typename [: parent_of (^^e) :];
+V &thud () { throw 1; }
+auto f = thud (); // { dg-error "declaration of variable
'f' with anonymous union type '<unnamed union>'" }
+ // { dg-error "temporary object with
anonymous union type '<unnamed union>'" "" { target *-*-* } .-1 }
+V g; // { dg-error "declaration of variable
'g' with anonymous union type 'V' {aka '<unnamed union>'}" }
+struct D { V d; }; // { dg-error "declaration of member
'D::d' with anonymous union type 'V' {aka '<unnamed union>'}" }
+struct E { U e[2]; }; // { dg-error "declaration of member
'E::e' with array of anonymous union type 'U \\\[2\\\]' {aka 'A::<unnamed
union> \\\[2\\\]'}" }
+struct F { V f[2]; }; // { dg-error "declaration of member
'F::f' with array of anonymous union type 'V \\\[2\\\]' {aka '<unnamed union>
\\\[2\\\]'}" }
+struct G { static U g; }; // { dg-error "declaration of member
'G::g' with anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+struct H { static V h; }; // { dg-error "declaration of member
'H::h' with anonymous union type 'V' {aka '<unnamed union>'}" }
+struct I { static U i[1][2]; }; // { dg-error "declaration of
member 'I::i' with array of anonymous union type 'U \\\[1\\\]\\\[2\\\]' {aka
'A::<unnamed union> \\\[1\\\]\\\[2\\\]'}" }
+struct J { static V j[2][1]; }; // { dg-error "declaration of
member 'J::j' with array of anonymous union type 'V \\\[2\\\]\\\[1\\\]' {aka
'<unnamed union> \\\[2\\\]\\\[1\\\]'}" }
+using UA = U[2];
+using VA = V[3];
+
+void
+foo (U x) // { dg-error "declaration of parameter
'x' with anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+{
+ U ({ .a = 1 }); // { dg-error "temporary object with
anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+}
+
+void
+foo (U &x)
+{
+ throw x; // { dg-error "'throw' operand has
anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+}
+
+void
+bar ()
+{
+ U y; // { dg-error "declaration of variable
'y' with anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+ U r[4]; // { dg-error "object with array of
anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+ V s[2]; // { dg-error "object with array of
anonymous union type 'V'" }
+ union W { U u; } v; // { dg-error "declaration of member
'bar\\\(\\\)::W::u' with anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+ try
+ {
+ }
+ catch (U z) // { dg-error "'catch' parameter with
anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+ {
+ }
+ try
+ {
+ }
+ catch (U) // { dg-error "'catch' parameter with
anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+ {
+ }
+}
+
+void
+baz (U) // { dg-error "declaration of a
parameter with anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+{
+}
+
+long
+garply (const U &x)
+{
+ return x.b;
+}
+
+void
+corge ()
+{
+ garply (U { .b = 42 }); // { dg-error "temporary object with
anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+}
+
+V *
+xyzzy ()
+{
+ return new V { .e = 42 }; // { dg-error "temporary object with
anonymous union type 'V' {aka '<unnamed union>'}" }
+}
+
+void
+foo (V &x)
+{
+ V ({ .d = 1 }); // { dg-error "temporary object with
anonymous union type 'V' {aka '<unnamed union>'}" }
+ throw x; // { dg-error "'throw' operand has
anonymous union type 'V' {aka '<unnamed union>'}" }
+}
+
+void qux (U);
+void fred (V x);
+void waldo (int, ...);
+
+void
+boo (U &x, V &y)
+{
+ qux (x); // { dg-error "temporary object with
anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+ fred (y); // { dg-error "temporary object with
anonymous union type 'V' {aka '<unnamed union>'}" }
+ waldo (1, x); // { dg-error "temporary object
with anonymous union type 'U' {aka 'A::<unnamed union>'}" }
+ waldo (2, y); // { dg-error "temporary object
with anonymous union type 'V' {aka '<unnamed union>'}" }
+}
--- gcc/testsuite/g++.dg/reflect/anon7.C.jj 2026-07-22 13:44:01.207220236
+0200
+++ gcc/testsuite/g++.dg/reflect/anon7.C 2026-07-22 14:34:26.892246524
+0200
@@ -0,0 +1,86 @@
+// { dg-do compile { target c++26 } }
+// { dg-options "-freflection" }
+
+#include <meta>
+
+struct A { struct { int a; long b; }; }; // { dg-message "anonymous struct
declared here" }
+using U = typename [: parent_of (^^A::a) :];
+U b; // { dg-error "declaration of variable
'b' with anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+struct B { U b; }; // { dg-error "declaration of member
'B::b' with anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+U &plugh ();
+auto c = plugh (); // { dg-error "declaration of variable
'c' with anonymous struct type 'A::<unnamed struct>'" }
+ // { dg-error "temporary object with
anonymous struct type 'A::<unnamed struct>'" "" { target *-*-* } .-1 }
+U g; // { dg-error "declaration of variable
'g' with anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+struct E { U e[2]; }; // { dg-error "declaration of member
'E::e' with array of anonymous struct type 'U \\\[2\\\]' {aka 'A::<unnamed
struct> \\\[2\\\]'}" }
+struct F { static U f; }; // { dg-error "declaration of member
'F::f' with anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+struct G { static U g[2][42]; }; // { dg-error "declaration of member
'G::g' with array of anonymous struct type 'U \\\[2\\\]\\\[42\\\]' {aka
'A::<unnamed struct> \\\[2\\\]\\\[42\\\]'}" }
+using UA = U[2];
+
+void
+foo (U x) // { dg-error "declaration of parameter
'x' with anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+{
+ U ({ .a = 1 }); // { dg-error "temporary object with
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+}
+
+void
+foo (U &x)
+{
+ throw x; // { dg-error "'throw' operand has
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+}
+
+void
+bar ()
+{
+ U y; // { dg-error "declaration of variable
'y' with anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+ U r[4]; // { dg-error "object with array of
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+ union W { U u; } v; // { dg-error "declaration of member
'bar\\\(\\\)::W::u' with anonymous struct type 'U' {aka 'A::<unnamed struct>'}"
}
+ try
+ {
+ }
+ catch (U z) // { dg-error "'catch' parameter with
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+ {
+ }
+ try
+ {
+ }
+ catch (U) // { dg-error "'catch' parameter with
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+ {
+ }
+}
+
+void
+baz (U) // { dg-error "declaration of a
parameter with anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+{
+}
+
+struct D : public U {}; // { dg-error "base type 'U'
{aka 'A::<unnamed struct>'} is anonymous struct type" }
+
+long
+garply (const U &x)
+{
+ return x.b;
+}
+
+void
+corge ()
+{
+ garply (U { .b = 42 }); // { dg-error "temporary object with
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+}
+
+U *
+xyzzy ()
+{
+ return new U { .b = 42 }; // { dg-error "temporary object with
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+}
+
+void qux (U);
+void fred (U x);
+void waldo (int, ...);
+
+void
+boo (U &x)
+{
+ qux (x); // { dg-error "temporary object with
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+ fred (x); // { dg-error "temporary object with
anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+ waldo (1, x); // { dg-error "temporary object
with anonymous struct type 'U' {aka 'A::<unnamed struct>'}" }
+}
--- gcc/testsuite/g++.dg/reflect/anon8.C.jj 2026-07-22 13:44:01.207358056
+0200
+++ gcc/testsuite/g++.dg/reflect/anon8.C 2026-07-22 13:44:01.207358056
+0200
@@ -0,0 +1,24 @@
+// CWG3130 - Naming function members of anonymous unions
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct A { union { int a; long b; }; };
+using U = typename [: parent_of (^^A::a) :];
+
+long
+foo (U &x)
+{
+ return x.b;
+}
+
+int
+main ()
+{
+ A a;
+ a.b = 42;
+ constexpr auto ctx = std::meta::access_context::unchecked ();
+ if (foo (a.[: members_of (^^A, ctx)[1] :]) != 42)
+ __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/reflect/anon9.C.jj 2026-07-22 13:44:01.207467434
+0200
+++ gcc/testsuite/g++.dg/reflect/anon9.C 2026-07-22 13:44:01.207467434
+0200
@@ -0,0 +1,24 @@
+// { dg-do run { target c++26 } }
+// { dg-options "-freflection" }
+
+#include <meta>
+
+struct A { struct { int a; long b; }; };
+using U = typename [: parent_of (^^A::a) :];
+
+long
+foo (U &x)
+{
+ return x.a + x.b;
+}
+
+int
+main ()
+{
+ A a;
+ a.a = 2;
+ a.b = 42;
+ constexpr auto ctx = std::meta::access_context::unchecked ();
+ if (foo (a.[: members_of (^^A, ctx)[1] :]) != 44)
+ __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/template/anonunion3.C.jj 2026-07-20
16:54:59.941704343 +0200
+++ gcc/testsuite/g++.dg/template/anonunion3.C 2026-07-22 13:44:01.207605312
+0200
@@ -4,7 +4,7 @@
extern "C" int printf (const char *, ...);
template<typename T> static char const * f(T *t) {
- T u(*t);
+ T u(*t); // { dg-error "declaration of variable 'u' with
anonymous union type 'main\\\(\\\)::<unnamed union>'" }
u.x = "hello world";
printf("%s\n", u.x);
return "initialized";
Jakub