Daily bump.
[gcc.git] / libcpp / files.c
index 2bc3a801e3562e0d391ac7de6e69770073abd574..85c79a1ef9314a0734bfbcc9b4f7e6c05a89cf6b 100644 (file)
@@ -1,7 +1,5 @@
 /* Part of CPP library.  File handling.
-   Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright (C) 1986-2020 Free Software Foundation, Inc.
    Written by Per Bothner, 1994.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -10,7 +8,7 @@
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
+Free Software Foundation; either version 3, or (at your option) any
 later version.
 
 This program is distributed in the hope that it will be useful,
@@ -19,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+along with this program; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -52,7 +50,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 /* This structure represents a file searched for by CPP, whether it
    exists or not.  An instance may be pointed to by more than one
-   file_hash_entry; at present no reference count is kept.  */
+   cpp_file_hash_entry; at present no reference count is kept.  */
 struct _cpp_file
 {
   /* Filename as given to #include or command line switch.  */
@@ -74,6 +72,10 @@ struct _cpp_file
   /* The contents of NAME after calling read_file().  */
   const uchar *buffer;
 
+  /* Pointer to the real start of BUFFER.  read_file() might increment
+     BUFFER; when freeing, this this pointer must be used instead.  */
+  const uchar *buffer_start;
+
   /* The macro, if any, preventing re-inclusion.  */
   const cpp_hashnode *cmacro;
 
@@ -96,16 +98,19 @@ struct _cpp_file
   unsigned short stack_count;
 
   /* If opened with #import or contains #pragma once.  */
-  bool once_only;
+  bool once_only : 1;
 
   /* If read() failed before.  */
-  bool dont_read;
+  bool dont_read : 1;
 
   /* If this file is the main file.  */
-  bool main_file;
+  bool main_file : 1;
 
   /* If BUFFER above contains the true contents of the file.  */
-  bool buffer_valid;
+  bool buffer_valid : 1;
+
+  /* If this file is implicitly preincluded.  */
+  bool implicit_preinclude : 1;
 };
 
 /* A singly-linked list for all searches for a given file name, with
@@ -135,11 +140,11 @@ struct _cpp_file
    have to do more work re-preprocessing the file, and/or comparing
    its contents against earlier once-only files.
 */
-struct file_hash_entry
+struct cpp_file_hash_entry
 {
-  struct file_hash_entry *next;
+  struct cpp_file_hash_entry *next;
   cpp_dir *start_dir;
-  source_location location;
+  location_t location;
   union
   {
     _cpp_file *file;
@@ -147,10 +152,10 @@ struct file_hash_entry
   } u;
 };
 
-/* Number of entries to put in a file_hash_entry pool.  */
+/* Number of entries to put in a cpp_file_hash_entry pool.  */
 #define FILE_HASH_POOL_SIZE 127
 
-/* A file hash entry pool.  We allocate file_hash_entry object from
+/* A file hash entry pool.  We allocate cpp_file_hash_entry object from
    one of these.  */
 struct file_hash_entry_pool
 {
@@ -159,28 +164,30 @@ struct file_hash_entry_pool
   /* Next pool in the chain; used when freeing.  */
   struct file_hash_entry_pool *next;
   /* The memory pool.  */
-  struct file_hash_entry pool[FILE_HASH_POOL_SIZE];
+  struct cpp_file_hash_entry pool[FILE_HASH_POOL_SIZE];
 };
 
 static bool open_file (_cpp_file *file);
 static bool pch_open_file (cpp_reader *pfile, _cpp_file *file,
                           bool *invalid_pch);
 static bool find_file_in_dir (cpp_reader *pfile, _cpp_file *file,
-                             bool *invalid_pch);
-static bool read_file_guts (cpp_reader *pfile, _cpp_file *file);
-static bool read_file (cpp_reader *pfile, _cpp_file *file);
-static bool should_stack_file (cpp_reader *, _cpp_file *file, bool import);
+                             bool *invalid_pch, location_t loc);
+static bool read_file_guts (cpp_reader *pfile, _cpp_file *file,
+                           location_t loc);
+static bool read_file (cpp_reader *pfile, _cpp_file *file,
+                      location_t loc);
 static struct cpp_dir *search_path_head (cpp_reader *, const char *fname,
                                 int angle_brackets, enum include_type);
 static const char *dir_name_of_file (_cpp_file *file);
-static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int);
-static struct file_hash_entry *search_cache (struct file_hash_entry *head,
+static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int,
+                             location_t);
+static struct cpp_file_hash_entry *search_cache (struct cpp_file_hash_entry *head,
                                             const cpp_dir *start_dir);
 static _cpp_file *make_cpp_file (cpp_reader *, cpp_dir *, const char *fname);
 static void destroy_cpp_file (_cpp_file *);
 static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp);
 static void allocate_file_hash_entries (cpp_reader *pfile);
-static struct file_hash_entry *new_file_hash_entry (cpp_reader *pfile);
+static struct cpp_file_hash_entry *new_file_hash_entry (cpp_reader *pfile);
 static int report_missing_guard (void **slot, void *b);
 static hashval_t file_hash_hash (const void *p);
 static int file_hash_eq (const void *p, const void *q);
@@ -284,6 +291,16 @@ pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
   if (file->name[0] == '\0' || !pfile->cb.valid_pch)
     return false;
 
+  /* If the file is not included as first include from either the toplevel
+     file or the command-line it is not a valid use of PCH.  */
+  for (_cpp_file *f = pfile->all_files; f; f = f->next_file)
+    if (f->implicit_preinclude)
+      continue;
+    else if (f->main_file)
+      break;
+    else
+      return false;
+
   flen = strlen (path);
   len = flen + sizeof (extension);
   pchname = XNEWVEC (char, len);
@@ -331,13 +348,34 @@ pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
   return valid;
 }
 
+/* Canonicalize the path to FILE.  Return the canonical form if it is
+   shorter, otherwise return NULL.  This function does NOT free the
+   memory pointed by FILE.  */
+
+static char *
+maybe_shorter_path (const char * file)
+{
+  char * file2 = lrealpath (file);
+  if (file2 && strlen (file2) < strlen (file))
+    {
+      return file2;
+    }
+  else 
+    {
+      free (file2);
+      return NULL;
+    }
+}
+
 /* Try to open the path FILE->name appended to FILE->dir.  This is
    where remap and PCH intercept the file lookup process.  Return true
    if the file was found, whether or not the open was successful.
-   Set *INVALID_PCH to true if a PCH file is found but wasn't valid.  */
+   Set *INVALID_PCH to true if a PCH file is found but wasn't valid.
+   Use LOC when emitting any diagnostics.  */
 
 static bool
-find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
+find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch,
+                 location_t loc)
 {
   char *path;
 
@@ -351,10 +389,30 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
 
   if (path)
     {
-      hashval_t hv = htab_hash_string (path);
+      hashval_t hv;
       char *copy;
       void **pp;
 
+      /* We try to canonicalize system headers.  For DOS based file
+       * system, we always try to shorten non-system headers, as DOS
+       * has a tighter constraint on max path length.  */
+      if ((CPP_OPTION (pfile, canonical_system_headers) && file->dir->sysp)
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+         || !file->dir->sysp
+#endif
+        )
+       {
+         char * canonical_path = maybe_shorter_path (path);
+         if (canonical_path)
+           {
+             /* The canonical path was newly allocated.  Let's free the
+                non-canonical one.  */
+             free (path);
+             path = canonical_path;
+           }
+       }
+
+      hv = htab_hash_string (path);
       if (htab_find_with_hash (pfile->nonexistent_file_hash, path, hv) != NULL)
        {
          file->err_no = ENOENT;
@@ -370,15 +428,15 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
 
       if (file->err_no != ENOENT)
        {
-         open_file_failed (pfile, file, 0);
+         open_file_failed (pfile, file, 0, loc);
          return true;
        }
 
       /* We copy the path name onto an obstack partly so that we don't
         leak the memory, but mostly so that we don't fragment the
         heap.  */
-      copy = obstack_copy0 (&pfile->nonexistent_file_ob, path,
-                           strlen (path));
+      copy = (char *) obstack_copy0 (&pfile->nonexistent_file_ob, path,
+                                    strlen (path));
       free (path);
       pp = htab_find_slot_with_hash (pfile->nonexistent_file_hash,
                                     copy, hv, INSERT);
@@ -395,7 +453,7 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
   return false;
 }
 
-/* Return tue iff the missing_header callback found the given HEADER.  */
+/* Return true iff the missing_header callback found the given HEADER.  */
 static bool
 search_path_exhausted (cpp_reader *pfile, const char *header, _cpp_file *file)
 {
@@ -437,12 +495,17 @@ _cpp_find_failed (_cpp_file *file)
    descriptor.  FD can be -1 if the file was found in the cache and
    had previously been closed.  To open it again pass the return value
    to open_file().
-*/
+
+   If KIND is _cpp_FFK_PRE_INCLUDE then it is OK for the file to be
+   missing.  If present, it is OK for a precompiled header to be
+   included after it.
+
+   Use LOC as the location for any errors.  */
+
 _cpp_file *
-_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool fake, int angle_brackets)
+_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
+               int angle_brackets, _cpp_find_file_kind kind, location_t loc)
 {
-  struct file_hash_entry *entry, **hash_slot;
-  _cpp_file *file;
   bool invalid_pch = false;
   bool saw_bracket_include = false;
   bool saw_quote_include = false;
@@ -450,69 +513,104 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool f
 
   /* Ensure we get no confusion between cached files and directories.  */
   if (start_dir == NULL)
-    cpp_error (pfile, CPP_DL_ICE, "NULL directory in find_file");
+    cpp_error_at (pfile, CPP_DL_ICE, loc, "NULL directory in find_file");
 
-  hash_slot = (struct file_hash_entry **)
-    htab_find_slot_with_hash (pfile->file_hash, fname,
-                             htab_hash_string (fname),
-                             INSERT);
+  void **hash_slot
+    = htab_find_slot_with_hash (pfile->file_hash, fname,
+                               htab_hash_string (fname), INSERT);
 
   /* First check the cache before we resort to memory allocation.  */
-  entry = search_cache (*hash_slot, start_dir);
+  cpp_file_hash_entry *entry
+    = search_cache ((struct cpp_file_hash_entry *) *hash_slot, start_dir);
   if (entry)
     return entry->u.file;
 
-  file = make_cpp_file (pfile, start_dir, fname);
-
-  /* Try each path in the include chain.  */
-  for (; !fake ;)
-    {
-      if (find_file_in_dir (pfile, file, &invalid_pch))
-       break;
+  _cpp_file *file = make_cpp_file (pfile, start_dir, fname);
+  file->implicit_preinclude
+    = (kind == _cpp_FFK_PRE_INCLUDE
+       || (pfile->buffer && pfile->buffer->file->implicit_preinclude));
 
-      file->dir = file->dir->next;
-      if (file->dir == NULL)
-       {
-         if (search_path_exhausted (pfile, fname, file))
-           {
-             /* Although this file must not go in the cache, because
-                the file found might depend on things (like the current file)
-                that aren't represented in the cache, it still has to go in
-                the list of all files so that #import works.  */
-             file->next_file = pfile->all_files;
-             pfile->all_files = file;
-             return file;
-           }
-
-         open_file_failed (pfile, file, angle_brackets);
-         if (invalid_pch)
-           {
-             cpp_error (pfile, CPP_DL_ERROR,
-              "one or more PCH files were found, but they were invalid");
-             if (!cpp_get_options (pfile)->warn_invalid_pch)
-               cpp_error (pfile, CPP_DL_ERROR,
-                          "use -Winvalid-pch for more information");
-           }
+  if (kind != _cpp_FFK_FAKE)
+    /* Try each path in the include chain.  */
+    for (;;)
+      {
+       if (find_file_in_dir (pfile, file, &invalid_pch, loc))
          break;
-       }
-
-      /* Only check the cache for the starting location (done above)
-        and the quote and bracket chain heads because there are no
-        other possible starting points for searches.  */
-      if (file->dir == pfile->bracket_include)
-       saw_bracket_include = true;
-      else if (file->dir == pfile->quote_include)
-       saw_quote_include = true;
-      else
-       continue;
 
-      entry = search_cache (*hash_slot, file->dir);
-      if (entry)
-       {
-         found_in_cache = file->dir;
-         break;
-       }
-    }
+       file->dir = file->dir->next;
+       if (file->dir == NULL)
+         {
+           if (search_path_exhausted (pfile, fname, file))
+             {
+               /* Although this file must not go in the cache,
+                  because the file found might depend on things (like
+                  the current file) that aren't represented in the
+                  cache, it still has to go in the list of all files
+                  so that #import works.  */
+               file->next_file = pfile->all_files;
+               pfile->all_files = file;
+               if (*hash_slot == NULL)
+                 {
+                   /* If *hash_slot is NULL, the above
+                      htab_find_slot_with_hash call just created the
+                      slot, but we aren't going to store there
+                      anything, so need to remove the newly created
+                      entry.  htab_clear_slot requires that it is
+                      non-NULL, so store there some non-NULL pointer,
+                      htab_clear_slot will overwrite it
+                      immediately.  */
+                   *hash_slot = file;
+                   htab_clear_slot (pfile->file_hash, hash_slot);
+                 }
+               return file;
+             }
+
+           if (invalid_pch)
+             {
+               cpp_error (pfile, CPP_DL_ERROR,
+                          "one or more PCH files were found,"
+                          " but they were invalid");
+               if (!cpp_get_options (pfile)->warn_invalid_pch)
+                 cpp_error (pfile, CPP_DL_ERROR,
+                            "use -Winvalid-pch for more information");
+             }
+
+           if (kind == _cpp_FFK_PRE_INCLUDE)
+             {
+               free ((char *) file->name);
+               free (file);
+               if (*hash_slot == NULL)
+                 {
+                   /* See comment on the above htab_clear_slot call.  */
+                   *hash_slot = file;
+                   htab_clear_slot (pfile->file_hash, hash_slot);
+                 }
+               return NULL;
+             }
+
+           if (kind != _cpp_FFK_HAS_INCLUDE)
+             open_file_failed (pfile, file, angle_brackets, loc);
+           break;
+         }
+
+       /* Only check the cache for the starting location (done above)
+          and the quote and bracket chain heads because there are no
+          other possible starting points for searches.  */
+       if (file->dir == pfile->bracket_include)
+         saw_bracket_include = true;
+       else if (file->dir == pfile->quote_include)
+         saw_quote_include = true;
+       else
+         continue;
+
+       entry
+         = search_cache ((struct cpp_file_hash_entry *) *hash_slot, file->dir);
+       if (entry)
+         {
+           found_in_cache = file->dir;
+           break;
+         }
+      }
 
   if (entry)
     {
@@ -530,11 +628,11 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool f
 
   /* Store this new result in the hash table.  */
   entry = new_file_hash_entry (pfile);
-  entry->next = *hash_slot;
+  entry->next = (struct cpp_file_hash_entry *) *hash_slot;
   entry->start_dir = start_dir;
-  entry->location = pfile->line_table->highest_location;
+  entry->location = loc;
   entry->u.file = file;
-  *hash_slot = entry;
+  *hash_slot = (void *) entry;
 
   /* If we passed the quote or bracket chain heads, cache them also.
      This speeds up processing if there are lots of -I options.  */
@@ -543,22 +641,22 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool f
       && found_in_cache != pfile->bracket_include)
     {
       entry = new_file_hash_entry (pfile);
-      entry->next = *hash_slot;
+      entry->next = (struct cpp_file_hash_entry *) *hash_slot;
       entry->start_dir = pfile->bracket_include;
-      entry->location = pfile->line_table->highest_location;
+      entry->location = loc;
       entry->u.file = file;
-      *hash_slot = entry;
+      *hash_slot = (void *) entry;
     }
   if (saw_quote_include
       && pfile->quote_include != start_dir
       && found_in_cache != pfile->quote_include)
     {
       entry = new_file_hash_entry (pfile);
-      entry->next = *hash_slot;
+      entry->next = (struct cpp_file_hash_entry *) *hash_slot;
       entry->start_dir = pfile->quote_include;
-      entry->location = pfile->line_table->highest_location;
+      entry->location = loc;
       entry->u.file = file;
-      *hash_slot = entry;
+      *hash_slot = (void *) entry;
     }
 
   return file;
@@ -571,9 +669,11 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool f
    except for plain files and block devices, since there is no
    reliable portable way of doing this.
 
+   Use LOC for any diagnostics.
+
    FIXME: Flush file cache and try again if we run out of memory.  */
 static bool
-read_file_guts (cpp_reader *pfile, _cpp_file *file)
+read_file_guts (cpp_reader *pfile, _cpp_file *file, location_t loc)
 {
   ssize_t size, total, count;
   uchar *buf;
@@ -581,11 +681,12 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file)
 
   if (S_ISBLK (file->st.st_mode))
     {
-      cpp_error (pfile, CPP_DL_ERROR, "%s is a block device", file->path);
+      cpp_error_at (pfile, CPP_DL_ERROR, loc,
+                   "%s is a block device", file->path);
       return false;
     }
 
-  regular = S_ISREG (file->st.st_mode);
+  regular = S_ISREG (file->st.st_mode) != 0;
   if (regular)
     {
       /* off_t might have a wider range than ssize_t - in other words,
@@ -598,7 +699,8 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file)
         does not bite us.  */
       if (file->st.st_size > INTTYPE_MAXIMUM (ssize_t))
        {
-         cpp_error (pfile, CPP_DL_ERROR, "%s is too large", file->path);
+         cpp_error_at (pfile, CPP_DL_ERROR, loc,
+                       "%s is too large", file->path);
          return false;
        }
 
@@ -610,7 +712,11 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file)
        the majority of C source files.  */
     size = 8 * 1024;
 
-  buf = XNEWVEC (uchar, size + 1);
+  /* The + 16 here is space for the final '\n' and 15 bytes of padding,
+     used to quiet warnings from valgrind or Address Sanitizer, when the
+     optimized lexer accesses aligned 16-byte memory chunks, including
+     the bytes after the malloced, area, and stops lexing on '\n'.  */
+  buf = XNEWVEC (uchar, size + 16);
   total = 0;
   while ((count = read (file->fd, buf + total, size - total)) > 0)
     {
@@ -621,22 +727,26 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file)
          if (regular)
            break;
          size *= 2;
-         buf = XRESIZEVEC (uchar, buf, size + 1);
+         buf = XRESIZEVEC (uchar, buf, size + 16);
        }
     }
 
   if (count < 0)
     {
-      cpp_errno (pfile, CPP_DL_ERROR, file->path);
+      cpp_errno_filename (pfile, CPP_DL_ERROR, file->path, loc);
+      free (buf);
       return false;
     }
 
   if (regular && total != size && STAT_SIZE_RELIABLE (file->st))
-    cpp_error (pfile, CPP_DL_WARNING,
+    cpp_error_at (pfile, CPP_DL_WARNING, loc,
               "%s is shorter than expected", file->path);
 
-  file->buffer = _cpp_convert_input (pfile, CPP_OPTION (pfile, input_charset),
-                                    buf, size, total, &file->st.st_size);
+  file->buffer = _cpp_convert_input (pfile,
+                                    CPP_OPTION (pfile, input_charset),
+                                    buf, size + 16, total,
+                                    &file->buffer_start,
+                                    &file->st.st_size);
   file->buffer_valid = true;
 
   return true;
@@ -644,9 +754,10 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file)
 
 /* Convenience wrapper around read_file_guts that opens the file if
    necessary and closes the file descriptor after reading.  FILE must
-   have been passed through find_file() at some stage.  */
+   have been passed through find_file() at some stage.  Use LOC for
+   any diagnostics.  */
 static bool
-read_file (cpp_reader *pfile, _cpp_file *file)
+read_file (cpp_reader *pfile, _cpp_file *file, location_t loc)
 {
   /* If we already have its contents in memory, succeed immediately.  */
   if (file->buffer_valid)
@@ -658,27 +769,25 @@ read_file (cpp_reader *pfile, _cpp_file *file)
 
   if (file->fd == -1 && !open_file (file))
     {
-      open_file_failed (pfile, file, 0);
+      open_file_failed (pfile, file, 0, loc);
       return false;
     }
 
-  file->dont_read = !read_file_guts (pfile, file);
+  file->dont_read = !read_file_guts (pfile, file, loc);
   close (file->fd);
   file->fd = -1;
 
   return !file->dont_read;
 }
 
-/* Returns TRUE if FILE's contents have been successfully placed in
-   FILE->buffer and the file should be stacked, otherwise false.  */
+/* Returns TRUE if FILE is already known to be idempotent, and should
+   therefore not be read again.  */
 static bool
-should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
+is_known_idempotent_file (cpp_reader *pfile, _cpp_file *file, bool import)
 {
-  _cpp_file *f;
-
   /* Skip once-only files.  */
   if (file->once_only)
-    return false;
+    return true;
 
   /* We must mark the file once-only if #import now, before header
      guard checks.  Otherwise, undefining the header guard might
@@ -689,13 +798,13 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
 
       /* Don't stack files that have been stacked before.  */
       if (file->stack_count)
-       return false;
+       return true;
     }
 
   /* Skip if the file had a header guard and the macro is defined.
      PCH relies on this appearing before the PCH handler below.  */
-  if (file->cmacro && file->cmacro->type == NT_MACRO)
-    return false;
+  if (file->cmacro && cpp_macro_p (file->cmacro))
+    return true;
 
   /* Handle PCH files immediately; don't stack them.  */
   if (file->pchname)
@@ -704,12 +813,19 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
       file->fd = -1;
       free ((void *) file->pchname);
       file->pchname = NULL;
-      return false;
+      return true;
     }
 
-  if (!read_file (pfile, file))
-    return false;
+  return false;
+}
+
+/* Return TRUE if file has unique contents, so we should read process
+   it.  The file's contents must already have been read.  */
 
+static bool
+has_unique_contents (cpp_reader *pfile, _cpp_file *file, bool import,
+                    location_t loc)
+{
   /* Check the file against the PCH file.  This is done before
      checking against files we've already seen, since it may save on
      I/O.  */
@@ -730,10 +846,10 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
 
   /* We may have read the file under a different name.  Look
      for likely candidates and compare file contents to be sure.  */
-  for (f = pfile->all_files; f; f = f->next_file)
+  for (_cpp_file *f = pfile->all_files; f; f = f->next_file)
     {
       if (f == file)
-       continue;
+       continue; /* It'sa me!  */
 
       if ((import || f->once_only)
          && f->err_no == 0
@@ -741,7 +857,6 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
          && f->st.st_size == file->st.st_size)
        {
          _cpp_file *ref_file;
-         bool same_file_p = false;
 
          if (f->buffer && !f->buffer_valid)
            {
@@ -754,12 +869,11 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
            /* The file is not stacked anymore.  We can reuse it.  */
            ref_file = f;
 
-         same_file_p = read_file (pfile, ref_file)
-                       /* Size might have changed in read_file().  */
-                       && ref_file->st.st_size == file->st.st_size
-                       && !memcmp (ref_file->buffer,
-                                   file->buffer,
-                                   file->st.st_size);
+         bool same_file_p = (read_file (pfile, ref_file, loc)
+                             /* Size might have changed in read_file().  */
+                             && ref_file->st.st_size == file->st.st_size
+                             && !memcmp (ref_file->buffer, file->buffer,
+                                         file->st.st_size));
 
          if (f->buffer && !f->buffer_valid)
            {
@@ -768,54 +882,71 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
            }
 
          if (same_file_p)
-           break;
+           /* Already seen under a different name.  */
+           return false;
        }
     }
 
-  return f == NULL;
+  return true;
 }
 
 /* Place the file referenced by FILE into a new buffer on the buffer
    stack if possible.  IMPORT is true if this stacking attempt is
    because of a #import directive.  Returns true if a buffer is
-   stacked.  */
+   stacked.  Use LOC for any diagnostics.  */
 bool
-_cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
+_cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type,
+                location_t loc)
 {
-  cpp_buffer *buffer;
-  int sysp;
+  if (is_known_idempotent_file (pfile, file, type == IT_IMPORT))
+    return false;
 
-  if (!should_stack_file (pfile, file, import))
-      return false;
+  if (!read_file (pfile, file, loc))
+    return false;
 
-  if (pfile->buffer == NULL || file->dir == NULL)
-    sysp = 0;
-  else
-    sysp = MAX (pfile->buffer->sysp,  file->dir->sysp);
+  if (!has_unique_contents (pfile, file, type == IT_IMPORT, loc))
+    return false;
+
+  int sysp = 0;
+  if (pfile->buffer && file->dir)
+    sysp = MAX (pfile->buffer->sysp, file->dir->sysp);
 
   /* Add the file to the dependencies on its first inclusion.  */
-  if (CPP_OPTION (pfile, deps.style) > !!sysp && !file->stack_count)
-    {
-      if (!file->main_file || !CPP_OPTION (pfile, deps.ignore_main_file))
-       deps_add_dep (pfile->deps, file->path);
-    }
+  if (CPP_OPTION (pfile, deps.style) > (sysp != 0)
+      && !file->stack_count
+      && file->path[0]
+      && !(file->main_file && CPP_OPTION (pfile, deps.ignore_main_file)))
+    deps_add_dep (pfile->deps, file->path);
 
   /* Clear buffer_valid since _cpp_clean_line messes it up.  */
   file->buffer_valid = false;
   file->stack_count++;
 
   /* Stack the buffer.  */
-  buffer = cpp_push_buffer (pfile, file->buffer, file->st.st_size,
-                           CPP_OPTION (pfile, preprocessed)
-                           && !CPP_OPTION (pfile, directives_only));
+  cpp_buffer *buffer
+    = cpp_push_buffer (pfile, file->buffer, file->st.st_size,
+                      CPP_OPTION (pfile, preprocessed)
+                      && !CPP_OPTION (pfile, directives_only));
   buffer->file = file;
   buffer->sysp = sysp;
+  buffer->to_free = file->buffer_start;
 
   /* Initialize controlling macro state.  */
   pfile->mi_valid = true;
   pfile->mi_cmacro = 0;
 
-  /* Generate the call back.  */
+  /* In the case of a normal #include, we're now at the start of the
+     line *following* the #include.  A separate location_t for this
+     location makes no sense, until we do the LC_LEAVE.
+
+     This does not apply if we found a PCH file, we're not a regular
+     include, or we ran out of locations.  */
+  if (file->pchname == NULL
+      && type < IT_DIRECTIVE_HWM
+      && pfile->line_table->highest_location != LINE_MAP_MAX_LOCATION - 1)
+    pfile->line_table->highest_location--;
+
+  /* Add line map and do callbacks.  */
   _cpp_do_file_change (pfile, LC_ENTER, file->path, 1, sysp);
 
   return true;
@@ -894,55 +1025,78 @@ dir_name_of_file (_cpp_file *file)
    Returns true if a buffer was stacked.  */
 bool
 _cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets,
-                   enum include_type type)
+                   enum include_type type, location_t loc)
 {
-  struct cpp_dir *dir;
-  _cpp_file *file;
-
-  dir = search_path_head (pfile, fname, angle_brackets, type);
+  /* For -include command-line flags we have type == IT_CMDLINE.
+     When the first -include file is processed we have the case, where
+     pfile->cur_token == pfile->cur_run->base, we are directly called up
+     by the front end.  However in the case of the second -include file,
+     we are called from _cpp_lex_token -> _cpp_get_fresh_line ->
+     cpp_push_include, with pfile->cur_token != pfile->cur_run->base,
+     and pfile->cur_token[-1].src_loc not (yet) initialized.
+     However, when the include file cannot be found, we need src_loc to
+     be initialized to some safe value: 0 means UNKNOWN_LOCATION.  */
+  if (type == IT_CMDLINE && pfile->cur_token != pfile->cur_run->base)
+    pfile->cur_token[-1].src_loc = 0;
+
+  cpp_dir *dir = search_path_head (pfile, fname, angle_brackets, type);
   if (!dir)
     return false;
 
-  file = _cpp_find_file (pfile, fname, dir, false, angle_brackets);
-
-  /* Compensate for the increment in linemap_add.  In the case of a
-     normal #include, we're currently at the start of the line
-     *following* the #include.  A separate source_location for this
-     location makes no sense (until we do the LC_LEAVE), and
-     complicates LAST_SOURCE_LINE_LOCATION.  This does not apply if we
-     found a PCH file (in which case linemap_add is not called) or we
-     were included from the command-line.  */
-  if (file->pchname == NULL && file->err_no == 0 && type != IT_CMDLINE)
-    pfile->line_table->highest_location--;
+  _cpp_file *file = _cpp_find_file (pfile, fname, dir, angle_brackets,
+                                   type == IT_DEFAULT ? _cpp_FFK_PRE_INCLUDE
+                                   : _cpp_FFK_NORMAL, loc);
+  if (type == IT_DEFAULT && file == NULL)
+    return false;
 
-  return _cpp_stack_file (pfile, file, type == IT_IMPORT);
+  return _cpp_stack_file (pfile, file, type, loc);
 }
 
 /* Could not open FILE.  The complication is dependency output.  */
 static void
-open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets)
+open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets,
+                 location_t loc)
 {
   int sysp = pfile->line_table->highest_line > 1 && pfile->buffer ? pfile->buffer->sysp : 0;
   bool print_dep = CPP_OPTION (pfile, deps.style) > (angle_brackets || !!sysp);
 
   errno = file->err_no;
   if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT)
-    deps_add_dep (pfile->deps, file->name);
+    {
+      deps_add_dep (pfile->deps, file->name);
+      /* If the preprocessor output (other than dependency information) is
+         being used, we must also flag an error.  */
+      if (CPP_OPTION (pfile, deps.need_preprocessor_output))
+       cpp_errno_filename (pfile, CPP_DL_FATAL,
+                           file->path ? file->path : file->name,
+                           loc);
+    }
   else
     {
-      /* If we are outputting dependencies but not for this file then
-        don't error because we can still produce correct output.  */
-      if (CPP_OPTION (pfile, deps.style) && ! print_dep)
-       cpp_errno (pfile, CPP_DL_WARNING, file->path);
+      /* If we are not outputting dependencies, or if we are and dependencies
+         were requested for this file, or if preprocessor output is needed
+         in addition to dependency information, this is an error.
+
+         Otherwise (outputting dependencies but not for this file, and not
+         using the preprocessor output), we can still produce correct output
+         so it's only a warning.  */
+      if (CPP_OPTION (pfile, deps.style) == DEPS_NONE
+          || print_dep
+          || CPP_OPTION (pfile, deps.need_preprocessor_output))
+       cpp_errno_filename (pfile, CPP_DL_FATAL,
+                           file->path ? file->path : file->name,
+                           loc);
       else
-       cpp_errno (pfile, CPP_DL_ERROR, file->path);
+       cpp_errno_filename (pfile, CPP_DL_WARNING,
+                           file->path ? file->path : file->name,
+                           loc);
     }
 }
 
 /* Search in the chain beginning at HEAD for a file whose search path
    started at START_DIR != NULL.  */
-static struct file_hash_entry *
-search_cache (struct file_hash_entry *head, const cpp_dir *start_dir)
+static struct cpp_file_hash_entry *
+search_cache (struct cpp_file_hash_entry *head, const cpp_dir *start_dir)
 {
   while (head && head->start_dir != start_dir)
     head = head->next;
@@ -969,9 +1123,9 @@ make_cpp_file (cpp_reader *pfile, cpp_dir *dir, const char *fname)
 static void
 destroy_cpp_file (_cpp_file *file)
 {
-  if (file->buffer)
-    free ((void *) file->buffer);
+  free ((void *) file->buffer_start);
   free ((void *) file->name);
+  free ((void *) file->path);
   free (file);
 }
 
@@ -998,10 +1152,10 @@ destroy_all_cpp_files (cpp_reader *pfile)
 static cpp_dir *
 make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp)
 {
-  struct file_hash_entry *entry, **hash_slot;
+  struct cpp_file_hash_entry *entry, **hash_slot;
   cpp_dir *dir;
 
-  hash_slot = (struct file_hash_entry **)
+  hash_slot = (struct cpp_file_hash_entry **)
     htab_find_slot_with_hash (pfile->dir_hash, dir_name,
                              htab_hash_string (dir_name),
                              INSERT);
@@ -1040,7 +1194,7 @@ allocate_file_hash_entries (cpp_reader *pfile)
 }
 
 /* Return a new file hash entry.  */
-static struct file_hash_entry *
+static struct cpp_file_hash_entry *
 new_file_hash_entry (cpp_reader *pfile)
 {
   unsigned int idx;
@@ -1070,9 +1224,9 @@ free_file_hash_entries (cpp_reader *pfile)
 bool
 cpp_included (cpp_reader *pfile, const char *fname)
 {
-  struct file_hash_entry *entry;
+  struct cpp_file_hash_entry *entry;
 
-  entry = (struct file_hash_entry *)
+  entry = (struct cpp_file_hash_entry *)
      htab_find_with_hash (pfile->file_hash, fname, htab_hash_string (fname));
 
   while (entry && (entry->start_dir == NULL || entry->u.file->err_no))
@@ -1086,12 +1240,14 @@ cpp_included (cpp_reader *pfile, const char *fname)
    filenames aliased by links or redundant . or .. traversals etc.  */
 bool
 cpp_included_before (cpp_reader *pfile, const char *fname,
-                    source_location location)
+                    location_t location)
 {
-  struct file_hash_entry *entry;
+  struct cpp_file_hash_entry *entry
+    = (struct cpp_file_hash_entry *)
+      htab_find_with_hash (pfile->file_hash, fname, htab_hash_string (fname));
 
-  entry = (struct file_hash_entry *)
-     htab_find_with_hash (pfile->file_hash, fname, htab_hash_string (fname));
+  if (IS_ADHOC_LOC (location))
+    location = get_location_from_adhoc_loc (pfile->line_table, location);
 
   while (entry && (entry->start_dir == NULL || entry->u.file->err_no
                   || entry->location > location))
@@ -1105,7 +1261,7 @@ cpp_included_before (cpp_reader *pfile, const char *fname,
 static hashval_t
 file_hash_hash (const void *p)
 {
-  struct file_hash_entry *entry = (struct file_hash_entry *) p;
+  struct cpp_file_hash_entry *entry = (struct cpp_file_hash_entry *) p;
   const char *hname;
   if (entry->start_dir)
     hname = entry->u.file->name;
@@ -1119,7 +1275,7 @@ file_hash_hash (const void *p)
 static int
 file_hash_eq (const void *p, const void *q)
 {
-  struct file_hash_entry *entry = (struct file_hash_entry *) p;
+  struct cpp_file_hash_entry *entry = (struct cpp_file_hash_entry *) p;
   const char *fname = (const char *) q;
   const char *hname;
 
@@ -1128,7 +1284,7 @@ file_hash_eq (const void *p, const void *q)
   else
     hname = entry->u.dir->name;
 
-  return strcmp (hname, fname) == 0;
+  return filename_cmp (hname, fname) == 0;
 }
 
 /* Compare entries in the nonexistent file hash table.  These are just
@@ -1136,7 +1292,7 @@ file_hash_eq (const void *p, const void *q)
 static int
 nonexistent_file_hash_eq (const void *p, const void *q)
 {
-  return strcmp (p, q) == 0;
+  return filename_cmp ((const char *) p, (const char *) q) == 0;
 }
 
 /* Initialize everything in this source file.  */
@@ -1151,9 +1307,8 @@ _cpp_init_files (cpp_reader *pfile)
   pfile->nonexistent_file_hash = htab_create_alloc (127, htab_hash_string,
                                                    nonexistent_file_hash_eq,
                                                    NULL, xcalloc, free);
-  _obstack_begin (&pfile->nonexistent_file_ob, 0, 0,
-                 (void *(*) (long)) xmalloc,
-                 (void (*) (void *)) free);
+  obstack_specify_allocation (&pfile->nonexistent_file_ob, 0, 0,
+                             xmalloc, free);
 }
 
 /* Finalize everything in this source file.  */
@@ -1183,7 +1338,7 @@ cpp_clear_file_cache (cpp_reader *pfile)
 void
 _cpp_fake_include (cpp_reader *pfile, const char *fname)
 {
-  _cpp_find_file (pfile, fname, pfile->buffer->file->dir, true, 0);
+  _cpp_find_file (pfile, fname, pfile->buffer->file->dir, 0, _cpp_FFK_FAKE, 0);
 }
 
 /* Not everyone who wants to set system-header-ness on a buffer can
@@ -1193,15 +1348,15 @@ void
 cpp_make_system_header (cpp_reader *pfile, int syshdr, int externc)
 {
   int flags = 0;
-  const struct line_maps *line_table = pfile->line_table;
-  const struct line_map *map = &line_table->maps[line_table->used-1];
-
+  const class line_maps *line_table = pfile->line_table;
+  const line_map_ordinary *map = LINEMAPS_LAST_ORDINARY_MAP (line_table);
   /* 1 = system header, 2 = system header to be treated as C.  */
   if (syshdr)
     flags = 1 + (externc != 0);
   pfile->buffer->sysp = flags;
-  _cpp_do_file_change (pfile, LC_RENAME, map->to_file,
-                      SOURCE_LINE (map, pfile->line_table->highest_line), flags);
+  _cpp_do_file_change (pfile, LC_RENAME, ORDINARY_MAP_FILE_NAME (map),
+                      SOURCE_LINE (map, pfile->line_table->highest_line),
+                      flags);
 }
 
 /* Allow the client to change the current file.  Used by the front end
@@ -1214,12 +1369,19 @@ cpp_change_file (cpp_reader *pfile, enum lc_reason reason,
   _cpp_do_file_change (pfile, reason, new_name, 1, 0);
 }
 
+struct report_missing_guard_data
+{
+  const char **paths;
+  size_t count;
+};
+
 /* Callback function for htab_traverse.  */
 static int
-report_missing_guard (void **slot, void *b)
+report_missing_guard (void **slot, void *d)
 {
-  struct file_hash_entry *entry = (struct file_hash_entry *) *slot;
-  int *bannerp = (int *) b;
+  struct cpp_file_hash_entry *entry = (struct cpp_file_hash_entry *) *slot;
+  struct report_missing_guard_data *data
+    = (struct report_missing_guard_data *) d;
 
   /* Skip directories.  */
   if (entry->start_dir != NULL)
@@ -1227,21 +1389,28 @@ report_missing_guard (void **slot, void *b)
       _cpp_file *file = entry->u.file;
 
       /* We don't want MI guard advice for the main file.  */
-      if (file->cmacro == NULL && file->stack_count == 1 && !file->main_file)
+      if (!file->once_only && file->cmacro == NULL
+         && file->stack_count == 1 && !file->main_file)
        {
-         if (*bannerp == 0)
+         if (data->paths == NULL)
            {
-             fputs (_("Multiple include guards may be useful for:\n"),
-                    stderr);
-             *bannerp = 1;
+             data->paths = XCNEWVEC (const char *, data->count);
+             data->count = 0;
            }
 
-         fputs (entry->u.file->path, stderr);
-         putc ('\n', stderr);
+         data->paths[data->count++] = file->path;
        }
     }
 
-  return 0;
+  /* Keep traversing the hash table.  */
+  return 1;
+}
+
+/* Comparison function for qsort.  */
+static int
+report_missing_guard_cmp (const void *p1, const void *p2)
+{
+  return strcmp (*(const char *const *) p1, *(const char *const *) p2);
 }
 
 /* Report on all files that might benefit from a multiple include guard.
@@ -1249,9 +1418,29 @@ report_missing_guard (void **slot, void *b)
 void
 _cpp_report_missing_guards (cpp_reader *pfile)
 {
-  int banner = 0;
+  struct report_missing_guard_data data;
 
-  htab_traverse (pfile->file_hash, report_missing_guard, &banner);
+  data.paths = NULL;
+  data.count = htab_elements (pfile->file_hash);
+  htab_traverse (pfile->file_hash, report_missing_guard, &data);
+
+  if (data.paths != NULL)
+    {
+      size_t i;
+
+      /* Sort the paths to avoid outputting them in hash table
+        order.  */
+      qsort (data.paths, data.count, sizeof (const char *),
+            report_missing_guard_cmp);
+      fputs (_("Multiple include guards may be useful for:\n"),
+            stderr);
+      for (i = 0; i < data.count; i++)
+       {
+         fputs (data.paths[i], stderr);
+         putc ('\n', stderr);
+       }
+      free (data.paths);
+    }
 }
 
 /* Locate HEADER, and determine whether it is newer than the current
@@ -1268,7 +1457,7 @@ _cpp_compare_file_date (cpp_reader *pfile, const char *fname,
   if (!dir)
     return -1;
 
-  file = _cpp_find_file (pfile, fname, dir, false, angle_brackets);
+  file = _cpp_find_file (pfile, fname, dir, angle_brackets, _cpp_FFK_NORMAL, 0);
   if (file->err_no)
     return -1;
 
@@ -1286,13 +1475,23 @@ _cpp_compare_file_date (cpp_reader *pfile, const char *fname,
 bool
 cpp_push_include (cpp_reader *pfile, const char *fname)
 {
-  return _cpp_stack_include (pfile, fname, false, IT_CMDLINE);
+  return _cpp_stack_include (pfile, fname, false, IT_CMDLINE, 0);
+}
+
+/* Pushes the given file, implicitly included at the start of a
+   compilation, onto the buffer stack but without any errors if the
+   file is not found.  Returns nonzero if successful.  */
+bool
+cpp_push_default_include (cpp_reader *pfile, const char *fname)
+{
+  return _cpp_stack_include (pfile, fname, true, IT_DEFAULT, 0);
 }
 
 /* Do appropriate cleanup when a file INC's buffer is popped off the
    input stack.  */
 void
-_cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file)
+_cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file,
+                     const unsigned char *to_free)
 {
   /* Record the inclusion-preventing macro, which could be NULL
      meaning no controlling macro.  */
@@ -1302,14 +1501,25 @@ _cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file)
   /* Invalidate control macros in the #including file.  */
   pfile->mi_valid = false;
 
-  if (file->buffer)
+  if (to_free)
     {
-      free ((void *) file->buffer);
-      file->buffer = NULL;
-      file->buffer_valid = false;
+      if (to_free == file->buffer_start)
+       {
+         file->buffer_start = NULL;
+         file->buffer = NULL;
+         file->buffer_valid = false;
+       }
+      free ((void *) to_free);
     }
 }
 
+/* Return the file name associated with FILE.  */
+const char *
+_cpp_get_file_name (_cpp_file *file)
+{
+  return file->name;
+}
+
 /* Inteface to file statistics record in _cpp_file structure. */
 struct stat *
 _cpp_get_file_stat (_cpp_file *file)
@@ -1351,7 +1561,7 @@ append_file_to_dir (const char *fname, cpp_dir *dir)
   flen = strlen (fname);
   path = XNEWVEC (char, dlen + 1 + flen + 1);
   memcpy (path, dir->name, dlen);
-  if (dlen && path[dlen - 1] != '/')
+  if (dlen && !IS_DIR_SEPARATOR (path[dlen - 1]))
     path[dlen++] = '/';
   memcpy (&path[dlen], fname, flen + 1);
 
@@ -1399,7 +1609,7 @@ read_name_map (cpp_dir *dir)
   len = dir->len;
   name = (char *) alloca (len + sizeof (FILE_NAME_MAP_FILE) + 1);
   memcpy (name, dir->name, len);
-  if (len && name[len - 1] != '/')
+  if (len && !IS_DIR_SEPARATOR (name[len - 1]))
     name[len++] = '/';
   strcpy (name + len, FILE_NAME_MAP_FILE);
   f = fopen (name, "r");
@@ -1457,7 +1667,7 @@ static char *
 remap_filename (cpp_reader *pfile, _cpp_file *file)
 {
   const char *fname, *p;
-  char *new_dir;
+  char *new_dir, *p3;
   cpp_dir *dir;
   size_t index, len;
 
@@ -1470,17 +1680,31 @@ remap_filename (cpp_reader *pfile, _cpp_file *file)
        read_name_map (dir);
 
       for (index = 0; dir->name_map[index]; index += 2)
-       if (!strcmp (dir->name_map[index], fname))
+       if (!filename_cmp (dir->name_map[index], fname))
            return xstrdup (dir->name_map[index + 1]);
-
+      if (IS_ABSOLUTE_PATH (fname))
+       return NULL;
       p = strchr (fname, '/');
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+      {
+       char *p2 = strchr (fname, '\\');
+       if (!p || (p > p2))
+         p = p2;
+      }
+#endif
       if (!p || p == fname)
        return NULL;
 
       len = dir->len + (p - fname + 1);
-      new_dir = XNEWVEC (char, len + 1);
+      new_dir = XNEWVEC (char, len + 2);
+      p3 = new_dir + dir->len;
       memcpy (new_dir, dir->name, dir->len);
-      memcpy (new_dir + dir->len, fname, p - fname + 1);
+      if (dir->len && !IS_DIR_SEPARATOR (dir->name[dir->len - 1]))
+       {
+         *p3++ = '/';
+         len++;
+       }
+      memcpy (p3, fname, p - fname + 1);
       new_dir[len] = '\0';
 
       dir = make_cpp_dir (pfile, new_dir, dir->sysp);
@@ -1612,6 +1836,7 @@ _cpp_save_file_entries (cpp_reader *pfile, FILE *fp)
   struct pchf_data *result;
   size_t result_size;
   _cpp_file *f;
+  bool ret;
 
   for (f = pfile->all_files; f; f = f->next_file)
     ++count;
@@ -1650,7 +1875,8 @@ _cpp_save_file_entries (cpp_reader *pfile, FILE *fp)
 
          if (!open_file (f))
            {
-             open_file_failed (pfile, f, 0);
+             open_file_failed (pfile, f, 0, 0);
+             free (result);
              return false;
            }
          ff = fdopen (f->fd, "rb");
@@ -1667,7 +1893,9 @@ _cpp_save_file_entries (cpp_reader *pfile, FILE *fp)
   qsort (result->entries, result->count, sizeof (struct pchf_entry),
         pchf_save_compare);
 
-  return fwrite (result, result_size, 1, fp) == 1;
+  ret = fwrite (result, result_size, 1, fp) == 1;
+  free (result);
+  return ret;
 }
 
 /* Read the pchf_data structure from F.  */
@@ -1763,3 +1991,17 @@ check_file_against_entries (cpp_reader *pfile ATTRIBUTE_UNUSED,
   return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry),
                  pchf_compare) != NULL;
 }
+
+/* Return true if the file FNAME is found in the appropriate include file path
+   as indicated by ANGLE_BRACKETS.  */
+
+bool
+_cpp_has_header (cpp_reader *pfile, const char *fname, int angle_brackets,
+                enum include_type type)
+{
+  cpp_dir *start_dir = search_path_head (pfile, fname, angle_brackets, type);
+  _cpp_file *file = _cpp_find_file (pfile, fname, start_dir, angle_brackets,
+                                   _cpp_FFK_HAS_INCLUDE, 0);
+  return file->err_no != ENOENT;
+}
+