OSDN Git Service

2014-04-01 Richard Biener <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / gengtype.c
index badb8f1..7450eeb 100644 (file)
@@ -1,5 +1,5 @@
 /* Process source files and output type information.
 /* Process source files and output type information.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    This file is part of GCC.
    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/>.  */
 
    along with GCC; see the file COPYING3.  If not see
    <http://www.gnu.org/licenses/>.  */
 
+#ifdef GENERATOR_FILE
 #include "bconfig.h"
 #include "bconfig.h"
+#else
+#include "config.h"
+#endif
 #include "system.h"
 #include "system.h"
-#include "gengtype.h"
 #include "errors.h"            /* for fatal */
 #include "errors.h"            /* for fatal */
+#include "getopt.h"
 #include "double-int.h"
 #include "double-int.h"
+#include "version.h"           /* for version_string & pkgversion_string.  */
 #include "hashtab.h"
 #include "hashtab.h"
+#include "xregex.h"
+#include "obstack.h"
+#include "gengtype.h"
+#include "filenames.h"
 
 /* Data types, macros, etc. used only in this file.  */
 
 
 /* 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
-};
-
-typedef unsigned lang_bitmap;
 
 
-/* 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;
-};
+/* The list of output files.  */
+outf_p output_files;
 
 
-/* A name and a type.  */
-struct pair
-{
-  pair_p next;
-  const char *name;
-  type_p type;
-  struct fileloc line;
-  options_p opt;
-};
+/* The output header file that is included into pretty much every
+   source file.  */
+outf_p header_file;
 
 
-#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
-};
+/* The name of the file containing the list of input files.  */
+static char *inputlist;
 
 
-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;
-};
+/* The plugin input files and their number; in that case only
+   a single file is produced.  */
+static input_file **plugin_files;
+static size_t nb_plugin_files;
 
 
-#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)
-
-/* Structure representing an output file.  */
-struct outf
-{
-  struct outf *next;
-  const char *name;
-  size_t buflength;
-  size_t bufused;
-  char *buf;
-};
-typedef struct outf *outf_p;
+/* The generated plugin output file and name.  */
+static outf_p plugin_output;
+static char *plugin_output_filename;
 
 
-/* An output file, suitable for definitions, that can see declarations
-   made in INPUT_FILE and is linked into every language that uses
-   INPUT_FILE.  May return NULL in plugin mode. */
-extern outf_p get_output_file_with_visibility (const char *input_file);
-const char *get_output_file_name (const char *);
+/* Our source directory and its length.  */
+const char *srcdir;
+size_t srcdir_len;
 
 
-/* Print, like fprintf, to O.  No-op if O is NULL. */
-static void
-oprintf (outf_p o, const char *S, ...)
-  ATTRIBUTE_PRINTF_2;
+/* Variables used for reading and writing the state.  */
+const char *read_state_filename;
+const char *write_state_filename;
 
 
-/* The list of output files.  */
-static outf_p output_files;
+/* Variables to help debugging.  */
+int do_dump;
+int do_debug;
 
 
-/* The plugin input files and their number; in that case only
-   a single file is produced.  */
-static char **plugin_files;
-static size_t nb_plugin_files;
-/* the generated plugin output name & file */
-static outf_p plugin_output;
+/* Level for verbose messages.  */
+int verbosity_level;
 
 
-/* The output header file that is included into pretty much every
-   source file.  */
-static outf_p header_file;
+/* 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;
 
 
-/* Source directory.  */
-static const char *srcdir;
+/* 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.  */
+static const char* backup_dir; /* (-B) program option.  */
 
 
-/* Length of srcdir name.  */
-static size_t srcdir_len = 0;
 
 static outf_p create_file (const char *, const char *);
 
 
 static outf_p create_file (const char *, const char *);
 
-static const char *get_file_basename (const char *);
-static const char *get_file_realbasename (const char *);
-static const char *get_file_srcdir_relative_path (const char *);
+static const char *get_file_basename (const input_file *);
+static const char *get_file_realbasename (const input_file *);
 
 static int get_prefix_langdir_index (const char *);
 
 static int get_prefix_langdir_index (const char *);
-static const char *get_file_langdir (const char *);
+static const char *get_file_langdir (const input_file *);
 \f
 
 /* Nonzero iff an error has occurred.  */
 \f
 
 /* Nonzero iff an error has occurred.  */
@@ -192,9 +106,10 @@ error_at_line (const struct fileloc *pos, const char *msg, ...)
 {
   va_list ap;
 
 {
   va_list ap;
 
+  gcc_assert (pos != NULL && pos->file != NULL);
   va_start (ap, msg);
 
   va_start (ap, msg);
 
-  fprintf (stderr, "%s:%d: ", pos->file, pos->line);
+  fprintf (stderr, "%s:%d: ", get_input_file_name (pos->file), pos->line);
   vfprintf (stderr, msg, ap);
   fputc ('\n', stderr);
   hit_error = true;
   vfprintf (stderr, msg, ap);
   fputc ('\n', stderr);
   hit_error = true;
@@ -222,63 +137,83 @@ xasprintf (const char *format, ...)
 /* Input file handling. */
 
 /* Table of all input files.  */
 /* Input file handling. */
 
 /* Table of all input files.  */
-static const char **gt_files;
-static size_t num_gt_files;
+const input_file **gt_files;
+size_t num_gt_files;
 
 
-/* A number of places use the name of this file for a location for
-   things that we can't rely on the source to define.  Make sure we
-   can still use pointer comparison on filenames.  */
-static const char this_file[] = __FILE__;
+/* A number of places use the name of this "gengtype.c" file for a
+   location for things that we can't rely on the source to define.
+   Make sure we can still use pointer comparison on filenames.  */
+input_file* this_file;
+/* The "system.h" file is likewise specially useful.  */
+input_file* system_h_file;
 
 /* Vector of per-language directories.  */
 
 /* Vector of per-language directories.  */
-static const char **lang_dir_names;
-static size_t num_lang_dirs;
+const char **lang_dir_names;
+size_t num_lang_dirs;
 
 /* An array of output files suitable for definitions.  There is one
    BASE_FILES entry for each language.  */
 static outf_p *base_files;
 
 
 /* An array of output files suitable for definitions.  There is one
    BASE_FILES entry for each language.  */
 static outf_p *base_files;
 
-/* Return a bitmap which has bit `1 << BASE_FILE_<lang>' set iff
-   INPUT_FILE is used by <lang>.
-
-   This function should be written to assume that a file _is_ used
-   if the situation is unclear.  If it wrongly assumes a file _is_ used,
-   a linker error will result.  If it wrongly assumes a file _is not_ used,
-   some GC roots may be missed, which is a much harder-to-debug problem.
 
 
-   The relevant bitmap is stored immediately before the file's name in the
-   buffer set up by read_input_list.  It may be unaligned, so we have to
-   read it byte-by-byte.  */
-
-static lang_bitmap
-get_lang_bitmap (const char *gtfile)
-{
 
 
-  if (gtfile == this_file)
-    /* Things defined in this file are universal.  */
-    return (((lang_bitmap) 1) << num_lang_dirs) - 1;
-  else
-    {
-      lang_bitmap n = 0;
-      int i;
-      for (i = -(int) sizeof (lang_bitmap); i < 0; i++)
-       n = (n << CHAR_BIT) + (unsigned char) gtfile[i];
-      return n;
-    }
-}
-
-/* Set the bitmap returned by get_lang_bitmap.  The only legitimate
-   caller of this function is read_input_list.  */
-static void
-set_lang_bitmap (char *gtfile, lang_bitmap n)
+#if ENABLE_CHECKING
+/* Utility debugging function, printing the various type counts within
+   a list of types.  Called thru the DBGPRINT_COUNT_TYPE macro.  */
+void
+dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
 {
 {
-  int i;
-  for (i = -1; i >= -(int) sizeof (lang_bitmap); i--)
+  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;
+  type_p p = NULL;
+  for (p = t; p; p = p->next)
     {
     {
-      gtfile[i] = n & ((1U << CHAR_BIT) - 1);
-      n >>= CHAR_BIT;
+      nb_types++;
+      switch (p->kind)
+       {
+       case TYPE_SCALAR:
+         nb_scalar++;
+         break;
+       case TYPE_STRING:
+         nb_string++;
+         break;
+       case TYPE_STRUCT:
+         nb_struct++;
+         break;
+       case TYPE_UNION:
+         nb_union++;
+         break;
+       case TYPE_POINTER:
+         nb_pointer++;
+         break;
+       case TYPE_ARRAY:
+         nb_array++;
+         break;
+       case TYPE_LANG_STRUCT:
+         nb_lang_struct++;
+         break;
+       case TYPE_PARAM_STRUCT:
+         nb_param_struct++;
+         break;
+       default:
+         gcc_unreachable ();
+       }
     }
     }
+  fprintf (stderr, "\n" "%s:%d: %s: @@%%@@ %d types ::\n",
+          lbasename (fil), lin, msg, nb_types);
+  if (nb_scalar > 0 || nb_string > 0)
+    fprintf (stderr, "@@%%@@ %d scalars, %d strings\n", nb_scalar, nb_string);
+  if (nb_struct > 0 || nb_union > 0)
+    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);
+  fprintf (stderr, "\n");
 }
 }
+#endif /* ENABLE_CHECKING */
 
 /* Scan the input file, LIST, and determine how much space we need to
    store strings in.  Also, count the number of language directories
 
 /* Scan the input file, LIST, and determine how much space we need to
    store strings in.  Also, count the number of language directories
@@ -412,11 +347,11 @@ read_input_list (const char *listname)
       size_t nfiles = 0;
       lang_bitmap curlangs = (1 << num_lang_dirs) - 1;
 
       size_t nfiles = 0;
       lang_bitmap curlangs = (1 << num_lang_dirs) - 1;
 
-      epos.file = listname;
+      epos.file = input_file_by_name (listname);
       epos.line = 0;
 
       lang_dir_names = XNEWVEC (const char *, num_lang_dirs);
       epos.line = 0;
 
       lang_dir_names = XNEWVEC (const char *, num_lang_dirs);
-      gt_files = XNEWVEC (const char *, num_gt_files);
+      gt_files = XNEWVEC (const input_file *, num_gt_files);
 
       for (;;)
        {
 
       for (;;)
        {
@@ -447,13 +382,16 @@ read_input_list (const char *listname)
          else
            {
              size_t i;
          else
            {
              size_t i;
+             input_file *inpf = input_file_by_name (line);
              gcc_assert (nfiles <= num_gt_files);
              for (i = 0; i < nfiles; i++)
              gcc_assert (nfiles <= num_gt_files);
              for (i = 0; i < nfiles; i++)
-               if (strcmp (gt_files[i], line) == 0)
+               /* Since the input_file-s are uniquely hash-consed, we
+                  can just compare pointers! */
+               if (gt_files[i] == inpf)
                  {
                    /* Throw away the string we just read, and add the
                       current language to the existing string's bitmap.  */
                  {
                    /* Throw away the string we just read, and add the
                       current language to the existing string's bitmap.  */
-                   lang_bitmap bmap = get_lang_bitmap (gt_files[i]);
+                   lang_bitmap bmap = get_lang_bitmap (inpf);
                    if (bmap & curlangs)
                      error_at_line (&epos,
                                     "file %s specified more than once "
                    if (bmap & curlangs)
                      error_at_line (&epos,
                                     "file %s specified more than once "
@@ -463,13 +401,13 @@ read_input_list (const char *listname)
                                                                  1]);
 
                    bmap |= curlangs;
                                                                  1]);
 
                    bmap |= curlangs;
-                   set_lang_bitmap (CONST_CAST (char *, gt_files[i]), bmap);
+                   set_lang_bitmap (inpf, bmap);
                    here = committed;
                    goto next_line;
                  }
 
                    here = committed;
                    goto next_line;
                  }
 
-             set_lang_bitmap (line, curlangs);
-             gt_files[nfiles++] = line;
+             set_lang_bitmap (inpf, curlangs);
+             gt_files[nfiles++] = inpf;
            }
        }
       /* Update the global counts now that we know accurately how many
            }
        }
       /* Update the global counts now that we know accurately how many
@@ -496,6 +434,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, '/');
        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)
          {
 
        if (slashpos)
          {
@@ -525,27 +469,27 @@ read_input_list (const char *listname)
 
 /* The one and only TYPE_STRING.  */
 
 
 /* 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
 };
 
 /* 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.  */
 
 };
 
 /* Lists of various things.  */
 
-static pair_p typedefs;
-static type_p structures;
-static type_p param_structs;
-static pair_p variables;
+pair_p typedefs;
+type_p structures;
+type_p param_structs;
+pair_p variables;
 
 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 find_param_structure (type_p t, type_p param[NUM_PARAM]);
 static type_p adjust_field_tree_exp (type_p t, options_p opt);
@@ -619,12 +563,6 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
   type_p s = NULL;
   lang_bitmap bitmap = get_lang_bitmap (pos->file);
 
   type_p s = NULL;
   lang_bitmap bitmap = get_lang_bitmap (pos->file);
 
-  /* temporary kludge - gengtype doesn't handle conditionals or
-     macros.  Ignore any attempt to define struct location_s, unless
-     it is coming from this file (main() sets it up safely). */
-  if (!strcmp (name, "location_s") && !isunion && pos->file != this_file)
-    return find_structure (name, 0);
-
   for (si = structures; si != NULL; si = si->next)
     if (strcmp (name, si->u.s.tag) == 0 && UNION_P (si) == isunion)
       {
   for (si = structures; si != NULL; si = si->next)
     if (strcmp (name, si->u.s.tag) == 0 && UNION_P (si) == isunion)
       {
@@ -640,12 +578,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;
        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 = 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;
          }
            si->pointer_to = NULL;
            si->u.s.lang_struct = ls;
          }
@@ -654,7 +594,9 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
 
        if (ls != NULL && s == NULL)
          {
 
        if (ls != NULL && s == NULL)
          {
+           type_count++;
            s = XCNEW (struct type);
            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;
            s->next = ls->u.s.lang_struct;
            ls->u.s.lang_struct = s;
            s->u.s.lang_struct = ls;
@@ -664,7 +606,9 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
 
   if (s == NULL)
     {
 
   if (s == NULL)
     {
+      type_count++;
       s = XCNEW (struct type);
       s = XCNEW (struct type);
+      s->state_number = -type_count;
       s->next = structures;
       structures = s;
     }
       s->next = structures;
       structures = s;
     }
@@ -686,20 +630,6 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
   if (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;
 
-  /* Reset location_s's location to input.h so that we know where to
-     write out its mark routine.  */
-  if (!strcmp (name, "location_s") && !isunion && pos->file == this_file)
-    {
-      size_t n;
-      for (n = 0; n < num_gt_files; n++)
-       if (!strcmp (gt_files[n] + strlen (gt_files[n]) - strlen ("input.h"),
-                    "input.h"))
-         {
-           s->u.s.line.file = gt_files[n];
-           break;
-         }
-    }
-
   return s;
 }
 
   return s;
 }
 
@@ -716,8 +646,10 @@ find_structure (const char *name, int isunion)
     if (strcmp (name, s->u.s.tag) == 0 && UNION_P (s) == isunion)
       return s;
 
     if (strcmp (name, s->u.s.tag) == 0 && UNION_P (s) == isunion)
       return s;
 
+  type_count++;
   s = XCNEW (struct type);
   s->next = structures;
   s = XCNEW (struct type);
   s->next = structures;
+  s->state_number = -type_count;
   structures = s;
   s->kind = isunion ? TYPE_UNION : TYPE_STRUCT;
   s->u.s.tag = name;
   structures = s;
   s->kind = isunion ? TYPE_UNION : TYPE_STRUCT;
   s->u.s.tag = name;
@@ -741,9 +673,11 @@ find_param_structure (type_p t, type_p param[NUM_PARAM])
       break;
   if (res == NULL)
     {
       break;
   if (res == NULL)
     {
+      type_count++;
       res = XCNEW (struct type);
       res->kind = TYPE_PARAM_STRUCT;
       res->next = param_structs;
       res = XCNEW (struct type);
       res->kind = TYPE_PARAM_STRUCT;
       res->next = param_structs;
+      res->state_number = -type_count;
       param_structs = res;
       res->u.param_struct.stru = t;
       memcpy (res->u.param_struct.param, param, sizeof (type_p) * NUM_PARAM);
       param_structs = res;
       res->u.param_struct.stru = t;
       memcpy (res->u.param_struct.param, param, sizeof (type_p) * NUM_PARAM);
@@ -770,6 +704,8 @@ create_pointer (type_p t)
   if (!t->pointer_to)
     {
       type_p r = XCNEW (struct type);
   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;
       r->kind = TYPE_POINTER;
       r->u.p = t;
       t->pointer_to = r;
@@ -784,23 +720,53 @@ create_array (type_p t, const char *len)
 {
   type_p v;
 
 {
   type_p v;
 
+  type_count++;
   v = XCNEW (struct type);
   v->kind = TYPE_ARRAY;
   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;
 }
 
   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
 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;
 {
   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;
 }
 
   return o;
 }
 
@@ -814,12 +780,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;
   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'.  */
 }
 
 /* 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)
 {
 void
 note_variable (const char *s, type_p t, options_p o, struct fileloc *pos)
 {
@@ -836,7 +801,7 @@ note_variable (const char *s, type_p t, options_p o, struct fileloc *pos)
 /* Most-general structure field creator.  */
 static pair_p
 create_field_all (pair_p next, type_p type, const char *name, options_p opt,
 /* Most-general structure field creator.  */
 static pair_p
 create_field_all (pair_p next, type_p type, const char *name, options_p opt,
-                 const char *file, int line)
+                 const input_file *inpf, int line)
 {
   pair_p field;
 
 {
   pair_p field;
 
@@ -845,7 +810,7 @@ create_field_all (pair_p next, type_p type, const char *name, options_p opt,
   field->type = type;
   field->name = name;
   field->opt = opt;
   field->type = type;
   field->name = name;
   field->opt = opt;
-  field->line.file = file;
+  field->line.file = inpf;
   field->line.line = line;
   return field;
 }
   field->line.line = line;
   return field;
 }
@@ -864,7 +829,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 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.  */
 
 /* Like create_field, but the field is only valid when condition COND
    is true.  */
@@ -881,19 +846,23 @@ 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, "");
      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++), 1,
+                   &lexer_line, union_fields, 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 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)     \
 }
 
 #define create_optional_field(next,type,name,cond)     \
-  create_optional_field_(next,type,name,cond,__LINE__)
+       create_optional_field_(next,type,name,cond,__LINE__)
 
 /* Reverse a linked list of 'struct pair's in place.  */
 pair_p
 
 /* Reverse a linked list of 'struct pair's in place.  */
 pair_p
@@ -1022,14 +991,16 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
       return &string_type;
     }
 
       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));
 
   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));
+  reg_attrs_tp = 
+    create_pointer (find_structure ("reg_attrs", 0));
+  basic_block_tp = 
+    create_pointer (find_structure ("basic_block_def", 0));
   constant_tp =
     create_pointer (find_structure ("constant_descriptor_rtx", 0));
   scalar_tp = &scalar_nonchar; /* rtunion int */
   constant_tp =
     create_pointer (find_structure ("constant_descriptor_rtx", 0));
   scalar_tp = &scalar_nonchar; /* rtunion int */
@@ -1044,6 +1015,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_MAX:
          case NOTE_INSN_DELETED_LABEL:
+         case NOTE_INSN_DELETED_DEBUG_LABEL:
            note_flds = create_field (note_flds, &string_type, "rt_str");
            break;
 
            note_flds = create_field (note_flds, &string_type, "rt_str");
            break;
 
@@ -1053,6 +1025,7 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
            break;
 
          case NOTE_INSN_VAR_LOCATION:
            break;
 
          case NOTE_INSN_VAR_LOCATION:
+         case NOTE_INSN_CALL_ARG_LOCATION:
            note_flds = create_field (note_flds, rtx_tp, "rt_rtx");
            break;
 
            note_flds = create_field (note_flds, rtx_tp, "rt_rtx");
            break;
 
@@ -1063,9 +1036,11 @@ 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_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
        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", 1,
                                   &lexer_line, note_flds, NULL);
@@ -1073,13 +1048,10 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
   /* Create a type to represent the various forms of SYMBOL_REF_DATA.  */
   {
     pair_p sym_flds;
   /* 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 = 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 = create_field (sym_flds, constant_tp, "rt_constant");
-    sym_flds->opt = create_option (nodot, "tag", "1");
-
+    sym_flds->opt = create_string_option (nodot, "tag", "1");
     symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
                                     &lexer_line, sym_flds, NULL);
   }
     symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
                                     &lexer_line, sym_flds, NULL);
   }
@@ -1141,11 +1113,14 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
                t = symbol_union_tp, subname = "";
              else if (i == BARRIER && aindex >= 3)
                t = scalar_tp, subname = "rt_int";
                t = symbol_union_tp, subname = "";
              else if (i == BARRIER && aindex >= 3)
                t = scalar_tp, subname = "rt_int";
+             else if (i == ENTRY_VALUE && aindex == 0)
+               t = rtx_tp, subname = "rt_rtx";
              else
                {
              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";
                }
                  t = &string_type;
                  subname = "rt_int";
                }
@@ -1181,10 +1156,11 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
              break;
 
            default:
              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;
              t = &string_type;
              subname = "rt_int";
              break;
@@ -1196,16 +1172,19 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
                                               subname));
          subfields->opt = nodot;
          if (t == note_union_tp)
                                               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)
          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 == SYMBOL_REF)
        {
        }
 
       if (i == SYMBOL_REF)
        {
-         /* Add the "block_sym" field if SYMBOL_REF_HAS_BLOCK_INFO_P holds.  */
+         /* Add the "block_sym" field if SYMBOL_REF_HAS_BLOCK_INFO_P
+            holds.  */
          type_p field_tp = find_structure ("block_symbol", 0);
          subfields
            = create_optional_field (subfields, field_tp, "block_sym",
          type_p field_tp = find_structure ("block_symbol", 0);
          subfields
            = create_optional_field (subfields, field_tp, "block_sym",
@@ -1218,11 +1197,9 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
       ftag = xstrdup (rtx_name[i]);
       for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
        ftag[nmindex] = TOUPPER (ftag[nmindex]);
       ftag = xstrdup (rtx_name[i]);
       for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
        ftag[nmindex] = TOUPPER (ftag[nmindex]);
-
       flds = create_field (flds, substruct, "");
       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", 1, &lexer_line, flds, nodot);
 }
 
@@ -1245,12 +1222,12 @@ adjust_field_tree_exp (type_p t, options_p opt ATTRIBUTE_UNUSED)
       return &string_type;
     }
 
       return &string_type;
     }
 
-  nodot = create_option (NULL, "dot", "");
+  nodot = create_string_option (NULL, "dot", "");
 
   flds = create_field (NULL, t, "");
 
   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", 1, &lexer_line, flds, nodot);
 }
@@ -1280,10 +1257,11 @@ adjust_field_type (type_p t, options_p opt)
   for (; opt; opt = opt->next)
     if (strcmp (opt->name, "length") == 0)
       length_p = 1;
   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))
+    else if ((strcmp (opt->name, "param_is") == 0
+             || (strncmp (opt->name, "param", 5) == 0
+                 && ISDIGIT (opt->name[5])
+                 && strcmp (opt->name + 6, "_is") == 0))
+            && opt->kind == OPTION_TYPE)
       {
        int num = ISDIGIT (opt->name[5]) ? opt->name[5] - '0' : 0;
 
       {
        int num = ISDIGIT (opt->name[5]) ? opt->name[5] - '0' : 0;
 
@@ -1300,14 +1278,14 @@ adjust_field_type (type_p t, options_p opt)
        if (params[num] != NULL)
          error_at_line (&lexer_line, "duplicate `%s' option", opt->name);
        if (!ISDIGIT (opt->name[5]))
        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));
+         params[num] = create_pointer (opt->info.type);
        else
        else
-         params[num] = CONST_CAST2 (type_p, const char *, opt->info);
+         params[num] = opt->info.type;
       }
       }
-    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)
        if (strcmp (special_name, "tree_exp") == 0)
          t = adjust_field_tree_exp (t, opt);
        else if (strcmp (special_name, "rtx_def") == 0)
@@ -1350,8 +1328,9 @@ process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
 {
   options_p o;
   for (o = opt; o; o = o->next)
 {
   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),
+    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, NULL);
     else if (strcmp (o->name, "maybe_undef") == 0)
       *maybe_undef = 1;
                        GC_POINTED_TO, NULL);
     else if (strcmp (o->name, "maybe_undef") == 0)
       *maybe_undef = 1;
@@ -1361,12 +1340,13 @@ process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
       *length = 1;
     else if (strcmp (o->name, "skip") == 0)
       *skip = 1;
       *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.  */
 static void
 set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
 {
 static void
 set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
 {
@@ -1454,9 +1434,15 @@ set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
 static void
 set_gc_used (pair_p variables)
 {
 static void
 set_gc_used (pair_p variables)
 {
+  int nbvars = 0;
   pair_p p;
   for (p = variables; p; p = p->next)
   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, NULL);
+      nbvars++;
+    };
+  if (verbosity_level >= 2)
+    printf ("%s used %d GTY-ed variables\n", progname, nbvars);
 }
 \f
 /* File mapping routines.  For each input file, there is one output .c file
 }
 \f
 /* File mapping routines.  For each input file, there is one output .c file
@@ -1578,7 +1564,8 @@ open_base_files (void)
       "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",
       "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
+      "target.h", "ipa-prop.h", "lto-streamer.h", "target-globals.h",
+      "ipa-inline.h", "dwarf2out.h", NULL
     };
     const char *const *ifp;
     outf_p gtype_desc_c;
     };
     const char *const *ifp;
     outf_p gtype_desc_c;
@@ -1593,40 +1580,40 @@ open_base_files (void)
   }
 }
 
   }
 }
 
-/* For F a filename, return the real basename of F, with all the directory
-   components skipped.  */
+/* For INPF an input file, return the real basename of INPF, with all
+   the directory components skipped.  */
 
 static const char *
 
 static const char *
-get_file_realbasename (const char *f)
+get_file_realbasename (const input_file *inpf)
 {
 {
-  const char *lastslash = strrchr (f, '/');
-
-  return (lastslash != NULL) ? lastslash + 1 : f;
+  return lbasename (get_input_file_name (inpf));
 }
 
 }
 
-/* For F a filename, return the relative path to F from $(srcdir) if the
-   latter is a prefix in F, NULL otherwise.  */
+/* For INPF a filename, return the relative path to INPF from
+   $(srcdir) if the latter is a prefix in INPF, NULL otherwise.  */
 
 
-static const char *
-get_file_srcdir_relative_path (const char *f)
+const char *
+get_file_srcdir_relative_path (const input_file *inpf)
 {
 {
+  const char *f = get_input_file_name (inpf);
   if (strlen (f) > srcdir_len
       && IS_DIR_SEPARATOR (f[srcdir_len])
   if (strlen (f) > srcdir_len
       && IS_DIR_SEPARATOR (f[srcdir_len])
-      && memcmp (f, srcdir, srcdir_len) == 0)
+      && strncmp (f, srcdir, srcdir_len) == 0)
     return f + srcdir_len + 1;
   else
     return NULL;
 }
 
     return f + srcdir_len + 1;
   else
     return NULL;
 }
 
-/* For F a filename, return the relative path to F from $(srcdir) if the
-   latter is a prefix in F, or the real basename of F otherwise.  */
+/*  For INPF an input_file, return the relative path to INPF from
+    $(srcdir) if the latter is a prefix in INPF, or the real basename
+    of INPF otherwise. */
 
 static const char *
 
 static const char *
-get_file_basename (const char *f)
+get_file_basename (const input_file *inpf)
 {
 {
-  const char *srcdir_path = get_file_srcdir_relative_path (f);
+  const char *srcdir_path = get_file_srcdir_relative_path (inpf);
 
 
-  return (srcdir_path != NULL) ? srcdir_path : get_file_realbasename (f);
+  return (srcdir_path != NULL) ? srcdir_path : get_file_realbasename (inpf);
 }
 
 /* For F a filename, return the lang_dir_names relative index of the language
 }
 
 /* For F a filename, return the lang_dir_names relative index of the language
@@ -1652,18 +1639,19 @@ get_prefix_langdir_index (const char *f)
   return -1;
 }
 
   return -1;
 }
 
-/* For F a filename, return the name of language directory where F is located,
-   if any, NULL otherwise.  */
+/* For INPF an input file, return the name of language directory where
+   F is located, if any, NULL otherwise.  */
 
 static const char *
 
 static const char *
-get_file_langdir (const char *f)
+get_file_langdir (const input_file *inpf)
 {
 {
-  /* Get the relative path to F from $(srcdir) and find the language by
-     comparing the prefix with language directory names.  If F is not even
-     srcdir relative, no point in looking further.  */
+  /* Get the relative path to INPF from $(srcdir) and find the
+     language by comparing the prefix with language directory names.
+     If INPF is not even srcdir relative, no point in looking
+     further.  */
 
   int lang_index;
 
   int lang_index;
-  const char *srcdir_relative_path = get_file_srcdir_relative_path (f);
+  const char *srcdir_relative_path = get_file_srcdir_relative_path (inpf);
   const char *r;
 
   if (!srcdir_relative_path)
   const char *r;
 
   if (!srcdir_relative_path)
@@ -1680,16 +1668,16 @@ get_file_langdir (const char *f)
   return r;
 }
 
   return r;
 }
 
-/* The gt- output file name for F.  */
+/* The gt- output file name for INPF.  */
 
 static const char *
 
 static const char *
-get_file_gtfilename (const char *f)
+get_file_gtfilename (const input_file *inpf)
 {
   /* Cook up an initial version of the gt- file name from the file real
      basename and the language name, if any.  */
 
 {
   /* Cook up an initial version of the gt- file name from the file real
      basename and the language name, if any.  */
 
-  const char *basename = get_file_realbasename (f);
-  const char *langdir = get_file_langdir (f);
+  const char *basename = get_file_realbasename (inpf);
+  const char *langdir = get_file_langdir (inpf);
 
   char *result =
     (langdir ? xasprintf ("gt-%s-%s", langdir, basename)
 
   char *result =
     (langdir ? xasprintf ("gt-%s-%s", langdir, basename)
@@ -1710,24 +1698,291 @@ get_file_gtfilename (const char *f)
   return result;
 }
 
   return result;
 }
 
+/* Each input_file has its associated output file outf_p.  The
+   association is computed by the function
+   get_output_file_with_visibility.  The associated file is cached
+   inside input_file in its inpoutf field, so is really computed only
+   once.  Associated output file paths (i.e. output_name-s) are
+   computed by a rule based regexp machinery, using the files_rules
+   array of struct file_rule_st.  A for_name is also computed, giving
+   the source file name for which the output_file is generated; it is
+   often the last component of the input_file path.  */
+
+
+/*
+ Regexpr machinery to compute the output_name and for_name-s of each
+ input_file.  We have a sequence of file rules which gives the POSIX
+ extended regular expression to match an input file path, and two
+ transformed strings for the corresponding output_name and the
+ corresponding for_name.  The transformed string contain dollars: $0
+ is replaced by the entire match, $1 is replaced by the substring
+ matching the first parenthesis in the regexp, etc.  And $$ is replaced
+ by a single verbatim dollar.  The rule order is important.  The
+ general case is last, and the particular cases should come before.
+ An action routine can, when needed, update the out_name & for_name
+ and/or return the appropriate output file.  It is invoked only when a
+ rule is triggered.  When a rule is triggered, the output_name and
+ for_name are computed using their transform string in while $$, $0,
+ $1, ... are suitably replaced.  If there is an action, it is called.
+ In some few cases, the action can directly return the outf_p, but
+ usually it just updates the output_name and for_name so should free
+ them before replacing them.  The get_output_file_with_visibility
+ function creates an outf_p only once per each output_name, so it
+ scans the output_files list for previously seen output file names.
+ */
+
+/* Signature of actions in file rules.  */
+typedef outf_p (frul_actionrout_t) (input_file*, char**, char**);
+
+
+struct file_rule_st {
+  const char* frul_srcexpr;    /* Source string for regexp.  */
+  int frul_rflags;             /* Flags passed to regcomp, usually
+                                * REG_EXTENDED.  */
+  regex_t* frul_re;            /* Compiled regular expression
+                                  obtained by regcomp.  */
+  const char* frul_tr_out;     /* Transformation string for making
+                                * the output_name, with $1 ... $9 for
+                                * subpatterns and $0 for the whole
+                                * matched filename.  */
+  const char* frul_tr_for;     /* Tranformation string for making the
+                                  for_name.  */
+  frul_actionrout_t* frul_action; /* The action, if non null, is
+                                  * called once the rule matches, on
+                                  * the transformed out_name &
+                                  * for_name.  It could change them
+                                  * and/or give the output file.  */
+};
+
+/* File rule action handling *.h files.  */
+static outf_p header_dot_h_frul (input_file*, char**, char**);
+
+/* File rule action handling *.c files.  */
+static outf_p source_dot_c_frul (input_file*, char**, char**);
+
+#define NULL_REGEX (regex_t*)0
+
+/* The prefix in our regexp-s matching the directory.  */
+#define DIR_PREFIX_REGEX "^(([^/]*/)*)"
+
+#define NULL_FRULACT (frul_actionrout_t*)0
+
+/* The array of our rules governing file name generation.  Rules order
+   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,
+    "gt-c-family-$3.h", "c-family/$3.c", NULL_FRULACT},
+
+  { DIR_PREFIX_REGEX "c-family/([[:alnum:]_-]*)\\.h$",
+    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},
+
+  { DIR_PREFIX_REGEX "c-tree\\.h$",
+    REG_EXTENDED, NULL_REGEX, "gt-c-decl.h", "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$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-cp-tree.h", "cp/tree.c", NULL_FRULACT },
+
+  /* cp/decl.h & cp/decl.c gives gt-cp-decl.h for cp/decl.c !  */
+  { DIR_PREFIX_REGEX "cp/decl\\.[ch]$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-cp-decl.h", "cp/decl.c", NULL_FRULACT },
+
+  /* cp/name-lookup.h gives gt-cp-name-lookup.h for cp/name-lookup.c !  */
+  { DIR_PREFIX_REGEX "cp/name-lookup\\.h$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-cp-name-lookup.h", "cp/name-lookup.c", NULL_FRULACT },
+
+  /* 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 },
+
+  /* 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 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.  */
+  { DIR_PREFIX_REGEX "([[:alnum:]_-]*)\\.c$",
+    REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.c", 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.  */
+  { DIR_PREFIX_REGEX "([[:alnum:]_-]*)\\.h$",
+    REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.h", header_dot_h_frul},
+
+  { DIR_PREFIX_REGEX "([[:alnum:]_-]*)\\.in$",
+    REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.in", NULL_FRULACT},
+
+  /* Mandatory null last entry signaling end of rules.  */
+  {NULL, 0, NULL_REGEX, NULL, NULL, NULL_FRULACT}
+};
+
+/* Special file rules action for handling *.h header files.  It gives
+   "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 ATTRIBUTE_UNUSED)
+{
+  const char *basename = 0;
+  int lang_index = 0;
+  DBGPRINTF ("inpf %p inpname %s outname %s forname %s",
+            (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);
+
+  if (lang_index >= 0)
+    {
+      /* The header is language specific.  Given output_name &
+        for_name remains unchanged.  The base_files array gives the
+        outf_p.  */
+      DBGPRINTF ("header_dot_h found language specific @ %p '%s'",
+                (void*) base_files[lang_index],
+                (base_files[lang_index])->name);
+      return base_files[lang_index];
+    }
+  else
+    {
+      /* The header is common to all front-end languages.  So
+        output_name is "gtype-desc.c" file.  The calling function
+        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",
+                get_input_file_name (inpf));
+      return NULL;
+    }
+}
+
+
+/* Special file rules action for handling *.c source files using
+ * get_file_gtfilename to compute their output_name and
+ * get_file_basename to compute their for_name.  The output_name is
+ * gt-<LANG>-<BASE>.h for language specific source files, and
+ * gt-<BASE>.h for common source files.  */
+static outf_p
+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));
+  DBGPRINTF ("inpf %p inpname %s original outname %s forname %s",
+            (void*) inpf, get_input_file_name (inpf),
+            *poutname, *pforname);
+  DBGPRINTF ("newoutname %s", newoutname);
+  DBGPRINTF ("newbasename %s", newbasename);
+  free (*poutname);
+  free (*pforname);
+  *poutname = newoutname;
+  *pforname = newbasename;
+  return NULL;
+}
+
+/* Utility function for get_output_file_with_visibility which returns
+ * a malloc-ed substituted string using TRS on matching of the FILNAM
+ * file name, using the PMATCH array.  */
+static char*
+matching_file_name_substitute (const char *filnam, regmatch_t pmatch[10],
+                              const char *trs)
+{
+  struct obstack str_obstack;
+  char *str = NULL;
+  char *rawstr = NULL;
+  const char *pt = NULL;
+  DBGPRINTF ("filnam %s", filnam);
+  obstack_init (&str_obstack);
+  for (pt = trs; *pt; pt++) {
+    char c = *pt;
+    if (c == '$')
+      {
+       if (pt[1] == '$')
+         {
+           /* A double dollar $$ is substituted by a single verbatim
+              dollar, but who really uses dollar signs in file
+              paths? */
+           obstack_1grow (&str_obstack, '$');
+         }
+       else if (ISDIGIT (pt[1]))
+         {
+           /* Handle $0 $1 ... $9 by appropriate substitution.  */
+           int dolnum = pt[1] - '0';
+           int so = pmatch[dolnum].rm_so;
+           int eo = pmatch[dolnum].rm_eo;
+           DBGPRINTF ("so=%d eo=%d dolnum=%d", so, eo, dolnum);
+           if (so>=0 && eo>=so)
+             obstack_grow (&str_obstack, filnam + so, eo - so);
+         }
+       else
+         {
+           /* This can happen only when files_rules is buggy! */
+           gcc_unreachable();
+         }
+       /* Always skip the character after the dollar.  */
+       pt++;
+      }
+    else
+      obstack_1grow (&str_obstack, c);
+  }
+  obstack_1grow (&str_obstack, '\0');
+  rawstr = XOBFINISH (&str_obstack, char *);
+  str = xstrdup (rawstr);
+  obstack_free (&str_obstack, NULL);
+  DBGPRINTF ("matched replacement %s", str);
+  rawstr = NULL;
+  return str;
+}
+
+
 /* An output file, suitable for definitions, that can see declarations
 /* An output file, suitable for definitions, that can see declarations
-   made in INPUT_FILE and is linked into every language that uses
-   INPUT_FILE.  */
+   made in INPF and is linked into every language that uses INPF.
+   Since the result is cached inside INPF, that argument cannot be
+   declared constant, but is "almost" constant. */
 
 outf_p
 
 outf_p
-get_output_file_with_visibility (const char *input_file)
+get_output_file_with_visibility (input_file *inpf)
 {
   outf_p r;
 {
   outf_p r;
-  size_t len;
-  const char *basename;
-  const char *for_name;
-  const char *output_name;
+  char *for_name = NULL;
+  char *output_name = NULL;
+  const char* inpfname;
 
   /* This can happen when we need a file with visibility on a
      structure that we've never seen.  We have to just hope that it's
      globally visible.  */
 
   /* This can happen when we need a file with visibility on a
      structure that we've never seen.  We have to just hope that it's
      globally visible.  */
-  if (input_file == NULL)
-    input_file = "system.h";
+  if (inpf == NULL)
+    inpf = system_h_file;
+
+  /* The result is cached in INPF, so return it if already known.  */
+  if (inpf->inpoutf)
+    return inpf->inpoutf;
 
   /* In plugin mode, return NULL unless the input_file is one of the
      plugin_files.  */
 
   /* In plugin mode, return NULL unless the input_file is one of the
      plugin_files.  */
@@ -1735,80 +1990,140 @@ get_output_file_with_visibility (const char *input_file)
     {
       size_t i;
       for (i = 0; i < nb_plugin_files; i++)
     {
       size_t i;
       for (i = 0; i < nb_plugin_files; i++)
-       if (strcmp (input_file, plugin_files[i]) == 0)
-         return plugin_output;
+       if (inpf == plugin_files[i]) 
+         {
+           inpf->inpoutf = plugin_output;
+           return plugin_output;
+         }
 
       return NULL;
     }
 
 
       return NULL;
     }
 
-  /* Determine the output file name.  */
-  basename = get_file_basename (input_file);
+  inpfname = get_input_file_name (inpf);
 
 
-  len = strlen (basename);
-  if ((len > 2 && memcmp (basename + len - 2, ".c", 2) == 0)
-      || (len > 2 && memcmp (basename + len - 2, ".y", 2) == 0)
-      || (len > 3 && memcmp (basename + len - 3, ".in", 3) == 0))
-    {
-      output_name = get_file_gtfilename (input_file);
-      for_name = basename;
-    }
-  /* Some headers get used by more than one front-end; hence, it
-     would be inappropriate to spew them out to a single gtype-<lang>.h
-     (and gengtype doesn't know how to direct spewage into multiple
-     gtype-<lang>.h headers at this time).  Instead, we pair up these
-     headers with source files (and their special purpose gt-*.h headers).  */
-  else if (strncmp (basename, "c-family", 8) == 0
-          && IS_DIR_SEPARATOR (basename[8])
-          && strcmp (basename + 9, "c-common.h") == 0)
-    output_name = "gt-c-family-c-common.h", for_name = "c-family/c-common.c";
-  else if (strcmp (basename, "c-lang.h") == 0)
-    output_name = "gt-c-decl.h", for_name = "c-decl.c";
-  else if (strcmp (basename, "c-tree.h") == 0)
-    output_name = "gt-c-decl.h", for_name = "c-decl.c";
-  else if (strncmp (basename, "cp", 2) == 0 && IS_DIR_SEPARATOR (basename[2])
-          && strcmp (basename + 3, "cp-tree.h") == 0)
-    output_name = "gt-cp-tree.h", for_name = "cp/tree.c";
-  else if (strncmp (basename, "cp", 2) == 0 && IS_DIR_SEPARATOR (basename[2])
-          && strcmp (basename + 3, "decl.h") == 0)
-    output_name = "gt-cp-decl.h", for_name = "cp/decl.c";
-  else if (strncmp (basename, "cp", 2) == 0 && IS_DIR_SEPARATOR (basename[2])
-          && strcmp (basename + 3, "name-lookup.h") == 0)
-    output_name = "gt-cp-name-lookup.h", for_name = "cp/name-lookup.c";
-  else if (strncmp (basename, "objc", 4) == 0
-          && IS_DIR_SEPARATOR (basename[4])
-          && strcmp (basename + 5, "objc-act.h") == 0)
-    output_name = "gt-objc-objc-act.h", for_name = "objc/objc-act.c";
-  else
-    {
-      int lang_index = get_prefix_langdir_index (basename);
+  /* 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",
+              (void*) inpf, inpfname);
+
+    for (; files_rules[rulix].frul_srcexpr != NULL; rulix++)
+      {
+       DBGPRINTF ("rulix#%d srcexpr %s",
+                  rulix, files_rules[rulix].frul_srcexpr);
+
+       if (!files_rules[rulix].frul_re)
+         {
+           /* Compile the regexpr lazily.  */
+           int err = 0;
+           files_rules[rulix].frul_re = XCNEW (regex_t);
+           err = regcomp (files_rules[rulix].frul_re,
+                          files_rules[rulix].frul_srcexpr,
+                          files_rules[rulix].frul_rflags);
+           if (err)
+             {
+               /* The regular expression compilation fails only when
+                  file_rules is buggy.  */
+               gcc_unreachable ();
+             }
+         }
 
 
-      if (lang_index >= 0)
-       return base_files[lang_index];
+       output_name = NULL;
+       for_name = NULL;
 
 
-      output_name = "gtype-desc.c";
-      for_name = NULL;
+       /* Match the regexpr and trigger the rule if matched.  */
+       {
+         /* We have exactly ten pmatch-s, one for each $0, $1, $2,
+            $3, ... $9.  */
+         regmatch_t pmatch[10];
+         memset (pmatch, 0, sizeof (pmatch));
+         if (!regexec (files_rules[rulix].frul_re,
+                       inpfname, 10, pmatch, 0))
+           {
+             DBGPRINTF ("input @ %p filename %s matched rulix#%d pattern %s",
+                        (void*) inpf, inpfname, rulix,
+                        files_rules[rulix].frul_srcexpr);
+             for_name =
+               matching_file_name_substitute (inpfname, pmatch,
+                                              files_rules[rulix].frul_tr_for);
+             DBGPRINTF ("for_name %s", for_name);
+             output_name =
+               matching_file_name_substitute (inpfname, pmatch,
+                                              files_rules[rulix].frul_tr_out);
+             DBGPRINTF ("output_name %s", output_name);
+             if (files_rules[rulix].frul_action)
+               {
+                 /* Invoke our action routine.  */
+                 outf_p of = NULL;
+                 DBGPRINTF ("before action rulix#%d output_name %s for_name %s",
+                            rulix, output_name, for_name);
+                 of =
+                   (files_rules[rulix].frul_action) (inpf,
+                                                     &output_name, &for_name);
+                 DBGPRINTF ("after action rulix#%d of=%p output_name %s for_name %s",
+                            rulix, (void*)of, output_name, for_name);
+                 /* If the action routine returned something, give it back
+                    immediately and cache it in inpf.  */
+                 if (of)
+                   {
+                     inpf->inpoutf = of;
+                     return of;
+                   }
+               }
+             /* The rule matched, and had no action, or that action did
+                not return any output file but could have changed the
+                output_name or for_name.  We break out of the loop on the
+                files_rules.  */
+             break;
+           }
+         else
+           {
+             /* The regexpr did not match.  */
+             DBGPRINTF ("rulix#%d did not match %s pattern %s",
+                        rulix, inpfname, files_rules[rulix].frul_srcexpr);
+             continue;
+           }
+       }
+      }
+  }
+  if (!output_name || !for_name)
+    {
+      /* This is impossible, and could only happen if the files_rules is
+        incomplete or buggy.  */
+      gcc_unreachable ();
     }
 
     }
 
-  /* Look through to see if we've ever seen this output filename before.  */
+  /* 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)
   for (r = output_files; r; r = r->next)
-    if (strcmp (r->name, output_name) == 0)
-      return r;
+    if (filename_cmp (r->name, output_name) == 0)
+      {
+       inpf->inpoutf = r;
+       DBGPRINTF ("found r @ %p for output_name %s for_name %s", (void*)r,
+                  output_name, for_name);
+       return r;
+      }
 
 
-  /* If not, create it.  */
+  /* If not found, create it, and cache it in inpf.  */
   r = create_file (for_name, output_name);
 
   gcc_assert (r && r->name);
   r = create_file (for_name, output_name);
 
   gcc_assert (r && r->name);
+  DBGPRINTF ("created r @ %p for output_name %s for_name %s", (void*) r,
+            output_name, for_name);
+  inpf->inpoutf = r;
   return r;
   return r;
+
+
 }
 
 /* The name of an output file, suitable for definitions, that can see
 }
 
 /* The name of an output file, suitable for definitions, that can see
-   declarations made in INPUT_FILE and is linked into every language
-   that uses INPUT_FILE.  */
+   declarations made in INPF and is linked into every language that
+   uses INPF.  */
 
 const char *
 
 const char *
-get_output_file_name (const char *input_file)
+get_output_file_name (input_file* inpf)
 {
 {
-  outf_p o = get_output_file_with_visibility (input_file);
+  outf_p o = get_output_file_with_visibility (inpf);
   if (o)
     return o->name;
   return NULL;
   if (o)
     return o->name;
   return NULL;
@@ -1846,6 +2161,7 @@ is_file_equal (outf_p of)
 static void
 close_output_files (void)
 {
 static void
 close_output_files (void)
 {
+  int nbwrittenfiles = 0;
   outf_p of;
 
   for (of = output_files; of; of = of->next)
   outf_p of;
 
   for (of = output_files; of; of = of->next)
@@ -1853,25 +2169,53 @@ close_output_files (void)
 
       if (!is_file_equal (of))
        {
 
       if (!is_file_equal (of))
        {
-         FILE *newfile = fopen (of->name, "w");
+         FILE *newfile = NULL;
+         char *backupname = NULL;
+         /* Back up the old version of the output file gt-FOO.c as
+            BACKUPDIR/gt-FOO.c~ if we have a backup directory.  */
+         if (backup_dir)
+           {
+             backupname = concat (backup_dir, "/",
+                                  lbasename (of->name), "~", NULL);
+             if (!access (of->name, F_OK) && rename (of->name, backupname))
+               fatal ("failed to back up %s as %s: %s",
+                      of->name, backupname, xstrerror (errno));
+           }
+
+         newfile = fopen (of->name, "w");
          if (newfile == NULL)
            fatal ("opening output file %s: %s", of->name, xstrerror (errno));
          if (fwrite (of->buf, 1, of->bufused, newfile) != of->bufused)
            fatal ("writing output file %s: %s", of->name, xstrerror (errno));
          if (fclose (newfile) != 0)
            fatal ("closing output file %s: %s", of->name, xstrerror (errno));
          if (newfile == NULL)
            fatal ("opening output file %s: %s", of->name, xstrerror (errno));
          if (fwrite (of->buf, 1, of->bufused, newfile) != of->bufused)
            fatal ("writing output file %s: %s", of->name, xstrerror (errno));
          if (fclose (newfile) != 0)
            fatal ("closing output file %s: %s", of->name, xstrerror (errno));
+         nbwrittenfiles++;
+         if (verbosity_level >= 2 && backupname)
+           printf ("%s wrote #%-3d %s backed-up in %s\n",
+                   progname, nbwrittenfiles, of->name, backupname);
+         else if (verbosity_level >= 1)
+           printf ("%s write #%-3d %s\n", progname, nbwrittenfiles, of->name);
+         free (backupname);
+       }
+      else 
+       { 
+         /* output file remains unchanged. */
+         if (verbosity_level >= 2)
+           printf ("%s keep %s\n", progname, of->name);
        }
       free (of->buf);
       of->buf = NULL;
       of->bufused = of->buflength = 0;
     }
        }
       free (of->buf);
       of->buf = NULL;
       of->bufused = of->buflength = 0;
     }
+  if (verbosity_level >= 1)
+    printf ("%s wrote %d files.\n", progname, nbwrittenfiles);
 }
 \f
 struct flist
 {
   struct flist *next;
   int started_p;
 }
 \f
 struct flist
 {
   struct flist *next;
   int started_p;
-  const char *name;
+  const input_file* file;
   outf_p f;
 };
 
   outf_p f;
 };
 
@@ -1917,7 +2261,7 @@ 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);
 static int contains_scalar_p (type_p t);
                         type_p structures, type_p param_structs);
 static void write_enum_defn (type_p structures, type_p param_structs);
 static int contains_scalar_p (type_p t);
-static void put_mangled_filename (outf_p, const char *);
+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 finish_root_table (struct flist *flp, const char *pfx,
                               const char *tname, const char *lastname,
                               const char *name);
@@ -1959,6 +2303,9 @@ output_mangled_typename (outf_p of, const_type_p t)
   else
     switch (t->kind)
       {
   else
     switch (t->kind)
       {
+      case TYPE_NONE:
+       gcc_unreachable ();
+       break;
       case TYPE_POINTER:
        oprintf (of, "P");
        output_mangled_typename (of, t->u.p);
       case TYPE_POINTER:
        oprintf (of, "P");
        output_mangled_typename (of, t->u.p);
@@ -2049,13 +2396,14 @@ walk_type (type_p t, struct walk_type_data *d)
   int maybe_undef_p = 0;
   int use_param_num = -1;
   int use_params_p = 0;
   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)
   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
     else if (strcmp (oo->name, "maybe_undef") == 0)
       maybe_undef_p = 1;
     else if (strncmp (oo->name, "use_param", 9) == 0
@@ -2063,12 +2411,13 @@ walk_type (type_p t, struct walk_type_data *d)
       use_param_num = oo->name[9] == '\0' ? 0 : oo->name[9] - '0';
     else if (strcmp (oo->name, "use_params") == 0)
       use_params_p = 1;
       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, "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)
     else if (strcmp (oo->name, "dot") == 0)
       ;
     else if (strcmp (oo->name, "tag") == 0)
@@ -2077,10 +2426,10 @@ walk_type (type_p t, struct walk_type_data *d)
       ;
     else if (strcmp (oo->name, "skip") == 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, "default") == 0)
       ;
-    else if (strcmp (oo->name, "descbits") == 0)
-      ;
     else if (strcmp (oo->name, "param_is") == 0)
       ;
     else if (strncmp (oo->name, "param", 5) == 0
     else if (strcmp (oo->name, "param_is") == 0)
       ;
     else if (strncmp (oo->name, "param", 5) == 0
@@ -2144,6 +2493,12 @@ walk_type (type_p t, struct walk_type_data *d)
       return;
     }
 
       return;
     }
 
+  if (atomic_p && (t->kind != TYPE_POINTER))
+    {
+      error_at_line (d->line, "field `%s' has invalid option `atomic'\n", d->val);
+      return;
+    }
+
   switch (t->kind)
     {
     case TYPE_SCALAR:
   switch (t->kind)
     {
     case TYPE_SCALAR:
@@ -2159,6 +2514,25 @@ walk_type (type_p t, struct walk_type_data *d)
            break;
          }
 
            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)
        if (!length)
          {
            if (!UNION_OR_STRUCT_P (t->u.p)
@@ -2318,8 +2692,9 @@ 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)
 
        /* 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;
 
        d->prev_val[2] = oldval;
        d->prev_val[1] = oldprevval2;
 
        d->prev_val[2] = oldval;
        d->prev_val[1] = oldprevval2;
@@ -2350,16 +2725,19 @@ walk_type (type_p t, struct walk_type_data *d)
 
            d->reorder_fn = NULL;
            for (oo = f->opt; oo; oo = oo->next)
 
            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, "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 (strcmp (oo->name, "reorder") == 0
+                 && oo->kind == OPTION_STRING)
+               d->reorder_fn = oo->info.string;
              else if (strncmp (oo->name, "use_param", 9) == 0
                       && (oo->name[9] == '\0' || ISDIGIT (oo->name[9])))
                use_param_p = 1;
              else if (strncmp (oo->name, "use_param", 9) == 0
                       && (oo->name[9] == '\0' || ISDIGIT (oo->name[9])))
                use_param_p = 1;
@@ -2387,7 +2765,8 @@ walk_type (type_p t, struct walk_type_data *d)
              {
                fprintf (stderr,
                         "%s:%d: warning: field `%s' is missing `tag' or `default' option\n",
              {
                fprintf (stderr,
                         "%s:%d: warning: field `%s' is missing `tag' or `default' option\n",
-                        d->line->file, d->line->line, f->name);
+                        get_input_file_name (d->line->file), d->line->line, 
+                        f->name);
                continue;
              }
            else if (union_p && !(default_p || tagid))
                continue;
              }
            else if (union_p && !(default_p || tagid))
@@ -2472,6 +2851,8 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
 
   switch (f->kind)
     {
 
   switch (f->kind)
     {
+    case TYPE_NONE:
+      gcc_unreachable ();
     case TYPE_POINTER:
       oprintf (d->of, "%*s%s (%s%s", d->indent, "",
               wtd->subfield_marker_routine, cast, d->val);
     case TYPE_POINTER:
       oprintf (d->of, "%*s%s (%s%s", d->indent, "",
               wtd->subfield_marker_routine, cast, d->val);
@@ -2524,7 +2905,7 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
     case TYPE_SCALAR:
       break;
 
     case TYPE_SCALAR:
       break;
 
-    default:
+    case TYPE_ARRAY:
       gcc_unreachable ();
     }
 }
       gcc_unreachable ();
     }
 }
@@ -2554,16 +2935,21 @@ output_type_enum (outf_p of, type_p s)
 static outf_p
 get_output_file_for_structure (const_type_p s, type_p *param)
 {
 static outf_p
 get_output_file_for_structure (const_type_p s, type_p *param)
 {
-  const char *fn = s->u.s.line.file;
+  const input_file *fn;
   int i;
 
   int i;
 
+  gcc_assert (UNION_OR_STRUCT_P (s));
+  fn = s->u.s.line.file;
+
   /* 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;
 
   /* 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;
 
-  return get_output_file_with_visibility (fn);
+  /* 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));
 }
 
 /* For S, a structure that's part of ORIG_S, and using parameters
 }
 
 /* For S, a structure that's part of ORIG_S, and using parameters
@@ -2587,17 +2973,19 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
 
   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
 
   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
-
   for (opt = s->u.s.opt; opt; opt = opt->next)
   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;
   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)
   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)
@@ -2740,6 +3128,7 @@ static void
 write_types (outf_p output_header, type_p structures, type_p param_structs,
             const struct write_types_data *wtd)
 {
 write_types (outf_p output_header, type_p structures, type_p param_structs,
             const struct write_types_data *wtd)
 {
+  int nbfun = 0;               /* Count the emitted functions.  */
   type_p s;
 
   oprintf (output_header, "\n/* %s*/\n", wtd->comment);
   type_p s;
 
   oprintf (output_header, "\n/* %s*/\n", wtd->comment);
@@ -2763,9 +3152,10 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
        oprintf (output_header, "  } while (0)\n");
 
        for (opt = s->u.s.opt; opt; opt = opt->next)
        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,
              if (t->kind == TYPE_STRUCT
                  || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT)
                oprintf (output_header,
@@ -2829,11 +3219,29 @@ write_types (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)
          {
            type_p ss;
            for (ss = s->u.s.lang_struct; ss; ss = ss->next)
-             write_func_for_structure (s, ss, NULL, wtd);
+             {
+               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);
+             }
          }
        else
          }
        else
-         write_func_for_structure (s, s, NULL, wtd);
+         {
+           nbfun++;
+           DBGPRINTF ("writing func #%d struct s @ %p '%s'",
+                      nbfun, (void*) s, s->u.s.tag);
+           write_func_for_structure (s, s, NULL, wtd);
+         }
       }
       }
+    else
+      {
+       /* Structure s is not possibly pointed to, so can be ignored.  */
+       DBGPRINTF ("ignored s @ %p  '%s' gc_used#%d",
+                  (void*)s,  s->u.s.tag,
+                  (int) s->gc_used);
+      }
+
   for (s = param_structs; s; s = s->next)
     if (s->gc_used == GC_POINTED_TO)
       {
   for (s = param_structs; s; s = s->next)
     if (s->gc_used == GC_POINTED_TO)
       {
@@ -2845,11 +3253,30 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
          {
            type_p ss;
            for (ss = stru->u.s.lang_struct; ss; ss = ss->next)
          {
            type_p ss;
            for (ss = stru->u.s.lang_struct; ss; ss = ss->next)
-             write_func_for_structure (s, ss, param, wtd);
+             {
+               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
          }
        else
-         write_func_for_structure (s, stru, param, wtd);
+         {
+           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);
 }
 
 static const struct write_types_data ggc_wtd = {
 }
 
 static const struct write_types_data ggc_wtd = {
@@ -2951,11 +3378,11 @@ write_local (outf_p output_header, type_p structures, type_p param_structs)
 
        if (s->u.s.line.file == NULL)
          continue;
 
        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)
                {
              if (t->kind == TYPE_STRUCT
                  || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT)
                {
@@ -3039,6 +3466,8 @@ static void
 write_enum_defn (type_p structures, type_p param_structs)
 {
   type_p s;
 write_enum_defn (type_p structures, type_p param_structs)
 {
   type_p s;
+  int nbstruct = 0;
+  int nbparamstruct = 0;
 
   if (!header_file)
     return;
 
   if (!header_file)
     return;
@@ -3047,6 +3476,12 @@ write_enum_defn (type_p structures, type_p param_structs)
   for (s = structures; s; s = s->next)
     if (USED_BY_TYPED_GC_P (s))
       {
   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");
        oprintf (header_file, " gt_ggc_e_");
        output_mangled_typename (header_file, s);
        oprintf (header_file, ",\n");
@@ -3054,12 +3489,19 @@ write_enum_defn (type_p structures, type_p param_structs)
   for (s = param_structs; s; s = s->next)
     if (s->gc_used == GC_POINTED_TO)
       {
   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");
       }
   oprintf (header_file, " gt_types_enum_last\n");
   oprintf (header_file, "};\n");
        oprintf (header_file, " gt_e_");
        output_mangled_typename (header_file, s);
        oprintf (header_file, ",\n");
       }
   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);
+
 }
 
 /* Might T contain any non-pointer elements?  */
 }
 
 /* Might T contain any non-pointer elements?  */
@@ -3081,12 +3523,15 @@ contains_scalar_p (type_p t)
     }
 }
 
     }
 }
 
-/* Mangle FN and print it to F.  */
+/* Mangle INPF and print it to F.  */
 
 static void
 
 static void
-put_mangled_filename (outf_p f, const char *fn)
+put_mangled_filename (outf_p f, const input_file *inpf)
 {
 {
-  const char *name = get_output_file_name (fn);
+  /* The call to get_output_file_name may indirectly update fn since
+     get_output_file_with_visibility caches its result inside, so we
+     need the CONST_CAST.  */
+  const char *name = get_output_file_name (CONST_CAST (input_file*, inpf));
   if (!f || !name)
     return;
   for (; *name != 0; name++)
   if (!f || !name)
     return;
   for (; *name != 0; name++)
@@ -3116,7 +3561,7 @@ finish_root_table (struct flist *flp, const char *pfx, const char *lastname,
   for (fli2 = flp; fli2 && base_files; fli2 = fli2->next)
     if (fli2->started_p)
       {
   for (fli2 = flp; fli2 && base_files; fli2 = fli2->next)
     if (fli2->started_p)
       {
-       lang_bitmap bitmap = get_lang_bitmap (fli2->name);
+       lang_bitmap bitmap = get_lang_bitmap (fli2->file);
        int fnum;
 
        for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
        int fnum;
 
        for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
@@ -3124,7 +3569,7 @@ finish_root_table (struct flist *flp, const char *pfx, const char *lastname,
            {
              oprintf (base_files[fnum],
                       "extern const struct %s gt_%s_", tname, pfx);
            {
              oprintf (base_files[fnum],
                       "extern const struct %s gt_%s_", tname, pfx);
-             put_mangled_filename (base_files[fnum], fli2->name);
+             put_mangled_filename (base_files[fnum], fli2->file);
              oprintf (base_files[fnum], "[];\n");
            }
       }
              oprintf (base_files[fnum], "[];\n");
            }
       }
@@ -3140,7 +3585,7 @@ finish_root_table (struct flist *flp, const char *pfx, const char *lastname,
   for (fli2 = flp; fli2; fli2 = fli2->next)
     if (fli2->started_p)
       {
   for (fli2 = flp; fli2; fli2 = fli2->next)
     if (fli2->started_p)
       {
-       lang_bitmap bitmap = get_lang_bitmap (fli2->name);
+       lang_bitmap bitmap = get_lang_bitmap (fli2->file);
        int fnum;
 
        fli2->started_p = 0;
        int fnum;
 
        fli2->started_p = 0;
@@ -3149,7 +3594,7 @@ finish_root_table (struct flist *flp, const char *pfx, const char *lastname,
          if (bitmap & 1)
            {
              oprintf (base_files[fnum], "  gt_%s_", pfx);
          if (bitmap & 1)
            {
              oprintf (base_files[fnum], "  gt_%s_", pfx);
-             put_mangled_filename (base_files[fnum], fli2->name);
+             put_mangled_filename (base_files[fnum], fli2->file);
              oprintf (base_files[fnum], ",\n");
            }
       }
              oprintf (base_files[fnum], ",\n");
            }
       }
@@ -3206,14 +3651,13 @@ 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,
                  bool emit_pch, type_p field_type, const char *field_name)
 {
                  int has_length, struct fileloc *line, const char *if_marked,
                  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)
     {
   /* 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));
       newv = *v;
       newv.type = field_type;
       newv.name = ACONCAT ((v->name, ".", field_name, NULL));
@@ -3230,13 +3674,13 @@ write_field_root (outf_p f, pair_p v, type_p type, const char *name,
 /* Write out to F the table entry and any marker routines needed to
    mark NAME as TYPE.  V can be one of three values:
 
 /* Write out to F the table entry and any marker routines needed to
    mark NAME as TYPE.  V can be one of three values:
 
-   - null, if NAME is too complex to represent using a single
-   count and stride.  In this case, it is an error for NAME to
-   contain any gc-ed data.
+     - null, if NAME is too complex to represent using a single
+       count and stride.  In this case, it is an error for NAME to
+       contain any gc-ed data.
 
 
-   - the outermost array that contains NAME, if NAME is part of an array.
+     - the outermost array that contains NAME, if NAME is part of an array.
 
 
-   - the C variable that contains NAME, if NAME is not part of an array.
+     - 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
 
    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
@@ -3260,8 +3704,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;
            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, "desc") == 0
+                      && o->kind == OPTION_STRING)
+               desc = o->info.string;
              else if (strcmp (o->name, "param_is") == 0)
                ;
              else
              else if (strcmp (o->name, "param_is") == 0)
                ;
              else
@@ -3280,10 +3725,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;
                  {
                    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)
                    if (tag == NULL || strcmp (tag, desc) != 0)
                      continue;
                    if (validf != NULL)
@@ -3447,15 +3892,17 @@ write_roots (pair_p variables, bool emit_pch)
 
   for (v = variables; v; v = v->next)
     {
 
   for (v = variables; v; v = v->next)
     {
-      outf_p f = get_output_file_with_visibility (v->line.file);
+      outf_p f = 
+       get_output_file_with_visibility (CONST_CAST (input_file*,
+                                                    v->line.file));
       struct flist *fli;
       const char *length = NULL;
       int deletable_p = 0;
       options_p o;
       struct flist *fli;
       const char *length = NULL;
       int deletable_p = 0;
       options_p o;
-
       for (o = v->opt; o; o = o->next)
       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 (strcmp (o->name, "deletable") == 0)
          deletable_p = 1;
        else if (strcmp (o->name, "param_is") == 0)
@@ -3479,8 +3926,8 @@ write_roots (pair_p variables, bool emit_pch)
          fli->f = f;
          fli->next = flp;
          fli->started_p = 0;
          fli->f = f;
          fli->next = flp;
          fli->started_p = 0;
-         fli->name = v->line.file;
-         gcc_assert (fli->name);
+         fli->file = v->line.file;
+         gcc_assert (fli->file);
          flp = fli;
 
          oprintf (f, "\n/* GC roots.  */\n\n");
          flp = fli;
 
          oprintf (f, "\n/* GC roots.  */\n\n");
@@ -3499,7 +3946,8 @@ write_roots (pair_p variables, bool emit_pch)
 
   for (v = variables; v; v = v->next)
     {
 
   for (v = variables; v; v = v->next)
     {
-      outf_p f = get_output_file_with_visibility (v->line.file);
+      outf_p f = get_output_file_with_visibility (CONST_CAST (input_file*,
+                                                             v->line.file));
       struct flist *fli;
       int skip_p = 0;
       int length_p = 0;
       struct flist *fli;
       int skip_p = 0;
       int length_p = 0;
@@ -3535,7 +3983,8 @@ write_roots (pair_p variables, bool emit_pch)
 
   for (v = variables; v; v = v->next)
     {
 
   for (v = variables; v; v = v->next)
     {
-      outf_p f = get_output_file_with_visibility (v->line.file);
+      outf_p f = get_output_file_with_visibility (CONST_CAST (input_file*,
+                                                             v->line.file));
       struct flist *fli;
       int skip_p = 1;
       options_p o;
       struct flist *fli;
       int skip_p = 1;
       options_p o;
@@ -3570,7 +4019,8 @@ write_roots (pair_p variables, bool emit_pch)
 
   for (v = variables; v; v = v->next)
     {
 
   for (v = variables; v; v = v->next)
     {
-      outf_p f = get_output_file_with_visibility (v->line.file);
+      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;
       struct flist *fli;
       const char *if_marked = NULL;
       int length_p = 0;
@@ -3579,12 +4029,11 @@ 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;
       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)
+       else if (strcmp (o->name, "if_marked") == 0
+                      && o->kind == OPTION_STRING)
+         if_marked = o->info.string;
+       if (if_marked == NULL)
        continue;
        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))
       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))
@@ -3618,7 +4067,8 @@ write_roots (pair_p variables, bool emit_pch)
 
   for (v = variables; v; v = v->next)
     {
 
   for (v = variables; v; v = v->next)
     {
-      outf_p f = get_output_file_with_visibility (v->line.file);
+      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;
       struct flist *fli;
       int length_p = 0;
       int if_marked_p = 0;
@@ -3653,7 +4103,8 @@ write_roots (pair_p variables, bool emit_pch)
 
   for (v = variables; v; v = v->next)
     {
 
   for (v = variables; v; v = v->next)
     {
-      outf_p f = get_output_file_with_visibility (v->line.file);
+      outf_p f = get_output_file_with_visibility (CONST_CAST (input_file*,
+                                                             v->line.file));
       struct flist *fli;
       int skip_p = 0;
       options_p o;
       struct flist *fli;
       int skip_p = 0;
       options_p o;
@@ -3688,14 +4139,36 @@ write_roots (pair_p variables, bool emit_pch)
   finish_root_table (flp, "pch_rs", "LAST_GGC_ROOT_TAB", "ggc_root_tab",
                     "gt_pch_scalar_rtab");
 }
   finish_root_table (flp, "pch_rs", "LAST_GGC_ROOT_TAB", "ggc_root_tab",
                     "gt_pch_scalar_rtab");
 }
+/* Record the definition of the vec_prefix structure, as defined in vec.h:
+
+   struct vec_prefix GTY(()) {
+   unsigned num;
+   unsigned alloc;
+   };  */
+static type_p
+vec_prefix_type (void)
+{
+  static type_p prefix_type = NULL;
+  if (prefix_type == NULL)
+    {
+      pair_p fields;
+      static struct fileloc pos = { NULL, 0 };
+      type_p len_ty = create_scalar_type ("unsigned");
+      pos.file = input_file_by_name (__FILE__); pos.line = __LINE__;
+      fields = create_field_at (0, len_ty, "alloc", 0, &pos);
+      fields = create_field_at (fields, len_ty, "num", 0, &pos);
+      prefix_type = new_structure ("vec_prefix", 0, &pos, fields, 0);
+      prefix_type->u.s.bitmap = -1;
+    }
+  return prefix_type;
+}
 
 /* Record the definition of a generic VEC structure, as if we had expanded
    the macros in vec.h:
 
    typedef struct VEC_<type>_base GTY(()) {
 
 /* 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];
+   struct vec_prefix prefix;
+   <type> GTY((length ("%h.prefix.num"))) vec[1];
    } VEC_<type>_base
 
    where the GTY(()) tags are only present if is_scalar is _false_.  */
    } VEC_<type>_base
 
    where the GTY(()) tags are only present if is_scalar is _false_.  */
@@ -3706,7 +4179,6 @@ note_def_vec (const char *type_name, bool is_scalar, struct fileloc *pos)
   pair_p fields;
   type_p t;
   options_p o;
   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)
   const char *name = concat ("VEC_", type_name, "_base", (char *) 0);
 
   if (is_scalar)
@@ -3717,13 +4189,11 @@ note_def_vec (const char *type_name, bool is_scalar, struct fileloc *pos)
   else
     {
       t = resolve_typedef (type_name, pos);
   else
     {
       t = resolve_typedef (type_name, pos);
-      o = create_option (0, "length", "%h.num");
+      o = create_string_option (0, "length", "%h.prefix.num");
     }
     }
-
   /* We assemble the field list in reverse order.  */
   fields = create_field_at (0, create_array (t, "1"), "vec", o, pos);
   /* 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);
+  fields = create_field_at (fields, vec_prefix_type (), "prefix", 0, pos);
 
   do_typedef (name, new_structure (name, 0, pos, fields, 0), pos);
 }
 
   do_typedef (name, new_structure (name, 0, pos, fields, 0), pos);
 }
@@ -3732,7 +4202,7 @@ note_def_vec (const char *type_name, bool is_scalar, struct fileloc *pos)
    we had expanded the macros in vec.h:
 
    typedef struct VEC_<type>_<astrat> {
    we had expanded the macros in vec.h:
 
    typedef struct VEC_<type>_<astrat> {
-   VEC_<type>_base base;
+     VEC_<type>_base base;
    } VEC_<type>_<astrat>;
 */
 void
    } VEC_<type>_<astrat>;
 */
 void
@@ -3777,104 +4247,127 @@ enum alloc_quantity
 enum alloc_zone
 { any_zone, specific_zone };
 
 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,
+/* Writes one typed allocator definition into output F 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
    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)
+write_typed_alloc_def (outf_p f, 
+                       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)));
 {
   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) ",
+  gcc_assert (f != NULL);
+  oprintf (f, "#define ggc_alloc_%s%s", allocator_type, type_name);
+  oprintf (f, "(%s%s%s%s%s) ",
           (variable_size ? "SIZE" : ""),
           (two_args ? ", " : ""),
           (quantity == vector) ? "n" : "",
           (third_arg ? ", " : ""), (zone == specific_zone) ? "z" : "");
           (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);
+  oprintf (f, "((%s%s *)", type_specifier, type_name);
+  oprintf (f, "(ggc_internal_%salloc_stat (", allocator_type);
   if (zone == specific_zone)
   if (zone == specific_zone)
-    oprintf (header_file, "z, ");
+    oprintf (f, "z, ");
   if (variable_size)
   if (variable_size)
-    oprintf (header_file, "SIZE");
+    oprintf (f, "SIZE");
   else
   else
-    oprintf (header_file, "sizeof (%s%s)", type_specifier, type_name);
+    oprintf (f, "sizeof (%s%s)", type_specifier, type_name);
   if (quantity == vector)
   if (quantity == vector)
-    oprintf (header_file, ", n");
-  oprintf (header_file, " MEM_STAT_INFO)))\n");
+    oprintf (f, ", n");
+  oprintf (f, " MEM_STAT_INFO)))\n");
 }
 
 }
 
-/* Writes a typed allocator definition for a struct or union S.  */
+/* Writes a typed allocator definition into output F for a struct or
+   union S, with a given ALLOCATOR_TYPE and QUANTITY for ZONE.  */
 
 static void
 
 static void
-write_typed_struct_alloc_def (const type_p s, const char *allocator_type,
+write_typed_struct_alloc_def (outf_p f,
+                             const type_p s, const char *allocator_type,
                              enum alloc_quantity quantity,
                              enum alloc_zone zone)
 {
                              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);
+  gcc_assert (UNION_OR_STRUCT_P (s));
+  write_typed_alloc_def (f, 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.  */
+/* Writes a typed allocator definition into output F for a typedef P,
+   with a given ALLOCATOR_TYPE and QUANTITY for ZONE.  */
 
 static void
 
 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_typedef_alloc_def (outf_p f,
+                               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);
+  write_typed_alloc_def (f, 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.  */
+/* Writes typed allocator definitions into output F for the types in
+   STRUCTURES and TYPEDEFS that are used by GC.  */
 
 static void
 
 static void
-write_typed_alloc_defns (const type_p structures, const pair_p typedefs)
+write_typed_alloc_defns (outf_p f,
+                         const type_p structures, const pair_p typedefs)
 {
   type_p s;
   pair_p p;
 
 {
   type_p s;
   pair_p p;
 
-  oprintf (header_file,
+  gcc_assert (f != NULL);
+  oprintf (f,
           "\n/* Allocators for known structs and unions.  */\n\n");
   for (s = structures; s; s = s->next)
     {
       if (!USED_BY_TYPED_GC_P (s))
        continue;
           "\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,
+      gcc_assert (UNION_OR_STRUCT_P (s));
+      /* In plugin mode onput output ggc_alloc macro definitions
+        relevant to plugin input files.  */
+      if (nb_plugin_files > 0 
+         && ((s->u.s.line.file == NULL) || !s->u.s.line.file->inpisplugin))
+       continue;
+      write_typed_struct_alloc_def (f, s, "", single, any_zone);
+      write_typed_struct_alloc_def (f, s, "cleared_", single, any_zone);
+      write_typed_struct_alloc_def (f, s, "vec_", vector, any_zone);
+      write_typed_struct_alloc_def (f, s, "cleared_vec_", vector, any_zone);
+      write_typed_struct_alloc_def (f, s, "zone_", single, specific_zone);
+      write_typed_struct_alloc_def (f, s, "zone_cleared_", single,
                                    specific_zone);
                                    specific_zone);
-      write_typed_struct_alloc_def (s, "zone_vec_", vector, specific_zone);
-      write_typed_struct_alloc_def (s, "zone_cleared_vec_", vector,
+      write_typed_struct_alloc_def (f, s, "zone_vec_", vector, specific_zone);
+      write_typed_struct_alloc_def (f, s, "zone_cleared_vec_", vector,
                                    specific_zone);
     }
 
                                    specific_zone);
     }
 
-  oprintf (header_file, "\n/* Allocators for known typedefs.  */\n");
+  oprintf (f, "\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;
   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,
+      /* In plugin mode onput output ggc_alloc macro definitions
+        relevant to plugin input files.  */
+      if (nb_plugin_files > 0) 
+       {
+         struct fileloc* filoc = type_fileloc(s);
+         if (!filoc || !filoc->file->inpisplugin)
+           continue;
+       };
+      write_typed_typedef_alloc_def (f, p, "", single, any_zone);
+      write_typed_typedef_alloc_def (f, p, "cleared_", single, any_zone);
+      write_typed_typedef_alloc_def (f, p, "vec_", vector, any_zone);
+      write_typed_typedef_alloc_def (f, p, "cleared_vec_", vector, any_zone);
+      write_typed_typedef_alloc_def (f, p, "zone_", single, specific_zone);
+      write_typed_typedef_alloc_def (f, p, "zone_cleared_", single,
                                     specific_zone);
                                     specific_zone);
-      write_typed_typedef_alloc_def (p, "zone_cleared_vec_", vector,
+      write_typed_typedef_alloc_def (f, p, "zone_cleared_vec_", vector,
                                     specific_zone);
     }
 }
                                     specific_zone);
     }
 }
@@ -3926,7 +4419,7 @@ output_typename (outf_p of, const_type_p t)
 static void
 write_splay_tree_allocator_def (const_type_p s)
 {
 static void
 write_splay_tree_allocator_def (const_type_p s)
 {
-  outf_p of = get_output_file_for_structure (s, NULL);
+  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, "void * ggc_alloc_splay_tree_");
   output_typename (of, s);
   oprintf (of, " (int sz, void * nl)\n");
@@ -4037,7 +4530,21 @@ dump_options (int indent, options_p opt)
   o = opt;
   while (o)
     {
   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");
       o = o->next;
     }
   printf ("\n");
@@ -4048,7 +4555,8 @@ dump_options (int indent, options_p opt)
 static void
 dump_fileloc (int indent, struct fileloc line)
 {
 static void
 dump_fileloc (int indent, struct fileloc line)
 {
-  printf ("%*cfileloc: file = %s, line = %d\n", indent, ' ', line.file,
+  printf ("%*cfileloc: file = %s, line = %d\n", indent, ' ', 
+         get_input_file_name (line.file),
          line.line);
 }
 
          line.line);
 }
 
@@ -4209,7 +4717,9 @@ dump_structures (const char *name, type_p structures)
   printf ("End of %s\n\n", name);
 }
 
   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)
 
 static void
 dump_everything (void)
@@ -4223,100 +4733,362 @@ dump_everything (void)
 }
 \f
 
 }
 \f
 
+
+/* Option specification for getopt_long.  */
+static const struct option gengtype_long_options[] = {
+  {"help", no_argument, NULL, 'h'},
+  {"version", no_argument, NULL, 'V'},
+  {"verbose", no_argument, NULL, 'v'},
+  {"dump", no_argument, NULL, 'd'},
+  {"debug", no_argument, NULL, 'D'},
+  {"plugin", required_argument, NULL, 'P'},
+  {"srcdir", required_argument, NULL, 'S'},
+  {"backupdir", required_argument, NULL, 'B'},
+  {"inputs", required_argument, NULL, 'I'},
+  {"read-state", required_argument, NULL, 'r'},
+  {"write-state", required_argument, NULL, 'w'},
+  /* Terminating NULL placeholder.  */
+  {NULL, no_argument, NULL, 0},
+};
+
+
+static void
+print_usage (void)
+{
+  printf ("Usage: %s\n", progname);
+  printf ("\t -h | --help " " \t# Give this help.\n");
+  printf ("\t -D | --debug "
+         " \t# Give debug output to debug %s itself.\n", progname);
+  printf ("\t -V | --version " " \t# Give version information.\n");
+  printf ("\t -v | --verbose  \t# Increase verbosity.  Can be given several times.\n");
+  printf ("\t -d | --dump " " \t# Dump state for debugging.\n");
+  printf ("\t -P | --plugin <output-file> <plugin-src> ... "
+         " \t# Generate for plugin.\n");
+  printf ("\t -S | --srcdir <GCC-directory> "
+         " \t# Specify the GCC source directory.\n");
+  printf ("\t -B | --backupdir <directory> "
+         " \t# Specify the backup directory for updated files.\n");
+  printf ("\t -I | --inputs <input-list> "
+         " \t# Specify the file with source files list.\n");
+  printf ("\t -w | --write-state <state-file> " " \t# Write a state file.\n");
+  printf ("\t -r | --read-state <state-file> " " \t# Read a state file.\n");
+}
+
+static void
+print_version (void)
+{
+  printf ("%s %s%s\n", progname, pkgversion_string, version_string);
+  printf ("Report bugs: %s\n", bug_report_url);
+}
+
+/* Parse the program options using getopt_long... */
+static void
+parse_program_options (int argc, char **argv)
+{
+  int opt = -1;
+  while ((opt = getopt_long (argc, argv, "hVvdP:S:B:I:w:r:D",
+                            gengtype_long_options, NULL)) >= 0)
+    {
+      switch (opt)
+       {
+       case 'h':               /* --help */
+         print_usage ();
+         break;
+       case 'V':               /* --version */
+         print_version ();
+         break;
+       case 'd':               /* --dump */
+         do_dump = 1;
+         break;
+       case 'D':               /* --debug */
+         do_debug = 1;
+         break;
+       case 'v':               /* --verbose */
+         verbosity_level++;
+         break;
+       case 'P':               /* --plugin */
+         if (optarg)
+           plugin_output_filename = optarg;
+         else
+           fatal ("missing plugin output file name");
+         break;
+       case 'S':               /* --srcdir */
+         if (optarg)
+           srcdir = optarg;
+         else
+           fatal ("missing source directory");
+         srcdir_len = strlen (srcdir);
+         break;
+       case 'B':               /* --backupdir */
+         if (optarg)
+           backup_dir = optarg;
+         else
+           fatal ("missing backup directory");
+         break;
+       case 'I':               /* --inputs */
+         if (optarg)
+           inputlist = optarg;
+         else
+           fatal ("missing input list");
+         break;
+       case 'r':               /* --read-state */
+         if (optarg)
+           read_state_filename = optarg;
+         else
+           fatal ("missing read state file");
+         DBGPRINTF ("read state %s\n", optarg);
+         break;
+       case 'w':               /* --write-state */
+         DBGPRINTF ("write state %s\n", optarg);
+         if (optarg)
+           write_state_filename = optarg;
+         else
+           fatal ("missing write state file");
+         break;
+       default:
+         fprintf (stderr, "%s: unknown flag '%c'\n", progname, opt);
+         print_usage ();
+         fatal ("unexpected flag");
+       }
+    };
+  if (plugin_output_filename)
+    {
+      /* In plugin mode we require some input files.  */
+      int i = 0;
+      if (optind >= argc)
+       fatal ("no source files given in plugin mode");
+      nb_plugin_files = argc - optind;
+      plugin_files = XNEWVEC (input_file*, nb_plugin_files);
+      for (i = 0; i < (int) nb_plugin_files; i++)
+       {
+         char *name = argv[i + optind];
+         plugin_files[i] = input_file_by_name (name);
+       }
+    }
+}
+
+
+\f
+/******* Manage input files.  ******/
+
+/* Hash table of unique input file names.  */
+static htab_t input_file_htab;
+
+/* Find or allocate a new input_file by hash-consing it.  */
+input_file*
+input_file_by_name (const char* name)
+{
+  PTR* slot;
+  input_file* f = NULL;
+  int namlen = 0;
+  if (!name)
+    return NULL;
+  namlen = strlen (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);
+  if (*slot)
+    {
+      /* Already known input file.  */
+      free (f);
+      return (input_file*)(*slot);
+    }
+  /* New input file.  */
+  *slot = f;
+  return f;
+    }
+
+/* Hash table support routines for input_file-s.  */
+static hashval_t
+htab_hash_inputfile (const void *p)
+{
+  const input_file *inpf = (const input_file *) p;
+  gcc_assert (inpf);
+  return htab_hash_string (get_input_file_name (inpf));
+}
+
+static int
+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 !filename_cmp (get_input_file_name (inpfx), get_input_file_name (inpfy));
+}
+
+
 int
 main (int argc, char **argv)
 {
   size_t i;
 int
 main (int argc, char **argv)
 {
   size_t i;
-  static struct fileloc pos = { this_file, 0 };
-  char *inputlist = 0;
-  int do_dump = 0;
+  static struct fileloc pos = { NULL, 0 };
   outf_p output_header;
   outf_p output_header;
-  char *plugin_output_filename = NULL;
-  /* fatal uses this */
-  progname = "gengtype";
 
 
-  if (argc >= 2 && !strcmp (argv[1], "-d"))
+  /* Mandatory common initializations.  */
+  progname = "gengtype";       /* For fatal and messages.  */
+  /* Create the hash-table used to hash-cons input files.  */
+  input_file_htab =
+    htab_create (800, htab_hash_inputfile, htab_eq_inputfile, NULL);
+  /* Initialize our special input files.  */
+  this_file = input_file_by_name (__FILE__);
+  system_h_file = input_file_by_name ("system.h");
+  /* Set the scalar_is_char union number for predefined scalar types.  */
+  scalar_nonchar.u.scalar_is_char = FALSE;
+  scalar_char.u.scalar_is_char = TRUE;
+
+  parse_program_options (argc, argv);
+
+#if ENABLE_CHECKING
+  if (do_debug)
     {
     {
-      do_dump = 1;
-      argv = &argv[1];
-      argc--;
+      time_t now = (time_t) 0;
+      time (&now);
+      DBGPRINTF ("gengtype started pid %d at %s",
+                (int) getpid (), ctime (&now));
     }
     }
+#endif /* ENABLE_CHECKING */
 
 
-  if (argc >= 6 && !strcmp (argv[1], "-P"))
+  /* Parse the input list and the input files.  */
+  DBGPRINTF ("inputlist %s", inputlist);
+  if (read_state_filename)
     {
     {
-      plugin_output_filename = argv[2];
-      plugin_output = create_file ("GCC", plugin_output_filename);
-      srcdir = argv[3];
-      inputlist = argv[4];
-      nb_plugin_files = argc - 5;
-      plugin_files = XCNEWVEC (char *, nb_plugin_files);
-      for (i = 0; i < nb_plugin_files; i++)
-       {
-         /* Place an all zero lang_bitmap before the plugin file
-            name.  */
-         char *name = argv[i + 5];
-         int len = strlen (name) + 1 + sizeof (lang_bitmap);
-         plugin_files[i] = XCNEWVEC (char, len) + sizeof (lang_bitmap);
-         strcpy (plugin_files[i], name);
-       }
+      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);
+      DBGPRINT_COUNT_TYPE ("param_structs after read_state", param_structs);
     }
     }
-  else if (argc == 3)
+  else if (inputlist)
     {
     {
-      srcdir = argv[1];
-      inputlist = argv[2];
-    }
-  else
-    fatal ("usage: gengtype [-d] [-P pluginout.h] srcdir input-list "
-          "[file1 file2 ... fileN]");
+      /* These types are set up with #define or else outside of where
+         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)
+      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 ("uint64_t", &pos));
+      POS_HERE (do_scalar_typedef ("uint8", &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_typedef ("PTR", 
+                           create_pointer (resolve_typedef ("void", &pos)),
+                           &pos));
+#undef POS_HERE
+      read_input_list (inputlist);
+      for (i = 0; i < num_gt_files; i++)
+       {
+         parse_file (get_input_file_name (gt_files[i]));
+         DBGPRINTF ("parsed file #%d %s", 
+                    (int) i, get_input_file_name (gt_files[i]));
+       }
+      if (verbosity_level >= 1)
+       printf ("%s parsed %d files with %d GTY types\n", 
+               progname, (int) num_gt_files, type_count);
 
 
-  srcdir_len = strlen (srcdir);
+      DBGPRINT_COUNT_TYPE ("structures after parsing", structures);
+      DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs);
 
 
-  read_input_list (inputlist);
+    }
+  else
+    fatal ("either an input list or a read state file should be given");
   if (hit_error)
     return 1;
 
   if (hit_error)
     return 1;
 
-  scalar_char.u.scalar_is_char = true;
-  scalar_nonchar.u.scalar_is_char = false;
-  gen_rtx_next ();
 
 
-  /* These types are set up with #define or else outside of where
-     we can see them.  */
-  pos.line = __LINE__ + 1;
-  do_scalar_typedef ("CUMULATIVE_ARGS", &pos);
-  pos.line++;
-  do_scalar_typedef ("REAL_VALUE_TYPE", &pos);
-  pos.line++;
-  do_scalar_typedef ("FIXED_VALUE_TYPE", &pos);
-  pos.line++;
-  do_scalar_typedef ("double_int", &pos);
-  pos.line++;
-  do_scalar_typedef ("uint64_t", &pos);
-  pos.line++;
-  do_scalar_typedef ("uint8", &pos);
-  pos.line++;
-  do_scalar_typedef ("jword", &pos);
-  pos.line++;
-  do_scalar_typedef ("JCF_u2", &pos);
-  pos.line++;
-  do_scalar_typedef ("void", &pos);
-  pos.line++;
-  do_typedef ("PTR", create_pointer (resolve_typedef ("void", &pos)), &pos);
-
-  for (i = 0; i < num_gt_files; i++)
-    parse_file (gt_files[i]);
+  if (plugin_output_filename)
+    {
+      size_t ix = 0;
+      /* In plugin mode, we should have read a state file, and have
+        given at least one plugin file.  */
+      if (!read_state_filename)
+       fatal ("No read state given in plugin mode for %s",
+              plugin_output_filename);
+
+      if (nb_plugin_files == 0 || !plugin_files)
+       fatal ("No plugin files given in plugin mode for %s",
+              plugin_output_filename);
+
+      /* Parse our plugin files and augment the state.  */
+      for (ix = 0; ix < nb_plugin_files; ix++)
+       {
+         input_file* pluginput = plugin_files [ix];
+         pluginput->inpisplugin = true;
+         parse_file (get_input_file_name (pluginput));
+       }
+      if (hit_error)
+       return 1;
 
 
+      plugin_output = create_file ("GCC", plugin_output_filename);
+      DBGPRINTF ("created plugin_output %p named %s",
+                (void *) plugin_output, plugin_output->name);
+    }
+  else
+    {                          /* No plugin files, we are in normal mode.  */
+      if (!srcdir)
+       fatal ("gengtype needs a source directory in normal mode");
+    }
   if (hit_error)
     return 1;
 
   if (hit_error)
     return 1;
 
+  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);
 
   set_gc_used (variables);
 
+ /* 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)
+    {
+      DBGPRINT_COUNT_TYPE ("structures before write_state", structures);
+      DBGPRINT_COUNT_TYPE ("param_structs before write_state", param_structs);
+
+      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 ();
   open_base_files ();
+
   write_enum_defn (structures, param_structs);
   write_enum_defn (structures, param_structs);
-  write_typed_alloc_defns (structures, typedefs);
   output_header = plugin_output ? plugin_output : header_file;
   output_header = plugin_output ? plugin_output : header_file;
+  write_typed_alloc_defns (output_header, structures, typedefs);
+  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);
   if (plugin_files == NULL)
     {
   write_types (output_header, structures, param_structs, &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, param_structs, &pch_wtd);
       write_local (header_file, structures, param_structs);
     }
@@ -4328,12 +5100,7 @@ main (int argc, char **argv)
   if (do_dump)
     dump_everything ();
 
   if (do_dump)
     dump_everything ();
 
-  if (plugin_files)
-    {
-      for (i = 0; i < nb_plugin_files; i++)
-       free (plugin_files[i] - sizeof (lang_bitmap));
-      free (plugin_files);
-    }
+  /* Don't bother about free-ing any input or plugin file, etc.  */
 
   if (hit_error)
     return 1;
 
   if (hit_error)
     return 1;