diff --git a/gcc/cp/ChangeLog.pph b/gcc/cp/ChangeLog.pph
index 39ac194..47d9bc04 100644
--- a/gcc/cp/ChangeLog.pph
+++ b/gcc/cp/ChangeLog.pph
@@ -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.
diff --git a/gcc/cp/pph-core.c b/gcc/cp/pph-core.c
index f470cfc..e7cf444 100644
--- a/gcc/cp/pph-core.c
+++ b/gcc/cp/pph-core.c
@@ -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)
diff --git a/gcc/cp/pph-in.c b/gcc/cp/pph-in.c
index aa82e3a..2dbad83 100644
--- a/gcc/cp/pph-in.c
+++ b/gcc/cp/pph-in.c
@@ -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
diff --git a/gcc/cp/pph-out.c b/gcc/cp/pph-out.c
index f60438d..e80ad7b 100644
--- a/gcc/cp/pph-out.c
+++ b/gcc/cp/pph-out.c
@@ -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;
+}
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index 21b1c24..b641776 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -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 *);
diff --git a/gcc/testsuite/ChangeLog.pph b/gcc/testsuite/ChangeLog.pph
index 282f4d7..f7e3bdf 100644
--- a/gcc/testsuite/ChangeLog.pph
+++ b/gcc/testsuite/ChangeLog.pph
@@ -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.
diff --git a/gcc/testsuite/g++.dg/pph/d0include-next.h b/gcc/testsuite/g++.dg/pph/d0include-next.h
new file mode 100644
index 0000000..e4e9366
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pph/d0include-next.h
@@ -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
diff --git a/libcpp/ChangeLog.pph b/libcpp/ChangeLog.pph
index f876c8f..a74344f 100644
--- a/libcpp/ChangeLog.pph
+++ b/libcpp/ChangeLog.pph
@@ -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.
diff --git a/libcpp/files.c b/libcpp/files.c
index 5e9f3ea..74c2783 100644
--- a/libcpp/files.c
+++ b/libcpp/files.c
@@ -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;
+}
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 250ef57..0e3f121 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -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;
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 30484ca..9b35507 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -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 *);
