public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* gengtype improvements for plugins, thirdround! patch 1/7 [declprog]
@ 2010-09-21 19:41 Basile Starynkevitch
  2010-09-21 22:07 ` gengtype improvements for plugins, thirdround! patch 2/7 [verbosity] Basile Starynkevitch
  2010-09-22 11:08 ` gengtype improvements for plugins, thirdround! patch 1/7 [declprog] Laurynas Biveinis
  0 siblings, 2 replies; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-21 19:41 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 7189 bytes --]



Hello All,

[join work by Basile Starynkevitch & Jeremie Salvucci]

References: http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02058.html 
http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02050.html
http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02051.html
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00616.html
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00744.html

I am submitting the third round of a serie of patches on gengtype,
provind some significant code clean-up & ability to persist the state
of gengtype to enable running gengtype for plugin use without requiring
them to have both GCC build and source trees.
The mails are improved versions of previous emails, and the patches are
improved versions of previously sent patches. I tried hard to have well
indented & well commented patches, and I did try to take into account
all the previous remarks.

I really hope to get an "OK", or at least an "OK with those changes".

I also hope the patches will be committed before end of stage 1 for 4.6
i.e. end of october 2010


Our patch serie is as before made of seven pieces.

patch 1 [declprog], like
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00663.html moves many
private definitions, types, functions from gengtype.c to gengtype.h &
provide a GNU friendly gengtype program invocation. We have to declare
publicly most internal types of gengtype since we really want the
persistent machinery to be in a separate file gengtype-state.c and
because we feel that gengtype.c is messy and big enough.

patch 2 [verbosity], like
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00682.html  add a verbose
flag -v to the gengtype program. When given (it can be given more than
once to increase verbosity), it explains what gengtype is doing. This
flag should be useful to any gengtype user.

patch 3 [inputfile], like
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00842.html provides an
input_file structure remove the horrible disgusting hack of encoding
the set of languages in a bitmap in four bytes before the file path.
Honestly, I cannot understand why the old gengtype had such an horrible
coding, and how could it have been accepted in the first place, nearly
nine or ten years ago.

patch 4 [filesrules] like
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00983.html provides a
better machinery to associate an output file to each input_file. So it
is improving the get_output_file_with_visibility function with a rule &
regular-expression based machinery.  I did thought a few seconds about
adding a convention in comments -for instance requiring that gimple.h
has a comment /*@@ GENGTYPEOUTPUT gt-gimple.h */, and tree.h have /*@@
GENGTYPEOUTPUT gt-tree.h */ etc, and have gengtype parse such comments.
However, such a patch would require me to patch, by adding just a
comment, almost every file of GCC, and I am sadly pretty sure nobody
will review such a work; the social rules of GCC make such an idea
impractical.

patch 5 [typedopt] like
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01017.html is making each
option a disciminated union. This is needed to be able to persist
gengtype state. 

patch 6 [wstate] see
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01029.html gives the
gengtype-state.c which has all the persistency machinery and enable its
use.

patch 7 [doc] improves the documentation gty.texi see
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01032.html



The first piece [declprog] of our series of patches moves many private
definitions, types, functions from gengtype.c to gengtype.h & provide
a GNU friendly gengtype program invocation. Since a later patch of the
same serie implement the state persistency in a separate file
gengtype-state.c (see our future patch 6/N[wstate]) a lot of variables
& types which used to be internal to gengtype.c are now publicly
available in gengtype.h.


We did incorporate Paolo Bonzini's & Ralf Wildenhues' suggestions on
build/version.o in Makefile.in from
http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02114.html &
http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02050.html

We did improve the help message as suggested by Laurynas Biveinis in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00207.html and in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00744.html

Please notice an important point in this patch (and other patches of
this serie): we program defensively, since we feel that gengtype is
very difficult to understand.  In particular, we added several
debugging tricks, notably the DBGPRINTF & DBGPRINT_COUNT_TYPE macros,
whose sole side-effect is to produce debugging output when gengtype is
given the --debug (or -D) program argument.  This feature (only
available when ENABLE_CHECKING is configured) is deemed necessary
because gengtype code is really difficult to grasp and to debug.  It
is complementary to the dump_everything & friends functions already
incorporated into gengtype and contributed by Laurynas Biveinis:
Laurynas dump feature is useful not only to debug and enhance gengtype
itself (a not trivial task, believe us!) but may also be useful by
gengtype users (e.g. plugins developers).  In contrast, our DBGPRINTF
... macros are mostly useful to debug & understand the processing of
gengtype itself.  Of course, we could remove them, but we strongly
feel that they could be useful to some other gengtype hacker (the same
can be said of Laurynas dump facility).  So to the attention of the
allmighty reviewers: please measure the pro & conses before asking us
to remove these DBGPRINTF macros.  We really hope they will stay... 

################################################################
gcc/ChangeLog entry:

2010-09-20  Jeremie Salvucci  <jeremie.salvucci@free.fr>
	    Basile Starynkevitch  <basile@starynkevitch.net>

	* gengtype.c:  Include getopt.h and version.h.

	(lang_bitmap, struct outf, outf_p)
	(get_output_file_with_visibility, oprintf): Definitions moved to
	gengtype.h
	(output_files, header_file, srcdir, srcdir_len, this_file,
do_dump): No more static variables.
	(do_debug): New.
	(dbgprint_count_type_at): Added new function.
	(gengtype_long_options): New.
	(print_usage, print_version, parse_program_options): New.
	(main): Call parse_program_options, and removed old option
	handling code.  Added some debug output.

	* gengtype.h:  Updated copyright year.
	(lang_bitmap, struct outf, outf_p, header_file, oprintf)
	(get_output_file_with_visibility, srcdir, srcdir_len, do_dump):
	Moved from gengtype.c to here.
	(do_debug, read_state_filename, write_state_filename): New
variables. (DBGPRINTF, DBGPRINT_COUNT_TYPE): New macros.

	* Makefile.in:
	(REVISION): Always defined.
	(version.o): Removed ifdef REVISION_c.
	(s-gtype): Pass arguments to build/gengtype program.
	(build/version.o): Added building rule.
	(build/gengtype$(build_exeext)): Added build/version.o.
################################################################

the diff file against trunk rev 164437.

Ok for trunk? or Ok with what changes?

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 mine, sont seulement les miennes} ***

[-- Attachment #2: cumulatedpatch1_declprog__gengtypethird_r164437.diff --]
[-- Type: text/x-diff, Size: 21541 bytes --]

Index: gcc/gengtype.c
===================================================================
--- gcc/gengtype.c	(revision 164437)
+++ gcc/gengtype.c	(working copy)
@@ -20,10 +20,12 @@
 
 #include "bconfig.h"
 #include "system.h"
-#include "gengtype.h"
 #include "errors.h"	/* for fatal */
+#include "getopt.h"
 #include "double-int.h"
+#include "version.h"    /* for version_string & pkgversion_string.  */
 #include "hashtab.h"
+#include "gengtype.h"
 
 /* Data types, macros, etc. used only in this file.  */
 
@@ -39,7 +41,6 @@ enum typekind {
   TYPE_PARAM_STRUCT
 };
 
-typedef unsigned lang_bitmap;
 
 /* A way to pass data through to the output end.  */
 struct options
@@ -120,47 +121,42 @@ struct type
   || (x)->kind == TYPE_STRUCT 			\
   || (x)->kind == TYPE_LANG_STRUCT)
 
-/* Structure representing an output file.  */
-struct outf
-{
-  struct outf *next;
-  const char *name;
-  size_t buflength;
-  size_t bufused;
-  char *buf;
-};
-typedef struct outf * outf_p;
 
-/* An output file, suitable for definitions, that can see declarations
-   made in INPUT_FILE and is linked into every language that uses
-   INPUT_FILE.  May return NULL in plugin mode. */
-extern outf_p get_output_file_with_visibility
-   (const char *input_file);
+
 const char *get_output_file_name (const char *);
 
-/* Print, like fprintf, to O.  No-op if O is NULL. */
-static void oprintf (outf_p o, const char *S, ...)
-     ATTRIBUTE_PRINTF_2;
 
 /* The list of output files.  */
-static outf_p output_files;
+outf_p output_files;
 
+/* The output header file that is included into pretty much every
+   source file.  */
+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;
 static size_t nb_plugin_files;
-/* the generated plugin output name & file */
+
+/* the generated plugin output file and name.  */
 static outf_p plugin_output;
+static char* plugin_output_filename;
 
-/* The output header file that is included into pretty much every
-   source file.  */
-static outf_p header_file;
+/* Our source directory and its length.  */
+const char *srcdir;
+size_t srcdir_len;
 
-/* Source directory.  */
-static const char *srcdir;
+/* Variables used for reading and writing the state.  */
+const char *read_state_filename;
+const char *write_state_filename;
 
-/* Length of srcdir name.  */
-static size_t srcdir_len = 0;
+/* Variables to help debugging.  */
+int do_dump;
+int do_debug;
 
 static outf_p create_file (const char *, const char *);
 
@@ -220,10 +216,12 @@ xasprintf (const char *format, ...)
 static const char **gt_files;
 static size_t num_gt_files;
 
-/* A number of places use the name of this file for a location for
-   things that we can't rely on the source to define.  Make sure we
-   can still use pointer comparison on filenames.  */
-static const char this_file[] = __FILE__;
+/* A number of places use the name of this "gengtype.h" 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__;
+/* The "system.h" file is likewise specially useful.  */
+const char system_h_file[] = "system.h";
 
 /* Vector of per-language directories.  */
 static const char **lang_dir_names;
@@ -249,8 +247,10 @@ static lang_bitmap
 get_lang_bitmap (const char *gtfile)
 {
 
-  if (gtfile == this_file)
-    /* Things defined in this file are universal.  */
+  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
     {
@@ -275,6 +275,67 @@ set_lang_bitmap (char *gtfile, lang_bitmap n)
     }
 }
 
+
+#if ENABLE_CHECKING
+/* Utility debugging function, printing the various type counts within
+   a list of types.  Called thru the DBGPRINT_COUNT_TYPE macro.  */
+void dbgprint_count_type_at (const char*fil, int lin, const char*msg,  type_p t)
+{
+  int nb_types=0, nb_scalar=0, nb_string=0;
+  int nb_struct=0, nb_union=0, nb_array=0, nb_pointer=0;
+  int nb_lang_struct=0, nb_param_struct=0;
+  type_p p=NULL;
+  for (p=t; p; p=p->next)
+    {
+      nb_types++;
+      switch (p->kind)
+	{
+	case TYPE_SCALAR:
+	  nb_scalar++;
+	  break;
+	case TYPE_STRING:
+	  nb_string++;
+	  break;
+	case TYPE_STRUCT:
+	  nb_struct++;
+	  break;
+	case TYPE_UNION:
+	  nb_union++;
+	  break;
+	case TYPE_POINTER:
+	  nb_pointer++;
+	  break;
+	case TYPE_ARRAY:
+	  nb_array++;
+	  break;
+	case TYPE_LANG_STRUCT:
+	  nb_lang_struct++;
+	  break;
+	case TYPE_PARAM_STRUCT:
+	  nb_param_struct++;
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+    }
+  fprintf (stderr, "\n" "%s:%d: %s: @@%%@@ %d types ::\n",
+	   lbasename (fil), lin, msg, nb_types);
+  if (nb_scalar>0 || nb_string>0)
+    fprintf (stderr, "@@%%@@ %d scalars, %d strings\n",
+	     nb_scalar, nb_string);
+  if (nb_struct>0 || nb_union>0)
+    fprintf (stderr, "@@%%@@ %d structs, %d unions\n",
+	     nb_struct, nb_union);
+  if (nb_pointer>0 || nb_array>0)
+    fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n",
+	     nb_pointer, nb_array);
+  if (nb_lang_struct>0 || nb_param_struct>0)
+    fprintf (stderr, "@@%%@@ %d lang_structs, %d param_structs\n",
+	     nb_lang_struct, nb_param_struct);
+  fprintf (stderr, "\n");
+}
+#endif /*ENABLE_CHECKING*/
+
 /* Scan the input file, LIST, and determine how much space we need to
    store strings in.  Also, count the number of language directories
    and files.  The numbers returned are overestimates as they does not
@@ -4209,91 +4270,258 @@ dump_everything (void)
 }
 
 \f
+
+/* Option specification for getopt_long.  */
+static const struct option gengtype_long_options[] = {
+  { "help",      no_argument, NULL, 'h' },
+  { "version",   no_argument, NULL, 'V' },
+  { "dump",      no_argument, NULL, 'd' },
+  { "debug",     no_argument, NULL, 'D' },
+  { "plugin",    required_argument, NULL, 'P' },
+  { "srcdir",    required_argument, NULL, 'S' },
+  { "inputs",    required_argument, NULL, 'I' },
+  { "read-state",    required_argument, NULL, 'r' },
+  { "write-state",    required_argument, NULL, 'w' },
+  /* Terminating NULL placeholder.  */
+  { NULL,        no_argument, NULL, 0   },
+};
+
+
+static void
+print_usage (void)
+{
+    printf ("Usage: %s\n", progname);
+    printf ("\t -h | --help "
+	    " \t# Give this help.\n");
+    printf ("\t -D | --debug "
+	    " \t# Give debug output to debug %s itself.\n",
+            progname);
+    printf ("\t -V | --version "
+	    " \t# Give version information.\n");
+    printf ("\t -d | --dump "
+	    " \t# Dump state for debugging.\n");
+    printf ("\t -P | --plugin <output-file> <plugin-src> ... "
+            " \t# Generate for plugin.\n");
+    printf ("\t -S | --srcdir <GCC-directory> "
+            " \t# Specify the GCC source directory.\n");
+    printf ("\t -I | --inputs <input-list> "
+            " \t# Specify the file with source files list.\n");
+    printf ("\t -w | --write-state <state-file> "
+            " \t# Write a state file.\n");
+    printf ("\t -r | --read-state <state-file> "
+            " \t# Read a state file.\n");
+}
+
+static void
+print_version (void)
+{
+    printf ("%s %s%s\n", progname, pkgversion_string, version_string);
+    printf ("Report bugs: %s\n", bug_report_url);
+}
+
+/* Parse the program options using getopt_long... */
+static void
+parse_program_options (int argc, char**argv)
+{
+    int opt = -1;
+    while ((opt = getopt_long (argc, argv, "hVdP:S:I:w:r:D",
+			       gengtype_long_options, NULL)) >= 0)
+    {
+	switch (opt)
+	{
+	case 'h': /* --help */
+	    print_usage ();
+	    break;
+	case 'V': /* --version */
+	    print_version ();
+	    break;
+	case 'd': /* --dump */
+      do_dump = 1;
+	    break;
+	case 'D': /* --debug */
+	    do_debug = 1;
+	    break;
+	case 'P': /* --plugin */
+	    if (optarg)
+		plugin_output_filename = optarg;
+	    else
+		fatal ("missing plugin output file name");
+	    break;
+	case 'S': /* --srcdir */
+	    if (optarg)
+		srcdir = optarg;
+	    else
+		fatal ("missing source directory");
+	    srcdir_len = strlen (srcdir);
+	    break;
+	case 'I': /* --inputs */
+	    if (optarg)
+		inputlist = optarg;
+	    else
+		fatal ("missing input list");
+	    break;
+	case 'r': /* --read-state */
+	    if (optarg)
+		read_state_filename = optarg;
+	    else
+		fatal ("missing read state file");
+	    DBGPRINTF ("read state %s\n", optarg);
+	    break;
+	case 'w': /* --write-state */
+	    DBGPRINTF ("write state %s\n", optarg);
+	    if (optarg)
+		write_state_filename = optarg;
+	    else
+		fatal ("missing write state file");
+	    break;
+	default:
+	    fprintf (stderr, "%s: unknown flag '%c'\n", progname, opt);
+	    print_usage ();
+	    fatal ("unexpected flag");
+    }
+    };
+    if (plugin_output_filename)
+    {
+	/* In plugin mode we require some input files.  */
+	int i = 0;
+	if (optind >= argc)
+	    fatal ("no source files given in plugin mode");
+	nb_plugin_files = argc - optind;
+	for (i = 0; i < (int) nb_plugin_files; i++)
+      {
+	    char *name = argv[i + optind];
+	    plugin_files[i] = name;
+      }
+    }
+}
+
+
 int
 main (int argc, char **argv)
 {
   size_t i;
-  static struct fileloc pos = { this_file, 0 };
-  char* inputlist = 0;
-  int do_dump = 0;
+  static struct fileloc pos = { NULL, 0 };
   outf_p output_header;
-  char* plugin_output_filename = NULL;
-  /* fatal uses this */
-  progname = "gengtype";
 
-  if (argc >= 2 && !strcmp (argv[1], "-d"))
+  /* Mandatory common initializations.  */
+  progname = "gengtype"; /* For fatal and messages.  */
+  /* Set the scalar_is_char union number for predefined scalar types.  */
+  scalar_nonchar.u.scalar_is_char = FALSE;
+  scalar_char.u.scalar_is_char = TRUE;
+
+  parse_program_options (argc, argv);
+
+#if ENABLE_CHECKING
+  if (do_debug)
     {
-      do_dump = 1;
-      argv = &argv[1];
-      argc--;
+      time_t now = (time_t) 0;
+      time (&now);
+      DBGPRINTF ("gengtype started pid %d at %s",
+		 (int) getpid (), ctime (&now));
     }
+#endif
 
-  if (argc >= 6 && !strcmp (argv[1], "-P"))
+  /*** Parse the input list and the input files.  ***/
+  DBGPRINTF ("inputlist %s", inputlist);
+  if (read_state_filename)
     {
-      plugin_output_filename = argv[2];
-      plugin_output = create_file ("GCC", plugin_output_filename);
-      srcdir = argv[3];
-      inputlist = argv[4];
-      nb_plugin_files = argc - 5;
-      plugin_files = XCNEWVEC (char *, nb_plugin_files);
-      for (i = 0; i < nb_plugin_files; i++)
-      {
-        /* Place an all zero lang_bitmap before the plugin file
-	   name.  */
-        char *name = argv[i + 5];
-        int len = strlen(name) + 1 + sizeof (lang_bitmap);
-        plugin_files[i] = XCNEWVEC (char, len) + sizeof (lang_bitmap);
-        strcpy (plugin_files[i], name);
-      }
+      fatal ("read state %s not implemented yet", read_state_filename);
+      /* TODO: implement read state.  */
     }
-  else if (argc == 3)
+  else if (inputlist)
     {
-      srcdir = argv[1];
-      inputlist = argv[2];
+      /* These types are set up with #define or else outside of where
+	 we can see them.  We should initialize them before calling
+	 read_input_list.  */
+      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);
+      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]);
+      }
+      DBGPRINT_COUNT_TYPE ("structures after parsing", structures);
+      DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs);
+
     }
   else
-    fatal ("usage: gengtype [-d] [-P pluginout.h] srcdir input-list "
-           "[file1 file2 ... fileN]");
-
-  srcdir_len = strlen (srcdir);
-
-  read_input_list (inputlist);
+    fatal ("either an input list or a read state file should be given");
   if (hit_error)
     return 1;
 
-  scalar_char.u.scalar_is_char = true;
-  scalar_nonchar.u.scalar_is_char = false;
-  gen_rtx_next ();
 
-  /* These types are set up with #define or else outside of where
-     we can see them.  */
-  pos.line = __LINE__ + 1;
-  do_scalar_typedef ("CUMULATIVE_ARGS", &pos); pos.line++;
-  do_scalar_typedef ("REAL_VALUE_TYPE", &pos); pos.line++;
-  do_scalar_typedef ("FIXED_VALUE_TYPE", &pos); pos.line++;
-  do_scalar_typedef ("double_int", &pos); pos.line++;
-  do_scalar_typedef ("uint64_t", &pos); pos.line++;
-  do_scalar_typedef ("uint8", &pos); pos.line++;
-  do_scalar_typedef ("jword", &pos); pos.line++;
-  do_scalar_typedef ("JCF_u2", &pos); pos.line++;
-  do_scalar_typedef ("void", &pos); pos.line++;
-  do_typedef ("PTR", create_pointer (resolve_typedef ("void", &pos)), &pos);
+  if (plugin_output_filename)
+    {
+      size_t ix = 0;
+      /* In plugin mode, we should have read a state file, and have
+	 given at least one plugin file.  */
+      if (!read_state_filename)
+	fatal ("No read state given in plugin mode for %s", plugin_output_filename);
 
-  for (i = 0; i < num_gt_files; i++)
-    parse_file (gt_files[i]);
+      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]);
+
+      if (hit_error)
+	return 1;
+
+      plugin_output = create_file ("GCC", plugin_output_filename);
+      DBGPRINTF ("created plugin_output %p named %s",
+		 (void*) plugin_output, plugin_output->name);
+    }
+  else
+    { /* No plugin files, we are in normal mode.  */
+      if (!srcdir)
+	fatal ("gengtype needs a source directory in normal mode");
+    }
   if (hit_error)
     return 1;
 
+  gen_rtx_next ();
+
+  /* The call to set_gc_used may indirectly call find_param_structure
+     hence enlarge the param_structs list of types.  So it should
+     happen before writing the state.  */
   set_gc_used (variables);
 
+  /* We should write the state here, but it is not yet implemented.  */
+  if (write_state_filename)
+    {
+      fatal ("write state %s in not yet implemented", write_state_filename);
+      /* TODO: implement write state.  */
+    }
+
+
   open_base_files ();
+
   write_enum_defn (structures, param_structs);
   write_typed_alloc_defns (structures, typedefs);
   output_header = plugin_output ? plugin_output : header_file;
+  DBGPRINT_COUNT_TYPE ("structures before write_types outputheader",
+                       structures);
+  DBGPRINT_COUNT_TYPE ("param_structs before write_types outputheader",
+                       param_structs);
+
   write_types (output_header, structures, param_structs, &ggc_wtd);
   if (plugin_files == NULL)
     {
+      DBGPRINT_COUNT_TYPE ("structures before write_types headerfil",
+                           structures);
+      DBGPRINT_COUNT_TYPE ("param_structs before write_types headerfil",
+                           param_structs);
       write_types (header_file, structures, param_structs, &pch_wtd);
       write_local (header_file, structures, param_structs);
     }
@@ -4305,12 +4533,7 @@ main (int argc, char **argv)
   if (do_dump)
     dump_everything ();
 
-  if (plugin_files)
-  {
-    for (i = 0; i < nb_plugin_files; i++)
-      free (plugin_files[i] - sizeof (lang_bitmap));
-    free (plugin_files);
-  }
+  /* Don't bother about free-ing any input file, etc.  */
 
   if (hit_error)
     return 1;
Index: gcc/gengtype.h
===================================================================
--- gcc/gengtype.h	(revision 164437)
+++ gcc/gengtype.h	(working copy)
@@ -1,5 +1,6 @@
 /* Process source files and output type information.
-   Copyright (C) 2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2007, 2008, 2010
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -20,6 +21,10 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_GENGTYPE_H
 #define GCC_GENGTYPE_H
 
+/* Sets of accepted source languages like C, C++, Ada... are
+   represented by a bitmap.  */
+typedef unsigned lang_bitmap;
+
 /* A file position, mostly for error messages.
    The FILE element may be compared using pointer equality.  */
 struct fileloc {
@@ -37,6 +42,44 @@ typedef struct options *options_p;
 extern int lexer_toplevel_done;
 extern struct fileloc lexer_line;
 
+/* Structure representing an output file.  */
+struct outf
+{
+  struct outf *next;
+  const char *name;
+  size_t buflength;
+  size_t bufused;
+  char *buf;
+};
+typedef struct outf* outf_p;
+
+/* The list of output files.  */
+extern outf_p output_files;
+
+/* The output header file that is included into pretty much every
+   source file.  */
+extern outf_p header_file;
+
+/* Print, like fprintf, to O.  No-op if O is NULL.  */
+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);
+
+/* Source directory.  */
+extern const char *srcdir;
+
+/* Length of srcdir name.  */
+extern size_t srcdir_len;
+
+/* Variable used for reading and writing the state.  */
+extern const char *read_state_filename;
+extern const char *write_state_filename;
+
 /* Print an error message.  */
 extern void error_at_line
   (const struct fileloc *pos, const char *msg, ...) ATTRIBUTE_PRINTF_2;
@@ -110,4 +153,22 @@ enum {
      a meaningful value to be printed.  */
   FIRST_TOKEN_WITH_VALUE = PARAM_IS
 };
+
+
+/* For debugging purposes of gengtype itself!  */
+extern int do_dump;
+extern int do_debug;
+
+#if ENABLE_CHECKING
+#define DBGPRINTF(Fmt,...) do {if (do_debug)				\
+	    fprintf (stderr, "%s:%d: " Fmt "\n",			\
+		    lbasename (__FILE__),__LINE__, ##__VA_ARGS__);} while (0)
+void dbgprint_count_type_at (const char*, int, const char*, type_p);
+#define DBGPRINT_COUNT_TYPE(Msg,Ty) do {if (do_debug) \
+      dbgprint_count_type_at (__FILE__, __LINE__, Msg, Ty);}while (0)
+#else
+#define DBGPRINTF(Fmt,...) do {/*nodbgrintf*/} while (0)
+#define DBGPRINT_COUNT_TYPE(Msg,Ty) do{/*nodbgprint_count_type*/}while (0)
+#endif /*ENABLE_CHECKING*/
+
 #endif
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 164437)
+++ gcc/Makefile.in	(working copy)
@@ -837,6 +837,7 @@ DATESTAMP_c := $(shell cat $(DATESTAMP))
 
 ifeq (,$(wildcard $(REVISION)))
 REVISION_c  :=
+REVISION    :=
 else
 REVISION_c  := $(shell cat $(REVISION))
 endif
@@ -2245,11 +2246,7 @@ gcc-options.o: options.c $(CONFIG_H) $(SYSTEM_H) c
 
 dumpvers: dumpvers.c
 
-ifdef REVISION_c
 version.o: version.c version.h $(REVISION) $(DATESTAMP) $(BASEVER) $(DEVPHASE)
-else
-version.o: version.c version.h $(DATESTAMP) $(BASEVER) $(DEVPHASE)
-endif
 	$(COMPILER) $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \
 	-DBASEVER=$(BASEVER_s) -DDATESTAMP=$(DATESTAMP_s) \
 	-DREVISION=$(REVISION_s) \
@@ -3809,7 +3806,7 @@ s-gtyp-input: Makefile
 
 s-gtype: build/gengtype$(build_exeext) $(filter-out [%], $(GTFILES)) \
 	 gtyp-input.list
-	$(RUN_GEN) build/gengtype$(build_exeext) $(srcdir) gtyp-input.list
+	$(RUN_GEN) build/gengtype$(build_exeext) -S $(srcdir) -I gtyp-input.list
 	$(STAMP) s-gtype
 
 generated_files = config.h tm.h $(TM_P_H) $(TM_H) multilib.h \
@@ -3829,6 +3826,16 @@ build/%.o :  # dependencies provided by explicit r
 	$(COMPILER_FOR_BUILD) -c $(BUILD_COMPILERFLAGS) $(BUILD_CPPFLAGS) \
 		-o $@ $<
 
+## build/version.o is compiled by the $(COMPILER_FOR_BUILD) but needs
+## several C macro definitions, just like version.o
+build/version.o:  version.c version.h \
+                  $(REVISION) $(DATESTAMP) $(BASEVER) $(DEVPHASE)
+	$(COMPILER_FOR_BUILD) -c $(BUILD_COMPILERFLAGS) $(BUILD_CPPFLAGS) \
+	-DBASEVER=$(BASEVER_s) -DDATESTAMP=$(DATESTAMP_s) \
+	-DREVISION=$(REVISION_s) \
+	-DDEVPHASE=$(DEVPHASE_s) -DPKGVERSION=$(PKGVERSION_s) \
+	-DBUGURL=$(BUGURL_s) -o $@ $<
+
 # Header dependencies for the programs that generate source code.
 # These are library modules...
 build/errors.o : errors.c $(BCONFIG_H) $(SYSTEM_H) errors.h
@@ -3940,7 +3947,8 @@ $(genprog:%=build/gen%$(build_exeext)): $(BUILD_ER
 build/genautomata$(build_exeext) : BUILD_LIBS += -lm
 
 # These programs are not linked with the MD reader.
-build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o
+build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \
+              build/version.o
 build/genhooks$(build_exeext) : $(BUILD_ERRORS)
 
 # Generated source files for gengtype.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* gengtype improvements for plugins, thirdround! patch 2/7 [verbosity]
  2010-09-21 19:41 gengtype improvements for plugins, thirdround! patch 1/7 [declprog] Basile Starynkevitch
@ 2010-09-21 22:07 ` Basile Starynkevitch
  2010-09-21 22:43   ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Basile Starynkevitch
  2010-09-22 11:11   ` gengtype improvements for plugins, thirdround! patch 2/7 [verbosity] Laurynas Biveinis
  2010-09-22 11:08 ` gengtype improvements for plugins, thirdround! patch 1/7 [declprog] Laurynas Biveinis
  1 sibling, 2 replies; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-21 22:07 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3127 bytes --]


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-09/msg01702.html

The second piece [verbosity] of our serie of patches adds verbosity to
gengtype. The gengtype user (either a plugin developer or a true GCC
hacker) can pass the -v program flag. This flag can even be passed
more than once, to increase the verbosity level. Verbose messages
explain succintly to the user what gengtype is actually doing.  We
feel this functionality is useful for plugin developpers (who might
not understand what gengtype is doing today, since it is essentially
silent) and even for GCC hackers.

We did took into account Laurynas comments from
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00210.html

In addition of verbose messages, we added a tiny but useful feature to
gengtype. When given a backup directory thru the -B program option and
when it is generating a file gt-foo.h, gengtype renames the old
version into the backup directory so that the user could compare the
old version with the current one.  Verbosity & backing up of old files
go together (in verbose mode, the renaming is told to the
user). Backing up is no longer by default.  Per Laurynas' wish, it
should be enabled by its program option.

Some existing functions has been slightly improved, for instance to
count the number of GTY-ed variables.

The verbosity_level variable needs to be global. It will be used in
file gengtype-state.c.

The attached patch is relative to the previous patch 1 [declprog] sent
in http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01702.html This
relative patch was obtained with
  diff -u -p  -N $(svn stat | awk '/[AM]/{print $2}') \
      --from-file ../thirdround_01_declprog/ > \
        $HOME/Gengtype_Thirdround/patch2_verbosity-relto01.diff

I am also attaching the gzipped cumulated patches against trunk 164437 
as file cumulatedpatch2_verbosity__gengtypethird_r164437.diff.gz

######################################
gcc/ChangeLog entry [of the relative patch]
2010-09-20  Jeremie Salvucci  <jeremie.salvucci@free.fr>
	    Basile Starynkevitch  <basile@starynkevitch.net>

	* gengtype.c (verbosity_level, backup_dir): Added variables.
	(set_gc_used): Count variables for verbosity.
	(close_output_files): Backing up files, counting written ones
	verbosily.
	(write_types): Count emitted functions for verbosity. Added
        debug messages.
	(write_enum_defn): Count structures for verbosity. Added debug
	messages.
	(gengtype_long_options): Added "verbose".
	(print_usage): Ditto.
	(main): Verbose display of parsed files.

	* gengtype.h (verbosity_level): Added declaration.

#####################################################

Ok for trunk?


-- 
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 mine, sont seulement les miennes} ***

[-- Attachment #2: patch2_verbosity-relto01.diff --]
[-- Type: text/x-diff, Size: 10316 bytes --]

--- ../thirdround_01_declprog//gengtype.c	2010-09-20 21:36:24.000000000 +0200
+++ gcc/gengtype.c	2010-09-20 22:35:07.000000000 +0200
@@ -158,6 +158,15 @@ const char *write_state_filename;
 int do_dump;
 int do_debug;
 
+/* For verbose messages to the user.  */
+int verbosity_level;
+
+/* The backup directory should be in the same file-system as the
+   generated files, otherwise the rename(2) system call would fail.
+   If NULL, no backup is made when overwriting a generated file.  */
+static const char* backup_dir;
+
+
 static outf_p create_file (const char *, const char *);
 
 static const char * get_file_basename (const char *);
@@ -1511,8 +1520,15 @@ static void
 set_gc_used (pair_p variables)
 {
   pair_p p;
+  int nbvars = 0;
   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++;
+    };
+  if (verbosity_level >= 2)
+    printf ("%s used %d GTY-ed variables\n", progname, nbvars);
 }
 \f
 /* File mapping routines.  For each input file, there is one output .c file
@@ -1901,26 +1917,56 @@ static void
 close_output_files (void)
 {
   outf_p of;
+  int nbwrittenfiles = 0;
 
   for (of = output_files; of; of = of->next)
     {
 
-      if (!is_file_equal(of))
-      {
-        FILE *newfile = fopen (of->name, "w");
-        if (newfile == NULL)
-          fatal ("opening output file %s: %s", of->name, xstrerror (errno));
-        if (fwrite (of->buf, 1, of->bufused, newfile) != of->bufused)
-          fatal ("writing output file %s: %s", of->name, xstrerror (errno));
-        if (fclose (newfile) != 0)
-          fatal ("closing output file %s: %s", of->name, xstrerror (errno));
-      }
+      if (!is_file_equal (of))
+	{
+	  FILE *newfile = NULL;
+	  char *backupname = NULL;
+	  /* Backup the old version of the output file gt-FOO.c as
+	     BACKUPDIR/gt-FOO.c~ if we have a backup directory.  */
+	  if (backup_dir)
+	    {
+	      backupname = concat (backup_dir, "/",
+				   lbasename (of->name), "~", NULL);
+	      if (!access (of->name, F_OK) && rename (of->name, backupname))
+		fatal ("failed to backup %s as %s: %s",
+		       of->name, backupname, xstrerror (errno));
+	    }
+	  newfile = fopen (of->name, "w");
+	  if (newfile == NULL)
+	    fatal ("opening output file %s: %s", of->name, xstrerror (errno));
+	  if (fwrite (of->buf, 1, of->bufused, newfile) != of->bufused)
+	    fatal ("writing output file %s: %s", of->name, xstrerror (errno));
+	  if (fclose (newfile) != 0)
+	    fatal ("closing output file %s: %s", of->name, xstrerror (errno));
+	  nbwrittenfiles++;
+	  if (verbosity_level >= 2 && backupname)
+	    printf ("%s wrote #%-3d %s backed-up in %s\n",
+		    progname, nbwrittenfiles, of->name, backupname);
+	  else if (verbosity_level >= 1)
+	    printf ("%s wrote #%-3d %s\n", progname, nbwrittenfiles, of->name);
+	  if (backupname)
+	    free (backupname);
+	}
+      else
+	{
+	  /* Output file remains unchanged! */
+	  if (verbosity_level >= 2)
+	    printf ("%s kept %s\n", progname, of->name);
+	}
       free(of->buf);
       of->buf = NULL;
       of->bufused = of->buflength = 0;
     }
+  if (verbosity_level >= 1)
+    printf ("%s wrote %d files.\n", progname, nbwrittenfiles);
 }
 \f
+\f
 struct flist {
   struct flist *next;
   int started_p;
@@ -2800,6 +2846,7 @@ write_types (outf_p output_header, type_
 	     const struct write_types_data *wtd)
 {
   type_p s;
+  int nbfun = 0; /* Count the emitted functions.  */
 
   oprintf (output_header, "\n/* %s*/\n", wtd->comment);
   /* We first emit the macros and the declarations. Functions' code is
@@ -2894,11 +2941,26 @@ write_types (outf_p output_header, type_
 	  {
 	    type_p ss;
 	    for (ss = s->u.s.lang_struct; ss; ss = ss->next)
+	      {
+		nbfun++;
+		DBGPRINTF ("writing func #%d lang_struct ss @ %p '%s'",
+			   nbfun, (void*) ss, ss->u.s.tag);
 	      write_func_for_structure (s, ss, NULL, wtd);
 	  }
+	  }
 	else
+	  {
+	    nbfun++;
+	    DBGPRINTF ("writing func #%d struct s @ %p '%s'",
+		       nbfun, (void*) s, s->u.s.tag);
 	  write_func_for_structure (s, s, NULL, wtd);
       }
+      }
+    else
+      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)
       {
@@ -2910,11 +2972,27 @@ write_types (outf_p output_header, type_
 	  {
 	    type_p ss;
 	    for (ss = stru->u.s.lang_struct; ss; ss = ss->next)
+	      {
+		nbfun++;
+		DBGPRINTF ("writing func #%d param lang_struct ss @ %p '%s'",
+			   nbfun, (void*) ss,  ss->u.s.tag);
 	      write_func_for_structure (s, ss, param, wtd);
 	  }
+	  }
 	else
+	  {
+	    nbfun++;
+	    DBGPRINTF ("writing func #%d param struct s @ %p stru @ %p '%s'",
+		       nbfun, (void*) s,
+		       (void*) stru,  stru->u.s.tag);
 	  write_func_for_structure (s, stru, param, wtd);
       }
+      }
+    else
+      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 =
@@ -3108,27 +3186,44 @@ static void
 write_enum_defn (type_p structures, type_p param_structs)
 {
   type_p s;
+  int nbstruct = 0;
+  int nbparamstruct = 0;
 
   if (!header_file)
     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))
       {
+	DBGPRINTF ("write_enum_defn s @ %p nbstruct %d",
+		  (void*) s, nbstruct);
+	if (UNION_OR_STRUCT_P (s))
+	  DBGPRINTF ("write_enum_defn s %p #%d is unionorstruct tagged %s",
+		     (void*) s, nbstruct, s->u.s.tag);
 	oprintf (header_file, " gt_ggc_e_");
 	output_mangled_typename (header_file, s);
 	oprintf (header_file, ",\n");
+	nbstruct++;
       }
+
   for (s = param_structs; s; s = s->next)
     if (s->gc_used == GC_POINTED_TO)
       {
+	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?  */
@@ -4273,17 +4368,19 @@ dump_everything (void)
 
 /* Option specification for getopt_long.  */
 static const struct option gengtype_long_options[] = {
-  { "help",      no_argument, NULL, 'h' },
-  { "version",   no_argument, NULL, 'V' },
-  { "dump",      no_argument, NULL, 'd' },
-  { "debug",     no_argument, NULL, 'D' },
-  { "plugin",    required_argument, NULL, 'P' },
-  { "srcdir",    required_argument, NULL, 'S' },
-  { "inputs",    required_argument, NULL, 'I' },
+  { "help",          no_argument, 	NULL, 'h' },
+  { "version",       no_argument, 	NULL, 'V' },
+  { "verbose",       no_argument, 	NULL, 'v' },
+  { "dump",          no_argument, 	NULL, 'd' },
+  { "debug",         no_argument, 	NULL, 'D' },
+  { "plugin",        required_argument, NULL, 'P' },
+  { "srcdir",        required_argument, NULL, 'S' },
+  { "backupdir",     required_argument, NULL, 'B' },
+  { "inputs",        required_argument, NULL, 'I' },
   { "read-state",    required_argument, NULL, 'r' },
-  { "write-state",    required_argument, NULL, 'w' },
+  { "write-state",   required_argument, NULL, 'w' },
   /* Terminating NULL placeholder.  */
-  { NULL,        no_argument, NULL, 0   },
+  { NULL,            no_argument,       NULL,  0  },
 };
 
 
@@ -4298,12 +4395,16 @@ print_usage (void)
             progname);
     printf ("\t -V | --version "
 	    " \t# Give version information.\n");
+    printf ("\t -v | --verbose "
+	    " \t# Increase verbosity.  Can be given several times.\n");
     printf ("\t -d | --dump "
 	    " \t# Dump state for debugging.\n");
     printf ("\t -P | --plugin <output-file> <plugin-src> ... "
             " \t# Generate for plugin.\n");
     printf ("\t -S | --srcdir <GCC-directory> "
             " \t# Specify the GCC source directory.\n");
+    printf ("\t -B | --backupdir <directory> "
+            " \t# Specify the backup directory for updated files.\n");
     printf ("\t -I | --inputs <input-list> "
             " \t# Specify the file with source files list.\n");
     printf ("\t -w | --write-state <state-file> "
@@ -4324,7 +4425,7 @@ static void
 parse_program_options (int argc, char**argv)
 {
     int opt = -1;
-    while ((opt = getopt_long (argc, argv, "hVdP:S:I:w:r:D",
+  while ((opt = getopt_long (argc, argv, "hvVdP:S:B:I:w:r:D",
 			       gengtype_long_options, NULL)) >= 0)
     {
 	switch (opt)
@@ -4332,6 +4433,9 @@ parse_program_options (int argc, char**a
 	case 'h': /* --help */
 	    print_usage ();
 	    break;
+	case 'v': /* --verbose */
+	  verbosity_level++;
+	  break;
 	case 'V': /* --version */
 	    print_version ();
 	    break;
@@ -4354,6 +4458,13 @@ parse_program_options (int argc, char**a
 		fatal ("missing source directory");
 	    srcdir_len = strlen (srcdir);
 	    break;
+	case 'B': /* --backupdir */
+	    if (optarg)
+		srcdir = optarg;
+	    else
+		fatal ("missing backup directory");
+	    srcdir_len = strlen (srcdir);
+	    break;
 	case 'I': /* --inputs */
 	    if (optarg)
 		inputlist = optarg;
@@ -4452,6 +4563,8 @@ main (int argc, char **argv)
       }
       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);
 
     }
   else
--- ../thirdround_01_declprog//gengtype.h	2010-09-20 21:12:46.000000000 +0200
+++ gcc/gengtype.h	2010-09-20 22:03:42.000000000 +0200
@@ -154,6 +154,9 @@ enum {
   FIRST_TOKEN_WITH_VALUE = PARAM_IS
 };
 
+/* Level for verbose messages.  Gengtype tells something to its user
+   when it is positive, and tells more if it is greater.  */
+extern int verbosity_level;
 
 /* For debugging purposes of gengtype itself!  */
 extern int do_dump;

[-- Attachment #3: cumulatedpatch2_verbosity-gengtypethird-r164437.diff.gz --]
[-- Type: application/octet-stream, Size: 8389 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* gengtype improvements for plugins, thirdround! patch 3/7 [inputfile]
  2010-09-21 22:07 ` gengtype improvements for plugins, thirdround! patch 2/7 [verbosity] Basile Starynkevitch
@ 2010-09-21 22:43   ` Basile Starynkevitch
  2010-09-22  0:29     ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Basile Starynkevitch
                       ` (2 more replies)
  2010-09-22 11:11   ` gengtype improvements for plugins, thirdround! patch 2/7 [verbosity] Laurynas Biveinis
  1 sibling, 3 replies; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-21 22:43 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 5157 bytes --]


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
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00887.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01702.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01706.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 latter gave more feedback in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00887.html that we did
take into account.

The gengtype-lex.l & gengtype-parse.c files need to include fatal.h
because it is used from gengtype.h

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.

The http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00842.html previous
version of this patch contained two variants, one with the
INPUT_FILE_MAGIC trick and one without.  I would prefer the magic
trick to be included, since it will definitely help any brave or
foolish :-) enough gengtype hacker.  If you really want me to remove
the trick before committing this patch, please ask.  Notice that since
I added the CHECK_INPUT_FILE_MAGIC macro, the trick don't need much
lines in the patch.


Since struct location_s is no longer used inside GCC, the hack in
new_structure to handle it is removed.
 
The attached patch is relative to the previous patch 2 [verbosity] sent

This relative patch was obtained with
 diff -u -p  -N $(svn stat | awk '/[AM]/{print $2}') \
     --from-file ../thirdround_02_verbosity/ > \
        $HOME/Gengtype_Thirdround/patch3_inputfile-relto02.diff

########## gcc/ChangeLog entry is
2010-09-20  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): Remove location_s hack.
	(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.

##########


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 mine, sont seulement les miennes} ***

[-- Attachment #2: patch3_inputfile-relto02.diff --]
[-- Type: text/x-diff, Size: 35129 bytes --]

--- ../thirdround_02_verbosity//gengtype.c	2010-09-20 22:35:07.000000000 +0200
+++ gcc/gengtype.c	2010-09-21 11:02:01.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;
 
@@ -169,12 +168,11 @@ static const char* backup_dir;
 
 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 *);
 
 \f
 /* Nonzero iff an error has occurred.  */
@@ -194,7 +192,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;
@@ -222,68 +221,24 @@ 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
@@ -477,11 +432,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 (;;)
 	{
@@ -511,13 +466,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
@@ -525,13 +483,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
@@ -750,21 +708,6 @@ new_structure (const char *name, int isu
   if (s->u.s.lang_struct)
     s->u.s.lang_struct->u.s.bitmap |= bitmap;
 
-  /* Reset location_s's location to input.h so that we know where to
-     write out its mark routine.  */
-  if (!strcmp (name, "location_s") && !isunion
-      && pos->file == this_file)
-    {
-      size_t n;
-      for (n = 0; n < num_gt_files; n++)
-	if (!strcmp (gt_files[n] + strlen (gt_files[n]) - strlen ("input.h"),
-		     "input.h"))
-	  {
-	    s->u.s.line.file = gt_files[n];
-	    break;
-	  }
-    }
-
     return s;
 }
 
@@ -902,7 +845,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)
+		  const input_file* inpf, int line)
 {
   pair_p field;
 
@@ -911,7 +854,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;
 }
@@ -1667,8 +1610,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;
@@ -1677,26 +1621,28 @@ 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
-   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
@@ -1722,19 +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
+   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;
@@ -1751,16 +1697,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)
@@ -1786,7 +1732,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;
@@ -1797,30 +1743,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
@@ -1872,13 +1818,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;
@@ -1970,7 +1916,7 @@ close_output_files (void)
 struct flist {
   struct flist *next;
   int started_p;
-  const char *name;
+  const input_file *file;
   outf_p f;
 };
 
@@ -2019,7 +1965,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);
@@ -2490,7 +2436,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))
@@ -2658,16 +2604,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
@@ -3248,9 +3205,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++)
@@ -3280,7 +3240,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)
@@ -3289,7 +3249,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");
 	    }
       }
@@ -3306,7 +3266,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;
@@ -3315,7 +3275,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");
 	    }
       }
@@ -3651,8 +3611,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");
@@ -4190,8 +4150,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
@@ -4424,89 +4384,142 @@ print_version (void)
 static void
 parse_program_options (int argc, char**argv)
 {
-    int opt = -1;
+  int opt = -1;
   while ((opt = getopt_long (argc, argv, "hvVdP:S:B:I:w:r:D",
-			       gengtype_long_options, NULL)) >= 0)
+			     gengtype_long_options, NULL)) >= 0)
     {
-	switch (opt)
+      switch (opt)
 	{
 	case 'h': /* --help */
-	    print_usage ();
-	    break;
+	  print_usage ();
+	  break;
 	case 'v': /* --verbose */
 	  verbosity_level++;
 	  break;
 	case 'V': /* --version */
-	    print_version ();
-	    break;
+	  print_version ();
+	  break;
 	case 'd': /* --dump */
-      do_dump = 1;
-	    break;
+	  do_dump = 1;
+	  break;
 	case 'D': /* --debug */
-	    do_debug = 1;
-	    break;
+	  do_debug = 1;
+	  break;
 	case 'P': /* --plugin */
-	    if (optarg)
-		plugin_output_filename = optarg;
-	    else
-		fatal ("missing plugin output file name");
-	    break;
+	  if (optarg)
+	    plugin_output_filename = optarg;
+	  else
+	    fatal ("missing plugin output file name");
+	  break;
 	case 'S': /* --srcdir */
-	    if (optarg)
-		srcdir = optarg;
-	    else
-		fatal ("missing source directory");
-	    srcdir_len = strlen (srcdir);
-	    break;
+	  if (optarg)
+	    srcdir = optarg;
+	  else
+	    fatal ("missing source directory");
+	  srcdir_len = strlen (srcdir);
+	  break;
 	case 'B': /* --backupdir */
-	    if (optarg)
-		srcdir = optarg;
-	    else
-		fatal ("missing backup directory");
-	    srcdir_len = strlen (srcdir);
-	    break;
+	  if (optarg)
+	    srcdir = optarg;
+	  else
+	    fatal ("missing backup directory");
+	  srcdir_len = strlen (srcdir);
+	  break;
 	case 'I': /* --inputs */
-	    if (optarg)
-		inputlist = optarg;
-	    else
-		fatal ("missing input list");
-	    break;
+	  if (optarg)
+	    inputlist = optarg;
+	  else
+	    fatal ("missing input list");
+	  break;
 	case 'r': /* --read-state */
-	    if (optarg)
-		read_state_filename = optarg;
-	    else
-		fatal ("missing read state file");
-	    DBGPRINTF ("read state %s\n", optarg);
-	    break;
+	  if (optarg)
+	    read_state_filename = optarg;
+	  else
+	    fatal ("missing read state file");
+	  DBGPRINTF ("read state %s\n", optarg);
+	  break;
 	case 'w': /* --write-state */
-	    DBGPRINTF ("write state %s\n", optarg);
-	    if (optarg)
-		write_state_filename = optarg;
-	    else
-		fatal ("missing write state file");
-	    break;
+	  DBGPRINTF ("write state %s\n", optarg);
+	  if (optarg)
+	    write_state_filename = optarg;
+	  else
+	    fatal ("missing write state file");
+	  break;
 	default:
-	    fprintf (stderr, "%s: unknown flag '%c'\n", progname, opt);
-	    print_usage ();
-	    fatal ("unexpected flag");
-    }
+	  fprintf (stderr, "%s: unknown flag '%c'\n", progname, opt);
+	  print_usage ();
+	  fatal ("unexpected flag");
+	}
     };
-    if (plugin_output_filename)
+  if (plugin_output_filename)
     {
-	/* In plugin mode we require some input files.  */
-	int i = 0;
-	if (optind >= argc)
-	    fatal ("no source files given in plugin mode");
-	nb_plugin_files = argc - optind;
-	for (i = 0; i < (int) nb_plugin_files; i++)
-      {
-	    char *name = argv[i + optind];
-	    plugin_files[i] = name;
-      }
+      /* In plugin mode we require some input files.  */
+      int i = 0;
+      if (optind >= argc)
+	fatal ("no source files given in plugin mode");
+      nb_plugin_files = argc - optind;
+      for (i = 0; i < (int) nb_plugin_files; i++)
+	{
+	  char *name = argv[i + optind];
+	  plugin_files[i] = input_file_by_name (name);
+	}
     }
 }
 
 
+\f
+/******* Manage input files.  ******/
+
+/* Hash table of unique input file names.  */
+static htab_t input_file_htab;
+
+/* Find or allocate a new input_file by hash-consing it.  */
+input_file*
+input_file_by_name (const char* name)
+{
+  PTR* slot;
+  input_file* f = NULL;
+  int namlen = 0;
+  if (!name)
+    return NULL;
+  namlen = strlen (name);
+  f = XCNEWVAR (input_file, sizeof (input_file)+namlen+2);
+  f->inpbitmap = 0;
+  f->inpoutf = NULL;
+  f->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));
+}
+
+\f
 int
 main (int argc, char **argv)
 {
@@ -4519,6 +4532,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);
 
@@ -4557,10 +4576,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)
@@ -4586,11 +4606,14 @@ 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;
-
       plugin_output = create_file ("GCC", plugin_output_filename);
       DBGPRINTF ("created plugin_output %p named %s",
 		 (void*) plugin_output, plugin_output->name);
--- ../thirdround_02_verbosity//gengtype.h	2010-09-20 22:03:42.000000000 +0200
+++ gcc/gengtype.h	2010-09-21 10:27:50.000000000 +0200
@@ -25,13 +25,116 @@ 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 {
+#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;
+  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 +168,17 @@ 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.  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;
--- ../thirdround_02_verbosity//gengtype-lex.l	2010-09-21 07:40:27.000000000 +0200
+++ gcc/gengtype-lex.l	2010-09-21 07:34:33.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;
 }
 
--- ../thirdround_02_verbosity//gengtype-parse.c	2010-09-21 07:40:34.000000000 +0200
+++ gcc/gengtype-parse.c	2010-09-21 07:36:06.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 ())
     {
@@ -713,40 +716,61 @@ 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 +778,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);

[-- Attachment #3: cumulatedpatch3_inputfile-gengtypethird-r164437.diff.gz --]
[-- Type: application/octet-stream, Size: 15629 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* gengtype improvements for plugins, thirdround! patch 4/7 [filerules]
  2010-09-21 22:43   ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Basile Starynkevitch
@ 2010-09-22  0:29     ` Basile Starynkevitch
  2010-09-22  1:50       ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Basile Starynkevitch
  2010-09-22 12:06       ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Laurynas Biveinis
  2010-09-22 12:05     ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Laurynas Biveinis
  2010-10-18 17:21     ` gengtype patch removing location_s Basile Starynkevitch
  2 siblings, 2 replies; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-22  0:29 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2431 bytes --]



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
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01709.html

This is a slightly improved version of the patch
http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html with Laurynas
comments from http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00419.html
adressed.  As I told before, it improves the core
get_output_file_with_visibility function. This version (relative to
http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html I did sent
before) improved comments and function names, following Laurynas
advices; I also avoided calling regexec twice needlessly. I added a
lot of explanatory comments.  It is made much more modular and less ad
hoc by a file rule machinery. We now use regular expressions to match
the input file name and compute the associated output name & for name.

A detailed comment is available in the patch.

The patch relative to http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01709.html is obtained
with

diff -u -p  $(svn stat . |awk '/[AM]/{print $2}') \
     --from-file ../thirdround_03_inputfile/ > \
     $HOME/Gengtype_Thirdround/patch4_filesrules-relto03.diff

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

	* gengtype.c: Include xregex.h and obstack.h
	Added comments about role of get_output_file_with_visibility and
	our regexpr machinery.
	(frul_actionrout_t, struct file_rule_st): New.
	(hader_dot_h_frul, source_dot_c_frul): New functions.
	(NULL_REGEX,  NULL_FRULACT): New.
	(files_rules): New.
	(matching_file_name_substitute): New function.
	(get_output_file_with_visibility): Updated comments and rewritten
	to use the new files_rules machinery.
#######################


For convenience, I am also attaching the cumulated patches against trunk 
Ok for trunk?

Cheers.
-- 
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 mine, sont seulement les miennes} ***

[-- Attachment #2: patch4_filesrules-relto03.diff --]
[-- Type: text/x-diff, Size: 18077 bytes --]

--- ../thirdround_03_inputfile//gengtype.c	2010-09-21 11:02:01.000000000 +0200
+++ gcc/gengtype.c	2010-09-21 13:53:03.000000000 +0200
@@ -25,6 +25,8 @@
 #include "double-int.h"
 #include "version.h"    /* for version_string & pkgversion_string.  */
 #include "hashtab.h"
+#include "xregex.h"
+#include "obstack.h"
 #include "gengtype.h"
 
 /* Data types, macros, etc. used only in this file.  */
@@ -854,7 +856,7 @@ create_field_all (pair_p next, type_p ty
   field->type = type;
   field->name = name;
   field->opt = opt;
-  field->line.file = inpf;
+  field->line.file = CONST_CAST (input_file*, inpf);
   field->line.line = line;
   return field;
 }
@@ -1727,18 +1729,259 @@ get_file_gtfilename (const input_file *i
   return result;
 }
 
-/* An output file, suitable for definitions, that can see declarations
-   made in INPUT_FILE and is linked into every language that uses
-   INPUT_FILE.  */
+\f
+/** Each input_file has its associated output file outf_p.  The
+    association is computed by the function
+    get_output_file_with_visibility.  The associated file is cached
+    inside input_file in its inpoutf field, so is really computed only
+    once.  Associated output file paths (i.e. output_name-s) are
+    computed by a rule based regexp machinery, using the files_rules
+    array of struct file_rule_st.  A for_name is also computed, giving
+    the source file name for which the output_file is generated; it is
+    often the last component of the input_file path.  */
+
+
+/***
+ Regexpr machinery to compute the output_name and for_name-s of each
+ input_file.  We have a sequence of file rules which gives the POSIX
+ extended regular expression to match an input file path, and two
+ transformed strings for the corresponding output_name and the
+ corresponding for_name.  The transformed string contain dollars: $0
+ is replaced by the entire match, $1 is replaced by the substring
+ matching the first parenthesis in the regexp, etc.  And $$ is replaced
+ by a single verbatim dollar.  The rule order is important.  The
+ general case is last, and the particular cases should come before.
+ An action routine can, when needed, update the out_name & for_name
+ and/or return the appropriate output file.  It is invoked only when a
+ rule is triggered.  When a rule is triggered, the output_name and
+ for_name are computed using their transform string in while $$, $0,
+ $1, ... are suitably replaced.  If there is an action, it is called.
+ In some few cases, the action can directly return the outf_p, but
+ usually it just updates the output_name and for_name so should free
+ them before replacing them.  The get_output_file_with_visibility
+ function creates an outf_p only once per each output_name, so it
+ scans the output_files list for previously seen output file names.
+ */
+
+/* Signature of actions in file rules.  */
+typedef outf_p (frul_actionrout_t) (input_file*, char**, char**);
+
+
+struct file_rule_st {
+  const char* frul_srcexpr;	/* Source string for regexp.  */
+  int frul_rflags;		/* Flags passed to regcomp, usually
+				 * REG_EXTENDED.  */
+  regex_t* frul_re;		/* Compiled regular expression
+				   obtained by regcomp.  */
+  const char* frul_tr_out;	/* Transform string for making the
+				 * output_name, with $1 ... $9 for
+				 * subpatterns and $0 for the whole
+				 * matched filename.  */
+  const char* frul_tr_for;	/* Tranform string for making the
+				   for_name.  */
+  frul_actionrout_t* frul_action; /* The action, if non null, is
+				   * called once the rule matches, on
+				   * the transformed out_name &
+				   * for_name.  It could change them
+				   * and/or give the output file.  */
+};
+
+/* File rule action handling *.h files.  */
+static outf_p header_dot_h_frul (input_file*, char**, char**);
+
+/* File rule action handling *.c files.  */
+static outf_p source_dot_c_frul (input_file*, char**, char**);
+
+#define NULL_REGEX (regex_t*)0
+#define NULL_FRULACT (frul_actionrout_t*)0
+
+/* The array of our rules governing file name generation.  Rules order
+   matters!  Change these rules with extreme care!  */
+
+struct file_rule_st files_rules[] = {
+  /* the c-family/ source directory is special.  */
+  { "^(([^/]*/)*)c-family/([[:alnum:]_-]*)\\.c$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-c-family-$3.h", "c-family/$3.c", NULL_FRULACT},
+
+  { "^(([^/]*/)*)c-family/([[:alnum:]_-]*)\\.h$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-c-family-$3.h", "c-family/$3.h", NULL_FRULACT},
+
+  /* Both c-lang.h & c-tree.h gives gt-c-decl.h for c-decl.c !  */
+  { "^(([^/]*/)*)c-lang\\.h$",
+    REG_EXTENDED, NULL_REGEX, "gt-c-decl.h", "c-decl.c", NULL_FRULACT},
+
+  { "^(([^/]*/)*)c-tree\\.h$",
+    REG_EXTENDED, NULL_REGEX, "gt-c-decl.h", "c-decl.c", NULL_FRULACT},
+
+  /* cp/cp-tree.h gives gt-cp-tree.h for cp/tree.c !  */
+  { "^(([^/]*/)*)cp/cp-tree\\.h$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-cp-tree.h", "cp/tree.c", NULL_FRULACT },
+
+  /* cp/decl.h & cp/decl.c gives gt-cp-decl.h for cp/decl.c !  */
+  { "^(([^/]*/)*)cp/decl\\.[ch]$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-cp-decl.h", "cp/decl.c", NULL_FRULACT },
+
+  /* cp/name-lookup.h gives gt-cp-name-lookup.h for cp/name-lookup.c !  */
+  { "^(([^/]*/)*)cp/name-lookup\\.h$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-cp-name-lookup.h", "cp/name-lookup.c", NULL_FRULACT },
+
+  /* objc/objc-act.h fives gt-objc-objc-act.h for objc/objc-act.c !  */
+  { "^(([^/]*/)*)objc/objc-act\\.h$",
+    REG_EXTENDED, NULL_REGEX,
+    "gt-objc-objc-act.h", "objc/objc-act.c", NULL_FRULACT },
+
+  /* General cases.  For header *.h and source *.c files, we need
+   * special actions to handle the language.  */
+
+  /* Source *.c files are using get_file_gtfilename to compute their
+     output_name and get_file_basename to compute their for_name
+     thru the source_dot_c_frul action.  */
+  { "^(([^/]*/)*)([[:alnum:]_-]*)\\.c$",
+    REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.c", source_dot_c_frul},
+  /* Common header files get "gtype-desc.c" as their output_name,
+   * while language specific header files are handled specially.  So
+   * we need the header_dot_h_frul action.  */
+  { "^(([^/]*/)*)([[:alnum:]_-]*)\\.h$",
+    REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.h", header_dot_h_frul},
+
+  { "^(([^/]*/)*)([[:alnum:]_-]*)\\.in$",
+    REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.in", NULL_FRULACT},
+
+  /* Mandatory null last entry signaling end of rules.  */
+  {NULL, 0, NULL_REGEX, NULL, NULL, NULL_FRULACT}
+};
+
+/* Special file rules action for handling *.h header files.  It gives
+   "gtype-desc.c" for common headers and compute language specific
+   header files.  */
+static outf_p
+header_dot_h_frul (input_file* inpf, char**poutname, char**pforname)
+{
+  const char *basename = 0;
+  int lang_index = 0;
+  const char* inpname = get_input_file_name (inpf);
+  DBGPRINTF ("inpf %p inpname %s outname %s forname %s",
+	     (void*) inpf, inpname, *poutname, *pforname);
+  basename = get_file_basename (inpf);
+  lang_index = get_prefix_langdir_index (basename);
+  DBGPRINTF ("basename %s lang_index %d", basename, lang_index);
+
+  if (lang_index >= 0)
+    {
+      /* The header is language specific.  Given output_name &
+	 for_name remains unchanged.  The base_files array gives the
+	 outf_p.  */
+      DBGPRINTF ("header_dot_h found language specific @ %p '%s'",
+		 (void*) base_files[lang_index],
+		 (base_files[lang_index])->name);
+      return base_files[lang_index];
+    }
+  else
+    {
+      /* The header is common to all front-end languages.  So
+	 output_name is "gtype-desc.c" file.  The calling function
+	 get_output_file_with_visibility will find its outf_p.  */
+      free (*poutname);
+      *poutname = CONST_CAST (char*, "gtype-desc.c");
+      DBGPRINTF ("special 'gtype-desc.c' for inpname %s", inpname);
+      return NULL;
+    }
+}
+
+
+/* Special file rules action for handling *.c source files using
+ * get_file_gtfilename to compute their output_name and
+ * get_file_basename to compute their for_name.  The output_name is
+ * gt-<LANG>-<BASE>.h for language specific source files, and
+ * gt-<BASE>.h for common source files.  */
+static outf_p
+source_dot_c_frul (input_file* inpf, char**poutname, char**pforname)
+{
+  char *newbasename = NULL;
+  char* newoutname = NULL;
+  const char* inpname = get_input_file_name (inpf);
+  DBGPRINTF ("inpf %p inpname %s oriiginal outname %s forname %s",
+	     (void*) inpf, inpname, *poutname, *pforname);
+  newoutname = CONST_CAST (char*, get_file_gtfilename (inpf));
+  DBGPRINTF ("newoutname %s", newoutname);
+  newbasename = CONST_CAST (char*, get_file_basename (inpf));
+  DBGPRINTF ("newbasename %s", newbasename);
+  free (*poutname);
+  free (*pforname);
+  *poutname = newoutname;
+  *pforname = newbasename;
+  return NULL;
+}
+
+/* Utility function for get_output_file_with_visibility which returns
+ * a malloc-ed substituted string using TRS on matching of the FILNAM
+ * file name, using the PMATCH array.  */
+static char*
+matching_file_name_substitute (const char *filnam, regmatch_t pmatch[10],
+			       const char* trs)
+{
+  struct obstack str_obstack;
+  char* str = NULL;
+  char* rawstr = NULL;
+  const char* pt = NULL;
+  DBGPRINTF ("filnam %s", filnam);
+  obstack_init (&str_obstack);
+  for (pt = trs; *pt; pt++) {
+    char c = *pt;
+    if (c == '$')
+      {
+	if (pt[1] == '$')
+	  {
+	    /* A double dollar $$ is substituted by a single verbatim
+	       dollar, but who really uses dollar signs in file
+	       paths? */
+	    obstack_1grow (&str_obstack, '$');
+	  }
+	else if (ISDIGIT (pt[1]))
+	  {
+	    /* Handle $0 $1 ... $9 by appropriate substitution.  */
+	    int dolnum = pt[1] - '0';
+	    int so = pmatch[dolnum].rm_so;
+	    int eo = pmatch[dolnum].rm_eo;
+	    DBGPRINTF ("so=%d eo=%d dolnum=%d", so, eo, dolnum);
+	    if (so>=0 && eo>=so)
+	      obstack_grow (&str_obstack, filnam + so, eo - so);
+	  }
+	else
+	  /* This can happen only when files_rules is buggy! */
+	  fatal ("invalid dollar in transform string %s", trs);
+	/* Always skip the character after the dollar.  */
+	pt++;
+      }
+    else
+      obstack_1grow (&str_obstack, c);
+  }
+  obstack_1grow (&str_obstack, (char) 0);
+  rawstr = XOBFINISH (&str_obstack, char *);
+  str = xstrdup (rawstr);
+  obstack_free (&str_obstack, rawstr);
+  DBGPRINTF ("matched replacement %s", str);
+  rawstr = NULL;
+  return str;
+}
+
+
 
+/* An output file, suitable for definitions, that can see declarations
+   made in INPF and is linked into every language that uses INPF.  Use
+   the files_rules and regexp matching.  */
 outf_p
 get_output_file_with_visibility (input_file* inpf)
 {
-  outf_p r;
-  size_t len;
-  const char *basename;
-  const char *for_name;
-  const char *output_name;
+  outf_p r = NULL;
+  char *for_name = NULL;
+  char *output_name = NULL;
+  const char* inpfname = NULL;
 
   /* 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
@@ -1747,7 +1990,8 @@ get_output_file_with_visibility (input_f
     inpf = system_h_file;
 
   /* In plugin mode, return NULL unless the INPF is one of the
-     plugin_files.  We can compare input_file-s by pointer equality.  */
+     plugin_files.  We can compare input_file-s by pointer equality.
+     We don't use our files_rules machinery in plugin mode.  */
   if (plugin_files)
     {
       size_t i;
@@ -1758,69 +2002,133 @@ get_output_file_with_visibility (input_f
       return NULL;
     }
 
-  /* Determine the output file name.  */
-  basename = get_file_basename (inpf);
+  inpfname = get_input_file_name (inpf);
+  /* Use our files_rules machinery, by trying each rule in sequence
+     until a rule is triggered.  Rule regexpr-s are compiled only once,
+     lazily.  */
+  {
+    int rulix = 0;
+    DBGPRINTF ("passing input file @ %p named %s thru the files_rules",
+	       (void*) inpf, inpfname);
 
-  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 (inpf);
-      for_name = basename;
-    }
-  /* Some headers get used by more than one front-end; hence, it
-     would be inappropriate to spew them out to a single gtype-<lang>.h
-     (and gengtype doesn't know how to direct spewage into multiple
-     gtype-<lang>.h headers at this time).  Instead, we pair up these
-     headers with source files (and their special purpose gt-*.h headers).  */
-  else if (strncmp (basename, "c-family", 8) == 0
-	   && IS_DIR_SEPARATOR (basename[8])
-	   && strcmp (basename + 9, "c-common.h") == 0)
-    output_name = "gt-c-family-c-common.h", for_name = "c-family/c-common.c";
-  else if (strcmp (basename, "c-lang.h") == 0)
-    output_name = "gt-c-decl.h", for_name = "c-decl.c";
-  else if (strcmp (basename, "c-tree.h") == 0)
-    output_name = "gt-c-decl.h", for_name = "c-decl.c";
-  else if (strncmp (basename, "cp", 2) == 0 && IS_DIR_SEPARATOR (basename[2])
-	   && strcmp (basename + 3, "cp-tree.h") == 0)
-    output_name = "gt-cp-tree.h", for_name = "cp/tree.c";
-  else if (strncmp (basename, "cp", 2) == 0 && IS_DIR_SEPARATOR (basename[2])
-	   && strcmp (basename + 3, "decl.h") == 0)
-    output_name = "gt-cp-decl.h", for_name = "cp/decl.c";
-  else if (strncmp (basename, "cp", 2) == 0 && IS_DIR_SEPARATOR (basename[2])
-	   && strcmp (basename + 3, "name-lookup.h") == 0)
-    output_name = "gt-cp-name-lookup.h", for_name = "cp/name-lookup.c";
-  else if (strncmp (basename, "objc", 4) == 0 && IS_DIR_SEPARATOR (basename[4])
-	   && strcmp (basename + 5, "objc-act.h") == 0)
-    output_name = "gt-objc-objc-act.h", for_name = "objc/objc-act.c";
-  else
-    {
-      int lang_index = get_prefix_langdir_index (basename);
+    for (; files_rules[rulix].frul_srcexpr != NULL; rulix++)
+      {
+	DBGPRINTF ("rulix#%d srcexpr %s",
+		   rulix, files_rules[rulix].frul_srcexpr);
 
-      if (lang_index >= 0)
-	return base_files[lang_index];
+	if (!files_rules[rulix].frul_re)
+	  {
+	    /* The regexpr has not been compiled yet.  We lazily
+	       compile it only once.  */
+	    int err = 0;
+	    files_rules[rulix].frul_re = XCNEW (regex_t);
+	    err = regcomp (files_rules[rulix].frul_re,
+			   files_rules[rulix].frul_srcexpr,
+			   files_rules[rulix].frul_rflags);
+	    if (err)
+	      {
+		/* The regular expression compilation fails only when
+		   file_rules is buggy.  We give a possibly truncated
+		   error message in this impossible case, when the
+		   files_rules sequence is erroneous.  */
+		char rxerrbuf[128];
+		memset (rxerrbuf, 0, sizeof (rxerrbuf));
+		regerror (err, files_rules[rulix].frul_re,
+			  rxerrbuf, sizeof (rxerrbuf)-1);
+		fatal ("file rule #%d regexpr error %s", rulix, rxerrbuf);
+	      }
+	  }
 
-      output_name = "gtype-desc.c";
-      for_name = NULL;
-    }
+	output_name = NULL;
+	for_name = NULL;
 
-  /* Look through to see if we've ever seen this output filename before.  */
+	/* Match the regexpr and trigger the rule if matched.  */
+	{
+	  /* We have exactly ten pmatch-s, one for each $0, $1, $2,
+	     $3, ... $9.  */
+	  regmatch_t pmatch[10];
+	  memset (pmatch, 0, sizeof (pmatch));
+	  if (!regexec (files_rules[rulix].frul_re,
+			inpfname, 10, pmatch, 0))
+	    {
+	      DBGPRINTF ("input @ %p filename %s matched rulix#%d pattern %s",
+			 (void*) inpf, inpfname, rulix,
+			 files_rules[rulix].frul_srcexpr);
+	      for_name =
+		matching_file_name_substitute (inpfname, pmatch,
+					       files_rules[rulix].frul_tr_for);
+	      DBGPRINTF ("for_name %s", for_name);
+	      output_name =
+		matching_file_name_substitute (inpfname, pmatch,
+					       files_rules[rulix].frul_tr_out);
+	      DBGPRINTF ("output_name %s", output_name);
+	      if (files_rules[rulix].frul_action)
+		{
+		  /* Invoke our action routine.  */
+		  outf_p of = NULL;
+		  DBGPRINTF ("before action rulix#%d output_name %s for_name %s",
+			     rulix, output_name, for_name);
+		  of =
+		    (files_rules[rulix].frul_action) (inpf,
+						      &output_name, &for_name);
+		  DBGPRINTF ("after action rulix#%d of=%p output_name %s for_name %s",
+			     rulix, (void*)of, output_name, for_name);
+		  /* If the action routine returned something, give it back
+		     immediately and cache it in inpf.  */
+		  if (of)
+		    {
+		      inpf->inpoutf = of;
+		      return of;
+		    }
+		}
+	      /* The rule matched, and had no action, or that action did
+		 not return any output file but could have changed the
+		 output_name or for_name.  We break out of the loop on the
+		 files_rules.  */
+	      break;
+	    }
+	  else
+	    {
+	      /* The regexpr did not match.  */
+	      DBGPRINTF ("rulix#%d did not match %s pattern %s",
+			 rulix, inpfname, files_rules[rulix].frul_srcexpr);
+	      continue;
+	    }
+	}
+      }
+  }
+
+  if (!output_name || !for_name)
+    /* This is impossible, and could only happen if the files_rules is
+       incomplete or buggy.  */
+    fatal ("no output name for input file %s", inpfname);
+
+  /* Look through to see if we've ever seen this output filename
+     before.  If found, cache the result in inpf.  */
   for (r = output_files; r; r = r->next)
     if (strcmp (r->name, output_name) == 0)
-      return r;
+      {
+	inpf->inpoutf = r;
+	DBGPRINTF ("found r @ %p for output_name %s for_name %s", (void*)r,
+		   output_name, for_name);
+	return r;
+      }
 
-  /* If not, create it.  */
+  /* If not found, create it, and cache it in inpf.  */
   r = create_file (for_name, output_name);
 
   gcc_assert (r && r->name);
+  DBGPRINTF ("created r @ %p for output_name %s for_name %s", (void*) r,
+	     output_name, for_name);
+  inpf->inpoutf = r;
   return r;
 }
 
+
+
 /* 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.  */
-
 const char *
 get_output_file_name (input_file *inpf)
 {

[-- Attachment #3: cumulatedpatch4_filesrules-gengtypethird-r164437.diff.gz --]
[-- Type: application/octet-stream, Size: 19990 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* gengtype improvements for plugins, thirdround! patch 5/7 [typedopt]
  2010-09-22  0:29     ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Basile Starynkevitch
@ 2010-09-22  1:50       ` Basile Starynkevitch
  2010-09-22  1:58         ` gengtype improvements for plugins, thirdround! patch 6/7 [wstate] Basile Starynkevitch
  2010-09-22 12:13         ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Laurynas Biveinis
  2010-09-22 12:06       ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Laurynas Biveinis
  1 sibling, 2 replies; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-22  1:50 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4380 bytes --]


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
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02068.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00983.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01079.html
This fifth patch chunk is an improved version of
http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02068.html taking into
account Laurynas comments in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00420.html 
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01079.html

I hope that adding comments don't decrease the probability of
having this work accepted into GCC 4.6 end of stage 1.

In addition to the improved comments, I made some minor cleanups
w.r.t. http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02068.html (such
as using OPTION_STRING instead of INFO_STRING for the kind of a string
option, etc.).

I also changed the indentation: old gengtype.c had severals 
  struct FOOBAR
  {
while it seems that the preferred indentation style (at least when
looking into gimple.h or tree.h) is instead
  struct FOOBAR {
which I suppose is the politically correct way of GCC coding.

In addition of moving lots of typing definitions from gengtype.c to
gengtype.h I also (and this is already the case in the previous
version http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02068.html of
this patch), and obviously, made the 'struct options' a typed &
discriminated data, because to persist the gengtype state every union
should be a sum type discriminated conveniently.

The attached patch relative to the "thirdround" patch 4 [filesrules]
obtained with

diff -u -p  $(svn stat . |awk '/[AM]/{print $2}') \
     --from-file ../thirdround_04_filesrules/ > \
     $HOME/Gengtype_Thirdround/patch5_typedopt-relto04.diff


In am also attaching for convenience the cumulated patches against
trunk 164437 as a gzip file

######## gcc/ChangeLog entry relative to patch 5/N thirdround! [filesrules]
2010-09-21  Jeremie Salvucci  <jeremie.salvucci@free.fr>
	    Basile Starynkevitch  <basile@starynkevitch.net>

	* gengtype.c
	(enum typekind, struct options, struct nested_ptr_data)
	(struct pair, NUM_PARAM, enum gc_used_enum, struct type, UNION_P)
	(UNION_OR_STRUCT_P): Moved into gengtype.h

	(string_type, scalar_nonchar, scalar_char): Removed static and
	added state_number fake value.
	(typedefs, structures, param_structs, variables): Removed static.
	(create_option): Removed function.
	(create_string_option, create_type_option, created_nested_option):
	New.
	(created_nested_ptr_option, create_optional_field_)
	(adjust_field_rtx_def, adjust_field_tree_exp): Updated accordingly.
	(adjust_field_type, process_gc_options, output_mangled_typename)
	(walk_type, write_func_for_structure, write_types, write_roots)
	(note_def_vec, dump_options): Ditto.  Access to options is
	protected by tests on their kind.

	* gengtype.h: Added a lot of comments.  Moved many definitions
	from gengtype.h and updated them.
	(typedef, structures, param_structs, variables): Declared extern.
	(enum typekind): Moved from gengtype.c and added TYPE_NONE.
	(enum option_kind): New.
	(struct options): Added discriminating kind, and info union.
	(struct nested_ptr_data): Moved from gengtype.c.
	(create_string_option, create_type_option, create_nested_option):
	New.
	(struct pair, enum_gc_used_enum, NUM_PARAM): Moved
	from gengtype.c and commented more.
	(struct_type): Ditto, added state_number.
	(string_type, scalar_nonchar, scalar_char): Moved from gengtype.c.
	(type_lineloc): New function.
	(UNION_P, UNION_OR_STRUCT_P): Moved from gengtype.c and commented
	more.
	(struct outf): Indented better.

	* gengtype-parse.c (str_optvalue_opt, type_optvalue, option):
	Updated for our discriminated option.

################################################################

Comments and/or Ok for trunk are welcome!

Cheers.

-- 
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 mine, sont seulement les miennes} ***

[-- Attachment #2: patch5_typedopt-relto04.diff --]
[-- Type: text/x-diff, Size: 31491 bytes --]

--- ../thirdround_04_filesrules//gengtype.c	2010-09-21 13:53:03.000000000 +0200
+++ gcc/gengtype.c	2010-09-21 16:16:19.000000000 +0200
@@ -31,98 +31,6 @@
 
 /* Data types, macros, etc. used only in this file.  */
 
-/* Kinds of types we can understand.  */
-enum typekind {
-  TYPE_SCALAR,
-  TYPE_STRING,
-  TYPE_STRUCT,
-  TYPE_UNION,
-  TYPE_POINTER,
-  TYPE_ARRAY,
-  TYPE_LANG_STRUCT,
-  TYPE_PARAM_STRUCT
-};
-
-
-/* A way to pass data through to the output end.  */
-struct options
-{
-  struct options *next;
-  const char *name;
-  const char *info;
-};
-
-/* Option data for the 'nested_ptr' option.  */
-struct nested_ptr_data
-{
-  type_p type;
-  const char *convert_to;
-  const char *convert_from;
-};
-
-/* A name and a type.  */
-struct pair
-{
-  pair_p next;
-  const char *name;
-  type_p type;
-  struct fileloc line;
-  options_p opt;
-};
-
-#define NUM_PARAM 10
-
-/* A description of a type.  */
-enum gc_used_enum
-  {
-    GC_UNUSED = 0,
-    GC_USED,
-    /* Used for structures whose definitions we haven't seen so far when
-       we encounter a pointer to it that is annotated with ``maybe_undef''.
-       If after reading in everything we don't have source file
-       information for it, we assume that it never has been defined. */
-    GC_MAYBE_POINTED_TO,
-    GC_POINTED_TO
-  };
-
-struct type
-{
-  enum typekind kind;
-  type_p next;
-  type_p pointer_to;
-  enum gc_used_enum gc_used;
-  union {
-    type_p p;
-    struct {
-      const char *tag;
-      struct fileloc line;
-      pair_p fields;
-      options_p opt;
-      lang_bitmap bitmap;
-      type_p lang_struct;
-    } s;
-    bool scalar_is_char;
-    struct {
-      type_p p;
-      const char *len;
-    } a;
-    struct {
-      type_p stru;
-      type_p param[NUM_PARAM];
-      struct fileloc line;
-    } param_struct;
-  } u;
-};
-
-#define UNION_P(x)					\
- ((x)->kind == TYPE_UNION || 				\
-  ((x)->kind == TYPE_LANG_STRUCT 			\
-   && (x)->u.s.lang_struct->kind == TYPE_UNION))
-#define UNION_OR_STRUCT_P(x)			\
- ((x)->kind == TYPE_UNION 			\
-  || (x)->kind == TYPE_STRUCT 			\
-  || (x)->kind == TYPE_LANG_STRUCT)
-
 
 
 
@@ -547,26 +455,26 @@ read_input_list (const char *listname)
 \f
 /* The one and only TYPE_STRING.  */
 
-static struct type string_type = {
-  TYPE_STRING, 0, 0, GC_USED, {0}
+struct type string_type = {
+  TYPE_STRING, 0, 0, 0, GC_USED, {0}
 };
 
 /* The two and only TYPE_SCALARs.  Their u.scalar_is_char flags are
    set to appropriate values at the beginning of main.  */
 
-static struct type scalar_nonchar = {
-  TYPE_SCALAR, 0, 0, GC_USED, {0}
+struct type scalar_nonchar = {
+  TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
 };
-static struct type scalar_char = {
-  TYPE_SCALAR, 0, 0, GC_USED, {0}
+struct type scalar_char = {
+  TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
 };
 
 /* Lists of various things.  */
 
-static pair_p typedefs;
-static type_p structures;
-static type_p param_structs;
-static pair_p variables;
+pair_p typedefs;
+type_p structures;
+type_p param_structs;
+pair_p variables;
 
 static type_p find_param_structure
   (type_p t, type_p param[NUM_PARAM]);
@@ -802,16 +710,46 @@ create_array (type_p t, const char *len)
   return v;
 }
 
-/* Return an options structure with name NAME and info INFO.  NEXT is the
-   next option in the chain.  */
+/* Return a string options structure with name NAME and info INFO.
+   NEXT is the next option in the chain.  */
+options_p
+create_string_option (options_p next, const char *name, const char *info)
+{
+  options_p o = XCNEW (struct options);
+  o->kind = OPTION_STRING;
+  o->next = next;
+  o->name = name;
+  o->info.string = (const char*) info;
+  return o;
+}
 
+/* Create a type options structure with name NAME and info INFO.  NEXT
+   is the next option in the chain.  */
 options_p
-create_option (options_p next, const char *name, const void *info)
+create_type_option (options_p next, const char* name, type_p info)
 {
-  options_p o = XNEW (struct options);
+  options_p o;
+  o = XCNEW (struct options);
   o->next = next;
   o->name = name;
-  o->info = (const char*) info;
+  o->kind = OPTION_TYPE;
+  o->info.type = info;
+  return o;
+}
+
+
+/* Create a nested pointer options structure with name NAME and info
+   INFO.  NEXT is the next option in the chain.  */
+options_p
+create_nested_option (options_p next, const char* name,
+		      struct nested_ptr_data* info)
+{
+  options_p o;
+  o = XCNEW (struct options);
+  o->next = next;
+  o->name = name;
+  o->kind = OPTION_NESTED;
+  o->info.nested = info;
   return o;
 }
 
@@ -825,10 +763,9 @@ create_nested_ptr_option (options_p next
   d->type = adjust_field_type (t, 0);
   d->convert_to = to;
   d->convert_from = from;
-  return create_option (next, "nested_ptr", d);
+  return create_nested_option (next, "nested_ptr", d);
 }
-
-/* Add a variable named S of type T with options O defined at POS,
+ /* Add a variable named S of type T with options O defined at POS,
    to `variables'.  */
 
 void
@@ -892,15 +829,14 @@ create_optional_field_ (pair_p next, typ
      The field has a tag of "1".  This allows us to make the presence
      of a field of type TYPE depend on some boolean "desc" being true.  */
   union_fields = create_field (NULL, type, "");
-  union_fields->opt = create_option (union_fields->opt, "dot", "");
-  union_fields->opt = create_option (union_fields->opt, "tag", "1");
+  union_fields->opt = create_string_option (union_fields->opt, "dot", "");
+  union_fields->opt = create_string_option (union_fields->opt, "tag", "1");
   union_type = new_structure (xasprintf ("%s_%d", "fake_union", id++), 1,
 			      &lexer_line, union_fields, NULL);
-
-  /* Create the field and give it the new fake union type.  Add a "desc"
+   /* Create the field and give it the new fake union type.  Add a "desc"
      tag that specifies the condition under which the field is valid.  */
   return create_field_all (next, union_type, name,
-			   create_option (0, "desc", cond),
+			   create_string_option (0, "desc", cond),
 			   this_file, line);
 }
 #define create_optional_field(next,type,name,cond)	\
@@ -1032,7 +968,7 @@ adjust_field_rtx_def (type_p t, options_
       return &string_type;
     }
 
-  nodot = create_option (NULL, "dot", "");
+  nodot = create_string_option (NULL, "dot", "");
 
   rtx_tp = create_pointer (find_structure ("rtx_def", 0));
   rtvec_tp = create_pointer (find_structure ("rtvec_def", 0));
@@ -1072,9 +1008,9 @@ adjust_field_rtx_def (type_p t, options_
 	/* NOTE_INSN_MAX is used as the default field for line
 	   number notes.  */
 	if (c == NOTE_INSN_MAX)
-	  note_flds->opt = create_option (nodot, "default", "");
+	  note_flds->opt = create_string_option (nodot, "default", "");
 	else
-	  note_flds->opt = create_option (nodot, "tag", note_insn_name[c]);
+	  note_flds->opt = create_string_option (nodot, "tag", note_insn_name[c]);
       }
     note_union_tp = new_structure ("rtx_def_note_subunion", 1,
 				   &lexer_line, note_flds, NULL);
@@ -1082,14 +1018,11 @@ adjust_field_rtx_def (type_p t, options_
   /* Create a type to represent the various forms of SYMBOL_REF_DATA.  */
   {
     pair_p sym_flds;
-
-    sym_flds = create_field (NULL, tree_tp, "rt_tree");
-    sym_flds->opt = create_option (nodot, "default", "");
-
-    sym_flds = create_field (sym_flds, constant_tp, "rt_constant");
-    sym_flds->opt = create_option (nodot, "tag", "1");
-
-    symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
+     sym_flds = create_field (NULL, tree_tp, "rt_tree");
+    sym_flds->opt = create_string_option (nodot, "default", "");
+     sym_flds = create_field (sym_flds, constant_tp, "rt_constant");
+    sym_flds->opt = create_string_option (nodot, "tag", "1");
+     symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
 				     &lexer_line, sym_flds, NULL);
   }
   for (i = 0; i < NUM_RTX_CODE; i++)
@@ -1206,11 +1139,11 @@ adjust_field_rtx_def (type_p t, options_
 					       subname));
 	  subfields->opt = nodot;
 	  if (t == note_union_tp)
-	    subfields->opt = create_option (subfields->opt, "desc",
-					    "NOTE_KIND (&%0)");
+	    subfields->opt = create_string_option (subfields->opt, "desc",
+						   "NOTE_KIND (&%0)");
 	  if (t == symbol_union_tp)
-	    subfields->opt = create_option (subfields->opt, "desc",
-					    "CONSTANT_POOL_ADDRESS_P (&%0)");
+	    subfields->opt = create_string_option (subfields->opt, "desc",
+						   "CONSTANT_POOL_ADDRESS_P (&%0)");
 	}
 
       if (i == SYMBOL_REF)
@@ -1228,12 +1161,10 @@ adjust_field_rtx_def (type_p t, options_
       ftag = xstrdup (rtx_name[i]);
       for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
 	ftag[nmindex] = TOUPPER (ftag[nmindex]);
-
-      flds = create_field (flds, substruct, "");
-      flds->opt = create_option (nodot, "tag", ftag);
+       flds = create_field (flds, substruct, "");
+      flds->opt = create_string_option (nodot, "tag", ftag);
     }
-
-  return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
+   return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
 }
 
 /* Handle `special("tree_exp")'.  This is a special case for
@@ -1255,12 +1186,12 @@ adjust_field_tree_exp (type_p t, options
       return &string_type;
     }
 
-  nodot = create_option (NULL, "dot", "");
+  nodot = create_string_option (NULL, "dot", "");
 
   flds = create_field (NULL, t, "");
-  flds->opt = create_option (nodot, "length",
-			     "TREE_OPERAND_LENGTH ((tree) &%0)");
-  flds->opt = create_option (flds->opt, "default", "");
+  flds->opt = create_string_option (nodot, "length",
+				    "TREE_OPERAND_LENGTH ((tree) &%0)");
+  flds->opt = create_string_option (flds->opt, "default", "");
 
   return new_structure ("tree_exp_subunion", 1, &lexer_line, flds, nodot);
 }
@@ -1290,10 +1221,11 @@ adjust_field_type (type_p t, options_p o
   for (; opt; opt = opt->next)
     if (strcmp (opt->name, "length") == 0)
       length_p = 1;
-    else if (strcmp (opt->name, "param_is") == 0
-	     || (strncmp (opt->name, "param", 5) == 0
-		 && ISDIGIT (opt->name[5])
-		 && strcmp (opt->name + 6, "_is") == 0))
+    else if ((strcmp (opt->name, "param_is") == 0
+	      || (strncmp (opt->name, "param", 5) == 0
+		  && ISDIGIT (opt->name[5])
+		  && strcmp (opt->name + 6, "_is") == 0))
+	     && opt->kind == OPTION_TYPE)
       {
 	int num = ISDIGIT (opt->name[5]) ? opt->name[5] - '0' : 0;
 
@@ -1310,13 +1242,14 @@ adjust_field_type (type_p t, options_p o
 	if (params[num] != NULL)
 	  error_at_line (&lexer_line, "duplicate `%s' option", opt->name);
 	if (! ISDIGIT (opt->name[5]))
-	  params[num] = create_pointer (CONST_CAST2(type_p, const char *, opt->info));
+	  params[num] = create_pointer (opt->info.type);
 	else
-	  params[num] = CONST_CAST2 (type_p, const char *, opt->info);
+	  params[num] = opt->info.type;
       }
-    else if (strcmp (opt->name, "special") == 0)
+    else if (strcmp (opt->name, "special") == 0
+	     && opt->kind == OPTION_STRING)
       {
-	const char *special_name = opt->info;
+	const char *special_name = opt->info.string;
 	if (strcmp (special_name, "tree_exp") == 0)
 	  t = adjust_field_tree_exp (t, opt);
 	else if (strcmp (special_name, "rtx_def") == 0)
@@ -1360,8 +1293,9 @@ process_gc_options (options_p opt, enum
 {
   options_p o;
   for (o = opt; o; o = o->next)
-    if (strcmp (o->name, "ptr_alias") == 0 && level == GC_POINTED_TO)
-      set_gc_used_type (CONST_CAST2 (type_p, const char *, o->info),
+    if (strcmp (o->name, "ptr_alias") == 0 && level == GC_POINTED_TO
+	&& o->kind == OPTION_TYPE)
+      set_gc_used_type (o->info.type,
 			GC_POINTED_TO, NULL);
     else if (strcmp (o->name, "maybe_undef") == 0)
       *maybe_undef = 1;
@@ -1371,12 +1305,11 @@ process_gc_options (options_p opt, enum
       *length = 1;
     else if (strcmp (o->name, "skip") == 0)
       *skip = 1;
-    else if (strcmp (o->name, "nested_ptr") == 0)
-      *nested_ptr = ((const struct nested_ptr_data *) o->info)->type;
+    else if (strcmp (o->name, "nested_ptr") == 0
+	     && o->kind == OPTION_NESTED)
+      *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
 }
-
-/* Set the gc_used field of T to LEVEL, and handle the types it references.  */
-
+ /* Set the gc_used field of T to LEVEL, and handle the types it references.  */
 static void
 set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
 {
@@ -2314,6 +2247,8 @@ output_mangled_typename (outf_p of, cons
     oprintf (of, "Z");
   else switch (t->kind)
     {
+    case TYPE_NONE:
+      fatal ("uninitialized type to mangle");
     case TYPE_POINTER:
       oprintf (of, "P");
       output_mangled_typename (of, t->u.p);
@@ -2405,10 +2340,10 @@ walk_type (type_p t, struct walk_type_da
   options_p oo;
   const struct nested_ptr_data *nested_ptr_d = NULL;
 
-  d->needs_cast_p = false;
+   d->needs_cast_p = false;
   for (oo = d->opt; oo; oo = oo->next)
-    if (strcmp (oo->name, "length") == 0)
-      length = oo->info;
+    if (strcmp (oo->name, "length") == 0 && oo->kind == OPTION_STRING)
+      length = oo->info.string;
     else if (strcmp (oo->name, "maybe_undef") == 0)
       maybe_undef_p = 1;
     else if (strncmp (oo->name, "use_param", 9) == 0
@@ -2416,12 +2351,12 @@ walk_type (type_p t, struct walk_type_da
       use_param_num = oo->name[9] == '\0' ? 0 : oo->name[9] - '0';
     else if (strcmp (oo->name, "use_params") == 0)
       use_params_p = 1;
-    else if (strcmp (oo->name, "desc") == 0)
-      desc = oo->info;
+    else if (strcmp (oo->name, "desc") == 0 && oo->kind == OPTION_STRING)
+      desc = oo->info.string;
     else if (strcmp (oo->name, "mark_hook") == 0)
       ;
-    else if (strcmp (oo->name, "nested_ptr") == 0)
-      nested_ptr_d = (const struct nested_ptr_data *) oo->info;
+    else if (strcmp (oo->name, "nested_ptr") == 0 && oo->kind == OPTION_NESTED)
+      nested_ptr_d = (const struct nested_ptr_data *) oo->info.nested;
     else if (strcmp (oo->name, "dot") == 0)
       ;
     else if (strcmp (oo->name, "tag") == 0)
@@ -2674,12 +2609,12 @@ walk_type (type_p t, struct walk_type_da
 	    error_at_line (&t->u.s.line, "one structure defined here");
 	  }
 
-	/* Some things may also be defined in the structure's options.  */
+ 	/* Some things may also be defined in the structure's options.  */
 	for (o = t->u.s.opt; o; o = o->next)
-	  if (! desc && strcmp (o->name, "desc") == 0)
-	    desc = o->info;
-
-	d->prev_val[2] = oldval;
+	  if (! desc && strcmp (o->name, "desc") == 0
+	      && o->kind == OPTION_STRING)
+	    desc = o->info.string;
+ 	d->prev_val[2] = oldval;
 	d->prev_val[1] = oldprevval2;
 	if (union_p)
 	  {
@@ -2705,22 +2640,24 @@ walk_type (type_p t, struct walk_type_da
 	    int use_param_p = 0;
 	    char *newval;
 
-	    d->reorder_fn = NULL;
+ 	    d->reorder_fn = NULL;
 	    for (oo = f->opt; oo; oo = oo->next)
-	      if (strcmp (oo->name, "dot") == 0)
-		dot = oo->info;
-	      else if (strcmp (oo->name, "tag") == 0)
-		tagid = oo->info;
+	      if (strcmp (oo->name, "dot") == 0
+		  && oo->kind == OPTION_STRING)
+		dot = oo->info.string;
+	      else if (strcmp (oo->name, "tag") == 0
+		       && oo->kind == OPTION_STRING)
+		tagid = oo->info.string;
 	      else if (strcmp (oo->name, "skip") == 0)
 		skip_p = 1;
 	      else if (strcmp (oo->name, "default") == 0)
 		default_p = 1;
-	      else if (strcmp (oo->name, "reorder") == 0)
-		d->reorder_fn = oo->info;
+	      else if (strcmp (oo->name, "reorder") == 0
+		       && oo->kind == OPTION_STRING)
+		d->reorder_fn = oo->info.string;
 	      else if (strncmp (oo->name, "use_param", 9) == 0
 		       && (oo->name[9] == '\0' || ISDIGIT (oo->name[9])))
 		use_param_p = 1;
-
 	    if (skip_p)
 	      continue;
 
@@ -2956,18 +2893,20 @@ write_func_for_structure (type_p orig_s,
 
   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
-
-  for (opt = s->u.s.opt; opt; opt = opt->next)
-    if (strcmp (opt->name, "chain_next") == 0)
-      chain_next = opt->info;
-    else if (strcmp (opt->name, "chain_prev") == 0)
-      chain_prev = opt->info;
-    else if (strcmp (opt->name, "chain_circular") == 0)
-      chain_circular = opt->info;
-    else if (strcmp (opt->name, "mark_hook") == 0)
-      mark_hook_name = opt->info;
-
-  if (chain_prev != NULL && chain_next == NULL)
+   for (opt = s->u.s.opt; opt; opt = opt->next)
+    if (strcmp (opt->name, "chain_next") == 0
+	&& opt->kind == OPTION_STRING)
+      chain_next = opt->info.string;
+    else if (strcmp (opt->name, "chain_prev") == 0
+	&& opt->kind == OPTION_STRING)
+      chain_prev = opt->info.string;
+    else if (strcmp (opt->name, "chain_circular") == 0
+	&& opt->kind == OPTION_STRING)
+      chain_circular = opt->info.string;
+    else if (strcmp (opt->name, "mark_hook") == 0
+	&& opt->kind == OPTION_STRING)
+      mark_hook_name = opt->info.string;
+   if (chain_prev != NULL && chain_next == NULL)
     error_at_line (&s->u.s.line, "chain_prev without chain_next");
   if (chain_circular != NULL && chain_next != NULL)
     error_at_line (&s->u.s.line, "chain_circular with chain_next");
@@ -3135,11 +3074,11 @@ write_types (outf_p output_header, type_
 		 s->u.s.tag);
 	oprintf (output_header,
 		 "  } while (0)\n");
-
-	for (opt = s->u.s.opt; opt; opt = opt->next)
-	  if (strcmp (opt->name, "ptr_alias") == 0)
+ 	for (opt = s->u.s.opt; opt; opt = opt->next)
+	  if (strcmp (opt->name, "ptr_alias") == 0
+	      && opt->kind == OPTION_TYPE)
 	    {
-	      const_type_p const t = (const_type_p) opt->info;
+	      const_type_p const t = (const_type_p) opt->info.type;
 	      if (t->kind == TYPE_STRUCT
 		  || t->kind == TYPE_UNION
 		  || t->kind == TYPE_LANG_STRUCT)
@@ -3362,11 +3301,11 @@ write_local (outf_p output_header, type_
 
 	if (s->u.s.line.file == NULL)
 	  continue;
-
-	for (opt = s->u.s.opt; opt; opt = opt->next)
-	  if (strcmp (opt->name, "ptr_alias") == 0)
+ 	for (opt = s->u.s.opt; opt; opt = opt->next)
+	  if (strcmp (opt->name, "ptr_alias") == 0
+	      && opt->kind == OPTION_TYPE)
 	    {
-	      const_type_p const t = (const_type_p) opt->info;
+	      const_type_p const t = (const_type_p) opt->info.type;
 	      if (t->kind == TYPE_STRUCT
 		  || t->kind == TYPE_UNION
 		  || t->kind == TYPE_LANG_STRUCT)
@@ -3694,8 +3633,9 @@ write_root (outf_p f, pair_p v, type_p t
 	    for (o = fld->opt; o; o = o->next)
 	      if (strcmp (o->name, "skip") == 0)
 		skip_p = 1;
-	      else if (strcmp (o->name, "desc") == 0)
-		desc = o->info;
+	      else if (strcmp (o->name, "desc") == 0
+		       && o->kind == OPTION_STRING)
+		desc = o->info.string;
 	      else if (strcmp (o->name, "param_is") == 0)
 		;
 	      else
@@ -3714,10 +3654,10 @@ write_root (outf_p f, pair_p v, type_p t
 		  {
 		    const char *tag = NULL;
 		    options_p oo;
-
-		    for (oo = ufld->opt; oo; oo = oo->next)
-		      if (strcmp (oo->name, "tag") == 0)
-			tag = oo->info;
+ 		    for (oo = ufld->opt; oo; oo = oo->next)
+		      if (strcmp (oo->name, "tag") == 0
+		       && oo->kind == OPTION_STRING)
+			tag = oo->info.string;
 		    if (tag == NULL || strcmp (tag, desc) != 0)
 		      continue;
 		    if (validf != NULL)
@@ -3891,10 +3831,10 @@ write_roots (pair_p variables, bool emit
       const char *length = NULL;
       int deletable_p = 0;
       options_p o;
-
-      for (o = v->opt; o; o = o->next)
-	if (strcmp (o->name, "length") == 0)
-	  length = o->info;
+       for (o = v->opt; o; o = o->next)
+	if (strcmp (o->name, "length") == 0
+		       && o->kind == OPTION_STRING)
+	  length = o->info.string;
 	else if (strcmp (o->name, "deletable") == 0)
 	  deletable_p = 1;
 	else if (strcmp (o->name, "param_is") == 0)
@@ -4019,12 +3959,11 @@ write_roots (pair_p variables, bool emit
       for (o = v->opt; o; o = o->next)
 	if (strcmp (o->name, "length") == 0)
 	  length_p = 1;
-	else if (strcmp (o->name, "if_marked") == 0)
-	  if_marked = o->info;
-
-      if (if_marked == NULL)
+	else if (strcmp (o->name, "if_marked") == 0
+		       && o->kind == OPTION_STRING)
+	  if_marked = o->info.string;
+       if (if_marked == NULL)
 	continue;
-
       if (v->type->kind != TYPE_POINTER
 	  || v->type->u.p->kind != TYPE_PARAM_STRUCT
 	  || v->type->u.p->u.param_struct.stru != find_structure ("htab", 0))
@@ -4156,10 +4095,9 @@ note_def_vec (const char *type_name, boo
   else
     {
       t = resolve_typedef (type_name, pos);
-      o = create_option (0, "length", "%h.num");
+      o = create_string_option (0, "length", "%h.num");
     }
-
-  /* We assemble the field list in reverse order.  */
+   /* We assemble the field list in reverse order.  */
   fields = create_field_at (0, create_array (t, "1"), "vec", o, pos);
   fields = create_field_at (fields, len_ty, "alloc", 0, pos);
   fields = create_field_at (fields, len_ty, "num", 0, pos);
@@ -4447,8 +4385,22 @@ dump_options (int indent, options_p opt)
   o = opt;
   while (o)
     {
-       printf ("%s:%s ", o->name, o->info);
-       o = o->next;
+      switch (o->kind)
+	{
+	case OPTION_STRING:
+	  printf ("%s:string %s ", o->name, o->info.string);
+	  break;
+	case OPTION_TYPE:
+	  printf ("%s:type ", o->name);
+	  dump_type (indent+1, o->info.type);
+	  break;
+	case OPTION_NESTED:
+	  printf ("%s:nested ", o->name);
+	  break;
+	case OPTION_NONE:
+	  fatal ("corrupted option %p: %s", (void*) o, o->name);
+	}
+      o = o->next;
     }
   printf ("\n");
 }
--- ../thirdround_04_filesrules//gengtype.h	2010-09-21 10:27:50.000000000 +0200
+++ gcc/gengtype.h	2010-09-21 16:11:46.000000000 +0200
@@ -135,12 +135,256 @@ extern size_t num_lang_dirs;
 
 
 
-/* Data types handed around within, but opaque to, the lexer and parser.  */
+/* Common types, for structures defined below.  */
 typedef struct pair *pair_p;
 typedef struct type *type_p;
 typedef const struct type *const_type_p;
 typedef struct options *options_p;
 
+/* Various things, organized as linked lists, needed both in
+   gengtype.c & in gengtype-state.c files.  */
+extern pair_p typedefs;
+extern type_p structures;
+extern type_p param_structs;
+extern pair_p variables;
+
+
+
+/* Discrimating kind of types we can understand.  */
+
+enum typekind {
+  TYPE_NONE=0,		/* Never used, so zero-ed memory is
+			   invalid.  */
+  TYPE_SCALAR,		/* Scalar types like char.  */
+  TYPE_STRING,		/* The string type.  */
+  TYPE_STRUCT,		/* Type for GTY-ed struct-ures.  */
+  TYPE_UNION,		/* Type for GTY-ed discriminated
+			   union-s.  */
+  TYPE_POINTER,		/* Pointer type to GTY-ed type.  */
+  TYPE_ARRAY,		/* Array of GTY-ed types.  */
+  TYPE_LANG_STRUCT,	/* GCC front-end language specific
+			   struct-s.  Various languages may have
+			   homonymous but different
+			   struct-s.  */
+  TYPE_PARAM_STRUCT	/* Type for parametrized struct-ures,
+			   e.g. hash_t hash-tables, ...  See
+			   (param_is, use_param, param1_is,
+			   param2_is,... use_param1,
+			   use_param_2,... use_params) GTY
+			   options.  */
+};
+
+/* Discriminating kind for options.  */
+enum option_kind {
+  OPTION_NONE=0,		/* Never used, so zero-ed memory is
+				   invalid.  */
+  OPTION_STRING,		/* A string-valued option.  Most options
+				   are strings.  */
+  OPTION_TYPE,			/* A type-valued option.  */
+  OPTION_NESTED			/* Option data for 'nested_ptr'.  */
+};
+
+
+/* A way to pass data through to the output end.  */
+struct options {
+  struct options *next;		/* next option of the same pair.  */
+  const char *name;		/* GTY option name.  */
+  enum option_kind kind;		/* disciminating option kind.  */
+  /* the union below is discriminated by the 'kind' field above.  */
+  union {
+    const char* string;		    /* When OPTION_STRING.  */
+    type_p type;		    /* When OPTION_TYPE.  */
+    struct nested_ptr_data* nested; /* when OPTION_NESTED.  */
+  } info;
+};
+
+
+/* Option data for the 'nested_ptr' option.  */
+struct nested_ptr_data {
+  type_p type;
+  const char *convert_to;
+  const char *convert_from;
+};
+
+/* Some functions to create various options structures with name NAME
+   and info INFO.  NEXT is the next option in the chain.  */
+
+/* Create a string option.  */
+options_p create_string_option (options_p next, const char* name,
+                                const char* info);
+
+/* Create a type option.  */
+options_p create_type_option (options_p next, const char* name,
+                              type_p info);
+
+/* Create a nested option.  */
+options_p create_nested_option (options_p next, const char* name,
+				struct nested_ptr_data* info);
+
+/* Create a nested pointer option.  */
+options_p create_nested_ptr_option (options_p, type_p t,
+			 	     const char *from, const char *to);
+
+/* A name and a type.  */
+struct pair {
+  pair_p next;			/* The next pair in the linked list.  */
+  const char *name;		/* The defined name.  */
+  type_p type;			/* Its GTY-ed type.  */
+  struct fileloc line;		/* The file location.  */
+  options_p opt;		/* GTY options, as a linked list.  */
+};
+
+/* Usage information for GTY-ed types.  Gengtype has to care only of
+   used GTY-ed types.  Types are initially unused, and their usage is
+   computed by set_gc_used_type and set_gc_used functions.  */
+
+enum gc_used_enum {
+
+  /* We need that zero-ed types are initially unused.  */
+  GC_UNUSED=0,
+
+  /* The GTY-ed type is used, e.g by a GTY-ed variable or a field
+     inside a GTY-ed used type.  */
+  GC_USED,
+
+  /* For GTY-ed structures whose definitions we haven't seen so far
+     when we encounter a pointer to it that is annotated with
+     ``maybe_undef''.  If after reading in everything we don't have
+     source file information for it, we assume that it never has been
+     defined.  */
+  GC_MAYBE_POINTED_TO,
+
+  /* For known GTY-ed structures which are pointed to by GTY-ed
+     variables or fields.  */
+  GC_POINTED_TO
+};
+
+/* We have at most ten type parameters in parameterized structures.  */
+#define NUM_PARAM 10
+
+/* Our type structure describes all types handled by gengtype.  */
+struct type {
+  /* Discriminating kind, cannot be TYPE_NONE.  */
+  enum typekind kind;
+
+  /* For top-level struct-s or union-s, the 'next' field link the
+     global list 'structures' or 'param_structs'; for lang_struct-s,
+     their homonymous struct-s are linked using this next field.  The
+     homonymous list starts at the s.lang_struct field of the
+     lang_struct.  See the new_structure function for details.  This is
+     tricky!  */
+  type_p next;
+
+  /* State number used when writing & reading the persistent state.  A
+     type with a positive number has already been written.  For ease
+     of debugging, newly allocated types have a unique negative
+     number.  */
+  int state_number;
+
+  /* Each GTY-ed type which is pointed to by some GTY-ed type knows
+     the GTY pointer type pointing to it.  See create_pointer
+     function.  */
+  type_p pointer_to;
+
+  /* Type usage information, computed by set_gc_used_type and
+     set_gc_used functions.  */
+  enum gc_used_enum gc_used;
+
+  /* The following union is discriminated by the 'kind' field above.  */
+  union {
+    /* TYPE__NONE is impossible.  */
+
+    /* when TYPE_POINTER:  */
+    type_p p;
+
+    /* when TYPE_STRUCT or TYPE_UNION or TYPE_LANG_STRUCT, we have an
+       aggregate type containing fields: */
+    struct {
+      const char *tag;		/* the aggragate tag, if any.  */
+      struct fileloc line;	/* the source location.  */
+      pair_p fields;		/* the linked list of fields.  */
+      options_p opt;		/* the GTY options if any.  */
+      lang_bitmap bitmap;	/* the set of front-end languages
+				   using that GTY-ed aggregate.  */
+      /* For TYPE_LANG_STRUCT, the lang_struct field gives the first
+	 element of a linked list of homonymous struct or union types.
+	 Within this list, each homonymous type has as its lang_struct
+	 field the original TYPE_LANG_STRUCT type.  This is a dirty
+	 trick, see the new_structure function for details.  */
+      type_p lang_struct;
+    } s;
+
+    /* when TYPE_SCALAR: */
+    bool scalar_is_char;
+
+    /* when TYPE_ARRAY: */
+    struct {
+      type_p p;		/* The array component type.  */
+      const char *len;		/* The string if any giving its length.  */
+    } a;
+
+    /* When TYPE_PARAM_STRUCT for (param_is, use_param, param1_is,
+       param2_is, ... use_param1, use_param_2, ... use_params) GTY
+       options.  */
+    struct {
+      type_p stru;		/* The generic GTY-ed type.  */
+      type_p param[NUM_PARAM];	/* The actual parameter types.  */
+      struct fileloc line;	/* The source location.  */
+    } param_struct;
+
+  } u;
+};
+
+/* The one and only TYPE_STRING.  */
+extern struct type string_type;
+
+/* The two and only TYPE_SCALARs.  Their u.scalar_is_char flags are
+   set appropriately early in main.  */
+extern struct type scalar_nonchar;
+extern struct type scalar_char;
+
+/* Gives the file location of a type, if any.  */
+static inline struct fileloc*
+type_lineloc (const_type_p ty)
+{
+  if (!ty)
+    return NULL;
+  switch (ty->kind)
+    {
+    case TYPE_NONE:
+      fatal ("type_lineloc on bad zeroed type %p", (const void*)ty);
+    case TYPE_STRUCT:
+    case TYPE_UNION:
+    case TYPE_LANG_STRUCT:
+      return CONST_CAST (struct fileloc*, &ty->u.s.line);
+    case TYPE_PARAM_STRUCT:
+      return CONST_CAST (struct fileloc*, &ty->u.param_struct.line);
+    case TYPE_SCALAR:
+    case TYPE_STRING:
+    case TYPE_POINTER:
+    case TYPE_ARRAY:
+      return NULL;
+    }
+  fatal ("type_lineloc on corrupted type %p kd#%d",
+	 (const void*)ty, (int) ty->kind);
+}
+
+/* Test if a type is a union, either a plain one or a language
+   specific one.  */
+#define UNION_P(x)					\
+    ((x)->kind == TYPE_UNION ||			\
+     ((x)->kind == TYPE_LANG_STRUCT 			\
+      && (x)->u.s.lang_struct->kind == TYPE_UNION))
+
+/* Test if a type is a union or a structure, perhaps a language
+   specific one.  */
+#define UNION_OR_STRUCT_P(x)			\
+    ((x)->kind == TYPE_UNION 			\
+     || (x)->kind == TYPE_STRUCT		\
+     || (x)->kind == TYPE_LANG_STRUCT)
+
+\f
+
 /* Variables used to communicate between the lexer and the parser.  */
 extern int lexer_toplevel_done;
 extern struct fileloc lexer_line;
--- ../thirdround_04_filesrules//gengtype-parse.c	2010-09-21 07:36:06.000000000 +0200
+++ gcc/gengtype-parse.c	2010-09-21 16:04:11.000000000 +0200
@@ -343,10 +343,9 @@ str_optvalue_opt (options_p prev)
       value = string_seq ();
       require (')');
     }
-  return create_option (prev, name, value);
+  return create_string_option (prev, name, value);
 }
-
-/* absdecl: type '*'*
+ /* absdecl: type '*'*
    -- a vague approximation to what the C standard calls an abstract
    declarator.  The only kinds that are actually used are those that
    are just a bare type and those that have trailing pointer-stars.
@@ -381,10 +380,9 @@ type_optvalue (options_p prev, const cha
   require ('(');
   ty = absdecl ();
   require (')');
-  return create_option (prev, name, ty);
+  return create_type_option (prev, name, ty);
 }
-
-/* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */
+ /* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */
 static options_p
 nestedptr_optvalue (options_p prev)
 {
@@ -431,7 +429,7 @@ option (options_p prev)
       parse_error ("expected an option keyword, have %s",
 		   print_cur_token ());
       advance ();
-      return create_option (prev, "", "");
+      return create_string_option (prev, "", "");
     }
 }
 

[-- Attachment #3: cumulatedpatch5_typedopt-gengtypethird-r164437.diff.gz --]
[-- Type: application/octet-stream, Size: 27610 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* gengtype improvements for plugins, thirdround! patch 6/7 [wstate]
  2010-09-22  1:50       ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Basile Starynkevitch
@ 2010-09-22  1:58         ` Basile Starynkevitch
  2010-09-22  2:16           ` Basile Starynkevitch
  2010-09-22 14:08           ` gengtype improvements for plugins, thirdround! patch 6/7 [wstate] Laurynas Biveinis
  2010-09-22 12:13         ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Laurynas Biveinis
  1 sibling, 2 replies; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-22  1:58 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2957 bytes --]


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
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02068.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00983.html
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02069.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01150.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01153.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01713.html

The 6th part [wstate] of our patch series (thirdround) is a slightly
improved version of
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01150.html by adding
comments notably taking into account Laurynas remarks in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01151.html &
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01153.html

diff -u -p -N $(svn stat . |awk '/[AM]/{print $2}') \
     --from-file ../thirdround_05_typedopt/ > \
     $HOME/Gengtype_Thirdround/patch6_wstate-relto05.diff

#################### gcc/ChangeLog entry relative to patch piece 5 [typedopt]
2010-09-21  Jeremie Salvucci  <jeremie.salvucci@free.fr>
	    Basile Starynkevitch  <basile@starynkevitch.net>

	* gengtype-state.c: Added new file.

	* gengtype.c:
	(type_count): New static variable.
	(new_structure, find_structure, find_param_structure)
	(create_pointer, create_array): Use type_count for initializing
	state_number field of types.
	(main): Initialize state_number in predefined types.  Call
	read_state and write_state appropriately.  Show the
	type_count when verbose.

	* gengtype.h: Updated comment about per-language directories.
	(read_state, write_state): New declarations.

	* Makefile.in (MOSTLYCLEANFILES): Added gtype.state.
	(GENGTYPE_FLAGS): New variable.
	(s-gtype): Runs gengtype twice, once to write the gtype.state,
	once to read it.
	(build/gengtype-state.o): New target.
	(build/gengtype): Use it.
	(mostlyclean): Remove gtype.state
################################################################



Also, how should the gengtype program be installed? Perhaps it should
be named gcc-gengtype?  I still need help on these minor issues, in
particular as ways to patch gcc/Makefile.in.... There has been some
discussions & suggestions, but I was not able to imagine a
gcc/Makefile.in patch from them.  I confess that I don't understand all
of gcc/Makefile.in in particular the installations tricks. 

I am as usual attaching the cumulated patch w.r.t. trunk 164437.

Ok for trunk?

Cheers.
-- 
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 mine, sont seulement les miennes} ***

[-- Attachment #2: patch6_wstate__gengtypethird.mail --]
[-- Type: application/octet-stream, Size: 2362 bytes --]


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
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02068.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00983.html
  http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02069.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01150.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01153.html

The 6th part [wstate] of our patch series (thirdround) is a slightly
improved version of
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01150.html by adding
comments notably taking into account Laurynas remarks in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01151.html &
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01153.html

diff -u -p -N $(svn stat . |awk '/[AM]/{print $2}') \
     --from-file ../thirdround_05_typedopt/ > \
     $HOME/Gengtype_Thirdround/patch6_wstate-relto05.diff

#################### gcc/ChangeLog entry relative to patch piece 5 [typedopt]
2010-09-21  Jeremie Salvucci  <jeremie.salvucci@free.fr>
	    Basile Starynkevitch  <basile@starynkevitch.net>

	* gengtype-state.c: Added new file.

	* gengtype.c:
	(type_count): New static variable.
	(new_structure, find_structure, find_param_structure)
	(create_pointer, create_array): Use type_count for initializing
	state_number field of types.
	(main): Initialize state_number in predefined types.  Call
	read_state and write_state appropriately.  Show the
	type_count when verbose.

	* gengtype.h: Updated comment about per-language directories.
	(read_state, write_state): New declarations.

	* Makefile.in (MOSTLYCLEANFILES): Added gtype.state.
	(GENGTYPE_FLAGS): New variable.
	(s-gtype): Runs gengtype twice, once to write the gtype.state,
	once to read it.
	(build/gengtype-state.o): New target.
	(build/gengtype): Use it.
	(mostlyclean): Remove gtype.state
################################################################



Also, how should the gengtype program be installed? Perhaps it should
be named gcc-gengtype?  I still need help on these minor issues, in
particular as ways to patch gcc/Makefile.in....

Cheers.

[-- Attachment #3: cumulatedpatch6_wstate-gengtypethird-r164437.diff.gz --]
[-- Type: application/octet-stream, Size: 42158 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 6/7 [wstate]
  2010-09-22  1:58         ` gengtype improvements for plugins, thirdround! patch 6/7 [wstate] Basile Starynkevitch
@ 2010-09-22  2:16           ` Basile Starynkevitch
  2010-09-22  3:03             ` gengtype improvements for plugins, thirdround! patch 7/7 [doc] Basile Starynkevitch
  2010-09-22 14:08           ` gengtype improvements for plugins, thirdround! patch 6/7 [wstate] Laurynas Biveinis
  1 sibling, 1 reply; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-22  2:16 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3637 bytes --]

On Tue, 21 Sep 2010 21:29:26 +0200
Basile Starynkevitch <basile@starynkevitch.net> wrote:

> 
> 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
>   http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html
>   http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02068.html
>   http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00983.html
>   http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02069.html
>   http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01150.html
>   http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01153.html
>   http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01713.html
> 
> The 6th part [wstate] of our patch series (thirdround) is a slightly
> improved version of
> http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01150.html by adding
> comments notably taking into account Laurynas remarks in
> http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01151.html &
> http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01153.html
> 
> diff -u -p -N $(svn stat . |awk '/[AM]/{print $2}') \
>      --from-file ../thirdround_05_typedopt/ > \
>      $HOME/Gengtype_Thirdround/patch6_wstate-relto05.diff
> 
> #################### gcc/ChangeLog entry relative to patch piece 5 [typedopt]
> 2010-09-21  Jeremie Salvucci  <jeremie.salvucci@free.fr>
> 	    Basile Starynkevitch  <basile@starynkevitch.net>
> 
> 	* gengtype-state.c: Added new file.
> 
> 	* gengtype.c:
> 	(type_count): New static variable.
> 	(new_structure, find_structure, find_param_structure)
> 	(create_pointer, create_array): Use type_count for initializing
> 	state_number field of types.
> 	(main): Initialize state_number in predefined types.  Call
> 	read_state and write_state appropriately.  Show the
> 	type_count when verbose.
> 
> 	* gengtype.h: Updated comment about per-language directories.
> 	(read_state, write_state): New declarations.
> 
> 	* Makefile.in (MOSTLYCLEANFILES): Added gtype.state.
> 	(GENGTYPE_FLAGS): New variable.
> 	(s-gtype): Runs gengtype twice, once to write the gtype.state,
> 	once to read it.
> 	(build/gengtype-state.o): New target.
> 	(build/gengtype): Use it.
> 	(mostlyclean): Remove gtype.state
> ################################################################
> 
> 
> 
> Also, how should the gengtype program be installed? Perhaps it should
> be named gcc-gengtype?  I still need help on these minor issues, in
> particular as ways to patch gcc/Makefile.in.... There has been some
> discussions & suggestions, but I was not able to imagine a
> gcc/Makefile.in patch from them.  I confess that I don't understand all
> of gcc/Makefile.in in particular the installations tricks. 
> 
> I am as usual attaching the cumulated patch w.r.t. trunk 164437.

Sorry attachment in previous email was wrong.
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01714.html I attached by
mistake a draft version of the email, not the relative patch. Apologies!



> 
> Ok for trunk?
> 
> Cheers.
> -- 
> 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 mine, sont seulement les miennes} ***


-- 
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 mine, sont seulement les miennes} ***

[-- Attachment #2: patch6_wstate-relto05.diff --]
[-- Type: text/x-diff, Size: 78299 bytes --]

--- ../thirdround_05_typedopt//gengtype-state.c	2010-09-21 19:56:44.000000000 +0200
+++ gcc/gengtype-state.c	2010-09-21 19:58:32.000000000 +0200
@@ -0,0 +1,2469 @@
+/* Gengtype persistent state serialization & de-serialization.
+   Useful for gengtype in plugin mode.
+
+   Copyright (C) 2010  Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.
+
+   Contributed by Jeremie Salvucci <jeremie.salvucci@free.fr>
+   and Basile Starynkevitch <basile@starynkevitch.net>
+*/
+
+#include "bconfig.h"
+#include "system.h"
+#include "getopt.h"
+#include "errors.h"	/* For fatal.  */
+#include "double-int.h"
+#include "hashtab.h"
+#include "version.h"	/* For version_string & pkgversion_string.  */
+#include "obstack.h"
+#include "xregex.h"
+#include "gengtype.h"
+
+
+/* The state file has simplistic lispy lexical tokens.  Its lexer gives
+   a linked list of struct state_token_st, thru the peek_state_token
+   function.  Lexical tokens are consumed with next_state_tokens.  */
+
+
+/* The lexical kind of each lispy token.  */
+enum state_token_en
+{
+  STOK_NONE,			/* Never used.  */
+  STOK_INTEGER,		/* Integer token.  */
+  STOK_STRING,			/* String token.  */
+  STOK_LEFTPAR,		/* Left parenthesis.  */
+  STOK_RIGHTPAR,		/* Right parenthesis.  */
+  STOK_NAME			/* hash-consed name or identifier.  */
+};
+
+
+/* Structure and hash-table used to share identifiers or names.  */
+struct state_ident_st
+{
+  /* TODO: We could improve the parser by reserving identifiers for
+     state keywords and adding a keyword number for them.  That would
+     mean adding another field in this state_ident_st struct.  */
+  char stid_name[1];		/* actually bigger & null terminated */
+};
+static htab_t state_ident_tab;
+
+
+/* The state_token_st structure is for lexical tokens in the read
+   state file.  The stok_kind field discriminates the union.  Tokens
+   are allocated by peek_state_token which calls read_a_state_token
+   which allocate them.  Tokens are freed by calls to
+   next_state_tokens.  Token are organized in a FIFO look-ahead queue
+   filled by peek_state_token.  */
+struct state_token_st
+{
+  enum state_token_en stok_kind;	/* the lexical kind
+					   discriminates the stok_un
+					   union  */
+  int stok_line;		/* the line number */
+  int stok_col;			/* the column number */
+  const char *stok_file;	/* the file path */
+  struct state_token_st *stok_next;	/* the next token in the
+					   queue, when peeked */
+  union				/* discriminated by stok_kind! */
+  {
+    int stok_num;		/* when STOK_INTEGER */
+    char stok_string[1];	/* when STOK_STRING, actual size is
+				   bigger and null terminated */
+    struct state_ident_st *stok_ident;	/* when STOK_IDENT */
+    void *stok_ptr;		/* null otherwise */
+  }
+  stok_un;
+};
+
+
+
+
+#define NULL_STATE_TOKEN (struct state_token_st*)0
+
+/* the state_token pointer contains the leftmost current token.  The
+   tokens are organized in a linked queue, using stok_next, for token
+   look-ahead.  */
+struct state_token_st *state_token = NULL_STATE_TOKEN;
+
+/* Used by the reading lexer.  */
+static FILE *state_file;
+static const char *state_path = NULL;
+static int state_line = 0;
+static long state_bol = 0;	/* offset of beginning of line */
+
+
+/* Counter of written types.  */
+static int state_written_type_count = 0;
+
+
+/* Fatal error messages when reading the state.  They are extremely
+   unlikely, and only appear when this gengtype-state.c file is buggy,
+   or when reading a gengtype state which was not generated by the
+   same version of gengtype or GCC.  */
+
+
+/* Fatal message while reading state.  */
+#define fatal_reading_state(Tok,Msg)  do {		\
+    struct state_token_st* badtok = Tok;		\
+    if (badtok)					\
+      fatal ("%s:%d:%d: Invalid state file; " Msg,	\
+	      badtok->stok_file,			\
+	      badtok->stok_line,			\
+	      badtok->stok_col);			\
+    else						\
+      fatal ("%s:%d: Invalid state file; " Msg,	\
+	      state_path, state_line);			\
+  } while(0)
+
+#define fatal_reading_state_printf(Tok,Fmt,...) do {	\
+    struct state_token_st* badtok = Tok;		\
+    if (badtok)					\
+      fatal ("%s:%d:%d: Invalid state file; " Fmt,	\
+	      badtok->stok_file,			\
+	      badtok->stok_line,			\
+	      badtok->stok_col, __VA_ARGS__);		\
+    else						\
+      fatal ("%s:%d: Invalid state file; " Fmt,		\
+	     state_path, state_line, __VA_ARGS__);	\
+  } while(0)
+
+
+/* Find or allocate an identifier in our name hash table.  */
+static struct state_ident_st *
+state_ident_by_name (const char *name, enum insert_option optins)
+{
+  PTR *slot = NULL;
+  int namlen = 0;
+  struct state_ident_st *stid = NULL;
+
+  if (!name || !name[0])
+    return NULL;
+
+  slot = htab_find_slot (state_ident_tab, name, optins);
+  if (!slot)
+    return NULL;
+
+  namlen = strlen (name);
+  stid =
+    (struct state_ident_st *) xmalloc (sizeof (struct state_ident_st) +
+				       namlen);
+  memset (stid, 0, sizeof (struct state_ident_st) + namlen);
+  strcpy (stid->stid_name, name);
+  *slot = stid;
+
+  return stid;
+}
+
+/* Our token lexer is heavily inspired by MELT's lexer, and share some
+   code with the file gcc/melt-runtime.c of the GCC MELT branch!  We
+   really want the gengtype state to be easily parsable by MELT.  This
+   is a usual lispy lexing routine, dealing with spaces and comments,
+   numbers, parenthesis, names, strings.  */
+static struct state_token_st *
+read_a_state_token (void)
+{
+  int c = 0;
+  long curoff = 0;
+  struct state_token_st *tk = NULL;
+ again: /* Read again, e.g. after a comment.  */
+  c = getc (state_file);
+
+  if (c == EOF)
+    return NULL;
+  /* Handle spaces, count lines.  */
+  if (c == '\n')
+    {
+      state_line++;
+      state_bol = curoff = ftell (state_file);
+      goto again;
+    };
+  if (ISSPACE (c))
+    goto again;
+  /* Skip comments starting with semi-colon.  */
+  if (c == ';')
+    {	
+      do
+	{
+	  c = getc (state_file);
+	}
+      while (c > 0 && c != '\n');
+      if (c == '\n')
+	{
+	  state_line++;
+	  state_bol = curoff = ftell (state_file);
+	}
+      goto again;
+    };
+  /* Read signed numbers.  */
+  if (ISDIGIT (c) || c == '-' || c == '+')
+    {				/* number */
+      int n = 0;
+      ungetc (c, state_file);
+      curoff = ftell (state_file);
+      if (fscanf (state_file, "%d", &n) <= 0)
+	fatal_reading_state (NULL_STATE_TOKEN, "Lexical error in number");
+      tk = XCNEW (struct state_token_st);
+      tk->stok_kind = STOK_INTEGER;
+      tk->stok_line = state_line;
+      tk->stok_col = curoff - state_bol;
+      tk->stok_file = state_path;
+      tk->stok_next = NULL;
+      tk->stok_un.stok_num = n;
+
+      return tk;
+    }
+  /* Read an opening left parenthesis.  */
+  else if (c == '(')
+    {
+      curoff = ftell (state_file);
+      tk = XCNEW (struct state_token_st);
+      tk->stok_kind = STOK_LEFTPAR;
+      tk->stok_line = state_line;
+      tk->stok_col = curoff - state_bol;
+      tk->stok_file = state_path;
+      tk->stok_next = NULL;
+
+      return tk;
+    }
+  /* Read an closing right parenthesis.  */
+  else if (c == ')')
+    {
+      curoff = ftell (state_file);
+      tk = XCNEW (struct state_token_st);
+      tk->stok_kind = STOK_RIGHTPAR;
+      tk->stok_line = state_line;
+      tk->stok_col = curoff - state_bol;
+      tk->stok_file = state_path;
+      tk->stok_next = NULL;
+
+      return tk;
+    }
+  /* Read identifiers, using an obstack.  */
+  else if (ISALPHA (c) || c == '_' || c == '$' || c == '!' || c == '#')
+    {
+      struct obstack id_obstack;
+      struct state_ident_st *sid = NULL;
+      char *ids = NULL;
+      obstack_init (&id_obstack);
+      curoff = ftell (state_file);
+      while (ISALNUM (c) || c == '_' || c == '$' || c == '!' || c == '#')
+	{
+	  obstack_1grow (&id_obstack, c);
+	  c = getc (state_file);
+	  if (c < 0)
+	    break;
+	};
+      if (c >= 0)
+	ungetc (c, state_file);
+      obstack_1grow (&id_obstack, (char) 0);
+      ids = XOBFINISH (&id_obstack, char *);
+      sid = state_ident_by_name (ids, INSERT);
+      obstack_free (&id_obstack, ids);
+      ids = NULL;
+      tk = XCNEW (struct state_token_st);
+      tk->stok_kind = STOK_NAME;
+      tk->stok_line = state_line;
+      tk->stok_col = curoff - state_bol;
+      tk->stok_file = state_path;
+      tk->stok_next = NULL;
+      tk->stok_un.stok_ident = sid;
+
+      return tk;
+    }
+  /* Read a string, dealing with escape sequences a la C! */
+  else if (c == '"')
+    {
+      char *cstr = NULL;
+      int cslen = 0;
+      struct obstack bstring_obstack;
+      obstack_init (&bstring_obstack);
+      curoff = ftell (state_file);
+      while ((c = getc (state_file)) != '"' && c >= 0)
+	{
+	  if (ISPRINT (c) && c != '\\')
+	    obstack_1grow (&bstring_obstack, (char) c);
+	  else if (ISSPACE (c) && c != '\n')
+	    obstack_1grow (&bstring_obstack, (char) c);
+	  else if (c == '\\')
+	    {
+	      c = getc (state_file);
+	      switch (c)
+		{
+		case 'a':
+		  obstack_1grow (&bstring_obstack, '\a');
+		  c = getc (state_file);
+		  break;
+		case 'b':
+		  obstack_1grow (&bstring_obstack, '\b');
+		  c = getc (state_file);
+		  break;
+		case 't':
+		  obstack_1grow (&bstring_obstack, '\t');
+		  c = getc (state_file);
+		  break;
+		case 'n':
+		  obstack_1grow (&bstring_obstack, '\n');
+		  c = getc (state_file);
+		  break;
+		case 'v':
+		  obstack_1grow (&bstring_obstack, '\v');
+		  c = getc (state_file);
+		  break;
+		case 'f':
+		  obstack_1grow (&bstring_obstack, '\f');
+		  c = getc (state_file);
+		  break;
+		case 'r':
+		  obstack_1grow (&bstring_obstack, '\r');
+		  c = getc (state_file);
+		  break;
+		case '"':
+		  obstack_1grow (&bstring_obstack, '\"');
+		  c = getc (state_file);
+		  break;
+		case '\\':
+		  obstack_1grow (&bstring_obstack, '\\');
+		  c = getc (state_file);
+		  break;
+		case ' ':
+		  obstack_1grow (&bstring_obstack, ' ');
+		  c = getc (state_file);
+		  break;
+		case 'x':
+		  {
+		    unsigned int cx = 0;
+		    if (fscanf (state_file, "%02x", &cx) > 0 && cx > 0)
+		      obstack_1grow (&bstring_obstack, cx);
+		    else
+		      fatal_reading_state (NULL_STATE_TOKEN,
+					   "Lexical error in string escape");
+		    c = getc (state_file);
+		    break;
+		  }
+		default:
+		  fatal_reading_state (NULL_STATE_TOKEN,
+				       "Lexical error in string escape");
+		}
+	    }
+	  else
+	    fatal_reading_state (NULL_STATE_TOKEN, "Lexical error...");
+	};
+      if (c != '"')
+	fatal_reading_state (NULL_STATE_TOKEN, "Unterminated string");
+      obstack_1grow (&bstring_obstack, (char) 0);
+      cstr = XOBFINISH (&bstring_obstack, char *);
+      cslen = strlen (cstr);
+      tk = (struct state_token_st *)
+	xcalloc (sizeof (struct state_token_st) + cslen, 1);
+      tk->stok_kind = STOK_STRING;
+      tk->stok_line = state_line;
+      tk->stok_col = curoff - state_bol;
+      tk->stok_file = state_path;
+      tk->stok_next = NULL;
+      strcpy (tk->stok_un.stok_string, cstr);
+      obstack_free (&bstring_obstack, cstr);
+
+      return tk;
+    }
+  /* Got an unexpected character.  */
+  fatal_reading_state_printf (NULL_STATE_TOKEN, "Lexical error at offset %ld",
+			      ftell (state_file));
+}
+
+/* Used for lexical look-ahead.  Retrieves the lexical token of rank
+   DEPTH, starting with 0 when reading the state file.  Gives null on
+   end of file.  */
+static struct state_token_st *
+peek_state_token (int depth)
+{
+  int remdepth = depth;
+  struct state_token_st **ptoken = &state_token;
+  struct state_token_st *tok = NULL;
+
+  while (remdepth >= 0)
+    {
+      if (*ptoken == NULL)
+	{
+	  *ptoken = tok = read_a_state_token ();
+	  if (tok == NULL)
+	    return NULL;
+	}
+      tok = *ptoken;
+      ptoken = &((*ptoken)->stok_next);
+      remdepth--;
+    }
+
+  return tok;
+}
+
+/* Consume the next DEPTH tokens and free them.  */
+static void
+next_state_tokens (int depth)
+{
+  struct state_token_st *n;
+
+  while (depth > 0)
+    {
+      if (state_token != NULL)
+	{
+	  n = state_token->stok_next;
+	  free (state_token);
+	  state_token = n;
+	}
+      else
+	fatal_reading_state (NULL_STATE_TOKEN, "Tokens stack empty");
+
+      depth--;
+    }
+}
+
+/* Safely retrieve the lexical kind of a token.  */
+static inline enum state_token_en
+state_token_kind (struct state_token_st *p)
+{
+  if (p == NULL)
+    return STOK_NONE;
+  else
+    return p->stok_kind;
+}
+
+/* Test if a token is a given name i.e. an identifier.  */
+static inline bool
+state_token_is_name (struct state_token_st *p, const char *name)
+{
+  if (p == NULL)
+    return false;
+
+  if (p->stok_kind != STOK_NAME)
+    return false;
+
+  return !strcmp (p->stok_un.stok_ident->stid_name, name);
+}
+
+
+/* Following routines are useful for serializing datas.
+ *
+ * We want to serialize :
+ *          - typedefs list
+ *          - structures list
+ *          - param_structs list
+ *          - variables list
+ *
+ * So, we have one routine for each kind of data.  The main writing
+ * routine is write_state.  The main reading routine is
+ * read_state.  Most writing routines write_state_FOO have a
+ * corresponding reading routine read_state_FOO.  Reading is done in a
+ * recursive descending way, and any read error is fatal.
+ */
+
+/* When reading the state, we need to remember the previously seen
+   types by their state_number, since GTY-ed types are usually
+   shared.  */
+static htab_t state_seen_types;
+
+/* Return the length of a linked list made of pairs.  */
+static int pair_list_length (pair_p list);
+
+/* Write a pair */
+static void write_state_pair (pair_p);
+
+/* return the number of pairs written.  Should match the length given
+   by pair_list_length.  */
+static int write_state_pair_list (pair_p list);
+
+/* Write a type.  When a type is written, its state_number is updated,
+   to ensure that a "reference" to a seen type is written on next
+   occurrences.  */
+static void write_state_type (type_p);
+
+/* Write a null-terminatel string using our Lispy lexical conventions,
+   similar to those of C or MELT.  */
+static void write_state_a_string (const char *s);
+
+/* Compute the length of a list of pairs, starting from the first
+   one.  */
+static int
+pair_list_length (pair_p list)
+{
+  int nbpair = 0;
+  pair_p l = NULL;
+  for (l = list; l; l = l->next)
+    nbpair++;
+  return nbpair;
+}
+
+/* Write a file location.  Files relative to $(srcdir) are quite
+   frequent and are handled specially.  This ensures that two gengtype
+   state file-s produced by gengtype on the same GCC source tree are
+   very similar and can be reasonably compared with diff, even if the
+   two GCC source trees have different absolute paths.  */
+static void
+write_state_fileloc (struct fileloc *floc)
+{
+
+  if (floc != NULL && floc->line > 0)
+    {
+      const char *srcrelpath = NULL;
+      gcc_assert (floc->file != NULL);
+      /* Most of the files are inside $(srcdir) so it is worth to
+         handle them specially.  */
+      srcrelpath = get_file_srcdir_relative_path (floc->file);
+      if (srcrelpath != NULL)
+	{
+	  fprintf (state_file, "\n(!srcfileloc ");
+	  write_state_a_string (srcrelpath);
+	}
+      else
+	{
+	  fprintf (state_file, "\n(!fileloc ");
+	  write_state_a_string (get_input_file_name (floc->file));
+	}
+      fprintf (state_file, " %d", floc->line);
+      fprintf (state_file, ")\n");
+    }
+  else
+    fprintf (state_file, "nil ");
+}
+
+/* Write a list of fields.  */
+static void
+write_state_fields (pair_p fields)
+{
+  int nbfields = pair_list_length (fields);
+  int nbpairs = 0;
+  fprintf (state_file, "\n(!fields %d ", nbfields);
+  nbpairs = write_state_pair_list (fields);
+  gcc_assert (nbpairs == nbfields);
+  fprintf (state_file, ")\n");
+}
+
+/* Write a null-terminated string in our lexical convention, very
+   similar to the convention of C.  */
+static void
+write_state_a_string (const char *s)
+{
+  char c;
+
+  fputs (" \"", state_file);
+  for (; *s != 0; s++)
+    {
+      c = *s;
+      switch (c)
+	{
+	case '\a':
+	  fputs ("\\a", state_file);
+	  break;
+	case '\b':
+	  fputs ("\\b", state_file);
+	  break;
+	case '\t':
+	  fputs ("\\t", state_file);
+	  break;
+	case '\n':
+	  fputs ("\\n", state_file);
+	  break;
+	case '\v':
+	  fputs ("\\v", state_file);
+	  break;
+	case '\f':
+	  fputs ("\\f", state_file);
+	  break;
+	case '\r':
+	  fputs ("\\r", state_file);
+	  break;
+	case '\"':
+	  fputs ("\\\"", state_file);
+	  break;
+	case '\\':
+	  fputs ("\\\\", state_file);
+	  break;
+	default:
+	  if (ISPRINT (c))
+	    putc (c, state_file);
+	  else
+	    fprintf (state_file, "\\x%02x", (unsigned) c);
+	}
+    }
+  fputs ("\"", state_file);
+}
+
+/* Our option-s have three kinds, each with its writer.  */
+static void
+write_state_string_option (options_p current)
+{
+  fprintf (state_file, "string ");
+  if (current->info.string != NULL)
+    write_state_a_string (current->info.string);
+  else
+    fprintf (state_file, " nil ");
+}
+
+static void
+write_state_type_option (options_p current)
+{
+  fprintf (state_file, "type ");
+  write_state_type (current->info.type);
+}
+
+static void
+write_state_nested_option (options_p current)
+{
+  fprintf (state_file, "nested ");
+  write_state_type (current->info.nested->type);
+  if (current->info.nested->convert_from != NULL)
+    write_state_a_string (current->info.nested->convert_from);
+  else
+    fprintf (state_file, " nil ");
+
+  if (current->info.nested->convert_to != NULL)
+    write_state_a_string (current->info.nested->convert_to);
+  else
+    fprintf (state_file, " nil ");
+}
+
+static void
+write_state_option (options_p current)
+{
+  fprintf (state_file, "\n(!option ");
+
+  if (current->name != NULL)
+    fprintf (state_file, "%s ", current->name);
+  else
+    fprintf (state_file, "nil ");
+
+  switch (current->kind)
+    {
+    case OPTION_STRING:
+      write_state_string_option (current);
+      break;
+    case OPTION_TYPE:
+      write_state_type_option (current);
+      break;
+    case OPTION_NESTED:
+      write_state_nested_option (current);
+      break;
+    default:
+      fatal ("Option tag unknown");
+    }
+
+  fprintf (state_file, ")\n");
+}
+
+
+
+/* Write a list of GTY options.  */
+static void
+write_state_options (options_p opt)
+{
+  options_p current;
+
+  if (opt == NULL)
+    {
+      fprintf (state_file, "nil ");
+      return;
+    }
+
+  fprintf (state_file, "\n(!options ");
+  for (current = opt; current != NULL; current = current->next)
+      write_state_option (current);
+  fprintf (state_file, ")\n");
+}
+
+
+/* Write a bitmap representing a set of GCC front-end languages.  */
+static void
+write_state_lang_bitmap (lang_bitmap bitmap)
+{
+  fprintf (state_file, "%d ", (int) bitmap);
+}
+
+/* Write version information.  */
+static void
+write_state_version (const char *version)
+{
+  fprintf (state_file, "\n(!version ");
+  write_state_a_string (version);
+  fprintf (state_file, ")\n");
+}
+
+/* Common routine to write the common content of all types.  */
+static void write_state_common_type_content (type_p current);
+
+/* Write a scalar type.  We have only two of these.  */
+static void
+write_state_scalar_type (type_p current)
+{
+  if (current == &scalar_nonchar)
+    fprintf (state_file, "scalar_nonchar ");
+  else if (current == &scalar_char)
+    fprintf (state_file, "scalar_char ");
+  else
+    fatal ("Unexpected type in write_state_scalar_type");
+
+  write_state_common_type_content (current);
+}
+
+/* Write the string type.  There is only one such thing! */
+static void
+write_state_string_type (type_p current)
+{
+  if (current == &string_type)
+    {
+      fprintf (state_file, "string ");
+      write_state_common_type_content (current);
+    }
+  else
+    fatal ("Unexpected type in write_state_string_type");
+}
+
+
+/* Common code to write structure like types.  */
+static void
+write_state_struct_union_type (type_p current, const char *kindstr)
+{
+  DBGPRINTF ("%s type @ %p #%d '%s'", kindstr, (void *) current,
+	     current->state_number, current->u.s.tag);
+  fprintf (state_file, "%s ", kindstr);
+  write_state_common_type_content (current);
+  if (current->u.s.tag != NULL)
+    write_state_a_string (current->u.s.tag);
+  else
+    fprintf (state_file, "nil");
+
+  write_state_fileloc (type_lineloc (current));
+  write_state_fields (current->u.s.fields);
+  write_state_options (current->u.s.opt);
+  write_state_lang_bitmap (current->u.s.bitmap);
+}
+
+
+/* Write a GTY struct type.  */
+static void
+write_state_struct_type (type_p current)
+{
+  write_state_struct_union_type (current, "struct");
+  write_state_type (current->u.s.lang_struct);
+}
+
+/* write a GTY union type.  */
+static void
+write_state_union_type (type_p current)
+{
+  write_state_struct_union_type (current, "union");
+  write_state_type (current->u.s.lang_struct);
+}
+
+/* Write a lang_struct type.  This is tricky and was painful to debug,
+   we deal with the next field specifically within their lang_struct
+   subfield, which points to a linked list of homonumous types.
+   Change this function with extreme care, see also
+   read_state_lang_struct_type.  */
+static void
+write_state_lang_struct_type (type_p current)
+{
+  int nbhomontype = 0;
+  type_p hty = NULL;
+  const char *homoname = 0;
+  write_state_struct_union_type (current, "lang_struct");
+  /* lang_struct-ures are particularily tricky, since their
+     u.s.lang_struct field gives a list of homonymous struct-s or
+     union-s! */
+  DBGPRINTF ("lang_struct @ %p #%d", (void *) current, current->state_number);
+  for (hty = current->u.s.lang_struct; hty != NULL; hty = hty->next)
+    {
+      nbhomontype++;
+      DBGPRINTF ("homonymous #%d hty @ %p #%d '%s'", nbhomontype,
+		 (void *) hty, hty->state_number, hty->u.s.tag);
+      /* Every member of the homonymous list should have the same tag.  */
+      gcc_assert (UNION_OR_STRUCT_P (hty));
+      gcc_assert (hty->u.s.lang_struct == current);
+      if (!homoname)
+	homoname = hty->u.s.tag;
+      gcc_assert (strcmp (homoname, hty->u.s.tag) == 0);
+    }
+  fprintf (state_file, "(!homotypes %d\n", nbhomontype);
+  for (hty = current->u.s.lang_struct; hty != NULL; hty = hty->next)
+    write_state_type (hty);
+  fprintf (state_file, ")\n");
+}
+
+/* Write a parametrized structure GTY type.  */
+static void
+write_state_param_struct_type (type_p current)
+{
+  int i;
+
+  fprintf (state_file, "param_struct ");
+  write_state_common_type_content (current);
+  write_state_type (current->u.param_struct.stru);
+  for (i = 0; i < NUM_PARAM; i++)
+    {
+      if (current->u.param_struct.param[i] != NULL)
+	write_state_type (current->u.param_struct.param[i]);
+      else
+	fprintf (state_file, "nil ");
+    }
+  write_state_fileloc (&current->u.param_struct.line);
+}
+
+/* Write a pointer type.  */
+static void
+write_state_pointer_type (type_p current)
+{
+  fprintf (state_file, "pointer ");
+  write_state_common_type_content (current);
+  write_state_type (current->u.p);
+}
+
+/* Write an array type.  */
+static void
+write_state_array_type (type_p current)
+{
+  fprintf (state_file, "array ");
+  write_state_common_type_content (current);
+  if (current->u.a.len != NULL)
+    write_state_a_string (current->u.a.len);
+  else
+    fprintf (state_file, " nil");
+
+  fprintf (state_file, " ");
+  write_state_type (current->u.a.p);
+}
+
+/* Write the gc_used information.  */
+static void
+write_state_gc_used (enum gc_used_enum gus)
+{
+  switch (gus)
+    {
+    case GC_UNUSED:
+      fprintf (state_file, " gc_unused");
+      break;
+    case GC_USED:
+      fprintf (state_file, " gc_used");
+      break;
+    case GC_MAYBE_POINTED_TO:
+      fprintf (state_file, " gc_maybe_pointed_to");
+      break;
+    case GC_POINTED_TO:
+      fprintf (state_file, " gc_pointed_to");
+      break;
+    }
+}
+
+/* Utility routine to write the common content of all types.  Notice
+   that the next field is *not* written on purpose.  */
+static void
+write_state_common_type_content (type_p current)
+{
+  fprintf (state_file, "%d ", current->state_number);
+  /* We do not write the next type, because list of types are
+     explicitly written.  However, lang_struct are special in that
+     respect.  See function write_state_lang_struct_type for more.  */
+  write_state_type (current->pointer_to);
+  write_state_gc_used (current->gc_used);
+}
+
+
+/* The important and recursive routine writing GTY types as understood
+   by gengtype.  Types which have a positive state_number have already
+   been seen and written.  */
+static void
+write_state_type (type_p current)
+{
+  if (current == NULL)
+    {
+      fprintf (state_file, "nil ");
+      return;
+    }
+
+  fprintf (state_file, "\n(!type ");
+
+  if (current->state_number > 0)
+    fprintf (state_file, "already_seen %d", current->state_number);
+  else
+    {
+      state_written_type_count++;
+      DBGPRINTF ("writing type #%d @%p old number %d", state_written_type_count,
+		 (void *) current, current->state_number);
+      current->state_number = state_written_type_count;
+      switch (current->kind)
+	{
+	case TYPE_STRUCT:
+	  write_state_struct_type (current);
+	  break;
+	case TYPE_UNION:
+	  write_state_union_type (current);
+	  break;
+	case TYPE_POINTER:
+	  write_state_pointer_type (current);
+	  break;
+	case TYPE_ARRAY:
+	  write_state_array_type (current);
+	  break;
+	case TYPE_LANG_STRUCT:
+	  write_state_lang_struct_type (current);
+	  break;
+	case TYPE_PARAM_STRUCT:
+	  write_state_param_struct_type (current);
+	  break;
+	case TYPE_SCALAR:
+	  write_state_scalar_type (current);
+	  break;
+	case TYPE_STRING:
+	  write_state_string_type (current);
+	  break;
+
+	default:
+	  fatal ("Unexpected type...");
+	}
+    }
+
+  fprintf (state_file, ")\n");
+}
+
+
+/* Write a pair.  */
+static void
+write_state_pair (pair_p current)
+{
+  if (current == NULL)
+    {
+      fprintf (state_file, "nil)");
+      return;
+    }
+
+  fprintf (state_file, "\n(!pair ");
+
+  if (current->name != NULL)
+    write_state_a_string (current->name);
+  else
+    write_state_a_string ("nil");
+
+  write_state_type (current->type);
+  write_state_fileloc (&(current->line));
+  write_state_options (current->opt);
+
+  fprintf (state_file, ")");
+}
+
+/* Write a pair list and return the number of pairs written.  */
+static int
+write_state_pair_list (pair_p list)
+{
+  int nbpair = 0;
+  pair_p current;
+
+  for (current = list; current != NULL; current = current->next)
+    {
+      write_state_pair (current);
+      nbpair++;
+    }
+  return nbpair;
+
+}
+
+/* When writting imported linked lists, like typedefs, structures,
+   param_structs, ... we count their length first and write it.  These
+   eases the reading, and enables an extra verification on the number
+   of actually read items.  */
+
+/* Write our typedefs.  */
+static void
+write_state_typedefs (void)
+{
+  int nbtypedefs = pair_list_length (typedefs);
+  int nbpairs = 0;
+  fprintf (state_file, "\n(!typedefs %d\n", nbtypedefs);
+  nbpairs = write_state_pair_list (typedefs);
+  gcc_assert (nbpairs == nbtypedefs);
+  fprintf (state_file, ")\n");
+  if (verbosity_level >= 2)
+    printf ("%s wrote %d typedefs\n", progname, nbtypedefs);
+}
+
+/* Write our structures.  */
+static void
+write_state_structures (void)
+{
+  int nbstruct = 0;
+  type_p current;
+
+  for (current = structures; current != NULL; current = current->next)
+    nbstruct++;
+
+  fprintf (state_file, "\n(!structures %d\n", nbstruct);
+
+  for (current = structures; current != NULL; current = current->next)
+    write_state_type (current);
+
+  fprintf (state_file, ")\n");
+  if (verbosity_level >= 2)
+    printf ("%s wrote %d structures in state\n", progname, nbstruct);
+}
+
+/* Write our param_struct-s.  */
+static void
+write_state_param_structs (void)
+{
+  int nbparamstruct = 0;
+  type_p current;
+
+  for (current = param_structs; current != NULL; current = current->next)
+    nbparamstruct++;
+
+  fprintf (state_file, "\n(!param_structs %d\n", nbparamstruct);
+
+  for (current = param_structs; current != NULL; current = current->next)
+    write_state_type (current);
+
+  fprintf (state_file, ")\n");
+}
+
+/* Write our variables.  */
+static void
+write_state_variables (void)
+{
+  int nbvars = pair_list_length (variables);
+  int nbpairs = 0;
+  fprintf (state_file, "\n(!variables %d\n", nbvars);
+  nbpairs = write_state_pair_list (variables);
+  gcc_assert (nbpairs == nbvars);
+  fprintf (state_file, ")\n");
+  if (verbosity_level >= 2)
+    printf ("%s wrote %d variables.\n", progname, nbvars);
+}
+
+/* Write the source directory.  File locations within the source
+   directory have been written specifically.  */
+static void
+write_state_srcdir (void)
+{
+  fprintf (state_file, "\n(!srcdir ");
+  write_state_a_string (srcdir);
+  fprintf (state_file, ")\n");
+}
+
+/* Count and write the list of our files.  */
+static void
+write_state_files_list (void)
+{
+  int i = 0;
+  /* Write the list of files with their lang_bitmap.  */
+  fprintf (state_file, "\n(!fileslist %d\n", (int) num_gt_files);
+  for (i = 0; i < (int) num_gt_files; i++)
+    {
+      const char *cursrcrelpath = NULL;
+      input_file *curfil = gt_files[i];
+      /* Most of the files are inside $(srcdir) so it is worth to
+         handle them specially.  */
+      cursrcrelpath = get_file_srcdir_relative_path (curfil);
+      if (cursrcrelpath)
+	{
+	  fprintf (state_file, "(!srcfile %d ", get_lang_bitmap (curfil));
+	  write_state_a_string (cursrcrelpath);
+	}
+      else
+	{
+	  fprintf (state_file, "(!file %d ", get_lang_bitmap (curfil));
+	  write_state_a_string (get_input_file_name (curfil));
+	}
+      fprintf (state_file, ")\n");
+    }
+  fprintf (state_file, ")\n");
+}
+
+/* Write the list of GCC front-end languages.  */
+static void
+write_state_languages (void)
+{
+  int i = 0;
+  fprintf (state_file, "\n(!languages %d", (int) num_lang_dirs);
+  for (i = 0; i < (int) num_lang_dirs; i++)
+    {
+      /* Languages names are identifiers, we expect only letters or
+         underscores or digits in them.  In particular, C++ is not a
+         valid language name, but cp is valid.  */
+      fprintf (state_file, " %s", lang_dir_names[i]);
+    }
+  fprintf (state_file, ")\n");
+}
+
+/* Write the trailer.  */
+static void
+write_state_trailer (void)
+{
+  /* This test should probably catch IO errors like disk full...  */
+  if (fputs ("\n(!endfile)\n", state_file) == EOF)
+    fatal ("failed to write state trailer [%s]", xstrerror (errno));
+}
+
+/* The write_state routine is the only writing routine called by main
+   in gengtype.c.  To avoid messing the state if gengtype is
+   interrupted or aborted, we write a temporary file and rename it
+   after having written it in totality.  */
+void
+write_state (const char *state_path)
+{
+  long statelen = 0;
+  time_t now = 0;
+  char *temp_state_path = NULL;
+  char tempsuffix[40];
+  time (&now);
+
+  /* We write a unique temporary file which is renamed when complete
+   * only.  So even if gengtype is interrupted, the written state file
+   * won't be partially written, since the temporary file is not yet
+   * renamed in that case....  */
+  memset (tempsuffix, 0, sizeof (tempsuffix));
+  snprintf (tempsuffix, sizeof (tempsuffix) - 1, "-%ld-%d.tmp", (long) now,
+	    (int) getpid ());
+  temp_state_path = concat (state_path, tempsuffix, NULL);
+  state_file = fopen (temp_state_path, "w");
+  if (state_file == NULL)
+    fatal ("Failed to open file %s for writing state: %s",
+	   temp_state_path, xstrerror (errno));
+  if (verbosity_level >= 3)
+    printf ("%s writing state file %s temporarily in %s\n",
+	    progname, state_path, temp_state_path);
+  /* This is the first line of the state.  Perhaps the file utility
+     could know about that, so don't change it often.  */
+  fprintf (state_file, ";;; @@@ GCC gengtype state\n");
+  fprintf (state_file,
+	   ";;; DON'T EDIT THIS FILE, since generated by GCC's gengtype\n");
+  fprintf (state_file,
+	   ";;; The format of this file is tied to a particular version of GCC.\n");
+  fprintf (state_file,
+	   ";;; Don't parse this file wihout knowing GCC gengtype internals.\n");
+  fprintf (state_file,
+	   ";;; This file should be parsed by the same %s who wrote it.\n",
+	   progname);
+  fprintf (state_file, ";;; file %s generated on %s\n", state_path,
+	   ctime (&now));
+  /* The first non-comment significant line gives the version string.  */
+  write_state_version (version_string);
+  write_state_srcdir ();
+  write_state_languages ();
+  write_state_files_list ();
+  write_state_structures ();
+  /* The writing of structures probably wrote a lot, so we flush to
+     disk and check for errors, e.g. to catch disk full situations a
+     bit earlier.  */
+  if (fflush (state_file) || ferror (state_file))
+    fatal ("output error when writing state file %s [%s]",
+	   temp_state_path, xstrerror (errno));
+  write_state_typedefs ();
+  write_state_param_structs ();
+  write_state_variables ();
+  write_state_trailer ();
+  statelen = ftell (state_file);
+  if (ferror (state_file))
+    fatal ("output error when writing state file %s [%s]",
+	   temp_state_path, xstrerror (errno));
+  if (fclose (state_file))
+    fatal ("failed to close state file %s [%s]",
+	   temp_state_path, xstrerror (errno));
+  if (rename (temp_state_path, state_path))
+    fatal ("failed to rename %s to state file %s [%s]", temp_state_path,
+	   state_path, xstrerror (errno));
+  free (temp_state_path);
+
+  if (verbosity_level >= 1)
+    printf ("%s wrote state file %s of %ld bytes with %d GTY-ed types\n",
+	    progname, state_path, statelen, state_written_type_count);
+
+}
+\f
+/*****************************************************************
+ * End of writing routines!  The corresponding reading routines follow.
+ *****************************************************************/
+
+
+/* Forward declarations, since some read_state_* functions are
+   recursive! */
+static void read_state_fileloc (struct fileloc *line);
+static void read_state_options (options_p *opt);
+static void read_state_type (type_p *current);
+static void read_state_pair (pair_p *pair);
+/* Return the number of pairs actually read.  */
+static int read_state_pair_list (pair_p *list);
+static void read_state_fields (pair_p *fields);
+static void read_state_common_type_content (type_p current);
+
+
+
+
+/* Record into the state_seen_types hash-table a type which we are
+   reading, to enable recursive or circular references to it.  */
+static void
+record_type (type_p type)
+{
+  PTR *slot;
+
+  slot = htab_find_slot (state_seen_types, type, INSERT);
+  gcc_assert (slot);
+
+  *slot = type;
+}
+
+/* Read an already seen type.  */
+static void
+read_state_already_seen_type (type_p *type)
+{
+  struct state_token_st *t0;
+
+  t0 = peek_state_token (0);
+
+  if (state_token_kind (t0) == STOK_INTEGER)
+    {
+      PTR *slot = NULL;
+      struct type loctype = { TYPE_SCALAR, 0, 0, 0, GC_UNUSED, {0} };
+
+      loctype.state_number = t0->stok_un.stok_num;
+      slot = htab_find_slot (state_seen_types, &loctype, NO_INSERT);
+      if (slot == NULL)
+	{
+	  fatal_reading_state (t0, "Unknown type");
+	}
+
+      next_state_tokens (1);
+      *type = (type_p) *slot;
+    }
+  else
+    {
+      fatal_reading_state (t0, "Bad seen type");
+    }
+}
+
+
+/* Read the scalar_nonchar type.  */
+static void
+read_state_scalar_nonchar_type (type_p *type)
+{
+  *type = &scalar_nonchar;
+  read_state_common_type_content (*type);
+}
+
+
+/* Read the scalar_char type.  */
+static void
+read_state_scalar_char_type (type_p *type)
+{
+  *type = &scalar_char;
+  read_state_common_type_content (*type);
+}
+
+
+/* Read the string_type.  */
+static void
+read_state_string_type (type_p *type)
+{
+  *type = &string_type;
+  read_state_common_type_content (*type);
+}
+
+
+/* Read a lang_bitmap representing a set of GCC front-end languages.  */
+static void
+read_state_lang_bitmap (lang_bitmap *bitmap)
+{
+  struct state_token_st *t;
+
+  t = peek_state_token (0);
+  if (state_token_kind (t) == STOK_INTEGER)
+    {
+      *bitmap = t->stok_un.stok_num;
+      next_state_tokens (1);
+    }
+  else
+    {
+      fatal_reading_state (t, "Bad syntax for bitmap");
+    }
+}
+
+
+/* Read a GTY-ed struct type.  */
+static void
+read_state_struct_type (type_p type)
+{
+  struct state_token_st *t0;
+
+  type->kind = TYPE_STRUCT;
+  read_state_common_type_content (type);
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      if (state_token_is_name (t0, "nil"))
+	{
+	  type->u.s.tag = NULL;
+	  DBGPRINTF ("read anonymous struct type @%p #%d",
+		     (void *) type, type->state_number);
+	}
+      else
+	{
+	  type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+	  DBGPRINTF ("read struct type @%p #%d '%s'",
+		     (void *) type, type->state_number, type->u.s.tag);
+	}
+
+      next_state_tokens (1);
+      read_state_fileloc (&(type->u.s.line));
+      read_state_fields (&(type->u.s.fields));
+      read_state_options (&(type->u.s.opt));
+      read_state_lang_bitmap (&(type->u.s.bitmap));
+      read_state_type (&(type->u.s.lang_struct));
+    }
+  else
+    {
+      fatal_reading_state (t0, "Bad tag in struct type");
+    }
+}
+
+
+/* Read a GTY-ed union type.  */
+static void
+read_state_union_type (type_p type)
+{
+  struct state_token_st *t0;
+
+  type->kind = TYPE_UNION;
+  read_state_common_type_content (type);
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      if (state_token_is_name (t0, "nil"))
+	{
+	  type->u.s.tag = NULL;
+	  DBGPRINTF ("read anonymous union type @%p #%d",
+		     (void *) type, type->state_number);
+	}
+      else
+	{
+	  type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+	  DBGPRINTF ("read union type @%p #%d '%s'",
+		     (void *) type, type->state_number, type->u.s.tag);
+	}
+      next_state_tokens (1);
+      read_state_fileloc (&(type->u.s.line));
+      read_state_fields (&(type->u.s.fields));
+      read_state_options (&(type->u.s.opt));
+      read_state_lang_bitmap (&(type->u.s.bitmap));
+      read_state_type (&(type->u.s.lang_struct));
+    }
+  else
+    fatal_reading_state (t0, "Bad tag in union type");
+}
+
+
+/* Read a GTY-ed pointer type.  */
+static void
+read_state_pointer_type (type_p type)
+{
+  type->kind = TYPE_POINTER;
+  read_state_common_type_content (type);
+  DBGPRINTF ("read pointer type @%p #%d", (void *) type, type->state_number);
+  read_state_type (&(type->u.p));
+}
+
+
+/* Read a GTY-ed array type.  */
+static void
+read_state_array_type (type_p type)
+{
+  struct state_token_st *t0;
+
+  type->kind = TYPE_ARRAY;
+  read_state_common_type_content (type);
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      type->u.a.len = xstrdup (t0->stok_un.stok_string);
+      DBGPRINTF ("read array type @%p #%d length '%s'",
+		 (void *) type, type->state_number, type->u.a.len);
+      next_state_tokens (1);
+    }
+
+  else if (state_token_is_name (t0, "nil"))
+    {
+      type->u.a.len = NULL;
+      DBGPRINTF ("read array type @%p #%d without length",
+		 (void *) type, type->state_number);
+      next_state_tokens (1);
+    }
+
+  else
+    fatal_reading_state (t0, "Bad array name type");
+  read_state_type (&(type->u.a.p));
+}
+
+
+
+/* Read a lang_struct type for GTY-ed struct-s which depends upon GCC
+   front-end languages.  This is a tricky function and it was painful
+   to debug.  Change it with extreme care.  See also
+   write_state_lang_struct_type.  */
+static void
+read_state_lang_struct_type (type_p type)
+{
+  struct state_token_st *t0 = NULL;
+  struct state_token_st *t1 = NULL;
+  struct state_token_st *t2 = NULL;
+
+  type->kind = TYPE_LANG_STRUCT;
+  read_state_common_type_content (type);
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      if (state_token_is_name (t0, "nil"))
+	{
+	  DBGPRINTF ("read anonymous lang_struct type @%p #%d",
+		     (void *) type, type->state_number);
+	  type->u.s.tag = NULL;
+	}
+      else
+	{
+	  type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+	  DBGPRINTF ("read lang_struct type @%p #%d '%s'",
+		     (void *) type, type->state_number, type->u.s.tag);
+	}
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "Bad tag in lang struct type");
+  read_state_fileloc (&(type->u.s.line));
+  read_state_fields (&(type->u.s.fields));
+  read_state_options (&(type->u.s.opt));
+  read_state_lang_bitmap (&(type->u.s.bitmap));
+  /* Within lang_struct-ures, the lang_struct field is a linked list
+     of homonymous types! */
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+  /* Parse (!homotypes <number-types> <type-1> .... <type-n>) */
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!homotypes")
+      && state_token_kind (t2) == STOK_INTEGER)
+    {
+      type_p *prevty = &type->u.s.lang_struct;
+      int nbhomotype = t2->stok_un.stok_num;
+      int i = 0;
+      t0 = t1 = t2 = NULL;
+      next_state_tokens (3);
+      for (i = 0; i < nbhomotype; i++)
+	{
+	  read_state_type (prevty);
+	  t0 = peek_state_token (0);
+	  if (*prevty)
+	    prevty = &(*prevty)->next;
+	  else
+	      fatal_reading_state (t0,
+				   "expecting type in homotype list for lang_struct");
+	};
+      if (state_token_kind (t0) != STOK_RIGHTPAR)
+	fatal_reading_state (t0,
+			     "expecting ) in homotype list for lang_struct");
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "expecting !homotypes for lang_struct");
+}
+
+
+/* Read a param_struct type for GTY parametrized structures.  */
+static void
+read_state_param_struct_type (type_p type)
+{
+  int i;
+  struct state_token_st *t0;
+
+  type->kind = TYPE_PARAM_STRUCT;
+  read_state_common_type_content (type);
+  DBGPRINTF ("read param_struct type @%p #%d",
+	     (void *) type, type->state_number);
+  read_state_type (&(type->u.param_struct.stru));
+
+  for (i = 0; i < NUM_PARAM; i++)
+    {
+      t0 = peek_state_token (0);
+      if (state_token_is_name (t0, "nil"))
+	{
+	  type->u.param_struct.param[i] = NULL;
+	  next_state_tokens (1);
+	}
+      else
+	read_state_type (&(type->u.param_struct.param[i]));
+    }
+  read_state_fileloc (&(type->u.param_struct.line));
+}
+
+
+/* Read the gc used information.  */
+static void
+read_state_gc_used (enum gc_used_enum *pgus)
+{
+  struct state_token_st *t0;
+  t0 = peek_state_token (0);
+  if (state_token_is_name (t0, "gc_unused"))
+    *pgus = GC_UNUSED;
+  else if (state_token_is_name (t0, "gc_used"))
+    *pgus = GC_USED;
+  else if (state_token_is_name (t0, "gc_maybe_pointed_to"))
+    *pgus = GC_MAYBE_POINTED_TO;
+  else if (state_token_is_name (t0, "gc_pointed_to"))
+    *pgus = GC_POINTED_TO;
+  else
+    fatal_reading_state (t0, "invalid gc_used information");
+  next_state_tokens (1);
+}
+
+
+/* Utility function to read the common content of types.  */
+static void
+read_state_common_type_content (type_p current)
+{
+  struct state_token_st *t0;
+
+  t0 = peek_state_token (0);
+
+  if (state_token_kind (t0) == STOK_INTEGER)
+    {
+      current->state_number = t0->stok_un.stok_num;
+      next_state_tokens (1);
+      record_type (current);
+    }
+  else
+      fatal_reading_state_printf (t0,
+				  "Expected integer for state_number line %d",
+				  state_line);
+  /* We don't read the next field of the type.  */
+  read_state_type (&current->pointer_to);
+  read_state_gc_used (&current->gc_used);
+}
+
+
+/* Read a GTY-ed type.  */
+void
+read_state_type (type_p *current)
+{
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR &&
+      state_token_is_name (t1, "!type"))
+    {
+      next_state_tokens (2);
+      t0 = peek_state_token (0);
+      if (state_token_is_name (t0, "already_seen"))
+	{
+	  next_state_tokens (1);
+	  read_state_already_seen_type (current);
+	}
+      else
+	{
+	  t0 = peek_state_token (0);
+
+	  if (state_token_is_name (t0, "scalar_nonchar"))
+	    {
+	      next_state_tokens (1);
+	      read_state_scalar_nonchar_type (current);
+	    }
+	  else if (state_token_is_name (t0, "scalar_char"))
+	    {
+	      next_state_tokens (1);
+	      read_state_scalar_char_type (current);
+	    }
+	  else if (state_token_is_name (t0, "string"))
+	    {
+	      next_state_tokens (1);
+	      read_state_string_type (current);
+	    }
+	  else if (state_token_is_name (t0, "struct"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_struct_type (*current);
+	    }
+	  else if (state_token_is_name (t0, "union"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_union_type (*current);
+	    }
+	  else if (state_token_is_name (t0, "lang_struct"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_lang_struct_type (*current);
+	    }
+	  else if (state_token_is_name (t0, "param_struct"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_param_struct_type (*current);
+	    }
+	  else if (state_token_is_name (t0, "pointer"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_pointer_type (*current);
+	    }
+	  else if (state_token_is_name (t0, "array"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_array_type (*current);
+	    }
+	  else
+	    fatal_reading_state (t0, "bad type in (!type");
+	}
+      t0 = peek_state_token (0);
+      if (state_token_kind (t0) != STOK_RIGHTPAR)
+	fatal_reading_state (t0, "missing ) in type");
+      next_state_tokens (1);
+    }
+  else if (state_token_is_name (t0, "nil"))
+    {
+      next_state_tokens (1);
+      *current = NULL;
+    }
+  else
+    fatal_reading_state (t0, "bad type syntax");
+}
+
+
+/* Read a file location.  Files within the source directory are dealt
+   with specifically.  */
+void
+read_state_fileloc (struct fileloc *floc)
+{
+  bool issrcfile = false;
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+
+  gcc_assert (floc != NULL);
+  gcc_assert (srcdir != NULL);
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR &&
+      (state_token_is_name (t1, "!fileloc")
+       || (issrcfile = state_token_is_name (t1, "!srcfileloc"))))
+    {
+      next_state_tokens (2);
+      t0 = peek_state_token (0);
+      t1 = peek_state_token (1);
+      if (state_token_kind (t0) == STOK_STRING &&
+	  state_token_kind (t1) == STOK_INTEGER)
+	{
+	  char *path = t0->stok_un.stok_string;
+	  if (issrcfile)
+	    {
+	      static const char dirsepstr[2] = { DIR_SEPARATOR, (char) 0 };
+	      char *fullpath = concat (srcdir, dirsepstr, path, NULL);
+	      floc->file = input_file_by_name (fullpath);
+	      free (fullpath);
+	    }
+	  else
+	    floc->file = input_file_by_name (path);
+	  floc->line = t1->stok_un.stok_num;
+	  next_state_tokens (2);
+	}
+      else
+	fatal_reading_state (t0,
+			     "Bad fileloc syntax, expected path string and line");
+      t0 = peek_state_token (0);
+      if (state_token_kind (t0) != STOK_RIGHTPAR)
+	fatal_reading_state (t0, "Bad fileloc syntax, expected )");
+      next_state_tokens (1);
+    }
+  else if (state_token_is_name (t0, "nil"))
+    {
+      next_state_tokens (1);
+      floc->file = NULL;
+      floc->line = 0;
+    }
+  else
+    fatal_reading_state (t0, "Bad fileloc syntax");
+}
+
+
+/* Read the fields of a GTY-ed type.  */
+void
+read_state_fields (pair_p *fields)
+{
+  pair_p tmp = NULL;
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+  struct state_token_st *t2;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!fields")
+      && state_token_kind (t2) == STOK_INTEGER)
+    {
+      int nbfields = t2->stok_un.stok_num;
+      int nbpairs = 0;
+      next_state_tokens (3);
+      nbpairs = read_state_pair_list (&tmp);
+      t0 = peek_state_token (0);
+      if (nbpairs != nbfields)
+	fatal_reading_state_printf
+	  (t0,
+	   "Mismatched fields number, expected %d got %d", nbpairs, nbfields);
+      if (state_token_kind (t0) == STOK_RIGHTPAR)
+	next_state_tokens (1);
+      else
+	fatal_reading_state (t0, "Bad fields expecting )");
+    }
+
+  *fields = tmp;
+}
+
+
+/* Read a string option.  */
+static void
+read_state_string_option (options_p opt)
+{
+  struct state_token_st *t0;
+
+  t0 = peek_state_token (0);
+  opt->kind = OPTION_STRING;
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      opt->info.string = xstrdup (t0->stok_un.stok_string);
+      next_state_tokens (1);
+    }
+  else if (state_token_is_name (t0, "nil"))
+    {
+      opt->info.string = NULL;
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "Missing name in string option");
+}
+
+
+/* Read a type option.  */
+static void
+read_state_type_option (options_p opt)
+{
+  opt->kind = OPTION_TYPE;
+  read_state_type (&(opt->info.type));
+}
+
+
+/* Read a nested option.  */
+static void
+read_state_nested_option (options_p opt)
+{
+  struct state_token_st *t0;
+
+  opt->info.nested = XCNEW (struct nested_ptr_data);
+  opt->kind = OPTION_NESTED;
+  read_state_type (&(opt->info.nested->type));
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      opt->info.nested->convert_from = xstrdup (t0->stok_un.stok_string);
+      next_state_tokens (1);
+    }
+  else if (state_token_is_name (t0, "nil"))
+    {
+      opt->info.nested->convert_from = NULL;
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "Bad nested convert_from option");
+
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      opt->info.nested->convert_to = xstrdup (t0->stok_un.stok_string);
+      next_state_tokens (1);
+    }
+  else if (state_token_is_name (t0, "nil"))
+    {
+      opt->info.nested->convert_to = NULL;
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "Bad nested convert_from option");
+}
+
+
+/* Read an GTY option.  */
+static void
+read_state_option (options_p *opt)
+{
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR &&
+      state_token_is_name (t1, "!option"))
+    {
+      next_state_tokens (2);
+      t0 = peek_state_token (0);
+      if (state_token_kind (t0) == STOK_NAME)
+	{
+	  *opt = XCNEW (struct options);
+	  if (state_token_is_name (t0, "nil"))
+	    (*opt)->name = NULL;
+	  else
+	    (*opt)->name = t0->stok_un.stok_ident->stid_name;
+	  next_state_tokens (1);
+	  t0 = peek_state_token (0);
+	  if (state_token_kind (t0) == STOK_NAME)
+	    {
+	      if (state_token_is_name (t0, "string"))
+		{
+		  next_state_tokens (1);
+		  read_state_string_option (*opt);
+		}
+	      else if (state_token_is_name (t0, "type"))
+		{
+		  next_state_tokens (1);
+		  read_state_type_option (*opt);
+		}
+	      else if (state_token_is_name (t0, "nested"))
+		{
+		  next_state_tokens (1);
+		  read_state_nested_option (*opt);
+		}
+	      else
+		fatal_reading_state (t0, "Bad option type");
+	      t0 = peek_state_token (0);
+	      if (state_token_kind (t0) != STOK_RIGHTPAR)
+		fatal_reading_state (t0, "Bad syntax in option, expecting )");
+
+	      next_state_tokens (1);
+	    }
+	  else
+	    fatal_reading_state (t0, "Missing option type");
+	}
+      else
+	fatal_reading_state (t0, "Bad name for option");
+    }
+  else
+    fatal_reading_state (t0, "Bad option, waiting for )");
+}
+
+/* Read a list of options.  */
+void
+read_state_options (options_p *opt)
+{
+  options_p head = NULL;
+  options_p previous = NULL;
+  options_p current_option = NULL;
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR &&
+      state_token_is_name (t1, "!options"))
+    {
+      next_state_tokens (2);
+      t0 = peek_state_token (0);
+      while (state_token_kind (t0) != STOK_RIGHTPAR)
+	{
+	  read_state_option (&current_option);
+	  if (head == NULL)
+	    {
+	      head = current_option;
+	      previous = head;
+	    }
+	  else
+	    {
+	      previous->next = current_option;
+	      previous = current_option;
+	    }
+	  t0 = peek_state_token (0);
+	}
+      next_state_tokens (1);
+    }
+  else if (state_token_is_name (t0, "nil"))
+    {
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "Bad options syntax");
+
+  *opt = head;
+}
+
+
+/* Read a version, and check against the version of the gengtype.  */
+static void
+read_state_version (const char *version_string)
+{
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR &&
+      state_token_is_name (t1, "!version"))
+    {
+      next_state_tokens (2);
+      t0 = peek_state_token (0);
+      t1 = peek_state_token (1);
+      if (state_token_kind (t0) == STOK_STRING &&
+	  state_token_kind (t1) == STOK_RIGHTPAR)
+	{
+	  /* Check that the read version string is the same as current
+	     version.  */
+	  if (strcmp (version_string, t0->stok_un.stok_string))
+	    fatal_reading_state_printf (t0,
+					"version string mismatch; expecting %s but got %s",
+					version_string,
+					t0->stok_un.stok_string);
+	  next_state_tokens (2);
+	}
+      else
+	fatal_reading_state (t0, "Missing version or right parenthesis");
+    }
+  else
+    fatal_reading_state (t0, "Bad version syntax");
+}
+
+
+/* Read a pair.  */
+void
+read_state_pair (pair_p *current)
+{
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  if (state_token_kind (t0) == STOK_LEFTPAR &&
+      state_token_is_name (t1, "!pair"))
+    {
+      *current = XCNEW (struct pair);
+      next_state_tokens (2);
+      t0 = peek_state_token (0);
+      if (state_token_kind (t0) == STOK_STRING)
+	{
+	  if (strcmp (t0->stok_un.stok_string, "nil") == 0)
+	    {
+	      (*current)->name = NULL;
+	    }
+	  else
+	    {
+	      (*current)->name = xstrdup (t0->stok_un.stok_string);
+	    }
+	  next_state_tokens (1);
+	  read_state_type (&((*current)->type));
+	  read_state_fileloc (&((*current)->line));
+	  read_state_options (&((*current)->opt));;
+	  t0 = peek_state_token (0);
+	  if (state_token_kind (t0) == STOK_RIGHTPAR)
+	    {
+	      next_state_tokens (1);
+	    }
+	  else
+	    {
+	      fatal_reading_state (t0, "Bad syntax for pair, )");
+	    }
+	}
+      else
+	{
+	  fatal_reading_state (t0, "Bad name for pair");
+	}
+    }
+  else if (state_token_kind (t0) == STOK_NAME &&
+	   state_token_is_name (t0, "nil"))
+    {
+      next_state_tokens (1);
+      *current = NULL;
+    }
+  else
+    fatal_reading_state_printf (t0, "Bad syntax for pair, (!pair %d",
+				state_token->stok_kind);
+}
+
+
+/* Return the number of pairs actually read.  */
+int
+read_state_pair_list (pair_p *list)
+{
+  int nbpair = 0;
+  pair_p head = NULL;
+  pair_p previous = NULL;
+  pair_p tmp = NULL;
+  struct state_token_st *t0;
+  t0 = peek_state_token (0);
+  while (t0 && state_token_kind (t0) != STOK_RIGHTPAR)
+    {
+      read_state_pair (&tmp);
+      if (head == NULL)
+	{
+	  head = tmp;
+	  previous = head;
+	}
+      else
+	{
+	  previous->next = tmp;
+	  previous = tmp;
+	}
+      t0 = peek_state_token (0);
+      nbpair++;
+    }
+
+  /* don't consume the ); the caller will eat it.  */
+  *list = head;
+  return nbpair;
+}
+
+/* Read the typedefs.  */
+static void
+read_state_typedefs (pair_p *typedefs)
+{
+  int nbtypedefs = 0;
+  pair_p list = NULL;
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+  struct state_token_st *t2;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!typedefs")
+      && state_token_kind (t2) == STOK_INTEGER)
+    {
+      int nbpairs = 0;
+      nbtypedefs = t2->stok_un.stok_num;
+      next_state_tokens (3);
+      nbpairs = read_state_pair_list (&list);
+      t0 = peek_state_token (0);
+      if (nbpairs != nbtypedefs)
+	fatal_reading_state_printf
+	  (t0,
+	   "invalid number of typedefs, expected %d but got %d",
+	   nbtypedefs, nbpairs);
+      if (state_token_kind (t0) == STOK_RIGHTPAR)
+	next_state_tokens (1);
+      else
+	fatal_reading_state (t0, "Bad typedefs syntax )");
+    }
+  else
+    fatal_reading_state (t0, "Bad typedefs syntax (!typedefs");
+
+  if (verbosity_level >= 2)
+    printf ("%s read %d typedefs from state\n", progname, nbtypedefs);
+  *typedefs = list;
+}
+
+
+/* Read the structures.  */
+static void
+read_state_structures (type_p *structures)
+{
+  type_p head = NULL;
+  type_p previous;
+  type_p tmp;
+  int nbstruct = 0, countstruct = 0;
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+  struct state_token_st *t2;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!structures")
+      && state_token_kind (t2) == STOK_INTEGER)
+    {
+      nbstruct = t2->stok_un.stok_num;
+      next_state_tokens (3);
+      t0 = peek_state_token (0);
+      while (t0 && state_token_kind (t0) != STOK_RIGHTPAR)
+	{
+	  tmp = NULL;
+	  read_state_type (&tmp);
+	  countstruct++;
+	  if (head == NULL)
+	    {
+	      head = tmp;
+	      previous = head;
+	    }
+	  else
+	    {
+	      previous->next = tmp;
+	      previous = tmp;
+	    }
+	  t0 = peek_state_token (0);
+	}
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "Bad structures syntax");
+  if (countstruct != nbstruct)
+    fatal_reading_state_printf (NULL_STATE_TOKEN, 
+				"expected %d structures but got %d",
+				nbstruct, countstruct);
+  if (verbosity_level >= 2)
+    printf ("%s read %d structures from state\n", progname, nbstruct);
+  *structures = head;
+}
+
+
+/* Read the param_struct-s.  */
+static void
+read_state_param_structs (type_p *param_structs)
+{
+  int nbparamstructs = 0;
+  int countparamstructs = 0;
+  type_p head = NULL;
+  type_p previous;
+  type_p tmp;
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+  struct state_token_st *t2;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!param_structs")
+      && state_token_kind (t2) == STOK_INTEGER)
+    {
+      nbparamstructs = t2->stok_un.stok_num;
+      next_state_tokens (3);
+      t0 = t1 = t2 = NULL;
+      t0 = peek_state_token (0);
+      while (state_token_kind (t0) != STOK_RIGHTPAR)
+	{
+	  tmp = NULL;
+	  read_state_type (&tmp);
+	  if (head == NULL)
+	    {
+	      head = tmp;
+	      previous = head;
+	    }
+	  else
+	    {
+	      previous->next = tmp;
+	      previous = tmp;
+	    }
+	  t0 = peek_state_token (0);
+	  countparamstructs++;
+	}
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "Bad param_structs syntax");
+  t0 = peek_state_token (0);
+  if (countparamstructs != nbparamstructs)
+    fatal_reading_state_printf
+      (t0,
+       "invalid number of param_structs expected %d got %d",
+       nbparamstructs, countparamstructs);
+  *param_structs = head;
+}
+
+
+/* Read the variables.  */
+static void
+read_state_variables (pair_p *variables)
+{
+  pair_p list = NULL;
+  int nbvars = 0;
+  struct state_token_st *t0;
+  struct state_token_st *t1;
+  struct state_token_st *t2;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!variables")
+      && state_token_kind (t2) == STOK_INTEGER)
+    {
+      int nbpairs = 0;
+      nbvars = t2->stok_un.stok_num;
+      next_state_tokens (3);
+      nbpairs = read_state_pair_list (&list);
+      t0 = peek_state_token (0);
+      if (nbpairs != nbvars)
+	fatal_reading_state_printf
+	  (t0, "Invalid number of variables, expected %d but got %d",
+	   nbvars, nbpairs);
+      if (state_token_kind (t0) == STOK_RIGHTPAR)
+	next_state_tokens (1);
+      else
+	fatal_reading_state (t0, "Waiting for ) in variables");
+    }
+  else
+    fatal_reading_state (t0, "Bad variables syntax");
+  *variables = list;
+  if (verbosity_level >= 2)
+    printf ("%s read %d variables from state\n", progname, nbvars);
+}
+
+
+/* Read the source directory.  */
+static void
+read_state_srcdir (void)
+{
+  struct state_token_st *t0 = NULL;
+  struct state_token_st *t1 = NULL;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  if (state_token_kind (t0) == STOK_LEFTPAR &&
+      state_token_is_name (t1, "!srcdir"))
+    {
+      next_state_tokens (2);
+      t0 = peek_state_token (0);
+      t1 = peek_state_token (1);
+      if (state_token_kind (t0) == STOK_STRING &&
+	  state_token_kind (t1) == STOK_RIGHTPAR)
+	{
+	  srcdir = xstrdup (t0->stok_un.stok_string);
+	  srcdir_len = strlen (srcdir);
+	  next_state_tokens (2);
+	  return;
+	}
+    }
+
+  fatal_reading_state (t0, "Bad srcdir in state_file");
+}
+
+
+/* Read the sequence of GCC front-end languages.  */
+static void
+read_state_languages (void)
+{
+  struct state_token_st *t0 = NULL;
+  struct state_token_st *t1 = NULL;
+  struct state_token_st *t2 = NULL;
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!languages")
+      && state_token_kind (t2) == STOK_INTEGER)
+    {
+      int i = 0;
+      num_lang_dirs = t2->stok_un.stok_num;
+      lang_dir_names = XCNEWVEC (const char *, num_lang_dirs);
+      next_state_tokens (3);
+      t0 = t1 = t2 = NULL;
+      for (i = 0; i < (int) num_lang_dirs; i++)
+	{
+	  t0 = peek_state_token (0);
+	  if (state_token_kind (t0) != STOK_NAME)
+	    fatal_reading_state (t0, "expecting language name in state file");
+	  lang_dir_names[i] = t0->stok_un.stok_ident->stid_name;
+	  next_state_tokens (1);
+	}
+      t0 = peek_state_token (0);
+      if (state_token_kind (t0) != STOK_RIGHTPAR)
+	fatal_reading_state (t0, "missing ) in languages list of state file");
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "expecting languages list in state file");
+
+}
+
+/* Read the sequences of files.  */
+static void
+read_state_files_list (void)
+{
+  struct state_token_st *t0 = NULL;
+  struct state_token_st *t1 = NULL;
+  struct state_token_st *t2 = NULL;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!fileslist")
+      && state_token_kind (t2) == STOK_INTEGER)
+    {
+      int i = 0;
+      num_gt_files = t2->stok_un.stok_num;
+      next_state_tokens (3);
+      t0 = t1 = t2 = NULL;
+      gt_files = XCNEWVEC (input_file *, num_gt_files);
+      for (i = 0; i < (int) num_gt_files; i++)
+	{
+	  bool issrcfile = FALSE;
+	  t0 = t1 = t2 = NULL;
+	  t0 = peek_state_token (0);
+	  t1 = peek_state_token (1);
+	  t2 = peek_state_token (2);
+	  if (state_token_kind (t0) == STOK_LEFTPAR
+	      && (state_token_is_name (t1, "!file")
+		  || (issrcfile = state_token_is_name (t1, "!srcfile")))
+	      && state_token_kind (t2) == STOK_INTEGER)
+	    {
+	      lang_bitmap bmap = t2->stok_un.stok_num;
+	      next_state_tokens (3);
+	      t0 = t1 = t2 = NULL;
+	      t0 = peek_state_token (0);
+	      t1 = peek_state_token (1);
+	      if (state_token_kind (t0) == STOK_STRING
+		  && state_token_kind (t1) == STOK_RIGHTPAR)
+		{
+		  const char *fnam = t0->stok_un.stok_string;
+		  /* Allocate & fill a gt_file entry with space for the lang_bitmap before! */
+		  input_file *curgt = NULL;
+		  if (issrcfile)
+		    {
+		      static const char dirsepstr[2] =
+			{ DIR_SEPARATOR, (char) 0 };
+		      char *fullpath = concat (srcdir, dirsepstr, fnam, NULL);
+		      curgt = input_file_by_name (fullpath);
+		      free (fullpath);
+		    }
+		  else
+		    curgt = input_file_by_name (fnam);
+		  set_lang_bitmap (curgt, bmap);
+		  gt_files[i] = curgt;
+		  next_state_tokens (2);
+		}
+	      else
+		fatal_reading_state (t0,
+				     "bad file in !fileslist of state file");
+	    }
+	  else
+	    fatal_reading_state (t0,
+				 "expecting file in !fileslist of state file");
+	};
+      t0 = peek_state_token (0);
+      if (!state_token_kind (t0) == STOK_RIGHTPAR)
+	fatal_reading_state (t0, "missing ) for !fileslist in state file");
+      next_state_tokens (1);
+    }
+  else
+    fatal_reading_state (t0, "missing !fileslist in state file");
+}
+
+
+/* Read the trailer.  */
+static void
+read_state_trailer (void)
+{
+  struct state_token_st *t0 = NULL;
+  struct state_token_st *t1 = NULL;
+  struct state_token_st *t2 = NULL;
+
+  t0 = peek_state_token (0);
+  t1 = peek_state_token (1);
+  t2 = peek_state_token (2);
+
+  if (state_token_kind (t0) == STOK_LEFTPAR
+      && state_token_is_name (t1, "!endfile")
+      && state_token_kind (t2) == STOK_RIGHTPAR)
+    next_state_tokens (3);
+  else
+    fatal_reading_state (t0, "missing !endfile in state file");
+}
+
+
+/* Utility functions for the state_seen_types hash table.  */
+static unsigned
+hash_type_number (const void *ty)
+{
+  const struct type *type = (const struct type *) ty;
+
+  return type->state_number;
+}
+
+static int
+equals_type_number (const void *ty1, const void *ty2)
+{
+  const struct type *type1 = (const struct type *) ty1;
+  const struct type *type2 = (const struct type *) ty2;
+
+  return type1->state_number == type2->state_number;
+}
+
+
+/* The function reading the state, called by main from gengtype.c.  */
+void
+read_state (const char *path)
+{
+  state_file = fopen (path, "r");
+  if (state_file == NULL)
+    fatal ("Failed to open state file %s for reading [%s]", path,
+	   xstrerror (errno));
+  state_path = path;
+  state_line = 1;
+
+  if (verbosity_level >= 1)
+    {
+      printf ("%s reading state file %s;", progname, state_path);
+      if (verbosity_level >= 2)
+	putchar ('\n');
+      fflush (stdout);
+    }
+
+  state_seen_types =
+    htab_create (2017, hash_type_number, equals_type_number, NULL);
+  state_ident_tab =
+    htab_create (4027, htab_hash_string, (htab_eq) strcmp, NULL);
+  read_state_version (version_string);
+  read_state_srcdir ();
+  read_state_languages ();
+  read_state_files_list ();
+  read_state_structures (&structures);
+  if (ferror (state_file))
+    fatal_reading_state_printf
+      (NULL_STATE_TOKEN, "input error while reading state [%s]",
+       xstrerror (errno));
+  read_state_typedefs (&typedefs);
+  read_state_param_structs (&param_structs);
+  read_state_variables (&variables);
+  read_state_trailer ();
+
+  if (verbosity_level >= 1)
+    {
+      printf ("%s read %ld bytes.\n", progname, ftell (state_file));
+      fflush (stdout);
+    };
+
+  if (fclose (state_file))
+    fatal ("failed to close read state file %s [%s]",
+	   path, xstrerror (errno));
+  state_file = NULL;
+  state_path = NULL;
+}
+
+/* End of file gengtype-state.c.  */
--- ../thirdround_05_typedopt//gengtype.c	2010-09-21 16:16:19.000000000 +0200
+++ gcc/gengtype.c	2010-09-21 19:40:11.000000000 +0200
@@ -70,6 +70,10 @@ int do_debug;
 /* For verbose messages to the user.  */
 int verbosity_level;
 
+/* We have a type count and use it to set the state_number of newly
+   allocated types to some unique negative number.  */
+static int type_count;
+
 /* The backup directory should be in the same file-system as the
    generated files, otherwise the rename(2) system call would fail.
    If NULL, no backup is made when overwriting a generated file.  */
@@ -572,12 +576,14 @@ new_structure (const char *name, int isu
 	else if (si->u.s.line.file != NULL && si->u.s.bitmap != bitmap)
 	  {
 	    ls = si;
+	    type_count++;
 	    si = XCNEW (struct type);
 	    memcpy (si, ls, sizeof (struct type));
 	    ls->kind = TYPE_LANG_STRUCT;
 	    ls->u.s.lang_struct = si;
 	    ls->u.s.fields = NULL;
 	    si->next = NULL;
+	    si->state_number = -type_count;
 	    si->pointer_to = NULL;
 	    si->u.s.lang_struct = ls;
 	  }
@@ -587,6 +593,8 @@ new_structure (const char *name, int isu
 	if (ls != NULL && s == NULL)
 	  {
 	    s = XCNEW (struct type);
+	    type_count++;
+	    s->state_number = -type_count;
 	    s->next = ls->u.s.lang_struct;
 	    ls->u.s.lang_struct = s;
 	    s->u.s.lang_struct = ls;
@@ -598,6 +606,8 @@ new_structure (const char *name, int isu
     {
       s = XCNEW (struct type);
       s->next = structures;
+      type_count++;
+      s->state_number = -type_count;
       structures = s;
     }
 
@@ -634,11 +644,12 @@ find_structure (const char *name, int is
     if (strcmp (name, s->u.s.tag) == 0
 	&& UNION_P (s) == isunion)
       return s;
-
-  s = XCNEW (struct type);
+   s = XCNEW (struct type);
+  type_count++;
   s->next = structures;
   structures = s;
   s->kind = isunion ? TYPE_UNION : TYPE_STRUCT;
+  s->state_number = -type_count;
   s->u.s.tag = name;
   structures = s;
   return s;
@@ -661,8 +672,10 @@ find_param_structure (type_p t, type_p p
   if (res == NULL)
     {
       res = XCNEW (struct type);
+      type_count++;
       res->kind = TYPE_PARAM_STRUCT;
       res->next = param_structs;
+      res->state_number = -type_count;
       param_structs = res;
       res->u.param_struct.stru = t;
       memcpy (res->u.param_struct.param, param, sizeof (type_p) * NUM_PARAM);
@@ -689,7 +702,9 @@ create_pointer (type_p t)
   if (! t->pointer_to)
     {
       type_p r = XCNEW (struct type);
+      type_count++;
       r->kind = TYPE_POINTER;
+      r->state_number = -type_count;
       r->u.p = t;
       t->pointer_to = r;
     }
@@ -703,8 +718,10 @@ create_array (type_p t, const char *len)
 {
   type_p v;
 
-  v = XCNEW (struct type);
+   v = XCNEW (struct type);
   v->kind = TYPE_ARRAY;
+  type_count++;
+  v->state_number = -type_count;
   v->u.a.p = t;
   v->u.a.len = len;
   return v;
@@ -4571,8 +4588,10 @@ dump_structures (const char * name, type
   printf ("End of %s\n\n", name);
 }
 
-/* Dumps the internal structures of gengtype.  */
-
+/* Dumps the internal structures of gengtype. This can be used to
+   debug gengtype itself, or perhaps to understand what is happenning,
+   e.g. the role of some difficult to grasp GTY-s.  So it might be
+   useful for plugin or GCC developers.  */
 static void
 dump_everything (void)
 {
@@ -4787,8 +4806,12 @@ main (int argc, char **argv)
   static struct fileloc pos = { NULL, 0 };
   outf_p output_header;
 
-  /* Mandatory common initializations.  */
+   /* Mandatory common initializations.  */
   progname = "gengtype"; /* For fatal and messages.  */
+  /* Initialize the state number of statically predefined types.  */
+  string_type.state_number = - (++type_count);
+  scalar_nonchar.state_number = - (++type_count);
+  scalar_char.state_number = - (++type_count);
   /* 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;
@@ -4815,8 +4838,12 @@ main (int argc, char **argv)
   DBGPRINTF ("inputlist %s", inputlist);
   if (read_state_filename)
     {
-      fatal ("read state %s not implemented yet", read_state_filename);
-      /* TODO: implement read state.  */
+      if (inputlist)
+	fatal ("input list %s cannot be given with a read state file %s",
+	       inputlist, read_state_filename);
+      read_state (read_state_filename);
+      DBGPRINT_COUNT_TYPE ("structures after read_state", structures);
+      DBGPRINT_COUNT_TYPE ("param_structs after read_state", param_structs);
     }
   else if (inputlist)
     {
@@ -4844,9 +4871,9 @@ main (int argc, char **argv)
       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);
-
-    }
+	printf ("%s parsed %d files with %d GTY types\n",
+		progname, (int) num_gt_files, type_count);
+     }
   else
     fatal ("either an input list or a read state file should be given");
   if (hit_error)
@@ -4893,11 +4920,30 @@ main (int argc, char **argv)
      happen before writing the state.  */
   set_gc_used (variables);
 
-  /* We should write the state here, but it is not yet implemented.  */
+
+  /* We write the state here.  It could eventually happen that the
+     state file is written after some plugin files have been parsed,
+     perhaps to enlarge the state file for other plugins needs.  But
+     this is an uncommon scenario.  */
   if (write_state_filename)
     {
-      fatal ("write state %s in not yet implemented", write_state_filename);
-      /* TODO: implement write state.  */
+      DBGPRINT_COUNT_TYPE ("structures before writestate", structures);
+      DBGPRINT_COUNT_TYPE ("param_structs before writestate", param_structs);
+      /* We definitely don't want to write a state file if some error
+	 occurred while reading input files processed by gengtype,
+	 because we only want to write sane state files!  */
+      if (hit_error)
+	fatal ("won't write state %s after errors", write_state_filename);
+      write_state (write_state_filename);
+      if (do_dump)
+	dump_everything ();
+
+      /* After having written the state file we return immediately to
+	 avoid generating any output file.  */
+      if (hit_error)
+	return 1;
+      else
+	return 0;
     }
 
 
--- ../thirdround_05_typedopt//gengtype.h	2010-09-21 16:11:46.000000000 +0200
+++ gcc/gengtype.h	2010-09-21 19:40:29.000000000 +0200
@@ -434,6 +434,13 @@ extern size_t srcdir_len;
 extern const char *read_state_filename;
 extern const char *write_state_filename;
 
+/* Functions reading and writing the entire gengtype state, called from
+   main, and implemented in file gengtype-state.c.  */
+void read_state (const char* path);
+/* Write the state, and update the state_number field in types.  */
+void write_state (const char* path);
+
+
 /* Print an error message.  */
 extern void error_at_line
   (const struct fileloc *pos, const char *msg, ...) ATTRIBUTE_PRINTF_2;
--- ../thirdround_05_typedopt//Makefile.in	2010-09-20 21:13:15.000000000 +0200
+++ gcc/Makefile.in	2010-09-21 19:41:05.000000000 +0200
@@ -1492,7 +1492,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-con
  insn-attr.h insn-attrtab.c insn-opinit.c insn-preds.c insn-constants.h \
  tm-preds.h tm-constrs.h \
  tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
- genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \
+ genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list gtype.state \
  xgcc$(exeext) cpp$(exeext) cc1$(exeext) cc1*-dummy$(exeext) $(EXTRA_PASSES) \
  $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \
  $(SPECS) collect2$(exeext) lto-wrapper$(exeext) \
@@ -3798,6 +3798,9 @@ ALL_GTFILES_H := $(sort $(GTFILES_H) $(G
 
 $(ALL_GTFILES_H) gtype-desc.c gtype-desc.h : s-gtype ; @true
 
+## Common flags to gengtype [e.g. -v for verbosity or -B . for backups].
+GENGTYPE_FLAGS = 
+
 gtyp-input.list: s-gtyp-input ; @true
 s-gtyp-input: Makefile
 	@: $(call write_entries_to_file,$(GTFILES),tmp-gi.list)
@@ -3806,7 +3809,13 @@ s-gtyp-input: Makefile
 
 s-gtype: build/gengtype$(build_exeext) $(filter-out [%], $(GTFILES)) \
 	 gtyp-input.list
-	$(RUN_GEN) build/gengtype$(build_exeext) -S $(srcdir) -I gtyp-input.list
+# First, parse all files and save a state file.
+	$(RUN_GEN) build/gengtype$(build_exeext) $(GENGTYPE_FLAGS) \
+                    -S $(srcdir) -I gtyp-input.list -w gtype.state
+# Second, read the state file and generate all files.  This ensure that
+# gtype.state is correctly read:
+	$(RUN_GEN) build/gengtype$(build_exeext) $(GENGTYPE_FLAGS) \
+                    -r gtype.state
 	$(STAMP) s-gtype
 
 generated_files = config.h tm.h $(TM_P_H) $(TM_H) multilib.h \
@@ -3902,6 +3911,8 @@ build/gengenrtl.o : gengenrtl.c $(BCONFI
 build/gengtype-lex.o : gengtype-lex.c gengtype.h $(BCONFIG_H) $(SYSTEM_H)
 build/gengtype-parse.o : gengtype-parse.c gengtype.h $(BCONFIG_H)	\
   $(SYSTEM_H)
+build/gengtype-state.o : gengtype-state.c gengtype.h $(BCONFIG_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	\
@@ -3948,7 +3959,7 @@ build/genautomata$(build_exeext) : BUILD
 
 # These programs are not linked with the MD reader.
 build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \
-              build/version.o
+              build/gengtype-state.o build/version.o
 build/genhooks$(build_exeext) : $(BUILD_ERRORS)
 
 # Generated source files for gengtype.
@@ -4404,6 +4415,7 @@ mostlyclean: lang.mostlyclean
 # Delete files generated by gengtype.c
 	-rm -f gtype-*
 	-rm -f gt-*
+	-rm gtype.state
 # Delete genchecksum outputs
 	-rm -f *-checksum.c
 

[-- Attachment #3: cumulatedpatch6_wstate-gengtypethird-r164437.diff.gz --]
[-- Type: application/octet-stream, Size: 42158 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* gengtype improvements for plugins, thirdround! patch 7/7 [doc]
  2010-09-22  2:16           ` Basile Starynkevitch
@ 2010-09-22  3:03             ` Basile Starynkevitch
  2010-09-22 14:17               ` Laurynas Biveinis
  0 siblings, 1 reply; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-22  3:03 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1744 bytes --]


Hello All


Please notice that I made a mail mistake in the previous patch chunk.
The 6th patch [wstate] is in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01716.html and not in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01714.html which got the
wrong attachments (no patches there!).  Sorry for the noise.

References
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01716.html 
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01032.html
  http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01081.html

The last patch takes into account Lauryanas remarks in
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01081.html and is a
documentation patch. I added some more explanations so please check my
poor english language.

I still hope that my patch serie "thirdround" will be Ok, with perhaps
minor changes required.


#################### gcc/ChangeLog entry for documentation 
2010-09-21  Basile Starynkevitch  <basile@starynkevitch.net>

	* gcc/doc/gty.texi:
	(Generating GGC code with gengtype): New node.
	(GTY Options): Documented that tag should be unique.
	Added ptr_alias documentation.
	(How to run the gengtype generator): New section.
################################################################

The attached patch is relative to
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01716.html 

Ok for trunk? With what changes?

BTW, the dates in the patch series (and notably their ChangeLog entry)
might be wrong. If Ok-ed, I will put the date (as seen from Paris,
France) of the commit.

Cheers

-- 
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 mine, sont seulement les miennes} ***

[-- Attachment #2: patch7_doc-relto06.diff --]
[-- Type: text/x-diff, Size: 22322 bytes --]

--- ../thirdround_06_wstate//gty.texi	2010-09-21 20:21:19.000000000 +0200
+++ gcc/doc/gty.texi	2010-09-21 20:20:20.000000000 +0200
@@ -0,0 +1,552 @@
+@c Copyright (C) 2002, 2003, 2004, 2007, 2008, 2009
+@c Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Type Information
+@chapter Memory Management and Type Information
+@cindex GGC
+@findex GTY
+
+GCC uses some fairly sophisticated memory management techniques, which
+involve determining information about GCC's data structures from GCC's
+source code and using this information to perform garbage collection and
+implement precompiled headers.
+
+A full C parser would be too complicated for this task, so a limited
+subset of C is interpreted and special markers are used to determine
+what parts of the source to look at.  All @code{struct} and
+@code{union} declarations that define data structures that are
+allocated under control of the garbage collector must be marked.  All
+global variables that hold pointers to garbage-collected memory must
+also be marked.  Finally, all global variables that need to be saved
+and restored by a precompiled header must be marked.  (The precompiled
+header mechanism can only save static variables if they're scalar.
+Complex data structures must be allocated in garbage-collected memory
+to be saved in a precompiled header.)
+
+The full format of a marker is
+@smallexample
+GTY (([@var{option}] [(@var{param})], [@var{option}] [(@var{param})] @dots{}))
+@end smallexample
+@noindent
+but in most cases no options are needed.  The outer double parentheses
+are still necessary, though: @code{GTY(())}.  Markers can appear:
+
+@itemize @bullet
+@item
+In a structure definition, before the open brace;
+@item
+In a global variable declaration, after the keyword @code{static} or
+@code{extern}; and
+@item
+In a structure field definition, before the name of the field.
+@end itemize
+
+Here are some examples of marking simple data structures and globals.
+
+@smallexample
+struct GTY(()) @var{tag}
+@{
+  @var{fields}@dots{}
+@};
+
+typedef struct GTY(()) @var{tag}
+@{
+  @var{fields}@dots{}
+@} *@var{typename};
+
+static GTY(()) struct @var{tag} *@var{list};   /* @r{points to GC memory} */
+static GTY(()) int @var{counter};        /* @r{save counter in a PCH} */
+@end smallexample
+
+The parser understands simple typedefs such as
+@code{typedef struct @var{tag} *@var{name};} and
+@code{typedef int @var{name};}.
+These don't need to be marked.
+
+@menu
+* GTY Options::         What goes inside a @code{GTY(())}.
+* GGC Roots::           Making global variables GGC roots.
+* Files::               How the generated files work.
+* Generating GGC code with gengtype::    How to run the gengtype generator.
+* Invoking the garbage collector::   How to invoke the garbage collector.
+@end menu
+
+@node GTY Options
+@section The Inside of a @code{GTY(())}
+
+Sometimes the C code is not enough to fully describe the type
+structure.  Extra information can be provided with @code{GTY} options
+and additional markers.  Some options take a parameter, which may be
+either a string or a type name, depending on the parameter.  If an
+option takes no parameter, it is acceptable either to omit the
+parameter entirely, or to provide an empty string as a parameter.  For
+example, @code{@w{GTY ((skip))}} and @code{@w{GTY ((skip ("")))}} are
+equivalent.
+
+When the parameter is a string, often it is a fragment of C code.  Four
+special escapes may be used in these strings, to refer to pieces of
+the data structure being marked:
+
+@cindex % in GTY option
+@table @code
+@item %h
+The current structure.
+@item %1
+The structure that immediately contains the current structure.
+@item %0
+The outermost structure that contains the current structure.
+@item %a
+A partial expression of the form @code{[i1][i2]@dots{}} that indexes
+the array item currently being marked.
+@end table
+
+For instance, suppose that you have a structure of the form
+@smallexample
+struct A @{
+  @dots{}
+@};
+struct B @{
+  struct A foo[12];
+@};
+@end smallexample
+@noindent
+and @code{b} is a variable of type @code{struct B}.  When marking
+@samp{b.foo[11]}, @code{%h} would expand to @samp{b.foo[11]},
+@code{%0} and @code{%1} would both expand to @samp{b}, and @code{%a}
+would expand to @samp{[11]}.
+
+As in ordinary C, adjacent strings will be concatenated; this is
+helpful when you have a complicated expression.
+@smallexample
+@group
+GTY ((chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE"
+                  " ? TYPE_NEXT_VARIANT (&%h.generic)"
+                  " : TREE_CHAIN (&%h.generic)")))
+@end group
+@end smallexample
+
+The available options are:
+
+@table @code
+@findex length
+@item length ("@var{expression}")
+
+There are two places the type machinery will need to be explicitly told
+the length of an array.  The first case is when a structure ends in a
+variable-length array, like this:
+@smallexample
+struct GTY(()) rtvec_def @{
+  int num_elem;         /* @r{number of elements} */
+  rtx GTY ((length ("%h.num_elem"))) elem[1];
+@};
+@end smallexample
+
+In this case, the @code{length} option is used to override the specified
+array length (which should usually be @code{1}).  The parameter of the
+option is a fragment of C code that calculates the length.
+
+The second case is when a structure or a global variable contains a
+pointer to an array, like this:
+@smallexample
+struct gimple_omp_for_iter * GTY((length ("%h.collapse"))) iter;
+@end smallexample
+In this case, @code{iter} has been allocated by writing something like
+@smallexample
+  x->iter = ggc_alloc_cleared_vec_gimple_omp_for_iter (collapse);
+@end smallexample
+and the @code{collapse} provides the length of the field.
+
+This second use of @code{length} also works on global variables, like:
+@verbatim
+static GTY((length("reg_known_value_size"))) rtx *reg_known_value;
+@end verbatim
+
+@findex skip
+@item skip
+
+If @code{skip} is applied to a field, the type machinery will ignore it.
+This is somewhat dangerous; the only safe use is in a union when one
+field really isn't ever used.
+
+@findex desc
+@findex tag
+@findex default
+@item desc ("@var{expression}")
+@itemx tag ("@var{constant}")
+@itemx default
+
+The type machinery needs to be told which field of a @code{union} is
+currently active.  This is done by giving each field a constant
+@code{tag} value, and then specifying a discriminator using @code{desc}.
+The value of the expression given by @code{desc} is compared against
+each @code{tag} value, each of which should be different.  If no
+@code{tag} is matched, the field marked with @code{default} is used if
+there is one, otherwise no field in the union will be marked.
+A union field can have at most one @code{tag}.
+
+In the @code{desc} option, the ``current structure'' is the union that
+it discriminates.  Use @code{%1} to mean the structure containing it.
+There are no escapes available to the @code{tag} option, since it is a
+constant.
+
+For example,
+@smallexample
+struct GTY(()) tree_binding
+@{
+  struct tree_common common;
+  union tree_binding_u @{
+    tree GTY ((tag ("0"))) scope;
+    struct cp_binding_level * GTY ((tag ("1"))) level;
+  @} GTY ((desc ("BINDING_HAS_LEVEL_P ((tree)&%0)"))) xscope;
+  tree value;
+@};
+@end smallexample
+
+In this example, the value of BINDING_HAS_LEVEL_P when applied to a
+@code{struct tree_binding *} is presumed to be 0 or 1.  If 1, the type
+mechanism will treat the field @code{level} as being present and if 0,
+will treat the field @code{scope} as being present.
+
+@findex param_is
+@findex use_param
+@item param_is (@var{type})
+@itemx use_param
+
+Sometimes it's convenient to define some data structure to work on
+generic pointers (that is, @code{PTR}) and then use it with a specific
+type.  @code{param_is} specifies the real type pointed to, and
+@code{use_param} says where in the generic data structure that type
+should be put.
+
+For instance, to have a @code{htab_t} that points to trees, one would
+write the definition of @code{htab_t} like this:
+@smallexample
+typedef struct GTY(()) @{
+  @dots{}
+  void ** GTY ((use_param, @dots{})) entries;
+  @dots{}
+@} htab_t;
+@end smallexample
+and then declare variables like this:
+@smallexample
+  static htab_t GTY ((param_is (union tree_node))) ict;
+@end smallexample
+
+@findex param@var{n}_is
+@findex use_param@var{n}
+@item param@var{n}_is (@var{type})
+@itemx use_param@var{n}
+
+In more complicated cases, the data structure might need to work on
+several different types, which might not necessarily all be pointers.
+For this, @code{param1_is} through @code{param9_is} may be used to
+specify the real type of a field identified by @code{use_param1} through
+@code{use_param9}.
+
+@findex use_params
+@item use_params
+
+When a structure contains another structure that is parameterized,
+there's no need to do anything special, the inner structure inherits the
+parameters of the outer one.  When a structure contains a pointer to a
+parameterized structure, the type machinery won't automatically detect
+this (it could, it just doesn't yet), so it's necessary to tell it that
+the pointed-to structure should use the same parameters as the outer
+structure.  This is done by marking the pointer with the
+@code{use_params} option.
+
+@findex deletable
+@item deletable
+
+@code{deletable}, when applied to a global variable, indicates that when
+garbage collection runs, there's no need to mark anything pointed to
+by this variable, it can just be set to @code{NULL} instead.  This is used
+to keep a list of free structures around for re-use.
+
+@findex if_marked
+@item if_marked ("@var{expression}")
+
+Suppose you want some kinds of object to be unique, and so you put them
+in a hash table.  If garbage collection marks the hash table, these
+objects will never be freed, even if the last other reference to them
+goes away.  GGC has special handling to deal with this: if you use the
+@code{if_marked} option on a global hash table, GGC will call the
+routine whose name is the parameter to the option on each hash table
+entry.  If the routine returns nonzero, the hash table entry will
+be marked as usual.  If the routine returns zero, the hash table entry
+will be deleted.
+
+The routine @code{ggc_marked_p} can be used to determine if an element
+has been marked already; in fact, the usual case is to use
+@code{if_marked ("ggc_marked_p")}.
+
+@findex mark_hook
+@item mark_hook ("@var{hook-routine-name}")
+
+If provided for a structure or union type, the given
+@var{hook-routine-name} (between double-quotes) is the name of a
+routine called when the garbage collector has just marked the data as
+reachable. This routine should not change the data, or call any ggc
+routine. Its only argument is a pointer to the just marked (const)
+structure or union.
+
+@findex maybe_undef
+@item maybe_undef
+
+When applied to a field, @code{maybe_undef} indicates that it's OK if
+the structure that this fields points to is never defined, so long as
+this field is always @code{NULL}.  This is used to avoid requiring
+backends to define certain optional structures.  It doesn't work with
+language frontends.
+
+@findex nested_ptr
+@item nested_ptr (@var{type}, "@var{to expression}", "@var{from expression}")
+
+The type machinery expects all pointers to point to the start of an
+object.  Sometimes for abstraction purposes it's convenient to have
+a pointer which points inside an object.  So long as it's possible to
+convert the original object to and from the pointer, such pointers
+can still be used.  @var{type} is the type of the original object,
+the @var{to expression} returns the pointer given the original object,
+and the @var{from expression} returns the original object given
+the pointer.  The pointer will be available using the @code{%h}
+escape.
+
+@findex ptr_alias
+@item ptr_alias (@var{type})
+
+When applied to a type, @code{ptr_alias} indicates that the GTY-ed
+type is an alias or synonym of the given @var{type}.
+
+@findex chain_next
+@findex chain_prev
+@findex chain_circular
+@item chain_next ("@var{expression}")
+@itemx chain_prev ("@var{expression}")
+@itemx chain_circular ("@var{expression}")
+
+It's helpful for the type machinery to know if objects are often
+chained together in long lists; this lets it generate code that uses
+less stack space by iterating along the list instead of recursing down
+it.  @code{chain_next} is an expression for the next item in the list,
+@code{chain_prev} is an expression for the previous item.  For singly
+linked lists, use only @code{chain_next}; for doubly linked lists, use
+both.  The machinery requires that taking the next item of the
+previous item gives the original item.  @code{chain_circular} is similar
+to @code{chain_next}, but can be used for circular single linked lists.
+
+@findex reorder
+@item reorder ("@var{function name}")
+
+Some data structures depend on the relative ordering of pointers.  If
+the precompiled header machinery needs to change that ordering, it
+will call the function referenced by the @code{reorder} option, before
+changing the pointers in the object that's pointed to by the field the
+option applies to.  The function must take four arguments, with the
+signature @samp{@w{void *, void *, gt_pointer_operator, void *}}.
+The first parameter is a pointer to the structure that contains the
+object being updated, or the object itself if there is no containing
+structure.  The second parameter is a cookie that should be ignored.
+The third parameter is a routine that, given a pointer, will update it
+to its correct new value.  The fourth parameter is a cookie that must
+be passed to the second parameter.
+
+PCH cannot handle data structures that depend on the absolute values
+of pointers.  @code{reorder} functions can be expensive.  When
+possible, it is better to depend on properties of the data, like an ID
+number or the hash of a string instead.
+
+@findex variable_size
+@item variable_size
+
+The type machinery expects the types to be of constant size.  When this
+is not true, for example, with structs that have array fields or unions,
+the type machinery cannot tell how many bytes need to be allocated at 
+each allocation.  The @code{variable_size} is used to mark such types.
+The type machinery then provides allocators that take a parameter 
+indicating an exact size of object being allocated.  
+
+For example,
+@smallexample
+struct GTY((variable_size)) sorted_fields_type @{
+  int len;
+  tree GTY((length ("%h.len"))) elts[1];
+@};
+@end smallexample
+
+Then the objects of @code{struct sorted_fields_type} are allocated in GC 
+memory as follows:
+@smallexample
+  field_vec = ggc_alloc_sorted_fields_type (size);
+@end smallexample
+
+@findex special
+@item special ("@var{name}")
+
+The @code{special} option is used to mark types that have to be dealt
+with by special case machinery.  The parameter is the name of the
+special case.  See @file{gengtype.c} for further details.  Avoid
+adding new special cases unless there is no other alternative.
+@end table
+
+@node GGC Roots
+@section Marking Roots for the Garbage Collector
+@cindex roots, marking
+@cindex marking roots
+
+In addition to keeping track of types, the type machinery also locates
+the global variables (@dfn{roots}) that the garbage collector starts
+at.  Roots must be declared using one of the following syntaxes:
+
+@itemize @bullet
+@item
+@code{extern GTY(([@var{options}])) @var{type} @var{name};}
+@item
+@code{static GTY(([@var{options}])) @var{type} @var{name};}
+@end itemize
+@noindent
+The syntax
+@itemize @bullet
+@item
+@code{GTY(([@var{options}])) @var{type} @var{name};}
+@end itemize
+@noindent
+is @emph{not} accepted.  There should be an @code{extern} declaration
+of such a variable in a header somewhere---mark that, not the
+definition.  Or, if the variable is only used in one file, make it
+@code{static}.
+
+@node Files
+@section Source Files Containing Type Information
+@cindex generated files
+@cindex files, generated
+
+Whenever you add @code{GTY} markers to a source file that previously
+had none, or create a new source file containing @code{GTY} markers,
+there are three things you need to do:
+
+@enumerate
+@item
+You need to add the file to the list of source files the type
+machinery scans.  There are four cases:
+
+@enumerate a
+@item
+For a back-end file, this is usually done
+automatically; if not, you should add it to @code{target_gtfiles} in
+the appropriate port's entries in @file{config.gcc}.
+
+@item
+For files shared by all front ends, add the filename to the
+@code{GTFILES} variable in @file{Makefile.in}.
+
+@item
+For files that are part of one front end, add the filename to the
+@code{gtfiles} variable defined in the appropriate
+@file{config-lang.in}.  For C, the file is @file{c-config-lang.in}.
+Headers should appear before non-headers in this list.
+
+@item
+For files that are part of some but not all front ends, add the
+filename to the @code{gtfiles} variable of @emph{all} the front ends
+that use it.
+@end enumerate
+
+@item
+If the file was a header file, you'll need to check that it's included
+in the right place to be visible to the generated files.  For a back-end
+header file, this should be done automatically.  For a front-end header
+file, it needs to be included by the same file that includes
+@file{gtype-@var{lang}.h}.  For other header files, it needs to be
+included in @file{gtype-desc.c}, which is a generated file, so add it to
+@code{ifiles} in @code{open_base_file} in @file{gengtype.c}.
+
+For source files that aren't header files, the machinery will generate a
+header file that should be included in the source file you just changed.
+The file will be called @file{gt-@var{path}.h} where @var{path} is the
+pathname relative to the @file{gcc} directory with slashes replaced by
+@verb{|-|}, so for example the header file to be included in
+@file{cp/parser.c} is called @file{gt-cp-parser.c}.  The
+generated header file should be included after everything else in the
+source file.  Don't forget to mention this file as a dependency in the
+@file{Makefile}!
+
+@end enumerate
+
+For language frontends, there is another file that needs to be included
+somewhere.  It will be called @file{gtype-@var{lang}.h}, where
+@var{lang} is the name of the subdirectory the language is contained in.
+
+Plugins can add additional root tables.  Run the @code{gengtype}
+utility in plugin mode as @code{gengtype -P @var{gt-pluginout.h} -r
+@var{gtype.state} @var{plugin*.c}} with your plugin files
+@var{plugin*.c} using @code{GTY} to generate the @var{gt-pluginout.h}
+file.  The @var{gtype.state} is usually in the plugin directory.
+
+
+@node Generating GGC code with gengtype
+@section How to run the gengtype generator.
+@cindex garbage collector, generation, gengtype
+@findex gengtype
+
+The @code{gengtype} utility (which may be installed as
+@code{gcc-gengtype} or some other name on your system) is a C code
+generator program.  It generates suitable marking and type-walking C
+routines for GGC.  Generated GC marking routines ensure that every
+live data is ultimately marked, so that GGC can delete, at the end of
+its @code{ggc_collect} function, every non-marked data (which is
+unreachable and dead).  Generated PCH type-walking routines are used
+for ``compilation'' of header files @var{*.h} into a @var{*.gch}
+file.  The @code{gengtype} utility is used when building GCC itself
+from its source tree, and also for plugins dealing with their own
+GTY-ed data.
+
+The @code{gengtype} utility is run once specially when compiling GCC
+itself.  It parses many GCC source files (mostly internal GCC headers
+declaring @code{GTY}-ed types and internal GCC files declaring
+@code{GTY}-ed variables). It saves its state in a persistent textual
+file @file{gtype.state}.  This file has a format tied to a particular
+GCC release and configuration.  This @file{gtype.state} file should be
+parsed only by @code{gengtype} (of the same version which has
+generated it).  Following GNU usage, @code{gengtype} accepts the usual
+@code{--version} or @code{-V} and @code{--help} arguments.  It also
+accepts @code{--verbose} or @code{-v} to show what it is doing, and
+@code{--debug} or @code{-D} for debugging purposes.  It may dump every
+internal data in human readable form with @code{--dump} or @code{-d}.
+The @code{--backupdir} @var{directory} or @code{-B} @var{directory}
+specifies a back-up directory used to store, as e.g. @file{gt-*.h~}
+files, the previous version of generated C files.
+
+During GCC build process, a file @file{gtyp-input.list} is built and
+contains a long list of files to be parsed.  Then, @code{gengtype} is
+run once to generate its state with @code{gengtype -S
+@file{source-directory} -I @file{gtyp-input.list} -w
+@file{gtype.state}}.  Immediately after, it is re-run to read its just
+generated state and generate @file{gt*.[ch]} files with @code{gengtype
+-r @file{gtype.state}}.
+
+Plugin developers using @code{GTY} in their plugin source code should
+run @code{gengtype -P @var{gt-pluginout.h} -r @file{gtype.state}
+@var{plugin*.c}}
+
+
+@node Invoking the garbage collector
+@section How to invoke the garbage collector
+@cindex garbage collector, invocation
+@findex ggc_collect
+
+The GCC garbage collector GGC is only invoked explicitly. In contrast
+with many other garbage collectors, it is not implicitly invoked by
+allocation routines when a lot of memory has been consumed. So the
+only way to have GGC reclaim storage it to call the @code{ggc_collect}
+function explicitly. This call is an expensive operation, as it may
+have to scan the entire heap. Beware that local variables (on the GCC
+call stack) are not followed by such an invocation (as many other
+garbage collectors do): you should reference all your data from static
+or external @code{GTY}-ed variables, and it is advised to call
+@code{ggc_collect} with a shallow call stack. The GGC is an exact mark
+and sweep garbage collector (so it does not scan the call stack for
+pointers). In practice GCC passes don't often call @code{ggc_collect}
+themselves, because it is called by the pass manager between passes.

[-- Attachment #3: cumulatedpatch7_doc-gengtypethird-r164437.diff.gz --]
[-- Type: application/octet-stream, Size: 43782 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 1/7 [declprog]
  2010-09-21 19:41 gengtype improvements for plugins, thirdround! patch 1/7 [declprog] Basile Starynkevitch
  2010-09-21 22:07 ` gengtype improvements for plugins, thirdround! patch 2/7 [verbosity] Basile Starynkevitch
@ 2010-09-22 11:08 ` Laurynas Biveinis
  1 sibling, 0 replies; 28+ messages in thread
From: Laurynas Biveinis @ 2010-09-22 11:08 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

The indentation of the patch is still (glaringly) wrong in a
significant number of places.

-/* the generated plugin output name & file */
+
+/* the generated plugin output file and name.  */

The

+static void
+print_usage (void)
+{
+    printf ("Usage: %s\n", progname);

Wrong indentation.

+/* Parse the program options using getopt_long... */
+static void
+parse_program_options (int argc, char**argv)
+{
+    int opt = -1;
+    while ((opt = getopt_long (argc, argv, "hVdP:S:I:w:r:D",
+			       gengtype_long_options, NULL)) >= 0)
+    {
+	switch (opt)
+	{
+	case 'h': /* --help */
+	    print_usage ();
+	    break;
+	case 'V': /* --version */
+	    print_version ();
+	    break;
+	case 'd': /* --dump */
+      do_dump = 1;
+	    break;

Wrong indentation...

+  /*** Parse the input list and the input files.  ***/

/* Parse ... */

+      for (i = 0; i < num_gt_files; i++) {
+	parse_file (gt_files[i]);
+	DBGPRINTF ("parsed file #%d %s", (int) i, gt_files[i]);
+      }

Wrong formatting.

+      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]);
+
+      if (hit_error)
+	return 1;
+
+      plugin_output = create_file ("GCC", plugin_output_filename);
+      DBGPRINTF ("created plugin_output %p named %s",
+		 (void*) plugin_output, plugin_output->name);
+    }
+  else
+    { /* No plugin files, we are in normal mode.  */
+      if (!srcdir)
+	fatal ("gengtype needs a source directory in normal mode");
+    }

Wrong formatting.

+  /* The call to set_gc_used may indirectly call find_param_structure
+     hence enlarge the param_structs list of types.  So it should
+     happen before writing the state.  */
   set_gc_used (variables);

Can you explain this comment? I mean, *all* source processing things
must happen before writing the state, so isn't the comment too
obvious?

+#endif /*ENABLE_CHECKING*/

Space after /* and before */

> gcc/ChangeLog entry:
>
> 2010-09-20  Jeremie Salvucci  <jeremie.salvucci@free.fr>
>            Basile Starynkevitch  <basile@starynkevitch.net>
>
>        * gengtype.c:  Include getopt.h and version.h.
>
>        (lang_bitmap, struct outf, outf_p)
>        (get_output_file_with_visibility, oprintf): Definitions moved to
>        gengtype.h
>        (output_files, header_file, srcdir, srcdir_len, this_file,
> do_dump): No more static variables.
>        (do_debug): New.
>        (dbgprint_count_type_at): Added new function.
>        (gengtype_long_options): New.
>        (print_usage, print_version, parse_program_options): New.
>        (main): Call parse_program_options, and removed old option
>        handling code.  Added some debug output.
>
>        * gengtype.h:  Updated copyright year.
>        (lang_bitmap, struct outf, outf_p, header_file, oprintf)
>        (get_output_file_with_visibility, srcdir, srcdir_len, do_dump):
>        Moved from gengtype.c to here.
>        (do_debug, read_state_filename, write_state_filename): New
> variables. (DBGPRINTF, DBGPRINT_COUNT_TYPE): New macros.
>
>        * Makefile.in:
>        (REVISION): Always defined.
>        (version.o): Removed ifdef REVISION_c.
>        (s-gtype): Pass arguments to build/gengtype program.
>        (build/version.o): Added building rule.
>        (build/gengtype$(build_exeext)): Added build/version.o.


-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 2/7 [verbosity]
  2010-09-21 22:07 ` gengtype improvements for plugins, thirdround! patch 2/7 [verbosity] Basile Starynkevitch
  2010-09-21 22:43   ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Basile Starynkevitch
@ 2010-09-22 11:11   ` Laurynas Biveinis
  1 sibling, 0 replies; 28+ messages in thread
From: Laurynas Biveinis @ 2010-09-22 11:11 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

2010/9/21 Basile Starynkevitch <basile@starynkevitch.net>:
> In addition of verbose messages, we added a tiny but useful feature to
> gengtype. When given a backup directory thru the -B program option and
> when it is generating a file gt-foo.h, gengtype renames the old
> version into the backup directory so that the user could compare the
> old version with the current one.  Verbosity & backing up of old files
> go together (in verbose mode, the renaming is told to the
> user). Backing up is no longer by default.  Per Laurynas' wish, it
> should be enabled by its program option.

Although I agree that if backups go in, they should have their own
switch, my wish was to remove the backup feature altogether. Merits of
backups aside, since now backup is independent from verbosity, it
should be submitted in a separate patch.

@@ -1511,8 +1520,15 @@ static void
 set_gc_used (pair_p variables)
 {
   pair_p p;
+  int nbvars = 0;
   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);

Indentation is wrong.

+      if (!is_file_equal (of))
+	{

Indentation is wrong.

@@ -2894,11 +2941,26 @@ write_types (outf_p output_header, type_
 	  {
 	    type_p ss;
 	    for (ss = s->u.s.lang_struct; ss; ss = ss->next)
+	      {
+		nbfun++;
+		DBGPRINTF ("writing func #%d lang_struct ss @ %p '%s'",
+			   nbfun, (void*) ss, ss->u.s.tag);
 	      write_func_for_structure (s, ss, NULL, wtd);
 	  }
+	  }
 	else
+	  {
+	    nbfun++;
+	    DBGPRINTF ("writing func #%d struct s @ %p '%s'",
+		       nbfun, (void*) s, s->u.s.tag);
 	  write_func_for_structure (s, s, NULL, wtd);
       }
+      }

Indentation is wrong.

+	  DBGPRINTF ("write_enum_defn s %p #%d is unionorstruct tagged %s",

union or struct. Also indentation is wrong in the code surrounding this line.

> 2010-09-20  Jeremie Salvucci  <jeremie.salvucci@free.fr>
>            Basile Starynkevitch  <basile@starynkevitch.net>
>
>        * gengtype.c (verbosity_level, backup_dir): Added variables.
>        (set_gc_used): Count variables for verbosity.
>        (close_output_files): Backing up files, counting written ones
>        verbosily.
>        (write_types): Count emitted functions for verbosity. Added
>        debug messages.
>        (write_enum_defn): Count structures for verbosity. Added debug
>        messages.
>        (gengtype_long_options): Added "verbose".
>        (print_usage): Ditto.
>        (main): Verbose display of parsed files.
>
>        * gengtype.h (verbosity_level): Added declaration.

-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 3/7 [inputfile]
  2010-09-21 22:43   ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Basile Starynkevitch
  2010-09-22  0:29     ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Basile Starynkevitch
@ 2010-09-22 12:05     ` Laurynas Biveinis
  2010-10-18 17:21     ` gengtype patch removing location_s Basile Starynkevitch
  2 siblings, 0 replies; 28+ messages in thread
From: Laurynas Biveinis @ 2010-09-22 12:05 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

2010/9/21 Basile Starynkevitch <basile@starynkevitch.net>:
> The gengtype-lex.l & gengtype-parse.c files need to include fatal.h
> because it is used from gengtype.h

OK. In that case bonus points for a follow-up patch that includes
fatal.h from gengtype.h and updates Makefile accordingly :)

> Since struct location_s is no longer used inside GCC, the hack in
> new_structure to handle it is removed.

This is excellent, but it really should be a separate patch.

-/* 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;

Please remove the comment part after semicolon (the comment should
explain plugin_files definition, the numer of output files is
irrelevant to that definition)

-/* 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)

Drop the empty line between the comment and the definition.

@@ -4424,89 +4384,142 @@ print_version (void)
 static void
 parse_program_options (int argc, char**argv)
 {
-    int opt = -1;
+  int opt = -1;
[...two hundred lines or so of indentation changes follow...]

These parse_program_options changes only fix indentation in the first
patch, so please fix the first patch and this will disappear. If there
were any real code changes here, I couldn't tell through all those
formatting changes.

-      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]));
+	}

Same here. (Here at least I can see the non-formatting code change)

+	    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);

Here and in similar following fragments, please add { } on if and else
clauses (too many visual lines).

As far as I'm concerned, the non-magic patch would be OK with these changes.

> ########## gcc/ChangeLog entry is
> 2010-09-20  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): Remove location_s hack.
>        (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.

-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 4/7 [filerules]
  2010-09-22  0:29     ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Basile Starynkevitch
  2010-09-22  1:50       ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Basile Starynkevitch
@ 2010-09-22 12:06       ` Laurynas Biveinis
  1 sibling, 0 replies; 28+ messages in thread
From: Laurynas Biveinis @ 2010-09-22 12:06 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

+/* Special file rules action for handling *.c source files using
+ * get_file_gtfilename to compute their output_name and
+ * get_file_basename to compute their for_name.  The output_name is
+ * gt-<LANG>-<BASE>.h for language specific source files, and
+ * gt-<BASE>.h for common source files.  */

Here and everywhere else, please drop the leading columns of '*'.
Otherwise, the patch looks OK to me. (I was hoping for net code size
savings here, but it looks like regexps only balloon it. Anyway, I
still like the patch for its data-driveness).

2010/9/21 Basile Starynkevitch <basile@starynkevitch.net>:
> 2010-09-21  Jeremie Salvucci  <jeremie.salvucci@free.fr>
>            Basile Starynkevitch  <basile@starynkevitch.net>
>
>        * gengtype.c: Include xregex.h and obstack.h
>        Added comments about role of get_output_file_with_visibility and
>        our regexpr machinery.
>        (frul_actionrout_t, struct file_rule_st): New.
>        (hader_dot_h_frul, source_dot_c_frul): New functions.
>        (NULL_REGEX,  NULL_FRULACT): New.
>        (files_rules): New.
>        (matching_file_name_substitute): New function.
>        (get_output_file_with_visibility): Updated comments and rewritten
>        to use the new files_rules machinery.

-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 5/7 [typedopt]
  2010-09-22  1:50       ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Basile Starynkevitch
  2010-09-22  1:58         ` gengtype improvements for plugins, thirdround! patch 6/7 [wstate] Basile Starynkevitch
@ 2010-09-22 12:13         ` Laurynas Biveinis
  2010-09-23 19:17           ` Basile Starynkevitch
  1 sibling, 1 reply; 28+ messages in thread
From: Laurynas Biveinis @ 2010-09-22 12:13 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

2010/9/21 Basile Starynkevitch <basile@starynkevitch.net>:

@@ -1082,14 +1018,11 @@ adjust_field_rtx_def (type_p t, options_
   /* Create a type to represent the various forms of SYMBOL_REF_DATA.  */
   {
     pair_p sym_flds;
-
-    sym_flds = create_field (NULL, tree_tp, "rt_tree");
-    sym_flds->opt = create_option (nodot, "default", "");
-
-    sym_flds = create_field (sym_flds, constant_tp, "rt_constant");
-    sym_flds->opt = create_option (nodot, "tag", "1");
-
-    symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
+     sym_flds = create_field (NULL, tree_tp, "rt_tree");
+    sym_flds->opt = create_string_option (nodot, "default", "");
+     sym_flds = create_field (sym_flds, constant_tp, "rt_constant");
+    sym_flds->opt = create_string_option (nodot, "tag", "1");
+     symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
 				     &lexer_line, sym_flds, NULL);
   }
   for (i = 0; i < NUM_RTX_CODE; i++)

Indentation is wrong.

@@ -1228,12 +1161,10 @@ adjust_field_rtx_def (type_p t, options_
       ftag = xstrdup (rtx_name[i]);
       for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
 	ftag[nmindex] = TOUPPER (ftag[nmindex]);
-
-      flds = create_field (flds, substruct, "");
-      flds->opt = create_option (nodot, "tag", ftag);
+       flds = create_field (flds, substruct, "");
+      flds->opt = create_string_option (nodot, "tag", ftag);
     }
-
-  return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
+   return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
 }

 /* Handle `special("tree_exp")'.  This is a special case for

Indentation is wrong.

 }
-
-/* Set the gc_used field of T to LEVEL, and handle the types it references.  */
-
+ /* Set the gc_used field of T to LEVEL, and handle the types it
references.  */
 static void
 set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
 {

Comment should start on the first column.

-  d->needs_cast_p = false;
+   d->needs_cast_p = false;

Please do not break indentation in the code you don't touch :)

-	/* Some things may also be defined in the structure's options.  */
+ 	/* Some things may also be defined in the structure's options.  */

Please drop.

-	    d->reorder_fn = NULL;
+ 	    d->reorder_fn = NULL;

Likewise.

 		use_param_p = 1;
-
 	    if (skip_p)

Likewise.

@@ -2956,18 +2893,20 @@ write_func_for_structure (type_p orig_s,

   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
-
-  for (opt = s->u.s.opt; opt; opt = opt->next)
-    if (strcmp (opt->name, "chain_next") == 0)
-      chain_next = opt->info;
-    else if (strcmp (opt->name, "chain_prev") == 0)
-      chain_prev = opt->info;
-    else if (strcmp (opt->name, "chain_circular") == 0)
-      chain_circular = opt->info;
-    else if (strcmp (opt->name, "mark_hook") == 0)
-      mark_hook_name = opt->info;
-
-  if (chain_prev != NULL && chain_next == NULL)
+   for (opt = s->u.s.opt; opt; opt = opt->next)
[...continues...]

Indentation is wrong.

+       for (o = v->opt; o; o = o->next)
+	if (strcmp (o->name, "length") == 0
+		       && o->kind == OPTION_STRING)
+	  length = o->info.string;

Indentation is wrong.

+	else if (strcmp (o->name, "if_marked") == 0
+		       && o->kind == OPTION_STRING)
+	  if_marked = o->info.string;
+       if (if_marked == NULL)

And wrong.

-
-  /* We assemble the field list in reverse order.  */
+   /* We assemble the field list in reverse order.  */

Again, you are not changing anything here except that you break indentation.

+	case OPTION_NONE:
+	  fatal ("corrupted option %p: %s", (void*) o, o->name);

Insert default label too between these two lines.

+  TYPE_UNION,		/* Type for GTY-ed discriminated
+			   union-s.  */
+  TYPE_POINTER,		/* Pointer type to GTY-ed type.  */
+  TYPE_ARRAY,		/* Array of GTY-ed types.  */

Align TYPE_POINTER comment.

+  OPTION_TYPE,			/* A type-valued option.  */
+  OPTION_NESTED			/* Option data for 'nested_ptr'.  */

Align OPTION_NESTED comment.

+/* A way to pass data through to the output end.  */
+struct options {
+  struct options *next;		/* next option of the same pair.  */
+  const char *name;		/* GTY option name.  */
+  enum option_kind kind;		/* disciminating option kind.  */
+  /* the union below is discriminated by the 'kind' field above.  */
+  union {
+    const char* string;		    /* When OPTION_STRING.  */
+    type_p type;		    /* When OPTION_TYPE.  */
+    struct nested_ptr_data* nested; /* when OPTION_NESTED.  */
+  } info;
+};

Align all the comments.

+  /* State number used when writing & reading the persistent state.  A
+     type with a positive number has already been written.  For ease
+     of debugging, newly allocated types have a unique negative
+     number.  */
+  int state_number;

Should be a part of patch 7 in the series but I'm inclined to let this one slip.

+    /* TYPE__NONE is impossible.  */

TYPE_NONE

+    case TYPE_NONE:
+      fatal ("type_lineloc on bad zeroed type %p", (const void*)ty);

Move to the end of switch, add default label too.

-/* absdecl: type '*'*
+ /* absdecl: type '*'*

Column 1.

-/* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */
+ /* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */

Likewise.


> 2010-09-21  Jeremie Salvucci  <jeremie.salvucci@free.fr>
>            Basile Starynkevitch  <basile@starynkevitch.net>
>
>        * gengtype.c
>        (enum typekind, struct options, struct nested_ptr_data)
>        (struct pair, NUM_PARAM, enum gc_used_enum, struct type, UNION_P)
>        (UNION_OR_STRUCT_P): Moved into gengtype.h
>
>        (string_type, scalar_nonchar, scalar_char): Removed static and
>        added state_number fake value.
>        (typedefs, structures, param_structs, variables): Removed static.
>        (create_option): Removed function.
>        (create_string_option, create_type_option, created_nested_option):
>        New.
>        (created_nested_ptr_option, create_optional_field_)
>        (adjust_field_rtx_def, adjust_field_tree_exp): Updated accordingly.
>        (adjust_field_type, process_gc_options, output_mangled_typename)
>        (walk_type, write_func_for_structure, write_types, write_roots)
>        (note_def_vec, dump_options): Ditto.  Access to options is
>        protected by tests on their kind.
>
>        * gengtype.h: Added a lot of comments.  Moved many definitions
>        from gengtype.h and updated them.
>        (typedef, structures, param_structs, variables): Declared extern.
>        (enum typekind): Moved from gengtype.c and added TYPE_NONE.
>        (enum option_kind): New.
>        (struct options): Added discriminating kind, and info union.
>        (struct nested_ptr_data): Moved from gengtype.c.
>        (create_string_option, create_type_option, create_nested_option):
>        New.
>        (struct pair, enum_gc_used_enum, NUM_PARAM): Moved
>        from gengtype.c and commented more.
>        (struct_type): Ditto, added state_number.
>        (string_type, scalar_nonchar, scalar_char): Moved from gengtype.c.
>        (type_lineloc): New function.
>        (UNION_P, UNION_OR_STRUCT_P): Moved from gengtype.c and commented
>        more.
>        (struct outf): Indented better.
>
>        * gengtype-parse.c (str_optvalue_opt, type_optvalue, option):
>        Updated for our discriminated option.
>
> ################################################################
>
> Comments and/or Ok for trunk are welcome!
>
> Cheers.
>
> --
> 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 mine, sont seulement les miennes} ***
>



-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 6/7 [wstate]
  2010-09-22  1:58         ` gengtype improvements for plugins, thirdround! patch 6/7 [wstate] Basile Starynkevitch
  2010-09-22  2:16           ` Basile Starynkevitch
@ 2010-09-22 14:08           ` Laurynas Biveinis
  1 sibling, 0 replies; 28+ messages in thread
From: Laurynas Biveinis @ 2010-09-22 14:08 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

2010/9/21 Basile Starynkevitch <basile@starynkevitch.net>:

+/* Fatal message while reading state.  */
+#define fatal_reading_state(Tok,Msg)  do {		\
...

+#define fatal_reading_state_printf(Tok,Fmt,...) do {	\

Would you mind doing functions instead of function-like macros here?

+/* Write the gc_used information.  */
+static void
+write_state_gc_used (enum gc_used_enum gus)
+{
+  switch (gus)
+    {
+    case GC_UNUSED:
+      fprintf (state_file, " gc_unused");
+      break;
+    case GC_USED:
+      fprintf (state_file, " gc_used");
+      break;
+    case GC_MAYBE_POINTED_TO:
+      fprintf (state_file, " gc_maybe_pointed_to");
+      break;
+    case GC_POINTED_TO:
+      fprintf (state_file, " gc_pointed_to");
+      break;
+    }
+}

Please add default: ggc_unreachable() or something in that spirit.

+void
+write_state (const char *state_path)
+{
+  long statelen = 0;
+  time_t now = 0;
+  char *temp_state_path = NULL;
+  char tempsuffix[40];
+  time (&now);
+
+  /* We write a unique temporary file which is renamed when complete
+   * only.  So even if gengtype is interrupted, the written state file
+   * won't be partially written, since the temporary file is not yet
+   * renamed in that case....  */

case.  */

+  /* The writing of structures probably wrote a lot, so we flush to
+     disk and check for errors, e.g. to catch disk full situations a
+     bit earlier.  */
+  if (fflush (state_file) || ferror (state_file))
+    fatal ("output error when writing state file %s [%s]",
+	   temp_state_path, xstrerror (errno));

IMHO just drop this. IMHO the benefit of early abort is too
insignificant and the less code the better.

+/*****************************************************************
+ * End of writing routines!  The corresponding reading routines follow.
+ *****************************************************************/

I'm against ASCII art of stars in general in comments, and this one
has too few stars to match the text.

@@ -634,11 +644,12 @@ find_structure (const char *name, int is
     if (strcmp (name, s->u.s.tag) == 0
 	&& UNION_P (s) == isunion)
       return s;
-
-  s = XCNEW (struct type);
+   s = XCNEW (struct type);

Broke indentation.

@@ -703,8 +718,10 @@ create_array (type_p t, const char *len)
 {
   type_p v;

-  v = XCNEW (struct type);
+   v = XCNEW (struct type);

Likewise.

@@ -4787,8 +4806,12 @@ main (int argc, char **argv)
   static struct fileloc pos = { NULL, 0 };
   outf_p output_header;

-  /* Mandatory common initializations.  */
+   /* Mandatory common initializations.  */

Likewise.

+  /* We write the state here.  It could eventually happen that the
+     state file is written after some plugin files have been parsed,
+     perhaps to enlarge the state file for other plugins needs.  But
+     this is an uncommon scenario.  */

Probably not the best place to discuss what may or may not happen in
the future. More like wiki material.

+      /* We definitely don't want to write a state file if some error
+	 occurred while reading input files processed by gengtype,
+	 because we only want to write sane state files!  */

Redundant.

> 2010-09-21  Jeremie Salvucci  <jeremie.salvucci@free.fr>
>            Basile Starynkevitch  <basile@starynkevitch.net>
>
>        * gengtype-state.c: Added new file.
>
>        * gengtype.c:
>        (type_count): New static variable.
>        (new_structure, find_structure, find_param_structure)
>        (create_pointer, create_array): Use type_count for initializing
>        state_number field of types.
>        (main): Initialize state_number in predefined types.  Call
>        read_state and write_state appropriately.  Show the
>        type_count when verbose.
>
>        * gengtype.h: Updated comment about per-language directories.
>        (read_state, write_state): New declarations.
>
>        * Makefile.in (MOSTLYCLEANFILES): Added gtype.state.
>        (GENGTYPE_FLAGS): New variable.
>        (s-gtype): Runs gengtype twice, once to write the gtype.state,
>        once to read it.
>        (build/gengtype-state.o): New target.
>        (build/gengtype): Use it.
>        (mostlyclean): Remove gtype.state

-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 7/7 [doc]
  2010-09-22  3:03             ` gengtype improvements for plugins, thirdround! patch 7/7 [doc] Basile Starynkevitch
@ 2010-09-22 14:17               ` Laurynas Biveinis
  0 siblings, 0 replies; 28+ messages in thread
From: Laurynas Biveinis @ 2010-09-22 14:17 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

The patch7_doc-relto06.diff file size increased four times since the
last submission. Are you sure you sent the correct patch?

-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 5/7 [typedopt]
  2010-09-22 12:13         ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Laurynas Biveinis
@ 2010-09-23 19:17           ` Basile Starynkevitch
  2010-09-23 19:29             ` Diego Novillo
  0 siblings, 1 reply; 28+ messages in thread
From: Basile Starynkevitch @ 2010-09-23 19:17 UTC (permalink / raw)
  To: Laurynas Biveinis, gcc-patches

On Wed, Sep 22, 2010 at 05:46:29AM +0300, Laurynas Biveinis wrote:


A big and warm thanks to Laurynas for your review and for taking time
to read our patch. 

However, I believe that gengtype is misindented from the start, and
this explains most of my indentation issues. Please read
http://gcc.gnu.org/ml/gcc/2010-09/msg00448.html for details.


> 2010/9/21 Basile Starynkevitch <basile@starynkevitch.net>:
> 
> @@ -1082,14 +1018,11 @@ adjust_field_rtx_def (type_p t, options_
>    /* Create a type to represent the various forms of SYMBOL_REF_DATA.  */
>    {
>      pair_p sym_flds;
> -
> -    sym_flds = create_field (NULL, tree_tp, "rt_tree");
> -    sym_flds->opt = create_option (nodot, "default", "");
> -
> -    sym_flds = create_field (sym_flds, constant_tp, "rt_constant");
> -    sym_flds->opt = create_option (nodot, "tag", "1");
> -
> -    symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
> +     sym_flds = create_field (NULL, tree_tp, "rt_tree");
> +    sym_flds->opt = create_string_option (nodot, "default", "");
> +     sym_flds = create_field (sym_flds, constant_tp, "rt_constant");
> +    sym_flds->opt = create_string_option (nodot, "tag", "1");
> +     symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1,
>  				     &lexer_line, sym_flds, NULL);
>    }
>    for (i = 0; i < NUM_RTX_CODE; i++)
> 
> Indentation is wrong.
> 
> @@ -1228,12 +1161,10 @@ adjust_field_rtx_def (type_p t, options_
>        ftag = xstrdup (rtx_name[i]);
>        for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
>  	ftag[nmindex] = TOUPPER (ftag[nmindex]);
> -
> -      flds = create_field (flds, substruct, "");
> -      flds->opt = create_option (nodot, "tag", ftag);
> +       flds = create_field (flds, substruct, "");
> +      flds->opt = create_string_option (nodot, "tag", ftag);
>      }
> -
> -  return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
> +   return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
>  }
> 
>  /* Handle `special("tree_exp")'.  This is a special case for
> 
> Indentation is wrong.
> 
>  }
> -
> -/* Set the gc_used field of T to LEVEL, and handle the types it references.  */
> -
> + /* Set the gc_used field of T to LEVEL, and handle the types it
> references.  */
>  static void
>  set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
>  {
> 
> Comment should start on the first column.
> 
> -  d->needs_cast_p = false;
> +   d->needs_cast_p = false;
> 
> Please do not break indentation in the code you don't touch :)
> 
>    memset (&d, 0, sizeof (d));
>    d.of = get_output_file_for_structure (s, param);
> -
> -  for (opt = s->u.s.opt; opt; opt = opt->next)
> -    if (strcmp (opt->name, "chain_next") == 0)
> -      chain_next = opt->info;
> -    else if (strcmp (opt->name, "chain_prev") == 0)
> -      chain_prev = opt->info;
> -    else if (strcmp (opt->name, "chain_circular") == 0)
> -      chain_circular = opt->info;
> -    else if (strcmp (opt->name, "mark_hook") == 0)
> -      mark_hook_name = opt->info;
> -
> -  if (chain_prev != NULL && chain_next == NULL)
> +   for (opt = s->u.s.opt; opt; opt = opt->next)
> [...continues...]
> 
> Indentation is wrong.
> 
> +       for (o = v->opt; o; o = o->next)
> +	if (strcmp (o->name, "length") == 0
> +		       && o->kind == OPTION_STRING)
> +	  length = o->info.string;
> 
> Indentation is wrong.
> 
> +	else if (strcmp (o->name, "if_marked") == 0
> +		       && o->kind == OPTION_STRING)
> +	  if_marked = o->info.string;
> +       if (if_marked == NULL)
> 
> And wrong.
> 
> -
> -  /* We assemble the field list in reverse order.  */
> +   /* We assemble the field list in reverse order.  */
> 
> Again, you are not changing anything here except that you break indentation.
> 
> +	case OPTION_NONE:
> +	  fatal ("corrupted option %p: %s", (void*) o, o->name);
> 
> Insert default label too between these two lines.
> 
> +  TYPE_UNION,		/* Type for GTY-ed discriminated
> +			   union-s.  */
> +  TYPE_POINTER,		/* Pointer type to GTY-ed type.  */
> +  TYPE_ARRAY,		/* Array of GTY-ed types.  */
> 
> Align TYPE_POINTER comment.
> 
> +  OPTION_TYPE,			/* A type-valued option.  */
> +  OPTION_NESTED			/* Option data for 'nested_ptr'.  */
> 
> Align OPTION_NESTED comment.
> 
> +/* A way to pass data through to the output end.  */
> +struct options {
> +  struct options *next;		/* next option of the same pair.  */
> +  const char *name;		/* GTY option name.  */
> +  enum option_kind kind;		/* disciminating option kind.  */
> +  /* the union below is discriminated by the 'kind' field above.  */
> +  union {
> +    const char* string;		    /* When OPTION_STRING.  */
> +    type_p type;		    /* When OPTION_TYPE.  */
> +    struct nested_ptr_data* nested; /* when OPTION_NESTED.  */
> +  } info;
> +};
> 
> Align all the comments.


Regarding indentation issues in gengtype, please read
http://gcc.gnu.org/ml/gcc/2010-09/msg00448.html

I thanks warmly Laurynas for reading & commenting my patches, but I
need *specific* and *detailed* help on indentation, as detailed in the
message referenced above.  The best case for me is to be able to
submit a preliminary indentation patch, [option 1 of email
http://gcc.gnu.org/ml/gcc/2010-09/msg00448.html] which would only
change the indentation of gengtype.c & gengtype.h.  But I need
approval on the idea of submitting an indentation-only patch (this is
against GCC habits).

Only once indentation issues are settled would I be able to work on
the bulk of Laurynas comments. I put many hours of indentation efforts
in vain in these patches, and I strongly believe that it is because
the original (ie current trunk) gengtype.[ch] is badly indented, so I
don't know if I should perpetuate the indentation errors in gengtype
or correct them. (I did a mix of both).



Cheers.


-- 
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} ***

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 5/7 [typedopt]
  2010-09-23 19:17           ` Basile Starynkevitch
@ 2010-09-23 19:29             ` Diego Novillo
  2010-09-23 19:39               ` Richard Guenther
  0 siblings, 1 reply; 28+ messages in thread
From: Diego Novillo @ 2010-09-23 19:29 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: Laurynas Biveinis, gcc-patches

On Thu, Sep 23, 2010 at 10:07, Basile Starynkevitch
<basile@starynkevitch.net> wrote:

> However, I believe that gengtype is misindented from the start, and
> this explains most of my indentation issues. Please read
> http://gcc.gnu.org/ml/gcc/2010-09/msg00448.html for details.

If gengtype is misindented, please submit a separate patch fixing
indentation issues.  Don't mix the two things in one patch.  Your
changes are sufficiently big already.


Diego.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype improvements for plugins, thirdround! patch 5/7 [typedopt]
  2010-09-23 19:29             ` Diego Novillo
@ 2010-09-23 19:39               ` Richard Guenther
  0 siblings, 0 replies; 28+ messages in thread
From: Richard Guenther @ 2010-09-23 19:39 UTC (permalink / raw)
  To: Diego Novillo; +Cc: Basile Starynkevitch, Laurynas Biveinis, gcc-patches

On Thu, Sep 23, 2010 at 4:14 PM, Diego Novillo <dnovillo@google.com> wrote:
> On Thu, Sep 23, 2010 at 10:07, Basile Starynkevitch
> <basile@starynkevitch.net> wrote:
>
>> However, I believe that gengtype is misindented from the start, and
>> this explains most of my indentation issues. Please read
>> http://gcc.gnu.org/ml/gcc/2010-09/msg00448.html for details.
>
> If gengtype is misindented, please submit a separate patch fixing
> indentation issues.  Don't mix the two things in one patch.  Your
> changes are sufficiently big already.

And note that using GNU indent is not going to produce something
that is free of indentation issues.

Usual practice is to fix indentation issues in the code snippets you
are changing anyway.

Richard.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* gengtype patch removing location_s
  2010-09-21 22:43   ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Basile Starynkevitch
  2010-09-22  0:29     ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Basile Starynkevitch
  2010-09-22 12:05     ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Laurynas Biveinis
@ 2010-10-18 17:21     ` Basile Starynkevitch
  2010-10-19  6:57       ` Laurynas Biveinis
  2 siblings, 1 reply; 28+ messages in thread
From: Basile Starynkevitch @ 2010-10-18 17:21 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 866 bytes --]

On Tue, 21 Sep 2010 21:12:17 +0200
Basile Starynkevitch <basile@starynkevitch.net> wrote:
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01709.html

and Laurynas latter replied in http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01742.html
>> Since struct location_s is no longer used inside GCC, the hack in
>> new_structure to handle it is removed.

> This is excellent, but it really should be a separate patch.

Here it is, against trunk 165645.

### gcc/ChangeLog entry ###

2010-10-18  Basile Starynkevitch  <basile@starynkevitch.net>
	* gengtype (new_structure): Remove ad-hoc "location_s" processing.
###
Ok for trunk?

-- 
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 mine, sont seulement les miennes} ***

[-- Attachment #2: gengtype-nolocation_s-rev165645.diff --]
[-- Type: text/x-diff, Size: 740 bytes --]

Index: gcc/gengtype.c
===================================================================
--- gcc/gengtype.c	(revision 165645)
+++ gcc/gengtype.c	(working copy)
@@ -756,20 +756,6 @@ new_structure (const char *name, int isunion, stru
   if (s->u.s.lang_struct)
     s->u.s.lang_struct->u.s.bitmap |= bitmap;
 
-  /* Reset location_s's location to input.h so that we know where to
-     write out its mark routine.  */
-  if (!strcmp (name, "location_s") && !isunion && pos->file == this_file)
-    {
-      size_t n;
-      for (n = 0; n < num_gt_files; n++)
-	if (!strcmp (gt_files[n] + strlen (gt_files[n]) - strlen ("input.h"),
-		     "input.h"))
-	  {
-	    s->u.s.line.file = gt_files[n];
-	    break;
-	  }
-    }
-
   return s;
 }
 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype patch removing location_s
  2010-10-18 17:21     ` gengtype patch removing location_s Basile Starynkevitch
@ 2010-10-19  6:57       ` Laurynas Biveinis
  2010-10-19  7:11         ` Basile Starynkevitch
  0 siblings, 1 reply; 28+ messages in thread
From: Laurynas Biveinis @ 2010-10-19  6:57 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

2010/10/18 Basile Starynkevitch <basile@starynkevitch.net>:
> 2010-10-18  Basile Starynkevitch  <basile@starynkevitch.net>
>        * gengtype (new_structure): Remove ad-hoc "location_s" processing.

* gengtype.c

OK with ChangeLog fix and...

  /* temporary kludge - gengtype doesn't handle conditionals or
     macros.  Ignore any attempt to define struct location_s, unless
     it is coming from this file (main() sets it up safely). */
  if (!strcmp (name, "location_s") && !isunion && pos->file != this_file)
    return find_structure (name, 0);

...this fragment removed too (beginning of new_structure).

BTW grep shows that location_s is mentioned in a comment in
libcpp/include/input.h, bonus points if you take care of that too :)

Thanks,
-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype patch removing location_s
  2010-10-19  6:57       ` Laurynas Biveinis
@ 2010-10-19  7:11         ` Basile Starynkevitch
  2010-10-19  7:27           ` Laurynas Biveinis
  2010-10-19 16:38           ` Tom Tromey
  0 siblings, 2 replies; 28+ messages in thread
From: Basile Starynkevitch @ 2010-10-19  7:11 UTC (permalink / raw)
  To: Laurynas Biveinis; +Cc: gcc-patches

On Tue, 19 Oct 2010 05:48:02 +0300
Laurynas Biveinis <laurynas.biveinis@gmail.com> wrote:
> BTW grep shows that location_s is mentioned in a comment in
> libcpp/include/input.h, bonus points if you take care of that too :)

It is not libcpp/include/input.h but libcpp/include/line-map.h
where I dared commiting the following change (only on comments)

Index: libcpp/include/line-map.h
===================================================================
--- libcpp/include/line-map.h	(revision 165678)
+++ libcpp/include/line-map.h	(working copy)
@@ -39,8 +39,6 @@ enum lc_reason {LC_ENTER = 0, LC_LEAVE, LC_RENAME,
 typedef unsigned int linenum_type;
 
 /* A logical line/column number, i.e. an "index" into a line_map.  */
-/* Long-term, we want to use this to replace struct location_s (in
input.h),
-   and effectively typedef source_location location_t.  */
 typedef unsigned int source_location;
 

### libcpp/ChangeLog entry
2010-10-19  Basile Starynkevitch  <basile@starynkevitch.net>
	* line-map.h (source_location): Remove obsolete comment
	mentioning location_s.
###

I hope that svn commit-ting removing an obsolete comment in this file is
permitted with your previous OK.

Committed revision 165680.

-- 
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 mine, sont seulement les miennes} ***

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype patch removing location_s
  2010-10-19  7:11         ` Basile Starynkevitch
@ 2010-10-19  7:27           ` Laurynas Biveinis
  2010-10-19  7:29             ` Basile Starynkevitch
  2010-10-19 16:38           ` Tom Tromey
  1 sibling, 1 reply; 28+ messages in thread
From: Laurynas Biveinis @ 2010-10-19  7:27 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

2010/10/19 Basile Starynkevitch <basile@starynkevitch.net>:
> 2010-10-19  Basile Starynkevitch  <basile@starynkevitch.net>
>        * line-map.h (source_location): Remove obsolete comment
>        mentioning location_s.

> I hope that svn commit-ting removing an obsolete comment in this file is
> permitted with your previous OK.

No it's not, my OK is not that powerful and I should have been more
explicit about that. However I believe this particular patch is
obvious.

-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype patch removing location_s
  2010-10-19  7:27           ` Laurynas Biveinis
@ 2010-10-19  7:29             ` Basile Starynkevitch
  2010-10-19  8:17               ` Laurynas Biveinis
  2010-10-19  8:49               ` Dave Korn
  0 siblings, 2 replies; 28+ messages in thread
From: Basile Starynkevitch @ 2010-10-19  7:29 UTC (permalink / raw)
  To: Laurynas Biveinis, dnovillo, tromey; +Cc: gcc-patches

On Tue, 19 Oct 2010 10:06:44 +0300
Laurynas Biveinis <laurynas.biveinis@gmail.com> wrote:

> 2010/10/19 Basile Starynkevitch <basile@starynkevitch.net>:
> > 2010-10-19  Basile Starynkevitch  <basile@starynkevitch.net>
> >        * line-map.h (source_location): Remove obsolete comment
> >        mentioning location_s.
> 
> > I hope that svn commit-ting removing an obsolete comment in this file is
> > permitted with your previous OK.
> 
> No it's not, my OK is not that powerful and I should have been more
> explicit about that. However I believe this particular patch is
> obvious.

Should I undo my change? If some people want that, please tell! I'm
explicitly CC-ing Diego & Tromey...

But I also believe this particular patch is obvious. (But I am not sure
understanding what obvious means).

Cheers
-- 
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 mine, sont seulement les miennes} ***

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype patch removing location_s
  2010-10-19  7:29             ` Basile Starynkevitch
@ 2010-10-19  8:17               ` Laurynas Biveinis
  2010-10-19  8:49               ` Dave Korn
  1 sibling, 0 replies; 28+ messages in thread
From: Laurynas Biveinis @ 2010-10-19  8:17 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: dnovillo, tromey, gcc-patches

2010/10/19 Basile Starynkevitch <basile@starynkevitch.net>:
> Should I undo my change? If some people want that, please tell! I'm
> explicitly CC-ing Diego & Tromey...

IMHO you don't have to do anything about it now. It's only a two-line
outdated comment removal. And if I'm wrong, then the maintainers will
ask you to revert or whatever.

-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype patch removing location_s
  2010-10-19  7:29             ` Basile Starynkevitch
  2010-10-19  8:17               ` Laurynas Biveinis
@ 2010-10-19  8:49               ` Dave Korn
  1 sibling, 0 replies; 28+ messages in thread
From: Dave Korn @ 2010-10-19  8:49 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: Laurynas Biveinis, dnovillo, tromey, gcc-patches

On 19/10/2010 08:10, Basile Starynkevitch wrote:
> On Tue, 19 Oct 2010 10:06:44 +0300 Laurynas Biveinis
> <laurynas.biveinis@gmail.com> wrote:
> 
>> 2010/10/19 Basile Starynkevitch <basile@starynkevitch.net>:
>>> 2010-10-19  Basile Starynkevitch  <basile@starynkevitch.net> *
>>> line-map.h (source_location): Remove obsolete comment mentioning
>>> location_s. I hope that svn commit-ting removing an obsolete comment in
>>> this file is permitted with your previous OK.
>> No it's not, my OK is not that powerful and I should have been more 
>> explicit about that. However I believe this particular patch is obvious.
> 
> Should I undo my change? If some people want that, please tell! I'm 
> explicitly CC-ing Diego & Tromey...

  I don't think so, it really is obvious, and "obvious" means no approval
needed to commit.

> But I also believe this particular patch is obvious. (But I am not sure 
> understanding what obvious means).

  It is defined at http://gcc.gnu.org/svnwrite.html, although the term used
there is "Free for all":

> The following changes can be made by everyone with SVN write access:
> 
> Fixes for obvious typos in ChangeLog files, docs, web pages, comments and
> similar stuff. Just check in the fix and copy it to gcc-patches. We don't
> want to get overly anal-retentive about checkin policies.
> 
> Similarly, no outside approval is needed to revert a patch that you checked
> in.
> 
> Importing files maintained outside the tree from their official versions.
> 
> Creating and using a branch for development, including outside the parts of
> the compiler one maintains, provided that changes on the branch have
> copyright assignments on file. Merging such developments back to the
> mainline still needs approval in the usual way.

  "Fixes for obvious typos in  ... comments" covers removing an obsolete
comment, I'm sure nobody would object.

    cheers,
      DaveK


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype patch removing location_s
  2010-10-19  7:11         ` Basile Starynkevitch
  2010-10-19  7:27           ` Laurynas Biveinis
@ 2010-10-19 16:38           ` Tom Tromey
  2010-10-20 20:39             ` gengtype plugin improvement last2round - patch3 [inputfile] Basile Starynkevitch
  1 sibling, 1 reply; 28+ messages in thread
From: Tom Tromey @ 2010-10-19 16:38 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: Laurynas Biveinis, gcc-patches

>>>>> "Basile" == Basile Starynkevitch <basile@starynkevitch.net> writes:

Basile> It is not libcpp/include/input.h but libcpp/include/line-map.h
Basile> where I dared commiting the following change (only on comments)

For avoidance of doubt, this is ok.
This comment should have been deleted long ago.

Tom

^ permalink raw reply	[flat|nested] 28+ messages in thread

* gengtype plugin improvement last2round -  patch3 [inputfile]
  2010-10-19 16:38           ` Tom Tromey
@ 2010-10-20 20:39             ` Basile Starynkevitch
  2010-10-21  4:46               ` Laurynas Biveinis
  0 siblings, 1 reply; 28+ messages in thread
From: Basile Starynkevitch @ 2010-10-20 20:39 UTC (permalink / raw)
  To: Laurynas Biveinis; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2723 bytes --]


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).

-- 
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 mine, sont seulement les miennes} ***

[-- Attachment #2: gengtype-last2round-inputfile-r165733.diff --]
[-- Type: text/x-diff, Size: 52592 bytes --]

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 *);
 \f
 
 /* 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);
 }
 \f
-struct flist
+\f
+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);
 	}
     }
 }
 
 
+\f
+/******* Manage input files.  ******/
+
+/* Hash table of unique input file names.  */
+static htab_t input_file_htab;
+
+/* Find or allocate a new input_file by hash-consing it.  */
+input_file*
+input_file_by_name (const char* name)
+{
+  PTR* slot;
+  input_file* f = NULL;
+  int namlen = 0;
+  if (!name)
+    return NULL;
+  namlen = strlen (name);
+  f = XCNEWVAR (input_file, sizeof (input_file)+namlen+2);
+  f->inpbitmap = 0;
+  f->inpoutf = NULL;
+  f->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	\

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: gengtype plugin improvement last2round - patch3 [inputfile]
  2010-10-20 20:39             ` gengtype plugin improvement last2round - patch3 [inputfile] Basile Starynkevitch
@ 2010-10-21  4:46               ` Laurynas Biveinis
  0 siblings, 0 replies; 28+ messages in thread
From: Laurynas Biveinis @ 2010-10-21  4:46 UTC (permalink / raw)
  To: Basile Starynkevitch; +Cc: gcc-patches

To shortly sum up the review (details below):
- The patch should not contain any seemingly random code shuffling,
reformatting and whitespace changes
- I found two or three parts that should be independent submissions
- I'm afraid I am going to ask you to drop the magic. I do believe
that these days the tool support at least on Linux is good enough to
keep the source code concise.

Thanks,
Laurynas

-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 const char *get_file_basename ...
static const char *get_file_realbasename ...

-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)

Please drop this chunk.

 		    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]);

Is this only formatting change? If yes, please drop.

@@ -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;

GNU coding standards say the star sticks to the parameter name, so

const input_file *inpf, int line)

@@ -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;
@@ -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;

Here the only change is an extra space at the end of the line. Please
drop all these chunks.

@@ -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 *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;
 }

The header comment should refer to INPF, not F

const char *fname =

Please use strncmp instead of memcmp.

-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);

const char *srcdir_path = ...

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

input_file *inpf

@@ -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

Please drop this chunk.

+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);

Watch the spaces around =.

@@ -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)
     {

Please drop this.

@@ -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);

Indent the line with free.

@@ -1952,11 +1909,12 @@ close_output_files (void)
     printf ("%s wrote %d files.\n", progname, nbwrittenfiles);
 }
 \f
-struct flist
+\f
+struct flist
 {

Please drop this change.

@@ -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.  */

Please drop this change.

@@ -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);

Please drop this change.

@@ -2041,7 +1999,7 @@ output_mangled_typename (outf_p of, const_type_p t
 {
   if (t == NULL)
     oprintf (of, "Z");
-  else
+  else

Please drop.

@@ -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);

Please drop.

@@ -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;

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;

Can you submit this separately?

+
+  CHECK_INPUT_FILE_MAGIC (fn);
+

I'm going to ask you to drop the magic, sorry.

@@ -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);

Please drop.

@@ -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");
 	    }
       }

 	      oprintf (base_files[fnum],
 		       "extern const struct %s gt_%s_", tname, pfx);
              put_mangled_filename (base_files[fnum], fli2->file);

@@ -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);
   }
@@ -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");

Please drop.

@@ -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)
 	  ;

Please drop.

@@ -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;
 	}

Please drop.

@@ -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));

Here and everywhere below, break the line before the =, not after:

outf_p f
   = get_output_ ....

@@ -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)
 	  ;

Please drop this change.

@@ -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;
 	}

@@ -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

And this one.

@@ -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, "_");
 	    }

And this one.

@@ -4109,32 +4097,15 @@ dump_typekind (int indent, enum typekind kind)
   printf ("%*ckind = ", indent, ' ');
   switch (kind)
     {
-    case TYPE_SCALAR:
-      printf ("TYPE_SCALAR");
-      break;
[...]

And all the changes that only reformat code. I have stopped here reading them.

+  if (*slot)
+    {
+      /* Already known input file.  */
+      free (f);
+      return (input_file*)(*slot);
+	}
+  /* New input file.  */
+  *slot = f;
+  return f;
+    }

Watch the indentation of the closing braces.

@@ -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);

This is unrelated. Please drop or submit in a separate patch. If you
submit a separate patch, correct indentation (two spaces instead of
one).

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.  */

/* Variable length structure representing an input file.  Each unique given
   file name has one and only one variable of this type, stored in a hash
   table input_file_htab in gengtype.c.  */

Index: gcc/gengtype-lex.l
===================================================================
--- gcc/gengtype-lex.l	(revision 165733)
+++ gcc/gengtype-lex.l	(working copy)
@@ -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;
 }

We have discussed this before but I still do not follow. This patch
does not add include of gengtype.h, so if it worked previsouly without
#include "errors.h", it should still work.  Likewise for
gengtype-parse.c.

@@ -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 ('{', '}');

Separate patch please.


2010/10/20 Basile Starynkevitch <basile@starynkevitch.net>:
>
> 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).
>
> --
> 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 mine, sont seulement les miennes} ***
>



-- 
Laurynas

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2010-10-21  2:21 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-21 19:41 gengtype improvements for plugins, thirdround! patch 1/7 [declprog] Basile Starynkevitch
2010-09-21 22:07 ` gengtype improvements for plugins, thirdround! patch 2/7 [verbosity] Basile Starynkevitch
2010-09-21 22:43   ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Basile Starynkevitch
2010-09-22  0:29     ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Basile Starynkevitch
2010-09-22  1:50       ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Basile Starynkevitch
2010-09-22  1:58         ` gengtype improvements for plugins, thirdround! patch 6/7 [wstate] Basile Starynkevitch
2010-09-22  2:16           ` Basile Starynkevitch
2010-09-22  3:03             ` gengtype improvements for plugins, thirdround! patch 7/7 [doc] Basile Starynkevitch
2010-09-22 14:17               ` Laurynas Biveinis
2010-09-22 14:08           ` gengtype improvements for plugins, thirdround! patch 6/7 [wstate] Laurynas Biveinis
2010-09-22 12:13         ` gengtype improvements for plugins, thirdround! patch 5/7 [typedopt] Laurynas Biveinis
2010-09-23 19:17           ` Basile Starynkevitch
2010-09-23 19:29             ` Diego Novillo
2010-09-23 19:39               ` Richard Guenther
2010-09-22 12:06       ` gengtype improvements for plugins, thirdround! patch 4/7 [filerules] Laurynas Biveinis
2010-09-22 12:05     ` gengtype improvements for plugins, thirdround! patch 3/7 [inputfile] Laurynas Biveinis
2010-10-18 17:21     ` gengtype patch removing location_s Basile Starynkevitch
2010-10-19  6:57       ` Laurynas Biveinis
2010-10-19  7:11         ` Basile Starynkevitch
2010-10-19  7:27           ` Laurynas Biveinis
2010-10-19  7:29             ` Basile Starynkevitch
2010-10-19  8:17               ` Laurynas Biveinis
2010-10-19  8:49               ` Dave Korn
2010-10-19 16:38           ` Tom Tromey
2010-10-20 20:39             ` gengtype plugin improvement last2round - patch3 [inputfile] Basile Starynkevitch
2010-10-21  4:46               ` Laurynas Biveinis
2010-09-22 11:11   ` gengtype improvements for plugins, thirdround! patch 2/7 [verbosity] Laurynas Biveinis
2010-09-22 11:08 ` gengtype improvements for plugins, thirdround! patch 1/7 [declprog] Laurynas Biveinis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).