This patch is the handwritten part of the conversion of these types
to C++; it requires the followup patch, which is autogenerated.

It converts:
  struct GTY(()) symtab_node_base
to:
  class GTY((user)) symtab_node_base

and converts:
  struct GTY(()) cgraph_node
to:
  struct GTY((user)) cgraph_node : public symtab_node_base

and:
  struct GTY(()) varpool_node
to:
  class GTY((user)) varpool_node : public symtab_node_base

dropping the symtab_node_def union.

Since gengtype is unable to cope with inheritance, we have to mark the
types with GTY((user)), and handcode the gty field-visiting functions.
Given the simple hierarchy, we don't need virtual functions for this.

Unfortunately doing so runs into various bugs in gengtype's handling
of GTY((user)), so the patch also includes workarounds for these bugs.

gengtype walks the graph of the *types* in the code, and produces
functions in gtype-desc.[ch] for all types that are reachable from a
GTY root.

However, it ignores the contents of GTY((user)) types when walking
this graph.

Hence if you have a subgraph of types that are only reachable
via fields in GTY((user)) types, gengtype won't generate helper code
for those types.

Ideally there would be some way to mark a GTY((user)) type to say
which types it references, to avoid having to mark these types as
GTY((user)).

For now, work around this issue by providing explicit roots of the
missing types, of dummy variables (see the bottom of cgraph.c)

gcc/

        * cgraph.c (gt_ggc_mx): New.
        (gt_pch_nx (symtab_node_base *)): New.
        (gt_pch_nx (symtab_node_base *, gt_pointer_operator, void *)): New.
        (dummy_call_site_hash): New.
        (dummy_ipa_ref_list): New.
        (dummy_cgraph_clone_info): New.
        (dummy_ipa_replace_map_pointer): New.
        (dummy_varpool_node_ptr): New.

        * cgraph.h (symtab_node_base): Convert to a class;
        add GTY((user)).
        (gt_ggc_mx): New.
        (gt_pch_nx (symtab_node_base *p)): New.
        (gt_pch_nx (symtab_node_base *p, gt_pointer_operator op,
        void *cookie)): New.
        (cgraph_node): Inherit from symtab_node; convert to GTY((user)).
        (varpool_node): Likewise.
        (symtab_node_def): Remove.
        (is_a_helper <cgraph_node>::test (symtab_node_def *)): Convert to...
        (is_a_helper <cgraph_node>::test (symtab_node_base *)): ...this.
        (is_a_helper <varpool_node>::test (symtab_node_def *)): Convert to...
        (is_a_helper <varpool_node>::test (symtab_node_base *)): ...this.

        * ipa-ref.h (symtab_node_def): Drop.
        (symtab_node): Change underlying type from symtab_node_def to
        symtab_node_base.
        (const_symtab_node): Likwise.

        * is-a.h: Update examples in comment.

        * symtab.c (symtab_hash): Change symtab_node_def to symtab_node_base.
        (assembler_name_hash): Likewise.
---
 gcc/cgraph.c  | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/cgraph.h  |  48 ++++++-------
 gcc/ipa-ref.h |   6 +-
 gcc/is-a.h    |   6 +-
 gcc/symtab.c  |   4 +-
 5 files changed, 247 insertions(+), 35 deletions(-)

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 50d13ab..5cb6a31 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -3035,4 +3035,222 @@ cgraph_get_body (struct cgraph_node *node)
   return true;
 }
 
+/* GTY((user)) hooks for symtab_node_base (and its subclasses).
+   We could use virtual functions for this, but given the presence of the
+   "type" field and the trivial size of the class hierarchy, switches are
+   perhaps simpler and faster.  */
+
+void gt_ggc_mx (symtab_node_base *x)
+{
+  /* Hand-written equivalent of the chain_next/chain_prev machinery, to
+     avoid deep call-stacks.
+
+     Locate the neighbors of x (within the linked-list) that haven't been
+     marked yet, so that x through xlimit give a range suitable for marking.
+     Note that x (on entry) itself has already been marked by the
+     gtype-desc.c code, so we first try its successor.
+  */
+  symtab_node_base * xlimit = x ? x->next : NULL;
+  while (ggc_test_and_set_mark (xlimit))
+   xlimit = xlimit->next;
+  if (x != xlimit)
+    for (;;)
+      {
+        symtab_node_base * const xprev = x->previous;
+        if (xprev == NULL) break;
+        x = xprev;
+        (void) ggc_test_and_set_mark (xprev);
+      }
+  while (x != xlimit)
+    {
+      /* Code common to all symtab nodes. */
+      gt_ggc_m_9tree_node (x->decl);
+      gt_ggc_mx_symtab_node_base (x->next);
+      gt_ggc_mx_symtab_node_base (x->previous);
+      gt_ggc_mx_symtab_node_base (x->next_sharing_asm_name);
+      gt_ggc_mx_symtab_node_base (x->previous_sharing_asm_name);
+      gt_ggc_mx_symtab_node_base (x->same_comdat_group);
+      gt_ggc_m_20vec_ipa_ref_t_va_gc_ (x->ref_list.references);
+      gt_ggc_m_9tree_node (x->alias_target);
+      gt_ggc_m_18lto_file_decl_data (x->lto_file_data);
+
+      /* Extra code, per subclass. */
+      switch (x->type)
+        {
+        case SYMTAB_FUNCTION:
+          {
+            cgraph_node *cgn = static_cast <cgraph_node *> (x);
+            gt_ggc_m_11cgraph_edge (cgn->callees);
+            gt_ggc_m_11cgraph_edge (cgn->callers);
+            gt_ggc_m_11cgraph_edge (cgn->indirect_calls);
+            gt_ggc_m_11cgraph_node (cgn->origin);
+            gt_ggc_m_11cgraph_node (cgn->nested);
+            gt_ggc_m_11cgraph_node (cgn->next_nested);
+            gt_ggc_m_11cgraph_node (cgn->next_sibling_clone);
+            gt_ggc_m_11cgraph_node (cgn->prev_sibling_clone);
+            gt_ggc_m_11cgraph_node (cgn->clones);
+            gt_ggc_m_11cgraph_node (cgn->clone_of);
+            gt_ggc_m_P11cgraph_edge4htab (cgn->call_site_hash);
+            gt_ggc_m_9tree_node (cgn->former_clone_of);
+            gt_ggc_m_11cgraph_node (cgn->global.inlined_to);
+            gt_ggc_m_28vec_ipa_replace_map_p_va_gc_ (cgn->clone.tree_map);
+            gt_ggc_m_15bitmap_head_def (cgn->clone.args_to_skip);
+            gt_ggc_m_15bitmap_head_def (cgn->clone.combined_args_to_skip);
+            gt_ggc_m_9tree_node (cgn->thunk.alias);
+          }
+          break;
+        default:
+          break;
+        }
+      x = x->next;
+    }
+}
+
+void gt_pch_nx (symtab_node_base *x)
+{
+  symtab_node_base * xlimit = x ? x->next : NULL;
+  while (gt_pch_note_object (xlimit, xlimit, gt_pch_p_16symtab_node_base))
+   xlimit = xlimit->next;
+  if (x != xlimit)
+    for (;;)
+      {
+        symtab_node_base * const xprev = x->previous;
+        if (xprev == NULL) break;
+        x = xprev;
+        (void) gt_pch_note_object (xprev, xprev,
+                                   gt_pch_p_16symtab_node_base);
+      }
+  while (x != xlimit)
+    {
+      /* Code common to all symtab nodes. */
+      gt_pch_n_9tree_node (x->decl);
+      gt_pch_nx_symtab_node_base (x->next);
+      gt_pch_nx_symtab_node_base (x->previous);
+      gt_pch_nx_symtab_node_base (x->next_sharing_asm_name);
+      gt_pch_nx_symtab_node_base (x->previous_sharing_asm_name);
+      gt_pch_nx_symtab_node_base (x->same_comdat_group);
+      gt_pch_n_20vec_ipa_ref_t_va_gc_ (x->ref_list.references);
+      gt_pch_n_9tree_node (x->alias_target);
+      gt_pch_n_18lto_file_decl_data (x->lto_file_data);
+
+      /* Extra code, per subclass. */
+      switch (x->type)
+        {
+        case SYMTAB_FUNCTION:
+          {
+            cgraph_node *cgn = static_cast <cgraph_node *> (x);
+            gt_pch_n_11cgraph_edge (cgn->callees);
+            gt_pch_n_11cgraph_edge (cgn->callers);
+            gt_pch_n_11cgraph_edge (cgn->indirect_calls);
+            gt_pch_n_11cgraph_node (cgn->origin);
+            gt_pch_n_11cgraph_node (cgn->nested);
+            gt_pch_n_11cgraph_node (cgn->next_nested);
+            gt_pch_n_11cgraph_node (cgn->next_sibling_clone);
+            gt_pch_n_11cgraph_node (cgn->prev_sibling_clone);
+            gt_pch_n_11cgraph_node (cgn->clones);
+            gt_pch_n_11cgraph_node (cgn->clone_of);
+            gt_pch_n_P11cgraph_edge4htab (cgn->call_site_hash);
+            gt_pch_n_9tree_node (cgn->former_clone_of);
+            gt_pch_n_11cgraph_node (cgn->global.inlined_to);
+            gt_pch_n_28vec_ipa_replace_map_p_va_gc_ (cgn->clone.tree_map);
+            gt_pch_n_15bitmap_head_def (cgn->clone.args_to_skip);
+            gt_pch_n_15bitmap_head_def (cgn->clone.combined_args_to_skip);
+            gt_pch_n_9tree_node (cgn->thunk.alias);
+          }
+          break;
+        default:
+          break;
+        }
+      x = x->next;
+    }
+}
+
+void gt_pch_nx (symtab_node_base *p, gt_pointer_operator op, void *cookie)
+{
+  /* Code common to all symtab nodes. */
+  op (&(p->decl), cookie);
+  op (&(p->next), cookie);
+  op (&(p->previous), cookie);
+  op (&(p->next_sharing_asm_name), cookie);
+  op (&(p->previous_sharing_asm_name), cookie);
+  op (&(p->same_comdat_group), cookie);
+  op (&(p->ref_list.references), cookie);
+  op (&(p->alias_target), cookie);
+  op (&(p->lto_file_data), cookie);
+
+  /* Extra code, per subclass. */
+  switch (p->type)
+    {
+    case SYMTAB_FUNCTION:
+      {
+        cgraph_node *cgn = static_cast <cgraph_node *> (p);
+        op (&(cgn->callees), cookie);
+        op (&(cgn->callers), cookie);
+        op (&(cgn->indirect_calls), cookie);
+        op (&(cgn->origin), cookie);
+        op (&(cgn->nested), cookie);
+        op (&(cgn->next_nested), cookie);
+        op (&(cgn->next_sibling_clone), cookie);
+        op (&(cgn->prev_sibling_clone), cookie);
+        op (&(cgn->clones), cookie);
+        op (&(cgn->clone_of), cookie);
+        op (&(cgn->call_site_hash), cookie);
+        op (&(cgn->former_clone_of), cookie);
+        op (&(cgn->global.inlined_to), cookie);
+        op (&(cgn->clone.tree_map), cookie);
+        op (&(cgn->clone.args_to_skip), cookie);
+        op (&(cgn->clone.combined_args_to_skip), cookie);
+        op (&(cgn->thunk.alias), cookie);
+      }
+      break;
+    default:
+      break;
+    }
+}
+
+/* Workarounds for deficiencies in gengtype's handling of GTY((user)).
+
+   gengtype walks the graph of the *types* in the code, and produces
+   functions in gtype-desc.[ch] for all types that are reachable from a
+   GTY root.
+
+   However, it ignores the contents of GTY((user)) types when walking
+   this graph.
+
+   Hence if you have a subgraph of types that are only reachable
+   via fields in GTY((user)) types, gengtype won't generate helper code
+   for those types.
+
+   Ideally there would be some way to mark a GTY((user)) type to say
+   which types it references, to avoid having to mark these types as
+   GTY((user)).
+
+   For now, work around this issue by providing explicit roots of the
+   missing types, of dummy variables.  */
+
+/* Force gengtype into providing GTY hooks for the type of this field:
+     htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
+   within cgraph_node.  */
+static GTY(()) htab_t GTY((param_is (struct cgraph_edge))) 
dummy_call_site_hash;
+
+/* Similarly for this field of symtab_node_base:
+     struct ipa_ref_list ref_list;
+ */
+static GTY((deletable)) struct ipa_ref_list *dummy_ipa_ref_list;
+
+/* Similarly for this field of cgraph_node:
+     struct cgraph_clone_info clone;
+*/
+static GTY((deletable)) struct cgraph_clone_info *dummy_cgraph_clone_info;
+
+/* Non-existent pointer, to trick gengtype into (correctly) realizing that
+   ipa_replace_map is indeed used in the code, and thus should have ggc_alloc_*
+   routines.  */
+static GTY((deletable)) struct ipa_replace_map *dummy_ipa_replace_map_pointer;
+
+/* Non-existent pointer, to trick gengtype into (correctly) realizing that
+   varpool_node is indeed used in the code, and thus should have ggc_alloc_*
+   routines.  */
+static GTY((deletable)) varpool_node *dummy_varpool_node_ptr;
+
 #include "gt-cgraph.h"
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index e430533..412b5bb 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -40,8 +40,9 @@ enum symtab_type
 
 /* Base of all entries in the symbol table.
    The symtab_node is inherited by cgraph and varpol nodes.  */
-struct GTY(()) symtab_node_base
+class GTY((user)) symtab_node_base
 {
+public:
   /* Type of the symbol.  */
   ENUM_BITFIELD (symtab_type) type : 8;
 
@@ -143,6 +144,16 @@ struct GTY(()) symtab_node_base
   PTR GTY ((skip)) aux;
 };
 
+/* These user-provided hooks are called by code in gtype-desc.c
+   autogenerated by gengtype.c.
+
+   They are called the first time that the given object is visited
+   within a GC/PCH traversal.
+*/
+extern void gt_ggc_mx (symtab_node_base *p);
+extern void gt_pch_nx (symtab_node_base *p);
+extern void gt_pch_nx (symtab_node_base *p, gt_pointer_operator op, void 
*cookie);
+
 enum availability
 {
   /* Not yet set by cgraph_function_body_availability.  */
@@ -252,25 +263,19 @@ struct GTY(()) cgraph_clone_info
 /* The cgraph data structure.
    Each function decl has assigned cgraph_node listing callees and callers.  */
 
-struct GTY(()) cgraph_node {
-  struct symtab_node_base symbol;
+struct GTY((user)) cgraph_node : public symtab_node_base {
+public:
   struct cgraph_edge *callees;
   struct cgraph_edge *callers;
   /* List of edges representing indirect calls with a yet undetermined
      callee.  */
   struct cgraph_edge *indirect_calls;
   /* For nested functions points to function the node is nested in.  */
-  struct cgraph_node *
-    GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", 
"(symtab_node)%h")))
-    origin;
+  struct cgraph_node *origin;
   /* Points to first nested function, if any.  */
-  struct cgraph_node *
-    GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", 
"(symtab_node)%h")))
-    nested;
+  struct cgraph_node *nested;
   /* Pointer to the next function with same origin, if any.  */
-  struct cgraph_node *
-    GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", 
"(symtab_node)%h")))
-    next_nested;
+  struct cgraph_node *next_nested;
   /* Pointer to the next clone.  */
   struct cgraph_node *next_sibling_clone;
   struct cgraph_node *prev_sibling_clone;
@@ -518,9 +523,8 @@ typedef struct cgraph_edge *cgraph_edge_p;
 /* The varpool data structure.
    Each static variable decl has assigned varpool_node.  */
 
-struct GTY(()) varpool_node {
-  struct symtab_node_base symbol;
-
+class GTY((user)) varpool_node : public symtab_node_base {
+public:
   /* Set when variable is scheduled to be assembled.  */
   unsigned output : 1;
 };
@@ -536,22 +540,12 @@ struct GTY(()) asm_node {
   int order;
 };
 
-/* Symbol table entry.  */
-union GTY((desc ("%h.symbol.type"), chain_next ("%h.symbol.next"),
-          chain_prev ("%h.symbol.previous"))) symtab_node_def {
-  struct symtab_node_base GTY ((tag ("SYMTAB_SYMBOL"))) symbol;
-  /* To access the following fields,
-     use the use dyn_cast or as_a to obtain the concrete type.  */
-  struct cgraph_node GTY ((tag ("SYMTAB_FUNCTION"))) x_function;
-  struct varpool_node GTY ((tag ("SYMTAB_VARIABLE"))) x_variable;
-};
-
 /* Report whether or not THIS symtab node is a function, aka cgraph_node.  */
 
 template <>
 template <>
 inline bool
-is_a_helper <cgraph_node>::test (symtab_node_def *p)
+is_a_helper <cgraph_node>::test (symtab_node_base *p)
 {
   return p->symbol.type == SYMTAB_FUNCTION;
 }
@@ -561,7 +555,7 @@ is_a_helper <cgraph_node>::test (symtab_node_def *p)
 template <>
 template <>
 inline bool
-is_a_helper <varpool_node>::test (symtab_node_def *p)
+is_a_helper <varpool_node>::test (symtab_node_base *p)
 {
   return p->symbol.type == SYMTAB_VARIABLE;
 }
diff --git a/gcc/ipa-ref.h b/gcc/ipa-ref.h
index e0553bb..dc6e238 100644
--- a/gcc/ipa-ref.h
+++ b/gcc/ipa-ref.h
@@ -20,9 +20,9 @@ along with GCC; see the file COPYING3.  If not see
 
 struct cgraph_node;
 struct varpool_node;
-union symtab_node_def;
-typedef union symtab_node_def *symtab_node;
-typedef const union symtab_node_def *const_symtab_node;
+class symtab_node_base;
+typedef symtab_node_base *symtab_node;
+typedef const symtab_node_base *const_symtab_node;
 
 
 /* How the reference is done.  */
diff --git a/gcc/is-a.h b/gcc/is-a.h
index b5ee854..ccf12be 100644
--- a/gcc/is-a.h
+++ b/gcc/is-a.h
@@ -31,7 +31,7 @@ bool is_a <TYPE> (pointer)
 
     Tests whether the pointer actually points to a more derived TYPE.
 
-    Suppose you have a symtab_node_def *ptr, AKA symtab_node ptr.  You can test
+    Suppose you have a symtab_node_base *ptr, AKA symtab_node ptr.  You can 
test
     whether it points to a 'derived' cgraph_node as follows.
 
       if (is_a <cgraph_node> (ptr))
@@ -110,7 +110,7 @@ example,
   template <>
   template <>
   inline bool
-  is_a_helper <cgraph_node>::test (symtab_node_def *p)
+  is_a_helper <cgraph_node>::test (symtab_node_base *p)
   {
     return p->symbol.type == SYMTAB_FUNCTION;
   }
@@ -122,7 +122,7 @@ when needed may result in a crash.  For example,
   template <>
   template <>
   inline bool
-  is_a_helper <cgraph_node>::cast (symtab_node_def *p)
+  is_a_helper <cgraph_node>::cast (symtab_node_base *p)
   {
     return &p->x_function;
   }
diff --git a/gcc/symtab.c b/gcc/symtab.c
index a86bf6b..ba41f89 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -48,9 +48,9 @@ const char * const ld_plugin_symbol_resolution_names[]=
 };
 
 /* Hash table used to convert declarations into nodes.  */
-static GTY((param_is (union symtab_node_def))) htab_t symtab_hash;
+static GTY((param_is (symtab_node_base))) htab_t symtab_hash;
 /* Hash table used to convert assembler names into nodes.  */
-static GTY((param_is (union symtab_node_def))) htab_t assembler_name_hash;
+static GTY((param_is (symtab_node_base))) htab_t assembler_name_hash;
 
 /* Linked list of symbol table nodes.  */
 symtab_node symtab_nodes;
-- 
1.7.11.7

Reply via email to