Index: include/clang/Lex/DirectoryLookup.h =================================================================== --- include/clang/Lex/DirectoryLookup.h +++ include/clang/Lex/DirectoryLookup.h @@ -61,24 +61,31 @@ /// \brief Whether we've performed an exhaustive search for module maps /// within the subdirectories of this directory. unsigned SearchedAllModuleMaps : 1; + + /// \brief Whether the lookup should be case insensitive. This is required + /// for compatibility with case-sensitive file systems and Mcirosoft mode + /// which does not include headers with the correct case. + unsigned CaseInsensitive : 1; public: /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of /// 'dir'. DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT, - bool isFramework) + bool isFramework, bool isCaseInsensitive) : DirCharacteristic(DT), LookupType(isFramework ? LT_Framework : LT_NormalDir), - IsIndexHeaderMap(false), SearchedAllModuleMaps(false) { + IsIndexHeaderMap(false), SearchedAllModuleMaps(false), + CaseInsensitive(isCaseInsensitive) { u.Dir = dir; } /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of /// 'map'. DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT, - bool isIndexHeaderMap) + bool isIndexHeaderMap, bool isCaseInsensitive) : DirCharacteristic(DT), LookupType(LT_HeaderMap), - IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) { + IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false), + CaseInsensitive(isCaseInsensitive) { u.Map = map; } Index: include/clang/Lex/HeaderSearch.h =================================================================== --- include/clang/Lex/HeaderSearch.h +++ include/clang/Lex/HeaderSearch.h @@ -235,6 +235,9 @@ bool EnabledModules; + /// \brief Whether we are performing case insensitive header searches + bool CaseInsensitive; + // HeaderSearch doesn't support default or copy construction. HeaderSearch(const HeaderSearch&) LLVM_DELETED_FUNCTION; void operator=(const HeaderSearch&) LLVM_DELETED_FUNCTION; Index: lib/Frontend/InitHeaderSearch.cpp =================================================================== --- lib/Frontend/InitHeaderSearch.cpp +++ lib/Frontend/InitHeaderSearch.cpp @@ -45,12 +45,15 @@ bool Verbose; std::string IncludeSysroot; bool HasSysroot; + bool CaseInsensitive; public: - InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot) + InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot, + bool caseInsensitive) : Headers(HS), Verbose(verbose), IncludeSysroot(sysroot), - HasSysroot(!(sysroot.empty() || sysroot == "/")) { + HasSysroot(!(sysroot.empty() || sysroot == "/")), + CaseInsensitive(caseInsensitive) { } /// AddPath - Add the specified path to the specified group list, prefixing @@ -153,8 +156,9 @@ // If the directory exists, add it. if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) { - IncludePath.push_back( - std::make_pair(Group, DirectoryLookup(DE, Type, isFramework))); + IncludePath.push_back(std::make_pair(Group, + DirectoryLookup(DE, Type, isFramework, + CaseInsensitive))); return; } @@ -164,9 +168,10 @@ if (const FileEntry *FE = FM.getFile(MappedPathStr)) { if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) { // It is a headermap, add it to the search path. - IncludePath.push_back( - std::make_pair(Group, - DirectoryLookup(HM, Type, Group == IndexHeaderMap))); + IncludePath.push_back(std::make_pair(Group, + DirectoryLookup(HM, Type, + Group == IndexHeaderMap, + CaseInsensitive))); return; } } @@ -671,7 +676,7 @@ const HeaderSearchOptions &HSOpts, const LangOptions &Lang, const llvm::Triple &Triple) { - InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot); + InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot, Lang.MSVCCompat); // Add the user defined entries. for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { Index: lib/Lex/HeaderSearch.cpp =================================================================== --- lib/Lex/HeaderSearch.cpp +++ lib/Lex/HeaderSearch.cpp @@ -29,6 +29,21 @@ #endif using namespace clang; +static bool IsEquivalent(StringRef Path, StringRef LowerFilename) { + llvm::sys::path::reverse_iterator PI, PE, FI, FE; + const std::string LowerPath = Path.lower(); + + for (PI = llvm::sys::path::rbegin(LowerPath), + PE = llvm::sys::path::rend(LowerPath), + FI = llvm::sys::path::rbegin(LowerFilename), + FE = llvm::sys::path::rend(LowerFilename); + FI != FE && PI != PE; ++PI, ++FI) + if (FI->str() != PI->str()) + return false; + + return FI == FE; +} + const IdentifierInfo * HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) { if (ControllingMacro) @@ -47,8 +62,9 @@ SourceManager &SourceMgr, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target) - : HSOpts(HSOpts), Diags(Diags), FileMgr(SourceMgr.getFileManager()), - FrameworkMap(64), ModMap(SourceMgr, Diags, LangOpts, Target, *this) { + : HSOpts(HSOpts), Diags(Diags), FileMgr(SourceMgr.getFileManager()), + FrameworkMap(64), ModMap(SourceMgr, Diags, LangOpts, Target, *this), + CaseInsensitive(LangOpts.MSVCCompat) { AngledDirIdx = 0; SystemDirIdx = 0; NoCurDirSearch = false; @@ -237,6 +253,17 @@ // Concatenate the requested file onto the directory. TmpDir = getDir()->getName(); llvm::sys::path::append(TmpDir, Filename); + if (CaseInsensitive && !llvm::sys::fs::exists(TmpDir.str())) { + llvm::error_code EC; + std::string LowerFilename = Filename.lower(); + for (llvm::sys::fs::directory_iterator DI(getDir()->getName(), EC), DE; + !EC && DI != DE; DI = DI.increment(EC)) { + if (IsEquivalent(DI->path(), LowerFilename)) { + TmpDir = DI->path(); + break; + } + } + } if (SearchPath != NULL) { StringRef SearchPathRef(getDir()->getName()); SearchPath->clear(); @@ -567,6 +594,15 @@ RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } + if (CaseInsensitive && !llvm::sys::fs::exists(Filename)) { + llvm::error_code EC; + std::string LowerFilename = Filename.lower(); + for (llvm::sys::fs::directory_iterator + DI(llvm::sys::path::parent_path(Filename), EC), DE; + !EC && DI != DE; DI = DI.increment(EC)) + if (IsEquivalent(DI->path(), LowerFilename)) + return FileMgr.getFile(DI->path(), /*openFile=*/true); + } // Otherwise, just return the file. return FileMgr.getFile(Filename, /*openFile=*/true); } @@ -590,6 +626,18 @@ TmpDir = Includer->getDir()->getName(); TmpDir.push_back('/'); TmpDir.append(Filename.begin(), Filename.end()); + if (CaseInsensitive && !llvm::sys::fs::exists(TmpDir.str())) { + llvm::error_code EC; + std::string LowerFilename = Filename.lower(); + for (llvm::sys::fs::directory_iterator + DI(Includer->getDir()->getName(), EC), DE; + !EC && DI != DE; DI = DI.increment(EC)) { + if (IsEquivalent(DI->path(), LowerFilename)) { + TmpDir = DI->path(); + break; + } + } + } if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(), /*openFile=*/true)) { // Leave CurDir unset. Index: lib/Lex/PPDirectives.cpp =================================================================== --- lib/Lex/PPDirectives.cpp +++ lib/Lex/PPDirectives.cpp @@ -1461,7 +1461,7 @@ if (Callbacks->FileNotFound(Filename, RecoveryPath)) { if (const DirectoryEntry *DE = FileMgr.getDirectory(RecoveryPath)) { // Add the recovery path to the list of search paths. - DirectoryLookup DL(DE, SrcMgr::C_User, false); + DirectoryLookup DL(DE, SrcMgr::C_User, false, false); HeaderInfo.AddSearchPath(DL, isAngled); // Try the lookup again, skipping the cache. Index: unittests/Lex/PPCallbacksTest.cpp =================================================================== --- unittests/Lex/PPCallbacksTest.cpp +++ unittests/Lex/PPCallbacksTest.cpp @@ -140,7 +140,7 @@ // Add header's parent path to search path. StringRef SearchPath = path::parent_path(HeaderPath); const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath); - DirectoryLookup DL(DE, SrcMgr::C_User, false); + DirectoryLookup DL(DE, SrcMgr::C_User, false, false); HeaderInfo.AddSearchPath(DL, IsSystemHeader); }