Merge remote-tracking branch 'origin/swift-3.1-branch' into stable

* origin/swift-3.1-branch:
  [API Notes] Ensure that modules get rebuilt when binary API notes change.
  [API Notes] Ensure that modules get rebuilt when API notes change.
  [API Notes] Load both public and private API notes when they are present.
  [API Notes] Load API notes from framework/header search paths.
diff --git a/include/clang/APINotes/APINotesManager.h b/include/clang/APINotes/APINotesManager.h
index 7f540b9..a300c14 100644
--- a/include/clang/APINotes/APINotesManager.h
+++ b/include/clang/APINotes/APINotesManager.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_APINOTES_APINOTESMANAGER_H
 
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/Module.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PointerUnion.h"
@@ -54,8 +55,11 @@
   /// source file from which an entity was declared.
   bool ImplicitAPINotes;
 
-  /// The API notes reader for the current module.
-  std::unique_ptr<APINotesReader> CurrentModuleReader;
+  /// API notes readers for the current module.
+  ///
+  /// There can be up to two of these, one for public headers and one
+  /// for private headers.
+  APINotesReader *CurrentModuleReaders[2] = { nullptr, nullptr };
 
   /// Whether we have already pruned the API notes cache.
   bool PrunedCache;
@@ -81,6 +85,13 @@
   bool loadAPINotes(const DirectoryEntry *HeaderDir,
                     const FileEntry *APINotesFile);
 
+  /// Look for API notes in the given directory.
+  ///
+  /// This might find either a binary or source API notes.
+  const FileEntry *findAPINotesFile(const DirectoryEntry *directory,
+                                    StringRef filename,
+                                    bool wantPublic = true);
+
   /// Attempt to load API notes for the given framework.
   ///
   /// \param FrameworkPath The path to the framework.
@@ -100,21 +111,25 @@
 
   /// Load the API notes for the current module.
   ///
-  /// \param moduleName The name of the current module.
+  /// \param module The current module.
+  /// \param lookInModule Whether to look inside the module itself.
   /// \param searchPaths The paths in which we should search for API notes
   /// for the current module.
   ///
-  /// \returns the file entry for the API notes file loaded, or nullptr if
-  /// no API notes were found.
-  const FileEntry *loadCurrentModuleAPINotes(StringRef moduleName,
-                                             ArrayRef<std::string> searchPaths);
+  /// \returns true if API notes were successfully loaded, \c false otherwise.
+  bool loadCurrentModuleAPINotes(const Module *module,
+                                 bool lookInModule,
+                                 ArrayRef<std::string> searchPaths);
 
-  /// Find the API notes reader that corresponds to the given source location.
-  APINotesReader *findAPINotes(SourceLocation Loc);
-
-  APINotesReader *getCurrentModuleReader() {
-    return CurrentModuleReader.get();
+  /// Retrieve the set of API notes readers for the current module.
+  ArrayRef<APINotesReader *> getCurrentModuleReaders() const {
+    unsigned numReaders = static_cast<unsigned>(CurrentModuleReaders[0] != nullptr) +
+      static_cast<unsigned>(CurrentModuleReaders[1] != nullptr);
+    return llvm::makeArrayRef(CurrentModuleReaders).slice(0, numReaders);
   }
+
+  /// Find the API notes readers that correspond to the given source location.
+  llvm::SmallVector<APINotesReader *, 2> findAPINotes(SourceLocation Loc);
 };
 
 } // end namespace api_notes
diff --git a/include/clang/APINotes/APINotesReader.h b/include/clang/APINotes/APINotesReader.h
index cc6dafb..aa88bac 100644
--- a/include/clang/APINotes/APINotesReader.h
+++ b/include/clang/APINotes/APINotesReader.h
@@ -31,7 +31,8 @@
 
   Implementation &Impl;
 
-  APINotesReader(std::unique_ptr<llvm::MemoryBuffer> inputBuffer, bool &failed);
+  APINotesReader(llvm::MemoryBuffer *inputBuffer, bool ownsInputBuffer,
+                 bool &failed);
 
 public:
   /// Create a new API notes reader from the given member buffer, which
@@ -41,6 +42,13 @@
   static std::unique_ptr<APINotesReader>
   get(std::unique_ptr<llvm::MemoryBuffer> inputBuffer);
 
+  /// Create a new API notes reader from the given member buffer, which
+  /// contains the contents of a binary API notes file.
+  ///
+  /// \returns the new API notes reader, or null if an error occurred.
+  static std::unique_ptr<APINotesReader>
+  getUnmanaged(llvm::MemoryBuffer *inputBuffer);
+
   ~APINotesReader();
 
   APINotesReader(const APINotesReader &) = delete;
@@ -50,6 +58,10 @@
   /// notes.
   StringRef getModuleName() const;
 
+  /// Retrieve the size and modification time of the source file from
+  /// which this API notes file was created, if known.
+  Optional<std::pair<off_t, time_t>> getSourceFileSizeAndModTime() const;
+
   /// Retrieve the module options
   ModuleOptions getModuleOptions() const;
 
diff --git a/include/clang/APINotes/APINotesWriter.h b/include/clang/APINotes/APINotesWriter.h
index cc93a5f..4bf3ce1 100644
--- a/include/clang/APINotes/APINotesWriter.h
+++ b/include/clang/APINotes/APINotesWriter.h
@@ -23,6 +23,9 @@
 }
 
 namespace clang {
+
+class FileEntry;
+
 namespace api_notes {
 
 /// A class that writes API notes data to a binary representation that can be
@@ -32,8 +35,9 @@
   Implementation &Impl;
 
 public:
-  /// Create a new API notes writer with the given module name.
-  APINotesWriter(StringRef moduleName);
+  /// Create a new API notes writer with the given module name and
+  /// (optional) source file.
+  APINotesWriter(StringRef moduleName, const FileEntry *sourceFile);
   ~APINotesWriter();
 
   APINotesWriter(const APINotesWriter &) = delete;
diff --git a/include/clang/APINotes/APINotesYAMLCompiler.h b/include/clang/APINotes/APINotesYAMLCompiler.h
index f459e07..508da65 100644
--- a/include/clang/APINotes/APINotesYAMLCompiler.h
+++ b/include/clang/APINotes/APINotesYAMLCompiler.h
@@ -23,6 +23,9 @@
 }
 
 namespace clang {
+
+class FileEntry;
+
 namespace api_notes {
 
   enum class ActionType {
@@ -42,6 +45,7 @@
 
   /// Converts API notes from YAML format to binary format.
   bool compileAPINotes(llvm::StringRef yamlInput,
+                       const FileEntry *sourceFile,
                        llvm::raw_ostream &os,
                        OSType targetOS,
                        llvm::SourceMgr::DiagHandlerTy diagHandler = nullptr,
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index a9b6d27..d192601 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -252,6 +252,7 @@
 
 LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
 LANGOPT(APINotes, 1, 0, "use external API notes")
+LANGOPT(APINotesModules, 1, 0, "use external API notes")
 
 LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
                                            "field padding (0: none, 1:least "
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index b86ef88..cbd2a4a 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -542,8 +542,12 @@
 
 def fapinotes : Flag<["-"], "fapinotes">, Group<f_clang_Group>,
   Flags<[CC1Option]>, HelpText<"Enable external API notes support">;
+def fapinotes_modules : Flag<["-"], "fapinotes-modules">, Group<f_clang_Group>,
+  Flags<[CC1Option]>, HelpText<"Enable module-based external API notes support">;
 def fno_apinotes : Flag<["-"], "fno-apinotes">, Group<f_clang_Group>,
   Flags<[CC1Option]>, HelpText<"Disable external API notes support">;
+def fno_apinotes_modules : Flag<["-"], "fno-apinotes-modules">, Group<f_clang_Group>,
+  Flags<[CC1Option]>, HelpText<"Disable module-based external API notes support">;
 def fapinotes_cache_path : Joined<["-"], "fapinotes-cache-path=">,
   Group<i_Group>, Flags<[DriverOption, CC1Option]>, MetaVarName<"<directory>">,
   HelpText<"Specify the API notes cache path">;
diff --git a/lib/APINotes/APINotesFormat.h b/lib/APINotes/APINotesFormat.h
index 1db2380..542f908 100644
--- a/lib/APINotes/APINotesFormat.h
+++ b/lib/APINotes/APINotesFormat.h
@@ -36,7 +36,7 @@
 /// API notes file minor version number.
 ///
 /// When the format changes IN ANY WAY, this number should be incremented.
-const uint16_t VERSION_MINOR = 14;  // Objective-C class properties
+const uint16_t VERSION_MINOR = 15;  // source file info
 
 using IdentifierID = PointerEmbeddedInt<unsigned, 31>;
 using IdentifierIDField = BCVBR<16>;
@@ -106,7 +106,8 @@
   enum {
     METADATA = 1,
     MODULE_NAME = 2,
-    MODULE_OPTIONS = 3
+    MODULE_OPTIONS = 3,
+    SOURCE_FILE = 4,
   };
 
   using MetadataLayout = BCRecordLayout<
@@ -124,6 +125,12 @@
     MODULE_OPTIONS,
     BCFixed<1> // SwiftInferImportAsMember
   >;
+
+  using SourceFileLayout = BCRecordLayout<
+    SOURCE_FILE,
+    BCVBR<16>, // file size
+    BCVBR<16>  // creation time
+  >;
 }
 
 namespace identifier_block {
diff --git a/lib/APINotes/APINotesManager.cpp b/lib/APINotes/APINotesManager.cpp
index 3c3d5fd..834d7e1 100644
--- a/lib/APINotes/APINotesManager.cpp
+++ b/lib/APINotes/APINotesManager.cpp
@@ -1,4 +1,4 @@
-//===--- APINotesMAnager.cpp - Manage API Notes Files ---------------------===//
+//===--- APINotesManager.cpp - Manage API Notes Files ---------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -63,6 +63,9 @@
       delete reader;
     }
   }
+
+  delete CurrentModuleReaders[0];
+  delete CurrentModuleReaders[1];
 }
 
 /// \brief Write a new timestamp file with the given path.
@@ -143,12 +146,14 @@
   StringRef apiNotesFileExt = llvm::sys::path::extension(apiNotesFileName);
   if (!apiNotesFileExt.empty() &&
       apiNotesFileExt.substr(1) == BINARY_APINOTES_EXTENSION) {
+    auto compiledFileID = SourceMgr.createFileID(apiNotesFile, SourceLocation(), SrcMgr::C_User);
+
     // Load the file.
-    auto buffer = fileMgr.getBufferForFile(apiNotesFile);
+    auto buffer = SourceMgr.getBuffer(compiledFileID, SourceLocation());
     if (!buffer) return nullptr;
 
     // Load the binary form.
-    return APINotesReader::get(std::move(buffer.get()));
+    return APINotesReader::getUnmanaged(buffer);
   }
 
   // If we haven't pruned the API notes cache yet during this execution, do
@@ -178,11 +183,16 @@
                                                       /*cacheFailure=*/false)) {
     // Load the file contents.
     if (auto buffer = fileMgr.getBufferForFile(compiledFile)) {
-      // Make sure the file is up-to-date.
-      if (compiledFile->getModificationTime()
-            >= apiNotesFile->getModificationTime()) {
-        // Load the file.
-        if (auto reader = APINotesReader::get(std::move(buffer.get()))) {
+      // Load the file.
+      if (auto reader = APINotesReader::get(std::move(buffer.get()))) {
+        bool outOfDate = false;
+        if (auto sizeAndModTime = reader->getSourceFileSizeAndModTime()) {
+          if (sizeAndModTime->first != apiNotesFile->getSize() ||
+              sizeAndModTime->second != apiNotesFile->getModificationTime())
+            outOfDate = true;
+        }
+
+        if (!outOfDate) {
           // Success.
           ++NumBinaryCacheHits;
           return reader;
@@ -199,13 +209,15 @@
   }
 
   // Open the source file.
-  auto buffer = fileMgr.getBufferForFile(apiNotesFile);
-  if (!buffer) return nullptr;
+  auto sourceFileID = SourceMgr.createFileID(apiNotesFile, SourceLocation(), SrcMgr::C_User);
+  auto sourceBuffer = SourceMgr.getBuffer(sourceFileID, SourceLocation());
+  if (!sourceBuffer) return nullptr;
 
   // Compile the API notes source into a buffer.
   // FIXME: Either propagate OSType through or, better yet, improve the binary
   // APINotes format to maintain complete availability information.
   llvm::SmallVector<char, 1024> apiNotesBuffer;
+  std::unique_ptr<llvm::MemoryBuffer> compiledBuffer;
   {
     SourceMgrAdapter srcMgrAdapter(SourceMgr, SourceMgr.getDiagnostics(),
                                    diag::err_apinotes_message,
@@ -213,7 +225,8 @@
                                    diag::note_apinotes_message,
                                    apiNotesFile);
     llvm::raw_svector_ostream OS(apiNotesBuffer);
-    if (api_notes::compileAPINotes(buffer.get()->getBuffer(),
+    if (api_notes::compileAPINotes(sourceBuffer->getBuffer(),
+                                   SourceMgr.getFileEntryForID(sourceFileID),
                                    OS,
                                    api_notes::OSType::Absent,
                                    srcMgrAdapter.getDiagHandler(),
@@ -221,7 +234,7 @@
       return nullptr;
 
     // Make a copy of the compiled form into the buffer.
-    buffer = llvm::MemoryBuffer::getMemBufferCopy(
+    compiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
                StringRef(apiNotesBuffer.data(), apiNotesBuffer.size()));
   }
 
@@ -244,7 +257,8 @@
     bool hadError;
     {
       llvm::raw_fd_ostream out(temporaryFD, /*shouldClose=*/true);
-      out.write(buffer.get()->getBufferStart(), buffer.get()->getBufferSize());
+      out.write(compiledBuffer.get()->getBufferStart(),
+                compiledBuffer.get()->getBufferSize());
       out.flush();
 
       hadError = out.has_error();
@@ -258,7 +272,7 @@
   }
 
   // Load the binary form we just compiled.
-  auto reader = APINotesReader::get(std::move(*buffer));
+  auto reader = APINotesReader::get(std::move(compiledBuffer));
   assert(reader && "Could not load the API notes we just generated?");
   return reader;
 }
@@ -275,6 +289,34 @@
   return true;
 }
 
+const FileEntry *APINotesManager::findAPINotesFile(const DirectoryEntry *directory,
+                                                   StringRef basename,
+                                                   bool wantPublic) {
+  FileManager &fileMgr = SourceMgr.getFileManager();
+
+  llvm::SmallString<128> path;
+  path += directory->getName();
+
+  unsigned pathLen = path.size();
+
+  StringRef basenameSuffix = "";
+  if (!wantPublic) basenameSuffix = "_private";
+
+  // Look for a binary API notes file.
+  llvm::sys::path::append(path, 
+    llvm::Twine(basename) + basenameSuffix + "." + BINARY_APINOTES_EXTENSION);
+  if (const FileEntry *binaryFile = fileMgr.getFile(path))
+    return binaryFile;
+
+  // Go back to the original path.
+  path.resize(pathLen);
+
+  // Look for the source API notes file.
+  llvm::sys::path::append(path, 
+    llvm::Twine(basename) + basenameSuffix + "." + SOURCE_APINOTES_EXTENSION);
+  return fileMgr.getFile(path);
+}
+
 const DirectoryEntry *APINotesManager::loadFrameworkAPINotes(
                         llvm::StringRef FrameworkPath,
                         llvm::StringRef FrameworkName,
@@ -325,65 +367,88 @@
   return HeaderDir;
 }
 
-const FileEntry *APINotesManager::loadCurrentModuleAPINotes(
-                   StringRef moduleName,
+bool APINotesManager::loadCurrentModuleAPINotes(
+                   const Module *module,
+                   bool lookInModule,
                    ArrayRef<std::string> searchPaths) {
-  assert(!CurrentModuleReader &&
+  assert(!CurrentModuleReaders[0] &&
          "Already loaded API notes for the current module?");
 
   FileManager &fileMgr = SourceMgr.getFileManager();
+  auto moduleName = module->getTopLevelModuleName();
 
-  // Look for API notes for this module in the module search paths.
-  for (const auto &searchPath : searchPaths) {
-    // First, look for a binary API notes file.
-    llvm::SmallString<128> apiNotesFilePath;
-    apiNotesFilePath += searchPath;
-    llvm::sys::path::append(
-      apiNotesFilePath,
-      llvm::Twine(moduleName) + "." + BINARY_APINOTES_EXTENSION);
+  // First, look relative to the module itself.
+  if (lookInModule) {
+    bool foundAny = false;
+    unsigned numReaders = 0;
 
-    // Try to open the binary API Notes file.
-    if (const FileEntry *binaryAPINotesFile
-          = fileMgr.getFile(apiNotesFilePath)) {
-      CurrentModuleReader = loadAPINotes(binaryAPINotesFile);
-      return CurrentModuleReader ? binaryAPINotesFile : nullptr;
+    // Local function to try loading an API notes file in the given directory.
+    auto tryAPINotes = [&](const DirectoryEntry *dir, bool wantPublic) {
+      if (auto file = findAPINotesFile(dir, moduleName, wantPublic)) {
+        foundAny = true;
+
+        // Try to load the API notes file.
+        CurrentModuleReaders[numReaders] = loadAPINotes(file).release();
+        if (CurrentModuleReaders[numReaders])
+          ++numReaders;
+      }
+    };
+
+    if (module->IsFramework) {
+      // For frameworks, we search in the "APINotes" subdirectory.
+      llvm::SmallString<128> path;
+      path += module->Directory->getName();
+      llvm::sys::path::append(path, "APINotes");
+      if (auto apinotesDir = fileMgr.getDirectory(path)) {
+        tryAPINotes(apinotesDir, /*wantPublic=*/true);
+        tryAPINotes(apinotesDir, /*wantPublic=*/false);
+      }
+    } else {
+      tryAPINotes(module->Directory, /*wantPublic=*/true);
+      tryAPINotes(module->Directory, /*wantPublic=*/false);
     }
 
-    // Try to open the source API Notes file.
-    apiNotesFilePath = searchPath;
-    llvm::sys::path::append(
-      apiNotesFilePath,
-      llvm::Twine(moduleName) + "." + SOURCE_APINOTES_EXTENSION);
-    if (const FileEntry *sourceAPINotesFile
-          = fileMgr.getFile(apiNotesFilePath)) {
-      CurrentModuleReader = loadAPINotes(sourceAPINotesFile);
-      return CurrentModuleReader ? sourceAPINotesFile : nullptr;
+    if (foundAny)
+      return numReaders > 0;
+  }
+
+  // Second, look for API notes for this module in the module API
+  // notes search paths.
+  for (const auto &searchPath : searchPaths) {
+    if (auto searchDir = fileMgr.getDirectory(searchPath)) {
+      if (auto file = findAPINotesFile(searchDir, moduleName)) {
+        CurrentModuleReaders[0] = loadAPINotes(file).release();
+        return !getCurrentModuleReaders().empty();
+      }
     }
   }
 
   // Didn't find any API notes.
-  return nullptr;
+  return false;
 }
 
-APINotesReader *APINotesManager::findAPINotes(SourceLocation Loc) {
-  // If there is a reader for the current module, return it.
-  if (CurrentModuleReader) return CurrentModuleReader.get();
+llvm::SmallVector<APINotesReader *, 2> APINotesManager::findAPINotes(SourceLocation Loc) {
+  llvm::SmallVector<APINotesReader *, 2> Results;
+
+  // If there are readers for the current module, return them.
+  if (!getCurrentModuleReaders().empty()) {
+    Results.append(getCurrentModuleReaders().begin(), getCurrentModuleReaders().end());
+    return Results;
+  }
 
   // If we're not allowed to implicitly load API notes files, we're done.
-  if (!ImplicitAPINotes) return nullptr;
+  if (!ImplicitAPINotes) return Results;
 
   // If we don't have source location information, we're done.
-  if (Loc.isInvalid()) return nullptr;
+  if (Loc.isInvalid()) return Results;
 
   // API notes are associated with the expansion location. Retrieve the
   // file for this location.
   SourceLocation ExpansionLoc = SourceMgr.getExpansionLoc(Loc);
   FileID ID = SourceMgr.getFileID(ExpansionLoc);
-  if (ID.isInvalid())
-    return nullptr;
+  if (ID.isInvalid()) return Results;
   const FileEntry *File = SourceMgr.getFileEntryForID(ID);
-  if (!File)
-    return nullptr;
+  if (!File) return Results;
 
   // Look for API notes in the directory corresponding to this file, or one of
   // its its parent directories.
@@ -392,7 +457,6 @@
   llvm::SetVector<const DirectoryEntry *,
                   SmallVector<const DirectoryEntry *, 4>,
                   llvm::SmallPtrSet<const DirectoryEntry *, 4>> DirsVisited;
-  APINotesReader *Result = nullptr;
   do {
     // Look for an API notes reader for this header search directory.
     auto Known = Readers.find(Dir);
@@ -409,7 +473,8 @@
       }
 
       // We have the answer.
-      Result = Known->second.dyn_cast<APINotesReader *>();
+      if (auto Reader = Known->second.dyn_cast<APINotesReader *>())
+        Results.push_back(Reader);
       break;
     }
 
@@ -445,7 +510,8 @@
         }
 
         // Grab the result.
-        Result = Readers[Dir].dyn_cast<APINotesReader *>();;
+        if (auto Reader = Readers[Dir].dyn_cast<APINotesReader *>())
+          Results.push_back(Reader);
         break;
       }
     } else {
@@ -461,7 +527,8 @@
       if (const FileEntry *APINotesFile = FileMgr.getFile(APINotesPath)) {
         if (!loadAPINotes(Dir, APINotesFile)) {
           ++NumHeaderAPINotes;
-          Result = Readers[Dir].dyn_cast<APINotesReader *>();
+          if (auto Reader = Readers[Dir].dyn_cast<APINotesReader *>())
+            Results.push_back(Reader);
           break;
         }
       }
@@ -491,5 +558,5 @@
     Readers[Visited] = Dir;
   }
 
-  return Result;
+  return Results;
 }
diff --git a/lib/APINotes/APINotesReader.cpp b/lib/APINotes/APINotesReader.cpp
index 2b49125..0c93756 100644
--- a/lib/APINotes/APINotesReader.cpp
+++ b/lib/APINotes/APINotesReader.cpp
@@ -578,7 +578,10 @@
 class APINotesReader::Implementation {
 public:
   /// The input buffer for the API notes data.
-  std::unique_ptr<llvm::MemoryBuffer> InputBuffer;
+  llvm::MemoryBuffer *InputBuffer;
+
+  /// Whether we own the input buffer.
+  bool OwnsInputBuffer;
 
   /// The reader attached to \c InputBuffer.
   llvm::BitstreamReader InputReader;
@@ -586,6 +589,10 @@
   /// The name of the module that we read from the control block.
   std::string ModuleName;
 
+  // The size and modification time of the source file from
+  // which this API notes file was created, if known.
+  Optional<std::pair<off_t, time_t>> SourceFileSizeAndModTime;
+
   /// Various options and attributes for the module
   ModuleOptions ModuleOpts;
 
@@ -766,6 +773,10 @@
       ModuleOpts.SwiftInferImportAsMember = (scratch.front() & 1) != 0;
       break;
 
+    case control_block::SOURCE_FILE:
+      SourceFileSizeAndModTime = { scratch[0], scratch[1] };
+      break;
+
     default:
       // Unknown metadata record, possibly for use by a future version of the
       // module format.
@@ -1313,14 +1324,16 @@
   return false;
 }
 
-APINotesReader::APINotesReader(std::unique_ptr<llvm::MemoryBuffer> inputBuffer, 
-                             bool &failed) 
+APINotesReader::APINotesReader(llvm::MemoryBuffer *inputBuffer, 
+                               bool ownsInputBuffer,
+                               bool &failed) 
   : Impl(*new Implementation)
 {
   failed = false;
 
   // Initialize the input buffer.
-  Impl.InputBuffer = std::move(inputBuffer);
+  Impl.InputBuffer = inputBuffer;
+  Impl.OwnsInputBuffer = ownsInputBuffer;
   Impl.InputReader.init(
     reinterpret_cast<const uint8_t *>(Impl.InputBuffer->getBufferStart()), 
     reinterpret_cast<const uint8_t *>(Impl.InputBuffer->getBufferEnd()));
@@ -1453,6 +1466,9 @@
 }
 
 APINotesReader::~APINotesReader() {
+  if (Impl.OwnsInputBuffer)
+    delete Impl.InputBuffer;
+
   delete &Impl;
 }
 
@@ -1460,7 +1476,20 @@
 APINotesReader::get(std::unique_ptr<llvm::MemoryBuffer> inputBuffer) {
   bool failed = false;
   std::unique_ptr<APINotesReader> 
-    reader(new APINotesReader(std::move(inputBuffer), failed));
+    reader(new APINotesReader(inputBuffer.release(), /*ownsInputBuffer=*/true,
+                              failed));
+  if (failed)
+    return nullptr;
+
+  return reader;
+}
+
+std::unique_ptr<APINotesReader> 
+APINotesReader::getUnmanaged(llvm::MemoryBuffer *inputBuffer) {
+  bool failed = false;
+  std::unique_ptr<APINotesReader> 
+    reader(new APINotesReader(inputBuffer, /*ownsInputBuffer=*/false,
+                              failed));
   if (failed)
     return nullptr;
 
@@ -1471,6 +1500,11 @@
   return Impl.ModuleName;
 }
 
+Optional<std::pair<off_t, time_t>>
+APINotesReader::getSourceFileSizeAndModTime() const {
+  return Impl.SourceFileSizeAndModTime;
+}
+
 ModuleOptions APINotesReader::getModuleOptions() const {
   return Impl.ModuleOpts;
 }
diff --git a/lib/APINotes/APINotesWriter.cpp b/lib/APINotes/APINotesWriter.cpp
index b0a4650..2df5e76 100644
--- a/lib/APINotes/APINotesWriter.cpp
+++ b/lib/APINotes/APINotesWriter.cpp
@@ -15,6 +15,7 @@
 //===----------------------------------------------------------------------===//
 #include "clang/APINotes/APINotesWriter.h"
 #include "APINotesFormat.h"
+#include "clang/Basic/FileManager.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallString.h"
@@ -43,6 +44,10 @@
   /// The name of the module
   std::string ModuleName;
 
+  /// The source file from which this binary representation was
+  /// created, if known.
+  const FileEntry *SourceFile;
+
   bool SwiftInferImportAsMember = false;
 
   /// Information about Objective-C contexts (classes or protocols).
@@ -222,6 +227,12 @@
     control_block::ModuleOptionsLayout moduleOptions(writer);
     moduleOptions.emit(ScratchRecord, SwiftInferImportAsMember);
   }
+
+  if (SourceFile) {
+    control_block::SourceFileLayout sourceFile(writer);
+    sourceFile.emit(ScratchRecord, SourceFile->getSize(),
+                    SourceFile->getModificationTime());
+  }
 }
 
 namespace {
@@ -1006,10 +1017,11 @@
   os.flush();
 }
 
-APINotesWriter::APINotesWriter(StringRef moduleName)
+APINotesWriter::APINotesWriter(StringRef moduleName, const FileEntry *sourceFile)
   : Impl(*new Implementation)
 {
   Impl.ModuleName = moduleName;
+  Impl.SourceFile = sourceFile;
 }
 
 APINotesWriter::~APINotesWriter() {
diff --git a/lib/APINotes/APINotesYAMLCompiler.cpp b/lib/APINotes/APINotesYAMLCompiler.cpp
index b964095..0d30731 100644
--- a/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -501,6 +501,7 @@
 
   class YAMLConverter {
     const Module &TheModule;
+    const FileEntry *SourceFile;
     APINotesWriter *Writer;
     OSType TargetOS;
     llvm::raw_ostream &OS;
@@ -519,11 +520,12 @@
 
   public:
     YAMLConverter(const Module &module,
-                 OSType targetOS,
-                 llvm::raw_ostream &os,
-                 llvm::SourceMgr::DiagHandlerTy diagHandler,
-                 void *diagHandlerCtxt) :
-      TheModule(module), Writer(0), TargetOS(targetOS), OS(os),
+                  const FileEntry *sourceFile,
+                  OSType targetOS,
+                  llvm::raw_ostream &os,
+                  llvm::SourceMgr::DiagHandlerTy diagHandler,
+                  void *diagHandlerCtxt) :
+      TheModule(module), SourceFile(sourceFile), Writer(0), TargetOS(targetOS), OS(os),
       DiagHandler(diagHandler), DiagHandlerCtxt(diagHandlerCtxt),
       ErrorOccured(false) {}
 
@@ -739,7 +741,7 @@
 
       // Set up the writer.
       // FIXME: This is kindof ugly.
-      APINotesWriter writer(TheModule.Name);
+      APINotesWriter writer(TheModule.Name, SourceFile);
       Writer = &writer;
 
       // Write all classes.
@@ -877,13 +879,14 @@
 }
 
 static bool compile(const Module &module,
+                    const FileEntry *sourceFile,
                     llvm::raw_ostream &os,
                     api_notes::OSType targetOS,
                     llvm::SourceMgr::DiagHandlerTy diagHandler,
                     void *diagHandlerCtxt){
   using namespace api_notes;
 
-  YAMLConverter c(module, targetOS, os, diagHandler, diagHandlerCtxt);
+  YAMLConverter c(module, sourceFile, targetOS, os, diagHandler, diagHandlerCtxt);
   return c.convertModule();
 }
 
@@ -905,6 +908,7 @@
 }
 
 bool api_notes::compileAPINotes(StringRef yamlInput,
+                                const FileEntry *sourceFile,
                                 llvm::raw_ostream &os,
                                 OSType targetOS,
                                 llvm::SourceMgr::DiagHandlerTy diagHandler,
@@ -918,7 +922,7 @@
   if (parseAPINotes(yamlInput, module, diagHandler, diagHandlerCtxt))
     return true;
 
-  return compile(module, os, targetOS, diagHandler, diagHandlerCtxt);
+  return compile(module, sourceFile, os, targetOS, diagHandler, diagHandlerCtxt);
 }
 
 namespace {
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index ff311b3..0cb09f1 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -5334,9 +5334,14 @@
 
   if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes,
                    false) ||
+      Args.hasFlag(options::OPT_fapinotes_modules,
+                     options::OPT_fno_apinotes_modules, false) ||
       Args.hasArg(options::OPT_iapinotes_modules)) {
     if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false))
       CmdArgs.push_back("-fapinotes");
+    if (Args.hasFlag(options::OPT_fapinotes_modules,
+                     options::OPT_fno_apinotes_modules, false))
+      CmdArgs.push_back("-fapinotes-modules");
 
     SmallString<128> APINotesCachePath;
     if (Arg *A = Args.getLastArg(options::OPT_fapinotes_cache_path)) {
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 70f6a54..a68d87b 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -540,20 +540,19 @@
   TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
                          TUKind, CompletionConsumer));
 
-  // If we're building a module, notify the API notes manager.
-  StringRef currentModuleName = getLangOpts().CurrentModule;
-  if (!currentModuleName.empty()) {
+  // If we're building a module and are supposed to load API notes,
+  // notify the API notes manager.
+  if (auto currentModule = getPreprocessor().getCurrentModule()) {
     (void)TheSema->APINotes.loadCurrentModuleAPINotes(
-            currentModuleName,
+            currentModule,
+            getLangOpts().APINotesModules,
             getAPINotesOpts().ModuleSearchPaths);
     // Check for any attributes we should add to the module
-    if (auto curReader = TheSema->APINotes.getCurrentModuleReader()) {
-      auto currentModule = getPreprocessor().getCurrentModule();
-      assert(currentModule && "how can we have a reader for it?");
-
+    for (auto reader : TheSema->APINotes.getCurrentModuleReaders()) {
       // swift_infer_import_as_member
-      if (curReader->getModuleOptions().SwiftInferImportAsMember) {
+      if (reader->getModuleOptions().SwiftInferImportAsMember) {
         currentModule->IsSwiftInferImportAsMember = true;
+        break;
       }
     }
   }
@@ -953,7 +952,7 @@
                               SourceLocation ImportLoc,
                               Module *Module,
                               StringRef ModuleFileName) {
-  ModuleMap &ModMap 
+  ModuleMap &ModMap
     = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
     
   // Construct a compiler invocation for creating this module.
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 140a4aa..bf65770 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1969,6 +1969,7 @@
   Opts.HalfArgsAndReturns = Args.hasArg(OPT_fallow_half_arguments_and_returns)
                             | Opts.NativeHalfArgsAndReturns;
   Opts.APINotes = Args.hasArg(OPT_fapinotes);
+  Opts.APINotesModules = Args.hasArg(OPT_fapinotes_modules);
   Opts.GNUAsm = !Args.hasArg(OPT_fno_gnu_inline_asm);
 
   // __declspec is enabled by default for the PS4 by the driver, and also
@@ -2389,8 +2390,8 @@
     if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
       LangOpts.ObjCExceptions = 1;
 
-    // -fapinotes requires -fapinotes-cache-path=<directory>.
-    if (LangOpts.APINotes &&
+    // -fapinotes and -fapinotes-modules requires -fapinotes-cache-path=<directory>.
+    if ((LangOpts.APINotes || LangOpts.APINotesModules) &&
         Res.getFileSystemOpts().APINotesCachePath.empty()) {
       Diags.Report(diag::err_no_apinotes_cache_path);
       Success = false;
diff --git a/lib/Sema/SemaAPINotes.cpp b/lib/Sema/SemaAPINotes.cpp
index a0c5ca8..29861d1 100644
--- a/lib/Sema/SemaAPINotes.cpp
+++ b/lib/Sema/SemaAPINotes.cpp
@@ -327,8 +327,7 @@
   if (D->getDeclContext()->isFileContext()) {
     // Global variables.
     if (auto VD = dyn_cast<VarDecl>(D)) {
-      if (api_notes::APINotesReader *Reader
-            = APINotes.findAPINotes(D->getLocation())) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         if (auto Info = Reader->lookupGlobalVariable(VD->getName())) {
           ::ProcessAPINotes(*this, VD, *Info);
         }
@@ -340,8 +339,7 @@
     // Global functions.
     if (auto FD = dyn_cast<FunctionDecl>(D)) {
       if (FD->getDeclName().isIdentifier()) {
-        if (api_notes::APINotesReader *Reader
-              = APINotes.findAPINotes(D->getLocation())) {
+        for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
           if (auto Info = Reader->lookupGlobalFunction(FD->getName())) {
             ::ProcessAPINotes(*this, FD, *Info);
           }
@@ -353,8 +351,7 @@
 
     // Objective-C classes.
     if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) {
-      if (api_notes::APINotesReader *Reader
-            = APINotes.findAPINotes(D->getLocation())) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         if (auto Info = Reader->lookupObjCClass(Class->getName())) {
           ::ProcessAPINotes(*this, Class, Info->second);
         }
@@ -365,8 +362,7 @@
 
     // Objective-C protocols.
     if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) {
-      if (api_notes::APINotesReader *Reader
-            = APINotes.findAPINotes(D->getLocation())) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         if (auto Info = Reader->lookupObjCProtocol(Protocol->getName())) {
           ::ProcessAPINotes(*this, Protocol, Info->second);
         }
@@ -377,8 +373,7 @@
 
     // Tags
     if (auto Tag = dyn_cast<TagDecl>(D)) {
-      if (api_notes::APINotesReader *Reader
-            = APINotes.findAPINotes(D->getLocation())) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         if (auto Info = Reader->lookupTag(Tag->getName())) {
           ::ProcessAPINotes(*this, Tag, *Info);
         }
@@ -389,8 +384,7 @@
 
     // Typedefs
     if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {
-      if (api_notes::APINotesReader *Reader
-            = APINotes.findAPINotes(D->getLocation())) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         if (auto Info = Reader->lookupTypedef(Typedef->getName())) {
           ::ProcessAPINotes(*this, Typedef, *Info);
         }
@@ -405,8 +399,7 @@
   // Enumerators.
   if (D->getDeclContext()->getRedeclContext()->isFileContext()) {
     if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {
-      if (api_notes::APINotesReader *Reader
-            = APINotes.findAPINotes(D->getLocation())) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         if (auto Info = Reader->lookupEnumConstant(EnumConstant->getName())) {
           ::ProcessAPINotes(*this, EnumConstant, *Info);
         }
@@ -461,8 +454,7 @@
 
     // Objective-C methods.
     if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
-      if (api_notes::APINotesReader *Reader
-            = APINotes.findAPINotes(D->getLocation())) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         if (auto Context = GetContext(Reader)) {
           // Map the selector.
           Selector Sel = Method->getSelector();
@@ -488,8 +480,7 @@
 
     // Objective-C properties.
     if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
-      if (api_notes::APINotesReader *Reader
-            = APINotes.findAPINotes(D->getLocation())) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         if (auto Context = GetContext(Reader)) {
           bool isInstanceProperty =
             (Property->getPropertyAttributesAsWritten() &
diff --git a/test/APINotes/Inputs/APINotes/SomeKit.apinotes b/test/APINotes/Inputs/APINotes/SomeKit.apinotes
deleted file mode 100644
index 52336df..0000000
--- a/test/APINotes/Inputs/APINotes/SomeKit.apinotes
+++ /dev/null
@@ -1,48 +0,0 @@
-Name: SomeKit
-Classes:
-  - Name: A
-    Methods:         
-      - Selector:        "transform:"
-        MethodKind:      Instance
-        Availability:    none
-        AvailabilityMsg: "anything but this"
-      - Selector: "transform:integer:"
-        MethodKind:      Instance
-        NullabilityOfRet: N
-        Nullability:      [ N, S ]
-      - Selector: "privateTransform:input:"
-        MethodKind:      Instance
-        NullabilityOfRet: N
-        Nullability:      [ N, S ]
-    Properties:
-      - Name: intValue
-        Availability: none
-        AvailabilityMsg: "wouldn't work anyway"
-      - Name: internalProperty
-        Nullability: N
-      - Name: nonnullAInstance
-        PropertyKind:    Instance
-        Nullability:     N
-      - Name: nonnullAClass
-        PropertyKind:    Class
-        Nullability:     N
-      - Name: nonnullABoth
-        Nullability:     N
-  - Name: B
-    Availability: none
-    AvailabilityMsg: "just don't"
-  - Name: C
-    Methods:
-      - Selector: "initWithA:"
-        MethodKind: Instance
-        DesignatedInit: true
-  - Name: ProcessInfo
-    Methods:
-      - Selector: "processInfo"
-        MethodKind: Class
-        FactoryAsInit: C
-
-Protocols:
-  - Name: InternalProtocol
-    Availability: none
-    AvailabilityMsg: "not for you"
diff --git a/test/APINotes/Inputs/APINotes/SomeOtherKit.apinotes b/test/APINotes/Inputs/APINotes/SomeOtherKit.apinotes
new file mode 100644
index 0000000..ccdc4e1
--- /dev/null
+++ b/test/APINotes/Inputs/APINotes/SomeOtherKit.apinotes
@@ -0,0 +1,8 @@
+Name: SomeOtherKit
+Classes:
+  - Name: A
+    Methods:
+      - Selector:        "methodB"
+        MethodKind:      Instance
+        Availability:    none
+        AvailabilityMsg: "anything but this"
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes b/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes
index ade66a1..e79a210 100644
--- a/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes
@@ -1,7 +1,7 @@
 Name: SomeKit
 Classes:
   - Name: A
-    Methods:         
+    Methods:
       - Selector:        "transform:"
         MethodKind:      Instance
         Availability:    none
diff --git a/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/APINotes/SomeOtherKit.apinotes b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/APINotes/SomeOtherKit.apinotes
new file mode 100644
index 0000000..2ad546b
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/APINotes/SomeOtherKit.apinotes
@@ -0,0 +1,8 @@
+Name: SomeOtherKit
+Classes:
+  - Name: A
+    Methods:
+      - Selector:        "methodA"
+        MethodKind:      Instance
+        Availability:    none
+        AvailabilityMsg: "anything but this"
diff --git a/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.h b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.h
new file mode 100644
index 0000000..3911d76
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Headers/SomeOtherKit.h
@@ -0,0 +1,9 @@
+#ifndef SOME_OTHER_KIT_H
+
+__attribute__((objc_root_class))
+@interface A
+-(void)methodA;
+-(void)methodB;
+@end
+
+#endif
diff --git a/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Modules/module.modulemap b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Modules/module.modulemap
new file mode 100644
index 0000000..0aaad92
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/SomeOtherKit.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module SomeOtherKit {
+  umbrella header "SomeOtherKit.h"
+  export *
+  module * { export * }
+}
diff --git a/test/APINotes/Inputs/APINotes/HeaderLib.apinotes b/test/APINotes/Inputs/Headers/HeaderLib.apinotes
similarity index 95%
rename from test/APINotes/Inputs/APINotes/HeaderLib.apinotes
rename to test/APINotes/Inputs/Headers/HeaderLib.apinotes
index 9df8c3d..f1cd086 100644
--- a/test/APINotes/Inputs/APINotes/HeaderLib.apinotes
+++ b/test/APINotes/Inputs/Headers/HeaderLib.apinotes
@@ -1,4 +1,5 @@
 Name: HeaderLib
+SwiftInferImportAsMember: true
 Functions:
   - Name: custom_realloc
     NullabilityOfRet: N
@@ -16,17 +17,15 @@
         NoEscape: true
       - Position: 1
         NoEscape: true
-    
 Globals:
   - Name: global_int
     Nullability: N
   - Name: unavailable_global_int
     Availability: none
-
 Tags:
   - Name: unavailable_struct
     Availability: none
 
 Typedefs:
   - Name: unavailable_typedef
-    Availability: none
+    Availability: none
\ No newline at end of file
diff --git a/test/APINotes/availability.m b/test/APINotes/availability.m
index 1cfc658..5537316 100644
--- a/test/APINotes/availability.m
+++ b/test/APINotes/availability.m
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %S/Inputs/APINotes -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
 
 #include "HeaderLib.h"
 #import <SomeKit/SomeKit.h>
diff --git a/test/APINotes/cache.m b/test/APINotes/cache.m
index 6a2c2f5..b87bdf1 100644
--- a/test/APINotes/cache.m
+++ b/test/APINotes/cache.m
@@ -1,19 +1,19 @@
 // RUN: rm -rf %t/APINotesCache
-// RUN: %clang_cc1 -fapinotes -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
 
 // Check for the presence of the cached compiled form.
 // RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
 
 // Run test again to ensure that caching doesn't cause problems.
-// RUN: %clang_cc1 -fapinotes -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks  %s -verify
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks  %s -verify
 
 // Check that the driver provides a default -fapinotes-cache-path=
-// RUN: %clang -fsyntax-only -fapinotes -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -### 2>&1 | FileCheck --check-prefix=CHECK-DEFAULT-PATH %s
+// RUN: %clang -fsyntax-only -fapinotes -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -### 2>&1 | FileCheck --check-prefix=CHECK-DEFAULT-PATH %s
 // CHECK-DEFAULT-PATH: -fapinotes-cache-path={{.*}}org.llvm.clang/APINotesCache
 
 // Check that the driver passes through a provided -fapinotes-cache-path=
-// RUN: %clang -fsyntax-only -fapinotes -fapinotes-cache-path=/wobble -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -### 2>&1 | FileCheck --check-prefix=CHECK-PATH %s
+// RUN: %clang -fsyntax-only -fapinotes -fapinotes-modules -fapinotes-cache-path=/wobble -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -### 2>&1 | FileCheck --check-prefix=CHECK-PATH %s
 // CHECK-PATH: -fapinotes-cache-path=/wobble
 
 #include "HeaderLib.h"
@@ -30,4 +30,3 @@
 
   return 0;
 }
-
diff --git a/test/APINotes/cache_pruning.m b/test/APINotes/cache_pruning.m
index 54b0c64..1a36570 100644
--- a/test/APINotes/cache_pruning.m
+++ b/test/APINotes/cache_pruning.m
@@ -4,7 +4,7 @@
 // RUN: rm -rf %t/APINotesCache
 
 // Run Clang. This should generated the cached versions of both and a timestamp.
-// RUN: %clang_cc1 -fapinotes -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DINCLUDE_HEADERLIB
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DINCLUDE_HEADERLIB
 // RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
@@ -12,7 +12,7 @@
 // Set the timestamp back a very long time. We should try to prune,
 // but nothing gets pruned because the API Notes files are new enough.
 // RUN: touch -m -a -t 201101010000 %t/APINotes.timestamp 
-// RUN: %clang_cc1 -fapinotes -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
 // RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
@@ -21,7 +21,7 @@
 // This shouldn't prune anything, because the timestamp has been updated, so
 // the pruning mechanism won't fire.
 // RUN: find %t/APINotesCache -name APINotes-*.apinotesc | xargs touch -a -t 201101010000
-// RUN: %clang_cc1 -fapinotes -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
 // RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
@@ -30,13 +30,13 @@
 // HeaderLib file, because the pruning mechanism should fire and
 // HeaderLib is both old and not used.
 // RUN: touch -m -a -t 201101010000 %t/APINotesCache/APINotes.timestamp 
-// RUN: %clang_cc1 -fapinotes -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
 // RUN: ls %t/APINotesCache | not grep "APINotes-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
 
 // Run Clang. This should generated the cached versions of both and a timestamp.
-// RUN: %clang_cc1 -fapinotes -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DINCLUDE_HEADERLIB
+// RUN: %clang_cc1 -fapinotes -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DINCLUDE_HEADERLIB
 // RUN: ls %t/APINotesCache | grep "APINotes-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "SomeKit-.*.apinotesc"
 // RUN: ls %t/APINotesCache | grep "APINotes.timestamp"
diff --git a/test/APINotes/module-cache.m b/test/APINotes/module-cache.m
new file mode 100644
index 0000000..2324697
--- /dev/null
+++ b/test/APINotes/module-cache.m
@@ -0,0 +1,90 @@
+// RUN: rm -rf %t
+
+// Set up a directory with API notes
+// RUN: mkdir -p %t/APINotes
+// RUN: cp %S/Inputs/APINotes/SomeOtherKit.apinotes %t/APINotes/SomeOtherKit.apinotes
+
+// First build: check that 'methodB' is unavailable but 'methodA' is available.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/APINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/before.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/before.log
+// RUN: FileCheck -check-prefix=CHECK-REBUILD %s < %t/before.log
+// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/before.log
+
+// Do it again; now we're using caches.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/APINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/before.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/before.log
+// RUN: FileCheck -check-prefix=CHECK-WITHOUT-REBUILD %s < %t/before.log
+// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/before.log
+
+// Change the API notes file.
+// RUN: echo '      - Selector: "methodA"' >> %t/APINotes/SomeOtherKit.apinotes
+// RUN: echo '        MethodKind: Instance' >> %t/APINotes/SomeOtherKit.apinotes
+// RUN: echo '        Availability: none' >> %t/APINotes/SomeOtherKit.apinotes
+// RUN: echo '        AvailabilityMsg: "not here either"' >> %t/APINotes/SomeOtherKit.apinotes
+
+// Build again: check that both methods are now unavailable and that the module rebuilt.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/APINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/after.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODA %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-REBUILD %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-TWO-ERRORS %s < %t/after.log
+
+// Run the build again: check that both methods are now unavailable
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/APINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/after.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODA %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-WITHOUT-REBUILD %s < %t/after.log
+// RUN: FileCheck -check-prefix=CHECK-TWO-ERRORS %s < %t/after.log
+
+// Set up a directory with pre-compiled API notes.
+// RUN: mkdir -p %t/CompiledAPINotes
+// RUN: rm -rf %t/ModulesCache
+// RUN: rm -rf %t/APINotesCache
+// RUN: %clang -cc1apinotes -yaml-to-binary -o %t/CompiledAPINotes/SomeOtherKit.apinotesc %S/Inputs/APINotes/SomeOtherKit.apinotes
+
+// First build: check that 'methodB' is unavailable but 'methodA' is available.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/CompiledAPINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/compiled-before.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/compiled-before.log
+// RUN: FileCheck -check-prefix=CHECK-REBUILD %s < %t/compiled-before.log
+// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/compiled-before.log
+
+// Do it again; now we're using caches.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/CompiledAPINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/compiled-before.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/compiled-before.log
+// RUN: FileCheck -check-prefix=CHECK-WITHOUT-REBUILD %s < %t/compiled-before.log
+// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/compiled-before.log
+
+// Compile a new API notes file to replace the old one.
+// RUN: %clang -cc1apinotes -yaml-to-binary -o %t/CompiledAPINotes/SomeOtherKit.apinotesc %t/APINotes/SomeOtherKit.apinotes
+
+// Build again: check that both methods are now unavailable and that the module rebuilt.
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/CompiledAPINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/compiled-after.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODA %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-REBUILD %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-TWO-ERRORS %s < %t/compiled-after.log
+
+// Run the build again: check that both methods are now unavailable
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -Rmodule-build -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %t/CompiledAPINotes -fapinotes-cache-path=%t/APINotesCache -F %S/Inputs/Frameworks %s > %t/compiled-after.log 2>&1
+// RUN: FileCheck -check-prefix=CHECK-METHODA %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-METHODB %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-WITHOUT-REBUILD %s < %t/compiled-after.log
+// RUN: FileCheck -check-prefix=CHECK-TWO-ERRORS %s < %t/compiled-after.log
+
+@import SomeOtherKit;
+
+void test(A *a) {
+  // CHECK-METHODA: error: 'methodA' is unavailable: not here either
+  [a methodA];
+
+  // CHECK-METHODB: error: 'methodB' is unavailable: anything but this
+  [a methodB];
+}
+
+// CHECK-REBUILD: remark: building module{{.*}}SomeOtherKit
+
+// CHECK-WITHOUT-REBUILD-NOT: remark: building module{{.*}}SomeOtherKit
+
+// CHECK-ONE-ERROR: 1 error generated.
+// CHECK-TWO-ERRORS: 2 errors generated.
+
diff --git a/test/APINotes/nullability.c b/test/APINotes/nullability.c
index 1d5939b..36507f1 100644
--- a/test/APINotes/nullability.c
+++ b/test/APINotes/nullability.c
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t && mkdir -p %t
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %S/Inputs/APINotes -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
 
 #include "HeaderLib.h"
 
diff --git a/test/APINotes/nullability.m b/test/APINotes/nullability.m
index 486b2c5..fc149b4 100644
--- a/test/APINotes/nullability.m
+++ b/test/APINotes/nullability.m
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t && mkdir -p %t
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %S/Inputs/APINotes -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
 
 #import <SomeKit/SomeKit.h>
 
@@ -17,6 +17,8 @@
   [a setNonnullABoth: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
   [A setNonnullABoth: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
 
+  [a setInternalProperty: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+
   return 0;
 }
 
diff --git a/test/APINotes/objc_designated_inits.m b/test/APINotes/objc_designated_inits.m
index bbb50ba..1df8cf8 100644
--- a/test/APINotes/objc_designated_inits.m
+++ b/test/APINotes/objc_designated_inits.m
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t && mkdir -p %t
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %S/Inputs/APINotes -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
 
 #include "HeaderLib.h"
 #import <SomeKit/SomeKit.h>
diff --git a/test/APINotes/search-order.m b/test/APINotes/search-order.m
new file mode 100644
index 0000000..2c667be
--- /dev/null
+++ b/test/APINotes/search-order.m
@@ -0,0 +1,25 @@
+// RUN: rm -rf %t && mkdir -p %t
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DFROM_FRAMEWORK=1 -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -iapinotes-modules %S/Inputs/APINotes -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DFROM_SEARCH_PATH=1 -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -iapinotes-modules %S/Inputs/APINotes -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -DFROM_FRAMEWORK=1 -verify
+
+@import SomeOtherKit;
+
+void test(A *a) {
+#if FROM_FRAMEWORK
+  [a methodA]; // expected-error{{unavailable}}
+  [a methodB];
+
+  // expected-note@SomeOtherKit/SomeOtherKit.h:5{{'methodA' has been explicitly marked unavailable here}}
+#elif FROM_SEARCH_PATH
+  [a methodA];
+  [a methodB]; // expected-error{{unavailable}}
+
+  // expected-note@SomeOtherKit/SomeOtherKit.h:6{{'methodB' has been explicitly marked unavailable here}}
+#else
+#  error Not something we need to test
+#endif
+}
diff --git a/tools/driver/apinotes_main.cpp b/tools/driver/apinotes_main.cpp
index cbd8045..e4ccc2e 100644
--- a/tools/driver/apinotes_main.cpp
+++ b/tools/driver/apinotes_main.cpp
@@ -119,7 +119,7 @@
     llvm::raw_fd_ostream os(OutputFilename, EC,
                             llvm::sys::fs::OpenFlags::F_None);
 
-    if (api_notes::compileAPINotes(input, os, targetOS))
+    if (api_notes::compileAPINotes(input, /*sourceFile=*/nullptr, os, targetOS))
       return 1;
     
     os.flush();