https://gcc.gnu.org/g:5e375a47bc7bfd8d97318e23c689487ed936041b

commit r16-8909-g5e375a47bc7bfd8d97318e23c689487ed936041b
Author: Jakub Jelinek <[email protected]>
Date:   Thu May 7 08:45:32 2026 +0200

    c++: Reflection vs. CLASSTYPE_TYPEINFO_VAR/ANON_AGGR_TYPE_FIELD sharing 
[PR124991]
    
    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.
    
    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-07  Jakub Jelinek  <[email protected]>
    
            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.
    
    Reviewed-by: Jason Merrill <[email protected]>
    (cherry picked from commit 6481ee18e339356e3f5ff65428224ee4c500bc41)

Diff:
---
 gcc/cp/cp-tree.h                     | 73 +++++++++++++++++++++++++++++++++++-
 gcc/cp/decl.cc                       |  2 +-
 gcc/cp/module.cc                     |  7 ++--
 gcc/cp/rtti.cc                       |  2 +-
 gcc/cp/semantics.cc                  |  2 +-
 gcc/testsuite/g++.dg/reflect/anon5.C | 16 ++++++++
 6 files changed, 93 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fc5bb5638be1..cd37a931e4ab 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2683,6 +2683,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;
@@ -3076,11 +3079,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.  */
 
@@ -5414,9 +5450,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.  */
 
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 9924c0fc1725..d2c66c902753 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6204,7 +6204,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).
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f4f0e6f6b969..61e56824f8d3 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13735,9 +13735,8 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
                {
                  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;
@@ -13778,7 +13777,7 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
                       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
diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc
index a0f7029fed88..7e6fa51936ab 100644
--- a/gcc/cp/rtti.cc
+++ b/gcc/cp/rtti.cc
@@ -490,7 +490,7 @@ get_tinfo_decl_direct (tree type, tree name, int pseudo_ix)
 
       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);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index cd42695aa824..dfde8f1925b5 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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)
diff --git a/gcc/testsuite/g++.dg/reflect/anon5.C 
b/gcc/testsuite/g++.dg/reflect/anon5.C
new file mode 100644
index 000000000000..cd490c7c308b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/anon5.C
@@ -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 ();
+}

Reply via email to