Treat GTY structs that have a "desc" as being the root of an inheritance
hierarchy.  Generate a switch on desc within the marking function with
cases for each subclass, visiting all fields of the type (including
inherited ones).

Don't create marking functions for subclasses, instead using the base
class marking functions.  Use walk_type on them within walk_subclasses
to generate the case within the switch for handling the tag, directly
walking all fields of the type.

        * gengtype.c (output_mangled_typename):  Convert references
        to classes within an inheritance hierarchy to reference the
        ultimate base class, since only it will have gt_ functions.
        (get_string_option): New.
        (walk_subclasses): New.
        (walk_type): Treat GTY structs that have a "desc" as being the
        root of an inheritance hierarchy.  Generate a switch on it
        within the marking function which walks all subclasses, adding
        cases for them via walk_subclasses.  For subclasses, visit all
        fields of the type (including inherited ones).
        (write_func_for_structure): Don't write fns for subclasses, only
        for the ultimate base class within an inheritance hierarchy.
        Subclasses-marking will be handled by the base class marking
        functions.
        (write_types): Likewise.
        (write_local_func_for_structure): Likewise.
        (USED_BY_TYPED_GC_P): Emit allocators for subclasses.
        (write_root): Use the marker function for the ultimate base class.
        * gengtype.h (FOR_ALL_INHERITED_FIELDS): New.
---
 gcc/gengtype.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 gcc/gengtype.h |   5 +++
 2 files changed, 100 insertions(+), 5 deletions(-)

diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index a6dc221..a078b44 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -2534,6 +2534,11 @@ output_mangled_typename (outf_p of, const_type_p t)
       case TYPE_LANG_STRUCT:
       case TYPE_USER_STRUCT:
        {
+         /* For references to classes within an inheritance hierarchy,
+            only ever reference the ultimate base class, since only
+            it will have gt_ functions.  */
+         while (t->u.s.base_class)
+           t = t->u.s.base_class;
          const char *id_for_tag = filter_type_name (t->u.s.tag);
          oprintf (of, "%lu%s", (unsigned long) strlen (id_for_tag),
                   id_for_tag);
@@ -2596,6 +2601,42 @@ output_escaped_param (struct walk_type_data *d, const 
char *param,
        }
 }
 
+const char *
+get_string_option (options_p opt, const char *key)
+{
+  for (; opt; opt = opt->next)
+    if (strcmp (opt->name, key) == 0)
+      return opt->info.string;
+  return NULL;
+}
+
+static void
+walk_subclasses (type_p base, struct walk_type_data *d)
+{
+  for (type_p sub = structures; sub != NULL; sub = sub->next)
+    {
+      if (sub->u.s.base_class == base)
+       {
+         const char *type_tag = get_string_option (sub->u.s.opt, "tag");
+         oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag);
+         d->indent += 2;
+         oprintf (d->of, "%*s{\n", d->indent, "");
+         d->indent += 2;
+         oprintf (d->of, "%*s%s *sub = static_cast <%s *> (x);\n",
+                  d->indent, "", sub->u.s.tag, sub->u.s.tag);
+         const char *old_val = d->val;
+         d->val = "(*sub)";
+         walk_type (sub, d);
+         d->val = old_val;
+         d->indent -= 2;
+         oprintf (d->of, "%*s}\n", d->indent, "");
+         oprintf (d->of, "%*sbreak;\n", d->indent, "");
+         d->indent -= 2;
+
+         walk_subclasses (sub, d);
+       }
+    }
+}
 
 /* Call D->PROCESS_FIELD for every field (or subfield) of D->VAL,
    which is of type T.  Write code to D->OF to constrain execution (at
@@ -2613,6 +2654,7 @@ walk_type (type_p t, struct walk_type_data *d)
 {
   const char *length = NULL;
   const char *desc = NULL;
+  const char *type_tag = NULL;
   int maybe_undef_p = 0;
   int use_param_num = -1;
   int use_params_p = 0;
@@ -2641,7 +2683,7 @@ walk_type (type_p t, struct walk_type_data *d)
     else if (strcmp (oo->name, "dot") == 0)
       ;
     else if (strcmp (oo->name, "tag") == 0)
-      ;
+      type_tag = oo->info.string;
     else if (strcmp (oo->name, "special") == 0)
       ;
     else if (strcmp (oo->name, "skip") == 0)
@@ -2960,8 +3002,21 @@ walk_type (type_p t, struct walk_type_data *d)
            d->indent += 2;
            oprintf (d->of, "%*s{\n", d->indent, "");
          }
+       else
+         {
+           if (desc)
+             {
+               oprintf (d->of, "%*sswitch (", d->indent, "");
+               output_escaped_param (d, desc, "desc");
+               oprintf (d->of, ")\n");
+               d->indent += 2;
+               oprintf (d->of, "%*s{\n", d->indent, "");
+               oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag);
+               d->indent += 2;
+             }
+         }
 
-       for (f = t->u.s.fields; f; f = f->next)
+       FOR_ALL_INHERITED_FIELDS (t, f)
          {
            options_p oo;
            int skip_p = 0;
@@ -2999,7 +3054,7 @@ walk_type (type_p t, struct walk_type_data *d)
          }
        endcounter = d->counter;
 
-       for (f = t->u.s.fields; f; f = f->next)
+       FOR_ALL_INHERITED_FIELDS (t, f)
          {
            options_p oo;
            const char *dot = ".";
@@ -3101,11 +3156,29 @@ walk_type (type_p t, struct walk_type_data *d)
            oprintf (d->of, "%*sdefault:\n", d->indent, "");
            oprintf (d->of, "%*s  break;\n", d->indent, "");
          }
+
+       if (desc && !union_p)
+         {
+               oprintf (d->of, "%*sbreak;\n", d->indent, "");
+               d->indent -= 2;
+          }
        if (union_p)
          {
            oprintf (d->of, "%*s}\n", d->indent, "");
            d->indent -= 2;
          }
+       else
+         {
+           if (desc)
+             {
+               /* Add cases to handle subclasses.  */
+               walk_subclasses (t, d);
+
+               /* End of the switch statement */
+               oprintf (d->of, "%*s}\n", d->indent, "");
+               d->indent -= 2;
+             }
+         }
        if (any_length_seen)
          {
            d->indent -= 2;
@@ -3451,6 +3524,11 @@ write_func_for_structure (type_p orig_s, type_p s, 
type_p *param,
   options_p opt;
   struct walk_type_data d;
 
+  /* Don't write fns for subclasses, only for the ultimate base class
+     within an inheritance hierarchy.  */
+  if (s->u.s.base_class)
+    return;
+
   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
   for (opt = s->u.s.opt; opt; opt = opt->next)
@@ -3627,7 +3705,10 @@ write_types (outf_p output_header, type_p structures, 
type_p param_structs,
      emitted afterwards.  This is needed in plugin mode.  */
   oprintf (output_header, "/* Macros and declarations.  */\n");
   for (s = structures; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO)
+    /* Do not emit handlers for derived classes; we only ever deal with
+       the ultimate base class within an inheritance hierarchy.  */
+    if ((s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO)
+        && !s->u.s.base_class)
       {
        options_p opt;
 
@@ -3932,6 +4013,11 @@ write_local_func_for_structure (const_type_p orig_s, 
type_p s, type_p *param)
 {
   struct walk_type_data d;
 
+  /* Don't write fns for subclasses, only for the ultimate base class
+     within an inheritance hierarchy.  */
+  if (s->u.s.base_class)
+    return;
+
   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
   d.process_field = write_types_local_process_field;
@@ -4076,7 +4162,9 @@ write_local (outf_p output_header, type_p structures, 
type_p param_structs)
           || ((s)->gc_used == GC_MAYBE_POINTED_TO                      \
               && s->u.s.line.file != NULL)                             \
           || ((s)->gc_used == GC_USED                                  \
-              && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous"))))))
+              && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous"))) \
+          || (s->u.s.base_class))))
+
 
 
 /* Might T contain any non-pointer elements?  */
@@ -4360,6 +4448,8 @@ write_root (outf_p f, pair_p v, type_p type, const char 
*name, int has_length,
 
        if (!has_length && union_or_struct_p (tp))
          {
+           while (tp->u.s.base_class)
+             tp = tp->u.s.base_class;
            const char *id_for_tag = filter_type_name (tp->u.s.tag);
            oprintf (f, "    &gt_ggc_mx_%s,\n", id_for_tag);
            if (emit_pch)
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
index 06ebbed..4850723 100644
--- a/gcc/gengtype.h
+++ b/gcc/gengtype.h
@@ -506,4 +506,9 @@ void dbgprint_count_type_at (const char *, int, const char 
*, type_p);
 #define DBGPRINT_COUNT_TYPE(Msg,Ty) do{/*nodbgprint_count_type*/}while (0)
 #endif /*ENABLE_CHECKING */
 
+#define FOR_ALL_INHERITED_FIELDS(TYPE, FIELD_VAR) \
+  for (type_p sub = (TYPE); sub; sub = sub->u.s.base_class) \
+    for (FIELD_VAR = sub->u.s.fields; FIELD_VAR; FIELD_VAR = FIELD_VAR->next)
+
+
 #endif
-- 
1.7.11.7

Reply via email to