===================================================================
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.
#include "splay-tree.h"
#include "plugin.h"
#include "langhooks.h"
+#include "pph.h"
/* Possible cases of bad specifiers type used by bad_specifiers. */
enum bad_spec_place {
===================================================================
@@ -81,7 +81,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.
cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o tree-mudflap.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/pph.o tree-mudflap.o $(CXX_C_OBJS)
# Language-specific object files for C++.
CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -243,19 +243,23 @@ CXX_TREE_H = $(TREE_H) cp/name-lookup.h
$(FUNCTION_H) \
$(SYSTEM_H) coretypes.h $(CONFIG_H) $(TARGET_H) $(GGC_H) \
$(srcdir)/../include/hashtab.h
-
+CXX_PARSER_H = tree.h c-family/c-pragma.h cp/parser.h
CXX_PRETTY_PRINT_H = cp/cxx-pretty-print.h $(C_PRETTY_PRINT_H)
+CXX_PPH_H = $(srcdir)/../libcpp/include/line-map.h $(HASHTAB_H) \
+ $(CXX_PARSER_H) $(TIMEVAR_H) cp/pph.h
cp/lex.o: cp/lex.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \
$(C_PRAGMA_H) toplev.h output.h input.h cp/operators.def $(TM_P_H)
cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H) $(TM_H) toplev.h debug.h langhooks.h \
$(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-cp.h gt-cp-cp-lang.h \
- cp/cp-objcp-common.h $(EXPR_H) $(TARGET_H)
+ cp/cp-objcp-common.h $(EXPR_H) $(TARGET_H) $(CXX_PARSER_H) \
+ $(CXX_PPH_H)
cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \
output.h toplev.h $(HASHTAB_H) $(RTL_H) \
cp/operators.def $(TM_P_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(C_PRAGMA_H) \
debug.h gt-cp-decl.h $(TIMEVAR_H) $(TARGET_H) $(PLUGIN_H) \
- intl.h tree-iterator.h $(SPLAY_TREE_H) langhooks.h
+ intl.h tree-iterator.h $(SPLAY_TREE_H) langhooks.h \
+ $(CXX_PPH_H)
cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \
output.h toplev.h $(C_COMMON_H) gt-cp-decl2.h $(CGRAPH_H) \
$(C_PRAGMA_H) $(TREE_DUMP_H) intl.h $(TARGET_H) $(GIMPLE_H) $(POINTER_SET_H) \
@@ -273,7 +277,8 @@ cp/class.o: cp/class.c $(CXX_TREE_H) $(T
$(TARGET_H) convert.h $(CGRAPH_H) $(TREE_DUMP_H) gt-cp-class.h \
$(SPLAY_TREE_H)
cp/call.o: cp/call.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) toplev.h \
- $(DIAGNOSTIC_CORE_H) intl.h gt-cp-call.h convert.h $(TARGET_H) langhooks.h
+ $(DIAGNOSTIC_CORE_H) intl.h gt-cp-call.h convert.h $(TARGET_H) langhooks.h \
+ $(CXX_PPH_H)
cp/friend.o: cp/friend.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) toplev.h
cp/init.o: cp/init.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \
toplev.h $(EXCEPT_H) $(TARGET_H)
@@ -293,7 +298,8 @@ cp/except.o: cp/except.c $(CXX_TREE_H) $
toplev.h cp/cfns.h $(TREE_INLINE_H) $(TARGET_H)
cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) toplev.h $(TM_P_H)
cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/cp-objcp-common.h \
- toplev.h $(TREE_INLINE_H) pointer-set.h gt-cp-pt.h vecprim.h intl.h
+ toplev.h $(TREE_INLINE_H) pointer-set.h gt-cp-pt.h vecprim.h intl.h \
+ $(CXX_PPH_H)
cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) toplev.h $(DIAGNOSTIC_H) \
$(FLAGS_H) $(REAL_H) $(LANGHOOKS_DEF_H) $(CXX_PRETTY_PRINT_H) \
tree-diagnostic.h tree-pretty-print.h
@@ -312,13 +318,19 @@ cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $
cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_CORE_H) \
gt-cp-parser.h output.h $(TARGET_H) $(PLUGIN_H) intl.h \
pointer-set.h fixed-value.h $(MD5_H) $(HASHTAB_H) tree-pass.h \
- $(TREE_INLINE_H) tree-pretty-print.h
+ $(TREE_INLINE_H) tree-pretty-print.h $(CXX_PARSER_H) \
+ $(CXX_PPH_H)
cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) toplev.h $(C_COMMON_H) \
$(TM_H) coretypes.h pointer-set.h tree-iterator.h
cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h toplev.h \
- $(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h tree-pretty-print.h
+ $(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h tree-pretty-print.h \
+ $(CXX_PPH_H)
cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \
$(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h
+cp/pph.c: cp/pph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) \
+ toplev.h $(TREE_H) $(CXX_TREE_H) $(TIMEVAR_H) pointer-set.h \
+ fixed-value.h $(TREE_PASS_H) $(TREE_INLINE_H) tree-pretty-print.h \
+ $(CXX_PARSER_H) $(CXX_PPH_H)
===================================================================
@@ -0,0 +1,4137 @@
+/* Factored pre-tokenized header (PTH) support for C++
+ Copyright (C) 2010 Free Software Foundation, Inc.
+ Contributed by Lawrence Crowl <crowl@google.com> and
+ Diego Novillo <dnovillo@google.com>.
+
+ 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "cpplib.h"
+#include "toplev.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "timevar.h"
+#include "pointer-set.h"
+#include "fixed-value.h"
+#include "md5.h"
+#include "tree-pass.h"
+#include "tree-inline.h"
+#include "tree-pretty-print.h"
+#include "parser.h"
+#include "pph.h"
+
+/* Statistics collected for PTH/PPH. */
+struct pth_stats_d pth_stats;
+struct pph_stats_d pph_stats;
+
+/* Forward declarations to solve cyclical references. */
+static void pph_print_trees_tokens (VEC(tree,heap) *, cp_token *, cp_token *);
+
+/* Map of decl dependencies. */
+static struct pph_decl_deps_d *pph_decl_deps = NULL;
+
+/* Tree catcher for the incremental compiler. Whenever this array is
+ allocated, make_node_stat() will push certain trees into this array. */
+static VEC(tree,heap) *pph_tree_catcher = NULL;
+
+/* Catcher for name lookups. This stores every name lookup performed
+ on identifiers while we are catching ASTs in the parser. */
+static VEC(tree,heap) *pph_name_lookups = NULL;
+
+/* Since identifiers may be looked up more than once during parsing,
+ this set prevents duplicate symbols from being placed in
+ pph_name_lookups. */
+static struct pointer_set_t *pph_name_lookups_set = NULL;
+
+/* This map stores the token locations where a given symbol was looked
+ up. When an identifier is looked up and resolved to symbol S, we
+ check where the current token pointer is and save it in a vector
+ associated with S. */
+static struct pointer_map_t *pph_nl_token_map = NULL;
+
+/* Log file where PPH analysis is written to. Controlled by
+ -fpph_logfile. If this flag is not given, stdout is used. */
+FILE *pph_logfile = NULL;
+
+/* Cache of token ranges for head of symbol declarations. For each
+ *_DECL tree intercepted during parsing, we store the vector of
+ tokens that make up the head of the declaration for the node. */
+static struct pointer_map_t *pph_decl_head_token_cache = NULL;
+
+/* Cache of token ranges for body of symbol declarations. For each
+ *_DECL tree intercepted during parsing, we store the vector of
+ tokens that make up the body of the declaration for the node. */
+static struct pointer_map_t *pph_decl_body_token_cache = NULL;
+
+
+/* Return true if path P1 and path P2 point to the same file. */
+
+static inline bool
+pathnames_equal_p (const char *p1, const char *p2)
+{
+ return strcmp (lrealpath (p1), lrealpath (p2)) == 0;
+}
+
+/* Expand and print location LOC to FILE. If FILE is NULL, pph_logfile
+ is used. */
+
+static void
+pph_debug_location (FILE *file, location_t loc)
+{
+ expanded_location xloc;
+ file = (file) ? file : pph_logfile;
+ xloc = expand_location (loc);
+ fprintf (file, "%s:%d:%d", lrealpath (xloc.file), xloc.line, xloc.column);
+}
+
+
+/* Expand and print the location of tree T to FILE. If FILE is NULL,
+ pph_logfile is used. */
+
+static void
+pph_debug_loc_of_tree (FILE *file, tree t)
+{
+ pph_debug_location (file, DECL_SOURCE_LOCATION (t));
+}
+
+
+/* Hash and comparison functions for the directory of cached images. */
+
+static hashval_t
+pth_image_dir_hash (const void *p)
+{
+ const char *s = lrealpath (((const pth_image *)p)->fname);
+ return htab_hash_string (s);
+}
+
+
+static int
+pth_image_dir_eq (const void *p1, const void *p2)
+{
+ const char *s1 = ((const pth_image *)p1)->fname;
+ const char *s2 = ((const pth_image *)p2)->fname;
+ return pathnames_equal_p (s1, s2);
+}
+
+
+static GTY(()) pth_state *pth_global_state = NULL;
+
+/* Return the global PTH state where the cache and its directory
+ are stored. */
+
+pth_state *
+pth_get_state (void)
+{
+ if (pth_global_state == NULL)
+ {
+ pth_global_state = ggc_alloc_cleared_pth_state ();
+ pth_global_state->cache_dir = htab_create_ggc (10, pth_image_dir_hash,
+ pth_image_dir_eq, NULL);
+ }
+
+ return pth_global_state;
+}
+
+
+/* Return an identification string for a PTH image. */
+
+static const char *
+pth_id_str (void)
+{
+ /* FIXME pph - Build a better identification string. */
+ return "PTH0x42";
+}
+
+
+/* Return the number of bytes taken by the header of a PTH image. */
+
+static size_t
+pth_header_len (void)
+{
+ /* The header of a PTH image contains:
+ - An identification string (pth_id_str ())
+ - The MD5 digest for the source file associated with the image.
+ */
+ return strlen (pth_id_str ()) + DIGEST_LEN;
+}
+
+
+#define PTH_EXTENSION ".pth"
+
+/* Return a new string with the extension PTH_EXTENSION appended to NAME. The
+ caller is responsible for freeing the returned string. */
+
+static char *
+pth_name_for (const char *name)
+{
+ size_t i, len;
+ char *s;
+
+ len = strlen (name) + sizeof (PTH_EXTENSION) + 1;
+ s = XCNEWVEC (char, len);
+ sprintf (s, "%s" PTH_EXTENSION, name);
+
+ /* Make the file name unique and store it in the current directory. */
+ for (i = 0; i < len - sizeof (PTH_EXTENSION) - 1; i++)
+ if (!ISALNUM (s[i]))
+ s[i] = '_';
+
+ return s;
+}
+
+
+/* Open an image file for path NAME with MODE. */
+
+static FILE *
+pth_file_for (const char *name, const char *mode)
+{
+ char *s;
+ FILE *f;
+
+ s = pth_name_for (name);
+ f = fopen (s, mode);
+ if (f == NULL)
+ fatal_error ("can%'t open token stream file %s: %m", s);
+ free (s);
+
+ return f;
+}
+
+
+/* Compute the MD5 digest for FNAME. Store it in DIGEST. */
+
+static void
+pth_get_md5_digest (const char *fname, unsigned char digest[DIGEST_LEN])
+{
+ if (flag_pth_md5)
+ {
+ FILE *f;
+
+ timevar_push (TV_PTH_MD5);
+
+ f = fopen (fname, "rb");
+ if (f == NULL)
+ fatal_error ("Cannot open %s for computing its digest: %m", fname);
+
+ md5_stream (f, digest);
+
+ fclose (f);
+
+ timevar_pop (TV_PTH_MD5);
+ }
+ else
+ {
+ struct stat buf;
+
+ if (stat (fname,&buf) != 0)
+ fatal_error ("Cannot stat %s: %m", fname);
+
+ memset (digest, 0, DIGEST_LEN);
+ memcpy (digest, &buf.st_mtime, sizeof (buf.st_mtime));
+ }
+}
+
+
+/* Compute an index value for TYPE suitable for restoring it later
+ from global_trees[] or integer_types. The index is saved
+ in TYPE_IX_P and the number category (one of CPP_N_INTEGER,
+ CPP_N_FLOATING, etc) is saved in CATEGORY_P. */
+
+static void
+pth_get_index_from_type (tree type, unsigned *type_ix_p, unsigned *category_p)
+{
+ void **val_p;
+ static struct pointer_map_t *type_cache = NULL;
+
+ /* For complex types we will just use the type of the components. */
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ {
+ *type_ix_p = 0;
+ *category_p = CPP_N_IMAGINARY;
+ return;
+ }
+
+ if (type_cache == NULL)
+ type_cache = pointer_map_create ();
+
+ val_p = pointer_map_contains (type_cache, type);
+ if (val_p)
+ *type_ix_p = *((unsigned *) val_p);
+ else
+ {
+ if (CP_INTEGRAL_TYPE_P (type))
+ {
+ unsigned i;
+ for (i = itk_char; i < itk_none; i++)
+ if (type == integer_types[i])
+ {
+ *type_ix_p = (unsigned) i;
+ break;
+ }
+
+ gcc_assert (i != itk_none);
+ }
+ else if (FLOAT_TYPE_P (type) || FIXED_POINT_TYPE_P (type))
+ {
+ unsigned i;
+
+ for (i = TI_ERROR_MARK; i < TI_MAX; i++)
+ if (global_trees[i] == type)
+ {
+ *type_ix_p = (unsigned) i;
+ break;
+ }
+
+ gcc_assert (i != TI_MAX);
+ }
+ else
+ gcc_unreachable ();
+ }
+
+ if (CP_INTEGRAL_TYPE_P (type))
+ *category_p = CPP_N_INTEGER;
+ else if (FLOAT_TYPE_P (type))
+ *category_p = CPP_N_FLOATING;
+ else if (FIXED_POINT_TYPE_P (type))
+ *category_p = CPP_N_FRACT;
+ else
+ gcc_unreachable ();
+}
+
+
+/* Write a uint VALUE to the STREAM. Return the number of bytes written. */
+
+static inline size_t
+pth_write_uint (unsigned int value, FILE *stream)
+{
+ size_t sent = fwrite (&value, 1, sizeof (value), stream);
+ gcc_assert (sent == sizeof (value));
+ return sent;
+}
+
+
+/* Write a size_t VALUE to the STREAM. Return the number of bytes written. */
+
+static inline size_t
+pth_write_sizet (size_t value, FILE *stream)
+{
+ size_t sent = fwrite (&value, 1, sizeof (value), stream);
+ gcc_assert (sent == sizeof (value));
+ return sent;
+}
+
+
+/* Write N bytes from P to STREAM. */
+
+static inline size_t
+pth_write_bytes (const void *p, size_t n, FILE *stream)
+{
+ size_t sent = fwrite (p, 1, n, stream);
+ gcc_assert (sent == n);
+ return sent;
+}
+
+
+/* Write string STR and its LENGTH to STREAM. */
+
+static inline size_t
+pth_write_string (const char *str, unsigned int length, FILE *stream)
+{
+ size_t sent;
+
+ if (str == NULL)
+ sent = pth_write_uint (-1, stream);
+ else
+ {
+ sent = pth_write_uint (length, stream);
+ if (length > 0)
+ sent += pth_write_bytes (str, length, stream);
+ }
+
+ return sent;
+}
+
+
+/* Save the number VAL to file F. Return the number of bytes written. */
+
+static size_t
+pth_write_number (tree val, FILE *f)
+{
+ unsigned type_idx, type_kind;
+ size_t nbytes;
+
+ pth_get_index_from_type (TREE_TYPE (val), &type_idx, &type_kind);
+
+ nbytes = 0;
+ nbytes += pth_write_uint (type_idx, f);
+ nbytes += pth_write_uint (type_kind, f);
+
+ if (type_kind == CPP_N_INTEGER)
+ {
+ HOST_WIDE_INT v[2];
+
+ v[0] = TREE_INT_CST_LOW (val);
+ v[1] = TREE_INT_CST_HIGH (val);
+ nbytes += pth_write_bytes (v, 2 * sizeof (HOST_WIDE_INT), f);
+ }
+ else if (type_kind == CPP_N_FLOATING)
+ {
+ REAL_VALUE_TYPE r = TREE_REAL_CST (val);
+ nbytes += pth_write_bytes (&r, sizeof (REAL_VALUE_TYPE), f);
+ }
+ else if (type_kind == CPP_N_FRACT)
+ {
+ FIXED_VALUE_TYPE fv = TREE_FIXED_CST (val);
+ nbytes += pth_write_bytes (&fv, sizeof (FIXED_VALUE_TYPE), f);
+ }
+ else if (type_kind == CPP_N_IMAGINARY)
+ {
+ pth_write_number (TREE_REALPART (val), f);
+ pth_write_number (TREE_IMAGPART (val), f);
+ }
+ else
+ gcc_unreachable ();
+
+ return nbytes;
+}
+
+
+/* Save the tree associated with TOKEN to file F. Return the number
+ of bytes written. */
+
+static size_t
+pth_save_token_value (cp_token *token, FILE *f)
+{
+ const char *str;
+ size_t nbytes;
+ unsigned len;
+ tree val;
+
+ val = token->u.value;
+ nbytes = 0;
+ switch (token->type)
+ {
+ case CPP_TEMPLATE_ID:
+ case CPP_NESTED_NAME_SPECIFIER:
+ break;
+
+ case CPP_NAME:
+ /* FIXME pph. Hash the strings and emit a string table. */
+ str = IDENTIFIER_POINTER (val);
+ len = IDENTIFIER_LENGTH (val);
+ nbytes += pth_write_string (str, len, f);
+ break;
+
+ case CPP_KEYWORD:
+ /* Nothing to do. We will reconstruct the keyword from
+ ridpointers[token->keyword] at load time. */
+ break;
+
+ case CPP_CHAR:
+ case CPP_WCHAR:
+ case CPP_CHAR16:
+ case CPP_CHAR32:
+ case CPP_NUMBER:
+ nbytes += pth_write_number (val, f);
+ break;
+
+ case CPP_STRING:
+ case CPP_WSTRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ /* FIXME pph. Need to represent the type. */
+ str = TREE_STRING_POINTER (val);
+ len = TREE_STRING_LENGTH (val);
+ nbytes += pth_write_string (str, len, f);
+ break;
+
+ case CPP_PRAGMA:
+ /* Nothing to do. Field pragma_kind has already been written. */
+ break;
+
+ default:
+ gcc_assert (token->u.value == NULL);
+ nbytes += pth_write_bytes (&token->u.value, sizeof (token->u.value), f);
+ }
+
+ return nbytes;
+}
+
+
+/* Save TOKEN on file F. Return the number of bytes written on F. */
+
+static size_t
+pth_save_token (cp_token *token, FILE *f)
+{
+ size_t nbytes;
+
+ /* Do not write out the final field in TOKEN. It contains
+ pointers that need to be pickled separately.
+
+ FIXME pph - Need to also emit the location_t table so we can
+ reconstruct it when reading the PTH state. */
+ nbytes = pth_write_bytes (token, sizeof (cp_token) - sizeof (void *), f);
+ nbytes += pth_save_token_value (token, f);
+
+ return nbytes;
+}
+
+
+/* Write header information for IMAGE to STREAM. */
+
+static void
+pth_write_header (pth_image *image, FILE *stream)
+{
+ size_t nbytes;
+ const char *id = pth_id_str ();
+
+ if (!image->digest_computed_p)
+ {
+ pth_get_md5_digest (image->fname, image->digest);
+ image->digest_computed_p = true;
+ }
+
+ nbytes = pth_write_bytes (id, strlen (id), stream);
+ nbytes += pth_write_bytes (image->digest, DIGEST_LEN, stream);
+
+ gcc_assert (nbytes == pth_header_len ());
+}
+
+/* Dump a table of IDENTIFIERS to the STREAM. */
+
+static void
+pth_dump_identifiers (FILE *stream, cpp_idents_used *identifiers)
+{
+ unsigned int idx, col = 1;
+
+ fprintf (stream, "%u identifiers up to %u chars\n",
+ identifiers->num_entries, identifiers->max_length);
+ for (idx = 0; idx < identifiers->num_entries; ++idx)
+ {
+ cpp_ident_use *ident = identifiers->entries + idx;
+
+ if (col + ident->ident_len >= 80)
+ {
+ fprintf (stream, "\n");
+ col = 1;
+ }
+ if (ident->before_str || ident->after_str)
+ {
+ if (col > 1)
+ fprintf (stream, "\n");
+ fprintf (stream, " %s = %s -> %s\n", ident->ident_str,
+ ident->before_str, ident->after_str);
+ col = 1;
+ }
+ else
+ {
+ fprintf (stream, " %s", ident->ident_str);
+ col += ident->ident_len;
+ }
+ }
+ fprintf (stream, "\n");
+}
+
+/* Dump a debug log of the IDENTIFIERS. */
+
+void
+pth_debug_identifiers (cpp_idents_used *identifiers);
+
+void
+pth_debug_identifiers (cpp_idents_used *identifiers)
+{
+ pth_dump_identifiers (stderr, identifiers);
+}
+
+/* Dump a HUNK to the STREAM. */
+
+static void
+pth_dump_hunk (FILE *stream, cp_token_hunk *hunk)
+{
+ fprintf (stream, "Hunk location: { %lu, %lu, %lu }\n", hunk->text_offset.cur,
+ hunk->text_offset.line_base, hunk->text_offset.next_line);
+ fprintf (stream, "Hunk length: %lu characters\n", hunk->text_length);
+ pth_dump_identifiers (stream, &hunk->identifiers);
+ cp_lexer_dump_tokens (stream, hunk->buffer, 0);
+}
+
+/* Dump a debug log of the HUNK. */
+
+static void
+pth_debug_hunk (cp_token_hunk *hunk)
+{
+ pth_dump_hunk (stderr, hunk);
+}
+
+
+/* Dump #include command INCLUDE to FILE. */
+
+static void
+pth_dump_include (FILE *f, pth_include *include)
+{
+ if (include == NULL)
+ return;
+
+ if (include->itype == IT_INCLUDE)
+ fprintf (f, "#include ");
+ else if (include->itype == IT_INCLUDE_NEXT)
+ fprintf (f, "#include_next ");
+ else if (include->itype == IT_IMPORT)
+ fprintf (f, "#import ");
+ else
+ fprintf (f, "#??? ");
+
+ fprintf (f, "%c%s%c",
+ (include->angle_brackets) ? '<' : '"',
+ include->iname,
+ (include->angle_brackets) ? '>' : '"');
+
+ fprintf (f, " (found in %s)\n", include->dname);
+}
+
+
+/* Dump #include command INCLUDE to stderr. */
+
+static void
+pth_debug_include (pth_include *include)
+{
+ pth_dump_include (stderr, include);
+}
+
+
+/* Recursive helper for pth_dump_token_hunks_1. VISITED keeps track of
+ images that have already been dumped to avoid infinite recursion. */
+
+static void
+pth_dump_token_hunks_1 (FILE *f, pth_image *image,
+ struct pointer_set_t *visited)
+{
+ unsigned i, h_ix, i_ix;
+ char s;
+
+ if (pointer_set_insert (visited, image))
+ return;
+
+ fprintf (f, "LC_ENTER: %s {\n", image->fname);
+
+ for (i = 0, h_ix = 0, i_ix = 0;
+ VEC_iterate (char, image->ih_sequence, i, s);
+ i++)
+ {
+ if (s == 'H')
+ {
+ cp_token_hunk *hunk;
+ hunk = VEC_index (cp_token_hunk_ptr, image->token_hunks, h_ix++);
+ pth_dump_hunk (f, hunk);
+ }
+ else if (s == 'I')
+ {
+ pth_include *include;
+ include = VEC_index (pth_include_ptr, image->includes, i_ix++);
+ pth_dump_include (f, include);
+ pth_dump_token_hunks_1 (f, include->image, visited);
+ }
+ }
+
+ fprintf (f, "LC_LEAVE: %s }\n", image->fname);
+}
+
+
+/* Dump all the tokens in IMAGE and the files included by it to F. */
+
+static void
+pth_dump_token_hunks (FILE *f, pth_image *image)
+{
+ struct pointer_set_t *visited = pointer_set_create ();
+ pth_dump_token_hunks_1 (f, image, visited);
+ pointer_set_destroy (visited);
+}
+
+
+/* Dump all the tokens in IMAGE and the files included by it to stderr. */
+
+void
+pth_debug_token_hunks (pth_image *image)
+{
+ pth_dump_token_hunks (stderr, image);
+}
+
+
+/* Dump a debugging representation of IMAGE to F. */
+
+static void
+pth_dump_image (FILE *f, pth_image *image)
+{
+ unsigned i;
+ cp_token_hunk *hunk;
+ pth_include *include;
+ char s;
+
+ if (image == NULL)
+ return;
+
+ fprintf (f, "Image for: %s\n", image->fname);
+
+ fprintf (f, " MD5 digest: ");
+ if (image->digest_computed_p)
+ {
+ for (i = 0; i < DIGEST_LEN; i++)
+ fprintf (f, "%02x", image->digest[i]);
+ fprintf (f, "\n");
+ }
+ else
+ fprintf (f, "NOT COMPUTED\n");
+
+ fprintf (f, " %u token hunks: { ",
+ VEC_length (cp_token_hunk_ptr, image->token_hunks));
+ for (i = 0; VEC_iterate (cp_token_hunk_ptr, image->token_hunks, i, hunk); i++)
+ fprintf (f, "%u ", VEC_length (cp_token, hunk->buffer));
+ fprintf (f, "}\n");
+
+ fprintf (f, " %u includes:\n",
+ VEC_length (pth_include_ptr, image->includes));
+ for (i = 0; VEC_iterate (pth_include_ptr, image->includes, i, include); i++)
+ {
+ fprintf (f, "\t");
+ pth_dump_include (f, include);
+ }
+
+ fprintf (f, " Include-Hunk (IH) sequence: ");
+ for (i = 0; VEC_iterate (char, image->ih_sequence, i, s); i++)
+ fputc (s, f);
+ fputc ('\n', f);
+
+ if (image->loaded_p)
+ fprintf (f, " Instantiated from image: %s\n", pth_name_for (image->fname));
+ else
+ {
+ fprintf (f, " Instantiated from character stream: %s\n", image->fname);
+
+ if (image->save_p)
+ fprintf (f, " Will be saved to image: %s\n",
+ pth_name_for (image->fname));
+ else
+ fprintf (f, " Will NOT be saved to an image (not include-guarded)\n");
+ }
+
+ if (image->used_p)
+ fprintf (f, " Image already applied to current compilation context\n");
+
+ if (flag_pth_debug >= 4)
+ pth_dump_token_hunks (f, image);
+}
+
+
+/* Dump a debugging representation of IMAGE to stderr. */
+
+static void
+pth_debug_image (pth_image *image)
+{
+ pth_dump_image (stderr, image);
+}
+
+
+/* Show statistics for PTH image IMAGE on FILE. if FILE is NULL, use
+ pph_logfile. */
+
+static void
+pth_show_image_stats (FILE *file, pth_image *image)
+{
+ unsigned i, num_tokens;
+ cp_token_hunk *hunk;
+
+ if (image == NULL)
+ return;
+
+ if (file == NULL)
+ file = pph_logfile;
+
+ num_tokens = 0;
+ for (i = 0; VEC_iterate (cp_token_hunk_ptr, image->token_hunks, i, hunk); i++)
+ num_tokens += VEC_length (cp_token, hunk->buffer);
+
+ fprintf (file, "%s: %u tokens, %u token hunks\n", image->fname, num_tokens,
+ VEC_length (cp_token_hunk_ptr, image->token_hunks));
+}
+
+
+/* Dump the current PTH state to F. */
+
+static void
+pth_dump_state (FILE *f)
+{
+ unsigned i;
+ pth_state *state;
+ pth_image *image;
+
+ state = pth_get_state ();
+ fprintf (f, "Incremental compilation state\n\n");
+ fprintf (f, "%u file images\n", VEC_length (pth_image_ptr, state->cache));
+ for (i = 0; VEC_iterate (pth_image_ptr, state->cache, i, image); i++)
+ pth_dump_image (f, image);
+
+ fprintf (f, "\nCurrent image being processed: %s\n",
+ (state->cur_image) ? state->cur_image->fname : "NONE");
+
+ if (state->lexer)
+ {
+ fprintf (f, "Tokens in main lexer:\n");
+ cp_lexer_dump_tokens (f, state->lexer->buffer, 0);
+ }
+}
+
+
+/* Dump the current PTH state to stderr. */
+
+void
+pth_debug_state (void)
+{
+ pth_dump_state (stderr);
+}
+
+
+/* Save the IDENTIFIERS to the STREAM. */
+
+static void
+pth_save_identifiers (cpp_idents_used *identifiers, FILE *stream)
+{
+ unsigned int num_entries, id;
+
+ num_entries = identifiers->num_entries;
+ pth_write_uint (identifiers->max_length, stream);
+ pth_write_uint (num_entries, stream);
+
+ for ( id = 0; id < num_entries; ++id )
+ {
+ cpp_ident_use *entry = identifiers->entries + id;
+
+ gcc_assert (entry->ident_len <= identifiers->max_length);
+ pth_write_string (entry->ident_str, entry->ident_len, stream);
+
+ gcc_assert (entry->before_len <= identifiers->max_length);
+ pth_write_string (entry->before_str, entry->before_len, stream);
+
+ gcc_assert (entry->after_len <= identifiers->max_length);
+ pth_write_string (entry->after_str, entry->after_len, stream);
+ }
+}
+
+/* Save the HUNK to the STREAM. */
+
+static void
+pth_save_hunk (cp_token_hunk *hunk, FILE *stream)
+{
+ unsigned j;
+ cp_token *token;
+
+ if (flag_pth_debug >= 5)
+ pth_debug_hunk (hunk);
+
+ /* Write out the identifiers used by HUNK. */
+ pth_save_identifiers (&hunk->identifiers, stream);
+
+ /* Write the offset into the text file where this token starts. */
+ pth_write_sizet (hunk->text_offset.cur, stream);
+ pth_write_sizet (hunk->text_offset.line_base, stream);
+ pth_write_sizet (hunk->text_offset.next_line, stream);
+
+ /* Write the length of the hunk. */
+ pth_write_sizet (hunk->text_length, stream);
+
+ /* Write the number of tokens in HUNK. */
+ pth_write_uint (VEC_length (cp_token, hunk->buffer), stream);
+
+ /* Write the tokens. */
+ for (j = 0; VEC_iterate (cp_token, hunk->buffer, j, token); j++)
+ pth_save_token (token, stream);
+}
+
+
+/* Save the #include directive INCLUDE to STREAM. */
+
+static void
+pth_save_include (pth_include *include, FILE *stream)
+{
+ pth_write_string (include->image->fname, strlen (include->image->fname),
+ stream);
+ pth_write_uint ((unsigned int) include->itype, stream);
+ pth_write_uint (include->angle_brackets, stream);
+ pth_write_string (include->iname, strlen (include->iname), stream);
+ pth_write_string (include->dname,
+ include->dname ? strlen (include->dname) : 0,
+ stream);
+}
+
+
+/* Save the PTH image IMAGE to a file. */
+
+static void
+pth_save_image (pth_image *image)
+{
+ FILE *stream;
+ cp_token_hunk *hunk;
+ unsigned i, num;
+ char *buf;
+ pth_include *include;
+
+ timevar_push (TV_PTH_SAVE);
+
+ /* Open the stream in append mode since we have already created
+ it in pth_new_image. */
+ stream = pth_file_for (image->fname, "wb");
+
+ /* Write an invalid header first to avoid leaving a seemingly
+ valid file in case of failure. */
+ buf = XCNEWVEC (char, pth_header_len ());
+ pth_write_bytes (buf, pth_header_len (), stream);
+
+ /* Write the include-hunk (IH) sequencing vector. */
+ num = VEC_length (char, image->ih_sequence);
+ pth_write_uint (num, stream);
+ if (num > 0)
+ pth_write_bytes (VEC_address (char, image->ih_sequence), num, stream);
+
+ /* Write the number of #include commands. */
+ pth_write_uint (VEC_length (pth_include_ptr, image->includes), stream);
+
+ /* Write all the #include commands used by IMAGE. */
+ for (i = 0; VEC_iterate (pth_include_ptr, image->includes, i, include); i++)
+ pth_save_include (include, stream);
+
+ /* Write the number of token caches in the cache. */
+ pth_write_uint (VEC_length (cp_token_hunk_ptr, image->token_hunks), stream);
+
+ /* Write all the token hunks in image. */
+ for (i = 0; VEC_iterate (cp_token_hunk_ptr, image->token_hunks, i, hunk); i++)
+ pth_save_hunk (hunk, stream);
+
+ /* Now write a valid header. */
+ fseek (stream, 0, SEEK_SET);
+ pth_write_header (image, stream);
+
+ /* Clean up. */
+ fclose (stream);
+ free (buf);
+ image->save_p = false;
+
+ if (flag_pth_debug >= 3)
+ {
+ fprintf (stderr, "\nSaved image for %s:\n", image->fname);
+ pth_debug_image (image);
+ }
+
+ timevar_pop (TV_PTH_SAVE);
+}
+
+
+/* Given a type index TYPE_IDX and TYPE_KIND specifying the kind of type,
+ return a type from integer_types or global_trees. */
+
+static tree
+pth_get_type_from_index (unsigned type_idx, unsigned type_kind)
+{
+ if (type_kind == CPP_N_INTEGER)
+ return integer_types[type_idx];
+ else if (type_kind == CPP_N_FLOATING || type_kind == CPP_N_FRACT)
+ return global_trees[type_idx];
+ else if (type_kind == CPP_N_IMAGINARY)
+ {
+ /* We don't need a type for the complex number. The type is
+ associated with the real and imaginary parts. */
+ return NULL_TREE;
+ }
+ else
+ gcc_unreachable ();
+}
+
+
+/* Read an unsigned int into *VAR_P. */
+
+static void
+pth_read_uint (unsigned int *var_p, FILE *stream)
+{
+ size_t received = fread (var_p, sizeof *var_p, 1, stream);
+ gcc_assert (received == 1);
+}
+
+
+/* Read a size_t into *VAR_P. */
+
+static void
+pth_read_sizet (size_t *var_p, FILE *stream)
+{
+ size_t received = fread (var_p, sizeof *var_p, 1, stream);
+ gcc_assert (received == 1);
+}
+
+
+/* Read N bytes into P from STREAM. The caller is responsible
+ for allocating sufficient memory for P. */
+
+static inline void
+pth_read_bytes (void *p, size_t n, FILE *stream)
+{
+ size_t received = fread (p, 1, n, stream);
+ gcc_assert (received == n);
+}
+
+
+/* Read a string of up to MAX characters from STREAM into BUFFER.
+ Return the actual string length read from STREAM. The caller is
+ responsible for allocating sufficient memory for BUFFER. */
+
+static unsigned int
+pth_read_string (char *buffer, unsigned int max, FILE *stream)
+{
+ unsigned int length;
+ size_t received;
+
+ received = fread (&length, sizeof length, 1, stream);
+ gcc_assert (received == 1 && (length == -1U || length <= max));
+ if (length > 0 && length != -1U)
+ {
+ received = fread (buffer, 1, length, stream);
+ gcc_assert (received == length);
+ }
+
+ return length;
+}
+
+
+/* Read a string from STREAM allocating enough memory on the
+ heap to hold it.
+
+ This function assumes that strings are represented as a length
+ followed by the string content. A terminating '\0' is added
+ automatically. */
+
+static inline char *
+pth_read_string_alloc (FILE *stream)
+{
+ char *s;
+ unsigned int len;
+
+ pth_read_uint (&len, stream);
+
+ /* By convention, NULL strings are represented with length -1U. */
+ if (len == -1U)
+ return NULL;
+
+ s = XCNEWVEC (char, len + 1);
+ pth_read_bytes (s, len, stream);
+
+ return s;
+}
+
+
+/* Load a numeric value from file F. Return the corresponding tree. */
+
+static tree
+pth_load_number (FILE *f)
+{
+ unsigned type_idx, type_kind;
+ tree type, val;
+
+ pth_read_uint (&type_idx, f);
+ pth_read_uint (&type_kind, f);
+
+ type = pth_get_type_from_index (type_idx, type_kind);
+
+ if (type_kind == CPP_N_INTEGER)
+ {
+ HOST_WIDE_INT v[2];
+ pth_read_bytes (v, 2 * sizeof (HOST_WIDE_INT), f);
+ val = build_int_cst_wide (type, v[0], v[1]);
+ }
+ else if (type_kind == CPP_N_FLOATING)
+ {
+ REAL_VALUE_TYPE r;
+ pth_read_bytes (&r, sizeof (REAL_VALUE_TYPE), f);
+ val = build_real (type, r);
+ }
+ else if (type_kind == CPP_N_FRACT)
+ {
+ FIXED_VALUE_TYPE fv;
+ pth_read_bytes (&fv, sizeof (FIXED_VALUE_TYPE), f);
+ val = build_fixed (type, fv);
+ }
+ else if (type_kind == CPP_N_IMAGINARY)
+ {
+ tree r = pth_load_number (f);
+ tree i = pth_load_number (f);
+ val = build_complex (NULL_TREE, r, i);
+ }
+ else
+ gcc_unreachable ();
+
+ return val;
+}
+
+
+/* Load the tree value associated with TOKEN to file F. */
+
+static void
+pth_load_token_value (cp_token *token, FILE *f)
+{
+ char *str;
+
+ switch (token->type)
+ {
+ case CPP_TEMPLATE_ID:
+ case CPP_NESTED_NAME_SPECIFIER:
+ break;
+
+ case CPP_NAME:
+ str = pth_read_string_alloc (f);
+ token->u.value = get_identifier (str);
+ free (str);
+ break;
+
+ case CPP_KEYWORD:
+ token->u.value = ridpointers[token->keyword];
+ break;
+
+ case CPP_CHAR:
+ case CPP_WCHAR:
+ case CPP_CHAR16:
+ case CPP_CHAR32:
+ case CPP_NUMBER:
+ token->u.value = pth_load_number (f);
+ break;
+
+ case CPP_STRING:
+ case CPP_WSTRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ str = pth_read_string_alloc (f);
+ token->u.value = build_string (strlen (str), str);
+ free (str);
+ break;
+
+ case CPP_PRAGMA:
+ /* Nothing to do. Field pragma_kind has already been loaded. */
+ break;
+
+ default:
+ pth_read_bytes (&token->u.value, sizeof (token->u.value), f);
+ gcc_assert (token->u.value == NULL);
+ }
+}
+
+
+/* Load the IDENTIFERS for a hunk from a STREAM. */
+
+static void
+pth_load_identifiers (cpp_idents_used *identifiers, FILE *stream)
+{
+ unsigned int j;
+ unsigned int max_length, num_entries;
+ char *buffer;
+ unsigned int ident_len, before_len, after_len;
+
+ pth_read_uint (&max_length, stream);
+ identifiers->max_length = max_length;
+ pth_read_uint (&num_entries, stream);
+ identifiers->num_entries = num_entries;
+ identifiers->entries = XCNEWVEC (cpp_ident_use, num_entries);
+ identifiers->strings = XCNEW (struct obstack);
+
+ /* Strings need no alignment. */
+ _obstack_begin (identifiers->strings, 0, 0,
+ (void *(*) (long)) xmalloc,
+ (void (*) (void *)) free);
+ obstack_alignment_mask (identifiers->strings) = 0;
+ /* FIXME pph: We probably need to free all these things somewhere. */
+
+ buffer = XCNEWVEC (char, max_length + 1);
+
+ /* Read the identifiers in HUNK. */
+ for (j = 0; j < num_entries; ++j)
+ {
+ ident_len = pth_read_string ( buffer, max_length, stream);
+ gcc_assert (ident_len > 0 && ident_len != -1U);
+ identifiers->entries[j].ident_len = ident_len;
+ identifiers->entries[j].ident_str =
+ (const char *) obstack_copy0 (identifiers->strings, buffer, ident_len);
+
+ before_len = pth_read_string ((char *) buffer, max_length, stream);
+ identifiers->entries[j].before_len = before_len;
+ if (before_len == -1U)
+ identifiers->entries[j].before_str = NULL;
+ else
+ identifiers->entries[j].before_str = (const char *)
+ obstack_copy0 (identifiers->strings, buffer, before_len);
+
+ after_len = pth_read_string ((char *) buffer, max_length, stream);
+ identifiers->entries[j].after_len = after_len;
+ if (after_len == -1U)
+ identifiers->entries[j].after_str = NULL;
+ else
+ identifiers->entries[j].after_str = (const char *)
+ obstack_copy0 (identifiers->strings, buffer, after_len);
+ }
+
+ free (buffer);
+}
+
+
+/* Load a hunk into the IMAGE from a STREAM. */
+
+static void
+pth_load_hunk (pth_image *image, FILE *stream)
+{
+ unsigned j, num_tokens;
+ cp_token_hunk *hunk;
+
+ hunk = ggc_alloc_cleared_cp_token_hunk ();
+
+ /* Setup the identifier list. */
+ pth_load_identifiers (&hunk->identifiers, stream);
+
+ /* Read the offset into the text file where this token starts. */
+ pth_read_sizet (&hunk->text_offset.cur, stream);
+ pth_read_sizet (&hunk->text_offset.line_base, stream);
+ pth_read_sizet (&hunk->text_offset.next_line, stream);
+
+ /* Read the text length of the hunk. */
+ pth_read_sizet (&hunk->text_length, stream);
+
+ /* Read the number of tokens in HUNK. */
+ pth_read_uint (&num_tokens, stream);
+
+ /* Read the tokens in the HUNK. */
+ hunk->buffer = VEC_alloc (cp_token, gc, num_tokens);
+ for (j = 0; j < num_tokens; j++)
+ {
+ cp_token *token = VEC_quick_push (cp_token, hunk->buffer, NULL);
+
+ /* Do not read the whole structure, the token value has
+ dynamic size as it contains swizzled pointers.
+ FIXME pph, restructure to allow bulk reads of the whole
+ section. */
+ pth_read_bytes (token, sizeof (cp_token) - sizeof (void *), stream);
+
+ /* FIXME pph. Use an arbitrary (but valid) location to avoid
+ confusing the rest of the compiler for now. */
+ token->location = input_location;
+
+ /* FIXME pph: verify that pth_load_token_value works with no tokens. */
+ pth_load_token_value (token, stream);
+ }
+ gcc_assert (num_tokens == VEC_length (cp_token, hunk->buffer));
+
+ VEC_quick_push (cp_token_hunk_ptr, image->token_hunks, hunk);
+}
+
+
+/* Create a new empty #include directive for NAME. ITYPE is one of
+ the supported include commands. ANGLE_BRACKETS is true if the
+ include used '<>'. */
+
+static pth_include *
+pth_create_include (enum include_type itype, bool angle_brackets,
+ const char *name)
+{
+ pth_include *include = ggc_alloc_cleared_pth_include ();
+ include->itype = itype;
+ include->angle_brackets = angle_brackets;
+ include->iname = (name) ? xstrdup (name) : name;
+
+ return include;
+}
+
+
+/* Load an #include directive for IMAGE from STREAM. */
+
+static void
+pth_load_include (pth_state *state, pth_image *image, cpp_reader *reader,
+ FILE *stream)
+{
+ char *s;
+ pth_include *include;
+ unsigned tmp;
+
+ include = pth_create_include (IT_INCLUDE, false, NULL);
+
+ s = pth_read_string_alloc (stream);
+ include->image = pth_image_lookup (state, s, reader);
+
+ pth_read_uint (&tmp, stream);
+ include->itype = (enum include_type) tmp;
+
+ pth_read_uint (&tmp, stream);
+ include->angle_brackets = (tmp != 0);
+
+ include->iname = pth_read_string_alloc (stream);
+ include->dname = pth_read_string_alloc (stream);
+
+ VEC_safe_push (pth_include_ptr, gc, image->includes, include);
+}
+
+
+/* Load a PTH image for LEXER using the READER. */
+
+static void
+pth_load_image (pth_state *state, pth_image *image, cpp_reader *reader)
+{
+ FILE *stream;
+ unsigned i, num;
+
+ timevar_push (TV_PTH_LOAD);
+
+ stream = pth_file_for (image->fname, "r+b");
+
+ /* Skip over the header, as we assume that it has already been
+ validated by pth_have_valid_image_for. */
+ fseek (stream, (long) pth_header_len (), SEEK_SET);
+
+ /* Read the include-hunk (IH) sequencing vector. */
+ pth_read_uint (&num, stream);
+ if (num > 0)
+ {
+ image->ih_sequence = VEC_alloc (char, gc, num);
+ VEC_safe_grow (char, gc, image->ih_sequence, num);
+ pth_read_bytes (VEC_address (char, image->ih_sequence), num, stream);
+ }
+
+ /* Read the number path names of all the files #included by
+ IMAGE->FNAME. */
+ pth_read_uint (&num, stream);
+ image->includes = VEC_alloc (pth_include_ptr, gc, num);
+
+ /* Now read all the path names #included by IMAGE->FNAME. */
+ for (i = 0; i < num; i++)
+ pth_load_include (state, image, reader, stream);
+
+ /* Read how many token hunks are contained in this image. */
+ pth_read_uint (&num, stream);
+ image->token_hunks = VEC_alloc (cp_token_hunk_ptr, gc, num);
+
+ PTH_STATS_INCR (hunks, num);
+
+ /* Read all the token hunks. */
+ for (i = 0; i < num; i++)
+ pth_load_hunk (image, stream);
+
+ fclose (stream);
+
+ /* Indicate that we have loaded this image from a file. */
+ image->loaded_p = true;
+ image->save_p = false;
+ image->used_p = false;
+
+ if (flag_pth_debug >= 3)
+ {
+ fprintf (stderr, "\nLoaded image for %s:\n", image->fname);
+ pth_debug_image (image);
+ }
+
+ timevar_pop (TV_PTH_LOAD);
+}
+
+
+/* Return true if FNAME has a PTH image that can be used. If an image
+ already exists, compute the MD5 digest for FNAME and store it
+ in IMAGE. */
+
+static bool
+pth_have_valid_image_for (const char *fname, pth_image *image)
+{
+ FILE *f = NULL;
+ struct stat s;
+ char *img_name, *id;
+ const char *good_id;
+ char saved_digest[DIGEST_LEN];
+
+ image->digest_computed_p = false;
+
+ img_name = pth_name_for (fname);
+ if (stat (img_name, &s) != 0)
+ goto invalid_img;
+
+ /* If the file exists, check if it has a valid signature. */
+ f = fopen (img_name, "r");
+
+ good_id = pth_id_str ();
+ id = XCNEWVEC (char, strlen (good_id) + 1);
+ pth_read_bytes (id, strlen (good_id), f);
+ if (strcmp (id, good_id) != 0)
+ goto invalid_img;
+
+ /* Now check if the MD5 digest stored in the image file matches the
+ digest for FNAME. */
+ pth_read_bytes (saved_digest, DIGEST_LEN, f);
+ pth_get_md5_digest (fname, image->digest);
+ image->digest_computed_p = true;
+ if (memcmp (image->digest, saved_digest, DIGEST_LEN) != 0)
+ goto invalid_img;
+
+ fclose (f);
+ return true;
+
+invalid_img:
+ if (f)
+ fclose (f);
+
+ return false;
+}
+
+
+/* Create a new PTH cache object for file FNAME. */
+
+static pth_image *
+pth_new_image (const char *fname)
+{
+ pth_image *image;
+
+ image = ggc_alloc_cleared_pth_image ();
+ image->fname = fname;
+
+ return image;
+}
+
+
+/* Return a cache image associated with file FNAME. STATE holds
+ the PTH cache to use. */
+
+pth_image *
+pth_image_lookup (pth_state *state, const char *fname, cpp_reader *reader)
+{
+ void **slot;
+ pth_image *image, e;
+
+ if (fname == NULL)
+ return NULL;
+
+ e.fname = fname;
+ slot = htab_find_slot (state->cache_dir, &e, INSERT);
+ if (*slot == NULL)
+ {
+ /* Create a new image and store it in the cache. */
+ image = pth_new_image (fname);
+ *slot = image;
+ VEC_safe_push (pth_image_ptr, gc, state->cache, image);
+
+ /* If a valid disk image already exists for FNAME, load it.
+ Otherwise, mark the memory image for processing and saving. */
+ if (pth_have_valid_image_for (fname, image))
+ pth_load_image (state, image, reader);
+ else
+ image->save_p = true;
+ }
+ else
+ image = *((pth_image **) slot);
+
+ return image;
+}
+
+
+/* Add all the tokens in HUNK to the end of LEXER->BUFFER. IMAGE is
+ the memory image holding HUNK. */
+
+static void
+pth_append_hunk (cp_lexer *lexer, pth_image *image, cp_token_hunk *hunk)
+{
+ cp_token *lexer_addr, *hunk_addr;
+ unsigned lexer_len, hunk_len;
+
+ PTH_STATS_INCR (valid_hunks, 1);
+
+ /* Apply all the identifiers used and defined by HUNK. */
+ cpp_lt_replay (parse_in, &hunk->identifiers);
+
+ /* If this file has been read in memory (e.g., by being #included
+ from a tainted file), advance the text buffer pointer to the end
+ of the hunk to avoid reading it again. */
+ if (image->buffer)
+ cpp_set_pos (image->buffer, hunk->text_offset);
+
+ hunk_len = VEC_length (cp_token, hunk->buffer);
+
+ /* Some hunks have no tokens and they are only useful for the
+ macros defined by them. This is useful when one or more
+ image files are tainted and need to be restored from their
+ character stream. */
+ if (hunk_len == 0)
+ return;
+
+ /* Determine the last location in LEXER->BUFFER before growing it. */
+ lexer_len = VEC_length (cp_token, lexer->buffer);
+ VEC_safe_grow (cp_token, gc, lexer->buffer, lexer_len + hunk_len);
+
+ /* Bulk copy all the tokens in HUNK to the end of LEXER->BUFFER. */
+ lexer_addr = VEC_address (cp_token, lexer->buffer);
+ hunk_addr = VEC_address (cp_token, hunk->buffer);
+ memcpy (&lexer_addr[lexer_len], hunk_addr, hunk_len * sizeof (cp_token));
+
+ if (flag_pth_debug >= 2)
+ {
+ fprintf (stderr, "\n=> ADDED TOKEN HUNK TO LEXER BUFFER");
+ if (flag_pth_debug >= 5)
+ pth_debug_hunk (hunk);
+ }
+}
+
+
+/* Return true if HUNK can be used in the current compilation
+ context of the cpp READER. It must validate the identifier state. */
+
+static bool
+pth_hunk_is_valid_p (pth_image *image, cp_token_hunk *hunk, cpp_reader *reader)
+{
+ bool verified;
+ cpp_ident_use *bad_use;
+ const char *cur_def;
+
+ timevar_push (TV_PTH_DEPENDENCY);
+ verified = cpp_lt_verify (reader, &hunk->identifiers, &bad_use, &cur_def);
+ if (!verified && flag_pth_debug >= 1)
+ {
+ fprintf (stderr, "PTH: %s failed verification: %s : <%s> -> <%s>\n",
+ pth_name_for (image->fname), bad_use->ident_str,
+ bad_use->before_str, cur_def);
+ }
+ PTH_STATS_INCR (verified_hunks, 1);
+ PTH_STATS_INCR (verified_identifiers, hunk->identifiers.num_entries);
+ timevar_pop (TV_PTH_DEPENDENCY);
+ return verified;
+}
+
+
+/* Return true if IMAGE can be used in the current compilation context. */
+
+static bool
+pth_image_can_be_used (pth_image *image)
+{
+ return image && image->loaded_p && !image->used_p;
+}
+
+
+/* Split NAME into its directory and file name components, storing them
+ in *DNAME_P and *FNAME_P. After using it, *DNAME_P should be freed
+ by the caller. */
+
+static void
+pth_get_dir_and_name (const char *name, char **dname_p, const char **fname_p)
+{
+ size_t len;
+
+ *fname_p = lbasename (name);
+ *dname_p = NULL;
+
+ len = *fname_p - name;
+ if (len > 0)
+ {
+ *dname_p = XNEWVEC (char, len + 1);
+ memcpy (*dname_p, name, len);
+ (*dname_p)[len] = '\0';
+ gcc_assert (IS_DIR_SEPARATOR ((*dname_p)[len - 1]));
+ }
+}
+
+
+/* Read tokens from the text stream in IMAGE->FNAME into LEXER.
+ If INCLUDE is not NULL, it describes how IMAGE->FNAME was
+ #included originally. Otherwise, it is assumed to be an
+ include command done with the flag -include.
+
+ This is used when an image is found to be tainted and tokens
+ need to be read from the original character stream. OFFSET
+ indicates how far into the character stream to start reading at. */
+
+static void
+pth_process_text_file (cp_lexer *lexer, pth_image *image, pth_include *include,
+ cpp_offset offset)
+{
+ bool prev_permissive, prev_inhibit_warnings;
+ bool pushed_p;
+ cpp_buffer *buffer;
+ lexer_state *state;
+
+ /* Emulate a #include directive on IMAGE->FNAME, if needed. Note
+ that if we are already inside the CPP buffer for IMAGE->FNAME
+ we should not include it again, since this will cause another
+ call to pth_file_change which will again register IMAGE->FNAME as
+ an include for the parent file. */
+ state = NULL;
+ if (image->buffer != cpp_get_buffer (parse_in))
+ {
+ if (include == NULL || include->itype == IT_INCLUDE_NEXT)
+ {
+ char *dname;
+ const char *fname;
+ pth_get_dir_and_name (image->fname, &dname, &fname);
+ pushed_p = cpp_push_include_type (parse_in, dname, fname, false,
+ IT_INCLUDE);
+
+ /* FIXME pph. We are leaking DNAME here. libcpp
+ wants the directory name in permanent storage so we
+ cannot free it, but we should put it in an obstack
+ so it can be reclaimed at some point. */
+ }
+ else
+ pushed_p = cpp_push_include_type (parse_in,
+ include->dname,
+ include->iname,
+ include->angle_brackets,
+ include->itype);
+
+ if (!pushed_p)
+ return;
+ }
+ else
+ {
+ /* Since we already have the buffer on top of the stack,
+ reset the state of the lexer to avoid skipping over it. */
+ state = cpp_reset_lexer_state (parse_in);
+ }
+
+ /* Inhibit libcpp error messages (ignore things like unmatched #endifs).
+ We need to do this because token hunks may span #if/#endif boundaries.
+ For instance,
+
+ #if <COND>
+ H1 [1]
+ #else
+ H2 [2]
+ #include "foo.h"
+ H3 [3]
+ #endif
+ H1 or H3 [4]
+
+ In this example we have 3 hunks (H1, H2 and H3). Depending on the
+ value of <COND> at image creation time, point [4] will belong to
+ hunk H1 (if <COND> was true) or hunk H3 (if <COND> was false).
+
+ When this image is loaded, if H3 cannot be applied because its
+ dependences fail to hold, then we will start pre-processing the
+ text for the file at the start of hunk H3. This will find a
+ dangling #endif which triggers a libcpp error. Since we know
+ that we are in the correct arm of the #if (after all H2 was
+ applied from the image), we can safely ignore the error. */
+ prev_permissive = global_dc->permissive;
+ prev_inhibit_warnings = global_dc->dc_inhibit_warnings;
+ global_dc->dc_inhibit_warnings = true;
+ global_dc->permissive = true;
+
+ /* Position the reader at OFFSET and request to stop reading at
+ the end of it. */
+ buffer = cpp_get_buffer (parse_in);
+ cpp_set_pos (buffer, offset);
+ cpp_return_at_eof (buffer, true);
+
+ /* Get tokens from IMAGE->FNAME. */
+ cp_lexer_get_tokens (lexer);
+
+ /* Since we read this file separately, the very last token in LEXER
+ will now contain an EOF, which we do not need. */
+ VEC_pop (cp_token, lexer->buffer);
+ cpp_return_at_eof (buffer, false);
+
+ /* Restore libcpp error/warnings. */
+ global_dc->permissive = prev_permissive;
+ global_dc->dc_inhibit_warnings = prev_inhibit_warnings;
+
+ /* Restore the parser state, if necessary. */
+ if (state)
+ cpp_restore_lexer_state (parse_in, state);
+}
+
+
+/* Populate LEXER->BUFFER with all the valid token hunks in
+ IMAGE. If possible, try to load token hunks from files
+ included by IMAGE as well.
+
+ This means that we try to load the whole transitive closure
+ starting at IMAGE until we find the first unloadable file.
+
+ Once we find the first unloadable token hunk, we skip the token
+ hunks from the character stream so that they don't need to be
+ pre-processed again.
+
+ If non-NULL, INCLUDE describes the #include command used to include
+ IMAGE->FNAME. */
+
+static void
+pth_image_to_lexer (cp_lexer *lexer, pth_image *image, pth_include *include)
+{
+ unsigned i, h_ix, i_ix;
+ char s;
+
+ /* If we are trying to apply the same image more than once,
+ something is wrong. We never create images for files that
+ are included more than once, so we should never try to apply
+ the same image more than once. */
+ gcc_assert (pth_image_can_be_used (image));
+
+ image->used_p = true;
+
+ if (flag_pth_debug >= 2)
+ {
+ fprintf (stderr, "\n<= INCORPORATING IMAGE %s INTO COMPILATION CONTEXT\n",
+ image->fname);
+ if (flag_pth_debug >= 3)
+ pth_debug_include (include);
+ }
+
+ PTH_STATS_INCR (valid_images, 1);
+
+ for (i = 0, h_ix = 0, i_ix = 0;
+ VEC_iterate (char, image->ih_sequence, i, s);
+ i++)
+ {
+ if (s == 'H')
+ {
+ cp_token_hunk *hunk;
+
+ hunk = VEC_index (cp_token_hunk_ptr, image->token_hunks, h_ix++);
+ if (pth_hunk_is_valid_p (image, hunk, parse_in))
+ pth_append_hunk (lexer, image, hunk);
+ else
+ {
+ PTH_STATS_INCR (invalid_hunks, 1);
+
+ pth_process_text_file (lexer, image, NULL, hunk->text_offset);
+
+ /* Since this hunk is invalid, assume that everything
+ downstream from this hunk is also invalid. FIXME pph,
+ it may be possible to optimize this. We should be
+ able to pre-process from text exactly
+ HUNK->TEXT_LENGTH characters instead of the whole
+ file. */
+ break;
+ }
+ }
+ else if (s == 'I')
+ {
+ pth_include *incdir;
+ pth_get_state ()->cur_image = image;
+ incdir = VEC_index (pth_include_ptr, image->includes, i_ix++);
+ if (pth_image_can_be_used (incdir->image))
+ pth_image_to_lexer (lexer, incdir->image, incdir);
+ else
+ pth_process_text_file (lexer, incdir->image, incdir,
+ cpp_buffer_start);
+ }
+ else
+ gcc_unreachable ();
+ }
+
+ /* If we just applied the tokens for the main input filename,
+ we need to append a CPP_EOF token, since that one is never
+ saved with the token hunks. */
+ if (pathnames_equal_p (image->fname, main_input_filename))
+ VEC_safe_push (cp_token, gc, lexer->buffer, &eof_token);
+
+ /* If IMAGE has a libcpp buffer associated with it, it means that a
+ file that was being pre-processed from text has #included IMAGE
+ and the pre-processor has executed the file change logic.
+
+ In that case, the pre-processor will want to finish processing
+ IMAGE's text, and since we have just applied its tokens from
+ the image, the result will be duplicate tokens. To prevent
+ this, we tell libcpp to skip over the whole text buffer
+ associated with IMAGE. */
+ if (image->buffer)
+ cpp_set_pos (image->buffer, cpp_buffer_end);
+
+ return;
+}
+
+
+/* Create a token hunk for IMAGE from the token buffer in
+ LEXER->BUFFER. The hunk will contain all the tokens starting at
+ IMAGE->HUNK_START_IX to the end of LEXER->BUFFER.
+
+ The new token hunk will be added to the end of IMAGE->TOKEN_HUNKS. */
+
+static void
+pth_lexer_to_image (pth_image *image, cp_lexer *lexer, cpp_reader *reader)
+{
+ cp_token *lexer_addr, *hunk_addr;
+ cp_token_hunk *hunk;
+ unsigned num_tokens, start_ix, end_ix;
+ cpp_offset pos;
+
+ /* Create a new token hunk. */
+ hunk = ggc_alloc_cleared_cp_token_hunk ();
+ VEC_safe_push (cp_token_hunk_ptr, gc, image->token_hunks, hunk);
+ VEC_safe_push (char, gc, image->ih_sequence, 'H');
+
+ /* The identifiers that may conflict with macros. */
+ if (flag_pth_debug >= 2)
+ cpp_lt_statistics (reader);
+ hunk->identifiers = cpp_lt_capture (reader);
+
+ /* Remember the text offset where this hunk started and its length. */
+ hunk->text_offset = image->hunk_text_offset;
+ pos = cpp_get_pos (image->buffer);
+ gcc_assert (pos.cur >= hunk->text_offset.cur);
+ hunk->text_length = pos.cur - hunk->text_offset.cur;
+
+ /* Compute the bounds for the new token hunk. */
+ start_ix = image->hunk_start_ix;
+ end_ix = VEC_length (cp_token, lexer->buffer);
+ gcc_assert (end_ix >= start_ix);
+ num_tokens = end_ix - start_ix;
+
+ if (num_tokens > 0)
+ {
+ /* Copy tokens from LEXER->BUFFER into the new hunk. */
+ hunk->buffer = VEC_alloc (cp_token, gc, num_tokens);
+ VEC_safe_grow (cp_token, gc, hunk->buffer, num_tokens);
+ lexer_addr = VEC_address (cp_token, lexer->buffer);
+ hunk_addr = VEC_address (cp_token, hunk->buffer);
+ memcpy (hunk_addr, &lexer_addr[start_ix], num_tokens * sizeof (cp_token));
+ }
+
+ if (flag_pth_debug >= 3)
+ {
+ fprintf (stderr, "\n=> SAVED HUNK TO IMAGE: %s\n", image->fname);
+ if (flag_pth_debug >= 5)
+ pth_debug_hunk (hunk);
+ }
+}
+
+
+/* Compute the effects of a file transition given the file change
+ described by MAP. On exit:
+
+ - *PREV_IMAGE_P will point to the image for the file that we just left,
+
+ - *NEW_IMAGE_P will point to the image for the file that we just
+ entered. If *NEW_IMAGE_P is NULL, it means that we just left
+ the last file in the translation unit, so there isn't anything
+ else to be done.
+
+ - *REASON_P will have the LC_* reason for the change. */
+
+static void
+pth_get_file_transition (const struct line_map *map, pth_image **prev_image_p,
+ pth_image **new_image_p, enum lc_reason *reason_p)
+{
+ const char *fname;
+ pth_state *state;
+
+ /* MAP is NULL when we leave the main file in this translation unit. */
+ if (map == NULL)
+ {
+ fname = NULL;
+ *reason_p = LC_LEAVE;
+ }
+ else
+ {
+ fname = map->to_file;
+ *reason_p = map->reason;
+ }
+
+ state = pth_get_state ();
+ *prev_image_p = state->cur_image;
+
+ /* FIXME pph. Sanitize use of PARSE_IN. Stick it in
+ pth_state together with lexer. */
+ *new_image_p = pth_image_lookup (state, fname, parse_in);
+}
+
+
+/* Do bookkeeping actions required when the pre-processor is leaving
+ file IMAGE->FNAME. READER is the cpp file reader object we
+ are using for lexing. */
+
+static void
+pth_leave_file (cpp_reader *reader, pth_image *image)
+{
+ pth_state *state;
+
+ /* We are only interested in processing IMAGE if we have decided to
+ save its image. */
+ if (!image->save_p)
+ return;
+
+ state = pth_get_state ();
+
+ /* If the image for the file we just finished is marked as
+ modified, create a new token hunk spanning from the token
+ that started the image to the current end of the lexer
+ buffer. */
+ pth_lexer_to_image (image, state->lexer, reader);
+}
+
+
+/* Do bookkeeping actions required when the pre-processor is entering
+ file IMAGE->FNAME for reason REASON. READER is the cpp file reader
+ object we are using for lexing. INCLUDE is the #include command
+ used to enter IMAGE->FNAME. It can be NULL in the case of the
+ top file in the translation unit. */
+
+static void
+pth_enter_file (cpp_reader *reader, pth_image *image, pth_include *include,
+ enum lc_reason reason)
+{
+ pth_state *state;
+
+ state = pth_get_state ();
+
+ /* Associate the current buffer with IMAGE. */
+ image->buffer = cpp_get_buffer (reader);
+
+ /* Complete the current #include command with the directory
+ and image for the file that we just switched to. */
+ if (include)
+ {
+ const char *dname = cpp_get_dir (cpp_get_file (image->buffer))->name;
+ include->image = image;
+ include->dname = (*dname) ? xstrdup (dname) : NULL;
+ }
+
+ /* If the file we are about to switch to has been loaded into an
+ image, try to get as many tokens as possible from the image
+ instead of the character stream. */
+ if (pth_image_can_be_used (image))
+ pth_image_to_lexer (state->lexer, image, include);
+
+ /* If IMAGE does not need to be saved, we are done. */
+ if (!image->save_p)
+ return;
+
+ /* Detect multiple inclusions of the same header file. When a file
+ is included more than once, each inclusion will usually produce
+ different token hunks (e.g., <stddef.h> is typically included
+ from different places with "arguments" in the form of #defines
+ that determine what the caller wants stddef.h to provide. See
+ <wchar.h> for an example).
+
+ This disrupts the validity of the image, as the hunks saved in it
+ no longer correspond to a single pre-processing of the file. We
+ avoid this problem by tainting the image and forcing the file to
+ be always processed from its character stream. */
+ if (reason == LC_ENTER && !VEC_empty (cp_token_hunk_ptr, image->token_hunks))
+ image->save_p = false;
+
+ /* The starting point for the next token hunk in the new
+ file image will be at the current last slot in
+ STATE->LEXER->BUFFER. */
+ image->hunk_start_ix = VEC_length (cp_token, state->lexer->buffer);
+
+ /* The new hunk starts at the current offset in the current
+ libcpp buffer. If this hunk is ever invalidated, this is
+ the offset at which to start pre-processing. */
+ image->hunk_text_offset = cpp_get_pos (image->buffer);
+}
+
+
+/* Callback from the pre-processor when changing in or out of a file.
+ READER is the pre-processor state. MAP is the line map for the
+ file that we are changing to. */
+
+static void
+pth_file_change (cpp_reader *reader, const struct line_map *map)
+{
+ enum lc_reason reason;
+ pth_state *state;
+ pth_image *prev_image, *new_image;
+
+ /* Call the previous file change handler, if it exists. */
+ state = pth_get_state ();
+ if (state->file_change_prev)
+ state->file_change_prev (reader, map);
+
+ /* When processing pre-processed output, we will see names like
+ '<built-in>' and '<command-line>'. Reject those.
+ ??? This rejects real path names that may start with '<', but
+ those should be rare. */
+ if (map && map->to_file && map->to_file[0] == '<')
+ return;
+
+ /* Ignore LC_RENAME events. They do not affect the actual image
+ that we are processing. */
+ if (map && map->reason == LC_RENAME)
+ return;
+
+ timevar_push (TV_PTH_MANAGE);
+
+ /* Get images for the file involved in the transition. */
+ pth_get_file_transition (map, &prev_image, &new_image, &reason);
+ gcc_assert (prev_image);
+
+ /* Ignore self-referential file change events. These can happen
+ when mixing token images with text buffers. */
+ if (prev_image == new_image)
+ {
+ timevar_pop (TV_PTH_MANAGE);
+ return;
+ }
+
+ /* Process the file we just left (get tokens from lexer buffer,
+ etc). */
+ pth_leave_file (reader, prev_image);
+
+ /* Process the file we are about to enter (try to use its tokens if
+ the file is valid, etc). */
+ if (new_image)
+ {
+ pth_include *include = NULL;
+
+ if (reason == LC_ENTER)
+ include = pth_create_include (state->new_itype,
+ state->new_angle_brackets,
+ state->new_iname);
+
+ pth_enter_file (reader, new_image, include, reason);
+
+ /* If we are LC_ENTERing NEW_IMAGE, it means that PREV_IMAGE has
+ #included NEW_IMAGE. In that case, add NEW_IMAGE to the list
+ of included files by PREV_IMAGE. */
+ if (reason == LC_ENTER)
+ {
+ PTH_STATS_INCR (included_files, 1);
+
+ if (prev_image->save_p)
+ {
+ gcc_assert (include->image == new_image);
+ VEC_safe_push (pth_include_ptr, gc, prev_image->includes,
+ include);
+ VEC_safe_push (char, gc, prev_image->ih_sequence, 'I');
+ }
+ }
+ }
+
+ /* Update the current image. */
+ state->cur_image = new_image;
+
+ timevar_pop (TV_PTH_MANAGE);
+}
+
+
+/* Record a #include or #include_next. */
+
+static void
+pth_include_handler (cpp_reader *reader ATTRIBUTE_UNUSED,
+ location_t loc ATTRIBUTE_UNUSED,
+ const unsigned char *dname,
+ const char *name,
+ int angle_brackets,
+ const cpp_token **tok_p ATTRIBUTE_UNUSED)
+{
+ pth_state *state;
+
+ state = pth_get_state ();
+
+ /* Remember the attributes for this #include command. This is
+ used in pth_file_change to register a new include event for
+ the parent file. */
+ if (strcmp ((const char *)dname, "include") == 0)
+ state->new_itype = IT_INCLUDE;
+ else if (strcmp ((const char *)dname, "include_next") == 0)
+ state->new_itype = IT_INCLUDE_NEXT;
+ else if (strcmp ((const char *)dname, "import") == 0)
+ state->new_itype = IT_IMPORT;
+ else
+ gcc_unreachable ();
+
+ state->new_angle_brackets = angle_brackets;
+ state->new_iname = name;
+}
+
+
+/* Initialize PTH support. LEXER is the main lexer object used for
+ pre-processing. */
+
+void
+pth_init (cp_lexer *lexer)
+{
+ pth_state *state;
+ cpp_callbacks *cb;
+ cpp_lookaside *table;
+
+ timevar_push (TV_PTH_INIT);
+
+ gcc_assert (flag_pth);
+
+ table = cpp_lt_exchange (parse_in, cpp_lt_create (/*2 to the power*/15,
+ flag_pth_debug));
+ gcc_assert (table == NULL);
+
+ memset (&pth_stats, 0, sizeof (pth_stats));
+
+ state = pth_get_state ();
+
+ /* If not using MD5 signatures, make sure that time stamps given
+ by stat() are smaller than DIGEST_LEN bytes. FIXME pph, this is
+ slighly hacky. */
+ if (!flag_pth_md5)
+ {
+ struct stat tmp;
+ gcc_assert (sizeof (tmp.st_mtime) < DIGEST_LEN);
+ }
+
+ /* Set an handler for file change events in libcpp. */
+ cb = cpp_get_callbacks (parse_in);
+ state->file_change_prev = cb->file_change;
+ cb->file_change = pth_file_change;
+ cb->include = pth_include_handler;
+
+ state->lexer = lexer;
+
+ /* Make sure that we have not tried to get any tokens yet. */
+ gcc_assert (VEC_empty (cp_token, lexer->buffer));
+
+ /* If we have a valid image for the main input file, populate as
+ many tokens from its transitive closure as possible. */
+ state->cur_image = pth_image_lookup (state, main_input_filename, parse_in);
+ pth_enter_file (parse_in, state->cur_image, NULL, LC_ENTER);
+
+ timevar_pop (TV_PTH_INIT);
+}
+
+
+/* Show statistics on PTH on FILE. If FILE is NULL, use pph_logfile.
+ LEXER is the lexer we just filled with tokens. This is usually
+ the same as pth_get_state()->lexer, but it may be NULL if PTH is
+ not enabled (in cases where we just want stats on pre-processed
+ files). */
+
+void
+pth_print_stats (FILE *file, cp_lexer *lexer)
+{
+ unsigned i, num_tokens, total_tokens;
+ pth_state *state;
+ pth_image *image;
+ const char *prev_fname;
+ cp_token *token;
+
+ if (file == NULL)
+ file = pph_logfile;
+
+ fprintf (file, "\nPTH statistics\n\n");
+ fprintf (file, "#included files: %lu\n", pth_stats.included_files);
+ fprintf (file, "Valid images: %lu\n", pth_stats.valid_images);
+ fprintf (file, "Token hunks: %lu\n", pth_stats.hunks);
+ fprintf (file, "Valid hunks: %lu\n", pth_stats.valid_hunks);
+ fprintf (file, "Invalid hunks: %lu\n", pth_stats.invalid_hunks);
+ fprintf (file, "Verified hunks: %lu\n", pth_stats.verified_hunks);
+ fprintf (file, "Verified identifiers: %lu\n", pth_stats.verified_identifiers);
+
+ state = pth_get_state ();
+ fprintf (file, "\n\nPTH image statistics (%u files)\n\n",
+ VEC_length (pth_image_ptr, state->cache));
+ for (i = 0; VEC_iterate (pth_image_ptr, state->cache, i, image); i++)
+ pth_show_image_stats (file, image);
+
+ fprintf (file, "\nToken counts per file in #include order:\n");
+ num_tokens = total_tokens = 0;
+ prev_fname = NULL;
+ for (i = 0; VEC_iterate (cp_token, lexer->buffer, i, token); i++)
+ {
+ const char *fname = LOCATION_FILE (token->location);
+
+ if (prev_fname == NULL)
+ prev_fname = fname;
+
+ if ((fname
+ && strcmp (fname, prev_fname) != 0)
+ || i == VEC_length (cp_token, lexer->buffer) - 1)
+ {
+ fprintf (file, "tokens: %u %s\n", num_tokens, lrealpath (prev_fname));
+ prev_fname = fname;
+ total_tokens += num_tokens;
+ num_tokens = 0;
+ }
+
+ num_tokens++;
+ }
+
+ /* The main lexer buffer should have one more token: CPP_EOF. */
+ if (total_tokens != VEC_length (cp_token, lexer->buffer) - 1)
+ fprintf (stderr, "*** WARNING: I counted %u, but there are %u\n",
+ total_tokens, VEC_length (cp_token, lexer->buffer));
+
+ fprintf (file, "\n");
+}
+
+
+/* Save all the header images that have been marked modified from
+ the incremental state. */
+
+void
+pth_finish (void)
+{
+ /* If PPH is enabled, do not save PTH images to prevent analysis problems
+ due to lack of location information in PTH images. FIXME pph:
+ Unneeded after we start saving proper location information. */
+ if (flag_pph_debug >= 1)
+ {
+ if (flag_pph_debug > 1)
+ fprintf (stderr, "*** WARNING: Not saving PTH images because PPH "
+ "is enabled\n");
+ }
+ else
+ {
+ pth_state *state;
+ pth_image *image;
+ size_t i;
+
+ state = pth_get_state ();
+ for (i = 0; VEC_iterate (pth_image_ptr, state->cache, i, image); i++)
+ if (image->save_p)
+ pth_save_image (image);
+ }
+}
+
+
+static void
+pph_log_exposed (cp_parser *parser, const char *end)
+{
+ if (flag_pph_debug >= 2)
+ {
+ cp_token *pos = cp_lexer_token_position (parser->lexer, false);
+ fprintf (pph_logfile, "PPH: %s exposed declaration at ", end);
+ pph_debug_location (pph_logfile, pos->location);
+ fprintf (pph_logfile, "\n");
+ }
+}
+
+
+/* Allocate the various arrays, maps and sets used to collect ASTs and
+ their dependencies during parsing. This memory is allocated and
+ freed for every grammar rule intercepted by pph_start_exposed() and
+ pph_stop_exposed(). */
+
+static void
+pph_allocate_catcher_memory (void)
+{
+ /* Note. pph_tree_catcher *must* be instantiated to indicate that
+ we are going to be catching trees during parsing. */
+ pph_tree_catcher = VEC_alloc (tree, heap, 5);
+ pph_decl_head_token_cache = pointer_map_create ();
+ pph_decl_body_token_cache = pointer_map_create ();
+ pph_decl_deps = XCNEW (struct pph_decl_deps_d);
+ pph_decl_deps->header = pointer_map_create ();
+ pph_decl_deps->body = pointer_map_create ();
+ pph_name_lookups = NULL;
+ pph_name_lookups_set = pointer_set_create ();
+ pph_nl_token_map = pointer_map_create ();
+}
+
+
+/* Free all the memory allocated by pph_allocate_catcher_memory. */
+
+static void
+pph_free_catcher_memory (void)
+{
+ VEC_free (tree, heap, pph_tree_catcher);
+
+ pointer_map_destroy (pph_decl_head_token_cache);
+ pph_decl_head_token_cache = NULL;
+
+ pointer_map_destroy (pph_decl_body_token_cache);
+ pph_decl_body_token_cache = NULL;
+
+ pointer_map_destroy (pph_decl_deps->header);
+ pointer_map_destroy (pph_decl_deps->body);
+ free (pph_decl_deps);
+ pph_decl_deps = NULL;
+
+ VEC_free (tree, heap, pph_name_lookups);
+
+ pointer_set_destroy (pph_name_lookups_set);
+ pph_name_lookups_set = NULL;
+
+ pointer_map_destroy (pph_nl_token_map);
+ pph_nl_token_map = NULL;
+}
+
+
+/* Start collecting ASTs and dependencies. */
+
+cp_token *
+pph_start_exposed (cp_parser *parser)
+{
+ if (flag_pph_debug >= 1)
+ {
+ timevar_push (TV_PPH_MANAGE);
+
+ if (flag_pph_debug >= 4)
+ fprintf (pph_logfile, "\n--------------------------------------------------------------------------\n");
+ pph_log_exposed (parser, "start");
+ pph_allocate_catcher_memory ();
+ timevar_pop (TV_PPH_MANAGE);
+
+ return parser->lexer->next_token; /* the first token */
+ }
+ else
+ return NULL;
+}
+
+/* Return the token cache associated with tree node T. */
+
+static VEC(cp_token, heap) *
+pph_lookup_head_token_cache_for (tree t)
+{
+ void **slot = pointer_map_contains (pph_decl_head_token_cache, t);
+ if (slot)
+ return ((VEC(cp_token, heap) *) *slot);
+
+ return NULL;
+}
+
+static VEC(cp_token, heap) *
+pph_lookup_body_token_cache_for (tree t)
+{
+ void **slot = pointer_map_contains (pph_decl_body_token_cache, t);
+ if (slot)
+ return ((VEC(cp_token, heap) *) *slot);
+
+ return NULL;
+}
+
+
+/* Set the token cache associated with tree node T to CACHE. */
+
+static void
+pph_set_head_token_cache_for (tree t, VEC(cp_token, heap) *cache)
+{
+ void **slot = pointer_map_insert (pph_decl_head_token_cache, t);
+ *slot = (void *) cache;
+}
+
+static void
+pph_set_body_token_cache_for (tree t, VEC(cp_token, heap) *cache)
+{
+ void **slot = pointer_map_insert (pph_decl_body_token_cache, t);
+ *slot = (void *) cache;
+}
+
+/* Emulate the copying of declarations into the parser cache. Deep
+ copy all the declarations in V. */
+
+static void
+pph_copy_decls_into_cache (VEC(tree, heap) *v)
+{
+ unsigned i;
+ static tree t_copy, type_copy, t;
+ void **slot;
+ VEC(tree, heap) *ast_cache, *old_pph_tree_catcher, *old_pph_name_lookups;
+ static struct pointer_map_t *hunk_to_decls_map = NULL;
+ static htab_t cache_dir = NULL;
+ const char *fname;
+
+ timevar_push (TV_PPH_CACHE_IN);
+
+ if (hunk_to_decls_map == NULL)
+ hunk_to_decls_map = pointer_map_create ();
+
+ if (cache_dir == NULL)
+ cache_dir = htab_create (10, htab_hash_pointer, htab_eq_pointer, 0);
+
+ /* We will be copying trees, which will call into the tree catching
+ routines. Prevent that. */
+ old_pph_tree_catcher = pph_tree_catcher;
+ old_pph_name_lookups = pph_name_lookups;
+ pph_tree_catcher = pph_name_lookups = NULL;
+
+ /* Copy every declaration in V into the cache. */
+ for (i = 0; VEC_iterate (tree, v, i, t); i++)
+ {
+ /* 1- Determine the token hunk H that owns T. We first determine
+ the PTH image and then which hunk inside that PTH image. For
+ choosing the hunk within the image, we simulate a second
+ hash table lookup hashing the location to the token hunk. */
+ pth_image *image, *hunk;
+ VEC(cp_token, heap) *head_tokens, *body_tokens;
+ cp_token *first;
+
+ head_tokens = pph_lookup_head_token_cache_for (t);
+ body_tokens = pph_lookup_body_token_cache_for (t);
+ if (VEC_empty (cp_token, head_tokens))
+ continue;
+ first = VEC_index (cp_token, head_tokens, 0);
+ fname = LOCATION_FILE (first->location);
+ slot = htab_find_slot (cache_dir, fname, INSERT);
+ if (*slot == NULL)
+ {
+ image = XCNEW (pth_image);
+ *slot = CONST_CAST (char *, fname);
+ }
+ else
+ image = *((pth_image **) slot);
+
+ /* For now, re-do the pth_image_lookup to simulate the lookup of
+ the hunk within the image. */
+ slot = htab_find_slot (cache_dir, fname, NO_INSERT);
+ hunk = *((pth_image **) slot);
+
+ /* Insert dummy uses for head_tokens, body_tokens and image. */
+ if (i > VEC_length (tree, v))
+ {
+ free (head_tokens);
+ free (body_tokens);
+ free (image);
+ }
+
+ /* 2- Find the tree cache associated with HUNK. */
+ slot = pointer_map_insert (hunk_to_decls_map, hunk);
+ ast_cache = (VEC(tree, heap) *) *slot;
+
+ /* 3- Copy T and its type into the cache associated with HUNK.
+ If T has a body (a FUNCTION_DECL), copy the body. FIXME pph,
+ copying ASTs will need new copying code to be implemented,
+ the current routines do not handle everything that can be
+ generated by the C++ FE. */
+ t_copy = copy_decl (t);
+ if (!type_copy || TREE_TYPE (t))
+ type_copy = copy_type (TREE_TYPE (t));
+ if (TREE_CODE (t) == FUNCTION_DECL)
+ walk_tree (&DECL_SAVED_TREE (t_copy), copy_tree_r, (void *)1, NULL);
+ VEC_safe_push (tree, heap, ast_cache, t_copy);
+ *slot = (void *) ast_cache;
+ }
+
+ PPH_STATS_INCR (cached_decls, VEC_length (tree, v));
+
+ /* Restore tree and lookup catchers. */
+ pph_tree_catcher = old_pph_tree_catcher;
+ pph_name_lookups = old_pph_name_lookups;
+
+ timevar_pop (TV_PPH_CACHE_IN);
+}
+
+
+/* Emulate the cache actions needed to get a declaration out of the
+ parser cache and instantiate it into the current compilation context. */
+
+static void
+pph_copy_decls_outof_cache (VEC(tree, heap) *v)
+{
+ unsigned i;
+ tree t;
+ static VEC(tree, heap) *compilation_context = NULL;
+ VEC(tree, heap) *old_pph_tree_catcher, *old_pph_name_lookups;
+
+ /* Conceptually, this will be called with a token hunk that contains
+ all the declarations that we want to instantiate. */
+ timevar_push (TV_PPH_CACHE_OUT);
+
+ /* We will be copying trees, which will call into the tree catching
+ routines. Prevent that. */
+ old_pph_tree_catcher = pph_tree_catcher;
+ old_pph_name_lookups = pph_name_lookups;
+ pph_tree_catcher = pph_name_lookups = NULL;
+
+ /* 1- Verify that the hunk is valid. Traverse all the declarations
+ checking that none have been tainted. */
+ for (i = 0; VEC_iterate (tree, v, i, t); i++)
+ {
+ /* If T is not valid, none of its users is valid. */
+ if (1 || TREE_VISITED (t))
+ {
+ unsigned j;
+ tree r;
+ for (j = 0; VEC_iterate (tree, v, j, r); j++)
+ TREE_VISITED (r) = TREE_VISITED (r);
+ }
+ }
+
+ /* 2- Copy all the trees in the hunk to the current compilation context. */
+ for (i = 0; VEC_iterate (tree, v, i, t); i++)
+ {
+ static tree t_copy, type_copy;
+
+ t_copy = copy_decl (t);
+ if (!type_copy || TREE_TYPE (t))
+ type_copy = copy_type (TREE_TYPE (t));
+ if (TREE_CODE (t) == FUNCTION_DECL)
+ walk_tree (&DECL_SAVED_TREE (t_copy), copy_tree_r, (void *)1, NULL);
+
+ /* Emulate restoration into compilation context. FIXME pph, this is
+ missing the name lookups that may be required. Estimate this
+ separately from the number of name lookup operations and the
+ time spent doing name lookups. */
+ VEC_safe_push (tree, heap, compilation_context, t_copy);
+ }
+
+ PPH_STATS_INCR (restored_decls, VEC_length (tree, v));
+
+ /* Restore tree and lookup catchers. */
+ pph_tree_catcher = old_pph_tree_catcher;
+ pph_name_lookups = old_pph_name_lookups;
+
+ timevar_pop (TV_PPH_CACHE_OUT);
+}
+
+void
+pph_stop_exposed (cp_parser *parser, cp_token *first_token)
+{
+ if (flag_pph_debug >= 1 && !VEC_empty (tree, pph_tree_catcher))
+ {
+ cp_token *last_token;
+
+ timevar_push (TV_PPH_MANAGE);
+
+ last_token = parser->lexer->next_token;
+ pph_print_trees_tokens (pph_tree_catcher, first_token, last_token);
+ pph_copy_decls_into_cache (pph_tree_catcher);
+ pph_copy_decls_outof_cache (pph_tree_catcher);
+ PPH_STATS_INCR (cached_refs, VEC_length(tree, pph_name_lookups));
+ pph_free_catcher_memory ();
+ if (flag_pph_debug >= 4)
+ pph_log_exposed (parser, "stop");
+
+ timevar_pop (TV_PPH_MANAGE);
+ }
+}
+
+
+/* PPH printing help. */
+
+static void
+pph_debug_tree (tree t, bool body)
+{
+ if (t == NULL)
+ {
+ fprintf (pph_logfile, "nulldecl");
+ return;
+ }
+
+ if (!DECL_P (t))
+ {
+ fprintf (pph_logfile, "__%s__", tree_code_name[TREE_CODE (t)]);
+ return;
+ }
+
+ if (flag_pph_decls >= 2)
+ fprintf (pph_logfile, "%s ", tree_code_name[TREE_CODE (t)]);
+ fprintf (pph_logfile, "%d", (DECL_UID (t) << 1) + body);
+ if (flag_pph_decls >= 1)
+ fprintf (pph_logfile, " '%s'", get_name (t));
+ if (flag_pph_decls >= 3)
+ {
+ fprintf (pph_logfile, " ");
+ pph_debug_loc_of_tree (pph_logfile, t);
+ if (flag_pph_decls >= 4)
+ fprintf (pph_logfile, " @%p", (void *) t);
+ }
+}
+
+static void
+pph_debug_type (tree t, bool body)
+{
+ tree t_decl;
+ if (t == NULL)
+ {
+ fprintf (pph_logfile, "nulltype");
+ return;
+ }
+ t_decl = get_type_decl (t);
+ if (t_decl == NULL)
+ fprintf (pph_logfile, "nameless");
+ else
+ pph_debug_tree (t_decl, body);
+}
+
+/* Return true if tree T has been caught already. */
+
+static bool
+pph_tree_caught_p (tree t)
+{
+ return (pph_lookup_head_token_cache_for (t) != NULL);
+}
+
+/* Collect the tokens needed for the head of DECL.
+ This assumes that the current token is positioned right after
+ the end of the declarator expression for DECL (i.e., it should
+ be called from grokdeclarator). */
+
+static VEC(cp_token, heap) *
+pph_catch_head_tokens_for (tree t)
+{
+ cp_token *tok, *last, *first;
+ cp_lexer *lexer;
+ VEC(cp_token, heap) *tokens;
+
+ gcc_assert (t != error_mark_node);
+
+ tokens = pph_lookup_head_token_cache_for (t);
+ if (tokens)
+ {
+ fprintf (stderr, "*** ");
+ pph_debug_location (stderr, input_location);
+ fprintf (stderr, ": Tried to catch head tokens more than once for: ");
+ print_generic_stmt (stderr, t, 0);
+ gcc_unreachable ();
+ }
+
+ lexer = the_parser->lexer;
+
+ /* Look for the tokens backwards until the first brace or semicolon. */
+ first = last = lexer->next_token;
+ for (tok = last - 1; tok >= VEC_address (cp_token, lexer->buffer); tok--)
+ {
+ if (tok->type == CPP_OPEN_BRACE
+ || tok->type == CPP_CLOSE_BRACE
+ || tok->type == CPP_SEMICOLON)
+ break;
+
+ first = tok;
+ }
+
+ /* Now include any trailing semicolon. */
+ if (last->type == CPP_SEMICOLON)
+ last++;
+
+ /* Add all the tokens in [FIRST, LAST) to TOKENS. */
+ for (tok = first; tok != last; tok++)
+ VEC_safe_push (cp_token, heap, tokens, tok);
+
+ pph_set_head_token_cache_for (t, tokens);
+
+ return tokens;
+}
+
+
+/* Collect the tokens needed for the body of DECL.
+ This assumes that the current token is positioned right after
+ the end of the declarator expression for DECL (i.e., it should
+ be called from grokdeclarator). */
+
+static VEC(cp_token, heap) *
+pph_catch_body_tokens_for (tree t)
+{
+ cp_token *tok, *last, *first;
+ cp_lexer *lexer;
+ VEC(cp_token, heap) *tokens;
+
+ gcc_assert (t != error_mark_node);
+
+ tokens = pph_lookup_body_token_cache_for (t);
+ if (tokens)
+ {
+ fprintf (stderr, "*** ");
+ pph_debug_location (stderr, input_location);
+ fprintf (stderr, ": Tried to catch body tokens more than once for: ");
+ print_generic_stmt (stderr, t, 0);
+ gcc_unreachable ();
+ }
+
+ lexer = the_parser->lexer;
+
+ /* Look for the tokens forwards until the closing brace or semicolon. */
+ first = last = lexer->next_token;
+ tok = first;
+ if (tok->type == CPP_EQ || tok->type == CPP_OPEN_PAREN)
+ {
+ /* Skip a variable-like definition. Find the semicolon. */
+ /* FIXME pph - This code changes with C++0x. */
+ for (; tok <= VEC_last (cp_token, lexer->buffer); tok++)
+ if (tok->type == CPP_SEMICOLON)
+ break;
+ last = tok;
+ }
+ else if (tok->type == CPP_OPEN_BRACE || tok->type == CPP_COLON)
+ {
+ /* Skip a class-like or function-like definition.
+ Skip to a left brace, then skip to the matching right brace. */
+ /* FIXME pph - This code changes with C++0x. */
+ int nesting = 0;
+ for (; tok <= VEC_last (cp_token, lexer->buffer); tok++)
+ if (tok->type == CPP_OPEN_BRACE)
+ nesting++;
+ else if (tok->type == CPP_CLOSE_BRACE)
+ {
+ if ( nesting <= 1)
+ break;
+ else
+ nesting--;
+ }
+ last = tok;
+ }
+ else
+ return NULL; /* no body */
+
+ /* Add all the tokens in [FIRST, LAST) to TOKENS. */
+ for (tok = first; tok <= last; tok++)
+ VEC_safe_push (cp_token, heap, tokens, tok);
+
+ pph_set_body_token_cache_for (t, tokens);
+
+ return tokens;
+}
+
+
+/* Return the dependencies for tree node T. If HEADER_P is true, it
+ returns the dependencies for the header of T's declaration.
+ Otherwise, it returns dependencies for T's body. */
+
+static VEC(tree,gc) *
+pph_lookup_dependencies_for (tree t, bool header_p)
+{
+ struct pointer_map_t *map;
+ void **slot;
+
+ map = (header_p) ? pph_decl_deps->header : pph_decl_deps->body;
+ slot = pointer_map_contains (map, t);
+ if (slot)
+ return ((VEC(tree,gc) *) *slot);
+
+ return NULL;
+}
+
+
+/* Set the dependencies for tree node T to DEPS. If HEADER_P is true,
+ DEPS are the dependencies for T's header. Otherwise, DEPS are the
+ dependencies for T's body. */
+
+static void
+pph_set_dependencies_for (tree t, VEC(tree,gc) *deps, bool header_p)
+{
+ void **slot;
+ struct pointer_map_t *map;
+
+ map = (header_p) ? pph_decl_deps->header : pph_decl_deps->body;
+ slot = pointer_map_insert (map, t);
+ *slot = (void *) deps;
+}
+
+#define PPH_ARTIFICIAL(t) \
+(DECL_ARTIFICIAL (t) \
+&& !(TREE_CODE (t) == TYPE_DECL && DECL_IMPLICIT_TYPEDEF_P (t)))
+
+static bool
+is_namespace (tree container)
+{
+ enum tree_code code;
+
+ if (container == NULL)
+ return true;
+
+ code = TREE_CODE (container);
+ if (code == NAMESPACE_DECL)
+ return true;
+
+ return false;
+}
+
+/* Find the exposed declaration containing a symbol lookup. */
+
+static tree
+pph_null_exposed (const char *reason)
+{
+ if (flag_pph_debug >= 3)
+ fprintf (pph_logfile, "%s\n", reason);
+ return NULL;
+}
+
+static tree
+pph_live_exposed (tree t, bool body)
+{
+ if (PPH_ARTIFICIAL (t))
+ return pph_null_exposed ("Artificial symbols are not exposed.");
+
+ if (flag_pph_debug >= 3)
+ {
+ if (t == NULL)
+ fprintf (pph_logfile, "(null)");
+ else
+ pph_debug_tree (t, body);
+ fprintf (pph_logfile, "\n");
+ }
+ return t;
+}
+
+static tree
+pph_find_exposed_for (tree t, bool *body)
+{
+ tree container;
+ enum tree_code code, t_code;
+ bool in_class;
+ *body = false; /* By default, we only depend on heads. */
+ for ( ; ; t = container, *body = true)
+ {
+ reclassify:
+ if (t == NULL)
+ {
+ PPH_STATS_INCR (bad_lookups, 1);
+ return pph_null_exposed ("NULLOID"); /* FIXME pph */
+ }
+ if (flag_pph_debug >= 3)
+ {
+ fprintf (pph_logfile, " exposed for ");
+ pph_debug_tree (t, false);
+ fprintf (pph_logfile, " is ");
+ }
+ code = TREE_CODE (t);
+ switch (code)
+ {
+ /* Types common to C and C++. */
+ case ARRAY_TYPE:
+ case BOOLEAN_TYPE:
+ case COMPLEX_TYPE:
+ case ENUMERAL_TYPE:
+ case FIXED_POINT_TYPE:
+ case FUNCTION_TYPE:
+ case INTEGER_TYPE:
+ case LANG_TYPE:
+ case METHOD_TYPE:
+ case OFFSET_TYPE:
+ case POINTER_TYPE:
+ case QUAL_UNION_TYPE:
+ case REAL_TYPE:
+ case RECORD_TYPE:
+ case REFERENCE_TYPE:
+ case UNION_TYPE:
+ case VECTOR_TYPE:
+ case VOID_TYPE:
+ /* C++-specific types. */
+ case BOUND_TEMPLATE_TEMPLATE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ case TEMPLATE_TYPE_PARM:
+ case TYPENAME_TYPE:
+ case TYPEOF_TYPE:
+ case UNBOUND_CLASS_TEMPLATE:
+ case TYPE_ARGUMENT_PACK:
+ case TYPE_PACK_EXPANSION:
+ case DECLTYPE_TYPE:
+ {
+ if (TYPE_NAME (t) == NULL)
+ return pph_null_exposed ("Anonymous Type");
+ else
+ t = TYPE_NAME (t);
+ /* FALLTHRU */
+ }
+
+ case TYPE_DECL:
+ {
+ container = DECL_CONTEXT (t);
+ in_class = container && CLASS_TYPE_P (container);
+ t_code = TREE_CODE (TREE_TYPE (t));
+ /* FIXME pph: Why DECL_TEMPLATE_TEMPLATE_PARM_P does not apply
+ here? It is a template template parameter, but the tree code
+ is inconsistent. */
+ if (DECL_TEMPLATE_PARM_P (t)
+ || t_code == TEMPLATE_TEMPLATE_PARM
+ || t_code == BOUND_TEMPLATE_TEMPLATE_PARM)
+ return pph_null_exposed ("TMPLPARM");
+
+ if (is_namespace (container))
+ return pph_live_exposed (t, *body);
+ break;
+ }
+
+ case VAR_DECL:
+ {
+ /* If var is lazy, depend on its body, not its head. */
+ tree enclass = DECL_CONTEXT (t);
+ bool in_class = enclass && CLASS_TYPE_P (enclass);
+ bool defined = DECL_INITIAL (t) != NULL;
+ /* FIXME pph: DECL_INITIALIZED_P (t) */
+ if (defined && (in_class || !DECL_THIS_EXTERN (t))
+ && DECL_INTEGRAL_CONSTANT_VAR_P (t))
+ *body = true;
+
+ container = DECL_CONTEXT (t);
+ in_class = container && CLASS_TYPE_P (container);
+ if (in_class && DECL_THIS_STATIC (t))
+ container = TYPE_CONTEXT (container);
+ if (is_namespace (container))
+ return pph_live_exposed (t, *body);
+ break;
+ }
+
+ case FUNCTION_DECL:
+ {
+ /* If function is lazy, depend on body. */
+ bool defined = DECL_INITIAL (t) != NULL;
+ if (defined && (DECL_DECLARED_INLINE_P (t)
+ || DECL_USE_TEMPLATE (t) != 2))
+ *body = true;
+
+ container = DECL_CONTEXT (t);
+ in_class = container && CLASS_TYPE_P (container);
+ if (in_class)
+ container = TYPE_CONTEXT (container);
+ if (is_namespace (container))
+ return pph_live_exposed (t, *body);;
+ break;
+ }
+
+ case TEMPLATE_DECL:
+ {
+ int generic = DECL_USE_TEMPLATE (t);
+ if (generic != 2)
+ {
+ t = DECL_TEMPLATE_RESULT (t);
+ if (flag_pph_debug >= 3)
+ fprintf (pph_logfile, "template redirected\n");
+ goto reclassify;
+ }
+ }
+
+ case SCOPE_REF:
+ return pph_null_exposed ("SCOPE_REF"); /* FIXME pph */
+
+ case OVERLOAD:
+ return pph_null_exposed ("OVERLOAD"); /* FIXME pph */
+
+ case BASELINK:
+ container = BASELINK_BINFO (t);
+ break;
+
+ case TREE_BINFO:
+ container = BINFO_TYPE (t);
+ break;
+
+ case TREE_LIST:
+ t = TREE_VALUE (t);
+ /* Fallthru */
+
+ default:
+ {
+ if (t == NULL)
+ {
+ PPH_STATS_INCR (bad_lookups, 1);
+ return pph_null_exposed ("NULLOID"); /* FIXME pph */
+ }
+ else if (!DECL_P (t))
+ {
+ PPH_STATS_INCR (bad_lookups, 1);
+ return pph_null_exposed ("BOZOID"); /* FIXME pph */
+ /*FIXME pph:
+ fatal_error ("Expecting a *_decl node. Got %s",
+ tree_code_name[TREE_CODE (t)]);
+ */
+ }
+
+ container = DECL_CONTEXT (t);
+ in_class = container && CLASS_TYPE_P (container);
+ if (is_namespace (container))
+ return pph_null_exposed ("UNKNOWN");
+ break;
+ }
+ }
+ if (flag_pph_debug >= 3)
+ {
+ pph_debug_tree (container, *body);
+ fprintf (pph_logfile, "\n");
+ }
+ }
+}
+
+
+/* Collect the AST nodes that node T depends on. HEADER_P is true if
+ we should collect ASTs from T's header. Otherwise, we collect
+ ASTs from T's body. */
+
+static VEC(tree,gc) *
+pph_catch_dependencies_for (tree t, bool header_p)
+{
+ VEC(cp_token, heap) *tokens;
+ unsigned i;
+ cp_token *tok;
+ VEC(tree,gc) *deps;
+
+ tokens = (header_p)
+ ? pph_lookup_head_token_cache_for (t)
+ : pph_lookup_body_token_cache_for (t);
+
+ if (tokens == NULL)
+ tokens = (header_p)
+ ? pph_catch_head_tokens_for (t)
+ : pph_catch_body_tokens_for (t);
+
+ deps = pph_lookup_dependencies_for (t, header_p);
+
+ for (i = 0; VEC_iterate (cp_token, tokens, i, tok); i++)
+ if (tok->type == CPP_NAME)
+ VEC_safe_push (tree, gc, deps, tok->u.value);
+
+ pph_set_dependencies_for (t, deps, header_p);
+
+ return deps;
+}
+
+
+/* Intercept tree node T by storing it in pph_tree_catcher and collecting
+ the tokens used in its instantiation. */
+
+void
+pph_catch_tree (tree t)
+{
+ /* Only collect trees if the parser instantiated pph_tree_catcher
+ and we are currently parsing from the main lexer. */
+ if (pph_tree_catcher && the_parser->lexer->buffer && !pph_tree_caught_p (t))
+ {
+ timevar_push (TV_PPH_MANAGE);
+
+ VEC_safe_push (tree, heap, pph_tree_catcher, t);
+ pph_catch_head_tokens_for (t);
+ pph_catch_body_tokens_for (t);
+ pph_catch_dependencies_for (t, true);
+ pph_catch_dependencies_for (t, false);
+
+ timevar_pop (TV_PPH_MANAGE);
+ }
+}
+
+
+/* Retract a caught tree. */
+
+void
+pph_uncatch_tree (tree t)
+{
+ /* Only uncollect trees if the parser instantiated pph_tree_catcher
+ and we are currently parsing from the main lexer. */
+ if (pph_tree_catcher && the_parser->lexer->buffer)
+ {
+ int i;
+ tree u;
+
+ timevar_push (TV_PPH_MANAGE);
+
+ /* Find the index; if present, remove it. */
+ for (i = 0; VEC_iterate (tree, pph_tree_catcher, i, u); i++)
+ {
+ if (u == t)
+ {
+ VEC_ordered_remove (tree, pph_tree_catcher, i);
+ break;
+ }
+ }
+
+ timevar_pop (TV_PPH_MANAGE);
+ }
+}
+
+
+/* Given a set of tokens TOKENS, return the symbols from pph_name_lookups
+ that occur in TOKENS. The returned vector is, then, the set of all
+ symbols that were resolved via name lookups during parsing. This set
+ is a subset of all the CPP_NAME tokens in TOKENS. */
+
+static void
+pph_locate_name_lookups_in (VEC(cp_token, heap) *tokens,
+ VEC(tree,gc) **heads_found,
+ VEC(tree,gc) **bodies_found)
+{
+ unsigned i;
+ tree t;
+ cp_token *first, *last;
+
+ *heads_found = NULL;
+ *bodies_found = NULL;
+
+ if (tokens == NULL || VEC_empty (cp_token, tokens))
+ return;
+
+ first = VEC_index (cp_token, tokens, 0);
+ last = VEC_last (cp_token, tokens);
+
+ for (i = 0; VEC_iterate (tree, pph_name_lookups, i, t); i++)
+ {
+ unsigned j;
+ cp_token *tok;
+ VEC(cp_token, heap) *lookup_locations;
+ void **slot;
+ bool pushed = false;
+
+ slot = pointer_map_contains (pph_nl_token_map, t);
+ gcc_assert (slot && *slot);
+ lookup_locations = (VEC(cp_token, heap) *) *slot;
+ for (j = 0; VEC_iterate (cp_token, lookup_locations, j, tok); j++)
+ {
+ if (tok->location >= first->location
+ && tok->location <= last->location)
+ {
+ if (!pushed)
+ {
+ bool body;
+ tree exposed = pph_find_exposed_for (t, &body);
+ if (exposed)
+ {
+ if (body)
+ VEC_safe_push (tree, gc, *bodies_found, exposed);
+ else
+ VEC_safe_push (tree, gc, *heads_found, exposed);
+ pushed = true;
+ }
+ }
+
+ /* Avoid double-counting lookups by removing the lookup
+ location after a class member declaration has found it.
+ To make that work, we must remove all redundant entries. */
+ if (flag_pph_debug >= 4)
+ {
+ fprintf (pph_logfile, " lookup in %p for ",
+ (void*)lookup_locations);
+ pph_debug_tree (t, false);
+ fprintf (pph_logfile, " found at ");
+ pph_debug_location (pph_logfile, tok->location);
+ fprintf (pph_logfile, "\n");
+ fprintf (pph_logfile, " vector length from %d",
+ VEC_length (cp_token, lookup_locations));
+
+ }
+ /* This code is slow, but VEC won't let me null entires. */
+ VEC_ordered_remove (cp_token, lookup_locations, j);
+ /* We have just shifted down all later entries,
+ and need to counteract the upcoming index increment. */
+ j--;
+ if (flag_pph_debug >= 4)
+ {
+ fprintf (pph_logfile, " to %d\n",
+ VEC_length (cp_token, lookup_locations));
+ }
+ }
+ }
+ }
+}
+
+
+/* Print all the trees in V and the tokens in the token range
+ [TOK1, TOK2). */
+
+static VEC(cp_token, heap) *
+pph_print_copy_tokens (cp_token *tok1, cp_token *tok2)
+{
+ cp_token *tok;
+ VEC(cp_token, heap) *vtok;
+
+ /* If TOK2 is CPP_EOF, it will have the address of eof_token, which
+ will make the loop below go off the deep end. Detect this and
+ make TOK2 the last token in the lexer buffer instead. */
+ if (tok2 == &eof_token)
+ tok2 = VEC_last (cp_token, the_parser->lexer->buffer);
+
+ vtok = NULL;
+ for (tok = tok1; tok != tok2; tok++)
+ VEC_safe_push (cp_token, heap, vtok, tok);
+
+ return vtok;
+}
+
+static void
+pph_print_token_range (VEC(tree,heap) *v, VEC(cp_token, heap) *vtok)
+{
+ unsigned i;
+ tree t;
+
+ if (flag_pph_debug >= 4)
+ {
+ fprintf (pph_logfile, "PPH: hunk location ");
+ pph_debug_location (pph_logfile, VEC_index (cp_token, vtok, 0)->location);
+ fprintf (pph_logfile, " to ");
+ pph_debug_location (pph_logfile, VEC_last (cp_token, vtok)->location);
+ fprintf (pph_logfile, "\n");
+ fprintf (pph_logfile, "PPH: hunk tokens ");
+ cp_lexer_dump_tokens (stderr, (VEC(cp_token, gc) *)vtok, 0);
+ fprintf (pph_logfile, "PPH: hunk ASTs:\n");
+ for (i = 0; VEC_iterate (tree, v, i, t); i++)
+ {
+ pph_debug_tree (t, true);
+ /* FIXME pph: this may not be right; we may not care. */
+ print_generic_stmt (stderr, t, 0);
+ }
+ fprintf (pph_logfile, "PPH: hunk decls:\n");
+ }
+}
+
+static void
+pph_print_dependence (bool user_body, bool used_body,
+ tree t, tree d)
+{
+ static bool prior_user_body = false;
+ static bool prior_used_body = false;
+ static tree prior_t = NULL;
+ static tree prior_d = NULL;
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " pd_base ");
+ pph_debug_tree (t, user_body);
+ fprintf (pph_logfile, " on ");
+ pph_debug_tree (d, used_body);
+ fprintf (pph_logfile, "\n");
+ }
+ if (t && d && DECL_P (t) && DECL_P (d) && (t != d || user_body != used_body))
+ {
+ if (PPH_ARTIFICIAL (t))
+ {
+ /* Okay, find the real symbol this articial one belongs to. */
+ d = pph_find_exposed_for (d, &used_body);
+ if (d == NULL)
+ return;
+ used_body = true;
+ }
+ if (user_body != prior_user_body
+ || used_body != prior_used_body
+ || t != prior_t
+ || d != prior_d)
+ {
+ fprintf (pph_logfile, "depend ");
+ pph_debug_tree (t, user_body);
+ fprintf (pph_logfile, " uses ");
+ pph_debug_tree (d, used_body);
+ fprintf (pph_logfile, "\n");
+ prior_user_body = user_body;
+ prior_used_body = used_body;
+ prior_t = t;
+ prior_d = d;
+ }
+ }
+}
+
+static void
+pph_print_depend_template (tree tmpl_info, tree t)
+{
+ tree tmpl_decl;
+ tree tmpl_ptrn;
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " pd_template ");
+ pph_debug_tree (t, true);
+ fprintf (pph_logfile, " %p", (void*)tmpl_info);
+ fprintf (pph_logfile, "\n");
+ }
+ tmpl_decl = TI_TEMPLATE (tmpl_info);
+ if (TREE_CODE (tmpl_decl) == OVERLOAD)
+ tmpl_decl = OVL_CURRENT (tmpl_decl);
+ tmpl_ptrn = DECL_TEMPLATE_RESULT (tmpl_decl);
+ if (tmpl_ptrn && t != tmpl_ptrn)
+ {
+ /* This is a template, but not the pattern. */
+ pph_print_dependence (true, true, t, tmpl_ptrn);
+ }
+}
+
+/* Print the dependence of a head of declaration
+ on the body of a type that the head uses directly.
+ If either of these is not exposed,
+ find the body of the exposed declaration that contains it. */
+
+static void
+pph_print_depend_decl (tree user, tree used)
+{
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " pd_decl ");
+ pph_debug_tree (user, false);
+ fprintf (pph_logfile, " on ");
+ pph_debug_tree (used, false);
+ fprintf (pph_logfile, "\n");
+ }
+ if (user != NULL)
+ {
+ if (used != NULL)
+ {
+ bool body;
+ tree exp_for_user = pph_find_exposed_for (user, &body);
+ tree exp_for_used = pph_find_exposed_for (used, &body);
+ if (exp_for_user && exp_for_used && exp_for_user != exp_for_used)
+ pph_print_dependence (exp_for_user != user, true,
+ exp_for_user, exp_for_used);
+ }
+ }
+}
+
+static void
+pph_print_depend_type (tree decl, tree type)
+{
+ tree type_decl;
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " pd_type ");
+ pph_debug_tree (decl, false);
+ fprintf (pph_logfile, " on ");
+ pph_debug_type (type, false);
+ fprintf (pph_logfile, "\n");
+ }
+ if (type != NULL)
+ {
+ type_decl = get_type_decl (type);
+ pph_print_depend_decl (decl, type_decl);
+ }
+}
+
+static void
+pph_print_depend_type_type (tree t)
+{
+ tree t_type;
+ tree field;
+
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " depending on typedecl type ");
+ pph_debug_tree (t, false);
+ fprintf (pph_logfile, "\n");
+ }
+
+ t_type = TREE_TYPE (t);
+ field = TYPE_FIELDS (t_type);
+ for (; field; field = TREE_CHAIN(field))
+ {
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " field ");
+ pph_debug_tree (field, false);
+ }
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ tree f_type = TREE_TYPE (field);
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " of type ");
+ pph_debug_type (f_type, false);
+ if (DECL_FIELD_IS_BASE (field))
+ fprintf (pph_logfile, " is a base field!!\n");
+ else
+ fprintf (pph_logfile, " is a plain field\n");
+ }
+ pph_print_depend_type (t, f_type);
+ }
+ else if (TREE_CODE (field) == TYPE_DECL)
+ {
+ tree f_type = TREE_TYPE (field);
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " of type ");
+ pph_debug_type (f_type, false);
+ fprintf (pph_logfile, " is a type field\n");
+ }
+ pph_print_depend_type (t, f_type);
+ }
+ }
+
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " end of fields\n");
+ }
+}
+
+static void
+pph_print_depend_func_type (tree t)
+{
+ /* We must print a dependence of the head of the function
+ on the body of the types of its signature. */
+
+ tree args;
+ tree func_type;
+
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " depending on function type ");
+ pph_debug_tree (t, false);
+ fprintf (pph_logfile, "\n");
+ }
+
+ func_type = TREE_TYPE (t);
+ pph_print_depend_type (t, TREE_TYPE (func_type)); /* return type */
+ for (args = TYPE_ARG_TYPES (func_type); args; args = TREE_CHAIN (args))
+ pph_print_depend_type (t, TREE_VALUE (args)); /* parameter */
+
+ if (DECL_VIRTUAL_P (t))
+ {
+ tree ctx_type = DECL_CONTEXT (t);
+ tree ctx_decl = get_type_decl (ctx_type);
+ /* Virtual functions depend on containing class's body.*/
+ pph_print_depend_type (t, ctx_type);
+ /* The virtual class's body also depends on the function
+ for construction of the vtable. */
+ pph_print_dependence (true, true, ctx_decl, t);
+ }
+}
+
+static void
+pph_print_depend_var_type (tree t)
+{
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " depending on var/field type ");
+ pph_debug_tree (t, false);
+ fprintf (pph_logfile, "\n");
+ }
+
+ pph_print_depend_type (t, TREE_TYPE (t));
+}
+
+enum decl_exposure { HIDDEN, EXPOSED, NEEDED };
+
+static enum decl_exposure
+pph_get_decl_exposure (tree t)
+{
+ tree container;
+ tree type;
+ tree tmpl_info;
+ bool defined = false;
+ bool inlined = false;
+ bool needed = false;
+ int generic = 0;
+ enum tree_code code = TREE_CODE (t);
+
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " get_exposure for ");
+ pph_debug_tree (t, false);
+ fprintf (pph_logfile, "\n");
+ }
+
+ /* For DECL_USE_TEMPLATE and CLASSTYPE_USE_TEMPLATE,
+ 1=implicit instantiation
+ 2=partial or explicit specialization, e.g.:
+ template <> int min<int> (int, int),
+ 3=explicit instantiation, e.g.:
+ template int min<int> (int, int);
+ */
+
+ if (code == TYPE_DECL)
+ {
+ pph_print_depend_type_type (t);
+
+ container = DECL_CONTEXT (t);
+ if (!is_namespace (container))
+ return HIDDEN;
+ type = TREE_TYPE (t);
+ defined = COMPLETE_TYPE_P (type);
+
+ /* FIXME pph: Why DECL_TEMPLATE_TEMPLATE_PARM_P does not apply
+ here? It is a template template parameter, but the tree code
+ is inconsistent. */
+ if (DECL_TEMPLATE_PARM_P (t)
+ || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+ return HIDDEN;
+ if (CLASS_TYPE_P (t))
+ {
+ tmpl_info = CLASSTYPE_TEMPLATE_INFO (type);
+ generic = CLASSTYPE_USE_TEMPLATE (type);
+ }
+ else
+ {
+ tmpl_info = NULL;
+ generic = 0;
+ }
+ if (generic == 1)
+ return HIDDEN;
+ if (tmpl_info != NULL)
+ {
+ pph_print_depend_template (tmpl_info, t);
+ needed = defined && generic == 3;
+ }
+ else
+ {
+ needed = false;
+ }
+ }
+ else if (code == VAR_DECL)
+ {
+ tree enclass = DECL_CONTEXT (t);
+ bool in_class = enclass && CLASS_TYPE_P (enclass);
+ /* If the VAR_DECL is in a class, it must be a static member. */
+ container = enclass;
+ if (in_class)
+ container = TYPE_CONTEXT (enclass);
+
+ pph_print_depend_var_type (t);
+
+ if (!is_namespace (container))
+ return HIDDEN;
+ defined = DECL_INITIAL (t) != NULL /* FIXME pph: DECL_INITIALIZED_P (t) */;
+ type = TREE_TYPE (t);
+ needed = !((!defined && (in_class || DECL_THIS_EXTERN (t)))
+ || DECL_INTEGRAL_CONSTANT_VAR_P (t));
+ if (in_class)
+ {
+ tmpl_info = DECL_TEMPLATE_INFO (t);
+ generic = DECL_USE_TEMPLATE (t);
+ if (generic == 1)
+ return HIDDEN;
+ }
+ else
+ {
+ tmpl_info = NULL;
+ generic = 0;
+ }
+ if (tmpl_info != NULL)
+ {
+ pph_print_depend_template (tmpl_info, t);
+ needed = needed && generic == 3;
+ }
+ }
+ else if (code == FUNCTION_DECL)
+ {
+ if (flag_pph_debug >= 2)
+ {
+ fprintf (pph_logfile, " depending on function ");
+ pph_debug_tree (t, false);
+ fprintf (pph_logfile, "\n");
+ }
+
+ container = DECL_CONTEXT (t);
+ if (container && CLASS_TYPE_P (container))
+ container = TYPE_CONTEXT (DECL_CONTEXT (t));
+
+ pph_print_depend_func_type (t);
+
+ if (!is_namespace (container))
+ return HIDDEN;
+ inlined = DECL_DECLARED_INLINE_P (t);
+ defined = DECL_INITIAL (t) != NULL;
+ tmpl_info = DECL_TEMPLATE_INFO (t);
+ generic = DECL_USE_TEMPLATE (t);
+ if (tmpl_info != NULL)
+ {
+ if (generic == 2)
+ needed = defined && !inlined;
+ else
+ {
+ pph_print_depend_template (tmpl_info, t);
+ needed = defined && !inlined && generic == 3;
+ }
+ }
+ else
+ {
+ needed = defined && !inlined;
+ }
+ }
+ else
+ {
+ gcc_assert (code < MAX_TREE_CODES);
+ return HIDDEN;
+ }
+
+ if (needed)
+ return NEEDED;
+ else
+ return EXPOSED;
+}
+
+static void
+pph_print_dependences (bool user_body, bool used_body,
+ tree t, VEC(tree,gc) *deps)
+{
+ unsigned j;
+ tree d;
+ for (j = 0; VEC_iterate (tree, deps, j, d); j++)
+ pph_print_dependence (user_body, used_body, t, d);
+}
+
+/* Print the head of declaration T and its dependencies. N_HEAD_TOKENS
+ is the number of tokens taken by T's head. N_HEAD_ITOKENS is the
+ number of invisible tokens.
+
+ HEAD_TOKENS is the array of tokens in the head (note that the
+ length of this array may be different than N_HEAD_TOKENS, due to
+ adjustments made by the caller).
+
+ If CONTAINER is set, then T is a member of it. */
+
+static void
+pph_print_declaration_head (tree t, bool artificial, tree container,
+ unsigned n_head_tokens, unsigned n_head_invis,
+ VEC(cp_token, heap) *head_tokens)
+{
+ VEC(tree,gc) *sym_head_deps, *sym_body_deps;
+ enum tree_code code = TREE_CODE (t);
+
+ fprintf (pph_logfile, "declaration ");
+ pph_debug_tree (t, false);
+
+ fprintf (pph_logfile, " htok %u,%u", n_head_tokens, n_head_invis);
+
+ /*FIXME pph: We want to get rid of most artificial tokens;
+ this is temporary to find them. */
+ if (artificial)
+ fprintf (pph_logfile, " artificial");
+
+ if (container)
+ {
+ fprintf (pph_logfile, " mbrof ");
+ pph_debug_tree (get_type_decl (container), true);
+ }
+
+ fprintf (pph_logfile, "\n");
+
+ /* Template instances should depend on their pattern body. */
+ if (artificial)
+ {
+ if (code == TYPE_DECL)
+ {
+ tree t_type = TREE_TYPE (t);
+ if (CLASS_TYPE_P (t_type))
+ {
+ tree tmpl_info = CLASSTYPE_TEMPLATE_INFO (t_type);
+ if (tmpl_info != NULL)
+ pph_print_depend_template (tmpl_info, t);
+ }
+ }
+ else if (code == VAR_DECL || code == FUNCTION_DECL)
+ {
+ tree tmpl_info;
+ tmpl_info = (DECL_LANG_SPECIFIC (t)) ? DECL_TEMPLATE_INFO (t) : NULL;
+ if (tmpl_info != NULL)
+ pph_print_depend_template (tmpl_info, t);
+ }
+ }
+ else
+ {
+ /* From the name dependencies, determine symbol dependencies
+ by correlating the location of the looked-up symbols with
+ the tokens in HEAD_TOKENS and BODY_TOKENS. */
+ if (flag_pph_debug >= 2)
+ fprintf (pph_logfile, " begin normal dependences\n");
+ pph_locate_name_lookups_in (head_tokens, &sym_head_deps, &sym_body_deps);
+ pph_print_dependences (false, false, t, sym_head_deps);
+ pph_print_dependences (true, false, t, sym_body_deps);
+ if (flag_pph_debug >= 2)
+ fprintf (pph_logfile, " end normal dependences\n");
+ }
+}
+
+
+/* Print the head of declaration T and its dependencies. N_BODY_TOKENS
+ is the number of tokens taken by T's head. N_BODY_ITOKENS is the
+ number of invisible tokens.
+
+ BODY_TOKENS is the array of tokens in the head (note that the
+ length of this array may be different than N_BODY_TOKENS, due to
+ adjustments made by the caller).
+
+ EXPOSURE indicates the exposure of T.
+
+ N_SUBTOKENS is the number of tokens that declarations inside T's
+ body have used up, those should be subtracted from the total number
+ of tokens in T to avoid double counting. */
+
+static void
+pph_print_declaration_body (tree t, bool artificial,
+ enum decl_exposure exposure,
+ unsigned n_body_tokens, unsigned n_body_invis,
+ VEC(cp_token, heap) *body_tokens)
+{
+ VEC(tree,gc) *sym_head_deps, *sym_body_deps;
+ const char* msg;
+
+ fprintf (pph_logfile, "declaration ");
+ pph_debug_tree (t, true);
+
+ fprintf (pph_logfile, " btok %u,%u", n_body_tokens, n_body_invis);
+
+ /* FIXME pph: We want to get rid of most artificial tokens;
+ this is temporary to find them. */
+ if (artificial)
+ msg = "artificial";
+ else if (exposure == NEEDED)
+ msg = "needed";
+ else
+ msg = "lazy";
+ fprintf (pph_logfile, " %s", msg);
+
+ fprintf (pph_logfile, "\n");
+
+ pph_print_dependence (true, false, t, t); /* body depends on its head */
+
+ if (flag_pph_debug >= 2)
+ fprintf (pph_logfile, " begin normal dependences\n");
+ pph_locate_name_lookups_in (body_tokens, &sym_head_deps, &sym_body_deps);
+ pph_print_dependences (true, false, t, sym_head_deps);
+ pph_print_dependences (true, false, t, sym_body_deps);
+ if (flag_pph_debug >= 2)
+ fprintf (pph_logfile, " end normal dependences\n");
+}
+
+
+/* Compute the implicit cost of a method F. */
+
+static unsigned
+pph_find_special_methods (tree f)
+{
+ unsigned found = 0;
+ tree o;
+ if (TREE_CODE (f) == OVERLOAD)
+ {
+ for (o = f; o; o = OVL_NEXT (o))
+ found |= pph_find_special_methods (OVL_CURRENT (o));
+ }
+ else if (TREE_CODE (f) == TEMPLATE_DECL)
+ found |= pph_find_special_methods (DECL_TEMPLATE_RESULT (f));
+ else
+ {
+ gcc_assert (TREE_CODE (f) == FUNCTION_DECL);
+ if (DECL_ARTIFICIAL (f))
+ return found;
+ if (DECL_CONSTRUCTOR_P (f))
+ if (DECL_COPY_CONSTRUCTOR_P (f))
+ found |= (1<<2); /* copy constructor */
+ else
+ found |= (1<<1); /* default constructor */
+ else if (DECL_DESTRUCTOR_P (f))
+ found |= (1<<0); /* destructor */
+ else if (DECL_ASSIGNMENT_OPERATOR_P (f))
+ found |= (1<<3); /* copy assign op */
+ }
+ return found;
+}
+
+/* Compute the implicit cost of a class type T_TYPE. */
+
+static unsigned
+pph_implicit_class_cost (tree t_type)
+{
+ VEC(tree,gc) *methods;
+ unsigned idx;
+ unsigned mbrs;
+ unsigned cost = 0;
+ unsigned found = 0;
+
+ /* Gather general statistics. */
+ unsigned fields = fields_length (t_type); /* also direct bases */
+ unsigned vptr = (TYPE_POLYMORPHIC_P (t_type) ? 1 : 0);
+ unsigned slots = fields + vptr;
+ unsigned vbases = VEC_length (tree, CLASSTYPE_VBASECLASSES (t_type));
+ unsigned vtables = list_length (CLASSTYPE_VTABLES (t_type));
+
+ /* Assign cost of implicit special member variables. */
+ /* These costs are somewhat arbitrary. */
+ cost += 20 * (CLASSTYPE_TYPEINFO_VAR (t_type) != NULL); /* typeinfo */
+ cost += 4 * vbases * vtables; /* virtual tables */
+
+ /* Assign cost of implicit special member functions. */
+ /* First find them. */
+ methods = CLASSTYPE_METHOD_VEC (t_type);
+ if (methods != NULL)
+ for (idx = 0; idx < VEC_length (tree, methods); idx++)
+ {
+ tree ovld = VEC_index (tree, methods, idx);
+ if (ovld)
+ found |= pph_find_special_methods (ovld);
+ }
+ /* These costs are somewhat arbitrary. */
+ /* FIXME pph: These queries seem to not work for templates.
+ We can accept the inaccuracy for now. */
+ mbrs = slots * 2 + vbases * 4;
+ if (!(found & (1<<2))) /* copy constructor */
+ {
+ if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (t_type))
+ cost += 4;
+ else
+ cost += (8 + 2*mbrs) * (vbases > 0 ? 2 : 1);
+ }
+ if (!(found & (1<<1))) /* default constructor */
+ if (!TYPE_HAS_TRIVIAL_DFLT (t_type))
+ cost += 4 + mbrs;
+ if (!(found & (1<<0))) /* destructor */
+ if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (t_type))
+ cost += (8 + 2*mbrs) * (vbases > 0 ? 2 : 1);
+ if (!(found & (1<<3))) /* copy assign op */
+ {
+ if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (t_type))
+ cost += 4;
+ else
+ cost += (8 + 2*mbrs);
+ }
+
+ return cost;
+}
+
+
+/* Print declaration T with the given EXPOSURE. If T has a body with
+ N tokens, subtract N_SUBTOKENS from it before printing them.
+ This is used when printing class declarations. The caller first
+ prints all the declarations inside the class, followed by the
+ class declaration itself, to avoid double counting tokens in the class
+ body, they are subtracted from the total count.
+
+ PRIMARY is true when T is the very first declaration captured
+ during a pph_start_exposed/pph_stop_exposed region. If T is a
+ member of a class, and it happens to be the first declaration
+ captured, it means that T is an out-of-line definition.
+
+ If T is a member of a class, and PARENT is the TYPE_DECL for that
+ class, it means that we are printing the in-class declaration of T.
+ In that case, when we print the parent, we should subtract the
+ tokens attributed to T. So, in these cases return the total
+ number of tokens printed in T's head and body. Otherwise,
+ return 0. */
+
+static unsigned
+pph_print_declaration (tree t, enum decl_exposure exposure,
+ unsigned n_subtokens, bool primary, tree parent)
+{
+ tree container = NULL;
+ enum tree_code code = TREE_CODE (t);
+ bool is_member = false;
+ bool artificial = PPH_ARTIFICIAL (t);
+ bool print_head = true, print_body = true;
+
+ /* The cost of a declaration is proportional to the number of tokens.
+ Artificial symbols are not represented in the file, so they do
+ not have tokens. We represent their cost as a number of
+ invisible tokens. */
+ VEC(cp_token, heap) *head_tokens = pph_lookup_head_token_cache_for (t);
+ unsigned n_head_tokens = VEC_length (cp_token, head_tokens);
+ unsigned n_head_invis = 0;
+ VEC(cp_token, heap) *body_tokens = pph_lookup_body_token_cache_for (t);
+ unsigned n_body_tokens = VEC_length (cp_token, body_tokens);
+ unsigned n_body_invis = 0;
+ unsigned n_member_tokens = 0;
+
+ /* If this is a member of a class, count the number of tokens in the
+ member that overlap with the containing class. */
+ if (code == FUNCTION_DECL || code == VAR_DECL)
+ {
+ container = DECL_CONTEXT (t);
+ if (container && CLASS_TYPE_P (container))
+ {
+ is_member = true;
+ if (parent && container == TREE_TYPE (parent))
+ n_member_tokens = n_head_tokens + n_body_tokens;
+ }
+ }
+
+ /* Now we need to adjust costs, and head/body printing. */
+
+ if (code == VAR_DECL)
+ {
+ if (artificial)
+ /* Artificial static member variables get their token
+ counts from the calling expression, which isn't helpful.
+ Build the cost into the class instead. All of which
+ means suppress this decl. */
+ return 0;
+
+ if (DECL_NONTRIVIALLY_INITIALIZED_P (t)
+ && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t))
+ n_body_invis += 10;
+
+ if (is_member)
+ {
+ if (primary) /* Must be an out-of-line declaration/definition. */
+ {
+ /* Merge out-of-line member definitions into the body.
+ This merge prevents two heads for the same symbol. */
+ n_body_tokens += n_head_tokens;
+ n_body_invis += n_head_invis;
+ n_head_tokens = 0;
+ n_head_invis = 0;
+ print_head = false;
+ /* Out-of-line member variable declarations are definitions,
+ and hence need to be generated. */
+ exposure = NEEDED;
+ }
+ else /* Not primary; must be an in-line declaration/definition. */
+ {
+ /* The only var bodies in the class are manifest constants;
+ merge them into the head. */
+ n_head_tokens += n_body_tokens;
+ n_head_invis += n_body_invis;
+ n_body_tokens = 0;
+ n_body_invis = 0;
+ print_body = false;
+ }
+ }
+ else /* not is_member */
+ {
+ if (exposure == EXPOSED)
+ {
+ /* Merge manifest constants into the head.
+ This code sweeps up extern declarations with no bodies,
+ but that's okay. */
+ n_head_tokens += n_body_tokens;
+ n_head_invis += n_body_invis;
+ n_body_tokens = 0;
+ n_body_invis = 0;
+ print_body = false;
+ }
+ }
+ if (exposure == NEEDED)
+ n_body_invis += 4; /* For emitting the actual variable declaration. */
+ }
+ else if (code == FUNCTION_DECL)
+ {
+ /* Pure function declarations get no body. */
+ if (exposure == EXPOSED && !artificial
+ && n_body_tokens == 0 && n_body_invis == 0)
+ print_body = false;
+ if (artificial)
+ {
+ if (is_member)
+ {
+ /* Artificial special member functions get their token
+ counts from the calling expression, which isn't helpful.
+ Build the cost into the class instead. All of which
+ means suppress this decl. */
+ return 0;
+ }
+ }
+ }
+ else if (code == TYPE_DECL)
+ {
+ tree t_type = TREE_TYPE (t);
+
+ if (artificial)
+ return 0;
+
+ if (DECL_IMPLICIT_TYPEDEF_P (t)
+ && CLASS_TYPE_P (t_type)
+ && TYPE_LANG_SPECIFIC (t_type))
+ {
+ tree tmpl_info;
+ int generic;
+
+ n_body_invis += pph_implicit_class_cost (t_type);
+
+ tmpl_info = CLASSTYPE_TEMPLATE_INFO (t_type);
+ if (tmpl_info)
+ {
+ generic = CLASSTYPE_USE_TEMPLATE (t_type);
+ if (generic == 1)
+ {
+ /* Implicit instantiations have no visibile tokens. */
+ n_head_invis += n_head_tokens;
+ n_head_tokens = 0;
+ n_body_invis += n_body_tokens;
+ n_body_tokens = 0;
+ }
+ else if (generic == 3)
+ {
+ /* Explicit instantiations have no bodies,
+ but they are work. This approximation is
+ unjustified, but we are presuming that explicit
+ instantiations are rare in application code. */
+ n_body_invis += 15;
+ exposure = NEEDED;
+ }
+ if (generic != 2)
+ {
+ bool defined;
+ defined = CLASS_TYPE_P (t_type) && COMPLETE_TYPE_P (t_type);
+ if (defined)
+ pph_print_depend_template (tmpl_info, t);
+ }
+ }
+ else if (primary)
+ {
+ /* Now subtract the sum of members from the body of the class.
+ This prevents double counting when emitting the parent.
+ For non-primary class symbols, this value will be zero. */
+ gcc_assert (n_body_tokens >= n_subtokens);
+ n_body_tokens -= n_subtokens;
+ }
+ }
+ else if (TREE_CODE (t_type) == ENUMERAL_TYPE)
+ {
+ /* No additional work for enum. */
+ }
+ else
+ {
+ /* Not artificial, not a C++ class, not an enum;
+ so must be a pure typedef. They have no body. */
+ gcc_assert (n_body_tokens == 0 && n_body_invis == 0);
+ print_body = false;
+ }
+ }
+
+ if (print_head)
+ pph_print_declaration_head (t, artificial, (is_member) ? container : NULL,
+ n_head_tokens, n_head_invis, head_tokens);
+
+ if (print_body)
+ pph_print_declaration_body (t, artificial, exposure,
+ n_body_tokens, n_body_invis, body_tokens);
+
+ if (flag_pph_debug >= 4)
+ {
+ fprintf (pph_logfile, " Declarator head tokens: ");
+ cp_lexer_debug_tokens ((VEC(cp_token, gc) *)head_tokens);
+ fprintf (pph_logfile, " Declarator body tokens: ");
+ cp_lexer_debug_tokens ((VEC(cp_token, gc) *)body_tokens);
+ fprintf (pph_logfile, "\n");
+ }
+
+ return n_member_tokens;
+}
+
+static void
+pph_print_declarations (VEC(tree,heap) *v)
+{
+ unsigned i, j, n, first_ix;
+ tree t, first, parent;
+ enum decl_exposure exposure;
+ unsigned n_subtokens = 0;
+
+ if (VEC_empty (tree, v))
+ return;
+
+ /* If the first AST in V is a class/structure declaration, process
+ the sub-declarations first. This will accumulate the tokens in
+ the sub-declarations, so that when we print the class itself
+ we don't double count the tokens in its body. */
+
+ /* Skip over un-exposed declarations, like template parameters. */
+ n = VEC_length (tree, v);
+ for ( i = 0; VEC_iterate (tree, v, i, t); i++)
+ {
+ exposure = pph_get_decl_exposure (t);
+ if (exposure >= EXPOSED)
+ break;
+ }
+ if (i >= n)
+ return; /* No exposed decls. */
+
+ first = VEC_index (tree, v, i);
+ if (VEC_length (tree, v) > i+1
+ && TREE_CODE (first) == TYPE_DECL
+ && CLASS_TYPE_P (TREE_TYPE (first)))
+ {
+ parent = first;
+ first_ix = i+1;
+ }
+ else
+ {
+ parent = NULL;
+ first_ix = i;
+ }
+
+ for (j = first_ix; VEC_iterate (tree, v, j, t); j++)
+ {
+ exposure = pph_get_decl_exposure (t);
+ if (exposure >= EXPOSED)
+ n_subtokens += pph_print_declaration (t, exposure, 0U, i == j, parent);
+ }
+
+ /* If we didn't print the first declaration, print it now. */
+ if (first_ix > i)
+ {
+ exposure = pph_get_decl_exposure (first);
+ if (exposure >= EXPOSED)
+ pph_print_declaration (first, exposure, n_subtokens, true, NULL);
+ }
+}
+
+static void
+pph_print_trees_tokens (VEC(tree,heap) *v, cp_token *tok1, cp_token *tok2)
+{
+ VEC(cp_token, heap) *vtok;
+
+ vtok = pph_print_copy_tokens (tok1, tok2);
+ if (vtok == NULL)
+ return;
+
+ pph_print_token_range (v, vtok);
+ pph_print_declarations (v);
+ fprintf (pph_logfile, "\n");
+}
+
+
+/* Intercept the result of a name lookup operation requested by the
+ parser while we are intercepting AST creation. T is the result
+ of a name lookup done by the parser. If this is the first time
+ we see it, store it in pph_name_lookups. */
+
+void
+pph_catch_name_lookup (tree t)
+{
+ if (t == NULL_TREE || t == error_mark_node || pph_tree_catcher == NULL)
+ return;
+
+ timevar_push (TV_PPH_MANAGE);
+
+ PPH_STATS_INCR (name_lookups, 1);
+
+ if (the_parser->lexer)
+ {
+ /* If we are parsing, we are stopped one token past the identifier
+ that we have just looked up. Store the token where we have seen
+ this identifier so that we can determine whether the identifier
+ was accessed in a head or a body.
+
+ Note that we do this for every instance we find for T, so that
+ we can store all the locations where T was accessed from. */
+ VEC(cp_token, heap) *tokens;
+ cp_token *tok;
+ void **slot;
+
+ slot = pointer_map_insert (pph_nl_token_map, t);
+ tokens = (VEC(cp_token, heap) *) *slot;
+ tok = the_parser->lexer->next_token - 1;
+ VEC_safe_push (cp_token, heap, tokens, tok);
+ *slot = tokens;
+ }
+
+ /* Make sure we do not store the same decl more than once. */
+ if (pointer_set_insert (pph_name_lookups_set, t))
+ {
+ timevar_pop (TV_PPH_MANAGE);
+ return;
+ }
+
+ VEC_safe_push (tree, heap, pph_name_lookups, t);
+ timevar_pop (TV_PPH_MANAGE);
+}
+
+
+/* Print statistics for the PPH cache. */
+
+static void
+pph_print_stats (void)
+{
+ fprintf (stderr, "\nPPH cache statistics\n");
+ fprintf (stderr, "Number of tokens in the lexer: %lu\n",
+ pph_stats.lexed_tokens);
+ fprintf (stderr, "Number of tokens consumed by the parser: %lu\n",
+ pph_stats.parsed_tokens);
+ fprintf (stderr, "Number of declarations cached in: %lu\n",
+ pph_stats.cached_decls);
+ fprintf (stderr, "Number of declarations restored: %lu\n",
+ pph_stats.restored_decls);
+ fprintf (stderr, "Number of cached decl references: %lu\n",
+ pph_stats.cached_refs);
+ fprintf (stderr, "Number of name lookups: %lu\n",
+ pph_stats.name_lookups);
+ fprintf (stderr, "Number of bad lookups: %lu\n",
+ pph_stats.bad_lookups);
+}
+
+
+/* Initialize PPH support. */
+
+void
+pph_init (void)
+{
+ if (flag_pph_logfile)
+ {
+ pph_logfile = fopen (flag_pph_logfile, "w");
+ if (!pph_logfile)
+ fatal_error ("Cannot create %s for writing: %m", flag_pph_logfile);
+ }
+ else
+ pph_logfile = stdout;
+}
+
+
+/* Finalize PPH support. */
+
+void
+pph_finish (void)
+{
+ if (flag_pph_stats)
+ pph_print_stats ();
+
+ if (flag_pph_logfile)
+ fclose (pph_logfile);
+}
+
+#include "gt-cp-pph.h"
===================================================================
@@ -0,0 +1,303 @@
+/* Factored pre-tokenized header (PTH) support for C++
+ Copyright (C) 2010 Free Software Foundation, Inc.
+ Contributed by Lawrence Crowl <crowl@google.com> and
+ Diego Novillo <dnovillo@google.com>.
+
+ 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/>. */
+
+#ifndef GCC_CP_PPH_H
+#define GCC_CP_PPH_H
+
+#include "line-map.h"
+#include "hashtab.h"
+#include "parser.h"
+#include "timevar.h"
+
+/* A set of contiguous tokens within a single file. */
+typedef struct GTY(()) cp_token_hunk
+{
+ /* Captured identifier and macro state. */
+ cpp_idents_used identifiers;
+
+ /* The array of tokens. */
+ VEC(cp_token,gc) *buffer;
+
+ /* Offset into the libcpp file buffer where this token hunk starts at.
+ If this token hunk is invalidated, the lexer is repositioned at
+ this offset into the file to start lexing again. */
+ cpp_offset text_offset;
+
+ /* Length of this hunk in characters. When the tokens in this hunk
+ are moved into the lexer buffer, the original character stream
+ is advanced this many characters to avoid future lexing from
+ seeing these tokens again. */
+ size_t text_length;
+} cp_token_hunk;
+
+typedef struct cp_token_hunk *cp_token_hunk_ptr;
+
+DEF_VEC_P (cp_token_hunk_ptr);
+DEF_VEC_ALLOC_P (cp_token_hunk_ptr,gc);
+
+/* Number of bytes in an MD5 signature. */
+#define DIGEST_LEN 16
+
+struct pth_image;
+typedef struct pth_image *pth_image_ptr;
+DEF_VEC_P (pth_image_ptr);
+DEF_VEC_ALLOC_P (pth_image_ptr,gc);
+
+DEF_VEC_ALLOC_I(char,gc);
+
+/* Description of a #include command. This records the #include type
+ used in the original source and the image included. It is used
+ to restore a file from its character stream in case that the
+ associated image is found to be tainted. */
+
+typedef struct GTY(()) pth_include
+{
+ /* The image to include. */
+ struct pth_image *image;
+
+ /* The #include command used: #include, #include_next or #import. */
+ enum include_type itype;
+
+ /* Nonzero if this include used angle brackets. */
+ unsigned int angle_brackets : 1;
+
+ /* Name used in the command used in this #include command. */
+ const char * GTY((skip)) iname;
+
+ /* Directory where INAME can be found. This is not necessarily
+ the same as lbasename (IMAGE->FNAME), but it is always true that
+ DNAME/INAME == IMAGE->FNAME. */
+ const char * GTY((skip)) dname;
+} pth_include;
+
+typedef struct pth_include *pth_include_ptr;
+DEF_VEC_P (pth_include_ptr);
+DEF_VEC_ALLOC_P (pth_include_ptr,gc);
+
+/* An entry in the incremental cache. Each entry represents
+ a single file in the translation unit. Tokens are saved in a linked
+ list of lexers, separated by file change events in the pre-processor.
+ Every time the preprocessor signals a file change, a new lexer for
+ this entry is created. */
+
+typedef struct GTY(()) pth_image
+{
+ /* Full path name. */
+ const char * GTY((skip)) fname;
+
+ /* MD5 sum for the contents of the original path name. */
+ unsigned char digest[DIGEST_LEN];
+
+ /* Vector of token hunks corresponding to this file, and this file
+ only. If this file includes other files, their tokens will not be
+ stored here. Each entry in this vector is a hunk of tokens
+ delimited by file change events. For instance, if a file is
+ laid out like this:
+
+ [ t1 t2 ... tN ]
+ #include "foo.h"
+ [ p1 p2 ... pM ]
+
+ The field token_caches will have two entries. One for the hunk
+ [t1, tN], the second one for the hunk [p1, pM]. */
+ VEC(cp_token_hunk_ptr,gc) *token_hunks;
+
+ /* Vector of files included by this file. */
+ VEC(pth_include_ptr,gc) *includes;
+
+ /* Sequencing string that describes how the elements from
+ TOKEN_HUNKS and INCLUDES are interleaved. Each character of this
+ string is either 'H' (hunk) or 'I' (include). This is used in
+ pth_image_to_lexer to know in what order should the hunks
+ and include files be processed.
+
+ FIXME pph, using a character string is heavy handed. A bitmap
+ would suffice, but for now this is easier and the space consumed
+ should not be too significant. */
+ VEC(char,gc) *ih_sequence;
+
+ /* True if this image needs to be flushed out to disk. */
+ unsigned int save_p : 1;
+
+ /* True if this image has been loaded from an image file. */
+ unsigned int loaded_p: 1;
+
+ /* True if this image has been incorporated into the current
+ compilation context. FIXME pph, should we keep track of this
+ at the hunk level? */
+ unsigned int used_p : 1;
+
+ /* True if we have computed the MD5 digest for FNAME. */
+ unsigned int digest_computed_p : 1;
+
+ /* Index into the lexer buffer where the next token hunk to be
+ created should start. This is managed by the file changing
+ logic in pth_file_change. */
+ unsigned hunk_start_ix;
+
+ /* Offset into the libcpp character buffer where the next token
+ hunk will be read from. */
+ cpp_offset hunk_text_offset;
+
+ /* libcpp buffer associated with IMAGE->FNAME. */
+ cpp_buffer * GTY((skip)) buffer;
+} pth_image;
+
+
+/* PTH state. This holds all the data needed to manage the PTH cache. */
+typedef struct GTY(()) pth_state
+{
+ /* The cache of pre-tokenized content. */
+ VEC(pth_image_ptr,gc) *cache;
+
+ /* Pointer map for speeding up cache lookups. */
+ htab_t GTY((param_is (struct pth_image))) cache_dir;
+
+ /* The current cache image being modified. */
+ pth_image *cur_image;
+
+ /* Attributes for the most recent #include command found by
+ pth_include_handler. */
+ enum include_type new_itype;
+ bool new_angle_brackets;
+ const char *new_iname;
+
+ /* The lexer used to pre-process the file. */
+ cp_lexer *lexer;
+
+ /* Previously registered file change callback. */
+ void (*file_change_prev) (cpp_reader *, const struct line_map *);
+} pth_state;
+
+
+/* Statistics on PTH. */
+
+struct pth_stats_d
+{
+ /* Number of files processed as a regular #include. */
+ size_t included_files;
+
+ /* Number of valid images. */
+ size_t valid_images;
+
+ /* Number of token hunks seen. */
+ size_t hunks;
+
+ /* Number of valid hunks copied from images. */
+ size_t valid_hunks;
+
+ /* Number of hunks that failed dependency checks. */
+ size_t invalid_hunks;
+
+ /* Number of verified hunks. */
+ size_t verified_hunks;
+
+ /* Number of verified identifiers. */
+ size_t verified_identifiers;
+};
+
+extern struct pth_stats_d pth_stats;
+
+#define PTH_STATS_INCR(CNT,N) \
+ do { \
+ if (flag_pth_stats) \
+ pth_stats.CNT += (N); \
+ } while (0)
+
+
+/* Statistics on PPH. */
+
+struct pph_stats_d
+{
+ /* Number of tokens parsed in this TU. */
+ size_t parsed_tokens;
+
+ /* Number of tokens in the lexer buffer. */
+ size_t lexed_tokens;
+
+ /* Number of declarations copied into the parser cache. */
+ size_t cached_decls;
+
+ /* Number of declarations restored from the parser cache. */
+ size_t restored_decls;
+
+ /* Number of references rebound when going in/out of the cache. */
+ size_t cached_refs;
+
+ /* Number of name lookups done by the parser. */
+ size_t name_lookups;
+
+ /* Number of decl lookups that were changed to something weird. */
+ size_t bad_lookups;
+};
+
+extern struct pph_stats_d pph_stats;
+
+#define PPH_STATS_INCR(CNT,N) \
+ do { \
+ if (flag_pph_stats) \
+ pph_stats.CNT += (N); \
+ } while (0)
+
+
+/* Maps for tracking decl dependencies. For each *_DECL tree intercepted
+ during parsing, we store the trees on which the node depends for
+ its declaration. Two maps are kept, one for the head of the declaration
+ and another for its body. */
+struct pph_decl_deps_d
+{
+ /* Symbol dependencies on the declaration header. */
+ struct pointer_map_t *header;
+
+ /* Symbol dependencies on the declaration body. */
+ struct pointer_map_t *body;
+};
+
+/* Global state. FIXME pph, get rid of these. */
+
+/* Log file where PPH analysis is written to. Controlled by
+ -fpph_logfile. If this flag is not given, stdout is used. */
+extern FILE *pph_logfile;
+
+#define PPH_POP_TIMEVAR_AND_RETURN(TV, T) \
+ do { \
+ pph_catch_name_lookup (T); \
+ POP_TIMEVAR_AND_RETURN(TV, T); \
+ } while (0)
+
+
+/* In pph.c */
+extern void pth_init (cp_lexer *);
+extern void pth_finish (void);
+extern void pth_debug_state (void);
+extern void pth_debug_token_hunks (pth_image *);
+extern pth_image *pth_image_lookup (pth_state *, const char *, cpp_reader *);
+extern pth_state *pth_get_state (void);
+extern void pth_print_stats (FILE *, cp_lexer *);
+extern cp_token *pph_start_exposed (cp_parser *);
+extern void pph_stop_exposed (cp_parser *, cp_token *);
+extern void pph_init (void);
+extern void pph_finish (void);
+extern void pph_catch_tree (tree);
+extern void pph_uncatch_tree (tree);
+extern void pph_catch_name_lookup (tree);
+
+#endif /* GCC_CP_PPH_H */
===================================================================
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.
#include "cp-objcp-common.h"
#include "hashtab.h"
#include "target.h"
+#include "parser.h"
+#include "pph.h"
enum c_language_kind c_language = clk_cxx;
static void cp_init_ts (void);
===================================================================
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.
#include "timevar.h"
#include "tree-iterator.h"
#include "vecprim.h"
+#include "pph.h"
/* The type of functions taking a tree, and some additional data, and
returning an int. */
===================================================================
@@ -37,432 +37,20 @@ along with GCC; see the file COPYING3.
#include "cgraph.h"
#include "c-family/c-common.h"
#include "plugin.h"
-#include "timevar.h"
-#include "pointer-set.h"
-#include "fixed-value.h"
-#include "cpplib.h"
-#include "line-map.h"
-#include "md5.h"
-#include "hashtab.h"
-#include "tree-pass.h"
-#include "tree-inline.h"
#include "tree-pretty-print.h"
+#include "parser.h"
+#include "pph.h"
-
/* The lexer. */
/* The cp_lexer_* routines mediate between the lexer proper (in libcpp
and c-lex.c) and the C++ parser. */
-/* A token's value and its associated deferred access checks and
- qualifying scope. */
-
-struct GTY(()) tree_check {
- /* The value associated with the token. */
- tree value;
- /* The checks that have been associated with value. */
- VEC (deferred_access_check, gc)* checks;
- /* The token's qualifying scope (used when it is a
- CPP_NESTED_NAME_SPECIFIER). */
- tree qualifying_scope;
-};
-
-/* A C++ token. */
-
-typedef struct GTY (()) cp_token {
- /* The kind of token. */
- ENUM_BITFIELD (cpp_ttype) type : 8;
- /* If this token is a keyword, this value indicates which keyword.
- Otherwise, this value is RID_MAX. */
- ENUM_BITFIELD (rid) keyword : 8;
- /* Token flags. */
- unsigned char flags;
- /* Identifier for the pragma. */
- ENUM_BITFIELD (pragma_kind) pragma_kind : 6;
- /* True if this token is from a context where it is implicitly extern "C" */
- BOOL_BITFIELD implicit_extern_c : 1;
- /* True for a CPP_NAME token that is not a keyword (i.e., for which
- KEYWORD is RID_MAX) iff this name was looked up and found to be
- ambiguous. An error has already been reported. */
- BOOL_BITFIELD ambiguous_p : 1;
- /* True for a token that has been purged. If a token is purged,
- it is no longer a valid token and it should be considered
- deleted. */
- BOOL_BITFIELD purged_p : 1;
- /* The location at which this token was found. */
- location_t location;
- /* The value associated with this token, if any. */
- union cp_token_value {
- /* Used for CPP_NESTED_NAME_SPECIFIER and CPP_TEMPLATE_ID. */
- struct tree_check* GTY((tag ("1"))) tree_check_value;
- /* Use for all other tokens. */
- tree GTY((tag ("0"))) value;
- } GTY((desc ("(%1.type == CPP_TEMPLATE_ID) || (%1.type == CPP_NESTED_NAME_SPECIFIER)"))) u;
-} cp_token;
-
-DEF_VEC_O (cp_token);
-DEF_VEC_ALLOC_O (cp_token,gc);
-DEF_VEC_ALLOC_O (cp_token,heap);
-
-
-/* We use a stack of token pointer for saving token sets. */
-typedef struct cp_token *cp_token_position;
-DEF_VEC_P (cp_token_position);
-DEF_VEC_ALLOC_P (cp_token_position,heap);
-
-static cp_token eof_token =
+cp_token eof_token =
{
CPP_EOF, RID_MAX, 0, PRAGMA_NONE, false, false, false, 0, { NULL }
};
-/* The cp_lexer structure represents the C++ lexer. It is responsible
- for managing the token stream from the preprocessor and supplying
- it to the parser. Tokens are never added to the cp_lexer after
- it is created. */
-
-typedef struct GTY (()) cp_lexer {
- /* The memory allocated for the buffer. NULL if this lexer does not
- own the token buffer. */
- VEC(cp_token,gc) *buffer;
-
- /* A pointer just past the last available token. The tokens
- in this lexer are [buffer, last_token). */
- cp_token_position GTY ((skip)) last_token;
-
- /* The next available token. If NEXT_TOKEN is &eof_token, then there are
- no more available tokens. */
- cp_token_position GTY ((skip)) next_token;
-
- /* A stack indicating positions at which cp_lexer_save_tokens was
- called. The top entry is the most recent position at which we
- began saving tokens. If the stack is non-empty, we are saving
- tokens. */
- VEC(cp_token_position,heap) *GTY ((skip)) saved_tokens;
-
- /* The next lexer in a linked list of lexers. */
- struct cp_lexer *next;
-
- /* True if we should output debugging information. */
- bool debugging_p;
-
- /* True if we're in the context of parsing a pragma, and should not
- increment past the end-of-line marker. */
- bool in_pragma;
-} cp_lexer;
-
-DEF_VEC_O (cp_lexer);
-DEF_VEC_ALLOC_O (cp_lexer,heap);
-
-/* cp_token_cache is a range of tokens. There is no need to represent
- allocate heap memory for it, since tokens are never removed from the
- lexer's array. There is also no need for the GC to walk through
- a cp_token_cache, since everything in here is referenced through
- a lexer. */
-
-typedef struct GTY(()) cp_token_cache {
- /* The beginning of the token range. */
- cp_token * GTY((skip)) first;
-
- /* Points immediately after the last token in the range. */
- cp_token * GTY ((skip)) last;
-} cp_token_cache;
-
-typedef cp_token_cache *cp_token_cache_ptr;
-DEF_VEC_P (cp_token_cache_ptr);
-DEF_VEC_ALLOC_P (cp_token_cache_ptr,gc);
-
-struct cp_token_ident_d
-{
- unsigned int ident_len;
- const char *ident_str;
- unsigned int before_len;
- const char *before_str;
- unsigned int after_len;
- const char *after_str;
-};
-
-typedef struct cp_token_ident_d cp_token_ident;
-
-/* A set of contiguous tokens within a single file. */
-typedef struct GTY(()) cp_token_hunk
-{
- /* Captured identifier and macro state. */
- cpp_idents_used identifiers;
-
- /* The array of tokens. */
- VEC(cp_token,gc) *buffer;
-
- /* Offset into the libcpp file buffer where this token hunk starts at.
- If this token hunk is invalidated, the lexer is repositioned at
- this offset into the file to start lexing again. */
- cpp_offset text_offset;
-
- /* Length of this hunk in characters. When the tokens in this hunk
- are moved into the lexer buffer, the original character stream
- is advanced this many characters to avoid future lexing from
- seeing these tokens again. */
- size_t text_length;
-} cp_token_hunk;
-
-typedef struct cp_token_hunk *cp_token_hunk_ptr;
-
-DEF_VEC_P (cp_token_hunk_ptr);
-DEF_VEC_ALLOC_P (cp_token_hunk_ptr,gc);
-
-/* Number of bytes in an MD5 signature. */
-#define DIGEST_LEN 16
-
-struct pth_image;
-typedef struct pth_image *pth_image_ptr;
-DEF_VEC_P (pth_image_ptr);
-DEF_VEC_ALLOC_P (pth_image_ptr,gc);
-
-DEF_VEC_ALLOC_I(char,gc);
-
-/* Description of a #include command. This records the #include type
- used in the original source and the image included. It is used
- to restore a file from its character stream in case that the
- associated image is found to be tainted. */
-
-typedef struct GTY(()) pth_include
-{
- /* The image to include. */
- struct pth_image *image;
-
- /* The #include command used: #include, #include_next or #import. */
- enum include_type itype;
-
- /* Nonzero if this include used angle brackets. */
- unsigned int angle_brackets : 1;
-
- /* Name used in the command used in this #include command. */
- const char * GTY((skip)) iname;
-
- /* Directory where INAME can be found. This is not necessarily
- the same as lbasename (IMAGE->FNAME), but it is always true that
- DNAME/INAME == IMAGE->FNAME. */
- const char * GTY((skip)) dname;
-} pth_include;
-
-typedef struct pth_include *pth_include_ptr;
-DEF_VEC_P (pth_include_ptr);
-DEF_VEC_ALLOC_P (pth_include_ptr,gc);
-
-/* An entry in the incremental cache. Each entry represents
- a single file in the translation unit. Tokens are saved in a linked
- list of lexers, separated by file change events in the pre-processor.
- Every time the preprocessor signals a file change, a new lexer for
- this entry is created. */
-
-typedef struct GTY(()) pth_image
-{
- /* Full path name. */
- const char * GTY((skip)) fname;
-
- /* MD5 sum for the contents of the original path name. */
- unsigned char digest[DIGEST_LEN];
-
- /* Vector of token hunks corresponding to this file, and this file
- only. If this file includes other files, their tokens will not be
- stored here. Each entry in this vector is a hunk of tokens
- delimited by file change events. For instance, if a file is
- laid out like this:
-
- [ t1 t2 ... tN ]
- #include "foo.h"
- [ p1 p2 ... pM ]
-
- The field token_caches will have two entries. One for the hunk
- [t1, tN], the second one for the hunk [p1, pM]. */
- VEC(cp_token_hunk_ptr,gc) *token_hunks;
-
- /* Vector of files included by this file. */
- VEC(pth_include_ptr,gc) *includes;
-
- /* Sequencing string that describes how the elements from
- TOKEN_HUNKS and INCLUDES are interleaved. Each character of this
- string is either 'H' (hunk) or 'I' (include). This is used in
- pth_image_to_lexer to know in what order should the hunks
- and include files be processed.
-
- FIXME pph, using a character string is heavy handed. A bitmap
- would suffice, but for now this is easier and the space consumed
- should not be too significant. */
- VEC(char,gc) *ih_sequence;
-
- /* True if this image needs to be flushed out to disk. */
- unsigned int save_p : 1;
-
- /* True if this image has been loaded from an image file. */
- unsigned int loaded_p: 1;
-
- /* True if this image has been incorporated into the current
- compilation context. FIXME pph, should we keep track of this
- at the hunk level? */
- unsigned int used_p : 1;
-
- /* True if we have computed the MD5 digest for FNAME. */
- unsigned int digest_computed_p : 1;
-
- /* Index into the lexer buffer where the next token hunk to be
- created should start. This is managed by the file changing
- logic in pth_file_change. */
- unsigned hunk_start_ix;
-
- /* Offset into the libcpp character buffer where the next token
- hunk will be read from. */
- cpp_offset hunk_text_offset;
-
- /* libcpp buffer associated with IMAGE->FNAME. */
- cpp_buffer * GTY((skip)) buffer;
-} pth_image;
-
-
-/* PTH state. This holds all the data needed to manage the PTH cache. */
-typedef struct GTY(()) pth_state
-{
- /* The cache of pre-tokenized content. */
- VEC(pth_image_ptr,gc) *cache;
-
- /* Pointer map for speeding up cache lookups. */
- htab_t GTY((param_is (struct pth_image))) cache_dir;
-
- /* The current cache image being modified. */
- pth_image *cur_image;
-
- /* Attributes for the most recent #include command found by
- pth_include_handler. */
- enum include_type new_itype;
- bool new_angle_brackets;
- const char *new_iname;
-
- /* The lexer used to pre-process the file. */
- cp_lexer *lexer;
-
- /* Previously registered file change callback. */
- void (*file_change_prev) (cpp_reader *, const struct line_map *);
-} pth_state;
-
-
-/* Statistics on PTH. */
-
-struct pth_stats_d
-{
- /* Number of files processed as a regular #include. */
- size_t included_files;
-
- /* Number of valid images. */
- size_t valid_images;
-
- /* Number of token hunks seen. */
- size_t hunks;
-
- /* Number of valid hunks copied from images. */
- size_t valid_hunks;
-
- /* Number of hunks that failed dependency checks. */
- size_t invalid_hunks;
-
- /* Number of verified hunks. */
- size_t verified_hunks;
-
- /* Number of verified identifiers. */
- size_t verified_identifiers;
-};
-
-static struct pth_stats_d pth_stats;
-
-#define PTH_STATS_INCR(CNT,N) \
- do { \
- if (flag_pth_stats) \
- pth_stats.CNT += (N); \
- } while (0)
-
-
-/* Statistics on PPH. */
-
-struct pph_stats_d
-{
- /* Number of tokens parsed in this TU. */
- size_t parsed_tokens;
-
- /* Number of tokens in the lexer buffer. */
- size_t lexed_tokens;
-
- /* Number of declarations copied into the parser cache. */
- size_t cached_decls;
-
- /* Number of declarations restored from the parser cache. */
- size_t restored_decls;
-
- /* Number of references rebound when going in/out of the cache. */
- size_t cached_refs;
-
- /* Number of name lookups done by the parser. */
- size_t name_lookups;
-
- /* Number of decl lookups that were changed to something weird. */
- size_t bad_lookups;
-};
-
-static struct pph_stats_d pph_stats;
-
-#define PPH_STATS_INCR(CNT,N) \
- do { \
- if (flag_pph_stats) \
- pph_stats.CNT += (N); \
- } while (0)
-
-
-/* Cache of token ranges for head of symbol declarations. For each
- *_DECL tree intercepted during parsing, we store the vector of
- tokens that make up the head of the declaration for the node. */
-static struct pointer_map_t *pph_decl_head_token_cache = NULL;
-
-/* Cache of token ranges for body of symbol declarations. For each
- *_DECL tree intercepted during parsing, we store the vector of
- tokens that make up the body of the declaration for the node. */
-static struct pointer_map_t *pph_decl_body_token_cache = NULL;
-
-/* Maps for tracking decl dependencies. For each *_DECL tree intercepted
- during parsing, we store the trees on which the node depends for
- its declaration. Two maps are kept, one for the head of the declaration
- and another for its body. */
-struct pph_decl_deps_d
-{
- /* Symbol dependencies on the declaration header. */
- struct pointer_map_t *header;
-
- /* Symbol dependencies on the declaration body. */
- struct pointer_map_t *body;
-};
-
-/* Map of decl dependencies. */
-static struct pph_decl_deps_d *pph_decl_deps = NULL;
-
-/* Tree catcher for the incremental compiler. Whenever this array is
- allocated, make_node_stat() will push certain trees into this array. */
-static VEC(tree,heap) *pph_tree_catcher = NULL;
-
-/* Catcher for name lookups. This stores every name lookup performed
- on identifiers while we are catching ASTs in the parser. */
-static VEC(tree,heap) *pph_name_lookups = NULL;
-
-/* Since identifiers may be looked up more than once during parsing,
- this set prevents duplicate symbols from being placed in
- pph_name_lookups. */
-static struct pointer_set_t *pph_name_lookups_set = NULL;
-
-/* This map stores the token locations where a given symbol was looked
- up. When an identifier is looked up and resolved to symbol S, we
- check where the current token pointer is and save it in a vector
- associated with S. */
-static struct pointer_map_t *pph_nl_token_map = NULL;
-
-/* Log file where PPH analysis is written to. Controlled by
- -fpph_logfile. If this flag is not given, stdout is used. */
-static FILE *pph_logfile = NULL;
-
/* The various kinds of non integral constant we encounter. */
typedef enum non_integral_constant {
NIC_NONE,
@@ -587,8 +175,6 @@ typedef enum required_token {
/* Prototypes. */
-static void pph_print_trees_tokens (VEC(tree,heap) *, cp_token *, cp_token *);
-
static cp_lexer *cp_lexer_new_main
(void);
static cp_lexer *cp_lexer_new_from_tokens
@@ -597,8 +183,6 @@ static void cp_lexer_destroy
(cp_lexer *);
static int cp_lexer_saving_tokens
(const cp_lexer *);
-static cp_token_position cp_lexer_token_position
- (cp_lexer *, bool);
static cp_token *cp_lexer_token_at
(cp_lexer *, cp_token_position);
static void cp_lexer_get_preprocessor_token
@@ -655,25 +239,6 @@ static void cp_parser_initial_pragma
#define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
#define CP_SAVED_TOKEN_STACK 5
-/* A token type for keywords, as opposed to ordinary identifiers. */
-#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
-
-/* A token type for template-ids. If a template-id is processed while
- parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
- the value of the CPP_TEMPLATE_ID is whatever was returned by
- cp_parser_template_id. */
-#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
-
-/* A token type for nested-name-specifiers. If a
- nested-name-specifier is processed while parsing tentatively, it is
- replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
- CPP_NESTED_NAME_SPECIFIER is whatever was returned by
- cp_parser_nested_name_specifier_opt. */
-#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
-
-/* The number of token types, including C++-specific ones. */
-#define N_CP_TTYPES ((int) (CPP_NESTED_NAME_SPECIFIER + 1))
-
/* Variables. */
#ifdef ENABLE_CHECKING
@@ -688,7 +253,7 @@ int cp_unevaluated_operand;
/* Dump up to NUM tokens in BUFFER to FILE. If NUM is 0, dump all the
tokens. */
-static void
+void
cp_lexer_dump_tokens (FILE *file, VEC(cp_token,gc) *buffer, unsigned num)
{
unsigned i;
@@ -729,1461 +294,12 @@ cp_lexer_dump_tokens (FILE *file, VEC(cp
/* Dump all tokens in BUFFER to stderr. */
-static void
+void
cp_lexer_debug_tokens (VEC(cp_token,gc) *buffer)
{
cp_lexer_dump_tokens (stderr, buffer, 0);
}
-/* Return true if path P1 and path P2 point to the same file. */
-
-static inline bool
-pathnames_equal_p (const char *p1, const char *p2)
-{
- return strcmp (lrealpath (p1), lrealpath (p2)) == 0;
-}
-
-/* Expand and print location LOC to FILE. If FILE is NULL, pph_logfile
- is used. */
-
-static void
-pph_debug_location (FILE *file, location_t loc)
-{
- expanded_location xloc;
- file = (file) ? file : pph_logfile;
- xloc = expand_location (loc);
- fprintf (file, "%s:%d:%d", lrealpath (xloc.file), xloc.line, xloc.column);
-}
-
-
-/* Expand and print the location of tree T to FILE. If FILE is NULL,
- pph_logfile is used. */
-
-static void
-pph_debug_loc_of_tree (FILE *file, tree t)
-{
- pph_debug_location (file, DECL_SOURCE_LOCATION (t));
-}
-
-
-/* Hash and comparison functions for the directory of cached images. */
-
-static hashval_t
-pth_image_dir_hash (const void *p)
-{
- const char *s = lrealpath (((const pth_image *)p)->fname);
- return htab_hash_string (s);
-}
-
-
-static int
-pth_image_dir_eq (const void *p1, const void *p2)
-{
- const char *s1 = ((const pth_image *)p1)->fname;
- const char *s2 = ((const pth_image *)p2)->fname;
- return pathnames_equal_p (s1, s2);
-}
-
-
-
-static GTY(()) pth_state *pth_global_state = NULL;
-
-/* Return the global PTH state where the cache and its directory
- are stored. */
-
-static pth_state *
-pth_get_state (void)
-{
- if (pth_global_state == NULL)
- {
- pth_global_state = ggc_alloc_cleared_pth_state ();
- pth_global_state->cache_dir = htab_create_ggc (10, pth_image_dir_hash,
- pth_image_dir_eq, NULL);
- }
-
- return pth_global_state;
-}
-
-
-/* Return an identification string for a PTH image. */
-
-static const char *
-pth_id_str (void)
-{
- /* FIXME pph - Build a better identification string. */
- return "PTH0x42";
-}
-
-
-/* Return the number of bytes taken by the header of a PTH image. */
-
-static size_t
-pth_header_len (void)
-{
- /* The header of a PTH image contains:
- - An identification string (pth_id_str ())
- - The MD5 digest for the source file associated with the image.
- */
- return strlen (pth_id_str ()) + DIGEST_LEN;
-}
-
-
-#define PTH_EXTENSION ".pth"
-
-/* Return a new string with the extension PTH_EXTENSION appended to NAME. The
- caller is responsible for freeing the returned string. */
-
-static char *
-pth_name_for (const char *name)
-{
- size_t i, len;
- char *s;
-
- len = strlen (name) + sizeof (PTH_EXTENSION) + 1;
- s = XCNEWVEC (char, len);
- sprintf (s, "%s" PTH_EXTENSION, name);
-
- /* Make the file name unique and store it in the current directory. */
- for (i = 0; i < len - sizeof (PTH_EXTENSION) - 1; i++)
- if (!ISALNUM (s[i]))
- s[i] = '_';
-
- return s;
-}
-
-
-/* Open an image file for path NAME with MODE. */
-
-static FILE *
-pth_file_for (const char *name, const char *mode)
-{
- char *s;
- FILE *f;
-
- s = pth_name_for (name);
- f = fopen (s, mode);
- if (f == NULL)
- fatal_error ("can%'t open token stream file %s: %m", s);
- free (s);
-
- return f;
-}
-
-
-/* Compute the MD5 digest for FNAME. Store it in DIGEST. */
-
-static void
-pth_get_md5_digest (const char *fname, unsigned char digest[DIGEST_LEN])
-{
- if (flag_pth_md5)
- {
- FILE *f;
-
- timevar_push (TV_PTH_MD5);
-
- f = fopen (fname, "rb");
- if (f == NULL)
- fatal_error ("Cannot open %s for computing its digest: %m", fname);
-
- md5_stream (f, digest);
-
- fclose (f);
-
- timevar_pop (TV_PTH_MD5);
- }
- else
- {
- struct stat buf;
-
- if (stat (fname,&buf) != 0)
- fatal_error ("Cannot stat %s: %m", fname);
-
- memset (digest, 0, DIGEST_LEN);
- memcpy (digest, &buf.st_mtime, sizeof (buf.st_mtime));
- }
-}
-
-
-/* Compute an index value for TYPE suitable for restoring it later
- from global_trees[] or integer_types. The index is saved
- in TYPE_IX_P and the number category (one of CPP_N_INTEGER,
- CPP_N_FLOATING, etc) is saved in CATEGORY_P. */
-
-static void
-pth_get_index_from_type (tree type, unsigned *type_ix_p, unsigned *category_p)
-{
- void **val_p;
- static struct pointer_map_t *type_cache = NULL;
-
- /* For complex types we will just use the type of the components. */
- if (TREE_CODE (type) == COMPLEX_TYPE)
- {
- *type_ix_p = 0;
- *category_p = CPP_N_IMAGINARY;
- return;
- }
-
- if (type_cache == NULL)
- type_cache = pointer_map_create ();
-
- val_p = pointer_map_contains (type_cache, type);
- if (val_p)
- *type_ix_p = *((unsigned *) val_p);
- else
- {
- if (CP_INTEGRAL_TYPE_P (type))
- {
- unsigned i;
- for (i = itk_char; i < itk_none; i++)
- if (type == integer_types[i])
- {
- *type_ix_p = (unsigned) i;
- break;
- }
-
- gcc_assert (i != itk_none);
- }
- else if (FLOAT_TYPE_P (type) || FIXED_POINT_TYPE_P (type))
- {
- unsigned i;
-
- for (i = TI_ERROR_MARK; i < TI_MAX; i++)
- if (global_trees[i] == type)
- {
- *type_ix_p = (unsigned) i;
- break;
- }
-
- gcc_assert (i != TI_MAX);
- }
- else
- gcc_unreachable ();
- }
-
- if (CP_INTEGRAL_TYPE_P (type))
- *category_p = CPP_N_INTEGER;
- else if (FLOAT_TYPE_P (type))
- *category_p = CPP_N_FLOATING;
- else if (FIXED_POINT_TYPE_P (type))
- *category_p = CPP_N_FRACT;
- else
- gcc_unreachable ();
-}
-
-
-/* Write a uint VALUE to the STREAM. Return the number of bytes written. */
-
-static inline size_t
-pth_write_uint (unsigned int value, FILE *stream)
-{
- size_t sent = fwrite (&value, 1, sizeof (value), stream);
- gcc_assert (sent == sizeof (value));
- return sent;
-}
-
-
-/* Write a size_t VALUE to the STREAM. Return the number of bytes written. */
-
-static inline size_t
-pth_write_sizet (size_t value, FILE *stream)
-{
- size_t sent = fwrite (&value, 1, sizeof (value), stream);
- gcc_assert (sent == sizeof (value));
- return sent;
-}
-
-
-/* Write N bytes from P to STREAM. */
-
-static inline size_t
-pth_write_bytes (const void *p, size_t n, FILE *stream)
-{
- size_t sent = fwrite (p, 1, n, stream);
- gcc_assert (sent == n);
- return sent;
-}
-
-
-/* Write string STR and its LENGTH to STREAM. */
-
-static inline size_t
-pth_write_string (const char *str, unsigned int length, FILE *stream)
-{
- size_t sent;
-
- if (str == NULL)
- sent = pth_write_uint (-1, stream);
- else
- {
- sent = pth_write_uint (length, stream);
- if (length > 0)
- sent += pth_write_bytes (str, length, stream);
- }
-
- return sent;
-}
-
-
-/* Save the number VAL to file F. Return the number of bytes written. */
-
-static size_t
-pth_write_number (tree val, FILE *f)
-{
- unsigned type_idx, type_kind;
- size_t nbytes;
-
- pth_get_index_from_type (TREE_TYPE (val), &type_idx, &type_kind);
-
- nbytes = 0;
- nbytes += pth_write_uint (type_idx, f);
- nbytes += pth_write_uint (type_kind, f);
-
- if (type_kind == CPP_N_INTEGER)
- {
- HOST_WIDE_INT v[2];
-
- v[0] = TREE_INT_CST_LOW (val);
- v[1] = TREE_INT_CST_HIGH (val);
- nbytes += pth_write_bytes (v, 2 * sizeof (HOST_WIDE_INT), f);
- }
- else if (type_kind == CPP_N_FLOATING)
- {
- REAL_VALUE_TYPE r = TREE_REAL_CST (val);
- nbytes += pth_write_bytes (&r, sizeof (REAL_VALUE_TYPE), f);
- }
- else if (type_kind == CPP_N_FRACT)
- {
- FIXED_VALUE_TYPE fv = TREE_FIXED_CST (val);
- nbytes += pth_write_bytes (&fv, sizeof (FIXED_VALUE_TYPE), f);
- }
- else if (type_kind == CPP_N_IMAGINARY)
- {
- pth_write_number (TREE_REALPART (val), f);
- pth_write_number (TREE_IMAGPART (val), f);
- }
- else
- gcc_unreachable ();
-
- return nbytes;
-}
-
-
-/* Save the tree associated with TOKEN to file F. Return the number
- of bytes written. */
-
-static size_t
-pth_save_token_value (cp_token *token, FILE *f)
-{
- const char *str;
- size_t nbytes;
- unsigned len;
- tree val;
-
- val = token->u.value;
- nbytes = 0;
- switch (token->type)
- {
- case CPP_TEMPLATE_ID:
- case CPP_NESTED_NAME_SPECIFIER:
- break;
-
- case CPP_NAME:
- /* FIXME pph. Hash the strings and emit a string table. */
- str = IDENTIFIER_POINTER (val);
- len = IDENTIFIER_LENGTH (val);
- nbytes += pth_write_string (str, len, f);
- break;
-
- case CPP_KEYWORD:
- /* Nothing to do. We will reconstruct the keyword from
- ridpointers[token->keyword] at load time. */
- break;
-
- case CPP_CHAR:
- case CPP_WCHAR:
- case CPP_CHAR16:
- case CPP_CHAR32:
- case CPP_NUMBER:
- nbytes += pth_write_number (val, f);
- break;
-
- case CPP_STRING:
- case CPP_WSTRING:
- case CPP_STRING16:
- case CPP_STRING32:
- /* FIXME pph. Need to represent the type. */
- str = TREE_STRING_POINTER (val);
- len = TREE_STRING_LENGTH (val);
- nbytes += pth_write_string (str, len, f);
- break;
-
- case CPP_PRAGMA:
- /* Nothing to do. Field pragma_kind has already been written. */
- break;
-
- default:
- gcc_assert (token->u.value == NULL);
- nbytes += pth_write_bytes (&token->u.value, sizeof (token->u.value), f);
- }
-
- return nbytes;
-}
-
-
-/* Save TOKEN on file F. Return the number of bytes written on F. */
-
-static size_t
-pth_save_token (cp_token *token, FILE *f)
-{
- size_t nbytes;
-
- /* Do not write out the final field in TOKEN. It contains
- pointers that need to be pickled separately.
-
- FIXME pph - Need to also emit the location_t table so we can
- reconstruct it when reading the PTH state. */
- nbytes = pth_write_bytes (token, sizeof (cp_token) - sizeof (void *), f);
- nbytes += pth_save_token_value (token, f);
-
- return nbytes;
-}
-
-
-/* Write header information for IMAGE to STREAM. */
-
-static void
-pth_write_header (pth_image *image, FILE *stream)
-{
- size_t nbytes;
- const char *id = pth_id_str ();
-
- if (!image->digest_computed_p)
- {
- pth_get_md5_digest (image->fname, image->digest);
- image->digest_computed_p = true;
- }
-
- nbytes = pth_write_bytes (id, strlen (id), stream);
- nbytes += pth_write_bytes (image->digest, DIGEST_LEN, stream);
-
- gcc_assert (nbytes == pth_header_len ());
-}
-
-/* Dump a table of IDENTIFIERS to the STREAM. */
-
-static void
-pth_dump_identifiers (FILE *stream, cpp_idents_used *identifiers)
-{
- unsigned int idx, col = 1;
-
- fprintf (stream, "%u identifiers up to %u chars\n",
- identifiers->num_entries, identifiers->max_length);
- for (idx = 0; idx < identifiers->num_entries; ++idx)
- {
- cpp_ident_use *ident = identifiers->entries + idx;
-
- if (col + ident->ident_len >= 80)
- {
- fprintf (stream, "\n");
- col = 1;
- }
- if (ident->before_str || ident->after_str)
- {
- if (col > 1)
- fprintf (stream, "\n");
- fprintf (stream, " %s = %s -> %s\n", ident->ident_str,
- ident->before_str, ident->after_str);
- col = 1;
- }
- else
- {
- fprintf (stream, " %s", ident->ident_str);
- col += ident->ident_len;
- }
- }
- fprintf (stream, "\n");
-}
-
-/* Dump a debug log of the IDENTIFIERS. */
-
-void
-pth_debug_identifiers (cpp_idents_used *identifiers);
-
-void
-pth_debug_identifiers (cpp_idents_used *identifiers)
-{
- pth_dump_identifiers (stderr, identifiers);
-}
-
-/* Dump a HUNK to the STREAM. */
-
-static void
-pth_dump_hunk (FILE *stream, cp_token_hunk *hunk)
-{
- fprintf (stream, "Hunk location: { %lu, %lu, %lu }\n", hunk->text_offset.cur,
- hunk->text_offset.line_base, hunk->text_offset.next_line);
- fprintf (stream, "Hunk length: %lu characters\n", hunk->text_length);
- pth_dump_identifiers (stream, &hunk->identifiers);
- cp_lexer_dump_tokens (stream, hunk->buffer, 0);
-}
-
-/* Dump a debug log of the HUNK. */
-
-static void
-pth_debug_hunk (cp_token_hunk *hunk)
-{
- pth_dump_hunk (stderr, hunk);
-}
-
-
-/* Dump #include command INCLUDE to FILE. */
-
-static void
-pth_dump_include (FILE *f, pth_include *include)
-{
- if (include == NULL)
- return;
-
- if (include->itype == IT_INCLUDE)
- fprintf (f, "#include ");
- else if (include->itype == IT_INCLUDE_NEXT)
- fprintf (f, "#include_next ");
- else if (include->itype == IT_IMPORT)
- fprintf (f, "#import ");
- else
- fprintf (f, "#??? ");
-
- fprintf (f, "%c%s%c",
- (include->angle_brackets) ? '<' : '"',
- include->iname,
- (include->angle_brackets) ? '>' : '"');
-
- fprintf (f, " (found in %s)\n", include->dname);
-}
-
-
-/* Dump #include command INCLUDE to stderr. */
-
-static void
-pth_debug_include (pth_include *include)
-{
- pth_dump_include (stderr, include);
-}
-
-
-/* Recursive helper for pth_dump_token_hunks_1. VISITED keeps track of
- images that have already been dumped to avoid infinite recursion. */
-
-static void
-pth_dump_token_hunks_1 (FILE *f, pth_image *image,
- struct pointer_set_t *visited)
-{
- unsigned i, h_ix, i_ix;
- char s;
-
- if (pointer_set_insert (visited, image))
- return;
-
- fprintf (f, "LC_ENTER: %s {\n", image->fname);
-
- for (i = 0, h_ix = 0, i_ix = 0;
- VEC_iterate (char, image->ih_sequence, i, s);
- i++)
- {
- if (s == 'H')
- {
- cp_token_hunk *hunk;
- hunk = VEC_index (cp_token_hunk_ptr, image->token_hunks, h_ix++);
- pth_dump_hunk (f, hunk);
- }
- else if (s == 'I')
- {
- pth_include *include;
- include = VEC_index (pth_include_ptr, image->includes, i_ix++);
- pth_dump_include (f, include);
- pth_dump_token_hunks_1 (f, include->image, visited);
- }
- }
-
- fprintf (f, "LC_LEAVE: %s }\n", image->fname);
-}
-
-
-/* Dump all the tokens in IMAGE and the files included by it to F. */
-
-static void
-pth_dump_token_hunks (FILE *f, pth_image *image)
-{
- struct pointer_set_t *visited = pointer_set_create ();
- pth_dump_token_hunks_1 (f, image, visited);
- pointer_set_destroy (visited);
-}
-
-
-/* Dump all the tokens in IMAGE and the files included by it to stderr. */
-
-static void
-pth_debug_token_hunks (pth_image *image)
-{
- pth_dump_token_hunks (stderr, image);
-}
-
-
-/* Dump a debugging representation of IMAGE to F. */
-
-static void
-pth_dump_image (FILE *f, pth_image *image)
-{
- unsigned i;
- cp_token_hunk *hunk;
- pth_include *include;
- char s;
-
- if (image == NULL)
- return;
-
- fprintf (f, "Image for: %s\n", image->fname);
-
- fprintf (f, " MD5 digest: ");
- if (image->digest_computed_p)
- {
- for (i = 0; i < DIGEST_LEN; i++)
- fprintf (f, "%02x", image->digest[i]);
- fprintf (f, "\n");
- }
- else
- fprintf (f, "NOT COMPUTED\n");
-
- fprintf (f, " %u token hunks: { ",
- VEC_length (cp_token_hunk_ptr, image->token_hunks));
- for (i = 0; VEC_iterate (cp_token_hunk_ptr, image->token_hunks, i, hunk); i++)
- fprintf (f, "%u ", VEC_length (cp_token, hunk->buffer));
- fprintf (f, "}\n");
-
- fprintf (f, " %u includes:\n",
- VEC_length (pth_include_ptr, image->includes));
- for (i = 0; VEC_iterate (pth_include_ptr, image->includes, i, include); i++)
- {
- fprintf (f, "\t");
- pth_dump_include (f, include);
- }
-
- fprintf (f, " Include-Hunk (IH) sequence: ");
- for (i = 0; VEC_iterate (char, image->ih_sequence, i, s); i++)
- fputc (s, f);
- fputc ('\n', f);
-
- if (image->loaded_p)
- fprintf (f, " Instantiated from image: %s\n", pth_name_for (image->fname));
- else
- {
- fprintf (f, " Instantiated from character stream: %s\n", image->fname);
-
- if (image->save_p)
- fprintf (f, " Will be saved to image: %s\n",
- pth_name_for (image->fname));
- else
- fprintf (f, " Will NOT be saved to an image (not include-guarded)\n");
- }
-
- if (image->used_p)
- fprintf (f, " Image already applied to current compilation context\n");
-
- if (flag_pth_debug >= 4)
- pth_dump_token_hunks (f, image);
-}
-
-
-/* Dump a debugging representation of IMAGE to stderr. */
-
-static void
-pth_debug_image (pth_image *image)
-{
- pth_dump_image (stderr, image);
-}
-
-
-/* Show statistics for PTH image IMAGE on FILE. if FILE is NULL, use
- pph_logfile. */
-
-static void
-pth_show_image_stats (FILE *file, pth_image *image)
-{
- unsigned i, num_tokens;
- cp_token_hunk *hunk;
-
- if (image == NULL)
- return;
-
- if (file == NULL)
- file = pph_logfile;
-
- num_tokens = 0;
- for (i = 0; VEC_iterate (cp_token_hunk_ptr, image->token_hunks, i, hunk); i++)
- num_tokens += VEC_length (cp_token, hunk->buffer);
-
- fprintf (file, "%s: %u tokens, %u token hunks\n", image->fname, num_tokens,
- VEC_length (cp_token_hunk_ptr, image->token_hunks));
-}
-
-
-/* Dump the current PTH state to F. */
-
-static void
-pth_dump_state (FILE *f)
-{
- unsigned i;
- pth_state *state;
- pth_image *image;
-
- state = pth_get_state ();
- fprintf (f, "Incremental compilation state\n\n");
- fprintf (f, "%u file images\n", VEC_length (pth_image_ptr, state->cache));
- for (i = 0; VEC_iterate (pth_image_ptr, state->cache, i, image); i++)
- pth_dump_image (f, image);
-
- fprintf (f, "\nCurrent image being processed: %s\n",
- (state->cur_image) ? state->cur_image->fname : "NONE");
-
- if (state->lexer)
- {
- fprintf (f, "Tokens in main lexer:\n");
- cp_lexer_dump_tokens (f, state->lexer->buffer, 0);
- }
-}
-
-
-/* Dump the current PTH state to stderr. */
-
-static void
-pth_debug_state (void)
-{
- pth_dump_state (stderr);
-}
-
-
-/* Save the IDENTIFIERS to the STREAM. */
-
-static void
-pth_save_identifiers (cpp_idents_used *identifiers, FILE *stream)
-{
- unsigned int num_entries, id;
-
- num_entries = identifiers->num_entries;
- pth_write_uint (identifiers->max_length, stream);
- pth_write_uint (num_entries, stream);
-
- for ( id = 0; id < num_entries; ++id )
- {
- cpp_ident_use *entry = identifiers->entries + id;
-
- gcc_assert (entry->ident_len <= identifiers->max_length);
- pth_write_string (entry->ident_str, entry->ident_len, stream);
-
- gcc_assert (entry->before_len <= identifiers->max_length);
- pth_write_string (entry->before_str, entry->before_len, stream);
-
- gcc_assert (entry->after_len <= identifiers->max_length);
- pth_write_string (entry->after_str, entry->after_len, stream);
- }
-}
-
-/* Save the HUNK to the STREAM. */
-
-static void
-pth_save_hunk (cp_token_hunk *hunk, FILE *stream)
-{
- unsigned j;
- cp_token *token;
-
- if (flag_pth_debug >= 5)
- pth_debug_hunk (hunk);
-
- /* Write out the identifiers used by HUNK. */
- pth_save_identifiers (&hunk->identifiers, stream);
-
- /* Write the offset into the text file where this token starts. */
- pth_write_sizet (hunk->text_offset.cur, stream);
- pth_write_sizet (hunk->text_offset.line_base, stream);
- pth_write_sizet (hunk->text_offset.next_line, stream);
-
- /* Write the length of the hunk. */
- pth_write_sizet (hunk->text_length, stream);
-
- /* Write the number of tokens in HUNK. */
- pth_write_uint (VEC_length (cp_token, hunk->buffer), stream);
-
- /* Write the tokens. */
- for (j = 0; VEC_iterate (cp_token, hunk->buffer, j, token); j++)
- pth_save_token (token, stream);
-}
-
-
-/* Save the #include directive INCLUDE to STREAM. */
-
-static void
-pth_save_include (pth_include *include, FILE *stream)
-{
- pth_write_string (include->image->fname, strlen (include->image->fname),
- stream);
- pth_write_uint ((unsigned int) include->itype, stream);
- pth_write_uint (include->angle_brackets, stream);
- pth_write_string (include->iname, strlen (include->iname), stream);
- pth_write_string (include->dname,
- include->dname ? strlen (include->dname) : 0,
- stream);
-}
-
-
-/* Save the PTH image IMAGE to a file. */
-
-static void
-pth_save_image (pth_image *image)
-{
- FILE *stream;
- cp_token_hunk *hunk;
- unsigned i, num;
- char *buf;
- pth_include *include;
-
- timevar_push (TV_PTH_SAVE);
-
- /* Open the stream in append mode since we have already created
- it in pth_new_image. */
- stream = pth_file_for (image->fname, "wb");
-
- /* Write an invalid header first to avoid leaving a seemingly
- valid file in case of failure. */
- buf = XCNEWVEC (char, pth_header_len ());
- pth_write_bytes (buf, pth_header_len (), stream);
-
- /* Write the include-hunk (IH) sequencing vector. */
- num = VEC_length (char, image->ih_sequence);
- pth_write_uint (num, stream);
- if (num > 0)
- pth_write_bytes (VEC_address (char, image->ih_sequence), num, stream);
-
- /* Write the number of #include commands. */
- pth_write_uint (VEC_length (pth_include_ptr, image->includes), stream);
-
- /* Write all the #include commands used by IMAGE. */
- for (i = 0; VEC_iterate (pth_include_ptr, image->includes, i, include); i++)
- pth_save_include (include, stream);
-
- /* Write the number of token caches in the cache. */
- pth_write_uint (VEC_length (cp_token_hunk_ptr, image->token_hunks), stream);
-
- /* Write all the token hunks in image. */
- for (i = 0; VEC_iterate (cp_token_hunk_ptr, image->token_hunks, i, hunk); i++)
- pth_save_hunk (hunk, stream);
-
- /* Now write a valid header. */
- fseek (stream, 0, SEEK_SET);
- pth_write_header (image, stream);
-
- /* Clean up. */
- fclose (stream);
- free (buf);
- image->save_p = false;
-
- if (flag_pth_debug >= 3)
- {
- fprintf (stderr, "\nSaved image for %s:\n", image->fname);
- pth_debug_image (image);
- }
-
- timevar_pop (TV_PTH_SAVE);
-}
-
-
-/* Given a type index TYPE_IDX and TYPE_KIND specifying the kind of type,
- return a type from integer_types or global_trees. */
-
-static tree
-pth_get_type_from_index (unsigned type_idx, unsigned type_kind)
-{
- if (type_kind == CPP_N_INTEGER)
- return integer_types[type_idx];
- else if (type_kind == CPP_N_FLOATING || type_kind == CPP_N_FRACT)
- return global_trees[type_idx];
- else if (type_kind == CPP_N_IMAGINARY)
- {
- /* We don't need a type for the complex number. The type is
- associated with the real and imaginary parts. */
- return NULL_TREE;
- }
- else
- gcc_unreachable ();
-}
-
-
-/* Read an unsigned int into *VAR_P. */
-
-static void
-pth_read_uint (unsigned int *var_p, FILE *stream)
-{
- size_t received = fread (var_p, sizeof *var_p, 1, stream);
- gcc_assert (received == 1);
-}
-
-
-/* Read a size_t into *VAR_P. */
-
-static void
-pth_read_sizet (size_t *var_p, FILE *stream)
-{
- size_t received = fread (var_p, sizeof *var_p, 1, stream);
- gcc_assert (received == 1);
-}
-
-
-/* Read N bytes into P from STREAM. The caller is responsible
- for allocating sufficient memory for P. */
-
-static inline void
-pth_read_bytes (void *p, size_t n, FILE *stream)
-{
- size_t received = fread (p, 1, n, stream);
- gcc_assert (received == n);
-}
-
-
-/* Read a string of up to MAX characters from STREAM into BUFFER.
- Return the actual string length read from STREAM. The caller is
- responsible for allocating sufficient memory for BUFFER. */
-
-static unsigned int
-pth_read_string (char *buffer, unsigned int max, FILE *stream)
-{
- unsigned int length;
- size_t received;
-
- received = fread (&length, sizeof length, 1, stream);
- gcc_assert (received == 1 && (length == -1U || length <= max));
- if (length > 0 && length != -1U)
- {
- received = fread (buffer, 1, length, stream);
- gcc_assert (received == length);
- }
-
- return length;
-}
-
-
-/* Read a string from STREAM allocating enough memory on the
- heap to hold it.
-
- This function assumes that strings are represented as a length
- followed by the string content. A terminating '\0' is added
- automatically. */
-
-static inline char *
-pth_read_string_alloc (FILE *stream)
-{
- char *s;
- unsigned int len;
-
- pth_read_uint (&len, stream);
-
- /* By convention, NULL strings are represented with length -1U. */
- if (len == -1U)
- return NULL;
-
- s = XCNEWVEC (char, len + 1);
- pth_read_bytes (s, len, stream);
-
- return s;
-}
-
-
-/* Load a numeric value from file F. Return the corresponding tree. */
-
-static tree
-pth_load_number (FILE *f)
-{
- unsigned type_idx, type_kind;
- tree type, val;
-
- pth_read_uint (&type_idx, f);
- pth_read_uint (&type_kind, f);
-
- type = pth_get_type_from_index (type_idx, type_kind);
-
- if (type_kind == CPP_N_INTEGER)
- {
- HOST_WIDE_INT v[2];
- pth_read_bytes (v, 2 * sizeof (HOST_WIDE_INT), f);
- val = build_int_cst_wide (type, v[0], v[1]);
- }
- else if (type_kind == CPP_N_FLOATING)
- {
- REAL_VALUE_TYPE r;
- pth_read_bytes (&r, sizeof (REAL_VALUE_TYPE), f);
- val = build_real (type, r);
- }
- else if (type_kind == CPP_N_FRACT)
- {
- FIXED_VALUE_TYPE fv;
- pth_read_bytes (&fv, sizeof (FIXED_VALUE_TYPE), f);
- val = build_fixed (type, fv);
- }
- else if (type_kind == CPP_N_IMAGINARY)
- {
- tree r = pth_load_number (f);
- tree i = pth_load_number (f);
- val = build_complex (NULL_TREE, r, i);
- }
- else
- gcc_unreachable ();
-
- return val;
-}
-
-
-/* Load the tree value associated with TOKEN to file F. */
-
-static void
-pth_load_token_value (cp_token *token, FILE *f)
-{
- char *str;
-
- switch (token->type)
- {
- case CPP_TEMPLATE_ID:
- case CPP_NESTED_NAME_SPECIFIER:
- break;
-
- case CPP_NAME:
- str = pth_read_string_alloc (f);
- token->u.value = get_identifier (str);
- free (str);
- break;
-
- case CPP_KEYWORD:
- token->u.value = ridpointers[token->keyword];
- break;
-
- case CPP_CHAR:
- case CPP_WCHAR:
- case CPP_CHAR16:
- case CPP_CHAR32:
- case CPP_NUMBER:
- token->u.value = pth_load_number (f);
- break;
-
- case CPP_STRING:
- case CPP_WSTRING:
- case CPP_STRING16:
- case CPP_STRING32:
- str = pth_read_string_alloc (f);
- token->u.value = build_string (strlen (str), str);
- free (str);
- break;
-
- case CPP_PRAGMA:
- /* Nothing to do. Field pragma_kind has already been loaded. */
- break;
-
- default:
- pth_read_bytes (&token->u.value, sizeof (token->u.value), f);
- gcc_assert (token->u.value == NULL);
- }
-}
-
-
-/* Need forward declaration for pth_image_lookup due to circular
- dependency. */
-static pth_image *pth_image_lookup (pth_state *, const char *, cpp_reader *);
-
-
-/* Load the IDENTIFERS for a hunk from a STREAM. */
-
-static void
-pth_load_identifiers (cpp_idents_used *identifiers, FILE *stream)
-{
- unsigned int j;
- unsigned int max_length, num_entries;
- char *buffer;
- unsigned int ident_len, before_len, after_len;
-
- pth_read_uint (&max_length, stream);
- identifiers->max_length = max_length;
- pth_read_uint (&num_entries, stream);
- identifiers->num_entries = num_entries;
- identifiers->entries = XCNEWVEC (cpp_ident_use, num_entries);
- identifiers->strings = XCNEW (struct obstack);
-
- /* Strings need no alignment. */
- _obstack_begin (identifiers->strings, 0, 0,
- (void *(*) (long)) xmalloc,
- (void (*) (void *)) free);
- obstack_alignment_mask (identifiers->strings) = 0;
- /* FIXME pph: We probably need to free all these things somewhere. */
-
- buffer = XCNEWVEC (char, max_length + 1);
-
- /* Read the identifiers in HUNK. */
- for (j = 0; j < num_entries; ++j)
- {
- ident_len = pth_read_string ( buffer, max_length, stream);
- gcc_assert (ident_len > 0 && ident_len != -1U);
- identifiers->entries[j].ident_len = ident_len;
- identifiers->entries[j].ident_str =
- (const char *) obstack_copy0 (identifiers->strings, buffer, ident_len);
-
- before_len = pth_read_string ((char *) buffer, max_length, stream);
- identifiers->entries[j].before_len = before_len;
- if (before_len == -1U)
- identifiers->entries[j].before_str = NULL;
- else
- identifiers->entries[j].before_str = (const char *)
- obstack_copy0 (identifiers->strings, buffer, before_len);
-
- after_len = pth_read_string ((char *) buffer, max_length, stream);
- identifiers->entries[j].after_len = after_len;
- if (after_len == -1U)
- identifiers->entries[j].after_str = NULL;
- else
- identifiers->entries[j].after_str = (const char *)
- obstack_copy0 (identifiers->strings, buffer, after_len);
- }
-
- free (buffer);
-}
-
-
-/* Load a hunk into the IMAGE from a STREAM. */
-
-static void
-pth_load_hunk (pth_image *image, FILE *stream)
-{
- unsigned j, num_tokens;
- cp_token_hunk *hunk;
-
- hunk = ggc_alloc_cleared_cp_token_hunk ();
-
- /* Setup the identifier list. */
- pth_load_identifiers (&hunk->identifiers, stream);
-
- /* Read the offset into the text file where this token starts. */
- pth_read_sizet (&hunk->text_offset.cur, stream);
- pth_read_sizet (&hunk->text_offset.line_base, stream);
- pth_read_sizet (&hunk->text_offset.next_line, stream);
-
- /* Read the text length of the hunk. */
- pth_read_sizet (&hunk->text_length, stream);
-
- /* Read the number of tokens in HUNK. */
- pth_read_uint (&num_tokens, stream);
-
- /* Read the tokens in the HUNK. */
- hunk->buffer = VEC_alloc (cp_token, gc, num_tokens);
- for (j = 0; j < num_tokens; j++)
- {
- cp_token *token = VEC_quick_push (cp_token, hunk->buffer, NULL);
-
- /* Do not read the whole structure, the token value has
- dynamic size as it contains swizzled pointers.
- FIXME pph, restructure to allow bulk reads of the whole
- section. */
- pth_read_bytes (token, sizeof (cp_token) - sizeof (void *), stream);
-
- /* FIXME pph. Use an arbitrary (but valid) location to avoid
- confusing the rest of the compiler for now. */
- token->location = input_location;
-
- /* FIXME pph: verify that pth_load_token_value works with no tokens. */
- pth_load_token_value (token, stream);
- }
- gcc_assert (num_tokens == VEC_length (cp_token, hunk->buffer));
-
- VEC_quick_push (cp_token_hunk_ptr, image->token_hunks, hunk);
-}
-
-
-/* Create a new empty #include directive for NAME. ITYPE is one of
- the supported include commands. ANGLE_BRACKETS is true if the
- include used '<>'. */
-
-static pth_include *
-pth_create_include (enum include_type itype, bool angle_brackets,
- const char *name)
-{
- pth_include *include = ggc_alloc_cleared_pth_include ();
- include->itype = itype;
- include->angle_brackets = angle_brackets;
- include->iname = (name) ? xstrdup (name) : name;
-
- return include;
-}
-
-
-/* Load an #include directive for IMAGE from STREAM. */
-
-static void
-pth_load_include (pth_state *state, pth_image *image, cpp_reader *reader,
- FILE *stream)
-{
- char *s;
- pth_include *include;
- unsigned tmp;
-
- include = pth_create_include (IT_INCLUDE, false, NULL);
-
- s = pth_read_string_alloc (stream);
- include->image = pth_image_lookup (state, s, reader);
-
- pth_read_uint (&tmp, stream);
- include->itype = (enum include_type) tmp;
-
- pth_read_uint (&tmp, stream);
- include->angle_brackets = (tmp != 0);
-
- include->iname = pth_read_string_alloc (stream);
- include->dname = pth_read_string_alloc (stream);
-
- VEC_safe_push (pth_include_ptr, gc, image->includes, include);
-}
-
-
-/* Load a PTH image for LEXER using the READER. */
-
-static void
-pth_load_image (pth_state *state, pth_image *image, cpp_reader *reader)
-{
- FILE *stream;
- unsigned i, num;
-
- timevar_push (TV_PTH_LOAD);
-
- stream = pth_file_for (image->fname, "r+b");
-
- /* Skip over the header, as we assume that it has already been
- validated by pth_have_valid_image_for. */
- fseek (stream, (long) pth_header_len (), SEEK_SET);
-
- /* Read the include-hunk (IH) sequencing vector. */
- pth_read_uint (&num, stream);
- if (num > 0)
- {
- image->ih_sequence = VEC_alloc (char, gc, num);
- VEC_safe_grow (char, gc, image->ih_sequence, num);
- pth_read_bytes (VEC_address (char, image->ih_sequence), num, stream);
- }
-
- /* Read the number path names of all the files #included by
- IMAGE->FNAME. */
- pth_read_uint (&num, stream);
- image->includes = VEC_alloc (pth_include_ptr, gc, num);
-
- /* Now read all the path names #included by IMAGE->FNAME. */
- for (i = 0; i < num; i++)
- pth_load_include (state, image, reader, stream);
-
- /* Read how many token hunks are contained in this image. */
- pth_read_uint (&num, stream);
- image->token_hunks = VEC_alloc (cp_token_hunk_ptr, gc, num);
-
- PTH_STATS_INCR (hunks, num);
-
- /* Read all the token hunks. */
- for (i = 0; i < num; i++)
- pth_load_hunk (image, stream);
-
- fclose (stream);
-
- /* Indicate that we have loaded this image from a file. */
- image->loaded_p = true;
- image->save_p = false;
- image->used_p = false;
-
- if (flag_pth_debug >= 3)
- {
- fprintf (stderr, "\nLoaded image for %s:\n", image->fname);
- pth_debug_image (image);
- }
-
- timevar_pop (TV_PTH_LOAD);
-}
-
-
-/* Return true if FNAME has a PTH image that can be used. If an image
- already exists, compute the MD5 digest for FNAME and store it
- in IMAGE. */
-
-static bool
-pth_have_valid_image_for (const char *fname, pth_image *image)
-{
- FILE *f = NULL;
- struct stat s;
- char *img_name, *id;
- const char *good_id;
- char saved_digest[DIGEST_LEN];
-
- image->digest_computed_p = false;
-
- img_name = pth_name_for (fname);
- if (stat (img_name, &s) != 0)
- goto invalid_img;
-
- /* If the file exists, check if it has a valid signature. */
- f = fopen (img_name, "r");
-
- good_id = pth_id_str ();
- id = XCNEWVEC (char, strlen (good_id) + 1);
- pth_read_bytes (id, strlen (good_id), f);
- if (strcmp (id, good_id) != 0)
- goto invalid_img;
-
- /* Now check if the MD5 digest stored in the image file matches the
- digest for FNAME. */
- pth_read_bytes (saved_digest, DIGEST_LEN, f);
- pth_get_md5_digest (fname, image->digest);
- image->digest_computed_p = true;
- if (memcmp (image->digest, saved_digest, DIGEST_LEN) != 0)
- goto invalid_img;
-
- fclose (f);
- return true;
-
-invalid_img:
- if (f)
- fclose (f);
-
- return false;
-}
-
-
-/* Create a new PTH cache object for file FNAME. */
-
-static pth_image *
-pth_new_image (const char *fname)
-{
- pth_image *image;
-
- image = ggc_alloc_cleared_pth_image ();
- image->fname = fname;
-
- return image;
-}
-
-
-/* Return a cache image associated with file FNAME. STATE holds
- the PTH cache to use. */
-
-static pth_image *
-pth_image_lookup (pth_state *state, const char *fname, cpp_reader *reader)
-{
- void **slot;
- pth_image *image, e;
-
- if (fname == NULL)
- return NULL;
-
- e.fname = fname;
- slot = htab_find_slot (state->cache_dir, &e, INSERT);
- if (*slot == NULL)
- {
- /* Create a new image and store it in the cache. */
- image = pth_new_image (fname);
- *slot = image;
- VEC_safe_push (pth_image_ptr, gc, state->cache, image);
-
- /* If a valid disk image already exists for FNAME, load it.
- Otherwise, mark the memory image for processing and saving. */
- if (pth_have_valid_image_for (fname, image))
- pth_load_image (state, image, reader);
- else
- image->save_p = true;
- }
- else
- image = *((pth_image **) slot);
-
- return image;
-}
-
-
-/* Add all the tokens in HUNK to the end of LEXER->BUFFER. IMAGE is
- the memory image holding HUNK. */
-
-static void
-pth_append_hunk (cp_lexer *lexer, pth_image *image, cp_token_hunk *hunk)
-{
- cp_token *lexer_addr, *hunk_addr;
- unsigned lexer_len, hunk_len;
-
- PTH_STATS_INCR (valid_hunks, 1);
-
- /* Apply all the identifiers used and defined by HUNK. */
- cpp_lt_replay (parse_in, &hunk->identifiers);
-
- /* If this file has been read in memory (e.g., by being #included
- from a tainted file), advance the text buffer pointer to the end
- of the hunk to avoid reading it again. */
- if (image->buffer)
- cpp_set_pos (image->buffer, hunk->text_offset);
-
- hunk_len = VEC_length (cp_token, hunk->buffer);
-
- /* Some hunks have no tokens and they are only useful for the
- macros defined by them. This is useful when one or more
- image files are tainted and need to be restored from their
- character stream. */
- if (hunk_len == 0)
- return;
-
- /* Determine the last location in LEXER->BUFFER before growing it. */
- lexer_len = VEC_length (cp_token, lexer->buffer);
- VEC_safe_grow (cp_token, gc, lexer->buffer, lexer_len + hunk_len);
-
- /* Bulk copy all the tokens in HUNK to the end of LEXER->BUFFER. */
- lexer_addr = VEC_address (cp_token, lexer->buffer);
- hunk_addr = VEC_address (cp_token, hunk->buffer);
- memcpy (&lexer_addr[lexer_len], hunk_addr, hunk_len * sizeof (cp_token));
-
- if (flag_pth_debug >= 2)
- {
- fprintf (stderr, "\n=> ADDED TOKEN HUNK TO LEXER BUFFER");
- if (flag_pth_debug >= 5)
- pth_debug_hunk (hunk);
- }
-}
-
-
-/* Return true if HUNK can be used in the current compilation
- context of the cpp READER. It must validate the identifier state. */
-
-static bool
-pth_hunk_is_valid_p (pth_image *image, cp_token_hunk *hunk, cpp_reader *reader)
-{
- bool verified;
- cpp_ident_use *bad_use;
- const char *cur_def;
-
- timevar_push (TV_PTH_DEPENDENCY);
- verified = cpp_lt_verify (reader, &hunk->identifiers, &bad_use, &cur_def);
- if (!verified && flag_pth_debug >= 1)
- {
- fprintf (stderr, "PTH: %s failed verification: %s : <%s> -> <%s>\n",
- pth_name_for (image->fname), bad_use->ident_str,
- bad_use->before_str, cur_def);
- }
- PTH_STATS_INCR (verified_hunks, 1);
- PTH_STATS_INCR (verified_identifiers, hunk->identifiers.num_entries);
- timevar_pop (TV_PTH_DEPENDENCY);
- return verified;
-}
-
-
-/* Return true if IMAGE can be used in the current compilation context. */
-
-static bool
-pth_image_can_be_used (pth_image *image)
-{
- return image && image->loaded_p && !image->used_p;
-}
-
-
/* Return true if LEXER has a CPP_EOF at the end of the buffer. */
static inline bool
@@ -2196,7 +312,7 @@ cp_lexer_finished_p (cp_lexer *lexer)
/* Get tokens from the pre-processor character stream into LEXER. */
-static void
+void
cp_lexer_get_tokens (cp_lexer *lexer)
{
cp_token token;
@@ -2222,678 +338,6 @@ cp_lexer_get_tokens (cp_lexer *lexer)
}
-/* Split NAME into its directory and file name components, storing them
- in *DNAME_P and *FNAME_P. After using it, *DNAME_P should be freed
- by the caller. */
-
-static void
-pth_get_dir_and_name (const char *name, char **dname_p, const char **fname_p)
-{
- size_t len;
-
- *fname_p = lbasename (name);
- *dname_p = NULL;
-
- len = *fname_p - name;
- if (len > 0)
- {
- *dname_p = XNEWVEC (char, len + 1);
- memcpy (*dname_p, name, len);
- (*dname_p)[len] = '\0';
- gcc_assert (IS_DIR_SEPARATOR ((*dname_p)[len - 1]));
- }
-}
-
-
-/* Read tokens from the text stream in IMAGE->FNAME into LEXER.
- If INCLUDE is not NULL, it describes how IMAGE->FNAME was
- #included originally. Otherwise, it is assumed to be an
- include command done with the flag -include.
-
- This is used when an image is found to be tainted and tokens
- need to be read from the original character stream. OFFSET
- indicates how far into the character stream to start reading at. */
-
-static void
-pth_process_text_file (cp_lexer *lexer, pth_image *image, pth_include *include,
- cpp_offset offset)
-{
- bool prev_permissive, prev_inhibit_warnings;
- bool pushed_p;
- cpp_buffer *buffer;
- lexer_state *state;
-
- /* Emulate a #include directive on IMAGE->FNAME, if needed. Note
- that if we are already inside the CPP buffer for IMAGE->FNAME
- we should not include it again, since this will cause another
- call to pth_file_change which will again register IMAGE->FNAME as
- an include for the parent file. */
- state = NULL;
- if (image->buffer != cpp_get_buffer (parse_in))
- {
- if (include == NULL || include->itype == IT_INCLUDE_NEXT)
- {
- char *dname;
- const char *fname;
- pth_get_dir_and_name (image->fname, &dname, &fname);
- pushed_p = cpp_push_include_type (parse_in, dname, fname, false,
- IT_INCLUDE);
-
- /* FIXME pph. We are leaking DNAME here. libcpp
- wants the directory name in permanent storage so we
- cannot free it, but we should put it in an obstack
- so it can be reclaimed at some point. */
- }
- else
- pushed_p = cpp_push_include_type (parse_in,
- include->dname,
- include->iname,
- include->angle_brackets,
- include->itype);
-
- if (!pushed_p)
- return;
- }
- else
- {
- /* Since we already have the buffer on top of the stack,
- reset the state of the lexer to avoid skipping over it. */
- state = cpp_reset_lexer_state (parse_in);
- }
-
- /* Inhibit libcpp error messages (ignore things like unmatched #endifs).
- We need to do this because token hunks may span #if/#endif boundaries.
- For instance,
-
- #if <COND>
- H1 [1]
- #else
- H2 [2]
- #include "foo.h"
- H3 [3]
- #endif
- H1 or H3 [4]
-
- In this example we have 3 hunks (H1, H2 and H3). Depending on the
- value of <COND> at image creation time, point [4] will belong to
- hunk H1 (if <COND> was true) or hunk H3 (if <COND> was false).
-
- When this image is loaded, if H3 cannot be applied because its
- dependences fail to hold, then we will start pre-processing the
- text for the file at the start of hunk H3. This will find a
- dangling #endif which triggers a libcpp error. Since we know
- that we are in the correct arm of the #if (after all H2 was
- applied from the image), we can safely ignore the error. */
- prev_permissive = global_dc->permissive;
- prev_inhibit_warnings = global_dc->dc_inhibit_warnings;
- global_dc->dc_inhibit_warnings = true;
- global_dc->permissive = true;
-
- /* Position the reader at OFFSET and request to stop reading at
- the end of it. */
- buffer = cpp_get_buffer (parse_in);
- cpp_set_pos (buffer, offset);
- cpp_return_at_eof (buffer, true);
-
- /* Get tokens from IMAGE->FNAME. */
- cp_lexer_get_tokens (lexer);
-
- /* Since we read this file separately, the very last token in LEXER
- will now contain an EOF, which we do not need. */
- VEC_pop (cp_token, lexer->buffer);
- cpp_return_at_eof (buffer, false);
-
- /* Restore libcpp error/warnings. */
- global_dc->permissive = prev_permissive;
- global_dc->dc_inhibit_warnings = prev_inhibit_warnings;
-
- /* Restore the parser state, if necessary. */
- if (state)
- cpp_restore_lexer_state (parse_in, state);
-}
-
-
-/* Populate LEXER->BUFFER with all the valid token hunks in
- IMAGE. If possible, try to load token hunks from files
- included by IMAGE as well.
-
- This means that we try to load the whole transitive closure
- starting at IMAGE until we find the first unloadable file.
-
- Once we find the first unloadable token hunk, we skip the token
- hunks from the character stream so that they don't need to be
- pre-processed again.
-
- If non-NULL, INCLUDE describes the #include command used to include
- IMAGE->FNAME. */
-
-static void
-pth_image_to_lexer (cp_lexer *lexer, pth_image *image, pth_include *include)
-{
- unsigned i, h_ix, i_ix;
- char s;
-
- /* If we are trying to apply the same image more than once,
- something is wrong. We never create images for files that
- are included more than once, so we should never try to apply
- the same image more than once. */
- gcc_assert (pth_image_can_be_used (image));
-
- image->used_p = true;
-
- if (flag_pth_debug >= 2)
- {
- fprintf (stderr, "\n<= INCORPORATING IMAGE %s INTO COMPILATION CONTEXT\n",
- image->fname);
- if (flag_pth_debug >= 3)
- pth_debug_include (include);
- }
-
- PTH_STATS_INCR (valid_images, 1);
-
- for (i = 0, h_ix = 0, i_ix = 0;
- VEC_iterate (char, image->ih_sequence, i, s);
- i++)
- {
- if (s == 'H')
- {
- cp_token_hunk *hunk;
-
- hunk = VEC_index (cp_token_hunk_ptr, image->token_hunks, h_ix++);
- if (pth_hunk_is_valid_p (image, hunk, parse_in))
- pth_append_hunk (lexer, image, hunk);
- else
- {
- PTH_STATS_INCR (invalid_hunks, 1);
-
- pth_process_text_file (lexer, image, NULL, hunk->text_offset);
-
- /* Since this hunk is invalid, assume that everything
- downstream from this hunk is also invalid. FIXME pph,
- it may be possible to optimize this. We should be
- able to pre-process from text exactly
- HUNK->TEXT_LENGTH characters instead of the whole
- file. */
- break;
- }
- }
- else if (s == 'I')
- {
- pth_include *incdir;
- pth_get_state ()->cur_image = image;
- incdir = VEC_index (pth_include_ptr, image->includes, i_ix++);
- if (pth_image_can_be_used (incdir->image))
- pth_image_to_lexer (lexer, incdir->image, incdir);
- else
- pth_process_text_file (lexer, incdir->image, incdir,
- cpp_buffer_start);
- }
- else
- gcc_unreachable ();
- }
-
- /* If we just applied the tokens for the main input filename,
- we need to append a CPP_EOF token, since that one is never
- saved with the token hunks. */
- if (pathnames_equal_p (image->fname, main_input_filename))
- VEC_safe_push (cp_token, gc, lexer->buffer, &eof_token);
-
- /* If IMAGE has a libcpp buffer associated with it, it means that a
- file that was being pre-processed from text has #included IMAGE
- and the pre-processor has executed the file change logic.
-
- In that case, the pre-processor will want to finish processing
- IMAGE's text, and since we have just applied its tokens from
- the image, the result will be duplicate tokens. To prevent
- this, we tell libcpp to skip over the whole text buffer
- associated with IMAGE. */
- if (image->buffer)
- cpp_set_pos (image->buffer, cpp_buffer_end);
-
- return;
-}
-
-
-/* Create a token hunk for IMAGE from the token buffer in
- LEXER->BUFFER. The hunk will contain all the tokens starting at
- IMAGE->HUNK_START_IX to the end of LEXER->BUFFER.
-
- The new token hunk will be added to the end of IMAGE->TOKEN_HUNKS. */
-
-static void
-pth_lexer_to_image (pth_image *image, cp_lexer *lexer, cpp_reader *reader)
-{
- cp_token *lexer_addr, *hunk_addr;
- cp_token_hunk *hunk;
- unsigned num_tokens, start_ix, end_ix;
- cpp_offset pos;
-
- /* Create a new token hunk. */
- hunk = ggc_alloc_cleared_cp_token_hunk ();
- VEC_safe_push (cp_token_hunk_ptr, gc, image->token_hunks, hunk);
- VEC_safe_push (char, gc, image->ih_sequence, 'H');
-
- /* The identifiers that may conflict with macros. */
- if (flag_pth_debug >= 2)
- cpp_lt_statistics (reader);
- hunk->identifiers = cpp_lt_capture (reader);
-
- /* Remember the text offset where this hunk started and its length. */
- hunk->text_offset = image->hunk_text_offset;
- pos = cpp_get_pos (image->buffer);
- gcc_assert (pos.cur >= hunk->text_offset.cur);
- hunk->text_length = pos.cur - hunk->text_offset.cur;
-
- /* Compute the bounds for the new token hunk. */
- start_ix = image->hunk_start_ix;
- end_ix = VEC_length (cp_token, lexer->buffer);
- gcc_assert (end_ix >= start_ix);
- num_tokens = end_ix - start_ix;
-
- if (num_tokens > 0)
- {
- /* Copy tokens from LEXER->BUFFER into the new hunk. */
- hunk->buffer = VEC_alloc (cp_token, gc, num_tokens);
- VEC_safe_grow (cp_token, gc, hunk->buffer, num_tokens);
- lexer_addr = VEC_address (cp_token, lexer->buffer);
- hunk_addr = VEC_address (cp_token, hunk->buffer);
- memcpy (hunk_addr, &lexer_addr[start_ix], num_tokens * sizeof (cp_token));
- }
-
- if (flag_pth_debug >= 3)
- {
- fprintf (stderr, "\n=> SAVED HUNK TO IMAGE: %s\n", image->fname);
- if (flag_pth_debug >= 5)
- pth_debug_hunk (hunk);
- }
-}
-
-
-/* Compute the effects of a file transition given the file change
- described by MAP. On exit:
-
- - *PREV_IMAGE_P will point to the image for the file that we just left,
-
- - *NEW_IMAGE_P will point to the image for the file that we just
- entered. If *NEW_IMAGE_P is NULL, it means that we just left
- the last file in the translation unit, so there isn't anything
- else to be done.
-
- - *REASON_P will have the LC_* reason for the change. */
-
-static void
-pth_get_file_transition (const struct line_map *map, pth_image **prev_image_p,
- pth_image **new_image_p, enum lc_reason *reason_p)
-{
- const char *fname;
- pth_state *state;
-
- /* MAP is NULL when we leave the main file in this translation unit. */
- if (map == NULL)
- {
- fname = NULL;
- *reason_p = LC_LEAVE;
- }
- else
- {
- fname = map->to_file;
- *reason_p = map->reason;
- }
-
- state = pth_get_state ();
- *prev_image_p = state->cur_image;
-
- /* FIXME pph. Sanitize use of PARSE_IN. Stick it in
- pth_state together with lexer. */
- *new_image_p = pth_image_lookup (state, fname, parse_in);
-}
-
-
-/* Do bookkeeping actions required when the pre-processor is leaving
- file IMAGE->FNAME. READER is the cpp file reader object we
- are using for lexing. */
-
-static void
-pth_leave_file (cpp_reader *reader, pth_image *image)
-{
- pth_state *state;
-
- /* We are only interested in processing IMAGE if we have decided to
- save its image. */
- if (!image->save_p)
- return;
-
- state = pth_get_state ();
-
- /* If the image for the file we just finished is marked as
- modified, create a new token hunk spanning from the token
- that started the image to the current end of the lexer
- buffer. */
- pth_lexer_to_image (image, state->lexer, reader);
-}
-
-
-/* Do bookkeeping actions required when the pre-processor is entering
- file IMAGE->FNAME for reason REASON. READER is the cpp file reader
- object we are using for lexing. INCLUDE is the #include command
- used to enter IMAGE->FNAME. It can be NULL in the case of the
- top file in the translation unit. */
-
-static void
-pth_enter_file (cpp_reader *reader, pth_image *image, pth_include *include,
- enum lc_reason reason)
-{
- pth_state *state;
-
- state = pth_get_state ();
-
- /* Associate the current buffer with IMAGE. */
- image->buffer = cpp_get_buffer (reader);
-
- /* Complete the current #include command with the directory
- and image for the file that we just switched to. */
- if (include)
- {
- const char *dname = cpp_get_dir (cpp_get_file (image->buffer))->name;
- include->image = image;
- include->dname = (*dname) ? xstrdup (dname) : NULL;
- }
-
- /* If the file we are about to switch to has been loaded into an
- image, try to get as many tokens as possible from the image
- instead of the character stream. */
- if (pth_image_can_be_used (image))
- pth_image_to_lexer (state->lexer, image, include);
-
- /* If IMAGE does not need to be saved, we are done. */
- if (!image->save_p)
- return;
-
- /* Detect multiple inclusions of the same header file. When a file
- is included more than once, each inclusion will usually produce
- different token hunks (e.g., <stddef.h> is typically included
- from different places with "arguments" in the form of #defines
- that determine what the caller wants stddef.h to provide. See
- <wchar.h> for an example).
-
- This disrupts the validity of the image, as the hunks saved in it
- no longer correspond to a single pre-processing of the file. We
- avoid this problem by tainting the image and forcing the file to
- be always processed from its character stream. */
- if (reason == LC_ENTER && !VEC_empty (cp_token_hunk_ptr, image->token_hunks))
- image->save_p = false;
-
- /* The starting point for the next token hunk in the new
- file image will be at the current last slot in
- STATE->LEXER->BUFFER. */
- image->hunk_start_ix = VEC_length (cp_token, state->lexer->buffer);
-
- /* The new hunk starts at the current offset in the current
- libcpp buffer. If this hunk is ever invalidated, this is
- the offset at which to start pre-processing. */
- image->hunk_text_offset = cpp_get_pos (image->buffer);
-}
-
-
-/* Callback from the pre-processor when changing in or out of a file.
- READER is the pre-processor state. MAP is the line map for the
- file that we are changing to. */
-
-static void
-pth_file_change (cpp_reader *reader, const struct line_map *map)
-{
- enum lc_reason reason;
- pth_state *state;
- pth_image *prev_image, *new_image;
-
- /* Call the previous file change handler, if it exists. */
- state = pth_get_state ();
- if (state->file_change_prev)
- state->file_change_prev (reader, map);
-
- /* When processing pre-processed output, we will see names like
- '<built-in>' and '<command-line>'. Reject those.
- ??? This rejects real path names that may start with '<', but
- those should be rare. */
- if (map && map->to_file && map->to_file[0] == '<')
- return;
-
- /* Ignore LC_RENAME events. They do not affect the actual image
- that we are processing. */
- if (map && map->reason == LC_RENAME)
- return;
-
- timevar_push (TV_PTH_MANAGE);
-
- /* Get images for the file involved in the transition. */
- pth_get_file_transition (map, &prev_image, &new_image, &reason);
- gcc_assert (prev_image);
-
- /* Ignore self-referential file change events. These can happen
- when mixing token images with text buffers. */
- if (prev_image == new_image)
- {
- timevar_pop (TV_PTH_MANAGE);
- return;
- }
-
- /* Process the file we just left (get tokens from lexer buffer,
- etc). */
- pth_leave_file (reader, prev_image);
-
- /* Process the file we are about to enter (try to use its tokens if
- the file is valid, etc). */
- if (new_image)
- {
- pth_include *include = NULL;
-
- if (reason == LC_ENTER)
- include = pth_create_include (state->new_itype,
- state->new_angle_brackets,
- state->new_iname);
-
- pth_enter_file (reader, new_image, include, reason);
-
- /* If we are LC_ENTERing NEW_IMAGE, it means that PREV_IMAGE has
- #included NEW_IMAGE. In that case, add NEW_IMAGE to the list
- of included files by PREV_IMAGE. */
- if (reason == LC_ENTER)
- {
- PTH_STATS_INCR (included_files, 1);
-
- if (prev_image->save_p)
- {
- gcc_assert (include->image == new_image);
- VEC_safe_push (pth_include_ptr, gc, prev_image->includes,
- include);
- VEC_safe_push (char, gc, prev_image->ih_sequence, 'I');
- }
- }
- }
-
- /* Update the current image. */
- state->cur_image = new_image;
-
- timevar_pop (TV_PTH_MANAGE);
-}
-
-
-/* Record a #include or #include_next. */
-
-static void
-pth_include_handler (cpp_reader *reader ATTRIBUTE_UNUSED,
- location_t loc ATTRIBUTE_UNUSED,
- const unsigned char *dname,
- const char *name,
- int angle_brackets,
- const cpp_token **tok_p ATTRIBUTE_UNUSED)
-{
- pth_state *state;
-
- state = pth_get_state ();
-
- /* Remember the attributes for this #include command. This is
- used in pth_file_change to register a new include event for
- the parent file. */
- if (strcmp ((const char *)dname, "include") == 0)
- state->new_itype = IT_INCLUDE;
- else if (strcmp ((const char *)dname, "include_next") == 0)
- state->new_itype = IT_INCLUDE_NEXT;
- else if (strcmp ((const char *)dname, "import") == 0)
- state->new_itype = IT_IMPORT;
- else
- gcc_unreachable ();
-
- state->new_angle_brackets = angle_brackets;
- state->new_iname = name;
-}
-
-
-/* Initialize PTH support. LEXER is the main lexer object used for
- pre-processing. */
-
-static void
-pth_init (cp_lexer *lexer)
-{
- pth_state *state;
- cpp_callbacks *cb;
- cpp_lookaside *table;
-
- timevar_push (TV_PTH_INIT);
-
- gcc_assert (flag_pth);
-
- table = cpp_lt_exchange (parse_in, cpp_lt_create (/*2 to the power*/15,
- flag_pth_debug));
- gcc_assert (table == NULL);
-
- memset (&pth_stats, 0, sizeof (pth_stats));
-
- state = pth_get_state ();
-
- /* If not using MD5 signatures, make sure that time stamps given
- by stat() are smaller than DIGEST_LEN bytes. FIXME pph, this is
- slighly hacky. */
- if (!flag_pth_md5)
- {
- struct stat tmp;
- gcc_assert (sizeof (tmp.st_mtime) < DIGEST_LEN);
- }
-
- /* Set an handler for file change events in libcpp. */
- cb = cpp_get_callbacks (parse_in);
- state->file_change_prev = cb->file_change;
- cb->file_change = pth_file_change;
- cb->include = pth_include_handler;
-
- state->lexer = lexer;
-
- /* Make sure that we have not tried to get any tokens yet. */
- gcc_assert (VEC_empty (cp_token, lexer->buffer));
-
- /* If we have a valid image for the main input file, populate as
- many tokens from its transitive closure as possible. */
- state->cur_image = pth_image_lookup (state, main_input_filename, parse_in);
- pth_enter_file (parse_in, state->cur_image, NULL, LC_ENTER);
-
- timevar_pop (TV_PTH_INIT);
-}
-
-
-/* Show statistics on PTH on FILE. If FILE is NULL, use pph_logfile.
- LEXER is the lexer we just filled with tokens. This is usually
- the same as pth_get_state()->lexer, but it may be NULL if PTH is
- not enabled (in cases where we just want stats on pre-processed
- files). */
-
-static void
-pth_print_stats (FILE *file, cp_lexer *lexer)
-{
- unsigned i, num_tokens, total_tokens;
- pth_state *state;
- pth_image *image;
- const char *prev_fname;
- cp_token *token;
-
- if (file == NULL)
- file = pph_logfile;
-
- fprintf (file, "\nPTH statistics\n\n");
- fprintf (file, "#included files: %lu\n", pth_stats.included_files);
- fprintf (file, "Valid images: %lu\n", pth_stats.valid_images);
- fprintf (file, "Token hunks: %lu\n", pth_stats.hunks);
- fprintf (file, "Valid hunks: %lu\n", pth_stats.valid_hunks);
- fprintf (file, "Invalid hunks: %lu\n", pth_stats.invalid_hunks);
- fprintf (file, "Verified hunks: %lu\n", pth_stats.verified_hunks);
- fprintf (file, "Verified identifiers: %lu\n", pth_stats.verified_identifiers);
-
- state = pth_get_state ();
- fprintf (file, "\n\nPTH image statistics (%u files)\n\n",
- VEC_length (pth_image_ptr, state->cache));
- for (i = 0; VEC_iterate (pth_image_ptr, state->cache, i, image); i++)
- pth_show_image_stats (file, image);
-
- fprintf (file, "\nToken counts per file in #include order:\n");
- num_tokens = total_tokens = 0;
- prev_fname = NULL;
- for (i = 0; VEC_iterate (cp_token, lexer->buffer, i, token); i++)
- {
- const char *fname = LOCATION_FILE (token->location);
-
- if (prev_fname == NULL)
- prev_fname = fname;
-
- if ((fname
- && strcmp (fname, prev_fname) != 0)
- || i == VEC_length (cp_token, lexer->buffer) - 1)
- {
- fprintf (file, "tokens: %u %s\n", num_tokens, lrealpath (prev_fname));
- prev_fname = fname;
- total_tokens += num_tokens;
- num_tokens = 0;
- }
-
- num_tokens++;
- }
-
- /* The main lexer buffer should have one more token: CPP_EOF. */
- if (total_tokens != VEC_length (cp_token, lexer->buffer) - 1)
- fprintf (stderr, "*** WARNING: I counted %u, but there are %u\n",
- total_tokens, VEC_length (cp_token, lexer->buffer));
-
- fprintf (file, "\n");
-}
-
-
-/* Save all the header images that have been marked modified from
- the incremental state. */
-
-static void
-pth_finish (void)
-{
- /* If PPH is enabled, do not save PTH images to prevent analysis problems
- due to lack of location information in PTH images. FIXME pph:
- Unneeded after we start saving proper location information. */
- if (flag_pph_debug >= 1)
- {
- if (flag_pph_debug > 1)
- fprintf (stderr, "*** WARNING: Not saving PTH images because PPH "
- "is enabled\n");
- }
- else
- {
- pth_state *state;
- pth_image *image;
- size_t i;
-
- state = pth_get_state ();
- for (i = 0; VEC_iterate (pth_image_ptr, state->cache, i, image); i++)
- if (image->save_p)
- pth_save_image (image);
- }
-}
-
-
/* Allocate memory for a new lexer object and return it. */
static cp_lexer *
@@ -3008,7 +452,6 @@ cp_lexer_new_main (void)
return lexer;
}
-
/* Create a new lexer whose token stream is primed with the tokens in
CACHE. When these tokens are exhausted, no new tokens will be read. */
@@ -3058,7 +501,7 @@ cp_lexer_debugging_p (cp_lexer *lexer)
#endif /* ENABLE_CHECKING */
-static inline cp_token_position
+cp_token_position
cp_lexer_token_position (cp_lexer *lexer, bool previous_p)
{
gcc_assert (!previous_p || lexer->next_token != &eof_token);
@@ -3964,19 +1407,6 @@ typedef struct cp_parser_binary_operatio
enum cp_parser_prec prec;
} cp_parser_binary_operations_map_node;
-/* The status of a tentative parse. */
-
-typedef enum cp_parser_status_kind
-{
- /* No errors have occurred. */
- CP_PARSER_STATUS_KIND_NO_ERROR,
- /* An error has occurred. */
- CP_PARSER_STATUS_KIND_ERROR,
- /* We are committed to this tentative parse, whether or not an error
- has occurred. */
- CP_PARSER_STATUS_KIND_COMMITTED
-} cp_parser_status_kind;
-
typedef struct cp_parser_expression_stack_entry
{
/* Left hand side of the binary operation we are currently
@@ -3997,21 +1427,6 @@ typedef struct cp_parser_expression_stac
typedef struct cp_parser_expression_stack_entry
cp_parser_expression_stack[NUM_PREC_VALUES];
-/* Context that is saved and restored when parsing tentatively. */
-typedef struct GTY (()) cp_parser_context {
- /* If this is a tentative parsing context, the status of the
- tentative parse. */
- enum cp_parser_status_kind status;
- /* If non-NULL, we have just seen a `x->' or `x.' expression. Names
- that are looked up in this context must be looked up both in the
- scope given by OBJECT_TYPE (the type of `x' or `*x') and also in
- the context of the containing expression. */
- tree object_type;
-
- /* The next parsing context in the stack. */
- struct cp_parser_context *next;
-} cp_parser_context;
-
/* Prototypes. */
/* Constructors and destructors. */
@@ -4102,174 +1517,6 @@ cp_parser_context_new (cp_parser_context
return context;
}
-/* An entry in a queue of function arguments that require post-processing. */
-
-typedef struct GTY(()) cp_default_arg_entry_d {
- /* The current_class_type when we parsed this arg. */
- tree class_type;
-
- /* The function decl itself. */
- tree decl;
-} cp_default_arg_entry;
-
-DEF_VEC_O(cp_default_arg_entry);
-DEF_VEC_ALLOC_O(cp_default_arg_entry,gc);
-
-/* An entry in a stack for member functions of local classes. */
-
-typedef struct GTY(()) cp_unparsed_functions_entry_d {
- /* Functions with default arguments that require post-processing.
- Functions appear in this list in declaration order. */
- VEC(cp_default_arg_entry,gc) *funs_with_default_args;
-
- /* Functions with defintions that require post-processing. Functions
- appear in this list in declaration order. */
- VEC(tree,gc) *funs_with_definitions;
-} cp_unparsed_functions_entry;
-
-DEF_VEC_O(cp_unparsed_functions_entry);
-DEF_VEC_ALLOC_O(cp_unparsed_functions_entry,gc);
-
-/* The cp_parser structure represents the C++ parser. */
-
-typedef struct GTY(()) cp_parser {
- /* The lexer from which we are obtaining tokens. */
- cp_lexer *lexer;
-
- /* The scope in which names should be looked up. If NULL_TREE, then
- we look up names in the scope that is currently open in the
- source program. If non-NULL, this is either a TYPE or
- NAMESPACE_DECL for the scope in which we should look. It can
- also be ERROR_MARK, when we've parsed a bogus scope.
-
- This value is not cleared automatically after a name is looked
- up, so we must be careful to clear it before starting a new look
- up sequence. (If it is not cleared, then `X::Y' followed by `Z'
- will look up `Z' in the scope of `X', rather than the current
- scope.) Unfortunately, it is difficult to tell when name lookup
- is complete, because we sometimes peek at a token, look it up,
- and then decide not to consume it. */
- tree scope;
-
- /* OBJECT_SCOPE and QUALIFYING_SCOPE give the scopes in which the
- last lookup took place. OBJECT_SCOPE is used if an expression
- like "x->y" or "x.y" was used; it gives the type of "*x" or "x",
- respectively. QUALIFYING_SCOPE is used for an expression of the
- form "X::Y"; it refers to X. */
- tree object_scope;
- tree qualifying_scope;
-
- /* A stack of parsing contexts. All but the bottom entry on the
- stack will be tentative contexts.
-
- We parse tentatively in order to determine which construct is in
- use in some situations. For example, in order to determine
- whether a statement is an expression-statement or a
- declaration-statement we parse it tentatively as a
- declaration-statement. If that fails, we then reparse the same
- token stream as an expression-statement. */
- cp_parser_context *context;
-
- /* True if we are parsing GNU C++. If this flag is not set, then
- GNU extensions are not recognized. */
- bool allow_gnu_extensions_p;
-
- /* TRUE if the `>' token should be interpreted as the greater-than
- operator. FALSE if it is the end of a template-id or
- template-parameter-list. In C++0x mode, this flag also applies to
- `>>' tokens, which are viewed as two consecutive `>' tokens when
- this flag is FALSE. */
- bool greater_than_is_operator_p;
-
- /* TRUE if default arguments are allowed within a parameter list
- that starts at this point. FALSE if only a gnu extension makes
- them permissible. */
- bool default_arg_ok_p;
-
- /* TRUE if we are parsing an integral constant-expression. See
- [expr.const] for a precise definition. */
- bool integral_constant_expression_p;
-
- /* TRUE if we are parsing an integral constant-expression -- but a
- non-constant expression should be permitted as well. This flag
- is used when parsing an array bound so that GNU variable-length
- arrays are tolerated. */
- bool allow_non_integral_constant_expression_p;
-
- /* TRUE if ALLOW_NON_CONSTANT_EXPRESSION_P is TRUE and something has
- been seen that makes the expression non-constant. */
- bool non_integral_constant_expression_p;
-
- /* TRUE if local variable names and `this' are forbidden in the
- current context. */
- bool local_variables_forbidden_p;
-
- /* TRUE if the declaration we are parsing is part of a
- linkage-specification of the form `extern string-literal
- declaration'. */
- bool in_unbraced_linkage_specification_p;
-
- /* TRUE if we are presently parsing a declarator, after the
- direct-declarator. */
- bool in_declarator_p;
-
- /* TRUE if we are presently parsing a template-argument-list. */
- bool in_template_argument_list_p;
-
- /* Set to IN_ITERATION_STMT if parsing an iteration-statement,
- to IN_OMP_BLOCK if parsing OpenMP structured block and
- IN_OMP_FOR if parsing OpenMP loop. If parsing a switch statement,
- this is bitwise ORed with IN_SWITCH_STMT, unless parsing an
- iteration-statement, OpenMP block or loop within that switch. */
-#define IN_SWITCH_STMT 1
-#define IN_ITERATION_STMT 2
-#define IN_OMP_BLOCK 4
-#define IN_OMP_FOR 8
-#define IN_IF_STMT 16
- unsigned char in_statement;
-
- /* TRUE if we are presently parsing the body of a switch statement.
- Note that this doesn't quite overlap with in_statement above.
- The difference relates to giving the right sets of error messages:
- "case not in switch" vs "break statement used with OpenMP...". */
- bool in_switch_statement_p;
-
- /* TRUE if we are parsing a type-id in an expression context. In
- such a situation, both "type (expr)" and "type (type)" are valid
- alternatives. */
- bool in_type_id_in_expr_p;
-
- /* TRUE if we are currently in a header file where declarations are
- implicitly extern "C". */
- bool implicit_extern_c;
-
- /* TRUE if strings in expressions should be translated to the execution
- character set. */
- bool translate_strings_p;
-
- /* TRUE if we are presently parsing the body of a function, but not
- a local class. */
- bool in_function_body;
-
- /* If non-NULL, then we are parsing a construct where new type
- definitions are not permitted. The string stored here will be
- issued as an error message if a type is defined. */
- const char *type_definition_forbidden_message;
-
- /* A stack used for member functions of local classes. The lists
- contained in an individual entry can only be processed once the
- outermost class being defined is complete. */
- VEC(cp_unparsed_functions_entry,gc) *unparsed_queues;
-
- /* The number of classes whose definitions are currently in
- progress. */
- unsigned num_classes_being_defined;
-
- /* The number of template parameter lists that apply directly to the
- current declaration. */
- unsigned num_template_parameter_lists;
-} cp_parser;
-
/* Managing the unparsed function queues. */
#define unparsed_funs_with_default_args \
@@ -11809,309 +9056,6 @@ cp_parser_already_scoped_statement (cp_p
}
}
-static void
-pph_log_exposed (cp_parser *parser, const char *end)
-{
- if (flag_pph_debug >= 2)
- {
- cp_token *pos = cp_lexer_token_position (parser->lexer, false);
- fprintf (pph_logfile, "PPH: %s exposed declaration at ", end);
- pph_debug_location (pph_logfile, pos->location);
- fprintf (pph_logfile, "\n");
- }
-}
-
-
-/* Allocate the various arrays, maps and sets used to collect ASTs and
- their dependencies during parsing. This memory is allocated and
- freed for every grammar rule intercepted by pph_start_exposed() and
- pph_stop_exposed(). */
-
-static void
-pph_allocate_catcher_memory (void)
-{
- /* Note. pph_tree_catcher *must* be instantiated to indicate that
- we are going to be catching trees during parsing. */
- pph_tree_catcher = VEC_alloc (tree, heap, 5);
- pph_decl_head_token_cache = pointer_map_create ();
- pph_decl_body_token_cache = pointer_map_create ();
- pph_decl_deps = XCNEW (struct pph_decl_deps_d);
- pph_decl_deps->header = pointer_map_create ();
- pph_decl_deps->body = pointer_map_create ();
- pph_name_lookups = NULL;
- pph_name_lookups_set = pointer_set_create ();
- pph_nl_token_map = pointer_map_create ();
-}
-
-
-/* Free all the memory allocated by pph_allocate_catcher_memory. */
-
-static void
-pph_free_catcher_memory (void)
-{
- VEC_free (tree, heap, pph_tree_catcher);
-
- pointer_map_destroy (pph_decl_head_token_cache);
- pph_decl_head_token_cache = NULL;
-
- pointer_map_destroy (pph_decl_body_token_cache);
- pph_decl_body_token_cache = NULL;
-
- pointer_map_destroy (pph_decl_deps->header);
- pointer_map_destroy (pph_decl_deps->body);
- free (pph_decl_deps);
- pph_decl_deps = NULL;
-
- VEC_free (tree, heap, pph_name_lookups);
-
- pointer_set_destroy (pph_name_lookups_set);
- pph_name_lookups_set = NULL;
-
- pointer_map_destroy (pph_nl_token_map);
- pph_nl_token_map = NULL;
-}
-
-
-/* Start collecting ASTs and dependencies. */
-
-static cp_token *
-pph_start_exposed (cp_parser *parser)
-{
- if (flag_pph_debug >= 1)
- {
- timevar_push (TV_PPH_MANAGE);
-
- if (flag_pph_debug >= 4)
- fprintf (pph_logfile, "\n--------------------------------------------------------------------------\n");
- pph_log_exposed (parser, "start");
- pph_allocate_catcher_memory ();
- timevar_pop (TV_PPH_MANAGE);
-
- return parser->lexer->next_token; /* the first token */
- }
- else
- return NULL;
-}
-
-/* Return the token cache associated with tree node T. */
-
-static VEC(cp_token, heap) *
-pph_lookup_head_token_cache_for (tree t)
-{
- void **slot = pointer_map_contains (pph_decl_head_token_cache, t);
- if (slot)
- return ((VEC(cp_token, heap) *) *slot);
-
- return NULL;
-}
-
-static VEC(cp_token, heap) *
-pph_lookup_body_token_cache_for (tree t)
-{
- void **slot = pointer_map_contains (pph_decl_body_token_cache, t);
- if (slot)
- return ((VEC(cp_token, heap) *) *slot);
-
- return NULL;
-}
-
-
-/* Set the token cache associated with tree node T to CACHE. */
-
-static void
-pph_set_head_token_cache_for (tree t, VEC(cp_token, heap) *cache)
-{
- void **slot = pointer_map_insert (pph_decl_head_token_cache, t);
- *slot = (void *) cache;
-}
-
-static void
-pph_set_body_token_cache_for (tree t, VEC(cp_token, heap) *cache)
-{
- void **slot = pointer_map_insert (pph_decl_body_token_cache, t);
- *slot = (void *) cache;
-}
-
-/* Emulate the copying of declarations into the parser cache. Deep
- copy all the declarations in V. */
-
-static void
-pph_copy_decls_into_cache (VEC(tree, heap) *v)
-{
- unsigned i;
- static tree t_copy, type_copy, t;
- void **slot;
- VEC(tree, heap) *ast_cache, *old_pph_tree_catcher, *old_pph_name_lookups;
- static struct pointer_map_t *hunk_to_decls_map = NULL;
- static htab_t cache_dir = NULL;
- const char *fname;
-
- timevar_push (TV_PPH_CACHE_IN);
-
- if (hunk_to_decls_map == NULL)
- hunk_to_decls_map = pointer_map_create ();
-
- if (cache_dir == NULL)
- cache_dir = htab_create (10, htab_hash_pointer, htab_eq_pointer, 0);
-
- /* We will be copying trees, which will call into the tree catching
- routines. Prevent that. */
- old_pph_tree_catcher = pph_tree_catcher;
- old_pph_name_lookups = pph_name_lookups;
- pph_tree_catcher = pph_name_lookups = NULL;
-
- /* Copy every declaration in V into the cache. */
- for (i = 0; VEC_iterate (tree, v, i, t); i++)
- {
- /* 1- Determine the token hunk H that owns T. We first determine
- the PTH image and then which hunk inside that PTH image. For
- choosing the hunk within the image, we simulate a second
- hash table lookup hashing the location to the token hunk. */
- pth_image *image, *hunk;
- VEC(cp_token, heap) *head_tokens, *body_tokens;
- cp_token *first;
-
- head_tokens = pph_lookup_head_token_cache_for (t);
- body_tokens = pph_lookup_body_token_cache_for (t);
- if (VEC_empty (cp_token, head_tokens))
- continue;
- first = VEC_index (cp_token, head_tokens, 0);
- fname = LOCATION_FILE (first->location);
- slot = htab_find_slot (cache_dir, fname, INSERT);
- if (*slot == NULL)
- {
- image = XCNEW (pth_image);
- *slot = CONST_CAST (char *, fname);
- }
- else
- image = *((pth_image **) slot);
-
- /* For now, re-do the pth_image_lookup to simulate the lookup of
- the hunk within the image. */
- slot = htab_find_slot (cache_dir, fname, NO_INSERT);
- hunk = *((pth_image **) slot);
-
- /* Insert dummy uses for head_tokens, body_tokens and image. */
- if (i > VEC_length (tree, v))
- {
- free (head_tokens);
- free (body_tokens);
- free (image);
- }
-
- /* 2- Find the tree cache associated with HUNK. */
- slot = pointer_map_insert (hunk_to_decls_map, hunk);
- ast_cache = (VEC(tree, heap) *) *slot;
-
- /* 3- Copy T and its type into the cache associated with HUNK.
- If T has a body (a FUNCTION_DECL), copy the body. FIXME pph,
- copying ASTs will need new copying code to be implemented,
- the current routines do not handle everything that can be
- generated by the C++ FE. */
- t_copy = copy_decl (t);
- if (!type_copy || TREE_TYPE (t))
- type_copy = copy_type (TREE_TYPE (t));
- if (TREE_CODE (t) == FUNCTION_DECL)
- walk_tree (&DECL_SAVED_TREE (t_copy), copy_tree_r, (void *)1, NULL);
- VEC_safe_push (tree, heap, ast_cache, t_copy);
- *slot = (void *) ast_cache;
- }
-
- PPH_STATS_INCR (cached_decls, VEC_length (tree, v));
-
- /* Restore tree and lookup catchers. */
- pph_tree_catcher = old_pph_tree_catcher;
- pph_name_lookups = old_pph_name_lookups;
-
- timevar_pop (TV_PPH_CACHE_IN);
-}
-
-
-/* Emulate the cache actions needed to get a declaration out of the
- parser cache and instantiate it into the current compilation context. */
-
-static void
-pph_copy_decls_outof_cache (VEC(tree, heap) *v)
-{
- unsigned i;
- tree t;
- static VEC(tree, heap) *compilation_context = NULL;
- VEC(tree, heap) *old_pph_tree_catcher, *old_pph_name_lookups;
-
- /* Conceptually, this will be called with a token hunk that contains
- all the declarations that we want to instantiate. */
- timevar_push (TV_PPH_CACHE_OUT);
-
- /* We will be copying trees, which will call into the tree catching
- routines. Prevent that. */
- old_pph_tree_catcher = pph_tree_catcher;
- old_pph_name_lookups = pph_name_lookups;
- pph_tree_catcher = pph_name_lookups = NULL;
-
- /* 1- Verify that the hunk is valid. Traverse all the declarations
- checking that none have been tainted. */
- for (i = 0; VEC_iterate (tree, v, i, t); i++)
- {
- /* If T is not valid, none of its users is valid. */
- if (1 || TREE_VISITED (t))
- {
- unsigned j;
- tree r;
- for (j = 0; VEC_iterate (tree, v, j, r); j++)
- TREE_VISITED (r) = TREE_VISITED (r);
- }
- }
-
- /* 2- Copy all the trees in the hunk to the current compilation context. */
- for (i = 0; VEC_iterate (tree, v, i, t); i++)
- {
- static tree t_copy, type_copy;
-
- t_copy = copy_decl (t);
- if (!type_copy || TREE_TYPE (t))
- type_copy = copy_type (TREE_TYPE (t));
- if (TREE_CODE (t) == FUNCTION_DECL)
- walk_tree (&DECL_SAVED_TREE (t_copy), copy_tree_r, (void *)1, NULL);
-
- /* Emulate restoration into compilation context. FIXME pph, this is
- missing the name lookups that may be required. Estimate this
- separately from the number of name lookup operations and the
- time spent doing name lookups. */
- VEC_safe_push (tree, heap, compilation_context, t_copy);
- }
-
- PPH_STATS_INCR (restored_decls, VEC_length (tree, v));
-
- /* Restore tree and lookup catchers. */
- pph_tree_catcher = old_pph_tree_catcher;
- pph_name_lookups = old_pph_name_lookups;
-
- timevar_pop (TV_PPH_CACHE_OUT);
-}
-
-static void
-pph_stop_exposed (cp_parser *parser, cp_token *first_token)
-{
- if (flag_pph_debug >= 1 && !VEC_empty (tree, pph_tree_catcher))
- {
- cp_token *last_token;
-
- timevar_push (TV_PPH_MANAGE);
-
- last_token = parser->lexer->next_token;
- pph_print_trees_tokens (pph_tree_catcher, first_token, last_token);
- pph_copy_decls_into_cache (pph_tree_catcher);
- pph_copy_decls_outof_cache (pph_tree_catcher);
- PPH_STATS_INCR (cached_refs, VEC_length(tree, pph_name_lookups));
- pph_free_catcher_memory ();
- if (flag_pph_debug >= 4)
- pph_log_exposed (parser, "stop");
-
- timevar_pop (TV_PPH_MANAGE);
- }
-}
-
-
/* Declarations [gram.dcl.dcl] */
/* Parse an optional declaration-sequence.
@@ -27646,1591 +24590,8 @@ cp_parser_omp_construct (cp_parser *pars
/* The parser. */
-static GTY (()) cp_parser *the_parser;
-
-/* PPH printing help. */
-
-static void
-pph_debug_tree (tree t, bool body)
-{
- if (t == NULL)
- {
- fprintf (pph_logfile, "nulldecl");
- return;
- }
-
- if (!DECL_P (t))
- {
- fprintf (pph_logfile, "__%s__", tree_code_name[TREE_CODE (t)]);
- return;
- }
-
- if (flag_pph_decls >= 2)
- fprintf (pph_logfile, "%s ", tree_code_name[TREE_CODE (t)]);
- fprintf (pph_logfile, "%d", (DECL_UID (t) << 1) + body);
- if (flag_pph_decls >= 1)
- fprintf (pph_logfile, " '%s'", get_name (t));
- if (flag_pph_decls >= 3)
- {
- fprintf (pph_logfile, " ");
- pph_debug_loc_of_tree (pph_logfile, t);
- if (flag_pph_decls >= 4)
- fprintf (pph_logfile, " @%p", (void *) t);
- }
-}
-
-static void
-pph_debug_type (tree t, bool body)
-{
- tree t_decl;
- if (t == NULL)
- {
- fprintf (pph_logfile, "nulltype");
- return;
- }
- t_decl = get_type_decl (t);
- if (t_decl == NULL)
- fprintf (pph_logfile, "nameless");
- else
- pph_debug_tree (t_decl, body);
-}
-
-/* Return true if tree T has been caught already. */
-
-static bool
-pph_tree_caught_p (tree t)
-{
- return (pph_lookup_head_token_cache_for (t) != NULL);
-}
-
-/* Collect the tokens needed for the head of DECL.
- This assumes that the current token is positioned right after
- the end of the declarator expression for DECL (i.e., it should
- be called from grokdeclarator). */
-
-static VEC(cp_token, heap) *
-pph_catch_head_tokens_for (tree t)
-{
- cp_token *tok, *last, *first;
- cp_lexer *lexer;
- VEC(cp_token, heap) *tokens;
-
- gcc_assert (t != error_mark_node);
-
- tokens = pph_lookup_head_token_cache_for (t);
- if (tokens)
- {
- fprintf (stderr, "*** ");
- pph_debug_location (stderr, input_location);
- fprintf (stderr, ": Tried to catch head tokens more than once for: ");
- print_generic_stmt (stderr, t, 0);
- gcc_unreachable ();
- }
-
- lexer = the_parser->lexer;
-
- /* Look for the tokens backwards until the first brace or semicolon. */
- first = last = lexer->next_token;
- for (tok = last - 1; tok >= VEC_address (cp_token, lexer->buffer); tok--)
- {
- if (tok->type == CPP_OPEN_BRACE
- || tok->type == CPP_CLOSE_BRACE
- || tok->type == CPP_SEMICOLON)
- break;
-
- first = tok;
- }
-
- /* Now include any trailing semicolon. */
- if (last->type == CPP_SEMICOLON)
- last++;
-
- /* Add all the tokens in [FIRST, LAST) to TOKENS. */
- for (tok = first; tok != last; tok++)
- VEC_safe_push (cp_token, heap, tokens, tok);
-
- pph_set_head_token_cache_for (t, tokens);
-
- return tokens;
-}
-
-
-/* Collect the tokens needed for the body of DECL.
- This assumes that the current token is positioned right after
- the end of the declarator expression for DECL (i.e., it should
- be called from grokdeclarator). */
-
-static VEC(cp_token, heap) *
-pph_catch_body_tokens_for (tree t)
-{
- cp_token *tok, *last, *first;
- cp_lexer *lexer;
- VEC(cp_token, heap) *tokens;
-
- gcc_assert (t != error_mark_node);
-
- tokens = pph_lookup_body_token_cache_for (t);
- if (tokens)
- {
- fprintf (stderr, "*** ");
- pph_debug_location (stderr, input_location);
- fprintf (stderr, ": Tried to catch body tokens more than once for: ");
- print_generic_stmt (stderr, t, 0);
- gcc_unreachable ();
- }
-
- lexer = the_parser->lexer;
-
- /* Look for the tokens forwards until the closing brace or semicolon. */
- first = last = lexer->next_token;
- tok = first;
- if (tok->type == CPP_EQ || tok->type == CPP_OPEN_PAREN)
- {
- /* Skip a variable-like definition. Find the semicolon. */
- /* FIXME pph - This code changes with C++0x. */
- for (; tok <= VEC_last (cp_token, lexer->buffer); tok++)
- if (tok->type == CPP_SEMICOLON)
- break;
- last = tok;
- }
- else if (tok->type == CPP_OPEN_BRACE || tok->type == CPP_COLON)
- {
- /* Skip a class-like or function-like definition.
- Skip to a left brace, then skip to the matching right brace. */
- /* FIXME pph - This code changes with C++0x. */
- int nesting = 0;
- for (; tok <= VEC_last (cp_token, lexer->buffer); tok++)
- if (tok->type == CPP_OPEN_BRACE)
- nesting++;
- else if (tok->type == CPP_CLOSE_BRACE)
- {
- if ( nesting <= 1)
- break;
- else
- nesting--;
- }
- last = tok;
- }
- else
- return NULL; /* no body */
-
- /* Add all the tokens in [FIRST, LAST) to TOKENS. */
- for (tok = first; tok <= last; tok++)
- VEC_safe_push (cp_token, heap, tokens, tok);
-
- pph_set_body_token_cache_for (t, tokens);
-
- return tokens;
-}
-
-
-/* Return the dependencies for tree node T. If HEADER_P is true, it
- returns the dependencies for the header of T's declaration.
- Otherwise, it returns dependencies for T's body. */
-
-static VEC(tree,gc) *
-pph_lookup_dependencies_for (tree t, bool header_p)
-{
- struct pointer_map_t *map;
- void **slot;
-
- map = (header_p) ? pph_decl_deps->header : pph_decl_deps->body;
- slot = pointer_map_contains (map, t);
- if (slot)
- return ((VEC(tree,gc) *) *slot);
-
- return NULL;
-}
-
-
-/* Set the dependencies for tree node T to DEPS. If HEADER_P is true,
- DEPS are the dependencies for T's header. Otherwise, DEPS are the
- dependencies for T's body. */
-
-static void
-pph_set_dependencies_for (tree t, VEC(tree,gc) *deps, bool header_p)
-{
- void **slot;
- struct pointer_map_t *map;
-
- map = (header_p) ? pph_decl_deps->header : pph_decl_deps->body;
- slot = pointer_map_insert (map, t);
- *slot = (void *) deps;
-}
-
-#define PPH_ARTIFICIAL(t) \
-(DECL_ARTIFICIAL (t) \
-&& !(TREE_CODE (t) == TYPE_DECL && DECL_IMPLICIT_TYPEDEF_P (t)))
-
-static bool
-is_namespace (tree container)
-{
- enum tree_code code;
-
- if (container == NULL)
- return true;
-
- code = TREE_CODE (container);
- if (code == NAMESPACE_DECL)
- return true;
-
- return false;
-}
-
-/* Find the exposed declaration containing a symbol lookup. */
-
-static tree
-pph_null_exposed (const char *reason)
-{
- if (flag_pph_debug >= 3)
- fprintf (pph_logfile, "%s\n", reason);
- return NULL;
-}
-
-static tree
-pph_live_exposed (tree t, bool body)
-{
- if (PPH_ARTIFICIAL (t))
- return pph_null_exposed ("Artificial symbols are not exposed.");
-
- if (flag_pph_debug >= 3)
- {
- if (t == NULL)
- fprintf (pph_logfile, "(null)");
- else
- pph_debug_tree (t, body);
- fprintf (pph_logfile, "\n");
- }
- return t;
-}
-
-static tree
-pph_find_exposed_for (tree t, bool *body)
-{
- tree container;
- enum tree_code code, t_code;
- bool in_class;
- *body = false; /* By default, we only depend on heads. */
- for ( ; ; t = container, *body = true)
- {
- reclassify:
- if (t == NULL)
- {
- PPH_STATS_INCR (bad_lookups, 1);
- return pph_null_exposed ("NULLOID"); /* FIXME pph */
- }
- if (flag_pph_debug >= 3)
- {
- fprintf (pph_logfile, " exposed for ");
- pph_debug_tree (t, false);
- fprintf (pph_logfile, " is ");
- }
- code = TREE_CODE (t);
- switch (code)
- {
- /* Types common to C and C++. */
- case ARRAY_TYPE:
- case BOOLEAN_TYPE:
- case COMPLEX_TYPE:
- case ENUMERAL_TYPE:
- case FIXED_POINT_TYPE:
- case FUNCTION_TYPE:
- case INTEGER_TYPE:
- case LANG_TYPE:
- case METHOD_TYPE:
- case OFFSET_TYPE:
- case POINTER_TYPE:
- case QUAL_UNION_TYPE:
- case REAL_TYPE:
- case RECORD_TYPE:
- case REFERENCE_TYPE:
- case UNION_TYPE:
- case VECTOR_TYPE:
- case VOID_TYPE:
- /* C++-specific types. */
- case BOUND_TEMPLATE_TEMPLATE_PARM:
- case TEMPLATE_TEMPLATE_PARM:
- case TEMPLATE_TYPE_PARM:
- case TYPENAME_TYPE:
- case TYPEOF_TYPE:
- case UNBOUND_CLASS_TEMPLATE:
- case TYPE_ARGUMENT_PACK:
- case TYPE_PACK_EXPANSION:
- case DECLTYPE_TYPE:
- {
- if (TYPE_NAME (t) == NULL)
- return pph_null_exposed ("Anonymous Type");
- else
- t = TYPE_NAME (t);
- /* FALLTHRU */
- }
-
- case TYPE_DECL:
- {
- container = DECL_CONTEXT (t);
- in_class = container && CLASS_TYPE_P (container);
- t_code = TREE_CODE (TREE_TYPE (t));
- /* FIXME pph: Why DECL_TEMPLATE_TEMPLATE_PARM_P does not apply
- here? It is a template template parameter, but the tree code
- is inconsistent. */
- if (DECL_TEMPLATE_PARM_P (t)
- || t_code == TEMPLATE_TEMPLATE_PARM
- || t_code == BOUND_TEMPLATE_TEMPLATE_PARM)
- return pph_null_exposed ("TMPLPARM");
-
- if (is_namespace (container))
- return pph_live_exposed (t, *body);
- break;
- }
-
- case VAR_DECL:
- {
- /* If var is lazy, depend on its body, not its head. */
- tree enclass = DECL_CONTEXT (t);
- bool in_class = enclass && CLASS_TYPE_P (enclass);
- bool defined = DECL_INITIAL (t) != NULL;
- /* FIXME pph: DECL_INITIALIZED_P (t) */
- if (defined && (in_class || !DECL_THIS_EXTERN (t))
- && DECL_INTEGRAL_CONSTANT_VAR_P (t))
- *body = true;
-
- container = DECL_CONTEXT (t);
- in_class = container && CLASS_TYPE_P (container);
- if (in_class && DECL_THIS_STATIC (t))
- container = TYPE_CONTEXT (container);
- if (is_namespace (container))
- return pph_live_exposed (t, *body);
- break;
- }
-
- case FUNCTION_DECL:
- {
- /* If function is lazy, depend on body. */
- bool defined = DECL_INITIAL (t) != NULL;
- if (defined && (DECL_DECLARED_INLINE_P (t)
- || DECL_USE_TEMPLATE (t) != 2))
- *body = true;
-
- container = DECL_CONTEXT (t);
- in_class = container && CLASS_TYPE_P (container);
- if (in_class)
- container = TYPE_CONTEXT (container);
- if (is_namespace (container))
- return pph_live_exposed (t, *body);;
- break;
- }
-
- case TEMPLATE_DECL:
- {
- int generic = DECL_USE_TEMPLATE (t);
- if (generic != 2)
- {
- t = DECL_TEMPLATE_RESULT (t);
- if (flag_pph_debug >= 3)
- fprintf (pph_logfile, "template redirected\n");
- goto reclassify;
- }
- }
-
- case SCOPE_REF:
- return pph_null_exposed ("SCOPE_REF"); /* FIXME pph */
-
- case OVERLOAD:
- return pph_null_exposed ("OVERLOAD"); /* FIXME pph */
-
- case BASELINK:
- container = BASELINK_BINFO (t);
- break;
-
- case TREE_BINFO:
- container = BINFO_TYPE (t);
- break;
-
- case TREE_LIST:
- t = TREE_VALUE (t);
- /* Fallthru */
-
- default:
- {
- if (t == NULL)
- {
- PPH_STATS_INCR (bad_lookups, 1);
- return pph_null_exposed ("NULLOID"); /* FIXME pph */
- }
- else if (!DECL_P (t))
- {
- PPH_STATS_INCR (bad_lookups, 1);
- return pph_null_exposed ("BOZOID"); /* FIXME pph */
- /*FIXME pph:
- fatal_error ("Expecting a *_decl node. Got %s",
- tree_code_name[TREE_CODE (t)]);
- */
- }
-
- container = DECL_CONTEXT (t);
- in_class = container && CLASS_TYPE_P (container);
- if (is_namespace (container))
- return pph_null_exposed ("UNKNOWN");
- break;
- }
- }
- if (flag_pph_debug >= 3)
- {
- pph_debug_tree (container, *body);
- fprintf (pph_logfile, "\n");
- }
- }
-}
-
-
-/* Collect the AST nodes that node T depends on. HEADER_P is true if
- we should collect ASTs from T's header. Otherwise, we collect
- ASTs from T's body. */
-
-static VEC(tree,gc) *
-pph_catch_dependencies_for (tree t, bool header_p)
-{
- VEC(cp_token, heap) *tokens;
- unsigned i;
- cp_token *tok;
- VEC(tree,gc) *deps;
-
- tokens = (header_p)
- ? pph_lookup_head_token_cache_for (t)
- : pph_lookup_body_token_cache_for (t);
-
- if (tokens == NULL)
- tokens = (header_p)
- ? pph_catch_head_tokens_for (t)
- : pph_catch_body_tokens_for (t);
-
- deps = pph_lookup_dependencies_for (t, header_p);
-
- for (i = 0; VEC_iterate (cp_token, tokens, i, tok); i++)
- if (tok->type == CPP_NAME)
- VEC_safe_push (tree, gc, deps, tok->u.value);
-
- pph_set_dependencies_for (t, deps, header_p);
-
- return deps;
-}
-
-
-/* Intercept tree node T by storing it in pph_tree_catcher and collecting
- the tokens used in its instantiation. */
-
-void
-pph_catch_tree (tree t)
-{
- /* Only collect trees if the parser instantiated pph_tree_catcher
- and we are currently parsing from the main lexer. */
- if (pph_tree_catcher && the_parser->lexer->buffer && !pph_tree_caught_p (t))
- {
- timevar_push (TV_PPH_MANAGE);
-
- VEC_safe_push (tree, heap, pph_tree_catcher, t);
- pph_catch_head_tokens_for (t);
- pph_catch_body_tokens_for (t);
- pph_catch_dependencies_for (t, true);
- pph_catch_dependencies_for (t, false);
-
- timevar_pop (TV_PPH_MANAGE);
- }
-}
-
-
-/* Retract a caught tree. */
-
-void
-pph_uncatch_tree (tree t)
-{
- /* Only uncollect trees if the parser instantiated pph_tree_catcher
- and we are currently parsing from the main lexer. */
- if (pph_tree_catcher && the_parser->lexer->buffer)
- {
- int i;
- tree u;
-
- timevar_push (TV_PPH_MANAGE);
-
- /* Find the index; if present, remove it. */
- for (i = 0; VEC_iterate (tree, pph_tree_catcher, i, u); i++)
- {
- if (u == t)
- {
- VEC_ordered_remove (tree, pph_tree_catcher, i);
- break;
- }
- }
-
- timevar_pop (TV_PPH_MANAGE);
- }
-}
-
-
-/* Given a set of tokens TOKENS, return the symbols from pph_name_lookups
- that occur in TOKENS. The returned vector is, then, the set of all
- symbols that were resolved via name lookups during parsing. This set
- is a subset of all the CPP_NAME tokens in TOKENS. */
-
-static void
-pph_locate_name_lookups_in (VEC(cp_token, heap) *tokens,
- VEC(tree,gc) **heads_found,
- VEC(tree,gc) **bodies_found)
-{
- unsigned i;
- tree t;
- cp_token *first, *last;
-
- *heads_found = NULL;
- *bodies_found = NULL;
-
- if (tokens == NULL || VEC_empty (cp_token, tokens))
- return;
-
- first = VEC_index (cp_token, tokens, 0);
- last = VEC_last (cp_token, tokens);
-
- for (i = 0; VEC_iterate (tree, pph_name_lookups, i, t); i++)
- {
- unsigned j;
- cp_token *tok;
- VEC(cp_token, heap) *lookup_locations;
- void **slot;
- bool pushed = false;
-
- slot = pointer_map_contains (pph_nl_token_map, t);
- gcc_assert (slot && *slot);
- lookup_locations = (VEC(cp_token, heap) *) *slot;
- for (j = 0; VEC_iterate (cp_token, lookup_locations, j, tok); j++)
- {
- if (tok->location >= first->location
- && tok->location <= last->location)
- {
- if (!pushed)
- {
- bool body;
- tree exposed = pph_find_exposed_for (t, &body);
- if (exposed)
- {
- if (body)
- VEC_safe_push (tree, gc, *bodies_found, exposed);
- else
- VEC_safe_push (tree, gc, *heads_found, exposed);
- pushed = true;
- }
- }
-
- /* Avoid double-counting lookups by removing the lookup
- location after a class member declaration has found it.
- To make that work, we must remove all redundant entries. */
- if (flag_pph_debug >= 4)
- {
- fprintf (pph_logfile, " lookup in %p for ",
- (void*)lookup_locations);
- pph_debug_tree (t, false);
- fprintf (pph_logfile, " found at ");
- pph_debug_location (pph_logfile, tok->location);
- fprintf (pph_logfile, "\n");
- fprintf (pph_logfile, " vector length from %d",
- VEC_length (cp_token, lookup_locations));
-
- }
- /* This code is slow, but VEC won't let me null entires. */
- VEC_ordered_remove (cp_token, lookup_locations, j);
- /* We have just shifted down all later entries,
- and need to counteract the upcoming index increment. */
- j--;
- if (flag_pph_debug >= 4)
- {
- fprintf (pph_logfile, " to %d\n",
- VEC_length (cp_token, lookup_locations));
- }
- }
- }
- }
-}
-
-
-/* Print all the trees in V and the tokens in the token range
- [TOK1, TOK2). */
-
-static VEC(cp_token, heap) *
-pph_print_copy_tokens (cp_token *tok1, cp_token *tok2)
-{
- cp_token *tok;
- VEC(cp_token, heap) *vtok;
-
- /* If TOK2 is CPP_EOF, it will have the address of eof_token, which
- will make the loop below go off the deep end. Detect this and
- make TOK2 the last token in the lexer buffer instead. */
- if (tok2 == &eof_token)
- tok2 = VEC_last (cp_token, the_parser->lexer->buffer);
-
- vtok = NULL;
- for (tok = tok1; tok != tok2; tok++)
- VEC_safe_push (cp_token, heap, vtok, tok);
-
- return vtok;
-}
-
-static void
-pph_print_token_range (VEC(tree,heap) *v, VEC(cp_token, heap) *vtok)
-{
- unsigned i;
- tree t;
-
- if (flag_pph_debug >= 4)
- {
- fprintf (pph_logfile, "PPH: hunk location ");
- pph_debug_location (pph_logfile, VEC_index (cp_token, vtok, 0)->location);
- fprintf (pph_logfile, " to ");
- pph_debug_location (pph_logfile, VEC_last (cp_token, vtok)->location);
- fprintf (pph_logfile, "\n");
- fprintf (pph_logfile, "PPH: hunk tokens ");
- cp_lexer_dump_tokens (stderr, (VEC(cp_token, gc) *)vtok, 0);
- fprintf (pph_logfile, "PPH: hunk ASTs:\n");
- for (i = 0; VEC_iterate (tree, v, i, t); i++)
- {
- pph_debug_tree (t, true);
- /* FIXME pph: this may not be right; we may not care. */
- print_generic_stmt (stderr, t, 0);
- }
- fprintf (pph_logfile, "PPH: hunk decls:\n");
- }
-}
-
-static void
-pph_print_dependence (bool user_body, bool used_body,
- tree t, tree d)
-{
- static bool prior_user_body = false;
- static bool prior_used_body = false;
- static tree prior_t = NULL;
- static tree prior_d = NULL;
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " pd_base ");
- pph_debug_tree (t, user_body);
- fprintf (pph_logfile, " on ");
- pph_debug_tree (d, used_body);
- fprintf (pph_logfile, "\n");
- }
- if (t && d && DECL_P (t) && DECL_P (d) && (t != d || user_body != used_body))
- {
- if (PPH_ARTIFICIAL (t))
- {
- /* Okay, find the real symbol this articial one belongs to. */
- d = pph_find_exposed_for (d, &used_body);
- if (d == NULL)
- return;
- used_body = true;
- }
- if (user_body != prior_user_body
- || used_body != prior_used_body
- || t != prior_t
- || d != prior_d)
- {
- fprintf (pph_logfile, "depend ");
- pph_debug_tree (t, user_body);
- fprintf (pph_logfile, " uses ");
- pph_debug_tree (d, used_body);
- fprintf (pph_logfile, "\n");
- prior_user_body = user_body;
- prior_used_body = used_body;
- prior_t = t;
- prior_d = d;
- }
- }
-}
-
-static void
-pph_print_depend_template (tree tmpl_info, tree t)
-{
- tree tmpl_decl;
- tree tmpl_ptrn;
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " pd_template ");
- pph_debug_tree (t, true);
- fprintf (pph_logfile, " %p", (void*)tmpl_info);
- fprintf (pph_logfile, "\n");
- }
- tmpl_decl = TI_TEMPLATE (tmpl_info);
- if (TREE_CODE (tmpl_decl) == OVERLOAD)
- tmpl_decl = OVL_CURRENT (tmpl_decl);
- tmpl_ptrn = DECL_TEMPLATE_RESULT (tmpl_decl);
- if (tmpl_ptrn && t != tmpl_ptrn)
- {
- /* This is a template, but not the pattern. */
- pph_print_dependence (true, true, t, tmpl_ptrn);
- }
-}
-
-/* Print the dependence of a head of declaration
- on the body of a type that the head uses directly.
- If either of these is not exposed,
- find the body of the exposed declaration that contains it. */
-
-static void
-pph_print_depend_decl (tree user, tree used)
-{
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " pd_decl ");
- pph_debug_tree (user, false);
- fprintf (pph_logfile, " on ");
- pph_debug_tree (used, false);
- fprintf (pph_logfile, "\n");
- }
- if (user != NULL)
- {
- if (used != NULL)
- {
- bool body;
- tree exp_for_user = pph_find_exposed_for (user, &body);
- tree exp_for_used = pph_find_exposed_for (used, &body);
- if (exp_for_user && exp_for_used && exp_for_user != exp_for_used)
- pph_print_dependence (exp_for_user != user, true,
- exp_for_user, exp_for_used);
- }
- }
-}
-
-static void
-pph_print_depend_type (tree decl, tree type)
-{
- tree type_decl;
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " pd_type ");
- pph_debug_tree (decl, false);
- fprintf (pph_logfile, " on ");
- pph_debug_type (type, false);
- fprintf (pph_logfile, "\n");
- }
- if (type != NULL)
- {
- type_decl = get_type_decl (type);
- pph_print_depend_decl (decl, type_decl);
- }
-}
-
-static void
-pph_print_depend_type_type (tree t)
-{
- tree t_type;
- tree field;
-
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " depending on typedecl type ");
- pph_debug_tree (t, false);
- fprintf (pph_logfile, "\n");
- }
-
- t_type = TREE_TYPE (t);
- field = TYPE_FIELDS (t_type);
- for (; field; field = TREE_CHAIN(field))
- {
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " field ");
- pph_debug_tree (field, false);
- }
- if (TREE_CODE (field) == FIELD_DECL)
- {
- tree f_type = TREE_TYPE (field);
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " of type ");
- pph_debug_type (f_type, false);
- if (DECL_FIELD_IS_BASE (field))
- fprintf (pph_logfile, " is a base field!!\n");
- else
- fprintf (pph_logfile, " is a plain field\n");
- }
- pph_print_depend_type (t, f_type);
- }
- else if (TREE_CODE (field) == TYPE_DECL)
- {
- tree f_type = TREE_TYPE (field);
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " of type ");
- pph_debug_type (f_type, false);
- fprintf (pph_logfile, " is a type field\n");
- }
- pph_print_depend_type (t, f_type);
- }
- }
-
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " end of fields\n");
- }
-}
-
-static void
-pph_print_depend_func_type (tree t)
-{
- /* We must print a dependence of the head of the function
- on the body of the types of its signature. */
-
- tree args;
- tree func_type;
-
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " depending on function type ");
- pph_debug_tree (t, false);
- fprintf (pph_logfile, "\n");
- }
-
- func_type = TREE_TYPE (t);
- pph_print_depend_type (t, TREE_TYPE (func_type)); /* return type */
- for (args = TYPE_ARG_TYPES (func_type); args; args = TREE_CHAIN (args))
- pph_print_depend_type (t, TREE_VALUE (args)); /* parameter */
-
- if (DECL_VIRTUAL_P (t))
- {
- tree ctx_type = DECL_CONTEXT (t);
- tree ctx_decl = get_type_decl (ctx_type);
- /* Virtual functions depend on containing class's body.*/
- pph_print_depend_type (t, ctx_type);
- /* The virtual class's body also depends on the function
- for construction of the vtable. */
- pph_print_dependence (true, true, ctx_decl, t);
- }
-}
-
-static void
-pph_print_depend_var_type (tree t)
-{
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " depending on var/field type ");
- pph_debug_tree (t, false);
- fprintf (pph_logfile, "\n");
- }
-
- pph_print_depend_type (t, TREE_TYPE (t));
-}
-
-enum decl_exposure { HIDDEN, EXPOSED, NEEDED };
-
-static enum decl_exposure
-pph_get_decl_exposure (tree t)
-{
- tree container;
- tree type;
- tree tmpl_info;
- bool defined = false;
- bool inlined = false;
- bool needed = false;
- int generic = 0;
- enum tree_code code = TREE_CODE (t);
-
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " get_exposure for ");
- pph_debug_tree (t, false);
- fprintf (pph_logfile, "\n");
- }
-
- /* For DECL_USE_TEMPLATE and CLASSTYPE_USE_TEMPLATE,
- 1=implicit instantiation
- 2=partial or explicit specialization, e.g.:
- template <> int min<int> (int, int),
- 3=explicit instantiation, e.g.:
- template int min<int> (int, int);
- */
-
- if (code == TYPE_DECL)
- {
- pph_print_depend_type_type (t);
-
- container = DECL_CONTEXT (t);
- if (!is_namespace (container))
- return HIDDEN;
- type = TREE_TYPE (t);
- defined = COMPLETE_TYPE_P (type);
-
- /* FIXME pph: Why DECL_TEMPLATE_TEMPLATE_PARM_P does not apply
- here? It is a template template parameter, but the tree code
- is inconsistent. */
- if (DECL_TEMPLATE_PARM_P (t)
- || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
- || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
- return HIDDEN;
- if (CLASS_TYPE_P (t))
- {
- tmpl_info = CLASSTYPE_TEMPLATE_INFO (type);
- generic = CLASSTYPE_USE_TEMPLATE (type);
- }
- else
- {
- tmpl_info = NULL;
- generic = 0;
- }
- if (generic == 1)
- return HIDDEN;
- if (tmpl_info != NULL)
- {
- pph_print_depend_template (tmpl_info, t);
- needed = defined && generic == 3;
- }
- else
- {
- needed = false;
- }
- }
- else if (code == VAR_DECL)
- {
- tree enclass = DECL_CONTEXT (t);
- bool in_class = enclass && CLASS_TYPE_P (enclass);
- /* If the VAR_DECL is in a class, it must be a static member. */
- container = enclass;
- if (in_class)
- container = TYPE_CONTEXT (enclass);
-
- pph_print_depend_var_type (t);
-
- if (!is_namespace (container))
- return HIDDEN;
- defined = DECL_INITIAL (t) != NULL /* FIXME pph: DECL_INITIALIZED_P (t) */;
- type = TREE_TYPE (t);
- needed = !((!defined && (in_class || DECL_THIS_EXTERN (t)))
- || DECL_INTEGRAL_CONSTANT_VAR_P (t));
- if (in_class)
- {
- tmpl_info = DECL_TEMPLATE_INFO (t);
- generic = DECL_USE_TEMPLATE (t);
- if (generic == 1)
- return HIDDEN;
- }
- else
- {
- tmpl_info = NULL;
- generic = 0;
- }
- if (tmpl_info != NULL)
- {
- pph_print_depend_template (tmpl_info, t);
- needed = needed && generic == 3;
- }
- }
- else if (code == FUNCTION_DECL)
- {
- if (flag_pph_debug >= 2)
- {
- fprintf (pph_logfile, " depending on function ");
- pph_debug_tree (t, false);
- fprintf (pph_logfile, "\n");
- }
-
- container = DECL_CONTEXT (t);
- if (container && CLASS_TYPE_P (container))
- container = TYPE_CONTEXT (DECL_CONTEXT (t));
-
- pph_print_depend_func_type (t);
-
- if (!is_namespace (container))
- return HIDDEN;
- inlined = DECL_DECLARED_INLINE_P (t);
- defined = DECL_INITIAL (t) != NULL;
- tmpl_info = DECL_TEMPLATE_INFO (t);
- generic = DECL_USE_TEMPLATE (t);
- if (tmpl_info != NULL)
- {
- if (generic == 2)
- needed = defined && !inlined;
- else
- {
- pph_print_depend_template (tmpl_info, t);
- needed = defined && !inlined && generic == 3;
- }
- }
- else
- {
- needed = defined && !inlined;
- }
- }
- else
- {
- gcc_assert (code < MAX_TREE_CODES);
- return HIDDEN;
- }
-
- if (needed)
- return NEEDED;
- else
- return EXPOSED;
-}
-
-static void
-pph_print_dependences (bool user_body, bool used_body,
- tree t, VEC(tree,gc) *deps)
-{
- unsigned j;
- tree d;
- for (j = 0; VEC_iterate (tree, deps, j, d); j++)
- pph_print_dependence (user_body, used_body, t, d);
-}
-
-/* Print the head of declaration T and its dependencies. N_HEAD_TOKENS
- is the number of tokens taken by T's head. N_HEAD_ITOKENS is the
- number of invisible tokens.
-
- HEAD_TOKENS is the array of tokens in the head (note that the
- length of this array may be different than N_HEAD_TOKENS, due to
- adjustments made by the caller).
-
- If CONTAINER is set, then T is a member of it. */
-
-static void
-pph_print_declaration_head (tree t, bool artificial, tree container,
- unsigned n_head_tokens, unsigned n_head_invis,
- VEC(cp_token, heap) *head_tokens)
-{
- VEC(tree,gc) *sym_head_deps, *sym_body_deps;
- enum tree_code code = TREE_CODE (t);
-
- fprintf (pph_logfile, "declaration ");
- pph_debug_tree (t, false);
-
- fprintf (pph_logfile, " htok %u,%u", n_head_tokens, n_head_invis);
-
- /*FIXME pph: We want to get rid of most artificial tokens;
- this is temporary to find them. */
- if (artificial)
- fprintf (pph_logfile, " artificial");
-
- if (container)
- {
- fprintf (pph_logfile, " mbrof ");
- pph_debug_tree (get_type_decl (container), true);
- }
-
- fprintf (pph_logfile, "\n");
-
- /* Template instances should depend on their pattern body. */
- if (artificial)
- {
- if (code == TYPE_DECL)
- {
- tree t_type = TREE_TYPE (t);
- if (CLASS_TYPE_P (t_type))
- {
- tree tmpl_info = CLASSTYPE_TEMPLATE_INFO (t_type);
- if (tmpl_info != NULL)
- pph_print_depend_template (tmpl_info, t);
- }
- }
- else if (code == VAR_DECL || code == FUNCTION_DECL)
- {
- tree tmpl_info;
- tmpl_info = (DECL_LANG_SPECIFIC (t)) ? DECL_TEMPLATE_INFO (t) : NULL;
- if (tmpl_info != NULL)
- pph_print_depend_template (tmpl_info, t);
- }
- }
- else
- {
- /* From the name dependencies, determine symbol dependencies
- by correlating the location of the looked-up symbols with
- the tokens in HEAD_TOKENS and BODY_TOKENS. */
- if (flag_pph_debug >= 2)
- fprintf (pph_logfile, " begin normal dependences\n");
- pph_locate_name_lookups_in (head_tokens, &sym_head_deps, &sym_body_deps);
- pph_print_dependences (false, false, t, sym_head_deps);
- pph_print_dependences (true, false, t, sym_body_deps);
- if (flag_pph_debug >= 2)
- fprintf (pph_logfile, " end normal dependences\n");
- }
-}
-
-
-/* Print the head of declaration T and its dependencies. N_BODY_TOKENS
- is the number of tokens taken by T's head. N_BODY_ITOKENS is the
- number of invisible tokens.
-
- BODY_TOKENS is the array of tokens in the head (note that the
- length of this array may be different than N_BODY_TOKENS, due to
- adjustments made by the caller).
-
- EXPOSURE indicates the exposure of T.
-
- N_SUBTOKENS is the number of tokens that declarations inside T's
- body have used up, those should be subtracted from the total number
- of tokens in T to avoid double counting. */
-
-static void
-pph_print_declaration_body (tree t, bool artificial,
- enum decl_exposure exposure,
- unsigned n_body_tokens, unsigned n_body_invis,
- VEC(cp_token, heap) *body_tokens)
-{
- VEC(tree,gc) *sym_head_deps, *sym_body_deps;
- const char* msg;
-
- fprintf (pph_logfile, "declaration ");
- pph_debug_tree (t, true);
-
- fprintf (pph_logfile, " btok %u,%u", n_body_tokens, n_body_invis);
-
- /* FIXME pph: We want to get rid of most artificial tokens;
- this is temporary to find them. */
- if (artificial)
- msg = "artificial";
- else if (exposure == NEEDED)
- msg = "needed";
- else
- msg = "lazy";
- fprintf (pph_logfile, " %s", msg);
-
- fprintf (pph_logfile, "\n");
-
- pph_print_dependence (true, false, t, t); /* body depends on its head */
-
- if (flag_pph_debug >= 2)
- fprintf (pph_logfile, " begin normal dependences\n");
- pph_locate_name_lookups_in (body_tokens, &sym_head_deps, &sym_body_deps);
- pph_print_dependences (true, false, t, sym_head_deps);
- pph_print_dependences (true, false, t, sym_body_deps);
- if (flag_pph_debug >= 2)
- fprintf (pph_logfile, " end normal dependences\n");
-}
-
-
-/* Compute the implicit cost of a method F. */
-
-static unsigned
-pph_find_special_methods (tree f)
-{
- unsigned found = 0;
- tree o;
- if (TREE_CODE (f) == OVERLOAD)
- {
- for (o = f; o; o = OVL_NEXT (o))
- found |= pph_find_special_methods (OVL_CURRENT (o));
- }
- else if (TREE_CODE (f) == TEMPLATE_DECL)
- found |= pph_find_special_methods (DECL_TEMPLATE_RESULT (f));
- else
- {
- gcc_assert (TREE_CODE (f) == FUNCTION_DECL);
- if (DECL_ARTIFICIAL (f))
- return found;
- if (DECL_CONSTRUCTOR_P (f))
- if (DECL_COPY_CONSTRUCTOR_P (f))
- found |= (1<<2); /* copy constructor */
- else
- found |= (1<<1); /* default constructor */
- else if (DECL_DESTRUCTOR_P (f))
- found |= (1<<0); /* destructor */
- else if (DECL_ASSIGNMENT_OPERATOR_P (f))
- found |= (1<<3); /* copy assign op */
- }
- return found;
-}
-
-/* Compute the implicit cost of a class type T_TYPE. */
-
-static unsigned
-pph_implicit_class_cost (tree t_type)
-{
- VEC(tree,gc) *methods;
- unsigned idx;
- unsigned mbrs;
- unsigned cost = 0;
- unsigned found = 0;
-
- /* Gather general statistics. */
- unsigned fields = fields_length (t_type); /* also direct bases */
- unsigned vptr = (TYPE_POLYMORPHIC_P (t_type) ? 1 : 0);
- unsigned slots = fields + vptr;
- unsigned vbases = VEC_length (tree, CLASSTYPE_VBASECLASSES (t_type));
- unsigned vtables = list_length (CLASSTYPE_VTABLES (t_type));
-
- /* Assign cost of implicit special member variables. */
- /* These costs are somewhat arbitrary. */
- cost += 20 * (CLASSTYPE_TYPEINFO_VAR (t_type) != NULL); /* typeinfo */
- cost += 4 * vbases * vtables; /* virtual tables */
-
- /* Assign cost of implicit special member functions. */
- /* First find them. */
- methods = CLASSTYPE_METHOD_VEC (t_type);
- if (methods != NULL)
- for (idx = 0; idx < VEC_length (tree, methods); idx++)
- {
- tree ovld = VEC_index (tree, methods, idx);
- if (ovld)
- found |= pph_find_special_methods (ovld);
- }
- /* These costs are somewhat arbitrary. */
- /* FIXME pph: These queries seem to not work for templates.
- We can accept the inaccuracy for now. */
- mbrs = slots * 2 + vbases * 4;
- if (!(found & (1<<2))) /* copy constructor */
- {
- if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (t_type))
- cost += 4;
- else
- cost += (8 + 2*mbrs) * (vbases > 0 ? 2 : 1);
- }
- if (!(found & (1<<1))) /* default constructor */
- if (!TYPE_HAS_TRIVIAL_DFLT (t_type))
- cost += 4 + mbrs;
- if (!(found & (1<<0))) /* destructor */
- if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (t_type))
- cost += (8 + 2*mbrs) * (vbases > 0 ? 2 : 1);
- if (!(found & (1<<3))) /* copy assign op */
- {
- if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (t_type))
- cost += 4;
- else
- cost += (8 + 2*mbrs);
- }
-
- return cost;
-}
-
-
-/* Print declaration T with the given EXPOSURE. If T has a body with
- N tokens, subtract N_SUBTOKENS from it before printing them.
- This is used when printing class declarations. The caller first
- prints all the declarations inside the class, followed by the
- class declaration itself, to avoid double counting tokens in the class
- body, they are subtracted from the total count.
-
- PRIMARY is true when T is the very first declaration captured
- during a pph_start_exposed/pph_stop_exposed region. If T is a
- member of a class, and it happens to be the first declaration
- captured, it means that T is an out-of-line definition.
-
- If T is a member of a class, and PARENT is the TYPE_DECL for that
- class, it means that we are printing the in-class declaration of T.
- In that case, when we print the parent, we should subtract the
- tokens attributed to T. So, in these cases return the total
- number of tokens printed in T's head and body. Otherwise,
- return 0. */
-
-static unsigned
-pph_print_declaration (tree t, enum decl_exposure exposure,
- unsigned n_subtokens, bool primary, tree parent)
-{
- tree container = NULL;
- enum tree_code code = TREE_CODE (t);
- bool is_member = false;
- bool artificial = PPH_ARTIFICIAL (t);
- bool print_head = true, print_body = true;
-
- /* The cost of a declaration is proportional to the number of tokens.
- Artificial symbols are not represented in the file, so they do
- not have tokens. We represent their cost as a number of
- invisible tokens. */
- VEC(cp_token, heap) *head_tokens = pph_lookup_head_token_cache_for (t);
- unsigned n_head_tokens = VEC_length (cp_token, head_tokens);
- unsigned n_head_invis = 0;
- VEC(cp_token, heap) *body_tokens = pph_lookup_body_token_cache_for (t);
- unsigned n_body_tokens = VEC_length (cp_token, body_tokens);
- unsigned n_body_invis = 0;
- unsigned n_member_tokens = 0;
-
- /* If this is a member of a class, count the number of tokens in the
- member that overlap with the containing class. */
- if (code == FUNCTION_DECL || code == VAR_DECL)
- {
- container = DECL_CONTEXT (t);
- if (container && CLASS_TYPE_P (container))
- {
- is_member = true;
- if (parent && container == TREE_TYPE (parent))
- n_member_tokens = n_head_tokens + n_body_tokens;
- }
- }
-
- /* Now we need to adjust costs, and head/body printing. */
-
- if (code == VAR_DECL)
- {
- if (artificial)
- /* Artificial static member variables get their token
- counts from the calling expression, which isn't helpful.
- Build the cost into the class instead. All of which
- means suppress this decl. */
- return 0;
-
- if (DECL_NONTRIVIALLY_INITIALIZED_P (t)
- && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t))
- n_body_invis += 10;
-
- if (is_member)
- {
- if (primary) /* Must be an out-of-line declaration/definition. */
- {
- /* Merge out-of-line member definitions into the body.
- This merge prevents two heads for the same symbol. */
- n_body_tokens += n_head_tokens;
- n_body_invis += n_head_invis;
- n_head_tokens = 0;
- n_head_invis = 0;
- print_head = false;
- /* Out-of-line member variable declarations are definitions,
- and hence need to be generated. */
- exposure = NEEDED;
- }
- else /* Not primary; must be an in-line declaration/definition. */
- {
- /* The only var bodies in the class are manifest constants;
- merge them into the head. */
- n_head_tokens += n_body_tokens;
- n_head_invis += n_body_invis;
- n_body_tokens = 0;
- n_body_invis = 0;
- print_body = false;
- }
- }
- else /* not is_member */
- {
- if (exposure == EXPOSED)
- {
- /* Merge manifest constants into the head.
- This code sweeps up extern declarations with no bodies,
- but that's okay. */
- n_head_tokens += n_body_tokens;
- n_head_invis += n_body_invis;
- n_body_tokens = 0;
- n_body_invis = 0;
- print_body = false;
- }
- }
- if (exposure == NEEDED)
- n_body_invis += 4; /* For emitting the actual variable declaration. */
- }
- else if (code == FUNCTION_DECL)
- {
- /* Pure function declarations get no body. */
- if (exposure == EXPOSED && !artificial
- && n_body_tokens == 0 && n_body_invis == 0)
- print_body = false;
- if (artificial)
- {
- if (is_member)
- {
- /* Artificial special member functions get their token
- counts from the calling expression, which isn't helpful.
- Build the cost into the class instead. All of which
- means suppress this decl. */
- return 0;
- }
- }
- }
- else if (code == TYPE_DECL)
- {
- tree t_type = TREE_TYPE (t);
-
- if (artificial)
- return 0;
-
- if (DECL_IMPLICIT_TYPEDEF_P (t)
- && CLASS_TYPE_P (t_type)
- && TYPE_LANG_SPECIFIC (t_type))
- {
- tree tmpl_info;
- int generic;
-
- n_body_invis += pph_implicit_class_cost (t_type);
-
- tmpl_info = CLASSTYPE_TEMPLATE_INFO (t_type);
- if (tmpl_info)
- {
- generic = CLASSTYPE_USE_TEMPLATE (t_type);
- if (generic == 1)
- {
- /* Implicit instantiations have no visibile tokens. */
- n_head_invis += n_head_tokens;
- n_head_tokens = 0;
- n_body_invis += n_body_tokens;
- n_body_tokens = 0;
- }
- else if (generic == 3)
- {
- /* Explicit instantiations have no bodies,
- but they are work. This approximation is
- unjustified, but we are presuming that explicit
- instantiations are rare in application code. */
- n_body_invis += 15;
- exposure = NEEDED;
- }
- if (generic != 2)
- {
- bool defined;
- defined = CLASS_TYPE_P (t_type) && COMPLETE_TYPE_P (t_type);
- if (defined)
- pph_print_depend_template (tmpl_info, t);
- }
- }
- else if (primary)
- {
- /* Now subtract the sum of members from the body of the class.
- This prevents double counting when emitting the parent.
- For non-primary class symbols, this value will be zero. */
- gcc_assert (n_body_tokens >= n_subtokens);
- n_body_tokens -= n_subtokens;
- }
- }
- else if (TREE_CODE (t_type) == ENUMERAL_TYPE)
- {
- /* No additional work for enum. */
- }
- else
- {
- /* Not artificial, not a C++ class, not an enum;
- so must be a pure typedef. They have no body. */
- gcc_assert (n_body_tokens == 0 && n_body_invis == 0);
- print_body = false;
- }
- }
-
- if (print_head)
- pph_print_declaration_head (t, artificial, (is_member) ? container : NULL,
- n_head_tokens, n_head_invis, head_tokens);
-
- if (print_body)
- pph_print_declaration_body (t, artificial, exposure,
- n_body_tokens, n_body_invis, body_tokens);
-
- if (flag_pph_debug >= 4)
- {
- fprintf (pph_logfile, " Declarator head tokens: ");
- cp_lexer_debug_tokens ((VEC(cp_token, gc) *)head_tokens);
- fprintf (pph_logfile, " Declarator body tokens: ");
- cp_lexer_debug_tokens ((VEC(cp_token, gc) *)body_tokens);
- fprintf (pph_logfile, "\n");
- }
-
- return n_member_tokens;
-}
-
-static void
-pph_print_declarations (VEC(tree,heap) *v)
-{
- unsigned i, j, n, first_ix;
- tree t, first, parent;
- enum decl_exposure exposure;
- unsigned n_subtokens = 0;
-
- if (VEC_empty (tree, v))
- return;
-
- /* If the first AST in V is a class/structure declaration, process
- the sub-declarations first. This will accumulate the tokens in
- the sub-declarations, so that when we print the class itself
- we don't double count the tokens in its body. */
-
- /* Skip over un-exposed declarations, like template parameters. */
- n = VEC_length (tree, v);
- for ( i = 0; VEC_iterate (tree, v, i, t); i++)
- {
- exposure = pph_get_decl_exposure (t);
- if (exposure >= EXPOSED)
- break;
- }
- if (i >= n)
- return; /* No exposed decls. */
-
- first = VEC_index (tree, v, i);
- if (VEC_length (tree, v) > i+1
- && TREE_CODE (first) == TYPE_DECL
- && CLASS_TYPE_P (TREE_TYPE (first)))
- {
- parent = first;
- first_ix = i+1;
- }
- else
- {
- parent = NULL;
- first_ix = i;
- }
-
- for (j = first_ix; VEC_iterate (tree, v, j, t); j++)
- {
- exposure = pph_get_decl_exposure (t);
- if (exposure >= EXPOSED)
- n_subtokens += pph_print_declaration (t, exposure, 0U, i == j, parent);
- }
-
- /* If we didn't print the first declaration, print it now. */
- if (first_ix > i)
- {
- exposure = pph_get_decl_exposure (first);
- if (exposure >= EXPOSED)
- pph_print_declaration (first, exposure, n_subtokens, true, NULL);
- }
-}
-
-static void
-pph_print_trees_tokens (VEC(tree,heap) *v, cp_token *tok1, cp_token *tok2)
-{
- VEC(cp_token, heap) *vtok;
-
- vtok = pph_print_copy_tokens (tok1, tok2);
- if (vtok == NULL)
- return;
-
- pph_print_token_range (v, vtok);
- pph_print_declarations (v);
- fprintf (pph_logfile, "\n");
-}
-
-
-/* Intercept the result of a name lookup operation requested by the
- parser while we are intercepting AST creation. T is the result
- of a name lookup done by the parser. If this is the first time
- we see it, store it in pph_name_lookups. */
-
-void
-pph_catch_name_lookup (tree t)
-{
- if (t == NULL_TREE || t == error_mark_node || pph_tree_catcher == NULL)
- return;
-
- timevar_push (TV_PPH_MANAGE);
-
- PPH_STATS_INCR (name_lookups, 1);
-
- if (the_parser->lexer)
- {
- /* If we are parsing, we are stopped one token past the identifier
- that we have just looked up. Store the token where we have seen
- this identifier so that we can determine whether the identifier
- was accessed in a head or a body.
-
- Note that we do this for every instance we find for T, so that
- we can store all the locations where T was accessed from. */
- VEC(cp_token, heap) *tokens;
- cp_token *tok;
- void **slot;
-
- slot = pointer_map_insert (pph_nl_token_map, t);
- tokens = (VEC(cp_token, heap) *) *slot;
- tok = the_parser->lexer->next_token - 1;
- VEC_safe_push (cp_token, heap, tokens, tok);
- *slot = tokens;
- }
-
- /* Make sure we do not store the same decl more than once. */
- if (pointer_set_insert (pph_name_lookups_set, t))
- {
- timevar_pop (TV_PPH_MANAGE);
- return;
- }
+GTY(()) cp_parser *the_parser;
- VEC_safe_push (tree, heap, pph_name_lookups, t);
- timevar_pop (TV_PPH_MANAGE);
-}
/* Special handling for the first token or line in the file. The first
thing in the file might be #pragma GCC pch_preprocess, which loads a
@@ -29409,58 +24770,6 @@ pragma_lex (tree *value)
return ret;
}
-
-/* Print statistics for the PPH cache. */
-
-static void
-pph_print_stats (void)
-{
- fprintf (stderr, "\nPPH cache statistics\n");
- fprintf (stderr, "Number of tokens in the lexer: %lu\n",
- pph_stats.lexed_tokens);
- fprintf (stderr, "Number of tokens consumed by the parser: %lu\n",
- pph_stats.parsed_tokens);
- fprintf (stderr, "Number of declarations cached in: %lu\n",
- pph_stats.cached_decls);
- fprintf (stderr, "Number of declarations restored: %lu\n",
- pph_stats.restored_decls);
- fprintf (stderr, "Number of cached decl references: %lu\n",
- pph_stats.cached_refs);
- fprintf (stderr, "Number of name lookups: %lu\n",
- pph_stats.name_lookups);
- fprintf (stderr, "Number of bad lookups: %lu\n",
- pph_stats.bad_lookups);
-}
-
-
-/* Initialize PPH support. */
-
-static void
-pph_init (void)
-{
- if (flag_pph_logfile)
- {
- pph_logfile = fopen (flag_pph_logfile, "w");
- if (!pph_logfile)
- fatal_error ("Cannot create %s for writing: %m", flag_pph_logfile);
- }
- else
- pph_logfile = stdout;
-}
-
-
-/* Finalize PPH support. */
-
-static void
-pph_finish (void)
-{
- if (flag_pph_stats)
- pph_print_stats ();
-
- if (flag_pph_logfile)
- fclose (pph_logfile);
-}
-
/* External interface. */
===================================================================
@@ -0,0 +1,375 @@
+/* Data structures and function exported by the C++ Parser.
+ 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/>. */
+
+#ifndef GCC_CP_PARSER_H
+#define GCC_CP_PARSER_H
+
+#include "tree.h"
+#include "c-family/c-pragma.h"
+
+/* A token type for keywords, as opposed to ordinary identifiers. */
+#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
+
+/* A token type for template-ids. If a template-id is processed while
+ parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
+ the value of the CPP_TEMPLATE_ID is whatever was returned by
+ cp_parser_template_id. */
+#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
+
+/* A token type for nested-name-specifiers. If a
+ nested-name-specifier is processed while parsing tentatively, it is
+ replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
+ CPP_NESTED_NAME_SPECIFIER is whatever was returned by
+ cp_parser_nested_name_specifier_opt. */
+#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
+
+/* The number of token types, including C++-specific ones. */
+#define N_CP_TTYPES ((int) (CPP_NESTED_NAME_SPECIFIER + 1))
+
+/* A token's value and its associated deferred access checks and
+ qualifying scope. */
+
+struct GTY(()) tree_check {
+ /* The value associated with the token. */
+ tree value;
+ /* The checks that have been associated with value. */
+ VEC (deferred_access_check, gc)* checks;
+ /* The token's qualifying scope (used when it is a
+ CPP_NESTED_NAME_SPECIFIER). */
+ tree qualifying_scope;
+};
+
+/* A C++ token. */
+
+typedef struct GTY (()) cp_token {
+ /* The kind of token. */
+ ENUM_BITFIELD (cpp_ttype) type : 8;
+ /* If this token is a keyword, this value indicates which keyword.
+ Otherwise, this value is RID_MAX. */
+ ENUM_BITFIELD (rid) keyword : 8;
+ /* Token flags. */
+ unsigned char flags;
+ /* Identifier for the pragma. */
+ ENUM_BITFIELD (pragma_kind) pragma_kind : 6;
+ /* True if this token is from a context where it is implicitly extern "C" */
+ BOOL_BITFIELD implicit_extern_c : 1;
+ /* True for a CPP_NAME token that is not a keyword (i.e., for which
+ KEYWORD is RID_MAX) iff this name was looked up and found to be
+ ambiguous. An error has already been reported. */
+ BOOL_BITFIELD ambiguous_p : 1;
+ /* True for a token that has been purged. If a token is purged,
+ it is no longer a valid token and it should be considered
+ deleted. */
+ BOOL_BITFIELD purged_p : 1;
+ /* The location at which this token was found. */
+ location_t location;
+ /* The value associated with this token, if any. */
+ union cp_token_value {
+ /* Used for CPP_NESTED_NAME_SPECIFIER and CPP_TEMPLATE_ID. */
+ struct tree_check* GTY((tag ("1"))) tree_check_value;
+ /* Use for all other tokens. */
+ tree GTY((tag ("0"))) value;
+ } GTY((desc ("(%1.type == CPP_TEMPLATE_ID) || (%1.type == CPP_NESTED_NAME_SPECIFIER)"))) u;
+} cp_token;
+
+DEF_VEC_O (cp_token);
+DEF_VEC_ALLOC_O (cp_token,gc);
+DEF_VEC_ALLOC_O (cp_token,heap);
+
+/* We use a stack of token pointer for saving token sets. */
+typedef struct cp_token *cp_token_position;
+DEF_VEC_P (cp_token_position);
+DEF_VEC_ALLOC_P (cp_token_position,heap);
+
+/* The cp_lexer structure represents the C++ lexer. It is responsible
+ for managing the token stream from the preprocessor and supplying
+ it to the parser. Tokens are never added to the cp_lexer after
+ it is created. */
+
+typedef struct GTY (()) cp_lexer {
+ /* The memory allocated for the buffer. NULL if this lexer does not
+ own the token buffer. */
+ VEC(cp_token,gc) *buffer;
+
+ /* A pointer just past the last available token. The tokens
+ in this lexer are [buffer, last_token). */
+ cp_token_position GTY ((skip)) last_token;
+
+ /* The next available token. If NEXT_TOKEN is &eof_token, then there are
+ no more available tokens. */
+ cp_token_position GTY ((skip)) next_token;
+
+ /* A stack indicating positions at which cp_lexer_save_tokens was
+ called. The top entry is the most recent position at which we
+ began saving tokens. If the stack is non-empty, we are saving
+ tokens. */
+ VEC(cp_token_position,heap) *GTY ((skip)) saved_tokens;
+
+ /* The next lexer in a linked list of lexers. */
+ struct cp_lexer *next;
+
+ /* True if we should output debugging information. */
+ bool debugging_p;
+
+ /* True if we're in the context of parsing a pragma, and should not
+ increment past the end-of-line marker. */
+ bool in_pragma;
+} cp_lexer;
+
+DEF_VEC_O (cp_lexer);
+DEF_VEC_ALLOC_O (cp_lexer,heap);
+
+/* cp_token_cache is a range of tokens. There is no need to represent
+ allocate heap memory for it, since tokens are never removed from the
+ lexer's array. There is also no need for the GC to walk through
+ a cp_token_cache, since everything in here is referenced through
+ a lexer. */
+
+typedef struct GTY(()) cp_token_cache {
+ /* The beginning of the token range. */
+ cp_token * GTY((skip)) first;
+
+ /* Points immediately after the last token in the range. */
+ cp_token * GTY ((skip)) last;
+} cp_token_cache;
+
+typedef cp_token_cache *cp_token_cache_ptr;
+DEF_VEC_P (cp_token_cache_ptr);
+DEF_VEC_ALLOC_P (cp_token_cache_ptr,gc);
+
+struct cp_token_ident_d
+{
+ unsigned int ident_len;
+ const char *ident_str;
+ unsigned int before_len;
+ const char *before_str;
+ unsigned int after_len;
+ const char *after_str;
+};
+
+typedef struct cp_token_ident_d cp_token_ident;
+
+/* An entry in a queue of function arguments that require post-processing. */
+
+typedef struct GTY(()) cp_default_arg_entry_d {
+ /* The current_class_type when we parsed this arg. */
+ tree class_type;
+
+ /* The function decl itself. */
+ tree decl;
+} cp_default_arg_entry;
+
+DEF_VEC_O(cp_default_arg_entry);
+DEF_VEC_ALLOC_O(cp_default_arg_entry,gc);
+
+/* An entry in a stack for member functions of local classes. */
+
+typedef struct GTY(()) cp_unparsed_functions_entry_d {
+ /* Functions with default arguments that require post-processing.
+ Functions appear in this list in declaration order. */
+ VEC(cp_default_arg_entry,gc) *funs_with_default_args;
+
+ /* Functions with defintions that require post-processing. Functions
+ appear in this list in declaration order. */
+ VEC(tree,gc) *funs_with_definitions;
+} cp_unparsed_functions_entry;
+
+DEF_VEC_O(cp_unparsed_functions_entry);
+DEF_VEC_ALLOC_O(cp_unparsed_functions_entry,gc);
+
+/* The status of a tentative parse. */
+
+typedef enum cp_parser_status_kind
+{
+ /* No errors have occurred. */
+ CP_PARSER_STATUS_KIND_NO_ERROR,
+ /* An error has occurred. */
+ CP_PARSER_STATUS_KIND_ERROR,
+ /* We are committed to this tentative parse, whether or not an error
+ has occurred. */
+ CP_PARSER_STATUS_KIND_COMMITTED
+} cp_parser_status_kind;
+
+
+/* Context that is saved and restored when parsing tentatively. */
+typedef struct GTY (()) cp_parser_context {
+ /* If this is a tentative parsing context, the status of the
+ tentative parse. */
+ enum cp_parser_status_kind status;
+ /* If non-NULL, we have just seen a `x->' or `x.' expression. Names
+ that are looked up in this context must be looked up both in the
+ scope given by OBJECT_TYPE (the type of `x' or `*x') and also in
+ the context of the containing expression. */
+ tree object_type;
+
+ /* The next parsing context in the stack. */
+ struct cp_parser_context *next;
+} cp_parser_context;
+
+
+/* The cp_parser structure represents the C++ parser. */
+
+typedef struct GTY(()) cp_parser {
+ /* The lexer from which we are obtaining tokens. */
+ cp_lexer *lexer;
+
+ /* The scope in which names should be looked up. If NULL_TREE, then
+ we look up names in the scope that is currently open in the
+ source program. If non-NULL, this is either a TYPE or
+ NAMESPACE_DECL for the scope in which we should look. It can
+ also be ERROR_MARK, when we've parsed a bogus scope.
+
+ This value is not cleared automatically after a name is looked
+ up, so we must be careful to clear it before starting a new look
+ up sequence. (If it is not cleared, then `X::Y' followed by `Z'
+ will look up `Z' in the scope of `X', rather than the current
+ scope.) Unfortunately, it is difficult to tell when name lookup
+ is complete, because we sometimes peek at a token, look it up,
+ and then decide not to consume it. */
+ tree scope;
+
+ /* OBJECT_SCOPE and QUALIFYING_SCOPE give the scopes in which the
+ last lookup took place. OBJECT_SCOPE is used if an expression
+ like "x->y" or "x.y" was used; it gives the type of "*x" or "x",
+ respectively. QUALIFYING_SCOPE is used for an expression of the
+ form "X::Y"; it refers to X. */
+ tree object_scope;
+ tree qualifying_scope;
+
+ /* A stack of parsing contexts. All but the bottom entry on the
+ stack will be tentative contexts.
+
+ We parse tentatively in order to determine which construct is in
+ use in some situations. For example, in order to determine
+ whether a statement is an expression-statement or a
+ declaration-statement we parse it tentatively as a
+ declaration-statement. If that fails, we then reparse the same
+ token stream as an expression-statement. */
+ cp_parser_context *context;
+
+ /* True if we are parsing GNU C++. If this flag is not set, then
+ GNU extensions are not recognized. */
+ bool allow_gnu_extensions_p;
+
+ /* TRUE if the `>' token should be interpreted as the greater-than
+ operator. FALSE if it is the end of a template-id or
+ template-parameter-list. In C++0x mode, this flag also applies to
+ `>>' tokens, which are viewed as two consecutive `>' tokens when
+ this flag is FALSE. */
+ bool greater_than_is_operator_p;
+
+ /* TRUE if default arguments are allowed within a parameter list
+ that starts at this point. FALSE if only a gnu extension makes
+ them permissible. */
+ bool default_arg_ok_p;
+
+ /* TRUE if we are parsing an integral constant-expression. See
+ [expr.const] for a precise definition. */
+ bool integral_constant_expression_p;
+
+ /* TRUE if we are parsing an integral constant-expression -- but a
+ non-constant expression should be permitted as well. This flag
+ is used when parsing an array bound so that GNU variable-length
+ arrays are tolerated. */
+ bool allow_non_integral_constant_expression_p;
+
+ /* TRUE if ALLOW_NON_CONSTANT_EXPRESSION_P is TRUE and something has
+ been seen that makes the expression non-constant. */
+ bool non_integral_constant_expression_p;
+
+ /* TRUE if local variable names and `this' are forbidden in the
+ current context. */
+ bool local_variables_forbidden_p;
+
+ /* TRUE if the declaration we are parsing is part of a
+ linkage-specification of the form `extern string-literal
+ declaration'. */
+ bool in_unbraced_linkage_specification_p;
+
+ /* TRUE if we are presently parsing a declarator, after the
+ direct-declarator. */
+ bool in_declarator_p;
+
+ /* TRUE if we are presently parsing a template-argument-list. */
+ bool in_template_argument_list_p;
+
+ /* Set to IN_ITERATION_STMT if parsing an iteration-statement,
+ to IN_OMP_BLOCK if parsing OpenMP structured block and
+ IN_OMP_FOR if parsing OpenMP loop. If parsing a switch statement,
+ this is bitwise ORed with IN_SWITCH_STMT, unless parsing an
+ iteration-statement, OpenMP block or loop within that switch. */
+#define IN_SWITCH_STMT 1
+#define IN_ITERATION_STMT 2
+#define IN_OMP_BLOCK 4
+#define IN_OMP_FOR 8
+#define IN_IF_STMT 16
+ unsigned char in_statement;
+
+ /* TRUE if we are presently parsing the body of a switch statement.
+ Note that this doesn't quite overlap with in_statement above.
+ The difference relates to giving the right sets of error messages:
+ "case not in switch" vs "break statement used with OpenMP...". */
+ bool in_switch_statement_p;
+
+ /* TRUE if we are parsing a type-id in an expression context. In
+ such a situation, both "type (expr)" and "type (type)" are valid
+ alternatives. */
+ bool in_type_id_in_expr_p;
+
+ /* TRUE if we are currently in a header file where declarations are
+ implicitly extern "C". */
+ bool implicit_extern_c;
+
+ /* TRUE if strings in expressions should be translated to the execution
+ character set. */
+ bool translate_strings_p;
+
+ /* TRUE if we are presently parsing the body of a function, but not
+ a local class. */
+ bool in_function_body;
+
+ /* If non-NULL, then we are parsing a construct where new type
+ definitions are not permitted. The string stored here will be
+ issued as an error message if a type is defined. */
+ const char *type_definition_forbidden_message;
+
+ /* A stack used for member functions of local classes. The lists
+ contained in an individual entry can only be processed once the
+ outermost class being defined is complete. */
+ VEC(cp_unparsed_functions_entry,gc) *unparsed_queues;
+
+ /* The number of classes whose definitions are currently in
+ progress. */
+ unsigned num_classes_being_defined;
+
+ /* The number of template parameter lists that apply directly to the
+ current declaration. */
+ unsigned num_template_parameter_lists;
+} cp_parser;
+
+/* In parser.c */
+extern cp_token eof_token;
+extern GTY(()) cp_parser *the_parser;
+
+extern void cp_lexer_dump_tokens (FILE *, VEC(cp_token,gc) *, unsigned);
+extern void cp_lexer_get_tokens (cp_lexer *);
+extern cp_token_position cp_lexer_token_position (cp_lexer *, bool);
+extern void cp_lexer_debug_tokens (VEC(cp_token,gc) *);
+
+#endif /* GCC_CP_PARSER_H */
===================================================================
@@ -30,4 +30,4 @@ compilers="cc1plus\$(exeext)"
target_libs="target-libstdc++-v3"
-gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c"
+gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/pph.h \$(srcdir)/cp/pph.c"
===================================================================
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.
#include "target.h"
#include "convert.h"
#include "langhooks.h"
+#include "pph.h"
/* The various kinds of conversion. */
===================================================================
@@ -5632,18 +5632,6 @@ extern tree cxx_omp_clause_dtor (tree,
extern void cxx_omp_finish_clause (tree);
extern bool cxx_omp_privatize_by_reference (const_tree);
-/* In parser.c */
-
-#define PPH_POP_TIMEVAR_AND_RETURN(TV, T) \
- do { \
- pph_catch_name_lookup (T); \
- POP_TIMEVAR_AND_RETURN(TV, T); \
- } while (0)
-
-extern void pph_catch_tree (tree);
-extern void pph_uncatch_tree (tree);
-extern void pph_catch_name_lookup (tree);
-
/* -- end of C++ */
#endif /* ! GCC_CP_TREE_H */
===================================================================
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.
#include "debug.h"
#include "c-family/c-pragma.h"
#include "tree-pretty-print.h"
+#include "pph.h"
/* The bindings for a particular name in a particular scope. */