Index: clang/include/clang/Serialization/ASTReader.h
===================================================================
--- clang/include/clang/Serialization/ASTReader.h
+++ clang/include/clang/Serialization/ASTReader.h
@@ -2231,6 +2231,10 @@
   // Read a path
   std::string ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx);
 
+  // Read a path
+  std::string ReadPath(StringRef BaseDirectory, const RecordData &Record,
+                       unsigned &Idx);
+
   // Skip a path
   static void SkipPath(const RecordData &Record, unsigned &Idx) {
     SkipString(Record, Idx);
Index: clang/include/clang/Serialization/InMemoryModuleCache.h
===================================================================
--- clang/include/clang/Serialization/InMemoryModuleCache.h
+++ clang/include/clang/Serialization/InMemoryModuleCache.h
@@ -30,54 +30,77 @@
 /// Critically, it ensures that a single process has a consistent view of each
 /// PCM.  This is used by \a CompilerInstance when building PCMs to ensure that
 /// each \a ModuleManager sees the same files.
-///
-/// \a finalizeCurrentBuffers() should be called before creating a new user.
-/// This locks in the current PCMs, ensuring that no PCM that has already been
-/// accessed can be purged, preventing use-after-frees.
 class InMemoryModuleCache : public llvm::RefCountedBase<InMemoryModuleCache> {
   struct PCM {
     std::unique_ptr<llvm::MemoryBuffer> Buffer;
 
     /// Track the timeline of when this was added to the cache.
-    unsigned Index;
+    bool IsFinal = false;
+
+    PCM() = default;
+    PCM(std::unique_ptr<llvm::MemoryBuffer> Buffer)
+        : Buffer(std::move(Buffer)) {}
   };
 
   /// Cache of buffers.
   llvm::StringMap<PCM> PCMs;
 
-  /// Monotonically increasing index.
-  unsigned NextIndex = 0;
-
-  /// Bumped to prevent "older" buffers from being removed.
-  unsigned FirstRemovableIndex = 0;
-
 public:
-  /// Store the Buffer under the Filename.
+  /// There are four states for a PCM.  It must monotonically increase.
+  ///
+  ///  1. Unknown: the PCM has neither been read from disk nor built.
+  ///  2. Tentative: the PCM has been read from disk but not yet imported or
+  ///     built.  It might work.
+  ///  3. ToBuild: the PCM read from disk did not work but a new one has not
+  ///     been built yet.
+  ///  4. Works: indicating that the current PCM was either built in this
+  ///     process or has been successfully imported.
+  enum State { Unknown, Tentative, ToBuild, Final };
+
+  /// Get the state of the PCM.
+  State getPCMState(llvm::StringRef Filename) const;
+
+  /// Store the PCM under the Filename.
   ///
-  /// \pre There is not already buffer is not already in the cache.
+  /// \pre state is Unknown
+  /// \post state is Tentative
   /// \return a reference to the buffer as a convenience.
-  llvm::MemoryBuffer &addBuffer(llvm::StringRef Filename,
-                                std::unique_ptr<llvm::MemoryBuffer> Buffer);
+  llvm::MemoryBuffer &addPCM(llvm::StringRef Filename,
+                             std::unique_ptr<llvm::MemoryBuffer> Buffer);
+
+  /// Store a just-built PCM under the Filename.
+  ///
+  /// \pre state is Unknown or ToBuild.
+  /// \pre state is not Tentative.
+  /// \return a reference to the buffer as a convenience.
+  llvm::MemoryBuffer &addBuiltPCM(llvm::StringRef Filename,
+                                  std::unique_ptr<llvm::MemoryBuffer> Buffer);
+
+  /// Try to remove a buffer from the cache.  No effect if state is Final.
+  ///
+  /// \pre state is Tentative/Final.
+  /// \post Tentative => ToBuild or Final => Final.
+  /// \return false on success, i.e. if Tentative => ToBuild.
+  bool tryToDropPCM(llvm::StringRef Filename);
 
-  /// Try to remove a buffer from the cache.
+  /// Mark a PCM as final.
   ///
-  /// \return false on success, iff \c !isBufferFinal().
-  bool tryToRemoveBuffer(llvm::StringRef Filename);
+  /// \pre state is Tentative or Final.
+  /// \post state is Final.
+  void finalizePCM(llvm::StringRef Filename);
 
-  /// Get a pointer to the buffer if it exists; else nullptr.
-  llvm::MemoryBuffer *lookupBuffer(llvm::StringRef Filename);
+  /// Get a pointer to the pCM if it exists; else nullptr.
+  llvm::MemoryBuffer *lookupPCM(llvm::StringRef Filename) const;
 
-  /// Check whether the buffer is final.
+  /// Check whether the PCM is final and has been shown to work.
   ///
-  /// \return true iff \a finalizeCurrentBuffers() has been called since the
-  /// buffer was added.  This prevents buffers from being removed.
-  bool isBufferFinal(llvm::StringRef Filename);
+  /// \return true iff state is Final.
+  bool isPCMFinal(llvm::StringRef Filename) const;
 
-  /// Finalize the current buffers in the cache.
+  /// Check whether the PCM is waiting to be built.
   ///
-  /// Should be called when creating a new user to ensure previous uses aren't
-  /// invalidated.
-  void finalizeCurrentBuffers();
+  /// \return true iff state is ToBuild.
+  bool shouldBuildPCM(llvm::StringRef Filename) const;
 };
 
 } // end namespace clang
Index: clang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- clang/lib/Frontend/CompilerInstance.cpp
+++ clang/lib/Frontend/CompilerInstance.cpp
@@ -62,11 +62,7 @@
       Invocation(new CompilerInvocation()),
       ModuleCache(SharedModuleCache ? SharedModuleCache
                                     : new InMemoryModuleCache),
-      ThePCHContainerOperations(std::move(PCHContainerOps)) {
-  // Don't allow this to invalidate buffers in use by others.
-  if (SharedModuleCache)
-    getModuleCache().finalizeCurrentBuffers();
-}
+      ThePCHContainerOperations(std::move(PCHContainerOps)) {}
 
 CompilerInstance::~CompilerInstance() {
   assert(OutputFiles.empty() && "Still output files in flight?");
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -92,6 +92,7 @@
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
@@ -2359,6 +2360,7 @@
   RecordData Record;
   unsigned NumInputs = 0;
   unsigned NumUserInputs = 0;
+  StringRef BaseDirectoryAsWritten;
   while (true) {
     llvm::BitstreamEntry Entry = Stream.advance();
 
@@ -2559,7 +2561,9 @@
             ImportedName, /*FileMapOnly*/ true);
 
         if (ImportedFile.empty())
-          ImportedFile = ReadPath(F, Record, Idx);
+          // Use BaseDirectoryAsWritten to ensure we use the same path in the
+          // ModuleCache as when writing.
+          ImportedFile = ReadPath(BaseDirectoryAsWritten, Record, Idx);
         else
           SkipPath(Record, Idx);
 
@@ -2624,6 +2628,9 @@
       break;
 
     case MODULE_DIRECTORY: {
+      // Save the BaseDirectory as written in the PCM for computing the module
+      // filename for the ModuleCache.
+      BaseDirectoryAsWritten = Blob;
       assert(!F.ModuleName.empty() &&
              "MODULE_DIRECTORY found before MODULE_NAME");
       // If we've already loaded a module map file covering this module, we may
@@ -4180,6 +4187,14 @@
 
   assert(M && "Missing module file");
 
+  bool ShouldFinalizePCM = false;
+  auto FinalizeOrDropPCM = llvm::make_scope_exit([&]() {
+    auto &MC = getModuleManager().getModuleCache();
+    if (ShouldFinalizePCM)
+      MC.finalizePCM(FileName);
+    else
+      MC.tryToDropPCM(FileName);
+  });
   ModuleFile &F = *M;
   BitstreamCursor &Stream = F.Stream;
   Stream = BitstreamCursor(PCHContainerRdr.ExtractPCH(*F.Buffer));
@@ -4246,6 +4261,7 @@
 
       // Record that we've loaded this module.
       Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
+      ShouldFinalizePCM = true;
       return Success;
 
     case UNHASHED_CONTROL_BLOCK_ID:
@@ -4309,7 +4325,7 @@
     // validation will fail during the as-system import since the PCM on disk
     // doesn't guarantee that -Werror was respected.  However, the -Werror
     // flags were checked during the initial as-user import.
-    if (getModuleManager().getModuleCache().isBufferFinal(F.FileName)) {
+    if (getModuleManager().getModuleCache().isPCMFinal(F.FileName)) {
       Diag(diag::warn_module_system_bit_conflict) << F.FileName;
       return Success;
     }
@@ -9099,6 +9115,14 @@
   return Filename;
 }
 
+std::string ASTReader::ReadPath(StringRef BaseDirectory,
+                                const RecordData &Record, unsigned &Idx) {
+  std::string Filename = ReadString(Record, Idx);
+  if (!BaseDirectory.empty())
+    ResolveImportedPath(Filename, BaseDirectory);
+  return Filename;
+}
+
 VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
                                          unsigned &Idx) {
   unsigned Major = Record[Idx++];
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -4621,9 +4621,9 @@
   WritingAST = false;
   if (SemaRef.Context.getLangOpts().ImplicitModules && WritingModule) {
     // Construct MemoryBuffer and update buffer manager.
-    ModuleCache.addBuffer(OutputFile,
-                          llvm::MemoryBuffer::getMemBufferCopy(
-                              StringRef(Buffer.begin(), Buffer.size())));
+    ModuleCache.addBuiltPCM(OutputFile,
+                            llvm::MemoryBuffer::getMemBufferCopy(
+                                StringRef(Buffer.begin(), Buffer.size())));
   }
   return Signature;
 }
Index: clang/lib/Serialization/InMemoryModuleCache.cpp
===================================================================
--- clang/lib/Serialization/InMemoryModuleCache.cpp
+++ clang/lib/Serialization/InMemoryModuleCache.cpp
@@ -11,39 +11,70 @@
 
 using namespace clang;
 
+InMemoryModuleCache::State
+InMemoryModuleCache::getPCMState(llvm::StringRef Filename) const {
+  auto I = PCMs.find(Filename);
+  if (I == PCMs.end())
+    return Unknown;
+  if (I->second.IsFinal)
+    return Final;
+  return I->second.Buffer ? Tentative : ToBuild;
+}
+
 llvm::MemoryBuffer &
-InMemoryModuleCache::addBuffer(llvm::StringRef Filename,
-                               std::unique_ptr<llvm::MemoryBuffer> Buffer) {
-  auto Insertion = PCMs.insert({Filename, PCM{std::move(Buffer), NextIndex++}});
-  assert(Insertion.second && "Already has a buffer");
+InMemoryModuleCache::addPCM(llvm::StringRef Filename,
+                            std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+  auto Insertion = PCMs.insert(std::make_pair(Filename, std::move(Buffer)));
+  assert(Insertion.second && "Already has a PCM");
   return *Insertion.first->second.Buffer;
 }
 
+llvm::MemoryBuffer &
+InMemoryModuleCache::addBuiltPCM(llvm::StringRef Filename,
+                                 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+  auto &PCM = PCMs[Filename];
+  assert(!PCM.IsFinal && "Trying to override finalized PCM?");
+  assert(!PCM.Buffer && "Trying to override tentative PCM?");
+  PCM.Buffer = std::move(Buffer);
+  PCM.IsFinal = true;
+  return *PCM.Buffer;
+}
+
 llvm::MemoryBuffer *
-InMemoryModuleCache::lookupBuffer(llvm::StringRef Filename) {
+InMemoryModuleCache::lookupPCM(llvm::StringRef Filename) const {
   auto I = PCMs.find(Filename);
   if (I == PCMs.end())
     return nullptr;
   return I->second.Buffer.get();
 }
 
-bool InMemoryModuleCache::isBufferFinal(llvm::StringRef Filename) {
-  auto I = PCMs.find(Filename);
-  if (I == PCMs.end())
-    return false;
-  return I->second.Index < FirstRemovableIndex;
+bool InMemoryModuleCache::isPCMFinal(llvm::StringRef Filename) const {
+  return getPCMState(Filename) == Final;
+}
+
+bool InMemoryModuleCache::shouldBuildPCM(llvm::StringRef Filename) const {
+  return getPCMState(Filename) == ToBuild;
 }
 
-bool InMemoryModuleCache::tryToRemoveBuffer(llvm::StringRef Filename) {
+bool InMemoryModuleCache::tryToDropPCM(llvm::StringRef Filename) {
   auto I = PCMs.find(Filename);
-  assert(I != PCMs.end() && "No buffer to remove...");
-  if (I->second.Index < FirstRemovableIndex)
+  assert(I != PCMs.end() && "PCM to remove is unknown...");
+
+  auto &PCM = I->second;
+  assert(PCM.Buffer && "PCM to remove is scheduled to be built...");
+
+  if (PCM.IsFinal)
     return true;
 
-  PCMs.erase(I);
+  PCM.Buffer.reset();
   return false;
 }
 
-void InMemoryModuleCache::finalizeCurrentBuffers() {
-  FirstRemovableIndex = NextIndex;
+void InMemoryModuleCache::finalizePCM(llvm::StringRef Filename) {
+  auto I = PCMs.find(Filename);
+  assert(I != PCMs.end() && "PCM to finalize is unknown...");
+
+  auto &PCM = I->second;
+  assert(PCM.Buffer && "Trying to finalize a dropped PCM...");
+  PCM.IsFinal = true;
 }
Index: clang/lib/Serialization/ModuleManager.cpp
===================================================================
--- clang/lib/Serialization/ModuleManager.cpp
+++ clang/lib/Serialization/ModuleManager.cpp
@@ -118,6 +118,8 @@
     // contents, but we can't check that.)
     ExpectedModTime = 0;
   }
+  // Note: ExpectedSize and ExpectedModTime will be 0 for MK_ImplicitModule
+  // when using an ASTFileSignature.
   if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
     ErrorStr = "module file out of date";
     return OutOfDate;
@@ -159,16 +161,21 @@
   // Load the contents of the module
   if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
     // The buffer was already provided for us.
-    NewModule->Buffer = &ModuleCache->addBuffer(FileName, std::move(Buffer));
+    NewModule->Buffer = &ModuleCache->addBuiltPCM(FileName, std::move(Buffer));
     // Since the cached buffer is reused, it is safe to close the file
     // descriptor that was opened while stat()ing the PCM in
     // lookupModuleFile() above, it won't be needed any longer.
     Entry->closeFile();
   } else if (llvm::MemoryBuffer *Buffer =
-                 getModuleCache().lookupBuffer(FileName)) {
+                 getModuleCache().lookupPCM(FileName)) {
     NewModule->Buffer = Buffer;
     // As above, the file descriptor is no longer needed.
     Entry->closeFile();
+  } else if (getModuleCache().shouldBuildPCM(FileName)) {
+    // Report that the module is out of date, since we tried (and failed) to
+    // import it earlier.
+    Entry->closeFile();
+    return OutOfDate;
   } else {
     // Open the AST file.
     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code()));
@@ -186,7 +193,7 @@
       return Missing;
     }
 
-    NewModule->Buffer = &getModuleCache().addBuffer(FileName, std::move(*Buf));
+    NewModule->Buffer = &getModuleCache().addPCM(FileName, std::move(*Buf));
   }
 
   // Initialize the stream.
@@ -198,7 +205,7 @@
                                           ExpectedSignature, ErrorStr)) {
     // Try to remove the buffer.  If it can't be removed, then it was already
     // validated by this process.
-    if (!getModuleCache().tryToRemoveBuffer(NewModule->FileName))
+    if (!getModuleCache().tryToDropPCM(NewModule->FileName))
       FileMgr.invalidateCache(NewModule->File);
     return OutOfDate;
   }
@@ -263,17 +270,6 @@
         mod->setASTFile(nullptr);
       }
     }
-
-    // Files that didn't make it through ReadASTCore successfully will be
-    // rebuilt (or there was an error). Invalidate them so that we can load the
-    // new files that will be renamed over the old ones.
-    //
-    // The ModuleCache tracks whether the module was successfully loaded in
-    // another thread/context; in that case, it won't need to be rebuilt (and
-    // we can't safely invalidate it anyway).
-    if (LoadedSuccessfully.count(&*victim) == 0 &&
-        !getModuleCache().tryToRemoveBuffer(victim->FileName))
-      FileMgr.invalidateCache(victim->File);
   }
 
   // Delete the modules.
Index: clang/test/Modules/Inputs/implicit-invalidate-chain/A.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/implicit-invalidate-chain/A.h
@@ -0,0 +1,2 @@
+// A
+#include "B.h"
Index: clang/test/Modules/Inputs/implicit-invalidate-chain/B.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/implicit-invalidate-chain/B.h
@@ -0,0 +1,2 @@
+// B
+#include "C.h"
Index: clang/test/Modules/Inputs/implicit-invalidate-chain/C.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/implicit-invalidate-chain/C.h
@@ -0,0 +1,2 @@
+// C
+#include "D.h"
Index: clang/test/Modules/Inputs/implicit-invalidate-chain/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/implicit-invalidate-chain/module.modulemap
@@ -0,0 +1,3 @@
+module A { header "A.h" }
+module B { header "B.h" }
+module C { header "C.h" }
Index: clang/test/Modules/Inputs/relative-import-path/A.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/relative-import-path/A.h
@@ -0,0 +1,2 @@
+// A
+#include "B.h"
Index: clang/test/Modules/Inputs/relative-import-path/B.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/relative-import-path/B.h
@@ -0,0 +1,2 @@
+// B
+#include "C.h"
Index: clang/test/Modules/Inputs/relative-import-path/C.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/relative-import-path/C.h
@@ -0,0 +1 @@
+// C
Index: clang/test/Modules/Inputs/relative-import-path/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/relative-import-path/module.modulemap
@@ -0,0 +1,3 @@
+module A { header "A.h" }
+module B { header "B.h" }
+module C { header "C.h" }
Index: clang/test/Modules/implicit-invalidate-chain.c
===================================================================
--- /dev/null
+++ clang/test/Modules/implicit-invalidate-chain.c
@@ -0,0 +1,67 @@
+// RUN: rm -rf %t1 %t2 %t-include
+// RUN: mkdir %t-include
+// RUN: echo 'module D { header "D.h" }' >> %t-include/module.modulemap
+
+// Run with -verify, which onliy gets remarks from the main TU.
+//
+// RUN: echo '#define D 0' > %t-include/D.h
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t1 \
+// RUN:     -fdisable-module-hash -fsyntax-only \
+// RUN:     -I%S/Inputs/implicit-invalidate-chain -I%t-include \
+// RUN:     -Rmodule-build -Rmodule-import %s
+// RUN: echo '#define D 11' > %t-include/D.h
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t1 \
+// RUN:     -fdisable-module-hash -fsyntax-only \
+// RUN:     -I%S/Inputs/implicit-invalidate-chain -I%t-include \
+// RUN:     -Rmodule-build -Rmodule-import -verify %s
+
+// Run again, using FileCheck to check remarks from the module builds.  This is
+// the key test: after the first attempt to import an out-of-date 'D', all the
+// modules have been invalidated and are not imported again until they are
+// rebuilt.
+//
+// RUN: echo '#define D 0' > %t-include/D.h
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t2 \
+// RUN:     -fdisable-module-hash -fsyntax-only \
+// RUN:     -I%S/Inputs/implicit-invalidate-chain -I%t-include \
+// RUN:     -Rmodule-build -Rmodule-import %s
+// RUN: echo '#define D 11' > %t-include/D.h
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t2 \
+// RUN:     -fdisable-module-hash -fsyntax-only \
+// RUN:     -I%S/Inputs/implicit-invalidate-chain -I%t-include \
+// RUN:     -Rmodule-build -Rmodule-import %s 2>&1 |\
+// RUN: FileCheck %s -implicit-check-not "remark:"
+
+#include "A.h" // \
+   expected-remark-re{{importing module 'A' from '{{.*}}/A.pcm'}} \
+   expected-remark-re{{importing module 'B' into 'A' from '{{.*}}/B.pcm'}} \
+   expected-remark-re{{importing module 'C' into 'B' from '{{.*}}/C.pcm'}} \
+   expected-remark-re{{importing module 'D' into 'C' from '{{.*}}/D.pcm'}} \
+   expected-remark-re{{building module 'A' as '{{.*}}/A.pcm'}} \
+   expected-remark{{finished building module 'A'}} \
+   expected-remark-re{{importing module 'A' from '{{.*}}/A.pcm'}} \
+   expected-remark-re{{importing module 'B' into 'A' from '{{.*}}/B.pcm'}} \
+   expected-remark-re{{importing module 'C' into 'B' from '{{.*}}/C.pcm'}} \
+   expected-remark-re{{importing module 'D' into 'C' from '{{.*}}/D.pcm'}}
+// CHECK: remark: importing module 'A' from '{{.*}}/A.pcm'
+// CHECK: remark: importing module 'B' into 'A' from '{{.*}}/B.pcm'
+// CHECK: remark: importing module 'C' into 'B' from '{{.*}}/C.pcm'
+// CHECK: remark: importing module 'D' into 'C' from '{{.*}}/D.pcm'
+// CHECK: remark: building module 'A'
+// CHECK: remark: building module 'B'
+// CHECK: remark: building module 'C'
+// CHECK: remark: building module 'D'
+// CHECK: remark: finished building module 'D'
+// CHECK: remark: importing module 'D' from '{{.*}}/D.pcm'
+// CHECK: remark: finished building module 'C'
+// CHECK: remark: importing module 'C' from '{{.*}}/C.pcm'
+// CHECK: remark: importing module 'D' into 'C' from '{{.*}}/D.pcm'
+// CHECK: remark: finished building module 'B'
+// CHECK: remark: importing module 'B' from '{{.*}}/B.pcm'
+// CHECK: remark: importing module 'C' into 'B' from '{{.*}}/C.pcm'
+// CHECK: remark: importing module 'D' into 'C' from '{{.*}}/D.pcm'
+// CHECK: remark: finished building module 'A'
+// CHECK: remark: importing module 'A' from '{{.*}}/A.pcm'
+// CHECK: remark: importing module 'B' into 'A' from '{{.*}}/B.pcm'
+// CHECK: remark: importing module 'C' into 'B' from '{{.*}}/C.pcm'
+// CHECK: remark: importing module 'D' into 'C' from '{{.*}}/D.pcm'
Index: clang/test/Modules/relative-import-path.c
===================================================================
--- /dev/null
+++ clang/test/Modules/relative-import-path.c
@@ -0,0 +1,26 @@
+// RUN: rm -rf %t
+// RUN: cp -rf %S/Inputs/relative-import-path %t
+// RUN: cp %s %t/t.c
+
+// Use FileCheck, which is more flexible.
+//
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache \
+// RUN:     -fdisable-module-hash -fsyntax-only \
+// RUN:     -I%S/Inputs/relative-import-path \
+// RUN:     -working-directory=%t \
+// RUN:     -Rmodule-build -Rmodule-import t.c 2>&1 |\
+// RUN: FileCheck %s -implicit-check-not "remark:" -DWORKDIR=%t
+
+#include "A.h" // \
+// CHECK: remark: building module 'A'
+// CHECK: remark: building module 'B'
+// CHECK: remark: building module 'C'
+// CHECK: remark: finished building module 'C'
+// CHECK: remark: importing module 'C' from '[[WORKDIR]]/cache/C.pcm'
+// CHECK: remark: finished building module 'B'
+// CHECK: remark: importing module 'B' from '[[WORKDIR]]/cache/B.pcm'
+// CHECK: remark: importing module 'C' into 'B' from '[[WORKDIR]]/cache/C.pcm'
+// CHECK: remark: finished building module 'A'
+// CHECK: remark: importing module 'A' from '[[WORKDIR]]/cache/A.pcm'
+// CHECK: remark: importing module 'B' into 'A' from '[[WORKDIR]]/cache/B.pcm'
+// CHECK: remark: importing module 'C' into 'B' from '[[WORKDIR]]/cache/C.pcm'
Index: clang/unittests/Serialization/InMemoryModuleCacheTest.cpp
===================================================================
--- clang/unittests/Serialization/InMemoryModuleCacheTest.cpp
+++ clang/unittests/Serialization/InMemoryModuleCacheTest.cpp
@@ -22,72 +22,99 @@
                                     /* RequiresNullTerminator = */ false);
 }
 
-TEST(InMemoryModuleCacheTest, addBuffer) {
-  auto B1 = getBuffer(1);
-  auto B2 = getBuffer(2);
-  auto B3 = getBuffer(3);
-  auto *RawB1 = B1.get();
-  auto *RawB2 = B2.get();
-  auto *RawB3 = B3.get();
-
-  // Add a few buffers.
+TEST(InMemoryModuleCacheTest, initialState) {
   InMemoryModuleCache Cache;
-  EXPECT_EQ(RawB1, &Cache.addBuffer("1", std::move(B1)));
-  EXPECT_EQ(RawB2, &Cache.addBuffer("2", std::move(B2)));
-  EXPECT_EQ(RawB3, &Cache.addBuffer("3", std::move(B3)));
-  EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
-  EXPECT_EQ(RawB2, Cache.lookupBuffer("2"));
-  EXPECT_EQ(RawB3, Cache.lookupBuffer("3"));
-  EXPECT_FALSE(Cache.isBufferFinal("1"));
-  EXPECT_FALSE(Cache.isBufferFinal("2"));
-  EXPECT_FALSE(Cache.isBufferFinal("3"));
-
-  // Remove the middle buffer.
-  EXPECT_FALSE(Cache.tryToRemoveBuffer("2"));
-  EXPECT_EQ(nullptr, Cache.lookupBuffer("2"));
-  EXPECT_FALSE(Cache.isBufferFinal("2"));
-
-  // Replace the middle buffer.
-  B2 = getBuffer(2);
-  RawB2 = B2.get();
-  EXPECT_EQ(RawB2, &Cache.addBuffer("2", std::move(B2)));
-
-  // Check that nothing is final.
-  EXPECT_FALSE(Cache.isBufferFinal("1"));
-  EXPECT_FALSE(Cache.isBufferFinal("2"));
-  EXPECT_FALSE(Cache.isBufferFinal("3"));
+  EXPECT_EQ(InMemoryModuleCache::Unknown, Cache.getPCMState("B"));
+  EXPECT_FALSE(Cache.isPCMFinal("B"));
+  EXPECT_FALSE(Cache.shouldBuildPCM("B"));
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+  EXPECT_DEATH(Cache.tryToDropPCM("B"), "PCM to remove is unknown");
+  EXPECT_DEATH(Cache.finalizePCM("B"), "PCM to finalize is unknown");
+#endif
 }
 
-TEST(InMemoryModuleCacheTest, finalizeCurrentBuffers) {
-  // Add a buffer.
+TEST(InMemoryModuleCacheTest, addPCM) {
+  auto B = getBuffer(1);
+  auto *RawB = B.get();
+
   InMemoryModuleCache Cache;
-  auto B1 = getBuffer(1);
-  auto *RawB1 = B1.get();
-  Cache.addBuffer("1", std::move(B1));
-  ASSERT_FALSE(Cache.isBufferFinal("1"));
-
-  // Finalize it.
-  Cache.finalizeCurrentBuffers();
-  EXPECT_TRUE(Cache.isBufferFinal("1"));
-  EXPECT_TRUE(Cache.tryToRemoveBuffer("1"));
-  EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
-  EXPECT_TRUE(Cache.isBufferFinal("1"));
-
-  // Repeat.
-  auto B2 = getBuffer(2);
-  auto *RawB2 = B2.get();
-  Cache.addBuffer("2", std::move(B2));
-  EXPECT_FALSE(Cache.isBufferFinal("2"));
-
-  Cache.finalizeCurrentBuffers();
-  EXPECT_TRUE(Cache.isBufferFinal("1"));
-  EXPECT_TRUE(Cache.isBufferFinal("2"));
-  EXPECT_TRUE(Cache.tryToRemoveBuffer("1"));
-  EXPECT_TRUE(Cache.tryToRemoveBuffer("2"));
-  EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
-  EXPECT_EQ(RawB2, Cache.lookupBuffer("2"));
-  EXPECT_TRUE(Cache.isBufferFinal("1"));
-  EXPECT_TRUE(Cache.isBufferFinal("2"));
+  EXPECT_EQ(RawB, &Cache.addPCM("B", std::move(B)));
+  EXPECT_EQ(InMemoryModuleCache::Tentative, Cache.getPCMState("B"));
+  EXPECT_EQ(RawB, Cache.lookupPCM("B"));
+  EXPECT_FALSE(Cache.isPCMFinal("B"));
+  EXPECT_FALSE(Cache.shouldBuildPCM("B"));
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+  EXPECT_DEATH(Cache.addPCM("B", getBuffer(2)), "Already has a PCM");
+  EXPECT_DEATH(Cache.addBuiltPCM("B", getBuffer(2)),
+               "Trying to override tentative PCM");
+#endif
+}
+
+TEST(InMemoryModuleCacheTest, addBuiltPCM) {
+  auto B = getBuffer(1);
+  auto *RawB = B.get();
+
+  InMemoryModuleCache Cache;
+  EXPECT_EQ(RawB, &Cache.addBuiltPCM("B", std::move(B)));
+  EXPECT_EQ(InMemoryModuleCache::Final, Cache.getPCMState("B"));
+  EXPECT_EQ(RawB, Cache.lookupPCM("B"));
+  EXPECT_TRUE(Cache.isPCMFinal("B"));
+  EXPECT_FALSE(Cache.shouldBuildPCM("B"));
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+  EXPECT_DEATH(Cache.addPCM("B", getBuffer(2)), "Already has a PCM");
+  EXPECT_DEATH(Cache.addBuiltPCM("B", getBuffer(2)),
+               "Trying to override finalized PCM");
+#endif
+}
+
+TEST(InMemoryModuleCacheTest, tryToDropPCM) {
+  auto B = getBuffer(1);
+  auto *RawB = B.get();
+
+  InMemoryModuleCache Cache;
+  EXPECT_EQ(InMemoryModuleCache::Unknown, Cache.getPCMState("B"));
+  EXPECT_EQ(RawB, &Cache.addPCM("B", std::move(B)));
+  EXPECT_FALSE(Cache.tryToDropPCM("B"));
+  EXPECT_EQ(nullptr, Cache.lookupPCM("B"));
+  EXPECT_EQ(InMemoryModuleCache::ToBuild, Cache.getPCMState("B"));
+  EXPECT_FALSE(Cache.isPCMFinal("B"));
+  EXPECT_TRUE(Cache.shouldBuildPCM("B"));
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+  EXPECT_DEATH(Cache.addPCM("B", getBuffer(2)), "Already has a PCM");
+  EXPECT_DEATH(Cache.tryToDropPCM("B"),
+               "PCM to remove is scheduled to be built");
+  EXPECT_DEATH(Cache.finalizePCM("B"), "Trying to finalize a dropped PCM");
+#endif
+
+  B = getBuffer(2);
+  ASSERT_NE(RawB, B.get());
+  RawB = B.get();
+
+  // Add a new one.
+  EXPECT_EQ(RawB, &Cache.addBuiltPCM("B", std::move(B)));
+  EXPECT_TRUE(Cache.isPCMFinal("B"));
+
+  // Can try to drop again, but this should error and do nothing.
+  EXPECT_TRUE(Cache.tryToDropPCM("B"));
+  EXPECT_EQ(RawB, Cache.lookupPCM("B"));
+}
+
+TEST(InMemoryModuleCacheTest, finalizePCM) {
+  auto B = getBuffer(1);
+  auto *RawB = B.get();
+
+  InMemoryModuleCache Cache;
+  EXPECT_EQ(InMemoryModuleCache::Unknown, Cache.getPCMState("B"));
+  EXPECT_EQ(RawB, &Cache.addPCM("B", std::move(B)));
+
+  // Call finalize.
+  Cache.finalizePCM("B");
+  EXPECT_EQ(InMemoryModuleCache::Final, Cache.getPCMState("B"));
+  EXPECT_TRUE(Cache.isPCMFinal("B"));
 }
 
 } // namespace