]> granicus.if.org Git - clang/blobdiff - lib/Lex/HeaderSearch.cpp
Revert r272562 for build bot failure (clang-x86-win2008-selfhost)
[clang] / lib / Lex / HeaderSearch.cpp
index cb68eb07e6d06604006ab63e74d67763bb2d66a0..f7fc0b0f65fc61bbbee04c4faf4fdb84a0990dc2 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "clang/Lex/HeaderSearch.h"
-#include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/IdentifierTable.h"
+#include "clang/Lex/ExternalPreprocessorSource.h"
 #include "clang/Lex/HeaderMap.h"
 #include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/LexDiagnostic.h"
 #include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Capacity.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
 #include <cstdio>
+#include <utility>
+#if defined(LLVM_ON_UNIX)
+#include <limits.h>
+#endif
 using namespace clang;
 
 const IdentifierInfo *
-HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
-  if (ControllingMacro)
+HeaderFileInfo::getControllingMacro(ExternalPreprocessorSource *External) {
+  if (ControllingMacro) {
+    if (ControllingMacro->isOutOfDate())
+      External->updateOutOfDateIdentifier(
+          *const_cast<IdentifierInfo *>(ControllingMacro));
     return ControllingMacro;
+  }
 
   if (!ControllingMacroID || !External)
-    return 0;
+    return nullptr;
 
   ControllingMacro = External->GetIdentifier(ControllingMacroID);
   return ControllingMacro;
@@ -39,19 +52,19 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
 
 ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
 
-HeaderSearch::HeaderSearch(llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
-                           FileManager &FM, DiagnosticsEngine &Diags,
-                           const LangOptions &LangOpts, 
+HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
+                           SourceManager &SourceMgr, DiagnosticsEngine &Diags,
+                           const LangOptions &LangOpts,
                            const TargetInfo *Target)
-  : HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64),
-    ModMap(FileMgr, *Diags.getClient(), LangOpts, Target)
-{
+    : HSOpts(std::move(HSOpts)), Diags(Diags),
+      FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
+      ModMap(SourceMgr, Diags, LangOpts, Target, *this) {
   AngledDirIdx = 0;
   SystemDirIdx = 0;
   NoCurDirSearch = false;
 
-  ExternalLookup = 0;
-  ExternalSource = 0;
+  ExternalLookup = nullptr;
+  ExternalSource = nullptr;
   NumIncluded = 0;
   NumMultiIncludeFileOptzn = 0;
   NumFrameworkLookups = NumSubFrameworkLookups = 0;
@@ -103,38 +116,59 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
     return HM;
   }
 
-  return 0;
+  return nullptr;
 }
 
 std::string HeaderSearch::getModuleFileName(Module *Module) {
-  // If we don't have a module cache path, we can't do anything.
-  if (ModuleCachePath.empty()) 
+  const FileEntry *ModuleMap =
+      getModuleMap().getModuleMapFileForUniquing(Module);
+  return getModuleFileName(Module->Name, ModuleMap->getName());
+}
+
+std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
+                                            StringRef ModuleMapPath) {
+  // If we don't have a module cache path or aren't supposed to use one, we
+  // can't do anything.
+  if (getModuleCachePath().empty())
     return std::string();
 
+  SmallString<256> Result(getModuleCachePath());
+  llvm::sys::fs::make_absolute(Result);
 
-  SmallString<256> Result(ModuleCachePath);
-  llvm::sys::path::append(Result, Module->getTopLevelModule()->Name + ".pcm");
-  return Result.str().str();
-}
+  if (HSOpts->DisableModuleHash) {
+    llvm::sys::path::append(Result, ModuleName + ".pcm");
+  } else {
+    // Construct the name <ModuleName>-<hash of ModuleMapPath>.pcm which should
+    // ideally be globally unique to this particular module. Name collisions
+    // in the hash are safe (because any translation unit can only import one
+    // module with each name), but result in a loss of caching.
+    //
+    // To avoid false-negatives, we form as canonical a path as we can, and map
+    // to lower-case in case we're on a case-insensitive file system.
+   auto *Dir =
+        FileMgr.getDirectory(llvm::sys::path::parent_path(ModuleMapPath));
+    if (!Dir)
+      return std::string();
+    auto DirName = FileMgr.getCanonicalName(Dir);
+    auto FileName = llvm::sys::path::filename(ModuleMapPath);
 
-std::string HeaderSearch::getModuleFileName(StringRef ModuleName) {
-  // If we don't have a module cache path, we can't do anything.
-  if (ModuleCachePath.empty()) 
-    return std::string();
-  
-  
-  SmallString<256> Result(ModuleCachePath);
-  llvm::sys::path::append(Result, ModuleName + ".pcm");
+    llvm::hash_code Hash =
+      llvm::hash_combine(DirName.lower(), FileName.lower());
+
+    SmallString<128> HashStr;
+    llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
+    llvm::sys::path::append(Result, ModuleName + "-" + HashStr + ".pcm");
+  }
   return Result.str().str();
 }
 
 Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
   // Look in the module map to determine if there is a module by this name.
   Module *Module = ModMap.findModule(ModuleName);
-  if (Module || !AllowSearch)
+  if (Module || !AllowSearch || !HSOpts->ImplicitModuleMaps)
     return Module;
   
-  // Look through the various header search paths to load any avai;able module 
+  // Look through the various header search paths to load any available module
   // maps, searching for a module map that describes this module.
   for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
     if (SearchDirs[Idx].isFramework()) {
@@ -157,9 +191,11 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
     // Only deal with normal search directories.
     if (!SearchDirs[Idx].isNormalDir())
       continue;
-    
+
+    bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
     // Search for a module map file in this directory.
-    if (loadModuleMapFile(SearchDirs[Idx].getDir()) == LMM_NewlyLoaded) {
+    if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem,
+                          /*IsFramework*/false) == LMM_NewlyLoaded) {
       // We just loaded a module map file; check whether the module is
       // available now.
       Module = ModMap.findModule(ModuleName);
@@ -172,14 +208,29 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
     SmallString<128> NestedModuleMapDirName;
     NestedModuleMapDirName = SearchDirs[Idx].getDir()->getName();
     llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
-    if (loadModuleMapFile(NestedModuleMapDirName) == LMM_NewlyLoaded) {
+    if (loadModuleMapFile(NestedModuleMapDirName, IsSystem,
+                          /*IsFramework*/false) == LMM_NewlyLoaded){
       // If we just loaded a module map file, look for the module again.
       Module = ModMap.findModule(ModuleName);
       if (Module)
         break;
     }
+
+    // If we've already performed the exhaustive search for module maps in this
+    // search directory, don't do it again.
+    if (SearchDirs[Idx].haveSearchedAllModuleMaps())
+      continue;
+
+    // Load all module maps in the immediate subdirectories of this search
+    // directory.
+    loadSubdirectoryModuleMaps(SearchDirs[Idx]);
+
+    // Look again for the module.
+    Module = ModMap.findModule(ModuleName);
+    if (Module)
+      break;
   }
-  
+
   return Module;
 }
 
@@ -198,64 +249,94 @@ const char *DirectoryLookup::getName() const {
   return getHeaderMap()->getFileName();
 }
 
+const FileEntry *HeaderSearch::getFileAndSuggestModule(
+    StringRef FileName, const DirectoryEntry *Dir, bool IsSystemHeaderDir,
+    Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
+  // If we have a module map that might map this header, load it and
+  // check whether we'll have a suggestion for a module.
+  const FileEntry *File = getFileMgr().getFile(FileName, /*OpenFile=*/true);
+  if (!File)
+    return nullptr;
+
+  // If there is a module that corresponds to this header, suggest it.
+  if (!findUsableModuleForHeader(File, Dir ? Dir : File->getDir(),
+                                 RequestingModule, SuggestedModule,
+                                 IsSystemHeaderDir))
+    return nullptr;
+
+  return File;
+}
 
 /// LookupFile - Lookup the specified file in this search path, returning it
 /// if it exists or returning null if not.
 const FileEntry *DirectoryLookup::LookupFile(
-    StringRef Filename,
+    StringRef &Filename,
     HeaderSearch &HS,
     SmallVectorImpl<char> *SearchPath,
     SmallVectorImpl<char> *RelativePath,
-    Module **SuggestedModule,
-    bool &InUserSpecifiedSystemFramework) const {
+    Module *RequestingModule,
+    ModuleMap::KnownHeader *SuggestedModule,
+    bool &InUserSpecifiedSystemFramework,
+    bool &HasBeenMapped,
+    SmallVectorImpl<char> &MappedName) const {
   InUserSpecifiedSystemFramework = false;
+  HasBeenMapped = false;
 
   SmallString<1024> TmpDir;
   if (isNormalDir()) {
     // Concatenate the requested file onto the directory.
     TmpDir = getDir()->getName();
     llvm::sys::path::append(TmpDir, Filename);
-    if (SearchPath != NULL) {
+    if (SearchPath) {
       StringRef SearchPathRef(getDir()->getName());
       SearchPath->clear();
       SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
     }
-    if (RelativePath != NULL) {
+    if (RelativePath) {
       RelativePath->clear();
       RelativePath->append(Filename.begin(), Filename.end());
     }
-    
-    // If we have a module map that might map this header, load it and
-    // check whether we'll have a suggestion for a module.
-    if (SuggestedModule && HS.hasModuleMap(TmpDir, getDir())) {
-      const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(), 
-                                                      /*openFile=*/false);
-      if (!File)
-        return File;
-      
-      // If there is a module that corresponds to this header, 
-      // suggest it.
-      *SuggestedModule = HS.findModuleForHeader(File);
-      return File;
-    }
-    
-    return HS.getFileMgr().getFile(TmpDir.str(), /*openFile=*/true);
+
+    return HS.getFileAndSuggestModule(TmpDir, getDir(),
+                                      isSystemHeaderDirectory(),
+                                      RequestingModule, SuggestedModule);
   }
 
   if (isFramework())
     return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath,
-                             SuggestedModule, InUserSpecifiedSystemFramework);
+                             RequestingModule, SuggestedModule,
+                             InUserSpecifiedSystemFramework);
 
   assert(isHeaderMap() && "Unknown directory lookup");
-  const FileEntry * const Result = getHeaderMap()->LookupFile(
-      Filename, HS.getFileMgr());
+  const HeaderMap *HM = getHeaderMap();
+  SmallString<1024> Path;
+  StringRef Dest = HM->lookupFilename(Filename, Path);
+  if (Dest.empty())
+    return nullptr;
+
+  const FileEntry *Result;
+
+  // Check if the headermap maps the filename to a framework include
+  // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the
+  // framework include.
+  if (llvm::sys::path::is_relative(Dest)) {
+    MappedName.clear();
+    MappedName.append(Dest.begin(), Dest.end());
+    Filename = StringRef(MappedName.begin(), MappedName.size());
+    HasBeenMapped = true;
+    Result = HM->LookupFile(Filename, HS.getFileMgr());
+
+  } else {
+    Result = HS.getFileMgr().getFile(Dest);
+  }
+
   if (Result) {
-    if (SearchPath != NULL) {
+    if (SearchPath) {
       StringRef SearchPathRef(getName());
       SearchPath->clear();
       SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
     }
-    if (RelativePath != NULL) {
+    if (RelativePath) {
       RelativePath->clear();
       RelativePath->append(Filename.begin(), Filename.end());
     }
@@ -263,22 +344,68 @@ const FileEntry *DirectoryLookup::LookupFile(
   return Result;
 }
 
+/// \brief Given a framework directory, find the top-most framework directory.
+///
+/// \param FileMgr The file manager to use for directory lookups.
+/// \param DirName The name of the framework directory.
+/// \param SubmodulePath Will be populated with the submodule path from the
+/// returned top-level module to the originally named framework.
+static const DirectoryEntry *
+getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
+                   SmallVectorImpl<std::string> &SubmodulePath) {
+  assert(llvm::sys::path::extension(DirName) == ".framework" &&
+         "Not a framework directory");
+
+  // Note: as an egregious but useful hack we use the real path here, because
+  // frameworks moving between top-level frameworks to embedded frameworks tend
+  // to be symlinked, and we base the logical structure of modules on the
+  // physical layout. In particular, we need to deal with crazy includes like
+  //
+  //   #include <Foo/Frameworks/Bar.framework/Headers/Wibble.h>
+  //
+  // where 'Bar' used to be embedded in 'Foo', is now a top-level framework
+  // which one should access with, e.g.,
+  //
+  //   #include <Bar/Wibble.h>
+  //
+  // Similar issues occur when a top-level framework has moved into an
+  // embedded framework.
+  const DirectoryEntry *TopFrameworkDir = FileMgr.getDirectory(DirName);
+  DirName = FileMgr.getCanonicalName(TopFrameworkDir);
+  do {
+    // Get the parent directory name.
+    DirName = llvm::sys::path::parent_path(DirName);
+    if (DirName.empty())
+      break;
+
+    // Determine whether this directory exists.
+    const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
+    if (!Dir)
+      break;
+
+    // If this is a framework directory, then we're a subframework of this
+    // framework.
+    if (llvm::sys::path::extension(DirName) == ".framework") {
+      SubmodulePath.push_back(llvm::sys::path::stem(DirName));
+      TopFrameworkDir = Dir;
+    }
+  } while (true);
+
+  return TopFrameworkDir;
+}
 
 /// DoFrameworkLookup - Do a lookup of the specified file in the current
 /// DirectoryLookup, which is a framework directory.
 const FileEntry *DirectoryLookup::DoFrameworkLookup(
-    StringRef Filename,
-    HeaderSearch &HS,
-    SmallVectorImpl<char> *SearchPath,
-    SmallVectorImpl<char> *RelativePath,
-    Module **SuggestedModule,
-    bool &InUserSpecifiedSystemFramework) const
-{
+    StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
+    SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
+    ModuleMap::KnownHeader *SuggestedModule,
+    bool &InUserSpecifiedSystemFramework) const {
   FileManager &FileMgr = HS.getFileMgr();
 
   // Framework names must have a '/' in the filename.
   size_t SlashPos = Filename.find('/');
-  if (SlashPos == StringRef::npos) return 0;
+  if (SlashPos == StringRef::npos) return nullptr;
 
   // Find out if this is the home for the specified framework, by checking
   // HeaderSearch.  Possible answers are yes/no and unknown.
@@ -287,7 +414,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
 
   // If it is known and in some other directory, fail.
   if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir())
-    return 0;
+    return nullptr;
 
   // Otherwise, construct the path to this framework dir.
 
@@ -305,12 +432,12 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
   FrameworkName += ".framework/";
 
   // If the cache entry was unresolved, populate it now.
-  if (CacheEntry.Directory == 0) {
+  if (!CacheEntry.Directory) {
     HS.IncrementFrameworkLookupCount();
 
     // If the framework dir doesn't exist, we fail.
-    const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
-    if (Dir == 0) return 0;
+    const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
+    if (!Dir) return nullptr;
 
     // Otherwise, if it does, remember that this is the right direntry for this
     // framework.
@@ -321,7 +448,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
     if (getDirCharacteristic() == SrcMgr::C_User) {
       SmallString<1024> SystemFrameworkMarker(FrameworkName);
       SystemFrameworkMarker += ".system_framework";
-      if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) {
+      if (llvm::sys::fs::exists(SystemFrameworkMarker)) {
         CacheEntry.IsUserSpecifiedSystemFramework = true;
       }
     }
@@ -330,55 +457,72 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
   // Set the 'user-specified system framework' flag.
   InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework;
 
-  if (RelativePath != NULL) {
+  if (RelativePath) {
     RelativePath->clear();
     RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
   }
-
-  // If we're allowed to look for modules, try to load or create the module
-  // corresponding to this framework.
-  Module *Module = 0;
-  if (SuggestedModule) {
-    if (const DirectoryEntry *FrameworkDir
-                                        = FileMgr.getDirectory(FrameworkName)) {
-      bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
-      Module = HS.loadFrameworkModule(ModuleName, FrameworkDir, IsSystem);
-    }
-  }
   
   // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
   unsigned OrigSize = FrameworkName.size();
 
   FrameworkName += "Headers/";
 
-  if (SearchPath != NULL) {
+  if (SearchPath) {
     SearchPath->clear();
     // Without trailing '/'.
     SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
   }
 
-  // Determine whether this is the module we're building or not.
-  bool AutomaticImport = Module;  
   FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
-  if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
-                                            /*openFile=*/!AutomaticImport)) {
-    if (AutomaticImport)
-      *SuggestedModule = HS.findModuleForHeader(FE);
-    return FE;
+  const FileEntry *FE = FileMgr.getFile(FrameworkName,
+                                        /*openFile=*/!SuggestedModule);
+  if (!FE) {
+    // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
+    const char *Private = "Private";
+    FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
+                         Private+strlen(Private));
+    if (SearchPath)
+      SearchPath->insert(SearchPath->begin()+OrigSize, Private,
+                         Private+strlen(Private));
+
+    FE = FileMgr.getFile(FrameworkName, /*openFile=*/!SuggestedModule);
   }
 
-  // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
-  const char *Private = "Private";
-  FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
-                       Private+strlen(Private));
-  if (SearchPath != NULL)
-    SearchPath->insert(SearchPath->begin()+OrigSize, Private,
-                       Private+strlen(Private));
-
-  const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), 
-                                        /*openFile=*/!AutomaticImport);
-  if (FE && AutomaticImport)
-    *SuggestedModule = HS.findModuleForHeader(FE);
+  // If we found the header and are allowed to suggest a module, do so now.
+  if (FE && SuggestedModule) {
+    // Find the framework in which this header occurs.
+    StringRef FrameworkPath = FE->getDir()->getName();
+    bool FoundFramework = false;
+    do {
+      // Determine whether this directory exists.
+      const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkPath);
+      if (!Dir)
+        break;
+
+      // If this is a framework directory, then we're a subframework of this
+      // framework.
+      if (llvm::sys::path::extension(FrameworkPath) == ".framework") {
+        FoundFramework = true;
+        break;
+      }
+
+      // Get the parent directory name.
+      FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
+      if (FrameworkPath.empty())
+        break;
+    } while (true);
+
+    bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
+    if (FoundFramework) {
+      if (!HS.findUsableModuleForFrameworkHeader(
+              FE, FrameworkPath, RequestingModule, SuggestedModule, IsSystem))
+        return nullptr;
+    } else {
+      if (!HS.findUsableModuleForHeader(FE, getDir(), RequestingModule,
+                                        SuggestedModule, IsSystem))
+        return nullptr;
+    }
+  }
   return FE;
 }
 
@@ -391,86 +535,147 @@ void HeaderSearch::setTarget(const TargetInfo &Target) {
 // Header File Location.
 //===----------------------------------------------------------------------===//
 
+/// \brief Return true with a diagnostic if the file that MSVC would have found
+/// fails to match the one that Clang would have found with MSVC header search
+/// disabled.
+static bool checkMSVCHeaderSearch(DiagnosticsEngine &Diags,
+                                  const FileEntry *MSFE, const FileEntry *FE,
+                                  SourceLocation IncludeLoc) {
+  if (MSFE && FE != MSFE) {
+    Diags.Report(IncludeLoc, diag::ext_pp_include_search_ms) << MSFE->getName();
+    return true;
+  }
+  return false;
+}
+
+static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
+  assert(!Str.empty());
+  char *CopyStr = Alloc.Allocate<char>(Str.size()+1);
+  std::copy(Str.begin(), Str.end(), CopyStr);
+  CopyStr[Str.size()] = '\0';
+  return CopyStr;
+}
 
 /// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file,
 /// return null on failure.  isAngled indicates whether the file reference is
-/// for system \#include's or not (i.e. using <> instead of "").  CurFileEnt, if
-/// non-null, indicates where the \#including file is, in case a relative search
-/// is needed.
+/// for system \#include's or not (i.e. using <> instead of ""). Includers, if
+/// non-empty, indicates where the \#including file(s) are, in case a relative
+/// search is needed. Microsoft mode will pass all \#including files.
 const FileEntry *HeaderSearch::LookupFile(
-    StringRef Filename,
-    bool isAngled,
-    const DirectoryLookup *FromDir,
-    const DirectoryLookup *&CurDir,
-    const FileEntry *CurFileEnt,
-    SmallVectorImpl<char> *SearchPath,
-    SmallVectorImpl<char> *RelativePath,
-    Module **SuggestedModule,
-    bool SkipCache)
-{
+    StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
+    const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
+    ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
+    SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
+    Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
+    bool SkipCache, bool BuildSystemModule) {
   if (SuggestedModule)
-    *SuggestedModule = 0;
+    *SuggestedModule = ModuleMap::KnownHeader();
     
   // If 'Filename' is absolute, check to see if it exists and no searching.
   if (llvm::sys::path::is_absolute(Filename)) {
-    CurDir = 0;
+    CurDir = nullptr;
 
     // If this was an #include_next "/absolute/file", fail.
-    if (FromDir) return 0;
+    if (FromDir) return nullptr;
 
-    if (SearchPath != NULL)
+    if (SearchPath)
       SearchPath->clear();
-    if (RelativePath != NULL) {
+    if (RelativePath) {
       RelativePath->clear();
       RelativePath->append(Filename.begin(), Filename.end());
     }
     // Otherwise, just return the file.
-    return FileMgr.getFile(Filename, /*openFile=*/true);
+    return getFileAndSuggestModule(Filename, nullptr,
+                                   /*IsSystemHeaderDir*/false,
+                                   RequestingModule, SuggestedModule);
   }
 
+  // This is the header that MSVC's header search would have found.
+  const FileEntry *MSFE = nullptr;
+  ModuleMap::KnownHeader MSSuggestedModule;
+
   // Unless disabled, check to see if the file is in the #includer's
-  // directory.  This has to be based on CurFileEnt, not CurDir, because
-  // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
-  // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
+  // directory.  This cannot be based on CurDir, because each includer could be
+  // a #include of a subdirectory (#include "foo/bar.h") and a subsequent
+  // include of "baz.h" should resolve to "whatever/foo/baz.h".
   // This search is not done for <> headers.
-  if (CurFileEnt && !isAngled && !NoCurDirSearch) {
+  if (!Includers.empty() && !isAngled && !NoCurDirSearch) {
     SmallString<1024> TmpDir;
-    // Concatenate the requested file onto the directory.
-    // FIXME: Portability.  Filename concatenation should be in sys::Path.
-    TmpDir += CurFileEnt->getDir()->getName();
-    TmpDir.push_back('/');
-    TmpDir.append(Filename.begin(), Filename.end());
-    if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(),/*openFile=*/true)) {
-      // Leave CurDir unset.
-      // This file is a system header or C++ unfriendly if the old file is.
+    bool First = true;
+    for (const auto &IncluderAndDir : Includers) {
+      const FileEntry *Includer = IncluderAndDir.first;
+
+      // Concatenate the requested file onto the directory.
+      // FIXME: Portability.  Filename concatenation should be in sys::Path.
+      TmpDir = IncluderAndDir.second->getName();
+      TmpDir.push_back('/');
+      TmpDir.append(Filename.begin(), Filename.end());
+
+      // FIXME: We don't cache the result of getFileInfo across the call to
+      // getFileAndSuggestModule, because it's a reference to an element of
+      // a container that could be reallocated across this call.
       //
-      // Note that we only use one of FromHFI/ToHFI at once, due to potential
-      // reallocation of the underlying vector potentially making the first
-      // reference binding dangling.
-      HeaderFileInfo &FromHFI = getFileInfo(CurFileEnt);
-      unsigned DirInfo = FromHFI.DirInfo;
-      bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
-      StringRef Framework = FromHFI.Framework;
-
-      HeaderFileInfo &ToHFI = getFileInfo(FE);
-      ToHFI.DirInfo = DirInfo;
-      ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
-      ToHFI.Framework = Framework;
-
-      if (SearchPath != NULL) {
-        StringRef SearchPathRef(CurFileEnt->getDir()->getName());
-        SearchPath->clear();
-        SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
-      }
-      if (RelativePath != NULL) {
-        RelativePath->clear();
-        RelativePath->append(Filename.begin(), Filename.end());
+      // If we have no includer, that means we're processing a #include
+      // from a module build. We should treat this as a system header if we're
+      // building a [system] module.
+      bool IncluderIsSystemHeader =
+          Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
+          BuildSystemModule;
+      if (const FileEntry *FE = getFileAndSuggestModule(
+              TmpDir, IncluderAndDir.second, IncluderIsSystemHeader,
+              RequestingModule, SuggestedModule)) {
+        if (!Includer) {
+          assert(First && "only first includer can have no file");
+          return FE;
+        }
+
+        // Leave CurDir unset.
+        // This file is a system header or C++ unfriendly if the old file is.
+        //
+        // Note that we only use one of FromHFI/ToHFI at once, due to potential
+        // reallocation of the underlying vector potentially making the first
+        // reference binding dangling.
+        HeaderFileInfo &FromHFI = getFileInfo(Includer);
+        unsigned DirInfo = FromHFI.DirInfo;
+        bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
+        StringRef Framework = FromHFI.Framework;
+
+        HeaderFileInfo &ToHFI = getFileInfo(FE);
+        ToHFI.DirInfo = DirInfo;
+        ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
+        ToHFI.Framework = Framework;
+
+        if (SearchPath) {
+          StringRef SearchPathRef(IncluderAndDir.second->getName());
+          SearchPath->clear();
+          SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
+        }
+        if (RelativePath) {
+          RelativePath->clear();
+          RelativePath->append(Filename.begin(), Filename.end());
+        }
+        if (First)
+          return FE;
+
+        // Otherwise, we found the path via MSVC header search rules.  If
+        // -Wmsvc-include is enabled, we have to keep searching to see if we
+        // would've found this header in -I or -isystem directories.
+        if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
+          return FE;
+        } else {
+          MSFE = FE;
+          if (SuggestedModule) {
+            MSSuggestedModule = *SuggestedModule;
+            *SuggestedModule = ModuleMap::KnownHeader();
+          }
+          break;
+        }
       }
-      return FE;
+      First = false;
     }
   }
 
-  CurDir = 0;
+  CurDir = nullptr;
 
   // If this is a system #include, ignore the user #include locs.
   unsigned i = isAngled ? AngledDirIdx : 0;
@@ -484,28 +689,37 @@ const FileEntry *HeaderSearch::LookupFile(
   // multiply included, and the "pragma once" optimization prevents them from
   // being relex/pp'd, but they would still have to search through a
   // (potentially huge) series of SearchDirs to find it.
-  std::pair<unsigned, unsigned> &CacheLookup =
-    LookupFileCache.GetOrCreateValue(Filename).getValue();
+  LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
 
   // If the entry has been previously looked up, the first value will be
   // non-zero.  If the value is equal to i (the start point of our search), then
   // this is a matching hit.
-  if (!SkipCache && CacheLookup.first == i+1) {
+  if (!SkipCache && CacheLookup.StartIdx == i+1) {
     // Skip querying potentially lots of directories for this lookup.
-    i = CacheLookup.second;
+    i = CacheLookup.HitIdx;
+    if (CacheLookup.MappedName)
+      Filename = CacheLookup.MappedName;
   } else {
     // Otherwise, this is the first query, or the previous query didn't match
     // our search start.  We will fill in our found location below, so prime the
     // start point value.
-    CacheLookup.first = i+1;
+    CacheLookup.reset(/*StartIdx=*/i+1);
   }
 
+  SmallString<64> MappedName;
+
   // Check each directory in sequence to see if it contains this file.
   for (; i != SearchDirs.size(); ++i) {
     bool InUserSpecifiedSystemFramework = false;
-    const FileEntry *FE =
-      SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath,
-                               SuggestedModule, InUserSpecifiedSystemFramework);
+    bool HasBeenMapped = false;
+    const FileEntry *FE = SearchDirs[i].LookupFile(
+        Filename, *this, SearchPath, RelativePath, RequestingModule,
+        SuggestedModule, InUserSpecifiedSystemFramework, HasBeenMapped,
+        MappedName);
+    if (HasBeenMapped) {
+      CacheLookup.MappedName =
+          copyString(Filename, LookupFileCache.getAllocator());
+    }
     if (!FE) continue;
 
     CurDir = &SearchDirs[i];
@@ -540,9 +754,15 @@ const FileEntry *HeaderSearch::LookupFile(
                                                          SlashPos));
       }
     }
-    
+
+    if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+      if (SuggestedModule)
+        *SuggestedModule = MSSuggestedModule;
+      return MSFE;
+    }
+
     // Remember this location for the next lookup we do.
-    CacheLookup.second = i;
+    CacheLookup.HitIdx = i;
     return FE;
   }
 
@@ -550,29 +770,42 @@ const FileEntry *HeaderSearch::LookupFile(
   // a header in a framework that is currently being built, and we couldn't
   // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
   // "Foo" is the name of the framework in which the including header was found.
-  if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) {
-    HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt);
+  if (!Includers.empty() && Includers.front().first && !isAngled &&
+      Filename.find('/') == StringRef::npos) {
+    HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front().first);
     if (IncludingHFI.IndexHeaderMapHeader) {
       SmallString<128> ScratchFilename;
       ScratchFilename += IncludingHFI.Framework;
       ScratchFilename += '/';
       ScratchFilename += Filename;
-      
-      const FileEntry *Result = LookupFile(ScratchFilename, /*isAngled=*/true,
-                                           FromDir, CurDir, CurFileEnt, 
-                                           SearchPath, RelativePath,
-                                           SuggestedModule);
-      std::pair<unsigned, unsigned> &CacheLookup 
-        = LookupFileCache.GetOrCreateValue(Filename).getValue();
-      CacheLookup.second
-        = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().second;
-      return Result;
+
+      const FileEntry *FE =
+          LookupFile(ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir,
+                     CurDir, Includers.front(), SearchPath, RelativePath,
+                     RequestingModule, SuggestedModule);
+
+      if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+        if (SuggestedModule)
+          *SuggestedModule = MSSuggestedModule;
+        return MSFE;
+      }
+
+      LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
+      CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx;
+      // FIXME: SuggestedModule.
+      return FE;
     }
   }
 
+  if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) {
+    if (SuggestedModule)
+      *SuggestedModule = MSSuggestedModule;
+    return MSFE;
+  }
+
   // Otherwise, didn't find it. Remember we didn't find this.
-  CacheLookup.second = SearchDirs.size();
-  return 0;
+  CacheLookup.HitIdx = SearchDirs.size();
+  return nullptr;
 }
 
 /// LookupSubframeworkHeader - Look up a subframework for the specified
@@ -584,13 +817,15 @@ const FileEntry *HeaderSearch::
 LookupSubframeworkHeader(StringRef Filename,
                          const FileEntry *ContextFileEnt,
                          SmallVectorImpl<char> *SearchPath,
-                         SmallVectorImpl<char> *RelativePath) {
+                         SmallVectorImpl<char> *RelativePath,
+                         Module *RequestingModule,
+                         ModuleMap::KnownHeader *SuggestedModule) {
   assert(ContextFileEnt && "No context file?");
 
   // Framework names must have a '/' in the filename.  Find it.
   // FIXME: Should we permit '\' on Windows?
   size_t SlashPos = Filename.find('/');
-  if (SlashPos == StringRef::npos) return 0;
+  if (SlashPos == StringRef::npos) return nullptr;
 
   // Look up the base framework name of the ContextFileEnt.
   const char *ContextName = ContextFileEnt->getName();
@@ -598,10 +833,10 @@ LookupSubframeworkHeader(StringRef Filename,
   // If the context info wasn't a framework, couldn't be a subframework.
   const unsigned DotFrameworkLen = 10;
   const char *FrameworkPos = strstr(ContextName, ".framework");
-  if (FrameworkPos == 0 || 
+  if (FrameworkPos == nullptr ||
       (FrameworkPos[DotFrameworkLen] != '/' && 
        FrameworkPos[DotFrameworkLen] != '\\'))
-    return 0;
+    return nullptr;
 
   SmallString<1024> FrameworkName(ContextName, FrameworkPos+DotFrameworkLen+1);
 
@@ -610,32 +845,33 @@ LookupSubframeworkHeader(StringRef Filename,
   FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
   FrameworkName += ".framework/";
 
-  llvm::StringMapEntry<FrameworkCacheEntry> &CacheLookup =
-    FrameworkMap.GetOrCreateValue(Filename.substr(0, SlashPos));
+  auto &CacheLookup =
+      *FrameworkMap.insert(std::make_pair(Filename.substr(0, SlashPos),
+                                          FrameworkCacheEntry())).first;
 
   // Some other location?
-  if (CacheLookup.getValue().Directory &&
-      CacheLookup.getKeyLength() == FrameworkName.size() &&
-      memcmp(CacheLookup.getKeyData(), &FrameworkName[0],
-             CacheLookup.getKeyLength()) != 0)
-    return 0;
+  if (CacheLookup.second.Directory &&
+      CacheLookup.first().size() == FrameworkName.size() &&
+      memcmp(CacheLookup.first().data(), &FrameworkName[0],
+             CacheLookup.first().size()) != 0)
+    return nullptr;
 
   // Cache subframework.
-  if (CacheLookup.getValue().Directory == 0) {
+  if (!CacheLookup.second.Directory) {
     ++NumSubFrameworkLookups;
 
     // If the framework dir doesn't exist, we fail.
-    const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
-    if (Dir == 0) return 0;
+    const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
+    if (!Dir) return nullptr;
 
     // Otherwise, if it does, remember that this is the right direntry for this
     // framework.
-    CacheLookup.getValue().Directory = Dir;
+    CacheLookup.second.Directory = Dir;
   }
 
-  const FileEntry *FE = 0;
+  const FileEntry *FE = nullptr;
 
-  if (RelativePath != NULL) {
+  if (RelativePath) {
     RelativePath->clear();
     RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
   }
@@ -643,27 +879,27 @@ LookupSubframeworkHeader(StringRef Filename,
   // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
   SmallString<1024> HeadersFilename(FrameworkName);
   HeadersFilename += "Headers/";
-  if (SearchPath != NULL) {
+  if (SearchPath) {
     SearchPath->clear();
     // Without trailing '/'.
     SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
   }
 
   HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
-  if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true))) {
+  if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true))) {
 
     // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
     HeadersFilename = FrameworkName;
     HeadersFilename += "PrivateHeaders/";
-    if (SearchPath != NULL) {
+    if (SearchPath) {
       SearchPath->clear();
       // Without trailing '/'.
       SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
     }
 
     HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
-    if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true)))
-      return 0;
+    if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true)))
+      return nullptr;
   }
 
   // This file is a system header or C++ unfriendly if the old file is.
@@ -673,29 +909,13 @@ LookupSubframeworkHeader(StringRef Filename,
   // of evaluation.
   unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
   getFileInfo(FE).DirInfo = DirInfo;
-  return FE;
-}
 
-/// \brief Helper static function to normalize a path for injection into
-/// a synthetic header.
-/*static*/ std::string
-HeaderSearch::NormalizeDashIncludePath(StringRef File, FileManager &FileMgr) {
-  // Implicit include paths should be resolved relative to the current
-  // working directory first, and then use the regular header search
-  // mechanism. The proper way to handle this is to have the
-  // predefines buffer located at the current working directory, but
-  // it has no file entry. For now, workaround this by using an
-  // absolute path if we find the file here, and otherwise letting
-  // header search handle it.
-  SmallString<128> Path(File);
-  llvm::sys::fs::make_absolute(Path);
-  bool exists;
-  if (llvm::sys::fs::exists(Path.str(), exists) || !exists)
-    Path = File;
-  else if (exists)
-    FileMgr.getFile(File);
-
-  return Lexer::Stringify(Path.str());
+  FrameworkName.pop_back(); // remove the trailing '/'
+  if (!findUsableModuleForFrameworkHeader(FE, FrameworkName, RequestingModule,
+                                          SuggestedModule, /*IsSystem*/ false))
+    return nullptr;
+
+  return FE;
 }
 
 //===----------------------------------------------------------------------===//
@@ -706,61 +926,117 @@ HeaderSearch::NormalizeDashIncludePath(StringRef File, FileManager &FileMgr) {
 /// header file info (\p HFI)
 static void mergeHeaderFileInfo(HeaderFileInfo &HFI, 
                                 const HeaderFileInfo &OtherHFI) {
+  assert(OtherHFI.External && "expected to merge external HFI");
+
   HFI.isImport |= OtherHFI.isImport;
   HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
+  HFI.isModuleHeader |= OtherHFI.isModuleHeader;
   HFI.NumIncludes += OtherHFI.NumIncludes;
-  
+
   if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
     HFI.ControllingMacro = OtherHFI.ControllingMacro;
     HFI.ControllingMacroID = OtherHFI.ControllingMacroID;
   }
-  
-  if (OtherHFI.External) {
-    HFI.DirInfo = OtherHFI.DirInfo;
-    HFI.External = OtherHFI.External;
-    HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader;
-  }
+
+  HFI.DirInfo = OtherHFI.DirInfo;
+  HFI.External = (!HFI.IsValid || HFI.External);
+  HFI.IsValid = true;
+  HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader;
 
   if (HFI.Framework.empty())
     HFI.Framework = OtherHFI.Framework;
-  
-  HFI.Resolved = true;
 }
                                 
 /// getFileInfo - Return the HeaderFileInfo structure for the specified
 /// FileEntry.
 HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
   if (FE->getUID() >= FileInfo.size())
-    FileInfo.resize(FE->getUID()+1);
-  
-  HeaderFileInfo &HFI = FileInfo[FE->getUID()];
-  if (ExternalSource && !HFI.Resolved)
-    mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(FE));
+    FileInfo.resize(FE->getUID() + 1);
+
+  HeaderFileInfo *HFI = &FileInfo[FE->getUID()];
+  // FIXME: Use a generation count to check whether this is really up to date.
+  if (ExternalSource && !HFI->Resolved) {
+    HFI->Resolved = true;
+    auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
+
+    HFI = &FileInfo[FE->getUID()];
+    if (ExternalHFI.External)
+      mergeHeaderFileInfo(*HFI, ExternalHFI);
+  }
+
+  HFI->IsValid = true;
+  // We have local information about this header file, so it's no longer
+  // strictly external.
+  HFI->External = false;
+  return *HFI;
+}
+
+const HeaderFileInfo *
+HeaderSearch::getExistingFileInfo(const FileEntry *FE,
+                                  bool WantExternal) const {
+  // If we have an external source, ensure we have the latest information.
+  // FIXME: Use a generation count to check whether this is really up to date.
+  HeaderFileInfo *HFI;
+  if (ExternalSource) {
+    if (FE->getUID() >= FileInfo.size()) {
+      if (!WantExternal)
+        return nullptr;
+      FileInfo.resize(FE->getUID() + 1);
+    }
+
+    HFI = &FileInfo[FE->getUID()];
+    if (!WantExternal && (!HFI->IsValid || HFI->External))
+      return nullptr;
+    if (!HFI->Resolved) {
+      HFI->Resolved = true;
+      auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
+
+      HFI = &FileInfo[FE->getUID()];
+      if (ExternalHFI.External)
+        mergeHeaderFileInfo(*HFI, ExternalHFI);
+    }
+  } else if (FE->getUID() >= FileInfo.size()) {
+    return nullptr;
+  } else {
+    HFI = &FileInfo[FE->getUID()];
+  }
+
+  if (!HFI->IsValid || (HFI->External && !WantExternal))
+    return nullptr;
+
   return HFI;
 }
 
 bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
   // Check if we've ever seen this file as a header.
-  if (File->getUID() >= FileInfo.size())
-    return false;
-
-  // Resolve header file info from the external source, if needed.
-  HeaderFileInfo &HFI = FileInfo[File->getUID()];
-  if (ExternalSource && !HFI.Resolved)
-    mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(File));
-
-  return HFI.isPragmaOnce || HFI.isImport ||
-      HFI.ControllingMacro || HFI.ControllingMacroID;
+  if (auto *HFI = getExistingFileInfo(File))
+    return HFI->isPragmaOnce || HFI->isImport || HFI->ControllingMacro ||
+           HFI->ControllingMacroID;
+  return false;
 }
 
-void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
-  if (UID >= FileInfo.size())
-    FileInfo.resize(UID+1);
-  HFI.Resolved = true;
-  FileInfo[UID] = HFI;
+void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
+                                        ModuleMap::ModuleHeaderRole Role,
+                                        bool isCompilingModuleHeader) {
+  bool isModularHeader = !(Role & ModuleMap::TextualHeader);
+
+  // Don't mark the file info as non-external if there's nothing to change.
+  if (!isCompilingModuleHeader) {
+    if (!isModularHeader)
+      return;
+    auto *HFI = getExistingFileInfo(FE);
+    if (HFI && HFI->isModuleHeader)
+      return;
+  }
+
+  auto &HFI = getFileInfo(FE);
+  HFI.isModuleHeader |= isModularHeader;
+  HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
 }
 
-bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
+bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
+                                          const FileEntry *File,
+                                          bool isImport, Module *M) {
   ++NumIncluded; // Count # of attempted #includes.
 
   // Get information about this file.
@@ -784,11 +1060,16 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
   // Next, check to see if the file is wrapped with #ifndef guards.  If so, and
   // if the macro that guards it is defined, we know the #include has no effect.
   if (const IdentifierInfo *ControllingMacro
-      = FileInfo.getControllingMacro(ExternalLookup))
-    if (ControllingMacro->hasMacroDefinition()) {
+      = FileInfo.getControllingMacro(ExternalLookup)) {
+    // If the header corresponds to a module, check whether the macro is already
+    // defined in that module rather than checking in the current set of visible
+    // modules.
+    if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M)
+          : PP.isMacroDefined(ControllingMacro)) {
       ++NumMultiIncludeFileOptzn;
       return false;
     }
+  }
 
   // Increment the number of times this file has been included.
   ++FileInfo.NumIncludes;
@@ -805,12 +1086,16 @@ size_t HeaderSearch::getTotalMemory() const {
 }
 
 StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
-  return FrameworkNames.GetOrCreateValue(Framework).getKey();
+  return FrameworkNames.insert(Framework).first->first();
 }
 
 bool HeaderSearch::hasModuleMap(StringRef FileName, 
-                                const DirectoryEntry *Root) {
-  llvm::SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
+                                const DirectoryEntry *Root,
+                                bool IsSystem) {
+  if (!HSOpts->ImplicitModuleMaps)
+    return false;
+
+  SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
   
   StringRef DirName = FileName;
   do {
@@ -818,21 +1103,22 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
     DirName = llvm::sys::path::parent_path(DirName);
     if (DirName.empty())
       return false;
-    
+
     // Determine whether this directory exists.
     const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
     if (!Dir)
       return false;
-    
+
     // Try to load the module map file in this directory.
-    switch (loadModuleMapFile(Dir)) {
+    switch (loadModuleMapFile(Dir, IsSystem,
+                              llvm::sys::path::extension(Dir->getName()) ==
+                                  ".framework")) {
     case LMM_NewlyLoaded:
     case LMM_AlreadyLoaded:
       // Success. All of the directories we stepped through inherit this module
       // map file.
       for (unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
         DirectoryHasModuleMap[FixUpDirectories[I]] = true;
-      
       return true;
 
     case LMM_NoDirectory:
@@ -850,238 +1136,246 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
   } while (true);
 }
 
-Module *HeaderSearch::findModuleForHeader(const FileEntry *File) {
-  if (Module *Mod = ModMap.findModuleForHeader(File))
-    return Mod;
-  
-  return 0;
+ModuleMap::KnownHeader
+HeaderSearch::findModuleForHeader(const FileEntry *File) const {
+  if (ExternalSource) {
+    // Make sure the external source has handled header info about this file,
+    // which includes whether the file is part of a module.
+    (void)getExistingFileInfo(File);
+  }
+  return ModMap.findModuleForHeader(File);
 }
 
-bool HeaderSearch::loadModuleMapFile(const FileEntry *File) {
-  const DirectoryEntry *Dir = File->getDir();
-  
-  llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
-    = DirectoryHasModuleMap.find(Dir);
-  if (KnownDir != DirectoryHasModuleMap.end())
-    return !KnownDir->second;
-  
-  bool Result = ModMap.parseModuleMapFile(File);
-  if (!Result && llvm::sys::path::filename(File->getName()) == "module.map") {
-    // If the file we loaded was a module.map, look for the corresponding
-    // module_private.map.
-    SmallString<128> PrivateFilename(Dir->getName());
+bool HeaderSearch::findUsableModuleForHeader(
+    const FileEntry *File, const DirectoryEntry *Root, Module *RequestingModule,
+    ModuleMap::KnownHeader *SuggestedModule, bool IsSystemHeaderDir) {
+  if (File && SuggestedModule) {
+    // If there is a module that corresponds to this header, suggest it.
+    hasModuleMap(File->getName(), Root, IsSystemHeaderDir);
+    *SuggestedModule = findModuleForHeader(File);
+  }
+  return true;
+}
+
+bool HeaderSearch::findUsableModuleForFrameworkHeader(
+    const FileEntry *File, StringRef FrameworkName, Module *RequestingModule,
+    ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework) {
+  // If we're supposed to suggest a module, look for one now.
+  if (SuggestedModule) {
+    // Find the top-level framework based on this framework.
+    SmallVector<std::string, 4> SubmodulePath;
+    const DirectoryEntry *TopFrameworkDir
+      = ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
+    
+    // Determine the name of the top-level framework.
+    StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
+
+    // Load this framework module. If that succeeds, find the suggested module
+    // for this header, if any.
+    loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystemFramework);
+
+    // FIXME: This can find a module not part of ModuleName, which is
+    // important so that we're consistent about whether this header
+    // corresponds to a module. Possibly we should lock down framework modules
+    // so that this is not possible.
+    *SuggestedModule = findModuleForHeader(File);
+  }
+  return true;
+}
+
+static const FileEntry *getPrivateModuleMap(const FileEntry *File,
+                                            FileManager &FileMgr) {
+  StringRef Filename = llvm::sys::path::filename(File->getName());
+  SmallString<128>  PrivateFilename(File->getDir()->getName());
+  if (Filename == "module.map")
     llvm::sys::path::append(PrivateFilename, "module_private.map");
-    if (const FileEntry *PrivateFile = FileMgr.getFile(PrivateFilename))
-      Result = ModMap.parseModuleMapFile(PrivateFile);
+  else if (Filename == "module.modulemap")
+    llvm::sys::path::append(PrivateFilename, "module.private.modulemap");
+  else
+    return nullptr;
+  return FileMgr.getFile(PrivateFilename);
+}
+
+bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
+  // Find the directory for the module. For frameworks, that may require going
+  // up from the 'Modules' directory.
+  const DirectoryEntry *Dir = nullptr;
+  if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd)
+    Dir = FileMgr.getDirectory(".");
+  else {
+    Dir = File->getDir();
+    StringRef DirName(Dir->getName());
+    if (llvm::sys::path::filename(DirName) == "Modules") {
+      DirName = llvm::sys::path::parent_path(DirName);
+      if (DirName.endswith(".framework"))
+        Dir = FileMgr.getDirectory(DirName);
+      // FIXME: This assert can fail if there's a race between the above check
+      // and the removal of the directory.
+      assert(Dir && "parent must exist");
+    }
   }
-  
-  DirectoryHasModuleMap[Dir] = !Result;  
-  return Result;
+
+  switch (loadModuleMapFileImpl(File, IsSystem, Dir)) {
+  case LMM_AlreadyLoaded:
+  case LMM_NewlyLoaded:
+    return false;
+  case LMM_NoDirectory:
+  case LMM_InvalidModuleMap:
+    return true;
+  }
+  llvm_unreachable("Unknown load module map result");
 }
 
-Module *HeaderSearch::loadFrameworkModule(StringRef Name, 
+HeaderSearch::LoadModuleMapResult
+HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem,
+                                    const DirectoryEntry *Dir) {
+  assert(File && "expected FileEntry");
+
+  // Check whether we've already loaded this module map, and mark it as being
+  // loaded in case we recursively try to load it from itself.
+  auto AddResult = LoadedModuleMaps.insert(std::make_pair(File, true));
+  if (!AddResult.second)
+    return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+
+  if (ModMap.parseModuleMapFile(File, IsSystem, Dir)) {
+    LoadedModuleMaps[File] = false;
+    return LMM_InvalidModuleMap;
+  }
+
+  // Try to load a corresponding private module map.
+  if (const FileEntry *PMMFile = getPrivateModuleMap(File, FileMgr)) {
+    if (ModMap.parseModuleMapFile(PMMFile, IsSystem, Dir)) {
+      LoadedModuleMaps[File] = false;
+      return LMM_InvalidModuleMap;
+    }
+  }
+
+  // This directory has a module map.
+  return LMM_NewlyLoaded;
+}
+
+const FileEntry *
+HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
+  if (!HSOpts->ImplicitModuleMaps)
+    return nullptr;
+  // For frameworks, the preferred spelling is Modules/module.modulemap, but
+  // module.map at the framework root is also accepted.
+  SmallString<128> ModuleMapFileName(Dir->getName());
+  if (IsFramework)
+    llvm::sys::path::append(ModuleMapFileName, "Modules");
+  llvm::sys::path::append(ModuleMapFileName, "module.modulemap");
+  if (const FileEntry *F = FileMgr.getFile(ModuleMapFileName))
+    return F;
+
+  // Continue to allow module.map
+  ModuleMapFileName = Dir->getName();
+  llvm::sys::path::append(ModuleMapFileName, "module.map");
+  return FileMgr.getFile(ModuleMapFileName);
+}
+
+Module *HeaderSearch::loadFrameworkModule(StringRef Name,
                                           const DirectoryEntry *Dir,
                                           bool IsSystem) {
   if (Module *Module = ModMap.findModule(Name))
     return Module;
-  
+
   // Try to load a module map file.
-  switch (loadModuleMapFile(Dir)) {
+  switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/true)) {
   case LMM_InvalidModuleMap:
+    // Try to infer a module map from the framework directory.
+    if (HSOpts->ImplicitModuleMaps)
+      ModMap.inferFrameworkModule(Dir, IsSystem, /*Parent=*/nullptr);
     break;
-    
+
   case LMM_AlreadyLoaded:
   case LMM_NoDirectory:
-    return 0;
-    
-  case LMM_NewlyLoaded:
-    return ModMap.findModule(Name);
-  }
-
-  // The top-level framework directory, from which we'll infer a framework
-  // module.
-  const DirectoryEntry *TopFrameworkDir = Dir;
-  
-  // The path from the module we're actually looking for back to the top-level
-  // framework name.
-  llvm::SmallVector<StringRef, 2> SubmodulePath;
-  SubmodulePath.push_back(Name);
-  
-  // Walk the directory structure to find any enclosing frameworks.
-#ifdef LLVM_ON_UNIX
-  // Note: as an egregious but useful hack we use the real path here, because
-  // frameworks moving from top-level frameworks to embedded frameworks tend
-  // to be symlinked from the top-level location to the embedded location,
-  // and we need to resolve lookups as if we had found the embedded location.
-  char RealDirName[PATH_MAX];
-  StringRef DirName;
-  if (realpath(Dir->getName(), RealDirName))
-    DirName = RealDirName;
-  else
-    DirName = Dir->getName();
-#else
-  StringRef DirName = Dir->getName();
-#endif
-  do {
-    // Get the parent directory name.
-    DirName = llvm::sys::path::parent_path(DirName);
-    if (DirName.empty())
-      break;
-    
-    // Determine whether this directory exists.
-    Dir = FileMgr.getDirectory(DirName);
-    if (!Dir)
-      break;
-    
-    // If this is a framework directory, then we're a subframework of this
-    // framework.
-    if (llvm::sys::path::extension(DirName) == ".framework") {
-      SubmodulePath.push_back(llvm::sys::path::stem(DirName));
-      TopFrameworkDir = Dir;
-    }
-  } while (true);
+    return nullptr;
 
-  // Determine whether we're allowed to infer a module map.
-  bool canInfer = false;
-  if (llvm::sys::path::has_parent_path(TopFrameworkDir->getName())) {
-    // Figure out the parent path.
-    StringRef Parent = llvm::sys::path::parent_path(TopFrameworkDir->getName());
-    if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
-      // If there's a module map file in the parent directory, it can
-      // explicitly allow us to infer framework modules.
-      switch (loadModuleMapFile(ParentDir)) {
-        case LMM_AlreadyLoaded:
-        case LMM_NewlyLoaded: {
-          StringRef Name = llvm::sys::path::stem(TopFrameworkDir->getName());
-          canInfer = ModMap.canInferFrameworkModule(ParentDir, Name, IsSystem);
-          break;
-        }
-        case LMM_InvalidModuleMap:
-        case LMM_NoDirectory:
-          break;
-      }
-    }
+  case LMM_NewlyLoaded:
+    break;
   }
 
-  // If we're not allowed to infer a module map, we're done.
-  if (!canInfer)
-    return 0;
-
-  // Try to infer a module map from the top-level framework directory.
-  Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(), 
-                                               TopFrameworkDir,
-                                               IsSystem,
-                                               /*Parent=*/0);
-  
-  // Follow the submodule path to find the requested (sub)framework module
-  // within the top-level framework module.
-  SubmodulePath.pop_back();
-  while (!SubmodulePath.empty() && Result) {
-    Result = ModMap.lookupModuleQualified(SubmodulePath.back(), Result);
-    SubmodulePath.pop_back();
-  }
-  return Result;
+  return ModMap.findModule(Name);
 }
 
 
 HeaderSearch::LoadModuleMapResult 
-HeaderSearch::loadModuleMapFile(StringRef DirName) {
+HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem,
+                                bool IsFramework) {
   if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
-    return loadModuleMapFile(Dir);
+    return loadModuleMapFile(Dir, IsSystem, IsFramework);
   
   return LMM_NoDirectory;
 }
 
 HeaderSearch::LoadModuleMapResult 
-HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir) {
-  llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
-    = DirectoryHasModuleMap.find(Dir);
+HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem,
+                                bool IsFramework) {
+  auto KnownDir = DirectoryHasModuleMap.find(Dir);
   if (KnownDir != DirectoryHasModuleMap.end())
-    return KnownDir->second? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
-  
-  SmallString<128> ModuleMapFileName;
-  ModuleMapFileName += Dir->getName();
-  unsigned ModuleMapDirNameLen = ModuleMapFileName.size();
-  llvm::sys::path::append(ModuleMapFileName, "module.map");
-  if (const FileEntry *ModuleMapFile = FileMgr.getFile(ModuleMapFileName)) {
-    // We have found a module map file. Try to parse it.
-    if (ModMap.parseModuleMapFile(ModuleMapFile)) {
-      // No suitable module map.
+    return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+
+  if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
+    LoadModuleMapResult Result =
+        loadModuleMapFileImpl(ModuleMapFile, IsSystem, Dir);
+    // Add Dir explicitly in case ModuleMapFile is in a subdirectory.
+    // E.g. Foo.framework/Modules/module.modulemap
+    //      ^Dir                  ^ModuleMapFile
+    if (Result == LMM_NewlyLoaded)
+      DirectoryHasModuleMap[Dir] = true;
+    else if (Result == LMM_InvalidModuleMap)
       DirectoryHasModuleMap[Dir] = false;
-      return LMM_InvalidModuleMap;
-    }
-
-    // This directory has a module map.
-    DirectoryHasModuleMap[Dir] = true;
-    
-    // Check whether there is a private module map that we need to load as well.
-    ModuleMapFileName.erase(ModuleMapFileName.begin() + ModuleMapDirNameLen,
-                            ModuleMapFileName.end());
-    llvm::sys::path::append(ModuleMapFileName, "module_private.map");
-    if (const FileEntry *PrivateModuleMapFile
-                                        = FileMgr.getFile(ModuleMapFileName)) {
-      if (ModMap.parseModuleMapFile(PrivateModuleMapFile)) {
-        // No suitable module map.
-        DirectoryHasModuleMap[Dir] = false;
-        return LMM_InvalidModuleMap;
-      }      
-    }
-    
-    return LMM_NewlyLoaded;
+    return Result;
   }
-  
-  // No suitable module map.
-  DirectoryHasModuleMap[Dir] = false;
   return LMM_InvalidModuleMap;
 }
 
-void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
+void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
   Modules.clear();
-  
-  // Load module maps for each of the header search directories.
-  for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
-    if (SearchDirs[Idx].isFramework()) {
-      llvm::error_code EC;
-      SmallString<128> DirNative;
-      llvm::sys::path::native(SearchDirs[Idx].getFrameworkDir()->getName(),
-                              DirNative);
-      
-      // Search each of the ".framework" directories to load them as modules.
-      bool IsSystem = SearchDirs[Idx].getDirCharacteristic() != SrcMgr::C_User;
-      for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
-           Dir != DirEnd && !EC; Dir.increment(EC)) {
-        if (llvm::sys::path::extension(Dir->path()) != ".framework")
-          continue;
-        
-        const DirectoryEntry *FrameworkDir = FileMgr.getDirectory(Dir->path());
-        if (!FrameworkDir)
-          continue;
-        
-        // Load this framework module.
-        loadFrameworkModule(llvm::sys::path::stem(Dir->path()), FrameworkDir,
-                            IsSystem);
+
+  if (HSOpts->ImplicitModuleMaps) {
+    // Load module maps for each of the header search directories.
+    for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
+      bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
+      if (SearchDirs[Idx].isFramework()) {
+        std::error_code EC;
+        SmallString<128> DirNative;
+        llvm::sys::path::native(SearchDirs[Idx].getFrameworkDir()->getName(),
+                                DirNative);
+
+        // Search each of the ".framework" directories to load them as modules.
+        vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+        for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
+             Dir != DirEnd && !EC; Dir.increment(EC)) {
+          if (llvm::sys::path::extension(Dir->getName()) != ".framework")
+            continue;
+
+          const DirectoryEntry *FrameworkDir =
+              FileMgr.getDirectory(Dir->getName());
+          if (!FrameworkDir)
+            continue;
+
+          // Load this framework module.
+          loadFrameworkModule(llvm::sys::path::stem(Dir->getName()),
+                              FrameworkDir, IsSystem);
+        }
+        continue;
       }
-      continue;
-    }
-    
-    // FIXME: Deal with header maps.
-    if (SearchDirs[Idx].isHeaderMap())
-      continue;
-    
-    // Try to load a module map file for the search directory.
-    loadModuleMapFile(SearchDirs[Idx].getDir());
-    
-    // Try to load module map files for immediate subdirectories of this search
-    // directory.
-    llvm::error_code EC;
-    SmallString<128> DirNative;
-    llvm::sys::path::native(SearchDirs[Idx].getDir()->getName(), DirNative);
-    for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
-         Dir != DirEnd && !EC; Dir.increment(EC)) {
-      loadModuleMapFile(Dir->path());
+
+      // FIXME: Deal with header maps.
+      if (SearchDirs[Idx].isHeaderMap())
+        continue;
+
+      // Try to load a module map file for the search directory.
+      loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem,
+                        /*IsFramework*/ false);
+
+      // Try to load module map files for immediate subdirectories of this
+      // search directory.
+      loadSubdirectoryModuleMaps(SearchDirs[Idx]);
     }
   }
-  
+
   // Populate the list of modules.
   for (ModuleMap::module_iterator M = ModMap.module_begin(), 
                                MEnd = ModMap.module_end();
@@ -1089,3 +1383,95 @@ void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
     Modules.push_back(M->getValue());
   }
 }
+
+void HeaderSearch::loadTopLevelSystemModules() {
+  if (!HSOpts->ImplicitModuleMaps)
+    return;
+
+  // Load module maps for each of the header search directories.
+  for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
+    // We only care about normal header directories.
+    if (!SearchDirs[Idx].isNormalDir()) {
+      continue;
+    }
+
+    // Try to load a module map file for the search directory.
+    loadModuleMapFile(SearchDirs[Idx].getDir(),
+                      SearchDirs[Idx].isSystemHeaderDirectory(),
+                      SearchDirs[Idx].isFramework());
+  }
+}
+
+void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
+  assert(HSOpts->ImplicitModuleMaps &&
+         "Should not be loading subdirectory module maps");
+
+  if (SearchDir.haveSearchedAllModuleMaps())
+    return;
+
+  std::error_code EC;
+  SmallString<128> DirNative;
+  llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
+  vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+  for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
+       Dir != DirEnd && !EC; Dir.increment(EC)) {
+    bool IsFramework =
+        llvm::sys::path::extension(Dir->getName()) == ".framework";
+    if (IsFramework == SearchDir.isFramework())
+      loadModuleMapFile(Dir->getName(), SearchDir.isSystemHeaderDirectory(),
+                        SearchDir.isFramework());
+  }
+
+  SearchDir.setSearchedAllModuleMaps(true);
+}
+
+std::string HeaderSearch::suggestPathToFileForDiagnostics(const FileEntry *File,
+                                                          bool *IsSystem) {
+  // FIXME: We assume that the path name currently cached in the FileEntry is
+  // the most appropriate one for this analysis (and that it's spelled the same
+  // way as the corresponding header search path).
+  const char *Name = File->getName();
+
+  unsigned BestPrefixLength = 0;
+  unsigned BestSearchDir;
+
+  for (unsigned I = 0; I != SearchDirs.size(); ++I) {
+    // FIXME: Support this search within frameworks and header maps.
+    if (!SearchDirs[I].isNormalDir())
+      continue;
+
+    const char *Dir = SearchDirs[I].getDir()->getName();
+    for (auto NI = llvm::sys::path::begin(Name),
+              NE = llvm::sys::path::end(Name),
+              DI = llvm::sys::path::begin(Dir),
+              DE = llvm::sys::path::end(Dir);
+         /*termination condition in loop*/; ++NI, ++DI) {
+      // '.' components in Name are ignored.
+      while (NI != NE && *NI == ".")
+        ++NI;
+      if (NI == NE)
+        break;
+
+      // '.' components in Dir are ignored.
+      while (DI != DE && *DI == ".")
+        ++DI;
+      if (DI == DE) {
+        // Dir is a prefix of Name, up to '.' components and choice of path
+        // separators.
+        unsigned PrefixLength = NI - llvm::sys::path::begin(Name);
+        if (PrefixLength > BestPrefixLength) {
+          BestPrefixLength = PrefixLength;
+          BestSearchDir = I;
+        }
+        break;
+      }
+
+      if (*NI != *DI)
+        break;
+    }
+  }
+
+  if (IsSystem)
+    *IsSystem = BestPrefixLength ? BestSearchDir >= SystemDirIdx : false;
+  return Name + BestPrefixLength;
+}