Patchwork gengtype plugin improvement last4round -patch 3 [inputfile]

login
register
mail settings
Submitter Basile Starynkevitch
Date Nov. 8, 2010, 6:33 p.m.
Message ID <20101108193358.58a88fd1.basile@starynkevitch.net>
Download mbox | patch
Permalink /patch/70442/
State New
Headers show

Comments

Basile Starynkevitch - Nov. 8, 2010, 6:33 p.m.
On Fri, 5 Nov 2010 05:51:31 +0200
Laurynas Biveinis <laurynas.biveinis@gmail.com> wrote:


References http://gcc.gnu.org/ml/gcc-patches/2010-10/msg01774.html
          http://gcc.gnu.org/ml/gcc-patches/2010-11/msg00483.html

> Basile -
> 
> We are getting there

Sorry, my english is much worse that yours,
what do you mean by "there"? What is the (imaginary) "place" you think
we are getting to?  What exactly do you mean? I was not able to parse
your sentence unambigously.


> and as much as I'd like to say "OK with such and
> such", I'll have to ask you to submit a new patch. Basically you did
> not address my last two comments from the previous round. Please take
> care to see that the new patch contains only relevant changes and
> nothing else.
> 
> -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);
> 
> Drop the last clause after "because".

I am not sure to understand what you mean by clause in that context;
but I shortened the comment to please you more.

The attached patch to trunk r166446 tries hard to take your comments
into account.

########## gcc/ChangeLog entry
2010-11-08  Basile Starynkevitch  <basile@starynkevitch.net>
	    Jeremie Salvucci  <jeremie.salvucci@free.fr>

	* gengtype.c (get_output_file_name): declaration moved to
	gengtype.h.
	(plugin_files, get_file_basename, get_file_realbasename)
	(get_file_langdir, error_at_line, gt_files, this_file)
	(system_h_file, read_input_list, create_field_all)
	(get_file_srcdir_relative_path, get_file_basename)
	(get_file_langdir, get_file_gtfilename)
	(get_output_file_with_visibility, get_output_file_name)
	(struct flist, put_mangled_filename, walk_type)
	(put_mangled_filename, finish_root_table, write_roots): use
	input_file-s.
	(lang_dir_names, num_lang_dirs): remove static.
	(get_lang_bitmap, set_lang_bitmap): moved to gengtype.h.
	(main): Use input_file-s. Don't fatal on plugin mode without
        state.

	* gengtype.h:
	(struct input_file_st, input_file): New type.
	(struct fileloc): use it.
	(gt_files, num_gt_files, this_file, system_h_file)
	(input_file_by_name, get_file_srcdir_relative_path); use
	input_file.
	(get_input_file_name): New function.
	(get_lang_bitmap, set_lang_bitmap): Moved from gengtype.c and
        use input_file.
	(lang_dir_names, num_lang_dirs, get_output_file_with_visibility)
	(get_output_file_name): Ditto.

	* gengtype-lex.l (yybegin): use input_file.

	* gengtype-parse.c (parse_error): use input_file.
##########

I am too afraid to ask if it is ok with some changes.  But I would like
this work to be accepted somehow...


Cheers.
Laurynas Biveinis - Nov. 9, 2010, 3:21 a.m.
2010/11/8 Basile Starynkevitch <basile@starynkevitch.net>:
>> We are getting there
>
> Sorry, my english is much worse that yours,
> what do you mean by "there"?

I was just saying that your patch is improving and is getting closer
and closer to an OK.

>> -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);
>>
>> Drop the last clause after "because".
>
> I am not sure to understand what you mean by clause in that context;
> but I shortened the comment to please you more.

Now it reads exactly as I suggested. Thanks.

> ########## gcc/ChangeLog entry
> 2010-11-08  Basile Starynkevitch  <basile@starynkevitch.net>
>            Jeremie Salvucci  <jeremie.salvucci@free.fr>
>
>        * gengtype.c (get_output_file_name): declaration moved to
>        gengtype.h.

"Declaration". Always capitalize the first word after colon in ChangeLog.

>        (plugin_files, get_file_basename, get_file_realbasename)
>        (get_file_langdir, error_at_line, gt_files, this_file)
>        (system_h_file, read_input_list, create_field_all)
>        (get_file_srcdir_relative_path, get_file_basename)
>        (get_file_langdir, get_file_gtfilename)
>        (get_output_file_with_visibility, get_output_file_name)
>        (struct flist, put_mangled_filename, walk_type)
>        (put_mangled_filename, finish_root_table, write_roots): use
>        input_file-s.

"Use"

>        (lang_dir_names, num_lang_dirs): remove static.

"Remove"

>        (get_lang_bitmap, set_lang_bitmap): moved to gengtype.h.

"Moved"

>        (main): Use input_file-s. Don't fatal on plugin mode without
>        state.
>
>        * gengtype.h:
>        (struct input_file_st, input_file): New type.
>        (struct fileloc): use it.

"Use"

>        (gt_files, num_gt_files, this_file, system_h_file)
>        (input_file_by_name, get_file_srcdir_relative_path); use
>        input_file.

"Use"

>        (get_input_file_name): New function.
>        (get_lang_bitmap, set_lang_bitmap): Moved from gengtype.c and
>        use input_file.
>        (lang_dir_names, num_lang_dirs, get_output_file_with_visibility)
>        (get_output_file_name): Ditto.
>
>        * gengtype-lex.l (yybegin): use input_file.
>
>        * gengtype-parse.c (parse_error): use input_file.

"Use" and "Use".

> @@ -4571,10 +4606,10 @@ 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
> -         given at least one plugin file.  */
> +      /* In plugin mode, we should preferably have read a state file,
> +         and should have given at least one plugin file.  */
>        if (!read_state_filename)
> -	fatal ("No read state given in plugin mode for %s",
> +	warning ("No read state given in plugin mode for %s",
>  	       plugin_output_filename);
>
>        if (nb_plugin_files == 0 || !plugin_files)

Just like the last time, this chunk is unrelated.

> @@ -4583,7 +4618,7 @@ main (int argc, char **argv)
>
>        /* 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]));
>
>        if (hit_error)
>  	return 1;

Please indent parse_file properly.

The patch is OK with:
- the ChangeLog entries capitalized;
- the unrelated chunk and its ChangeLog entry removed;
- parse_file call indentation fixed.

If you see that you need to make any other changes to the patch in
addition to these, please resubmit. Otherwise please go ahead and
commit.

Thanks,
Andreas Schwab - Nov. 9, 2010, 9:53 a.m.
Basile Starynkevitch <basile@starynkevitch.net> writes:

> 	* gengtype.h:
> 	(struct input_file_st, input_file): New type.
> 	(struct fileloc): use it.

You did bootstrap that?

../../gcc/gengtype-parse.c: In function 'type':
../../gcc/gengtype-parse.c:754:4: error: format '%s' expects type 'char *', but argument 2 has type 'const struct input_file *' [-Werror=format]
../../gcc/gengtype-parse.c:791:2: error: format '%s' expects type 'char *', but argument 2 has type 'const struct input_file *' [-Werror=format]

Even a simple grep would have found it.

Andreas.
H.J. Lu - Nov. 9, 2010, 1:08 p.m.
On Tue, Nov 9, 2010 at 1:53 AM, Andreas Schwab <schwab@redhat.com> wrote:
> Basile Starynkevitch <basile@starynkevitch.net> writes:
>
>>       * gengtype.h:
>>       (struct input_file_st, input_file): New type.
>>       (struct fileloc): use it.
>
> You did bootstrap that?
>
> ../../gcc/gengtype-parse.c: In function 'type':
> ../../gcc/gengtype-parse.c:754:4: error: format '%s' expects type 'char *', but argument 2 has type 'const struct input_file *' [-Werror=format]
> ../../gcc/gengtype-parse.c:791:2: error: format '%s' expects type 'char *', but argument 2 has type 'const struct input_file *' [-Werror=format]
>
> Even a simple grep would have found it.
>

I opened:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46392
Basile Starynkevitch - Nov. 9, 2010, 1:49 p.m.
Hello All,

Sorry for the bug.
http://gcc.gnu.org/ml/gcc-patches/2010-11/msg00887.html

Thanks to H.J.LU for the fix.

I have transient email problems (I am changing provider) and no Internet
access till now and did not got the email from list.

Will look more tomorrow morning.

Cheers.

Patch

Index: gcc/gengtype.c
===================================================================
--- gcc/gengtype.c	(revision 166446)
+++ gcc/gengtype.c	(working copy)
@@ -128,7 +128,6 @@  struct type
 
 
 
-const char *get_output_file_name (const char *);
 
 
 /* The list of output files.  */
@@ -144,7 +143,7 @@  static char *inputlist;
 
 /* The plugin input files and their number; in that case only
    a single file is produced.  */
-static char **plugin_files;
+static input_file **plugin_files;
 static size_t nb_plugin_files;
 
 /* The generated plugin output file and name.  */
@@ -174,12 +173,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.  */
@@ -197,9 +195,10 @@  error_at_line (const struct fileloc *pos, const ch
 {
   va_list ap;
 
+  gcc_assert (pos != NULL && pos->file != NULL);
   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;
@@ -227,71 +226,26 @@  xasprintf (const char *format, ...)
 /* 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 "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__;
+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.  */
@@ -482,11 +436,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 (const input_file *, num_gt_files);
 
       for (;;)
 	{
@@ -517,13 +471,16 @@  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 "
@@ -533,13 +490,13 @@  read_input_list (const char *listname)
 								  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 +843,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 +852,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;
 }
@@ -1649,40 +1606,43 @@  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 *
-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;
 }
 
-/* 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])
-      && memcmp (f, srcdir, srcdir_len) == 0)
+      && strncmp (f, srcdir, srcdir_len) == 0)
     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 *
-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 +1668,19 @@  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
+   F 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.  */
+  /* 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;
-  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 +1697,16 @@  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 +1728,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 the result is cached inside INPF, that argument cannot be
+   declared constant, but is "almost" 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,8 +1744,8 @@  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.  */
@@ -1791,21 +1753,21 @@  outf_p
     {
       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
@@ -1858,13 +1820,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;
@@ -1956,7 +1918,7 @@  struct flist
 {
   struct flist *next;
   int started_p;
-  const char *name;
+  const input_file* file;
   outf_p f;
 };
 
@@ -2002,7 +1964,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);
-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);
@@ -2470,7 +2432,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",
-			 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))
@@ -2637,7 +2600,7 @@  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;
+  const input_file *fn;
   int i;
 
   gcc_assert (UNION_OR_STRUCT_P (s));
@@ -2649,7 +2612,9 @@  get_output_file_for_structure (const_type_p s, typ
 	&& 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
@@ -3220,12 +3185,15 @@  contains_scalar_p (type_p t)
     }
 }
 
-/* Mangle FN and print it to F.  */
+/* Mangle INPF 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++)
@@ -3255,7 +3223,7 @@  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)
@@ -3263,7 +3231,7 @@  finish_root_table (struct flist *flp, const char *
 	    {
 	      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");
 	    }
       }
@@ -3279,7 +3247,7 @@  finish_root_table (struct flist *flp, const char *
   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;
@@ -3288,7 +3256,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");
 	    }
       }
@@ -3586,7 +3554,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;
@@ -3618,8 +3588,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");
@@ -3638,7 +3608,8 @@  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;
@@ -3674,7 +3645,8 @@  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;
@@ -3709,7 +3681,8 @@  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;
@@ -3757,7 +3730,8 @@  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;
@@ -3792,7 +3766,8 @@  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;
@@ -4187,7 +4162,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,
+  printf ("%*cfileloc: file = %s, line = %d\n", indent, ' ', 
+	  get_input_file_name (line.file),
 	  line.line);
 }
 
@@ -4487,16 +4463,68 @@  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;
+  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)
 {
@@ -4506,6 +4534,12 @@  main (int argc, char **argv)
 
   /* 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;
@@ -4552,8 +4586,9 @@  main (int argc, char **argv)
       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]));
 	}
       if (verbosity_level >= 1)
 	printf ("%s parsed %d files\n", progname, (int) num_gt_files);
@@ -4571,10 +4606,10 @@  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
-         given at least one plugin file.  */
+      /* In plugin mode, we should preferably have read a state file,
+         and should have given at least one plugin file.  */
       if (!read_state_filename)
-	fatal ("No read state given in plugin mode for %s",
+	warning ("No read state given in plugin mode for %s",
 	       plugin_output_filename);
 
       if (nb_plugin_files == 0 || !plugin_files)
@@ -4583,7 +4618,7 @@  main (int argc, char **argv)
 
       /* 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]));
 
       if (hit_error)
 	return 1;
Index: gcc/gengtype.h
===================================================================
--- gcc/gengtype.h	(revision 166446)
+++ gcc/gengtype.h	(working copy)
@@ -25,14 +25,87 @@ 
    represented by a bitmap.  */
 typedef unsigned lang_bitmap;
 
+/* 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 
+{
+  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 variable-length array, ended by a null
+                            char.  */
+};
+typedef struct input_file_st input_file;
+
 /* A file position, mostly for error messages.
    The FILE element may be compared using pointer equality.  */
 struct fileloc
 {
-  const char *file;
+  const input_file *file;
   int line;
 };
 
+
+/* Table of all input files and its size.  */
+extern const 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)
+      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;
+  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);
+  inpf->inpbitmap = n;
+}
+
+/* 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 +140,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.  */
+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 166446)
+++ gcc/gengtype-lex.l	(working copy)
@@ -202,7 +202,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 166446)
+++ gcc/gengtype-parse.c	(working copy)
@@ -135,7 +135,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);