c++: Reflection vs. CLASSTYPE_TYPEINFO_VAR/ANON_AGGR_TYPE_FIELD sharing [PR124991]
Commit Message
Hi!
typeinfo_var element of lang_type is used for 2 purposes,
CLASSTYPE_TYPEINFO_VAR and ANON_AGGR_TYPE_FIELD, a VAR_DECL for types
for which we need typeid etc. and FIELD_DECL for anonymous union/struct
types inside of classes.
Without reflection one can't ask for typeid of the anonymous union/struct
types, so sharing the same tree for both purposes is fine, but with
reflection we can ICE.
As anonymous unions are fairly rare and asking about typeid of those will be
even rarer, the following patch attempts to fix that without actually
growing the lang_type struct size by using the same tree for both. If it
is NULL_TREE, both CLASSTYPE_TYPEINFO_VAR and ANON_AGGR_TYPE_FIELD
are NULL, if it is a VAR_DECL, it is the former, if it is a FIELD_DECL,
it is the latter, in the really rare case we need both it is turned
into a TREE_LIST where TREE_VALUE is CLASSTYPE_TYPEINFO_VAR and
TREE_PURPOSE is ANON_AGGR_TYPE_FIELD.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/16.2?
Note, CWG3130 fortunately disallows attempts to create a different object
of ANON_AGGR_TYPE_P type (will need to implement that part), so the other
worries from PR124991 (that one can create a variable or member or parameter
etc. with the anon union type and get confused by ANON_AGGR_TYPE_FIELD on it
or trying to tweak lookup rules etc.) are gone.
2026-05-06 Jakub Jelinek <jakub@redhat.com>
PR c++/124991
* cp-tree.h (struct lang_type): Document typeinfo_var member.
(get_classtype_typeinfo_var): New inline function.
(CLASSTYPE_TYPEINFO_VAR): Use it.
(set_classtype_typeinfo_var): New inline function.
(SET_CLASSTYPE_TYPEINFO_VAR): Define.
(get_anon_aggr_type_field): New inline function.
(ANON_AGGR_TYPE_FIELD): Use it.
(set_anon_aggr_type_field): New inline function.
(SET_ANON_AGGR_TYPE_FIELD): Define.
* decl.cc (fixup_anonymous_aggr): Use SET_ANON_AGGR_TYPE_FIELD
instead of ANON_AGGR_TYPE_FIELD.
* module.cc (trees_in::read_class_def): Use
SET_CLASSTYPE_TYPEINFO_VAR instead of setting
CLASSTYPE_TYPEINFO_VAR and do it even for ANON_AGGR_TYPE_P
types. Use SET_ANON_AGGR_TYPE_FIELD instead of setting
ANON_AGGR_TYPE_FIELD.
* rtti.cc (get_tinfo_decl_direct): Use SET_CLASSTYPE_TYPEINFO_VAR
instead of setting CLASSTYPE_TYPEINFO_VAR.
* semantics.cc (finish_member_declaration): Use
SET_ANON_AGGR_TYPE_FIELD instead of setting ANON_AGGR_TYPE_FIELD.
* g++.dg/reflect/anon5.C: New test.
Jakub
Comments
On 5/6/26 4:20 AM, Jakub Jelinek wrote:
> Hi!
>
> typeinfo_var element of lang_type is used for 2 purposes,
> CLASSTYPE_TYPEINFO_VAR and ANON_AGGR_TYPE_FIELD, a VAR_DECL for types
> for which we need typeid etc. and FIELD_DECL for anonymous union/struct
> types inside of classes.
> Without reflection one can't ask for typeid of the anonymous union/struct
> types, so sharing the same tree for both purposes is fine, but with
> reflection we can ICE.
>
> As anonymous unions are fairly rare and asking about typeid of those will be
> even rarer, the following patch attempts to fix that without actually
> growing the lang_type struct size by using the same tree for both. If it
> is NULL_TREE, both CLASSTYPE_TYPEINFO_VAR and ANON_AGGR_TYPE_FIELD
> are NULL, if it is a VAR_DECL, it is the former, if it is a FIELD_DECL,
> it is the latter, in the really rare case we need both it is turned
> into a TREE_LIST where TREE_VALUE is CLASSTYPE_TYPEINFO_VAR and
> TREE_PURPOSE is ANON_AGGR_TYPE_FIELD.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/16.2?
OK.
> Note, CWG3130 fortunately disallows attempts to create a different object
> of ANON_AGGR_TYPE_P type (will need to implement that part), so the other
> worries from PR124991 (that one can create a variable or member or parameter
> etc. with the anon union type and get confused by ANON_AGGR_TYPE_FIELD on it
> or trying to tweak lookup rules etc.) are gone.
Though as you were saying elsewhere, the default constructor/destructor
changes in CWG3130 seems problematic for non-member anonymous unions, we
probably want to push back on that.
> 2026-05-06 Jakub Jelinek <jakub@redhat.com>
>
> PR c++/124991
> * cp-tree.h (struct lang_type): Document typeinfo_var member.
> (get_classtype_typeinfo_var): New inline function.
> (CLASSTYPE_TYPEINFO_VAR): Use it.
> (set_classtype_typeinfo_var): New inline function.
> (SET_CLASSTYPE_TYPEINFO_VAR): Define.
> (get_anon_aggr_type_field): New inline function.
> (ANON_AGGR_TYPE_FIELD): Use it.
> (set_anon_aggr_type_field): New inline function.
> (SET_ANON_AGGR_TYPE_FIELD): Define.
> * decl.cc (fixup_anonymous_aggr): Use SET_ANON_AGGR_TYPE_FIELD
> instead of ANON_AGGR_TYPE_FIELD.
> * module.cc (trees_in::read_class_def): Use
> SET_CLASSTYPE_TYPEINFO_VAR instead of setting
> CLASSTYPE_TYPEINFO_VAR and do it even for ANON_AGGR_TYPE_P
> types. Use SET_ANON_AGGR_TYPE_FIELD instead of setting
> ANON_AGGR_TYPE_FIELD.
> * rtti.cc (get_tinfo_decl_direct): Use SET_CLASSTYPE_TYPEINFO_VAR
> instead of setting CLASSTYPE_TYPEINFO_VAR.
> * semantics.cc (finish_member_declaration): Use
> SET_ANON_AGGR_TYPE_FIELD instead of setting ANON_AGGR_TYPE_FIELD.
>
> * g++.dg/reflect/anon5.C: New test.
>
> --- gcc/cp/cp-tree.h.jj 2026-04-28 08:52:42.674411768 +0200
> +++ gcc/cp/cp-tree.h 2026-05-05 11:26:48.237006358 +0200
> @@ -2682,6 +2682,9 @@ struct GTY(()) lang_type {
> tree primary_base;
> vec<tree_pair_s, va_gc> *vcall_indices;
> tree vtables;
> + /* CLASSTYPE_TYPEINFO_VAR and/or ANON_AGGR_TYPE_FIELD. If both,
> + this is a TREE_LIST with the former as TREE_VALUE and the latter
> + as TREE_PURPOSE. */
> tree typeinfo_var;
> vec<tree, va_gc> *vbases;
> tree as_base;
> @@ -3075,11 +3078,44 @@ struct GTY(()) lang_type {
> #define CLASSTYPE_VTABLES(NODE) \
> (LANG_TYPE_CLASS_CHECK (NODE)->vtables)
>
> +/* Helper for CLASSTYPE_TYPEINFO_VAR. */
> +
> +inline tree
> +get_classtype_typeinfo_var (tree typeinfo_var)
> +{
> + if (typeinfo_var == NULL_TREE)
> + return NULL_TREE;
> + if (TREE_CODE (typeinfo_var) == TREE_LIST)
> + return TREE_VALUE (typeinfo_var);
> + if (VAR_P (typeinfo_var))
> + return typeinfo_var;
> + return NULL_TREE;
> +}
> +
> /* The std::type_info variable representing this class, or NULL if no
> such variable has been created. This field is only set for the
> TYPE_MAIN_VARIANT of the class. */
> #define CLASSTYPE_TYPEINFO_VAR(NODE) \
> - (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var)
> + get_classtype_typeinfo_var (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var)
> +
> +/* Helper for SET_CLASSTYPE_TYPEINFO_VAR. */
> +
> +inline tree &
> +set_classtype_typeinfo_var (tree &typeinfo_var)
> +{
> + if (typeinfo_var == NULL_TREE)
> + return typeinfo_var;
> + if (TREE_CODE (typeinfo_var) == FIELD_DECL)
> + typeinfo_var = build_tree_list (typeinfo_var, NULL_TREE);
> + if (TREE_CODE (typeinfo_var) == TREE_LIST)
> + return TREE_VALUE (typeinfo_var);
> + return typeinfo_var;
> +}
> +
> +/* Setter for that. */
> +#define SET_CLASSTYPE_TYPEINFO_VAR(NODE, VAR) \
> + (set_classtype_typeinfo_var (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var) \
> + = (VAR))
>
> /* Accessor macros for the BINFO_VIRTUALS list. */
>
> @@ -5407,9 +5443,42 @@ get_vec_init_expr (tree t)
> #define ANON_UNION_TYPE_P(NODE) \
> (TREE_CODE (NODE) == UNION_TYPE && ANON_AGGR_TYPE_P (NODE))
>
> +/* Helper for ANON_AGGR_TYPE_FIELD. */
> +
> +inline tree
> +get_anon_aggr_type_field (tree typeinfo_var)
> +{
> + if (typeinfo_var == NULL_TREE)
> + return NULL_TREE;
> + if (TREE_CODE (typeinfo_var) == TREE_LIST)
> + return TREE_PURPOSE (typeinfo_var);
> + if (TREE_CODE (typeinfo_var) == FIELD_DECL)
> + return typeinfo_var;
> + return NULL_TREE;
> +}
> +
> /* For an ANON_AGGR_TYPE_P the single FIELD_DECL it is used with. */
> #define ANON_AGGR_TYPE_FIELD(NODE) \
> - (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var)
> + get_anon_aggr_type_field (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var)
> +
> +/* Helper for SET_ANON_AGGR_TYPE_FIELD. */
> +
> +inline tree &
> +set_anon_aggr_type_field (tree &typeinfo_var)
> +{
> + if (typeinfo_var == NULL_TREE)
> + return typeinfo_var;
> + if (VAR_P (typeinfo_var))
> + typeinfo_var = build_tree_list (NULL_TREE, typeinfo_var);
> + if (TREE_CODE (typeinfo_var) == TREE_LIST)
> + return TREE_PURPOSE (typeinfo_var);
> + return typeinfo_var;
> +}
> +
> +/* Setter for that. */
> +#define SET_ANON_AGGR_TYPE_FIELD(NODE, FIELD) \
> + (set_anon_aggr_type_field (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var) \
> + = (FIELD))
>
> /* Define fields and accessors for nodes representing declared names. */
>
> --- gcc/cp/decl.cc.jj 2026-04-28 08:52:47.345330582 +0200
> +++ gcc/cp/decl.cc 2026-05-05 11:22:05.379600563 +0200
> @@ -6200,7 +6200,7 @@ fixup_anonymous_aggr (tree t)
> vec_safe_truncate (vec, store);
>
> /* Wipe RTTI info. */
> - CLASSTYPE_TYPEINFO_VAR (t) = NULL_TREE;
> + SET_CLASSTYPE_TYPEINFO_VAR (t, NULL_TREE);
>
> /* Anonymous aggregates cannot have fields with ctors, dtors or complex
> assignment operators (because they cannot have these methods themselves).
> --- gcc/cp/module.cc.jj 2026-05-05 10:39:23.498137518 +0200
> +++ gcc/cp/module.cc 2026-05-05 11:24:58.090794839 +0200
> @@ -13730,9 +13730,8 @@ trees_in::read_class_def (tree defn, tre
> {
> CLASSTYPE_BEFRIENDING_CLASSES (type_dup)
> = CLASSTYPE_BEFRIENDING_CLASSES (type);
> - if (!ANON_AGGR_TYPE_P (type))
> - CLASSTYPE_TYPEINFO_VAR (type_dup)
> - = CLASSTYPE_TYPEINFO_VAR (type);
> + SET_CLASSTYPE_TYPEINFO_VAR (type_dup,
> + CLASSTYPE_TYPEINFO_VAR (type));
> }
> for (tree v = type; v; v = TYPE_NEXT_VARIANT (v))
> TYPE_LANG_SPECIFIC (v) = ls;
> @@ -13773,7 +13772,7 @@ trees_in::read_class_def (tree defn, tre
> to the as-base FIELD_DECL copy. */
> gcc_checking_assert (ANON_AGGR_TYPE_FIELD (anon_type));
> else
> - ANON_AGGR_TYPE_FIELD (anon_type) = decl;
> + SET_ANON_AGGR_TYPE_FIELD (anon_type, decl);
> }
>
> if (TREE_CODE (decl) == USING_DECL
> --- gcc/cp/rtti.cc.jj 2026-03-27 10:17:14.033332387 +0100
> +++ gcc/cp/rtti.cc 2026-05-05 11:23:27.832261102 +0200
> @@ -490,7 +490,7 @@ get_tinfo_decl_direct (tree type, tree n
>
> d = pushdecl_top_level_and_finish (d, NULL_TREE);
> if (CLASS_TYPE_P (type))
> - CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
> + SET_CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type), d);
>
> /* Add decl to the global array of tinfo decls. */
> vec_safe_push (unemitted_tinfo_decls, d);
> --- gcc/cp/semantics.cc.jj 2026-04-30 10:18:13.827688681 +0200
> +++ gcc/cp/semantics.cc 2026-05-05 11:24:36.620143633 +0200
> @@ -4284,7 +4284,7 @@ finish_member_declaration (tree decl)
> && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
> {
> gcc_assert (!ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl))));
> - ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl))) = decl;
> + SET_ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl)), decl);
> }
>
> if (TREE_CODE (decl) == USING_DECL)
> --- gcc/testsuite/g++.dg/reflect/anon5.C.jj 2026-05-05 11:52:55.849584570 +0200
> +++ gcc/testsuite/g++.dg/reflect/anon5.C 2026-05-05 12:03:15.339521433 +0200
> @@ -0,0 +1,16 @@
> +// PR c++/124991
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +
> +#include <meta>
> +
> +struct X { union { char b; float c; }; };
> +constexpr auto ctx = std::meta::access_context::unchecked ();
> +
> +int
> +main ()
> +{
> + if (typeid (typename [: parent_of (^^X::b) :])
> + != typeid (typename [: members_of (^^X, ctx)[0] :]))
> + __builtin_abort ();
> +}
>
> Jakub
>
@@ -2682,6 +2682,9 @@ struct GTY(()) lang_type {
tree primary_base;
vec<tree_pair_s, va_gc> *vcall_indices;
tree vtables;
+ /* CLASSTYPE_TYPEINFO_VAR and/or ANON_AGGR_TYPE_FIELD. If both,
+ this is a TREE_LIST with the former as TREE_VALUE and the latter
+ as TREE_PURPOSE. */
tree typeinfo_var;
vec<tree, va_gc> *vbases;
tree as_base;
@@ -3075,11 +3078,44 @@ struct GTY(()) lang_type {
#define CLASSTYPE_VTABLES(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->vtables)
+/* Helper for CLASSTYPE_TYPEINFO_VAR. */
+
+inline tree
+get_classtype_typeinfo_var (tree typeinfo_var)
+{
+ if (typeinfo_var == NULL_TREE)
+ return NULL_TREE;
+ if (TREE_CODE (typeinfo_var) == TREE_LIST)
+ return TREE_VALUE (typeinfo_var);
+ if (VAR_P (typeinfo_var))
+ return typeinfo_var;
+ return NULL_TREE;
+}
+
/* The std::type_info variable representing this class, or NULL if no
such variable has been created. This field is only set for the
TYPE_MAIN_VARIANT of the class. */
#define CLASSTYPE_TYPEINFO_VAR(NODE) \
- (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var)
+ get_classtype_typeinfo_var (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var)
+
+/* Helper for SET_CLASSTYPE_TYPEINFO_VAR. */
+
+inline tree &
+set_classtype_typeinfo_var (tree &typeinfo_var)
+{
+ if (typeinfo_var == NULL_TREE)
+ return typeinfo_var;
+ if (TREE_CODE (typeinfo_var) == FIELD_DECL)
+ typeinfo_var = build_tree_list (typeinfo_var, NULL_TREE);
+ if (TREE_CODE (typeinfo_var) == TREE_LIST)
+ return TREE_VALUE (typeinfo_var);
+ return typeinfo_var;
+}
+
+/* Setter for that. */
+#define SET_CLASSTYPE_TYPEINFO_VAR(NODE, VAR) \
+ (set_classtype_typeinfo_var (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var) \
+ = (VAR))
/* Accessor macros for the BINFO_VIRTUALS list. */
@@ -5407,9 +5443,42 @@ get_vec_init_expr (tree t)
#define ANON_UNION_TYPE_P(NODE) \
(TREE_CODE (NODE) == UNION_TYPE && ANON_AGGR_TYPE_P (NODE))
+/* Helper for ANON_AGGR_TYPE_FIELD. */
+
+inline tree
+get_anon_aggr_type_field (tree typeinfo_var)
+{
+ if (typeinfo_var == NULL_TREE)
+ return NULL_TREE;
+ if (TREE_CODE (typeinfo_var) == TREE_LIST)
+ return TREE_PURPOSE (typeinfo_var);
+ if (TREE_CODE (typeinfo_var) == FIELD_DECL)
+ return typeinfo_var;
+ return NULL_TREE;
+}
+
/* For an ANON_AGGR_TYPE_P the single FIELD_DECL it is used with. */
#define ANON_AGGR_TYPE_FIELD(NODE) \
- (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var)
+ get_anon_aggr_type_field (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var)
+
+/* Helper for SET_ANON_AGGR_TYPE_FIELD. */
+
+inline tree &
+set_anon_aggr_type_field (tree &typeinfo_var)
+{
+ if (typeinfo_var == NULL_TREE)
+ return typeinfo_var;
+ if (VAR_P (typeinfo_var))
+ typeinfo_var = build_tree_list (NULL_TREE, typeinfo_var);
+ if (TREE_CODE (typeinfo_var) == TREE_LIST)
+ return TREE_PURPOSE (typeinfo_var);
+ return typeinfo_var;
+}
+
+/* Setter for that. */
+#define SET_ANON_AGGR_TYPE_FIELD(NODE, FIELD) \
+ (set_anon_aggr_type_field (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var) \
+ = (FIELD))
/* Define fields and accessors for nodes representing declared names. */
@@ -6200,7 +6200,7 @@ fixup_anonymous_aggr (tree t)
vec_safe_truncate (vec, store);
/* Wipe RTTI info. */
- CLASSTYPE_TYPEINFO_VAR (t) = NULL_TREE;
+ SET_CLASSTYPE_TYPEINFO_VAR (t, NULL_TREE);
/* Anonymous aggregates cannot have fields with ctors, dtors or complex
assignment operators (because they cannot have these methods themselves).
@@ -13730,9 +13730,8 @@ trees_in::read_class_def (tree defn, tre
{
CLASSTYPE_BEFRIENDING_CLASSES (type_dup)
= CLASSTYPE_BEFRIENDING_CLASSES (type);
- if (!ANON_AGGR_TYPE_P (type))
- CLASSTYPE_TYPEINFO_VAR (type_dup)
- = CLASSTYPE_TYPEINFO_VAR (type);
+ SET_CLASSTYPE_TYPEINFO_VAR (type_dup,
+ CLASSTYPE_TYPEINFO_VAR (type));
}
for (tree v = type; v; v = TYPE_NEXT_VARIANT (v))
TYPE_LANG_SPECIFIC (v) = ls;
@@ -13773,7 +13772,7 @@ trees_in::read_class_def (tree defn, tre
to the as-base FIELD_DECL copy. */
gcc_checking_assert (ANON_AGGR_TYPE_FIELD (anon_type));
else
- ANON_AGGR_TYPE_FIELD (anon_type) = decl;
+ SET_ANON_AGGR_TYPE_FIELD (anon_type, decl);
}
if (TREE_CODE (decl) == USING_DECL
@@ -490,7 +490,7 @@ get_tinfo_decl_direct (tree type, tree n
d = pushdecl_top_level_and_finish (d, NULL_TREE);
if (CLASS_TYPE_P (type))
- CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
+ SET_CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type), d);
/* Add decl to the global array of tinfo decls. */
vec_safe_push (unemitted_tinfo_decls, d);
@@ -4284,7 +4284,7 @@ finish_member_declaration (tree decl)
&& ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
{
gcc_assert (!ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl))));
- ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl))) = decl;
+ SET_ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl)), decl);
}
if (TREE_CODE (decl) == USING_DECL)
@@ -0,0 +1,16 @@
+// PR c++/124991
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct X { union { char b; float c; }; };
+constexpr auto ctx = std::meta::access_context::unchecked ();
+
+int
+main ()
+{
+ if (typeid (typename [: parent_of (^^X::b) :])
+ != typeid (typename [: members_of (^^X, ctx)[0] :]))
+ __builtin_abort ();
+}