[multiple changes]
[gcc.git] / gcc / gengtype.c
index d24623491a9511763da11bf0d4894a3fe39bc59f..5d219c37e27e87c8fd08843e18c1ab05aae5c93e 100644 (file)
@@ -1,6 +1,5 @@
 /* Process source files and output type information.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2002-2015 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
    along with GCC; see the file COPYING3.  If not see
    <http://www.gnu.org/licenses/>.  */
 
+#ifdef HOST_GENERATOR_FILE
+#include "config.h"
+#define GENERATOR_FILE 1
+#else
 #include "bconfig.h"
+#endif
 #include "system.h"
 #include "errors.h"            /* for fatal */
 #include "getopt.h"
-#include "double-int.h"
 #include "version.h"           /* for version_string & pkgversion_string.  */
 #include "hashtab.h"
 #include "xregex.h"
 #include "obstack.h"
 #include "gengtype.h"
+#include "filenames.h"
 
 /* Data types, macros, etc. used only in this file.  */
 
-/* Kinds of types we can understand.  */
-enum typekind
-{
-  TYPE_SCALAR,
-  TYPE_STRING,
-  TYPE_STRUCT,
-  TYPE_UNION,
-  TYPE_POINTER,
-  TYPE_ARRAY,
-  TYPE_LANG_STRUCT,
-  TYPE_PARAM_STRUCT
-};
-
-
-/* A way to pass data through to the output end.  */
-struct options
-{
-  struct options *next;
-  const char *name;
-  const char *info;
-};
-
-/* Option data for the 'nested_ptr' option.  */
-struct nested_ptr_data
-{
-  type_p type;
-  const char *convert_to;
-  const char *convert_from;
-};
-
-/* A name and a type.  */
-struct pair
-{
-  pair_p next;
-  const char *name;
-  type_p type;
-  struct fileloc line;
-  options_p opt;
-};
-
-#define NUM_PARAM 10
-
-/* A description of a type.  */
-enum gc_used_enum
-{
-  GC_UNUSED = 0,
-  GC_USED,
-  /* Used for structures whose definitions we haven't seen so far when
-     we encounter a pointer to it that is annotated with ``maybe_undef''.
-     If after reading in everything we don't have source file
-     information for it, we assume that it never has been defined. */
-  GC_MAYBE_POINTED_TO,
-  GC_POINTED_TO
-};
-
-struct type
-{
-  enum typekind kind;
-  type_p next;
-  type_p pointer_to;
-  enum gc_used_enum gc_used;
-  union
-  {
-    type_p p;
-    struct
-    {
-      const char *tag;
-      struct fileloc line;
-      pair_p fields;
-      options_p opt;
-      lang_bitmap bitmap;
-      type_p lang_struct;
-    } s;
-    bool scalar_is_char;
-    struct
-    {
-      type_p p;
-      const char *len;
-    } a;
-    struct
-    {
-      type_p stru;
-      type_p param[NUM_PARAM];
-      struct fileloc line;
-    } param_struct;
-  } u;
-};
-
-#define UNION_P(x)                                     \
- ((x)->kind == TYPE_UNION ||                           \
-  ((x)->kind == TYPE_LANG_STRUCT                       \
-   && (x)->u.s.lang_struct->kind == TYPE_UNION))
-#define UNION_OR_STRUCT_P(x)                   \
- ((x)->kind == TYPE_UNION                      \
-  || (x)->kind == TYPE_STRUCT                  \
-  || (x)->kind == TYPE_LANG_STRUCT)
-
-
-
-
 
 /* The list of output files.  */
 outf_p output_files;
@@ -167,6 +71,10 @@ int do_debug;
 /* Level for verbose messages.  */
 int verbosity_level;
 
+/* We have a type count and use it to set the state_number of newly
+   allocated types to some unique negative number.  */
+static int type_count;
+
 /* The backup directory should be in the same file system as the
    generated files, otherwise the rename(2) system call would fail.
    If NULL, no backup is made when overwriting a generated file.  */
@@ -180,6 +88,10 @@ static const char *get_file_realbasename (const input_file *);
 
 static int get_prefix_langdir_index (const char *);
 static const char *get_file_langdir (const input_file *);
+
+static void dump_pair (int indent, pair_p p);
+static void dump_type (int indent, type_p p);
+static void dump_type_list (int indent, type_p p);
 \f
 
 /* Nonzero iff an error has occurred.  */
@@ -207,22 +119,23 @@ error_at_line (const struct fileloc *pos, const char *msg, ...)
 
   va_end (ap);
 }
+\f
+/* Locate the ultimate base class of struct S.  */
 
-/* asprintf, but produces fatal message on out-of-memory.  */
-char *
-xasprintf (const char *format, ...)
+static const_type_p
+get_ultimate_base_class (const_type_p s)
 {
-  int n;
-  char *result;
-  va_list ap;
-
-  va_start (ap, format);
-  n = vasprintf (&result, format, ap);
-  if (result == NULL || n < 0)
-    fatal ("out of memory");
-  va_end (ap);
+  while (s->u.s.base_class)
+    s = s->u.s.base_class;
+  return s;
+}
 
-  return result;
+static type_p
+get_ultimate_base_class (type_p s)
+{
+  while (s->u.s.base_class)
+    s = s->u.s.base_class;
+  return s;
 }
 \f
 /* Input file handling. */
@@ -250,19 +163,22 @@ static outf_p *base_files;
 
 #if ENABLE_CHECKING
 /* Utility debugging function, printing the various type counts within
-   a list of types.  Called thru the DBGPRINT_COUNT_TYPE macro.  */
+   a list of types.  Called through the DBGPRINT_COUNT_TYPE macro.  */
 void
 dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
 {
   int nb_types = 0, nb_scalar = 0, nb_string = 0;
   int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
-  int nb_lang_struct = 0, nb_param_struct = 0;
+  int nb_lang_struct = 0;
+  int nb_user_struct = 0, nb_undefined = 0;
   type_p p = NULL;
   for (p = t; p; p = p->next)
     {
       nb_types++;
       switch (p->kind)
        {
+       case TYPE_UNDEFINED:
+         nb_undefined++;
        case TYPE_SCALAR:
          nb_scalar++;
          break;
@@ -272,6 +188,9 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
        case TYPE_STRUCT:
          nb_struct++;
          break;
+       case TYPE_USER_STRUCT:
+         nb_user_struct++;
+         break;
        case TYPE_UNION:
          nb_union++;
          break;
@@ -284,10 +203,7 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
        case TYPE_LANG_STRUCT:
          nb_lang_struct++;
          break;
-       case TYPE_PARAM_STRUCT:
-         nb_param_struct++;
-         break;
-       default:
+       case TYPE_NONE:
          gcc_unreachable ();
        }
     }
@@ -299,9 +215,12 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
     fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
   if (nb_pointer > 0 || nb_array > 0)
     fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
-  if (nb_lang_struct > 0 || nb_param_struct > 0)
-    fprintf (stderr, "@@%%@@ %d lang_structs, %d param_structs\n",
-            nb_lang_struct, nb_param_struct);
+  if (nb_lang_struct > 0)
+    fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
+  if (nb_user_struct > 0)
+    fprintf (stderr, "@@%%@@ %d user_structs\n", nb_user_struct);
+  if (nb_undefined > 0)
+    fprintf (stderr, "@@%%@@ %d undefined types\n", nb_undefined);
   fprintf (stderr, "\n");
 }
 #endif /* ENABLE_CHECKING */
@@ -525,6 +444,12 @@ read_input_list (const char *listname)
        lang_bitmap bitmap = get_lang_bitmap (gt_files[f]);
        const char *basename = get_file_basename (gt_files[f]);
        const char *slashpos = strchr (basename, '/');
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+       const char *slashpos2 = strchr (basename, '\\');
+
+       if (!slashpos || (slashpos2 && slashpos2 < slashpos))
+         slashpos = slashpos2;
+#endif
 
        if (slashpos)
          {
@@ -554,29 +479,27 @@ read_input_list (const char *listname)
 
 /* The one and only TYPE_STRING.  */
 
-static struct type string_type = {
-  TYPE_STRING, 0, 0, GC_USED, {0}
+struct type string_type = {
+  TYPE_STRING, 0, 0, 0, GC_USED, {0}
 };
 
 /* The two and only TYPE_SCALARs.  Their u.scalar_is_char flags are
-   set to appropriate values at the beginning of main.  */
+   set early in main.  */
 
-static struct type scalar_nonchar = {
-  TYPE_SCALAR, 0, 0, GC_USED, {0}
+struct type scalar_nonchar = {
+  TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
 };
 
-static struct type scalar_char = {
-  TYPE_SCALAR, 0, 0, GC_USED, {0}
+struct type scalar_char = {
+  TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
 };
 
 /* Lists of various things.  */
 
-static pair_p typedefs;
-static type_p structures;
-static type_p param_structs;
-static pair_p variables;
+pair_p typedefs = NULL;
+type_p structures = NULL;
+pair_p variables = NULL;
 
-static type_p find_param_structure (type_p t, type_p param[NUM_PARAM]);
 static type_p adjust_field_tree_exp (type_p t, options_p opt);
 static type_p adjust_field_rtx_def (type_p t, options_p opt);
 
@@ -597,7 +520,7 @@ do_typedef (const char *s, type_p t, struct fileloc *pos)
   for (p = typedefs; p != NULL; p = p->next)
     if (strcmp (p->name, s) == 0)
       {
-       if (p->type != t)
+       if (p->type != t && strcmp (s, "result_type") != 0)
          {
            error_at_line (pos, "type `%s' previously defined", s);
            error_at_line (&p->line, "previously defined here");
@@ -624,29 +547,209 @@ do_scalar_typedef (const char *s, struct fileloc *pos)
   do_typedef (s, &scalar_nonchar, pos);
 }
 
-/* Return the type previously defined for S.  Use POS to report errors.  */
+/* Similar to strtok_r.  */
+
+static char *
+strtoken (char *str, const char *delim, char **next)
+{
+  char *p;
+
+  if (str == NULL)
+    str = *next;
+
+  /* Skip the leading delimiters.  */
+  str += strspn (str, delim);
+  if (*str == '\0')
+    /* This is an empty token.  */
+    return NULL;
+
+  /* The current token.  */
+  p = str;
+
+  /* Find the next delimiter.  */
+  str += strcspn (str, delim);
+  if (*str == '\0')
+    /* This is the last token.  */
+    *next = str;
+  else
+    {
+      /* Terminate the current token.  */
+      *str = '\0';
+      /* Advance to the next token.  */
+      *next = str + 1;
+    }
+
+  return p;
+}
+
+/* Define TYPE_NAME to be a user defined type at location POS.  */
 
 type_p
-resolve_typedef (const char *s, struct fileloc *pos)
+create_user_defined_type (const char *type_name, struct fileloc *pos)
+{
+  type_p ty = find_structure (type_name, TYPE_USER_STRUCT);
+
+  /* We might have already seen an incomplete decl of the given type,
+     in which case we won't have yet seen a GTY((user)), and the type will
+     only have kind "TYPE_STRUCT".  Mark it as a user struct.  */
+  ty->kind = TYPE_USER_STRUCT;
+
+  ty->u.s.line = *pos;
+  ty->u.s.bitmap = get_lang_bitmap (pos->file);
+  do_typedef (type_name, ty, pos);
+
+  /* If TYPE_NAME specifies a template, create references to the types
+     in the template by pretending that each type is a field of TY.
+     This is needed to make sure that the types referenced by the
+     template are marked as used.  */
+  char *str = xstrdup (type_name);
+  char *open_bracket = strchr (str, '<');
+  if (open_bracket)
+    {
+      /* We only accept simple template declarations (see
+        require_template_declaration), so we only need to parse a
+        comma-separated list of strings, implicitly assumed to
+        be type names, potentially with "*" characters.  */
+      char *arg = open_bracket + 1;
+      /* Workaround -Wmaybe-uninitialized false positive during
+        profiledbootstrap by initializing it.  */
+      char *next = NULL;
+      char *type_id = strtoken (arg, ",>", &next);
+      pair_p fields = 0;
+      while (type_id)
+       {
+         /* Create a new field for every type found inside the template
+            parameter list.  */
+
+         /* Support a single trailing "*" character.  */
+         const char *star = strchr (type_id, '*');
+         int is_ptr = (star != NULL);
+         size_t offset_to_star = star - type_id;
+         if (is_ptr)
+           offset_to_star = star - type_id;
+
+         if (strstr (type_id, "char*"))
+           {
+         type_id = strtoken (0, ",>", &next);
+         continue;
+           }
+
+         char *field_name = xstrdup (type_id);
+
+         type_p arg_type;
+         if (is_ptr)
+           {
+             /* Strip off the first '*' character (and any subsequent text). */
+             *(field_name + offset_to_star) = '\0';
+
+             arg_type = find_structure (field_name, TYPE_STRUCT);
+             arg_type = create_pointer (arg_type);
+           }
+         else
+           arg_type = resolve_typedef (field_name, pos);
+
+         fields = create_field_at (fields, arg_type, field_name, 0, pos);
+         type_id = strtoken (0, ",>", &next);
+       }
+
+      /* Associate the field list to TY.  */
+      ty->u.s.fields = fields;
+    }
+  free (str);
+
+  return ty;
+}
+
+
+/* Given a typedef name S, return its associated type.  Return NULL if
+   S is not a registered type name.  */
+
+static type_p
+type_for_name (const char *s)
 {
   pair_p p;
+
+  /* Special-case support for types within a "gcc::" namespace.  Rather
+     than fully-supporting namespaces, simply strip off the "gcc::" prefix
+     where present.  This allows us to have GTY roots of this form:
+         extern GTY(()) gcc::some_type *some_ptr;
+     where the autogenerated functions will refer to simply "some_type",
+     where they can be resolved into their namespace.  */
+  if (0 == strncmp (s, "gcc::", 5))
+    s += 5;
+
   for (p = typedefs; p != NULL; p = p->next)
     if (strcmp (p->name, s) == 0)
       return p->type;
-  error_at_line (pos, "unidentified type `%s'", s);
-  return &scalar_nonchar;      /* treat as "int" */
+  return NULL;
+}
+
+
+/* Create an undefined type with name S and location POS.  Return the
+   newly created type.  */
+
+static type_p
+create_undefined_type (const char *s, struct fileloc *pos)
+{
+  type_p ty = find_structure (s, TYPE_UNDEFINED);
+  ty->u.s.line = *pos;
+  ty->u.s.bitmap = get_lang_bitmap (pos->file);
+  do_typedef (s, ty, pos);
+  return ty;
+}
+
+
+/* Return the type previously defined for S.  Use POS to report errors.  */
+
+type_p
+resolve_typedef (const char *s, struct fileloc *pos)
+{
+  bool is_template_instance = (strchr (s, '<') != NULL);
+  type_p p = type_for_name (s);
+
+  /* If we did not find a typedef registered, generate a TYPE_UNDEFINED
+     type for regular type identifiers.  If the type identifier S is a
+     template instantiation, however, we treat it as a user defined
+     type.
+
+     FIXME, this is actually a limitation in gengtype.  Supporting
+     template types and their instances would require keeping separate
+     track of the basic types definition and its instances.  This
+     essentially forces all template classes in GC to be marked
+     GTY((user)).  */
+  if (!p)
+    p = (is_template_instance)
+       ? create_user_defined_type (s, pos)
+       : create_undefined_type (s, pos);
+
+  return p;
+}
+
+/* Add SUBCLASS to head of linked list of BASE's subclasses.  */
+
+void add_subclass (type_p base, type_p subclass)
+{
+  gcc_assert (union_or_struct_p (base));
+  gcc_assert (union_or_struct_p (subclass));
+
+  subclass->u.s.next_sibling_class = base->u.s.first_subclass;
+  base->u.s.first_subclass = subclass;
 }
 
-/* Create and return a new structure with tag NAME (or a union iff
-   ISUNION is nonzero), at POS with fields FIELDS and options O.  */
+/* Create and return a new structure with tag NAME at POS with fields
+   FIELDS and options O.  The KIND of structure must be one of
+   TYPE_STRUCT, TYPE_UNION or TYPE_USER_STRUCT.  */
 
 type_p
-new_structure (const char *name, int isunion, struct fileloc *pos,
-              pair_p fields, options_p o)
+new_structure (const char *name, enum typekind kind, struct fileloc *pos,
+              pair_p fields, options_p o, type_p base_class)
 {
   type_p si;
   type_p s = NULL;
   lang_bitmap bitmap = get_lang_bitmap (pos->file);
+  bool isunion = (kind == TYPE_UNION);
+
+  gcc_assert (union_or_struct_p (kind));
 
   for (si = structures; si != NULL; si = si->next)
     if (strcmp (name, si->u.s.tag) == 0 && UNION_P (si) == isunion)
@@ -663,12 +766,14 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
        else if (si->u.s.line.file != NULL && si->u.s.bitmap != bitmap)
          {
            ls = si;
+           type_count++;
            si = XCNEW (struct type);
            memcpy (si, ls, sizeof (struct type));
            ls->kind = TYPE_LANG_STRUCT;
            ls->u.s.lang_struct = si;
            ls->u.s.fields = NULL;
            si->next = NULL;
+           si->state_number = -type_count;
            si->pointer_to = NULL;
            si->u.s.lang_struct = ls;
          }
@@ -677,7 +782,9 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
 
        if (ls != NULL && s == NULL)
          {
+           type_count++;
            s = XCNEW (struct type);
+           s->state_number = -type_count;
            s->next = ls->u.s.lang_struct;
            ls->u.s.lang_struct = s;
            s->u.s.lang_struct = ls;
@@ -687,20 +794,21 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
 
   if (s == NULL)
     {
+      type_count++;
       s = XCNEW (struct type);
+      s->state_number = -type_count;
       s->next = structures;
       structures = s;
     }
 
-  if (s->u.s.line.file != NULL
-      || (s->u.s.lang_struct && (s->u.s.lang_struct->u.s.bitmap & bitmap)))
+  if (s->u.s.lang_struct && (s->u.s.lang_struct->u.s.bitmap & bitmap))
     {
       error_at_line (pos, "duplicate definition of '%s %s'",
                     isunion ? "union" : "struct", s->u.s.tag);
       error_at_line (&s->u.s.line, "previous definition here");
     }
 
-  s->kind = isunion ? TYPE_UNION : TYPE_STRUCT;
+  s->kind = kind;
   s->u.s.tag = name;
   s->u.s.line = *pos;
   s->u.s.fields = fields;
@@ -708,58 +816,41 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
   s->u.s.bitmap = bitmap;
   if (s->u.s.lang_struct)
     s->u.s.lang_struct->u.s.bitmap |= bitmap;
+  s->u.s.base_class = base_class;
+  if (base_class)
+    add_subclass (base_class, s);
 
   return s;
 }
 
-/* Return the previously-defined structure with tag NAME (or a union
-   iff ISUNION is nonzero), or a new empty structure or union if none
-   was defined previously.  */
+/* Return the previously-defined structure or union with tag NAME,
+   or a new empty structure or union if none was defined previously.
+   The KIND of structure must be one of TYPE_STRUCT, TYPE_UNION or
+   TYPE_USER_STRUCT.  */
 
 type_p
-find_structure (const char *name, int isunion)
+find_structure (const char *name, enum typekind kind)
 {
   type_p s;
+  bool isunion = (kind == TYPE_UNION);
+
+  gcc_assert (kind == TYPE_UNDEFINED || union_or_struct_p (kind));
 
   for (s = structures; s != NULL; s = s->next)
     if (strcmp (name, s->u.s.tag) == 0 && UNION_P (s) == isunion)
       return s;
 
+  type_count++;
   s = XCNEW (struct type);
   s->next = structures;
+  s->state_number = -type_count;
   structures = s;
-  s->kind = isunion ? TYPE_UNION : TYPE_STRUCT;
+  s->kind = kind;
   s->u.s.tag = name;
   structures = s;
   return s;
 }
 
-/* Return the previously-defined parameterized structure for structure
-   T and parameters PARAM, or a new parameterized empty structure or
-   union if none was defined previously.  */
-
-static type_p
-find_param_structure (type_p t, type_p param[NUM_PARAM])
-{
-  type_p res;
-
-  for (res = param_structs; res; res = res->next)
-    if (res->u.param_struct.stru == t
-       && memcmp (res->u.param_struct.param, param,
-                  sizeof (type_p) * NUM_PARAM) == 0)
-      break;
-  if (res == NULL)
-    {
-      res = XCNEW (struct type);
-      res->kind = TYPE_PARAM_STRUCT;
-      res->next = param_structs;
-      param_structs = res;
-      res->u.param_struct.stru = t;
-      memcpy (res->u.param_struct.param, param, sizeof (type_p) * NUM_PARAM);
-    }
-  return res;
-}
-
 /* Return a scalar type with name NAME.  */
 
 type_p
@@ -771,6 +862,7 @@ create_scalar_type (const char *name)
     return &scalar_nonchar;
 }
 
+
 /* Return a pointer to T.  */
 
 type_p
@@ -779,6 +871,8 @@ create_pointer (type_p t)
   if (!t->pointer_to)
     {
       type_p r = XCNEW (struct type);
+      type_count++;
+      r->state_number = -type_count;
       r->kind = TYPE_POINTER;
       r->u.p = t;
       t->pointer_to = r;
@@ -793,23 +887,53 @@ create_array (type_p t, const char *len)
 {
   type_p v;
 
+  type_count++;
   v = XCNEW (struct type);
   v->kind = TYPE_ARRAY;
+  v->state_number = -type_count;
   v->u.a.p = t;
   v->u.a.len = len;
   return v;
 }
 
-/* Return an options structure with name NAME and info INFO.  NEXT is the
-   next option in the chain.  */
+/* Return a string options structure with name NAME and info INFO.
+   NEXT is the next option in the chain.  */
+options_p
+create_string_option (options_p next, const char *name, const char *info)
+{
+  options_p o = XNEW (struct options);
+  o->kind = OPTION_STRING;
+  o->next = next;
+  o->name = name;
+  o->info.string = info;
+  return o;
+}
 
+/* Create a type options structure with name NAME and info INFO.  NEXT
+   is the next option in the chain.  */
 options_p
-create_option (options_p next, const char *name, const void *info)
+create_type_option (options_p next, const char* name, type_p info)
 {
   options_p o = XNEW (struct options);
   o->next = next;
   o->name = name;
-  o->info = (const char *) info;
+  o->kind = OPTION_TYPE;
+  o->info.type = info;
+  return o;
+}
+
+/* Create a nested pointer options structure with name NAME and info
+   INFO.  NEXT is the next option in the chain.  */
+options_p
+create_nested_option (options_p next, const char* name,
+                      struct nested_ptr_data* info)
+{
+  options_p o;
+  o = XNEW (struct options);
+  o->next = next;
+  o->name = name;
+  o->kind = OPTION_NESTED;
+  o->info.nested = info;
   return o;
 }
 
@@ -823,12 +947,11 @@ create_nested_ptr_option (options_p next, type_p t,
   d->type = adjust_field_type (t, 0);
   d->convert_to = to;
   d->convert_from = from;
-  return create_option (next, "nested_ptr", d);
+  return create_nested_option (next, "nested_ptr", d);
 }
 
 /* Add a variable named S of type T with options O defined at POS,
    to `variables'.  */
-
 void
 note_variable (const char *s, type_p t, options_p o, struct fileloc *pos)
 {
@@ -873,7 +996,7 @@ create_field_at (pair_p next, type_p type, const char *name, options_p opt,
 /* Create a fake field with the given type and name.  NEXT is the next
    field in the chain.  */
 #define create_field(next,type,name) \
-    create_field_all(next,type,name, 0, this_file, __LINE__)
+    create_field_all (next,type,name, 0, this_file, __LINE__)
 
 /* Like create_field, but the field is only valid when condition COND
    is true.  */
@@ -890,15 +1013,19 @@ create_optional_field_ (pair_p next, type_p type, const char *name,
      The field has a tag of "1".  This allows us to make the presence
      of a field of type TYPE depend on some boolean "desc" being true.  */
   union_fields = create_field (NULL, type, "");
-  union_fields->opt = create_option (union_fields->opt, "dot", "");
-  union_fields->opt = create_option (union_fields->opt, "tag", "1");
-  union_type = new_structure (xasprintf ("%s_%d", "fake_union", id++), 1,
-                             &lexer_line, union_fields, NULL);
+  union_fields->opt = 
+    create_string_option (union_fields->opt, "dot", "");
+  union_fields->opt = 
+    create_string_option (union_fields->opt, "tag", "1");
+  union_type = 
+    new_structure (xasprintf ("%s_%d", "fake_union", id++), TYPE_UNION,
+                   &lexer_line, union_fields, NULL, NULL);
 
   /* Create the field and give it the new fake union type.  Add a "desc"
      tag that specifies the condition under which the field is valid.  */
   return create_field_all (next, union_type, name,
-                          create_option (0, "desc", cond), this_file, line);
+                          create_string_option (0, "desc", cond), 
+                          this_file, line);
 }
 
 #define create_optional_field(next,type,name,cond)     \
@@ -980,8 +1107,8 @@ gen_rtx_next (void)
       int k;
 
       rtx_next_new[i] = -1;
-      if (strncmp (rtx_format[i], "iuu", 3) == 0)
-       rtx_next_new[i] = 2;
+      if (strncmp (rtx_format[i], "uu", 2) == 0)
+       rtx_next_new[i] = 1;
       else if (i == COND_EXEC || i == SET || i == EXPR_LIST || i == INSN_LIST)
        rtx_next_new[i] = 1;
       else
@@ -1031,16 +1158,18 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
       return &string_type;
     }
 
-  nodot = create_option (NULL, "dot", "");
+  nodot = create_string_option (NULL, "dot", "");
 
-  rtx_tp = create_pointer (find_structure ("rtx_def", 0));
-  rtvec_tp = create_pointer (find_structure ("rtvec_def", 0));
-  tree_tp = create_pointer (find_structure ("tree_node", 1));
-  mem_attrs_tp = create_pointer (find_structure ("mem_attrs", 0));
-  reg_attrs_tp = create_pointer (find_structure ("reg_attrs", 0));
-  basic_block_tp = create_pointer (find_structure ("basic_block_def", 0));
+  rtx_tp = create_pointer (find_structure ("rtx_def", TYPE_STRUCT));
+  rtvec_tp = create_pointer (find_structure ("rtvec_def", TYPE_STRUCT));
+  tree_tp = create_pointer (find_structure ("tree_node", TYPE_UNION));
+  mem_attrs_tp = create_pointer (find_structure ("mem_attrs", TYPE_STRUCT));
+  reg_attrs_tp = 
+    create_pointer (find_structure ("reg_attrs", TYPE_STRUCT));
+  basic_block_tp = 
+    create_pointer (find_structure ("basic_block_def", TYPE_STRUCT));
   constant_tp =
-    create_pointer (find_structure ("constant_descriptor_rtx", 0));
+    create_pointer (find_structure ("constant_descriptor_rtx", TYPE_STRUCT));
   scalar_tp = &scalar_nonchar; /* rtunion int */
 
   {
@@ -1053,6 +1182,7 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
          {
          case NOTE_INSN_MAX:
          case NOTE_INSN_DELETED_LABEL:
+         case NOTE_INSN_DELETED_DEBUG_LABEL:
            note_flds = create_field (note_flds, &string_type, "rt_str");
            break;
 
@@ -1062,6 +1192,7 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
            break;
 
          case NOTE_INSN_VAR_LOCATION:
+         case NOTE_INSN_CALL_ARG_LOCATION:
            note_flds = create_field (note_flds, rtx_tp, "rt_rtx");
            break;
 
@@ -1072,25 +1203,24 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
        /* NOTE_INSN_MAX is used as the default field for line
           number notes.  */
        if (c == NOTE_INSN_MAX)
-         note_flds->opt = create_option (nodot, "default", "");
+         note_flds->opt = 
+           create_string_option (nodot, "default", "");
        else
-         note_flds->opt = create_option (nodot, "tag", note_insn_name[c]);
+         note_flds->opt = 
+           create_string_option (nodot, "tag", note_insn_name[c]);
       }
-    note_union_tp = new_structure ("rtx_def_note_subunion", 1,
-                                  &lexer_line, note_flds, NULL);
+    note_union_tp = new_structure ("rtx_def_note_subunion", TYPE_UNION,
+                                  &lexer_line, note_flds, NULL, NULL);
   }
   /* Create a type to represent the various forms of SYMBOL_REF_DATA.  */
   {
     pair_p sym_flds;
-
     sym_flds = create_field (NULL, tree_tp, "rt_tree");
-    sym_flds->opt = create_option (nodot, "default", "");
-
+    sym_flds->opt = create_string_option (nodot, "default", "");
     sym_flds = create_field (sym_flds, constant_tp, "rt_constant");
-    sym_flds->opt = create_option (nodot, "tag", "1");
-
-    symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
-                                    &lexer_line, sym_flds, NULL);
+    sym_flds->opt = create_string_option (nodot, "tag", "1");
+    symbol_union_tp = new_structure ("rtx_def_symbol_subunion", TYPE_UNION,
+                                    &lexer_line, sym_flds, NULL, NULL);
   }
   for (i = 0; i < NUM_RTX_CODE; i++)
     {
@@ -1111,6 +1241,7 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
            case 'i':
            case 'n':
            case 'w':
+           case 'r':
              t = scalar_tp;
              subname = "rt_int";
              break;
@@ -1118,19 +1249,19 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
            case '0':
              if (i == MEM && aindex == 1)
                t = mem_attrs_tp, subname = "rt_mem";
-             else if (i == JUMP_INSN && aindex == 8)
+             else if (i == JUMP_INSN && aindex == 7)
                t = rtx_tp, subname = "rt_rtx";
-             else if (i == CODE_LABEL && aindex == 5)
-               t = scalar_tp, subname = "rt_int";
              else if (i == CODE_LABEL && aindex == 4)
+               t = scalar_tp, subname = "rt_int";
+             else if (i == CODE_LABEL && aindex == 3)
                t = rtx_tp, subname = "rt_rtx";
              else if (i == LABEL_REF && (aindex == 1 || aindex == 2))
                t = rtx_tp, subname = "rt_rtx";
-             else if (i == NOTE && aindex == 4)
+             else if (i == NOTE && aindex == 3)
                t = note_union_tp, subname = "";
-             else if (i == NOTE && aindex == 5)
+             else if (i == NOTE && aindex == 4)
                t = scalar_tp, subname = "rt_int";
-             else if (i == NOTE && aindex >= 7)
+             else if (i == NOTE && aindex >= 6)
                t = scalar_tp, subname = "rt_int";
              else if (i == ADDR_DIFF_VEC && aindex == 4)
                t = scalar_tp, subname = "rt_int";
@@ -1138,23 +1269,20 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
                t = scalar_tp, subname = "rt_int";
              else if (i == DEBUG_EXPR && aindex == 0)
                t = tree_tp, subname = "rt_tree";
-             else if (i == REG && aindex == 1)
-               t = scalar_tp, subname = "rt_int";
-             else if (i == REG && aindex == 2)
-               t = reg_attrs_tp, subname = "rt_reg";
-             else if (i == SCRATCH && aindex == 0)
-               t = scalar_tp, subname = "rt_int";
              else if (i == SYMBOL_REF && aindex == 1)
-               t = scalar_tp, subname = "rt_int";
-             else if (i == SYMBOL_REF && aindex == 2)
                t = symbol_union_tp, subname = "";
-             else if (i == BARRIER && aindex >= 3)
+             else if (i == JUMP_TABLE_DATA && aindex >= 4)
                t = scalar_tp, subname = "rt_int";
+             else if (i == BARRIER && aindex >= 2)
+               t = scalar_tp, subname = "rt_int";
+             else if (i == ENTRY_VALUE && aindex == 0)
+               t = rtx_tp, subname = "rt_rtx";
              else
                {
-                 error_at_line (&lexer_line,
-                                "rtx type `%s' has `0' in position %lu, can't handle",
-                                rtx_name[i], (unsigned long) aindex);
+                 error_at_line 
+                   (&lexer_line,
+                    "rtx type `%s' has `0' in position %lu, can't handle",
+                    rtx_name[i], (unsigned long) aindex);
                  t = &string_type;
                  subname = "rt_int";
                }
@@ -1190,10 +1318,11 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
              break;
 
            default:
-             error_at_line (&lexer_line,
-                            "rtx type `%s' has `%c' in position %lu, can't handle",
-                            rtx_name[i], rtx_format[i][aindex],
-                            (unsigned long) aindex);
+             error_at_line
+               (&lexer_line,
+                "rtx type `%s' has `%c' in position %lu, can't handle",
+                rtx_name[i], rtx_format[i][aindex],
+                (unsigned long) aindex);
              t = &string_type;
              subname = "rt_int";
              break;
@@ -1205,34 +1334,40 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
                                               subname));
          subfields->opt = nodot;
          if (t == note_union_tp)
-           subfields->opt = create_option (subfields->opt, "desc",
-                                           "NOTE_KIND (&%0)");
+           subfields->opt =
+             create_string_option (subfields->opt, "desc",
+                                   "NOTE_KIND (&%0)");
          if (t == symbol_union_tp)
-           subfields->opt = create_option (subfields->opt, "desc",
-                                           "CONSTANT_POOL_ADDRESS_P (&%0)");
+           subfields->opt = 
+             create_string_option (subfields->opt, "desc",
+                                   "CONSTANT_POOL_ADDRESS_P (&%0)");
        }
 
+      if (i == REG)
+       subfields = create_field (subfields, reg_attrs_tp, "reg.attrs");
+
       if (i == SYMBOL_REF)
        {
-         /* Add the "block_sym" field if SYMBOL_REF_HAS_BLOCK_INFO_P holds.  */
-         type_p field_tp = find_structure ("block_symbol", 0);
+         /* Add the "block_sym" field if SYMBOL_REF_HAS_BLOCK_INFO_P
+            holds.  */
+         type_p field_tp = find_structure ("block_symbol", TYPE_STRUCT);
          subfields
            = create_optional_field (subfields, field_tp, "block_sym",
                                     "SYMBOL_REF_HAS_BLOCK_INFO_P (&%0)");
        }
 
       sname = xasprintf ("rtx_def_%s", rtx_name[i]);
-      substruct = new_structure (sname, 0, &lexer_line, subfields, NULL);
+      substruct = new_structure (sname, TYPE_STRUCT, &lexer_line, subfields,
+                                NULL, NULL);
 
       ftag = xstrdup (rtx_name[i]);
       for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
        ftag[nmindex] = TOUPPER (ftag[nmindex]);
-
       flds = create_field (flds, substruct, "");
-      flds->opt = create_option (nodot, "tag", ftag);
+      flds->opt = create_string_option (nodot, "tag", ftag);
     }
-
-  return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
+  return new_structure ("rtx_def_subunion", TYPE_UNION, &lexer_line, flds,
+                       nodot, NULL);
 }
 
 /* Handle `special("tree_exp")'.  This is a special case for
@@ -1254,14 +1389,15 @@ adjust_field_tree_exp (type_p t, options_p opt ATTRIBUTE_UNUSED)
       return &string_type;
     }
 
-  nodot = create_option (NULL, "dot", "");
+  nodot = create_string_option (NULL, "dot", "");
 
   flds = create_field (NULL, t, "");
-  flds->opt = create_option (nodot, "length",
-                            "TREE_OPERAND_LENGTH ((tree) &%0)");
-  flds->opt = create_option (flds->opt, "default", "");
+  flds->opt = create_string_option (nodot, "length",
+                                   "TREE_OPERAND_LENGTH ((tree) &%0)");
+  flds->opt = create_string_option (flds->opt, "default", "");
 
-  return new_structure ("tree_exp_subunion", 1, &lexer_line, flds, nodot);
+  return new_structure ("tree_exp_subunion", TYPE_UNION, &lexer_line, flds,
+                       nodot, NULL);
 }
 
 /* Perform any special processing on a type T, about to become the type
@@ -1279,44 +1415,24 @@ adjust_field_type (type_p t, options_p opt)
 {
   int length_p = 0;
   const int pointer_p = t->kind == TYPE_POINTER;
-  type_p params[NUM_PARAM];
-  int params_p = 0;
-  int i;
-
-  for (i = 0; i < NUM_PARAM; i++)
-    params[i] = NULL;
 
   for (; opt; opt = opt->next)
     if (strcmp (opt->name, "length") == 0)
-      length_p = 1;
-    else if (strcmp (opt->name, "param_is") == 0
-            || (strncmp (opt->name, "param", 5) == 0
-                && ISDIGIT (opt->name[5])
-                && strcmp (opt->name + 6, "_is") == 0))
       {
-       int num = ISDIGIT (opt->name[5]) ? opt->name[5] - '0' : 0;
-
-       if (!UNION_OR_STRUCT_P (t)
-           && (t->kind != TYPE_POINTER || !UNION_OR_STRUCT_P (t->u.p)))
+       if (length_p)
+         error_at_line (&lexer_line, "duplicate `%s' option", opt->name);
+       if (t->u.p->kind == TYPE_SCALAR || t->u.p->kind == TYPE_STRING)
          {
            error_at_line (&lexer_line,
-                          "option `%s' may only be applied to structures or structure pointers",
-                          opt->name);
-           return t;
+                          "option `%s' may not be applied to "
+                          "arrays of atomic types", opt->name);
          }
-
-       params_p = 1;
-       if (params[num] != NULL)
-         error_at_line (&lexer_line, "duplicate `%s' option", opt->name);
-       if (!ISDIGIT (opt->name[5]))
-         params[num] =
-           create_pointer (CONST_CAST2 (type_p, const char *, opt->info));
-       else
-         params[num] = CONST_CAST2 (type_p, const char *, opt->info);
+       length_p = 1;
       }
-    else if (strcmp (opt->name, "special") == 0)
+    else if (strcmp (opt->name, "special") == 0
+            && opt->kind == OPTION_STRING)
       {
-       const char *special_name = opt->info;
+       const char *special_name = opt->info.string;
        if (strcmp (special_name, "tree_exp") == 0)
          t = adjust_field_tree_exp (t, opt);
        else if (strcmp (special_name, "rtx_def") == 0)
@@ -1325,16 +1441,6 @@ adjust_field_type (type_p t, options_p opt)
          error_at_line (&lexer_line, "unknown special `%s'", special_name);
       }
 
-  if (params_p)
-    {
-      type_p realt;
-
-      if (pointer_p)
-       t = t->u.p;
-      realt = find_param_structure (t, params);
-      t = pointer_p ? create_pointer (realt) : realt;
-    }
-
   if (!length_p
       && pointer_p && t->u.p->kind == TYPE_SCALAR && t->u.p->u.scalar_is_char)
     return &string_type;
@@ -1347,37 +1453,58 @@ adjust_field_type (type_p t, options_p opt)
 }
 \f
 
-static void set_gc_used_type (type_p, enum gc_used_enum, type_p *);
+static void set_gc_used_type (type_p, enum gc_used_enum, bool = false);
 static void set_gc_used (pair_p);
 
 /* Handle OPT for set_gc_used_type.  */
 
 static void
 process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
-                   int *pass_param, int *length, int *skip,
-                   type_p *nested_ptr)
+                   int *length, int *skip, type_p *nested_ptr)
 {
   options_p o;
   for (o = opt; o; o = o->next)
-    if (strcmp (o->name, "ptr_alias") == 0 && level == GC_POINTED_TO)
-      set_gc_used_type (CONST_CAST2 (type_p, const char *, o->info),
-                       GC_POINTED_TO, NULL);
+    if (strcmp (o->name, "ptr_alias") == 0 && level == GC_POINTED_TO
+       && o->kind == OPTION_TYPE)
+      set_gc_used_type (o->info.type,
+                       GC_POINTED_TO);
     else if (strcmp (o->name, "maybe_undef") == 0)
       *maybe_undef = 1;
-    else if (strcmp (o->name, "use_params") == 0)
-      *pass_param = 1;
     else if (strcmp (o->name, "length") == 0)
       *length = 1;
     else if (strcmp (o->name, "skip") == 0)
       *skip = 1;
-    else if (strcmp (o->name, "nested_ptr") == 0)
-      *nested_ptr = ((const struct nested_ptr_data *) o->info)->type;
+    else if (strcmp (o->name, "nested_ptr") == 0
+            && o->kind == OPTION_NESTED)
+      *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
 }
 
-/* Set the gc_used field of T to LEVEL, and handle the types it references.  */
+
+/* Set the gc_used field of T to LEVEL, and handle the types it references.
+
+   If ALLOWED_UNDEFINED_TYPES is true, types of kind TYPE_UNDEFINED
+   are set to GC_UNUSED.  Otherwise, an error is emitted for
+   TYPE_UNDEFINED types.  This is used to support user-defined
+   template types with non-type arguments.
+
+   For instance, when we parse a template type with enum arguments
+   (e.g. MyType<AnotherType, EnumValue>), the parser created two
+   artificial fields for 'MyType', one for 'AnotherType', the other
+   one for 'EnumValue'.
+
+   At the time that we parse this type we don't know that 'EnumValue'
+   is really an enum value, so the parser creates a TYPE_UNDEFINED
+   type for it.  Since 'EnumValue' is never resolved to a known
+   structure, it will stay with TYPE_UNDEFINED.
+
+   Since 'MyType' is a TYPE_USER_STRUCT, we can simply ignore
+   'EnumValue'.  Generating marking code for it would cause
+   compilation failures since the marking routines assumes that
+   'EnumValue' is a type.  */
 
 static void
-set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
+set_gc_used_type (type_p t, enum gc_used_enum level,
+                 bool allow_undefined_types)
 {
   if (t->gc_used >= level)
     return;
@@ -1388,69 +1515,67 @@ set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
     {
     case TYPE_STRUCT:
     case TYPE_UNION:
+    case TYPE_USER_STRUCT:
       {
        pair_p f;
        int dummy;
        type_p dummy2;
+       bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
 
-       process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
+       process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
                            &dummy2);
 
-       for (f = t->u.s.fields; f; f = f->next)
+       if (t->u.s.base_class)
+         set_gc_used_type (t->u.s.base_class, level, allow_undefined_types);
+       /* Anything pointing to a base class might actually be pointing
+          to a subclass.  */
+       for (type_p subclass = t->u.s.first_subclass; subclass;
+            subclass = subclass->u.s.next_sibling_class)
+         set_gc_used_type (subclass, level, allow_undefined_types);
+
+       FOR_ALL_INHERITED_FIELDS(t, f)
          {
            int maybe_undef = 0;
-           int pass_param = 0;
            int length = 0;
            int skip = 0;
            type_p nested_ptr = NULL;
-           process_gc_options (f->opt, level, &maybe_undef, &pass_param,
-                               &length, &skip, &nested_ptr);
+           process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
+                               &nested_ptr);
 
            if (nested_ptr && f->type->kind == TYPE_POINTER)
-             set_gc_used_type (nested_ptr, GC_POINTED_TO,
-                               pass_param ? param : NULL);
+             set_gc_used_type (nested_ptr, GC_POINTED_TO);
            else if (length && f->type->kind == TYPE_POINTER)
-             set_gc_used_type (f->type->u.p, GC_USED, NULL);
+             set_gc_used_type (f->type->u.p, GC_USED);
            else if (maybe_undef && f->type->kind == TYPE_POINTER)
-             set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO, NULL);
-           else if (pass_param && f->type->kind == TYPE_POINTER && param)
-             set_gc_used_type (find_param_structure (f->type->u.p, param),
-                               GC_POINTED_TO, NULL);
+             set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
            else if (skip)
              ;                 /* target type is not used through this field */
            else
-             set_gc_used_type (f->type, GC_USED, pass_param ? param : NULL);
+             set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
          }
        break;
       }
 
+    case TYPE_UNDEFINED:
+      if (level > GC_UNUSED)
+       {
+         if (!allow_undefined_types)
+           error_at_line (&t->u.s.line, "undefined type `%s'", t->u.s.tag);
+         t->gc_used = GC_UNUSED;
+       }
+      break;
+
     case TYPE_POINTER:
-      set_gc_used_type (t->u.p, GC_POINTED_TO, NULL);
+      set_gc_used_type (t->u.p, GC_POINTED_TO);
       break;
 
     case TYPE_ARRAY:
-      set_gc_used_type (t->u.a.p, GC_USED, param);
+      set_gc_used_type (t->u.a.p, GC_USED);
       break;
 
     case TYPE_LANG_STRUCT:
       for (t = t->u.s.lang_struct; t; t = t->next)
-       set_gc_used_type (t, level, param);
-      break;
-
-    case TYPE_PARAM_STRUCT:
-      {
-       int i;
-       for (i = 0; i < NUM_PARAM; i++)
-         if (t->u.param_struct.param[i] != 0)
-           set_gc_used_type (t->u.param_struct.param[i], GC_USED, NULL);
-      }
-      if (t->u.param_struct.stru->gc_used == GC_POINTED_TO)
-       level = GC_POINTED_TO;
-      else
-       level = GC_USED;
-      t->u.param_struct.stru->gc_used = GC_UNUSED;
-      set_gc_used_type (t->u.param_struct.stru, level,
-                       t->u.param_struct.param);
+       set_gc_used_type (t, level);
       break;
 
     default:
@@ -1467,7 +1592,7 @@ set_gc_used (pair_p variables)
   pair_p p;
   for (p = variables; p; p = p->next)
     {
-      set_gc_used_type (p->type, GC_USED, NULL);
+      set_gc_used_type (p->type, GC_USED);
       nbvars++;
     };
   if (verbosity_level >= 2)
@@ -1487,7 +1612,7 @@ static outf_p
 create_file (const char *name, const char *oname)
 {
   static const char *const hdr[] = {
-    "   Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc.\n",
+    "   Copyright (C) 2004-2015 Free Software Foundation, Inc.\n",
     "\n",
     "This file is part of GCC.\n",
     "\n",
@@ -1586,14 +1711,30 @@ open_base_files (void)
   {
     /* The order of files here matters very much.  */
     static const char *const ifiles[] = {
-      "config.h", "system.h", "coretypes.h", "tm.h",
+      "config.h", "system.h", "coretypes.h", "tm.h", "insn-codes.h",
       "hashtab.h", "splay-tree.h", "obstack.h", "bitmap.h", "input.h",
-      "tree.h", "rtl.h", "function.h", "insn-config.h", "expr.h",
-      "hard-reg-set.h", "basic-block.h", "cselib.h", "insn-addr.h",
-      "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h",
-      "tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h",
-      "cfglayout.h", "except.h", "output.h", "gimple.h", "cfgloop.h",
-      "target.h", "ipa-prop.h", "lto-streamer.h", "target-globals.h", NULL
+      "hash-set.h", "machmode.h", "vec.h", "double-int.h", "input.h",
+      "alias.h", "symtab.h", "options.h", 
+      "wide-int.h", "inchash.h",
+      "tree.h", "fold-const.h", "rtl.h",
+      "machmode.h", "tm.h", "hard-reg-set.h", "input.h", "predict.h",
+      "function.h", "insn-config.h", "flags.h", "statistics.h",
+      "real.h", "fixed-value.h", "tree.h", "expmed.h", "dojump.h",
+      "explow.h", "calls.h", "emit-rtl.h", "varasm.h", "stmt.h",
+      "expr.h", "alloc-pool.h",
+      "basic-block.h", "cselib.h", "insn-addr.h",
+      "optabs.h", "libfuncs.h", "debug.h", "ggc.h", 
+      "ggc.h", "dominance.h", "cfg.h", "basic-block.h",
+      "tree-ssa-alias.h", "internal-fn.h", "gimple-fold.h", "tree-eh.h",
+      "gimple-expr.h", "is-a.h",
+      "gimple.h", "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h",
+      "tree-phinodes.h", "ssa-iterators.h", "stringpool.h", "tree-ssanames.h",
+      "tree-ssa-loop.h", "tree-ssa-loop-ivopts.h", "tree-ssa-loop-manip.h",
+      "tree-ssa-loop-niter.h", "tree-into-ssa.h", "tree-dfa.h", 
+      "tree-ssa.h", "reload.h", "cpp-id-data.h", "tree-chrec.h",
+      "except.h", "output.h",  "cfgloop.h", "target.h", "lto-streamer.h",
+      "target-globals.h", "ipa-ref.h", "cgraph.h", "symbol-summary.h",
+      "ipa-prop.h", "ipa-inline.h", "dwarf2out.h", "omp-low.h", NULL
     };
     const char *const *ifp;
     outf_p gtype_desc_c;
@@ -1605,6 +1746,13 @@ open_base_files (void)
     /* Make sure we handle "cfun" specially.  */
     oprintf (gtype_desc_c, "\n/* See definition in function.h.  */\n");
     oprintf (gtype_desc_c, "#undef cfun\n");
+
+    oprintf (gtype_desc_c,
+            "\n"
+            "/* Types with a \"gcc::\" namespace have it stripped\n"
+            "   during gengtype parsing.  Provide a \"using\" directive\n"
+            "   to ensure that the fully-qualified types are found.  */\n"
+            "using namespace gcc;\n");
   }
 }
 
@@ -1614,10 +1762,7 @@ open_base_files (void)
 static const char *
 get_file_realbasename (const input_file *inpf)
 {
-  const char *f = get_input_file_name (inpf);
-  const char *lastslash = strrchr (f, '/');
-
-  return (lastslash != NULL) ? lastslash + 1 : f;
+  return lbasename (get_input_file_name (inpf));
 }
 
 /* For INPF a filename, return the relative path to INPF from
@@ -1802,6 +1947,12 @@ static outf_p source_dot_c_frul (input_file*, char**, char**);
    matters, so change with extreme care!  */
 
 struct file_rule_st files_rules[] = {
+  /* The general rule assumes that files in subdirectories belong to a
+     particular front-end, and files not in subdirectories are shared.
+     The following rules deal with exceptions - files that are in
+     subdirectories and yet are shared, and files that are top-level,
+     but are not shared.  */
+
   /* the c-family/ source directory is special.  */
   { DIR_PREFIX_REGEX "c-family/([[:alnum:]_-]*)\\.c$",
     REG_EXTENDED, NULL_REGEX,
@@ -1811,12 +1962,12 @@ struct file_rule_st files_rules[] = {
     REG_EXTENDED, NULL_REGEX,
     "gt-c-family-$3.h", "c-family/$3.h", NULL_FRULACT},
 
-  /* Both c-lang.h & c-tree.h gives gt-c-decl.h for c-decl.c !  */
-  { DIR_PREFIX_REGEX "c-lang\\.h$",
-    REG_EXTENDED, NULL_REGEX, "gt-c-decl.h", "c-decl.c", NULL_FRULACT},
+  /* Both c-lang.h & c-tree.h gives gt-c-c-decl.h for c-decl.c !  */
+  { DIR_PREFIX_REGEX "c/c-lang\\.h$",
+    REG_EXTENDED, NULL_REGEX, "gt-c-c-decl.h", "c/c-decl.c", NULL_FRULACT},
 
-  { DIR_PREFIX_REGEX "c-tree\\.h$",
-    REG_EXTENDED, NULL_REGEX, "gt-c-decl.h", "c-decl.c", NULL_FRULACT},
+  { DIR_PREFIX_REGEX "c/c-tree\\.h$",
+    REG_EXTENDED, NULL_REGEX, "gt-c-c-decl.h", "c/c-decl.c", NULL_FRULACT},
 
   /* cp/cp-tree.h gives gt-cp-tree.h for cp/tree.c !  */
   { DIR_PREFIX_REGEX "cp/cp-tree\\.h$",
@@ -1833,19 +1984,36 @@ struct file_rule_st files_rules[] = {
     REG_EXTENDED, NULL_REGEX,
     "gt-cp-name-lookup.h", "cp/name-lookup.c", NULL_FRULACT },
 
-  /* objc/objc-act.h fives gt-objc-objc-act.h for objc/objc-act.c !  */
+  /* cp/parser.h gives gt-cp-parser.h for cp/parser.c !  */
+  { DIR_PREFIX_REGEX "cp/parser\\.h$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-cp-parser.h", "cp/parser.c", NULL_FRULACT },
+
+  /* objc/objc-act.h gives gt-objc-objc-act.h for objc/objc-act.c !  */
   { DIR_PREFIX_REGEX "objc/objc-act\\.h$",
     REG_EXTENDED, NULL_REGEX,
     "gt-objc-objc-act.h", "objc/objc-act.c", NULL_FRULACT },
 
-  /* General cases.  For header *.h and source *.c files, we need
-   * special actions to handle the language.  */
+  /* objc/objc-map.h gives gt-objc-objc-map.h for objc/objc-map.c !  */
+  { DIR_PREFIX_REGEX "objc/objc-map\\.h$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-objc-objc-map.h", "objc/objc-map.c", NULL_FRULACT },
+
+  /* General cases.  For header *.h and source *.c or *.cc files, we
+   * need special actions to handle the language.  */
 
   /* Source *.c files are using get_file_gtfilename to compute their
      output_name and get_file_basename to compute their for_name
-     thru the source_dot_c_frul action.  */
+     through the source_dot_c_frul action.  */
   { DIR_PREFIX_REGEX "([[:alnum:]_-]*)\\.c$",
     REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.c", source_dot_c_frul},
+
+  /* Source *.cc files are using get_file_gtfilename to compute their
+     output_name and get_file_basename to compute their for_name
+     through the source_dot_c_frul action.  */
+  { DIR_PREFIX_REGEX "([[:alnum:]_-]*)\\.cc$",
+    REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.cc", source_dot_c_frul},
+
   /* Common header files get "gtype-desc.c" as their output_name,
    * while language specific header files are handled specially.  So
    * we need the header_dot_h_frul action.  */
@@ -1863,13 +2031,14 @@ struct file_rule_st files_rules[] = {
    "gtype-desc.c" for common headers and corresponding output
    files for language-specific header files.  */
 static outf_p
-header_dot_h_frul (input_file* inpf, char**poutname, char**pforname)
+header_dot_h_frul (input_file* inpf, char**poutname,
+                  char**pforname ATTRIBUTE_UNUSED)
 {
   const char *basename = 0;
   int lang_index = 0;
-  const char *inpname = get_input_file_name (inpf);
   DBGPRINTF ("inpf %p inpname %s outname %s forname %s",
-            (void*) inpf, inpname, *poutname, *pforname);
+            (void*) inpf, get_input_file_name (inpf),
+            *poutname, *pforname);
   basename = get_file_basename (inpf);
   lang_index = get_prefix_langdir_index (basename);
   DBGPRINTF ("basename %s lang_index %d", basename, lang_index);
@@ -1891,7 +2060,8 @@ header_dot_h_frul (input_file* inpf, char**poutname, char**pforname)
         get_output_file_with_visibility will find its outf_p.  */
       free (*poutname);
       *poutname = xstrdup ("gtype-desc.c");
-      DBGPRINTF ("special 'gtype-desc.c' for inpname %s", inpname);
+      DBGPRINTF ("special 'gtype-desc.c' for inpname %s",
+                get_input_file_name (inpf));
       return NULL;
     }
 }
@@ -1907,9 +2077,9 @@ source_dot_c_frul (input_file* inpf, char**poutname, char**pforname)
 {
   char *newbasename = CONST_CAST (char*, get_file_basename (inpf));
   char *newoutname = CONST_CAST (char*, get_file_gtfilename (inpf));
-  const char *inpname = get_input_file_name (inpf);
   DBGPRINTF ("inpf %p inpname %s original outname %s forname %s",
-            (void*) inpf, inpname, *poutname, *pforname);
+            (void*) inpf, get_input_file_name (inpf),
+            *poutname, *pforname);
   DBGPRINTF ("newoutname %s", newoutname);
   DBGPRINTF ("newbasename %s", newbasename);
   free (*poutname);
@@ -1956,7 +2126,7 @@ matching_file_name_substitute (const char *filnam, regmatch_t pmatch[10],
        else
          {
            /* This can happen only when files_rules is buggy! */
-           gcc_unreachable();
+           gcc_unreachable ();
          }
        /* Always skip the character after the dollar.  */
        pt++;
@@ -1967,7 +2137,7 @@ matching_file_name_substitute (const char *filnam, regmatch_t pmatch[10],
   obstack_1grow (&str_obstack, '\0');
   rawstr = XOBFINISH (&str_obstack, char *);
   str = xstrdup (rawstr);
-  obstack_free (&str_obstack, rawstr);
+  obstack_free (&str_obstack, NULL);
   DBGPRINTF ("matched replacement %s", str);
   rawstr = NULL;
   return str;
@@ -1976,7 +2146,7 @@ matching_file_name_substitute (const char *filnam, regmatch_t pmatch[10],
 
 /* An output file, suitable for definitions, that can see declarations
    made in INPF and is linked into every language that uses INPF.
-   Since the the result is cached inside INPF, that argument cannot be
+   Since the result is cached inside INPF, that argument cannot be
    declared constant, but is "almost" constant. */
 
 outf_p
@@ -2017,7 +2187,7 @@ get_output_file_with_visibility (input_file *inpf)
   /* Try each rule in sequence in files_rules until one is triggered. */
   {
     int rulix = 0;
-    DBGPRINTF ("passing input file @ %p named %s thru the files_rules",
+    DBGPRINTF ("passing input file @ %p named %s through the files_rules",
               (void*) inpf, inpfname);
 
     for (; files_rules[rulix].frul_srcexpr != NULL; rulix++)
@@ -2101,15 +2271,15 @@ get_output_file_with_visibility (input_file *inpf)
   }
   if (!output_name || !for_name)
     {
-      /* This is impossible, and could only happen if the files_rules is
-        incomplete or buggy.  */
-      gcc_unreachable ();
+      /* This should not be possible, and could only happen if the
+        files_rules is incomplete or buggy.  */
+      fatal ("failed to compute output name for %s", inpfname);
     }
 
   /* Look through to see if we've ever seen this output filename
      before.  If found, cache the result in inpf.  */
   for (r = output_files; r; r = r->next)
-    if (strcmp (r->name, output_name) == 0)
+    if (filename_cmp (r->name, output_name) == 0)
       {
        inpf->inpoutf = r;
        DBGPRINTF ("found r @ %p for output_name %s for_name %s", (void*)r,
@@ -2164,6 +2334,8 @@ is_file_equal (outf_p of)
          break;
        }
     }
+  if (equal && EOF != fgetc (newfile))
+    equal = false;
   fclose (newfile);
   return equal;
 }
@@ -2179,7 +2351,6 @@ close_output_files (void)
 
   for (of = output_files; of; of = of->next)
     {
-
       if (!is_file_equal (of))
        {
          FILE *newfile = NULL;
@@ -2252,34 +2423,32 @@ struct write_types_data
   const char *reorder_note_routine;
   const char *comment;
   int skip_hooks;              /* skip hook generation if non zero */
+  enum write_types_kinds kind;
 };
 
 static void output_escaped_param (struct walk_type_data *d,
                                  const char *, const char *);
 static void output_mangled_typename (outf_p, const_type_p);
 static void walk_type (type_p t, struct walk_type_data *d);
-static void write_func_for_structure (type_p orig_s, type_p s, type_p *param,
+static void write_func_for_structure (type_p orig_s, type_p s,
                                      const struct write_types_data *wtd);
 static void write_types_process_field
   (type_p f, const struct walk_type_data *d);
 static void write_types (outf_p output_header,
                         type_p structures,
-                        type_p param_structs,
                         const struct write_types_data *wtd);
 static void write_types_local_process_field
   (type_p f, const struct walk_type_data *d);
-static void write_local_func_for_structure
-  (const_type_p orig_s, type_p s, type_p *param);
+static void write_local_func_for_structure (const_type_p orig_s, type_p s);
 static void write_local (outf_p output_header,
-                        type_p structures, type_p param_structs);
-static void write_enum_defn (type_p structures, type_p param_structs);
+                        type_p structures);
 static int contains_scalar_p (type_p t);
 static void put_mangled_filename (outf_p, const input_file *);
 static void finish_root_table (struct flist *flp, const char *pfx,
                               const char *tname, const char *lastname,
                               const char *name);
 static void write_root (outf_p, pair_p, type_p, const char *, int,
-                       struct fileloc *, const char *, bool);
+                       struct fileloc *, bool);
 static void write_array (outf_p f, pair_p v,
                         const struct write_types_data *wtd);
 static void write_roots (pair_p, bool);
@@ -2298,14 +2467,46 @@ struct walk_type_data
   int counter;
   const struct fileloc *line;
   lang_bitmap bitmap;
-  type_p *param;
   int used_length;
   type_p orig_s;
   const char *reorder_fn;
   bool needs_cast_p;
   bool fn_wants_lvalue;
+  bool in_record_p;
+  int loopcounter;
+  bool in_ptr_field;
+  bool have_this_obj;
 };
 
+
+/* Given a string TYPE_NAME, representing a C++ typename, return a valid
+   pre-processor identifier to use in a #define directive.  This replaces
+   special characters used in C++ identifiers like '>', '<' and ':' with
+   '_'.
+
+   If no C++ special characters are found in TYPE_NAME, return
+   TYPE_NAME.  Otherwise, return a copy of TYPE_NAME with the special
+   characters replaced with '_'.  In this case, the caller is
+   responsible for freeing the allocated string.  */
+
+static const char *
+filter_type_name (const char *type_name)
+{
+  if (strchr (type_name, '<') || strchr (type_name, ':'))
+    {
+      size_t i;
+      char *s = xstrdup (type_name);
+      for (i = 0; i < strlen (s); i++)
+       if (s[i] == '<' || s[i] == '>' || s[i] == ':' || s[i] == ','
+           || s[i] == '*')
+         s[i] = '_';
+      return s;
+    }
+  else
+    return type_name;
+}
+
+
 /* Print a mangled name representing T to OF.  */
 
 static void
@@ -2316,6 +2517,10 @@ output_mangled_typename (outf_p of, const_type_p t)
   else
     switch (t->kind)
       {
+      case TYPE_NONE:
+      case TYPE_UNDEFINED:
+       gcc_unreachable ();
+       break;
       case TYPE_POINTER:
        oprintf (of, "P");
        output_mangled_typename (of, t->u.p);
@@ -2329,16 +2534,17 @@ output_mangled_typename (outf_p of, const_type_p t)
       case TYPE_STRUCT:
       case TYPE_UNION:
       case TYPE_LANG_STRUCT:
-       oprintf (of, "%lu%s", (unsigned long) strlen (t->u.s.tag),
-                t->u.s.tag);
-       break;
-      case TYPE_PARAM_STRUCT:
+      case TYPE_USER_STRUCT:
        {
-         int i;
-         for (i = 0; i < NUM_PARAM; i++)
-           if (t->u.param_struct.param[i] != NULL)
-             output_mangled_typename (of, t->u.param_struct.param[i]);
-         output_mangled_typename (of, t->u.param_struct.stru);
+         /* For references to classes within an inheritance hierarchy,
+            only ever reference the ultimate base class, since only
+            it will have gt_ functions.  */
+         t = get_ultimate_base_class (t);
+         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);
+         if (id_for_tag != t->u.s.tag)
+           free (CONST_CAST (char *, id_for_tag));
        }
        break;
       case TYPE_ARRAY:
@@ -2387,6 +2593,76 @@ 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;
+}
+
+/* Machinery for avoiding duplicate tags within switch statements.  */
+struct seen_tag
+{
+  const char *tag;
+  struct seen_tag *next;
+};
+
+int
+already_seen_tag (struct seen_tag *seen_tags, const char *tag)
+{
+  /* Linear search, so O(n^2), but n is currently small.  */
+  while (seen_tags)
+    {
+      if (!strcmp (seen_tags->tag, tag))
+       return 1;
+      seen_tags = seen_tags->next;
+    }
+  /* Not yet seen this tag. */
+  return 0;
+}
+
+void
+mark_tag_as_seen (struct seen_tag **seen_tags, const char *tag)
+{
+  /* Add to front of linked list. */
+  struct seen_tag *new_node = XCNEW (struct seen_tag);
+  new_node->tag = tag;
+  new_node->next = *seen_tags;
+  *seen_tags = new_node;
+}
+
+static void
+walk_subclasses (type_p base, struct walk_type_data *d,
+                struct seen_tag **seen_tags)
+{
+  for (type_p sub = base->u.s.first_subclass; sub != NULL;
+       sub = sub->u.s.next_sibling_class)
+    {
+      const char *type_tag = get_string_option (sub->u.s.opt, "tag");
+      if (type_tag && !already_seen_tag (*seen_tags, type_tag))
+       {
+         mark_tag_as_seen (seen_tags, type_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, seen_tags);
+    }
+}
+
 /* 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
    the point that D->PROCESS_FIELD is called) to the appropriate
@@ -2395,52 +2671,44 @@ output_escaped_param (struct walk_type_data *d, const char *param,
    containing the current object, D->OPT is a list of options to
    apply, D->INDENT is the current indentation level, D->LINE is used
    to print error messages, D->BITMAP indicates which languages to
-   print the structure for, and D->PARAM is the current parameter
-   (from an enclosing param_is option).  */
+   print the structure for.  */
 
 static void
 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;
+  int atomic_p = 0;
   options_p oo;
   const struct nested_ptr_data *nested_ptr_d = NULL;
 
   d->needs_cast_p = false;
   for (oo = d->opt; oo; oo = oo->next)
-    if (strcmp (oo->name, "length") == 0)
-      length = oo->info;
+    if (strcmp (oo->name, "length") == 0 && oo->kind == OPTION_STRING)
+      length = oo->info.string;
     else if (strcmp (oo->name, "maybe_undef") == 0)
       maybe_undef_p = 1;
-    else if (strncmp (oo->name, "use_param", 9) == 0
-            && (oo->name[9] == '\0' || ISDIGIT (oo->name[9])))
-      use_param_num = oo->name[9] == '\0' ? 0 : oo->name[9] - '0';
-    else if (strcmp (oo->name, "use_params") == 0)
-      use_params_p = 1;
-    else if (strcmp (oo->name, "desc") == 0)
-      desc = oo->info;
+    else if (strcmp (oo->name, "desc") == 0 && oo->kind == OPTION_STRING)
+      desc = oo->info.string;
     else if (strcmp (oo->name, "mark_hook") == 0)
       ;
-    else if (strcmp (oo->name, "nested_ptr") == 0)
-      nested_ptr_d = (const struct nested_ptr_data *) oo->info;
+    else if (strcmp (oo->name, "nested_ptr") == 0 
+            && oo->kind == OPTION_NESTED)
+      nested_ptr_d = (const struct nested_ptr_data *) oo->info.nested;
     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)
       ;
+    else if (strcmp (oo->name, "atomic") == 0)
+      atomic_p = 1;
     else if (strcmp (oo->name, "default") == 0)
       ;
-    else if (strcmp (oo->name, "param_is") == 0)
-      ;
-    else if (strncmp (oo->name, "param", 5) == 0
-            && ISDIGIT (oo->name[5]) && strcmp (oo->name + 6, "_is") == 0)
-      ;
     else if (strcmp (oo->name, "chain_next") == 0)
       ;
     else if (strcmp (oo->name, "chain_prev") == 0)
@@ -2451,47 +2719,16 @@ walk_type (type_p t, struct walk_type_data *d)
       ;
     else if (strcmp (oo->name, "variable_size") == 0)
       ;
+    else if (strcmp (oo->name, "for_user") == 0)
+      ;
     else
       error_at_line (d->line, "unknown option `%s'\n", oo->name);
 
   if (d->used_length)
     length = NULL;
 
-  if (use_params_p)
-    {
-      int pointer_p = t->kind == TYPE_POINTER;
-
-      if (pointer_p)
-       t = t->u.p;
-      if (!UNION_OR_STRUCT_P (t))
-       error_at_line (d->line, "`use_params' option on unimplemented type");
-      else
-       t = find_param_structure (t, d->param);
-      if (pointer_p)
-       t = create_pointer (t);
-    }
-
-  if (use_param_num != -1)
-    {
-      if (d->param != NULL && d->param[use_param_num] != NULL)
-       {
-         type_p nt = d->param[use_param_num];
-
-         if (t->kind == TYPE_ARRAY)
-           nt = create_array (nt, t->u.a.len);
-         else if (length != NULL && t->kind == TYPE_POINTER)
-           nt = create_pointer (nt);
-         d->needs_cast_p = (t->kind != TYPE_POINTER
-                            && (nt->kind == TYPE_POINTER
-                                || nt->kind == TYPE_STRING));
-         t = nt;
-       }
-      else
-       error_at_line (d->line, "no parameter defined for `%s'", d->val);
-    }
-
   if (maybe_undef_p
-      && (t->kind != TYPE_POINTER || !UNION_OR_STRUCT_P (t->u.p)))
+      && (t->kind != TYPE_POINTER || !union_or_struct_p (t->u.p)))
     {
       error_at_line (d->line,
                     "field `%s' has invalid option `maybe_undef_p'\n",
@@ -2499,25 +2736,50 @@ walk_type (type_p t, struct walk_type_data *d)
       return;
     }
 
-  switch (t->kind)
+  if (atomic_p && (t->kind != TYPE_POINTER) && (t->kind != TYPE_STRING))
     {
-    case TYPE_SCALAR:
+      error_at_line (d->line, "field `%s' has invalid option `atomic'\n", d->val);
+      return;
+    }
+
+  switch (t->kind)
+    {
+    case TYPE_SCALAR:
     case TYPE_STRING:
       d->process_field (t, d);
       break;
 
     case TYPE_POINTER:
       {
+       d->in_ptr_field = true;
        if (maybe_undef_p && t->u.p->u.s.line.file == NULL)
          {
            oprintf (d->of, "%*sgcc_assert (!%s);\n", d->indent, "", d->val);
            break;
          }
 
+       /* If a pointer type is marked as "atomic", we process the
+          field itself, but we don't walk the data that they point to.
+
+          There are two main cases where we walk types: to mark
+          pointers that are reachable, and to relocate pointers when
+          writing a PCH file.  In both cases, an atomic pointer is
+          itself marked or relocated, but the memory that it points
+          to is left untouched.  In the case of PCH, that memory will
+          be read/written unchanged to the PCH file.  */
+       if (atomic_p)
+         {
+           oprintf (d->of, "%*sif (%s != NULL) {\n", d->indent, "", d->val);
+           d->indent += 2;
+           d->process_field (t, d);
+           d->indent -= 2;
+           oprintf (d->of, "%*s}\n", d->indent, "");
+           break;
+         }
+
        if (!length)
          {
-           if (!UNION_OR_STRUCT_P (t->u.p)
-               && t->u.p->kind != TYPE_PARAM_STRUCT)
+           if (!union_or_struct_p (t->u.p))
              {
                error_at_line (d->line,
                               "field `%s' is pointer to unimplemented type",
@@ -2529,7 +2791,7 @@ walk_type (type_p t, struct walk_type_data *d)
              {
                const char *oldprevval2 = d->prev_val[2];
 
-               if (!UNION_OR_STRUCT_P (nested_ptr_d->type))
+               if (!union_or_struct_p (nested_ptr_d->type))
                  {
                    error_at_line (d->line,
                                   "field `%s' has invalid "
@@ -2573,7 +2835,7 @@ walk_type (type_p t, struct walk_type_data *d)
          }
        else
          {
-           int loopcounter = d->counter++;
+           int loopcounter = d->loopcounter;
            const char *oldval = d->val;
            const char *oldprevval3 = d->prev_val[3];
            char *newval;
@@ -2583,7 +2845,13 @@ walk_type (type_p t, struct walk_type_data *d)
            oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter);
            oprintf (d->of, "%*sfor (i%d = 0; i%d != (size_t)(", d->indent,
                     "", loopcounter, loopcounter);
-           output_escaped_param (d, length, "length");
+           if (!d->in_record_p)
+             output_escaped_param (d, length, "length");
+           else
+             oprintf (d->of, "l%d", loopcounter);
+           if (d->have_this_obj)
+             /* Try to unswitch loops (see PR53880).  */
+             oprintf (d->of, ") && ((void *)%s == this_obj", oldval);
            oprintf (d->of, "); i%d++) {\n", loopcounter);
            d->indent += 2;
            d->val = newval = xasprintf ("%s[i%d]", oldval, loopcounter);
@@ -2600,12 +2868,13 @@ walk_type (type_p t, struct walk_type_data *d)
            d->indent -= 2;
            oprintf (d->of, "%*s}\n", d->indent, "");
          }
+       d->in_ptr_field = false;
       }
       break;
 
     case TYPE_ARRAY:
       {
-       int loopcounter = d->counter++;
+       int loopcounter;
        const char *oldval = d->val;
        char *newval;
 
@@ -2614,6 +2883,11 @@ walk_type (type_p t, struct walk_type_data *d)
        if (t->u.a.p->kind == TYPE_SCALAR)
          break;
 
+       if (length)
+         loopcounter = d->loopcounter;
+       else
+         loopcounter = d->counter++;
+
        /* When walking an array, compute the length and store it in a
           local variable before walking the array elements, instead of
           recomputing the length expression each time through the loop.
@@ -2624,13 +2898,16 @@ walk_type (type_p t, struct walk_type_data *d)
        oprintf (d->of, "%*s{\n", d->indent, "");
        d->indent += 2;
        oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter);
-       oprintf (d->of, "%*ssize_t l%d = (size_t)(",
-                d->indent, "", loopcounter);
-       if (length)
-         output_escaped_param (d, length, "length");
-       else
-         oprintf (d->of, "%s", t->u.a.len);
-       oprintf (d->of, ");\n");
+       if (!d->in_record_p || !length)
+         {
+           oprintf (d->of, "%*ssize_t l%d = (size_t)(",
+                    d->indent, "", loopcounter);
+           if (length)
+             output_escaped_param (d, length, "length");
+           else
+             oprintf (d->of, "%s", t->u.a.len);
+           oprintf (d->of, ");\n");
+         }
 
        oprintf (d->of, "%*sfor (i%d = 0; i%d != l%d; i%d++) {\n",
                 d->indent, "",
@@ -2656,9 +2933,13 @@ walk_type (type_p t, struct walk_type_data *d)
        const char *oldval = d->val;
        const char *oldprevval1 = d->prev_val[1];
        const char *oldprevval2 = d->prev_val[2];
+       const char *struct_mark_hook = NULL;
        const int union_p = t->kind == TYPE_UNION;
        int seen_default_p = 0;
        options_p o;
+       int lengths_seen = 0;
+       int endcounter;
+       bool any_length_seen = false;
 
        if (!t->u.s.line.file)
          error_at_line (d->line, "incomplete structure `%s'", t->u.s.tag);
@@ -2673,8 +2954,16 @@ walk_type (type_p t, struct walk_type_data *d)
 
        /* Some things may also be defined in the structure's options.  */
        for (o = t->u.s.opt; o; o = o->next)
-         if (!desc && strcmp (o->name, "desc") == 0)
-           desc = o->info;
+         if (!desc && strcmp (o->name, "desc") == 0
+             && o->kind == OPTION_STRING)
+           desc = o->info.string;
+         else if (!struct_mark_hook && strcmp (o->name, "mark_hook") == 0
+                  && o->kind == OPTION_STRING)
+           struct_mark_hook = o->info.string;
+
+       if (struct_mark_hook)
+         oprintf (d->of, "%*s%s (&%s);\n",
+                  d->indent, "", struct_mark_hook, oldval);
 
        d->prev_val[2] = oldval;
        d->prev_val[1] = oldprevval2;
@@ -2687,37 +2976,103 @@ walk_type (type_p t, struct walk_type_data *d)
                               t->u.s.tag);
                desc = "1";
              }
-           oprintf (d->of, "%*sswitch (", d->indent, "");
+           oprintf (d->of, "%*sswitch ((int) (", d->indent, "");
            output_escaped_param (d, desc, "desc");
-           oprintf (d->of, ")\n");
+           oprintf (d->of, "))\n");
            d->indent += 2;
            oprintf (d->of, "%*s{\n", d->indent, "");
          }
-       for (f = t->u.s.fields; f; f = f->next)
+       else if (desc)
+         {
+           /* We have a "desc" option on a struct, signifying the
+              base class within a GC-managed inheritance hierarchy.
+              The current code specialcases the base class, then walks
+              into subclasses, recursing into this routine to handle them.
+              This organization requires the base class to have a case in
+              the switch statement, and hence a tag value is mandatory
+              for the base class.   This restriction could be removed, but
+              it would require some restructing of this code.  */
+           if (!type_tag)
+             {
+               error_at_line (d->line,
+                              "missing `tag' option for type `%s'",
+                              t->u.s.tag);
+             }
+           oprintf (d->of, "%*sswitch ((int) (", 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_ALL_INHERITED_FIELDS (t, f)
+         {
+           options_p oo;
+           int skip_p = 0;
+           const char *fieldlength = NULL;
+
+           d->reorder_fn = NULL;
+           for (oo = f->opt; oo; oo = oo->next)
+             if (strcmp (oo->name, "skip") == 0)
+               skip_p = 1;
+             else if (strcmp (oo->name, "length") == 0
+                      && oo->kind == OPTION_STRING)
+               fieldlength = oo->info.string;
+
+           if (skip_p)
+             continue;
+           if (fieldlength)
+             {
+               lengths_seen++;
+               d->counter++;
+               if (!union_p)
+                 {
+                   if (!any_length_seen)
+                     {
+                       oprintf (d->of, "%*s{\n", d->indent, "");
+                       d->indent += 2;
+                     }
+                   any_length_seen = true;
+
+                   oprintf (d->of, "%*ssize_t l%d = (size_t)(",
+                            d->indent, "", d->counter - 1);
+                   output_escaped_param (d, fieldlength, "length");
+                   oprintf (d->of, ");\n");
+                 }
+             }
+         }
+       endcounter = d->counter;
+
+       FOR_ALL_INHERITED_FIELDS (t, f)
          {
            options_p oo;
            const char *dot = ".";
            const char *tagid = NULL;
            int skip_p = 0;
            int default_p = 0;
-           int use_param_p = 0;
+           const char *fieldlength = NULL;
            char *newval;
 
            d->reorder_fn = NULL;
            for (oo = f->opt; oo; oo = oo->next)
-             if (strcmp (oo->name, "dot") == 0)
-               dot = oo->info;
-             else if (strcmp (oo->name, "tag") == 0)
-               tagid = oo->info;
+             if (strcmp (oo->name, "dot") == 0
+                 && oo->kind == OPTION_STRING)
+               dot = oo->info.string;
+             else if (strcmp (oo->name, "tag") == 0
+                      && oo->kind == OPTION_STRING)
+               tagid = oo->info.string;
              else if (strcmp (oo->name, "skip") == 0)
                skip_p = 1;
              else if (strcmp (oo->name, "default") == 0)
                default_p = 1;
-             else if (strcmp (oo->name, "reorder") == 0)
-               d->reorder_fn = oo->info;
-             else if (strncmp (oo->name, "use_param", 9) == 0
-                      && (oo->name[9] == '\0' || ISDIGIT (oo->name[9])))
-               use_param_p = 1;
+             else if (strcmp (oo->name, "reorder") == 0
+                 && oo->kind == OPTION_STRING)
+               d->reorder_fn = oo->info.string;
+             else if (strcmp (oo->name, "length") == 0
+                      && oo->kind == OPTION_STRING)
+               fieldlength = oo->info.string;
 
            if (skip_p)
              continue;
@@ -2751,15 +3106,20 @@ walk_type (type_p t, struct walk_type_data *d)
                             "field `%s' is missing `tag' or `default' option",
                             f->name);
 
+           if (fieldlength)
+             {
+               d->loopcounter = endcounter - lengths_seen--;
+             }
+
            d->line = &f->line;
            d->val = newval = xasprintf ("%s%s%s", oldval, dot, f->name);
            d->opt = f->opt;
            d->used_length = false;
+           d->in_record_p = !union_p;
 
-           if (union_p && use_param_p && d->param == NULL)
-             oprintf (d->of, "%*sgcc_unreachable ();\n", d->indent, "");
-           else
-             walk_type (f->type, d);
+           walk_type (f->type, d);
+
+           d->in_record_p = false;
 
            free (newval);
 
@@ -2780,11 +3140,42 @@ 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.  */
+           struct seen_tag *tags = NULL;
+           walk_subclasses (t, d, &tags);
+
+           /* Ensure that if someone forgets a "tag" option that we don't
+              silent fail to traverse that subclass's fields.  */
+           if (!seen_default_p)
+             {
+               oprintf (d->of, "%*s/* Unrecognized tag value.  */\n",
+                        d->indent, "");
+               oprintf (d->of, "%*sdefault: gcc_unreachable (); \n",
+                        d->indent, "");
+             }
+
+           /* End of the switch statement */
+           oprintf (d->of, "%*s}\n", d->indent, "");
+           d->indent -= 2;
+         }
+       if (any_length_seen)
+         {
+           d->indent -= 2;
+           oprintf (d->of, "%*s}\n", d->indent, "");
+         }
       }
       break;
 
@@ -2802,17 +3193,12 @@ walk_type (type_p t, struct walk_type_data *d)
       }
       break;
 
-    case TYPE_PARAM_STRUCT:
-      {
-       type_p *oldparam = d->param;
-
-       d->param = t->u.param_struct.param;
-       walk_type (t->u.param_struct.stru, d);
-       d->param = oldparam;
-      }
+    case TYPE_USER_STRUCT:
+      d->process_field (t, d);
       break;
 
-    default:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
       gcc_unreachable ();
     }
 }
@@ -2828,12 +3214,34 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
 
   switch (f->kind)
     {
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
+      gcc_unreachable ();
     case TYPE_POINTER:
       oprintf (d->of, "%*s%s (%s%s", d->indent, "",
               wtd->subfield_marker_routine, cast, d->val);
       if (wtd->param_prefix)
        {
-         oprintf (d->of, ", %s", d->prev_val[3]);
+         if (f->u.p->kind == TYPE_SCALAR)
+           /* The current type is a pointer to a scalar (so not
+              considered like a pointer to instances of user defined
+              types) and we are seeing it; it means we must be even
+              more careful about the second argument of the
+              SUBFIELD_MARKER_ROUTINE call.  That argument must
+              always be the instance of the type for which
+              write_func_for_structure was called - this really is
+              what the function SUBFIELD_MARKER_ROUTINE expects.
+              That is, it must be an instance of the ORIG_S type
+              parameter of write_func_for_structure.  The convention
+              is that that argument must be "x" in that case (as set
+              by write_func_for_structure).  The problem is, we can't
+              count on d->prev_val[3] to be always set to "x" in that
+              case.  Sometimes walk_type can set it to something else
+              (to e.g cooperate with write_array when called from
+              write_roots).  So let's set it to "x" here then.  */
+           oprintf (d->of, ", x");
+         else
+           oprintf (d->of, ", %s", d->prev_val[3]);
          if (d->orig_s)
            {
              oprintf (d->of, ", gt_%s_", wtd->param_prefix);
@@ -2841,20 +3249,6 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
            }
          else
            oprintf (d->of, ", gt_%sa_%s", wtd->param_prefix, d->prev_val[0]);
-
-         if (f->u.p->kind == TYPE_PARAM_STRUCT
-             && f->u.p->u.s.line.file != NULL)
-           {
-             oprintf (d->of, ", gt_e_");
-             output_mangled_typename (d->of, f);
-           }
-         else if (UNION_OR_STRUCT_P (f) && f->u.p->u.s.line.file != NULL)
-           {
-             oprintf (d->of, ", gt_ggc_e_");
-             output_mangled_typename (d->of, f);
-           }
-         else
-           oprintf (d->of, ", gt_types_enum_last");
        }
       oprintf (d->of, ");\n");
       if (d->reorder_fn && wtd->reorder_note_routine)
@@ -2867,76 +3261,228 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
     case TYPE_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
-    case TYPE_PARAM_STRUCT:
-      oprintf (d->of, "%*sgt_%s_", d->indent, "", wtd->prefix);
-      output_mangled_typename (d->of, f);
-      oprintf (d->of, " (%s%s);\n", cast, d->val);
-      if (d->reorder_fn && wtd->reorder_note_routine)
-       oprintf (d->of, "%*s%s (%s%s, %s%s, %s);\n", d->indent, "",
-                wtd->reorder_note_routine, cast, d->val, cast, d->val,
-                d->reorder_fn);
+    case TYPE_USER_STRUCT:
+      if (f->kind == TYPE_USER_STRUCT && !d->in_ptr_field)
+       {
+         /* If F is a user-defined type and the field is not a
+            pointer to the type, then we should not generate the
+            standard pointer-marking code.  All we need to do is call
+            the user-provided marking function to process the fields
+            of F.  */
+         oprintf (d->of, "%*sgt_%sx (&(%s));\n", d->indent, "", wtd->prefix,
+                  d->val);
+       }
+      else
+       {
+         oprintf (d->of, "%*sgt_%s_", d->indent, "", wtd->prefix);
+         output_mangled_typename (d->of, f);
+         oprintf (d->of, " (%s%s);\n", cast, d->val);
+         if (d->reorder_fn && wtd->reorder_note_routine)
+           oprintf (d->of, "%*s%s (%s%s, %s%s, %s);\n", d->indent, "",
+                    wtd->reorder_note_routine, cast, d->val, cast, d->val,
+                    d->reorder_fn);
+       }
       break;
 
     case TYPE_SCALAR:
       break;
 
-    default:
+    case TYPE_ARRAY:
       gcc_unreachable ();
     }
 }
 
-/* A subroutine of write_func_for_structure.  Write the enum tag for S.  */
+/* Return an output file that is suitable for definitions which can
+   reference struct S */
+
+static outf_p
+get_output_file_for_structure (const_type_p s)
+{
+  const input_file *fn;
+
+  gcc_assert (union_or_struct_p (s));
+  fn = s->u.s.line.file;
+
+  /* The call to get_output_file_with_visibility may update fn by
+     caching its result inside, so we need the CONST_CAST.  */
+  return get_output_file_with_visibility (CONST_CAST (input_file*, fn));
+}
+
+
+/* Returns the specifier keyword for a string or union type S, empty string
+   otherwise.  */
+
+static const char *
+get_type_specifier (const type_p s)
+{
+  if (s->kind == TYPE_STRUCT)
+    return "struct ";
+  else if (s->kind == TYPE_LANG_STRUCT)
+    return get_type_specifier (s->u.s.lang_struct);
+  else if (s->kind == TYPE_UNION)
+    return "union ";
+  return "";
+}
+
+
+/* Emits a declaration for type TY (assumed to be a union or a
+   structure) on stream OUT.  */
 
 static void
-output_type_enum (outf_p of, type_p s)
+write_type_decl (outf_p out, type_p ty)
 {
-  if (s->kind == TYPE_PARAM_STRUCT && s->u.param_struct.line.file != NULL)
+  if (union_or_struct_p (ty))
+    oprintf (out, "%s%s", get_type_specifier (ty), ty->u.s.tag);
+  else if (ty->kind == TYPE_SCALAR)
+    {
+      if (ty->u.scalar_is_char)
+       oprintf (out, "const char");
+      else
+       oprintf (out, "void");
+    }
+  else if (ty->kind == TYPE_POINTER)
+    {
+      write_type_decl (out, ty->u.p);
+      oprintf (out, " *");
+    }
+  else if (ty->kind == TYPE_ARRAY)
     {
-      oprintf (of, ", gt_e_");
-      output_mangled_typename (of, s);
+      write_type_decl (out, ty->u.a.p);
+      oprintf (out, " *");
     }
-  else if (UNION_OR_STRUCT_P (s) && s->u.s.line.file != NULL)
+  else if (ty->kind == TYPE_STRING)
     {
-      oprintf (of, ", gt_ggc_e_");
-      output_mangled_typename (of, s);
+      oprintf (out, "const char *");
     }
   else
-    oprintf (of, ", gt_types_enum_last");
+    gcc_unreachable ();
 }
 
-/* Return an output file that is suitable for definitions which can
-   reference struct S */
 
-static outf_p
-get_output_file_for_structure (const_type_p s, type_p *param)
+/* Write on OF the name of the marker function for structure S. PREFIX
+   is the prefix to use (to distinguish ggc from pch markers).  */
+
+static void
+write_marker_function_name (outf_p of, type_p s, const char *prefix)
 {
-  const input_file *fn;
-  int i;
+  if (union_or_struct_p (s))
+    {
+      const char *id_for_tag = filter_type_name (s->u.s.tag);
+      oprintf (of, "gt_%sx_%s", prefix, id_for_tag);
+      if (id_for_tag != s->u.s.tag)
+       free (CONST_CAST (char *, id_for_tag));
+    }
+  else
+    gcc_unreachable ();
+}
 
-  gcc_assert (UNION_OR_STRUCT_P (s));
-  fn = s->u.s.line.file;
+/* Write on OF a user-callable routine to act as an entry point for
+   the marking routine for S, generated by write_func_for_structure.
+   WTD distinguishes between ggc and pch markers.  */
 
-  /* This is a hack, and not the good kind either.  */
-  for (i = NUM_PARAM - 1; i >= 0; i--)
-    if (param && param[i] && param[i]->kind == TYPE_POINTER
-       && UNION_OR_STRUCT_P (param[i]->u.p))
-      fn = param[i]->u.p->u.s.line.file;
+static void
+write_user_func_for_structure_ptr (outf_p of, type_p s, const write_types_data *wtd)
+{
+  gcc_assert (union_or_struct_p (s));
 
-  /* The call to get_output_file_with_visibility may update fn by
-     caching its result inside, so we need the CONST_CAST.  */
-  return get_output_file_with_visibility (CONST_CAST (input_file*, fn));
+  type_p alias_of = NULL;
+  for (options_p opt = s->u.s.opt; opt; opt = opt->next)
+    if (strcmp (opt->name, "ptr_alias") == 0)
+      {
+       /* ALIAS_OF is set if ORIG_S is marked "ptr_alias". This means that
+          we do not generate marking code for ORIG_S here. Instead, a
+          forwarder #define in gtype-desc.h will cause every call to its
+          marker to call the target of this alias.
+
+          However, we still want to create a user entry code for the
+          aliased type. So, if ALIAS_OF is set, we only generate the
+          user-callable marker function.  */
+       alias_of = opt->info.type;
+       break;
+      }
+
+  DBGPRINTF ("write_user_func_for_structure_ptr: %s %s", s->u.s.tag,
+            wtd->prefix);
+
+  /* Only write the function once. */
+  if (s->u.s.wrote_user_func_for_ptr[wtd->kind])
+    return;
+  s->u.s.wrote_user_func_for_ptr[wtd->kind] = true;
+
+  oprintf (of, "\nvoid\n");
+  oprintf (of, "gt_%sx (", wtd->prefix);
+  write_type_decl (of, s);
+  oprintf (of, " *& x)\n");
+  oprintf (of, "{\n");
+  oprintf (of, "  if (x)\n    ");
+  write_marker_function_name (of,
+                             alias_of ? alias_of : get_ultimate_base_class (s),
+                             wtd->prefix);
+  oprintf (of, " ((void *) x);\n");
+  oprintf (of, "}\n");
 }
 
-/* For S, a structure that's part of ORIG_S, and using parameters
-   PARAM, write out a routine that:
+
+/* Write a function to mark all the fields of type S on OF.  PREFIX
+   and D are as in write_user_marking_functions.  */
+
+static void
+write_user_func_for_structure_body (type_p s, const char *prefix,
+                                   struct walk_type_data *d)
+{
+  oprintf (d->of, "\nvoid\n");
+  oprintf (d->of, "gt_%sx (", prefix);
+  write_type_decl (d->of, s);
+  oprintf (d->of, "& x_r ATTRIBUTE_UNUSED)\n");
+  oprintf (d->of, "{\n");
+  oprintf (d->of, "  ");
+  write_type_decl (d->of, s);
+  oprintf (d->of, " * ATTRIBUTE_UNUSED x = &x_r;\n");
+  d->val = "(*x)";
+  d->indent = 2;
+  walk_type (s, d);
+  oprintf (d->of, "}\n");
+}
+
+/* Emit the user-callable functions needed to mark all the types used
+   by the user structure S.  PREFIX is the prefix to use to
+   distinguish ggc and pch markers.  D contains data needed to pass to
+   walk_type when traversing the fields of a type.
+
+   For every type T referenced by S, two routines are generated: one
+   that takes 'T *', marks the pointer and calls the second routine,
+   which just marks the fields of T.  */
+
+static void
+write_user_marking_functions (type_p s,
+                             const write_types_data *w,
+                             struct walk_type_data *d)
+{
+  gcc_assert (s->kind == TYPE_USER_STRUCT);
+
+  for (pair_p fld = s->u.s.fields; fld; fld = fld->next)
+    {
+      type_p fld_type = fld->type;
+      if (fld_type->kind == TYPE_POINTER)
+       {
+         type_p pointed_to_type = fld_type->u.p;
+         if (union_or_struct_p (pointed_to_type))
+           write_user_func_for_structure_ptr (d->of, pointed_to_type, w);
+       }
+      else if (union_or_struct_p (fld_type))
+       write_user_func_for_structure_body (fld_type, w->prefix, d);
+    }
+}
+
+
+/* For S, a structure that's part of ORIG_S write out a routine that:
    - Takes a parameter, a void * but actually of type *S
    - If SEEN_ROUTINE returns nonzero, calls write_types_process_field on each
    field of S or its substructures and (in some cases) things
-   that are pointed to by S.
-*/
+   that are pointed to by S.  */
 
 static void
-write_func_for_structure (type_p orig_s, type_p s, type_p *param,
+write_func_for_structure (type_p orig_s, type_p s,
                          const struct write_types_data *wtd)
 {
   const char *chain_next = NULL;
@@ -2946,19 +3492,43 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
   options_p opt;
   struct walk_type_data d;
 
+  if (s->u.s.base_class)
+    {
+      /* Verify that the base class has a "desc", since otherwise
+        the traversal hooks there won't attempt to visit fields of
+        subclasses such as this one.  */
+      const_type_p ubc = get_ultimate_base_class (s);
+      if ((!opts_have (ubc->u.s.opt, "user")
+          && !opts_have (ubc->u.s.opt, "desc")))
+       error_at_line (&s->u.s.line,
+                      ("'%s' is a subclass of non-GTY(user) GTY class '%s'"
+                       ", but '%s' lacks a discriminator 'desc' option"),
+                      s->u.s.tag, ubc->u.s.tag, ubc->u.s.tag);
+
+      /* Don't write fns for subclasses, only for the ultimate base class
+        within an inheritance hierarchy.  */
+      return;
+    }
+
   memset (&d, 0, sizeof (d));
-  d.of = get_output_file_for_structure (s, param);
+  d.of = get_output_file_for_structure (s);
 
+  bool for_user = false;
   for (opt = s->u.s.opt; opt; opt = opt->next)
-    if (strcmp (opt->name, "chain_next") == 0)
-      chain_next = opt->info;
-    else if (strcmp (opt->name, "chain_prev") == 0)
-      chain_prev = opt->info;
-    else if (strcmp (opt->name, "chain_circular") == 0)
-      chain_circular = opt->info;
-    else if (strcmp (opt->name, "mark_hook") == 0)
-      mark_hook_name = opt->info;
-
+    if (strcmp (opt->name, "chain_next") == 0
+       && opt->kind == OPTION_STRING)
+      chain_next = opt->info.string;
+    else if (strcmp (opt->name, "chain_prev") == 0
+            && opt->kind == OPTION_STRING)
+      chain_prev = opt->info.string;
+    else if (strcmp (opt->name, "chain_circular") == 0
+            && opt->kind == OPTION_STRING)
+      chain_circular = opt->info.string;
+    else if (strcmp (opt->name, "mark_hook") == 0
+            && opt->kind == OPTION_STRING)
+      mark_hook_name = opt->info.string;
+    else if (strcmp (opt->name, "for_user") == 0)
+      for_user = true;
   if (chain_prev != NULL && chain_next == NULL)
     error_at_line (&s->u.s.line, "chain_prev without chain_next");
   if (chain_circular != NULL && chain_next != NULL)
@@ -2972,30 +3542,31 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
   d.opt = s->u.s.opt;
   d.line = &s->u.s.line;
   d.bitmap = s->u.s.bitmap;
-  d.param = param;
   d.prev_val[0] = "*x";
   d.prev_val[1] = "not valid postage"; /* Guarantee an error.  */
   d.prev_val[3] = "x";
   d.val = "(*x)";
+  d.have_this_obj = false;
 
   oprintf (d.of, "\n");
   oprintf (d.of, "void\n");
-  if (param == NULL)
-    oprintf (d.of, "gt_%sx_%s", wtd->prefix, orig_s->u.s.tag);
-  else
-    {
-      oprintf (d.of, "gt_%s_", wtd->prefix);
-      output_mangled_typename (d.of, orig_s);
-    }
+  write_marker_function_name (d.of, orig_s, wtd->prefix);
   oprintf (d.of, " (void *x_p)\n");
-  oprintf (d.of, "{\n");
-  oprintf (d.of, "  %s %s * %sx = (%s %s *)x_p;\n",
-          s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
-          chain_next == NULL ? "const " : "",
-          s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+  oprintf (d.of, "{\n  ");
+  write_type_decl (d.of, s);
+  oprintf (d.of, " * %sx = (", chain_next == NULL ? "const " : "");
+  write_type_decl (d.of, s);
+  oprintf (d.of, " *)x_p;\n");
   if (chain_next != NULL)
-    oprintf (d.of, "  %s %s * xlimit = x;\n",
-            s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+    {
+      /* TYPE_USER_STRUCTs should not occur here.  These structures
+        are completely handled by user code.  */
+      gcc_assert (orig_s->kind != TYPE_USER_STRUCT);
+
+      oprintf (d.of, "  ");
+      write_type_decl (d.of, s);
+      oprintf (d.of, " * xlimit = x;\n");
+    }
   if (chain_next == NULL)
     {
       oprintf (d.of, "  if (%s (x", wtd->marker_routine);
@@ -3003,7 +3574,6 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
        {
          oprintf (d.of, ", x, gt_%s_", wtd->param_prefix);
          output_mangled_typename (d.of, orig_s);
-         output_type_enum (d.of, orig_s);
        }
       oprintf (d.of, "))\n");
     }
@@ -3017,7 +3587,6 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
        {
          oprintf (d.of, ", xlimit, gt_%s_", wtd->param_prefix);
          output_mangled_typename (d.of, orig_s);
-         output_type_enum (d.of, orig_s);
        }
       oprintf (d.of, "))\n");
       if (chain_circular != NULL)
@@ -3051,7 +3620,6 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
            {
              oprintf (d.of, ", xprev, gt_%s_", wtd->param_prefix);
              output_mangled_typename (d.of, orig_s);
-             output_type_enum (d.of, orig_s);
            }
          oprintf (d.of, ");\n");
          oprintf (d.of, "      }\n");
@@ -3063,7 +3631,6 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
            {
              oprintf (d.of, ", xlimit, gt_%s_", wtd->param_prefix);
              output_mangled_typename (d.of, orig_s);
-             output_type_enum (d.of, orig_s);
            }
          oprintf (d.of, "));\n");
          if (mark_hook_name && !wtd->skip_hooks)
@@ -3078,9 +3645,17 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
     {
       oprintf (d.of, "      %s (x);\n", mark_hook_name);
     }
+
   d.prev_val[2] = "*x";
   d.indent = 6;
-  walk_type (s, &d);
+  if (orig_s->kind != TYPE_USER_STRUCT)
+    walk_type (s, &d);
+  else
+    {
+      /* User structures have no fields to walk. Simply generate a call
+        to the user-provided structure marker.  */
+      oprintf (d.of, "%*sgt_%sx (x);\n", d.indent, "", wtd->prefix);
+    }
 
   if (chain_next != NULL)
     {
@@ -3093,46 +3668,68 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
   if (chain_circular != NULL)
     oprintf (d.of, "  while (x != xlimit);\n");
   oprintf (d.of, "}\n");
+
+  if (orig_s->kind == TYPE_USER_STRUCT)
+    write_user_marking_functions (orig_s, wtd, &d);
+
+  if (for_user)
+    {
+      write_user_func_for_structure_body (orig_s, wtd->prefix, &d);
+      write_user_func_for_structure_ptr (d.of, orig_s, wtd);
+    }
 }
 
+
 /* Write out marker routines for STRUCTURES and PARAM_STRUCTS.  */
 
 static void
-write_types (outf_p output_header, type_p structures, type_p param_structs,
+write_types (outf_p output_header, type_p structures,
             const struct write_types_data *wtd)
 {
   int nbfun = 0;               /* Count the emitted functions.  */
   type_p s;
 
   oprintf (output_header, "\n/* %s*/\n", wtd->comment);
+
   /* We first emit the macros and the declarations. Functions' code is
      emitted afterwards.  This is needed in plugin mode.  */
-  oprintf (output_header, "/* macros and declarations */\n");
+  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;
 
        if (s->gc_used == GC_MAYBE_POINTED_TO && s->u.s.line.file == NULL)
          continue;
 
+       const char *s_id_for_tag = filter_type_name (s->u.s.tag);
+
        oprintf (output_header, "#define gt_%s_", wtd->prefix);
        output_mangled_typename (output_header, s);
        oprintf (output_header, "(X) do { \\\n");
        oprintf (output_header,
                 "  if (X != NULL) gt_%sx_%s (X);\\\n", wtd->prefix,
-                s->u.s.tag);
+                s_id_for_tag);
        oprintf (output_header, "  } while (0)\n");
 
        for (opt = s->u.s.opt; opt; opt = opt->next)
-         if (strcmp (opt->name, "ptr_alias") == 0)
+         if (strcmp (opt->name, "ptr_alias") == 0
+             && opt->kind == OPTION_TYPE)
            {
-             const_type_p const t = (const_type_p) opt->info;
+             const_type_p const t = (const_type_p) opt->info.type;
              if (t->kind == TYPE_STRUCT
                  || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT)
-               oprintf (output_header,
-                        "#define gt_%sx_%s gt_%sx_%s\n",
-                        wtd->prefix, s->u.s.tag, wtd->prefix, t->u.s.tag);
+               {
+                 const char *t_id_for_tag = filter_type_name (t->u.s.tag);
+                 oprintf (output_header,
+                          "#define gt_%sx_%s gt_%sx_%s\n",
+                          wtd->prefix, s->u.s.tag, wtd->prefix, t_id_for_tag);
+                 if (t_id_for_tag != t->u.s.tag)
+                   free (CONST_CAST (char *, t_id_for_tag));
+               }
              else
                error_at_line (&s->u.s.line,
                               "structure alias is not a structure");
@@ -3144,27 +3741,12 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
        /* Declare the marker procedure only once.  */
        oprintf (output_header,
                 "extern void gt_%sx_%s (void *);\n",
-                wtd->prefix, s->u.s.tag);
-
-       if (s->u.s.line.file == NULL)
-         {
-           fprintf (stderr, "warning: structure `%s' used but not defined\n",
-                    s->u.s.tag);
-           continue;
-         }
-      }
+                wtd->prefix, s_id_for_tag);
 
-  for (s = param_structs; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO)
-      {
-       type_p stru = s->u.param_struct.stru;
-
-       /* Declare the marker procedure.  */
-       oprintf (output_header, "extern void gt_%s_", wtd->prefix);
-       output_mangled_typename (output_header, s);
-       oprintf (output_header, " (void *);\n");
+       if (s_id_for_tag != s->u.s.tag)
+         free (CONST_CAST (char *, s_id_for_tag));
 
-       if (stru->u.s.line.file == NULL)
+       if (s->u.s.line.file == NULL)
          {
            fprintf (stderr, "warning: structure `%s' used but not defined\n",
                     s->u.s.tag);
@@ -3195,7 +3777,7 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
                nbfun++;
                DBGPRINTF ("writing func #%d lang_struct ss @ %p '%s'",
                           nbfun, (void*) ss, ss->u.s.tag);
-               write_func_for_structure (s, ss, NULL, wtd);
+               write_func_for_structure (s, ss, wtd);
              }
          }
        else
@@ -3203,7 +3785,7 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
            nbfun++;
            DBGPRINTF ("writing func #%d struct s @ %p '%s'",
                       nbfun, (void*) s, s->u.s.tag);
-           write_func_for_structure (s, s, NULL, wtd);
+           write_func_for_structure (s, s, wtd);
          }
       }
     else
@@ -3214,38 +3796,6 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
                   (int) s->gc_used);
       }
 
-  for (s = param_structs; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO)
-      {
-       type_p *param = s->u.param_struct.param;
-       type_p stru = s->u.param_struct.stru;
-       if (stru->u.s.line.file == NULL)
-         continue;
-       if (stru->kind == TYPE_LANG_STRUCT)
-         {
-           type_p ss;
-           for (ss = stru->u.s.lang_struct; ss; ss = ss->next)
-             {
-               nbfun++;
-               DBGPRINTF ("writing func #%d param lang_struct ss @ %p '%s'",
-                          nbfun, (void*) ss,  ss->u.s.tag);
-               write_func_for_structure (s, ss, param, wtd);
-             }
-         }
-       else
-         {
-           nbfun++;
-           DBGPRINTF ("writing func #%d param struct s @ %p stru @ %p '%s'",
-                      nbfun, (void*) s,
-                      (void*) stru,  stru->u.s.tag);
-           write_func_for_structure (s, stru, param, wtd);
-         }
-      }
-    else
-      { 
-       /* Param structure s is not pointed to, so should be ignored.  */
-       DBGPRINTF ("ignored s @ %p", (void*)s);
-      }
   if (verbosity_level >= 2)
     printf ("%s emitted %d routines for %s\n",
            progname, nbfun, wtd->comment);
@@ -3254,44 +3804,142 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
 static const struct write_types_data ggc_wtd = {
   "ggc_m", NULL, "ggc_mark", "ggc_test_and_set_mark", NULL,
   "GC marker procedures.  ",
-  FALSE
+  FALSE, WTK_GGC
 };
 
 static const struct write_types_data pch_wtd = {
   "pch_n", "pch_p", "gt_pch_note_object", "gt_pch_note_object",
   "gt_pch_note_reorder",
   "PCH type-walking procedures.  ",
-  TRUE
+  TRUE, WTK_PCH
 };
 
 /* Write out the local pointer-walking routines.  */
 
+/* process_field routine for local pointer-walking for user-callable
+   routines.  The difference between this and
+   write_types_local_process_field is that, in this case, we do not
+   need to check whether the given pointer matches the address of the
+   parent structure.  This check was already generated by the call
+   to gt_pch_nx in the main gt_pch_p_*() function that is calling
+   this code.  */
+
+static void
+write_types_local_user_process_field (type_p f, const struct walk_type_data *d)
+{
+  switch (f->kind)
+    {
+    case TYPE_POINTER:
+    case TYPE_STRUCT:
+    case TYPE_UNION:
+    case TYPE_LANG_STRUCT:
+    case TYPE_STRING:
+      oprintf (d->of, "%*s  op (&(%s), cookie);\n", d->indent, "", d->val);
+      break;
+
+    case TYPE_USER_STRUCT:
+      if (d->in_ptr_field)
+       oprintf (d->of, "%*s  op (&(%s), cookie);\n", d->indent, "", d->val);
+      else
+       oprintf (d->of, "%*s  gt_pch_nx (&(%s), op, cookie);\n",
+                d->indent, "", d->val);
+      break;
+
+    case TYPE_SCALAR:
+      break;
+
+    case TYPE_ARRAY:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
+      gcc_unreachable ();
+    }
+}
+
+
+/* Write a function to PCH walk all the fields of type S on OF.
+   D contains data needed by walk_type to recurse into the fields of S.  */
+
+static void
+write_pch_user_walking_for_structure_body (type_p s, struct walk_type_data *d)
+{
+  oprintf (d->of, "\nvoid\n");
+  oprintf (d->of, "gt_pch_nx (");
+  write_type_decl (d->of, s);
+  oprintf (d->of, "* x ATTRIBUTE_UNUSED,\n"
+          "\tATTRIBUTE_UNUSED gt_pointer_operator op,\n"
+          "\tATTRIBUTE_UNUSED void *cookie)\n");
+  oprintf (d->of, "{\n");
+  d->val = "(*x)";
+  d->indent = 2;
+  d->process_field = write_types_local_user_process_field;
+  walk_type (s, d);
+  oprintf (d->of, "}\n");
+}
+
+
+/* Emit the user-callable functions needed to mark all the types used
+   by the user structure S.  PREFIX is the prefix to use to
+   distinguish ggc and pch markers. CHAIN_NEXT is set if S has the
+   chain_next option defined.  D contains data needed to pass to
+   walk_type when traversing the fields of a type.
+
+   For every type T referenced by S, two routines are generated: one
+   that takes 'T *', marks the pointer and calls the second routine,
+   which just marks the fields of T.  */
+
+static void
+write_pch_user_walking_functions (type_p s, struct walk_type_data *d)
+{
+  gcc_assert (s->kind == TYPE_USER_STRUCT);
+
+  for (pair_p fld = s->u.s.fields; fld; fld = fld->next)
+    {
+      type_p fld_type = fld->type;
+      if (union_or_struct_p (fld_type))
+       write_pch_user_walking_for_structure_body (fld_type, d);
+    }
+}
+
+
 /* process_field routine for local pointer-walking.  */
 
 static void
 write_types_local_process_field (type_p f, const struct walk_type_data *d)
 {
+  gcc_assert (d->have_this_obj);
   switch (f->kind)
     {
     case TYPE_POINTER:
     case TYPE_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
-    case TYPE_PARAM_STRUCT:
     case TYPE_STRING:
       oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
               d->prev_val[3]);
       oprintf (d->of, "%*s  op (&(%s), cookie);\n", d->indent, "", d->val);
       break;
 
+    case TYPE_USER_STRUCT:
+      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
+              d->prev_val[3]);
+      if (d->in_ptr_field)
+       oprintf (d->of, "%*s  op (&(%s), cookie);\n", d->indent, "", d->val);
+      else
+       oprintf (d->of, "%*s  gt_pch_nx (&(%s), op, cookie);\n",
+                d->indent, "", d->val);
+      break;
+
     case TYPE_SCALAR:
       break;
 
-    default:
+    case TYPE_ARRAY:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
       gcc_unreachable ();
     }
 }
 
+
 /* For S, a structure that's part of ORIG_S, and using parameters
    PARAM, write out a routine that:
    - Is of type gt_note_pointers
@@ -3299,17 +3947,21 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d)
 */
 
 static void
-write_local_func_for_structure (const_type_p orig_s, type_p s, type_p *param)
+write_local_func_for_structure (const_type_p orig_s, type_p s)
 {
   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.of = get_output_file_for_structure (s);
   d.process_field = write_types_local_process_field;
   d.opt = s->u.s.opt;
   d.line = &s->u.s.line;
   d.bitmap = s->u.s.bitmap;
-  d.param = param;
   d.prev_val[0] = d.prev_val[2] = "*x";
   d.prev_val[1] = "not valid postage"; /* Guarantee an error.  */
   d.prev_val[3] = "x";
@@ -3325,23 +3977,48 @@ write_local_func_for_structure (const_type_p orig_s, type_p s, type_p *param)
           "\tATTRIBUTE_UNUSED gt_pointer_operator op,\n"
           "\tATTRIBUTE_UNUSED void *cookie)\n");
   oprintf (d.of, "{\n");
-  oprintf (d.of, "  %s %s * const x ATTRIBUTE_UNUSED = (%s %s *)x_p;\n",
+  oprintf (d.of, "  %s %s * x ATTRIBUTE_UNUSED = (%s %s *)x_p;\n",
           s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
           s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
   d.indent = 2;
-  walk_type (s, &d);
+  d.have_this_obj = true;
+
+  if (s->kind != TYPE_USER_STRUCT)
+    walk_type (s, &d);
+  else
+    {
+      /* User structures have no fields to walk. Simply generate a
+        call to the user-provided PCH walker.  */
+      oprintf (d.of, "%*sif ((void *)(%s) == this_obj)\n", d.indent, "",
+              d.prev_val[3]);
+      oprintf (d.of, "%*s  gt_pch_nx (&(%s), op, cookie);\n",
+              d.indent, "", d.val);
+    }
+
   oprintf (d.of, "}\n");
+
+  /* Write user-callable entry points for the PCH walking routines.  */
+  if (orig_s->kind == TYPE_USER_STRUCT)
+    write_pch_user_walking_functions (s, &d);
+
+  for (options_p o = s->u.s.opt; o; o = o->next)
+    if (strcmp (o->name, "for_user") == 0)
+      {
+       write_pch_user_walking_for_structure_body (s, &d);
+       break;
+      }
 }
 
 /* Write out local marker routines for STRUCTURES and PARAM_STRUCTS.  */
 
 static void
-write_local (outf_p output_header, type_p structures, type_p param_structs)
+write_local (outf_p output_header, type_p structures)
 {
   type_p s;
 
   if (!output_header)
     return;
+
   oprintf (output_header, "\n/* Local pointer-walking routines.  */\n");
   for (s = structures; s; s = s->next)
     if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO)
@@ -3350,11 +4027,11 @@ write_local (outf_p output_header, type_p structures, type_p param_structs)
 
        if (s->u.s.line.file == NULL)
          continue;
-
-       for (opt = s->u.s.opt; opt; opt = opt->next)
-         if (strcmp (opt->name, "ptr_alias") == 0)
+       for (opt = s->u.s.opt; opt; opt = opt->next)
+         if (strcmp (opt->name, "ptr_alias") == 0
+             && opt->kind == OPTION_TYPE)
            {
-             const_type_p const t = (const_type_p) opt->info;
+             const_type_p const t = (const_type_p) opt->info.type;
              if (t->kind == TYPE_STRUCT
                  || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT)
                {
@@ -3382,100 +4059,29 @@ write_local (outf_p output_header, type_p structures, type_p param_structs)
          {
            type_p ss;
            for (ss = s->u.s.lang_struct; ss; ss = ss->next)
-             write_local_func_for_structure (s, ss, NULL);
-         }
-       else
-         write_local_func_for_structure (s, s, NULL);
-      }
-
-  for (s = param_structs; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO)
-      {
-       type_p *param = s->u.param_struct.param;
-       type_p stru = s->u.param_struct.stru;
-
-       /* Declare the marker procedure.  */
-       oprintf (output_header, "extern void gt_pch_p_");
-       output_mangled_typename (output_header, s);
-       oprintf (output_header,
-                "\n    (void *, void *, gt_pointer_operator, void *);\n");
-
-       if (stru->u.s.line.file == NULL)
-         {
-           fprintf (stderr, "warning: structure `%s' used but not defined\n",
-                    s->u.s.tag);
-           continue;
-         }
-
-       if (stru->kind == TYPE_LANG_STRUCT)
-         {
-           type_p ss;
-           for (ss = stru->u.s.lang_struct; ss; ss = ss->next)
-             write_local_func_for_structure (s, ss, param);
-         }
-       else
-         write_local_func_for_structure (s, stru, param);
-      }
-}
-
-/* Nonzero if S is a type for which typed GC allocators should be output.  */
-
-#define USED_BY_TYPED_GC_P(s)                                          \
-  (((s->kind == TYPE_POINTER)                                          \
-    && ((s->u.p->gc_used == GC_POINTED_TO)                             \
-       || (s->u.p->gc_used == GC_USED)))                               \
-   || (UNION_OR_STRUCT_P (s) &&                                                \
-       (((s)->gc_used == GC_POINTED_TO)                                        \
-       || ((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"))))))
-
-
-/* Write out the 'enum' definition for gt_types_enum.  */
-
-static void
-write_enum_defn (type_p structures, type_p param_structs)
-{
-  type_p s;
-  int nbstruct = 0;
-  int nbparamstruct = 0;
-
-  if (!header_file)
-    return;
-  oprintf (header_file, "\n/* Enumeration of types known.  */\n");
-  oprintf (header_file, "enum gt_types_enum {\n");
-  for (s = structures; s; s = s->next)
-    if (USED_BY_TYPED_GC_P (s))
-      {
-       nbstruct++;
-       DBGPRINTF ("write_enum_defn s @ %p nbstruct %d",
-                  (void*) s, nbstruct);
-       if (UNION_OR_STRUCT_P (s))
-         DBGPRINTF ("write_enum_defn s %p #%d is unionorstruct tagged %s",
-                    (void*) s, nbstruct, s->u.s.tag);
-       oprintf (header_file, " gt_ggc_e_");
-       output_mangled_typename (header_file, s);
-       oprintf (header_file, ",\n");
-      }
-  for (s = param_structs; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO)
-      {
-       nbparamstruct++;
-       DBGPRINTF ("write_enum_defn s %p nbparamstruct %d",
-                  (void*) s, nbparamstruct);
-       oprintf (header_file, " gt_e_");
-       output_mangled_typename (header_file, s);
-       oprintf (header_file, ",\n");
+             write_local_func_for_structure (s, ss);
+         }
+       else
+         write_local_func_for_structure (s, s);
       }
-  oprintf (header_file, " gt_types_enum_last\n");
-  oprintf (header_file, "};\n");
-  if (verbosity_level >= 2)
-    printf ("%s handled %d GTY-ed structures & %d parameterized structures.\n",
-           progname, nbstruct, nbparamstruct);
-
 }
 
+/* Nonzero if S is a type for which typed GC allocators should be output.  */
+
+#define USED_BY_TYPED_GC_P(s)                                          \
+  ((s->kind == TYPE_POINTER                                            \
+    && (s->u.p->gc_used == GC_POINTED_TO                               \
+       || s->u.p->gc_used == GC_USED))                                 \
+   || (union_or_struct_p (s)                                                   \
+       && ((s)->gc_used == GC_POINTED_TO                               \
+          || ((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"))) \
+          || (s->u.s.base_class && opts_have (s->u.s.opt, "tag")))))
+
+
+
 /* Might T contain any non-pointer elements?  */
 
 static int
@@ -3488,6 +4094,9 @@ contains_scalar_p (type_p t)
       return 0;
     case TYPE_ARRAY:
       return contains_scalar_p (t->u.a.p);
+    case TYPE_USER_STRUCT:
+      /* User-marked structures will typically contain pointers.  */
+      return 0;
     default:
       /* Could also check for structures that have no non-pointer
          fields, but there aren't enough of those to worry about.  */
@@ -3581,6 +4190,60 @@ finish_root_table (struct flist *flp, const char *pfx, const char *lastname,
   }
 }
 
+/* Finish off the created gt_clear_caches_file_c functions.  */
+
+static void
+finish_cache_funcs (flist *flp)
+{
+  struct flist *fli2;
+
+  for (fli2 = flp; fli2; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+       oprintf (fli2->f, "}\n\n");
+      }
+
+  for (fli2 = flp; fli2 && base_files; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+       lang_bitmap bitmap = get_lang_bitmap (fli2->file);
+       int fnum;
+
+       for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
+         if (bitmap & 1)
+           {
+             oprintf (base_files[fnum], "extern void gt_clear_caches_");
+             put_mangled_filename (base_files[fnum], fli2->file);
+             oprintf (base_files[fnum], " ();\n");
+           }
+      }
+
+  for (size_t fnum = 0; base_files && fnum < num_lang_dirs; fnum++)
+    oprintf (base_files[fnum], "void\ngt_clear_caches ()\n{\n");
+
+  for (fli2 = flp; fli2; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+       lang_bitmap bitmap = get_lang_bitmap (fli2->file);
+       int fnum;
+
+       fli2->started_p = 0;
+
+       for (fnum = 0; base_files && bitmap != 0; fnum++, bitmap >>= 1)
+         if (bitmap & 1)
+           {
+             oprintf (base_files[fnum], "  gt_clear_caches_");
+             put_mangled_filename (base_files[fnum], fli2->file);
+             oprintf (base_files[fnum], " ();\n");
+           }
+      }
+
+  for (size_t fnum = 0; base_files && fnum < num_lang_dirs; fnum++)
+    {
+      oprintf (base_files[fnum], "}\n");
+    }
+}
+
 /* Write the first three fields (pointer, count and stride) for
    root NAME to F.  V and LINE are as for write_root.
 
@@ -3620,17 +4283,16 @@ start_root_entry (outf_p f, pair_p v, const char *name, struct fileloc *line)
 
 static void
 write_field_root (outf_p f, pair_p v, type_p type, const char *name,
-                 int has_length, struct fileloc *line, const char *if_marked,
+                 int has_length, struct fileloc *line,
                  bool emit_pch, type_p field_type, const char *field_name)
 {
+  struct pair newv;
   /* If the field reference is relative to V, rather than to some
      subcomponent of V, we can mark any subarrays with a single stride.
      We're effectively treating the field as a global variable in its
      own right.  */
   if (v && type == v->type)
     {
-      struct pair newv;
-
       newv = *v;
       newv.type = field_type;
       newv.name = ACONCAT ((v->name, ".", field_name, NULL));
@@ -3641,7 +4303,7 @@ write_field_root (outf_p f, pair_p v, type_p type, const char *name,
   else if (field_type->kind == TYPE_ARRAY)
     v = NULL;
   write_root (f, v, field_type, ACONCAT ((name, ".", field_name, NULL)),
-             has_length, line, if_marked, emit_pch);
+             has_length, line, emit_pch);
 }
 
 /* Write out to F the table entry and any marker routines needed to
@@ -3656,12 +4318,11 @@ write_field_root (outf_p f, pair_p v, type_p type, const char *name,
      - the C variable that contains NAME, if NAME is not part of an array.
 
    LINE is the line of the C source that declares the root variable.
-   HAS_LENGTH is nonzero iff V was a variable-length array.  IF_MARKED
-   is nonzero iff we are building the root table for hash table caches.  */
+   HAS_LENGTH is nonzero iff V was a variable-length array.  */
 
 static void
 write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
-           struct fileloc *line, const char *if_marked, bool emit_pch)
+           struct fileloc *line, bool emit_pch)
 {
   switch (type->kind)
     {
@@ -3677,10 +4338,9 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
            for (o = fld->opt; o; o = o->next)
              if (strcmp (o->name, "skip") == 0)
                skip_p = 1;
-             else if (strcmp (o->name, "desc") == 0)
-               desc = o->info;
-             else if (strcmp (o->name, "param_is") == 0)
-               ;
+             else if (strcmp (o->name, "desc") == 0
+                      && o->kind == OPTION_STRING)
+               desc = o->info.string;
              else
                error_at_line (line,
                               "field `%s' of global `%s' has unknown option `%s'",
@@ -3697,10 +4357,10 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
                  {
                    const char *tag = NULL;
                    options_p oo;
-
-                   for (oo = ufld->opt; oo; oo = oo->next)
-                     if (strcmp (oo->name, "tag") == 0)
-                       tag = oo->info;
+                   for (oo = ufld->opt; oo; oo = oo->next)
+                     if (strcmp (oo->name, "tag") == 0
+                         && oo->kind == OPTION_STRING)
+                       tag = oo->info.string;
                    if (tag == NULL || strcmp (tag, desc) != 0)
                      continue;
                    if (validf != NULL)
@@ -3711,8 +4371,8 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
                    validf = ufld;
                  }
                if (validf != NULL)
-                 write_field_root (f, v, type, name, 0, line, if_marked,
-                                   emit_pch, validf->type,
+                 write_field_root (f, v, type, name, 0, line, emit_pch,
+                                   validf->type,
                                    ACONCAT ((fld->name, ".",
                                              validf->name, NULL)));
              }
@@ -3721,8 +4381,8 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
                             "global `%s.%s' has `desc' option but is not union",
                             name, fld->name);
            else
-             write_field_root (f, v, type, name, 0, line, if_marked,
-                               emit_pch, fld->type, fld->name);
+             write_field_root (f, v, type, name, 0, line, emit_pch, fld->type,
+                               fld->name);
          }
       }
       break;
@@ -3731,43 +4391,40 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
       {
        char *newname;
        newname = xasprintf ("%s[0]", name);
-       write_root (f, v, type->u.a.p, newname, has_length, line, if_marked,
-                   emit_pch);
+       write_root (f, v, type->u.a.p, newname, has_length, line, emit_pch);
        free (newname);
       }
       break;
 
+    case TYPE_USER_STRUCT:
+      error_at_line (line, "`%s' must be a pointer type, because it is "
+                    "a GC root and its type is marked with GTY((user))",
+                    v->name);
+      break;
+
     case TYPE_POINTER:
       {
-       type_p tp;
+       const_type_p tp;
 
        if (!start_root_entry (f, v, name, line))
          return;
 
        tp = type->u.p;
 
-       if (!has_length && UNION_OR_STRUCT_P (tp))
+       if (!has_length && union_or_struct_p (tp))
          {
-           oprintf (f, "    &gt_ggc_mx_%s,\n", tp->u.s.tag);
+           tp = get_ultimate_base_class (tp);
+           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)
-             oprintf (f, "    &gt_pch_nx_%s", tp->u.s.tag);
+             oprintf (f, "    &gt_pch_nx_%s", id_for_tag);
            else
              oprintf (f, "    NULL");
-         }
-       else if (!has_length && tp->kind == TYPE_PARAM_STRUCT)
-         {
-           oprintf (f, "    &gt_ggc_m_");
-           output_mangled_typename (f, tp);
-           if (emit_pch)
-             {
-               oprintf (f, ",\n    &gt_pch_n_");
-               output_mangled_typename (f, tp);
-             }
-           else
-             oprintf (f, ",\n    NULL");
+           if (id_for_tag != tp->u.s.tag)
+             free (CONST_CAST (char *, id_for_tag));
          }
        else if (has_length
-                && (tp->kind == TYPE_POINTER || UNION_OR_STRUCT_P (tp)))
+                && (tp->kind == TYPE_POINTER || union_or_struct_p (tp)))
          {
            oprintf (f, "    &gt_ggc_ma_%s,\n", name);
            if (emit_pch)
@@ -3781,8 +4438,6 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
                           "global `%s' is pointer to unimplemented type",
                           name);
          }
-       if (if_marked)
-         oprintf (f, ",\n    &%s", if_marked);
        oprintf (f, "\n  },\n");
       }
       break;
@@ -3801,7 +4456,10 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
     case TYPE_SCALAR:
       break;
 
-    default:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
+    case TYPE_UNION:
+    case TYPE_LANG_STRUCT:
       error_at_line (line, "global `%s' is unimplemented type", name);
     }
 }
@@ -3821,7 +4479,6 @@ write_array (outf_p f, pair_p v, const struct write_types_data *wtd)
   d.line = &v->line;
   d.opt = v->opt;
   d.bitmap = get_lang_bitmap (v->line.file);
-  d.param = NULL;
 
   d.prev_val[3] = prevval3 = xasprintf ("&%s", v->name);
 
@@ -3838,6 +4495,7 @@ write_array (outf_p f, pair_p v, const struct write_types_data *wtd)
       oprintf (d.of, "{\n");
       d.prev_val[0] = d.prev_val[1] = d.prev_val[2] = d.val = v->name;
       d.process_field = write_types_local_process_field;
+      d.have_this_obj = true;
       walk_type (v->type, &d);
       oprintf (f, "}\n\n");
     }
@@ -3849,6 +4507,7 @@ write_array (outf_p f, pair_p v, const struct write_types_data *wtd)
   oprintf (f, "{\n");
   d.prev_val[0] = d.prev_val[1] = d.prev_val[2] = d.val = v->name;
   d.process_field = write_types_process_field;
+  d.have_this_obj = false;
   walk_type (v->type, &d);
   free (prevval3);
   oprintf (f, "}\n\n");
@@ -3871,18 +4530,13 @@ write_roots (pair_p variables, bool emit_pch)
       const char *length = NULL;
       int deletable_p = 0;
       options_p o;
-
       for (o = v->opt; o; o = o->next)
-       if (strcmp (o->name, "length") == 0)
-         length = o->info;
+       if (strcmp (o->name, "length") == 0
+           && o->kind == OPTION_STRING)
+         length = o->info.string;
        else if (strcmp (o->name, "deletable") == 0)
          deletable_p = 1;
-       else if (strcmp (o->name, "param_is") == 0)
-         ;
-       else if (strncmp (o->name, "param", 5) == 0
-                && ISDIGIT (o->name[5]) && strcmp (o->name + 6, "_is") == 0)
-         ;
-       else if (strcmp (o->name, "if_marked") == 0)
+       else if (strcmp (o->name, "cache") == 0)
          ;
        else
          error_at_line (&v->line,
@@ -3928,8 +4582,7 @@ write_roots (pair_p variables, bool emit_pch)
       for (o = v->opt; o; o = o->next)
        if (strcmp (o->name, "length") == 0)
          length_p = 1;
-       else if (strcmp (o->name, "deletable") == 0
-                || strcmp (o->name, "if_marked") == 0)
+       else if (strcmp (o->name, "deletable") == 0)
          skip_p = 1;
 
       if (skip_p)
@@ -3947,7 +4600,7 @@ write_roots (pair_p variables, bool emit_pch)
          oprintf (f, "[] = {\n");
        }
 
-      write_root (f, v, v->type, v->name, length_p, &v->line, NULL, emit_pch);
+      write_root (f, v, v->type, v->name, length_p, &v->line, emit_pch);
     }
 
   finish_root_table (flp, "ggc_r", "LAST_GGC_ROOT_TAB", "ggc_root_tab",
@@ -3964,8 +4617,6 @@ write_roots (pair_p variables, bool emit_pch)
       for (o = v->opt; o; o = o->next)
        if (strcmp (o->name, "deletable") == 0)
          skip_p = 0;
-       else if (strcmp (o->name, "if_marked") == 0)
-         skip_p = 1;
 
       if (skip_p)
        continue;
@@ -3994,28 +4645,15 @@ write_roots (pair_p variables, bool emit_pch)
       outf_p f = get_output_file_with_visibility (CONST_CAST (input_file*,
                                                              v->line.file));
       struct flist *fli;
-      const char *if_marked = NULL;
-      int length_p = 0;
+      bool cache = false;
       options_p o;
 
       for (o = v->opt; o; o = o->next)
-       if (strcmp (o->name, "length") == 0)
-         length_p = 1;
-       else if (strcmp (o->name, "if_marked") == 0)
-         if_marked = o->info;
-
-      if (if_marked == NULL)
+       if (strcmp (o->name, "cache") == 0)
+         cache = true;
+       if (!cache)
        continue;
 
-      if (v->type->kind != TYPE_POINTER
-         || v->type->u.p->kind != TYPE_PARAM_STRUCT
-         || v->type->u.p->u.param_struct.stru != find_structure ("htab", 0))
-       {
-         error_at_line (&v->line,
-                        "if_marked option used but not hash table");
-         continue;
-       }
-
       for (fli = flp; fli; fli = fli->next)
        if (fli->f == f)
          break;
@@ -4023,57 +4661,19 @@ write_roots (pair_p variables, bool emit_pch)
        {
          fli->started_p = 1;
 
-         oprintf (f, "EXPORTED_CONST struct ggc_cache_tab gt_ggc_rc_");
+         oprintf (f, "void\ngt_clear_caches_");
          put_mangled_filename (f, v->line.file);
-         oprintf (f, "[] = {\n");
+         oprintf (f, " ()\n{\n");
        }
 
-      write_root (f, v, v->type->u.p->u.param_struct.param[0],
-                 v->name, length_p, &v->line, if_marked, emit_pch);
+      oprintf (f, "  gt_cleare_cache (%s);\n", v->name);
     }
 
-  finish_root_table (flp, "ggc_rc", "LAST_GGC_CACHE_TAB", "ggc_cache_tab",
-                    "gt_ggc_cache_rtab");
+  finish_cache_funcs (flp);
 
   if (!emit_pch)
     return;
 
-  for (v = variables; v; v = v->next)
-    {
-      outf_p f = get_output_file_with_visibility (CONST_CAST (input_file*,
-                                                             v->line.file));
-      struct flist *fli;
-      int length_p = 0;
-      int if_marked_p = 0;
-      options_p o;
-
-      for (o = v->opt; o; o = o->next)
-       if (strcmp (o->name, "length") == 0)
-         length_p = 1;
-       else if (strcmp (o->name, "if_marked") == 0)
-         if_marked_p = 1;
-
-      if (!if_marked_p)
-       continue;
-
-      for (fli = flp; fli; fli = fli->next)
-       if (fli->f == f)
-         break;
-      if (!fli->started_p)
-       {
-         fli->started_p = 1;
-
-         oprintf (f, "EXPORTED_CONST struct ggc_root_tab gt_pch_rc_");
-         put_mangled_filename (f, v->line.file);
-         oprintf (f, "[] = {\n");
-       }
-
-      write_root (f, v, v->type, v->name, length_p, &v->line, NULL, emit_pch);
-    }
-
-  finish_root_table (flp, "pch_rc", "LAST_GGC_ROOT_TAB", "ggc_root_tab",
-                    "gt_pch_cache_rtab");
-
   for (v = variables; v; v = v->next)
     {
       outf_p f = get_output_file_with_visibility (CONST_CAST (input_file*,
@@ -4083,9 +4683,11 @@ write_roots (pair_p variables, bool emit_pch)
       options_p o;
 
       for (o = v->opt; o; o = o->next)
-       if (strcmp (o->name, "deletable") == 0
-           || strcmp (o->name, "if_marked") == 0)
-         skip_p = 1;
+       if (strcmp (o->name, "deletable") == 0)
+         {
+           skip_p = 1;
+           break;
+         }
 
       if (skip_p)
        continue;
@@ -4113,196 +4715,6 @@ write_roots (pair_p variables, bool emit_pch)
                     "gt_pch_scalar_rtab");
 }
 
-/* Record the definition of a generic VEC structure, as if we had expanded
-   the macros in vec.h:
-
-   typedef struct VEC_<type>_base GTY(()) {
-   unsigned num;
-   unsigned alloc;
-   <type> GTY((length ("%h.num"))) vec[1];
-   } VEC_<type>_base
-
-   where the GTY(()) tags are only present if is_scalar is _false_.  */
-
-void
-note_def_vec (const char *type_name, bool is_scalar, struct fileloc *pos)
-{
-  pair_p fields;
-  type_p t;
-  options_p o;
-  type_p len_ty = create_scalar_type ("unsigned");
-  const char *name = concat ("VEC_", type_name, "_base", (char *) 0);
-
-  if (is_scalar)
-    {
-      t = create_scalar_type (type_name);
-      o = 0;
-    }
-  else
-    {
-      t = resolve_typedef (type_name, pos);
-      o = create_option (0, "length", "%h.num");
-    }
-
-  /* We assemble the field list in reverse order.  */
-  fields = create_field_at (0, create_array (t, "1"), "vec", o, pos);
-  fields = create_field_at (fields, len_ty, "alloc", 0, pos);
-  fields = create_field_at (fields, len_ty, "num", 0, pos);
-
-  do_typedef (name, new_structure (name, 0, pos, fields, 0), pos);
-}
-
-/* Record the definition of an allocation-specific VEC structure, as if
-   we had expanded the macros in vec.h:
-
-   typedef struct VEC_<type>_<astrat> {
-     VEC_<type>_base base;
-   } VEC_<type>_<astrat>;
-*/
-void
-note_def_vec_alloc (const char *type, const char *astrat, struct fileloc *pos)
-{
-  const char *astratname = concat ("VEC_", type, "_", astrat, (char *) 0);
-  const char *basename = concat ("VEC_", type, "_base", (char *) 0);
-
-  pair_p field = create_field_at (0, resolve_typedef (basename, pos),
-                                 "base", 0, pos);
-
-  do_typedef (astratname, new_structure (astratname, 0, pos, field, 0), pos);
-}
-
-/* Returns the specifier keyword for a string or union type S, empty string
-   otherwise.  */
-
-static const char *
-get_type_specifier (const type_p s)
-{
-  if (s->kind == TYPE_STRUCT || s->kind == TYPE_LANG_STRUCT)
-    return "struct ";
-  if (s->kind == TYPE_UNION)
-    return "union ";
-  return "";
-}
-
-/* TRUE if type S has the GTY variable_size annotation.  */
-
-static bool
-variable_size_p (const type_p s)
-{
-  options_p o;
-  for (o = s->u.s.opt; o; o = o->next)
-    if (strcmp (o->name, "variable_size") == 0)
-      return true;
-  return false;
-}
-
-enum alloc_quantity
-{ single, vector };
-enum alloc_zone
-{ any_zone, specific_zone };
-
-/* Writes one typed allocator definition for type identifier TYPE_NAME with
-   optional type specifier TYPE_SPECIFIER.  The allocator name will contain
-   ALLOCATOR_TYPE.  If VARIABLE_SIZE is true, the allocator will have an extra
-   parameter specifying number of bytes to allocate.  If QUANTITY is set to
-   VECTOR, a vector allocator will be output, if ZONE is set to SPECIFIC_ZONE,
-   the allocator will be zone-specific.  */
-
-static void
-write_typed_alloc_def (bool variable_size, const char *type_specifier,
-                      const char *type_name, const char *allocator_type,
-                      enum alloc_quantity quantity, enum alloc_zone zone)
-{
-  bool two_args = variable_size && (quantity == vector);
-  bool third_arg = ((zone == specific_zone)
-                   && (variable_size || (quantity == vector)));
-
-  oprintf (header_file, "#define ggc_alloc_%s%s", allocator_type, type_name);
-  oprintf (header_file, "(%s%s%s%s%s) ",
-          (variable_size ? "SIZE" : ""),
-          (two_args ? ", " : ""),
-          (quantity == vector) ? "n" : "",
-          (third_arg ? ", " : ""), (zone == specific_zone) ? "z" : "");
-  oprintf (header_file, "((%s%s *)", type_specifier, type_name);
-  oprintf (header_file, "(ggc_internal_%salloc_stat (", allocator_type);
-  if (zone == specific_zone)
-    oprintf (header_file, "z, ");
-  if (variable_size)
-    oprintf (header_file, "SIZE");
-  else
-    oprintf (header_file, "sizeof (%s%s)", type_specifier, type_name);
-  if (quantity == vector)
-    oprintf (header_file, ", n");
-  oprintf (header_file, " MEM_STAT_INFO)))\n");
-}
-
-/* Writes a typed allocator definition for a struct or union S.  */
-
-static void
-write_typed_struct_alloc_def (const type_p s, const char *allocator_type,
-                             enum alloc_quantity quantity,
-                             enum alloc_zone zone)
-{
-  write_typed_alloc_def (variable_size_p (s), get_type_specifier (s),
-                        s->u.s.tag, allocator_type, quantity, zone);
-}
-
-/* Writes a typed allocator definition for a typedef P.  */
-
-static void
-write_typed_typedef_alloc_def (const pair_p p, const char *allocator_type,
-                              enum alloc_quantity quantity,
-                              enum alloc_zone zone)
-{
-  write_typed_alloc_def (variable_size_p (p->type), "", p->name,
-                        allocator_type, quantity, zone);
-}
-
-/* Writes typed allocator definitions for the types in STRUCTURES and
-   TYPEDEFS that are used by GC.  */
-
-static void
-write_typed_alloc_defns (const type_p structures, const pair_p typedefs)
-{
-  type_p s;
-  pair_p p;
-
-  oprintf (header_file,
-          "\n/* Allocators for known structs and unions.  */\n\n");
-  for (s = structures; s; s = s->next)
-    {
-      if (!USED_BY_TYPED_GC_P (s))
-       continue;
-      write_typed_struct_alloc_def (s, "", single, any_zone);
-      write_typed_struct_alloc_def (s, "cleared_", single, any_zone);
-      write_typed_struct_alloc_def (s, "vec_", vector, any_zone);
-      write_typed_struct_alloc_def (s, "cleared_vec_", vector, any_zone);
-      write_typed_struct_alloc_def (s, "zone_", single, specific_zone);
-      write_typed_struct_alloc_def (s, "zone_cleared_", single,
-                                   specific_zone);
-      write_typed_struct_alloc_def (s, "zone_vec_", vector, specific_zone);
-      write_typed_struct_alloc_def (s, "zone_cleared_vec_", vector,
-                                   specific_zone);
-    }
-
-  oprintf (header_file, "\n/* Allocators for known typedefs.  */\n");
-  for (p = typedefs; p; p = p->next)
-    {
-      s = p->type;
-      if (!USED_BY_TYPED_GC_P (s) || (strcmp (p->name, s->u.s.tag) == 0))
-       continue;
-      write_typed_typedef_alloc_def (p, "", single, any_zone);
-      write_typed_typedef_alloc_def (p, "cleared_", single, any_zone);
-      write_typed_typedef_alloc_def (p, "vec_", vector, any_zone);
-      write_typed_typedef_alloc_def (p, "cleared_vec_", vector, any_zone);
-      write_typed_typedef_alloc_def (p, "zone_", single, specific_zone);
-      write_typed_typedef_alloc_def (p, "zone_cleared_", single,
-                                    specific_zone);
-      write_typed_typedef_alloc_def (p, "zone_cleared_vec_", vector,
-                                    specific_zone);
-    }
-}
-
 /* Prints not-as-ugly version of a typename of T to OF.  Trades the uniquness
    guaranteee for somewhat increased readability.  If name conflicts do happen,
    this funcion will have to be adjusted to be more like
@@ -4323,68 +4735,18 @@ output_typename (outf_p of, const_type_p t)
       output_typename (of, t->u.p);
       break;
     case TYPE_STRUCT:
+    case TYPE_USER_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
       oprintf (of, "%s", t->u.s.tag);
       break;
-    case TYPE_PARAM_STRUCT:
-      {
-       int i;
-       for (i = 0; i < NUM_PARAM; i++)
-         if (t->u.param_struct.param[i] != NULL)
-           {
-             output_typename (of, t->u.param_struct.param[i]);
-             oprintf (of, "_");
-           }
-       output_typename (of, t->u.param_struct.stru);
-       break;
-      }
-    default:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
+    case TYPE_ARRAY:
       gcc_unreachable ();
     }
 }
 
-/* Writes a typed GC allocator for type S that is suitable as a callback for
-   the splay tree implementation in libiberty.  */
-
-static void
-write_splay_tree_allocator_def (const_type_p s)
-{
-  outf_p of = get_output_file_with_visibility (NULL);
-  oprintf (of, "void * ggc_alloc_splay_tree_");
-  output_typename (of, s);
-  oprintf (of, " (int sz, void * nl)\n");
-  oprintf (of, "{\n");
-  oprintf (of, "  return ggc_splay_alloc (");
-  oprintf (of, "gt_e_");
-  output_mangled_typename (of, s);
-  oprintf (of, ", sz, nl);\n");
-  oprintf (of, "}\n\n");
-}
-
-/* Writes typed GC allocators for PARAM_STRUCTS that are suitable as callbacks
-   for the splay tree implementation in libiberty.  */
-
-static void
-write_splay_tree_allocators (const_type_p param_structs)
-{
-  const_type_p s;
-
-  oprintf (header_file, "\n/* Splay tree callback allocators.  */\n");
-  for (s = param_structs; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO)
-      {
-       oprintf (header_file, "extern void * ggc_alloc_splay_tree_");
-       output_typename (header_file, s);
-       oprintf (header_file, " (int, void *);\n");
-       write_splay_tree_allocator_def (s);
-      }
-}
-
-static void dump_pair (int indent, pair_p p);
-static void dump_type (int indent, type_p p);
-static void dump_type_list (int indent, type_p p);
-
 #define INDENT 2
 
 /* Dumps the value of typekind KIND.  */
@@ -4404,6 +4766,12 @@ dump_typekind (int indent, enum typekind kind)
     case TYPE_STRUCT:
       printf ("TYPE_STRUCT");
       break;
+    case TYPE_UNDEFINED:
+      printf ("TYPE_UNDEFINED");
+      break;
+    case TYPE_USER_STRUCT:
+      printf ("TYPE_USER_STRUCT");
+      break;
     case TYPE_UNION:
       printf ("TYPE_UNION");
       break;
@@ -4416,9 +4784,6 @@ dump_typekind (int indent, enum typekind kind)
     case TYPE_LANG_STRUCT:
       printf ("TYPE_LANG_STRUCT");
       break;
-    case TYPE_PARAM_STRUCT:
-      printf ("TYPE_PARAM_STRUCT");
-      break;
     default:
       gcc_unreachable ();
     }
@@ -4461,7 +4826,21 @@ dump_options (int indent, options_p opt)
   o = opt;
   while (o)
     {
-      printf ("%s:%s ", o->name, o->info);
+      switch (o->kind)
+       {
+       case OPTION_STRING:
+         printf ("%s:string %s ", o->name, o->info.string);
+         break;
+       case OPTION_TYPE:
+         printf ("%s:type ", o->name);
+         dump_type (indent+1, o->info.type);
+         break;
+       case OPTION_NESTED:
+         printf ("%s:nested ", o->name);
+         break;
+       case OPTION_NONE:
+         gcc_unreachable ();
+       }
       o = o->next;
     }
   printf ("\n");
@@ -4485,8 +4864,7 @@ dump_type_u_s (int indent, type_p t)
 {
   pair_p fields;
 
-  gcc_assert (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION
-             || t->kind == TYPE_LANG_STRUCT);
+  gcc_assert (union_or_struct_p (t));
   printf ("%*cu.s.tag = %s\n", indent, ' ', t->u.s.tag);
   dump_fileloc (indent, t->u.s.line);
   printf ("%*cu.s.fields =\n", indent, ' ');
@@ -4516,25 +4894,6 @@ dump_type_u_a (int indent, type_p t)
   dump_type_list (indent + INDENT, t->u.a.p);
 }
 
-/* Recursively dumps the parameterized struct T.  */
-
-static void
-dump_type_u_param_struct (int indent, type_p t)
-{
-  int i;
-  gcc_assert (t->kind == TYPE_PARAM_STRUCT);
-  printf ("%*cu.param_struct.stru:\n", indent, ' ');
-  dump_type_list (indent, t->u.param_struct.stru);
-  dump_fileloc (indent, t->u.param_struct.line);
-  for (i = 0; i < NUM_PARAM; i++)
-    {
-      if (t->u.param_struct.param[i] == NULL)
-       continue;
-      printf ("%*cu.param_struct.param[%d]:\n", indent, ' ', i);
-      dump_type (indent + INDENT, t->u.param_struct.param[i]);
-    }
-}
-
 /* Recursively dumps the type list T.  */
 
 static void
@@ -4557,6 +4916,9 @@ dump_type (int indent, type_p t)
 {
   PTR *slot;
 
+  if (seen_types == NULL)
+    seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL);
+
   printf ("%*cType at %p: ", indent, ' ', (void *) t);
   slot = htab_find_slot (seen_types, t, INSERT);
   if (*slot != NULL)
@@ -4582,6 +4944,7 @@ dump_type (int indent, type_p t)
     case TYPE_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
+    case TYPE_USER_STRUCT:
       dump_type_u_s (indent + INDENT, t);
       break;
     case TYPE_POINTER:
@@ -4591,9 +4954,6 @@ dump_type (int indent, type_p t)
     case TYPE_ARRAY:
       dump_type_u_a (indent + INDENT, t);
       break;
-    case TYPE_PARAM_STRUCT:
-      dump_type_u_param_struct (indent + INDENT, t);
-      break;
     default:
       gcc_unreachable ();
     }
@@ -4634,16 +4994,18 @@ dump_structures (const char *name, type_p structures)
   printf ("End of %s\n\n", name);
 }
 
-/* Dumps the internal structures of gengtype.  */
+/* Dumps the internal structures of gengtype.  This is useful to debug
+   gengtype itself, or to understand what it does, e.g. for plugin
+   developers.  */
 
 static void
 dump_everything (void)
 {
-  seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL);
   dump_pair_list ("typedefs", typedefs);
   dump_structures ("structures", structures);
-  dump_structures ("param_structs", param_structs);
   dump_pair_list ("variables", variables);
+
+  /* Allocated with the first call to dump_type.  */
   htab_delete (seen_types);
 }
 \f
@@ -4802,6 +5164,7 @@ input_file_by_name (const char* name)
   f = XCNEWVAR (input_file, sizeof (input_file)+namlen+2);
   f->inpbitmap = 0;
   f->inpoutf = NULL;
+  f->inpisplugin = false;
   strcpy (f->inpname, name);
   slot = htab_find_slot (input_file_htab, f, INSERT);
   gcc_assert (slot != NULL);
@@ -4831,7 +5194,7 @@ htab_eq_inputfile (const void *x, const void *y)
   const input_file *inpfx = (const input_file *) x;
   const input_file *inpfy = (const input_file *) y;
   gcc_assert (inpfx != NULL && inpfy != NULL);
-  return !strcmp (get_input_file_name (inpfx), get_input_file_name (inpfy));
+  return !filename_cmp (get_input_file_name (inpfx), get_input_file_name (inpfy));
 }
 
 
@@ -4870,8 +5233,11 @@ main (int argc, char **argv)
   DBGPRINTF ("inputlist %s", inputlist);
   if (read_state_filename)
     {
-      fatal ("read state %s not implemented yet", read_state_filename);
-      /* TODO: implement read state.  */
+      if (inputlist)
+       fatal ("input list %s cannot be given with a read state file %s",
+              inputlist, read_state_filename);
+      read_state (read_state_filename);
+      DBGPRINT_COUNT_TYPE ("structures after read_state", structures);
     }
   else if (inputlist)
     {
@@ -4879,16 +5245,21 @@ main (int argc, char **argv)
          we can see them.  We should initialize them before calling
          read_input_list.  */
 #define POS_HERE(Call) do { pos.file = this_file; pos.line = __LINE__; \
-       Call;} while(0)
+       Call;} while (0)
       POS_HERE (do_scalar_typedef ("CUMULATIVE_ARGS", &pos));
       POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("double_int", &pos));
+      POS_HERE (do_scalar_typedef ("offset_int", &pos));
+      POS_HERE (do_scalar_typedef ("widest_int", &pos));
+      POS_HERE (do_scalar_typedef ("int64_t", &pos));
       POS_HERE (do_scalar_typedef ("uint64_t", &pos));
       POS_HERE (do_scalar_typedef ("uint8", &pos));
+      POS_HERE (do_scalar_typedef ("uintptr_t", &pos));
       POS_HERE (do_scalar_typedef ("jword", &pos));
       POS_HERE (do_scalar_typedef ("JCF_u2", &pos));
       POS_HERE (do_scalar_typedef ("void", &pos));
+      POS_HERE (do_scalar_typedef ("machine_mode", &pos));
       POS_HERE (do_typedef ("PTR", 
                            create_pointer (resolve_typedef ("void", &pos)),
                            &pos));
@@ -4901,11 +5272,10 @@ main (int argc, char **argv)
                     (int) i, get_input_file_name (gt_files[i]));
        }
       if (verbosity_level >= 1)
-       printf ("%s parsed %d files\n", progname, (int) num_gt_files);
+       printf ("%s parsed %d files with %d GTY types\n", 
+               progname, (int) num_gt_files, type_count);
 
       DBGPRINT_COUNT_TYPE ("structures after parsing", structures);
-      DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs);
-
     }
   else
     fatal ("either an input list or a read state file should be given");
@@ -4926,10 +5296,13 @@ main (int argc, char **argv)
        fatal ("No plugin files given in plugin mode for %s",
               plugin_output_filename);
 
-      /* Parse our plugin files.  */
+      /* Parse our plugin files and augment the state.  */
       for (ix = 0; ix < nb_plugin_files; ix++)
-       parse_file (get_input_file_name (plugin_files[ix]));
-
+       {
+         input_file* pluginput = plugin_files [ix];
+         pluginput->inpisplugin = true;
+         parse_file (get_input_file_name (pluginput));
+       }
       if (hit_error)
        return 1;
 
@@ -4947,39 +5320,61 @@ main (int argc, char **argv)
 
   gen_rtx_next ();
 
-  /* The call to set_gc_used may indirectly call find_param_structure
-     hence enlarge the param_structs list of types.  */
   set_gc_used (variables);
 
-  /* We should write the state here, but it is not yet implemented.  */
+  for (type_p t = structures; t; t = t->next)
+    {
+      bool for_user = false;
+      for (options_p o = t->u.s.opt; o; o = o->next)
+       if (strcmp (o->name, "for_user") == 0)
+         {
+           for_user = true;
+           break;
+         }
+
+      if (for_user)
+       set_gc_used_type (t, GC_POINTED_TO);
+    }
+ /* The state at this point is read from the state input file or by
+    parsing source files and optionally augmented by parsing plugin
+    source files.  Write it now.  */
   if (write_state_filename)
     {
-      fatal ("write state %s in not yet implemented", write_state_filename);
-      /* TODO: implement write state.  */
+      DBGPRINT_COUNT_TYPE ("structures before write_state", structures);
+
+      if (hit_error)
+       fatal ("didn't write state file %s after errors", 
+              write_state_filename);
+
+      DBGPRINTF ("before write_state %s", write_state_filename);
+      write_state (write_state_filename);
+
+      if (do_dump)
+       dump_everything ();
+
+      /* After having written the state file we return immediately to
+        avoid generating any output file.  */
+      if (hit_error)
+       return 1;
+      else
+       return 0;
     }
 
 
   open_base_files ();
 
-  write_enum_defn (structures, param_structs);
-  write_typed_alloc_defns (structures, typedefs);
   output_header = plugin_output ? plugin_output : header_file;
   DBGPRINT_COUNT_TYPE ("structures before write_types outputheader",
                       structures);
-  DBGPRINT_COUNT_TYPE ("param_structs before write_types outputheader",
-                      param_structs);
 
-  write_types (output_header, structures, param_structs, &ggc_wtd);
+  write_types (output_header, structures, &ggc_wtd);
   if (plugin_files == NULL)
     {
       DBGPRINT_COUNT_TYPE ("structures before write_types headerfil",
                           structures);
-      DBGPRINT_COUNT_TYPE ("param_structs before write_types headerfil",
-                          param_structs);
-      write_types (header_file, structures, param_structs, &pch_wtd);
-      write_local (header_file, structures, param_structs);
+      write_types (header_file, structures, &pch_wtd);
+      write_local (header_file, structures);
     }
-  write_splay_tree_allocators (param_structs);
   write_roots (variables, plugin_files == NULL);
   write_rtx_next ();
   close_output_files ();