Patchwork gengtype improvements for plugins, completed! patch 3/N [inputfile]

login
register
mail settings
Submitter Basile Starynkevitch
Date Sept. 9, 2010, 4:35 p.m.
Message ID <20100909163502.GA26609@hector.lesours>
Download mbox | patch
Permalink /patch/64311/
State New
Headers show

Comments

Basile Starynkevitch - Sept. 9, 2010, 4:35 p.m.
Hello All,

[join work by Basile Starynkevitch & Jeremie Salvucci]

References: 
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02060.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00616.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00663.html
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02063.html

As I told in http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00808.html I
am continuing to send the complete patch series of our gengtype
work. This does not mean I am ignoring the recieved feedback.  I intend
to send a third round of patches once this "complete!" round is ended.

I am taking into account most of Laurynas comments in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00212.html with the
important exception of INPUT_FILE_MAGIC, discussed below.

Laurynas thinks that adding a magic number don't bring anything and is
just a temporary trick we (Jeremie & me Basile) used to code this
patch.  This is indeed true, but I (Basile) believe that this trick is
really useful to future gengtype hackers, since input files are
painfully reachable from types in a non-trivial way (and that very
fact is an occasion for bugs).  I would like opinion of other people,
in particular of reviewers, on that issue.  As I told before sending
our patch serie, gengtype is difficult to understand, and we insist on
defensive programming.  And this INPUT_FILE_MAGIC used in macro
CHECK_INPUT_FILE_MAGIC is exactly a case of defensive programming
(disabled unless ENABLE_CHECKING is configured).  It will be very
probably useful to future gengtype hackers, so I pray the allmighty
reviewers to consider accepting it.

So to please Laurynas and some potential reviewer, I am providing two
variants of this patch.  Both variants did take into account all
Laurynas comments (except those related to INPUT_FILE_MAGIC).  In a
first variant, produced with

diff -u -p $(svn stat . |awk '/M/{print $2}') \
    --from-file ../gengtype-gcc-02-verbosity > \
     $HOME/tmp/gengtype_patch_3_of_N__inputfile-relto02.diff

contains the INPUT_FILE_MAGIC trick. This produce a first variant of a
relative patch. It has my strong preference, and future patches
patches of this patch serie will be relative to it.

To please Laurynas and a potential reviewer, I am then editing
manually gengtype.[ch] to remove every INPUT_FILE_MAGIC trick and
running again

diff -u -p $(svn stat . |awk '/M/{print $2}') \
    --from-file ../gengtype-gcc-02-verbosity > \
     $HOME/tmp/gengtype_patch_3_of_N__inputfile-relto02-nomagic.diff

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

	* gengtype.c (get_output_file_name, plugin_files)
	(get_file_srcdir_relative_path, nb_plugin_files): moved to gengtype.h.
	(get_file_basename, get_file_realbasename, get_file_langdir): Use
	an input_file as argument.
	(error_at_line): Use input_file-s.
	(gt_files, num_gt_files, this_file, system_h_file): Declared as
	input_file-s.
	(lang_dir_names, num_lang_dirs): No static.
	(get_lang_bitmap, set_lang_bitmap): Moved to gengtype.h.
	(read_input_list): Use input_file-s.
	(new_structure): Use system_h_file.
	(creat_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): Use input_file-s.
	(struct flist): Removed name and added file field.
	(output_type_enum): Use input_file-s.
	(finish_root_table, write_roots): Use file not name field of
	struct flist.
	(dump_fileloc, parse_program_options): Use input_file-s.

	* gengtype.h (struct input_file_st, input_file): New structure and
	type.
	(INPUT_FILE_MAGIC, CHECK_INPUT_FILE_MAGIC): New macros.
	(gt_files, num_gt_files): New variables moved from gengtype.c.
	(this_file, system_h_file): New variables.
	(input_file_by_name): Declared new function.
	(get_input_file_name): New inline function.
	(get_lang_bitmap, set_lang_bitmap): Moved from gengtype.c and
	updated.
	(struct fileloc): field file changed type.
	(lang_dir_names, num_lang_dirs): moved from gengtype.c.
	(get_output_file_with_visibility, get_output_file_name): Use
	input_file-s.

	* gengtype-lex.l:  Updated copyright year. Included errors.h.
	(yybegin): use input_file-s.

	* gengtype-parse.c:   Updated copyright year. Included errors.h.
	(parse_error): Use input_file-s.
	(type): Generate anonymous names differently for GCC source input
	and other input.

##########

I particularily welcome comments on this patch, especially comments by
reviewers about magic or no magic.

Regards.
Laurynas Biveinis - Sept. 10, 2010, 2:36 a.m.
The non-magic version of the patch:

+/* Special files, initialized very early in main.  */
+input_file* this_file; 		/* for gengtype.c */
+input_file* system_h_file;	/* for system.h */

Alignment of comments.

-		  const char *file, int line)
+		  input_file* inpf, int line)

const input_file * ?

-/* For F a filename, return the relative path to F from $(srcdir) if the
+/* For F an input_file, return the relative path to F from $(srcdir) if the
    latter is a prefix in F, or the real basename of F otherwise.  */

 static const char *
-get_file_basename (const char *f)
+get_file_basename (const input_file *inpf)
 {

Comment out of sync with the function signature (INPF not F)

-get_output_file_with_visibility (const char *input_file)
+get_output_file_with_visibility (input_file* inpf)

const

-get_output_file_name (const char *input_file)
+get_output_file_name (input_file *inpf)

const

-static void put_mangled_filename (outf_p , const char *);
+static void put_mangled_filename (outf_p , const input_file *);

Drop the space before the comma (although you didn't introduce it)

For the lexer and parser parts, my comment from the last iteration still stands:

--- ../gengtype-gcc-02/gengtype-lex.l	2010-08-29 11:04:49.000000000 +0200
+++ gcc/gengtype-lex.l	2010-08-29 11:07:30.000000000 +0200
...
+#include "errors.h"             /* for fatal */
...
-  lexer_line.file = fname;
+  lexer_line.ifile = input_file_by_name (fname);

You are not using fatal here. Either remove the include or adjust the
comment why this is needed.  Same for gengtype-parse.c.

@@ -695,15 +698,15 @@ type (options_p *optsp, bool nested)
-    /* GTY annotations follow attribute syntax
-       GTY_BEFORE_ID is for union/struct declarations
-       GTY_AFTER_ID is for variable declarations.  */
-    enum {
-        NO_GTY,
-        GTY_BEFORE_ID,
-        GTY_AFTER_ID
-    } is_gty = NO_GTY;
-    bool is_union = (token () == UNION);
+	/* GTY annotations follow attribute syntax
+	   GTY_BEFORE_ID is for union/struct declarations
+	   GTY_AFTER_ID is for variable declarations.  */
+	enum {
+	  NO_GTY,
+	  GTY_BEFORE_ID,
+	  GTY_AFTER_ID
+	} is_gty = NO_GTY;
+	bool is_union = (token () == UNION);

Only formatting changes? If yes, then please drop this chunk.

-        is_gty = GTY_BEFORE_ID;
-        opts = gtymarker_opt ();
+	    is_gty = GTY_BEFORE_ID;
+	    opts = gtymarker_opt ();

Likewise.

-        is_gty = GTY_AFTER_ID;
-        opts = gtymarker_opt ();
+	    is_gty = GTY_AFTER_ID;
+	    opts = gtymarker_opt ();

Likewise.

-    if (is_gty)
-      {
-        if (token () == '{')
-          {
-            pair_p fields;
-
-            if (is_gty == GTY_AFTER_ID)
-                parse_error ("GTY must be specified before identifier");
-
-            advance ();
-            fields = struct_field_seq ();
-            require ('}');
-            return new_structure (s, is_union, &lexer_line, fields, opts);
-          }
-      }
-    else if (token () == '{')
-      consume_balanced ('{', '}');
+	if (is_gty)
+	  {
+	    if (token () == '{')
+	      {
+		pair_p fields;
+
+		if (is_gty == GTY_AFTER_ID)
+		  parse_error ("GTY must be specified before identifier");
+
+		advance ();
+		fields = struct_field_seq ();
+		require ('}');
+		return new_structure (s, is_union, &lexer_line, fields, opts);
+	      }
+	  }
+	else if (token () == '{')
+	  consume_balanced ('{', '}');

Likewise.

-	if (token () == ID)
-	  s = advance ();
-	else
-	  s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
-
+      if (token () == ID)
+	s = advance ();
+      else
+	{
+	    /* 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-then clause breaks previously-OK formatting with 1-space indentation.

2010/9/9 Basile Starynkevitch <basile@starynkevitch.net>:
>
> Hello All,
>
> [join work by Basile Starynkevitch & Jeremie Salvucci]
>
> References:
>  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02060.html
>  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00616.html
>  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00663.html
>  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02063.html
>
> As I told in http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00808.html I
> am continuing to send the complete patch series of our gengtype
> work. This does not mean I am ignoring the recieved feedback.  I intend
> to send a third round of patches once this "complete!" round is ended.
>
> I am taking into account most of Laurynas comments in
> http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00212.html with the
> important exception of INPUT_FILE_MAGIC, discussed below.
>
> Laurynas thinks that adding a magic number don't bring anything and is
> just a temporary trick we (Jeremie & me Basile) used to code this
> patch.  This is indeed true, but I (Basile) believe that this trick is
> really useful to future gengtype hackers, since input files are
> painfully reachable from types in a non-trivial way (and that very
> fact is an occasion for bugs).  I would like opinion of other people,
> in particular of reviewers, on that issue.  As I told before sending
> our patch serie, gengtype is difficult to understand, and we insist on
> defensive programming.  And this INPUT_FILE_MAGIC used in macro
> CHECK_INPUT_FILE_MAGIC is exactly a case of defensive programming
> (disabled unless ENABLE_CHECKING is configured).  It will be very
> probably useful to future gengtype hackers, so I pray the allmighty
> reviewers to consider accepting it.
>
> So to please Laurynas and some potential reviewer, I am providing two
> variants of this patch.  Both variants did take into account all
> Laurynas comments (except those related to INPUT_FILE_MAGIC).  In a
> first variant, produced with
>
> diff -u -p $(svn stat . |awk '/M/{print $2}') \
>    --from-file ../gengtype-gcc-02-verbosity > \
>     $HOME/tmp/gengtype_patch_3_of_N__inputfile-relto02.diff
>
> contains the INPUT_FILE_MAGIC trick. This produce a first variant of a
> relative patch. It has my strong preference, and future patches
> patches of this patch serie will be relative to it.
>
> To please Laurynas and a potential reviewer, I am then editing
> manually gengtype.[ch] to remove every INPUT_FILE_MAGIC trick and
> running again
>
> diff -u -p $(svn stat . |awk '/M/{print $2}') \
>    --from-file ../gengtype-gcc-02-verbosity > \
>     $HOME/tmp/gengtype_patch_3_of_N__inputfile-relto02-nomagic.diff
>
> ########## gcc/ChangeLog entry is
> 2010-09-09  Jeremie Salvucci  <jeremie.salvucci@free.fr>
>            Basile Starynkevitch  <basile@starynkevitch.net>
>
>        * gengtype.c (get_output_file_name, plugin_files)
>        (get_file_srcdir_relative_path, nb_plugin_files): moved to gengtype.h.
>        (get_file_basename, get_file_realbasename, get_file_langdir): Use
>        an input_file as argument.
>        (error_at_line): Use input_file-s.
>        (gt_files, num_gt_files, this_file, system_h_file): Declared as
>        input_file-s.
>        (lang_dir_names, num_lang_dirs): No static.
>        (get_lang_bitmap, set_lang_bitmap): Moved to gengtype.h.
>        (read_input_list): Use input_file-s.
>        (new_structure): Use system_h_file.
>        (creat_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): Use input_file-s.
>        (struct flist): Removed name and added file field.
>        (output_type_enum): Use input_file-s.
>        (finish_root_table, write_roots): Use file not name field of
>        struct flist.
>        (dump_fileloc, parse_program_options): Use input_file-s.
>
>        * gengtype.h (struct input_file_st, input_file): New structure and
>        type.
>        (INPUT_FILE_MAGIC, CHECK_INPUT_FILE_MAGIC): New macros.
>        (gt_files, num_gt_files): New variables moved from gengtype.c.
>        (this_file, system_h_file): New variables.
>        (input_file_by_name): Declared new function.
>        (get_input_file_name): New inline function.
>        (get_lang_bitmap, set_lang_bitmap): Moved from gengtype.c and
>        updated.
>        (struct fileloc): field file changed type.
>        (lang_dir_names, num_lang_dirs): moved from gengtype.c.
>        (get_output_file_with_visibility, get_output_file_name): Use
>        input_file-s.
>
>        * gengtype-lex.l:  Updated copyright year. Included errors.h.
>        (yybegin): use input_file-s.
>
>        * gengtype-parse.c:   Updated copyright year. Included errors.h.
>        (parse_error): Use input_file-s.
>        (type): Generate anonymous names differently for GCC source input
>        and other input.
>
> ##########
>
> I particularily welcome comments on this patch, especially comments by
> reviewers about magic or no magic.
>
> Regards.
>
> --
> Basile STARYNKEVITCH         http://starynkevitch.net/Basile/
> email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359
> 8, rue de la Faiencerie, 92340 Bourg La Reine, France
> *** opinions {are only mines, sont seulement les miennes} ***
>
Basile Starynkevitch - Sept. 10, 2010, 5:26 a.m.
On Fri, 10 Sep 2010 05:36:22 +0300
Laurynas Biveinis <laurynas.biveinis@gmail.com> wrote:
> 
> -		  const char *file, int line)
> +		  input_file* inpf, int line)
> 
> const input_file * ?
> 
> -/* For F a filename, return the relative path to F from $(srcdir) if the
> +/* For F an input_file, return the relative path to F from $(srcdir) if the
>     latter is a prefix in F, or the real basename of F otherwise.  */
> 
>  static const char *
> -get_file_basename (const char *f)
> +get_file_basename (const input_file *inpf)
>  {
> 
> Comment out of sync with the function signature (INPF not F)
> 
> -get_output_file_with_visibility (const char *input_file)
> +get_output_file_with_visibility (input_file* inpf)
> 
> const
> 
> -get_output_file_name (const char *input_file)
> +get_output_file_name (input_file *inpf)
> 

Thanks for the comments, I am replying here only to one: having all
input_file* be const.

In principle you are right, in the sense that all the functions you
mentioned do not conceptually modify the input_file structure, with
however one significant exception, its inpoutf field which is caching
the result of get_ouput_file_with_visibility. In C++ parlance that
field would probably be declared as mutable, since it can change even
in functions dealing with const input_file* but gengtype is not in C++!

All these functions may indirectly call
get_output_file_with_visibility.  See the next patch 4/N [files_rules]
which I did not yet send in its "completed!" form, but which I first
sent in http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html and
which you commented in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00419.html etc.

And the new get_output_file_with_visibility will indeed use and update
the inpoutf 

So I see several ways of dealing with that:

A. Use const input_file* in every function which conceptually don't
modify input_file-s, but then adding some CONST_CAST at every call to
get_output_file_with_visibility.

B. Declare every function with const input_file* including even
get_output_file_with_visibility which will have to CONST_CAST its
argument to update its inpoutf field.  But that function indeed and
importantly updates the inpoutf field of input_file and honestly is not
dealing with its input_file* as a constant argument.

C. remove every const for input_file* functions, since they all
indirectly can modifiy its inpoutf field thru
get_output_file_with_visibility.


What do people think?  I believe that I tried to implement solution A,
but my personal preference go to C, which would make a bigger patch.
[I tried nearly systematically to make the patches shorter than longer].

I would like comments on this (in particular by reviewers & by
Laurynas).

In general, I tend to dislike the const keyword in C code, except when
it indicates that the data is in read-only segment and would SEGV when
modified. However, I do admit it permit better diagnostics from the
compiler. 

Cheers.
Laurynas Biveinis - Sept. 10, 2010, 5:44 a.m.
2010/9/10 Basile Starynkevitch <basile@starynkevitch.net>:
> A. Use const input_file* in every function which conceptually don't
> modify input_file-s, but then adding some CONST_CAST at every call to
> get_output_file_with_visibility.
>
> B. Declare every function with const input_file* including even
> get_output_file_with_visibility which will have to CONST_CAST its
> argument to update its inpoutf field.  But that function indeed and
> importantly updates the inpoutf field of input_file and honestly is not
> dealing with its input_file* as a constant argument.
>
> C. remove every const for input_file* functions, since they all
> indirectly can modifiy its inpoutf field thru
> get_output_file_with_visibility.

I see. In that case I'd leave the patch as-is and postpone const
cleanups to a later separate patch once the initial ones are reviewed
& committed. And then I'd go with option C.

Patch

--- ../gengtype-gcc-02-verbosity/gengtype.c	2010-09-08 16:36:26.000000000 +0200
+++ gcc/gengtype.c	2010-09-09 16:05:41.000000000 +0200
@@ -123,7 +123,6 @@  struct type
 
 
 
-const char *get_output_file_name (const char *);
 
 
 /* The list of output files.  */
@@ -137,12 +136,12 @@  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; in plugin mode only a
+   single file is produced.  */
+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;
 
@@ -164,12 +163,11 @@  int verbosity_level;
 
 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.  */
@@ -189,7 +187,8 @@  error_at_line (const struct fileloc *pos
 
   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;
@@ -217,18 +216,17 @@  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;
+
+/* Special files, initialized very early in main.  */
+input_file* this_file; 		/* for gengtype.c */
+input_file* system_h_file;	/* for system.h */
 
-/* A number of places use the name of this file for a location for
-   things that we can't rely on the source to define.  Make sure we
-   can still use pointer comparison on filenames.  */
-const char this_file[] = __FILE__;
-const char system_h_file[] = "system.h";
 
 /* 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.  */
@@ -246,37 +244,6 @@  static outf_p *base_files;
    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 file are universal.  */
-    return (((lang_bitmap)1) << num_lang_dirs) - 1;
-  else
-    {
-      lang_bitmap n = 0;
-      int i;
-      for (i = -(int) sizeof (lang_bitmap); i < 0; i++)
-	n = (n << CHAR_BIT) + (unsigned char)gtfile[i];
-      return n;
-    }
-}
-
-/* Set the bitmap returned by get_lang_bitmap.  The only legitimate
-   caller of this function is read_input_list.  */
-static void
-set_lang_bitmap (char *gtfile, lang_bitmap n)
-{
-  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.  */
@@ -468,11 +435,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 (;;)
 	{
@@ -502,13 +469,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 "
 				     "for language %s", line, langno == 0
@@ -516,13 +486,13 @@  read_input_list (const char *listname)
 				     : 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
@@ -745,16 +715,7 @@  new_structure (const char *name, int isu
      write out its mark routine.  */
   if (!strcmp (name, "location_s") && !isunion
       && pos->file == this_file)
-    {
-      size_t n;
-      for (n = 0; n < num_gt_files; n++)
-	if (!strcmp (gt_files[n] + strlen (gt_files[n]) - strlen ("input.h"),
-		     "input.h"))
-	  {
-	    s->u.s.line.file = gt_files[n];
-	    break;
-	  }
-    }
+    s->u.s.line.file = system_h_file;
 
     return s;
 }
@@ -893,7 +854,7 @@  note_variable (const char *s, type_p t,
 /* 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)
+		  input_file* inpf, int line)
 {
   pair_p field;
 
@@ -902,7 +863,7 @@  create_field_all (pair_p next, type_p ty
   field->type = type;
   field->name = name;
   field->opt = opt;
-  field->line.file = file;
+  field->line.file = inpf;
   field->line.line = line;
   return field;
 }
@@ -1658,8 +1619,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;
@@ -1668,26 +1630,27 @@  get_file_realbasename (const char *f)
 /* 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
+/* For F an input_file, return the relative path to F from $(srcdir) if the
    latter is a prefix in F, or the real basename of F 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
@@ -1713,19 +1676,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
+   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 * r;
+  const char *srcdir_relative_path = get_file_srcdir_relative_path (inpf);
+  const char *r;
 
   if (!srcdir_relative_path)
     return NULL;
@@ -1742,16 +1705,16 @@  get_file_langdir (const char *f)
   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)
@@ -1777,7 +1740,7 @@  get_file_gtfilename (const char *f)
    INPUT_FILE.  */
 
 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;
@@ -1788,30 +1751,30 @@  get_output_file_with_visibility (const c
   /* 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
@@ -1863,13 +1826,13 @@  get_output_file_with_visibility (const c
 }
 
 /* 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;
@@ -1951,7 +1914,7 @@  close_output_files (void)
 struct flist {
   struct flist *next;
   int started_p;
-  const char *name;
+  const input_file *file;
   outf_p f;
 };
 
@@ -2000,7 +1963,7 @@  static void write_local (outf_p output_h
 			 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);
@@ -2471,7 +2434,7 @@  walk_type (type_p t, struct walk_type_da
 	      {
 		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 +2602,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
@@ -3229,9 +3203,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 *fn)
 {
-  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*, fn));
   if (!f || !name)
     return;
   for (; *name != 0; name++)
@@ -3261,7 +3238,7 @@  finish_root_table (struct flist *flp, co
   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)
@@ -3270,7 +3247,7 @@  finish_root_table (struct flist *flp, co
 	      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");
 	    }
       }
@@ -3287,7 +3264,7 @@  finish_root_table (struct flist *flp, co
   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;
@@ -3296,7 +3273,7 @@  finish_root_table (struct flist *flp, co
 	  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");
 	    }
       }
@@ -3632,8 +3609,8 @@  write_roots (pair_p variables, bool emit
 	  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");
@@ -4171,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
@@ -4461,12 +4438,64 @@  parse_program_options (int argc, char**a
       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)
 {
@@ -4479,6 +4508,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);
 
@@ -4516,10 +4551,11 @@  main (int argc, char **argv)
       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]);
-      }
+      for (i = 0; i < num_gt_files; i++) 
+	{
+	  parse_file (get_input_file_name (gt_files[i]));
+	  DBGPRINTF ("parsed file #%d %s", (int) i, get_input_file_name (gt_files[i]));
+	}
       DBGPRINT_COUNT_TYPE ("structures after parsing", structures);
       DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs);
       if (verbosity_level >= 1)
@@ -4546,7 +4582,11 @@  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]));
+	  DBGPRINTF ("parsed plugin file #%d %s", (int) ix, 
+		     get_input_file_name (plugin_files[ix]));
+	}
 
       if (hit_error)
 	return 1;
--- ../gengtype-gcc-02-verbosity/gengtype.h	2010-09-08 16:09:52.000000000 +0200
+++ gcc/gengtype.h	2010-09-09 16:31:09.000000000 +0200
@@ -25,13 +25,86 @@  along with GCC; see the file COPYING3.
    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 {
+  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;
+
+/* 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) 
+    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;
+}
+
+/* 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;
+  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;
@@ -65,10 +138,14 @@  void 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. */
+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;
--- ../gengtype-gcc-02-verbosity/gengtype-lex.l	2010-08-27 07:56:01.000000000 +0200
+++ gcc/gengtype-lex.l	2010-09-09 16:01:23.000000000 +0200
@@ -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,6 +24,7 @@  along with GCC; see the file COPYING3.
 %{
 #include "bconfig.h"
 #include "system.h"
+#include "errors.h"             /* for fatal, needed by gengtype.h */
 
 #define malloc xmalloc
 #define realloc xrealloc
@@ -202,7 +203,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;
 }
 
--- ../gengtype-gcc-02-verbosity/gengtype-parse.c	2010-08-27 07:56:01.000000000 +0200
+++ gcc/gengtype-parse.c	2010-09-09 16:01:41.000000000 +0200
@@ -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 @@  along with GCC; see the file COPYING3.
 
 #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);
@@ -679,6 +681,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 ())
     {
@@ -695,15 +698,15 @@  type (options_p *optsp, bool nested)
     case UNION:
       {
 	options_p opts = 0;
-    /* GTY annotations follow attribute syntax
-       GTY_BEFORE_ID is for union/struct declarations
-       GTY_AFTER_ID is for variable declarations.  */
-    enum {
-        NO_GTY,
-        GTY_BEFORE_ID,
-        GTY_AFTER_ID
-    } is_gty = NO_GTY;
-    bool is_union = (token () == UNION);
+	/* GTY annotations follow attribute syntax
+	   GTY_BEFORE_ID is for union/struct declarations
+	   GTY_AFTER_ID is for variable declarations.  */
+	enum {
+	  NO_GTY,
+	  GTY_BEFORE_ID,
+	  GTY_AFTER_ID
+	} is_gty = NO_GTY;
+	bool is_union = (token () == UNION);
 	advance ();
 
 	/* Top-level structures that are not explicitly tagged GTY(())
@@ -713,40 +716,62 @@  type (options_p *optsp, bool nested)
 	   that we can't handle.  */
 	if (nested || token () == GTY_TOKEN)
 	  {
-        is_gty = GTY_BEFORE_ID;
-        opts = gtymarker_opt ();
+	    is_gty = GTY_BEFORE_ID;
+	    opts = gtymarker_opt ();
 	  }
 
 	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.  */
 	if (token () == GTY_TOKEN)
 	  {
-        is_gty = GTY_AFTER_ID;
-        opts = gtymarker_opt ();
+	    is_gty = GTY_AFTER_ID;
+	    opts = gtymarker_opt ();
 	  }
 
-    if (is_gty)
-      {
-        if (token () == '{')
-          {
-            pair_p fields;
-
-            if (is_gty == GTY_AFTER_ID)
-                parse_error ("GTY must be specified before identifier");
-
-            advance ();
-            fields = struct_field_seq ();
-            require ('}');
-            return new_structure (s, is_union, &lexer_line, fields, opts);
-          }
-      }
-    else if (token () == '{')
-      consume_balanced ('{', '}');
+	if (is_gty)
+	  {
+	    if (token () == '{')
+	      {
+		pair_p fields;
+
+		if (is_gty == GTY_AFTER_ID)
+		  parse_error ("GTY must be specified before identifier");
+
+		advance ();
+		fields = struct_field_seq ();
+		require ('}');
+		return new_structure (s, is_union, &lexer_line, fields, opts);
+	      }
+	  }
+	else if (token () == '{')
+	  consume_balanced ('{', '}');
 	if (opts)
 	  *optsp = opts;
 	return find_structure (s, is_union);
@@ -754,11 +779,22 @@  type (options_p *optsp, bool nested)
 
     case ENUM:
       advance ();
-	if (token () == ID)
-	  s = advance ();
-	else
-	  s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
-
+      if (token () == ID)
+	s = advance ();
+      else
+	{
+	    /* 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 ('{','}');
       return create_scalar_type (s);