Patchwork gengtype plugin improvement last2round - patch3 [inputfile]

login
register
mail settings
Submitter Basile Starynkevitch
Date Oct. 20, 2010, 8:09 p.m.
Message ID <20101020220935.cac67eac.basile@starynkevitch.net>
Download mbox | patch
Permalink /patch/68469/
State New
Headers show

Comments

Basile Starynkevitch - Oct. 20, 2010, 8:09 p.m.
Hello all,

References:
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01742.html
http://gcc.gnu.org/ml/gcc-patches/2010-10/msg01536.html
http://gcc.gnu.org/ml/gcc-patches/2010-10/msg01452.html

and others linked from them.

After having separately commited the removal of location_s and having
taken account Laurynas's comments
http://gcc.gnu.org/ml/gcc-patches/2010-10/msg01452.html I am attaching
a patch on gengtype adding a real input_file structure relative to
trunk rev 165733.

### gcc/ChangeLog entry ###
2010-10-20  Basile Starynkevitch  <basile@starynkevitch.net>
	    Jeremie Salvucci  <basile@starynkevitch.net>

	* gengtype.c (plugin_files, gt_files, this_file, system_file):
	Change type to input_file.
	(get_file_basename, get_file_realbasename)
	(get_file_srcdir_relative_path, get_file_langdir): Change
argument type to input_file.
	(error_at_line): Use input_file.
	(lang_dir_names, num_lang_dirs): Not static anymore.
	(get_lang_bitmap, set_lang_bitmap): Moved to gengtype.h.
	(read_input_file_name, read_input_list, note_variable)
	(create_field_all, get_file_realbasename)
	(get_file_srcdir_relative_path, get_file_basename)
	(get_file_langdir, get_file_gtfilename)
	(get_output_file_with_visibility, get_output_file_name)
	(put_mangled_filename, walk_type, get_output_file_for_structure)
	(parse_program_options)
	(struct flist): Use input_file.
	(input_file_htab): Add variable.
	(input_file_by_name, htab_hash_inputfile, htab_eq_inputfile): 
	Added functions.
	(main): Initialize input_file_htab and this_file and
system_file, use input_file.

	* gengtype.h (struct input_file_st, input_file): Add struct and
	type.
	(CHECK_INPUT_FILE_MAGIC): Added macro.
	(gt_files, num_gt_files, this_file, system_file): Moved from
	gengtype.c and declared as input_file-s.
	(input_file_by_name, get_file_srcdir_relative_path)
	(get_lang_bitmap, set_lang_bitmap)
	(get_output_file_with_visibility, get_output_file_name): Ditto.
	(get_input_file_name): New inlined function.
	(struct fileloc): Use input_file.
	(lang_dir_names, num_lang_dirs): Moved from gengtype.c.

	* gengtype-lex.l: Include errors.h.
	(yybegin): Use input_file_by_name.

	* gengtype-parse.c: Includes errors.h.
	(parse_error): Use input_file.
	(type): Counts the anonymous pseudo-identifiers.

	* Makefile.in (gengtype-lex.o, gengtype-parse.o): Depends upon
	errors.h

#####

Ok for trunk?

PS. I might not have time to send more patches before the GCC Summit next week
(my slides are unfinished).

Patch

Index: gcc/gengtype.c
===================================================================
--- gcc/gengtype.c	(revision 165733)
+++ gcc/gengtype.c	(working copy)
@@ -128,7 +128,6 @@  struct type
 
 
 
-const char *get_output_file_name (const char *);
 
 
 /* The list of output files.  */
@@ -142,12 +141,11 @@  outf_p header_file;
 /* The name of the file containing the list of input files.  */
 static char *inputlist;
 
-/* The plugin input files and their number; in that case only
-   a single file is produced.  */
-static char **plugin_files;
+/* The plugin input files and their number.  */
+static input_file** plugin_files;
 static size_t nb_plugin_files;
 
-/* The generated plugin output file and name.  */
+/* the generated plugin output file and name in plugin mode.  */
 static outf_p plugin_output;
 static char *plugin_output_filename;
 
@@ -174,12 +172,11 @@  static const char* backup_dir;	/* (-B) program opt
 
 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 const char *get_file_langdir (const char *);
+static const char * get_file_langdir (const input_file *);
 
 
 /* Nonzero iff an error has occurred.  */
@@ -199,7 +196,8 @@  error_at_line (const struct fileloc *pos, const ch
 
   va_start (ap, msg);
 
-  fprintf (stderr, "%s:%d: ", pos->file, pos->line);
+  gcc_assert (pos != NULL && pos->file != NULL);
+  fprintf (stderr, "%s:%d: ", get_input_file_name (pos->file), pos->line);
   vfprintf (stderr, msg, ap);
   fputc ('\n', stderr);
   hit_error = true;
@@ -227,76 +225,30 @@  xasprintf (const char *format, ...)
 /* Input file handling. */
 
 /* Table of all input files.  */
-static const char **gt_files;
-static size_t num_gt_files;
+input_file** gt_files;
+size_t num_gt_files;
 
-/* A number of places use the name of this "gengtype.h" file for a
+/* 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.  */
-const char this_file[] = __FILE__;
+   Initialized early in main.  */
+input_file* this_file;
 /* The "system.h" file is likewise specially useful.  */
-const char system_h_file[] = "system.h";
+input_file* system_h_file;
 
 /* 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;
 
-/* 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 || gtfile == system_h_file)
-    {
-      /* Things defined in this "gengtype.c" file or in "system.h" are
-	 universal (and there is no space for their lang_bitmap before
-	 their file names).  */
-      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)
-{
-  int i;
-  for (i = -1; i >= -(int) sizeof (lang_bitmap); i--)
-    {
-      gtfile[i] = n & ((1U << CHAR_BIT) - 1);
-      n >>= CHAR_BIT;
-    }
-}
-
-
 #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)
+dbgprint_count_type_at (const char *fil, int lin, const char*msg,  type_p t)
 {
   int nb_types = 0, nb_scalar = 0, nb_string = 0;
   int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
@@ -482,11 +434,11 @@  read_input_list (const char *listname)
       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);
-      gt_files = XNEWVEC (const char *, num_gt_files);
+      gt_files = XNEWVEC (input_file *, num_gt_files);
 
       for (;;)
 	{
@@ -517,29 +469,30 @@  read_input_list (const char *listname)
 	  else
 	    {
 	      size_t i;
+	      input_file *inpf = input_file_by_name (line);
 	      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.  */
-		    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 "
+		      error_at_line (&epos, "file %s specified more than once "
 				     "for language %s", line,
-				     langno ==
-				     0 ? "(all)" : lang_dir_names[langno -
-								  1]);
+				     langno == 0 
+				     ? "(all)" : lang_dir_names[langno - 1]);
 
 		    bmap |= curlangs;
-		    set_lang_bitmap (CONST_CAST (char *, gt_files[i]), bmap);
+		    set_lang_bitmap (inpf, bmap);
 		    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
@@ -886,7 +839,7 @@  note_variable (const char *s, type_p t, options_p
 /* 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;
 
@@ -895,7 +848,7 @@  create_field_all (pair_p next, type_p type, const
   field->type = type;
   field->name = name;
   field->opt = opt;
-  field->line.file = file;
+  field->line.file = inpf;
   field->line.line = line;
   return field;
 }
@@ -1080,7 +1033,7 @@  adjust_field_rtx_def (type_p t, options_p ARG_UNUS
   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));
-  constant_tp =
+  constant_tp = 
     create_pointer (find_structure ("constant_descriptor_rtx", 0));
   scalar_tp = &scalar_nonchar;	/* rtunion int */
 
@@ -1350,7 +1303,7 @@  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]))
-	  params[num] =
+	  params[num] = 
 	    create_pointer (CONST_CAST2 (type_p, const char *, opt->info));
 	else
 	  params[num] = CONST_CAST2 (type_p, const char *, opt->info);
@@ -1395,7 +1348,7 @@  static void set_gc_used (pair_p);
 
 static void
 process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
-		    int *pass_param, int *length, int *skip,
+		    int *pass_param, int *length, int *skip, 
 		    type_p *nested_ptr)
 {
   options_p o;
@@ -1508,6 +1461,7 @@  set_gc_used (pair_p variables)
   pair_p p;
   for (p = variables; p; p = p->next)
     {
+      DBGPRINTF ("set_gc_used p %p '%s' nbvars %d", (void*) p, p->name, nbvars);
       set_gc_used_type (p->type, GC_USED, NULL);
       nbvars++;
     };
@@ -1592,10 +1546,10 @@  oprintf (outf_p o, const char *format, ...)
       size_t new_len = o->buflength;
       if (new_len == 0)
 	new_len = 1024;
-      do
+      do 
 	{
 	  new_len *= 2;
-	}
+	} 
       while (o->bufused + slength >= new_len);
       o->buf = XRESIZEVEC (char, o->buf, new_len);
       o->buflength = new_len;
@@ -1653,8 +1607,9 @@  open_base_files (void)
    components skipped.  */
 
 static const char *
-get_file_realbasename (const char *f)
+get_file_realbasename (const input_file *inpf)
 {
+  const char* f = get_input_file_name (inpf);
   const char *lastslash = strrchr (f, '/');
 
   return (lastslash != NULL) ? lastslash + 1 : f;
@@ -1663,26 +1618,28 @@  static const char *
 /* For F a filename, return the relative path to F from $(srcdir) if the
    latter is a prefix in F, NULL otherwise.  */
 
-static const char *
-get_file_srcdir_relative_path (const char *f)
+const char *
+get_file_srcdir_relative_path (const input_file *inpf)
 {
-  if (strlen (f) > srcdir_len
-      && IS_DIR_SEPARATOR (f[srcdir_len])
-      && memcmp (f, srcdir, srcdir_len) == 0)
-    return f + srcdir_len + 1;
+  const char* fname = get_input_file_name (inpf);
+  if (strlen (fname) > srcdir_len
+      && IS_DIR_SEPARATOR (fname[srcdir_len])
+      && memcmp (fname, srcdir, srcdir_len) == 0)
+    return fname + 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 *
-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
@@ -1708,18 +1665,18 @@  get_prefix_langdir_index (const char *f)
   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
+   INPF is located, if any, NULL otherwise.  */
 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.  */
 
   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)
@@ -1736,16 +1693,15 @@  static const char *
   return r;
 }
 
-/* The gt- output file name for F.  */
-
+/* The gt- output file name for INPF.  */
 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.  */
 
-  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)
@@ -1767,11 +1723,12 @@  static const char *
 }
 
 /* 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.  */
 
 outf_p
-get_output_file_with_visibility (const char *input_file)
+get_output_file_with_visibility (input_file* inpf)
 {
   outf_p r;
   size_t len;
@@ -1782,30 +1739,30 @@  outf_p
   /* 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;
 
-  /* In plugin mode, return NULL unless the input_file is one of the
-     plugin_files.  */
+  /* In plugin mode, return NULL unless the INPF is one of the
+     plugin_files.  We can compare input_file-s by pointer equality.  */
   if (plugin_files)
     {
       size_t i;
       for (i = 0; i < nb_plugin_files; i++)
-	if (strcmp (input_file, plugin_files[i]) == 0)
+	if (inpf == plugin_files[i])
 	  return plugin_output;
 
       return NULL;
     }
 
   /* Determine the output file name.  */
-  basename = get_file_basename (input_file);
+  basename = get_file_basename (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);
+      output_name = get_file_gtfilename (inpf);
       for_name = basename;
     }
   /* Some headers get used by more than one front-end; hence, it
@@ -1830,8 +1787,7 @@  outf_p
   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])
+  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
@@ -1858,13 +1814,13 @@  outf_p
 }
 
 /* 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 *
-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;
@@ -1902,8 +1858,8 @@  is_file_equal (outf_p of)
 static void
 close_output_files (void)
 {
+  outf_p of;
   int nbwrittenfiles = 0;
-  outf_p of;
 
   for (of = output_files; of; of = of->next)
     {
@@ -1936,11 +1892,12 @@  close_output_files (void)
 		    progname, nbwrittenfiles, of->name, backupname);
 	  else if (verbosity_level >= 1)
 	    printf ("%s write #%-3d %s\n", progname, nbwrittenfiles, of->name);
+	  if (backupname)
 	  free (backupname);
 	}
       else 
 	{ 
-	  /* output file remains unchanged. */
+	  /* Output file remains unchanged. */
 	  if (verbosity_level >= 2)
 	    printf ("%s keep %s\n", progname, of->name);
 	}
@@ -1952,11 +1909,12 @@  close_output_files (void)
     printf ("%s wrote %d files.\n", progname, nbwrittenfiles);
 }
 
-struct flist
+
+struct flist 
 {
   struct flist *next;
   int started_p;
-  const char *name;
+  const input_file *file;
   outf_p f;
 };
 
@@ -1966,8 +1924,8 @@  struct walk_type_data;
    For structures, given a pointer to the item in 'val'.
    For misc. pointers, given the item in 'val'.
 */
-typedef void (*process_field_fn) (type_p f, const struct walk_type_data * p);
-typedef void (*func_name_fn) (type_p s, const struct walk_type_data * p);
+typedef void (*process_field_fn) (type_p f, const struct walk_type_data *p);
+typedef void (*func_name_fn) (type_p s, const struct walk_type_data *p);
 
 /* Parameters for write_types.  */
 
@@ -1999,10 +1957,10 @@  static void write_types_local_process_field
 static void write_local_func_for_structure
   (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);
+                         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);
@@ -2041,7 +1999,7 @@  output_mangled_typename (outf_p of, const_type_p t
 {
   if (t == NULL)
     oprintf (of, "Z");
-  else
+  else 
     switch (t->kind)
       {
       case TYPE_POINTER:
@@ -2057,8 +2015,8 @@  output_mangled_typename (outf_p of, const_type_p t
       case TYPE_STRUCT:
       case TYPE_UNION:
       case TYPE_LANG_STRUCT:
-	oprintf (of, "%lu%s", (unsigned long) strlen (t->u.s.tag),
-		 t->u.s.tag);
+      oprintf (of, "%lu%s", (unsigned long) strlen (t->u.s.tag),
+	       t->u.s.tag);
 	break;
       case TYPE_PARAM_STRUCT:
 	{
@@ -2088,7 +2046,7 @@  output_escaped_param (struct walk_type_data *d, co
   for (p = param; *p; p++)
     if (*p != '%')
       oprintf (d->of, "%c", *p);
-    else
+    else 
       switch (*++p)
 	{
 	case 'h':
@@ -2311,7 +2269,7 @@  walk_type (type_p t, struct walk_type_data *d)
 	    oprintf (d->of, "%*sif (%s != NULL) {\n", d->indent, "", d->val);
 	    d->indent += 2;
 	    oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter);
-	    oprintf (d->of, "%*sfor (i%d = 0; i%d != (size_t)(", d->indent,
+	    oprintf (d->of, "%*sfor (i%d = 0; i%d != (size_t)(", d->indent, 
 		     "", loopcounter, loopcounter);
 	    output_escaped_param (d, length, "length");
 	    oprintf (d->of, "); i%d++) {\n", loopcounter);
@@ -2472,7 +2430,7 @@  walk_type (type_p t, struct walk_type_data *d)
 	      {
 		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))
@@ -2639,16 +2597,27 @@  output_type_enum (outf_p of, type_p s)
 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 = NULL;
   int i;
 
+  if (UNION_OR_STRUCT_P (s))
+    fn = s->u.s.line.file;
+  else if (s->kind == TYPE_PARAM_STRUCT)
+    fn = s->u.param_struct.line.file;
+
+  CHECK_INPUT_FILE_MAGIC (fn);
+
   /* 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);
+  CHECK_INPUT_FILE_MAGIC (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
@@ -2825,8 +2794,8 @@  static void
 write_types (outf_p output_header, type_p structures, type_p param_structs,
 	     const struct write_types_data *wtd)
 {
+  type_p s;
   int nbfun = 0;		/* Count the emitted functions.  */
-  type_p s;
 
   oprintf (output_header, "\n/* %s*/\n", wtd->comment);
   /* We first emit the macros and the declarations. Functions' code is
@@ -2931,12 +2900,9 @@  write_types (outf_p output_header, type_p structur
 	  }
       }
     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)
@@ -2966,22 +2932,21 @@  write_types (outf_p output_header, type_p structur
 	  }
       }
     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 =
+{
   "ggc_m", NULL, "ggc_mark", "ggc_test_and_set_mark", NULL,
   "GC marker procedures.  ",
   FALSE
 };
 
-static const struct write_types_data pch_wtd = {
+static const struct write_types_data pch_wtd =
+{
   "pch_n", "pch_p", "gt_pch_note_object", "gt_pch_note_object",
   "gt_pch_note_reorder",
   "PCH type-walking procedures.  ",
@@ -3068,7 +3033,8 @@  write_local (outf_p output_header, type_p structur
     return;
   oprintf (output_header, "\n/* Local pointer-walking routines.  */\n");
   for (s = structures; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO)
+    if (s->gc_used == GC_POINTED_TO
+	|| s->gc_used == GC_MAYBE_POINTED_TO)
       {
 	options_p opt;
 
@@ -3080,7 +3046,8 @@  write_local (outf_p output_header, type_p structur
 	    {
 	      const_type_p const t = (const_type_p) opt->info;
 	      if (t->kind == TYPE_STRUCT
-		  || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT)
+		  || t->kind == TYPE_UNION
+		  || t->kind == TYPE_LANG_STRUCT)
 		{
 		  oprintf (output_header, "#define gt_pch_p_");
 		  output_mangled_typename (output_header, s);
@@ -3169,10 +3136,10 @@  write_enum_defn (type_p structures, type_p param_s
     return;
   oprintf (header_file, "\n/* Enumeration of types known.  */\n");
   oprintf (header_file, "enum gt_types_enum {\n");
+
   for (s = structures; s; s = s->next)
     if (USED_BY_TYPED_GC_P (s))
       {
-	nbstruct++;
 	DBGPRINTF ("write_enum_defn s @ %p nbstruct %d",
 		   (void*) s, nbstruct);
 	if (UNION_OR_STRUCT_P (s))
@@ -3181,23 +3148,25 @@  write_enum_defn (type_p structures, type_p param_s
 	oprintf (header_file, " gt_ggc_e_");
 	output_mangled_typename (header_file, s);
 	oprintf (header_file, ",\n");
+	nbstruct++;
       }
+
   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");
+	nbparamstruct++;
       }
+
   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?  */
@@ -3222,9 +3191,12 @@  contains_scalar_p (type_p t)
 /* Mangle FN and print it to F.  */
 
 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++)
@@ -3254,15 +3226,16 @@  finish_root_table (struct flist *flp, const char *
   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)
 	  if (bitmap & 1)
 	    {
 	      oprintf (base_files[fnum],
-		       "extern const struct %s gt_%s_", tname, pfx);
-	      put_mangled_filename (base_files[fnum], fli2->name);
+		       "extern const struct %s gt_%s_",
+		       tname, pfx);
+	      put_mangled_filename (base_files[fnum], fli2->file);
 	      oprintf (base_files[fnum], "[];\n");
 	    }
       }
@@ -3271,14 +3244,15 @@  finish_root_table (struct flist *flp, const char *
     size_t fnum;
     for (fnum = 0; base_files && fnum < num_lang_dirs; fnum++)
       oprintf (base_files[fnum],
-	       "EXPORTED_CONST struct %s * const %s[] = {\n", tname, name);
+	       "EXPORTED_CONST struct %s * const %s[] = {\n",
+	       tname, name);
   }
 
 
   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;
@@ -3287,7 +3261,7 @@  finish_root_table (struct flist *flp, const char *
 	  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");
 	    }
       }
@@ -3428,7 +3402,8 @@  write_root (outf_p f, pair_p v, type_p type, const
 		      error_at_line (line,
 				     "both `%s.%s.%s' and `%s.%s.%s' have tag `%s'",
 				     name, fld->name, validf->name,
-				     name, fld->name, ufld->name, tag);
+				     name, fld->name, ufld->name,
+				     tag);
 		    validf = ufld;
 		  }
 		if (validf != NULL)
@@ -3523,7 +3498,9 @@  write_root (outf_p f, pair_p v, type_p type, const
       break;
 
     default:
-      error_at_line (line, "global `%s' is unimplemented type", name);
+      error_at_line (line,
+		     "global `%s' is unimplemented type",
+		     name);
     }
 }
 
@@ -3549,7 +3526,8 @@  write_array (outf_p f, pair_p v, const struct writ
   if (wtd->param_prefix)
     {
       oprintf (f, "static void gt_%sa_%s\n", wtd->param_prefix, v->name);
-      oprintf (f, "    (void *, void *, gt_pointer_operator, void *);\n");
+      oprintf (f,
+       "    (void *, void *, gt_pointer_operator, void *);\n");
       oprintf (f, "static void gt_%sa_%s (ATTRIBUTE_UNUSED void *this_obj,\n",
 	       wtd->param_prefix, v->name);
       oprintf (d.of,
@@ -3564,7 +3542,8 @@  write_array (outf_p f, pair_p v, const struct writ
     }
 
   d.opt = v->opt;
-  oprintf (f, "static void gt_%sa_%s (void *);\n", wtd->prefix, v->name);
+  oprintf (f, "static void gt_%sa_%s (void *);\n",
+	   wtd->prefix, v->name);
   oprintf (f, "static void\ngt_%sa_%s (ATTRIBUTE_UNUSED void *x_p)\n",
 	   wtd->prefix, v->name);
   oprintf (f, "{\n");
@@ -3585,7 +3564,9 @@  write_roots (pair_p variables, bool emit_pch)
 
   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;
@@ -3599,7 +3580,8 @@  write_roots (pair_p variables, bool emit_pch)
 	else if (strcmp (o->name, "param_is") == 0)
 	  ;
 	else if (strncmp (o->name, "param", 5) == 0
-		 && ISDIGIT (o->name[5]) && strcmp (o->name + 6, "_is") == 0)
+		 && ISDIGIT (o->name[5])
+		 && strcmp (o->name + 6, "_is") == 0)
 	  ;
 	else if (strcmp (o->name, "if_marked") == 0)
 	  ;
@@ -3617,8 +3599,8 @@  write_roots (pair_p variables, bool emit_pch)
 	  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");
@@ -3637,7 +3619,9 @@  write_roots (pair_p variables, bool emit_pch)
 
   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;
@@ -3673,7 +3657,9 @@  write_roots (pair_p variables, bool emit_pch)
 
   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;
@@ -3708,7 +3694,9 @@  write_roots (pair_p variables, bool emit_pch)
 
   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;
@@ -3727,8 +3715,7 @@  write_roots (pair_p variables, bool emit_pch)
 	  || v->type->u.p->kind != TYPE_PARAM_STRUCT
 	  || v->type->u.p->u.param_struct.stru != find_structure ("htab", 0))
 	{
-	  error_at_line (&v->line,
-			 "if_marked option used but not hash table");
+	  error_at_line (&v->line, "if_marked option used but not hash table");
 	  continue;
 	}
 
@@ -3756,7 +3743,9 @@  write_roots (pair_p variables, bool emit_pch)
 
   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;
@@ -3791,7 +3780,9 @@  write_roots (pair_p variables, bool emit_pch)
 
   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;
@@ -3910,10 +3901,8 @@  variable_size_p (const type_p s)
   return false;
 }
 
-enum alloc_quantity
-{ single, vector };
-enum alloc_zone
-{ any_zone, specific_zone };
+enum alloc_quantity { single, vector };
+enum alloc_zone { any_zone, specific_zone };
 
 /* Writes one typed allocator definition for type identifier TYPE_NAME with
    optional type specifier TYPE_SPECIFIER.  The allocator name will contain
@@ -4045,8 +4034,7 @@  output_typename (outf_p of, const_type_p t)
       {
 	int i;
 	for (i = 0; i < NUM_PARAM; i++)
-	  if (t->u.param_struct.param[i] != NULL)
-	    {
+	  if (t->u.param_struct.param[i] != NULL) {
 	      output_typename (of, t->u.param_struct.param[i]);
 	      oprintf (of, "_");
 	    }
@@ -4109,32 +4097,15 @@  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 ();
+    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");
 }
@@ -4147,20 +4118,11 @@  dump_gc_used (int indent, enum gc_used_enum gc_use
   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 ();
+    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");
 }
@@ -4186,8 +4148,8 @@  dump_options (int indent, options_p opt)
 static void
 dump_fileloc (int indent, struct fileloc line)
 {
-  printf ("%*cfileloc: file = %s, line = %d\n", indent, ' ', line.file,
-	  line.line);
+  printf ("%*cfileloc: file = %s, line = %d\n", indent, ' ',
+	  get_input_file_name (line.file), line.line);
 }
 
 /* Recursively dumps the struct, union, or a language-specific
@@ -4384,12 +4346,17 @@  static void
 print_usage (void)
 {
   printf ("Usage: %s\n", progname);
-  printf ("\t -h | --help " " \t# Give this help.\n");
+  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");
+	  " \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> "
@@ -4398,8 +4365,10 @@  print_usage (void)
 	  " \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");
+  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
@@ -4414,7 +4383,7 @@  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",
+  while ((opt = getopt_long (argc, argv, "hvVdP:S:B:I:w:r:D",
 			     gengtype_long_options, NULL)) >= 0)
     {
       switch (opt)
@@ -4422,6 +4391,9 @@  parse_program_options (int argc, char **argv)
 	case 'h':		/* --help */
 	  print_usage ();
 	  break;
+	case 'v': /* --verbose */
+	  verbosity_level++;
+	  break;
 	case 'V':		/* --version */
 	  print_version ();
 	  break;
@@ -4431,9 +4403,6 @@  parse_program_options (int argc, char **argv)
 	case 'D':		/* --debug */
 	  do_debug = 1;
 	  break;
-	case 'v':		/* --verbose */
-	  verbosity_level++;
-	  break;
 	case 'P':		/* --plugin */
 	  if (optarg)
 	    plugin_output_filename = optarg;
@@ -4486,16 +4455,69 @@  parse_program_options (int argc, char **argv)
       if (optind >= argc)
 	fatal ("no source files given in plugin mode");
       nb_plugin_files = argc - optind;
-      plugin_files = XNEWVEC (char*, nb_plugin_files);
+      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] = name;
+	  plugin_files[i] = input_file_by_name (name);
 	}
     }
 }
 
 
+
+/******* 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->inpmagic = INPUT_FILE_MAGIC;
+  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 !strcmp (get_input_file_name (inpfx), get_input_file_name (inpfy));
+}
+
+
 int
 main (int argc, char **argv)
 {
@@ -4508,6 +4530,12 @@  main (int argc, char **argv)
   /* 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;
+  /* 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");
 
   parse_program_options (argc, argv);
 
@@ -4519,7 +4547,7 @@  main (int argc, char **argv)
       DBGPRINTF ("gengtype started pid %d at %s",
 		 (int) getpid (), ctime (&now));
     }
-#endif	/* ENABLE_CHECKING */
+#endif /* ENABLE_CHECKING */
 
   /* Parse the input list and the input files.  */
   DBGPRINTF ("inputlist %s", inputlist);
@@ -4535,38 +4563,27 @@  main (int argc, char **argv)
          read_input_list.  */
       pos.file = this_file;
       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);
+      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);
       read_input_list (inputlist);
       for (i = 0; i < num_gt_files; i++)
 	{
-	  parse_file (gt_files[i]);
-	  DBGPRINTF ("parsed file #%d %s", (int) i, 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]));
 	}
+      DBGPRINT_COUNT_TYPE ("structures after parsing", structures);
+      DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs);
       if (verbosity_level >= 1)
 	printf ("%s parsed %d files\n", progname, (int) num_gt_files);
 
-      DBGPRINT_COUNT_TYPE ("structures after parsing", structures);
-      DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs);
-
     }
   else
     fatal ("either an input list or a read state file should be given");
@@ -4577,23 +4594,24 @@  main (int argc, char **argv)
   if (plugin_output_filename)
     {
       size_t ix = 0;
-      /* In plugin mode, we should have read a state file, and have
+      /* In plugin mode, we better 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);
+	warning ("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);
+      if (nb_plugin_files <= 0 || !plugin_files)
+	fatal ("No plugin files given in plugin mode for %s", plugin_output_filename);
 
       /* Parse our plugin files.  */
       for (ix = 0; ix < nb_plugin_files; ix++)
-	parse_file (plugin_files[ix]);
+	{
+	  parse_file (get_input_file_name (plugin_files[ix]));
+	  DBGPRINTF ("parsed plugin file #%d %s", (int) ix,
+		     get_input_file_name (plugin_files[ix]));
+	}
 
       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);
Index: gcc/gengtype.h
===================================================================
--- gcc/gengtype.h	(revision 165733)
+++ gcc/gengtype.h	(working copy)
@@ -25,14 +25,117 @@ 
    represented by a bitmap.  */
 typedef unsigned lang_bitmap;
 
-/* A file position, mostly for error messages.
-   The FILE element may be compared using pointer equality.  */
+/* Variable length structure representing an input file.  A hash table
+   ensure uniqueness for a given input file name.  The only function
+   allocating input_file-s is input_file_by_name.  */
+struct input_file_st 
+{
+#if ENABLE_CHECKING
+  /* The magic number is intended to help debugging gengtype.  We
+     check that it is indeed what it should be.  This could help
+     catching bugs where an input_file pointer is bogus.  */
+  int inpmagic;		/* Always INPUT_FILE_MAGIC.  */
+#endif /*ENABLE_CHECKING*/
+  struct outf* inpoutf;	/* Cached corresponding output file, computed
+			   in get_output_file_with_visibility.  */
+  lang_bitmap inpbitmap; /* The set of languages using this file.  */
+  char inpname[1]; /* a flexible array, ended by a null char.  */
+};
+typedef struct input_file_st input_file;
+
+#if ENABLE_CHECKING
+/*  0x371c433f is 924599103 in decimal, and was randomly choosen.  The
+    input file magic number is intended to help catching bugs.  */
+#define INPUT_FILE_MAGIC 0x371c433f
+  /* This is a fancy assert which displays a more precise message.  It
+     should never happen!  But it can help a lot when hacking
+     gengtype.  */
+#define CHECK_INPUT_FILE_MAGIC(Inpf)				\
+    do {							\
+      const input_file* badinpf = Inpf;			\
+      if (badinpf && badinpf->inpmagic != INPUT_FILE_MAGIC)	\
+	fatal ("corrupted input file %p bad magic %d in %s:%d",	\
+	       (const void*) badinpf, badinpf->inpmagic,	\
+	       lbasename (__FILE__), __LINE__);			\
+    } while (0)
+#else
+#define CHECK_INPUT_FILE_MAGIC(Inpf) do{} while (0)
+#endif	/* ENABLE_CHECKING */
+
+/* Table of all input files, and its size.  */
+extern input_file** gt_files;
+extern size_t num_gt_files;
+
+/* 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.  We
+   also need to refer to the "system.h" file specifically.  These two
+   pointers are initialized early in main.  */
+extern input_file* this_file;
+extern input_file* system_h_file;
+
+/* Retrieve or create the input_file for a given name, which is a file
+   path.  This is the only function allocating input_file-s and it is
+   hash-consing them.  */
+input_file* input_file_by_name (const char* name);
+
+
+/* For F an input_file, return the relative path to F from $(srcdir)
+   if the latter is a prefix in F, NULL otherwise.  */
+const char *get_file_srcdir_relative_path (const input_file *inpf);
+
+/* Get the name of an input file.  */
+static inline const char*
+get_input_file_name (const input_file *inpf)
+{
+  if (inpf)
+    {
+      CHECK_INPUT_FILE_MAGIC (inpf);
+      return inpf->inpname;
+    }
+  return NULL;
+}
+
+/* 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.
+  */
+
+static inline lang_bitmap
+get_lang_bitmap (const input_file* inpf)
+{
+  if (inpf == NULL)
+    return 0;
+  CHECK_INPUT_FILE_MAGIC (inpf);
+  return inpf->inpbitmap;
+}
+
+/* Set the bitmap returned by get_lang_bitmap.  The only legitimate
+   callers of this function are read_input_list & read_state_*.  */
+static inline void
+set_lang_bitmap (input_file* inpf, lang_bitmap n)
+{
+  gcc_assert (inpf);
+  CHECK_INPUT_FILE_MAGIC (inpf);
+  inpf->inpbitmap = n;
+}
+
+/* A file position, mostly for error messages.  The FILE element may
+   be compared using pointer equality since it is hash-consed.  */
 struct fileloc
 {
-  const char *file;
+  const input_file *file;
   int line;
 };
 
+ 
+/* Vector of per-language directories.  */
+extern const char **lang_dir_names;
+extern size_t num_lang_dirs;
+
 /* Data types handed around within, but opaque to, the lexer and parser.  */
 typedef struct pair *pair_p;
 typedef struct type *type_p;
@@ -67,10 +170,18 @@  oprintf (outf_p o, const char *S, ...)
   ATTRIBUTE_PRINTF_2;
 
 /* 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);
+   made in INPF and is linked into every language that uses INPF.  May
+   return NULL in plugin mode.  The INPF argument is almost const, but
+   since the result is cached in its inpoutf field it cannot be
+   declared const, because this function stores the computed output
+   file in that field to speed it up for further invocations.  */
+outf_p get_output_file_with_visibility (input_file* inpf);
 
+/* The name of an output file, suitable for definitions, that can see
+   declarations made in INPF and is linked into every language that
+   uses INPF.  May return NULL.  */
+const char *get_output_file_name (input_file *inpf);
+
 /* Source directory.  */
 extern const char *srcdir;	/* (-S) program argument. */
 
Index: gcc/gengtype-lex.l
===================================================================
--- gcc/gengtype-lex.l	(revision 165733)
+++ gcc/gengtype-lex.l	(working copy)
@@ -1,6 +1,6 @@ 
 /* -*- indented-text -*- */
 /* Process source files and output type information.
-   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009
+   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -24,7 +24,9 @@  along with GCC; see the file COPYING3.  If not see
 %{
 #include "bconfig.h"
 #include "system.h"
+#include "errors.h"             /* for fatal, needed by gengtype.h */
 
+
 #define malloc xmalloc
 #define realloc xrealloc
 
@@ -202,7 +204,7 @@  yybegin (const char *fname)
       perror (fname);
       exit (1);
     }
-  lexer_line.file = fname;
+  lexer_line.file = input_file_by_name (fname);
   lexer_line.line = 1;
 }
 
Index: gcc/gengtype-parse.c
===================================================================
--- gcc/gengtype-parse.c	(revision 165733)
+++ gcc/gengtype-parse.c	(working copy)
@@ -1,5 +1,5 @@ 
 /* Process source files and output type information.
-   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -19,6 +19,7 @@ 
 
 #include "bconfig.h"
 #include "system.h"
+#include "errors.h"	/* for fatal, needed by gengtype.h */
 #include "gengtype.h"
 
 /* This is a simple recursive-descent parser which understands a subset of
@@ -135,7 +136,8 @@  parse_error (const char *msg, ...)
 {
   va_list ap;
 
-  fprintf (stderr, "%s:%d: parse error: ", lexer_line.file, lexer_line.line);
+  fprintf (stderr, "%s:%d: parse error: ", 
+	   get_input_file_name (lexer_line.file), lexer_line.line);
 
   va_start (ap, msg);
   vfprintf (stderr, msg, ap);
@@ -708,6 +710,7 @@  static type_p
 type (options_p *optsp, bool nested)
 {
   const char *s;
+  static int anonymous_count; /* To generate unique pseudo-identifiers! */
   *optsp = 0;
   switch (token ())
     {
@@ -750,7 +753,32 @@  type (options_p *optsp, bool nested)
 	if (token () == ID)
 	  s = advance ();
 	else
-	  s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
+	  {
+	    /* We don't want to wire in the source directory (because
+	       in plugin mode, the source directory can be unavailable
+	       since gengtype has read its state).  So if the input is
+	       from GCC source directory, we use its relative path to
+	       build an anonymous unique tag.  */
+	    const char* relp = get_file_srcdir_relative_path (lexer_line.file);
+	    anonymous_count++;
+	    if (relp)
+	      {
+		/* The input file is a GCC source file, we use a double
+		   colon after anonymous.  To be sure s is truly unique,
+		   we also use anonymous_count.  */
+		s = xasprintf ("anonymous::%s:%d::%d",
+			       relp, lexer_line.line, anonymous_count);
+	      }
+	    else
+	      {
+		/* The input file is outside of GCC source tree, we use
+		   a single colon after anonymous.  To be sure s is
+		   truly unique, we also use anonymous_count.  */
+		s = xasprintf ("anonymous:%s:%d::%d",
+			       get_input_file_name (lexer_line.file),
+			       lexer_line.line, anonymous_count);
+	      }
+	  }
 
 	/* Unfortunately above GTY_TOKEN check does not capture the
 	   typedef struct_type GTY case.  */
@@ -787,7 +815,19 @@  type (options_p *optsp, bool nested)
       if (token () == ID)
 	s = advance ();
       else
-	s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
+	{
+	  /* Again, we don't want to wire in the GCC source tree
+	     directory.  */
+	  const char* relp = get_file_srcdir_relative_path (lexer_line.file);
+	  anonymous_count++;
+	  if (relp)
+	    s = xasprintf ("anonymous::%s:%d::%d",
+			   relp, lexer_line.line, anonymous_count);
+	  else
+	    s = xasprintf ("anonymous:%s:%d::%d",
+			   get_input_file_name (lexer_line.file),
+			   lexer_line.line, anonymous_count);
+	}
 
       if (token () == '{')
 	consume_balanced ('{', '}');
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 165733)
+++ gcc/Makefile.in	(working copy)
@@ -3893,9 +3893,10 @@  build/genextract.o : genextract.c $(RTL_BASE_H) $(
 build/genflags.o : genflags.c $(RTL_BASE_H) $(OBSTACK_H) $(BCONFIG_H)	\
   $(SYSTEM_H) coretypes.h $(GTM_H) errors.h $(READ_MD_H) gensupport.h
 build/gengenrtl.o : gengenrtl.c $(BCONFIG_H) $(SYSTEM_H) rtl.def
-build/gengtype-lex.o : gengtype-lex.c gengtype.h $(BCONFIG_H) $(SYSTEM_H)
+build/gengtype-lex.o : gengtype-lex.c gengtype.h $(BCONFIG_H) $(SYSTEM_H) \
+	errors.h
 build/gengtype-parse.o : gengtype-parse.c gengtype.h $(BCONFIG_H)	\
-  $(SYSTEM_H)
+  $(SYSTEM_H) errors.h
 build/gengtype.o : gengtype.c $(BCONFIG_H) $(SYSTEM_H) gengtype.h 	\
   rtl.def insn-notes.def errors.h double-int.h $(HASHTAB_H)
 build/genmddeps.o: genmddeps.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h	\