@@ -1,3 +1,23 @@
+2012-01-18 Diego Novillo <dnovillo@google.com>
+
+ * pph-core.c (pph_include_handler): If the primary file
+ uses #include_next, emit a warning and call
+ pph_disable_output.
+ (pph_stream_close_1): Factor out of ...
+ (pph_stream_close): ... here.
+ (pph_stream_close_no_flush): New.
+ (pph_streamer_finish): Call pph_writer_finish if
+ pph_writer_enabled_p returns true.
+ Call pph_reader_finish if pph_reader_enabled_p returns
+ true.
+ * pph-in.c (pph_in_include): Assert that we are not
+ trying to read STREAM from STREAM.
+ * pph-out.c (pph_out_line_table_and_includes): Do not
+ emit a line table reference to STREAM.
+ (pph_disable_output): New.
+ * pph-streamer.h (pph_stream_close_no_flush): Declare.
+ (pph_disable_output): Declare.
+
2012-01-17 Lawrence Crowl <crowl@google.com>
* pph.h (pph_files_read): New.
@@ -669,6 +669,21 @@ pph_include_handler (cpp_reader *reader,
fprintf (pph_logfile, "%c\n", angle_brackets ? '>' : '"');
}
+ /* If we find a #include_next directive in the primary file,
+ refuse to generate a PPH image for it. #include_next cannot
+ be resolved from the primary source file, so generating an
+ image for it would cause an infinite self-referential loop
+ in the line table. */
+ if (cpp_in_primary_file (reader)
+ && strcmp ((const char *)dname, "include_next") == 0)
+ {
+ warning_at (loc, OPT_Winvalid_pph, "#include_next found in the "
+ "primary source file. PPH generation disabled for %s",
+ LOCATION_FILE (loc));
+ pph_disable_output ();
+ return true;
+ }
+
read_text_file_p = true;
pph_file = query_pph_include_map (name);
if (pph_file != NULL
@@ -1026,10 +1041,15 @@ pph_stream_open (const char *name, const char *mode)
}
-/* Close PPH stream STREAM. */
+/* Close PPH stream STREAM. If FLUSH_P is true and STREAM was being
+ written to, then STREAM's encoding buffers are flushed before
+ closing it. Otherwise, STREAM is closed without flushing internal
+ buffers and its associated file is removed. This is used when an
+ exceptional condition occurs that prevents us from generating a PPH
+ image. */
-void
-pph_stream_close (pph_stream *stream)
+static void
+pph_stream_close_1 (pph_stream *stream, bool flush_p)
{
/* STREAM can be NULL if it could not be properly opened. An error
has already been emitted, so avoid crashing here. */
@@ -1039,13 +1059,23 @@ pph_stream_close (pph_stream *stream)
if (flag_pph_tracer >= 1)
fprintf (pph_logfile, "PPH: Closing %s\n", stream->name);
- /* If we were writing to STREAM, flush all the memory buffers. This
- does the actual writing of all the pickled data structures. */
- if (stream->write_p)
+ /* If we were writing to STREAM and the caller tells us to, flush
+ all the memory buffers. This does the actual writing of all the
+ pickled data structures. */
+ if (stream->write_p && flush_p)
pph_flush_buffers (stream);
fclose (stream->file);
+ /* If we were writing but the caller did not want STREAM's buffers
+ flushed, remove the PPH file. */
+ if (stream->write_p && !flush_p)
+ {
+ if (flag_pph_tracer >= 1)
+ fprintf (pph_logfile, "PPH: Removing %s", stream->name);
+ unlink (stream->name);
+ }
+
/* Deallocate all memory used. */
stream->file = NULL;
VEC_free (pph_cache_entry, heap, stream->cache.v);
@@ -1078,6 +1108,25 @@ pph_stream_close (pph_stream *stream)
}
+/* Close PPH stream STREAM. If STREAM was being written to, flush its
+ encoding buffers. */
+
+void
+pph_stream_close (pph_stream *stream)
+{
+ pph_stream_close_1 (stream, true);
+}
+
+
+/* Close PPH stream STREAM. If STREAM was being written to, do not
+ flush its encoding buffers and remove the associated file. */
+
+void
+pph_stream_close_no_flush (pph_stream *stream)
+{
+ pph_stream_close_1 (stream, false);
+}
+
/********************************************************** stream callbacks */
@@ -1232,10 +1281,12 @@ pph_streamer_finish (void)
pph_stream *image;
/* Finalize the writer. */
- pph_writer_finish ();
+ if (pph_writer_enabled_p ())
+ pph_writer_finish ();
/* Finalize the reader. */
- pph_reader_finish ();
+ if (pph_reader_enabled_p ())
+ pph_reader_finish ();
/* Close any images read during parsing. */
FOR_EACH_VEC_ELT (pph_stream_ptr, pph_stream_registry.v, i, image)
@@ -327,6 +327,9 @@ pph_in_include (pph_stream *stream)
old_loc_offset = pph_loc_offset;
include_name = pph_in_string (stream);
+
+ /* We should not be trying to include STREAM again. */
+ gcc_assert (strcmp (include_name, stream->name) != 0);
include_stream = pph_read_file (include_name);
/* Add INCLUDE_STREAM, and the images included by it, to the list
@@ -343,12 +343,15 @@ pph_out_line_table_and_includes (pph_stream *stream)
/* If LM is an entry for an included PPH image, output a line table
reference to it, so the reader can load the included image at
- this point. */
+ this point. Make sure we do not emit self-referential
+ entries (even if a file is properly guarded against double
+ inclusion, there will be linemap entries in the line table
+ for it). */
current_include = (lm->reason == LC_ENTER
&& ix > PPH_NUM_IGNORED_LINE_TABLE_ENTRIES)
? pph_stream_registry_lookup (LINEMAP_FILE (lm))
: NULL;
- if (current_include)
+ if (current_include && current_include != stream)
{
struct line_map *included_from;
@@ -2794,3 +2797,20 @@ pph_writer_add_include (pph_stream *include)
{
pph_add_include (pph_out_stream, include);
}
+
+
+/* Disable PPH generation. Used when we discover that the file that we
+ are currently converting into PPH is not compatible. This does not
+ necessarily stop compilation, so make sure that the PPH file is
+ not generated. */
+
+void
+pph_disable_output (void)
+{
+ /* If we are not generating a PPH image, do nothing. */
+ if (!pph_out_stream)
+ return;
+
+ pph_stream_close_no_flush (pph_out_stream);
+ pph_out_file = NULL;
+}
@@ -254,6 +254,7 @@ pph_stream *pph_stream_registry_lookup (const char *);
void pph_stream_set_header_name (pph_stream *, const char *);
pph_stream *pph_stream_open (const char *, const char *);
void pph_stream_close (pph_stream *);
+void pph_stream_close_no_flush (pph_stream *);
void pph_add_include (pph_stream *, pph_stream *);
void pph_trace_marker (enum pph_record_marker marker, enum pph_tag tag);
void pph_trace_tree (tree, enum pph_trace_end, enum pph_trace_kind);
@@ -277,6 +278,7 @@ void pph_writer_init (void);
void pph_writer_finish (void);
void pph_out_location (pph_stream *, location_t);
void pph_out_tree (pph_stream *, tree);
+void pph_disable_output (void);
/* In pph-in.c. */
void pph_init_read (pph_stream *);
@@ -1,3 +1,7 @@
+2012-01-18 Diego Novillo <dnovillo@google.com>
+
+ * g++.dg/pph/d0include-next.h: New.
+
2011-01-17 Lawrence Crowl <crowl@google.com>
* g++.dg/pph/x6dynarray3.cc: Add expected overload failures.
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-options "-Winvalid-pph" } */
+/* We do not support #include_next in PPH images. */
+#ifndef D0INCLUDE_NEXT_H
+#define D0INCLUDE_NEXT_H
+#include_next "d0include-next.h" { dg-warning ".*PPH generation disabled" }
+#endif
@@ -1,3 +1,9 @@
+2012-01-18 Diego Novillo <dnovillo@google.com>
+
+ * internal.h (cpp_in_primary_file): Move ...
+ * files.c (cpp_in_primary_file): ... here.
+ * include/cpplib.h (cpp_in_primary_file): Declare.
+
2011-11-22 Diego Novillo <dnovillo@google.com>
* include/line-map.h (linemap_dump): Declare.
@@ -1936,3 +1936,12 @@ cpp_return_at_eof (cpp_buffer *buffer, bool val)
{
buffer->return_at_eof = val;
}
+
+
+/* Return true if PFILE is currently reading the primary file. */
+
+bool
+cpp_in_primary_file (cpp_reader *pfile)
+{
+ return pfile->line_table->depth == 1;
+}
@@ -1070,6 +1070,7 @@ extern void cpp_return_at_eof (cpp_buffer *, bool);
/* Return the path name of the main file iff it does not have a
multiple include guard. */
extern const char *cpp_main_missing_guard (cpp_reader *pfile);
+extern bool cpp_in_primary_file (cpp_reader *);
/* In pch.c */
struct save_macro_data;
@@ -646,13 +646,6 @@ cpp_in_system_header (cpp_reader *pfile)
#define CPP_PEDANTIC(PF) CPP_OPTION (PF, cpp_pedantic)
#define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, cpp_warn_traditional)
-static inline int cpp_in_primary_file (cpp_reader *);
-static inline int
-cpp_in_primary_file (cpp_reader *pfile)
-{
- return pfile->line_table->depth == 1;
-}
-
/* In macro.c */
extern void _cpp_free_definition (cpp_hashnode *);
extern bool _cpp_create_definition (cpp_reader *, cpp_hashnode *);