This patch mostly adds several test cases reduced from full-scale attempts to use PPH.
c?anonymous* -- problems handling anonymous/tagless types c?features* -- problems with benign macro redefinitions x?tmpldfltparm* -- inappropriately merging default template arguments It also add an option -fpph-check to refine our check for headers compatible with PPH. It implies -fprimary-system-header-okay and checks for the main source file missing a guard. Generating a pph file implies the same check. Tested on x64. Index: gcc/c-family/ChangeLog.pph 2012-03-15 Lawrence Crowl <cr...@google.com> * c.opt (-fpph-check): New. * c-opts.c (c_common_handle_option): Add OPT_fpph_check. (case OPT__output_pph_): Also imply -fpph-check. * c-common.h (bool pph_check_main_missing_guard): New. * c-common.c (bool pph_check_main_missing_guard): New. (const char *pph_out_file): Explicitly initialize to NULL. Index: gcc/testsuite/ChangeLog.pph 2012-03-15 Lawrence Crowl <cr...@google.com> * g++.dg/pph/c0anonymous.h: New. * g++.dg/pph/c1anonymous1.h: New. * g++.dg/pph/c1anonymous2.h: New. * g++.dg/pph/c5features1.h: New. * g++.dg/pph/c5features2.h: New. * g++.dg/pph/c7features.cc: New. * g++.dg/pph/d8dupguard.cc: Add xfail-if comment. * g++.dg/pph/x0tmpldfltparm.h: New. * g++.dg/pph/x1tmpldfltparm.cc: New. * g++.dg/pph/y9overload.cc: Add xfail-if comment. Index: gcc/cp/ChangeLog.pph 2012-03-15 Lawrence Crowl <cr...@google.com> * pph.h (pph_check_main_guarded): New. * pph-core.c (pph_check_main_guarded): New. * pph-out.c (pph_writer_finish): Factor out guard check into pph_check_main_guarded. * parser.c (c_parse_file): Add guard check for non-pph compiles. Index: gcc/c-family/c.opt =================================================================== --- gcc/c-family/c.opt (revision 185442) +++ gcc/c-family/c.opt (working copy) @@ -981,6 +981,10 @@ fplan9-extensions C ObjC Var(flag_plan9_extensions) Enable Plan 9 language extensions +fpph-check +C++ +-fpph-check Check a header for minimal compatibility with PPH. + fpph-debug= C++ Joined RejectNegative UInteger Var(flag_pph_debug) -fpph-debug=N Enable debugging output at level N from PPH support Index: gcc/c-family/c-opts.c =================================================================== --- gcc/c-family/c-opts.c (revision 185442) +++ gcc/c-family/c-opts.c (working copy) @@ -404,6 +404,7 @@ c_common_handle_option (size_t scode, co case OPT__output_pph_: pph_out_file = arg; cpp_opts->primary_system_header_okay = true; + pph_check_main_missing_guard = true; break; case OPT_A: @@ -814,6 +815,11 @@ c_common_handle_option (size_t scode, co set_struct_debug_option (&global_options, loc, arg); break; + case OPT_fpph_check: + cpp_opts->primary_system_header_okay = true; + pph_check_main_missing_guard = true; + break; + case OPT_fpph_hdr_: add_pph_header_map (arg); break; Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c (revision 185442) +++ gcc/c-family/c-common.c (working copy) @@ -194,7 +194,11 @@ const char *pch_file; /* The file name to which we should write a preparsed header, or NULL if no header will be written in this compile. */ -const char *pph_out_file; +const char *pph_out_file = NULL; + +/* Whether or not we should check for a guard on the main input file. */ + +bool pph_check_main_missing_guard = false; /* Nonzero if an ISO standard was selected. It rejects macros in the user's namespace. */ Index: gcc/c-family/c-common.h =================================================================== --- gcc/c-family/c-common.h (revision 185442) +++ gcc/c-family/c-common.h (working copy) @@ -585,6 +585,10 @@ extern const char *pch_file; extern const char *pph_out_file; +/* Whether or not we should check for a guard on the main input file. */ + +extern bool pph_check_main_missing_guard; + /* Return true if we have any map from INCLUDE to PPH file. */ extern bool Index: gcc/testsuite/g++.dg/pph/c1anonymous1.h =================================================================== --- gcc/testsuite/g++.dg/pph/c1anonymous1.h (revision 0) +++ gcc/testsuite/g++.dg/pph/c1anonymous1.h (revision 0) @@ -0,0 +1,11 @@ +// { xfail-if "ANONYMOUS MERGING" { "*-*-*" } { "-fpph-map=pph.map" } } +// { dg-bogus "c0anonymous.h:4:16: error: 'anon_t' has a previous declaration here" "" { xfail *-*-* } 0 } + +#ifndef C1ANONYMOUS +#define C1ANONYMOUS + +#include "c0anonymous.h" + +enum { first, second }; // { dg-bogus "'anon_t' referred to as enum" "" { xfail *-*-* } } + +#endif Index: gcc/testsuite/g++.dg/pph/c1anonymous2.h =================================================================== --- gcc/testsuite/g++.dg/pph/c1anonymous2.h (revision 0) +++ gcc/testsuite/g++.dg/pph/c1anonymous2.h (revision 0) @@ -0,0 +1,14 @@ +// { xfail-if "ANONYMOUS MERGING" { "*-*-*" } { "-fpph-map=pph.map" } } +// { dg-bogus "c0anonymous.h:4:16: error: 'struct anon_t' has a previous declaration as 'struct anon_t'" "" { xfail *-*-* } 0 } + +#ifndef C1ANONYMOUS2_H +#define C1ANONYMOUS2_H + +#include "c0anonymous.h" + +typedef struct { // { dg-bogus "conflicting declaration 'struct<anonymous>'" "" { xfail *-*-* } } + + char *field; +} anon2_t; // { dg-bogus "invalid type in declaration before ';' token" "" { xfail *-*-* } } + +#endif Index: gcc/testsuite/g++.dg/pph/c5features1.h =================================================================== --- gcc/testsuite/g++.dg/pph/c5features1.h (revision 0) +++ gcc/testsuite/g++.dg/pph/c5features1.h (revision 0) @@ -0,0 +1,4 @@ +#ifndef C5FEATURES1_H +#define C5FEATURES1_H +#include <features.h> +#endif Index: gcc/testsuite/g++.dg/pph/c0anonymous.h =================================================================== --- gcc/testsuite/g++.dg/pph/c0anonymous.h (revision 0) +++ gcc/testsuite/g++.dg/pph/c0anonymous.h (revision 0) @@ -0,0 +1,6 @@ +#ifndef C0ANONYMOUS_H +#define C0ANONYMOUS_H + +typedef struct { int field; } anon_t; + +#endif Index: gcc/testsuite/g++.dg/pph/x0tmpldfltparm.h =================================================================== --- gcc/testsuite/g++.dg/pph/x0tmpldfltparm.h (revision 0) +++ gcc/testsuite/g++.dg/pph/x0tmpldfltparm.h (revision 0) @@ -0,0 +1,17 @@ +#ifndef X0TMPLDFLTPARM_H +#define X0TMPLDFLTPARM_H + +template< typename T > +struct auxillary +{ +}; + +template< typename T, typename U = auxillary< T > > +struct primary +{ +}; + +typedef primary< int > handlei; +typedef primary< long > handlel; + +#endif Index: gcc/testsuite/g++.dg/pph/c5features2.h =================================================================== --- gcc/testsuite/g++.dg/pph/c5features2.h (revision 0) +++ gcc/testsuite/g++.dg/pph/c5features2.h (revision 0) @@ -0,0 +1,4 @@ +#ifndef C5FEATURES2_H +#define C5FEATURES2_H +#include <features.h> +#endif Index: gcc/testsuite/g++.dg/pph/x1tmpldfltparm.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x1tmpldfltparm.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x1tmpldfltparm.cc (revision 0) @@ -0,0 +1,7 @@ +// { dg-xfail-if "DEFAULT TEMPLATE ARG MERGING" { "*-*-*" } { "-fpph-map=pph.map" } } +// { dg-bogus "Trying to merge distinct trees from the same PPH image x0tmpldfltparm.pph" "" { xfail *-*-* } 0 } + +#include "x0tmpldfltparm.h" + +handlei x; +handlel y; Index: gcc/testsuite/g++.dg/pph/c7features.cc =================================================================== --- gcc/testsuite/g++.dg/pph/c7features.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/c7features.cc (revision 0) @@ -0,0 +1,7 @@ +// { xfail-if "UNKNOWN" { "*-*-*" } { "-fpph-map=pph.map" } } +// { dg-bogus "warning: .__STDC_IEC_559_COMPLEX__. redefined" "" { xfail *-*-* } 0 } +// { dg-bogus "warning: .__STDC_ISO_10646__. redefined" "" { xfail *-*-* } 0 } +// { dg-bogus "warning: .__STDC_IEC_559__. redefined" "" { xfail *-*-* } 0 } + +#include "c5features1.h" +#include "c5features2.h" Index: gcc/testsuite/g++.dg/pph/y9overload.cc =================================================================== --- gcc/testsuite/g++.dg/pph/y9overload.cc (revision 185442) +++ gcc/testsuite/g++.dg/pph/y9overload.cc (working copy) @@ -1,3 +1,5 @@ +// { xfail-if "UNWANTED ERROR DETECTION" { "*-*-*" } { "-fpph-map=pph.map" } } + #include "x0overload1.h" #include "x0overload2.h" #include "x1overload3.h" Index: gcc/testsuite/g++.dg/pph/d8dupguard.cc =================================================================== --- gcc/testsuite/g++.dg/pph/d8dupguard.cc (revision 185442) +++ gcc/testsuite/g++.dg/pph/d8dupguard.cc (working copy) @@ -1,3 +1,5 @@ +// { xfail-if "LOW ERROR DETECTION" { "*-*-*" } { "-fpph-map=pph.map" } } + #include "c0dupguard1.h" #include "c0dupguard2.h" // { dg-error "fails macro validation" "" { xfail *-*-* } } int foo() { return x; } Index: gcc/cp/pph-core.c =================================================================== --- gcc/cp/pph-core.c (revision 185442) +++ gcc/cp/pph-core.c (working copy) @@ -1547,6 +1547,19 @@ pph_streamer_finish (void) } +/* Return true when the main source file is guarded against preprocessor + multiple inclusions. */ + +bool pph_check_main_guarded (void) +{ + const char *offending_file = cpp_main_missing_guard (parse_in); + if (offending_file == NULL) + return true; + error ("header lacks guard for PPH"); + return false; +} + + /* Finalize PPH support. */ void Index: gcc/cp/pph.h =================================================================== --- gcc/cp/pph.h (revision 185442) +++ gcc/cp/pph.h (working copy) @@ -144,6 +144,7 @@ extern FILE *pph_logfile; extern void pph_init (void); extern void pph_loaded (void); extern void pph_finish (void); +extern bool pph_check_main_guarded (void); extern void pph_dump_location (FILE *file, location_t loc); extern void pph_dump_tree_name (FILE *file, tree t, int flags); extern void pph_dump_vec_tree (FILE *file, VEC(tree,gc) *v); Index: gcc/cp/pph-out.c =================================================================== --- gcc/cp/pph-out.c (revision 185442) +++ gcc/cp/pph-out.c (working copy) @@ -2750,16 +2750,11 @@ pph_flush_buffers (pph_stream *stream) void pph_writer_finish (void) { - const char *offending_file; - if (pph_out_stream == NULL) return; - offending_file = cpp_main_missing_guard (parse_in); - if (offending_file == NULL) + if (!pph_check_main_missing_guard || pph_check_main_guarded ()) pph_write_file (pph_out_stream); - else - error ("header lacks guard for PPH: %s", offending_file); pph_stream_close (pph_out_stream); pph_out_stream = NULL; Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 185442) +++ gcc/cp/parser.c (working copy) @@ -27509,6 +27509,8 @@ c_parse_file (void) if (pph_enabled_p ()) pph_finish (); + else if (pph_check_main_missing_guard) + pph_check_main_guarded (); } #include "gt-cp-parser.h" -- This patch is available for review at http://codereview.appspot.com/5820069