This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PCH] cpp & dependencies


This adds saving/restoring CPP macros, and validity checking of the
CPP macro state.  This should be enough to precompile any header that
doesn't actually contain any C code.

Bootstrapped & tested on x86-linux.

-- 
Geoff Keating <geoffk@redhat.com>

===File ~/patches/pchbranch-cpp.patch=======================
Index: ChangeLog
2002-09-01  Geoffrey Keating  <geoffk@redhat.com>
	    Catherine Moore  <clm@redhat.com>

	* Makefile (c-pch.o): Update dependencies.
	(LIBCPP_OBJS): Add cpppch.o.
	(cpppch.o): New.
	* c-common.c (c_common_init): Don't call pch_init here.
	* c-common.h (c_common_read_pch): Update prototype.
	* c-lex.c (c_common_parse_file): Call pch_init here.
	* c-opts.c (COMMAND_LINE_OPTIONS): Add -Winvalid-pch, -fpch-deps.
	(c_common_decode_option): Handle them.
	* c-pch.c: Include c-pragma.h.
	(save_asm_offset): Delete.
	(pch_init): Move contents of save_asm_offset into here, call
	cpp_save_state.
	(c_common_write_pch): Call cpp_write_pch.
	(c_common_valid_pch): Warn only when -Winvalid-pch.  Call
	cpp_valid_state.
	(c_common_read_pch): Add NAME parameter.  Call cpp_read_state.
	* cppfiles.c (stack_include_file): Update for change to 
	parameters of cb.read_pch.
	* cpphash.h (struct cpp_reader): Add `savedstate' field.
	* cpplib.h (struct cpp_options): Add `warn_invalid_pch' and
	`restore_pch_deps' fields.
	(struct cpp_callbacks): Add NAME parameter to `read_pch'.
	(cpp_save_state): Prototype.
	(cpp_write_pch): Prototype.
	(cpp_valid_state): Prototype.
	(cpp_read_state): Prototype.
	* cpppch.c: New file.
	* flags.h (version_flag): Remove prototype.
	* mkdeps.c (deps_save): New.
	(deps_restore): New.
	* mkdeps.h (deps_save): Prototype.
	(deps_restore): Prototype.
	* toplev.c (late_init_hook): Delete.
	(version_flag): Make static again.
	(compile_file): Don't call late_init_hook.
	* toplev.h (late_init_hook): Delete.
	* doc/cppopts.texi: Document -fpch-deps.
	* doc/invoke.texi (Warning Options): Document -Winvalid-pch.

Index: testsuite/ChangeLog
2002-09-01  Geoffrey Keating  <geoffk@redhat.com>

	* g++.dg/pch/pch.exp: Better handle failing testcases.
	* gcc.dg/pch/pch.exp: Likewise.
	* gcc.dg/pch/macro-1.c: New.
	* gcc.dg/pch/macro-1.h: New.
	* gcc.dg/pch/macro-2.c: New.
	* gcc.dg/pch/macro-2.h: New.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.822.2.31
diff -p -u -p -r1.822.2.31 Makefile.in
--- Makefile.in	25 Aug 2002 00:47:56 -0000	1.822.2.31
+++ Makefile.in	2 Sep 2002 00:21:59 -0000
@@ -1261,7 +1261,7 @@ c-semantics.o : c-semantics.c $(CONFIG_H
 c-dump.o : c-dump.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(C_TREE_H) tree-dump.h
 
 c-pch.o : c-pch.c $(CONFIG_H) $(SYSTEM_H) $(CPPLIB_H) $(TREE_H) c-common.h \
-	output.h toplev.h
+	output.h toplev.h c-pragma.h
 
 # Language-independent files.
 
@@ -2194,7 +2194,7 @@ PREPROCESSOR_DEFINES = \
 
 LIBCPP_OBJS =	cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o cpptrad.o \
 		cpphash.o cpperror.o cppinit.o cppdefault.o cppmain.o \
-		hashtable.o line-map.o mkdeps.o prefix.o mbchar.o
+		hashtable.o line-map.o mkdeps.o prefix.o mbchar.o cpppch.o
 
 LIBCPP_DEPS =	$(CPPLIB_H) cpphash.h line-map.h hashtable.h intl.h \
 		$(OBSTACK_H) $(SYSTEM_H)
@@ -2218,6 +2218,7 @@ cpptrad.o:  cpptrad.c  $(CONFIG_H) $(LIB
 cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h
 cppinit.o:  cppinit.c  $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \
 		mkdeps.h prefix.h version.h
+cpppch.o:   cpptrad.c  $(CONFIG_H) $(LIBCPP_DEPS) mkdeps.h
 
 cppdefault.o: cppdefault.c $(CONFIG_H) $(SYSTEM_H) cppdefault.h Makefile
 	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.286.4.13
diff -p -u -p -r1.286.4.13 c-common.c
--- c-common.c	25 Aug 2002 00:47:56 -0000	1.286.4.13
+++ c-common.c	2 Sep 2002 00:21:59 -0000
@@ -4931,8 +4931,6 @@ c_common_init (filename)
 
   init_pragma ();
 
-  pch_init ();
-
   if (!c_attrs_initialized)
     c_init_attributes ();
 
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.112.4.15
diff -p -u -p -r1.112.4.15 c-common.h
--- c-common.h	27 Aug 2002 23:58:25 -0000	1.112.4.15
+++ c-common.h	2 Sep 2002 00:21:59 -0000
@@ -1243,6 +1243,7 @@ extern int c_common_valid_pch			PARAMS (
 							 const char *name,
 							 int fd));
 extern void c_common_read_pch			PARAMS ((cpp_reader *pfile,
+							 const char *name,
 							 int fd));
 extern void c_common_write_pch			PARAMS ((void));
 
Index: c-lex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-lex.c,v
retrieving revision 1.163.4.8
diff -p -u -p -r1.163.4.8 c-lex.c
--- c-lex.c	27 Aug 2002 23:58:25 -0000	1.163.4.8
+++ c-lex.c	2 Sep 2002 00:22:00 -0000
@@ -161,6 +161,8 @@ c_common_parse_file (set_yydebug)
   (*debug_hooks->start_source_file) (lineno, input_filename);
   cpp_finish_options (parse_in);
 
+  pch_init();
+  
   yyparse ();
   free_parser_stacks ();
 }
Index: c-opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-opts.c,v
retrieving revision 1.10.2.4
diff -p -u -p -r1.10.2.4 c-opts.c
--- c-opts.c	27 Aug 2002 23:58:25 -0000	1.10.2.4
+++ c-opts.c	2 Sep 2002 00:22:00 -0000
@@ -112,6 +112,7 @@ static void handle_OPT_d PARAMS ((const 
   OPT("Wimplicit-function-declaration",	CL_C, OPT_Wimplicit_function_decl)   \
   OPT("Wimplicit-int",		CL_C,	  OPT_Wimplicit_int)		     \
   OPT("Wimport",                CL_ALL,   OPT_Wimport)			     \
+  OPT("Winvalid-pch",           CL_ALL,   OPT_Winvalid_pch)		     \
   OPT("Wlong-long",		CL_ALL,   OPT_Wlong_long)		     \
   OPT("Wmain",			CL_C,     OPT_Wmain)			     \
   OPT("Wmissing-braces",	CL_ALL,   OPT_Wmissing_braces)		     \
@@ -187,6 +188,7 @@ static void handle_OPT_d PARAMS ((const 
   OPT("fnonnull-objects",	CL_CXX,   OPT_fnonnull_objects)		     \
   OPT("foperator-names",	CL_CXX,   OPT_foperator_names)		     \
   OPT("foptional-diags",	CL_CXX,   OPT_foptional_diags)		     \
+  OPT("fpch-deps",		CL_ALL,	  OPT_fpch_deps)		     \
   OPT("fpermissive",		CL_CXX,   OPT_fpermissive)		     \
   OPT("fpreprocessed",		CL_ALL,   OPT_fpreprocessed)		     \
   OPT("frepo",			CL_CXX,   OPT_frepo)			     \
@@ -681,6 +683,10 @@ c_common_decode_option (argc, argv)
       cpp_opts->warn_import = on;
       break;
 
+    case OPT_Winvalid_pch:
+      cpp_opts->warn_invalid_pch = on;
+      break;
+
     case OPT_Wlong_long:
       warn_long_long = on;
       break;
@@ -1010,6 +1016,10 @@ c_common_decode_option (argc, argv)
 
     case OPT_foptional_diags:
       flag_optional_diags = on;
+      break;
+
+    case OPT_fpch_deps:
+      cpp_opts->restore_pch_deps = on;
       break;
 
     case OPT_fpermissive:
Index: c-pch.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/c-pch.c,v
retrieving revision 1.1.2.2
diff -p -u -p -r1.1.2.2 c-pch.c
--- c-pch.c	27 Aug 2002 23:58:25 -0000	1.1.2.2
+++ c-pch.c	2 Sep 2002 00:22:00 -0000
@@ -25,6 +25,7 @@ Boston, MA 02111-1307, USA.  */
 #include "c-common.h"
 #include "output.h"
 #include "toplev.h"
+#include "c-pragma.h"
 
 struct c_pch_header 
 {
@@ -37,17 +38,6 @@ static FILE *pch_outfile;
 
 extern char *asm_file_name;
 static off_t asm_file_startpos;
-static void (*old_late_init_hook) PARAMS((void));
-
-static void save_asm_offset PARAMS((void));
-
-static void
-save_asm_offset ()
-{
-  if (old_late_init_hook)
-    old_late_init_hook ();
-  asm_file_startpos = ftello (asm_out_file);
-}
 
 void
 pch_init ()
@@ -63,9 +53,6 @@ pch_init ()
       
       if (fwrite (pch_ident, sizeof (pch_ident), 1, f) != 1)
 	fatal_io_error ("can't write to %s", pch_file);
-#if 0
-      cpp_save_state (&parse_in, f);
-#endif
 
       /* We need to be able to re-read the output.  */
       /* The driver always provides a valid -o option.  */
@@ -73,8 +60,9 @@ pch_init ()
 	  || strcmp (asm_file_name, "-") == 0)
 	fatal_error ("`%s' is not a valid output file", asm_file_name);
 
-      old_late_init_hook = late_init_hook;
-      late_init_hook = save_asm_offset;
+      asm_file_startpos = ftello (asm_out_file);
+      
+      cpp_save_state (parse_in, f);
     }
 }
 
@@ -86,9 +74,7 @@ c_common_write_pch ()
   off_t written;
   struct c_pch_header h;
 
-#if 0
-  cpp_write_pch (&parse_in, pch_outfile);
-#endif
+  cpp_write_pch (parse_in, pch_outfile);
 
   asm_file_end = ftello (asm_out_file);
   h.asm_size = asm_file_end - asm_file_startpos;
@@ -145,32 +131,37 @@ c_common_valid_pch (pfile, name, fd)
   
   if (memcmp (ident, pch_ident, sizeof (pch_ident)) != 0)
     {
-      if (memcmp (ident, pch_ident, 5) == 0)
-	/* It's a PCH, for the right language, but has the wrong version.  */
-	cpp_error (pfile, DL_WARNING, "not compatible with this GCC version");
-      else if (memcmp (ident, pch_ident, 4) == 0)
-	/* It's a PCH for the wrong language.  */
-	cpp_error (pfile, DL_WARNING, "not for C language");
+      if (cpp_get_options (pfile)->warn_invalid_pch)
+	{
+	  if (memcmp (ident, pch_ident, 5) == 0)
+	    /* It's a PCH, for the right language, but has the wrong version.
+	     */
+	    cpp_error (pfile, DL_WARNING, 
+		       "%s: not compatible with this GCC version", name);
+	  else if (memcmp (ident, pch_ident, 4) == 0)
+	    /* It's a PCH for the wrong language.  */
+	    cpp_error (pfile, DL_WARNING, "%s: not for C language", name);
+	  else 
+	    /* Not any kind of PCH.  */
+	    cpp_error (pfile, DL_WARNING, "%s: not a PCH file", name);
+	}
       return 2;
     }
 
-#if 0
   /* Check the preprocessor macros are the same as when the PCH was
      generated.  */
   
-  result = cpp_valid_state (pfile, fd);
+  result = cpp_valid_state (pfile, name, fd);
   if (result == -1)
     return 2;
   else
     return result == 0;
-#else
-  return 1;
-#endif
 }
 
 void
-c_common_read_pch (pfile, fd)
+c_common_read_pch (pfile, name, fd)
      cpp_reader *pfile;
+     const char *name;
      int fd;
 {
   FILE *f;
@@ -187,10 +178,8 @@ c_common_read_pch (pfile, fd)
 
   allow_pch = 0;
 
-#if 0
-  if (cpp_read_state (pfile, f) != 0)
+  if (cpp_read_state (pfile, name, f) != 0)
     return;
-#endif
 
   if (fread (&h, sizeof (h), 1, f) != 1)
     {
Index: cppfiles.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppfiles.c,v
retrieving revision 1.143.2.6
diff -p -u -p -r1.143.2.6 cppfiles.c
--- cppfiles.c	25 Aug 2002 00:47:57 -0000	1.143.2.6
+++ cppfiles.c	2 Sep 2002 00:22:00 -0000
@@ -368,7 +368,7 @@ stack_include_file (pfile, inc)
      will approximately double the memory consumption of the compiler.  */
   if (INCLUDE_PCH_P (inc))
     {
-      pfile->cb.read_pch (pfile, inc->fd);
+      pfile->cb.read_pch (pfile, inc->name, inc->fd);
       close (inc->fd);
       inc->fd = -1;
       
Index: cpphash.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpphash.h,v
retrieving revision 1.139.4.6
diff -p -u -p -r1.139.4.6 cpphash.h
--- cpphash.h	13 Aug 2002 17:56:22 -0000	1.139.4.6
+++ cpphash.h	2 Sep 2002 00:22:00 -0000
@@ -434,6 +434,10 @@ struct cpp_reader
   /* Used to save the original line number during traditional
      preprocessing.  */
   unsigned int saved_line;
+
+  /* A saved list of the defined macros, for dependency checking
+     of precompiled headers.  */
+  struct cpp_savedstate *savedstate;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
Index: cpplib.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.h,v
retrieving revision 1.199.4.8
diff -p -u -p -r1.199.4.8 cpplib.h
--- cpplib.h	25 Aug 2002 00:47:58 -0000	1.199.4.8
+++ cpplib.h	2 Sep 2002 00:22:00 -0000
@@ -412,6 +412,12 @@ struct cpp_options
 
   /* Nonzero means __STDC__ should have the value 0 in system headers.  */
   unsigned char stdc_0_in_system_headers;
+
+  /* True to warn about precompiled header files we couldn't use.  */
+  bool warn_invalid_pch;
+
+  /* True if dependencies should be restored from a precompiled header.  */
+  bool restore_pch_deps;
 };
 
 /* Call backs.  */
@@ -430,7 +436,7 @@ struct cpp_callbacks
      built-ins with cpp_define() and cpp_assert().  */
   void (*register_builtins) PARAMS ((cpp_reader *));
   int (*valid_pch) PARAMS ((cpp_reader *, const char *, int));
-  void (*read_pch) PARAMS ((cpp_reader *, int));
+  void (*read_pch) PARAMS ((cpp_reader *, const char *, int));
 };
 
 /* Name under which this program was invoked.  */
@@ -718,6 +724,12 @@ extern unsigned char *cpp_quote_string	P
 /* In cppfiles.c */
 extern int cpp_included	PARAMS ((cpp_reader *, const char *));
 extern void cpp_make_system_header PARAMS ((cpp_reader *, int, int));
+
+/* In cpppch.c */
+extern int cpp_save_state PARAMS ((cpp_reader *, FILE *));
+extern int cpp_write_pch PARAMS ((cpp_reader *, FILE *));
+extern int cpp_valid_state PARAMS ((cpp_reader *, const char *, int));
+extern int cpp_read_state PARAMS ((cpp_reader *, const char *, FILE *));
 
 /* In cppmain.c */
 extern void cpp_preprocess_file PARAMS ((cpp_reader *));
Index: cpppch.c
===================================================================
RCS file: cpppch.c
diff -N cpppch.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cpppch.c	2 Sep 2002 00:22:00 -0000
@@ -0,0 +1,539 @@
+/* Part of CPP library.  (Precompiled header reading/writing.)
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+
+This program 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 2, or (at your option) any
+later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "cpphash.h"
+#include "intl.h"
+#include "hashtab.h"
+#include "mkdeps.h"
+
+static int write_macdef PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+static int save_idents PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+static hashval_t hashmem PARAMS ((const void *, size_t));
+static hashval_t cpp_string_hash PARAMS ((const void *));
+static int cpp_string_eq PARAMS ((const void *, const void *));
+static int count_defs PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+static int write_defs PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+
+/* This structure represents a macro definition on disk.  */
+struct macrodef_struct 
+{
+  unsigned int definition_length;
+  unsigned short name_length;
+  unsigned short flags;
+};
+
+/* This is how we write out a macro definition.  
+   Suitable for being called by cpp_forall_identifiers.  */
+
+static int
+write_macdef (pfile, hn, file_p)
+     cpp_reader *pfile;
+     cpp_hashnode *hn;
+     void *file_p;
+{
+  FILE *f = (FILE *) file_p;
+  switch (hn->type)
+    {
+    case NT_VOID:
+      if (! (hn->flags & NODE_POISONED))
+	return 1;
+      
+    case NT_MACRO:
+      if ((hn->flags & NODE_BUILTIN))
+	return 1;
+
+      {
+	struct macrodef_struct s;
+	const unsigned char *defn;
+
+	s.name_length = NODE_LEN (hn);
+	s.flags = hn->flags & NODE_POISONED;
+
+	if (hn->type == NT_MACRO)
+	  {
+	    defn = cpp_macro_definition (pfile, hn);
+	    s.definition_length = ustrlen (defn);
+	  }
+	else
+	  {
+	    defn = NODE_NAME (hn);
+	    s.definition_length = s.name_length;
+	  }
+	
+	if (fwrite (&s, sizeof (s), 1, f) != 1
+	    || fwrite (defn, 1, s.definition_length, f) != s.definition_length)
+	  {
+	    cpp_errno (pfile, DL_ERROR, "while writing precompiled header");
+	    return 0;
+	  }
+      }
+      return 1;
+      
+    case NT_ASSERTION:
+      /* Not currently implemented.  */
+      return 1;
+
+    default:
+      abort ();
+    }
+}
+
+/* This structure records the names of the defined macros.
+   It's also used as a callback structure for size_initial_idents
+   and save_idents.  */
+
+struct cpp_savedstate
+{
+  /* A hash table of the defined identifiers.  */
+  htab_t definedhash;
+  /* The size of the definitions of those identifiers (the size of
+     'definedstrs').  */
+  size_t hashsize;
+  /* Space for the next definition.  Definitions are null-terminated
+     strings.  */
+  unsigned char *definedstrs;
+};
+
+/* Save this identifier into the state: put it in the hash table,
+   put the definition in 'definedstrs'.  */
+
+static int
+save_idents (pfile, hn, ss_p)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_hashnode *hn;
+     void *ss_p;
+{
+  struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
+  
+  if (hn->type != NT_VOID)
+    {
+      struct cpp_string news;
+      void **slot;
+
+      news.len = NODE_LEN (hn);
+      news.text= NODE_NAME (hn);
+      slot = htab_find_slot (ss->definedhash, &news, INSERT);
+      if (*slot == NULL)
+	{
+	  struct cpp_string *sp;
+	  unsigned char *text;
+	  
+	  sp = xmalloc (sizeof (struct cpp_string));
+	  *slot = sp;
+
+	  sp->len = NODE_LEN (hn);
+	  sp->text = text = xmalloc (NODE_LEN (hn));
+	  memcpy (text, NODE_NAME (hn), NODE_LEN (hn));
+	}
+    }
+
+  return 1;
+}
+
+/* Hash some memory in a generic way.  */
+
+static hashval_t
+hashmem (p_p, sz)
+     const void *p_p;
+     size_t sz;
+{
+  const unsigned char *p = (const unsigned char *)p_p;
+  size_t i;
+  hashval_t h;
+  
+  h = 0;
+  for (i = 0; i < sz; i++)
+    h = h * 67 - (*p++ - 113);
+  return h;
+}
+
+/* Hash a cpp string for the hashtable machinery.  */
+
+static hashval_t
+cpp_string_hash (a_p)
+     const void *a_p;
+{
+  const struct cpp_string *a = (const struct cpp_string *) a_p;
+  return hashmem (a->text, a->len);
+}
+
+/* Compare two cpp strings for the hashtable machinery.  */
+
+static int
+cpp_string_eq (a_p, b_p)
+     const void *a_p;
+     const void *b_p;
+{
+  const struct cpp_string *a = (const struct cpp_string *) a_p;
+  const struct cpp_string *b = (const struct cpp_string *) b_p;
+  return (a->len == b->len
+	  && memcmp (a->text, b->text, a->len) == 0);
+}
+
+/* Save the current definitions of the cpp_reader for dependency
+   checking purposes.  When writing a precompiled header, this should
+   be called at the same point in the compilation as cpp_valid_state
+   would be called when reading the precompiled header back in.  */
+
+int
+cpp_save_state (r, f)
+     cpp_reader *r;
+     FILE *f;
+{
+  /* Save the list of non-void identifiers for the dependency checking.  */
+  r->savedstate = xmalloc (sizeof (struct cpp_savedstate));
+  r->savedstate->definedhash = htab_create (100, cpp_string_hash, 
+					    cpp_string_eq, NULL);
+  cpp_forall_identifiers (r, save_idents, r->savedstate);
+  
+  /* Write out the list of defined identifiers.  */
+  cpp_forall_identifiers (r, write_macdef, f);
+
+  return 0;
+}
+
+/* Calculate the 'hashsize' field of the saved state.  */
+
+static int
+count_defs (pfile, hn, ss_p)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_hashnode *hn;
+     void *ss_p;
+{
+  struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
+  
+  switch (hn->type)
+    {
+    case NT_MACRO:
+      if (hn->flags & NODE_BUILTIN)
+	return 1;
+      
+      /* else fall through.  */
+
+    case NT_VOID:
+      {
+	struct cpp_string news;
+	void **slot;
+	
+	news.len = NODE_LEN (hn);
+	news.text = NODE_NAME (hn);
+	slot = htab_find (ss->definedhash, &news);
+	if (slot == NULL)
+	  ss->hashsize += NODE_LEN (hn) + 1;
+      }
+      return 1;
+
+    case NT_ASSERTION:
+      /* Not currently implemented.  */
+      return 1;
+
+    default:
+      abort ();
+    }
+}
+
+/* Write the identifiers into 'definedstrs' of the state.  */
+
+static int
+write_defs (pfile, hn, ss_p)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_hashnode *hn;
+     void *ss_p;
+{
+  struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
+  
+  switch (hn->type)
+    {
+    case NT_MACRO:
+      if (hn->flags & NODE_BUILTIN)
+	return 1;
+      
+      /* else fall through.  */
+
+    case NT_VOID:
+      {
+	struct cpp_string news;
+	void **slot;
+	
+	news.len = NODE_LEN (hn);
+	news.text = NODE_NAME (hn);
+	slot = htab_find (ss->definedhash, &news);
+	if (slot == NULL)
+	  {
+	    memcpy (ss->definedstrs, NODE_NAME (hn), NODE_LEN (hn));
+	    ss->definedstrs[NODE_LEN (hn)] = 0;
+	    ss->definedstrs += NODE_LEN (hn) + 1;
+	  }
+      }
+      return 1;
+
+    case NT_ASSERTION:
+      /* Not currently implemented.  */
+      return 1;
+
+    default:
+      abort ();
+    }
+}
+
+/* Write out the definitions of the preprocessor, in a form suitable for
+   cpp_read_state.  */
+
+int
+cpp_write_pch (r, f)
+     cpp_reader *r;
+     FILE *f;
+{
+  struct macrodef_struct z;
+  struct cpp_savedstate *const ss = r->savedstate;
+  unsigned char *definedstrs;
+  
+  ss->hashsize = 0;
+  
+  /* Write out the list of identifiers which have been seen and
+     weren't defined to anything previously.  */
+  cpp_forall_identifiers (r, count_defs, ss);
+  definedstrs = ss->definedstrs = xmalloc (ss->hashsize);
+  cpp_forall_identifiers (r, write_defs, ss);
+  memset (&z, 0, sizeof (z));
+  z.definition_length = ss->hashsize;
+  if (fwrite (&z, sizeof (z), 1, f) != 1
+      || fwrite (definedstrs, ss->hashsize, 1, f) != 1)
+    {
+      cpp_errno (r, DL_ERROR, "while writing precompiled header");
+      return -1;
+    }
+  free (definedstrs);
+
+  /* Free the saved state.  */
+  free (ss);
+  r->savedstate = NULL;
+  
+  /* Write out the list of defined identifiers.  */
+  cpp_forall_identifiers (r, write_macdef, f);
+  memset (&z, 0, sizeof (z));
+  if (fwrite (&z, sizeof (z), 1, f) != 1)
+    {
+      cpp_errno (r, DL_ERROR, "while writing precompiled header");
+      return -1;
+    }
+
+  if (deps_save (r->deps, f) != 0)
+    {
+      cpp_errno (r, DL_ERROR, "while writing precompiled header");
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Return nonzero if FD is a precompiled header which is consistent
+   with the preprocessor's current definitions.  It will be consistent
+   when:
+
+   - anything that was defined just before the PCH was generated 
+     is defined the same way now; and
+   - anything that was not defined then, but is defined now, was not
+     used by the PCH.
+
+   NAME is used to print warnings if `warn_invalid_pch' is set in the
+   reader's flags.
+*/
+
+int
+cpp_valid_state (r, name, fd)
+     cpp_reader *r;
+     const char *name;
+     int fd;
+{
+  struct macrodef_struct m;
+  size_t namebufsz = 256;
+  unsigned char *namebuf = xmalloc (namebufsz);
+  unsigned char *undeftab = NULL;
+  unsigned int i;
+  
+  /* Read in the list of identifiers that must be defined
+     Check that they are defined in the same way.  */
+  for (;;)
+    {
+      cpp_hashnode *h;
+      const unsigned char *newdefn;
+      
+      if (read (fd, &m, sizeof (m)) != sizeof (m))
+	goto error;
+      
+      if (m.name_length == 0)
+	break;
+
+      if (m.definition_length > namebufsz)
+	{
+	  free (namebuf);
+	  namebufsz = m.definition_length + 256;
+	  namebuf = xmalloc (namebufsz);
+	}
+      
+      if ((size_t)read (fd, namebuf, m.definition_length) 
+	  != m.definition_length)
+	goto error;
+      
+      h = cpp_lookup (r, namebuf, m.name_length);
+      if (m.flags & NODE_POISONED
+	  || h->type != NT_MACRO
+	  || h->flags & NODE_POISONED)
+	{
+	  if (CPP_OPTION (r, warn_invalid_pch))
+	    cpp_error (r, DL_WARNING,
+		       "%s: not used because `%.*s' not defined",
+		       name, m.name_length, namebuf);
+	  goto fail;
+	}
+
+      newdefn = cpp_macro_definition (r, h);
+      
+      if (m.definition_length != ustrlen (newdefn)
+	  || memcmp (namebuf, newdefn, m.definition_length) != 0)
+	{
+	  if (CPP_OPTION (r, warn_invalid_pch))
+	    cpp_error (r, DL_WARNING, 
+	       "%s: not used because `%.*s' defined as `%s' not `%.*s'",
+		       name, m.name_length, namebuf, newdefn + m.name_length,
+		       m.definition_length - m.name_length,
+		       namebuf +  m.name_length);
+	  goto fail;
+	}
+    }
+  free (namebuf);
+  namebuf = NULL;
+
+  /* Read in the list of identifiers that must not be defined.
+     Check that they really aren't.  */
+  undeftab = xmalloc (m.definition_length);
+  if ((size_t) read (fd, undeftab, m.definition_length) != m.definition_length)
+    goto error;
+  for (i = 0; i < m.definition_length; )
+    {
+      int l = ustrlen (undeftab + i);
+      cpp_hashnode *h;
+      h = cpp_lookup (r, undeftab + i, l);
+      if (h->type != NT_VOID
+	  || h->flags & NODE_POISONED)
+	{
+	  if (CPP_OPTION (r, warn_invalid_pch))
+	    cpp_error (r, DL_WARNING, "%s: not used because `%s' is defined",
+		       name, undeftab + i);
+	  goto fail;
+	}
+      i += l + 1;
+    }
+  free (undeftab);
+
+  /* We win!  */
+  return 0;
+
+ error:
+  cpp_errno (r, DL_ERROR, "while reading precompiled header");
+  return -1;
+
+ fail:
+  if (namebuf != NULL)
+    free (namebuf);
+  if (undeftab != NULL)
+    free (undeftab);
+  return 1;
+}
+
+/* Given a precompiled header that was previously determined to be valid,
+   apply all its definitions (and undefinitions) to the current state. 
+   DEPNAME is passed to deps_restore.  */
+
+int
+cpp_read_state (r, name, f)
+     cpp_reader *r;
+     const char *name;
+     FILE *f;
+{
+  struct macrodef_struct m;
+  size_t defnlen = 256;
+  unsigned char *defn = xmalloc (defnlen);
+  struct lexer_state old_state;
+
+  old_state = r->state;
+
+  r->state.in_directive = 1;
+  r->state.prevent_expansion = 1;
+  r->state.angled_headers = 0;
+
+  /* Read in the identifiers that must be defined.  */
+  for (;;)
+    {
+      cpp_hashnode *h;
+      
+      if (fread (&m, sizeof (m), 1, f) != 1)
+	goto error;
+      
+      if (m.name_length == 0)
+	break;
+
+      if (defnlen < m.definition_length + 1)
+	{
+	  free (defn);
+	  defnlen = m.definition_length + 256;
+	  defn = xmalloc (m.definition_length);
+	}
+
+      if (fread (defn, 1, m.definition_length, f) != m.definition_length)
+	goto error;
+      defn[m.definition_length] = '\0';
+      
+      h = cpp_lookup (r, defn, m.name_length);
+
+      if (h->type == NT_MACRO)
+	_cpp_free_definition (h);
+      if (m.flags & NODE_POISONED)
+	h->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
+      else if (m.name_length != m.definition_length)
+	{
+	  if (cpp_push_buffer (r, defn + m.name_length, 
+			       m.definition_length - m.name_length, 
+			       true, 1) != NULL)
+	    {
+	      if (!_cpp_create_definition (r, h))
+		abort ();
+	      _cpp_pop_buffer (r);
+	    }
+	  else
+	    abort ();
+	}
+    }
+
+  r->state = old_state;
+  free (defn);
+  defn = NULL;
+
+  if (deps_restore (r->deps, f, CPP_OPTION (r, restore_pch_deps) ? name : NULL)
+      != 0)
+    goto error;
+
+  return 0;
+  
+ error:
+  cpp_errno (r, DL_ERROR, "while reading precompiled header");
+  return -1;
+}
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.76.2.6
diff -p -u -p -r1.76.2.6 flags.h
--- flags.h	25 Aug 2002 00:47:58 -0000	1.76.2.6
+++ flags.h	2 Sep 2002 00:22:00 -0000
@@ -226,10 +226,6 @@ extern int in_system_header;
    pattern and alternative used.  */
 
 extern int flag_print_asm_name;
-
-/* Print compiler version information.  -v.  */
-
-extern int version_flag;
 
 /* Now the symbols that are set with `-f' switches.  */
 
Index: mkdeps.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/mkdeps.c,v
retrieving revision 1.15
diff -p -u -p -r1.15 mkdeps.c
--- mkdeps.c	3 Aug 2001 15:42:25 -0000	1.15
+++ mkdeps.c	2 Sep 2002 00:22:00 -0000
@@ -289,3 +289,77 @@ deps_phony_targets (d, fp)
       putc ('\n', fp);
     }
 }
+
+/* Write out a deps buffer to a file, in a form that can be read back
+   with deps_restore.  Returns nonzero on error, in which case the
+   error number will be in errno.  */
+
+int
+deps_save (deps, f)
+     struct deps *deps;
+     FILE *f;
+{
+  unsigned int i;
+
+  /* The cppreader structure contains makefile dependences.  Write out this
+     structure.  */
+
+  /* The number of dependences.  */
+  if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
+      return -1;
+  /* The length of each dependence followed by the string.  */
+  for (i = 0; i < deps->ndeps; i++)
+    {
+      size_t num_to_write = strlen (deps->depv[i]);
+      if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
+          return -1;
+      if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
+          return -1;
+    }
+
+  return 0;
+}
+
+/* Read back dependency information written with deps_save into
+   the deps buffer.  The third argument may be NULL, in which case
+   the dependency information is just skipped, or it may be a filename,
+   in which case that filename is skipped.  */
+
+int
+deps_restore (deps, fd, self)
+     struct deps *deps;
+     FILE *fd;
+     const char *self;
+{
+  unsigned int i, count;
+  size_t num_to_read;
+  size_t buf_size = 512;
+  char *buf = (char *) xmalloc (buf_size);
+
+  /* Number of dependences.  */
+  if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
+    return -1;
+
+  /* The length of each dependence string, followed by the string.  */
+  for (i = 0; i < count; i++)
+    {
+      /* Read in # bytes in string.  */
+      if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
+	return -1;
+      if (buf_size < num_to_read + 1)
+	{
+	  buf_size = num_to_read + 1 + 127;
+	  buf = xrealloc (buf, buf_size);
+	}
+      if (fread (buf, 1, num_to_read, fd) != num_to_read)
+	return -1;
+      buf[num_to_read] = '\0';
+
+      /* Generate makefile dependencies from .pch if -nopch-deps.  */ 
+      if (self != NULL && strcmp (buf, self) != 0)
+        deps_add_dep (deps, buf);
+    }
+
+  free (buf);
+  return 0;
+}
Index: mkdeps.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/mkdeps.h,v
retrieving revision 1.4
diff -p -u -p -r1.4 mkdeps.h
--- mkdeps.h	26 May 2001 01:31:34 -0000	1.4
+++ mkdeps.h	2 Sep 2002 00:22:00 -0000
@@ -53,6 +53,17 @@ extern void deps_add_dep	PARAMS ((struct
 extern void deps_write		PARAMS ((const struct deps *, FILE *,
 					 unsigned int));
 
+/* Write out a deps buffer to a file, in a form that can be read back
+   with deps_restore.  Returns nonzero on error, in which case the
+   error number will be in errno.  */
+extern int deps_save		PARAMS ((struct deps *, FILE *));
+
+/* Read back dependency information written with deps_save into
+   the deps buffer.  The third argument may be NULL, in which case
+   the dependency information is just skipped, or it may be a filename,
+   in which case that filename is skipped.  */
+extern int deps_restore		PARAMS ((struct deps *, FILE *, const char *));
+
 /* For each dependency *except the first*, emit a dummy rule for that
    file, causing it to depend on nothing.  This is used to work around
    the intermediate-file deletion misfeature in Make, in some
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.571.2.10
diff -p -u -p -r1.571.2.10 toplev.c
--- toplev.c	25 Aug 2002 00:47:58 -0000	1.571.2.10
+++ toplev.c	2 Sep 2002 00:22:01 -0000
@@ -138,9 +138,6 @@ const char *progname;
 /* Copy of arguments to toplev_main.  */
 int save_argc;
 char **save_argv;
-
-/* A hook for last-second initialisations.  */
-void (*late_init_hook) PARAMS((void));
 
 /* Name of current original source file (what was input to cpp).
    This comes from each #-command in the actual input.  */
@@ -311,13 +308,10 @@ static void close_dump_file PARAMS ((enu
 
 int rtl_dump_and_exit;
 int flag_print_asm_name;
+static int version_flag;
 static char *filename;
 enum graph_dump_types graph_dump_format;
 
-/* Print compiler version information.  -v.  */
-
-int version_flag;
-
 /* Name for output file of assembly code, specified with -o.  */
 
 char *asm_file_name;
@@ -2128,10 +2122,6 @@ compile_file ()
 
   init_final (main_input_filename);
   init_branch_prob (aux_base_name);
-
-  /* Last call, time to go... */
-  if (late_init_hook)
-    late_init_hook ();
 
   timevar_push (TV_PARSE);
 
Index: toplev.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.h,v
retrieving revision 1.82.2.5
diff -p -u -p -r1.82.2.5 toplev.h
--- toplev.h	25 Aug 2002 00:47:59 -0000	1.82.2.5
+++ toplev.h	2 Sep 2002 00:22:01 -0000
@@ -115,9 +115,6 @@ extern int target_flags_explicit;
 /* The hashtable, so that the C front ends can pass it to cpplib.  */
 extern struct ht *ident_hash;
 
-/* A hook for last-second initialisations.  */
-extern void (*late_init_hook) PARAMS((void));
-
 /* This function can be used by targets to set the flags originally
     implied by -ffast-math and -fno-fast-math.  */
 
Index: doc/cppopts.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/cppopts.texi,v
retrieving revision 1.2.4.5
diff -p -u -p -r1.2.4.5 cppopts.texi
--- doc/cppopts.texi	13 Aug 2002 17:57:41 -0000	1.2.4.5
+++ doc/cppopts.texi	2 Sep 2002 00:22:01 -0000
@@ -303,6 +303,17 @@ a dependency output file as a side-effec
 Like @option{-MD} except mention only user header files, not system
 -header files.
 
+@ifclear cppmanual
+@item -fpch-deps
+@opindex fpch-deps
+When using precompiled headers (@pxref{Precompiled Headers}), this flag
+will cause the dependency-output flags to also list the files from the
+precompiled header's dependencies.  If not specified only the
+precompiled header would be listed and not the files that were used to
+create it because those files are not consulted when a precompiled
+header is used.
+
+@end ifclear
 @item -x c
 @itemx -x c++
 @itemx -x objective-c
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.107.2.9
diff -p -u -p -r1.107.2.9 invoke.texi
--- doc/invoke.texi	25 Aug 2002 00:48:00 -0000	1.107.2.9
+++ doc/invoke.texi	2 Sep 2002 00:22:03 -0000
@@ -221,7 +221,7 @@ in the following sections.
 -Wimplicit  -Wimplicit-int  @gol
 -Wimplicit-function-declaration @gol
 -Werror-implicit-function-declaration @gol
--Wimport  -Winline -Wno-endif-labels @gol
+-Wimport  -Winline  -Winvalid-pch  -Wno-endif-labels @gol
 -Wlarger-than-@var{len}  -Wlong-long @gol
 -Wmain  -Wmissing-braces  -Wmissing-declarations @gol
 -Wmissing-format-attribute  -Wmissing-noreturn @gol
@@ -2626,6 +2626,11 @@ code is to provide behavior which is sel
 @item -Winline
 @opindex Winline
 Warn if a function can not be inlined and it was declared as inline.
+
+@item -Winvalid-pch
+@opindex Winvalid-pch
+Warn if a precompiled header (@pxref{Precompiled Headers}) is found in
+the search path but can't be used.
 
 @item -Wlong-long
 @opindex Wlong-long
Index: testsuite/g++.dg/pch/pch.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/pch/Attic/pch.exp,v
retrieving revision 1.1.2.1
diff -p -u -p -r1.1.2.1 pch.exp
--- testsuite/g++.dg/pch/pch.exp	27 Aug 2002 23:58:29 -0000	1.1.2.1
+++ testsuite/g++.dg/pch/pch.exp	2 Sep 2002 00:22:05 -0000
@@ -36,23 +36,28 @@ foreach test [lsort [glob -nocomplain $s
 
     verbose "Testing $nshort" 1
 
+    catch { file delete "$bname.Hp.pch" }
+    catch { file delete "$bname.H.pch" }
+
     # For the header files, the default is to precompile.
     set old_dg_do_what_default "${dg-do-what-default}"
     set dg-do-what-default precompile
     dg-test -keep-output "[file rootname $test].H" "" ""
     set dg-do-what-default "$old_dg_do_what_default"
     
-    # To ensure that the PCH is used, not the original header,
-    # the actual PCH file is renamed to "<foo>.Hp.pch".
-    if { [ is_remote host ] } {
-	remote_upload host "$bname.H.pch" "$bname.Hp.pch"
-	file_on_host delete "$bname.H.pch"
-	remote_download host "$bname.Hp.pch"
-    } else {
+    if { [ file exists "$bname.H.pch" ] } {
+	# To ensure that the PCH is used, not the original header,
+	# the actual PCH file is renamed to "<foo>.hp.pch".
 	file rename "$bname.H.pch" "$bname.Hp.pch"
+	if { [ is_remote host ] } {
+	    remote_download host "$bname.Hp.pch"
+	}
+	
+	dg-test $test "" "-I."
+	file delete "$bname.Hp.pch"
+    } else {
+	untested $test
     }
-    dg-test $test "" "-I."
-    file delete "$bname.Hp.pch"
 }
 
 # All done.
Index: testsuite/gcc.dg/pch/macro-1.c
===================================================================
RCS file: testsuite/gcc.dg/pch/macro-1.c
diff -N testsuite/gcc.dg/pch/macro-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pch/macro-1.c	2 Sep 2002 00:22:06 -0000
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+
+#include "macro-1.hp"
+
+int main(void) 
+{
+  return DEFINED_VALUE + 1 - DEFINED_PARAM (3);
+}
Index: testsuite/gcc.dg/pch/macro-1.h
===================================================================
RCS file: testsuite/gcc.dg/pch/macro-1.h
diff -N testsuite/gcc.dg/pch/macro-1.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pch/macro-1.h	2 Sep 2002 00:22:06 -0000
@@ -0,0 +1,2 @@
+#define DEFINED_VALUE 3
+#define DEFINED_PARAM(x) (x+1)
Index: testsuite/gcc.dg/pch/macro-2.c
===================================================================
RCS file: testsuite/gcc.dg/pch/macro-2.c
diff -N testsuite/gcc.dg/pch/macro-2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pch/macro-2.c	2 Sep 2002 00:22:06 -0000
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+
+#define DEFINED_VALUE_2 3
+
+#include "macro-2.hp"
+
+int main(void) 
+{
+  return DEFINED_VALUE - DEFINED_VALUE_2;
+}
Index: testsuite/gcc.dg/pch/macro-2.h
===================================================================
RCS file: testsuite/gcc.dg/pch/macro-2.h
diff -N testsuite/gcc.dg/pch/macro-2.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pch/macro-2.h	2 Sep 2002 00:22:06 -0000
@@ -0,0 +1,2 @@
+#define DEFINED_VALUE 3
+
Index: testsuite/gcc.dg/pch/pch.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/pch/Attic/pch.exp,v
retrieving revision 1.1.2.1
diff -p -u -p -r1.1.2.1 pch.exp
--- testsuite/gcc.dg/pch/pch.exp	27 Aug 2002 23:58:29 -0000	1.1.2.1
+++ testsuite/gcc.dg/pch/pch.exp	2 Sep 2002 00:22:06 -0000
@@ -34,6 +34,9 @@ foreach test [lsort [glob -nocomplain $s
     set nshort [file tail [file dirname $test]]/[file tail $test]
     set bname "[file rootname [file tail $test]]"
 
+    catch { file delete "$bname.hp.pch" }
+    catch { file delete "$bname.h.pch" }
+
     # We don't try to use the loop-optimizing options, since they are highly
     # unlikely to make any difference to PCH.
     foreach flags $torture_without_loops {
@@ -45,17 +48,19 @@ foreach test [lsort [glob -nocomplain $s
 	dg-test -keep-output "[file rootname $test].h" $flags ""
 	set dg-do-what-default "$old_dg_do_what_default"
 
-	# To ensure that the PCH is used, not the original header,
-	# the actual PCH file is renamed to "<foo>.hp.pch".
-	if { [ is_remote host ] } {
-	    remote_upload host "$bname.h.pch" "$bname.hp.pch"
-	    file_on_host delete "$bname.h.pch"
-	    remote_download host "$bname.hp.pch"
-	} else {
+	if { [ file exists "$bname.h.pch" ] } {
+	    # To ensure that the PCH is used, not the original header,
+	    # the actual PCH file is renamed to "<foo>.hp.pch".
 	    file rename "$bname.h.pch" "$bname.hp.pch"
+	    if { [ is_remote host ] } {
+		remote_download host "$bname.hp.pch"
+	    }
+
+	    dg-test $test $flags "-I."
+	    file delete "$bname.hp.pch"
+	} else {
+	    untested $test
 	}
-	dg-test $test $flags "-I."
-	file delete "$bname.hp.pch"
     }
 }
 
============================================================


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]