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


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

[pph] Fix ICE with circular #includes (issue5588046)


When generating PPH images, circular #includes cannot be handled using
the usual double-guard inclusion in the pre-processor.  This happens
because we generate PPH images in separate compilations.  So, even
with properly double-guarded headers, each header will include the
other in its image:

1.h
#ifndef _1_H
#define _1_H
#include "2.h"
#endif

2.h
#ifndef _2_H
#define _2_H
#include "1.h"
#endif

When compiling 1.h, we will try open 2.pph, which in turn includes
1.h, which is being generated.  To avoid this situation, we simply
force the inclusion of 1.h to proceed as a text inclusion.

When adding a test for this, I ran into trouble with the testing
harness.  The test would fail depending on which PPH images were
already present in the build directory.  So, I modified pph.exp to
remove all the PPH images before starting the main test loop.  I think
this will not work in a remote test setting, but I will deal with that
later.


2012-01-27   Diego Novillo  <dnovillo@google.com>

cp/ChangeLog.pph
	* pph-core.c (pph_stream_open): If STREAM exists and its mode
	is different than the mode in which it was originally opened,
	return NULL.

testsuite/ChangeLog.pph
	* g++.dg/pph/pph.exp: Remove PPH images before running the tests.
	* g++.dg/pph/x1circular.h: New.
	* g++.dg/pph/x2circular.h: New.
	* g++.dg/pph/x3circular.cc: New.

diff --git a/gcc/cp/pph-core.c b/gcc/cp/pph-core.c
index f252720..5f6c27f 100644
--- a/gcc/cp/pph-core.c
+++ b/gcc/cp/pph-core.c
@@ -1117,7 +1117,9 @@ pph_stream_unregister (pph_stream *stream)
 
 
 /* Create a new PPH stream to be stored on the file called NAME.
-   MODE is passed to fopen directly.  */
+   MODE is passed to fopen directly.  If NAME could not be opened,
+   return NULL to indicate to the caller that it should process NAME
+   as a regular text header.  */
 
 pph_stream *
 pph_stream_open (const char *name, const char *mode)
@@ -1130,6 +1132,15 @@ pph_stream_open (const char *name, const char *mode)
   stream = pph_stream_registry_lookup (name);
   if (stream)
     {
+      /* In a circular #include scenario, we will eventually try to
+	 read from the same PPH image that we are generating.  To
+	 avoid that problem, detect circularity and return NULL to
+	 force the caller to process NAME as a regular text header.  */
+      if (stream->write_p && strchr (mode, 'r') != NULL)
+	return NULL;
+
+      /* Otherwise, assert that we have read (or are reading) STREAM
+	 and return it.  */
       gcc_assert (stream->in_memory_p);
       return stream;
     }
diff --git a/gcc/testsuite/g++.dg/pph/pph.exp b/gcc/testsuite/g++.dg/pph/pph.exp
index a632365..7df3596 100644
--- a/gcc/testsuite/g++.dg/pph/pph.exp
+++ b/gcc/testsuite/g++.dg/pph/pph.exp
@@ -41,6 +41,14 @@ exec echo "string.h	string.pph" >> pph.map
 
 set mapflag -fpph-map=pph.map
 
+# Remove all existing PPH images to prevent stale state issues.
+verbose "Removing existing PPH images" 0
+set pph_file_list "[glob -nocomplain *.pph]"
+foreach pph_file $pph_file_list {
+  remote_file build delete $pph_file
+}
+
+verbose "Running PPH tests" 0
 foreach scenario $scenarios {
 
     set old_dg_do_what_default "${dg-do-what-default}"
diff --git a/gcc/testsuite/g++.dg/pph/x1circular.h b/gcc/testsuite/g++.dg/pph/x1circular.h
new file mode 100644
index 0000000..5b9f744
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pph/x1circular.h
@@ -0,0 +1,8 @@
+#ifndef X1_CIRCULAR_H
+#define X1_CIRCULAR_H
+/* We are purposely generating a circular #include chain.  Neither
+   header will be able to open the other one as their images are
+   being generated.  */
+#include "x2circular.h" // { dg-warning "cannot open PPH file x2circular.pph.*" }
+int foo(int, int);
+#endif
diff --git a/gcc/testsuite/g++.dg/pph/x2circular.h b/gcc/testsuite/g++.dg/pph/x2circular.h
new file mode 100644
index 0000000..d276f28
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pph/x2circular.h
@@ -0,0 +1,7 @@
+#ifndef X2_CIRCULAR_H
+#define X2_CIRCULAR_H
+int bar(int, int);
+
+#include "x1circular.h"
+
+#endif
diff --git a/gcc/testsuite/g++.dg/pph/x3circular.cc b/gcc/testsuite/g++.dg/pph/x3circular.cc
new file mode 100644
index 0000000..410cba5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pph/x3circular.cc
@@ -0,0 +1,21 @@
+// { dg-do run }
+#include "x2circular.h"
+
+extern "C" { void abort(void); }
+
+int bar(int x, int y)
+{
+  return x - y;
+}
+
+int foo(int x, int y)
+{
+  return bar (x, y) + x + y;
+}
+
+int main(void)
+{
+  if (foo (0, 0) != 0)
+    abort ();
+  return 0;
+}

--
This patch is available for review at http://codereview.appspot.com/5588046


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