OSDN Git Service

PR c++/43875
[pf3gnuchains/gcc-fork.git] / gcc / gengtype.c
index 0ee9c48..cb3d9bb 100644 (file)
@@ -23,6 +23,7 @@
 #include "gengtype.h"
 #include "errors.h"    /* for fatal */
 #include "double-int.h"
+#include "hashtab.h"
 
 /* Data types, macros, etc. used only in this file.  */
 
@@ -73,6 +74,10 @@ 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
   };
@@ -141,10 +146,11 @@ static void oprintf (outf_p o, const char *S, ...)
 static outf_p output_files;
 
 /* The plugin input files and their number; in that case only
-   corresponding gt-<plugin>.h are generated in the current
-   directory.  */
+   a single file is produced.  */
 static char** plugin_files;
-static int nb_plugin_files;
+static size_t nb_plugin_files;
+/* the generated plugin output name & file */
+static outf_p plugin_output;
 
 /* The output header file that is included into pretty much every
    source file.  */
@@ -177,7 +183,7 @@ static void close_output_files (void);
 /* Report an error at POS, printing MSG.  */
 
 void
-error_at_line (struct fileloc *pos, const char *msg, ...)
+error_at_line (const struct fileloc *pos, const char *msg, ...)
 {
   va_list ap;
 
@@ -462,9 +468,9 @@ read_input_list (const char *listname)
         things there are.  (We do not bother resizing the arrays down.)  */
       num_lang_dirs = langno;
       /* Add the plugin files if provided.  */
-      if (plugin_files) 
+      if (plugin_files)
        {
-         int i;
+         size_t i;
          for (i = 0; i < nb_plugin_files; i++)
            gt_files[nfiles++] = plugin_files[i];
        }
@@ -567,6 +573,7 @@ do_typedef (const char *s, type_p t, struct fileloc *pos)
   p->name = s;
   p->type = t;
   p->line = *pos;
+  p->opt = NULL;
   typedefs = p;
 }
 
@@ -975,7 +982,7 @@ write_rtx_next (void)
 {
   outf_p f = get_output_file_with_visibility (NULL);
   int i;
-  if (!f) 
+  if (!f)
     return;
 
   oprintf (f, "\n/* Used to implement the RTX_NEXT macro.  */\n");
@@ -1001,7 +1008,7 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
   options_p nodot;
   int i;
   type_p rtx_tp, rtvec_tp, tree_tp, mem_attrs_tp, note_union_tp, scalar_tp;
-  type_p bitmap_tp, basic_block_tp, reg_attrs_tp, constant_tp, symbol_union_tp;
+  type_p basic_block_tp, reg_attrs_tp, constant_tp, symbol_union_tp;
 
   if (t->kind != TYPE_UNION)
     {
@@ -1017,7 +1024,6 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
   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));
-  bitmap_tp = create_pointer (find_structure ("bitmap_element_def", 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 */
@@ -1116,6 +1122,8 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
                t = scalar_tp, subname = "rt_int";
              else if (i == VALUE && aindex == 0)
                t = scalar_tp, subname = "rt_int";
+             else if (i == DEBUG_EXPR && aindex == 0)
+               t = tree_tp, subname = "rt_tree";
              else if (i == REG && aindex == 1)
                t = scalar_tp, subname = "rt_int";
              else if (i == REG && aindex == 2)
@@ -1162,11 +1170,6 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
              subname = "rt_tree";
              break;
 
-           case 'b':
-             t = bitmap_tp;
-             subname = "rt_bit";
-             break;
-
            case 'B':
              t = basic_block_tp;
              subname = "rt_bb";
@@ -1390,7 +1393,7 @@ set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
                                &length, &skip, &nested_ptr);
 
            if (nested_ptr && f->type->kind == TYPE_POINTER)
-             set_gc_used_type (nested_ptr, GC_POINTED_TO, 
+             set_gc_used_type (nested_ptr, GC_POINTED_TO,
                                pass_param ? param : NULL);
            else if (length && f->type->kind == TYPE_POINTER)
              set_gc_used_type (f->type->u.p, GC_USED, NULL);
@@ -1500,7 +1503,7 @@ create_file (const char *name, const char *oname)
   return f;
 }
 
-/* Print, like fprintf, to O.  
+/* Print, like fprintf, to O.
    N.B. You might think this could be implemented more efficiently
    with vsnprintf().  Unfortunately, there are C libraries that
    provide that function but without the C99 semantics for its return
@@ -1514,7 +1517,7 @@ oprintf (outf_p o, const char *format, ...)
 
   /* In plugin mode, the O could be a NULL pointer, so avoid crashing
      in that case.  */
-  if (!o) 
+  if (!o)
     return;
 
   va_start (ap, format);
@@ -1561,14 +1564,14 @@ open_base_files (void)
   {
     /* The order of files here matters very much.  */
     static const char *const ifiles [] = {
-      "config.h", "system.h", "coretypes.h", "tm.h", "varray.h", 
+      "config.h", "system.h", "coretypes.h", "tm.h",
       "hashtab.h", "splay-tree.h",  "obstack.h", "bitmap.h", "input.h",
       "tree.h", "rtl.h", "function.h", "insn-config.h", "expr.h",
       "hard-reg-set.h", "basic-block.h", "cselib.h", "insn-addr.h",
       "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h",
       "tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h",
       "cfglayout.h", "except.h", "output.h", "gimple.h", "cfgloop.h",
-      "target.h", NULL
+      "target.h", "ipa-prop.h", "lto-streamer.h", NULL
     };
     const char *const *ifp;
     outf_p gtype_desc_c;
@@ -1590,7 +1593,7 @@ static const char *
 get_file_realbasename (const char *f)
 {
   const char * lastslash = strrchr (f, '/');
-  
+
   return (lastslash != NULL) ? lastslash + 1 : f;
 }
 
@@ -1632,7 +1635,7 @@ get_prefix_langdir_index (const char *f)
     {
       const char * langdir = lang_dir_names [lang_index];
       size_t langdir_len = strlen (langdir);
-         
+
       if (f_len > langdir_len
          && IS_DIR_SEPARATOR (f[langdir_len])
          && memcmp (f, langdir, langdir_len) == 0)
@@ -1673,13 +1676,13 @@ get_file_gtfilename (const char *f)
 
   const char *basename = get_file_realbasename (f);
   const char *langdir = get_file_langdir (f);
-  
+
   char * result =
     (langdir ? xasprintf ("gt-%s-%s", langdir, basename)
      : xasprintf ("gt-%s", basename));
 
   /* Then replace all non alphanumerics characters by '-' and change the
-     extenstion to ".h".  We expect the input filename extension was at least
+     extension to ".h".  We expect the input filename extension was at least
      one character long.  */
 
   char *s = result;
@@ -1714,14 +1717,14 @@ get_output_file_with_visibility (const char *input_file)
 
   /* In plugin mode, return NULL unless the input_file is one of the
      plugin_files.  */
-  if (plugin_files && nb_plugin_files > 0) 
-    { 
-      int ix= -1, i;
-      for (i = 0; i < nb_plugin_files && ix < 0; i++)
-      if (strcmp (input_file, plugin_files[i]) == 0) 
-       ix = i;
-      if (ix < 0) 
-       return NULL;
+  if (plugin_files)
+    {
+      size_t i;
+      for (i = 0; i < nb_plugin_files; i++)
+       if (strcmp (input_file, plugin_files[i]) == 0)
+         return plugin_output;
+
+      return NULL;
     }
 
   /* Determine the output file name.  */
@@ -1732,7 +1735,7 @@ get_output_file_with_visibility (const char *input_file)
       || (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); 
+      output_name = get_file_gtfilename (input_file);
       for_name = basename;
     }
   /* Some headers get used by more than one front-end; hence, it
@@ -1758,7 +1761,7 @@ get_output_file_with_visibility (const char *input_file)
   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 
+  else
     {
       int lang_index = get_prefix_langdir_index (basename);
 
@@ -1794,6 +1797,32 @@ get_output_file_name (const char *input_file)
   return NULL;
 }
 
+/* Check if existing file is equal to the in memory buffer. */
+
+static bool
+is_file_equal (outf_p of)
+{
+  FILE *newfile = fopen (of->name, "r");
+  size_t i;
+  bool equal;
+  if (newfile == NULL)
+    return false;
+
+  equal = true;
+  for (i = 0; i < of->bufused; i++)
+    {
+      int ch;
+      ch = fgetc (newfile);
+      if (ch == EOF || ch != (unsigned char) of->buf[i])
+       {
+         equal = false;
+         break;
+       }
+    }
+  fclose (newfile);
+  return equal;
+}
+
 /* Copy the output to its final destination,
    but don't unnecessarily change modification times.  */
 
@@ -1804,35 +1833,20 @@ close_output_files (void)
 
   for (of = output_files; of; of = of->next)
     {
-      FILE * newfile;
 
-      newfile = fopen (of->name, "r");
-      if (newfile != NULL )
-       {
-         int no_write_p;
-         size_t i;
-
-         for (i = 0; i < of->bufused; i++)
-           {
-             int ch;
-             ch = fgetc (newfile);
-             if (ch == EOF || ch != (unsigned char) of->buf[i])
-               break;
-           }
-         no_write_p = i == of->bufused && fgetc (newfile) == EOF;
-         fclose (newfile);
-
-         if (no_write_p)
-           continue;
-       }
-
-      newfile = fopen (of->name, "w");
-      if (newfile == NULL)
-       fatal ("opening output file %s: %s", of->name, strerror (errno));
-      if (fwrite (of->buf, 1, of->bufused, newfile) != of->bufused)
-       fatal ("writing output file %s: %s", of->name, strerror (errno));
-      if (fclose (newfile) != 0)
-       fatal ("closing output file %s: %s", of->name, strerror (errno));
+      if (!is_file_equal(of))
+      {
+        FILE *newfile = fopen (of->name, "w");
+        if (newfile == NULL)
+          fatal ("opening output file %s: %s", of->name, strerror (errno));
+        if (fwrite (of->buf, 1, of->bufused, newfile) != of->bufused)
+          fatal ("writing output file %s: %s", of->name, strerror (errno));
+        if (fclose (newfile) != 0)
+          fatal ("closing output file %s: %s", of->name, strerror (errno));
+      }
+      free(of->buf);
+      of->buf = NULL;
+      of->bufused = of->buflength = 0;
     }
 }
 \f
@@ -1883,7 +1897,7 @@ static void write_types (outf_p output_header,
 static void write_types_local_process_field
      (type_p f, const struct walk_type_data *d);
 static void write_local_func_for_structure
-     (type_p orig_s, type_p s, type_p * param);
+     (const_type_p orig_s, type_p s, type_p * param);
 static void write_local (outf_p output_header,
                          type_p structures,
                         type_p param_structs);
@@ -1894,10 +1908,10 @@ static void finish_root_table (struct flist *flp, const char *pfx,
                               const char *tname, const char *lastname,
                               const char *name);
 static void write_root (outf_p , pair_p, type_p, const char *, int,
-                       struct fileloc *, const char *);
+                       struct fileloc *, const char *, bool);
 static void write_array (outf_p f, pair_p v,
                         const struct write_types_data *wtd);
-static void write_roots (pair_p);
+static void write_roots (pair_p, bool);
 
 /* Parameters for walk_type.  */
 
@@ -1911,7 +1925,7 @@ struct walk_type_data
   const char *prev_val[4];
   int indent;
   int counter;
-  struct fileloc *line;
+  const struct fileloc *line;
   lang_bitmap bitmap;
   type_p *param;
   int used_length;
@@ -2158,9 +2172,9 @@ walk_type (type_p t, struct walk_type_data *d)
                d->indent += 2;
                d->val = xasprintf ("x%d", d->counter++);
                oprintf (d->of, "%*s%s %s * %s%s =\n", d->indent, "",
-                        (nested_ptr_d->type->kind == TYPE_UNION 
-                         ? "union" : "struct"), 
-                        nested_ptr_d->type->u.s.tag, 
+                        (nested_ptr_d->type->kind == TYPE_UNION
+                         ? "union" : "struct"),
+                        nested_ptr_d->type->u.s.tag,
                         d->fn_wants_lvalue ? "" : "const ",
                         d->val);
                oprintf (d->of, "%*s", d->indent + 2, "");
@@ -2248,7 +2262,7 @@ walk_type (type_p t, struct walk_type_data *d)
        else
          oprintf (d->of, "%s", t->u.a.len);
        oprintf (d->of, ");\n");
-       
+
        oprintf (d->of, "%*sfor (i%d = 0; i%d != l%d; i%d++) {\n",
                 d->indent, "",
                 loopcounter, loopcounter, loopcounter, loopcounter);
@@ -2520,6 +2534,24 @@ output_type_enum (outf_p of, type_p s)
     oprintf (of, ", gt_types_enum_last");
 }
 
+/* Return an output file that is suitable for definitions which can
+   reference struct S */
+
+static outf_p
+get_output_file_for_structure (const_type_p s, type_p *param)
+{
+  const char * fn = s->u.s.line.file;
+  int i;
+
+  /* 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);
+}
+
 /* For S, a structure that's part of ORIG_S, and using parameters
    PARAM, write out a routine that:
    - Takes a parameter, a void * but actually of type *S
@@ -2532,8 +2564,6 @@ static void
 write_func_for_structure (type_p orig_s, type_p s, type_p *param,
                          const struct write_types_data *wtd)
 {
-  const char *fn = s->u.s.line.file;
-  int i;
   const char *chain_next = NULL;
   const char *chain_prev = NULL;
   const char *chain_circular = NULL;
@@ -2541,14 +2571,8 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
   options_p opt;
   struct walk_type_data d;
 
-  /* 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;
-
   memset (&d, 0, sizeof (d));
-  d.of = get_output_file_with_visibility (fn);
+  d.of = get_output_file_for_structure (s, param);
 
   for (opt = s->u.s.opt; opt; opt = opt->next)
     if (strcmp (opt->name, "chain_next") == 0)
@@ -2706,6 +2730,9 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
   type_p s;
 
   oprintf (output_header, "\n/* %s*/\n", wtd->comment);
+  /* We first emit the macros and the declarations. Functions' code is
+     emitted afterwards.  This is needed in plugin mode.  */
+  oprintf (output_header, "/* macros and declarations */\n");
   for (s = structures; s; s = s->next)
     if (s->gc_used == GC_POINTED_TO
        || s->gc_used == GC_MAYBE_POINTED_TO)
@@ -2754,21 +2781,11 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
                     s->u.s.tag);
            continue;
          }
-
-       if (s->kind == TYPE_LANG_STRUCT)
-         {
-           type_p ss;
-           for (ss = s->u.s.lang_struct; ss; ss = ss->next)
-             write_func_for_structure (s, ss, NULL, wtd);
-         }
-       else
-         write_func_for_structure (s, s, NULL, wtd);
       }
 
   for (s = param_structs; s; s = s->next)
     if (s->gc_used == GC_POINTED_TO)
       {
-       type_p * param = s->u.param_struct.param;
        type_p stru = s->u.param_struct.stru;
 
        /* Declare the marker procedure.  */
@@ -2782,7 +2799,41 @@ write_types (outf_p output_header, type_p structures, type_p param_structs,
                     s->u.s.tag);
            continue;
          }
+      }
 
+  /* At last we emit the functions code.  */
+  oprintf (output_header, "\n/* functions code */\n");
+  for (s = structures; s; s = s->next)
+    if (s->gc_used == GC_POINTED_TO
+       || s->gc_used == GC_MAYBE_POINTED_TO)
+      {
+       options_p opt;
+
+       if (s->gc_used == GC_MAYBE_POINTED_TO
+           && s->u.s.line.file == NULL)
+         continue;
+       for (opt = s->u.s.opt; opt; opt = opt->next)
+         if (strcmp (opt->name, "ptr_alias") == 0)
+           break;
+       if (opt)
+         continue;
+
+       if (s->kind == TYPE_LANG_STRUCT)
+         {
+           type_p ss;
+           for (ss = s->u.s.lang_struct; ss; ss = ss->next)
+             write_func_for_structure (s, ss, NULL, wtd);
+         }
+       else
+         write_func_for_structure (s, s, NULL, wtd);
+      }
+  for (s = param_structs; s; s = s->next)
+    if (s->gc_used == GC_POINTED_TO)
+      {
+       type_p *param = s->u.param_struct.param;
+       type_p stru = s->u.param_struct.stru;
+       if (stru->u.s.line.file == NULL)
+         continue;
        if (stru->kind == TYPE_LANG_STRUCT)
          {
            type_p ss;
@@ -2844,20 +2895,12 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d)
 */
 
 static void
-write_local_func_for_structure (type_p orig_s, type_p s, type_p *param)
+write_local_func_for_structure (const_type_p orig_s, type_p s, type_p *param)
 {
-  const char *fn = s->u.s.line.file;
-  int i;
   struct walk_type_data d;
 
-  /* 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;
-
   memset (&d, 0, sizeof (d));
-  d.of = get_output_file_with_visibility (fn);
+  d.of = get_output_file_for_structure (s, param);
   d.process_field = write_types_local_process_field;
   d.opt = s->u.s.opt;
   d.line = &s->u.s.line;
@@ -2893,7 +2936,7 @@ write_local (outf_p output_header, type_p structures, type_p param_structs)
 {
   type_p s;
 
-  if (!output_header) 
+  if (!output_header)
     return;
   oprintf (output_header, "\n/* Local pointer-walking routines.  */\n");
   for (s = structures; s; s = s->next)
@@ -2980,7 +3023,7 @@ write_enum_defn (type_p structures, type_p param_structs)
 {
   type_p s;
 
-  if (!header_file) 
+  if (!header_file)
     return;
   oprintf (header_file, "\n/* Enumeration of types known.  */\n");
   oprintf (header_file, "enum gt_types_enum {\n");
@@ -3032,7 +3075,7 @@ static void
 put_mangled_filename (outf_p f, const char *fn)
 {
   const char *name = get_output_file_name (fn);
-  if (!f || !name) 
+  if (!f || !name)
     return;
   for (; *name != 0; name++)
     if (ISALNUM (*name))
@@ -3118,7 +3161,7 @@ finish_root_table (struct flist *flp, const char *pfx, const char *lastname,
 
 static void
 write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
-           struct fileloc *line, const char *if_marked)
+           struct fileloc *line, const char *if_marked, bool emit_pch)
 {
   switch (type->kind)
     {
@@ -3174,7 +3217,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
                    newname = xasprintf ("%s.%s.%s",
                                         name, fld->name, validf->name);
                    write_root (f, v, validf->type, newname, 0, line,
-                               if_marked);
+                               if_marked, emit_pch);
                    free (newname);
                  }
              }
@@ -3186,7 +3229,8 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
              {
                char *newname;
                newname = xasprintf ("%s.%s", name, fld->name);
-               write_root (f, v, fld->type, newname, 0, line, if_marked);
+               write_root (f, v, fld->type, newname, 0, line, if_marked,
+                           emit_pch);
                free (newname);
              }
          }
@@ -3197,7 +3241,8 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
       {
        char *newname;
        newname = xasprintf ("%s[0]", name);
-       write_root (f, v, type->u.a.p, newname, has_length, line, if_marked);
+       write_root (f, v, type->u.a.p, newname, has_length, line, if_marked,
+                   emit_pch);
        free (newname);
       }
       break;
@@ -3226,20 +3271,31 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
        if (! has_length && UNION_OR_STRUCT_P (tp))
          {
            oprintf (f, "    &gt_ggc_mx_%s,\n", tp->u.s.tag);
-           oprintf (f, "    &gt_pch_nx_%s", tp->u.s.tag);
+           if (emit_pch)
+             oprintf (f, "    &gt_pch_nx_%s", tp->u.s.tag);
+           else
+             oprintf (f, "    NULL");
          }
        else if (! has_length && tp->kind == TYPE_PARAM_STRUCT)
          {
            oprintf (f, "    &gt_ggc_m_");
            output_mangled_typename (f, tp);
-           oprintf (f, ",\n    &gt_pch_n_");
-           output_mangled_typename (f, tp);
+           if (emit_pch)
+             {
+               oprintf (f, ",\n    &gt_pch_n_");
+               output_mangled_typename (f, tp);
+             }
+           else
+             oprintf (f, ",\n    NULL");
          }
        else if (has_length
                 && (tp->kind == TYPE_POINTER || UNION_OR_STRUCT_P (tp)))
          {
            oprintf (f, "    &gt_ggc_ma_%s,\n", name);
-           oprintf (f, "    &gt_pch_na_%s", name);
+           if (emit_pch)
+             oprintf (f, "    &gt_pch_na_%s", name);
+           else
+             oprintf (f, "    NULL");
          }
        else
          {
@@ -3328,7 +3384,7 @@ write_array (outf_p f, pair_p v, const struct write_types_data *wtd)
 /* Output a table describing the locations and types of VARIABLES.  */
 
 static void
-write_roots (pair_p variables)
+write_roots (pair_p variables, bool emit_pch)
 {
   pair_p v;
   struct flist *flp = NULL;
@@ -3416,7 +3472,7 @@ write_roots (pair_p variables)
          oprintf (f, "[] = {\n");
        }
 
-      write_root (f, v, v->type, v->name, length_p, &v->line, NULL);
+      write_root (f, v, v->type, v->name, length_p, &v->line, NULL, emit_pch);
     }
 
   finish_root_table (flp, "ggc_r", "LAST_GGC_ROOT_TAB", "ggc_root_tab",
@@ -3495,12 +3551,15 @@ write_roots (pair_p variables)
        }
 
       write_root (f, v, v->type->u.p->u.param_struct.param[0],
-                    v->name, length_p, &v->line, if_marked);
+                 v->name, length_p, &v->line, if_marked, emit_pch);
     }
 
   finish_root_table (flp, "ggc_rc", "LAST_GGC_CACHE_TAB", "ggc_cache_tab",
                     "gt_ggc_cache_rtab");
 
+  if (!emit_pch)
+    return;
+
   for (v = variables; v; v = v->next)
     {
       outf_p f = get_output_file_with_visibility (v->line.file);
@@ -3530,7 +3589,7 @@ write_roots (pair_p variables)
          oprintf (f, "[] = {\n");
        }
 
-      write_root (f, v, v->type, v->name, length_p, &v->line, NULL);
+      write_root (f, v, v->type, v->name, length_p, &v->line, NULL, emit_pch);
     }
 
   finish_root_table (flp, "pch_rc", "LAST_GGC_ROOT_TAB", "ggc_root_tab",
@@ -3632,6 +3691,245 @@ note_def_vec_alloc (const char *type, const char *astrat, struct fileloc *pos)
   do_typedef (astratname, new_structure (astratname, 0, pos, field, 0), pos);
 }
 
+static void dump_pair (int indent, pair_p p);
+static void dump_type (int indent, type_p p);
+static void dump_type_list (int indent, type_p p);
+
+#define INDENT 2
+
+/* Dumps the value of typekind KIND.  */
+
+static void
+dump_typekind (int indent, enum typekind kind)
+{
+  printf ("%*ckind = ", indent, ' ');
+  switch (kind)
+    {
+    case TYPE_SCALAR: printf ("TYPE_SCALAR"); break;
+    case TYPE_STRING: printf ("TYPE_STRING"); break;
+    case TYPE_STRUCT: printf ("TYPE_STRUCT"); break;
+    case TYPE_UNION:  printf ("TYPE_UNION"); break;
+    case TYPE_POINTER: printf ("TYPE_POINTER"); break;
+    case TYPE_ARRAY: printf ("TYPE_ARRAY"); break;
+    case TYPE_LANG_STRUCT: printf ("TYPE_LANG_STRUCT"); break;
+    case TYPE_PARAM_STRUCT: printf ("TYPE_PARAM_STRUCT"); break;
+    default: gcc_unreachable ();
+    }
+  printf ("\n");
+}
+
+/* Dumps the value of GC_USED flag.  */
+
+static void
+dump_gc_used (int indent, enum gc_used_enum gc_used)
+{
+  printf ("%*cgc_used = ", indent, ' ');
+  switch (gc_used)
+    {
+    case GC_UNUSED: printf ("GC_UNUSED"); break;
+    case GC_USED: printf ("GC_USED"); break;
+    case GC_MAYBE_POINTED_TO: printf ("GC_MAYBE_POINTED_TO"); break;
+    case GC_POINTED_TO: printf ("GC_POINTED_TO"); break;
+    default: gcc_unreachable ();
+    }
+  printf ("\n");
+}
+
+/* Dumps the type options OPT.  */
+
+static void
+dump_options (int indent, options_p opt)
+{
+  options_p o;
+  printf ("%*coptions = ", indent, ' ');
+  o = opt;
+  while (o)
+    {
+       printf ("%s:%s ", o->name, o->info);
+       o = o->next;
+    }
+  printf ("\n");
+}
+
+/* Dumps the source file location in LINE.  */
+
+static void
+dump_fileloc (int indent, struct fileloc line)
+{
+  printf ("%*cfileloc: file = %s, line = %d\n", indent, ' ', line.file,
+         line.line);
+}
+
+/* Recursively dumps the struct, union, or a language-specific
+   struct T.  */
+
+static void
+dump_type_u_s (int indent, type_p t)
+{
+  pair_p fields;
+
+  gcc_assert (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION
+             || t->kind == TYPE_LANG_STRUCT);
+  printf ("%*cu.s.tag = %s\n", indent, ' ', t->u.s.tag);
+  dump_fileloc (indent, t->u.s.line);
+  printf ("%*cu.s.fields =\n", indent, ' ');
+  fields = t->u.s.fields;
+  while (fields)
+    {
+       dump_pair (indent + INDENT, fields);
+       fields = fields->next;
+    }
+  printf ("%*cend of fields of type %p\n", indent, ' ', (void *) t);
+  dump_options (indent, t->u.s.opt);
+  printf ("%*cu.s.bitmap = %X\n", indent, ' ', t->u.s.bitmap);
+  if (t->kind == TYPE_LANG_STRUCT)
+    {
+      printf ("%*cu.s.lang_struct:\n", indent, ' ');
+      dump_type_list (indent + INDENT, t->u.s.lang_struct);
+    }
+}
+
+/* Recursively dumps the array T.  */
+
+static void
+dump_type_u_a (int indent, type_p t)
+{
+  gcc_assert (t->kind == TYPE_ARRAY);
+  printf ("%*clen = %s, u.a.p:\n", indent, ' ', t->u.a.len);
+  dump_type_list (indent + INDENT, t->u.a.p);
+}
+
+/* Recursively dumps the parameterized struct T.  */
+
+static void
+dump_type_u_param_struct (int indent, type_p t)
+{
+  int i;
+  gcc_assert (t->kind == TYPE_PARAM_STRUCT);
+  printf ("%*cu.param_struct.stru:\n", indent, ' ');
+  dump_type_list (indent, t->u.param_struct.stru);
+  dump_fileloc (indent, t->u.param_struct.line);
+  for (i = 0; i < NUM_PARAM; i++)
+    {
+      if (t->u.param_struct.param[i] == NULL)
+       continue;
+      printf ("%*cu.param_struct.param[%d]:\n", indent, ' ', i);
+      dump_type (indent + INDENT, t->u.param_struct.param[i]);
+    }
+}
+
+/* Recursively dumps the type list T.  */
+
+static void
+dump_type_list (int indent, type_p t)
+{
+  type_p p = t;
+  while (p)
+    {
+      dump_type (indent, p);
+      p = p->next;
+    }
+}
+
+static htab_t seen_types;
+
+/* Recursively dumps the type T if it was not dumped previously.  */
+
+static void
+dump_type (int indent, type_p t)
+{
+  PTR *slot;
+
+  printf ("%*cType at %p: ", indent, ' ', (void *)t);
+  slot = htab_find_slot (seen_types, t, INSERT);
+  if (*slot != NULL)
+    {
+      printf ("already seen.\n");
+      return;
+    }
+  *slot = t;
+  printf ("\n");
+
+  dump_typekind (indent, t->kind);
+  printf ("%*cpointer_to = %p\n", indent + INDENT, ' ',
+         (void *)t->pointer_to);
+  dump_gc_used (indent + INDENT, t->gc_used);
+  switch (t->kind)
+    {
+    case TYPE_SCALAR:
+      printf ("%*cscalar_is_char = %s\n", indent + INDENT, ' ',
+             t->u.scalar_is_char ? "true" : "false");
+      break;
+    case TYPE_STRING:
+      break;
+    case TYPE_STRUCT:
+    case TYPE_UNION:
+    case TYPE_LANG_STRUCT:
+      dump_type_u_s (indent + INDENT, t);
+      break;
+    case TYPE_POINTER:
+      printf ("%*cp:\n", indent + INDENT, ' ');
+      dump_type (indent + INDENT, t->u.p);
+      break;
+    case TYPE_ARRAY:
+      dump_type_u_a (indent + INDENT, t);
+      break;
+    case TYPE_PARAM_STRUCT:
+      dump_type_u_param_struct (indent + INDENT, t);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  printf ("%*cEnd of type at %p\n", indent, ' ', (void *)t);
+}
+
+/* Dumps the pair P.  */
+
+static void
+dump_pair (int indent, pair_p p)
+{
+  printf ("%*cpair: name = %s\n", indent, ' ', p->name);
+  dump_type (indent, p->type);
+  dump_fileloc (indent, p->line);
+  dump_options (indent, p->opt);
+  printf ("%*cEnd of pair %s\n", indent, ' ', p->name);
+}
+
+/* Dumps the list of pairs PP.  */
+
+static void
+dump_pair_list (const char * name, pair_p pp)
+{
+  pair_p p;
+  printf ("%s:\n", name);
+  for (p = pp; p != NULL; p = p->next)
+    dump_pair (0, p);
+  printf ("End of %s\n\n", name);
+}
+
+/* Dumps the STRUCTURES.  */
+
+static void
+dump_structures (const char * name, type_p structures)
+{
+  printf ("%s:\n", name);
+  dump_type_list (0, structures);
+  printf ("End of %s\n\n", name);
+}
+
+/* Dumps the internal structures of gengtype.  */
+
+static void
+dump_everything (void)
+{
+  seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL);
+  dump_pair_list ("typedefs", typedefs);
+  dump_structures ("structures", structures);
+  dump_structures ("param_structs", param_structs);
+  dump_pair_list ("variables", variables);
+  htab_delete (seen_types);
+}
+
 \f
 int
 main (int argc, char **argv)
@@ -3639,23 +3937,45 @@ main (int argc, char **argv)
   size_t i;
   static struct fileloc pos = { this_file, 0 };
   char* inputlist = 0;
+  int do_dump = 0;
+  outf_p output_header;
+  char* plugin_output_filename = NULL;
   /* fatal uses this */
   progname = "gengtype";
 
-  if (argc >= 5 && !strcmp (argv[1], "-p")) 
+  if (argc >= 2 && !strcmp (argv[1], "-d"))
     {
-      srcdir = argv[2];
-      inputlist = argv[3];
-      plugin_files = argv+4;
-      nb_plugin_files = argc-4;
+      do_dump = 1;
+      argv = &argv[1];
+      argc--;
+    }
+
+  if (argc >= 6 && !strcmp (argv[1], "-P"))
+    {
+      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);
+      }
     }
-  else if (argc == 3) 
+  else if (argc == 3)
     {
       srcdir = argv[1];
       inputlist = argv[2];
-    } 
+    }
   else
-    fatal ("usage: gengtype [-p] srcdir input-list [file1 file2 ... fileN]");
+    fatal ("usage: gengtype [-d] [-P pluginout.h] srcdir input-list "
+           "[file1 file2 ... fileN]");
 
   srcdir_len = strlen (srcdir);
 
@@ -3691,13 +4011,27 @@ main (int argc, char **argv)
 
   open_base_files ();
   write_enum_defn (structures, param_structs);
-  write_types (header_file, structures, param_structs, &ggc_wtd);
-  write_types (header_file, structures, param_structs, &pch_wtd);
-  write_local (header_file, structures, param_structs);
-  write_roots (variables);
+  output_header = plugin_output ? plugin_output : header_file;
+  write_types (output_header, structures, param_structs, &ggc_wtd);
+  if (plugin_files == NULL)
+    {
+      write_types (header_file, structures, param_structs, &pch_wtd);
+      write_local (header_file, structures, param_structs);
+    }
+  write_roots (variables, plugin_files == NULL);
   write_rtx_next ();
   close_output_files ();
 
+  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);
+  }
+
   if (hit_error)
     return 1;
   return 0;