This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PCH] cpp & dependencies
- From: Geoffrey Keating <geoffk at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: clm at redhat dot com
- Date: Sun, 1 Sep 2002 17:34:24 -0700
- Subject: [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"
}
}
============================================================