[PCH] Remove the stat cache from the PCH file.

The stat cache became essentially useless ever since we started
validating all file entries in the PCH.
But the motivating reason for removing it now is that it also affected
correctness in this situation:

-You have a header without include guards (using "#pragma once" or #import)
-When creating the PCH:
  -The same header is referenced in an #include with different filename cases.
  -In the PCH, of course, we record only one file entry for the header file
  -But we cache in the PCH file the stat info for both filename cases

-Then the source files are updated and the header file is updated in a way that
 its size and modification time are the same but its inode changes

-When using the PCH:
  -We validate the headers, we check that header file and we create a file entry with its current inode
  -There's another #include with a filename with different case than the previously created file entry
  -In order to get its stat info we go through the cached stat info of the PCH and we receive the old inode
  -because of the different inodes, we think they are different files so we go ahead and include its contents.

Removing the stat cache will potentially break clients that are attempting to use the stat cache
as a way of avoiding having the actual input files available. If that use case is important, patches are welcome
to bring it back in a way that will actually work correctly (i.e., emit a PCH that is self-contained, coping with
literal strings, line/column computations, etc.).

This fixes rdar://5502805

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167172 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 548ff86..3173ad4 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -531,7 +531,6 @@
   /// context.
   void createPCHExternalASTSource(StringRef Path,
                                   bool DisablePCHValidation,
-                                  bool DisableStatCache,
                                   bool AllowPCHWithCompilerErrors,
                                   void *DeserializationListener);
 
@@ -541,7 +540,6 @@
   static ExternalASTSource *
   createPCHExternalASTSource(StringRef Path, const std::string &Sysroot,
                              bool DisablePCHValidation,
-                             bool DisableStatCache,
                              bool AllowPCHWithCompilerErrors,
                              Preprocessor &PP, ASTContext &Context,
                              void *DeserializationListener, bool Preamble);
diff --git a/include/clang/Lex/PreprocessorOptions.h b/include/clang/Lex/PreprocessorOptions.h
index 4f32360..e5fe373 100644
--- a/include/clang/Lex/PreprocessorOptions.h
+++ b/include/clang/Lex/PreprocessorOptions.h
@@ -66,10 +66,6 @@
   /// precompiled headers.
   bool DisablePCHValidation;
 
-  /// \brief When true, disables the use of the stat cache within a
-  /// precompiled header or AST file.
-  bool DisableStatCache;
-
   /// \brief When true, a PCH with compiler errors will not be rejected.
   bool AllowPCHWithCompilerErrors;
 
@@ -168,7 +164,7 @@
 public:
   PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
                           DetailedRecordConditionalDirectives(false),
-                          DisablePCHValidation(false), DisableStatCache(false),
+                          DisablePCHValidation(false),
                           AllowPCHWithCompilerErrors(false),
                           DumpDeserializedPCHDecls(false),
                           PrecompiledPreambleBytes(0, true),
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 4dba7b57..8c58fb2 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -386,9 +386,6 @@
       /// preloaded.
       SOURCE_LOCATION_PRELOADS = 14,
 
-      /// \brief Record code for the stat() cache.
-      STAT_CACHE = 15,
-
       /// \brief Record code for the set of ext_vector type names.
       EXT_VECTOR_DECLS = 16,
       
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index c0d93c3..ba26a49 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -690,9 +690,6 @@
   /// headers when they are loaded.
   bool DisableValidation;
 
-  /// \brief Whether to disable the use of stat caches in AST files.
-  bool DisableStatCache;
-
   /// \brief Whether to accept an AST file with compiler errors.
   bool AllowASTWithCompilerErrors;
 
@@ -709,10 +706,6 @@
 
   SwitchCaseMapTy *CurrSwitchCaseStmts;
 
-  /// \brief The number of stat() calls that hit/missed the stat
-  /// cache.
-  unsigned NumStatHits, NumStatMisses;
-
   /// \brief The number of source location entries de-serialized from
   /// the PCH file.
   unsigned NumSLocEntriesRead;
@@ -1069,17 +1062,11 @@
   /// of its regular consistency checking, allowing the use of precompiled
   /// headers that cannot be determined to be compatible.
   ///
-  /// \param DisableStatCache If true, the AST reader will ignore the
-  /// stat cache in the AST files. This performance pessimization can
-  /// help when an AST file is being used in cases where the
-  /// underlying files in the file system may have changed, but
-  /// parsing should still continue.
-  ///
   /// \param AllowASTWithCompilerErrors If true, the AST reader will accept an
   /// AST file the was created out of an AST with compiler errors,
   /// otherwise it will reject it.
   ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot = "",
-            bool DisableValidation = false, bool DisableStatCache = false,
+            bool DisableValidation = false,
             bool AllowASTWithCompilerErrors = false);
 
   ~ASTReader();
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 919209c..ac81e21 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -50,7 +50,6 @@
 class HeaderSearch;
 class IdentifierResolver;
 class MacroDefinition;
-class MemorizeStatCalls;
 class OpaqueValueExpr;
 class OpenCLOptions;
 class ASTReader;
@@ -417,7 +416,6 @@
   void WriteControlBlock(Preprocessor &PP, ASTContext &Context,
                          StringRef isysroot, const std::string &OutputFile);
   void WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot);
-  void WriteStatCache(MemorizeStatCalls &StatCalls);
   void WriteSourceManagerBlock(SourceManager &SourceMgr,
                                const Preprocessor &PP,
                                StringRef isysroot);
@@ -467,7 +465,7 @@
   void WriteDeclsBlockAbbrevs();
   void WriteDecl(ASTContext &Context, Decl *D);
 
-  void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+  void WriteASTCore(Sema &SemaRef,
                     StringRef isysroot, const std::string &OutputFile,
                     Module *WritingModule);
 
@@ -482,15 +480,12 @@
   /// \param SemaRef a reference to the semantic analysis object that processed
   /// the AST to be written into the precompiled header.
   ///
-  /// \param StatCalls the object that cached all of the stat() calls made while
-  /// searching for source files and headers.
-  ///
   /// \param WritingModule The module that we are writing. If null, we are
   /// writing a precompiled header.
   ///
   /// \param isysroot if non-empty, write a relocatable file whose headers
   /// are relative to the given system root.
-  void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+  void WriteAST(Sema &SemaRef,
                 const std::string &OutputFile,
                 Module *WritingModule, StringRef isysroot,
                 bool hasErrors = false);
@@ -733,7 +728,6 @@
   std::string isysroot;
   raw_ostream *Out;
   Sema *SemaPtr;
-  MemorizeStatCalls *StatCalls; // owned by the FileManager
   llvm::SmallVector<char, 128> Buffer;
   llvm::BitstreamWriter Stream;
   ASTWriter Writer;
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 2915cfc..39fa3d9 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -385,11 +385,6 @@
   /// \brief Diagnostic IDs and their mappings that the user changed.
   SmallVector<uint64_t, 8> PragmaDiagMappings;
 
-  /// \brief The AST stat cache installed for this file, if any.
-  ///
-  /// The dynamic type of this stat cache is always ASTStatCache
-  void *StatCache;
-
   /// \brief List of modules which depend on this module
   llvm::SetVector<ModuleFile *> ImportedBy;
 
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index cc93d46..da30832 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -779,7 +779,6 @@
   Reader.reset(new ASTReader(PP, Context,
                              /*isysroot=*/"",
                              /*DisableValidation=*/disableValid,
-                             /*DisableStatCache=*/false,
                              AllowPCHWithCompilerErrors));
   
   // Recover resources if we crash before exiting this method.
@@ -2023,7 +2022,6 @@
 
   // Remap files.
   PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
-  PPOpts.DisableStatCache = true;
   for (PreprocessorOptions::remapped_file_buffer_iterator 
          R = PPOpts.remapped_file_buffer_begin(),
          REnd = PPOpts.remapped_file_buffer_end();
@@ -2436,7 +2434,6 @@
 
   // If the main file has been overridden due to the use of a preamble,
   // make that override happen and introduce the preamble.
-  PreprocessorOpts.DisableStatCache = true;
   StoredDiagnostics.insert(StoredDiagnostics.end(),
                            stored_diag_begin(),
                            stored_diag_afterDriver_begin());
@@ -2509,7 +2506,7 @@
                           Sema &S,
                           bool hasErrors,
                           raw_ostream &OS) {
-  Writer.WriteAST(S, 0, std::string(), 0, "", hasErrors);
+  Writer.WriteAST(S, std::string(), 0, "", hasErrors);
 
   // Write the generated bitstream to "Out".
   if (!Buffer.empty())
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 80d15c6..c6c5fb5 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -308,14 +308,12 @@
 
 void CompilerInstance::createPCHExternalASTSource(StringRef Path,
                                                   bool DisablePCHValidation,
-                                                  bool DisableStatCache,
                                                 bool AllowPCHWithCompilerErrors,
                                                  void *DeserializationListener){
   OwningPtr<ExternalASTSource> Source;
   bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
   Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
                                           DisablePCHValidation,
-                                          DisableStatCache,
                                           AllowPCHWithCompilerErrors,
                                           getPreprocessor(), getASTContext(),
                                           DeserializationListener,
@@ -328,7 +326,6 @@
 CompilerInstance::createPCHExternalASTSource(StringRef Path,
                                              const std::string &Sysroot,
                                              bool DisablePCHValidation,
-                                             bool DisableStatCache,
                                              bool AllowPCHWithCompilerErrors,
                                              Preprocessor &PP,
                                              ASTContext &Context,
@@ -337,7 +334,7 @@
   OwningPtr<ASTReader> Reader;
   Reader.reset(new ASTReader(PP, Context,
                              Sysroot.empty() ? "" : Sysroot.c_str(),
-                             DisablePCHValidation, DisableStatCache,
+                             DisablePCHValidation,
                              AllowPCHWithCompilerErrors));
 
   Reader->setDeserializationListener(
@@ -946,8 +943,7 @@
       const PreprocessorOptions &PPOpts = getPreprocessorOpts();
       ModuleManager = new ASTReader(getPreprocessor(), *Context,
                                     Sysroot.empty() ? "" : Sysroot.c_str(),
-                                    PPOpts.DisablePCHValidation,
-                                    PPOpts.DisableStatCache);
+                                    PPOpts.DisablePCHValidation);
       if (hasASTConsumer()) {
         ModuleManager->setDeserializationListener(
           getASTConsumer().GetASTDeserializationListener());
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index fa1655d..2974334 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -314,7 +314,6 @@
       CI.createPCHExternalASTSource(
                                 CI.getPreprocessorOpts().ImplicitPCHInclude,
                                 CI.getPreprocessorOpts().DisablePCHValidation,
-                                CI.getPreprocessorOpts().DisableStatCache,
                             CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
                                 DeserialListener);
       if (!CI.getASTContext().getExternalSource())
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 874d2c4..80fb464 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -769,104 +769,6 @@
   return false;
 }
 
-namespace {
-
-class ASTStatData {
-public:
-  const ino_t ino;
-  const dev_t dev;
-  const mode_t mode;
-  const time_t mtime;
-  const off_t size;
-
-  ASTStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
-    : ino(i), dev(d), mode(mo), mtime(m), size(s) {}
-};
-
-class ASTStatLookupTrait {
- public:
-  typedef const char *external_key_type;
-  typedef const char *internal_key_type;
-
-  typedef ASTStatData data_type;
-
-  static unsigned ComputeHash(const char *path) {
-    return llvm::HashString(path);
-  }
-
-  static internal_key_type GetInternalKey(const char *path) { return path; }
-
-  static bool EqualKey(internal_key_type a, internal_key_type b) {
-    return strcmp(a, b) == 0;
-  }
-
-  static std::pair<unsigned, unsigned>
-  ReadKeyDataLength(const unsigned char*& d) {
-    unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
-    unsigned DataLen = (unsigned) *d++;
-    return std::make_pair(KeyLen + 1, DataLen);
-  }
-
-  static internal_key_type ReadKey(const unsigned char *d, unsigned) {
-    return (const char *)d;
-  }
-
-  static data_type ReadData(const internal_key_type, const unsigned char *d,
-                            unsigned /*DataLen*/) {
-    using namespace clang::io;
-
-    ino_t ino = (ino_t) ReadUnalignedLE32(d);
-    dev_t dev = (dev_t) ReadUnalignedLE32(d);
-    mode_t mode = (mode_t) ReadUnalignedLE16(d);
-    time_t mtime = (time_t) ReadUnalignedLE64(d);
-    off_t size = (off_t) ReadUnalignedLE64(d);
-    return data_type(ino, dev, mode, mtime, size);
-  }
-};
-
-/// \brief stat() cache for precompiled headers.
-///
-/// This cache is very similar to the stat cache used by pretokenized
-/// headers.
-class ASTStatCache : public FileSystemStatCache {
-  typedef OnDiskChainedHashTable<ASTStatLookupTrait> CacheTy;
-  CacheTy *Cache;
-
-  unsigned &NumStatHits, &NumStatMisses;
-public:
-  ASTStatCache(const unsigned char *Buckets, const unsigned char *Base,
-               unsigned &NumStatHits, unsigned &NumStatMisses)
-    : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) {
-    Cache = CacheTy::Create(Buckets, Base);
-  }
-
-  ~ASTStatCache() { delete Cache; }
-
-  LookupResult getStat(const char *Path, struct stat &StatBuf,
-                       int *FileDescriptor) {
-    // Do the lookup for the file's data in the AST file.
-    CacheTy::iterator I = Cache->find(Path);
-
-    // If we don't get a hit in the AST file just forward to 'stat'.
-    if (I == Cache->end()) {
-      ++NumStatMisses;
-      return statChained(Path, StatBuf, FileDescriptor);
-    }
-
-    ++NumStatHits;
-    ASTStatData Data = *I;
-
-    StatBuf.st_ino = Data.ino;
-    StatBuf.st_dev = Data.dev;
-    StatBuf.st_mtime = Data.mtime;
-    StatBuf.st_mode = Data.mode;
-    StatBuf.st_size = Data.size;
-    return CacheExists;
-  }
-};
-} // end anonymous namespace
-
-
 /// \brief Read a source manager block
 bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
   using namespace SrcMgr;
@@ -2362,18 +2264,6 @@
       break;
     }
 
-    case STAT_CACHE: {
-      if (!DisableStatCache) {
-        ASTStatCache *MyStatCache =
-          new ASTStatCache((const unsigned char *)BlobStart + Record[0],
-                           (const unsigned char *)BlobStart,
-                           NumStatHits, NumStatMisses);
-        FileMgr.addStatCache(MyStatCache);
-        F.StatCache = MyStatCache;
-      }
-      break;
-    }
-
     case EXT_VECTOR_DECLS:
       for (unsigned I = 0, N = Record.size(); I != N; ++I)
         ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I]));
@@ -5624,8 +5514,6 @@
                                           SelectorsLoaded.end(),
                                           Selector());
 
-  std::fprintf(stderr, "  %u stat cache hits\n", NumStatHits);
-  std::fprintf(stderr, "  %u stat cache misses\n", NumStatMisses);
   if (unsigned TotalNumSLocEntries = getTotalNumSLocs())
     std::fprintf(stderr, "  %u/%u source location entries read (%f%%)\n",
                  NumSLocEntriesRead, TotalNumSLocEntries,
@@ -7005,16 +6893,14 @@
 
 ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
                      StringRef isysroot, bool DisableValidation,
-                     bool DisableStatCache, bool AllowASTWithCompilerErrors)
+                     bool AllowASTWithCompilerErrors)
   : Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
     SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
     Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
     Consumer(0), ModuleMgr(PP.getFileManager()),
     isysroot(isysroot), DisableValidation(DisableValidation),
-    DisableStatCache(DisableStatCache),
     AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), 
     CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
-    NumStatHits(0), NumStatMisses(0), 
     NumSLocEntriesRead(0), TotalNumSLocEntries(0), 
     NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), 
     TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), 
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 500351f..a2e8b71 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -803,7 +803,6 @@
   RECORD(PP_COUNTER_VALUE);
   RECORD(SOURCE_LOCATION_OFFSETS);
   RECORD(SOURCE_LOCATION_PRELOADS);
-  RECORD(STAT_CACHE);
   RECORD(EXT_VECTOR_DECLS);
   RECORD(PPD_ENTITIES_OFFSETS);
   RECORD(REFERENCED_SELECTOR_POOL);
@@ -1328,46 +1327,6 @@
 };
 } // end anonymous namespace
 
-/// \brief Write the stat() system call cache to the AST file.
-void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
-  // Build the on-disk hash table containing information about every
-  // stat() call.
-  OnDiskChainedHashTableGenerator<ASTStatCacheTrait> Generator;
-  unsigned NumStatEntries = 0;
-  for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
-                                StatEnd = StatCalls.end();
-       Stat != StatEnd; ++Stat, ++NumStatEntries) {
-    StringRef Filename = Stat->first();
-    Generator.insert(Filename.data(), Stat->second);
-  }
-
-  // Create the on-disk hash table in a buffer.
-  SmallString<4096> StatCacheData;
-  uint32_t BucketOffset;
-  {
-    llvm::raw_svector_ostream Out(StatCacheData);
-    // Make sure that no bucket is at offset 0
-    clang::io::Emit32(Out, 0);
-    BucketOffset = Generator.Emit(Out);
-  }
-
-  // Create a blob abbreviation
-  using namespace llvm;
-  BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
-  Abbrev->Add(BitCodeAbbrevOp(STAT_CACHE));
-  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
-  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
-  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
-  unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev);
-
-  // Write the stat cache
-  RecordData Record;
-  Record.push_back(STAT_CACHE);
-  Record.push_back(BucketOffset);
-  Record.push_back(NumStatEntries);
-  Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str());
-}
-
 //===----------------------------------------------------------------------===//
 // Source Manager Serialization
 //===----------------------------------------------------------------------===//
@@ -3404,7 +3363,7 @@
     delete I->second;
 }
 
-void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+void ASTWriter::WriteAST(Sema &SemaRef,
                          const std::string &OutputFile,
                          Module *WritingModule, StringRef isysroot,
                          bool hasErrors) {
@@ -3423,7 +3382,7 @@
   Context = &SemaRef.Context;
   PP = &SemaRef.PP;
   this->WritingModule = WritingModule;
-  WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule);
+  WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule);
   Context = 0;
   PP = 0;
   this->WritingModule = 0;
@@ -3440,7 +3399,7 @@
   }
 }
 
-void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+void ASTWriter::WriteASTCore(Sema &SemaRef,
                              StringRef isysroot,
                              const std::string &OutputFile, 
                              Module *WritingModule) {
@@ -3597,8 +3556,6 @@
   // Write the remaining AST contents.
   RecordData Record;
   Stream.EnterSubblock(AST_BLOCK_ID, 5);
-  if (StatCalls && isysroot.empty())
-    WriteStatCache(*StatCalls);
 
   // Create a lexical update block containing all of the declarations in the
   // translation unit that do not come from other AST files.
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index c2b353a..870d654 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -18,7 +18,6 @@
 #include "clang/AST/ASTConsumer.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemStatCache.h"
 #include "llvm/Bitcode/BitstreamWriter.h"
 #include "llvm/Support/raw_ostream.h"
 #include <string>
@@ -32,11 +31,7 @@
                            raw_ostream *OS)
   : PP(PP), OutputFile(OutputFile), Module(Module), 
     isysroot(isysroot.str()), Out(OS), 
-    SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream) {
-  // Install a stat() listener to keep track of all of the stat()
-  // calls.
-  StatCalls = new MemorizeStatCalls();
-  PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/false);
+    SemaPtr(0), Stream(Buffer), Writer(Stream) {
 }
 
 PCHGenerator::~PCHGenerator() {
@@ -48,7 +43,7 @@
   
   // Emit the PCH file
   assert(SemaPtr && "No Sema?");
-  Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, Module, isysroot);
+  Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot);
 
   // Write the generated bitstream to "Out".
   Out->write((char *)&Buffer.front(), Buffer.size());
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 09ea754..5e42ab4 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -41,7 +41,7 @@
     FileSortedDecls(0), NumFileSortedDecls(0),
     RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
     ObjCCategoriesMap(0), LocalNumObjCCategoriesInMap(0),
-    LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0)
+    LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0)
 {}
 
 ModuleFile::~ModuleFile() {
diff --git a/test/PCH/Inputs/case-insensitive-include.h b/test/PCH/Inputs/case-insensitive-include.h
new file mode 100644
index 0000000..60bdf36
--- /dev/null
+++ b/test/PCH/Inputs/case-insensitive-include.h
@@ -0,0 +1,5 @@
+#pragma once
+
+struct S {
+  int x;
+};
diff --git a/test/PCH/case-insensitive-include.c b/test/PCH/case-insensitive-include.c
new file mode 100644
index 0000000..707de70
--- /dev/null
+++ b/test/PCH/case-insensitive-include.c
@@ -0,0 +1,29 @@
+// REQUIRES: case-insensitive-filesystem
+
+// Test this without pch.
+// RUN: cp %S/Inputs/case-insensitive-include.h %T
+// RUN: %clang_cc1 -fsyntax-only %s -include %s -I %T -verify
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -o %t.pch %s -I %T
+
+// Modify inode of the header.
+// RUN: cp %T/case-insensitive-include.h %t.copy
+// RUN: touch -r %T/case-insensitive-include.h %t.copy
+// RUN: mv %t.copy %T/case-insensitive-include.h
+
+// RUN: %clang_cc1 -fsyntax-only %s -include-pch %t.pch -I %T -verify
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#include "case-insensitive-include.h"
+#include "Case-Insensitive-Include.h"
+
+#else
+
+#include "Case-Insensitive-Include.h"
+
+#endif
diff --git a/test/lit.cfg b/test/lit.cfg
index b22346e..3cbe013 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -4,6 +4,7 @@
 import platform
 import re
 import subprocess
+import tempfile
 
 
 # Configuration file for the 'lit' test runner.
@@ -225,6 +226,17 @@
 if platform.system() not in ['Windows']:
     config.available_features.add('ansi-escape-sequences')
 
+# Case-insensitive file system
+def is_filesystem_case_insensitive():
+    handle, path = tempfile.mkstemp(prefix='case-test')
+    isInsensitive = os.path.exists(path.upper())
+    os.close(handle)
+    os.remove(path)
+    return isInsensitive
+
+if is_filesystem_case_insensitive():
+    config.available_features.add('case-insensitive-filesystem')
+
 # [PR8833] LLP64-incompatible tests
 if not re.match(r'^x86_64.*-(win32|mingw32)$', config.target_triple):
     config.available_features.add('LP64')