diff mbox

[pph] Add preprocessor validation

Message ID AANLkTi=BxTkuHwnm9zj93Cj-zipEV+xq7uVwsUzFizK5@mail.gmail.com
State New
Headers show

Commit Message

Lawrence Crowl March 5, 2011, 1:46 a.m. UTC
Add preprocessor symbol verification to PPH.
   Write the used symbol table instead of a dummy PPH file.
   Reuse PTH code for verifying these symbols are correct.
   Modify verification to allow a preprocessor symbol to match the PPH
   file's after value as well as its before value.
   Stop storing the macro name redundantly within its value.
   Mark three tests as expected failures as a result.
   There are 2 unexpected failures and 2 unexpected passes to be fixed.

Add three different PPH output formats,
   the regular object file, the pretty printed form, and the full dump form.
   These formats are more stubs than anything else.

Make pretty printing closer to compilable code.
   Add new flag TDF_VISDEF to request display of visible definitions.
   For now, they are most particularly struct definitions.
   Turn off visible definitions for bases of arrays and pointers.

Comments

Diego Novillo March 5, 2011, 2:21 a.m. UTC | #1
On 03/04/2011 05:46 PM, Lawrence Crowl wrote:
> Add preprocessor symbol verification to PPH.
>     Write the used symbol table instead of a dummy PPH file.
>     Reuse PTH code for verifying these symbols are correct.
>     Modify verification to allow a preprocessor symbol to match the PPH
>     file's after value as well as its before value.
>     Stop storing the macro name redundantly within its value.
>     Mark three tests as expected failures as a result.
>     There are 2 unexpected failures and 2 unexpected passes to be fixed.
>
> Add three different PPH output formats,
>     the regular object file, the pretty printed form, and the full dump form.
>     These formats are more stubs than anything else.
>
> Make pretty printing closer to compilable code.
>     Add new flag TDF_VISDEF to request display of visible definitions.
>     For now, they are most particularly struct definitions.
>     Turn off visible definitions for bases of arrays and pointers.
>

OK.


Diego.
diff mbox

Patch

Index: gcc/tree-pretty-print.c
===================================================================
*** gcc/tree-pretty-print.c	(revision 170279)
--- gcc/tree-pretty-print.c	(working copy)
*************** dump_generic_node (pretty_printer *buffe
*** 771,777 ****
          {
  	  unsigned int quals = TYPE_QUALS (node);
  
!           dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false);
  	  pp_space (buffer);
  	  pp_string (buffer, str);
  
--- 771,778 ----
          {
  	  unsigned int quals = TYPE_QUALS (node);
  
!           dump_generic_node (buffer, TREE_TYPE (node), spc,
! 			     flags & !TDF_VISDEF, false);
  	  pp_space (buffer);
  	  pp_string (buffer, str);
  
*************** dump_generic_node (pretty_printer *buffe
*** 918,924 ****
  	for (tmp = TREE_TYPE (node); TREE_CODE (tmp) == ARRAY_TYPE;
  	     tmp = TREE_TYPE (tmp))
  	  ;
! 	dump_generic_node (buffer, tmp, spc, flags, false);
  
  	/* Print the dimensions.  */
  	for (tmp = node; TREE_CODE (tmp) == ARRAY_TYPE; tmp = TREE_TYPE (tmp))
--- 919,925 ----
  	for (tmp = TREE_TYPE (node); TREE_CODE (tmp) == ARRAY_TYPE;
  	     tmp = TREE_TYPE (tmp))
  	  ;
! 	dump_generic_node (buffer, tmp, spc, flags & !TDF_VISDEF, false);
  
  	/* Print the dimensions.  */
  	for (tmp = node; TREE_CODE (tmp) == ARRAY_TYPE; tmp = TREE_TYPE (tmp))
*************** dump_generic_node (pretty_printer *buffe
*** 937,957 ****
  	if (quals & TYPE_QUAL_VOLATILE)
  	  pp_string (buffer, "volatile ");
  
!         /* Print the name of the structure.  */
!         if (TREE_CODE (node) == RECORD_TYPE)
! 	  pp_string (buffer, "struct ");
!         else if (TREE_CODE (node) == UNION_TYPE)
! 	  pp_string (buffer, "union ");
! 
!         if (TYPE_NAME (node))
! 	  dump_generic_node (buffer, TYPE_NAME (node), spc, flags, false);
! 	else if (!(flags & TDF_SLIM))
! 	  /* FIXME: If we eliminate the 'else' above and attempt
! 	     to show the fields for named types, we may get stuck
! 	     following a cycle of pointers to structs.  The alleged
! 	     self-reference check in print_struct_decl will not detect
! 	     cycles involving more than one pointer or struct type.  */
  	  print_struct_decl (buffer, node, spc, flags);
          break;
        }
  
--- 938,962 ----
  	if (quals & TYPE_QUAL_VOLATILE)
  	  pp_string (buffer, "volatile ");
  
! 	if (flags & TDF_VISDEF)
  	  print_struct_decl (buffer, node, spc, flags);
+ 	else
+ 	  {
+ 	    /* Print the name of the structure.  */
+ 	    if (TREE_CODE (node) == RECORD_TYPE)
+ 	      pp_string (buffer, "struct ");
+ 	    else if (TREE_CODE (node) == UNION_TYPE)
+ 	      pp_string (buffer, "union ");
+ 	    if (TYPE_NAME (node))
+ 	      dump_generic_node (buffer, TYPE_NAME (node), spc, flags, false);
+ 	    else if (!(flags & TDF_SLIM))
+ 	      /* FIXME: If we eliminate the 'else' above and attempt
+ 		 to show the fields for named types, we may get stuck
+ 		 following a cycle of pointers to structs.  The alleged
+ 		 self-reference check in print_struct_decl will not detect
+ 		 cycles involving more than one pointer or struct type.  */
+ 	      print_struct_decl (buffer, node, spc, flags);
+ 	  }
          break;
        }
  
*************** dump_generic_node (pretty_printer *buffe
*** 2308,2329 ****
    return spc;
  }
  
! /* Print the declaration of a variable.  */
  
  void
  print_declaration (pretty_printer *buffer, tree t, int spc, int flags)
  {
!   INDENT (spc);
  
!   if (TREE_CODE (t) == TYPE_DECL)
!     pp_string (buffer, "typedef ");
  
    if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_WRTL) && DECL_REGISTER (t))
      pp_string (buffer, "register ");
  
    if (TREE_PUBLIC (t) && DECL_EXTERNAL (t))
      pp_string (buffer, "extern ");
!   else if (TREE_STATIC (t))
      pp_string (buffer, "static ");
  
    /* Print the type and name.  */
--- 2313,2341 ----
    return spc;
  }
  
! /* Print a declaration.  */
  
  void
  print_declaration (pretty_printer *buffer, tree t, int spc, int flags)
  {
!   /* When printing visible definitions, do not print artificial types,
!      unless the artifical typedef
!      is actually the implicit C++ typedef for a struct,
!      in which case do print the struct.  */
!   if ((flags & TDF_VISDEF)
!       && DECL_ARTIFICIAL (t)
!       && !(TREE_CODE (t) == TYPE_DECL && DECL_LANG_FLAG_2 (t)))
!           /* FIXME pph: DECL_IMPLICIT_TYPEDEF_P (t) from cp/cp-tree.h */
!     return;
  
!   INDENT (spc);
  
    if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_WRTL) && DECL_REGISTER (t))
      pp_string (buffer, "register ");
  
    if (TREE_PUBLIC (t) && DECL_EXTERNAL (t))
      pp_string (buffer, "extern ");
!   else if (TREE_STATIC (t) && !TREE_PUBLIC (t))
      pp_string (buffer, "static ");
  
    /* Print the type and name.  */
*************** print_declaration (pretty_printer *buffe
*** 2356,2361 ****
--- 2368,2393 ----
        dump_decl_name (buffer, t, flags);
        dump_function_declaration (buffer, TREE_TYPE (t), spc, flags);
      }
+   else if (TREE_CODE (t) == TYPE_DECL)
+     {
+       if ((flags & TDF_VISDEF) && DECL_ARTIFICIAL (t))
+         {
+           const char* id = IDENTIFIER_POINTER (DECL_NAME (t));
+           if (id[0] != '.')
+             {
+               /* Print type's value.  */
+               dump_generic_node (buffer, TREE_TYPE (t), spc, flags, false);
+             }
+         }
+       else
+         {
+           /* Print type declaration.  */
+           dump_generic_node (buffer, TREE_TYPE (t), spc, flags, false);
+           /* Print variable's name.  */
+           pp_space (buffer);
+           dump_generic_node (buffer, t, spc, flags, false);
+         }
+     }
    else
      {
        /* Print type declaration.  */
*************** print_declaration (pretty_printer *buffe
*** 2406,2422 ****
  static void
  print_struct_decl (pretty_printer *buffer, const_tree node, int spc, int flags)
  {
    /* Print the name of the structure.  */
!   if (TYPE_NAME (node))
      {
-       INDENT (spc);
        if (TREE_CODE (node) == RECORD_TYPE)
  	pp_string (buffer, "struct ");
        else if ((TREE_CODE (node) == UNION_TYPE
  		|| TREE_CODE (node) == QUAL_UNION_TYPE))
  	pp_string (buffer, "union ");
  
!       dump_generic_node (buffer, TYPE_NAME (node), spc, 0, false);
      }
  
    /* Print the contents of the structure.  */
--- 2438,2461 ----
  static void
  print_struct_decl (pretty_printer *buffer, const_tree node, int spc, int flags)
  {
+   tree name = TYPE_NAME (node);
    /* Print the name of the structure.  */
!   if (name)
      {
        if (TREE_CODE (node) == RECORD_TYPE)
  	pp_string (buffer, "struct ");
        else if ((TREE_CODE (node) == UNION_TYPE
  		|| TREE_CODE (node) == QUAL_UNION_TYPE))
  	pp_string (buffer, "union ");
  
!       if ((flags & TDF_VISDEF) && DECL_ARTIFICIAL (name))
!         {
!           const char* id = IDENTIFIER_POINTER (DECL_NAME (name));
!           if (id[0] != '.')
!             dump_generic_node (buffer, name, spc, 0, false);
!         }
!       else
!         dump_generic_node (buffer, name, spc, 0, false);
      }
  
    /* Print the contents of the structure.  */
*************** print_struct_decl (pretty_printer *buffe
*** 2431,2448 ****
      tmp = TYPE_FIELDS (node);
      while (tmp)
        {
! 	/* Avoid to print recursively the structure.  */
! 	/* FIXME : Not implemented correctly...,
! 	   what about the case when we have a cycle in the contain graph? ...
! 	   Maybe this could be solved by looking at the scope in which the
! 	   structure was declared.  */
! 	if (TREE_TYPE (tmp) != node
! 	    && (TREE_CODE (TREE_TYPE (tmp)) != POINTER_TYPE
! 		|| TREE_TYPE (TREE_TYPE (tmp)) != node))
  	  {
  	    print_declaration (buffer, tmp, spc+2, flags);
  	    pp_newline (buffer);
  	  }
  	tmp = DECL_CHAIN (tmp);
        }
    }
--- 2470,2496 ----
      tmp = TYPE_FIELDS (node);
      while (tmp)
        {
! 	if (flags & TDF_VISDEF)
  	  {
  	    print_declaration (buffer, tmp, spc+2, flags);
  	    pp_newline (buffer);
  	  }
+ 	else
+ 	  {
+ 	    /* Avoid to print recursively the structure.  */
+ 	    /* FIXME : Not implemented correctly...,
+ 	       what about the case when we have a cycle in the contain graph?
+ 	       ...
+ 	       Maybe this could be solved by looking at the scope in which the
+ 	       structure was declared.  */
+ 	    if (TREE_TYPE (tmp) != node
+ 		&& (TREE_CODE (TREE_TYPE (tmp)) != POINTER_TYPE
+ 		    || TREE_TYPE (TREE_TYPE (tmp)) != node))
+ 	      {
+ 		print_declaration (buffer, tmp, spc+2, flags);
+ 		pp_newline (buffer);
+ 	      }
+ 	  }
  	tmp = DECL_CHAIN (tmp);
        }
    }
Index: gcc/c-family/c.opt
===================================================================
*** gcc/c-family/c.opt	(revision 170280)
--- gcc/c-family/c.opt	(working copy)
*************** fpph-decls=
*** 929,934 ****
--- 929,938 ----
  C++ Joined RejectNegative UInteger Var(flag_pph_decls)
  -fpph-decls=N   Enable declaration identifier output at level N from PPH support
  
+ fpph-fmt=
+ C++ Joined RejectNegative UInteger Var(flag_pph_fmt)
+ -fpph-fmt=N   Output format is (0) normal (1) pretty summary (2) dump
+ 
  fpph-logfile=
  C++ Joined RejectNegative Var(flag_pph_logfile)
  -fpph-logfile=<file-name>	Emit PPH debug information to <file-name>
Index: gcc/tree-pass.h
===================================================================
*** gcc/tree-pass.h	(revision 170279)
--- gcc/tree-pass.h	(working copy)
*************** enum tree_dump_index
*** 83,88 ****
--- 83,89 ----
  #define TDF_ALIAS	(1 << 21)	/* display alias information  */
  #define TDF_ENUMERATE_LOCALS (1 << 22)	/* Enumerate locals by uid.  */
  #define TDF_CSELIB	(1 << 23)	/* Dump cselib details.  */
+ #define TDF_VISDEF	(1 << 24)	/* Dump visible definitions.  */
  
  
  /* In tree-dump.c */
Index: gcc/testsuite/g++.dg/pph/p1mean.cc
===================================================================
*** gcc/testsuite/g++.dg/pph/p1mean.cc	(revision 170280)
--- gcc/testsuite/g++.dg/pph/p1mean.cc	(working copy)
***************
*** 1,7 ****
! #include <stdlib.h>
! #include <stdio.h>
! #include <math.h>
! #include <string.h>
  
  static unsigned long long MAX_ITEMS = 10000;
  
--- 1,9 ----
! #include <stdlib.h> // {dg-error fails macro validation "" { xfail *-*-* } }
! #include <stdio.h> // {dg-error fails macro validation "" { xfail *-*-* } }
! #include <math.h> // {dg-error fails macro validation "" { xfail *-*-* } }
! #include <string.h> // {dg-error fails macro validation "" { xfail *-*-* } }
! // { dg-excess-errors "In file included from" { xfail *-*-* } }
! // { dg-excess-errors "assembly comparison" { xfail *-*-* } }
  
  static unsigned long long MAX_ITEMS = 10000;
  
Index: gcc/testsuite/g++.dg/pph/d2dupguard.cc
===================================================================
*** gcc/testsuite/g++.dg/pph/d2dupguard.cc	(revision 170280)
--- gcc/testsuite/g++.dg/pph/d2dupguard.cc	(working copy)
***************
*** 1,4 ****
  #include "c2dupguard1.h"
! #include "c2dupguard2.h"
! // { dg-error "duplicate PPH guard header" "" { xfail *-*-* } }
  int foo() { return x; }
--- 1,3 ----
  #include "c2dupguard1.h"
! #include "c2dupguard2.h" // { dg-error "fails macro validation" "" { xfail *-*-* } }
  int foo() { return x; }
Index: gcc/testsuite/g++.dg/pph/d1chained.cc
===================================================================
*** gcc/testsuite/g++.dg/pph/d1chained.cc	(revision 170280)
--- gcc/testsuite/g++.dg/pph/d1chained.cc	(working copy)
***************
*** 1,4 ****
  #include "c1chained1.h"
! #include "c1chained2.h"
! // { dg-error "Preprocessor state inconsistent for PPH" "" { xfail *-*-* } }
  int x = TWO;
--- 1,3 ----
  #include "c1chained1.h"
! #include "c1chained2.h" // { dg-error "fails macro validation" }
  int x = TWO;
Index: gcc/testsuite/g++.dg/pph/p1stdlib.cc
===================================================================
*** gcc/testsuite/g++.dg/pph/p1stdlib.cc	(revision 170280)
--- gcc/testsuite/g++.dg/pph/p1stdlib.cc	(working copy)
***************
*** 1,4 ****
! #include <stdlib.h>
  int f(const char* s)
  {
      return atoi(s);
--- 1,7 ----
! #include <stdlib.h> // { dg-error "fails macro validation" "" { xfail *-*-* } }
! // { dg-excess-errors "In file included from" { xfail *-*-* } }
! // { dg-excess-errors "regular compilation failed" { xfail *-*-* } }
! 
  int f(const char* s)
  {
      return atoi(s);
Index: gcc/cp/pph.c
===================================================================
*** gcc/cp/pph.c	(revision 170550)
--- gcc/cp/pph.c	(working copy)
*************** pth_write_header (pth_image *image, FILE
*** 502,507 ****
--- 502,556 ----
    gcc_assert (nbytes == pth_header_len ());
  }
  
+ 
+ /* Pretty print the previous macro definitions in the table of IDENTIFIERS to
+    the STREAM. */
+ 
+ static void
+ pph_print_macro_defs_before (FILE *stream, cpp_idents_used *identifiers)
+ {
+   unsigned int idx;
+ 
+   for (idx = 0; idx < identifiers->num_entries; ++idx)
+     {
+       cpp_ident_use *entry = identifiers->entries + idx;
+       const char *ident = entry->ident_str;
+       const char *before = entry->before_str;
+ 
+       if (before)
+           fprintf (stream, "#define %s%s\n", ident, before);
+       else
+           fprintf (stream, "#undef %s\n", ident);
+     }
+ }
+ 
+ 
+ /* Pretty print the subsequent macro definitions in the table of IDENTIFIERS to
+    the STREAM. */
+ 
+ static void
+ pph_print_macro_defs_after (FILE *stream, cpp_idents_used *identifiers)
+ {
+   unsigned int idx;
+ 
+   for (idx = 0; idx < identifiers->num_entries; ++idx)
+     {
+       cpp_ident_use *entry = identifiers->entries + idx;
+       const char *ident = entry->ident_str;
+       const char *before = entry->before_str;
+       const char *after = entry->after_str;
+ 
+       if (before != after)
+         {
+           if (after && (!before || strcmp (after, before) != 0))
+               fprintf (stream, "#define %s%s\n", ident, after);
+           else if (before)
+               fprintf (stream, "#undef %s\n", ident);
+         }
+     }
+ }
+ 
+ 
  /* Dump a table of IDENTIFIERS to the STREAM. */
  
  static void
*************** pth_file_change (cpp_reader *reader, con
*** 1900,1909 ****
  
  /* Write PPH output file.  */
  
  static void
! write_pph_output (void)
  {
    FILE *stream;
  
    if (flag_pph_debug >= 1)
      fprintf (pph_logfile, "PPH: Writing %s\n", pph_out_file);
--- 1949,2061 ----
  
  /* Write PPH output file.  */
  
+ typedef void (*write_pph_format)(FILE *stream, tree decl, int flags);
+ 
+ static void
+ write_pph_namespace (FILE *stream, tree decl, write_pph_format fmt, int flags);
+ 
+ 
+ /* Write symbol to PPH output file like C.  */
+ 
+ static void
+ write_pph_print (FILE *stream, tree decl, int flags)
+ {
+   print_generic_decl (stream, decl, flags | TDF_VISDEF);
+   fprintf (stream, "\n");
+ }
+ 
+ 
+ /* Write symbol to PPH output file as a dump.  */
+ 
+ static void
+ write_pph_dump (FILE *stream, tree decl, int flags)
+ {
+   dump_node (decl, flags, stream);
+ }
+ 
+ 
+ /* Write symbol to PPH output file.  */
+ 
+ static void
+ write_pph_symbol (FILE *stream, tree decl, write_pph_format fmt, int flags)
+ {
+   if (TREE_CODE (decl) == NAMESPACE_DECL)
+     write_pph_namespace (stream, decl, fmt, flags);
+   else if (!DECL_IS_BUILTIN (decl))
+     fmt (stream, decl, flags);
+ }
+ 
+ 
+ /* Write namespace to PPH output file.  */
+ 
+ typedef void (*declvisitor)(FILE *, tree, write_pph_format, int);
+ 
+ static void
+ write_pph_namespace_1 (declvisitor vtor, FILE *stream, tree decl,
+                        write_pph_format fmt, int flags)
+ {
+   tree prior = TREE_CHAIN (decl);
+   if (prior)
+     write_pph_namespace_1 (vtor, stream, prior, fmt, flags);
+   vtor (stream, decl, fmt, flags);
+ }
+ 
+ static void
+ write_pph_namespace (FILE *stream, tree decl, write_pph_format fmt, int flags)
+ {
+   struct cp_binding_level *level = NAMESPACE_LEVEL (decl);
+   decl = level->namespaces;
+   if (decl)
+     write_pph_namespace_1 (write_pph_namespace, stream, decl, fmt, flags);
+   decl = level->names;
+   if (decl)
+     write_pph_namespace_1 (write_pph_symbol, stream, decl, fmt, flags);
+ }
+ 
+ 
+ /* Write PPH output symbols and IDENTS_USED to STREAM as an object.  */
+ 
+ static void
+ write_pph_file_object (FILE *stream, cpp_idents_used *idents_used)
+ { 
+   int flags = 0;
+   pth_save_identifiers (idents_used, stream);
+   fprintf (stream, "\n====\n");
+   /* FIX pph: Wrong format for writing decls.  */
+   write_pph_namespace (stream, global_namespace, write_pph_print, flags);
+ }
+ 
+ 
+ /* Write PPH output symbols and IDENTS_USED to STREAM as a pretty summary.  */
+ 
+ static void
+ write_pph_file_summary (FILE *stream, cpp_idents_used *idents_used)
+ { 
+   int flags = 0;
+   pph_print_macro_defs_before (stream, idents_used);
+   write_pph_namespace (stream, global_namespace, write_pph_print, flags);
+   pph_print_macro_defs_after (stream, idents_used);
+ }
+ 
+ 
+ /* Write PPH output symbols and IDENTS_USED to STREAM as a textual dump.  */
+ 
+ static void
+ write_pph_file_dump (FILE *stream, cpp_idents_used *idents_used)
+ { 
+   int flags = TDF_UID | TDF_LINENO;
+   pth_dump_identifiers (stream, idents_used);
+   write_pph_namespace (stream, global_namespace, write_pph_dump, flags);
+ }
+ 
+ 
+ /* Write PPH output file.  */
+ 
  static void
! write_pph_file (void)
  {
    FILE *stream;
+   cpp_idents_used idents_used;
  
    if (flag_pph_debug >= 1)
      fprintf (pph_logfile, "PPH: Writing %s\n", pph_out_file);
*************** write_pph_output (void)
*** 1912,1930 ****
    if (!stream)
      fatal_error ("Cannot open PPH file for writing: %s: %m", pph_out_file);
  
!   fprintf (stream, "%s\n", pph_out_file);
    fclose (stream);
  }
  
  /* Read PPH file.  */
  
  static void
! read_pph_file (const char* filename)
  {
    FILE *stream;
-   char *line;
-   char *eol;
-   char linebuf[2*MAXPATHLEN];
  
    if (flag_pph_debug >= 1)
      fprintf (pph_logfile, "PPH: Reading %s\n", filename);
--- 2064,2158 ----
    if (!stream)
      fatal_error ("Cannot open PPH file for writing: %s: %m", pph_out_file);
  
!   idents_used = cpp_lt_capture (parse_in);
! 
!   if (flag_pph_fmt == 0)
!     write_pph_file_object (stream, &idents_used);
!   else if (flag_pph_fmt == 1)
!     write_pph_file_summary (stream, &idents_used);
!   else if (flag_pph_fmt == 2)
!     write_pph_file_dump (stream, &idents_used);
!   else
!     error ("unrecognized -fpph-fmt value: %d", flag_pph_fmt);
! 
!   /*FIX pph: double free or corruption: cpp_lt_idents_destroy (&idents_used); */
    fclose (stream);
  }
  
+ 
+ /* Wrap a macro DEFINITION for printing in an error.  */
+ 
+ static char *
+ wrap_macro_def (const char *definition)
+ {
+   char *string;
+   if (definition)
+     {
+       size_t length;
+       length = strlen (definition);
+       string = (char *) xmalloc (length+3);
+       string[0] = '"';
+       strcpy (string + 1, definition);
+       string[length + 1] = '"';
+       string[length + 2] = '\0';
+     }
+   else
+     string = xstrdup ("undefined");
+   return string;
+ }
+ 
+ 
+ /* Report a macro validation error in FILENAME for macro IDENT,
+    which should have the value EXPECTED but actually had the value FOUND. */
+ 
+ static void
+ report_validation_error (const char *filename,
+ 			 const char *ident, const char *found,
+ 			 const char *before, const char *after)
+ {
+   char* quote_found = wrap_macro_def (found);
+   char* quote_before = wrap_macro_def (before);
+   char* quote_after = wrap_macro_def (after);
+   error ("PPH file %s fails macro validation, "
+          "%s is %s and should be %s or %s\n",
+          filename, ident, quote_found, quote_before, quote_after);
+   free (quote_found);
+   free (quote_before);
+   free (quote_after);
+ }
+ 
+ 
+ /* Read PPH FILENAME from STREAM as an object.  */
+ 
+ static void
+ read_pph_file_object (const char *filename, FILE *stream)
+ {
+   bool verified;
+   cpp_ident_use *bad_use;
+   const char *cur_def;
+   cpp_idents_used idents_used;
+ 
+   pth_load_identifiers (&idents_used, stream);
+   /*FIXME pph: This validation is weak.  */
+   verified = cpp_lt_verify_1 (parse_in, &idents_used, &bad_use, &cur_def, true);
+   if (!verified)
+     report_validation_error (filename, bad_use->ident_str, cur_def,
+                              bad_use->before_str, bad_use->after_str);
+   /* FIX pph: We cannot replay the macro definitions
+      as long as we are still reading the actual file.
+   cpp_lt_replay (parse_in, &idents_used);
+   */
+ 
+   /* FIX pph: Also read decls.  */
+ }
+ 
+ 
  /* Read PPH file.  */
  
  static void
! read_pph_file (const char *filename)
  {
    FILE *stream;
  
    if (flag_pph_debug >= 1)
      fprintf (pph_logfile, "PPH: Reading %s\n", filename);
*************** read_pph_file (const char* filename)
*** 1933,1947 ****
    if (!stream)
      fatal_error ("Cannot open PPH file for reading: %s: %m", filename);
  
!   line = fgets (linebuf, sizeof linebuf, stream);
!   if (line == NULL)
!     fatal_error ("No line in PPH file %s: ", filename);
! 
!   eol = strchr (line, '\n');
!   *eol = '\0';
! 
!   if (strcmp (filename, line) != 0)
!     fatal_error ("Wrong content in PPH file %s: ", filename);
  
    fclose (stream);
  }
--- 2161,2168 ----
    if (!stream)
      fatal_error ("Cannot open PPH file for reading: %s: %m", filename);
  
!   if (flag_pph_fmt == 0)
!     read_pph_file_object (filename, stream);
  
    fclose (stream);
  }
*************** pth_include_handler (cpp_reader *reader 
*** 1979,1985 ****
  /* Record a #include or #include_next for PPH.  */
  
  static void
! pph_include_handler (cpp_reader *reader ATTRIBUTE_UNUSED,
                       location_t loc ATTRIBUTE_UNUSED,
                       const unsigned char *dname,
                       const char *name,
--- 2200,2206 ----
  /* Record a #include or #include_next for PPH.  */
  
  static void
! pph_include_handler (cpp_reader *reader /*FIXME pph: ATTRIBUTE_UNUSED */,
                       location_t loc ATTRIBUTE_UNUSED,
                       const unsigned char *dname,
                       const char *name,
*************** pph_include_handler (cpp_reader *reader 
*** 1997,2003 ****
      }
  
    pph_file = query_pph_include_map (name);
!   if (pph_file != NULL)
      read_pph_file (pph_file);
  }
  
--- 2218,2224 ----
      }
  
    pph_file = query_pph_include_map (name);
!   if (pph_file != NULL && ! cpp_included_before (reader, name, input_location))
      read_pph_file (pph_file);
  }
  
*************** pph_set_dependencies_for (tree t, VEC(tr
*** 2667,2674 ****
  }
  
  #define PPH_ARTIFICIAL(t) \
! (DECL_ARTIFICIAL (t) \
! && !(TREE_CODE (t) == TYPE_DECL && DECL_IMPLICIT_TYPEDEF_P (t)))
  
  static bool
  is_namespace (tree container)
--- 2888,2894 ----
  }
  
  #define PPH_ARTIFICIAL(t) \
! (DECL_ARTIFICIAL (t) && !DECL_IMPLICIT_TYPEDEF_P (t))
  
  static bool
  is_namespace (tree container)
*************** void
*** 4070,4075 ****
--- 4290,4296 ----
  pph_init (void)
  {
    cpp_callbacks *cb;
+   cpp_lookaside *table;
  
    if (flag_pph_logfile)
      {
*************** pph_init (void)
*** 4085,4090 ****
--- 4306,4319 ----
  
    cb = cpp_get_callbacks (parse_in);
    cb->include = pph_include_handler;
+   /* FIXME pph: Use file change instead.
+   state->file_change_prev = cb->file_change;
+   cb->file_change = pph_file_change;
+   */
+ 
+   table = cpp_lt_exchange (parse_in,
+                            cpp_lt_create (cpp_lt_order, flag_pth_debug));
+   gcc_assert (table == NULL);
  }
  
  
*************** pph_finish (void)
*** 4097,4103 ****
      {
        const char *offending_file = cpp_main_missing_guard (parse_in);
        if (offending_file == NULL)
!         write_pph_output ();
        else
          error ("header lacks guard for PPH: %s", offending_file);
      }
--- 4326,4332 ----
      {
        const char *offending_file = cpp_main_missing_guard (parse_in);
        if (offending_file == NULL)
!         write_pph_file ();
        else
          error ("header lacks guard for PPH: %s", offending_file);
      }
Index: libcpp/symtab.c
===================================================================
*** libcpp/symtab.c	(revision 170279)
--- libcpp/symtab.c	(working copy)
*************** lt_query_macro (cpp_reader *reader, cpp_
*** 505,517 ****
          {
            static char *string = 0;
            static unsigned int space = 0;
!           unsigned int front, back, needed;
            const char *value;
  
            value = (const char *)_cpp_builtin_macro_text (reader, cpp_node);
-           front = strlen (str);
            back = strlen (value);
!           needed = front + 1 + back + 1;
  	  if (space < needed)
              {
                if (string != NULL)
--- 505,516 ----
          {
            static char *string = 0;
            static unsigned int space = 0;
!           unsigned int back, needed;
            const char *value;
  
            value = (const char *)_cpp_builtin_macro_text (reader, cpp_node);
            back = strlen (value);
!           needed = 1 + back + 1;
  	  if (space < needed)
              {
                if (string != NULL)
*************** lt_query_macro (cpp_reader *reader, cpp_
*** 519,533 ****
                string = XCNEWVEC (char, needed);
                space = needed;
              }
!           strcpy (string, str);
!           string[front] = '=';
!           strcpy (string + front + 1, value);
! 
  	  definition = string;
          }
      }
    else
!     definition = (const char *) cpp_macro_definition (reader, cpp_node);
  
    if (reader->lookaside_table->pth_debug_level >= 3)
      fprintf (stderr, "PTH: macro %s is %s\n",
--- 518,542 ----
                string = XCNEWVEC (char, needed);
                space = needed;
              }
!           string[0] = ' ';
!           strcpy (string + 1, value);
  	  definition = string;
          }
      }
    else
!     {
!       char c;
!       definition = (const char *) cpp_macro_definition (reader, cpp_node);
!       /* Skip over the macro name within the definition.  */
!       c = *definition;
!       while (   ('0' <= c && c <= '9')
!              || ('A' <= c && c <= 'Z')
!              || ('a' <= c && c <= 'z')
!              ||             (c == '_'))
!         {
!           c = *++definition;
!         }
!     }
  
    if (reader->lookaside_table->pth_debug_level >= 3)
      fprintf (stderr, "PTH: macro %s is %s\n",
*************** cpp_lt_capture (cpp_reader *reader)
*** 645,652 ****
     inconsistency.  A null means 'not a macro'.  */
  
  bool
! cpp_lt_verify (cpp_reader *reader, cpp_idents_used* identifiers,
!                cpp_ident_use **bad_use, const char **cur_def)
  {
    unsigned int i;
    unsigned int num_entries = identifiers->num_entries;
--- 654,662 ----
     inconsistency.  A null means 'not a macro'.  */
  
  bool
! cpp_lt_verify_1 (cpp_reader *reader, cpp_idents_used* identifiers,
!                  cpp_ident_use **bad_use, const char **cur_def,
!                  int permit_postdef)
  {
    unsigned int i;
    unsigned int num_entries = identifiers->num_entries;
*************** cpp_lt_verify (cpp_reader *reader, cpp_i
*** 680,689 ****
            /* It was not saved as a macro.  */
            if (cpp_node->type == NT_MACRO)
              {
!               /* But it is a macro now!  */
!               *bad_use = entry;
!               *cur_def = (const char*) lt_query_macro (reader, cpp_node);
!               goto fail;
              }
            /* Otherwise, both agree it is not a macro.  */
          }
--- 690,719 ----
            /* It was not saved as a macro.  */
            if (cpp_node->type == NT_MACRO)
              {
! 	      /* But it is a macro now!  */
! 	      const char *definition;
! 	      definition = (const char*) lt_query_macro (reader, cpp_node);
! 	      if (permit_postdef)
!                 {
!                 /* Check to see if the current value is the after value.  */
!                 unsigned int after_len = entry->after_len;
!                 /* strlen is required to avoid the prefix problem.  */
!                 if (definition == NULL
!                     || after_len != strlen (definition)
!                     || memcmp (definition, entry->after_str, after_len) != 0)
!                   {
!                     /* They do not have the same value.  */
!                     *bad_use = entry;
!                     *cur_def = definition;
!                     goto fail;
!                   }
!                 }
! 	      else
! 		{
! 		  *bad_use = entry;
! 		  *cur_def = definition;
! 		  goto fail;
! 		}
              }
            /* Otherwise, both agree it is not a macro.  */
          }
*************** fail:
*** 722,747 ****
    return false;
  }
  
  /* Produce the macro definition syntax NEEDED by cpp_define from
     the syntax GIVEN by cpp_macro_definition.  */
  
  static void
! cpp_lt_define_syntax (char *needed, const char *given)
  {
    char c;
  
-   c = *given++;
- 
    /* Copy over macro identifier.  */
!   while (   ('0' <= c && c <= '9')
!          || ('A' <= c && c <= 'Z')
!          || ('a' <= c && c <= 'z')
!          ||             (c == '_'))
      {
        *needed++ = c;
!       c = *given++;
      }
  
    if (c == '(')
      {
        /* Copy over parameter list.  */
--- 752,782 ----
    return false;
  }
  
+ bool
+ cpp_lt_verify (cpp_reader *reader, cpp_idents_used* identifiers,
+                cpp_ident_use **bad_use, const char **cur_def)
+ {
+   return cpp_lt_verify_1 (reader, identifiers, bad_use, cur_def, false);
+ }
+ 
  /* Produce the macro definition syntax NEEDED by cpp_define from
     the syntax GIVEN by cpp_macro_definition.  */
  
  static void
! cpp_lt_define_syntax (char *needed, const char *ident, const char *given)
  {
    char c;
  
    /* Copy over macro identifier.  */
!   c = *ident++;
!   while (c != '\0')
      {
        *needed++ = c;
!       c = *ident++;
      }
  
+   /* Copy over macro definition.  */
+   c = *given++;
    if (c == '(')
      {
        /* Copy over parameter list.  */
*************** cpp_lt_define_syntax (char *needed, cons
*** 759,767 ****
    /* Replace definition space by assignment.  */
    /* (c == ' ') */
    *needed++ = '=';
-   c = *given++;
  
!   /* Copy over macro identifier.  */
    while (c != '\0')
      {
        *needed++ = c;
--- 794,802 ----
    /* Replace definition space by assignment.  */
    /* (c == ' ') */
    *needed++ = '=';
  
!   /* Copy over macro value.  */
!   c = *given++;
    while (c != '\0')
      {
        *needed++ = c;
*************** cpp_lt_replay (cpp_reader *reader, cpp_i
*** 795,801 ****
          {
            if (after_str != NULL)
              {
!               cpp_lt_define_syntax (buffer, after_str);
                cpp_define (reader, buffer);
              }
            /* else consistently not macros */
--- 830,836 ----
          {
            if (after_str != NULL)
              {
!               cpp_lt_define_syntax (buffer, ident_str, after_str);
                cpp_define (reader, buffer);
              }
            /* else consistently not macros */
*************** cpp_lt_replay (cpp_reader *reader, cpp_i
*** 809,815 ****
            else if (strcmp (before_str, after_str) != 0)
              {
                cpp_undef (reader, ident_str);
!               cpp_lt_define_syntax (buffer, after_str);
                cpp_define (reader, buffer);
              }
            /* else macro with the same definition */
--- 844,850 ----
            else if (strcmp (before_str, after_str) != 0)
              {
                cpp_undef (reader, ident_str);
!               cpp_lt_define_syntax (buffer, ident_str, after_str);
                cpp_define (reader, buffer);
              }
            /* else macro with the same definition */
*************** void
*** 827,833 ****
  cpp_lt_idents_destroy (cpp_idents_used *identifiers)
  {
    obstack_free (identifiers->strings, NULL);
!   XDELETEVEC (identifiers);
  }
  
  /* Mappings from hash to index.  */
--- 862,868 ----
  cpp_lt_idents_destroy (cpp_idents_used *identifiers)
  {
    obstack_free (identifiers->strings, NULL);
!   XDELETEVEC (identifiers->entries);
  }
  
  /* Mappings from hash to index.  */
Index: libcpp/include/symtab.h
===================================================================
*** libcpp/include/symtab.h	(revision 170279)
--- libcpp/include/symtab.h	(working copy)
*************** cpp_lt_capture (struct cpp_reader *reade
*** 153,158 ****
--- 153,162 ----
     If not, set BAD_USE and CUR_DEF to indicate the first  
     inconsistency.  A null means 'not a macro'.  */
  bool
+ cpp_lt_verify_1 (struct cpp_reader *reader, cpp_idents_used* identifiers,
+                  cpp_ident_use **bad_use, const char **cur_def,
+                  int permit_postdef);
+ bool
  cpp_lt_verify (struct cpp_reader *reader, cpp_idents_used* identifiers,
                 cpp_ident_use **bad_use, const char **cur_def);