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 <dnovi...@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